@@ -283,51 +283,6 @@ function sessionTitle(
283283 ) ;
284284}
285285
286- function shortSessionId (
287- sessionId : string ,
288- ) : string {
289- if ( sessionId . length <= 16 ) {
290- return sessionId ;
291- }
292-
293- return `${ sessionId . slice ( 0 , 12 ) } …` ;
294- }
295-
296- function normalizeThreadName (
297- value : string | undefined ,
298- ) : string | undefined {
299- const name = value ?. trim ( ) ;
300- return name ? name : undefined ;
301- }
302-
303- function sessionActionLabel (
304- item : SessionInventoryItem ,
305- peers : SessionInventoryItem [ ] ,
306- ) : string {
307- /*
308- * Keep the action label human-readable without pretending that a project
309- * directory identifies a Session. Thread names are preferred; duplicate
310- * names get a short Session ID suffix; unnamed Sessions use a short ID.
311- */
312- const threadName = normalizeThreadName ( item . threadName ) ;
313-
314- if ( ! threadName ) {
315- return shortSessionId ( item . sessionId ) ;
316- }
317-
318- const duplicateCount = peers . filter (
319- ( peer ) =>
320- normalizeThreadName ( peer . threadName ) ?. toLocaleLowerCase ( ) ===
321- threadName . toLocaleLowerCase ( ) ,
322- ) . length ;
323-
324- if ( duplicateCount > 1 ) {
325- return `${ threadName } · ${ shortSessionId ( item . sessionId ) } ` ;
326- }
327-
328- return threadName ;
329- }
330-
331286function inventoryForContext (
332287 ctx : any ,
333288) : {
@@ -473,12 +428,14 @@ function sessionActionButtons(
473428 ctx : any ,
474429 item : SessionInventoryItem ,
475430 bindings : LarkBinding [ ] ,
476- peers : SessionInventoryItem [ ] ,
477431 provider : SessionProvider ,
478432) : ButtonSpec [ ] {
479433 const linked = bindingsFor ( item , bindings ) ;
480434 const current = linked . some ( ( binding ) => binding . current ) ;
481- const target = sessionActionLabel ( item , peers ) ;
435+ // Labels name the action and its direction only: the row above already
436+ // shows the Session, and short labels keep two buttons per line on mobile.
437+ // The title is repeated in the hover tip for desktop.
438+ const title = sessionTitle ( item ) ;
482439
483440 const buttons : ButtonSpec [ ] = [ lastResponseButton ( item , provider ) ] ;
484441
@@ -490,10 +447,10 @@ function sessionActionButtons(
490447
491448 if ( current ) {
492449 buttons . push ( {
493- text : ` ↩ Hand Back ${ target } ` ,
450+ text : ' ↩ Hand Back to Windows' ,
494451 value : { cmd : 'handback' } ,
495452 style : 'primary' ,
496- hoverTips : ' Unbind the current Lark scope and make this Session Detached / ready to resume on Windows.' ,
453+ hoverTips : ` Unbind " ${ title } " from this Lark scope and make it Detached / ready to resume on Windows.` ,
497454 } ) ;
498455 return buttons ;
499456 }
@@ -516,27 +473,27 @@ function sessionActionButtons(
516473 }
517474
518475 buttons . push ( {
519- text : ` ↪ Handoff ${ target } ` ,
476+ text : ' ↪ Handoff to Lark' ,
520477 value : {
521478 cmd : 'local-handoff' ,
522479 // Always target the exact full Session ID; the label is display-only.
523480 arg : item . sessionId ,
524481 } ,
525482 style : 'primary' ,
526- hoverTips : ' Release the Windows writer and bind this Session to the current Lark scope.' ,
483+ hoverTips : ` Release the Windows writer of " ${ title } " and bind it to this Lark scope.` ,
527484 } ) ;
528485 return buttons ;
529486 }
530487
531488 buttons . push ( {
532- text : ` ▶ Use ${ target } ` ,
489+ text : ' ▶ Use in Lark' ,
533490 value : {
534491 cmd : 'use' ,
535492 // Always target the exact full Session ID; the label is display-only.
536493 arg : item . sessionId ,
537494 } ,
538495 style : 'primary' ,
539- hoverTips : ' Bind this Detached Codex Session to the current Lark scope.' ,
496+ hoverTips : ` Bind the Detached ${ provider . label } Session " ${ title } " to this Lark scope.` ,
540497 } ) ;
541498
542499 return buttons ;
@@ -673,7 +630,7 @@ export async function handleLocalSessions(
673630 lines . push ( `🕒 ${ formatUpdated ( item . updatedAtMs ) } ` ) ;
674631 elements . push ( divMd ( lines . join ( '\n' ) ) ) ;
675632
676- const buttons = sessionActionButtons ( ctx , item , bindings , candidates , provider ) ;
633+ const buttons = sessionActionButtons ( ctx , item , bindings , provider ) ;
677634 if ( buttons . length > 0 ) {
678635 elements . push ( actions ( buttons ) ) ;
679636 }
@@ -696,11 +653,11 @@ export async function handleLocalSessions(
696653 divMd (
697654 [
698655 '**Session actions**' ,
699- '• **Use in this Lark** — Detached Session → current Lark scope' ,
656+ '• **Use in Lark** — Detached Session → this Lark scope' ,
700657 provider . supportsHandoff
701- ? '• **Handoff to this Lark** — Windows → current Lark scope'
658+ ? '• **Handoff to Lark** — Windows → this Lark scope'
702659 : `• **Handoff** — not available for ${ provider . label } yet; quit the Windows window first, then Use` ,
703- '• **Hand Back to Windows** — current Lark scope → Detached / Windows-ready' ,
660+ '• **Hand Back to Windows** — this Lark scope → Detached / Windows-ready' ,
704661 `• **Last Response** — read the latest completed user-visible ${ provider . label } response` ,
705662 ...olderHint ,
706663 ] . join ( '\n' ) ,
@@ -1104,33 +1061,56 @@ export async function handleLocalUse(
11041061 } ) ;
11051062 }
11061063
1107- await reply (
1108- ctx ,
1109- [
1110- '✅ **Lark Session switched**' ,
1111- '' ,
1112- `🏷 **Thread:** ${ clean (
1113- sessionTitle (
1114- target ,
1115- ) ,
1116- ) } `,
1117- '' ,
1118- `🔗 **Session:** \`${ clean (
1119- target . sessionId ,
1120- ) } \``,
1121- '' ,
1122- `📂 **Directory:** \`${ clean (
1123- target . cwd ,
1124- ) } \``,
1125- '' ,
1126- ...( bound . catalogBound || provider . agentKind === 'claude'
1127- ? [ '**下一条普通消息将继续这个 Session。**' ]
1128- : [
1129- // Codex resumes only from the session catalog (run-flow.ts).
1130- '⚠️ **Session catalog 不可用,Codex 无法续接这个 Session;下一条消息会开启新 thread。**' ,
1131- ] ) ,
1132- ] . join ( '\n' ) ,
1064+ const summary = [
1065+ `🏷 **Thread:** ${ clean ( sessionTitle ( target ) ) } ` ,
1066+ ...( target . projectName ? [ `📁 **Project:** ${ clean ( target . projectName ) } ` ] : [ ] ) ,
1067+ `🔗 **Session:** ${ clean ( target . sessionId ) } ` ,
1068+ `📂 **Directory:** ${ clean ( target . cwd ) } ` ,
1069+ '👤 **Owner:** Lark · Current' ,
1070+ '' ,
1071+ ...( bound . catalogBound || provider . agentKind === 'claude'
1072+ ? [ '**Continue by sending a normal message in this Lark scope.**' ]
1073+ : [
1074+ // Codex resumes only from the session catalog (run-flow.ts).
1075+ '⚠️ **Session catalog 不可用,Codex 无法续接这个 Session;下一条消息会开启新 thread。**' ,
1076+ ] ) ,
1077+ ] ;
1078+
1079+ /*
1080+ * Like a handoff, show where the conversation left off — a Detached
1081+ * Session was usually last used on Windows, so this is what the user needs
1082+ * to pick it up from Lark. Display only: the resumed Session already has
1083+ * the full history.
1084+ */
1085+ const lastResponse = await provider . readLastResponse ( target , 5_000 ) ;
1086+
1087+ const elements : object [ ] = [ divMd ( summary . join ( '\n' ) ) , { tag : 'hr' } ] ;
1088+
1089+ if ( lastResponse ) {
1090+ elements . push ( divMd ( '**💬 Last Response**' ) , divPlain ( lastResponse . text ) ) ;
1091+ if ( lastResponse . truncated ) {
1092+ elements . push (
1093+ divMd ( `_The response was shortened for Lark display; the full text remains in the ${ provider . label } transcript._` ) ,
1094+ ) ;
1095+ }
1096+ }
1097+ else {
1098+ elements . push ( divMd ( '💬 **Last Response:** no completed user-visible response was found.' ) ) ;
1099+ }
1100+
1101+ elements . push (
1102+ { tag : 'hr' } ,
1103+ actions ( [
1104+ {
1105+ text : '↩ Hand Back to Windows' ,
1106+ value : { cmd : 'handback' } ,
1107+ style : 'primary' ,
1108+ hoverTips : 'Unbind this Session from the current Lark scope and make it Detached / Windows-ready.' ,
1109+ } ,
1110+ ] ) ,
11331111 ) ;
1112+
1113+ await replyCard ( ctx , shell ( '✅ Session Now in Lark' , elements ) ) ;
11341114}
11351115
11361116function powerShellQuote (
0 commit comments