lark-remote 0.1.13 → 0.2.1

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 (132) hide show
  1. package/CHANGELOG.md +36 -3
  2. package/README.en.md +7 -11
  3. package/README.md +7 -11
  4. package/dist/bridge/final-usage.d.ts +24 -0
  5. package/dist/bridge/final-usage.js +55 -0
  6. package/dist/bridge/index.d.ts +0 -7
  7. package/dist/bridge/index.js +22 -64
  8. package/dist/bridge/queue-manager.js +4 -3
  9. package/dist/card/approval-render.js +39 -94
  10. package/dist/card/bash-renderer.js +12 -21
  11. package/dist/card/card-shared.d.ts +13 -1
  12. package/dist/card/card-shared.js +21 -30
  13. package/dist/card/run-renderer.d.ts +0 -22
  14. package/dist/card/run-renderer.js +206 -153
  15. package/dist/card/run-state.d.ts +29 -1
  16. package/dist/card/run-state.js +172 -84
  17. package/dist/card/text-truncate.d.ts +0 -9
  18. package/dist/card/text-truncate.js +0 -9
  19. package/dist/card/tool-render.d.ts +4 -1
  20. package/dist/card/tool-render.js +76 -32
  21. package/dist/cli.js +2 -2
  22. package/dist/common/fs.d.ts +14 -0
  23. package/dist/common/fs.js +57 -3
  24. package/dist/config/codex-config.js +2 -0
  25. package/dist/config/index.d.ts +0 -5
  26. package/dist/config/index.js +0 -11
  27. package/dist/config/kimi-config.js +1 -0
  28. package/dist/config/opencode-config.js +13 -2
  29. package/dist/config/qr.d.ts +36 -0
  30. package/dist/config/qr.js +124 -0
  31. package/dist/config/wizard.js +69 -27
  32. package/dist/connector/index.d.ts +3 -2
  33. package/dist/connector/index.js +5 -4
  34. package/dist/index.js +15 -42
  35. package/dist/instance-lock.js +7 -0
  36. package/dist/persistence/atomic-write.d.ts +2 -0
  37. package/dist/persistence/atomic-write.js +20 -5
  38. package/dist/persistence/load-json-file.d.ts +1 -2
  39. package/dist/persistence/load-json-file.js +2 -3
  40. package/dist/platform/agent-stopper.d.ts +22 -0
  41. package/dist/platform/agent-stopper.js +19 -0
  42. package/dist/platform/command.d.ts +11 -0
  43. package/dist/platform/command.js +107 -0
  44. package/dist/platform/identity.d.ts +33 -0
  45. package/dist/platform/identity.js +187 -0
  46. package/dist/platform/path.d.ts +24 -0
  47. package/dist/platform/path.js +110 -0
  48. package/dist/platform/select.d.ts +9 -0
  49. package/dist/platform/select.js +12 -0
  50. package/dist/platform/shell.d.ts +51 -0
  51. package/dist/platform/shell.js +75 -0
  52. package/dist/platform/spawn.d.ts +41 -0
  53. package/dist/platform/spawn.js +77 -0
  54. package/dist/platform/terminator-posix.d.ts +38 -0
  55. package/dist/platform/terminator-posix.js +103 -0
  56. package/dist/platform/terminator-win32.d.ts +21 -0
  57. package/dist/platform/terminator-win32.js +110 -0
  58. package/dist/platform/terminator.d.ts +44 -0
  59. package/dist/platform/terminator.js +24 -0
  60. package/dist/platform/types.d.ts +23 -0
  61. package/dist/platform/types.js +5 -0
  62. package/dist/restart.js +4 -2
  63. package/dist/router/card-helpers.d.ts +33 -6
  64. package/dist/router/card-helpers.js +67 -11
  65. package/dist/router/config/common/render.d.ts +1 -1
  66. package/dist/router/config/common/render.js +1 -1
  67. package/dist/router/config-diff.d.ts +4 -0
  68. package/dist/router/config-diff.js +70 -0
  69. package/dist/router/index.d.ts +66 -6
  70. package/dist/router/index.js +451 -316
  71. package/dist/router/utils.d.ts +6 -0
  72. package/dist/router/utils.js +12 -0
  73. package/dist/runner/bash/runner.d.ts +9 -2
  74. package/dist/runner/bash/runner.js +45 -20
  75. package/dist/runner/claude/session.d.ts +4 -1
  76. package/dist/runner/claude/session.js +18 -4
  77. package/dist/runner/codex/app-server/protocol-types.d.ts +35 -1
  78. package/dist/runner/codex/app-server/translator.d.ts +18 -0
  79. package/dist/runner/codex/app-server/translator.js +146 -0
  80. package/dist/runner/common/acp/base-acp-runner.d.ts +116 -0
  81. package/dist/runner/common/acp/base-acp-runner.js +248 -0
  82. package/dist/runner/common/acp/base-translator.d.ts +141 -0
  83. package/dist/runner/common/acp/base-translator.js +271 -0
  84. package/dist/runner/common/acp/protocol-helpers.d.ts +39 -0
  85. package/dist/runner/common/acp/protocol-helpers.js +34 -0
  86. package/dist/runner/common/jsonrpc/transport.d.ts +2 -0
  87. package/dist/runner/common/jsonrpc/transport.js +25 -5
  88. package/dist/runner/common/process-stopper.d.ts +4 -26
  89. package/dist/runner/common/process-stopper.js +4 -76
  90. package/dist/runner/common/runner-utils.d.ts +0 -5
  91. package/dist/runner/common/runner-utils.js +0 -7
  92. package/dist/runner/common/spawning-runner.d.ts +42 -132
  93. package/dist/runner/common/spawning-runner.js +52 -271
  94. package/dist/runner/common/usage.d.ts +2 -0
  95. package/dist/runner/common/usage.js +2 -0
  96. package/dist/runner/index.d.ts +1 -1
  97. package/dist/runner/kimi/acp/runner.d.ts +45 -42
  98. package/dist/runner/kimi/acp/runner.js +140 -293
  99. package/dist/runner/kimi/acp/translator.d.ts +18 -100
  100. package/dist/runner/kimi/acp/translator.js +56 -242
  101. package/dist/runner/opencode/acp/runner.d.ts +22 -46
  102. package/dist/runner/opencode/acp/runner.js +73 -256
  103. package/dist/runner/opencode/acp/translator.d.ts +28 -103
  104. package/dist/runner/opencode/acp/translator.js +51 -236
  105. package/dist/runner/pi/rpc/translator.d.ts +3 -0
  106. package/dist/runner/pi/rpc/translator.js +47 -9
  107. package/dist/runner/probe.d.ts +8 -11
  108. package/dist/runner/probe.js +17 -21
  109. package/dist/runner/registry.d.ts +4 -4
  110. package/dist/runner/registry.js +4 -4
  111. package/dist/runner/types.d.ts +38 -1
  112. package/dist/session/claude/sessions.js +35 -58
  113. package/dist/session/codex/rollout-reader.d.ts +10 -0
  114. package/dist/session/codex/rollout-reader.js +123 -41
  115. package/dist/session/common/constants.d.ts +7 -0
  116. package/dist/session/common/constants.js +9 -0
  117. package/dist/session/common/two-pass.d.ts +22 -0
  118. package/dist/session/common/two-pass.js +70 -0
  119. package/dist/session/dsh/sessions.js +7 -6
  120. package/dist/session/kimi/sessions.d.ts +6 -0
  121. package/dist/session/kimi/sessions.js +50 -73
  122. package/dist/session/opencode/sessions.js +26 -8
  123. package/dist/session/pi/sessions.js +54 -73
  124. package/dist/update/index.d.ts +1 -2
  125. package/dist/update/index.js +1 -2
  126. package/dist/update/install.d.ts +2 -1
  127. package/dist/update/install.js +58 -9
  128. package/dist/update/version-check.d.ts +5 -0
  129. package/dist/update/version-check.js +9 -0
  130. package/package.json +9 -6
  131. package/dist/update/startup-hint.d.ts +0 -5
  132. package/dist/update/startup-hint.js +0 -11
