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
package/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.5.14] - 2026-10-28
9
+
10
+ ### 修复
11
+
12
+ - **卡片停止刷新不再查不到原因**:飞书拒收一次卡片更新后,这张卡会被永久剔除、此后不再原地刷新(用户侧表现为「卡片卡在最后一步」)。这条失败此前只记 debug 级日志,在默认 `info` 级别下看不到;现在按 warn 记录,带上下原因
13
+ - **自重启的前实例信息读取失败不再被误归因**:`/restart` 读旧实例的 startup-contact 时,只有「从未写过」(首次运行)算正常;解析失败或权限问题现在会留痕,否则排查时被当成「旧 owner 没有条目」而走错方向
14
+
15
+ ### 维护
16
+
17
+ - **agent 名单、会话读取契约、用量字段与模型别名各自单源**:新增 `src/agent-kinds.ts`、`src/session-contract.ts`、`src/model-catalog.ts`。用量字段清单原先手抄了 5 份、加一个字段要同时改三处,现在统一从一处派生。无行为变化
18
+ - **模块归位,依赖方向只剩单向**:`card-helpers` / `usage-format` 从 router 移入 card,DSH 的协议、类型与 home 解析从 runner 提到 `src/dsh/`;地基层(配置、会话、卡片)不再反向 import 上层,并加了依赖方向守卫用例守住这条边。无行为变化
19
+ - **`/config` 卡片删掉从未被任何字段使用的开关控件形态**,同时加「控件 ↔ 处理端」一致性守卫:渲染得出的按钮必定有对应处理分支,也不会漏进即时动作名单——「按钮点下去没人处理」这类状态从此被测出来
20
+ - **审批动作与排队管理从 bridge 拆成独立模块**,入口装配线(进程级异常处理器、ConfigDir 派生路径、agent 工厂闭包)收拢为单文件静态守卫;顺带清掉死代码、重复实现与静默吞错的分支。无行为变化
21
+ - **单元测试纳入类型检查**:`tsconfig.test-infra.json` 不再排除 `src/**/*.test.ts`,`bun run typecheck` 现在会检查测试文件的类型,测试夹具里的陈旧键当场可见
22
+
8
23
  ## [0.5.13] - 2026-10-26
9
24
 
