lark-remote 0.1.7 → 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.
- package/CHANGELOG.md +28 -0
- package/dist/bridge/approval-coordinator.d.ts +15 -1
- package/dist/bridge/approval-coordinator.js +35 -2
- package/dist/bridge/index.d.ts +19 -6
- package/dist/bridge/index.js +25 -8
- package/dist/card/approval-render.js +187 -45
- package/dist/card/card-shared.d.ts +6 -4
- package/dist/card/card-shared.js +6 -4
- package/dist/card/run-renderer.d.ts +7 -0
- package/dist/card/run-renderer.js +22 -11
- package/dist/config/index.d.ts +24 -1
- package/dist/config/index.js +34 -3
- package/dist/index.js +28 -14
- package/dist/router/card-action-payload.d.ts +30 -0
- package/dist/router/card-action-payload.js +39 -0
- package/dist/router/config/claude.js +8 -3
- package/dist/router/config/dsh.d.ts +51 -0
- package/dist/router/config/dsh.js +179 -0
- package/dist/router/config/index.d.ts +1 -1
- package/dist/router/config/index.js +4 -1
- package/dist/router/config/types.d.ts +6 -0
- package/dist/router/index.d.ts +20 -1
- package/dist/router/index.js +113 -7
- package/dist/router/utils.js +12 -2
- package/dist/runner/agent-choices-common.js +3 -0
- package/dist/runner/claude/session.js +24 -5
- package/dist/runner/codex/app-server/protocol-types.d.ts +35 -0
- package/dist/runner/codex/app-server/protocol-types.js +1 -1
- package/dist/runner/codex/app-server/runner.d.ts +10 -0
- package/dist/runner/codex/app-server/runner.js +56 -1
- package/dist/runner/codex/app-server/translator.d.ts +7 -0
- package/dist/runner/codex/app-server/translator.js +45 -0
- package/dist/runner/common/acp/protocol-types.d.ts +33 -0
- package/dist/runner/common/acp/protocol-types.js +2 -0
- package/dist/runner/dsh/client.d.ts +95 -0
- package/dist/runner/dsh/client.js +418 -0
- package/dist/runner/dsh/fake-dsh-server.d.ts +60 -0
- package/dist/runner/dsh/fake-dsh-server.js +156 -0
- package/dist/runner/dsh/index.d.ts +3 -0
- package/dist/runner/dsh/index.js +4 -0
- package/dist/runner/dsh/runner.d.ts +57 -0
- package/dist/runner/dsh/runner.js +191 -0
- package/dist/runner/dsh/translator.d.ts +28 -0
- package/dist/runner/dsh/translator.js +98 -0
- package/dist/runner/dsh/types.d.ts +155 -0
- package/dist/runner/dsh/types.js +14 -0
- package/dist/runner/index.d.ts +1 -0
- package/dist/runner/index.js +1 -0
- package/dist/runner/kimi/acp/runner.js +69 -1
- package/dist/runner/kimi/acp/translator.d.ts +14 -0
- package/dist/runner/kimi/acp/translator.js +108 -3
- package/dist/runner/pi/rpc/runner.d.ts +1 -7
- package/dist/runner/pi/rpc/runner.js +2 -11
- package/dist/runner/probe.js +6 -1
- package/dist/runner/question-common.d.ts +26 -0
- package/dist/runner/question-common.js +42 -0
- package/dist/runner/types.d.ts +63 -10
- package/dist/session/claude/sessions.js +37 -15
- package/dist/session/dsh/index.d.ts +1 -0
- package/dist/session/dsh/index.js +2 -0
- package/dist/session/dsh/sessions.d.ts +39 -0
- package/dist/session/dsh/sessions.js +237 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +1 -0
- package/dist/workspace/index.d.ts +4 -0
- package/dist/workspace/index.js +8 -1
- package/package.json +2 -1
|
@@ -25,13 +25,21 @@ function measureJson(obj) {
|
|
|
25
25
|
/** markdownDiv('', 'notation') 的序列化字节(空内容 div 的常量开销,估算时复用)。 */
|
|
26
26
|
const EMPTY_MD_DIV_BYTES = measureJson(markdownDiv('', 'notation'));
|
|
27
27
|
/**
|
|
28
|
-
* Compact
|
|
28
|
+
* Compact 按钮可见性:到达任意终态即可压缩。
|
|
29
29
|
* 异常退出(error/interrupted/idle_timeout)时上下文往往更大,更需要压缩后
|
|
30
30
|
* 再继续,因此不再要求 resultSubtype==='success'。compaction 卡
|
|
31
31
|
* (operationKind='compaction')永不显示,防止递归 Compact。
|
|
32
|
+
*
|
|
33
|
+
* 能力门控(compactSupported !== false)与执行侧 `'runCompact' in runner`
|
|
34
|
+
* 鸭子探测对齐:claude 走 stream-json,不发射 turn_started,operationKind
|
|
35
|
+
* 恒 undefined——若以 operationKind==='turn' 作门控,claude 终态卡永远拿
|
|
36
|
+
* 不到按钮(2026-08-19 缺陷)。compaction 卡的「防递归」仍由 operationKind
|
|
37
|
+
* 保证,两者是不同质的判断。
|
|
32
38
|
*/
|
|
33
|
-
function shouldShowCompactButton(state) {
|
|
34
|
-
if (state.operationKind
|
|
39
|
+
function shouldShowCompactButton(state, options) {
|
|
40
|
+
if (state.operationKind === 'compaction')
|
|
41
|
+
return false;
|
|
42
|
+
if (options.compactSupported === false)
|
|
35
43
|
return false;
|
|
36
44
|
return (state.terminal === 'done' ||
|
|
37
45
|
state.terminal === 'error' ||
|
|
@@ -201,15 +209,15 @@ const EXTREME_TIER = {
|
|
|
201
209
|
textBytes: DEGRADED_TEXT_BYTES,
|
|
202
210
|
};
|
|
203
211
|
/** Bottom action row: stop (if running) + compact (if applicable) + new session (always). */
|
|
204
|
-
function actionRow(state) {
|
|
212
|
+
function actionRow(state, options) {
|
|
205
213
|
const actionButtons = [];
|
|
206
214
|
// finalizing 也显示停止按钮(进程未退出,用户可 /stop)
|
|
207
215
|
const showStop = state.terminal === 'running' || state.terminal === 'finalizing';
|
|
208
216
|
if (showStop) {
|
|
209
217
|
actionButtons.push(stopButton(state.runId));
|
|
210
218
|
}
|
|
211
|
-
// Compact
|
|
212
|
-
if (shouldShowCompactButton(state)) {
|
|
219
|
+
// Compact 按钮:到达任意终态即可压缩(含异常退出),compaction 卡除外
|
|
220
|
+
if (shouldShowCompactButton(state, options)) {
|
|
213
221
|
actionButtons.push(compactButton(state.runId));
|
|
214
222
|
}
|
|
215
223
|
actionButtons.push(newSessionButton());
|
|
@@ -323,7 +331,7 @@ function buildFallbackElements(state, options, tier) {
|
|
|
323
331
|
elements.push(markdownDiv('_暂无输出_'));
|
|
324
332
|
}
|
|
325
333
|
elements.push(...buildSummaryContent(state));
|
|
326
|
-
elements.push(...actionRow(state));
|
|
334
|
+
elements.push(...actionRow(state, options));
|
|
327
335
|
elements.push(...approvalArea(state));
|
|
328
336
|
return elements;
|
|
329
337
|
}
|
|
@@ -374,7 +382,7 @@ function statusRow(state) {
|
|
|
374
382
|
* stop while running/finalizing). No block content is rendered, so the size is
|
|
375
383
|
* bounded by static structure regardless of input — closing the safety-net gap.
|
|
376
384
|
*/
|
|
377
|
-
function buildSkeletonElements(state) {
|
|
385
|
+
function buildSkeletonElements(state, options) {
|
|
378
386
|
const elements = [];
|
|
379
387
|
elements.push(statusRow(state));
|
|
380
388
|
elements.push(markdownDiv('_⚠️ 输出过大且含大量转义字符,已省略全部内容以避免超限;完整内容请查日志_'));
|
|
@@ -382,7 +390,7 @@ function buildSkeletonElements(state) {
|
|
|
382
390
|
elements.push(...buildSummaryContent(state));
|
|
383
391
|
// Bottom action row: stop (if running/finalizing) + compact (if applicable) + new session (always).
|
|
384
392
|
// Degraded paths must keep the action buttons reachable (design constraint).
|
|
385
|
-
elements.push(...actionRow(state));
|
|
393
|
+
elements.push(...actionRow(state, options));
|
|
386
394
|
return elements;
|
|
387
395
|
}
|
|
388
396
|
/**
|
|
@@ -450,6 +458,9 @@ export function estimateCardBytes(state, options = {}, shared) {
|
|
|
450
458
|
if (state.terminal === 'running' || state.terminal === 'finalizing') {
|
|
451
459
|
actionButtons.push(stopButton(state.runId));
|
|
452
460
|
}
|
|
461
|
+
if (shouldShowCompactButton(state, options)) {
|
|
462
|
+
actionButtons.push(compactButton(state.runId));
|
|
463
|
+
}
|
|
453
464
|
actionButtons.push(newSessionButton());
|
|
454
465
|
total += measureJson([
|
|
455
466
|
{ tag: 'div', text: { content: '', tag: 'lark_md' } },
|
|
@@ -551,7 +562,7 @@ export function renderRunCard(state, options = {}) {
|
|
|
551
562
|
statusRow(state),
|
|
552
563
|
...buildChronologicalContent(state, options, prepared, groups),
|
|
553
564
|
...buildSummaryContent(state),
|
|
554
|
-
...actionRow(state),
|
|
565
|
+
...actionRow(state, options),
|
|
555
566
|
...approvalArea(state),
|
|
556
567
|
];
|
|
557
568
|
const card = assembleRunCard(state, options, elements);
|
|
@@ -573,7 +584,7 @@ export function renderRunCard(state, options = {}) {
|
|
|
573
584
|
if (Buffer.byteLength(JSON.stringify(extremeCard), 'utf8') <= CARD_BUDGET_BYTES) {
|
|
574
585
|
return extremeCard;
|
|
575
586
|
}
|
|
576
|
-
const skeletonCard = assembleRunCard(state, options, buildSkeletonElements(state));
|
|
587
|
+
const skeletonCard = assembleRunCard(state, options, buildSkeletonElements(state, options));
|
|
577
588
|
// skeleton 卡是静态结构,理论上必 ≤28KB;保留兜底断言以防未来结构膨胀
|
|
578
589
|
if (Buffer.byteLength(JSON.stringify(skeletonCard), 'utf8') <= CARD_BUDGET_BYTES) {
|
|
579
590
|
return skeletonCard;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare const CLAUDE_EFFORTS: readonly ["low", "medium", "high", "xhigh",
|
|
|
6
6
|
* Claude 官方 --permission-mode 枚举(claude --help 输出,2026-08 实测)。
|
|
7
7
|
* 额外支持 'default':Claude settings.json 的官方未设置值,等价于不传
|
|
8
8
|
* --permission-mode(交互式默认:高风险工具逐个询问)。
|
|
9
|
+
* 'manual' 是 'default' 的别名(claude CLI 等价),schema 保留以向后兼容旧配置,
|
|
10
|
+
* 但 UI 下拉不展示(见 router/config/claude.ts)。
|
|
9
11
|
*/
|
|
10
12
|
export declare const CLAUDE_PERMISSION_MODES: readonly ["default", "acceptEdits", "auto", "bypassPermissions", "manual", "dontAsk", "plan"];
|
|
11
13
|
/** Valid thinking levels for Pi */
|
|
@@ -17,7 +19,7 @@ export declare const PI_THINKING_LEVELS: readonly ["off", "minimal", "low", "med
|
|
|
17
19
|
*/
|
|
18
20
|
export declare const DEFAULT_STOP_GRACE_MS: 5000;
|
|
19
21
|
/** Codex app-server turn idle timeout default (minutes). */
|
|
20
|
-
export declare const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES:
|
|
22
|
+
export declare const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES: 30;
|
|
21
23
|
/** 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。 */
|
|
22
24
|
export declare const DEFAULT_INBOUND_MEDIA_DIR_NAME = ".lark-remote-temp";
|
|
23
25
|
export declare const DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB = 50;
|
|
@@ -112,6 +114,15 @@ declare const KimiConfigSchema: z.ZodObject<{
|
|
|
112
114
|
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
113
115
|
}, z.core.$strip>>;
|
|
114
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>;
|
|
125
|
+
}, z.core.$strip>;
|
|
115
126
|
export declare const AppConfigSchema: z.ZodObject<{
|
|
116
127
|
feishu: z.ZodObject<{
|
|
117
128
|
appId: z.ZodString;
|
|
@@ -201,6 +212,12 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
201
212
|
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
202
213
|
}, z.core.$strip>>;
|
|
203
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>;
|
|
220
|
+
}, z.core.$strip>>;
|
|
204
221
|
}, z.core.$strip>>;
|
|
205
222
|
agentChoices: z.ZodOptional<z.ZodObject<{
|
|
206
223
|
codex: z.ZodOptional<z.ZodObject<{
|
|
@@ -220,6 +237,9 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
220
237
|
model: z.ZodOptional<z.ZodString>;
|
|
221
238
|
thinkingEffort: z.ZodOptional<z.ZodString>;
|
|
222
239
|
}, z.core.$strip>>;
|
|
240
|
+
dsh: z.ZodOptional<z.ZodObject<{
|
|
241
|
+
host: z.ZodOptional<z.ZodString>;
|
|
242
|
+
}, z.core.$strip>>;
|
|
223
243
|
}, z.core.$strip>>;
|
|
224
244
|
idle: z.ZodDefault<z.ZodObject<{
|
|
225
245
|
watchdogMinutes: z.ZodDefault<z.ZodNumber>;
|
|
@@ -248,6 +268,7 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
248
268
|
opencode: "opencode";
|
|
249
269
|
pi: "pi";
|
|
250
270
|
kimi: "kimi";
|
|
271
|
+
dsh: "dsh";
|
|
251
272
|
}>>;
|
|
252
273
|
checkUpdateOnStartup: z.ZodDefault<z.ZodBoolean>;
|
|
253
274
|
}, z.core.$strip>;
|
|
@@ -299,12 +320,14 @@ type CodexConfig = z.infer<typeof CodexConfigSchema>;
|
|
|
299
320
|
type OpencodeConfig = z.infer<typeof OpencodeConfigSchema>;
|
|
300
321
|
type PiConfig = z.infer<typeof PiConfigSchema>;
|
|
301
322
|
type KimiConfig = z.infer<typeof KimiConfigSchema>;
|
|
323
|
+
export type DshConfig = z.infer<typeof DshConfigSchema>;
|
|
302
324
|
/** Get configuration for a specific agent. Falls back to defaults if not configured. */
|
|
303
325
|
export declare function getAgentConfig(config: AppConfig, kind: 'claude'): ClaudeConfig;
|
|
304
326
|
export declare function getAgentConfig(config: AppConfig, kind: 'codex'): CodexConfig | undefined;
|
|
305
327
|
export declare function getAgentConfig(config: AppConfig, kind: 'opencode'): OpencodeConfig | undefined;
|
|
306
328
|
export declare function getAgentConfig(config: AppConfig, kind: 'pi'): PiConfig | undefined;
|
|
307
329
|
export declare function getAgentConfig(config: AppConfig, kind: 'kimi'): KimiConfig | undefined;
|
|
330
|
+
export declare function getAgentConfig(config: AppConfig, kind: 'dsh'): DshConfig | undefined;
|
|
308
331
|
/**
|
|
309
332
|
* 从 Claude settings.json 的 env 中读取所有以 MODEL 结尾的环境变量值,
|
|
310
333
|
* 返回去重后的模型 ID 列表。
|
package/dist/config/index.js
CHANGED
|
@@ -13,6 +13,8 @@ export const CLAUDE_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
|
13
13
|
* Claude 官方 --permission-mode 枚举(claude --help 输出,2026-08 实测)。
|
|
14
14
|
* 额外支持 'default':Claude settings.json 的官方未设置值,等价于不传
|
|
15
15
|
* --permission-mode(交互式默认:高风险工具逐个询问)。
|
|
16
|
+
* 'manual' 是 'default' 的别名(claude CLI 等价),schema 保留以向后兼容旧配置,
|
|
17
|
+
* 但 UI 下拉不展示(见 router/config/claude.ts)。
|
|
16
18
|
*/
|
|
17
19
|
export const CLAUDE_PERMISSION_MODES = [
|
|
18
20
|
'default',
|
|
@@ -30,7 +32,9 @@ const DEFAULTS = {
|
|
|
30
32
|
CLAUDE_MODEL: 'claude-opus-4-8',
|
|
31
33
|
STOP_GRACE_MS: 5000,
|
|
32
34
|
IDLE_WATCHDOG_MINUTES: 15,
|
|
33
|
-
|
|
35
|
+
/** ACP/app-server turn idle 超时默认 30 分钟:Kimi/opencode/codex 常因
|
|
36
|
+
* 等待 SubAgent 或长思考长时间静默,10 分钟会误杀正常进行中的 run。 */
|
|
37
|
+
TURN_IDLE_TIMEOUT_MINUTES: 30,
|
|
34
38
|
/** 审批超时默认 5 分钟(对齐 codex 红线:勿随意改短)。 */
|
|
35
39
|
APPROVAL_TIMEOUT_MS: 5 * 60 * 1000,
|
|
36
40
|
/** Claude 会话级空闲回收默认 30 分钟(对齐 codex appServer.idleTtlMs)。 */
|
|
@@ -157,6 +161,27 @@ const KimiConfigSchema = z.object({
|
|
|
157
161
|
})
|
|
158
162
|
.optional(),
|
|
159
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(),
|
|
184
|
+
});
|
|
160
185
|
/** 首次启动的默认 agents 配置:codex 默认 app-server / on-request / workspace-write。 */
|
|
161
186
|
const DEFAULT_AGENTS_CONFIG = {
|
|
162
187
|
codex: CodexConfigSchema.parse({}),
|
|
@@ -167,6 +192,7 @@ const AgentsConfigSchema = z.object({
|
|
|
167
192
|
opencode: OpencodeConfigSchema.optional(),
|
|
168
193
|
pi: PiConfigSchema.optional(),
|
|
169
194
|
kimi: KimiConfigSchema.optional(),
|
|
195
|
+
dsh: DshConfigSchema.optional(),
|
|
170
196
|
});
|
|
171
197
|
const IdleConfigSchema = z.object({
|
|
172
198
|
/**
|
|
@@ -220,6 +246,11 @@ const AgentChoicesSchema = z.object({
|
|
|
220
246
|
thinkingEffort: z.string().optional(),
|
|
221
247
|
})
|
|
222
248
|
.optional(),
|
|
249
|
+
dsh: z
|
|
250
|
+
.object({
|
|
251
|
+
host: z.string().optional(),
|
|
252
|
+
})
|
|
253
|
+
.optional(),
|
|
223
254
|
});
|
|
224
255
|
export const AppConfigSchema = z.object({
|
|
225
256
|
feishu: FeishuConfigSchema,
|
|
@@ -235,7 +266,7 @@ export const AppConfigSchema = z.object({
|
|
|
235
266
|
/** 入站媒体(图片/文件)落盘配置。 */
|
|
236
267
|
inboundMedia: InboundMediaConfigSchema.default(InboundMediaConfigSchema.parse({})),
|
|
237
268
|
/** Default agent for new runs. */
|
|
238
|
-
defaultAgent: z.enum(['claude', 'codex', 'opencode', 'pi', 'kimi']).default('claude'),
|
|
269
|
+
defaultAgent: z.enum(['claude', 'codex', 'opencode', 'pi', 'kimi', 'dsh']).default('claude'),
|
|
239
270
|
/** Check for updates on bridge startup (default: false). */
|
|
240
271
|
checkUpdateOnStartup: z.boolean().default(false),
|
|
241
272
|
});
|
|
@@ -288,7 +319,7 @@ export function loadConfig(configPath) {
|
|
|
288
319
|
* Agent key 前缀,这些前缀的 key 会映射到 `agents.<key>` 路径下。
|
|
289
320
|
* `claude.` 保持顶层(不映射到 agents.claude)。
|
|
290
321
|
*/
|
|
291
|
-
const AGENT_PREFIXES = ['pi', 'codex', 'opencode', 'kimi'];
|
|
322
|
+
const AGENT_PREFIXES = ['pi', 'codex', 'opencode', 'kimi', 'dsh'];
|
|
292
323
|
/**
|
|
293
324
|
* 将卡片短 key 映射到 schema 期望的路径:
|
|
294
325
|
* pi.xxx → agents.pi.xxx
|
package/dist/index.js
CHANGED
|
@@ -3,13 +3,14 @@ import { resolveAgentChoices, } from './runner/index.js';
|
|
|
3
3
|
import { ensureConfig } from './config/wizard.js';
|
|
4
4
|
import { parseCliArgs, resolveConfigDir, setConfigDir, printHelp, printVersion, } from './config/dir.js';
|
|
5
5
|
import { FeishuConnector } from './connector/index.js';
|
|
6
|
-
import { ClaudeRunner, CodexAppServerRunner, OpencodeAcpRunner, PiRpcRunner, KimiAcpRunner, } from './runner/index.js';
|
|
6
|
+
import { ClaudeRunner, CodexAppServerRunner, OpencodeAcpRunner, PiRpcRunner, KimiAcpRunner, DshRunner, } from './runner/index.js';
|
|
7
7
|
import { AgentRegistry } from './runner/registry.js';
|
|
8
8
|
import { probeAllAgents } from './runner/probe.js';
|
|
9
9
|
import { SessionReaderRegistry, SessionStore } from './session/index.js';
|
|
10
|
-
import { ClaudeSessionReader, CodexSessionReader, OpencodeSessionReader, PiSessionReader, KimiSessionReader, } from './session/index.js';
|
|
10
|
+
import { ClaudeSessionReader, CodexSessionReader, OpencodeSessionReader, PiSessionReader, KimiSessionReader, DshSessionReader, } from './session/index.js';
|
|
11
11
|
import { CommandRouter, isImmediateAction } from './router/index.js';
|
|
12
12
|
import { dispatchOrderExecForQueue } from './router/order-exec-dispatch.js';
|
|
13
|
+
import { buildCardActionFullValue } from './router/card-action-payload.js';
|
|
13
14
|
import { Bridge } from './bridge/index.js';
|
|
14
15
|
import { initLogger, getLogger } from './logger/index.js';
|
|
15
16
|
import { StartupContactStore, sendStartupHello } from './startup-contact.js';
|
|
@@ -238,12 +239,33 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
238
239
|
});
|
|
239
240
|
});
|
|
240
241
|
sessionReaderRegistry.register('kimi', kimiSessionReader);
|
|
242
|
+
// Register DshRunner (HTTP-only DSH Web Host agent) and DshSessionReader.
|
|
243
|
+
const dshSessionReader = new DshSessionReader({
|
|
244
|
+
host: getAgentConfig(config, 'dsh')?.host,
|
|
245
|
+
});
|
|
246
|
+
agentRegistry.register('dsh', (_ws) => {
|
|
247
|
+
// Read latest config from container so /config host changes take effect
|
|
248
|
+
// after bridge.setConfig() + clearRunners().
|
|
249
|
+
const container = agentRegistry.getConfigContainer();
|
|
250
|
+
const latestConfig = container?.current ?? config;
|
|
251
|
+
const dshConf = getAgentConfig(latestConfig, 'dsh');
|
|
252
|
+
return new DshRunner({
|
|
253
|
+
kind: 'dsh',
|
|
254
|
+
sessionReader: dshSessionReader,
|
|
255
|
+
host: dshConf?.host,
|
|
256
|
+
agentPreset: dshConf?.agentPreset,
|
|
257
|
+
model: dshConf?.model,
|
|
258
|
+
reasoningEffort: dshConf?.reasoningEffort,
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
sessionReaderRegistry.register('dsh', dshSessionReader);
|
|
241
262
|
// 2026-07-17: 注册所有 agent 的显示名,实现单点真相
|
|
242
263
|
agentRegistry.registerDisplayName('claude', 'Claude');
|
|
243
264
|
agentRegistry.registerDisplayName('codex', 'Codex');
|
|
244
265
|
agentRegistry.registerDisplayName('opencode', 'Opencode');
|
|
245
266
|
agentRegistry.registerDisplayName('pi', 'Pi');
|
|
246
267
|
agentRegistry.registerDisplayName('kimi', 'Kimi');
|
|
268
|
+
agentRegistry.registerDisplayName('dsh', 'DSH');
|
|
247
269
|
// 设置全局 registry,供 agentDisplayName 等全局函数使用
|
|
248
270
|
AgentRegistry.setGlobalInstance(agentRegistry);
|
|
249
271
|
// Probe agent CLI availability (fire-and-forget, populates cache for /config card).
|
|
@@ -493,18 +515,10 @@ function setupMessageHandlers(connector, router, bridge, sessionStore, workspace
|
|
|
493
515
|
}
|
|
494
516
|
const isImmediate = isImmediateAction(actionValue.cmd);
|
|
495
517
|
const workspace = sessionStore.getCwd(userId) ?? '';
|
|
496
|
-
// Build full value object — spread all fields from actionValue,
|
|
497
|
-
//
|
|
498
|
-
//
|
|
499
|
-
const fullValue =
|
|
500
|
-
...actionValue,
|
|
501
|
-
option: action.action.option,
|
|
502
|
-
formValue: action.action.formValue,
|
|
503
|
-
// CardKit 2.0 input ✓ 提交图标:输入值走 raw.action.input_value(SDK normalizer
|
|
504
|
-
// 丢弃 action.action.input_value,需 connector includeRawEvent: true)。
|
|
505
|
-
inputValue: action.raw?.action?.input_value ??
|
|
506
|
-
action.action.input_value,
|
|
507
|
-
};
|
|
518
|
+
// Build full value object — spread all fields from actionValue, then merge
|
|
519
|
+
// component out-of-band fields (option/formValue/inputValue/options) where
|
|
520
|
+
// present. See card-action-payload.ts for the component-type contract.
|
|
521
|
+
const fullValue = buildCardActionFullValue(actionValue, action);
|
|
508
522
|
// queue.input / config.save / approval.respond / approval.toggle /
|
|
509
523
|
// approval.answer 系列返回 CardActionResponse toast 给点击用户即时反馈。
|
|
510
524
|
// 必须直接返回值 -- enqueueImmediate / enqueueConfigAction 是
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card action payload assembly (entry layer).
|
|
3
|
+
*
|
|
4
|
+
* Feishu card callbacks arrive as a normalized `CardActionEvent` whose
|
|
5
|
+
* `action` only carries `value/tag/name/option/formValue` — the
|
|
6
|
+
* `@larksuite/channel` normalizer drops everything else (e.g. `input_value`,
|
|
7
|
+
* multi-select `options`). This module rebuilds the full payload that the
|
|
8
|
+
* router consumes, merging the button's behavior `value` with component
|
|
9
|
+
* out-of-band fields.
|
|
10
|
+
*
|
|
11
|
+
* Extracted from src/index.ts so the entry transform is behavior-testable
|
|
12
|
+
* (the main() wiring itself cannot be injected, see index-wiring.test.ts).
|
|
13
|
+
*/
|
|
14
|
+
import type { CardActionEvent } from '@larksuite/channel';
|
|
15
|
+
import type { CardActionPayload } from './index.js';
|
|
16
|
+
/**
|
|
17
|
+
* Build the full card action payload for router.handleCardAction.
|
|
18
|
+
*
|
|
19
|
+
* - `option`/`formValue`: select/form components deliver the user's choice
|
|
20
|
+
* out-of-band in `action.option`/`action.formValue`; button callbacks carry
|
|
21
|
+
* it in the behavior `value` instead (and `action.option` is absent). The
|
|
22
|
+
* behavior-value field must survive for buttons, so the component field
|
|
23
|
+
* only wins when it is actually present.
|
|
24
|
+
* - `inputValue`: CardKit 2.0 input submit-icon callbacks deliver the text in
|
|
25
|
+
* the raw event (`action.raw.action.input_value`); the SDK normalizer drops
|
|
26
|
+
* `action.action.input_value`.
|
|
27
|
+
* - `options`: reserved for multi-select components (future agent support);
|
|
28
|
+
* the SDK normalizer drops `action.options`, so it is read from raw.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildCardActionFullValue(actionValue: CardActionPayload, action: CardActionEvent): CardActionPayload;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card action payload assembly (entry layer).
|
|
3
|
+
*
|
|
4
|
+
* Feishu card callbacks arrive as a normalized `CardActionEvent` whose
|
|
5
|
+
* `action` only carries `value/tag/name/option/formValue` — the
|
|
6
|
+
* `@larksuite/channel` normalizer drops everything else (e.g. `input_value`,
|
|
7
|
+
* multi-select `options`). This module rebuilds the full payload that the
|
|
8
|
+
* router consumes, merging the button's behavior `value` with component
|
|
9
|
+
* out-of-band fields.
|
|
10
|
+
*
|
|
11
|
+
* Extracted from src/index.ts so the entry transform is behavior-testable
|
|
12
|
+
* (the main() wiring itself cannot be injected, see index-wiring.test.ts).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Build the full card action payload for router.handleCardAction.
|
|
16
|
+
*
|
|
17
|
+
* - `option`/`formValue`: select/form components deliver the user's choice
|
|
18
|
+
* out-of-band in `action.option`/`action.formValue`; button callbacks carry
|
|
19
|
+
* it in the behavior `value` instead (and `action.option` is absent). The
|
|
20
|
+
* behavior-value field must survive for buttons, so the component field
|
|
21
|
+
* only wins when it is actually present.
|
|
22
|
+
* - `inputValue`: CardKit 2.0 input submit-icon callbacks deliver the text in
|
|
23
|
+
* the raw event (`action.raw.action.input_value`); the SDK normalizer drops
|
|
24
|
+
* `action.action.input_value`.
|
|
25
|
+
* - `options`: reserved for multi-select components (future agent support);
|
|
26
|
+
* the SDK normalizer drops `action.options`, so it is read from raw.
|
|
27
|
+
*/
|
|
28
|
+
export function buildCardActionFullValue(actionValue, action) {
|
|
29
|
+
return {
|
|
30
|
+
...actionValue,
|
|
31
|
+
option: action.action.option ?? actionValue.option,
|
|
32
|
+
formValue: action.action.formValue ?? actionValue.formValue,
|
|
33
|
+
options: action.raw?.action?.options ??
|
|
34
|
+
actionValue.options,
|
|
35
|
+
inputValue: action.raw?.action?.input_value ??
|
|
36
|
+
action.action.input_value,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=card-action-payload.js.map
|
|
@@ -11,11 +11,14 @@ const PERMISSION_MODE_LABELS = {
|
|
|
11
11
|
acceptEdits: '自动接受文件编辑',
|
|
12
12
|
auto: '自动放行低风险操作',
|
|
13
13
|
bypassPermissions: '跳过所有权限检查',
|
|
14
|
-
manual: '手动审批(default 的别名)',
|
|
15
14
|
dontAsk: '仅预先批准的工具',
|
|
16
15
|
plan: '计划模式(只读探索)',
|
|
17
16
|
};
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* 下拉选项排除 manual:manual 是 default 的别名(claude CLI 等价),
|
|
19
|
+
* 只保留 default 一个,避免下拉出现两个等价项。schema 仍接受 manual(旧配置向后兼容)。
|
|
20
|
+
*/
|
|
21
|
+
const PERMISSION_MODE_OPTIONS = CLAUDE_PERMISSION_MODES.filter((m) => m !== 'manual').map((m) => ({
|
|
19
22
|
text: `${m}(${PERMISSION_MODE_LABELS[m] ?? ''})`,
|
|
20
23
|
value: m,
|
|
21
24
|
}));
|
|
@@ -78,12 +81,14 @@ export class ClaudeConfigBuilder {
|
|
|
78
81
|
// 权限模式(Claude 官方 --permission-mode 枚举;bypassPermissions 为 schema 默认,
|
|
79
82
|
// 保持旧行为无审批卡,配置为其他值后激活交互式审批)
|
|
80
83
|
const currentPermissionMode = displayConfig.claude?.permissionMode ?? 'bypassPermissions';
|
|
84
|
+
// manual 是 default 的别名:旧配置按 default 显示(下拉无 manual 项,避免空选)
|
|
85
|
+
const displayedPermissionMode = currentPermissionMode === 'manual' ? 'default' : currentPermissionMode;
|
|
81
86
|
fields.push({
|
|
82
87
|
key: 'claude.permissionMode',
|
|
83
88
|
label: '权限模式',
|
|
84
89
|
type: 'select',
|
|
85
90
|
options: PERMISSION_MODE_OPTIONS,
|
|
86
|
-
currentValue:
|
|
91
|
+
currentValue: displayedPermissionMode,
|
|
87
92
|
});
|
|
88
93
|
return fields;
|
|
89
94
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DshConfigBuilder — /config card fields for the DSH agent.
|
|
3
|
+
*
|
|
4
|
+
* DSH (DeepSeek Harness) is an HTTP-only agent. Beyond the Web Host base URL it
|
|
5
|
+
* exposes three runtime-configurable knobs — preset, model, reasoning effort.
|
|
6
|
+
*
|
|
7
|
+
* 清单来源分两期:
|
|
8
|
+
* - 动态清单(当前实现):打开 /config 前通过 `llm.models` / `agentPreset.list`
|
|
9
|
+
* 预取(Router 调 `prefetch()`),失败/离线回退下方固定兜底清单,卡不依赖
|
|
10
|
+
* DSH 服务在线。
|
|
11
|
+
* - 三个可选字段用空字符串哨兵表示「跟随服务端默认」:select 的 value `''`
|
|
12
|
+
* 在 handleFieldChange 中被转成 undefined patch(router 删除键),config.yaml
|
|
13
|
+
* 不写该键 = 服务端默认。
|
|
14
|
+
*/
|
|
15
|
+
import type { AgentConfigCardBuilder, ConfigField } from './types.js';
|
|
16
|
+
import { type AppConfig } from '../../config/index.js';
|
|
17
|
+
import type { DshModelCatalogValue, DshPresetListValue } from '../../runner/dsh/types.js';
|
|
18
|
+
/** DshConfigBuilder 预取只依赖的 client 方法子集。 */
|
|
19
|
+
export interface DshCatalogClient {
|
|
20
|
+
listModels(): Promise<DshModelCatalogValue>;
|
|
21
|
+
listPresets(): Promise<DshPresetListValue>;
|
|
22
|
+
}
|
|
23
|
+
export declare class DshConfigBuilder implements AgentConfigCardBuilder {
|
|
24
|
+
/** 最近一次预取用的 host;host 变更时缓存失效(下一张卡重新拉取)。 */
|
|
25
|
+
private prefetchHost;
|
|
26
|
+
private modelCatalog;
|
|
27
|
+
private presets;
|
|
28
|
+
/** 可注入 client 工厂(测试用);默认生产实现。 */
|
|
29
|
+
private readonly clientFactory;
|
|
30
|
+
constructor(clientFactory?: (baseUrl: string) => DshCatalogClient);
|
|
31
|
+
/** 异步预取模型/预设目录(§4.2 二期动态清单)。失败/离线静默回退固定兜底清单,
|
|
32
|
+
* 卡不依赖 DSH 服务在线;同一 host 只拉一次,避免每次刷卡重复请求。 */
|
|
33
|
+
prefetch(host?: string): Promise<void>;
|
|
34
|
+
/** 同步注入 catalog/presets(测试用,替代异步 prefetch;标记 prefetchHost 使
|
|
35
|
+
* 后续 prefetch 短路,避免测试误触发网络请求)。 */
|
|
36
|
+
setCatalog(catalog: DshModelCatalogValue, presets?: DshPresetListValue): void;
|
|
37
|
+
/** 展平 llm.models 各 provider group 的模型 id;无 catalog 时回退固定清单。 */
|
|
38
|
+
private modelOptions;
|
|
39
|
+
/** preset 清单;无 presets 时回退固定清单。显示名优先用 preset.yml 的 name。 */
|
|
40
|
+
private presetOptions;
|
|
41
|
+
/** 模型在 catalog 中声明的推理档位;无 catalog/模型不在目录时回退固定档位。 */
|
|
42
|
+
private effortOptionsForModel;
|
|
43
|
+
buildFields(displayConfig: AppConfig): ConfigField[];
|
|
44
|
+
handleFieldChange(key: string, value: unknown, config: AppConfig): Array<{
|
|
45
|
+
key: string;
|
|
46
|
+
value: unknown;
|
|
47
|
+
}>;
|
|
48
|
+
/** 切到 newModel 后的档位补丁:当前档位仍被新模型支持 → 不产出;否则用新模型
|
|
49
|
+
* 目录中位;无目录/空列表 → undefined(清空 = 跟随服务端默认)。 */
|
|
50
|
+
private effortPatchForModel;
|
|
51
|
+
}
|