@@ -28,13 +28,40 @@ type SessionUsageLike = Parameters<typeof formatUsageStats>[0];
28
28
  */
29
29
  export declare function sessionEventPanel(ev: AgentSessionContentEvent, index: number, totalEvents: number, tailExpandedCount?: number, agentKind?: string): object;
30
30
  export { markdownDiv };
31
+ /** 分页卡「跳转页码」输入框的组件 name(仅用于结构断言与可读性)。 */
32
+ export declare const PAGE_JUMP_INPUT_NAME = "pageInput";
33
+ /** 页码输入非法时的统一提示文案(/ls /ws /resume /active /order 共用)。 */
34
+ export declare const PAGE_JUMP_INVALID_HINT = "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u9875\u7801\uFF08\u6B63\u6574\u6570\uFF09";
31
35
  /**
32
- * Build a CardKit 2.0 pagination bar (prev-button / page-label / next-button
33
- * columns). Shared by /ls, /ws, /resume, /active, /order.
36
+ * 解析分页卡「跳转页码」输入框的提交值。
34
37
  *
35
- * Returns the `column_set` element (plus caller appends an `hr`). Each caller
36
- * supplies its own callback cmd + extra value fields and label text (semantic
37
- * differences are preserved, not silently unified).
38
+ * 三态返回:
39
+ * - `undefined` — 未输入(空串/非字符串),调用方应回退到 `offset`(上一页/下一页)
40
+ * - `null` — 输入非法(非正整数),调用方应回错误 toast 且不刷新卡片
41
+ * - `number` — 页码换算出的 offset(页码从 1 开始)
42
+ */
43
+ export declare function parseJumpOffset(inputValue: unknown, pageSize: number): number | null | undefined;
44
+ /**
45
+ * Build the CardKit 2.0 pagination block shared by /ls, /ws, /resume, /active,
46
+ * /order.
47
+ *
48
+ * 第一性原理(2026-09-10 窄屏重设计):分页栏要同时承载「页码信息」和「翻页
49
+ * 控件」两类需求。旧布局把两者塞进同一行 `column_set`(文案 weighted 4 : 输入
50
+ * weighted 2),手机窄屏下 auto 按钮先占走固有宽度,剩余宽度按 4:2 切分后文案
51
+ * 列只有百来像素、输入框只有几十像素——文案折行、输入框窄到没法点。
52
+ * 拆成两行后每一类都有足够的横向空间:
53
+ *
54
+ * 1. 页码文案独占整行(顶层 `div`),窄屏不折行;
55
+ * 2. 控件行 `column_set` = [上一页 auto] [跳转页码 input weighted] [下一页 auto],
56
+ * input 吃掉 auto 按钮之外的剩余宽度(窄屏约百来像素,桌面端更宽)。
57
+ *
58
+ * Returns an array of body elements: `[page-label div, controls column_set]`;
59
+ * 调用方展开进 `body.elements`(+ 自己的 `hr`)。input 仍留在控件 column_set
60
+ * 内部,不用 form 容器(form 触发 300123 / 200621 整卡不可用)。CardKit 2.0
61
+ * input 自带 ✓ 提交图标,提交值经 raw `action.input_value` 回传,见 connector
62
+ * includeRawEvent + router/card-action-payload.ts。
63
+ *
64
+ * 每个调用方自带 callback cmd / extra value / 文案(语义差异保留,不强行统一)。
38
65
  *
39
66
  * @param opts.cmd The pagination callback command (e.g. 'ls.page').
40
67
  * @param opts.offset Current page offset.
@@ -53,7 +80,7 @@ export declare function paginationBar(opts: {
53
80
  label: string;
54
81
  prevText?: string;
55
82
  nextText?: string;
56
- }): object;
83
+ }): object[];
57
84
  /**
58
85
  * Build a session-history resume card (shared by auto-restore, /resume <id>,
59
86
  * config-switch resume, and run-completion notification).
@@ -63,13 +63,51 @@ function eventLabel(ev, agentKind) {
63
63
  }
64
64
  }
65
65
  export { markdownDiv };
66
+ /** 分页卡「跳转页码」输入框的组件 name(仅用于结构断言与可读性)。 */
67
+ export const PAGE_JUMP_INPUT_NAME = 'pageInput';
68
+ /** 页码输入非法时的统一提示文案(/ls /ws /resume /active /order 共用)。 */
69
+ export const PAGE_JUMP_INVALID_HINT = '请输入有效的页码(正整数)';
66
70
  /**
67
- * Build a CardKit 2.0 pagination bar (prev-button / page-label / next-button
68
- * columns). Shared by /ls, /ws, /resume, /active, /order.
71
+ * 解析分页卡「跳转页码」输入框的提交值。
69
72
  *
70
- * Returns the `column_set` element (plus caller appends an `hr`). Each caller
71
- * supplies its own callback cmd + extra value fields and label text (semantic
72
- * differences are preserved, not silently unified).
73
+ * 三态返回:
74
+ * - `undefined` — 未输入(空串/非字符串),调用方应回退到 `offset`(上一页/下一页)
75
+ * - `null` — 输入非法(非正整数),调用方应回错误 toast 且不刷新卡片
76
+ * - `number` — 页码换算出的 offset(页码从 1 开始)
77
+ */
78
+ export function parseJumpOffset(inputValue, pageSize) {
79
+ if (typeof inputValue !== 'string' || inputValue.trim() === '')
80
+ return undefined;
81
+ const raw = inputValue.trim();
82
+ if (!/^[0-9]+$/.test(raw))
83
+ return null;
84
+ const page = Number(raw);
85
+ if (!Number.isFinite(page) || page < 1)
86
+ return null;
87
+ const size = Number.isFinite(pageSize) && pageSize > 0 ? Math.trunc(pageSize) : 1;
88
+ return (page - 1) * size;
89
+ }
90
+ /**
91
+ * Build the CardKit 2.0 pagination block shared by /ls, /ws, /resume, /active,
92
+ * /order.
93
+ *
94
+ * 第一性原理(2026-09-10 窄屏重设计):分页栏要同时承载「页码信息」和「翻页
95
+ * 控件」两类需求。旧布局把两者塞进同一行 `column_set`(文案 weighted 4 : 输入
96
+ * weighted 2),手机窄屏下 auto 按钮先占走固有宽度,剩余宽度按 4:2 切分后文案
97
+ * 列只有百来像素、输入框只有几十像素——文案折行、输入框窄到没法点。
98
+ * 拆成两行后每一类都有足够的横向空间:
99
+ *
100
+ * 1. 页码文案独占整行(顶层 `div`),窄屏不折行;
101
+ * 2. 控件行 `column_set` = [上一页 auto] [跳转页码 input weighted] [下一页 auto],
102
+ * input 吃掉 auto 按钮之外的剩余宽度(窄屏约百来像素,桌面端更宽)。
103
+ *
104
+ * Returns an array of body elements: `[page-label div, controls column_set]`;
105
+ * 调用方展开进 `body.elements`(+ 自己的 `hr`)。input 仍留在控件 column_set
106
+ * 内部,不用 form 容器(form 触发 300123 / 200621 整卡不可用)。CardKit 2.0
107
+ * input 自带 ✓ 提交图标,提交值经 raw `action.input_value` 回传,见 connector
108
+ * includeRawEvent + router/card-action-payload.ts。
109
+ *
110
+ * 每个调用方自带 callback cmd / extra value / 文案(语义差异保留,不强行统一)。
73
111
  *
74
112
  * @param opts.cmd The pagination callback command (e.g. 'ls.page').
75
113
  * @param opts.offset Current page offset.
@@ -84,9 +122,9 @@ export function paginationBar(opts) {
84
122
  const hasNext = opts.offset + opts.pageSize < opts.total;
85
123
  const prevText = opts.prevText ?? '⬅ 上一页';
86
124
  const nextText = opts.nextText ?? '下一页 ➡';
87
- const pageColumns = [];
125
+ const controls = [];
88
126
  if (hasPrev) {
89
- pageColumns.push({
127
+ controls.push({
90
128
  tag: 'column',
91
129
  width: 'auto',
92
130
  vertical_align: 'center',
@@ -106,15 +144,30 @@ export function paginationBar(opts) {
106
144
  ],
107
145
  });
108
146
  }
109
- pageColumns.push({
147
+ // 跳转页码输入:占满 auto 按钮之外的剩余宽度(窄屏可点、桌面不局促)。
148
+ // 提交后值经 raw.action.input_value 回传,见 connector includeRawEvent +
149
+ // router/card-action-payload.ts。
150
+ controls.push({
110
151
  tag: 'column',
111
152
  width: 'weighted',
112
153
  weight: 1,
113
154
  vertical_align: 'center',
114
- elements: [{ tag: 'div', text: { tag: 'lark_md', content: opts.label } }],
155
+ elements: [
156
+ {
157
+ tag: 'input',
158
+ name: PAGE_JUMP_INPUT_NAME,
159
+ placeholder: { tag: 'plain_text', content: '跳转页码' },
160
+ behaviors: [
161
+ {
162
+ type: 'callback',
163
+ value: { cmd: opts.cmd, pageSize: opts.pageSize, ...opts.extra },
164
+ },
165
+ ],
166
+ },
167
+ ],
115
168
  });
116
169
  if (hasNext) {
117
- pageColumns.push({
170
+ controls.push({
118
171
  tag: 'column',
119
172
  width: 'auto',
120
173
  vertical_align: 'center',
@@ -134,7 +187,10 @@ export function paginationBar(opts) {
134
187
  ],
135
188
  });
136
189
  }
137
- return { tag: 'column_set', columns: pageColumns };
190
+ return [
191
+ { tag: 'div', text: { tag: 'lark_md', content: opts.label } },
192
+ { tag: 'column_set', columns: controls },
193
+ ];
138
194
  }
139
195
  /**
140
196
  * Build a session-history resume card (shared by auto-restore, /resume <id>,
@@ -2,7 +2,7 @@
2
2
  * Shared config card rendering logic.
3
3
  *
4
4
  * Builds CardKit 2.0 elements for config fields (boolean toggle, select dropdown, input).
5
- * Used by all agent config builders and the shared tabs (idle, output, logging).
5
+ * Used by all agent config builders and the shared tabs (idle, logging).
6
6
  */
