lark-remote 0.5.13 → 0.5.14

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 (126) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/agent-kinds.d.ts +27 -0
  3. package/dist/agent-kinds.js +38 -0
  4. package/dist/bridge/approval-actions.d.ts +95 -0
  5. package/dist/bridge/approval-actions.js +104 -0
  6. package/dist/bridge/final-usage.d.ts +8 -17
  7. package/dist/bridge/final-usage.js +1 -18
  8. package/dist/bridge/index.d.ts +46 -39
  9. package/dist/bridge/index.js +201 -229
  10. package/dist/bridge/queue-manager.d.ts +25 -1
  11. package/dist/bridge/queue-manager.js +179 -160
  12. package/dist/bridge/run-approval.d.ts +2 -1
  13. package/dist/bridge/run-usage.d.ts +16 -30
  14. package/dist/bridge/run-usage.js +41 -50
  15. package/dist/bridge/session-writeback.d.ts +3 -2
  16. package/dist/card/approval-render.d.ts +3 -2
  17. package/dist/card/approval-render.js +3 -2
  18. package/dist/{router → card}/card-helpers.d.ts +7 -7
  19. package/dist/{router → card}/card-helpers.js +8 -8
  20. package/dist/card/card-session.d.ts +4 -2
  21. package/dist/card/card-session.js +8 -6
  22. package/dist/card/card-shared.d.ts +1 -1
  23. package/dist/card/card-shared.js +1 -1
  24. package/dist/card/final-answer-overflow.d.ts +0 -6
  25. package/dist/card/final-answer-overflow.js +1 -1
  26. package/dist/card/run-card-session.d.ts +2 -2
  27. package/dist/card/run-card-session.js +2 -2
  28. package/dist/card/run-renderer.js +7 -22
  29. package/dist/card/run-state.d.ts +28 -50
  30. package/dist/card/run-state.js +23 -0
  31. package/dist/card/usage-format.d.ts +30 -0
  32. package/dist/{router → card}/usage-format.js +3 -10
  33. package/dist/clone.js +6 -1
  34. package/dist/config/index.d.ts +16 -20
  35. package/dist/config/index.js +0 -16
  36. package/dist/config/pi-config.js +6 -4
  37. package/dist/connector/index.d.ts +2 -4
  38. package/dist/connector/index.js +7 -11
  39. package/dist/{runner/dsh → dsh}/auth.js +1 -1
  40. package/dist/dsh/protocol.d.ts +9 -0
  41. package/dist/dsh/protocol.js +61 -0
  42. package/dist/index.js +10 -5
  43. package/dist/model-catalog.d.ts +14 -0
  44. package/dist/model-catalog.js +25 -0
  45. package/dist/platform/path.d.ts +9 -0
  46. package/dist/platform/path.js +18 -0
  47. package/dist/router/active-run-usage.d.ts +4 -0
  48. package/dist/router/active-run-usage.js +12 -0
  49. package/dist/router/commands/ls.js +1 -1
  50. package/dist/router/commands/order.js +1 -1
  51. package/dist/router/commands/resume.d.ts +5 -4
  52. package/dist/router/commands/resume.js +4 -4
  53. package/dist/router/commands/ws.js +1 -1
  54. package/dist/router/config/claude.js +2 -1
  55. package/dist/router/config/common/render.d.ts +5 -1
  56. package/dist/router/config/common/render.js +6 -13
  57. package/dist/router/config/dsh.d.ts +1 -1
  58. package/dist/router/config/index.d.ts +1 -1
  59. package/dist/router/config/types.d.ts +11 -3
  60. package/dist/router/index.d.ts +41 -11
  61. package/dist/router/index.js +165 -226
  62. package/dist/runner/agent-choices-common.d.ts +1 -1
  63. package/dist/runner/claude/runner.d.ts +20 -2
  64. package/dist/runner/claude/runner.js +2 -15
  65. package/dist/runner/codex/app-server/runner.d.ts +3 -1
  66. package/dist/runner/codex/app-server/translator.d.ts +11 -0
  67. package/dist/runner/codex/app-server/translator.js +56 -149
  68. package/dist/runner/common/acp/base-acp-runner.d.ts +3 -1
  69. package/dist/runner/common/connection-based-runner.d.ts +3 -1
  70. package/dist/runner/common/jsonrpc/transport.js +17 -7
  71. package/dist/runner/dsh/client.d.ts +1 -4
  72. package/dist/runner/dsh/client.js +2 -55
  73. package/dist/runner/dsh/daemon.js +9 -2
  74. package/dist/runner/dsh/exit-cancel.js +1 -1
  75. package/dist/runner/dsh/mux-stream.js +21 -2
  76. package/dist/runner/dsh/runner.d.ts +21 -1
  77. package/dist/runner/dsh/runner.js +76 -73
  78. package/dist/runner/dsh/translator.d.ts +1 -1
  79. package/dist/runner/index.d.ts +1 -1
  80. package/dist/runner/kimi/acp/runner.d.ts +22 -1
  81. package/dist/runner/kimi/acp/runner.js +83 -60
  82. package/dist/runner/opencode/acp/error-monitor.d.ts +11 -0
  83. package/dist/runner/opencode/acp/error-monitor.js +31 -2
  84. package/dist/runner/opencode/acp/runner.d.ts +3 -1
  85. package/dist/runner/pi/rpc/runner.d.ts +2 -1
  86. package/dist/runner/probe.d.ts +1 -1
  87. package/dist/runner/probe.js +10 -9
  88. package/dist/runner/registry.d.ts +2 -1
  89. package/dist/runner/types.d.ts +20 -154
  90. package/dist/runner/types.js +4 -24
  91. package/dist/session/claude/session-index.d.ts +11 -4
  92. package/dist/session/claude/session-index.js +30 -8
  93. package/dist/session/claude/session-reader.d.ts +1 -1
  94. package/dist/session/claude/sessions.d.ts +2 -2
  95. package/dist/session/claude/sessions.js +41 -26
  96. package/dist/session/codex/rollout-reader.d.ts +1 -1
  97. package/dist/session/codex/rollout-reader.js +14 -13
  98. package/dist/session/codex/sessions.d.ts +1 -1
  99. package/dist/session/codex/sessions.js +4 -2
  100. package/dist/session/common/jsonl.js +7 -1
  101. package/dist/session/common/pagination.d.ts +2 -0
  102. package/dist/session/common/pagination.js +1 -1
  103. package/dist/session/common/recency.d.ts +6 -0
  104. package/dist/session/common/recency.js +7 -5
  105. package/dist/session/common/two-pass.d.ts +1 -1
  106. package/dist/session/common/usage-accumulator.d.ts +1 -1
  107. package/dist/session/dsh/sessions.d.ts +1 -1
  108. package/dist/session/dsh/sessions.js +37 -12
  109. package/dist/session/kimi/sessions.d.ts +1 -1
  110. package/dist/session/kimi/sessions.js +35 -8
  111. package/dist/session/opencode/sessions.d.ts +1 -1
  112. package/dist/session/opencode/sessions.js +51 -47
  113. package/dist/session/pi/sessions.d.ts +1 -1
  114. package/dist/session/pi/sessions.js +20 -7
  115. package/dist/session/registry.d.ts +2 -1
  116. package/dist/session/session-store.d.ts +1 -2
  117. package/dist/session/session-store.js +14 -7
  118. package/dist/session-contract.d.ts +178 -0
  119. package/dist/session-contract.js +9 -0
  120. package/package.json +1 -1
  121. package/dist/router/usage-format.d.ts +0 -60
  122. /package/dist/{runner/dsh → dsh}/auth.d.ts +0 -0
  123. /package/dist/{runner/dsh → dsh}/home.d.ts +0 -0
  124. /package/dist/{runner/dsh → dsh}/home.js +0 -0
  125. /package/dist/{runner/dsh → dsh}/types.d.ts +0 -0
  126. /package/dist/{runner/dsh → dsh}/types.js +0 -0
