lark-remote 0.1.6 → 0.1.8

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 (216) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.en.md +9 -1
  3. package/README.md +14 -2
  4. package/dist/bridge/approval-coordinator.d.ts +71 -34
  5. package/dist/bridge/approval-coordinator.js +225 -41
  6. package/dist/bridge/inbound-media.d.ts +62 -0
  7. package/dist/bridge/inbound-media.js +282 -0
  8. package/dist/bridge/index.d.ts +97 -13
  9. package/dist/bridge/index.js +227 -87
  10. package/dist/bridge/queue-manager.d.ts +2 -1
  11. package/dist/bridge/queue-manager.js +1 -0
  12. package/dist/card/approval-render.js +294 -36
  13. package/dist/card/bash-card-session.d.ts +2 -24
  14. package/dist/card/bash-card-session.js +6 -73
  15. package/dist/card/bash-renderer.js +2 -3
  16. package/dist/card/card-budget.js +29 -75
  17. package/dist/card/card-session.d.ts +48 -0
  18. package/dist/card/card-session.js +86 -0
  19. package/dist/card/card-shared.d.ts +7 -16
  20. package/dist/card/card-shared.js +7 -30
  21. package/dist/card/run-card-session.d.ts +2 -55
  22. package/dist/card/run-card-session.js +6 -104
  23. package/dist/card/run-renderer.d.ts +7 -0
  24. package/dist/card/run-renderer.js +116 -238
  25. package/dist/card/run-state.d.ts +13 -0
  26. package/dist/card/run-state.js +25 -16
  27. package/dist/card/text-truncate.d.ts +13 -12
  28. package/dist/card/text-truncate.js +13 -63
  29. package/dist/common/fs.d.ts +8 -0
  30. package/dist/common/fs.js +17 -0
  31. package/dist/common/guards.d.ts +0 -20
  32. package/dist/common/guards.js +0 -43
  33. package/dist/common/sleep.d.ts +2 -0
  34. package/dist/common/sleep.js +5 -0
  35. package/dist/common/truncate.d.ts +39 -0
  36. package/dist/common/truncate.js +92 -0
  37. package/dist/config/codex-config.d.ts +1 -1
  38. package/dist/config/codex-config.js +1 -1
  39. package/dist/config/index.d.ts +112 -24
  40. package/dist/config/index.js +139 -37
  41. package/dist/connector/index.d.ts +69 -2
  42. package/dist/connector/index.js +107 -1
  43. package/dist/index.js +150 -118
  44. package/dist/instance-lock.js +4 -12
  45. package/dist/order/alias-resolve.d.ts +13 -0
  46. package/dist/order/alias-resolve.js +22 -0
  47. package/dist/order/alias-store.d.ts +38 -0
  48. package/dist/order/alias-store.js +106 -0
  49. package/dist/persistence/atomic-write.d.ts +8 -2
  50. package/dist/persistence/atomic-write.js +23 -7
  51. package/dist/restart.js +2 -1
  52. package/dist/router/card-action-payload.d.ts +30 -0
  53. package/dist/router/card-action-payload.js +39 -0
  54. package/dist/router/card-helpers.d.ts +63 -0
  55. package/dist/router/card-helpers.js +146 -0
  56. package/dist/router/config/claude.js +30 -1
  57. package/dist/router/config/codex.js +29 -50
  58. package/dist/router/config/common/model-patch.d.ts +22 -0
  59. package/dist/router/config/common/model-patch.js +26 -0
  60. package/dist/router/config/common/render.js +5 -4
  61. package/dist/router/config/dsh.d.ts +51 -0
  62. package/dist/router/config/dsh.js +179 -0
  63. package/dist/router/config/index.d.ts +12 -0
  64. package/dist/router/config/index.js +28 -1
  65. package/dist/router/config/kimi.d.ts +4 -1
  66. package/dist/router/config/kimi.js +27 -0
  67. package/dist/router/config/opencode.js +18 -5
  68. package/dist/router/config/pi.js +4 -5
  69. package/dist/router/config/types.d.ts +17 -2
  70. package/dist/router/index.d.ts +76 -22
  71. package/dist/router/index.js +479 -548
  72. package/dist/router/utils.d.ts +2 -0
  73. package/dist/router/utils.js +16 -2
  74. package/dist/runner/agent-choices-common.d.ts +16 -0
  75. package/dist/runner/agent-choices-common.js +34 -0
  76. package/dist/runner/claude/runner.d.ts +47 -10
  77. package/dist/runner/claude/runner.js +117 -46
  78. package/dist/runner/claude/session.d.ts +166 -0
  79. package/dist/runner/claude/session.js +768 -0
  80. package/dist/runner/codex/app-server/protocol-types.d.ts +66 -39
  81. package/dist/runner/codex/app-server/protocol-types.js +2 -13
  82. package/dist/runner/codex/app-server/runner.d.ts +52 -59
  83. package/dist/runner/codex/app-server/runner.js +216 -338
  84. package/dist/runner/codex/app-server/translator.d.ts +8 -21
  85. package/dist/runner/codex/app-server/translator.js +45 -18
  86. package/dist/runner/codex/index.d.ts +0 -2
  87. package/dist/runner/codex/index.js +0 -2
  88. package/dist/runner/common/acp/protocol-helpers.d.ts +14 -0
  89. package/dist/runner/common/acp/protocol-helpers.js +21 -0
  90. package/dist/runner/common/acp/protocol-types.d.ts +271 -0
  91. package/dist/runner/common/acp/protocol-types.js +77 -0
  92. package/dist/runner/common/connection-based-runner.d.ts +111 -0
  93. package/dist/runner/common/connection-based-runner.js +261 -0
  94. package/dist/runner/{codex/app-server → common/jsonrpc}/client.d.ts +14 -7
  95. package/dist/runner/{codex/app-server → common/jsonrpc}/client.js +27 -18
  96. package/dist/runner/common/jsonrpc/connection-manager.d.ts +125 -0
  97. package/dist/runner/{codex/app-server → common/jsonrpc}/connection-manager.js +63 -28
  98. package/dist/runner/{codex/app-server → common/jsonrpc}/transport.d.ts +5 -4
  99. package/dist/runner/{codex/app-server → common/jsonrpc}/transport.js +18 -19
  100. package/dist/runner/common/jsonrpc/types.d.ts +32 -0
  101. package/dist/runner/common/jsonrpc/types.js +9 -0
  102. package/dist/runner/common/process-stopper.d.ts +2 -1
  103. package/dist/runner/common/process-stopper.js +1 -0
  104. package/dist/runner/common/runner-utils.d.ts +6 -13
  105. package/dist/runner/common/runner-utils.js +6 -47
  106. package/dist/runner/common/spawning-runner.d.ts +24 -70
  107. package/dist/runner/common/spawning-runner.js +98 -152
  108. package/dist/runner/dsh/client.d.ts +95 -0
  109. package/dist/runner/dsh/client.js +418 -0
  110. package/dist/runner/dsh/fake-dsh-server.d.ts +60 -0
  111. package/dist/runner/dsh/fake-dsh-server.js +156 -0
  112. package/dist/runner/dsh/index.d.ts +3 -0
  113. package/dist/runner/dsh/index.js +4 -0
  114. package/dist/runner/dsh/runner.d.ts +57 -0
  115. package/dist/runner/dsh/runner.js +191 -0
  116. package/dist/runner/dsh/translator.d.ts +28 -0
  117. package/dist/runner/dsh/translator.js +98 -0
  118. package/dist/runner/dsh/types.d.ts +155 -0
  119. package/dist/runner/dsh/types.js +14 -0
  120. package/dist/runner/index.d.ts +5 -4
  121. package/dist/runner/index.js +5 -4
  122. package/dist/runner/kimi/acp/runner.d.ts +106 -0
  123. package/dist/runner/kimi/acp/runner.js +516 -0
  124. package/dist/runner/kimi/acp/translator.d.ts +138 -0
  125. package/dist/runner/kimi/acp/translator.js +441 -0
  126. package/dist/runner/kimi/index.d.ts +1 -1
  127. package/dist/runner/kimi/index.js +1 -1
  128. package/dist/runner/opencode/acp/index.d.ts +1 -0
  129. package/dist/runner/opencode/acp/index.js +2 -0
  130. package/dist/runner/opencode/acp/runner.d.ts +121 -0
  131. package/dist/runner/opencode/acp/runner.js +429 -0
  132. package/dist/runner/opencode/acp/translator.d.ts +119 -0
  133. package/dist/runner/opencode/acp/translator.js +345 -0
  134. package/dist/runner/opencode/index.d.ts +1 -1
  135. package/dist/runner/opencode/index.js +1 -1
  136. package/dist/runner/pi/index.d.ts +1 -1
  137. package/dist/runner/pi/index.js +1 -1
  138. package/dist/runner/pi/rpc/client.d.ts +52 -0
  139. package/dist/runner/pi/rpc/client.js +114 -0
  140. package/dist/runner/pi/rpc/index.d.ts +4 -0
  141. package/dist/runner/pi/rpc/index.js +4 -0
  142. package/dist/runner/pi/rpc/protocol-types.d.ts +127 -0
  143. package/dist/runner/pi/rpc/protocol-types.js +21 -0
  144. package/dist/runner/pi/rpc/runner.d.ts +74 -0
  145. package/dist/runner/pi/rpc/runner.js +190 -0
  146. package/dist/runner/pi/rpc/translator.d.ts +55 -0
  147. package/dist/runner/pi/rpc/translator.js +258 -0
  148. package/dist/runner/probe.js +6 -1
  149. package/dist/runner/question-common.d.ts +26 -0
  150. package/dist/runner/question-common.js +42 -0
  151. package/dist/runner/registry.d.ts +7 -8
  152. package/dist/runner/registry.js +3 -4
  153. package/dist/runner/resolve-agent-choices.js +18 -59
  154. package/dist/runner/sync-agent-choices.js +16 -67
  155. package/dist/runner/types.d.ts +97 -14
  156. package/dist/session/claude/session-index.js +2 -3
  157. package/dist/session/claude/session-reader.js +3 -6
  158. package/dist/session/claude/sessions.js +43 -28
  159. package/dist/session/codex/rollout-reader.d.ts +2 -2
  160. package/dist/session/codex/rollout-reader.js +14 -17
  161. package/dist/session/codex/sessions.d.ts +1 -1
  162. package/dist/session/codex/sessions.js +2 -2
  163. package/dist/session/common/content-blocks.d.ts +7 -0
  164. package/dist/session/common/content-blocks.js +13 -9
  165. package/dist/session/common/jsonl.d.ts +8 -25
  166. package/dist/session/common/jsonl.js +126 -261
  167. package/dist/session/common/pagination.d.ts +28 -0
  168. package/dist/session/common/pagination.js +33 -0
  169. package/dist/session/dsh/index.d.ts +1 -0
  170. package/dist/session/dsh/index.js +2 -0
  171. package/dist/session/dsh/sessions.d.ts +39 -0
  172. package/dist/session/dsh/sessions.js +237 -0
  173. package/dist/session/index.d.ts +1 -0
  174. package/dist/session/index.js +1 -0
  175. package/dist/session/kimi/sessions.d.ts +34 -1
  176. package/dist/session/kimi/sessions.js +208 -98
  177. package/dist/session/opencode/sessions.d.ts +17 -3
  178. package/dist/session/opencode/sessions.js +29 -29
  179. package/dist/session/pi/sessions.d.ts +5 -1
  180. package/dist/session/pi/sessions.js +12 -16
  181. package/dist/session/session-store.d.ts +11 -1
  182. package/dist/session/session-store.js +75 -178
  183. package/dist/update/index.d.ts +2 -2
  184. package/dist/update/index.js +2 -2
  185. package/dist/update/install.d.ts +20 -2
  186. package/dist/update/install.js +51 -7
  187. package/dist/workspace/index.d.ts +4 -0
  188. package/dist/workspace/index.js +8 -1
  189. package/package.json +2 -1
  190. package/dist/runner/codex/app-server/connection-manager.d.ts +0 -56
  191. package/dist/runner/codex/argv.d.ts +0 -33
  192. package/dist/runner/codex/argv.js +0 -40
  193. package/dist/runner/codex/factory.d.ts +0 -29
  194. package/dist/runner/codex/factory.js +0 -39
  195. package/dist/runner/codex/jsonl.d.ts +0 -37
  196. package/dist/runner/codex/jsonl.js +0 -221
  197. package/dist/runner/codex/runner.d.ts +0 -66
  198. package/dist/runner/codex/runner.js +0 -129
  199. package/dist/runner/common/exec-translator.d.ts +0 -73
  200. package/dist/runner/common/exec-translator.js +0 -105
  201. package/dist/runner/kimi/jsonl.d.ts +0 -28
  202. package/dist/runner/kimi/jsonl.js +0 -143
  203. package/dist/runner/kimi/runner.d.ts +0 -49
  204. package/dist/runner/kimi/runner.js +0 -105
  205. package/dist/runner/opencode/argv.d.ts +0 -32
  206. package/dist/runner/opencode/argv.js +0 -35
  207. package/dist/runner/opencode/jsonl.d.ts +0 -68
  208. package/dist/runner/opencode/jsonl.js +0 -295
  209. package/dist/runner/opencode/runner.d.ts +0 -61
  210. package/dist/runner/opencode/runner.js +0 -93
  211. package/dist/runner/pi/jsonl.d.ts +0 -128
  212. package/dist/runner/pi/jsonl.js +0 -249
  213. package/dist/runner/pi/runner.d.ts +0 -36
  214. package/dist/runner/pi/runner.js +0 -76
  215. package/dist/session/common/catch-up.d.ts +0 -12
  216. package/dist/session/common/catch-up.js +0 -31
