@@ -395,6 +395,31 @@ describe("buildProjectActionItems", () => {
395395} ) ;
396396
397397describe ( "buildThreadActionItems" , ( ) => {
398+ it ( "selects the intended environment when thread IDs are shared" , async ( ) => {
399+ const local = makeThread ( ) ;
400+ const remote = makeThread ( { environmentId : EnvironmentId . make ( "remote-copy" ) } ) ;
401+ const runThread = vi . fn ( async ( ) => { } ) ;
402+ const items = buildThreadActionItems ( {
403+ threads : [ local , remote ] ,
404+ activeThread : remote ,
405+ projectByKey : new Map ( [
406+ [ `${ local . environmentId } :${ local . projectId } ` , { title : "Local project" } ] ,
407+ [ `${ remote . environmentId } :${ remote . projectId } ` , { title : "Remote project" } ] ,
408+ ] ) ,
409+ sortOrder : "updated_at" ,
410+ icon : null ,
411+ runThread,
412+ } ) ;
413+ const groups = [ { value : "threads" , label : "Threads" , items } ] ;
414+ const selected = findHighlightedCommandPaletteItem ( groups , items [ 1 ] ! . value ) ;
415+ if ( selected ?. kind === "action" ) await selected . run ( ) ;
416+ expect ( runThread ) . toHaveBeenCalledWith ( remote ) ;
417+ expect ( new Set ( buildCommandPaletteRows ( groups ) . itemValues ) . size ) . toBe ( 2 ) ;
418+ expect ( items [ 0 ] ?. description ) . toBe ( "Local project" ) ;
419+ expect ( items [ 1 ] ?. description ) . toBe ( "Remote project · Current thread" ) ;
420+ expect ( items [ 0 ] ?. searchTerms ) . not . toContain ( "Remote project" ) ;
421+ } ) ;
422+
398423 it ( "orders threads by most recent activity and formats timestamps from updatedAt" , ( ) => {
399424 vi . useFakeTimers ( ) ;
400425 vi . setSystemTime ( new Date ( "2026-03-25T12:00:00.000Z" ) ) ;
@@ -414,15 +439,15 @@ describe("buildThreadActionItems", () => {
414439 updatedAt : "2026-03-20T00:00:00.000Z" ,
415440 } ) ,
416441 ] ,
417- projectTitleById : new Map ( [ [ PROJECT_ID , "Project" ] ] ) ,
442+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "Project" } ] ] ) ,
418443 sortOrder : "updated_at" ,
419444 icon : null ,
420445 runThread : async ( _thread ) => undefined ,
421446 } ) ;
422447
423448 expect ( items . map ( ( item ) => item . value ) ) . toEqual ( [
424- "thread:thread-older" ,
425- "thread:thread-newer" ,
449+ "thread:environment-local: thread-older" ,
450+ "thread:environment-local: thread-newer" ,
426451 ] ) ;
427452 expect ( items [ 0 ] ?. timestamp ) . toBe ( "1d ago" ) ;
428453 expect ( items [ 1 ] ?. timestamp ) . toBe ( "5d ago" ) ;
@@ -446,7 +471,7 @@ describe("buildThreadActionItems", () => {
446471 updatedAt : "2026-03-19T00:00:00.000Z" ,
447472 } ) ,
448473 ] ,
449- projectTitleById : new Map ( [ [ PROJECT_ID , "Project" ] ] ) ,
474+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "Project" } ] ] ) ,
450475 sortOrder : "updated_at" ,
451476 icon : null ,
452477 runThread : async ( _thread ) => undefined ,
@@ -463,8 +488,8 @@ describe("buildThreadActionItems", () => {
463488 expect ( groups ) . toHaveLength ( 1 ) ;
464489 expect ( groups [ 0 ] ?. value ) . toBe ( "threads-search" ) ;
465490 expect ( groups [ 0 ] ?. items . map ( ( item ) => item . value ) ) . toEqual ( [
466- "thread:thread-title-match" ,
467- "thread:thread-context-match" ,
491+ "thread:environment-local: thread-title-match" ,
492+ "thread:environment-local: thread-context-match" ,
468493 ] ) ;
469494 } ) ;
470495
@@ -491,7 +516,7 @@ describe("buildThreadActionItems", () => {
491516 ] ;
492517 const items = buildThreadActionItems ( {
493518 threads,
494- projectTitleById : new Map ( [ [ PROJECT_ID , "T3 Code" ] ] ) ,
519+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "T3 Code" } ] ] ) ,
495520 sortOrder : "created_at" ,
496521 icon : null ,
497522 getContentMatch : ( thread ) =>
@@ -510,9 +535,9 @@ describe("buildThreadActionItems", () => {
510535 } ) ;
511536
512537 expect ( groups [ 0 ] ?. items . map ( ( item ) => item . value ) ) . toEqual ( [
513- "thread:recent-title" ,
514- "thread:old-prefix" ,
515- "thread:recent-content" ,
538+ "thread:environment-local: recent-title" ,
539+ "thread:environment-local: old-prefix" ,
540+ "thread:environment-local: recent-content" ,
516541 ] ) ;
517542 } ) ;
518543
@@ -640,7 +665,7 @@ describe("buildThreadActionItems", () => {
640665 it ( "keeps message excerpts searchable without replacing thread metadata" , ( ) => {
641666 const [ item ] = buildThreadActionItems ( {
642667 threads : [ makeThread ( { branch : "feat/search" } ) ] ,
643- projectTitleById : new Map ( [ [ PROJECT_ID , "T3 Code" ] ] ) ,
668+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "T3 Code" } ] ] ) ,
644669 sortOrder : "updated_at" ,
645670 icon : null ,
646671 getContentMatch : ( ) => ( {
@@ -673,7 +698,7 @@ describe("buildThreadActionItems", () => {
673698 } ) ;
674699 const items = buildThreadActionItems ( {
675700 threads : [ idThread , titleThread ] ,
676- projectTitleById : new Map ( [ [ PROJECT_ID , "T3 Code" ] ] ) ,
701+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "T3 Code" } ] ] ) ,
677702 sortOrder : "updated_at" ,
678703 icon : null ,
679704 runThread : async ( _thread ) => undefined ,
@@ -689,15 +714,15 @@ describe("buildThreadActionItems", () => {
689714 } ) ;
690715
691716 expect ( groups . flatMap ( ( group ) => group . items ) ) . toEqual ( [
692- expect . objectContaining ( { value : `thread:${ titleThread . id } ` } ) ,
693- expect . objectContaining ( { value : `thread:${ idThread . id } ` } ) ,
717+ expect . objectContaining ( { value : `thread:${ titleThread . environmentId } : ${ titleThread . id } ` } ) ,
718+ expect . objectContaining ( { value : `thread:${ idThread . environmentId } : ${ idThread . id } ` } ) ,
694719 ] ) ;
695720 } ) ;
696721
697722 it ( "prefers renderDescription when provided" , ( ) => {
698723 const [ item ] = buildThreadActionItems ( {
699724 threads : [ makeThread ( { branch : "feat/search" , worktreePath : "/tmp/wt" } ) ] ,
700- projectTitleById : new Map ( [ [ PROJECT_ID , "T3 Code" ] ] ) ,
725+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "T3 Code" } ] ] ) ,
701726 sortOrder : "updated_at" ,
702727 icon : null ,
703728 renderDescription : ( thread , { projectTitle } ) =>
@@ -724,13 +749,13 @@ describe("buildThreadActionItems", () => {
724749 updatedAt : "2026-03-20T00:00:00.000Z" ,
725750 } ) ,
726751 ] ,
727- projectTitleById : new Map ( [ [ PROJECT_ID , "Project" ] ] ) ,
752+ projectByKey : new Map ( [ [ ` ${ LOCAL_ENVIRONMENT_ID } : ${ PROJECT_ID } ` , { title : "Project" } ] ] ) ,
728753 sortOrder : "updated_at" ,
729754 icon : null ,
730755 runThread : async ( _thread ) => undefined ,
731756 } ) ;
732757
733- expect ( items . map ( ( item ) => item . value ) ) . toEqual ( [ "thread:thread-active" ] ) ;
758+ expect ( items . map ( ( item ) => item . value ) ) . toEqual ( [ "thread:environment-local: thread-active" ] ) ;
734759 } ) ;
735760} ) ;
736761
@@ -833,7 +858,7 @@ it.each([
833858 } ) ,
834859 makeThread ( { id : ThreadId . make ( "unrelated" ) , title : "Other work" } ) ,
835860 ] ,
836- projectTitleById : new Map ( ) ,
861+ projectByKey : new Map ( ) ,
837862 sortOrder : "updated_at" ,
838863 icon : null ,
839864 runThread : async ( ) => undefined ,
0 commit comments