lark-remote 0.5.13 → 0.5.15
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 +31 -0
- package/dist/agent-kinds.d.ts +27 -0
- package/dist/agent-kinds.js +38 -0
- package/dist/bridge/approval-actions.d.ts +95 -0
- package/dist/bridge/approval-actions.js +104 -0
- package/dist/bridge/approval-coordinator.d.ts +13 -0
- package/dist/bridge/approval-coordinator.js +18 -0
- package/dist/bridge/final-usage.d.ts +8 -17
- package/dist/bridge/final-usage.js +1 -18
- package/dist/bridge/index.d.ts +46 -39
- package/dist/bridge/index.js +269 -240
- package/dist/bridge/queue-manager.d.ts +25 -1
- package/dist/bridge/queue-manager.js +179 -160
- package/dist/bridge/run-approval.d.ts +2 -1
- package/dist/bridge/run-usage.d.ts +21 -30
- package/dist/bridge/run-usage.js +47 -51
- package/dist/bridge/session-writeback.d.ts +3 -2
- package/dist/card/approval-render.d.ts +3 -2
- package/dist/card/approval-render.js +3 -2
- package/dist/{router → card}/card-helpers.d.ts +7 -7
- package/dist/{router → card}/card-helpers.js +8 -8
- package/dist/card/card-session.d.ts +4 -2
- package/dist/card/card-session.js +8 -6
- package/dist/card/card-shared.d.ts +1 -1
- package/dist/card/card-shared.js +1 -1
- package/dist/card/final-answer-overflow.d.ts +0 -6
- package/dist/card/final-answer-overflow.js +1 -1
- package/dist/card/run-card-session.d.ts +2 -2
- package/dist/card/run-card-session.js +2 -2
- package/dist/card/run-renderer.js +29 -30
- package/dist/card/run-state.d.ts +28 -50
- package/dist/card/run-state.js +23 -0
- package/dist/card/usage-format.d.ts +30 -0
- package/dist/{router → card}/usage-format.js +3 -10
- package/dist/clone.js +6 -1
- package/dist/config/index.d.ts +16 -20
- package/dist/config/index.js +0 -16
- package/dist/config/pi-config.js +6 -4
- package/dist/connector/index.d.ts +2 -4
- package/dist/connector/index.js +7 -11
- package/dist/{runner/dsh → dsh}/auth.js +1 -1
- package/dist/dsh/protocol.d.ts +9 -0
- package/dist/dsh/protocol.js +61 -0
- package/dist/index.js +10 -5
- package/dist/model-catalog.d.ts +14 -0
- package/dist/model-catalog.js +25 -0
- package/dist/platform/path.d.ts +9 -0
- package/dist/platform/path.js +18 -0
- package/dist/router/active-run-usage.d.ts +4 -0
- package/dist/router/active-run-usage.js +12 -0
- package/dist/router/commands/ls.js +1 -1
- package/dist/router/commands/order.js +1 -1
- package/dist/router/commands/resume.d.ts +5 -4
- package/dist/router/commands/resume.js +4 -4
- package/dist/router/commands/ws.js +1 -1
- package/dist/router/config/claude.js +2 -1
- package/dist/router/config/common/render.d.ts +5 -1
- package/dist/router/config/common/render.js +6 -13
- package/dist/router/config/dsh.d.ts +1 -1
- package/dist/router/config/index.d.ts +1 -1
- package/dist/router/config/types.d.ts +11 -3
- package/dist/router/index.d.ts +41 -11
- package/dist/router/index.js +169 -233
- package/dist/runner/agent-choices-common.d.ts +1 -1
- package/dist/runner/claude/runner.d.ts +20 -2
- package/dist/runner/claude/runner.js +2 -15
- package/dist/runner/codex/app-server/runner.d.ts +3 -1
- package/dist/runner/codex/app-server/translator.d.ts +11 -0
- package/dist/runner/codex/app-server/translator.js +56 -149
- package/dist/runner/common/acp/base-acp-runner.d.ts +19 -1
- package/dist/runner/common/acp/base-acp-runner.js +37 -3
- package/dist/runner/common/connection-based-runner.d.ts +3 -1
- package/dist/runner/common/jsonrpc/transport.js +17 -7
- package/dist/runner/dsh/client.d.ts +1 -4
- package/dist/runner/dsh/client.js +7 -55
- package/dist/runner/dsh/daemon.js +9 -2
- package/dist/runner/dsh/exit-cancel.js +1 -1
- package/dist/runner/dsh/mux-stream.js +21 -2
- package/dist/runner/dsh/runner.d.ts +21 -1
- package/dist/runner/dsh/runner.js +97 -78
- package/dist/runner/dsh/translator.d.ts +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +22 -1
- package/dist/runner/kimi/acp/runner.js +83 -60
- package/dist/runner/opencode/acp/error-monitor.d.ts +11 -0
- package/dist/runner/opencode/acp/error-monitor.js +31 -2
- package/dist/runner/opencode/acp/runner.d.ts +14 -1
- package/dist/runner/opencode/acp/runner.js +13 -2
- package/dist/runner/pi/rpc/runner.d.ts +2 -1
- package/dist/runner/probe.d.ts +1 -1
- package/dist/runner/probe.js +10 -9
- package/dist/runner/registry.d.ts +2 -1
- package/dist/runner/types.d.ts +20 -154
- package/dist/runner/types.js +4 -24
- package/dist/session/claude/session-index.d.ts +11 -4
- package/dist/session/claude/session-index.js +30 -8
- package/dist/session/claude/session-reader.d.ts +1 -1
- package/dist/session/claude/sessions.d.ts +2 -2
- package/dist/session/claude/sessions.js +41 -26
- package/dist/session/codex/rollout-reader.d.ts +1 -1
- package/dist/session/codex/rollout-reader.js +14 -13
- package/dist/session/codex/sessions.d.ts +1 -1
- package/dist/session/codex/sessions.js +4 -2
- package/dist/session/common/jsonl.js +7 -1
- package/dist/session/common/pagination.d.ts +2 -0
- package/dist/session/common/pagination.js +1 -1
- package/dist/session/common/recency.d.ts +6 -0
- package/dist/session/common/recency.js +7 -5
- package/dist/session/common/two-pass.d.ts +1 -1
- package/dist/session/common/usage-accumulator.d.ts +1 -1
- package/dist/session/dsh/sessions.d.ts +1 -1
- package/dist/session/dsh/sessions.js +37 -12
- package/dist/session/kimi/sessions.d.ts +1 -1
- package/dist/session/kimi/sessions.js +72 -27
- package/dist/session/opencode/sessions.d.ts +1 -1
- package/dist/session/opencode/sessions.js +164 -81
- package/dist/session/pi/sessions.d.ts +1 -1
- package/dist/session/pi/sessions.js +20 -7
- package/dist/session/registry.d.ts +2 -1
- package/dist/session/session-store.d.ts +1 -2
- package/dist/session/session-store.js +14 -7
- package/dist/session-contract.d.ts +178 -0
- package/dist/session-contract.js +9 -0
- package/package.json +1 -1
- package/dist/router/usage-format.d.ts +0 -60
- /package/dist/{runner/dsh → dsh}/auth.d.ts +0 -0
- /package/dist/{runner/dsh → dsh}/home.d.ts +0 -0
- /package/dist/{runner/dsh → dsh}/home.js +0 -0
- /package/dist/{runner/dsh → dsh}/types.d.ts +0 -0
- /package/dist/{runner/dsh → dsh}/types.js +0 -0
package/dist/config/index.js
CHANGED
|
@@ -62,20 +62,6 @@ export const DEFAULT_APPROVAL_TIMEOUT_MS = DEFAULTS.APPROVAL_TIMEOUT_MS;
|
|
|
62
62
|
*/
|
|
63
63
|
export const DEFAULT_INBOUND_MEDIA_DIR_NAME = '.lark-remote-temp';
|
|
64
64
|
export const DEFAULT_INBOUND_MEDIA_MAX_SIZE_MB = 100;
|
|
65
|
-
/** 模型 ID → alias 映射。 */
|
|
66
|
-
export const MODEL_ID_TO_ALIAS = {
|
|
67
|
-
'claude-opus-4-8': 'opus',
|
|
68
|
-
'claude-sonnet-4-6': 'sonnet',
|
|
69
|
-
'claude-haiku-4-5-20250501': 'haiku',
|
|
70
|
-
'claude-fable-5': 'fable',
|
|
71
|
-
};
|
|
72
|
-
/** alias → model ID 反向映射。 */
|
|
73
|
-
export const MODEL_ALIAS_TO_ID = {
|
|
74
|
-
opus: 'claude-opus-4-8',
|
|
75
|
-
sonnet: 'claude-sonnet-4-6',
|
|
76
|
-
haiku: 'claude-haiku-4-5-20250501',
|
|
77
|
-
fable: 'claude-fable-5',
|
|
78
|
-
};
|
|
79
65
|
const FeishuConfigSchema = z.object({
|
|
80
66
|
appId: z.string().min(1),
|
|
81
67
|
appSecret: z.string().min(1),
|
|
@@ -568,8 +554,6 @@ export function getAgentConfig(config, kind) {
|
|
|
568
554
|
export function getModelOptionsFromSettings(settingsPath) {
|
|
569
555
|
if (!settingsPath)
|
|
570
556
|
return [];
|
|
571
|
-
if (!fs.existsSync(settingsPath))
|
|
572
|
-
return [];
|
|
573
557
|
try {
|
|
574
558
|
const content = fs.readFileSync(settingsPath, 'utf-8');
|
|
575
559
|
const settings = JSON.parse(content);
|
package/dist/config/pi-config.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
|
+
import { getLogger } from '../logger/index.js';
|
|
9
10
|
/**
|
|
10
11
|
* 解析 pi 配置目录。优先使用 PI_CONFIG_DIR 环境变量(测试隔离用),
|
|
11
12
|
* 默认 ~/.pi/agent。每次调用时动态读取环境变量,避免模块级缓存导致
|
|
@@ -71,8 +72,9 @@ export function loadPiProviderConfig() {
|
|
|
71
72
|
try {
|
|
72
73
|
modelsData = JSON.parse(fs.readFileSync(modelsFile, 'utf-8'));
|
|
73
74
|
}
|
|
74
|
-
catch {
|
|
75
|
-
//
|
|
75
|
+
catch (err) {
|
|
76
|
+
// 解析失败 = pi 模型选项会静默消失,必须留痕(此前全文件零日志)。
|
|
77
|
+
getLogger().warn(`[pi-config] cannot parse ${modelsFile}: ${err.message}`);
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
// 2. 读取 auth.json
|
|
@@ -81,8 +83,8 @@ export function loadPiProviderConfig() {
|
|
|
81
83
|
try {
|
|
82
84
|
authData = JSON.parse(fs.readFileSync(authFile, 'utf-8')) ?? {};
|
|
83
85
|
}
|
|
84
|
-
catch {
|
|
85
|
-
|
|
86
|
+
catch (err) {
|
|
87
|
+
getLogger().warn(`[pi-config] cannot parse ${authFile}: ${err.message}`);
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
// 3. 从 models.json 提取 providers
|
|
@@ -7,9 +7,9 @@ import type { AppConfig } from '../config/index.js';
|
|
|
7
7
|
* - SDK 的 cardAction dedup eventId = `card:{messageId}:{operator.openId}:{actionId}`
|
|
8
8
|
* - actionId = `tag|name|option|JSON.stringify(value)`,不含时间戳/事件序号
|
|
9
9
|
* - config 卡片原地更新(updateCardInPlace),用户在同一张卡上重复触发
|
|
10
|
-
* 固定 value 的按钮(如 config.
|
|
10
|
+
* 固定 value 的按钮(如 config.save):
|
|
11
11
|
* messageId / operator / value 三段都相同 → eventId 完全相同 → 第二次点击被
|
|
12
|
-
* seenCache drop
|
|
12
|
+
* seenCache drop,按钮不可逆(第二次点击静默失效)。
|
|
13
13
|
*
|
|
14
14
|
* SDK 默认 12h 太长;60s 仍会误伤连击。300ms 挡飞书瞬时重投递(<100ms 级),
|
|
15
15
|
* 放过用户连击(慢点两次通常 >500ms)。代价:削弱 message 秒级重投递防护——
|
|
@@ -166,8 +166,6 @@ export declare class FeishuConnector {
|
|
|
166
166
|
* `rawClient` 缺失(测试 mock)时回退 SDK 入口,行为退化为「看不见业务码」。
|
|
167
167
|
*/
|
|
168
168
|
updateCard(messageId: string, card: object): Promise<void>;
|
|
169
|
-
/** Format error for logging without causing circular serialization */
|
|
170
|
-
private formatError;
|
|
171
169
|
addReaction(messageId: string, emoji: string): Promise<void>;
|
|
172
170
|
/**
|
|
173
171
|
* Remove a reaction by emoji (e.g. retract the Typing indicator).
|
package/dist/connector/index.js
CHANGED
|
@@ -33,9 +33,9 @@ const noKeepAliveAgent = new https.Agent({ keepAlive: false });
|
|
|
33
33
|
* - SDK 的 cardAction dedup eventId = `card:{messageId}:{operator.openId}:{actionId}`
|
|
34
34
|
* - actionId = `tag|name|option|JSON.stringify(value)`,不含时间戳/事件序号
|
|
35
35
|
* - config 卡片原地更新(updateCardInPlace),用户在同一张卡上重复触发
|
|
36
|
-
* 固定 value 的按钮(如 config.
|
|
36
|
+
* 固定 value 的按钮(如 config.save):
|
|
37
37
|
* messageId / operator / value 三段都相同 → eventId 完全相同 → 第二次点击被
|
|
38
|
-
* seenCache drop
|
|
38
|
+
* seenCache drop,按钮不可逆(第二次点击静默失效)。
|
|
39
39
|
*
|
|
40
40
|
* SDK 默认 12h 太长;60s 仍会误伤连击。300ms 挡飞书瞬时重投递(<100ms 级),
|
|
41
41
|
* 放过用户连击(慢点两次通常 >500ms)。代价:削弱 message 秒级重投递防护——
|
|
@@ -520,7 +520,7 @@ export class FeishuConnector {
|
|
|
520
520
|
catch (err) {
|
|
521
521
|
// 抛出去前先落一条格式化日志(调用方只看到包装后的 message)。
|
|
522
522
|
// 抛普通 Error 而不是原 err:axios 错误对象跨层序列化会丢信息。
|
|
523
|
-
const errorInfo =
|
|
523
|
+
const errorInfo = formatErrorForLog(err);
|
|
524
524
|
getLogger().error('[feishu] streamCard failed:', errorInfo);
|
|
525
525
|
throw new Error(`streamCard failed: ${errorInfo}`, { cause: err });
|
|
526
526
|
}
|
|
@@ -554,7 +554,7 @@ export class FeishuConnector {
|
|
|
554
554
|
catch (err) {
|
|
555
555
|
// Log the error but don't swallow it - a plain error avoids axios
|
|
556
556
|
// serialization issues in the logger.
|
|
557
|
-
const errorInfo =
|
|
557
|
+
const errorInfo = formatErrorForLog(err);
|
|
558
558
|
getLogger().error('[feishu] updateCard failed:', errorInfo);
|
|
559
559
|
throw new Error(`updateCard failed: ${errorInfo}`, { cause: err });
|
|
560
560
|
}
|
|
@@ -562,16 +562,12 @@ export class FeishuConnector {
|
|
|
562
562
|
throw new Error(`updateCard failed: Feishu rejected the card (code=${rejection.code} msg=${rejection.msg ?? ''})`, { cause: rejection });
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
|
-
/** Format error for logging without causing circular serialization */
|
|
566
|
-
formatError(err) {
|
|
567
|
-
return formatErrorForLog(err);
|
|
568
|
-
}
|
|
569
565
|
async addReaction(messageId, emoji) {
|
|
570
566
|
try {
|
|
571
567
|
await this.channel.addReaction(messageId, emoji);
|
|
572
568
|
}
|
|
573
569
|
catch (err) {
|
|
574
|
-
getLogger().error('[feishu] addReaction failed:',
|
|
570
|
+
getLogger().error('[feishu] addReaction failed:', formatErrorForLog(err));
|
|
575
571
|
}
|
|
576
572
|
}
|
|
577
573
|
/**
|
|
@@ -583,7 +579,7 @@ export class FeishuConnector {
|
|
|
583
579
|
await this.channel.removeReactionByEmoji(messageId, emoji);
|
|
584
580
|
}
|
|
585
581
|
catch (err) {
|
|
586
|
-
getLogger().error('[feishu] removeReactionByEmoji failed:',
|
|
582
|
+
getLogger().error('[feishu] removeReactionByEmoji failed:', formatErrorForLog(err));
|
|
587
583
|
}
|
|
588
584
|
}
|
|
589
585
|
/**
|
|
@@ -635,7 +631,7 @@ export class FeishuConnector {
|
|
|
635
631
|
}
|
|
636
632
|
}
|
|
637
633
|
catch (err) {
|
|
638
|
-
const errorInfo =
|
|
634
|
+
const errorInfo = formatErrorForLog(err);
|
|
639
635
|
getLogger().error(`[feishu] ${label} failed:`, errorInfo);
|
|
640
636
|
throw new Error(`${label} failed: ${errorInfo}`, { cause: err });
|
|
641
637
|
}
|
|
@@ -12,7 +12,7 @@ import { createHash, createHmac } from 'node:crypto';
|
|
|
12
12
|
import fs from 'node:fs';
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import YAML from 'yaml';
|
|
15
|
-
import { isWin32 } from '
|
|
15
|
+
import { isWin32 } from '../platform/select.js';
|
|
16
16
|
import { resolveDshHome } from './home.js';
|
|
17
17
|
/** Credential record that owns the browser-cookie signing secret. */
|
|
18
18
|
export const DSH_BROWSER_CREDENTIAL_KEY = 'client-connection/browser-session';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSH 远程调用的线格式助手(中立层,runner 与 session 共用)。
|
|
3
|
+
*
|
|
4
|
+
* 这两个函数原先住在 `runner/dsh/client.ts`,于是 session/dsh 为了拼一个
|
|
5
|
+
* `args` 信封要 import 上层 runner —— 与 AgentSessionReader 同一类反向依赖。
|
|
6
|
+
*/
|
|
7
|
+
/** Extract the `token` query parameter from a pasted `dsh web` URL. */
|
|
8
|
+
export declare function extractDshToken(raw: string | undefined): string;
|
|
9
|
+
export declare function dshArgs(method: string, payload: unknown): Record<string, unknown>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSH 远程调用的线格式助手(中立层,runner 与 session 共用)。
|
|
3
|
+
*
|
|
4
|
+
* 这两个函数原先住在 `runner/dsh/client.ts`,于是 session/dsh 为了拼一个
|
|
5
|
+
* `args` 信封要 import 上层 runner —— 与 AgentSessionReader 同一类反向依赖。
|
|
6
|
+
*/
|
|
7
|
+
/** Extract the `token` query parameter from a pasted `dsh web` URL. */
|
|
8
|
+
export function extractDshToken(raw) {
|
|
9
|
+
const value = (raw ?? '').trim();
|
|
10
|
+
if (!value)
|
|
11
|
+
return '';
|
|
12
|
+
if (!value.includes('token=') && !value.includes('://'))
|
|
13
|
+
return value;
|
|
14
|
+
try {
|
|
15
|
+
const url = new URL(value.startsWith('?') ? `http://dsh.invalid/${value}` : value);
|
|
16
|
+
const token = url.searchParams.get('token');
|
|
17
|
+
if (token)
|
|
18
|
+
return token;
|
|
19
|
+
// 带 scheme 却没有 token 参数的输入是误贴的 host URL(如
|
|
20
|
+
// `http://127.0.0.1:3080`):整串不是合法 token,参与握手只会得到
|
|
21
|
+
// 指向性缺失的 401。返回空串让上游走「token 缺失」的诊断路径。
|
|
22
|
+
if (value.includes('://'))
|
|
23
|
+
return '';
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Remote methods take named parameters. Most session methods call their single
|
|
32
|
+
* argument `request`; `session/list` reserves `_request`; catalog methods take
|
|
33
|
+
* no arguments. `commands/*` address the receiving agent by its wire field
|
|
34
|
+
* `agentId`, so their payload is already in wire shape (pass-through).
|
|
35
|
+
* The gateway rejects any other `args` shape.
|
|
36
|
+
*/
|
|
37
|
+
const DSH_ARGS_KEY = {
|
|
38
|
+
'session/list': '_request',
|
|
39
|
+
'session/create': 'request',
|
|
40
|
+
'session/prompt': 'request',
|
|
41
|
+
'session/cancel': 'request',
|
|
42
|
+
'session/selectModel': 'request',
|
|
43
|
+
'session/projections': 'request',
|
|
44
|
+
'session/page': 'request',
|
|
45
|
+
'session/follow': 'request',
|
|
46
|
+
'session/updateQueue': 'request',
|
|
47
|
+
'job/list': 'request',
|
|
48
|
+
'job/kill': 'request',
|
|
49
|
+
'session/modelCatalog': null,
|
|
50
|
+
'agentPresets/list': null,
|
|
51
|
+
'permissionPresets/catalog': null,
|
|
52
|
+
};
|
|
53
|
+
export function dshArgs(method, payload) {
|
|
54
|
+
const key = DSH_ARGS_KEY[method];
|
|
55
|
+
if (key === null)
|
|
56
|
+
return {};
|
|
57
|
+
if (key === undefined)
|
|
58
|
+
return payload;
|
|
59
|
+
return { [key]: payload };
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=protocol.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadConfig, getAgentConfig } from './config/index.js';
|
|
2
|
-
import { resolveAgentChoices
|
|
2
|
+
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';
|
|
@@ -25,7 +25,7 @@ import { startSleepBlocker } from './platform/sleep-blocker.js';
|
|
|
25
25
|
import { checkLatestVersion, compareVersions, runInstallLatest, formatUpdateHint, } from './update/index.js';
|
|
26
26
|
import { classifyRejection } from './error-classification.js';
|
|
27
27
|
import { WorkspaceStore } from './workspace/index.js';
|
|
28
|
-
import { buildSessionHistoryCard, pickResumeCardEvents } from './
|
|
28
|
+
import { buildSessionHistoryCard, pickResumeCardEvents } from './card/card-helpers.js';
|
|
29
29
|
import { newSessionButton, resumeCompactButton, agentDisplayName } from './card/card-shared.js';
|
|
30
30
|
import path from 'node:path';
|
|
31
31
|
import { setupMessageHandlers } from './message-handlers.js';
|
|
@@ -137,6 +137,10 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
137
137
|
manageProcess: () => getAgentConfig(latest(), 'dsh')?.manageProcess ?? true,
|
|
138
138
|
startTimeoutMs: () => getAgentConfig(latest(), 'dsh')?.startTimeoutMs,
|
|
139
139
|
});
|
|
140
|
+
// claude 的会话读取器与其余 agent 一样由组合根注入:runner 侧不 import session
|
|
141
|
+
// 层(否则 runner ↔ session 互相依赖),且 bridge 读 usage / router 列 session
|
|
142
|
+
// 用的是同一个实例(缓存共用)。
|
|
143
|
+
const claudeSessionReader = new ClaudeSessionReader();
|
|
140
144
|
// Claude factory reads from configContainer (not closure) so runtime
|
|
141
145
|
// config changes (model, effort, stopGraceMs) take effect after
|
|
142
146
|
// bridge.setConfig() + clearRunners(). Same pattern as codex/pi/kimi.
|
|
@@ -149,6 +153,7 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
149
153
|
settings: cliArgs.settings,
|
|
150
154
|
pidDir: configDir,
|
|
151
155
|
cwd: ws,
|
|
156
|
+
sessionReader: claudeSessionReader,
|
|
152
157
|
permissionMode: claudeConfig.permissionMode,
|
|
153
158
|
idleTtlMs: claudeConfig.idleTtlMinutes != null ? claudeConfig.idleTtlMinutes * 60_000 : undefined,
|
|
154
159
|
});
|
|
@@ -179,7 +184,7 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
179
184
|
// Register OpencodeAcpRunner (pure ACP mode, `opencode acp` JSON-RPC over stdio)
|
|
180
185
|
// Register session reader (same instance as used by runner)
|
|
181
186
|
const sessionReaderRegistry = new SessionReaderRegistry();
|
|
182
|
-
sessionReaderRegistry.register('claude',
|
|
187
|
+
sessionReaderRegistry.register('claude', claudeSessionReader);
|
|
183
188
|
sessionReaderRegistry.register('codex', codexSessionReader);
|
|
184
189
|
// Register OpencodeSessionReader (CLI version)
|
|
185
190
|
// Using `opencode session list` and `session export` instead of HTTP API.
|
|
@@ -436,8 +441,8 @@ async function main() {
|
|
|
436
441
|
try {
|
|
437
442
|
await connector.connect();
|
|
438
443
|
}
|
|
439
|
-
catch {
|
|
440
|
-
logger.error('failed to connect to Feishu, check appId/appSecret');
|
|
444
|
+
catch (err) {
|
|
445
|
+
logger.error('failed to connect to Feishu, check appId/appSecret:', err);
|
|
441
446
|
process.exit(1);
|
|
442
447
|
}
|
|
443
448
|
if (binder.isBound()) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude 模型 ID ↔ CLI alias 的双向表。
|
|
3
|
+
*
|
|
4
|
+
* 中立层(谁都不许反向依赖它):config 要写默认值、runner/claude 要把 alias 传给
|
|
5
|
+
* CLI、router/config 要把 alias 显示给用户。此前这张表住在 config/,于是
|
|
6
|
+
* 「地基层被 runner 反向 import」;挪到这里后三方共同引用同一份。
|
|
7
|
+
*
|
|
8
|
+
* 表内容来自 Claude CLI 的模型别名(alias 是 CLI 侧的稳定名字,model ID 会随
|
|
9
|
+
* 版本变),新增一行只改这里。
|
|
10
|
+
*/
|
|
11
|
+
/** 模型 ID → alias 映射。 */
|
|
12
|
+
export declare const MODEL_ID_TO_ALIAS: Record<string, string>;
|
|
13
|
+
/** alias → model ID 反向映射。 */
|
|
14
|
+
export declare const MODEL_ALIAS_TO_ID: Record<string, string>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude 模型 ID ↔ CLI alias 的双向表。
|
|
3
|
+
*
|
|
4
|
+
* 中立层(谁都不许反向依赖它):config 要写默认值、runner/claude 要把 alias 传给
|
|
5
|
+
* CLI、router/config 要把 alias 显示给用户。此前这张表住在 config/,于是
|
|
6
|
+
* 「地基层被 runner 反向 import」;挪到这里后三方共同引用同一份。
|
|
7
|
+
*
|
|
8
|
+
* 表内容来自 Claude CLI 的模型别名(alias 是 CLI 侧的稳定名字,model ID 会随
|
|
9
|
+
* 版本变),新增一行只改这里。
|
|
10
|
+
*/
|
|
11
|
+
/** 模型 ID → alias 映射。 */
|
|
12
|
+
export const MODEL_ID_TO_ALIAS = {
|
|
13
|
+
'claude-opus-4-8': 'opus',
|
|
14
|
+
'claude-sonnet-4-6': 'sonnet',
|
|
15
|
+
'claude-haiku-4-5-20250501': 'haiku',
|
|
16
|
+
'claude-fable-5': 'fable',
|
|
17
|
+
};
|
|
18
|
+
/** alias → model ID 反向映射。 */
|
|
19
|
+
export const MODEL_ALIAS_TO_ID = {
|
|
20
|
+
opus: 'claude-opus-4-8',
|
|
21
|
+
sonnet: 'claude-sonnet-4-6',
|
|
22
|
+
haiku: 'claude-haiku-4-5-20250501',
|
|
23
|
+
fable: 'claude-fable-5',
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=model-catalog.js.map
|
package/dist/platform/path.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export interface PathOptions {
|
|
2
2
|
platform?: NodeJS.Platform;
|
|
3
3
|
}
|
|
4
|
+
/**
|
|
5
|
+
* realpath 归一(macOS `/tmp` → `/private/tmp`),失败回退原样输入。
|
|
6
|
+
*
|
|
7
|
+
* 各 session reader 此前有三种口径:静默回退(opencode)、回退 + warn(kimi
|
|
8
|
+
* 单会话读)、裸调让一次 ENOENT 把整张会话列表清掉(kimi list)。统一成
|
|
9
|
+
* 「回退优先于丢结果」,失败原因交给调用方记日志(`onFailure`),因为
|
|
10
|
+
* ENOENT(陈旧 cwd)是正常空态、EACCES/EBUSY 才需要留痕。
|
|
11
|
+
*/
|
|
12
|
+
export declare function safeRealpath(cwd: string, onFailure?: (err: unknown) => void): string;
|
|
4
13
|
/**
|
|
5
14
|
* 路径的「判等键」形态:把 samePath 的平台归一规则单源化,供 Map/Set 键控
|
|
6
15
|
* 场景使用(按 cwd 建倒排索引时不能每次查询做 O(n) 两两比较)。不变量:
|
package/dist/platform/path.js
CHANGED
|
@@ -9,8 +9,26 @@
|
|
|
9
9
|
* 全部函数接受显式 `platform` 参数(默认 currentPlatform),使 win32 语义
|
|
10
10
|
* 可在任意宿主的单元测试中验证。
|
|
11
11
|
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
12
13
|
import path from 'node:path';
|
|
13
14
|
import { currentPlatform, isWin32 } from './select.js';
|
|
15
|
+
/**
|
|
16
|
+
* realpath 归一(macOS `/tmp` → `/private/tmp`),失败回退原样输入。
|
|
17
|
+
*
|
|
18
|
+
* 各 session reader 此前有三种口径:静默回退(opencode)、回退 + warn(kimi
|
|
19
|
+
* 单会话读)、裸调让一次 ENOENT 把整张会话列表清掉(kimi list)。统一成
|
|
20
|
+
* 「回退优先于丢结果」,失败原因交给调用方记日志(`onFailure`),因为
|
|
21
|
+
* ENOENT(陈旧 cwd)是正常空态、EACCES/EBUSY 才需要留痕。
|
|
22
|
+
*/
|
|
23
|
+
export function safeRealpath(cwd, onFailure) {
|
|
24
|
+
try {
|
|
25
|
+
return fs.realpathSync(cwd);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
onFailure?.(err);
|
|
29
|
+
return cwd;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
14
32
|
function resolveOptions(opts) {
|
|
15
33
|
return { platform: opts?.platform ?? currentPlatform };
|
|
16
34
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ActiveRunSnapshot } from '../bridge/index.js';
|
|
2
|
+
import type { SessionDisplayUsage } from '../card/usage-format.js';
|
|
3
|
+
/** 从 bridge 的活跃 run 快照提取会话卡需要的用量字段。 */
|
|
4
|
+
export declare function activeRunUsage(activeRun: ActiveRunSnapshot | undefined): SessionDisplayUsage | undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** 从 bridge 的活跃 run 快照提取会话卡需要的用量字段。 */
|
|
2
|
+
export function activeRunUsage(activeRun) {
|
|
3
|
+
if (!activeRun || activeRun.contextLength === undefined)
|
|
4
|
+
return undefined;
|
|
5
|
+
return {
|
|
6
|
+
contextLength: activeRun.contextLength,
|
|
7
|
+
compactCount: activeRun.compactCount,
|
|
8
|
+
cacheReadTokens: activeRun.cacheReadTokens,
|
|
9
|
+
cacheCreationTokens: activeRun.cacheCreationTokens,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=active-run-usage.js.map
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { cardButton } from '../../card/card-shared.js';
|
|
5
|
-
import { paginationBar, searchBar } from '
|
|
5
|
+
import { paginationBar, searchBar } from '../../card/card-helpers.js';
|
|
6
6
|
import { inspectPath, statPath } from '../path-validation.js';
|
|
7
7
|
import { pageSlice } from '../paging.js';
|
|
8
8
|
export const LS_PAGE_SIZE = 30;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cardButton } from '../../card/card-shared.js';
|
|
2
|
-
import { paginationBar } from '
|
|
2
|
+
import { paginationBar } from '../../card/card-helpers.js';
|
|
3
3
|
import { pageSlice } from '../paging.js';
|
|
4
4
|
export const ORDER_PAGE_SIZE = 8;
|
|
5
5
|
export function buildOrderCommand(args, ctx, offset, deps) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { CommandContext, CommandResult } from '../../bridge/index.js';
|
|
2
|
-
import type { AgentKind
|
|
3
|
-
import type {
|
|
2
|
+
import type { AgentKind } from '../../agent-kinds.js';
|
|
3
|
+
import type { AgentSessionContentEvent, AgentSessionReader } from '../../session-contract.js';
|
|
4
|
+
import type { SessionDisplayUsage } from '../../card/usage-format.js';
|
|
4
5
|
export declare const AUTO_RESUME_MAX_EVENTS = 5;
|
|
5
6
|
export declare const RESUME_PAGE_SIZE = 5;
|
|
6
7
|
interface ResumeSessionEntry {
|
|
7
8
|
cwd?: string;
|
|
8
|
-
sessions
|
|
9
|
+
/** SessionStore 的 entry 恒有 sessions(`get()` 只会返回整条或缺席)。 */
|
|
10
|
+
sessions: Map<string, string>;
|
|
9
11
|
}
|
|
10
12
|
interface SessionDisplay {
|
|
11
13
|
events: AgentSessionContentEvent[];
|
|
@@ -18,7 +20,6 @@ interface SessionDisplay {
|
|
|
18
20
|
}
|
|
19
21
|
export interface ResumeCommandDeps {
|
|
20
22
|
defaultAgent: AgentKind;
|
|
21
|
-
validAgents: readonly AgentKind[];
|
|
22
23
|
getSessionEntry(userId: string): ResumeSessionEntry | undefined;
|
|
23
24
|
setSessionId(userId: string, agent: AgentKind, sessionId: string, cwd: string): void;
|
|
24
25
|
defaultReader(): AgentSessionReader;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { isAgentKind } from '../../agent-kinds.js';
|
|
1
2
|
import { agentDisplayName } from '../../card/card-shared.js';
|
|
2
|
-
import { buildSessionHistoryCard, paginationBar } from '
|
|
3
|
+
import { buildSessionHistoryCard, paginationBar } from '../../card/card-helpers.js';
|
|
3
4
|
import { pageInfo } from '../paging.js';
|
|
4
5
|
import { clampInt } from '../../common/clamp.js';
|
|
5
6
|
export const AUTO_RESUME_MAX_EVENTS = 5;
|
|
@@ -14,12 +15,11 @@ function sessionPreviewLine(text, max) {
|
|
|
14
15
|
export function buildResumeCommand(args, ctx, offset, deps) {
|
|
15
16
|
const entry = deps.getSessionEntry(ctx.userId);
|
|
16
17
|
const cwd = entry?.cwd;
|
|
17
|
-
const validAgents = deps.validAgents;
|
|
18
18
|
let agentKind = deps.defaultAgent;
|
|
19
19
|
let limit;
|
|
20
20
|
let sessionIdArg;
|
|
21
21
|
if (args[0]) {
|
|
22
|
-
if (
|
|
22
|
+
if (isAgentKind(args[0])) {
|
|
23
23
|
agentKind = args[0];
|
|
24
24
|
if (args[1]) {
|
|
25
25
|
if (/^\d+$/.test(args[1]))
|
|
@@ -149,7 +149,7 @@ export function buildResumeCommand(args, ctx, offset, deps) {
|
|
|
149
149
|
const elements = [
|
|
150
150
|
{ tag: 'div', text: { tag: 'lark_md', content: `📂 当前工作目录:\`${cwd}\`` } },
|
|
151
151
|
];
|
|
152
|
-
const currentId = entry
|
|
152
|
+
const currentId = entry.sessions.get(agentKind) ?? '';
|
|
153
153
|
for (const session of allSessions) {
|
|
154
154
|
const isCurrent = agentKind === deps.defaultAgent && session.sessionId === currentId;
|
|
155
155
|
const meta = sessionMeta.get(session.sessionId);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cardButton } from '../../card/card-shared.js';
|
|
2
|
-
import { paginationBar, searchBar } from '
|
|
2
|
+
import { paginationBar, searchBar } from '../../card/card-helpers.js';
|
|
3
3
|
import { pageSlice } from '../paging.js';
|
|
4
4
|
import { resolveDirectory } from '../path-validation.js';
|
|
5
5
|
export const WS_PAGE_SIZE = 5;
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import {
|
|
7
|
+
import { CLAUDE_EFFORTS, CLAUDE_PERMISSION_MODES, getModelOptionsFromSettings, } from '../../config/index.js';
|
|
8
|
+
import { MODEL_ALIAS_TO_ID, MODEL_ID_TO_ALIAS } from '../../model-catalog.js';
|
|
8
9
|
/** Claude 官方 --permission-mode 中文注释(value 走 CLAUDE_PERMISSION_MODES SSOT)。 */
|
|
9
10
|
const PERMISSION_MODE_LABELS = {
|
|
10
11
|
default: '默认(敏感操作逐项询问)',
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared config card rendering logic.
|
|
3
3
|
*
|
|
4
|
-
* Builds CardKit 2.0 elements for config fields (
|
|
4
|
+
* Builds CardKit 2.0 elements for config fields (select dropdown, input, note).
|
|
5
5
|
* Used by all agent config builders and the shared tabs (idle, logging).
|
|
6
|
+
*
|
|
7
|
+
* 控件形态只有 `ConfigField.type` 里那三种,且每种在本文件都有对应 builder:
|
|
8
|
+
* 渲染端与处理端(router 的 `config.set` / `config.input`)必须一一对应,
|
|
9
|
+
* 「渲染得出按钮、点了没人处理」是禁止状态(守卫见 config-card-controls.test.ts)。
|
|
6
10
|
*/
|
|
7
11
|
import { type AppConfig } from '../../../config/index.js';
|
|
8
12
|
import type { ConfigField } from '../types.js';
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared config card rendering logic.
|
|
3
3
|
*
|
|
4
|
-
* Builds CardKit 2.0 elements for config fields (
|
|
4
|
+
* Builds CardKit 2.0 elements for config fields (select dropdown, input, note).
|
|
5
5
|
* Used by all agent config builders and the shared tabs (idle, logging).
|
|
6
|
+
*
|
|
7
|
+
* 控件形态只有 `ConfigField.type` 里那三种,且每种在本文件都有对应 builder:
|
|
8
|
+
* 渲染端与处理端(router 的 `config.set` / `config.input`)必须一一对应,
|
|
9
|
+
* 「渲染得出按钮、点了没人处理」是禁止状态(守卫见 config-card-controls.test.ts)。
|
|
6
10
|
*/
|
|
7
11
|
import { getConfigValue } from '../../../config/index.js';
|
|
8
12
|
import { cardButton } from '../../../card/card-shared.js';
|
|
@@ -12,12 +16,7 @@ function buildFieldElements(fields, displayConfig) {
|
|
|
12
16
|
for (const field of fields) {
|
|
13
17
|
// Get current value from displayConfig for dynamic fields
|
|
14
18
|
const currentValue = getConfigValue(displayConfig, field.key);
|
|
15
|
-
if (field.type === '
|
|
16
|
-
// For boolean, use field.currentValue if set, otherwise use config value
|
|
17
|
-
const isOn = field.currentValue !== undefined ? field.currentValue === true : currentValue === true;
|
|
18
|
-
elements.push(buildBooleanElement(field, isOn));
|
|
19
|
-
}
|
|
20
|
-
else if (field.type === 'select' && field.options) {
|
|
19
|
+
if (field.type === 'select' && field.options) {
|
|
21
20
|
elements.push(buildSelectElement(field, currentValue));
|
|
22
21
|
}
|
|
23
22
|
else if (field.type === 'note') {
|
|
@@ -53,12 +52,6 @@ function fieldRow(label, control) {
|
|
|
53
52
|
],
|
|
54
53
|
};
|
|
55
54
|
}
|
|
56
|
-
function buildBooleanElement(field, isOn) {
|
|
57
|
-
const displayVal = isOn ? '✅ 已开启' : '⚪ 已关闭';
|
|
58
|
-
return fieldRow(field.label, cardButton(displayVal, { cmd: 'config.toggle', key: field.key }, {
|
|
59
|
-
type: isOn ? 'primary' : 'default',
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
55
|
function buildSelectElement(field, currentValue) {
|
|
63
56
|
// 优先使用 field.currentValue(卡片显示用覆盖值),否则使用 config 中的值
|
|
64
57
|
const selectedValue = field.currentValue != null
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { AgentConfigCardBuilder, ConfigField } from './types.js';
|
|
19
19
|
import { type AppConfig } from '../../config/index.js';
|
|
20
|
-
import type { DshModelCatalogValue, DshPermissionCatalogValue, DshPresetListValue } from '../../
|
|
20
|
+
import type { DshModelCatalogValue, DshPermissionCatalogValue, DshPresetListValue } from '../../dsh/types.js';
|
|
21
21
|
/** DshConfigBuilder 预取只依赖的 client 方法子集。 */
|
|
22
22
|
export interface DshCatalogClient {
|
|
23
23
|
listModels(): Promise<DshModelCatalogValue>;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Each agent implements AgentConfigCardBuilder in its own file.
|
|
5
5
|
* Adding a new agent = add a file + register here (no upstream changes needed).
|
|
6
6
|
*/
|
|
7
|
-
import type { AgentKind } from '../../
|
|
7
|
+
import type { AgentKind } from '../../agent-kinds.js';
|
|
8
8
|
import type { AgentConfigCardBuilder } from './types.js';
|
|
9
9
|
/**
|
|
10
10
|
* 首次启动默认展示的 Coding Agent 顺序:Codex → Claude → OpenCode → Pi → Kimi → DSH。
|
|
@@ -16,13 +16,21 @@ export interface SelectOption {
|
|
|
16
16
|
export interface ConfigField {
|
|
17
17
|
key: string;
|
|
18
18
|
label: string;
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* 卡片上真实存在的控件形态,每种都在 `common/render.ts` 有对应 builder:
|
|
21
|
+
* select=下拉、input=文本框、note=纯说明行(无回调)。
|
|
22
|
+
*
|
|
23
|
+
* 没有 boolean:卡片曾留着一套「开关」控件(`config.toggle`),但全仓没有
|
|
24
|
+
* 任何字段声明它,2026-10-27 成套删除。原则是**卡片只放配得了的控件**,
|
|
25
|
+
* 实现细节与未上卡的键走 YAML(见 `buildConfigCard` 的分 tab 注释)。
|
|
26
|
+
*/
|
|
27
|
+
type: 'select' | 'input' | 'note';
|
|
20
28
|
/** For select type: the list of options shown in the dropdown.
|
|
21
29
|
* Accepts plain strings (text=value) or {text, value} objects for
|
|
22
30
|
* display-value separation (e.g. 'manual(逐项审批)' → value 'manual'). */
|
|
23
31
|
options?: readonly (string | SelectOption)[];
|
|
24
32
|
/** Override the currentValue shown in the card (takes priority over getConfigValue). */
|
|
25
|
-
currentValue?: string
|
|
33
|
+
currentValue?: string;
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
28
36
|
* Builder that provides config fields and handles field changes for a specific agent.
|
|
@@ -40,7 +48,7 @@ export interface AgentConfigCardBuilder {
|
|
|
40
48
|
* Handle a field change for this agent.
|
|
41
49
|
*
|
|
42
50
|
* @param key - The field key (e.g. 'agents.codex.modelProvider')
|
|
43
|
-
* @param value - The new value (string for select/input
|
|
51
|
+
* @param value - The new value (string for select/input)
|
|
44
52
|
* @param config - The current pendingConfig (read-only reference for deriving dependent values)
|
|
45
53
|
* @returns An array of {key, value} patches to apply to pendingConfig.
|
|
46
54
|
* The caller (router) applies these via setNestedValue.
|