7
7
  import { type AppConfig } from '../../../config/index.js';
8
8
  import type { ConfigField } from '../types.js';
@@ -2,7 +2,7 @@
2
2
  * Shared config card rendering logic.
3
3
  *
4
4
  * Builds CardKit 2.0 elements for config fields (boolean toggle, select dropdown, input).
5
- * Used by all agent config builders and the shared tabs (idle, output, logging).
5
+ * Used by all agent config builders and the shared tabs (idle, logging).
6
6
  */
7
7
  import { getConfigValue } from '../../../config/index.js';
8
8
  /** Build CardKit 2.0 elements for a list of config fields. */
@@ -0,0 +1,4 @@
1
+ import type { AppConfig } from '../config/index.js';
2
+ /** 对比原始 config 与 pendingConfig,返回变化的 key→string 映射 */
3
+ export declare function diffConfig(original: AppConfig, pending: AppConfig): Record<string, string | undefined>;
4
+ export declare function setNestedValue(target: AppConfig, key: string, value: unknown): void;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Config diff / nested-value helpers extracted from CommandRouter
3
+ * (2026-09 round-2 simplification). Pure functions — no router state —
4
+ * previously inlined as methods (collectDiff recursed only into itself).
5
+ */
6
+ import { mapAgentKey, walkNestedContainer, assertSafeKeyPart } from '../config/index.js';
7
+ /** 对比原始 config 与 pendingConfig,返回变化的 key→string 映射 */
8
+ export function diffConfig(original, pending) {
9
+ const updates = {};
10
+ collectDiff('', original, pending, updates);
11
+ return updates;
12
+ }
13
+ /** 递归收集差异 */
14
+ function collectDiff(prefix, original, pending, result) {
15
+ if (original === pending)
16
+ return;
17
+ // 如果 pending 是对象(非 null)但 original 不是对象,
18
+ // 把 original 当作空对象递归进入 pending 内部,
19
+ // 避免把整个对象转成 "[object Object]" 字符串
20
+ if (typeof pending === 'object' &&
21
+ pending !== null &&
22
+ (typeof original !== 'object' || original === null)) {
23
+ const pendObj = pending;
24
+ for (const k of Object.keys(pendObj)) {
25
+ const newKey = prefix ? `${prefix}.${k}` : k;
26
+ collectDiff(newKey, undefined, pendObj[k], result);
27
+ }
28
+ return;
29
+ }
30
+ if (typeof original !== 'object' ||
31
+ typeof pending !== 'object' ||
32
+ original === null ||
33
+ pending === null) {
34
+ // 叶子节点,记录差异
35
+ const key = prefix || 'root';
36
+ // pending 为 undefined 表示键被删除,必须保留 undefined 语义,
37
+ // 不能 String(pending) 成 "undefined"
38
+ result[key] = pending === undefined ? undefined : String(pending);
39
+ return;
40
+ }
41
+ // 两者都是对象,递归比较
42
+ const origObj = original;
43
+ const pendObj = pending;
44
+ const allKeys = new Set([...Object.keys(origObj), ...Object.keys(pendObj)]);
45
+ for (const k of allKeys) {
46
+ const newKey = prefix ? `${prefix}.${k}` : k;
47
+ collectDiff(newKey, origObj[k], pendObj[k], result);
48
+ }
49
+ }
50
+ export function setNestedValue(target, key, value) {
51
+ // Path mapping 共用 config 模块的 mapAgentKey(G11 Inconsistency 修复):
52
+ // pi.xxx/codex.xxx/opencode.xxx → agents.xxx,claude.xxx 保持顶层
53
+ const mappedKey = mapAgentKey(key);
54
+ const parts = mappedKey.split('.');
55
+ // 复用 config 模块的 walkNestedContainer(含 __proto__/prototype/constructor
56
+ // 守卫与中间段补 {}),router 只保留 value=undefined → delete 分支。
57
+ const container = walkNestedContainer(target, parts, true);
58
+ const lastPart = parts[parts.length - 1];
59
+ assertSafeKeyPart(lastPart);
60
+ if (value === undefined) {
61
+ // value=undefined 表示"删除键"(如清空 reasoningEffort),
62
+ // 不能写成 undefined 值——diffConfig 会把 undefined 转成字面量 "undefined"
63
+ // 写入 config.yaml 并透传给 codex(ReasoningEffort::Custom("undefined"))。
64
+ delete container[lastPart];
65
+ }
66
+ else {
67
+ container[lastPart] = value;
68
+ }
69
+ }
70
+ //# sourceMappingURL=config-diff.js.map
@@ -51,6 +51,11 @@ export interface CardActionPayload {
51
51
  key?: string;
52
52
  /** /ls 与 /resume 列表分页起点(条目数)。 */
53
53
  offset?: number;
54
+ /**
55
+ * `/ls` 浏览起点(本次 `/ls <dir>` 指定的目录;省略时 = cwd)。
56
+ * 卡片上的「返回」按钮回到这里,而不是回到 workspace cwd。
57
+ */
58
+ root?: string;
54
59
  /** /resume 列表的 agent 类型。 */
55
60
  agent?: string;
56
61
  /** /resume 列表页大小覆盖。 */
@@ -89,6 +94,13 @@ interface CardActionResponse {
89
94
  };
90
95
  [key: string]: unknown;
91
96
  }
