lark-remote 0.1.0

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 (201) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +162 -0
  4. package/README.md +161 -0
  5. package/dist/binder.d.ts +57 -0
  6. package/dist/binder.js +105 -0
  7. package/dist/bridge/index.d.ts +338 -0
  8. package/dist/bridge/index.js +1281 -0
  9. package/dist/bridge/queue-manager.d.ts +277 -0
  10. package/dist/bridge/queue-manager.js +729 -0
  11. package/dist/card/bash-card-session.d.ts +78 -0
  12. package/dist/card/bash-card-session.js +174 -0
  13. package/dist/card/bash-renderer.d.ts +24 -0
  14. package/dist/card/bash-renderer.js +187 -0
  15. package/dist/card/card-budget.d.ts +31 -0
  16. package/dist/card/card-budget.js +280 -0
  17. package/dist/card/card-session.d.ts +83 -0
  18. package/dist/card/card-session.js +185 -0
  19. package/dist/card/card-shared.d.ts +28 -0
  20. package/dist/card/card-shared.js +99 -0
  21. package/dist/card/collapsible.d.ts +26 -0
  22. package/dist/card/collapsible.js +87 -0
  23. package/dist/card/run-card-session.d.ts +78 -0
  24. package/dist/card/run-card-session.js +165 -0
  25. package/dist/card/run-renderer.d.ts +66 -0
  26. package/dist/card/run-renderer.js +841 -0
  27. package/dist/card/run-state.d.ts +103 -0
  28. package/dist/card/run-state.js +313 -0
  29. package/dist/card/text-truncate.d.ts +56 -0
  30. package/dist/card/text-truncate.js +184 -0
  31. package/dist/card/time.d.ts +1 -0
  32. package/dist/card/time.js +14 -0
  33. package/dist/card/tool-render.d.ts +25 -0
  34. package/dist/card/tool-render.js +176 -0
  35. package/dist/cli.d.ts +28 -0
  36. package/dist/cli.js +89 -0
  37. package/dist/common/guards.d.ts +37 -0
  38. package/dist/common/guards.js +65 -0
  39. package/dist/config/codex-config.d.ts +113 -0
  40. package/dist/config/codex-config.js +428 -0
  41. package/dist/config/dir.d.ts +17 -0
  42. package/dist/config/dir.js +81 -0
  43. package/dist/config/index.d.ts +219 -0
  44. package/dist/config/index.js +388 -0
  45. package/dist/config/kimi-config.d.ts +33 -0
  46. package/dist/config/kimi-config.js +111 -0
  47. package/dist/config/opencode-config.d.ts +20 -0
  48. package/dist/config/opencode-config.js +124 -0
  49. package/dist/config/pi-config.d.ts +49 -0
  50. package/dist/config/pi-config.js +151 -0
  51. package/dist/config/wizard.d.ts +12 -0
  52. package/dist/config/wizard.js +84 -0
  53. package/dist/connector/file-limits.d.ts +7 -0
  54. package/dist/connector/file-limits.js +8 -0
  55. package/dist/connector/index.d.ts +86 -0
  56. package/dist/connector/index.js +340 -0
  57. package/dist/error-classification.d.ts +15 -0
  58. package/dist/error-classification.js +24 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +580 -0
  61. package/dist/instance-lock.d.ts +30 -0
  62. package/dist/instance-lock.js +184 -0
  63. package/dist/logger/index.d.ts +57 -0
  64. package/dist/logger/index.js +178 -0
  65. package/dist/order/index.d.ts +27 -0
  66. package/dist/order/index.js +90 -0
  67. package/dist/persistence/atomic-write.d.ts +10 -0
  68. package/dist/persistence/atomic-write.js +65 -0
  69. package/dist/persistence/load-json-file.d.ts +9 -0
  70. package/dist/persistence/load-json-file.js +23 -0
  71. package/dist/restart.d.ts +24 -0
  72. package/dist/restart.js +73 -0
  73. package/dist/router/card-helpers.d.ts +28 -0
  74. package/dist/router/card-helpers.js +65 -0
  75. package/dist/router/config/claude.d.ts +14 -0
  76. package/dist/router/config/claude.js +72 -0
  77. package/dist/router/config/codex.d.ts +22 -0
  78. package/dist/router/config/codex.js +100 -0
  79. package/dist/router/config/common/render.d.ts +16 -0
  80. package/dist/router/config/common/render.js +158 -0
  81. package/dist/router/config/index.d.ts +18 -0
  82. package/dist/router/config/index.js +38 -0
  83. package/dist/router/config/kimi.d.ts +21 -0
  84. package/dist/router/config/kimi.js +63 -0
  85. package/dist/router/config/opencode.d.ts +12 -0
  86. package/dist/router/config/opencode.js +44 -0
  87. package/dist/router/config/pi.d.ts +12 -0
  88. package/dist/router/config/pi.js +50 -0
  89. package/dist/router/config/types.d.ts +43 -0
  90. package/dist/router/config/types.js +8 -0
  91. package/dist/router/index.d.ts +318 -0
  92. package/dist/router/index.js +2715 -0
  93. package/dist/router/order-exec-dispatch.d.ts +30 -0
  94. package/dist/router/order-exec-dispatch.js +48 -0
  95. package/dist/router/utils.d.ts +44 -0
  96. package/dist/router/utils.js +116 -0
  97. package/dist/runner/bash/index.d.ts +4 -0
  98. package/dist/runner/bash/index.js +5 -0
  99. package/dist/runner/bash/runner.d.ts +55 -0
  100. package/dist/runner/bash/runner.js +213 -0
  101. package/dist/runner/claude/index.d.ts +4 -0
  102. package/dist/runner/claude/index.js +5 -0
  103. package/dist/runner/claude/runner.d.ts +29 -0
  104. package/dist/runner/claude/runner.js +83 -0
  105. package/dist/runner/codex/argv.d.ts +33 -0
  106. package/dist/runner/codex/argv.js +40 -0
  107. package/dist/runner/codex/index.d.ts +1 -0
  108. package/dist/runner/codex/index.js +2 -0
  109. package/dist/runner/codex/jsonl.d.ts +37 -0
  110. package/dist/runner/codex/jsonl.js +221 -0
  111. package/dist/runner/codex/runner.d.ts +65 -0
  112. package/dist/runner/codex/runner.js +124 -0
  113. package/dist/runner/common/exec-translator.d.ts +73 -0
  114. package/dist/runner/common/exec-translator.js +105 -0
  115. package/dist/runner/common/jsonl-stream.d.ts +39 -0
  116. package/dist/runner/common/jsonl-stream.js +203 -0
  117. package/dist/runner/common/process-stopper.d.ts +28 -0
  118. package/dist/runner/common/process-stopper.js +79 -0
  119. package/dist/runner/common/runner-utils.d.ts +21 -0
  120. package/dist/runner/common/runner-utils.js +65 -0
  121. package/dist/runner/common/spawn-heartbeat.d.ts +33 -0
  122. package/dist/runner/common/spawn-heartbeat.js +51 -0
  123. package/dist/runner/common/spawning-runner.d.ts +321 -0
  124. package/dist/runner/common/spawning-runner.js +634 -0
  125. package/dist/runner/common/usage.d.ts +31 -0
  126. package/dist/runner/common/usage.js +29 -0
  127. package/dist/runner/index.d.ts +19 -0
  128. package/dist/runner/index.js +24 -0
  129. package/dist/runner/kimi/index.d.ts +1 -0
  130. package/dist/runner/kimi/index.js +2 -0
  131. package/dist/runner/kimi/jsonl.d.ts +28 -0
  132. package/dist/runner/kimi/jsonl.js +143 -0
  133. package/dist/runner/kimi/runner.d.ts +50 -0
  134. package/dist/runner/kimi/runner.js +105 -0
  135. package/dist/runner/opencode/argv.d.ts +32 -0
  136. package/dist/runner/opencode/argv.js +35 -0
  137. package/dist/runner/opencode/index.d.ts +1 -0
  138. package/dist/runner/opencode/index.js +2 -0
  139. package/dist/runner/opencode/jsonl.d.ts +68 -0
  140. package/dist/runner/opencode/jsonl.js +295 -0
  141. package/dist/runner/opencode/runner.d.ts +63 -0
  142. package/dist/runner/opencode/runner.js +93 -0
  143. package/dist/runner/pi/index.d.ts +1 -0
  144. package/dist/runner/pi/index.js +2 -0
  145. package/dist/runner/pi/jsonl.d.ts +128 -0
  146. package/dist/runner/pi/jsonl.js +249 -0
  147. package/dist/runner/pi/runner.d.ts +37 -0
  148. package/dist/runner/pi/runner.js +76 -0
  149. package/dist/runner/registry.d.ts +54 -0
  150. package/dist/runner/registry.js +75 -0
  151. package/dist/runner/resolve-agent-choices.d.ts +7 -0
  152. package/dist/runner/resolve-agent-choices.js +76 -0
  153. package/dist/runner/sync-agent-choices.d.ts +6 -0
  154. package/dist/runner/sync-agent-choices.js +73 -0
  155. package/dist/runner/types.d.ts +250 -0
  156. package/dist/runner/types.js +8 -0
  157. package/dist/session/claude/index.d.ts +1 -0
  158. package/dist/session/claude/index.js +2 -0
  159. package/dist/session/claude/session-reader.d.ts +34 -0
  160. package/dist/session/claude/session-reader.js +46 -0
  161. package/dist/session/claude/sessions.d.ts +53 -0
  162. package/dist/session/claude/sessions.js +528 -0
  163. package/dist/session/codex/index.d.ts +1 -0
  164. package/dist/session/codex/index.js +2 -0
  165. package/dist/session/codex/rollout-reader.d.ts +88 -0
  166. package/dist/session/codex/rollout-reader.js +473 -0
  167. package/dist/session/codex/sessions.d.ts +21 -0
  168. package/dist/session/codex/sessions.js +40 -0
  169. package/dist/session/common/catch-up.d.ts +12 -0
  170. package/dist/session/common/catch-up.js +31 -0
  171. package/dist/session/common/constants.d.ts +11 -0
  172. package/dist/session/common/constants.js +12 -0
  173. package/dist/session/common/content-blocks.d.ts +37 -0
  174. package/dist/session/common/content-blocks.js +68 -0
  175. package/dist/session/common/jsonl.d.ts +77 -0
  176. package/dist/session/common/jsonl.js +351 -0
  177. package/dist/session/common/usage-accumulator.d.ts +58 -0
  178. package/dist/session/common/usage-accumulator.js +72 -0
  179. package/dist/session/index.d.ts +7 -0
  180. package/dist/session/index.js +11 -0
  181. package/dist/session/kimi/index.d.ts +1 -0
  182. package/dist/session/kimi/index.js +2 -0
  183. package/dist/session/kimi/sessions.d.ts +81 -0
  184. package/dist/session/kimi/sessions.js +527 -0
  185. package/dist/session/opencode/index.d.ts +1 -0
  186. package/dist/session/opencode/index.js +2 -0
  187. package/dist/session/opencode/sessions.d.ts +81 -0
  188. package/dist/session/opencode/sessions.js +388 -0
  189. package/dist/session/pi/index.d.ts +1 -0
  190. package/dist/session/pi/index.js +2 -0
  191. package/dist/session/pi/sessions.d.ts +27 -0
  192. package/dist/session/pi/sessions.js +399 -0
  193. package/dist/session/registry.d.ts +12 -0
  194. package/dist/session/registry.js +20 -0
  195. package/dist/session/session-store.d.ts +86 -0
  196. package/dist/session/session-store.js +450 -0
  197. package/dist/startup-contact.d.ts +18 -0
  198. package/dist/startup-contact.js +51 -0
  199. package/dist/workspace/index.d.ts +19 -0
  200. package/dist/workspace/index.js +53 -0
  201. package/package.json +93 -0
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Kimi config builder — builds fields and handles field changes for Kimi agent.
3
+ */
4
+ import { loadKimiConfig, KIMI_THINKING_EFFORTS, FALLBACK_EFFORTS, } from '../../config/kimi-config.js';
5
+ export class KimiConfigBuilder {
6
+ buildFields(displayConfig) {
7
+ const fields = [];
8
+ // Kimi 配置字段 - 动态从 `kimi provider list --json` 获取模型列表
9
+ const kimiCfg = loadKimiConfig();
10
+ const currentModel = displayConfig.agents?.kimi?.model ?? kimiCfg.currentModel;
11
+ const currentThinking = displayConfig.agents?.kimi?.thinkingEffort ?? 'max';
12
+ fields.push({
13
+ key: 'agents.kimi.model',
14
+ label: '使用模型',
15
+ type: 'select',
16
+ options: kimiCfg.modelOptions,
17
+ currentValue: currentModel,
18
+ });
19
+ fields.push({
20
+ key: 'agents.kimi.thinkingEffort',
21
+ label: '推理强度',
22
+ type: 'select',
23
+ // Layer 3: Double-defense filter - ensure only valid options show in UI
24
+ // (Layer 2 already filters, but this is the last line of defense)
25
+ options: (kimiCfg.modelEfforts[currentModel] ?? [...FALLBACK_EFFORTS]).filter((e) => KIMI_THINKING_EFFORTS.includes(e)),
26
+ currentValue: currentThinking,
27
+ });
28
+ return fields;
29
+ }
30
+ handleFieldChange(key, value, config) {
31
+ const patches = [{ key, value }];
32
+ // model 变更时,若当前档位不被新模型支持,重置到新模型支持的合法档位
33
+ if (key === 'agents.kimi.model' && typeof value === 'string') {
34
+ const effortPatch = this.thinkingEffortPatchForModel(config, value);
35
+ if (effortPatch)
36
+ patches.push(effortPatch);
37
+ }
38
+ return patches;
39
+ }
40
+ /**
41
+ * 切到 newModel 后的档位补丁(参照 codex effortPatchForModel 语义):
42
+ * - 当前档位仍被新模型支持 → 不产出补丁;
43
+ * - 否则优先 modelEfforts[newModel] 中位 (len-1)/2;
44
+ * - 列表为空才用 modelDefaultEfforts[newModel];
45
+ * - 两者皆无 → FALLBACK_EFFORTS 中位;仍无则 undefined(router setNestedValue
46
+ * 对 undefined 做键删除)。
47
+ */
48
+ thinkingEffortPatchForModel(config, newModel) {
49
+ const kimiCfg = loadKimiConfig();
50
+ const currentEffort = config.agents?.kimi?.thinkingEffort;
51
+ const supported = kimiCfg.modelEfforts[newModel] ?? [...FALLBACK_EFFORTS];
52
+ if (currentEffort && supported.includes(currentEffort))
53
+ return null;
54
+ const middle = supported[Math.floor((supported.length - 1) / 2)];
55
+ let newEffort = middle;
56
+ if (!newEffort)
57
+ newEffort = kimiCfg.modelDefaultEfforts?.[newModel];
58
+ if (!newEffort)
59
+ newEffort = FALLBACK_EFFORTS[Math.floor((FALLBACK_EFFORTS.length - 1) / 2)];
60
+ return { key: 'agents.kimi.thinkingEffort', value: newEffort };
61
+ }
62
+ }
63
+ //# sourceMappingURL=kimi.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * OpenCode config builder — builds fields and handles field changes for OpenCode agent.
3
+ */
4
+ import type { AgentConfigCardBuilder, ConfigField } from './types.js';
5
+ import type { AppConfig } from '../../config/index.js';
6
+ export declare class OpencodeConfigBuilder implements AgentConfigCardBuilder {
7
+ buildFields(displayConfig: AppConfig): ConfigField[];
8
+ handleFieldChange(key: string, value: unknown, config: AppConfig): Array<{
9
+ key: string;
10
+ value: unknown;
11
+ }>;
12
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * OpenCode config builder — builds fields and handles field changes for OpenCode agent.
3
+ */
4
+ import { loadOpencodeConfig } from '../../config/opencode-config.js';
5
+ export class OpencodeConfigBuilder {
6
+ buildFields(displayConfig) {
7
+ const fields = [];
8
+ // 从 opencode models 命令动态读取 provider 和 model
9
+ const opencodeCfg = loadOpencodeConfig();
10
+ const providerNames = opencodeCfg.providerNames;
11
+ // 根据 displayConfig 中已选的 provider 过滤 model 选项
12
+ const currentProvider = displayConfig.agents?.opencode?.providerID;
13
+ const modelOptions = opencodeCfg.modelOptions(currentProvider);
14
+ fields.push({
15
+ key: 'agents.opencode.providerID',
16
+ label: 'Provider',
17
+ type: 'select',
18
+ options: providerNames,
19
+ });
20
+ fields.push({
21
+ key: 'agents.opencode.modelID',
22
+ label: '使用模型',
23
+ type: 'select',
24
+ options: modelOptions,
25
+ });
26
+ return fields;
27
+ }
28
+ handleFieldChange(key, value, config) {
29
+ const patches = [];
30
+ patches.push({ key, value });
31
+ // provider 变更时,重置 model 为新 provider 的首个模型
32
+ if (key === 'agents.opencode.providerID' && typeof value === 'string') {
33
+ const opencodeCfg = loadOpencodeConfig();
34
+ const newModelOptions = opencodeCfg.modelOptions(value);
35
+ const currentModel = config.agents?.opencode?.modelID;
36
+ const currentModelIsValid = newModelOptions.some((m) => m === currentModel);
37
+ if (!currentModelIsValid && newModelOptions.length > 0) {
38
+ patches.push({ key: 'agents.opencode.modelID', value: newModelOptions[0] });
39
+ }
40
+ }
41
+ return patches;
42
+ }
43
+ }
44
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pi config builder — builds fields and handles field changes for Pi agent.
3
+ */
4
+ import type { AgentConfigCardBuilder, ConfigField } from './types.js';
5
+ import type { AppConfig } from '../../config/index.js';
6
+ export declare class PiConfigBuilder implements AgentConfigCardBuilder {
7
+ buildFields(displayConfig: AppConfig): ConfigField[];
8
+ handleFieldChange(key: string, value: unknown, config: AppConfig): Array<{
9
+ key: string;
10
+ value: unknown;
11
+ }>;
12
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Pi config builder — builds fields and handles field changes for Pi agent.
3
+ */
4
+ import { loadPiConfig, getPiModelOptions } from '../../config/pi-config.js';
5
+ import { PI_THINKING_LEVELS } from '../../config/index.js';
6
+ export class PiConfigBuilder {
7
+ buildFields(displayConfig) {
8
+ const fields = [];
9
+ const piCfg = loadPiConfig();
10
+ const providerOptions = piCfg.providerNames;
11
+ // 根据 displayConfig 中已选的 provider 过滤 model 选项
12
+ const currentProvider = displayConfig.agents?.pi?.provider;
13
+ const modelOptions = piCfg.modelOptions(currentProvider);
14
+ fields.push({
15
+ key: 'agents.pi.provider',
16
+ label: 'Pi Provider',
17
+ type: 'select',
18
+ options: providerOptions,
19
+ });
20
+ fields.push({
21
+ key: 'agents.pi.model',
22
+ label: '使用模型',
23
+ type: 'select',
24
+ options: modelOptions,
25
+ });
26
+ fields.push({
27
+ key: 'agents.pi.thinking',
28
+ label: '思考级别',
29
+ type: 'select',
30
+ // Use constant for thinking options (SSOT)
31
+ options: PI_THINKING_LEVELS,
32
+ });
33
+ return fields;
34
+ }
35
+ handleFieldChange(key, value, config) {
36
+ const patches = [];
37
+ patches.push({ key, value });
38
+ // provider 变更时,重置 model 为新 provider 的首个模型
39
+ if (key === 'agents.pi.provider' && typeof value === 'string') {
40
+ const newModelOptions = getPiModelOptions(value);
41
+ const currentModel = config.agents?.pi?.model;
42
+ const currentModelIsValid = newModelOptions.some((m) => m === currentModel);
43
+ if (!currentModelIsValid && newModelOptions.length > 0) {
44
+ patches.push({ key: 'agents.pi.model', value: newModelOptions[0] });
45
+ }
46
+ }
47
+ return patches;
48
+ }
49
+ }
50
+ //# sourceMappingURL=pi.js.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Config card builder interface — per-agent contract for /config card fields.
3
+ *
4
+ * Each agent implements this to declare its own config fields and change handlers.
5
+ * The router delegates to `getConfigBuilder(agent)` instead of a giant switch-case.
6
+ */
7
+ import type { AppConfig } from '../../config/index.js';
8
+ /** A single field descriptor in the /config card. */
9
+ export interface ConfigField {
10
+ key: string;
11
+ label: string;
12
+ type: 'boolean' | 'select' | 'input';
13
+ /** For select type: the list of options shown in the dropdown. */
14
+ options?: readonly string[];
15
+ /** Override the currentValue shown in the card (takes priority over getConfigValue). */
16
+ currentValue?: string | boolean;
17
+ }
18
+ /**
19
+ * Builder that provides config fields and handles field changes for a specific agent.
20
+ *
21
+ * Lifecycle:
22
+ * 1. `buildFields()` is called when the card is rendered (on open, on save, on any field change).
23
+ * 2. `handleFieldChange()` is called when a config.set or config.input modifies a field
24
+ * that belongs to this agent. It returns a list of {key, value} patches to apply
25
+ * to pendingConfig (side-effect-free: the caller applies the patches).
26
+ */
27
+ export interface AgentConfigCardBuilder {
28
+ /** Build config fields for this agent, given the current display config. */
29
+ buildFields(displayConfig: AppConfig): ConfigField[];
30
+ /**
31
+ * Handle a field change for this agent.
32
+ *
33
+ * @param key - The field key (e.g. 'agents.codex.modelProvider')
34
+ * @param value - The new value (string for select/input, already toggled for boolean)
35
+ * @param config - The current pendingConfig (read-only reference for deriving dependent values)
36
+ * @returns An array of {key, value} patches to apply to pendingConfig.
37
+ * The caller (router) applies these via setNestedValue.
38
+ */
39
+ handleFieldChange(key: string, value: unknown, config: AppConfig): Array<{
40
+ key: string;
41
+ value: unknown;
42
+ }>;
43
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Config card builder interface — per-agent contract for /config card fields.
3
+ *
4
+ * Each agent implements this to declare its own config fields and change handlers.
5
+ * The router delegates to `getConfigBuilder(agent)` instead of a giant switch-case.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,318 @@
1
+ import type { SessionStore, SessionReaderRegistry } from '../session/index.js';
2
+ import type { AppConfig } from '../config/index.js';
3
+ import type { Bridge } from '../bridge/index.js';
4
+ import type { AgentBinding } from '../bridge/queue-manager.js';
5
+ interface CommandContext {
6
+ userId: string;
7
+ chatId: string;
8
+ messageId: string;
9
+ }
10
+ interface CommandResult {
11
+ text?: string;
12
+ markdown?: string;
13
+ card?: object;
14
+ }
15
+ /**
16
+ * Card-action commands that must run with enqueue({ immediate: true }).
17
+ * These bypass the serial queue and execute immediately.
18
+ *
19
+ * ws.use — /ws list card "使用 <name>"
20
+ * queue.immediate — queue card "立即执行" button (§9.6)
21
+ * queue.cancel — queue card "撤销" button
22
+ * queue.diagnose — queue card "诊断" button
23
+ *
24
+ * §9.19: Extended to cover all control-only actions that never spawn Claude:
25
+ * new-session — clear sessionId only
26
+ * stop — interrupt current run
27
+ * ls.file — send file only
28
+ * ws.remove — delete workspace alias only
29
+ * resume.use — set sessionId only
30
+ * help.* — read-only help commands
31
+ * order.delete — delete order only
32
+ * order.exec is intercepted by index.ts at the enqueue boundary
33
+ * (resolveOrderExecForQueue → router.handle), never reaching this dispatcher.
34
+ */
35
+ export declare function isImmediateAction(cmd: string): boolean;
36
+ /** Payload carried by a card button click. */
37
+ export interface CardActionPayload {
38
+ cmd: string;
39
+ path?: string;
40
+ name?: string;
41
+ runId?: string;
42
+ sessionId?: string;
43
+ cwd?: string;
44
+ workspace?: string;
45
+ messageId?: string;
46
+ userId?: string;
47
+ chatId?: string;
48
+ key?: string;
49
+ /** /ls 与 /resume 列表分页起点(条目数)。 */
50
+ offset?: number;
51
+ /** /resume 列表的 agent 类型。 */
52
+ agent?: string;
53
+ /** /resume 列表页大小覆盖。 */
54
+ pageSize?: number;
55
+ option?: string;
56
+ formValue?: Record<string, unknown>;
57
+ /** CardKit 2.0 input 组件自带提交图标触发回调时回传的输入值 */
58
+ inputValue?: string;
59
+ orderId?: string;
60
+ }
61
+ /**
62
+ * Response a cardAction handler may return to give the clicking user native
63
+ * immediate feedback (mirrors the SDK's CardActionResponse, passed through by
64
+ * the connector). Currently only `toast` is used. Returning void/undefined
65
+ * means "no immediate response" (original behavior). The index signature
66
+ * keeps it assignable to the SDK's loose `Record<string, unknown>`.
67
+ */
68
+ interface CardActionResponse {
69
+ toast?: {
70
+ type: 'success' | 'info' | 'error' | 'warning' | 'loading';
71
+ content: string;
72
+ };
73
+ [key: string]: unknown;
74
+ }
75
+ export declare class CommandRouter {
76
+ private sessionStore;
77
+ private bridge;
78
+ private config;
79
+ private configPath;
80
+ private workspaceStore;
81
+ private orderStore;
82
+ private exitHandler;
83
+ private pendingExit;
84
+ /**
85
+ * Spawns the detached replacement bridge process (same argv/config dir) and
86
+ * returns its pid. Injected from index.ts; /restart is unavailable without it.
87
+ */
88
+ private restartSpawner?;
89
+ private idleTimeoutMs;
90
+ private pendingConfig;
91
+ /**
92
+ * Monotonic counter minting unique internal keys for order.exec enqueue
93
+ * actions. One order card can be clicked many times, so the Feishu card
94
+ * messageId is 1:N with enqueue actions and must not be reused as the queue
95
+ * dedup key. Date.now() alone is unsafe (two synchronous calls can share a
96
+ * millisecond); the counter guarantees uniqueness regardless of timing.
97
+ */
98
+ private orderExecKeyCounter;
99
+ /**
100
+ * Session reader registry for multi-agent path. Resolves the right
101
+ * reader by `config.defaultAgent` (and per-agent override params).
102
+ * NOTE: `/config` card's `defaultAgent` selector does NOT use this —
103
+ * it uses `listRegisteredAgents()` from `router/config/index.ts` (the
104
+ * config-builder registry), which mirrors the agents with a config card.
105
+ */
106
+ private sessionReaderRegistry;
107
+ /**
108
+ * 串行化 config.* 卡片回调(2026-07-04)。
109
+ * CardKit 2.0 input/button 回调经 `enqueueImmediate` 分发,**不进串行队列**,
110
+ * 多次快速点击 toggle/input 会并发读写 `pendingConfig` 并同时调
111
+ * `updateCardInPlace` → Feishu API 乱序到达,导致 toggle 卡死在某个状态。
112
+ * 此 Promise chain 把所有 config.* 动作串成一个执行链,保证后到的动作
113
+ * 等前一个动作的卡片 patch 完成后再读 `pendingConfig`。
114
+ */
115
+ private configActionQueue;
116
+ constructor(opts: {
117
+ sessionStore: SessionStore;
118
+ bridge: Bridge;
119
+ config: AppConfig;
120
+ configPath: string;
121
+ workspacePath?: string;
122
+ ordersPath?: string;
123
+ exitHandler?: () => void;
124
+ /** Spawn the detached replacement bridge process and return its pid (throws on failure). */
125
+ restartSpawner?: () => number;
126
+ idleTimeoutMs?: number;
127
+ /** Session reader registry (required). */
128
+ sessionReaderRegistry: SessionReaderRegistry;
129
+ });
130
+ /**
131
+ * Resolve the active session reader for the current defaultAgent.
132
+ * The reader is fetched from the registry each time to reflect config changes.
133
+ */
134
+ private get sessionReader();
135
+ /**
136
+ * Route a message: if it starts with /, handle as command; if it starts with !, execute as bash; otherwise forward to Claude.
137
+ */
138
+ handle(message: string, ctx: CommandContext, opts?: {
139
+ cwdOverride?: string;
140
+ binding?: AgentBinding;
141
+ }): Promise<CommandResult | null>;
142
+ /**
143
+ * Handle a CardKit card button click (§6.2).
144
+ * Validates payload and dispatches to the corresponding command.
145
+ */
146
+ handleCardAction(value: CardActionPayload, ctx: CommandContext): Promise<CardActionResponse | void>;
147
+ /**
148
+ * Handle queue.cancel: remove this message from the queue.
149
+ */
150
+ private handleQueueCancel;
151
+ /**
152
+ * Handle queue.immediate: stop current run, clear queue before this message, execute this message immediately.
153
+ * Instead of asking user to resend, we keep the target task in queue and let it execute.
154
+ */
155
+ private handleQueueImmediate;
156
+ /**
157
+ * Handle queue.diagnose: show diagnostic info for why message is queuing.
158
+ */
159
+ private handleQueueDiagnose;
160
+ /**
161
+ * Handle queue.edit: show input field for editing the queued message.
162
+ */
163
+ private handleQueueEdit;
164
+ /**
165
+ * Handle queue.input: update the queued message with new content.
166
+ * Returns a CardActionResponse carrying both a toast (immediate feedback,
167
+ * no separate message sent) and a `card` field so Feishu renders the
168
+ * updated queue card in place, closing the edit form. A toast-only response
169
+ * leaves the card stuck in the edit state (Feishu keeps the pre-click card
170
+ * when the callback response has no `card` field).
171
+ */
172
+ private handleQueueInput;
173
+ /**
174
+ * Handle ls.switch: switch cwd to target directory after path validation.
175
+ */
176
+ private handleLsSwitch;
177
+ /**
178
+ * Handle ls.refresh: reload current directory.
179
+ */
180
+ private handleLsRefresh;
181
+ /**
182
+ * Handle ls.page: paginate to a specific offset.
183
+ */
184
+ private handleLsPage;
185
+ /**
186
+ * Handle resume.page: paginate the /resume session list in place.
187
+ * Mirrors handleLsPage — updates the same card, never sends a new one.
188
+ */
189
+ private handleResumePage;
190
+ /**
191
+ * Handle ls.browse: browse directory without switching cwd.
192
+ */
193
+ private handleLsBrowse;
194
+ /**
195
+ * Handle stop card action: interrupt current run.
196
+ */
197
+ private handleCardStop;
198
+ /**
199
+ * Resolve an order's text at the enqueue boundary so order.exec can enter
200
+ * the serial queue as an equivalent user message (Plan A) — the same path a
201
+ * hand-typed message takes. index.ts calls this before bridge.enqueue and
202
+ * uses the returned `orderText` as the queue messagePreview / edit
203
+ * default_value, and `internalKey` as the queue dedup key.
204
+ *
205
+ * Why an internal key instead of the Feishu card messageId: one order card
206
+ * can be clicked many times, so the card messageId is 1:N with enqueue
207
+ * actions. Reusing it collides queuedTasks / queueCardMessages lookups.
208
+ * Each call therefore mints a unique key (the Feishu messageId still flows
209
+ * through ctx for replies/reactions — the two concerns are separate).
210
+ *
211
+ * `updateUsedAt` runs here, at resolve time, so the usage timestamp
212
+ * survives even an immediate crash before the queued task ever runs
213
+ * (preserves the H3 crash-safe property previously held by handleOrderExec,
214
+ * which recorded it right before forwardToClaude).
215
+ *
216
+ * Returns null when the order no longer exists; index.ts surfaces the error.
217
+ */
218
+ resolveOrderExecForQueue(orderId: string): {
219
+ orderText: string;
220
+ internalKey: string;
221
+ } | null;
222
+ /**
223
+ * Handle order.delete: remove the order and update card in place.
224
+ */
225
+ private handleOrderDelete;
226
+ /**
227
+ * Handle ws.remove: remove the workspace alias and refresh the /ws list card
228
+ * in place (mirrors handleOrderDelete). Without this the stale alias would
229
+ * remain visible on the card the user just clicked.
230
+ */
231
+ private handleWsRemove;
232
+ /**
233
+ * `ls.file` card button: send file to Feishu, rejecting if > 30MB.
234
+ */
235
+ private cardLsFile;
236
+ /** 确保 pendingConfig 已初始化(从当前 config 克隆) */
237
+ private ensurePendingConfig;
238
+ /**
239
+ * 串行化 config.* 卡片回调(2026-07-04 修复 toggle 卡死 bug)。
240
+ *
241
+ * CardKit 2.0 input/button 回调经 `enqueueImmediate` 分发,不进 bridge 的
242
+ * 串行队列;多次快速点击 toggle 会并发读写 `pendingConfig` 并同时调
243
+ * `updateCardInPlace` → 两个 patch 请求乱序到达飞书,后到达的 patch(点击 1
244
+ * 的旧卡片)覆盖先到达的 patch(点击 2 的新卡片),用户看到 toggle 卡死。
245
+ *
246
+ * 此方法把所有 config.* 动作串成一个 Promise chain:每个动作等前一个动作
247
+ * 的 `updateCardInPlace` 完全 settle 后再读 `pendingConfig`。
248
+ */
249
+ private enqueueConfigAction;
250
+ /** 实际的 config.* 分发逻辑(在串行队列内执行) */
251
+ private dispatchConfigAction;
252
+ /** 设置嵌套属性值(仅修改内存对象,不写盘) */
253
+ private setNestedValue;
254
+ /** 对比原始 config 与 pendingConfig,返回变化的 key→string 映射 */
255
+ private diffConfig;
256
+ /** 递归收集差异 */
257
+ private collectDiff;
258
+ /**
259
+ * config 写盘后的运行时传播(P1-6:自 config.save 卡片路径抽出,卡片保存与
260
+ * `/config <key> <value>` 文本直写两条路径共用)。
261
+ *
262
+ * 1. bridge 运行时值同步:setConfig + idle watchdog timeout;
263
+ * 2. agent 配置或 defaultAgent 变更 → clearRunners(否则 runner 缓存继续用旧
264
+ * 配置值,/status 与真实 run 自相矛盾);
265
+ * 3. defaultAgent 切换 → 旧 agent session 存 previousSessions、新 agent 恢复
266
+ * 或清空(等效 /new);
267
+ * 4. 当前 agent 配置变更 → syncAgentChoices 并原子写盘(P1-7:禁裸同步写盘,
268
+ * 写一半崩溃会截断 config.yaml 导致 bridge 起不来)。
269
+ *
270
+ * @param updates 以 config 路径形式给出的变更 key(卡片路径来自 diffConfig;
271
+ * 直写路径传 mapAgentKey(key),保证 pi./codex./opencode./kimi. 命中 agents.*)。
272
+ * @returns defaultAgent 切换时的通知文案(未切换返回 undefined)
273
+ */
274
+ private propagateConfigSave;
275
+ private executeCommand;
276
+ private cmdHelp;
277
+ private cmdStatus;
278
+ private cmdPs;
279
+ private cmdStop;
280
+ private cmdExit;
281
+ private cmdRestart;
282
+ private cmdNew;
283
+ private cmdCd;
284
+ private readSessionDisplayState;
285
+ /**
286
+ * Shared logic for switching cwd with user feedback.
287
+ * Used by cmdCd, cmdWs use, and handleLsSwitch to ensure consistent behavior:
288
+ * 1. Set cwd (and clear sessionId per §9.1)
289
+ * 2. Auto-resume newest session if available
290
+ * 3. Return appropriate CommandResult (auto-resume card or plain text)
291
+ */
292
+ private switchCwdAndNotify;
293
+ /** Build card for auto-resumed session with new session button */
294
+ private buildAutoResumeCard;
295
+ private static readonly LS_PAGE_SIZE;
296
+ private cmdLs;
297
+ private cmdWs;
298
+ /**
299
+ * L3: degraded card when a session's export is non-empty but unparseable
300
+ * (truncated by opencode's pipe cap on huge sessions, or otherwise corrupt).
301
+ * The session exists, so reuse listSessions metadata (title) instead of the
302
+ * misleading "未找到". Reuses the same card-builder helpers (markdownDiv) as
303
+ * the normal resume card; enforceCardBudget still applies at send time.
304
+ */
305
+ private cmdResume;
306
+ private cmdActive;
307
+ /**
308
+ * Build CardKit 2.0 /active card from bridge memory (not file system).
309
+ * Shows only runs that were started by THIS bridge process.
310
+ */
311
+ private buildActiveCardFromMemory;
312
+ private cmdReconnect;
313
+ private cmdConfig;
314
+ /** Build an interactive config card with CardKit 2.0 tabs + batch save */
315
+ private buildConfigCard;
316
+ private cmdOrder;
317
+ }
318
+ export { formatUsageStats } from './utils.js';