lark-remote 0.5.19 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/bridge/approval-actions.d.ts +1 -1
  3. package/dist/bridge/approval-actions.js +1 -1
  4. package/dist/bridge/bash-run.d.ts +71 -0
  5. package/dist/bridge/bash-run.js +217 -0
  6. package/dist/bridge/compact.d.ts +155 -0
  7. package/dist/bridge/compact.js +450 -0
  8. package/dist/bridge/final-usage.js +4 -4
  9. package/dist/bridge/inbound-media.js +72 -46
  10. package/dist/bridge/index.d.ts +106 -153
  11. package/dist/bridge/index.js +400 -1000
  12. package/dist/bridge/job-watch.d.ts +68 -0
  13. package/dist/bridge/job-watch.js +146 -0
  14. package/dist/bridge/queue-manager.d.ts +3 -3
  15. package/dist/bridge/queue-manager.js +10 -29
  16. package/dist/card/approval-render.d.ts +2 -2
  17. package/dist/card/approval-render.js +141 -130
  18. package/dist/card/card-budget.js +123 -98
  19. package/dist/card/card-helpers.d.ts +3 -3
  20. package/dist/card/card-helpers.js +6 -6
  21. package/dist/card/final-answer-file.js +1 -1
  22. package/dist/card/run-renderer.d.ts +3 -3
  23. package/dist/card/run-renderer.js +114 -159
  24. package/dist/card/run-state.d.ts +1 -15
  25. package/dist/card/run-state.js +358 -292
  26. package/dist/card/tool-render.d.ts +1 -1
  27. package/dist/card/tool-render.js +21 -17
  28. package/dist/card/usage-format.d.ts +22 -7
  29. package/dist/card/usage-format.js +119 -100
  30. package/dist/cli.js +15 -3
  31. package/dist/clone.js +2 -2
  32. package/dist/common/text-width.js +36 -24
  33. package/dist/common/tool-summary.js +132 -90
  34. package/dist/config/codex-config.js +130 -106
  35. package/dist/config/index.d.ts +16 -2
  36. package/dist/config/index.js +23 -8
  37. package/dist/connector/index.js +6 -6
  38. package/dist/error-classification.js +3 -2
  39. package/dist/inbound/placeholder.d.ts +1 -1
  40. package/dist/inbound/placeholder.js +1 -1
  41. package/dist/index.js +387 -281
  42. package/dist/logger/index.js +6 -6
  43. package/dist/message-handlers.d.ts +0 -5
  44. package/dist/message-handlers.js +254 -237
  45. package/dist/model-catalog.d.ts +2 -2
  46. package/dist/model-catalog.js +3 -8
  47. package/dist/platform/identity.js +1 -1
  48. package/dist/platform/path.d.ts +1 -1
  49. package/dist/platform/path.js +1 -1
  50. package/dist/platform/sleep-blocker.js +1 -1
  51. package/dist/platform/terminator-win32.js +2 -1
  52. package/dist/router/commands/ls.d.ts +3 -0
  53. package/dist/router/commands/ls.js +256 -175
  54. package/dist/router/commands/order.js +184 -159
  55. package/dist/router/commands/resume.js +190 -152
  56. package/dist/router/commands/ws.js +219 -174
  57. package/dist/router/config/dsh.d.ts +4 -8
  58. package/dist/router/config/dsh.js +3 -10
  59. package/dist/router/config/kimi.js +1 -1
  60. package/dist/router/config/types.d.ts +1 -1
  61. package/dist/router/config-diff.js +1 -1
  62. package/dist/router/index.d.ts +56 -11
  63. package/dist/router/index.js +401 -391
  64. package/dist/runner/bash/runner.js +2 -4
  65. package/dist/runner/claude/session.d.ts +1 -1
  66. package/dist/runner/claude/session.js +6 -4
  67. package/dist/runner/codex/app-server/runner.d.ts +9 -2
  68. package/dist/runner/codex/app-server/runner.js +30 -25
  69. package/dist/runner/codex/app-server/translator.d.ts +2 -5
  70. package/dist/runner/codex/app-server/translator.js +291 -238
  71. package/dist/runner/common/acp/acp-approval.d.ts +1 -1
  72. package/dist/runner/common/acp/acp-approval.js +1 -1
  73. package/dist/runner/common/acp/base-acp-runner.d.ts +5 -2
  74. package/dist/runner/common/acp/base-acp-runner.js +26 -65
  75. package/dist/runner/common/acp/base-translator.d.ts +12 -2
  76. package/dist/runner/common/acp/base-translator.js +50 -26
  77. package/dist/runner/common/acp/protocol-types.d.ts +1 -1
  78. package/dist/runner/common/acp/protocol-types.js +2 -2
  79. package/dist/runner/common/connection-based-runner.d.ts +32 -1
  80. package/dist/runner/common/connection-based-runner.js +32 -2
  81. package/dist/runner/common/jsonl-stream.js +154 -187
  82. package/dist/runner/common/jsonrpc/client.d.ts +29 -0
  83. package/dist/runner/common/jsonrpc/client.js +43 -12
  84. package/dist/runner/common/jsonrpc/connection-manager.d.ts +2 -2
  85. package/dist/runner/common/jsonrpc/connection-manager.js +4 -4
  86. package/dist/runner/common/spawning-runner.d.ts +6 -1
  87. package/dist/runner/common/spawning-runner.js +9 -4
  88. package/dist/runner/common/turn-started.d.ts +8 -0
  89. package/dist/runner/common/turn-started.js +11 -0
  90. package/dist/runner/dsh/approval.js +84 -51
  91. package/dist/runner/dsh/catalog-probe.d.ts +17 -0
  92. package/dist/runner/dsh/catalog-probe.js +10 -0
  93. package/dist/runner/dsh/client.d.ts +7 -11
  94. package/dist/runner/dsh/client.js +356 -289
  95. package/dist/runner/dsh/exit-cancel.d.ts +2 -2
  96. package/dist/runner/dsh/exit-cancel.js +2 -2
  97. package/dist/runner/dsh/inflight.d.ts +1 -1
  98. package/dist/runner/dsh/inflight.js +1 -1
  99. package/dist/runner/dsh/mux-stream.js +28 -8
  100. package/dist/runner/dsh/runner.d.ts +44 -4
  101. package/dist/runner/dsh/runner.js +296 -199
  102. package/dist/runner/dsh/translator.d.ts +1 -31
  103. package/dist/runner/dsh/translator.js +180 -178
  104. package/dist/runner/index.d.ts +1 -1
  105. package/dist/runner/kimi/acp/runner.d.ts +1 -2
  106. package/dist/runner/kimi/acp/runner.js +82 -46
  107. package/dist/runner/kimi/acp/translator.d.ts +1 -1
  108. package/dist/runner/kimi/acp/translator.js +3 -4
  109. package/dist/runner/opencode/acp/error-monitor.js +5 -5
  110. package/dist/runner/opencode/acp/runner.d.ts +2 -2
  111. package/dist/runner/opencode/acp/runner.js +4 -4
  112. package/dist/runner/pi/rpc/client.js +4 -13
  113. package/dist/runner/pi/rpc/protocol-types.d.ts +1 -1
  114. package/dist/runner/pi/rpc/protocol-types.js +1 -1
  115. package/dist/runner/pi/rpc/runner.d.ts +3 -0
  116. package/dist/runner/pi/rpc/runner.js +27 -42
  117. package/dist/runner/pi/rpc/translator.js +61 -60
  118. package/dist/runner/types.d.ts +2 -2
  119. package/dist/runner/types.js +1 -1
  120. package/dist/session/claude/sessions.d.ts +45 -0
  121. package/dist/session/claude/sessions.js +160 -122
  122. package/dist/session/codex/rollout-reader.js +181 -182
  123. package/dist/session/common/throw-session-list-error.d.ts +10 -0
  124. package/dist/session/common/throw-session-list-error.js +16 -0
  125. package/dist/session/dsh/sessions.js +291 -235
  126. package/dist/session/kimi/sessions.d.ts +40 -8
  127. package/dist/session/kimi/sessions.js +373 -301
  128. package/dist/session/opencode/sessions.d.ts +142 -1
  129. package/dist/session/opencode/sessions.js +378 -321
  130. package/dist/session/pi/sessions.js +4 -5
  131. package/dist/session/session-store.d.ts +9 -1
  132. package/dist/session/session-store.js +99 -99
  133. package/dist/update/version-check.js +2 -1
  134. package/dist/workspace/index.d.ts +1 -1
  135. package/dist/workspace/index.js +1 -1
  136. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { isAgentKind } from '../../agent-kinds.js';