@@ -2,6 +2,14 @@ import { z } from 'zod';
2
2
  export { getConfigDir } from './dir.js';
3
3
  /** Valid effort values for Claude */
4
4
  export declare const CLAUDE_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max"];
5
+ /**
6
+ * Claude 官方 --permission-mode 枚举(claude --help 输出,2026-08 实测)。
7
+ * 额外支持 'default':Claude settings.json 的官方未设置值,等价于不传
8
+ * --permission-mode(交互式默认:高风险工具逐个询问)。
9
+ * 'manual' 是 'default' 的别名(claude CLI 等价),schema 保留以向后兼容旧配置,
10
+ * 但 UI 下拉不展示(见 router/config/claude.ts)。
11
+ */
12
+ export declare const CLAUDE_PERMISSION_MODES: readonly ["default", "acceptEdits", "auto", "bypassPermissions", "manual", "dontAsk", "plan"];
5
13
  /** Valid thinking levels for Pi */
6
14
  export declare const PI_THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh"];
7
15
  /**
@@ -11,7 +19,10 @@ export declare const PI_THINKING_LEVELS: readonly ["off", "minimal", "low", "med
11
19
  */
12
20
  export declare const DEFAULT_STOP_GRACE_MS: 5000;
13
21
  /** Codex app-server turn idle timeout default (minutes). */