10
25
  ### 修复
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Agent 名单单源(运行时数组 + 类型同源,二者不可能漂移)。
3
+ *
4
+ * 中立层:config(校验 defaultAgent)、session(按 agent 存 sessionId)、card
5
+ * (显示名)、router(解析用户输入)、runner(实现各家 runner)都要用这个名字,
6
+ * 谁都不该为了拿它去 import 别层的模块 —— 名单原先住在 runner/types.ts 时,
7
+ * 地基层 config 就得反向 import 上层 runner。
8
+ *
9
+ * 历史上这份名单被手抄成多份(router 的 VALID_AGENTS、bridge 的 resume.compact
10
+ * 校验、各 agent 的 config builder…),漂移过:dsh 加入后 bridge 的
11
+ * resume.compact 仍只有 5 个,带 dsh 的 resume 卡片会静默退回 defaultAgent。
12
+ * 新增 agent 只改这里。
13
+ */
14
+ export declare const AGENT_KINDS: readonly ["claude", "codex", "opencode", "pi", "kimi", "dsh"];
15
+ export type AgentKind = (typeof AGENT_KINDS)[number];
16
+ /** 用户可见 agent 显示名单源:启动注册与无 registry 的回退路径共用。 */
17
+ export declare const AGENT_DISPLAY_NAMES: Record<AgentKind, string>;
18
+ /** 任意输入(卡片 payload / 命令行参数)是否是一个已知 agent 名。 */
19
+ export declare function isAgentKind(value: unknown): value is AgentKind;
20
+ /**
21
+ * 解析用户给出的 agent 名,未知/缺省时回退 `fallback`。
22
+ *
23
+ * 判定此前抄了三份(router 的两处 resume 分支 + commands/resume.ts);名单与
24
+ * 判定同源才有意义——`resume.compact` 曾因手抄名单漏掉 dsh 而静默退回
25
+ * defaultAgent(见 `AGENT_KINDS` 头注)。
26
+ */
27
+ export declare function resolveAgentKind(value: unknown, fallback: AgentKind): AgentKind;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Agent 名单单源(运行时数组 + 类型同源,二者不可能漂移)。
3
+ *
4
+ * 中立层:config(校验 defaultAgent)、session(按 agent 存 sessionId)、card
5
+ * (显示名)、router(解析用户输入)、runner(实现各家 runner)都要用这个名字,
6
+ * 谁都不该为了拿它去 import 别层的模块 —— 名单原先住在 runner/types.ts 时,
7
+ * 地基层 config 就得反向 import 上层 runner。
8
+ *
9
+ * 历史上这份名单被手抄成多份(router 的 VALID_AGENTS、bridge 的 resume.compact
10
+ * 校验、各 agent 的 config builder…),漂移过:dsh 加入后 bridge 的
11
+ * resume.compact 仍只有 5 个,带 dsh 的 resume 卡片会静默退回 defaultAgent。
12
+ * 新增 agent 只改这里。
13
+ */
14
+ export const AGENT_KINDS = ['claude', 'codex', 'opencode', 'pi', 'kimi', 'dsh'];
15
+ /** 用户可见 agent 显示名单源:启动注册与无 registry 的回退路径共用。 */
16
+ export const AGENT_DISPLAY_NAMES = {
17
+ claude: 'Claude',
18
+ codex: 'Codex',
19
+ opencode: 'Opencode',
20
+ pi: 'Pi',
21
+ kimi: 'Kimi',
22
+ dsh: 'DSH',
23
+ };
24
+ /** 任意输入(卡片 payload / 命令行参数)是否是一个已知 agent 名。 */
25
+ export function isAgentKind(value) {
26
+ return AGENT_KINDS.includes(value);
27
+ }
28
+ /**
29
+ * 解析用户给出的 agent 名,未知/缺省时回退 `fallback`。
30
+ *
31
+ * 判定此前抄了三份(router 的两处 resume 分支 + commands/resume.ts);名单与
32
+ * 判定同源才有意义——`resume.compact` 曾因手抄名单漏掉 dsh 而静默退回
33
+ * defaultAgent(见 `AGENT_KINDS` 头注)。
34
+ */
35
+ export function resolveAgentKind(value, fallback) {
36
+ return isAgentKind(value) ? value : fallback;
37
+ }
38
+ //# sourceMappingURL=agent-kinds.js.map
@@ -0,0 +1,95 @@
1
+ /**
2
+ * 审批卡动作分发(Bridge 的终态卡动作侧,审计 #32 的一刀)。
3
+ *
4
+ * 每个方法只做一件事:按 runId 找到那次 run 的 `ApprovalCoordinator`,把卡片
5
+ * payload 翻成一次 coordinator 调用。原先这 7 个 handler 连同「找不到
6
+ * coordinator 怎么回答」的公共前缀平铺在 Bridge 里,占了 160 行却不碰任何
7
+ * Bridge 状态——只碰 `approvalCoordinators` 这一张表。
8
+ *
9
+ * 语义红线(保留原位,别在调用方重新实现):
10
+ * - run 已结束(coordinator 已释放)时点审批按钮必须给用户明确反馈,不能静默;
11
+ * router 把这个异常转成 error toast。
12
+ * - `nonce` 原样透传给 coordinator:飞书会重投递同一个按钮回调,去重靠它
13
+ * (见 approval-coordinator.ts 的状态机注释)。
14
+ */
15
+ import type { ApprovalCoordinator } from './approval-coordinator.js';
16
+ export interface ApprovalActionDeps {
17
+ /** 按 runId 取该 run 的 coordinator;已结束返回 undefined。 */
18
+ coordinatorFor(runId: string): ApprovalCoordinator | undefined;
19
+ }
20
+ /** 所有 handler 共用的入参形状。 */
21
+ interface RunScopedOpts {
22
+ runId: string;
23
+ requestId: number | string;
24
+ }
25
+ export declare class ApprovalActions {
26
+ private deps;
27
+ constructor(deps: ApprovalActionDeps);
28
+ /**
29
+ * Resolve the ApprovalCoordinator for a run, or throw the standard
30
+ * "已结束" error. Shared preamble of all approval card-action handlers.
31
+ */
32
+ private withCoordinator;
33
+ private dispatchQuestionAction;
34
+ /**
35
+ * Handle an approval response from a card button click.
36
+ * Routes to the ApprovalCoordinator for the given run.
37
+ */
38
+ handleApprovalRespond(opts: RunScopedOpts & {
39
+ decision: string;
40
+ nonce: string;
41
+ }): Promise<void>;
42
+ /**
43
+ * 计划审批修改意见(ExitPlanMode 输入框):记录到 coordinator 并回流卡片。
44
+ * 「拒绝并附意见」/「批准并采纳修改」按钮复用该文本。
45
+ */
46
+ handleApprovalPlanFeedback(opts: RunScopedOpts & {
47
+ text: string;
48
+ nonce: string;
49
+ }): Promise<void>;
50
+ /**
51
+ * Handle a permission toggle from a card button click.
52
+ * Routes to the ApprovalCoordinator for the given run.
53
+ */
54
+ handleApprovalToggle(opts: RunScopedOpts & {
55
+ permId: string;
56
+ selected?: boolean;
57
+ }): Promise<void>;
58
+ /**
59
+ * Claude AskUserQuestion 选项点击(单选即时提交 / 多选切换勾选)。
60
+ * 路由到 ApprovalCoordinator.toggleAnswer。
61
+ */
62
+ handleApprovalAnswer(opts: RunScopedOpts & {
63
+ questionIndex: number;
64
+ option: string;
65
+ nonce: string;
66
+ }): Promise<void>;
67
+ /**
68
+ * Claude AskUserQuestion 多选问题的「提交答案」按钮。
69
+ * 路由到 ApprovalCoordinator.submitAnswers。
70
+ */
71
+ handleApprovalAnswerSubmit(opts: RunScopedOpts & {
72
+ questionIndex: number;
73
+ nonce: string;
74
+ }): Promise<void>;
75
+ /**
76
+ * Claude AskUserQuestion 自定义答案(Other):自由文本直接
77
+ * 作为该单选问题的答案提交。路由到 ApprovalCoordinator.answerCustom。
78
+ */
79
+ handleApprovalAnswerCustom(opts: RunScopedOpts & {
80
+ questionIndex: number;
81
+ text: string;
82
+ nonce: string;
83
+ }): Promise<void>;
84
+ /**
85
+ * Codex AskUserQuestion 补充说明(user_note,2026-08-18 live 验证模型理解
86
+ * "user_note: <text>" 条目):记录到 coordinator,随答案一起提交。
87
+ * 路由到 ApprovalCoordinator.answerNote。
88
+ */
89
+ handleApprovalAnswerNote(opts: RunScopedOpts & {
90
+ questionIndex: number;
91
+ text: string;
92
+ nonce: string;
93
+ }): Promise<void>;
94
+ }
95
+ export {};
@@ -0,0 +1,104 @@
1
+ /**
2
+ * 审批卡动作分发(Bridge 的终态卡动作侧,审计 #32 的一刀)。
3
+ *
4
+ * 每个方法只做一件事:按 runId 找到那次 run 的 `ApprovalCoordinator`,把卡片
5
+ * payload 翻成一次 coordinator 调用。原先这 7 个 handler 连同「找不到
6
+ * coordinator 怎么回答」的公共前缀平铺在 Bridge 里,占了 160 行却不碰任何
7
+ * Bridge 状态——只碰 `approvalCoordinators` 这一张表。
8
+ *
9
+ * 语义红线(保留原位,别在调用方重新实现):
10
+ * - run 已结束(coordinator 已释放)时点审批按钮必须给用户明确反馈,不能静默;
11
+ * router 把这个异常转成 error toast。
12
+ * - `nonce` 原样透传给 coordinator:飞书会重投递同一个按钮回调,去重靠它
13
+ * (见 approval-coordinator.ts 的状态机注释)。
14
+ */
15
+ import { getLogger } from '../logger/index.js';
16
+ import { decisionToApprovalAction } from './approval-coordinator.js';
17
+ export class ApprovalActions {
18
+ deps;
19
+ constructor(deps) {
20
+ this.deps = deps;
21
+ }
22
+ /**
23
+ * Resolve the ApprovalCoordinator for a run, or throw the standard
24
+ * "已结束" error. Shared preamble of all approval card-action handlers.
25
+ */
26
+ withCoordinator(runId, fn) {
27
+ const coordinator = this.deps.coordinatorFor(runId);
28
+ if (!coordinator) {
29
+ getLogger().warn(`[lark-remote] no approval coordinator for runId=${runId.slice(0, 8)}`);
30
+ throw new Error('任务已结束,审批无法响应');
31
+ }
32
+ return fn(coordinator);
33
+ }
34
+ dispatchQuestionAction(opts, action, invoke) {
35
+ getLogger().info(`[lark-remote] ${action} runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
36
+ return this.withCoordinator(opts.runId, invoke);
37
+ }
38
+ /**
39
+ * Handle an approval response from a card button click.
40
+ * Routes to the ApprovalCoordinator for the given run.
41
+ */
42
+ async handleApprovalRespond(opts) {
43
+ getLogger().info(`[lark-remote] handleApprovalRespond runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} decision=${opts.decision}`);
44
+ return this.withCoordinator(opts.runId, async (coordinator) => {
45
+ // Build ApprovalAction from the decision string
46
+ const action = decisionToApprovalAction(opts.decision);
47
+ await coordinator.submit(action, { requestId: opts.requestId, nonce: opts.nonce });
48
+ });
49
+ }
50
+ /**
51
+ * 计划审批修改意见(ExitPlanMode 输入框):记录到 coordinator 并回流卡片。
52
+ * 「拒绝并附意见」/「批准并采纳修改」按钮复用该文本。
53
+ */
54
+ async handleApprovalPlanFeedback(opts) {
55
+ return this.withCoordinator(opts.runId, async (coordinator) => {
56
+ await coordinator.planFeedback({ text: opts.text }, { requestId: opts.requestId, nonce: opts.nonce });
57
+ });
58
+ }
59
+ /**
60
+ * Handle a permission toggle from a card button click.
61
+ * Routes to the ApprovalCoordinator for the given run.
62
+ */
63
+ async handleApprovalToggle(opts) {
64
+ getLogger().info(`[lark-remote] handleApprovalToggle runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} permId=${opts.permId}`);
65
+ return this.withCoordinator(opts.runId, async (coordinator) => {
66
+ // selected 由卡片根据当前渲染状态传回(取反),不再硬编码只授不撤。
67
+ const toggleAction = {
68
+ permId: opts.permId,
69
+ selected: opts.selected ?? true,
70
+ };
71
+ await coordinator.togglePerm(toggleAction, { requestId: opts.requestId });
72
+ });
73
+ }
74
+ /**
75
+ * Claude AskUserQuestion 选项点击(单选即时提交 / 多选切换勾选)。
76
+ * 路由到 ApprovalCoordinator.toggleAnswer。
77
+ */
78
+ async handleApprovalAnswer(opts) {
79
+ return this.dispatchQuestionAction(opts, 'handleApprovalAnswer', (coordinator) => coordinator.toggleAnswer({ questionIndex: opts.questionIndex, option: opts.option }, { requestId: opts.requestId, nonce: opts.nonce }));
80
+ }
81
+ /**
82
+ * Claude AskUserQuestion 多选问题的「提交答案」按钮。
83
+ * 路由到 ApprovalCoordinator.submitAnswers。
84
+ */
85
+ async handleApprovalAnswerSubmit(opts) {
86
+ return this.dispatchQuestionAction(opts, 'handleApprovalAnswerSubmit', (coordinator) => coordinator.submitAnswers({ questionIndex: opts.questionIndex }, { requestId: opts.requestId, nonce: opts.nonce }));
87
+ }
88
+ /**
89
+ * Claude AskUserQuestion 自定义答案(Other):自由文本直接
90
+ * 作为该单选问题的答案提交。路由到 ApprovalCoordinator.answerCustom。
91
+ */
92
+ async handleApprovalAnswerCustom(opts) {
93
+ return this.dispatchQuestionAction(opts, 'handleApprovalAnswerCustom', (coordinator) => coordinator.answerCustom({ questionIndex: opts.questionIndex, text: opts.text }, { requestId: opts.requestId, nonce: opts.nonce }));
94
+ }
95
+ /**
96
+ * Codex AskUserQuestion 补充说明(user_note,2026-08-18 live 验证模型理解
97
+ * "user_note: <text>" 条目):记录到 coordinator,随答案一起提交。
98
+ * 路由到 ApprovalCoordinator.answerNote。
99
+ */
100
+ async handleApprovalAnswerNote(opts) {
101
+ return this.dispatchQuestionAction(opts, 'handleApprovalAnswerNote', (coordinator) => coordinator.answerNote({ questionIndex: opts.questionIndex, text: opts.text }, { requestId: opts.requestId, nonce: opts.nonce }));
102
+ }
103
+ }
104
+ //# sourceMappingURL=approval-actions.js.map
@@ -1,22 +1,13 @@
1
1
  import type { SessionReaderRegistry } from '../session/index.js';
2
- import type { AgentKind } from '../runner/index.js';
2
+ import type { AgentKind } from '../agent-kinds.js';
3
+ import type { AgentSessionUsage } from '../session-contract.js';
3
4
  export declare function errorMessage(error: unknown): string;
4
- export type FinalUsageSnapshot = {
5
- contextLength?: number;
6
- contextLimit?: number;
7
- compactCount?: number;
8
- compactPreContextLength?: number;
9
- cacheReadTokens?: number;
10
- cacheCreationTokens?: number;
11
- totalTokens?: number;
12
- inputTokens?: number;
13
- outputTokens?: number;
14
- cumulativeTotalTokens?: number;
15
- cumulativeInputTokens?: number;
16
- cumulativeOutputTokens?: number;
17
- cumulativeCacheReadTokens?: number;
18
- cumulativeCacheCreationTokens?: number;
19
- };
5
+ /**
6
+ * jsonl 侧的最终用量快照。就是 `AgentSessionUsage` 的可选形态:reader 保证
7
+ * input/output/contextLength 有值,这里允许「读不到」,字段清单不再手抄第二份
8
+ * (§9.21 的口径一致要求靠这个单源维持)。
9
+ */
10
+ export type FinalUsageSnapshot = Partial<AgentSessionUsage>;
20
11
  /**
21
12
  * Read final usage (contextLength + compactCount + cache tokens) from the
22
13
  * session jsonl. Called after a run finishes.
@@ -28,24 +28,7 @@ export function resolveFinalUsage(registry, defaultAgent, sessionId, cwd, agentK
28
28
  // fallback to per-run live usage is visible in logs, not silent.
29
29
  getLogger().warn(`[lark-remote] resolveFinalUsage: no usage from jsonl sessionId=${sessionId} cwd=${cwd} agent=${agentKind}, card falls back to per-run live usage`);
30
30
  }
31
- return content.usage
32
- ? {
33
- contextLength: content.usage.contextLength,
34
- contextLimit: content.usage.contextLimit,
35
- compactCount: content.usage.compactCount,
36
- compactPreContextLength: content.usage.compactPreContextLength,
37
- cacheReadTokens: content.usage.cacheReadTokens,
38
- cacheCreationTokens: content.usage.cacheCreationTokens,
39
- totalTokens: content.usage.totalTokens,
40
- inputTokens: content.usage.inputTokens,
41
- outputTokens: content.usage.outputTokens,
42
- cumulativeTotalTokens: content.usage.cumulativeTotalTokens,
43
- cumulativeInputTokens: content.usage.cumulativeInputTokens,
44
- cumulativeOutputTokens: content.usage.cumulativeOutputTokens,
45
- cumulativeCacheReadTokens: content.usage.cumulativeCacheReadTokens,
46
- cumulativeCacheCreationTokens: content.usage.cumulativeCacheCreationTokens,
47
- }
48
- : undefined;
31
+ return content.usage ? { ...content.usage } : undefined;
49
32
  }
50
33
  catch (err) {
51
34
  getLogger().warn(`[lark-remote] resolveFinalUsage failed sessionId=${sessionId}: ${errorMessage(err)}`);
@@ -4,7 +4,8 @@ import type { SessionReaderRegistry, SessionStore } from '../session/index.js';
4
4
  import type { AppConfig } from '../config/index.js';
5
5
  import { type RunCardChannel } from '../card/run-card-session.js';
6
6
  import { type RunTerminal } from '../card/run-state.js';
7
- import { type AgentKind, type StopOutcome } from '../runner/types.js';
7
+ import type { AgentKind } from '../agent-kinds.js';
8
+ import { type StopOutcome } from '../runner/types.js';
8
9
  import { QueueManager, type QueuedTask, type EnqueueOptions, type AgentBinding, type ExecutingInfo } from './queue-manager.js';
9
10
  import type { InboundMediaPayload } from '../connector/index.js';
10
11
  import type { MediaOutcome } from '../inbound/turn.js';
@@ -14,7 +15,7 @@ import type { MediaOutcome } from '../inbound/turn.js';
14
15
  * through it. Declared here so tests can satisfy it structurally without
15
16
  * `as unknown as` casts.
16
17
  */
17
- interface BridgeChannel extends RunCardChannel {
18
+ export interface BridgeChannel extends RunCardChannel {
18
19
  sendWithRetry(chatId: string, input: {
19
20
  text: string;
20
21
  } | {
@@ -149,6 +150,8 @@ export declare class Bridge {
149
150
  private activeRuns;
150
151
  /** Approval coordinators keyed by runId. */
151
152
  private approvalCoordinators;
153
+ /** 审批卡动作的实现(只读上面那张表;见 approval-actions.ts)。 */
154
+ private approvalActions;
152
155
  /**
153
156
  * 最近若干次已完成的、runner 有 runCompact 的 run(cwd → runId → 记录)。
154
157
  * run 结束后 activeRuns 已清空,而终态卡上的 Compact 按钮只带 runId,
@@ -378,7 +381,7 @@ export declare class Bridge {
378
381
  /**
379
382
  * Update an existing card in place (原地更新) instead of sending a new one.
380
383
  *
381
- * Used by /config cardAction handlers (config.toggle/set/input/save) so the
384
+ * Used by /config cardAction handlers (config.set/input/save) so the
382
385
  * user sees the card refresh on the same message bubble rather than getting
383
386
  * a new card per click — same-message-bubble update pattern.
384
387
  *
@@ -468,6 +471,38 @@ export declare class Bridge {
468
471
  * 队列继续推进(否则一个挂死的 run 永久堵住后续消息)。
469
472
  */
470
473
  private startIdleWatchdog;
474
+ /**
475
+ * result 事件的 pre-init 守卫(§9.22)。
476
+ *
477
+ * Claude CLI `--resume` 会在 system.init 之前先吐一条**上一轮**的陈旧 result。
478
+ * 认了它就会过早置 sawResult / 抓错 usage / 让 run-state reducer 提前进入
479
+ * finalizing(reducer 用 sessionId===undefined 守卫,同一条红线)。本轮真正的
480
+ * result 在 system.init 之后才到。
481
+ *
482
+ * 例外:app-server runner(usageAuthority==='live')的 init 是 runner 自己补发
483
+ * 的 synthetic init(2026-08-13 修复)。此分支保留为防御性兜底:live runner 若
484
+ * 在无 init 时发出 result(旧构建等),session 写回照常执行,但 sawResult 不置
485
+ * 真——卡片不会把半初始化的 run 当作已收尾。
486
+ *
487
+ * @param dropFromCard 该 result 是陈旧重放,不得进卡片(调用方 continue 跳过 push)
488
+ */
489
+ private observeResultEvent;
490
+ /**
491
+ * 审批三事件的派发(requested / resolved / view_updated)。
492
+ *
493
+ * coordinator 一 run 一个,首次 requested 时惰性建好并登记,`finally` 里统一
494
+ * onTurnEnded + 摘除。
495
+ */
496
+ private dispatchApprovalEvent;
497
+ /**
498
+ * 进程退出(for-await 自然结束)后的终态矩阵——它是本轮的唯一终态触发源。
499
+ *
500
+ * 1) finalizing(result 已收到)→ 三态映射 + usage meta
501
+ * 2) running(未收到 result)→ 错误路径;pre-init 终态优先当唯一线索
502
+ * 3) 已终态 + sawResult → 首终态不动,仅补 usage meta
503
+ * 4) 已终态且未收到 result(如 spawn 失败后 interrupted)→ 无 usage 可补,跳过
504
+ */
505
+ private finishRunAfterStream;
471
506
  /**
472
507
  * Step 2 of forwardToClaude: Run the agent and consume its event stream.
473
508
  * Handles idle watchdog, event processing, session sync, and state transitions.
@@ -494,45 +529,28 @@ export declare class Bridge {
494
529
  * find and return to this session without scrolling up.
495
530
  */
496
531
  private sendCompletionNotificationCard;
497
- /**
498
- * Resolve the ApprovalCoordinator for a run, or throw the standard
499
- * "已结束" error. Shared preamble of all approval card-action handlers.
500
- */
501
- private withCoordinator;
502
- /**
503
- * Handle an approval response from a card button click.
504
- * Routes to the ApprovalCoordinator for the given run.
505
- */
532
+ /** 审批响应(卡片按钮)→ ApprovalCoordinator.submit。 */
506
533
  handleApprovalRespond(opts: {
507
534
  runId: string;
508
535
  requestId: number | string;
509
536
  decision: string;
510
537
  nonce: string;
511
538
  }): Promise<void>;
512
- /**
513
- * 计划审批修改意见(ExitPlanMode 输入框):记录到 coordinator 并回流卡片。
514
- * 「拒绝并附意见」/「批准并采纳修改」按钮复用该文本。
515
- */
539
+ /** 计划审批修改意见(ExitPlanMode 输入框)→ coordinator.planFeedback。 */
516
540
  handleApprovalPlanFeedback(opts: {
517
541
  runId: string;
518
542
  requestId: number | string;
519
543
  text: string;
520
544
  nonce: string;
521
545
  }): Promise<void>;
522
- /**
523
- * Handle a permission toggle from a card button click.
524
- * Routes to the ApprovalCoordinator for the given run.
525
- */
546
+ /** 权限条目勾选(卡片按钮)→ coordinator.togglePerm。 */
526
547
  handleApprovalToggle(opts: {
527
548
  runId: string;
528
549
  requestId: number | string;
529
550
  permId: string;
530
551
  selected?: boolean;
531
552
  }): Promise<void>;
532
- /**
533
- * Claude AskUserQuestion 选项点击(单选即时提交 / 多选切换勾选)。
534
- * 路由到 ApprovalCoordinator.toggleAnswer。
535
- */
553
+ /** AskUserQuestion 选项点击 → coordinator.toggleAnswer。 */
536
554
  handleApprovalAnswer(opts: {
537
555
  runId: string;
538
556
  requestId: number | string;
@@ -540,20 +558,14 @@ export declare class Bridge {
540
558
  option: string;
541
559
  nonce: string;
542
560
  }): Promise<void>;
543
- /**
544
- * Claude AskUserQuestion 多选问题的「提交答案」按钮。
545
- * 路由到 ApprovalCoordinator.submitAnswers。
546
- */
561
+ /** AskUserQuestion 多选「提交答案」→ coordinator.submitAnswers。 */
547
562
  handleApprovalAnswerSubmit(opts: {
548
563
  runId: string;
549
564
  requestId: number | string;
550
565
  questionIndex: number;
551
566
  nonce: string;
552
567
  }): Promise<void>;
553
- /**
554
- * Claude AskUserQuestion 自定义答案(Other):自由文本直接
555
- * 作为该单选问题的答案提交。路由到 ApprovalCoordinator.answerCustom。
556
- */
568
+ /** AskUserQuestion 自定义答案(Other)→ coordinator.answerCustom。 */
557
569
  handleApprovalAnswerCustom(opts: {
558
570
  runId: string;
559
571
  requestId: number | string;
@@ -561,11 +573,7 @@ export declare class Bridge {
561
573
  text: string;
562
574
  nonce: string;
563
575
  }): Promise<void>;
564
- /**
565
- * Codex AskUserQuestion 补充说明(user_note,2026-08-18 live 验证模型理解
566
- * "user_note: <text>" 条目):记录到 coordinator,随答案一起提交。
567
- * 路由到 ApprovalCoordinator.answerNote。
568
- */
576
+ /** AskUserQuestion 补充说明(user_note)→ coordinator.answerNote。 */
569
577
  handleApprovalAnswerNote(opts: {
570
578
  runId: string;
571
579
  requestId: number | string;
@@ -573,7 +581,6 @@ export declare class Bridge {
573
581
  text: string;
574
582
  nonce: string;
575
583
  }): Promise<void>;
576
- private dispatchQuestionAction;
577
584
  /**
578
585
  * 记下一次「可压缩 run」:终态卡上的 Compact 按钮点击时据此反查
579
586
  * sessionId + agentKind。runId 是按钮自带的唯一键,同 cwd 内唯一。
@@ -616,7 +623,7 @@ export declare class Bridge {
616
623
  runId?: string;
617
624
  }, ctx: CommandContext): Promise<void>;
618
625
  /**
619
- * §5.3: kimi 压缩在途检测——reader 鸭子实现 `readCompactionState` 时,若
626
+ * §5.3: kimi 压缩在途检测——reader 实现契约的 `readCompactionState` 时,若
620
627
  * wire 状态机判定当前有未终结的压缩(最后一次 begin 无 terminal 记录),
621
628
  * 直接回文本「已有一次 Compact 正在进行」并返回 true(调用方不开卡、不发
622
629
  * session/prompt)。codex/claude 等 reader 无此方法 → 返回 false,行为不变。