lark-remote 0.1.5 → 0.1.7
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 +39 -0
- package/README.en.md +5 -1
- package/README.md +10 -2
- package/dist/bridge/approval-coordinator.d.ts +131 -0
- package/dist/bridge/approval-coordinator.js +409 -0
- package/dist/bridge/inbound-media.d.ts +62 -0
- package/dist/bridge/inbound-media.js +282 -0
- package/dist/bridge/index.d.ts +138 -5
- package/dist/bridge/index.js +569 -65
- package/dist/bridge/queue-manager.d.ts +11 -1
- package/dist/bridge/queue-manager.js +20 -11
- package/dist/card/approval-render.d.ts +16 -0
- package/dist/card/approval-render.js +363 -0
- package/dist/card/bash-card-session.d.ts +2 -24
- package/dist/card/bash-card-session.js +6 -73
- package/dist/card/bash-renderer.js +2 -3
- package/dist/card/card-budget.js +29 -75
- package/dist/card/card-session.d.ts +48 -0
- package/dist/card/card-session.js +86 -0
- package/dist/card/card-shared.d.ts +13 -10
- package/dist/card/card-shared.js +27 -24
- package/dist/card/run-card-session.d.ts +2 -55
- package/dist/card/run-card-session.js +6 -104
- package/dist/card/run-renderer.js +140 -202
- package/dist/card/run-state.d.ts +38 -3
- package/dist/card/run-state.js +221 -11
- package/dist/card/text-truncate.d.ts +13 -12
- package/dist/card/text-truncate.js +13 -63
- package/dist/common/fs.d.ts +8 -0
- package/dist/common/fs.js +17 -0
- package/dist/common/guards.d.ts +0 -20
- package/dist/common/guards.js +0 -43
- package/dist/common/sleep.d.ts +2 -0
- package/dist/common/sleep.js +5 -0
- package/dist/common/truncate.d.ts +39 -0
- package/dist/common/truncate.js +92 -0
- package/dist/config/codex-config.d.ts +1 -1
- package/dist/config/codex-config.js +1 -1
- package/dist/config/dir.js +1 -1
- package/dist/config/index.d.ts +116 -9
- package/dist/config/index.js +122 -29
- package/dist/connector/index.d.ts +74 -2
- package/dist/connector/index.js +119 -1
- package/dist/index.js +139 -99
- package/dist/instance-lock.js +4 -12
- package/dist/order/alias-resolve.d.ts +13 -0
- package/dist/order/alias-resolve.js +22 -0
- package/dist/order/alias-store.d.ts +38 -0
- package/dist/order/alias-store.js +106 -0
- package/dist/persistence/atomic-write.d.ts +8 -2
- package/dist/persistence/atomic-write.js +23 -7
- package/dist/restart.js +2 -1
- package/dist/router/card-helpers.d.ts +63 -0
- package/dist/router/card-helpers.js +146 -0
- package/dist/router/config/claude.js +25 -1
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +33 -5
- package/dist/router/config/common/model-patch.d.ts +22 -0
- package/dist/router/config/common/model-patch.js +26 -0
- package/dist/router/config/common/render.js +9 -4
- package/dist/router/config/index.d.ts +12 -0
- package/dist/router/config/index.js +25 -1
- package/dist/router/config/kimi.d.ts +4 -1
- package/dist/router/config/kimi.js +27 -0
- package/dist/router/config/opencode.js +18 -5
- package/dist/router/config/pi.js +4 -5
- package/dist/router/config/types.d.ts +12 -3
- package/dist/router/index.d.ts +77 -17
- package/dist/router/index.js +455 -549
- package/dist/router/utils.d.ts +4 -0
- package/dist/router/utils.js +9 -2
- package/dist/runner/agent-choices-common.d.ts +16 -0
- package/dist/runner/agent-choices-common.js +31 -0
- package/dist/runner/claude/runner.d.ts +47 -10
- package/dist/runner/claude/runner.js +117 -46
- package/dist/runner/claude/session.d.ts +166 -0
- package/dist/runner/claude/session.js +749 -0
- package/dist/runner/codex/app-server/protocol-types.d.ts +519 -0
- package/dist/runner/codex/app-server/protocol-types.js +56 -0
- package/dist/runner/codex/app-server/runner.d.ts +104 -0
- package/dist/runner/codex/app-server/runner.js +377 -0
- package/dist/runner/codex/app-server/translator.d.ts +89 -0
- package/dist/runner/codex/app-server/translator.js +716 -0
- package/dist/runner/codex/index.d.ts +1 -1
- package/dist/runner/codex/index.js +1 -1
- package/dist/runner/common/acp/protocol-helpers.d.ts +14 -0
- package/dist/runner/common/acp/protocol-helpers.js +21 -0
- package/dist/runner/common/acp/protocol-types.d.ts +238 -0
- package/dist/runner/common/acp/protocol-types.js +75 -0
- package/dist/runner/common/connection-based-runner.d.ts +111 -0
- package/dist/runner/common/connection-based-runner.js +261 -0
- package/dist/runner/common/jsonrpc/client.d.ts +89 -0
- package/dist/runner/common/jsonrpc/client.js +243 -0
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +125 -0
- package/dist/runner/common/jsonrpc/connection-manager.js +205 -0
- package/dist/runner/common/jsonrpc/transport.d.ts +50 -0
- package/dist/runner/common/jsonrpc/transport.js +230 -0
- package/dist/runner/common/jsonrpc/types.d.ts +32 -0
- package/dist/runner/common/jsonrpc/types.js +9 -0
- package/dist/runner/common/process-stopper.d.ts +2 -1
- package/dist/runner/common/process-stopper.js +1 -0
- package/dist/runner/common/runner-utils.d.ts +6 -13
- package/dist/runner/common/runner-utils.js +6 -47
- package/dist/runner/common/spawning-runner.d.ts +24 -70
- package/dist/runner/common/spawning-runner.js +98 -152
- package/dist/runner/common/usage.d.ts +2 -0
- package/dist/runner/common/usage.js +2 -0
- package/dist/runner/index.d.ts +5 -5
- package/dist/runner/index.js +4 -4
- package/dist/runner/kimi/acp/runner.d.ts +106 -0
- package/dist/runner/kimi/acp/runner.js +448 -0
- package/dist/runner/kimi/acp/translator.d.ts +124 -0
- package/dist/runner/kimi/acp/translator.js +336 -0
- package/dist/runner/kimi/index.d.ts +1 -1
- package/dist/runner/kimi/index.js +1 -1
- package/dist/runner/opencode/acp/index.d.ts +1 -0
- package/dist/runner/opencode/acp/index.js +2 -0
- package/dist/runner/opencode/acp/runner.d.ts +121 -0
- package/dist/runner/opencode/acp/runner.js +429 -0
- package/dist/runner/opencode/acp/translator.d.ts +119 -0
- package/dist/runner/opencode/acp/translator.js +345 -0
- package/dist/runner/opencode/index.d.ts +1 -1
- package/dist/runner/opencode/index.js +1 -1
- package/dist/runner/pi/index.d.ts +1 -1
- package/dist/runner/pi/index.js +1 -1
- package/dist/runner/pi/rpc/client.d.ts +52 -0
- package/dist/runner/pi/rpc/client.js +114 -0
- package/dist/runner/pi/rpc/index.d.ts +4 -0
- package/dist/runner/pi/rpc/index.js +4 -0
- package/dist/runner/pi/rpc/protocol-types.d.ts +127 -0
- package/dist/runner/pi/rpc/protocol-types.js +21 -0
- package/dist/runner/pi/rpc/runner.d.ts +80 -0
- package/dist/runner/pi/rpc/runner.js +199 -0
- package/dist/runner/pi/rpc/translator.d.ts +55 -0
- package/dist/runner/pi/rpc/translator.js +258 -0
- package/dist/runner/registry.d.ts +7 -8
- package/dist/runner/registry.js +3 -4
- package/dist/runner/resolve-agent-choices.js +18 -59
- package/dist/runner/sync-agent-choices.js +16 -67
- package/dist/runner/types.d.ts +153 -2
- package/dist/session/claude/session-index.js +2 -3
- package/dist/session/claude/session-reader.js +3 -6
- package/dist/session/claude/sessions.js +6 -13
- package/dist/session/codex/rollout-reader.d.ts +2 -2
- package/dist/session/codex/rollout-reader.js +57 -17
- package/dist/session/codex/sessions.d.ts +1 -1
- package/dist/session/codex/sessions.js +2 -2
- package/dist/session/common/content-blocks.d.ts +7 -0
- package/dist/session/common/content-blocks.js +13 -9
- package/dist/session/common/jsonl.d.ts +8 -25
- package/dist/session/common/jsonl.js +126 -261
- package/dist/session/common/pagination.d.ts +28 -0
- package/dist/session/common/pagination.js +33 -0
- package/dist/session/kimi/sessions.d.ts +34 -1
- package/dist/session/kimi/sessions.js +208 -98
- package/dist/session/opencode/sessions.d.ts +17 -3
- package/dist/session/opencode/sessions.js +29 -29
- package/dist/session/pi/sessions.d.ts +5 -1
- package/dist/session/pi/sessions.js +12 -16
- package/dist/session/session-store.d.ts +11 -1
- package/dist/session/session-store.js +75 -178
- package/dist/update/index.d.ts +2 -2
- package/dist/update/index.js +2 -2
- package/dist/update/install.d.ts +20 -2
- package/dist/update/install.js +51 -7
- package/package.json +1 -1
- package/dist/runner/codex/argv.d.ts +0 -33
- package/dist/runner/codex/argv.js +0 -40
- package/dist/runner/codex/jsonl.d.ts +0 -37
- package/dist/runner/codex/jsonl.js +0 -221
- package/dist/runner/codex/runner.d.ts +0 -63
- package/dist/runner/codex/runner.js +0 -124
- package/dist/runner/common/exec-translator.d.ts +0 -73
- package/dist/runner/common/exec-translator.js +0 -105
- package/dist/runner/kimi/jsonl.d.ts +0 -28
- package/dist/runner/kimi/jsonl.js +0 -143
- package/dist/runner/kimi/runner.d.ts +0 -49
- package/dist/runner/kimi/runner.js +0 -105
- package/dist/runner/opencode/argv.d.ts +0 -32
- package/dist/runner/opencode/argv.js +0 -35
- package/dist/runner/opencode/jsonl.d.ts +0 -68
- package/dist/runner/opencode/jsonl.js +0 -295
- package/dist/runner/opencode/runner.d.ts +0 -61
- package/dist/runner/opencode/runner.js +0 -93
- package/dist/runner/pi/jsonl.d.ts +0 -128
- package/dist/runner/pi/jsonl.js +0 -249
- package/dist/runner/pi/runner.d.ts +0 -36
- package/dist/runner/pi/runner.js +0 -76
- package/dist/session/common/catch-up.d.ts +0 -12
- package/dist/session/common/catch-up.js +0 -31
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared text truncation primitives.
|
|
3
|
+
*
|
|
4
|
+
* Centralizes the two truncation utilities previously split across the card
|
|
5
|
+
* layer (`card-shared.ts` char-based `truncate` and `card/text-truncate.ts`
|
|
6
|
+
* byte-safe `truncateUtf8`). Session readers import from here instead of the
|
|
7
|
+
* card layer (fixing the layer inversion), and the card layer re-exports for
|
|
8
|
+
* backward compatibility.
|
|
9
|
+
*/
|
|
10
|
+
/** Default truncation suffix, shared across all consumers for UX consistency. */
|
|
11
|
+
export const DEFAULT_TRUNCATE_SUFFIX = '…(已截断)';
|
|
12
|
+
/**
|
|
13
|
+
* Max byte budget for a single session `tool_result` event's content when
|
|
14
|
+
* replaying an opencode session (L2 pre-fold). Pre-folding here bounds the
|
|
15
|
+
* in-memory `events[]` array and the intermediate card JSON so a single
|
|
16
|
+
* pathological tool_result never inflates the replay payload to megabytes.
|
|
17
|
+
*/
|
|
18
|
+
export const TOOL_RESULT_MAX_BYTES = 4000;
|
|
19
|
+
/**
|
|
20
|
+
* Fit a UTF-8 string into `maxBytes` by iterating Unicode codepoints, never
|
|
21
|
+
* splitting a multi-byte sequence. When `fromEnd` is true, keeps the TAIL
|
|
22
|
+
* (useful for logs/tails); otherwise keeps the HEAD.
|
|
23
|
+
*/
|
|
24
|
+
export function fitUtf8(value, maxBytes, fromEnd = false) {
|
|
25
|
+
if (fromEnd) {
|
|
26
|
+
const codepoints = Array.from(value);
|
|
27
|
+
let bytes = 0;
|
|
28
|
+
let start = codepoints.length;
|
|
29
|
+
for (let i = codepoints.length - 1; i >= 0; i--) {
|
|
30
|
+
const cb = Buffer.byteLength(codepoints[i], 'utf8');
|
|
31
|
+
if (bytes + cb > maxBytes)
|
|
32
|
+
break;
|
|
33
|
+
bytes += cb;
|
|
34
|
+
start = i;
|
|
35
|
+
}
|
|
36
|
+
return codepoints.slice(start).join('');
|
|
37
|
+
}
|
|
38
|
+
// head 分支:惰性 for-of 迭代 + 字符串索引累计(O(1) 内存)。
|
|
39
|
+
let bytes = 0;
|
|
40
|
+
let end = 0;
|
|
41
|
+
for (const char of value) {
|
|
42
|
+
const cb = Buffer.byteLength(char, 'utf8');
|
|
43
|
+
if (bytes + cb > maxBytes)
|
|
44
|
+
break;
|
|
45
|
+
bytes += cb;
|
|
46
|
+
end += char.length;
|
|
47
|
+
}
|
|
48
|
+
return value.slice(0, end);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Truncate a UTF-8 string to fit within `maxBytes`, appending `suffix`
|
|
52
|
+
* (default `…(已截断)`) when truncation occurs. When `fromEnd` is true, keeps
|
|
53
|
+
* the tail and prepends the suffix (useful for "show the most recent N bytes").
|
|
54
|
+
*/
|
|
55
|
+
export function truncateUtf8(value, maxBytes, fromEnd = false, suffix = DEFAULT_TRUNCATE_SUFFIX) {
|
|
56
|
+
if (Buffer.byteLength(value, 'utf8') <= maxBytes)
|
|
57
|
+
return value;
|
|
58
|
+
const suffixBytes = Buffer.byteLength(suffix, 'utf8');
|
|
59
|
+
const budget = maxBytes - suffixBytes;
|
|
60
|
+
if (budget <= 0)
|
|
61
|
+
return suffix;
|
|
62
|
+
const truncated = fitUtf8(value, budget, fromEnd);
|
|
63
|
+
return fromEnd ? `${suffix}\n${truncated}` : `${truncated}${suffix}`;
|
|
64
|
+
}
|
|
65
|
+
/** Char-based truncation with optional suffix / whitespace normalization. */
|
|
66
|
+
export function truncate(str, max, options) {
|
|
67
|
+
const suffix = options?.suffix ?? '…';
|
|
68
|
+
const normalize = options?.normalizeWhitespace ?? false;
|
|
69
|
+
let s = str;
|
|
70
|
+
if (normalize)
|
|
71
|
+
s = s.replace(/\s+/g, ' ').trim();
|
|
72
|
+
if (s.length <= max)
|
|
73
|
+
return s;
|
|
74
|
+
const suffixLen = suffix.length;
|
|
75
|
+
const budget = max - suffixLen;
|
|
76
|
+
if (budget <= 0)
|
|
77
|
+
return suffix;
|
|
78
|
+
// Iterate by Unicode codepoint (for...of) so the cut never lands inside a
|
|
79
|
+
// surrogate pair (P2-31 anchor: must not emit a lone surrogate).
|
|
80
|
+
let end = 0;
|
|
81
|
+
for (const ch of s) {
|
|
82
|
+
if (end + ch.length > budget)
|
|
83
|
+
break;
|
|
84
|
+
end += ch.length; // 1 (BMP) or 2 (surrogate pair) — slice lands on a boundary
|
|
85
|
+
}
|
|
86
|
+
return s.slice(0, end) + suffix;
|
|
87
|
+
}
|
|
88
|
+
/** Char-level tail keep (used for store-time caps, e.g. bash output). */
|
|
89
|
+
export function keepTail(value, maxChars) {
|
|
90
|
+
return value.length <= maxChars ? value : value.slice(-maxChars);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=truncate.js.map
|
|
@@ -80,7 +80,7 @@ export declare function getCodexCatalogModels(codexHome?: string): BundledModelI
|
|
|
80
80
|
/**
|
|
81
81
|
* Test utility: clear the catalog cache. Tests that exercise the bundled
|
|
82
82
|
* command path (`--bundled`) directly use `invalidateCodexBundledTestCache`
|
|
83
|
-
* from `codex-bundled-test-helpers.ts`.
|
|
83
|
+
* from `tests/lib/codex-bundled-test-helpers.ts`.
|
|
84
84
|
*/
|
|
85
85
|
export declare function invalidateCodexBundledCache(): void;
|
|
86
86
|
/**
|
|
@@ -208,7 +208,7 @@ export function getCodexCatalogModels(codexHome) {
|
|
|
208
208
|
/**
|
|
209
209
|
* Test utility: clear the catalog cache. Tests that exercise the bundled
|
|
210
210
|
* command path (`--bundled`) directly use `invalidateCodexBundledTestCache`
|
|
211
|
-
* from `codex-bundled-test-helpers.ts`.
|
|
211
|
+
* from `tests/lib/codex-bundled-test-helpers.ts`.
|
|
212
212
|
*/
|
|
213
213
|
export function invalidateCodexBundledCache() {
|
|
214
214
|
catalogCache = null;
|
package/dist/config/dir.js
CHANGED
|
@@ -79,7 +79,7 @@ export function printHelp() {
|
|
|
79
79
|
'Options:',
|
|
80
80
|
' --config-dir <path> 自定义配置目录(默认 ~/.lark-remote,可用于同机多实例)',
|
|
81
81
|
' --settings <path> 指定 Claude 配置文件路径',
|
|
82
|
-
' --dev 开发模式:标记从源码 bun src/index.ts
|
|
82
|
+
' --dev 开发模式:标记从源码 bun src/index.ts 启动(看门狗据此选择拉起方式)',
|
|
83
83
|
' --update 升级到最新版本后退出(用于 cron/脚本自动化升级)',
|
|
84
84
|
' -h, --help 显示本帮助信息',
|
|
85
85
|
' -v, --version 显示版本号',
|
package/dist/config/index.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ 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
|
+
*/
|
|
10
|
+
export declare const CLAUDE_PERMISSION_MODES: readonly ["default", "acceptEdits", "auto", "bypassPermissions", "manual", "dontAsk", "plan"];
|
|
5
11
|
/** Valid thinking levels for Pi */
|
|
6
12
|
export declare const PI_THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
7
13
|
/**
|
|
@@ -10,6 +16,11 @@ export declare const PI_THINKING_LEVELS: readonly ["off", "minimal", "low", "med
|
|
|
10
16
|
* instead of re-literalizing `5000` (Clean Code P3-1, G25).
|
|
11
17
|
*/
|
|
12
18
|
export declare const DEFAULT_STOP_GRACE_MS: 5000;
|
|
19
|
+
/** Codex app-server turn idle timeout default (minutes). */
|
|
20
|
+
export declare const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES: 10;
|
|
21
|
+
/** 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。 */
|
|
22
|
+
export declare const DEFAULT_INBOUND_MEDIA_DIR_NAME = ".lark-remote-temp";
|
|
23
|
+
export declare const DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB = 50;
|
|
13
24
|
/** 模型 ID → alias 映射。 */
|
|
14
25
|
export declare const MODEL_ID_TO_ALIAS: Record<string, string>;
|
|
15
26
|
/** alias → model ID 反向映射。 */
|
|
@@ -18,11 +29,22 @@ declare const ClaudeConfigSchema: z.ZodObject<{
|
|
|
18
29
|
model: z.ZodDefault<z.ZodString>;
|
|
19
30
|
effort: z.ZodDefault<z.ZodEnum<{
|
|
20
31
|
medium: "medium";
|
|
21
|
-
max: "max";
|
|
22
32
|
low: "low";
|
|
23
33
|
high: "high";
|
|
24
34
|
xhigh: "xhigh";
|
|
35
|
+
max: "max";
|
|
25
36
|
}>>;
|
|
37
|
+
permissionMode: z.ZodDefault<z.ZodEnum<{
|
|
38
|
+
default: "default";
|
|
39
|
+
plan: "plan";
|
|
40
|
+
bypassPermissions: "bypassPermissions";
|
|
41
|
+
auto: "auto";
|
|
42
|
+
manual: "manual";
|
|
43
|
+
acceptEdits: "acceptEdits";
|
|
44
|
+
dontAsk: "dontAsk";
|
|
45
|
+
}>>;
|
|
46
|
+
approvalTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
47
|
+
idleTtlMinutes: z.ZodDefault<z.ZodNumber>;
|
|
26
48
|
stopGraceMs: z.ZodDefault<z.ZodNumber>;
|
|
27
49
|
}, z.core.$strip>;
|
|
28
50
|
/** Codex-specific configuration. */
|
|
@@ -30,12 +52,31 @@ export declare const CodexConfigSchema: z.ZodObject<{
|
|
|
30
52
|
model: z.ZodOptional<z.ZodString>;
|
|
31
53
|
modelProvider: z.ZodOptional<z.ZodString>;
|
|
32
54
|
reasoningEffort: z.ZodOptional<z.ZodString>;
|
|
33
|
-
|
|
55
|
+
approvalPolicy: z.ZodDefault<z.ZodEnum<{
|
|
56
|
+
untrusted: "untrusted";
|
|
57
|
+
"on-request": "on-request";
|
|
58
|
+
never: "never";
|
|
59
|
+
}>>;
|
|
60
|
+
sandbox: z.ZodDefault<z.ZodEnum<{
|
|
61
|
+
"read-only": "read-only";
|
|
62
|
+
"workspace-write": "workspace-write";
|
|
63
|
+
"danger-full-access": "danger-full-access";
|
|
64
|
+
}>>;
|
|
65
|
+
appServer: z.ZodOptional<z.ZodObject<{
|
|
66
|
+
binary: z.ZodDefault<z.ZodString>;
|
|
67
|
+
requestTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
68
|
+
idleTtlMs: z.ZodDefault<z.ZodNumber>;
|
|
69
|
+
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
70
|
+
}, z.core.$strip>>;
|
|
34
71
|
}, z.core.$strip>;
|
|
35
72
|
/** OpenCode-specific configuration (run mode: opencode run --format json --auto). */
|
|
36
73
|
declare const OpencodeConfigSchema: z.ZodObject<{
|
|
37
74
|
providerID: z.ZodDefault<z.ZodString>;
|
|
38
75
|
modelID: z.ZodDefault<z.ZodString>;
|
|
76
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
77
|
+
plan: "plan";
|
|
78
|
+
build: "build";
|
|
79
|
+
}>>;
|
|
39
80
|
}, z.core.$strip>;
|
|
40
81
|
/** Pi-specific configuration. pi is a spawn-per-message CLI like Claude. */
|
|
41
82
|
declare const PiConfigSchema: z.ZodObject<{
|
|
@@ -51,14 +92,25 @@ declare const PiConfigSchema: z.ZodObject<{
|
|
|
51
92
|
}>>;
|
|
52
93
|
tools: z.ZodDefault<z.ZodString>;
|
|
53
94
|
}, z.core.$strip>;
|
|
54
|
-
/** Kimi-specific configuration.
|
|
95
|
+
/** Kimi-specific configuration. Pure ACP mode (persistent `kimi acp` connection). */
|
|
55
96
|
declare const KimiConfigSchema: z.ZodObject<{
|
|
56
97
|
model: z.ZodDefault<z.ZodString>;
|
|
57
98
|
thinkingEffort: z.ZodDefault<z.ZodEnum<{
|
|
58
|
-
max: "max";
|
|
59
99
|
low: "low";
|
|
60
100
|
high: "high";
|
|
101
|
+
max: "max";
|
|
61
102
|
}>>;
|
|
103
|
+
permissionMode: z.ZodDefault<z.ZodEnum<{
|
|
104
|
+
auto: "auto";
|
|
105
|
+
yolo: "yolo";
|
|
106
|
+
manual: "manual";
|
|
107
|
+
}>>;
|
|
108
|
+
acp: z.ZodOptional<z.ZodObject<{
|
|
109
|
+
binary: z.ZodDefault<z.ZodString>;
|
|
110
|
+
requestTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
111
|
+
idleTtlMs: z.ZodDefault<z.ZodNumber>;
|
|
112
|
+
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
113
|
+
}, z.core.$strip>>;
|
|
62
114
|
}, z.core.$strip>;
|
|
63
115
|
export declare const AppConfigSchema: z.ZodObject<{
|
|
64
116
|
feishu: z.ZodObject<{
|
|
@@ -69,23 +121,53 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
69
121
|
model: z.ZodDefault<z.ZodString>;
|
|
70
122
|
effort: z.ZodDefault<z.ZodEnum<{
|
|
71
123
|
medium: "medium";
|
|
72
|
-
max: "max";
|
|
73
124
|
low: "low";
|
|
74
125
|
high: "high";
|
|
75
126
|
xhigh: "xhigh";
|
|
127
|
+
max: "max";
|
|
128
|
+
}>>;
|
|
129
|
+
permissionMode: z.ZodDefault<z.ZodEnum<{
|
|
130
|
+
default: "default";
|
|
131
|
+
plan: "plan";
|
|
132
|
+
bypassPermissions: "bypassPermissions";
|
|
133
|
+
auto: "auto";
|
|
134
|
+
manual: "manual";
|
|
135
|
+
acceptEdits: "acceptEdits";
|
|
136
|
+
dontAsk: "dontAsk";
|
|
76
137
|
}>>;
|
|
138
|
+
approvalTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
139
|
+
idleTtlMinutes: z.ZodDefault<z.ZodNumber>;
|
|
77
140
|
stopGraceMs: z.ZodDefault<z.ZodNumber>;
|
|
78
141
|
}, z.core.$strip>>;
|
|
79
|
-
agents: z.
|
|
80
|
-
codex: z.
|
|
142
|
+
agents: z.ZodDefault<z.ZodObject<{
|
|
143
|
+
codex: z.ZodDefault<z.ZodObject<{
|
|
81
144
|
model: z.ZodOptional<z.ZodString>;
|
|
82
145
|
modelProvider: z.ZodOptional<z.ZodString>;
|
|
83
146
|
reasoningEffort: z.ZodOptional<z.ZodString>;
|
|
84
|
-
|
|
147
|
+
approvalPolicy: z.ZodDefault<z.ZodEnum<{
|
|
148
|
+
untrusted: "untrusted";
|
|
149
|
+
"on-request": "on-request";
|
|
150
|
+
never: "never";
|
|
151
|
+
}>>;
|
|
152
|
+
sandbox: z.ZodDefault<z.ZodEnum<{
|
|
153
|
+
"read-only": "read-only";
|
|
154
|
+
"workspace-write": "workspace-write";
|
|
155
|
+
"danger-full-access": "danger-full-access";
|
|
156
|
+
}>>;
|
|
157
|
+
appServer: z.ZodOptional<z.ZodObject<{
|
|
158
|
+
binary: z.ZodDefault<z.ZodString>;
|
|
159
|
+
requestTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
160
|
+
idleTtlMs: z.ZodDefault<z.ZodNumber>;
|
|
161
|
+
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
162
|
+
}, z.core.$strip>>;
|
|
85
163
|
}, z.core.$strip>>;
|
|
86
164
|
opencode: z.ZodOptional<z.ZodObject<{
|
|
87
165
|
providerID: z.ZodDefault<z.ZodString>;
|
|
88
166
|
modelID: z.ZodDefault<z.ZodString>;
|
|
167
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
168
|
+
plan: "plan";
|
|
169
|
+
build: "build";
|
|
170
|
+
}>>;
|
|
89
171
|
}, z.core.$strip>>;
|
|
90
172
|
pi: z.ZodOptional<z.ZodObject<{
|
|
91
173
|
provider: z.ZodDefault<z.ZodString>;
|
|
@@ -103,10 +185,21 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
103
185
|
kimi: z.ZodOptional<z.ZodObject<{
|
|
104
186
|
model: z.ZodDefault<z.ZodString>;
|
|
105
187
|
thinkingEffort: z.ZodDefault<z.ZodEnum<{
|
|
106
|
-
max: "max";
|
|
107
188
|
low: "low";
|
|
108
189
|
high: "high";
|
|
190
|
+
max: "max";
|
|
191
|
+
}>>;
|
|
192
|
+
permissionMode: z.ZodDefault<z.ZodEnum<{
|
|
193
|
+
auto: "auto";
|
|
194
|
+
yolo: "yolo";
|
|
195
|
+
manual: "manual";
|
|
109
196
|
}>>;
|
|
197
|
+
acp: z.ZodOptional<z.ZodObject<{
|
|
198
|
+
binary: z.ZodDefault<z.ZodString>;
|
|
199
|
+
requestTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
200
|
+
idleTtlMs: z.ZodDefault<z.ZodNumber>;
|
|
201
|
+
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
202
|
+
}, z.core.$strip>>;
|
|
110
203
|
}, z.core.$strip>>;
|
|
111
204
|
}, z.core.$strip>>;
|
|
112
205
|
agentChoices: z.ZodOptional<z.ZodObject<{
|
|
@@ -144,6 +237,11 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
144
237
|
error: "error";
|
|
145
238
|
}>>;
|
|
146
239
|
}, z.core.$strip>>;
|
|
240
|
+
inboundMedia: z.ZodDefault<z.ZodObject<{
|
|
241
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
242
|
+
dirName: z.ZodDefault<z.ZodString>;
|
|
243
|
+
maxFileSizeMb: z.ZodDefault<z.ZodNumber>;
|
|
244
|
+
}, z.core.$strip>>;
|
|
147
245
|
defaultAgent: z.ZodDefault<z.ZodEnum<{
|
|
148
246
|
claude: "claude";
|
|
149
247
|
codex: "codex";
|
|
@@ -175,6 +273,15 @@ export declare function mapAgentKey(key: string): string;
|
|
|
175
273
|
* config 路径中不存在,写/删/读三条路径统一拒绝。
|
|
176
274
|
*/
|
|
177
275
|
export declare function assertSafeKeyPart(part: string): void;
|
|
276
|
+
/**
|
|
277
|
+
* 按 dot-separated key 下钻到目标键的父容器(不含最后一段)。
|
|
278
|
+
*
|
|
279
|
+
* - create=true:中间缺失/非对象段自动补 `{}`(set 语义)
|
|
280
|
+
* - create=false:中间缺失/非对象段返回 undefined(get/delete 语义)
|
|
281
|
+
*
|
|
282
|
+
* 危险段(__proto__/prototype/constructor)在每段统一拒绝。
|
|
283
|
+
*/
|
|
284
|
+
export declare function walkNestedContainer(target: unknown, parts: string[], create: boolean): Record<string, unknown> | undefined;
|
|
178
285
|
/** Get a nested value from config by dot-separated key, e.g. "feishu.appId" */
|
|
179
286
|
export declare function getConfigValue(config: AppConfig, key: string): unknown;
|
|
180
287
|
/** Set a nested value in config by dot-separated key, write back to YAML file */
|
package/dist/config/index.js
CHANGED
|
@@ -9,6 +9,20 @@ 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
|
+
*/
|
|
17
|
+
export const CLAUDE_PERMISSION_MODES = [
|
|
18
|
+
'default',
|
|
19
|
+
'acceptEdits',
|
|
20
|
+
'auto',
|
|
21
|
+
'bypassPermissions',
|
|
22
|
+
'manual',
|
|
23
|
+
'dontAsk',
|
|
24
|
+
'plan',
|
|
25
|
+
];
|
|
12
26
|
/** Valid thinking levels for Pi */
|
|
13
27
|
export const PI_THINKING_LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
14
28
|
/** 默认值常量:schema 与 template 共享,避免双源不一致(G25 Magic Numbers)。 */
|
|
@@ -16,6 +30,11 @@ const DEFAULTS = {
|
|
|
16
30
|
CLAUDE_MODEL: 'claude-opus-4-8',
|
|
17
31
|
STOP_GRACE_MS: 5000,
|
|
18
32
|
IDLE_WATCHDOG_MINUTES: 15,
|
|
33
|
+
TURN_IDLE_TIMEOUT_MINUTES: 10,
|
|
34
|
+
/** 审批超时默认 5 分钟(对齐 codex 红线:勿随意改短)。 */
|
|
35
|
+
APPROVAL_TIMEOUT_MS: 5 * 60 * 1000,
|
|
36
|
+
/** Claude 会话级空闲回收默认 30 分钟(对齐 codex appServer.idleTtlMs)。 */
|
|
37
|
+
CLAUDE_IDLE_TTL_MINUTES: 30,
|
|
19
38
|
};
|
|
20
39
|
/**
|
|
21
40
|
* Default SIGTERM→SIGKILL grace period (ms). Exported so runners (SpawningRunner)
|
|
@@ -23,6 +42,11 @@ const DEFAULTS = {
|
|
|
23
42
|
* instead of re-literalizing `5000` (Clean Code P3-1, G25).
|
|
24
43
|
*/
|
|
25
44
|
export const DEFAULT_STOP_GRACE_MS = DEFAULTS.STOP_GRACE_MS;
|
|
45
|
+
/** Codex app-server turn idle timeout default (minutes). */
|
|
46
|
+
export const DEFAULT_TURN_IDLE_TIMEOUT_MINUTES = DEFAULTS.TURN_IDLE_TIMEOUT_MINUTES;
|
|
47
|
+
/** 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。 */
|
|
48
|
+
export const DEFAULT_INBOUND_MEDIA_DIR_NAME = '.lark-remote-temp';
|
|
49
|
+
export const DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB = 50;
|
|
26
50
|
/** 模型 ID → alias 映射。 */
|
|
27
51
|
export const MODEL_ID_TO_ALIAS = {
|
|
28
52
|
'claude-opus-4-8': 'opus',
|
|
@@ -44,16 +68,37 @@ const FeishuConfigSchema = z.object({
|
|
|
44
68
|
const ClaudeConfigSchema = z.object({
|
|
45
69
|
model: z.string().default(DEFAULTS.CLAUDE_MODEL),
|
|
46
70
|
effort: z.enum(CLAUDE_EFFORTS).default('medium'),
|
|
47
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Claude 权限模式(官方 --permission-mode 枚举 + 'default'=省略该参数)。
|
|
73
|
+
* 默认 bypassPermissions 保持现有行为(无审批卡);配置为其他值后激活
|
|
74
|
+
* 交互式审批(control_request → run 卡审批区)。
|
|
75
|
+
*/
|
|
76
|
+
permissionMode: z.enum(CLAUDE_PERMISSION_MODES).default('bypassPermissions'),
|
|
77
|
+
/** 审批请求超时(ms),默认 5 分钟;超时自动发送 cancel 并中断 turn。
|
|
78
|
+
* 0 = 立即过期(fail-fast,避免审批永久挂起),不推荐;勿随意改短。 */
|
|
79
|
+
approvalTimeoutMs: z.number().int().min(0).default(DEFAULTS.APPROVAL_TIMEOUT_MS),
|
|
80
|
+
/** 会话级空闲回收(分钟):turn 之间无新消息超过该窗口则停止长驻进程。 */
|
|
81
|
+
idleTtlMinutes: z.number().int().min(0).default(DEFAULTS.CLAUDE_IDLE_TTL_MINUTES),
|
|
48
82
|
stopGraceMs: z.number().int().min(0).default(DEFAULTS.STOP_GRACE_MS),
|
|
49
83
|
});
|
|
84
|
+
/** Codex app-server connection configuration. */
|
|
85
|
+
const CodexAppServerConfigSchema = z.object({
|
|
86
|
+
/** Path to the codex binary for app-server mode. */
|
|
87
|
+
binary: z.string().default('codex'),
|
|
88
|
+
/** Request timeout in milliseconds. */
|
|
89
|
+
requestTimeoutMs: z.number().int().min(0).default(60000),
|
|
90
|
+
/** Idle TTL for connection pool in milliseconds. */
|
|
91
|
+
idleTtlMs: z.number().int().min(0).default(1800000),
|
|
92
|
+
/** Turn idle timeout in minutes: no app-server output for this long triggers
|
|
93
|
+
* turn/interrupt and fails the run. 0 disables the timeout. */
|
|
94
|
+
turnIdleTimeoutMinutes: z.number().int().min(0).default(DEFAULT_TURN_IDLE_TIMEOUT_MINUTES),
|
|
95
|
+
});
|
|
50
96
|
/** Codex-specific configuration. */
|
|
51
97
|
export const CodexConfigSchema = z.object({
|
|
52
98
|
/** model to use. Undefined → codex reads from its config.toml. */
|
|
53
99
|
model: z.string().optional(),
|
|
54
100
|
/** model provider, e.g. 'volcengine-coding-plan'. Undefined → codex reads from its config.toml. */
|
|
55
101
|
modelProvider: z.string().optional(),
|
|
56
|
-
// approvalPolicy 和 sandboxPolicy 在 runner 内硬编码(exec 模式使用 approval_policy=never)
|
|
57
102
|
/**
|
|
58
103
|
* Reasoning effort level。codex 标准档位 minimal/low/medium/high/xhigh/max/ultra
|
|
59
104
|
* 之外还接受 none 与模型自定义值(ReasoningEffort::Custom),目录声明什么就存什么
|
|
@@ -61,8 +106,14 @@ export const CodexConfigSchema = z.object({
|
|
|
61
106
|
*/
|
|
62
107
|
// codex 拒绝空串档位(ReasoningEffort::from_str "" → Err,P3-3)
|
|
63
108
|
reasoningEffort: z.string().min(1).optional(),
|
|
64
|
-
/**
|
|
65
|
-
|
|
109
|
+
/** Approval policy (Codex 官方 AskForApproval 标准值). 默认 on-request。 */
|
|
110
|
+
approvalPolicy: z.enum(['untrusted', 'on-request', 'never']).default('on-request'),
|
|
111
|
+
/** Sandbox mode (Codex 官方 SandboxMode 标准值). 默认 workspace-write。 */
|
|
112
|
+
sandbox: z
|
|
113
|
+
.enum(['read-only', 'workspace-write', 'danger-full-access'])
|
|
114
|
+
.default('workspace-write'),
|
|
115
|
+
/** App-server connection configuration. */
|
|
116
|
+
appServer: CodexAppServerConfigSchema.optional(),
|
|
66
117
|
});
|
|
67
118
|
/** OpenCode-specific configuration (run mode: opencode run --format json --auto). */
|
|
68
119
|
const OpencodeConfigSchema = z.object({
|
|
@@ -70,6 +121,8 @@ const OpencodeConfigSchema = z.object({
|
|
|
70
121
|
providerID: z.string().default('anthropic'),
|
|
71
122
|
/** Model ID for the LLM backend (e.g. 'claude-sonnet-4-20250514'). */
|
|
72
123
|
modelID: z.string().default('claude-sonnet-4-20250514'),
|
|
124
|
+
/** Session mode (opencode agent name): 'build' (default) or 'plan'. */
|
|
125
|
+
mode: z.enum(['build', 'plan']).default('build'),
|
|
73
126
|
});
|
|
74
127
|
/** Pi-specific configuration. pi is a spawn-per-message CLI like Claude. */
|
|
75
128
|
const PiConfigSchema = z.object({
|
|
@@ -82,16 +135,35 @@ const PiConfigSchema = z.object({
|
|
|
82
135
|
/** Comma-separated tool whitelist. */
|
|
83
136
|
tools: z.string().default('read,bash,edit,write,grep,find,ls'),
|
|
84
137
|
});
|
|
85
|
-
/** Kimi-specific configuration.
|
|
138
|
+
/** Kimi-specific configuration. Pure ACP mode (persistent `kimi acp` connection). */
|
|
86
139
|
const KimiConfigSchema = z.object({
|
|
87
140
|
/** Model ID or alias, e.g. 'kimi-code/k3'. */
|
|
88
141
|
model: z.string().default('kimi-code/k3'),
|
|
89
142
|
/** Thinking effort: 'on', 'max'. */
|
|
90
143
|
thinkingEffort: z.enum(KIMI_THINKING_EFFORTS).default('max'),
|
|
144
|
+
/** Permission mode: 'manual' (approve each), 'auto' (engine decides), 'yolo' (allow all). */
|
|
145
|
+
permissionMode: z.enum(['manual', 'auto', 'yolo']).default('manual'),
|
|
146
|
+
/** ACP sub-configuration. */
|
|
147
|
+
acp: z
|
|
148
|
+
.object({
|
|
149
|
+
/** Path to kimi binary for ACP mode. */
|
|
150
|
+
binary: z.string().default('kimi'),
|
|
151
|
+
/** Request timeout in milliseconds. */
|
|
152
|
+
requestTimeoutMs: z.number().int().min(0).default(60000),
|
|
153
|
+
/** Idle TTL for ACP connection in milliseconds. */
|
|
154
|
+
idleTtlMs: z.number().int().min(0).default(1800000),
|
|
155
|
+
/** Turn idle timeout in minutes (0 disables). */
|
|
156
|
+
turnIdleTimeoutMinutes: z.number().int().min(0).default(DEFAULT_TURN_IDLE_TIMEOUT_MINUTES),
|
|
157
|
+
})
|
|
158
|
+
.optional(),
|
|
91
159
|
});
|
|
160
|
+
/** 首次启动的默认 agents 配置:codex 默认 app-server / on-request / workspace-write。 */
|
|
161
|
+
const DEFAULT_AGENTS_CONFIG = {
|
|
162
|
+
codex: CodexConfigSchema.parse({}),
|
|
163
|
+
};
|
|
92
164
|
/** Agents configuration: per-agent settings keyed by agent kind. */
|
|
93
165
|
const AgentsConfigSchema = z.object({
|
|
94
|
-
codex: CodexConfigSchema.
|
|
166
|
+
codex: CodexConfigSchema.default(DEFAULT_AGENTS_CONFIG.codex),
|
|
95
167
|
opencode: OpencodeConfigSchema.optional(),
|
|
96
168
|
pi: PiConfigSchema.optional(),
|
|
97
169
|
kimi: KimiConfigSchema.optional(),
|
|
@@ -112,6 +184,15 @@ const OutputConfigSchema = z.object({
|
|
|
112
184
|
const LoggingConfigSchema = z.object({
|
|
113
185
|
level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
|
114
186
|
});
|
|
187
|
+
/** 入站媒体落盘配置(预留可配置,默认即可用)。 */
|
|
188
|
+
const InboundMediaConfigSchema = z.object({
|
|
189
|
+
/** 是否启用图片/文件落盘。 */
|
|
190
|
+
enabled: z.boolean().default(true),
|
|
191
|
+
/** 落盘根目录名(位于当前 cwd 下)。 */
|
|
192
|
+
dirName: z.string().min(1).default(DEFAULT_INBOUND_MEDIA_DIR_NAME),
|
|
193
|
+
/** 单文件大小上限(MiB)。 */
|
|
194
|
+
maxFileSizeMb: z.number().int().min(1).default(DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB),
|
|
195
|
+
});
|
|
115
196
|
/** Agent-specific saved choices for quick switching. */
|
|
116
197
|
const AgentChoicesSchema = z.object({
|
|
117
198
|
codex: z
|
|
@@ -144,13 +225,15 @@ export const AppConfigSchema = z.object({
|
|
|
144
225
|
feishu: FeishuConfigSchema,
|
|
145
226
|
/** Claude config (top-level; other agents live under `agents`). */
|
|
146
227
|
claude: ClaudeConfigSchema.default(ClaudeConfigSchema.parse({})),
|
|
147
|
-
/** Per-agent configuration for non-claude agents. */
|
|
148
|
-
agents: AgentsConfigSchema.
|
|
228
|
+
/** Per-agent configuration for non-claude agents. 首次启动默认含 codex(app-server / workspace-write / on-request)。 */
|
|
229
|
+
agents: AgentsConfigSchema.default(DEFAULT_AGENTS_CONFIG),
|
|
149
230
|
/** Agent-specific saved choices for quick switching. */
|
|
150
231
|
agentChoices: AgentChoicesSchema.optional(),
|
|
151
232
|
idle: IdleConfigSchema.default(IdleConfigSchema.parse({})),
|
|
152
233
|
output: OutputConfigSchema.default(OutputConfigSchema.parse({})),
|
|
153
234
|
logging: LoggingConfigSchema.default(LoggingConfigSchema.parse({})),
|
|
235
|
+
/** 入站媒体(图片/文件)落盘配置。 */
|
|
236
|
+
inboundMedia: InboundMediaConfigSchema.default(InboundMediaConfigSchema.parse({})),
|
|
154
237
|
/** Default agent for new runs. */
|
|
155
238
|
defaultAgent: z.enum(['claude', 'codex', 'opencode', 'pi', 'kimi']).default('claude'),
|
|
156
239
|
/** Check for updates on bridge startup (default: false). */
|
|
@@ -163,6 +246,9 @@ const TEMPLATE = `feishu:
|
|
|
163
246
|
claude:
|
|
164
247
|
model: ${DEFAULTS.CLAUDE_MODEL}
|
|
165
248
|
effort: medium
|
|
249
|
+
permissionMode: bypassPermissions
|
|
250
|
+
approvalTimeoutMs: ${DEFAULTS.APPROVAL_TIMEOUT_MS}
|
|
251
|
+
idleTtlMinutes: ${DEFAULTS.CLAUDE_IDLE_TTL_MINUTES}
|
|
166
252
|
stopGraceMs: ${DEFAULTS.STOP_GRACE_MS}
|
|
167
253
|
|
|
168
254
|
idle:
|
|
@@ -250,33 +336,45 @@ export function assertSafeKeyPart(part) {
|
|
|
250
336
|
throw new Error(`[lark-remote] invalid config key segment: '${part}'`);
|
|
251
337
|
}
|
|
252
338
|
}
|
|
253
|
-
/**
|
|
254
|
-
|
|
255
|
-
|
|
339
|
+
/**
|
|
340
|
+
* 按 dot-separated key 下钻到目标键的父容器(不含最后一段)。
|
|
341
|
+
*
|
|
342
|
+
* - create=true:中间缺失/非对象段自动补 `{}`(set 语义)
|
|
343
|
+
* - create=false:中间缺失/非对象段返回 undefined(get/delete 语义)
|
|
344
|
+
*
|
|
345
|
+
* 危险段(__proto__/prototype/constructor)在每段统一拒绝。
|
|
346
|
+
*/
|
|
347
|
+
export function walkNestedContainer(target, parts, create) {
|
|
256
348
|
let current = target;
|
|
257
349
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
258
350
|
assertSafeKeyPart(parts[i]);
|
|
259
351
|
const next = current[parts[i]];
|
|
260
352
|
if (next == null || typeof next !== 'object') {
|
|
353
|
+
if (!create)
|
|
354
|
+
return undefined;
|
|
261
355
|
current[parts[i]] = {};
|
|
262
356
|
}
|
|
263
357
|
current = current[parts[i]];
|
|
264
358
|
}
|
|
359
|
+
return current;
|
|
360
|
+
}
|
|
361
|
+
/** 在对象上按 dot-separated key 设置嵌套值(仅修改内存对象,不写盘)。 */
|
|
362
|
+
function setNestedValue(target, key, value) {
|
|
363
|
+
const parts = key.split('.');
|
|
364
|
+
const container = walkNestedContainer(target, parts, true);
|
|
265
365
|
const lastPart = parts[parts.length - 1];
|
|
266
366
|
assertSafeKeyPart(lastPart);
|
|
267
|
-
|
|
367
|
+
container[lastPart] = value;
|
|
268
368
|
}
|
|
269
369
|
/** Get a nested value from config by dot-separated key, e.g. "feishu.appId" */
|
|
270
370
|
export function getConfigValue(config, key) {
|
|
271
371
|
const parts = key.split('.');
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
return current;
|
|
372
|
+
const container = walkNestedContainer(config, parts, false);
|
|
373
|
+
if (!container)
|
|
374
|
+
return undefined;
|
|
375
|
+
const lastPart = parts[parts.length - 1];
|
|
376
|
+
assertSafeKeyPart(lastPart);
|
|
377
|
+
return container[lastPart];
|
|
280
378
|
}
|
|
281
379
|
/** Set a nested value in config by dot-separated key, write back to YAML file */
|
|
282
380
|
export function setConfigValue(configPath, config, key, value) {
|
|
@@ -315,17 +413,12 @@ export function setConfigValues(configPath, config, updates) {
|
|
|
315
413
|
*/
|
|
316
414
|
function deleteNestedValue(target, key) {
|
|
317
415
|
const parts = key.split('.');
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const next = current[parts[i]];
|
|
322
|
-
if (next == null || typeof next !== 'object')
|
|
323
|
-
return;
|
|
324
|
-
current = next;
|
|
325
|
-
}
|
|
416
|
+
const container = walkNestedContainer(target, parts, false);
|
|
417
|
+
if (!container)
|
|
418
|
+
return;
|
|
326
419
|
const lastPart = parts[parts.length - 1];
|
|
327
420
|
assertSafeKeyPart(lastPart);
|
|
328
|
-
delete
|
|
421
|
+
delete container[lastPart];
|
|
329
422
|
}
|
|
330
423
|
export function getAgentConfig(config, kind) {
|
|
331
424
|
if (kind === 'claude') {
|