14
- export declare const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES: 10;
22
+ export declare const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES: 30;
23
+ /** 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。 */
24
+ export declare const DEFAULT_INBOUND_MEDIA_DIR_NAME = ".lark-remote-temp";
25
+ export declare const DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB = 50;
15
26
  /** 模型 ID → alias 映射。 */
16
27
  export declare const MODEL_ID_TO_ALIAS: Record<string, string>;
17
28
  /** alias → model ID 反向映射。 */
@@ -20,11 +31,22 @@ declare const ClaudeConfigSchema: z.ZodObject<{
20
31
  model: z.ZodDefault<z.ZodString>;
21
32
  effort: z.ZodDefault<z.ZodEnum<{
22
33
  medium: "medium";
23
- max: "max";
24
34
  low: "low";
25
35
  high: "high";
26
36
  xhigh: "xhigh";
37
+ max: "max";
38
+ }>>;
39
+ permissionMode: z.ZodDefault<z.ZodEnum<{
40
+ default: "default";
41
+ plan: "plan";
42
+ bypassPermissions: "bypassPermissions";
43
+ auto: "auto";
44
+ manual: "manual";
45
+ acceptEdits: "acceptEdits";
46
+ dontAsk: "dontAsk";
27
47
  }>>;
48
+ approvalTimeoutMs: z.ZodDefault<z.ZodNumber>;
49
+ idleTtlMinutes: z.ZodDefault<z.ZodNumber>;
28
50
  stopGraceMs: z.ZodDefault<z.ZodNumber>;
29
51
  }, z.core.$strip>;
30
52
  /** Codex-specific configuration. */