@@ -33,9 +33,9 @@ const noKeepAliveAgent = new https.Agent({ keepAlive: false });
33
33
  * - SDK 的 cardAction dedup eventId = `card:{messageId}:{operator.openId}:{actionId}`
34
34
  * - actionId = `tag|name|option|JSON.stringify(value)`,不含时间戳/事件序号
35
35
  * - config 卡片原地更新(updateCardInPlace),用户在同一张卡上重复触发
36
- * 固定 value 的按钮(如 config.toggle):
36
+ * 固定 value 的按钮(如 config.save):
37
37
  * messageId / operator / value 三段都相同 → eventId 完全相同 → 第二次点击被
38
- * seenCache drop,toggle 不可逆(第二次点击静默失效)。
38
+ * seenCache drop,按钮不可逆(第二次点击静默失效)。
39
39
  *
40
40
  * SDK 默认 12h 太长;60s 仍会误伤连击。300ms 挡飞书瞬时重投递(<100ms 级),
41
41
  * 放过用户连击(慢点两次通常 >500ms)。代价:削弱 message 秒级重投递防护——
@@ -520,7 +520,7 @@ export class FeishuConnector {
520
520
  catch (err) {
521
521
  // 抛出去前先落一条格式化日志(调用方只看到包装后的 message)。
522
522
  // 抛普通 Error 而不是原 err:axios 错误对象跨层序列化会丢信息。
523
- const errorInfo = this.formatError(err);
523
+ const errorInfo = formatErrorForLog(err);
524
524
  getLogger().error('[feishu] streamCard failed:', errorInfo);
525
525
  throw new Error(`streamCard failed: ${errorInfo}`, { cause: err });
526
526
  }
@@ -554,7 +554,7 @@ export class FeishuConnector {
554
554
  catch (err) {
555
555
  // Log the error but don't swallow it - a plain error avoids axios
556
556
  // serialization issues in the logger.
557
- const errorInfo = this.formatError(err);
557
+ const errorInfo = formatErrorForLog(err);
558
558
  getLogger().error('[feishu] updateCard failed:', errorInfo);
559
559
  throw new Error(`updateCard failed: ${errorInfo}`, { cause: err });
560
560
  }
@@ -562,16 +562,12 @@ export class FeishuConnector {
562
562
  throw new Error(`updateCard failed: Feishu rejected the card (code=${rejection.code} msg=${rejection.msg ?? ''})`, { cause: rejection });
563
563
  }
564
564
  }
565
- /** Format error for logging without causing circular serialization */
566
- formatError(err) {
567
- return formatErrorForLog(err);
568
- }
569
565
  async addReaction(messageId, emoji) {
570
566
  try {
571
567
  await this.channel.addReaction(messageId, emoji);
572
568
  }
573
569
  catch (err) {
574
- getLogger().error('[feishu] addReaction failed:', this.formatError(err));
570
+ getLogger().error('[feishu] addReaction failed:', formatErrorForLog(err));
575
571
  }
576
572
  }
577
573
  /**
@@ -583,7 +579,7 @@ export class FeishuConnector {
583
579
  await this.channel.removeReactionByEmoji(messageId, emoji);
584
580
  }
585
581
  catch (err) {
586
- getLogger().error('[feishu] removeReactionByEmoji failed:', this.formatError(err));
582
+ getLogger().error('[feishu] removeReactionByEmoji failed:', formatErrorForLog(err));
587
583
  }
588
584
  }
589
585
  /**
@@ -635,7 +631,7 @@ export class FeishuConnector {
635
631
  }
636
632
  }
637
633
  catch (err) {
638
- const errorInfo = this.formatError(err);
634
+ const errorInfo = formatErrorForLog(err);
639
635
  getLogger().error(`[feishu] ${label} failed:`, errorInfo);
640
636
  throw new Error(`${label} failed: ${errorInfo}`, { cause: err });
641
637
  }
@@ -12,7 +12,7 @@ import { createHash, createHmac } from 'node:crypto';
12
12
  import fs from 'node:fs';
13
13
  import path from 'node:path';
14
14
  import YAML from 'yaml';
15
- import { isWin32 } from '../../platform/select.js';
15
+ import { isWin32 } from '../platform/select.js';
16
16
  import { resolveDshHome } from './home.js';
17
17
  /** Credential record that owns the browser-cookie signing secret. */
18
18
  export const DSH_BROWSER_CREDENTIAL_KEY = 'client-connection/browser-session';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * DSH 远程调用的线格式助手(中立层,runner 与 session 共用)。
3
+ *
4
+ * 这两个函数原先住在 `runner/dsh/client.ts`,于是 session/dsh 为了拼一个
5
+ * `args` 信封要 import 上层 runner —— 与 AgentSessionReader 同一类反向依赖。
6
+ */
7
+ /** Extract the `token` query parameter from a pasted `dsh web` URL. */
8
+ export declare function extractDshToken(raw: string | undefined): string;
9
+ export declare function dshArgs(method: string, payload: unknown): Record<string, unknown>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * DSH 远程调用的线格式助手(中立层,runner 与 session 共用)。
3
+ *
4
+ * 这两个函数原先住在 `runner/dsh/client.ts`,于是 session/dsh 为了拼一个
5
+ * `args` 信封要 import 上层 runner —— 与 AgentSessionReader 同一类反向依赖。
6
+ */
7
+ /** Extract the `token` query parameter from a pasted `dsh web` URL. */
8
+ export function extractDshToken(raw) {
9
+ const value = (raw ?? '').trim();
10
+ if (!value)
11
+ return '';
12
+ if (!value.includes('token=') && !value.includes('://'))
13
+ return value;
14
+ try {
15
+ const url = new URL(value.startsWith('?') ? `http://dsh.invalid/${value}` : value);
16
+ const token = url.searchParams.get('token');
17
+ if (token)
18
+ return token;
19
+ // 带 scheme 却没有 token 参数的输入是误贴的 host URL(如
20
+ // `http://127.0.0.1:3080`):整串不是合法 token,参与握手只会得到
21
+ // 指向性缺失的 401。返回空串让上游走「token 缺失」的诊断路径。
22
+ if (value.includes('://'))
23
+ return '';
24
+ return value;
25
+ }
26
+ catch {
27
+ return value;
28
+ }
29
+ }
30
+ /**
31
+ * Remote methods take named parameters. Most session methods call their single
32
+ * argument `request`; `session/list` reserves `_request`; catalog methods take
33
+ * no arguments. `commands/*` address the receiving agent by its wire field
34
+ * `agentId`, so their payload is already in wire shape (pass-through).
35
+ * The gateway rejects any other `args` shape.
36
+ */
37
+ const DSH_ARGS_KEY = {
38
+ 'session/list': '_request',
39
+ 'session/create': 'request',
40
+ 'session/prompt': 'request',
41
+ 'session/cancel': 'request',
42
+ 'session/selectModel': 'request',
43
+ 'session/projections': 'request',
44
+ 'session/page': 'request',
45
+ 'session/follow': 'request',
46
+ 'session/updateQueue': 'request',
47
+ 'job/list': 'request',
48
+ 'job/kill': 'request',
49
+ 'session/modelCatalog': null,
50
+ 'agentPresets/list': null,
51
+ 'permissionPresets/catalog': null,
52
+ };
53
+ export function dshArgs(method, payload) {
54
+ const key = DSH_ARGS_KEY[method];
55
+ if (key === null)
56
+ return {};
57
+ if (key === undefined)
58
+ return payload;
59
+ return { [key]: payload };
60
+ }
61
+ //# sourceMappingURL=protocol.js.map
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { loadConfig, getAgentConfig } from './config/index.js';
2
- import { resolveAgentChoices, } from './runner/index.js';
2
+ import { resolveAgentChoices } from './runner/index.js';
3
3
  import { ensureConfig } from './config/wizard.js';
4
4
  import { parseCliArgs, resolveConfigDir, setConfigDir, printHelp, printVersion, } from './config/dir.js';
5
5
  import { FeishuConnector } from './connector/index.js';
@@ -25,7 +25,7 @@ import { startSleepBlocker } from './platform/sleep-blocker.js';
25
25
  import { checkLatestVersion, compareVersions, runInstallLatest, formatUpdateHint, } from './update/index.js';
26
26
  import { classifyRejection } from './error-classification.js';
27
27
  import { WorkspaceStore } from './workspace/index.js';
28
- import { buildSessionHistoryCard, pickResumeCardEvents } from './router/card-helpers.js';
28
+ import { buildSessionHistoryCard, pickResumeCardEvents } from './card/card-helpers.js';
29
29
  import { newSessionButton, resumeCompactButton, agentDisplayName } from './card/card-shared.js';
30
30
  import path from 'node:path';
31
31
  import { setupMessageHandlers } from './message-handlers.js';
@@ -137,6 +137,10 @@ function initializeRunner(config, configDir, cliArgs) {
137
137
  manageProcess: () => getAgentConfig(latest(), 'dsh')?.manageProcess ?? true,
138
138
  startTimeoutMs: () => getAgentConfig(latest(), 'dsh')?.startTimeoutMs,
139
139
  });