97
+ /** 审批命令名清单(APPROVAL_ACTION_SPECS keys,handleCardAction 分发共用)。 */
98
+ export declare const APPROVAL_ACTION_CMDS: readonly string[];
99
+ /**
100
+ * 直返命令:点击后同步返回 toast 给飞书回调,不经队列。
101
+ * index.ts 控制层直返清单的唯一来源(勿在别处复制名单)。
102
+ */
103
+ export declare const DIRECT_RETURN_CMDS: ReadonlySet<string>;
92
104
  export declare class CommandRouter {
93
105
  /** Valid agent kinds — single source of truth for resume.use / resume.page / cmdResume. */
94
106
  static readonly VALID_AGENTS: readonly ["claude", "codex", "opencode", "pi", "kimi", "dsh"];
@@ -235,6 +247,12 @@ export declare class CommandRouter {
235
247
  * when the callback response has no `card` field).
236
248
  */
237
249
  private handleQueueInput;
250
+ /**
251
+ * 分页卡动作的 offset 解析:优先读取「跳转页码」输入框(paginationBar 内置
252
+ * 的 CardKit 2.0 input),未输入则回退 `payload.offset`(上一页/下一页按钮)。
253
+ * 非法页码返回 `{ error }`,调用方应回错误 toast 且不刷新卡片。
254
+ */
255
+ private pagingOffset;
238
256
  /**
239
257
  * Handle ls.switch: switch cwd to target directory after path validation.
240
258
  */
@@ -289,6 +307,23 @@ export declare class CommandRouter {
289
307
  orderText: string;
290
308
  internalKey: string;
291
309
  } | null;
310
+ /**
311
+ * W2.8 单源:重建 order/ws 列表卡(不投递,card 进 callback 响应体用)。
312
+ */
313
+ private rebuildListCard;
314
+ /**
315
+ * W2.8 单源:「重建列表卡 → updateCardInPlace」原地刷新骨架(列表卡删除/
316
+ * 翻页/移除/排序动作共用)。返回重建后的卡片;无卡时返回 undefined 且跳过更新。
317
+ */
318
+ private refreshListCard;
319
+ /**
320
+ * W2.8 单源:order 三个 input handler(aliasInput/aliasRemove/textInput)
321
+ * 的公共骨架——校验 orderId → reload+find → mutate → 成功后 toast + raw 卡。
322
+ * mutate 返回 error 时仅回 error toast,不重渲染。
323
+ * 注意:本 helper 只服务「toast + card 进响应体」语义(飞书需用响应体原地
324
+ * 替换 pre-click 编辑卡);updateCardInPlace 原地刷新走 refreshListCard。
325
+ */
326
+ private mutateOrderAndRefreshCard;
292
327
  /**
293
328
  * Handle order.delete: remove the order and update card in place.
294
329
  */
@@ -360,6 +395,13 @@ export declare class CommandRouter {
360
395
  * `ls.file` card button: send file to Feishu, rejecting if > 30MB.
361
396
  */
362
397
  private cardLsFile;
398
+ /**
399
+ * 校验并发送本地文件到飞书(≤30MB)。成功返回 null(文件已发出),失败返回
400
+ * 错误 CommandResult 由调用方展示。
401
+ *
402
+ * `/download` 与 `ls.file` 卡片按钮共用,避免两处重复 30MB/存在性校验。
403
+ */
404
+ private deliverFileToFeishu;
363
405
  /** 确保 pendingConfig 已初始化(从当前 config 克隆) */
364
406
  ensurePendingConfig(): void;
365
407
  /**
@@ -380,11 +422,7 @@ export declare class CommandRouter {
380
422
  /** 设置嵌套属性值(仅修改内存对象,不写盘) */
381
423
  /** 在 pendingConfig 上按 dot-separated key 设置嵌套值(config 卡片编辑用)。 */
382
424
  setNestedValue(target: AppConfig, key: string, value: unknown): void;
383
- /** 对比原始 config 与 pendingConfig,返回变化的 key→string 映射 */
384
- /** config diff(public:测试直接调用,替代 as unknown as)。 */
385
425
  diffConfig(original: AppConfig, pending: AppConfig): Record<string, string | undefined>;
386
- /** 递归收集差异 */
387
- private collectDiff;
388
426
  /**
389
427
  * config 写盘后的运行时传播(P1-6:自 config.save 卡片路径抽出,卡片保存与
390
428
  * `/config <key> <value>` 文本直写两条路径共用)。
@@ -458,8 +496,30 @@ export declare class CommandRouter {
458
496
  */
459
497
  private buildResumeActionButtons;
460
498
  private static readonly LS_PAGE_SIZE;
461
- /** /ls 实现(public:测试直接调用,替代 as unknown as)。 */
462
- cmdLs(args: string[], ctx: CommandContext, offset?: number): CommandResult;
499
+ /**
500
+ * `/ls` 实现(public:测试直接调用,替代 as unknown as)。
501
+ *
502
+ * @param args [] 列出 cwd;[path] 列出指定目录(或文件)
503
+ * @param offset 分页起点(条目数)
504
+ * @param rootDir 浏览起点:卡片「返回」按钮回到这里。省略时默认 = 本次列出的
505
+ * 目录(`/ls <dir>` 的起点即该目录),因此「返回」不会把用户
506
+ * 丢回 workspace cwd(用户明确反馈过)。
507
+ */
508
+ cmdLs(args: string[], ctx: CommandContext, offset?: number, rootDir?: string): CommandResult;
509
+ /**
510
+ * `/download <path>`(别名 `/d`):把本地文件直接发送到飞书。
511
+ *
512
+ * 路径解析与 `/ls` 一致:`~` 展开到 home;相对路径基于当前 cwd(无 cwd 时
513
+ * 必须给绝对路径)。成功时文件本身即回复,返回 null(不额外发文本)。
514
+ */
515
+ cmdDownload(args: string[], ctx: CommandContext): Promise<CommandResult | null>;
516
+ /**
517
+ * 单文件 ls 结果卡:路径 / 大小 / 修改时间 + 「下载」+「上级」。
518
+ *
519
+ * `/ls <file>` 命中普通文件时使用——用户可能想下载该文件或确认它是否存在,
520
+ * 此前直接回 `ls: xxx: Not a directory` 把文件路径当成错误处理。
521
+ */
522
+ private buildFileCard;
463
523
  private cmdWs;
464
524
  /**
465
525
  * L3: degraded card when a session's export is non-empty but unparseable