@@ -32,20 +54,15 @@ export declare const CodexConfigSchema: z.ZodObject<{
32
54
  model: z.ZodOptional<z.ZodString>;
33
55
  modelProvider: z.ZodOptional<z.ZodString>;
34
56
  reasoningEffort: z.ZodOptional<z.ZodString>;
35
- stopGraceMs: z.ZodDefault<z.ZodNumber>;
36
- serviceMode: z.ZodOptional<z.ZodEnum<{
37
- exec: "exec";
38
- "app-server": "app-server";
39
- }>>;
40
- approvalPolicy: z.ZodOptional<z.ZodEnum<{
57
+ approvalPolicy: z.ZodDefault<z.ZodEnum<{
41
58
  untrusted: "untrusted";
42
59
  "on-request": "on-request";
43
60
  never: "never";
44
61
  }>>;
45
- sandbox: z.ZodOptional<z.ZodEnum<{
46
- "danger-full-access": "danger-full-access";
62
+ sandbox: z.ZodDefault<z.ZodEnum<{
47
63
  "read-only": "read-only";
48
64
  "workspace-write": "workspace-write";
65
+ "danger-full-access": "danger-full-access";
49
66
  }>>;
50
67
  appServer: z.ZodOptional<z.ZodObject<{
51
68
  binary: z.ZodDefault<z.ZodString>;
@@ -58,6 +75,10 @@ export declare const CodexConfigSchema: z.ZodObject<{
58
75
  declare const OpencodeConfigSchema: z.ZodObject<{
59
76
  providerID: z.ZodDefault<z.ZodString>;
60
77
  modelID: z.ZodDefault<z.ZodString>;
78
+ mode: z.ZodDefault<z.ZodEnum<{
79
+ plan: "plan";
80
+ build: "build";
81
+ }>>;
61
82
  }, z.core.$strip>;
62
83
  /** Pi-specific configuration. pi is a spawn-per-message CLI like Claude. */
63
84
  declare const PiConfigSchema: z.ZodObject<{
@@ -73,14 +94,34 @@ declare const PiConfigSchema: z.ZodObject<{
73
94
  }>>;
74
95
  tools: z.ZodDefault<z.ZodString>;
75
96
  }, z.core.$strip>;
76
- /** Kimi-specific configuration. kimi is a spawn-per-message CLI. */
97
+ /** Kimi-specific configuration. Pure ACP mode (persistent `kimi acp` connection). */
77
98
  declare const KimiConfigSchema: z.ZodObject<{
78
99
  model: z.ZodDefault<z.ZodString>;
79
100
  thinkingEffort: z.ZodDefault<z.ZodEnum<{
80
- max: "max";
81
101
  low: "low";
82
102
  high: "high";
103
+ max: "max";
83
104
  }>>;
105
+ permissionMode: z.ZodDefault<z.ZodEnum<{
106
+ auto: "auto";
107
+ yolo: "yolo";
108
+ manual: "manual";
109
+ }>>;
110
+ acp: z.ZodOptional<z.ZodObject<{
111
+ binary: z.ZodDefault<z.ZodString>;
112
+ requestTimeoutMs: z.ZodDefault<z.ZodNumber>;
113
+ idleTtlMs: z.ZodDefault<z.ZodNumber>;
114
+ turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
115
+ }, z.core.$strip>>;
116
+ }, z.core.$strip>;
117
+ /** DSH (DeepSeek Harness) Web Host default base URL. */
118
+ export declare const DEFAULT_DSH_HOST = "http://127.0.0.1:3080";
119
+ /** DSH (DeepSeek Harness) Web Host connection config. */
120
+ declare const DshConfigSchema: z.ZodObject<{
121
+ host: z.ZodDefault<z.ZodString>;
122
+ agentPreset: z.ZodOptional<z.ZodString>;
123
+ model: z.ZodOptional<z.ZodString>;
124
+ reasoningEffort: z.ZodOptional<z.ZodString>;
84
125
  }, z.core.$strip>;
85
126
  export declare const AppConfigSchema: z.ZodObject<{
86
127
  feishu: z.ZodObject<{
@@ -91,32 +132,38 @@ export declare const AppConfigSchema: z.ZodObject<{
91
132
  model: z.ZodDefault<z.ZodString>;
92
133
  effort: z.ZodDefault<z.ZodEnum<{
93
134
  medium: "medium";
94
- max: "max";
95
135
  low: "low";
96
136
  high: "high";
97
137
  xhigh: "xhigh";
138
+ max: "max";
98
139
  }>>;
140
+ permissionMode: z.ZodDefault<z.ZodEnum<{
141
+ default: "default";
142
+ plan: "plan";
143
+ bypassPermissions: "bypassPermissions";
144
+ auto: "auto";
145
+ manual: "manual";
146
+ acceptEdits: "acceptEdits";
147
+ dontAsk: "dontAsk";
148
+ }>>;
149
+ approvalTimeoutMs: z.ZodDefault<z.ZodNumber>;
150
+ idleTtlMinutes: z.ZodDefault<z.ZodNumber>;
99
151
  stopGraceMs: z.ZodDefault<z.ZodNumber>;
100
152
  }, z.core.$strip>>;
101
- agents: z.ZodOptional<z.ZodObject<{
102
- codex: z.ZodOptional<z.ZodObject<{
153
+ agents: z.ZodDefault<z.ZodObject<{
154
+ codex: z.ZodDefault<z.ZodObject<{
103
155
  model: z.ZodOptional<z.ZodString>;
104
156
  modelProvider: z.ZodOptional<z.ZodString>;
105
157
  reasoningEffort: z.ZodOptional<z.ZodString>;
106
- stopGraceMs: z.ZodDefault<z.ZodNumber>;
107
- serviceMode: z.ZodOptional<z.ZodEnum<{
108
- exec: "exec";
109
- "app-server": "app-server";
110
- }>>;
111
- approvalPolicy: z.ZodOptional<z.ZodEnum<{
158
+ approvalPolicy: z.ZodDefault<z.ZodEnum<{
112
159
  untrusted: "untrusted";
113
160
  "on-request": "on-request";
114
161
  never: "never";
115
162
  }>>;
116
- sandbox: z.ZodOptional<z.ZodEnum<{
117
- "danger-full-access": "danger-full-access";
163
+ sandbox: z.ZodDefault<z.ZodEnum<{
118
164
  "read-only": "read-only";
119
165
  "workspace-write": "workspace-write";
166
+ "danger-full-access": "danger-full-access";
120
167
  }>>;
121
168
  appServer: z.ZodOptional<z.ZodObject<{
122
169
  binary: z.ZodDefault<z.ZodString>;
@@ -128,6 +175,10 @@ export declare const AppConfigSchema: z.ZodObject<{
128
175
  opencode: z.ZodOptional<z.ZodObject<{
129
176
  providerID: z.ZodDefault<z.ZodString>;
130
177
  modelID: z.ZodDefault<z.ZodString>;
178
+ mode: z.ZodDefault<z.ZodEnum<{
179
+ plan: "plan";
180
+ build: "build";
181
+ }>>;
131
182
  }, z.core.$strip>>;
132
183
  pi: z.ZodOptional<z.ZodObject<{
133
184
  provider: z.ZodDefault<z.ZodString>;
@@ -145,10 +196,27 @@ export declare const AppConfigSchema: z.ZodObject<{
145
196
  kimi: z.ZodOptional<z.ZodObject<{
146
197
  model: z.ZodDefault<z.ZodString>;
147
198
  thinkingEffort: z.ZodDefault<z.ZodEnum<{
148
- max: "max";
149
199
  low: "low";
150
200
  high: "high";
201
+ max: "max";
202
+ }>>;
203
+ permissionMode: z.ZodDefault<z.ZodEnum<{
204
+ auto: "auto";
205
+ yolo: "yolo";
206
+ manual: "manual";
151
207
  }>>;
208
+ acp: z.ZodOptional<z.ZodObject<{
209
+ binary: z.ZodDefault<z.ZodString>;
210
+ requestTimeoutMs: z.ZodDefault<z.ZodNumber>;
211
+ idleTtlMs: z.ZodDefault<z.ZodNumber>;
212
+ turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
213
+ }, z.core.$strip>>;
214
+ }, z.core.$strip>>;
215
+ dsh: z.ZodOptional<z.ZodObject<{
216
+ host: z.ZodDefault<z.ZodString>;
217
+ agentPreset: z.ZodOptional<z.ZodString>;
218
+ model: z.ZodOptional<z.ZodString>;
219
+ reasoningEffort: z.ZodOptional<z.ZodString>;
152
220
  }, z.core.$strip>>;
153
221
  }, z.core.$strip>>;
154
222
  agentChoices: z.ZodOptional<z.ZodObject<{
@@ -169,6 +237,9 @@ export declare const AppConfigSchema: z.ZodObject<{
169
237
  model: z.ZodOptional<z.ZodString>;
170
238
  thinkingEffort: z.ZodOptional<z.ZodString>;
171
239
  }, z.core.$strip>>;
240
+ dsh: z.ZodOptional<z.ZodObject<{
241
+ host: z.ZodOptional<z.ZodString>;
242
+ }, z.core.$strip>>;
172
243
  }, z.core.$strip>>;
173
244
  idle: z.ZodDefault<z.ZodObject<{
174
245
  watchdogMinutes: z.ZodDefault<z.ZodNumber>;
@@ -186,12 +257,18 @@ export declare const AppConfigSchema: z.ZodObject<{
186
257
  error: "error";
187
258
  }>>;
188
259
  }, z.core.$strip>>;
260
+ inboundMedia: z.ZodDefault<z.ZodObject<{
261
+ enabled: z.ZodDefault<z.ZodBoolean>;
262
+ dirName: z.ZodDefault<z.ZodString>;
263
+ maxFileSizeMb: z.ZodDefault<z.ZodNumber>;
264
+ }, z.core.$strip>>;
189
265
  defaultAgent: z.ZodDefault<z.ZodEnum<{
190
266
  claude: "claude";
191
267
  codex: "codex";
192
268
  opencode: "opencode";
193
269
  pi: "pi";
194
270
  kimi: "kimi";
271
+ dsh: "dsh";
195
272
  }>>;
196
273
  checkUpdateOnStartup: z.ZodDefault<z.ZodBoolean>;
197
274
  }, z.core.$strip>;
@@ -217,6 +294,15 @@ export declare function mapAgentKey(key: string): string;
217
294
  * config 路径中不存在,写/删/读三条路径统一拒绝。
218
295
  */
219
296
  export declare function assertSafeKeyPart(part: string): void;
297
+ /**
298
+ * 按 dot-separated key 下钻到目标键的父容器(不含最后一段)。
299
+ *
300
+ * - create=true:中间缺失/非对象段自动补 `{}`(set 语义)
301
+ * - create=false:中间缺失/非对象段返回 undefined(get/delete 语义)
302
+ *
303
+ * 危险段(__proto__/prototype/constructor)在每段统一拒绝。
304
+ */
305
+ export declare function walkNestedContainer(target: unknown, parts: string[], create: boolean): Record<string, unknown> | undefined;
220
306
  /** Get a nested value from config by dot-separated key, e.g. "feishu.appId" */
221
307
  export declare function getConfigValue(config: AppConfig, key: string): unknown;
222
308
  /** Set a nested value in config by dot-separated key, write back to YAML file */
@@ -234,12 +320,14 @@ type CodexConfig = z.infer<typeof CodexConfigSchema>;
234
320
  type OpencodeConfig = z.infer<typeof OpencodeConfigSchema>;
235
321
  type PiConfig = z.infer<typeof PiConfigSchema>;
236
322
  type KimiConfig = z.infer<typeof KimiConfigSchema>;
323
+ export type DshConfig = z.infer<typeof DshConfigSchema>;
237
324
  /** Get configuration for a specific agent. Falls back to defaults if not configured. */
238
325
  export declare function getAgentConfig(config: AppConfig, kind: 'claude'): ClaudeConfig;
239
326
  export declare function getAgentConfig(config: AppConfig, kind: 'codex'): CodexConfig | undefined;
240
327
  export declare function getAgentConfig(config: AppConfig, kind: 'opencode'): OpencodeConfig | undefined;
241
328
  export declare function getAgentConfig(config: AppConfig, kind: 'pi'): PiConfig | undefined;
242
329
  export declare function getAgentConfig(config: AppConfig, kind: 'kimi'): KimiConfig | undefined;
330
+ export declare function getAgentConfig(config: AppConfig, kind: 'dsh'): DshConfig | undefined;
243
331
  /**
244
332
  * 从 Claude settings.json 的 env 中读取所有以 MODEL 结尾的环境变量值,
245
333
  * 返回去重后的模型 ID 列表。
@@ -9,6 +9,22 @@ export { getConfigDir } from './dir.js';
9
9
  import { KIMI_THINKING_EFFORTS } from './kimi-config.js';
10
10
  /** Valid effort values for Claude */
11
11
  export const CLAUDE_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'];
12
+ /**
13
+ * Claude 官方 --permission-mode 枚举(claude --help 输出,2026-08 实测)。
14
+ * 额外支持 'default':Claude settings.json 的官方未设置值,等价于不传
15
+ * --permission-mode(交互式默认:高风险工具逐个询问)。
16
+ * 'manual' 是 'default' 的别名(claude CLI 等价),schema 保留以向后兼容旧配置,
17
+ * 但 UI 下拉不展示(见 router/config/claude.ts)。
18
+ */
19
+ export const CLAUDE_PERMISSION_MODES = [
20
+ 'default',
21
+ 'acceptEdits',
22
+ 'auto',
23
+ 'bypassPermissions',
24
+ 'manual',
25
+ 'dontAsk',
26
+ 'plan',
27
+ ];
12
28
  /** Valid thinking levels for Pi */
13
29
  export const PI_THINKING_LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh'];
14
30
  /** 默认值常量:schema 与 template 共享,避免双源不一致(G25 Magic Numbers)。 */
@@ -16,7 +32,13 @@ const DEFAULTS = {
16
32
  CLAUDE_MODEL: 'claude-opus-4-8',
17
33
  STOP_GRACE_MS: 5000,
18
34
  IDLE_WATCHDOG_MINUTES: 15,
19
- TURN_IDLE_TIMEOUT_MINUTES: 10,
35
+ /** ACP/app-server turn idle 超时默认 30 分钟:Kimi/opencode/codex 常因
36
+ * 等待 SubAgent 或长思考长时间静默,10 分钟会误杀正常进行中的 run。 */
37
+ TURN_IDLE_TIMEOUT_MINUTES: 30,
38
+ /** 审批超时默认 5 分钟(对齐 codex 红线:勿随意改短)。 */
39
+ APPROVAL_TIMEOUT_MS: 5 * 60 * 1000,
40
+ /** Claude 会话级空闲回收默认 30 分钟(对齐 codex appServer.idleTtlMs)。 */
41
+ CLAUDE_IDLE_TTL_MINUTES: 30,
20
42
  };
21
43
  /**
22
44
  * Default SIGTERM→SIGKILL grace period (ms). Exported so runners (SpawningRunner)
@@ -26,6 +48,9 @@ const DEFAULTS = {
26
48
  export const DEFAULT_STOP_GRACE_MS = DEFAULTS.STOP_GRACE_MS;
27
49
  /** Codex app-server turn idle timeout default (minutes). */
28
50
  export const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES = DEFAULTS.TURN_IDLE_TIMEOUT_MINUTES;
51
+ /** 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。 */
52
+ export const DEFAULT_INBOUND_MEDIA_DIR_NAME = '.lark-remote-temp';
53
+ export const DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB = 50;
29
54
  /** 模型 ID → alias 映射。 */
30
55
  export const MODEL_ID_TO_ALIAS = {
31
56
  'claude-opus-4-8': 'opus',
@@ -47,7 +72,17 @@ const FeishuConfigSchema = z.object({
47
72
  const ClaudeConfigSchema = z.object({
48
73
  model: z.string().default(DEFAULTS.CLAUDE_MODEL),
49
74
  effort: z.enum(CLAUDE_EFFORTS).default('medium'),
50
- // permissionMode 硬编码为 bypassPermissions(runner 内部),不通过 config 配置
75
+ /**
76
+ * Claude 权限模式(官方 --permission-mode 枚举 + 'default'=省略该参数)。
77
+ * 默认 bypassPermissions 保持现有行为(无审批卡);配置为其他值后激活
78
+ * 交互式审批(control_request → run 卡审批区)。
79
+ */
80
+ permissionMode: z.enum(CLAUDE_PERMISSION_MODES).default('bypassPermissions'),
81
+ /** 审批请求超时(ms),默认 5 分钟;超时自动发送 cancel 并中断 turn。
82
+ * 0 = 立即过期(fail-fast,避免审批永久挂起),不推荐;勿随意改短。 */
83
+ approvalTimeoutMs: z.number().int().min(0).default(DEFAULTS.APPROVAL_TIMEOUT_MS),
84
+ /** 会话级空闲回收(分钟):turn 之间无新消息超过该窗口则停止长驻进程。 */
85
+ idleTtlMinutes: z.number().int().min(0).default(DEFAULTS.CLAUDE_IDLE_TTL_MINUTES),
51
86
  stopGraceMs: z.number().int().min(0).default(DEFAULTS.STOP_GRACE_MS),
52
87
  });
53
88
  /** Codex app-server connection configuration. */
@@ -75,14 +110,12 @@ export const CodexConfigSchema = z.object({
75
110
  */
76
111
  // codex 拒绝空串档位(ReasoningEffort::from_str "" → Err,P3-3)
77
112
  reasoningEffort: z.string().min(1).optional(),
78
- /** Stop grace period in milliseconds. */
79
- stopGraceMs: z.number().int().min(0).default(5000),
80
- /** Service mode: 'exec' (spawn-per-message) or 'app-server' (persistent connection). */
81
- serviceMode: z.enum(['exec', 'app-server']).optional(),
82
- /** Approval policy (Codex 官方 AskForApproval 标准值). 仅 app-server 模式有效(exec 固定 approval_policy="never")。 */
83
- approvalPolicy: z.enum(['untrusted', 'on-request', 'never']).optional(),
84
- /** Sandbox mode (Codex 官方 SandboxMode 标准值). 仅 app-server 模式有效(exec 固定 --sandbox danger-full-access)。 */
85
- sandbox: z.enum(['read-only', 'workspace-write', 'danger-full-access']).optional(),
113
+ /** Approval policy (Codex 官方 AskForApproval 标准值). 默认 on-request。 */
114
+ approvalPolicy: z.enum(['untrusted', 'on-request', 'never']).default('on-request'),
115
+ /** Sandbox mode (Codex 官方 SandboxMode 标准值). 默认 workspace-write。 */
116
+ sandbox: z
117
+ .enum(['read-only', 'workspace-write', 'danger-full-access'])
118
+ .default('workspace-write'),
86
119
  /** App-server connection configuration. */
87
120
  appServer: CodexAppServerConfigSchema.optional(),
88
121
  });
@@ -92,6 +125,8 @@ const OpencodeConfigSchema = z.object({
92
125
  providerID: z.string().default('anthropic'),
93
126
  /** Model ID for the LLM backend (e.g. 'claude-sonnet-4-20250514'). */
94
127
  modelID: z.string().default('claude-sonnet-4-20250514'),
128
+ /** Session mode (opencode agent name): 'build' (default) or 'plan'. */
129
+ mode: z.enum(['build', 'plan']).default('build'),
95
130
  });
96
131
  /** Pi-specific configuration. pi is a spawn-per-message CLI like Claude. */
97
132
  const PiConfigSchema = z.object({
@@ -104,19 +139,60 @@ const PiConfigSchema = z.object({
104
139
  /** Comma-separated tool whitelist. */
105
140
  tools: z.string().default('read,bash,edit,write,grep,find,ls'),
106
141
  });
107
- /** Kimi-specific configuration. kimi is a spawn-per-message CLI. */
142
+ /** Kimi-specific configuration. Pure ACP mode (persistent `kimi acp` connection). */
108
143
  const KimiConfigSchema = z.object({
109
144
  /** Model ID or alias, e.g. 'kimi-code/k3'. */
110
145
  model: z.string().default('kimi-code/k3'),
111
146
  /** Thinking effort: 'on', 'max'. */
112
147
  thinkingEffort: z.enum(KIMI_THINKING_EFFORTS).default('max'),
148
+ /** Permission mode: 'manual' (approve each), 'auto' (engine decides), 'yolo' (allow all). */
149
+ permissionMode: z.enum(['manual', 'auto', 'yolo']).default('manual'),
150
+ /** ACP sub-configuration. */
151
+ acp: z
152
+ .object({
153
+ /** Path to kimi binary for ACP mode. */
154
+ binary: z.string().default('kimi'),
155
+ /** Request timeout in milliseconds. */
156
+ requestTimeoutMs: z.number().int().min(0).default(60000),
157
+ /** Idle TTL for ACP connection in milliseconds. */
158
+ idleTtlMs: z.number().int().min(0).default(1800000),
159
+ /** Turn idle timeout in minutes (0 disables). */
160
+ turnIdleTimeoutMinutes: z.number().int().min(0).default(DEFAULT_TURN_IDLE_TIMEOUT_MINUTES),
161
+ })
162
+ .optional(),
163
+ });
164
+ /** DSH (DeepSeek Harness) Web Host default base URL. */
165
+ export const DEFAULT_DSH_HOST = 'http://127.0.0.1:3080';
166
+ /** DSH (DeepSeek Harness) Web Host connection config. */
167
+ const DshConfigSchema = z.object({
168
+ /** DSH Web Host base URL (no auth, local). */
169
+ host: z.string().url().default(DEFAULT_DSH_HOST),
170
+ /**
171
+ * Session preset(agentPreset)。preset 在 session 创建时固定,中途切换会被
172
+ * 服务端拒绝(agent-preset-conflict)。留空 = 跟随服务端默认(不传 agentPreset)。
173
+ * 枚举不在此硬编码:preset 清单随 DSH profile bundle 变化,合法性由配置卡下拉
174
+ * 控制 + 运行时 DSH API 报错兜底。
175
+ */
176
+ agentPreset: z.string().optional(),
177
+ /** 模型 ID。留空 = 跟随服务端默认。 */
178
+ model: z.string().optional(),
179
+ /**
180
+ * 推理强度(off / low / high / max,跟随 llm.models 实际档位)。留空 = 跟随
181
+ * 服务端默认。枚举不硬编码(理由同上 agentPreset)。
182
+ */
183
+ reasoningEffort: z.string().optional(),
113
184
  });
185
+ /** 首次启动的默认 agents 配置:codex 默认 app-server / on-request / workspace-write。 */
186
+ const DEFAULT_AGENTS_CONFIG = {
187
+ codex: CodexConfigSchema.parse({}),
188
+ };
114
189
  /** Agents configuration: per-agent settings keyed by agent kind. */
115
190
  const AgentsConfigSchema = z.object({
116
- codex: CodexConfigSchema.optional(),
191
+ codex: CodexConfigSchema.default(DEFAULT_AGENTS_CONFIG.codex),
117
192
  opencode: OpencodeConfigSchema.optional(),
118
193
  pi: PiConfigSchema.optional(),
119
194
  kimi: KimiConfigSchema.optional(),
195
+ dsh: DshConfigSchema.optional(),
120
196
  });
121
197
  const IdleConfigSchema = z.object({
122
198
  /**
@@ -134,6 +210,15 @@ const OutputConfigSchema = z.object({
134
210
  const LoggingConfigSchema = z.object({
135
211
  level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
136
212
  });
213
+ /** 入站媒体落盘配置(预留可配置,默认即可用)。 */
214
+ const InboundMediaConfigSchema = z.object({
215
+ /** 是否启用图片/文件落盘。 */
216
+ enabled: z.boolean().default(true),
217
+ /** 落盘根目录名(位于当前 cwd 下)。 */
218
+ dirName: z.string().min(1).default(DEFAULT_INBOUND_MEDIA_DIR_NAME),
219
+ /** 单文件大小上限(MiB)。 */
220
+ maxFileSizeMb: z.number().int().min(1).default(DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB),
221
+ });
137
222
  /** Agent-specific saved choices for quick switching. */
138
223
  const AgentChoicesSchema = z.object({
139
224
  codex: z
@@ -161,20 +246,27 @@ const AgentChoicesSchema = z.object({
161
246
  thinkingEffort: z.string().optional(),
162
247
  })
163
248
  .optional(),
249
+ dsh: z
250
+ .object({
251
+ host: z.string().optional(),
252
+ })
253
+ .optional(),
164
254
  });
165
255
  export const AppConfigSchema = z.object({
166
256
  feishu: FeishuConfigSchema,
167
257
  /** Claude config (top-level; other agents live under `agents`). */
168
258
  claude: ClaudeConfigSchema.default(ClaudeConfigSchema.parse({})),
169
- /** Per-agent configuration for non-claude agents. */
170
- agents: AgentsConfigSchema.optional(),
259
+ /** Per-agent configuration for non-claude agents. 首次启动默认含 codex(app-server / workspace-write / on-request)。 */
260
+ agents: AgentsConfigSchema.default(DEFAULT_AGENTS_CONFIG),
171
261
  /** Agent-specific saved choices for quick switching. */
172
262
  agentChoices: AgentChoicesSchema.optional(),
173
263
  idle: IdleConfigSchema.default(IdleConfigSchema.parse({})),
174
264
  output: OutputConfigSchema.default(OutputConfigSchema.parse({})),
175
265
  logging: LoggingConfigSchema.default(LoggingConfigSchema.parse({})),
266
+ /** 入站媒体(图片/文件)落盘配置。 */
267
+ inboundMedia: InboundMediaConfigSchema.default(InboundMediaConfigSchema.parse({})),
176
268
  /** Default agent for new runs. */
177
- defaultAgent: z.enum(['claude', 'codex', 'opencode', 'pi', 'kimi']).default('claude'),
269
+ defaultAgent: z.enum(['claude', 'codex', 'opencode', 'pi', 'kimi', 'dsh']).default('claude'),
178
270
  /** Check for updates on bridge startup (default: false). */
179
271
  checkUpdateOnStartup: z.boolean().default(false),
180
272
  });
@@ -185,6 +277,9 @@ const TEMPLATE = `feishu:
185
277
  claude:
186
278
  model: ${DEFAULTS.CLAUDE_MODEL}
187
279
  effort: medium
280
+ permissionMode: bypassPermissions
281
+ approvalTimeoutMs: ${DEFAULTS.APPROVAL_TIMEOUT_MS}
282
+ idleTtlMinutes: ${DEFAULTS.CLAUDE_IDLE_TTL_MINUTES}
188
283
  stopGraceMs: ${DEFAULTS.STOP_GRACE_MS}
189
284
 
190
285
  idle:
@@ -224,7 +319,7 @@ export function loadConfig(configPath) {
224
319
  * Agent key 前缀,这些前缀的 key 会映射到 `agents.<key>` 路径下。
225
320
  * `claude.` 保持顶层(不映射到 agents.claude)。
226
321
  */
227
- const AGENT_PREFIXES = ['pi', 'codex', 'opencode', 'kimi'];
322
+ const AGENT_PREFIXES = ['pi', 'codex', 'opencode', 'kimi', 'dsh'];
228
323
  /**
229
324
  * 将卡片短 key 映射到 schema 期望的路径:
230
325
  * pi.xxx → agents.pi.xxx
@@ -272,33 +367,45 @@ export function assertSafeKeyPart(part) {
272
367
  throw new Error(`[lark-remote] invalid config key segment: '${part}'`);
273
368
  }
274
369
  }
275
- /** 在对象上按 dot-separated key 设置嵌套值(仅修改内存对象,不写盘)。 */
276
- function setNestedValue(target, key, value) {
277
- const parts = key.split('.');
370
+ /**
371
+ * 按 dot-separated key 下钻到目标键的父容器(不含最后一段)。
372
+ *
373
+ * - create=true:中间缺失/非对象段自动补 `{}`(set 语义)
374
+ * - create=false:中间缺失/非对象段返回 undefined(get/delete 语义)
375
+ *
376
+ * 危险段(__proto__/prototype/constructor)在每段统一拒绝。
377
+ */
378
+ export function walkNestedContainer(target, parts, create) {
278
379
  let current = target;
279
380
  for (let i = 0; i < parts.length - 1; i++) {
280
381
  assertSafeKeyPart(parts[i]);
281
382
  const next = current[parts[i]];
282
383
  if (next == null || typeof next !== 'object') {
384
+ if (!create)
385
+ return undefined;
283
386
  current[parts[i]] = {};
284
387
  }
285
388
  current = current[parts[i]];
286
389
  }
390
+ return current;
391
+ }
392
+ /** 在对象上按 dot-separated key 设置嵌套值(仅修改内存对象,不写盘)。 */
393
+ function setNestedValue(target, key, value) {
394
+ const parts = key.split('.');
395
+ const container = walkNestedContainer(target, parts, true);
287
396
  const lastPart = parts[parts.length - 1];
288
397
  assertSafeKeyPart(lastPart);
289
- current[lastPart] = value;
398
+ container[lastPart] = value;
290
399
  }
291
400
  /** Get a nested value from config by dot-separated key, e.g. "feishu.appId" */
292
401
  export function getConfigValue(config, key) {
293
402
  const parts = key.split('.');
294
- let current = config;
295
- for (const part of parts) {
296
- assertSafeKeyPart(part);
297
- if (current == null || typeof current !== 'object')
298
- return undefined;
299
- current = current[part];
300
- }
301
- return current;
403
+ const container = walkNestedContainer(config, parts, false);
404
+ if (!container)
405
+ return undefined;
406
+ const lastPart = parts[parts.length - 1];
407
+ assertSafeKeyPart(lastPart);
408
+ return container[lastPart];
302
409
  }
303
410
  /** Set a nested value in config by dot-separated key, write back to YAML file */
304
411
  export function setConfigValue(configPath, config, key, value) {
@@ -337,17 +444,12 @@ export function setConfigValues(configPath, config, updates) {
337
444
  */
338
445
  function deleteNestedValue(target, key) {
339
446
  const parts = key.split('.');
340
- let current = target;
341
- for (let i = 0; i < parts.length - 1; i++) {
342
- assertSafeKeyPart(parts[i]);
343
- const next = current[parts[i]];
344
- if (next == null || typeof next !== 'object')
345
- return;
346
- current = next;
347
- }
447
+ const container = walkNestedContainer(target, parts, false);
448
+ if (!container)
449
+ return;
348
450
  const lastPart = parts[parts.length - 1];
349
451
  assertSafeKeyPart(lastPart);
350
- delete current[lastPart];
452
+ delete container[lastPart];
351
453
  }
352
454
  export function getAgentConfig(config, kind) {
353
455
  if (kind === 'claude') {
@@ -1,4 +1,4 @@
1
- import { type CardActionEvent, type CardActionResponse, type CardStreamProducer } from '@larksuite/channel';
1
+ import { type CardActionEvent, type CardActionResponse, type CardStreamProducer, type LarkChannel } from '@larksuite/channel';
2
2
  import type { AppConfig } from '../config/index.js';
3
3
  /**
4
4
  * dedup 缓存 TTL(毫秒)。控制飞书事件去重窗口,全局作用于 message + cardAction。
@@ -26,6 +26,54 @@ interface FeishuMessage {
26
26
  content: string;
27
27
  }
28
28
  type MessageHandler = (msg: FeishuMessage) => void;
29
+ /**
30
+ * 入站媒体(image/file 消息的 resource)下载结果,交给 bridge 落盘。
31
+ * media 为通过大小限制、可落盘的项;failures 为下载失败或超限的项
32
+ * (bridge 负责把这些失败提示回用户)。
33
+ */
34
+ export interface InboundMediaItem {
35
+ /** 资源类型:image 消息按 MIME 生成 image_<HHmmss>_<n>.<ext>,file 保留文件名。 */
36
+ type: 'image' | 'file';
37
+ /** 原始文件名(file 消息有;image 消息无,由 bridge 按 MIME 生成)。 */
38
+ fileName?: string;
39
+ /** 服务端 content-type(参数已剥离;可能缺失,bridge 有兜底)。 */
40
+ mimeType?: string;
41
+ /**
42
+ * 下载内容所在临时文件(流式落盘,避免大文件全量进堆内存)。
43
+ * 由 bridge 移动到最终位置;任何未移动路径都必须清理该文件。
44
+ */
45
+ tempPath: string;
46
+ }
47
+ export interface InboundMediaFailure {
48
+ fileName?: string;
49
+ reason: string;
50
+ }
51
+ export interface InboundMediaPayload {
52
+ userId: string;
53
+ chatId: string;
54
+ messageId: string;
55
+ /** 引用上下文:不同 replyTo 强制拆批。 */
56
+ replyToMessageId?: string;
57
+ media: InboundMediaItem[];
58
+ failures: InboundMediaFailure[];
59
+ }
60
+ /**
61
+ * 媒体消息到达的轻量描述(未下载):供上层先做 owner/配置闸门,
62
+ * 通过后再调 downloadInboundMedia —— 下载发生在认证之后(P1 review 修复)。
63
+ */
64
+ export interface InboundMediaMessage {
65
+ userId: string;
66
+ chatId: string;
67
+ messageId: string;
68
+ /** 引用上下文:不同 replyTo 强制拆批。 */
69
+ replyToMessageId?: string;
70
+ resources: Array<{
71
+ type: 'image' | 'file';
72
+ fileKey: string;
73
+ fileName?: string;
74
+ }>;
75
+ }
76
+ type InboundMediaDetectedHandler = (msg: InboundMediaMessage) => void | Promise<void>;
29
77
  /**
30
78
  * CardAction handler may return a CardActionResponse (e.g. `{ toast: {...} }`)
31
79
  * to give the clicking user native immediate feedback. The SDK passes the
@@ -34,9 +82,11 @@ type MessageHandler = (msg: FeishuMessage) => void;
34
82
  */
35
83
  type CardActionHandler = (action: CardActionEvent) => void | CardActionResponse | Promise<void | CardActionResponse>;
36
84
  export declare class FeishuConnector {
37
- private channel;
85
+ /** 飞书 channel 实例(public:测试直接访问/注入 mock,替代 as unknown as)。 */
86
+ channel: LarkChannel;
38
87
  private onMessage?;
39
88
  private onCardAction?;
89
+ private onInboundMediaDetected?;
40
90
  private isConnected;
41
91
  private appId;
42
92
  private appSecret;
@@ -44,6 +94,23 @@ export declare class FeishuConnector {
44
94
  get connected(): boolean;
45
95
  setMessageHandler(handler: MessageHandler): void;
46
96
  setCardActionHandler(handler: CardActionHandler): void;
97
+ setInboundMediaDetectedHandler(handler: InboundMediaDetectedHandler): void;
98
+ /**
99
+ * 上报媒体消息到达(轻量,不含下载内容)。上层认证/配置闸门通过后
100
+ * 再调 downloadInboundMedia。
101
+ */
102
+ private handleInboundMediaDetected;
103
+ /**
104
+ * 下载消息里的全部资源(流式写临时文件,避免大文件全量进堆内存)。
105
+ * 逐资源 try/catch:单个失败不影响其他资源;超限项不进入 media(不落盘)。
106
+ * 下载失败/超限都随 failures 交给 bridge 提示用户(对齐"发送文件失败"文案风格)。
107
+ * 调用方必须已通过 owner/配置闸门(index.ts);maxFileSizeMb 由调用方从
108
+ * 当前配置传入(避免 connector 持有过期的 config 快照)。
109
+ */
110
+ downloadInboundMedia(msg: InboundMediaMessage, opts?: {
111
+ maxFileSizeMb?: number;
112
+ downloadTimeoutMs?: number;
113
+ }): Promise<InboundMediaPayload>;
47
114
  connect(): Promise<void>;
48
115
  disconnect(): Promise<void>;
49
116
  reconnect(): Promise<void>;