140
+ // claude 的会话读取器与其余 agent 一样由组合根注入:runner 侧不 import session
141
+ // 层(否则 runner ↔ session 互相依赖),且 bridge 读 usage / router 列 session
142
+ // 用的是同一个实例(缓存共用)。
143
+ const claudeSessionReader = new ClaudeSessionReader();
140
144
  // Claude factory reads from configContainer (not closure) so runtime
141
145
  // config changes (model, effort, stopGraceMs) take effect after
142
146
  // bridge.setConfig() + clearRunners(). Same pattern as codex/pi/kimi.
@@ -149,6 +153,7 @@ function initializeRunner(config, configDir, cliArgs) {
149
153
  settings: cliArgs.settings,
150
154
  pidDir: configDir,
151
155
  cwd: ws,
156
+ sessionReader: claudeSessionReader,
152
157
  permissionMode: claudeConfig.permissionMode,
153
158
  idleTtlMs: claudeConfig.idleTtlMinutes != null ? claudeConfig.idleTtlMinutes * 60_000 : undefined,
154
159
  });
@@ -179,7 +184,7 @@ function initializeRunner(config, configDir, cliArgs) {
179
184
  // Register OpencodeAcpRunner (pure ACP mode, `opencode acp` JSON-RPC over stdio)
180
185
  // Register session reader (same instance as used by runner)
181
186
  const sessionReaderRegistry = new SessionReaderRegistry();
182
- sessionReaderRegistry.register('claude', new ClaudeSessionReader());
187
+ sessionReaderRegistry.register('claude', claudeSessionReader);
183
188
  sessionReaderRegistry.register('codex', codexSessionReader);
184
189
  // Register OpencodeSessionReader (CLI version)
185
190
  // Using `opencode session list` and `session export` instead of HTTP API.
@@ -436,8 +441,8 @@ async function main() {
436
441
  try {
437
442
  await connector.connect();
438
443
  }
439
- catch {
440
- logger.error('failed to connect to Feishu, check appId/appSecret');
444
+ catch (err) {
445
+ logger.error('failed to connect to Feishu, check appId/appSecret:', err);
441
446
  process.exit(1);
442
447
  }
443
448
  if (binder.isBound()) {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Claude 模型 ID ↔ CLI alias 的双向表。
3
+ *
4
+ * 中立层(谁都不许反向依赖它):config 要写默认值、runner/claude 要把 alias 传给
5
+ * CLI、router/config 要把 alias 显示给用户。此前这张表住在 config/,于是
6
+ * 「地基层被 runner 反向 import」;挪到这里后三方共同引用同一份。
7
+ *
8
+ * 表内容来自 Claude CLI 的模型别名(alias 是 CLI 侧的稳定名字,model ID 会随
9
+ * 版本变),新增一行只改这里。
10
+ */
11
+ /** 模型 ID → alias 映射。 */
12
+ export declare const MODEL_ID_TO_ALIAS: Record<string, string>;
13
+ /** alias → model ID 反向映射。 */
14
+ export declare const MODEL_ALIAS_TO_ID: Record<string, string>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Claude 模型 ID ↔ CLI alias 的双向表。
3
+ *
4
+ * 中立层(谁都不许反向依赖它):config 要写默认值、runner/claude 要把 alias 传给
5
+ * CLI、router/config 要把 alias 显示给用户。此前这张表住在 config/,于是
6
+ * 「地基层被 runner 反向 import」;挪到这里后三方共同引用同一份。
7
+ *
8
+ * 表内容来自 Claude CLI 的模型别名(alias 是 CLI 侧的稳定名字,model ID 会随
9
+ * 版本变),新增一行只改这里。
10
+ */
11
+ /** 模型 ID → alias 映射。 */
12
+ export const MODEL_ID_TO_ALIAS = {
13
+ 'claude-opus-4-8': 'opus',
14
+ 'claude-sonnet-4-6': 'sonnet',
15
+ 'claude-haiku-4-5-20250501': 'haiku',
16
+ 'claude-fable-5': 'fable',
17
+ };
18
+ /** alias → model ID 反向映射。 */
19
+ export const MODEL_ALIAS_TO_ID = {
20
+ opus: 'claude-opus-4-8',
21
+ sonnet: 'claude-sonnet-4-6',
22
+ haiku: 'claude-haiku-4-5-20250501',
23
+ fable: 'claude-fable-5',
24
+ };
25
+ //# sourceMappingURL=model-catalog.js.map
@@ -1,6 +1,15 @@
1
1
  export interface PathOptions {
2
2
  platform?: NodeJS.Platform;
3
3
  }
4
+ /**
5
+ * realpath 归一(macOS `/tmp` → `/private/tmp`),失败回退原样输入。
6
+ *
7
+ * 各 session reader 此前有三种口径:静默回退(opencode)、回退 + warn(kimi
8
+ * 单会话读)、裸调让一次 ENOENT 把整张会话列表清掉(kimi list)。统一成
9
+ * 「回退优先于丢结果」,失败原因交给调用方记日志(`onFailure`),因为
10
+ * ENOENT(陈旧 cwd)是正常空态、EACCES/EBUSY 才需要留痕。
11
+ */
12
+ export declare function safeRealpath(cwd: string, onFailure?: (err: unknown) => void): string;
4
13
  /**
5
14
  * 路径的「判等键」形态:把 samePath 的平台归一规则单源化,供 Map/Set 键控
6
15
  * 场景使用(按 cwd 建倒排索引时不能每次查询做 O(n) 两两比较)。不变量:
@@ -9,8 +9,26 @@
9
9
  * 全部函数接受显式 `platform` 参数(默认 currentPlatform),使 win32 语义
10
10
  * 可在任意宿主的单元测试中验证。
11
11
  */
12
+ import fs from 'node:fs';
12
13
  import path from 'node:path';
13
14
  import { currentPlatform, isWin32 } from './select.js';
15
+ /**
16
+ * realpath 归一(macOS `/tmp` → `/private/tmp`),失败回退原样输入。
17
+ *
18
+ * 各 session reader 此前有三种口径:静默回退(opencode)、回退 + warn(kimi
19
+ * 单会话读)、裸调让一次 ENOENT 把整张会话列表清掉(kimi list)。统一成
20
+ * 「回退优先于丢结果」,失败原因交给调用方记日志(`onFailure`),因为
21
+ * ENOENT(陈旧 cwd)是正常空态、EACCES/EBUSY 才需要留痕。
22
+ */
23
+ export function safeRealpath(cwd, onFailure) {
24
+ try {
25
+ return fs.realpathSync(cwd);
26
+ }
27
+ catch (err) {
28
+ onFailure?.(err);
29
+ return cwd;
30
+ }
31
+ }
14
32
  function resolveOptions(opts) {
15
33
  return { platform: opts?.platform ?? currentPlatform };
16
34
  }
@@ -0,0 +1,4 @@
1
+ import type { ActiveRunSnapshot } from '../bridge/index.js';
2
+ import type { SessionDisplayUsage } from '../card/usage-format.js';
3
+ /** 从 bridge 的活跃 run 快照提取会话卡需要的用量字段。 */
4
+ export declare function activeRunUsage(activeRun: ActiveRunSnapshot | undefined): SessionDisplayUsage | undefined;
@@ -0,0 +1,12 @@
1
+ /** 从 bridge 的活跃 run 快照提取会话卡需要的用量字段。 */
2
+ export function activeRunUsage(activeRun) {
3
+ if (!activeRun || activeRun.contextLength === undefined)
4
+ return undefined;
5
+ return {
6
+ contextLength: activeRun.contextLength,
7
+ compactCount: activeRun.compactCount,
8
+ cacheReadTokens: activeRun.cacheReadTokens,
9
+ cacheCreationTokens: activeRun.cacheCreationTokens,
10
+ };
11
+ }
12
+ //# sourceMappingURL=active-run-usage.js.map
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { cardButton } from '../../card/card-shared.js';
5
- import { paginationBar, searchBar } from '../card-helpers.js';
5
+ import { paginationBar, searchBar } from '../../card/card-helpers.js';
6
6
  import { inspectPath, statPath } from '../path-validation.js';
7
7
  import { pageSlice } from '../paging.js';
8
8
  export const LS_PAGE_SIZE = 30;
@@ -1,5 +1,5 @@
1
1
  import { cardButton } from '../../card/card-shared.js';
2
- import { paginationBar } from '../card-helpers.js';
2
+ import { paginationBar } from '../../card/card-helpers.js';
3
3
  import { pageSlice } from '../paging.js';
4
4
  export const ORDER_PAGE_SIZE = 8;
5
5
  export function buildOrderCommand(args, ctx, offset, deps) {
@@ -1,11 +1,13 @@
1
1
  import type { CommandContext, CommandResult } from '../../bridge/index.js';
2
- import type { AgentKind, AgentSessionContentEvent, AgentSessionReader } from '../../runner/index.js';
3
- import type { SessionDisplayUsage } from '../usage-format.js';
2
+ import type { AgentKind } from '../../agent-kinds.js';
3
+ import type { AgentSessionContentEvent, AgentSessionReader } from '../../session-contract.js';
4
+ import type { SessionDisplayUsage } from '../../card/usage-format.js';
4
5
  export declare const AUTO_RESUME_MAX_EVENTS = 5;
5
6
  export declare const RESUME_PAGE_SIZE = 5;
6
7
  interface ResumeSessionEntry {
7
8
  cwd?: string;
8
- sessions?: Map<string, string>;
9
+ /** SessionStore 的 entry 恒有 sessions(`get()` 只会返回整条或缺席)。 */
10
+ sessions: Map<string, string>;
9
11
  }
10
12
  interface SessionDisplay {
11
13
  events: AgentSessionContentEvent[];
@@ -18,7 +20,6 @@ interface SessionDisplay {
18
20
  }
19
21
  export interface ResumeCommandDeps {
20
22
  defaultAgent: AgentKind;
21
- validAgents: readonly AgentKind[];
22
23
  getSessionEntry(userId: string): ResumeSessionEntry | undefined;
23
24
  setSessionId(userId: string, agent: AgentKind, sessionId: string, cwd: string): void;
24
25
  defaultReader(): AgentSessionReader;
@@ -1,5 +1,6 @@
1
+ import { isAgentKind } from '../../agent-kinds.js';
1
2
  import { agentDisplayName } from '../../card/card-shared.js';
2
- import { buildSessionHistoryCard, paginationBar } from '../card-helpers.js';
3
+ import { buildSessionHistoryCard, paginationBar } from '../../card/card-helpers.js';
3
4
  import { pageInfo } from '../paging.js';
4
5
  import { clampInt } from '../../common/clamp.js';
5
6
  export const AUTO_RESUME_MAX_EVENTS = 5;
@@ -14,12 +15,11 @@ function sessionPreviewLine(text, max) {
14
15
  export function buildResumeCommand(args, ctx, offset, deps) {
15
16
  const entry = deps.getSessionEntry(ctx.userId);
16
17
  const cwd = entry?.cwd;
17
- const validAgents = deps.validAgents;
18
18
  let agentKind = deps.defaultAgent;
19
19
  let limit;
20
20
  let sessionIdArg;
21
21
  if (args[0]) {
22
- if (validAgents.includes(args[0])) {
22
+ if (isAgentKind(args[0])) {
23
23
  agentKind = args[0];
24
24
  if (args[1]) {
25
25
  if (/^\d+$/.test(args[1]))
@@ -149,7 +149,7 @@ export function buildResumeCommand(args, ctx, offset, deps) {
149
149
  const elements = [
150
150
  { tag: 'div', text: { tag: 'lark_md', content: `📂 当前工作目录:\`${cwd}\`` } },
151
151
  ];
152
- const currentId = entry?.sessions?.get(agentKind) ?? '';
152
+ const currentId = entry.sessions.get(agentKind) ?? '';
153
153
  for (const session of allSessions) {
154
154
  const isCurrent = agentKind === deps.defaultAgent && session.sessionId === currentId;
155
155
  const meta = sessionMeta.get(session.sessionId);
@@ -1,5 +1,5 @@
1
1
  import { cardButton } from '../../card/card-shared.js';
2
- import { paginationBar, searchBar } from '../card-helpers.js';
2
+ import { paginationBar, searchBar } from '../../card/card-helpers.js';
3
3
  import { pageSlice } from '../paging.js';
4
4
  import { resolveDirectory } from '../path-validation.js';
5
5
  export const WS_PAGE_SIZE = 5;
@@ -4,7 +4,8 @@
4
4
  import fs from 'node:fs';
5
5
  import os from 'node:os';
6
6
  import path from 'node:path';
7
- import { MODEL_ID_TO_ALIAS, MODEL_ALIAS_TO_ID, getModelOptionsFromSettings, CLAUDE_EFFORTS, CLAUDE_PERMISSION_MODES, } from '../../config/index.js';
7
+ import { CLAUDE_EFFORTS, CLAUDE_PERMISSION_MODES, getModelOptionsFromSettings, } from '../../config/index.js';
8
+ import { MODEL_ALIAS_TO_ID, MODEL_ID_TO_ALIAS } from '../../model-catalog.js';
8
9
  /** Claude 官方 --permission-mode 中文注释(value 走 CLAUDE_PERMISSION_MODES SSOT)。 */
9
10
  const PERMISSION_MODE_LABELS = {
10
11
  default: '默认(敏感操作逐项询问)',
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * Shared config card rendering logic.
3
3
  *
4
- * Builds CardKit 2.0 elements for config fields (boolean toggle, select dropdown, input).
4
+ * Builds CardKit 2.0 elements for config fields (select dropdown, input, note).
5
5
  * Used by all agent config builders and the shared tabs (idle, logging).
6
+ *
7
+ * 控件形态只有 `ConfigField.type` 里那三种,且每种在本文件都有对应 builder:
8
+ * 渲染端与处理端(router 的 `config.set` / `config.input`)必须一一对应,
9
+ * 「渲染得出按钮、点了没人处理」是禁止状态(守卫见 config-card-controls.test.ts)。
6
10
  */
7
11
  import { type AppConfig } from '../../../config/index.js';
8
12
  import type { ConfigField } from '../types.js';
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * Shared config card rendering logic.
3
3
  *
4
- * Builds CardKit 2.0 elements for config fields (boolean toggle, select dropdown, input).
4
+ * Builds CardKit 2.0 elements for config fields (select dropdown, input, note).
5
5
  * Used by all agent config builders and the shared tabs (idle, logging).
6
+ *
7
+ * 控件形态只有 `ConfigField.type` 里那三种,且每种在本文件都有对应 builder:
8
+ * 渲染端与处理端(router 的 `config.set` / `config.input`)必须一一对应,
9
+ * 「渲染得出按钮、点了没人处理」是禁止状态(守卫见 config-card-controls.test.ts)。
6
10
  */
7
11
  import { getConfigValue } from '../../../config/index.js';
8
12
  import { cardButton } from '../../../card/card-shared.js';
@@ -12,12 +16,7 @@ function buildFieldElements(fields, displayConfig) {
12
16
  for (const field of fields) {
13
17
  // Get current value from displayConfig for dynamic fields
14
18
  const currentValue = getConfigValue(displayConfig, field.key);
15
- if (field.type === 'boolean') {
16
- // For boolean, use field.currentValue if set, otherwise use config value
17
- const isOn = field.currentValue !== undefined ? field.currentValue === true : currentValue === true;
18
- elements.push(buildBooleanElement(field, isOn));
19
- }
20
- else if (field.type === 'select' && field.options) {
19
+ if (field.type === 'select' && field.options) {
21
20
  elements.push(buildSelectElement(field, currentValue));
22
21
  }
23
22
  else if (field.type === 'note') {
@@ -53,12 +52,6 @@ function fieldRow(label, control) {
53
52
  ],
54
53
  };
55
54
  }
56
- function buildBooleanElement(field, isOn) {
57
- const displayVal = isOn ? '✅ 已开启' : '⚪ 已关闭';
58
- return fieldRow(field.label, cardButton(displayVal, { cmd: 'config.toggle', key: field.key }, {
59
- type: isOn ? 'primary' : 'default',
60
- }));
61
- }
62
55
  function buildSelectElement(field, currentValue) {
63
56
  // 优先使用 field.currentValue(卡片显示用覆盖值),否则使用 config 中的值
64
57
  const selectedValue = field.currentValue != null
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import type { AgentConfigCardBuilder, ConfigField } from './types.js';
19
19
  import { type AppConfig } from '../../config/index.js';
20
- import type { DshModelCatalogValue, DshPermissionCatalogValue, DshPresetListValue } from '../../runner/dsh/types.js';
20
+ import type { DshModelCatalogValue, DshPermissionCatalogValue, DshPresetListValue } from '../../dsh/types.js';
21
21
  /** DshConfigBuilder 预取只依赖的 client 方法子集。 */
22
22
  export interface DshCatalogClient {
23
23
  listModels(): Promise<DshModelCatalogValue>;
@@ -4,7 +4,7 @@
4
4
  * Each agent implements AgentConfigCardBuilder in its own file.
5
5
  * Adding a new agent = add a file + register here (no upstream changes needed).
6
6
  */
7
- import type { AgentKind } from '../../runner/types.js';
7
+ import type { AgentKind } from '../../agent-kinds.js';
8
8
  import type { AgentConfigCardBuilder } from './types.js';
9
9
  /**
10
10
  * 首次启动默认展示的 Coding Agent 顺序:Codex → Claude → OpenCode → Pi → Kimi → DSH。
@@ -16,13 +16,21 @@ export interface SelectOption {
16
16
  export interface ConfigField {
17
17
  key: string;
18
18
  label: string;
19
- type: 'boolean' | 'select' | 'input' | 'note';
19
+ /**
20
+ * 卡片上真实存在的控件形态,每种都在 `common/render.ts` 有对应 builder:
21
+ * select=下拉、input=文本框、note=纯说明行(无回调)。
22
+ *
23
+ * 没有 boolean:卡片曾留着一套「开关」控件(`config.toggle`),但全仓没有
24
+ * 任何字段声明它,2026-10-27 成套删除。原则是**卡片只放配得了的控件**,
25
+ * 实现细节与未上卡的键走 YAML(见 `buildConfigCard` 的分 tab 注释)。
26
+ */
27
+ type: 'select' | 'input' | 'note';
20
28
  /** For select type: the list of options shown in the dropdown.
21
29
  * Accepts plain strings (text=value) or {text, value} objects for
22
30
  * display-value separation (e.g. 'manual(逐项审批)' → value 'manual'). */
23
31
  options?: readonly (string | SelectOption)[];
24
32
  /** Override the currentValue shown in the card (takes priority over getConfigValue). */
25
- currentValue?: string | boolean;
33
+ currentValue?: string;
26
34
  }
27
35
  /**
28
36
  * Builder that provides config fields and handles field changes for a specific agent.
@@ -40,7 +48,7 @@ export interface AgentConfigCardBuilder {
40
48
  * Handle a field change for this agent.
41
49
  *
42
50
  * @param key - The field key (e.g. 'agents.codex.modelProvider')
43
- * @param value - The new value (string for select/input, already toggled for boolean)
51
+ * @param value - The new value (string for select/input)
44
52
  * @param config - The current pendingConfig (read-only reference for deriving dependent values)
45
53
  * @returns An array of {key, value} patches to apply to pendingConfig.
46
54
  * The caller (router) applies these via setNestedValue.
@@ -137,12 +137,6 @@ export declare const SESSION_MUTATING_ACTION_CMDS: ReadonlySet<string>;
137
137
  */
138
138
  export declare const COMPACT_ACTION_CMDS: ReadonlySet<string>;
139
139
  export declare class CommandRouter {
140
- /**
141
- * Valid agent kinds — single source of truth for resume.use / resume.page /
142
- * cmdResume. 名单本体在 `runner/types.ts` 的 AGENT_KINDS(与 AgentKind 类型
143
- * 同源),这里只做别名,避免人手抄第二份。
144
- */
145
- static readonly VALID_AGENTS: readonly ["claude", "codex", "opencode", "pi", "kimi", "dsh"];
146
140
  private sessionStore;
147
141
  /** 飞书桥接实例(public:测试直接访问断言,替代 as unknown as)。 */
148
142
  bridge: Bridge;
@@ -215,8 +209,8 @@ export declare class CommandRouter {
215
209
  /**
216
210
  * 串行化 config.* 卡片回调(2026-07-04)。
217
211
  * CardKit 2.0 input/button 回调经 `enqueueImmediate` 分发,**不进串行队列**,
218
- * 多次快速点击 toggle/input 会并发读写 `pendingConfig` 并同时调
219
- * `updateCardInPlace` → Feishu API 乱序到达,导致 toggle 卡死在某个状态。
212
+ * 多次快速点击下拉/文本框会并发读写 `pendingConfig` 并同时调
213
+ * `updateCardInPlace` → Feishu API 乱序到达,控件卡死在某个状态。
220
214
  * 此 Promise chain 把所有 config.* 动作串成一个执行链,保证后到的动作
221
215
  * 等前一个动作的卡片 patch 完成后再读 `pendingConfig`。
222
216
  */
@@ -304,7 +298,37 @@ export declare class CommandRouter {
304
298
  * Handle queue.immediate: stop current run, clear queue before this message, execute this message immediately.
305
299
  * Instead of asking user to resend, we keep the target task in queue and let it execute.
306
300
  */
301
+ /**
302
+ * 把「执行编辑后的内容」注册成原队列槽位的一次性 replacement(复用入队时
303
+ * 捕获的 binding + 恢复 lane cwd,否则编辑后重跑的 run 会丢 cwd 与绑定)。
304
+ *
305
+ * 重新入队不行:`enqueue` 只能追加到 promise 链尾部,会把编辑任务甩到
306
+ * 后来者后面,违背「立即执行 = 下一个就跑」。三个调用点都必须在任何 await
307
+ * 之前注册——begin 路径消费 replacement 的时机不可预测(见
308
+ * handleQueueImmediate 步骤 1.5 的竞态说明)。
309
+ */
310
+ private registerEditedReplacement;
307
311
  private handleQueueImmediate;
312
+ /**
313
+ * 清掉排在目标之前的所有排队任务,返回实际清除条数。
314
+ *
315
+ * 两条红线:
316
+ * - 目标可能在 interruptCurrentRun 等待期间已经接跑(链并发前进),那时它已不在
317
+ * 快照里,剩下的全部排在它**后面**——清除必须在目标位置之前停下,不得越界删掉
318
+ * 用户没要求清除的任务。
319
+ * - 移除循环必须整体同步:队列链在任何 await 处都会推进(卡片 PATCH 也算),
320
+ * 一旦让出事件循环,用户要求清除的任务可能趁撤销卡还在路上就跑起来了。
321
+ * 撤销卡片由 `removeFromQueue` 统一触发(fire-and-forget)。
322
+ */
323
+ private clearTasksAheadOfTarget;
324
+ /**
325
+ * `queue.immediate` 的终态反馈(唯一出口)。
326
+ *
327
+ * 承诺必须与真实调度一致:目标只有确实是停止后的下一个,才可以把它的卡翻成
328
+ * 「执行中」并说「将立即执行」;在途接跑/被撤销/被抢先/远程停止未确认四种状态
329
+ * 各给各的文案(把没发生的事说成发生了,比沉默更糟——用户会据文案决定要不要重发)。
330
+ */
331
+ private reportImmediateOutcome;
308
332
  /**
309
333
  * Handle queue.diagnose: show diagnostic info for why message is queuing.
310
334
  */
@@ -514,6 +538,12 @@ export declare class CommandRouter {
514
538
  * 无 messageId 的调用(测试/文本路径)不登记。
515
539
  */
516
540
  private rememberConfigCard;
541
+ /**
542
+ * 把一次字段变更交给当前 agent 的 config builder(处理 provider→model 这类
543
+ * 依赖关系),逐条写进草稿,再把草稿刷到所有配置卡。
544
+ * `config.set`(下拉)与 `config.input`(输入框提交)共用同一套应用逻辑。
545
+ */
546
+ private applyConfigFieldChange;
517
547
  /**
518
548
  * 把当前草稿刷到所有已知 config 卡片上(含本次点击的那张)。
519
549
  *
@@ -523,12 +553,12 @@ export declare class CommandRouter {
523
553
  */
524
554
  private refreshConfigCards;
525
555
  /**
526
- * 串行化 config.* 卡片回调(2026-07-04 修复 toggle 卡死 bug)。
556
+ * 串行化 config.* 卡片回调(2026-07-04 修复连击卡死 bug)。
527
557
  *
528
558
  * CardKit 2.0 input/button 回调经 `enqueueImmediate` 分发,不进 bridge 的
529
- * 串行队列;多次快速点击 toggle 会并发读写 `pendingConfig` 并同时调
559
+ * 串行队列;多次快速点击下拉/文本框会并发读写 `pendingConfig` 并同时调
530
560
  * `updateCardInPlace` → 两个 patch 请求乱序到达飞书,后到达的 patch(点击 1
531
- * 的旧卡片)覆盖先到达的 patch(点击 2 的新卡片),用户看到 toggle 卡死。
561
+ * 的旧卡片)覆盖先到达的 patch(点击 2 的新卡片),用户看到控件卡死。
532
562
  *
533
563
  * 此方法把所有 config.* 动作串成一个 Promise chain:每个动作等前一个动作
534
564
  * 的 `updateCardInPlace` 完全 settle 后再读 `pendingConfig`。