Skip to content

Commit 2281001

Browse files
denvenclaude
andcommitted
feat(session): action-only button labels; show Last Response on /session use
- Buttons name the action and its direction only — "Handoff to Lark", "Use in Lark", "Hand Back to Windows". The numbered row above already identifies the session, the name made labels long enough to break the two-per-line layout on mobile, and it now lives in the hover tip. The card legend and the handoff success cards use the same names. Removes the label helpers that only served the old names. - /session use replies with a card showing where the conversation left off (Last Response) plus a Hand Back button, as handoff already did. A Detached session was usually last used on Windows. Display only: the resumed session already has its full history. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 3dc06c3 commit 2281001

3 files changed

Lines changed: 65 additions & 85 deletions

File tree

‎src/commands/claude-handoff.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ export async function handleClaudeHandoff(
470470
hoverTips: 'Read the latest completed user-visible Claude Code response for this Session.',
471471
},
472472
{
473-
text: '↩ Hand Back',
473+
text: '↩ Hand Back to Windows',
474474
value: { cmd: 'handback' },
475475
style: 'primary',
476476
hoverTips: 'Unbind this Session from the current Lark scope and make it Detached / Windows-ready.',

‎src/commands/local-handoff.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ export async function handleLocalHandoff(
12501250
hoverTips: 'Read the latest completed user-visible Codex response for this Session.',
12511251
},
12521252
{
1253-
text: '↩ Hand Back',
1253+
text: '↩ Hand Back to Windows',
12541254
value: { cmd: 'handback' },
12551255
style: 'primary',
12561256
hoverTips: 'Unbind this Session from the current Lark scope and make it Detached / Windows-ready.',

‎src/commands/local-session-manager.ts‎

Lines changed: 63 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
331286
function 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

11361116
function powerShellQuote(

0 commit comments

Comments
 (0)