2
- import { agentDisplayName } from '../../card/card-shared.js';
2
+ import { agentDisplayName, cardButton } from '../../card/card-shared.js';
3
3
  import { buildSessionHistoryCard, paginationBar } from '../../card/card-helpers.js';
4
4
  import { pageInfo } from '../paging.js';
5
5
  import { clampInt } from '../../common/clamp.js';
@@ -12,10 +12,8 @@ function sessionPreviewLine(text, max) {
12
12
  const oneLine = text.replace(/\s+/g, ' ').trim();
13
13
  return oneLine.length > max ? oneLine.slice(0, max - 1) + '…' : oneLine;
14
14
  }
15
- export function buildResumeCommand(args, ctx, offset, deps) {
16
- const entry = deps.getSessionEntry(ctx.userId);
17
- const cwd = entry?.cwd;
18
- let agentKind = deps.defaultAgent;
15
+ function parseResumeArgs(args, defaultAgent) {
16
+ let agentKind = defaultAgent;
19
17
  let limit;
20
18
  let sessionIdArg;
21
19
  if (args[0]) {
@@ -35,88 +33,87 @@ export function buildResumeCommand(args, ctx, offset, deps) {
35
33
  sessionIdArg = args[0];
36
34
  }
37
35
  }
38
- if (sessionIdArg) {
39
- if (!entry || !cwd)
40
- return { text: '请先 /cd 设置工作目录' };
41
- const reader = agentKind !== deps.defaultAgent ? deps.readerFor(agentKind) : deps.defaultReader();
42
- const verifyContent = reader.readSessionContent(sessionIdArg, cwd);
43
- if (verifyContent.events.length === 0 &&
44
- !verifyContent.usage &&
45
- !verifyContent.aiTitle &&
46
- !verifyContent.recap &&
47
- !verifyContent.displayTitle) {
36
+ return { agentKind, limit, sessionIdArg };
37
+ }
38
+ function readerForAgent(deps, agentKind) {
39
+ return agentKind !== deps.defaultAgent ? deps.readerFor(agentKind) : deps.defaultReader();
40
+ }
41
+ /** 恢复指定 session 前的校验;返回 CommandResult 表示应当中止。 */
42
+ function verifyResumeTarget(reader, deps, agentKind, sessionIdArg, cwd) {
43
+ const verifyContent = reader.readSessionContent(sessionIdArg, cwd);
44
+ if (verifyContent.events.length === 0 &&
45
+ !verifyContent.usage &&
46
+ !verifyContent.aiTitle &&
47
+ !verifyContent.recap &&
48
+ !verifyContent.displayTitle) {
49
+ return {
50
+ text: `未找到 session ${sessionIdArg}(当前目录: ${cwd})。请确认该 session 属于此目录,或先 /cd 到正确目录。`,
51
+ };
52
+ }
53
+ if (agentKind === 'dsh' && deps.defaultAgent === 'dsh') {
54
+ const mismatch = deps.dshPresetMismatch(reader, sessionIdArg, cwd);
55
+ if (mismatch) {
48
56
  return {
49
- text: `未找到 session ${sessionIdArg}(当前目录: ${cwd})。请确认该 session 属于此目录,或先 /cd 到正确目录。`,
57
+ text: `⚠️ 该 DSH session 的 preset 是「${mismatch.sessionPreset}」,与当前配置「${mismatch.currentPreset}」不一致。\n` +
58
+ `preset 在 session 创建时固定,无法中途切换(DSH 返回 agent-preset-conflict)。\n` +
59
+ `继续恢复将在下次 run 失败。请在 /config 中把预设模式改回「${mismatch.sessionPreset}」后重试,或保持当前配置并发新消息新建会话。`,
50
60
  };
51
61
  }
52
- if (agentKind === 'dsh' && deps.defaultAgent === 'dsh') {
53
- const mismatch = deps.dshPresetMismatch(reader, sessionIdArg, cwd);
54
- if (mismatch) {
55
- return {
56
- text: `⚠️ 该 DSH session 的 preset 是「${mismatch.sessionPreset}」,与当前配置「${mismatch.currentPreset}」不一致。\n` +
57
- `preset 在 session 创建时固定,无法中途切换(DSH 返回 agent-preset-conflict)。\n` +
58
- `继续恢复将在下次 run 失败。请在 /config 中把预设模式改回「${mismatch.sessionPreset}」后重试,或保持当前配置并发新消息新建会话。`,
59
- };
60
- }
61
- }
62
- deps.setSessionId(ctx.userId, agentKind, sessionIdArg, cwd);
63
- const display = deps.readDisplay(sessionIdArg, cwd, {
64
- agentKind,
65
- maxEvents: AUTO_RESUME_MAX_EVENTS,
66
- });
67
- const actions = deps.buildActions({
68
- isActive: display.isActive,
69
- activeRunRunId: display.activeRunRunId,
70
- cwd,
71
- compact: deps.canCompact(agentKind, cwd) ? { sessionId: sessionIdArg, agentKind } : undefined,
72
- newSession: true,
73
- });
74
- return {
75
- card: buildSessionHistoryCard({
76
- sessionId: sessionIdArg,
77
- cwd,
78
- displayTitle: display.displayTitle,
79
- aiTitle: display.aiTitle,
80
- recap: display.recap,
81
- events: display.events,
82
- usage: display.usage,
83
- }, {
84
- agentKind,
85
- headerText: `📂 \`${cwd}\`\n会话: **${sessionIdArg}**`,
86
- title: `${display.isActive ? '⏳ 恢复会话(完成中)' : '🔁 恢复会话'} · ${agentDisplayName(agentKind)}`,
87
- usageResult: 'success',
88
- emptyPlaceholder: '_该会话暂无新消息可显示(最后一条为用户输入)_',
89
- actions,
90
- }),
91
- };
92
62
  }
93
- if (!cwd)
94
- return { text: '请先 /cd 设置工作目录' };
95
- const pageSize = clampInt(limit ?? RESUME_PAGE_SIZE, 1, RESUME_PAGE_SIZE);
96
- const reader = agentKind === deps.defaultAgent ? deps.defaultReader() : deps.readerFor(agentKind);
63
+ return undefined;
64
+ }
65
+ function resumeSessionCard(ctx, deps, agentKind, sessionIdArg, cwd) {
66
+ deps.setSessionId(ctx.userId, agentKind, sessionIdArg, cwd);
67
+ const display = deps.readDisplay(sessionIdArg, cwd, {
68
+ agentKind,
69
+ maxEvents: AUTO_RESUME_MAX_EVENTS,
70
+ });
71
+ const actions = deps.buildActions({
72
+ isActive: display.isActive,
73
+ activeRunRunId: display.activeRunRunId,
74
+ cwd,
75
+ compact: deps.canCompact(agentKind, cwd) ? { sessionId: sessionIdArg, agentKind } : undefined,
76
+ newSession: true,
77
+ });
78
+ return {
79
+ card: buildSessionHistoryCard({
80
+ sessionId: sessionIdArg,
81
+ cwd,
82
+ displayTitle: display.displayTitle,
83
+ aiTitle: display.aiTitle,
84
+ recap: display.recap,
85
+ events: display.events,
86
+ usage: display.usage,
87
+ }, {
88
+ agentKind,
89
+ headerText: `📂 \`${cwd}\`\n会话: **${sessionIdArg}**`,
90
+ title: `${display.isActive ? '⏳ 恢复会话(完成中)' : '🔁 恢复会话'} · ${agentDisplayName(agentKind)}`,
91
+ usageResult: 'success',
92
+ emptyPlaceholder: '_该会话暂无新消息可显示(最后一条为用户输入)_',
93
+ actions,
94
+ }),
95
+ };
96
+ }
97
+ function resumeById(ctx, deps, agentKind, sessionIdArg, cwd) {
98
+ const reader = readerForAgent(deps, agentKind);
99
+ const rejected = verifyResumeTarget(reader, deps, agentKind, sessionIdArg, cwd);
100
+ if (rejected)
101
+ return rejected;
102
+ return resumeSessionCard(ctx, deps, agentKind, sessionIdArg, cwd);
103
+ }
104
+ /** 一次列表读取 + offset 页对齐;异常交给调用方转文案。 */
105
+ function loadResumePage(reader, cwd, pageSize, offset) {
97
106
  let pageOffset = offset;
98
- let pageResult;
99
- try {
107
+ let pageResult = reader.listSessions(cwd, { limit: pageSize, offset: pageOffset });
108
+ const maxOffset = Math.max(0, Math.ceil(pageResult.total / pageSize) - 1) * pageSize;
109
+ if (pageOffset < 0 || pageOffset > maxOffset) {
110
+ pageOffset = clampInt(pageOffset, 0, maxOffset);
100
111
  pageResult = reader.listSessions(cwd, { limit: pageSize, offset: pageOffset });
101
- const maxOffset = Math.max(0, Math.ceil(pageResult.total / pageSize) - 1) * pageSize;
102
- if (pageOffset < 0 || pageOffset > maxOffset) {
103
- pageOffset = clampInt(pageOffset, 0, maxOffset);
104
- pageResult = reader.listSessions(cwd, { limit: pageSize, offset: pageOffset });
105
- }
106
- }
107
- catch (err) {
108
- const msg = err instanceof Error ? err.message : String(err);
109
- return { text: `读取 ${agentDisplayName(agentKind)} session 列表失败: ${msg}` };
110
- }
111
- const { sessions: allSessions, total } = pageResult;
112
- if (allSessions.length === 0) {
113
- const hint = agentKind === deps.defaultAgent
114
- ? `\n提示:可使用 /resume <agent> 切换查看其他 Agent 的 session`
115
- : '';
116
- return {
117
- text: `当前目录没有 ${agentDisplayName(agentKind)} session 记录\n${cwd}${hint}`,
118
- };
119
112
  }
113
+ return { pageOffset, sessions: pageResult.sessions, total: pageResult.total };
114
+ }
115
+ /** 行级预览字段缺失时才预取,且只预取前 5 条。 */
116
+ function prefetchResumeMeta(reader, allSessions, cwd) {
120
117
  const sessionMeta = new Map();
121
118
  for (const session of allSessions.slice(0, RESUME_CONTENT_PREFETCH)) {
122
119
  if (session.title || session.lastUserMessage || session.lastAssistantMessage)
@@ -133,90 +130,88 @@ export function buildResumeCommand(args, ctx, offset, deps) {
133
130
  })();
134
131
  sessionMeta.set(session.sessionId, meta);
135
132
  }
136
- const now = Date.now();
137
- const formatRelativeTime = (mtimeMs) => {
138
- const diffSec = Math.floor((now - mtimeMs) / 1000);
139
- if (diffSec < 60)
140
- return '刚刚';
141
- if (diffSec < 3600)
142
- return `${Math.floor(diffSec / 60)} 分钟前`;
143
- if (diffSec < 86400)
144
- return `${Math.floor(diffSec / 3600)} 小时前`;
145
- if (diffSec < 604800)
146
- return `${Math.floor(diffSec / 86400)} 天前`;
147
- return new Date(mtimeMs).toLocaleDateString('zh-CN');
148
- };
149
- const elements = [
150
- { tag: 'div', text: { tag: 'lark_md', content: `📂 当前工作目录:\`${cwd}\`` } },
151
- ];
152
- const currentId = entry.sessions.get(agentKind) ?? '';
153
- for (const session of allSessions) {
154
- const isCurrent = agentKind === deps.defaultAgent && session.sessionId === currentId;
155
- const meta = sessionMeta.get(session.sessionId);
156
- const summaryIsPlaceholder = RESUME_SUMMARY_PLACEHOLDERS.has(session.summary.trim());
157
- const prefetchedTitle = meta?.displayTitle;
158
- const rowTitleRaw = session.title?.trim() ?? '';
159
- const rowTitle = rowTitleRaw && !RESUME_SUMMARY_PLACEHOLDERS.has(rowTitleRaw) ? rowTitleRaw : undefined;
160
- const titleText = prefetchedTitle ?? rowTitle ?? (summaryIsPlaceholder ? '' : session.summary);
161
- const titleLabel = prefetchedTitle
162
- ? meta?.aiTitle
163
- ? 'AI 标题'
164
- : '最近输入'
165
- : rowTitle
166
- ? '标题'
167
- : summaryIsPlaceholder
168
- ? ''
169
- : '会话摘要';
170
- const sections = [];
171
- if (titleText) {
172
- sections.push(`🏷️ **${titleLabel}**\n${titleText.slice(0, 80)}${titleText.length > 80 ? '...' : ''}`);
173
- }
174
- if (meta?.recap) {
175
- sections.push(`📝 **Recap**\n${meta.recap.slice(0, 60)}${meta.recap.length > 60 ? '...' : ''}`);
176
- }
177
- if (session.lastUserMessage) {
178
- sections.push(`✏️ **最近输入**\n${sessionPreviewLine(session.lastUserMessage, RESUME_PREVIEW_MAX)}`);
179
- }
180
- if (session.lastAssistantMessage) {
181
- sections.push(`📤 **最后输出**\n${sessionPreviewLine(session.lastAssistantMessage, RESUME_PREVIEW_MAX)}`);
182
- }
183
- const infoStr = sections.length > 0 ? '\n' + sections.join('\n──\n') : '';
184
- elements.push({ tag: 'hr' }, {
133
+ return sessionMeta;
134
+ }
135
+ function formatRelativeTime(mtimeMs, now) {
136
+ const diffSec = Math.floor((now - mtimeMs) / 1000);
137
+ if (diffSec < 60)
138
+ return '刚刚';
139
+ if (diffSec < 3600)
140
+ return `${Math.floor(diffSec / 60)} 分钟前`;
141
+ if (diffSec < 86400)
142
+ return `${Math.floor(diffSec / 3600)} 小时前`;
143
+ if (diffSec < 604800)
144
+ return `${Math.floor(diffSec / 86400)} 天前`;
145
+ return new Date(mtimeMs).toLocaleDateString('zh-CN');
146
+ }
147
+ function resumeTitleParts(session, meta) {
148
+ const summaryIsPlaceholder = RESUME_SUMMARY_PLACEHOLDERS.has(session.summary.trim());
149
+ const prefetchedTitle = meta?.displayTitle;
150
+ const rowTitleRaw = session.title?.trim() ?? '';
151
+ const rowTitle = rowTitleRaw && !RESUME_SUMMARY_PLACEHOLDERS.has(rowTitleRaw) ? rowTitleRaw : undefined;
152
+ const titleText = prefetchedTitle ?? rowTitle ?? (summaryIsPlaceholder ? '' : session.summary);
153
+ const titleLabel = prefetchedTitle
154
+ ? meta?.aiTitle
155
+ ? 'AI 标题'
156
+ : '最近输入'
157
+ : rowTitle
158
+ ? '标题'
159
+ : summaryIsPlaceholder
160
+ ? ''
161
+ : '会话摘要';
162
+ return { titleText, titleLabel };
163
+ }
164
+ function resumeInfoSections(session, meta, titleText, titleLabel) {
165
+ const sections = [];
166
+ if (titleText) {
167
+ sections.push(`🏷️ **${titleLabel}**\n${titleText.slice(0, 80)}${titleText.length > 80 ? '...' : ''}`);
168
+ }
169
+ if (meta?.recap) {
170
+ sections.push(`📝 **Recap**\n${meta.recap.slice(0, 60)}${meta.recap.length > 60 ? '...' : ''}`);
171
+ }
172
+ if (session.lastUserMessage) {
173
+ sections.push(`✏️ **最近输入**\n${sessionPreviewLine(session.lastUserMessage, RESUME_PREVIEW_MAX)}`);
174
+ }
175
+ if (session.lastAssistantMessage) {
176
+ sections.push(`📤 **最后输出**\n${sessionPreviewLine(session.lastAssistantMessage, RESUME_PREVIEW_MAX)}`);
177
+ }
178
+ return sections;
179
+ }
180
+ function resumeRowElements(session, opts) {
181
+ const isCurrent = opts.agentKind === opts.defaultAgent && session.sessionId === opts.currentId;
182
+ const meta = opts.meta.get(session.sessionId);
183
+ const { titleText, titleLabel } = resumeTitleParts(session, meta);
184
+ const sections = resumeInfoSections(session, meta, titleText, titleLabel);
185
+ const infoStr = sections.length > 0 ? '\n' + sections.join('\n──\n') : '';
186
+ return [
187
+ { tag: 'hr' },
188
+ {
185
189
  tag: 'div',
186
190
  text: {
187
191
  tag: 'lark_md',
188
- content: `**${session.sessionId}**${infoStr}\n⏱ ${formatRelativeTime(session.mtime)}${isCurrent ? ' •' : ''}`,
192
+ content: `**${session.sessionId}**${infoStr}\n⏱ ${formatRelativeTime(session.mtime, opts.now)}${isCurrent ? ' •' : ''}`,
189
193
  },
190
- }, {
194
+ },
195
+ {
191
196
  tag: 'column_set',
192
197
  columns: [
193
198
  {
194
199
  tag: 'column',
195
200
  width: 'auto',
196
201
  elements: [
197
- {
198
- tag: 'button',
199
- text: {
200
- tag: 'plain_text',
201
- content: isCurrent ? '✓ 当前会话' : '恢复此会话',
202
- },
203
- type: isCurrent ? 'default' : 'primary',
204
- disabled: isCurrent,
205
- behaviors: [
206
- {
207
- type: 'callback',
208
- value: {
209
- cmd: 'resume.use',
210
- sessionId: session.sessionId,
211
- agent: agentKind,
212
- },
213
- },
214
- ],
215
- },
202
+ cardButton(isCurrent ? '✓ 当前会话' : '恢复此会话', { cmd: 'resume.use', sessionId: session.sessionId, agent: opts.agentKind }, { type: isCurrent ? 'default' : 'primary', disabled: isCurrent }),
216
203
  ],
217
204
  },
218
205
  ],
219
- });
206
+ },
207
+ ];
208
+ }
209
+ function resumeListElements(allSessions, cwd, total, pageSize, pageOffset, opts) {
210
+ const elements = [
211
+ { tag: 'div', text: { tag: 'lark_md', content: `📂 当前工作目录:\`${cwd}\`` } },
212
+ ];
213
+ for (const session of allSessions) {
214
+ elements.push(...resumeRowElements(session, opts));
220
215
  }
221
216
  if (total > pageSize) {
222
217
  const { totalPages, currentPage } = pageInfo(total, pageOffset, pageSize);
@@ -225,10 +220,40 @@ export function buildResumeCommand(args, ctx, offset, deps) {
225
220
  offset: pageOffset,
226
221
  pageSize,
227
222
  total,
228
- extra: { agent: agentKind, pageSize },
223
+ extra: { agent: opts.agentKind, pageSize },
229
224
  label: `第 ${currentPage}/${totalPages} 页 · 共 ${total} 个会话`,
230
225
  }));
231
226
  }
227
+ return elements;
228
+ }
229
+ function resumeList(deps, entry, agentKind, limit, offset, cwd) {
230
+ const pageSize = clampInt(limit ?? RESUME_PAGE_SIZE, 1, RESUME_PAGE_SIZE);
231
+ const reader = agentKind === deps.defaultAgent ? deps.defaultReader() : deps.readerFor(agentKind);
232
+ let page;
233
+ try {
234
+ page = loadResumePage(reader, cwd, pageSize, offset);
235
+ }
236
+ catch (err) {
237
+ const msg = err instanceof Error ? err.message : String(err);
238
+ return { text: `读取 ${agentDisplayName(agentKind)} session 列表失败: ${msg}` };
239
+ }
240
+ const { sessions: allSessions, total, pageOffset } = page;
241
+ if (allSessions.length === 0) {
242
+ const hint = agentKind === deps.defaultAgent
243
+ ? `\n提示:可使用 /resume <agent> 切换查看其他 Agent 的 session`
244
+ : '';
245
+ return {
246
+ text: `当前目录没有 ${agentDisplayName(agentKind)} session 记录\n${cwd}${hint}`,
247
+ };
248
+ }
249
+ const meta = prefetchResumeMeta(reader, allSessions, cwd);
250
+ const elements = resumeListElements(allSessions, cwd, total, pageSize, pageOffset, {
251
+ agentKind,
252
+ defaultAgent: deps.defaultAgent,
253
+ currentId: entry.sessions.get(agentKind) ?? '',
254
+ meta,
255
+ now: Date.now(),
256
+ });
232
257
  return {
233
258
  card: {
234
259
  schema: '2.0',
@@ -243,4 +268,17 @@ export function buildResumeCommand(args, ctx, offset, deps) {
243
268
  },
244
269
  };
245
270
  }
271
+ export function buildResumeCommand(args, ctx, offset, deps) {
272
+ const entry = deps.getSessionEntry(ctx.userId);
273
+ const cwd = entry?.cwd;
274
+ const { agentKind, limit, sessionIdArg } = parseResumeArgs(args, deps.defaultAgent);
275
+ if (sessionIdArg) {
276
+ if (!entry || !cwd)
277
+ return { text: '请先 /cd 设置工作目录' };
278
+ return resumeById(ctx, deps, agentKind, sessionIdArg, cwd);
279
+ }
280
+ if (!cwd)
281
+ return { text: '请先 /cd 设置工作目录' };
282
+ return resumeList(deps, entry, agentKind, limit, offset, cwd);
283
+ }
246
284
  //# sourceMappingURL=resume.js.map