lark-remote 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -1
- package/README.en.md +9 -1
- package/README.md +14 -2
- package/dist/bridge/approval-coordinator.d.ts +71 -34
- package/dist/bridge/approval-coordinator.js +225 -41
- package/dist/bridge/inbound-media.d.ts +62 -0
- package/dist/bridge/inbound-media.js +282 -0
- package/dist/bridge/index.d.ts +97 -13
- package/dist/bridge/index.js +227 -87
- package/dist/bridge/queue-manager.d.ts +2 -1
- package/dist/bridge/queue-manager.js +1 -0
- package/dist/card/approval-render.js +294 -36
- 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 +7 -16
- package/dist/card/card-shared.js +7 -30
- package/dist/card/run-card-session.d.ts +2 -55
- package/dist/card/run-card-session.js +6 -104
- package/dist/card/run-renderer.d.ts +7 -0
- package/dist/card/run-renderer.js +116 -238
- package/dist/card/run-state.d.ts +13 -0
- package/dist/card/run-state.js +25 -16
- 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/index.d.ts +112 -24
- package/dist/config/index.js +139 -37
- package/dist/connector/index.d.ts +69 -2
- package/dist/connector/index.js +107 -1
- package/dist/index.js +150 -118
- 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-action-payload.d.ts +30 -0
- package/dist/router/card-action-payload.js +39 -0
- package/dist/router/card-helpers.d.ts +63 -0
- package/dist/router/card-helpers.js +146 -0
- package/dist/router/config/claude.js +30 -1
- package/dist/router/config/codex.js +29 -50
- 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 +5 -4
- package/dist/router/config/dsh.d.ts +51 -0
- package/dist/router/config/dsh.js +179 -0
- package/dist/router/config/index.d.ts +12 -0
- package/dist/router/config/index.js +28 -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 +17 -2
- package/dist/router/index.d.ts +76 -22
- package/dist/router/index.js +479 -548
- package/dist/router/utils.d.ts +2 -0
- package/dist/router/utils.js +16 -2
- package/dist/runner/agent-choices-common.d.ts +16 -0
- package/dist/runner/agent-choices-common.js +34 -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 +768 -0
- package/dist/runner/codex/app-server/protocol-types.d.ts +66 -39
- package/dist/runner/codex/app-server/protocol-types.js +2 -13
- package/dist/runner/codex/app-server/runner.d.ts +52 -59
- package/dist/runner/codex/app-server/runner.js +216 -338
- package/dist/runner/codex/app-server/translator.d.ts +8 -21
- package/dist/runner/codex/app-server/translator.js +45 -18
- package/dist/runner/codex/index.d.ts +0 -2
- package/dist/runner/codex/index.js +0 -2
- 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 +271 -0
- package/dist/runner/common/acp/protocol-types.js +77 -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/{codex/app-server → common/jsonrpc}/client.d.ts +14 -7
- package/dist/runner/{codex/app-server → common/jsonrpc}/client.js +27 -18
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +125 -0
- package/dist/runner/{codex/app-server → common/jsonrpc}/connection-manager.js +63 -28
- package/dist/runner/{codex/app-server → common/jsonrpc}/transport.d.ts +5 -4
- package/dist/runner/{codex/app-server → common/jsonrpc}/transport.js +18 -19
- 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/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 +5 -4
- package/dist/runner/index.js +5 -4
- package/dist/runner/kimi/acp/runner.d.ts +106 -0
- package/dist/runner/kimi/acp/runner.js +516 -0
- package/dist/runner/kimi/acp/translator.d.ts +138 -0
- package/dist/runner/kimi/acp/translator.js +441 -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 +74 -0
- package/dist/runner/pi/rpc/runner.js +190 -0
- package/dist/runner/pi/rpc/translator.d.ts +55 -0
- package/dist/runner/pi/rpc/translator.js +258 -0
- 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/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 +97 -14
- package/dist/session/claude/session-index.js +2 -3
- package/dist/session/claude/session-reader.js +3 -6
- package/dist/session/claude/sessions.js +43 -28
- package/dist/session/codex/rollout-reader.d.ts +2 -2
- package/dist/session/codex/rollout-reader.js +14 -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/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/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/dist/workspace/index.d.ts +4 -0
- package/dist/workspace/index.js +8 -1
- package/package.json +2 -1
- package/dist/runner/codex/app-server/connection-manager.d.ts +0 -56
- package/dist/runner/codex/argv.d.ts +0 -33
- package/dist/runner/codex/argv.js +0 -40
- package/dist/runner/codex/factory.d.ts +0 -29
- package/dist/runner/codex/factory.js +0 -39
- 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 -66
- package/dist/runner/codex/runner.js +0 -129
- 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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AskUserQuestion 公共工厂与映射(agent 无关)。
|
|
3
|
+
*
|
|
4
|
+
* 接入约定(types.ts UserQuestion 注释的落点):
|
|
5
|
+
* - 各 runner 用 makeQuestionApprovalEvent 构造标准 question 审批事件,
|
|
6
|
+
* 避免四处手拼事件形状(claude/codex/kimi/pi 共用);
|
|
7
|
+
* - 用户答案经 ApprovalCoordinator 以 {问题文本: 值} 回传 runner 后,
|
|
8
|
+
* 用 mapAnswersByIndex 按问题顺序展开,再做协议级编码
|
|
9
|
+
* (Codex 问题 id、Kimi q{i}、Pi 单题取值)。
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 构造标准 question approval_requested 事件。
|
|
13
|
+
* availableDecisions 恒为空数组:提问只能作答或跳过(decline/cancel 是
|
|
14
|
+
* coordinator 的通用安全兜底),不允许 accept/decline 按钮混入提问卡。
|
|
15
|
+
*/
|
|
16
|
+
export function makeQuestionApprovalEvent(requestId, questions, threadId, opts) {
|
|
17
|
+
const view = {
|
|
18
|
+
requestId,
|
|
19
|
+
kind: 'question',
|
|
20
|
+
questions,
|
|
21
|
+
availableDecisions: [],
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
type: 'approval_requested',
|
|
25
|
+
requestId,
|
|
26
|
+
kind: 'question',
|
|
27
|
+
threadId,
|
|
28
|
+
turnId: '',
|
|
29
|
+
itemId: '',
|
|
30
|
+
view,
|
|
31
|
+
...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 按问题顺序把 coordinator 回传的 {问题文本: 值} 展开成索引对齐数组。
|
|
37
|
+
* 未作答的问题对应 undefined,由各 runner 决定协议编码(跳过/空 answers)。
|
|
38
|
+
*/
|
|
39
|
+
export function mapAnswersByIndex(questions, answers) {
|
|
40
|
+
return questions.map((q) => answers[q.question]);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=question-common.js.map
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { AgentKind,
|
|
1
|
+
import type { AgentKind, Runner } from './index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Registry of agent factories, keyed by `AgentKind`. `index.ts` registers one
|
|
4
4
|
* factory per available agent at startup; `Bridge.getRunner(workspace)` looks
|
|
5
5
|
* up `config.defaultAgent` here to pick the concrete runner.
|
|
6
6
|
*
|
|
7
|
-
* Singleton caching: the factory MAY cache its instance internally.
|
|
8
|
-
* current agents (claude,
|
|
9
|
-
*
|
|
10
|
-
* runner per call.
|
|
7
|
+
* Singleton caching: the factory MAY cache its instance internally. Most
|
|
8
|
+
* current agents (claude, opencode, pi, kimi) are spawn-per-message; codex is
|
|
9
|
+
* workspace-lifetime (app-server). Each factory returns a runner per call.
|
|
11
10
|
*
|
|
12
11
|
* Dynamic config reload: factory can read latest config via registry's
|
|
13
12
|
* configContainer, enabling runtime config changes to take effect.
|
|
@@ -17,7 +16,7 @@ export declare class AgentRegistry {
|
|
|
17
16
|
private readonly displayNames;
|
|
18
17
|
/** Container for runtime config updates (pi provider dynamic reload). */
|
|
19
18
|
private configContainer?;
|
|
20
|
-
register(kind: AgentKind, factory: (workspace: string) =>
|
|
19
|
+
register(kind: AgentKind, factory: (workspace: string) => Runner): void;
|
|
21
20
|
/**
|
|
22
21
|
* 注册 agent 的显示名。应在 register(kind, factory) 后调用。
|
|
23
22
|
* 用于 agentDisplayName 等全局查询,实现单点真相。
|
|
@@ -31,7 +30,7 @@ export declare class AgentRegistry {
|
|
|
31
30
|
* 设置全局 registry 实例,供 agentDisplayName 等全局函数使用。
|
|
32
31
|
* 在 index.ts 初始化所有 agents 后调用。
|
|
33
32
|
*/
|
|
34
|
-
static setGlobalInstance(reg: AgentRegistry): void;
|
|
33
|
+
static setGlobalInstance(reg: AgentRegistry | undefined): void;
|
|
35
34
|
/**
|
|
36
35
|
* 获取全局 registry 实例。
|
|
37
36
|
*/
|
|
@@ -50,5 +49,5 @@ export declare class AgentRegistry {
|
|
|
50
49
|
getConfigContainer(): {
|
|
51
50
|
current: unknown;
|
|
52
51
|
} | undefined;
|
|
53
|
-
get(kind: AgentKind, workspace: string):
|
|
52
|
+
get(kind: AgentKind, workspace: string): Runner;
|
|
54
53
|
}
|
package/dist/runner/registry.js
CHANGED
|
@@ -8,10 +8,9 @@ let globalRegistry;
|
|
|
8
8
|
* factory per available agent at startup; `Bridge.getRunner(workspace)` looks
|
|
9
9
|
* up `config.defaultAgent` here to pick the concrete runner.
|
|
10
10
|
*
|
|
11
|
-
* Singleton caching: the factory MAY cache its instance internally.
|
|
12
|
-
* current agents (claude,
|
|
13
|
-
*
|
|
14
|
-
* runner per call.
|
|
11
|
+
* Singleton caching: the factory MAY cache its instance internally. Most
|
|
12
|
+
* current agents (claude, opencode, pi, kimi) are spawn-per-message; codex is
|
|
13
|
+
* workspace-lifetime (app-server). Each factory returns a runner per call.
|
|
15
14
|
*
|
|
16
15
|
* Dynamic config reload: factory can read latest config via registry's
|
|
17
16
|
* configContainer, enabling runtime config changes to take effect.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { choiceFieldsFor } from './agent-choices-common.js';
|
|
1
2
|
export function resolveAgentChoices(config) {
|
|
2
|
-
const choices = config.agentChoices;
|
|
3
3
|
const agent = config.defaultAgent;
|
|
4
|
+
const choices = config.agentChoices;
|
|
4
5
|
if (!choices || !agent) {
|
|
5
6
|
return config;
|
|
6
7
|
}
|
|
@@ -9,67 +10,25 @@ export function resolveAgentChoices(config) {
|
|
|
9
10
|
return config;
|
|
10
11
|
}
|
|
11
12
|
const agentChoices = choices[agent];
|
|
12
|
-
|
|
13
|
+
const fields = choiceFieldsFor(agent);
|
|
14
|
+
if (!agentChoices || !fields) {
|
|
13
15
|
return config;
|
|
14
16
|
}
|
|
15
17
|
// Clone to avoid mutation
|
|
16
|
-
const resolved =
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!resolvedAny.agents.codex.modelProvider && agentChoicesAny.modelProvider) {
|
|
31
|
-
resolvedAny.agents.codex.modelProvider = agentChoicesAny.modelProvider;
|
|
32
|
-
}
|
|
33
|
-
break;
|
|
34
|
-
case 'pi':
|
|
35
|
-
if (!resolvedAny.agents)
|
|
36
|
-
resolvedAny.agents = {};
|
|
37
|
-
if (!resolvedAny.agents.pi)
|
|
38
|
-
resolvedAny.agents.pi = {};
|
|
39
|
-
if (!resolvedAny.agents.pi.model && agentChoicesAny.model) {
|
|
40
|
-
resolvedAny.agents.pi.model = agentChoicesAny.model;
|
|
41
|
-
}
|
|
42
|
-
if (!resolvedAny.agents.pi.provider && agentChoicesAny.provider) {
|
|
43
|
-
resolvedAny.agents.pi.provider = agentChoicesAny.provider;
|
|
44
|
-
}
|
|
45
|
-
if (!resolvedAny.agents.pi.thinking && agentChoicesAny.thinking) {
|
|
46
|
-
resolvedAny.agents.pi.thinking = agentChoicesAny.thinking;
|
|
47
|
-
}
|
|
48
|
-
break;
|
|
49
|
-
case 'opencode':
|
|
50
|
-
if (!resolvedAny.agents)
|
|
51
|
-
resolvedAny.agents = {};
|
|
52
|
-
if (!resolvedAny.agents.opencode)
|
|
53
|
-
resolvedAny.agents.opencode = {};
|
|
54
|
-
if (!resolvedAny.agents.opencode.modelID && agentChoicesAny.modelID) {
|
|
55
|
-
resolvedAny.agents.opencode.modelID = agentChoicesAny.modelID;
|
|
56
|
-
}
|
|
57
|
-
if (!resolvedAny.agents.opencode.providerID && agentChoicesAny.providerID) {
|
|
58
|
-
resolvedAny.agents.opencode.providerID = agentChoicesAny.providerID;
|
|
59
|
-
}
|
|
60
|
-
break;
|
|
61
|
-
case 'kimi':
|
|
62
|
-
if (!resolvedAny.agents)
|
|
63
|
-
resolvedAny.agents = {};
|
|
64
|
-
if (!resolvedAny.agents.kimi)
|
|
65
|
-
resolvedAny.agents.kimi = {};
|
|
66
|
-
if (!resolvedAny.agents.kimi.model && agentChoicesAny.model) {
|
|
67
|
-
resolvedAny.agents.kimi.model = agentChoicesAny.model;
|
|
68
|
-
}
|
|
69
|
-
if (!resolvedAny.agents.kimi.thinkingEffort && agentChoicesAny.thinkingEffort) {
|
|
70
|
-
resolvedAny.agents.kimi.thinkingEffort = agentChoicesAny.thinkingEffort;
|
|
71
|
-
}
|
|
72
|
-
break;
|
|
18
|
+
const resolved = structuredClone(config);
|
|
19
|
+
// agents.codex 在 schema 中必填(带默认值),此处按旧语义补空对象;
|
|
20
|
+
// 运行时只往 [agent] 槽位写字段,不依赖 codex 默认值。
|
|
21
|
+
if (!resolved.agents) {
|
|
22
|
+
resolved.agents = {};
|
|
23
|
+
}
|
|
24
|
+
const agents = resolved.agents;
|
|
25
|
+
const target = (agents[agent] ??= {});
|
|
26
|
+
const source = agentChoices;
|
|
27
|
+
for (const { configKey, choicesKey } of fields) {
|
|
28
|
+
const value = source[choicesKey];
|
|
29
|
+
if (!target[configKey] && value) {
|
|
30
|
+
target[configKey] = value;
|
|
31
|
+
}
|
|
73
32
|
}
|
|
74
33
|
return resolved;
|
|
75
34
|
}
|
|
@@ -1,72 +1,21 @@
|
|
|
1
|
+
import { choiceFieldsFor } from './agent-choices-common.js';
|
|
1
2
|
export function syncAgentChoices(config, agent) {
|
|
2
|
-
//
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const agentCfg = agents[agent];
|
|
6
|
-
// claude reads from top-level config.claude, not agents.claude
|
|
7
|
-
if (agent !== 'claude' && !agentCfg) {
|
|
3
|
+
// claude 的配置在顶层 config.claude,不在 agents 下,无需同步
|
|
4
|
+
const fields = choiceFieldsFor(agent);
|
|
5
|
+
if (!fields)
|
|
8
6
|
return config;
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
updatedAny.agentChoices.codex.model = agentCfg.model;
|
|
22
|
-
}
|
|
23
|
-
if (agentCfg.modelProvider) {
|
|
24
|
-
if (!updatedAny.agentChoices.codex)
|
|
25
|
-
updatedAny.agentChoices.codex = {};
|
|
26
|
-
updatedAny.agentChoices.codex.modelProvider = agentCfg.modelProvider;
|
|
27
|
-
}
|
|
28
|
-
break;
|
|
29
|
-
case 'pi':
|
|
30
|
-
if (agentCfg.model) {
|
|
31
|
-
if (!updatedAny.agentChoices.pi)
|
|
32
|
-
updatedAny.agentChoices.pi = {};
|
|
33
|
-
updatedAny.agentChoices.pi.model = agentCfg.model;
|
|
34
|
-
}
|
|
35
|
-
if (agentCfg.provider) {
|
|
36
|
-
if (!updatedAny.agentChoices.pi)
|
|
37
|
-
updatedAny.agentChoices.pi = {};
|
|
38
|
-
updatedAny.agentChoices.pi.provider = agentCfg.provider;
|
|
39
|
-
}
|
|
40
|
-
if (agentCfg.thinking) {
|
|
41
|
-
if (!updatedAny.agentChoices.pi)
|
|
42
|
-
updatedAny.agentChoices.pi = {};
|
|
43
|
-
updatedAny.agentChoices.pi.thinking = agentCfg.thinking;
|
|
44
|
-
}
|
|
45
|
-
break;
|
|
46
|
-
case 'opencode':
|
|
47
|
-
if (agentCfg.modelID) {
|
|
48
|
-
if (!updatedAny.agentChoices.opencode)
|
|
49
|
-
updatedAny.agentChoices.opencode = {};
|
|
50
|
-
updatedAny.agentChoices.opencode.modelID = agentCfg.modelID;
|
|
51
|
-
}
|
|
52
|
-
if (agentCfg.providerID) {
|
|
53
|
-
if (!updatedAny.agentChoices.opencode)
|
|
54
|
-
updatedAny.agentChoices.opencode = {};
|
|
55
|
-
updatedAny.agentChoices.opencode.providerID = agentCfg.providerID;
|
|
56
|
-
}
|
|
57
|
-
break;
|
|
58
|
-
case 'kimi':
|
|
59
|
-
if (agentCfg.model) {
|
|
60
|
-
if (!updatedAny.agentChoices.kimi)
|
|
61
|
-
updatedAny.agentChoices.kimi = {};
|
|
62
|
-
updatedAny.agentChoices.kimi.model = agentCfg.model;
|
|
63
|
-
}
|
|
64
|
-
if (agentCfg.thinkingEffort) {
|
|
65
|
-
if (!updatedAny.agentChoices.kimi)
|
|
66
|
-
updatedAny.agentChoices.kimi = {};
|
|
67
|
-
updatedAny.agentChoices.kimi.thinkingEffort = agentCfg.thinkingEffort;
|
|
68
|
-
}
|
|
69
|
-
break;
|
|
7
|
+
const agents = config.agents;
|
|
8
|
+
const agentCfg = agents?.[agent];
|
|
9
|
+
if (!agentCfg)
|
|
10
|
+
return config;
|
|
11
|
+
const updated = structuredClone(config);
|
|
12
|
+
const choices = (updated.agentChoices ??= {});
|
|
13
|
+
const agentChoices = (choices[agent] ??= {});
|
|
14
|
+
const source = agentCfg;
|
|
15
|
+
for (const { configKey, choicesKey } of fields) {
|
|
16
|
+
const value = source[configKey];
|
|
17
|
+
if (value)
|
|
18
|
+
agentChoices[choicesKey] = value;
|
|
70
19
|
}
|
|
71
20
|
return updated;
|
|
72
21
|
}
|
package/dist/runner/types.d.ts
CHANGED
|
@@ -25,11 +25,18 @@ export interface ApprovalRequestedEvent {
|
|
|
25
25
|
type: 'approval_requested';
|
|
26
26
|
/** JSON-RPC id of the server request. Wire type is string | integer — keep raw. */
|
|
27
27
|
requestId: number | string;
|
|
28
|
-
kind: 'command' | 'file' | 'permissions';
|
|
28
|
+
kind: 'command' | 'file' | 'permissions' | 'question' | 'tool';
|
|
29
29
|
threadId: string;
|
|
30
30
|
turnId: string;
|
|
31
31
|
itemId: string;
|
|
32
32
|
view: ApprovalView;
|
|
33
|
+
/**
|
|
34
|
+
* Per-request 审批超时覆盖(毫秒)。由 runner 在翻译时填入
|
|
35
|
+
* (Codex autoResolutionMs),coordinator 优先使用;
|
|
36
|
+
* 缺省回落 run 级默认超时。放在事件上而非桥按 agentKind 分支,
|
|
37
|
+
* 保证公共层无 agent 分支。
|
|
38
|
+
*/
|
|
39
|
+
timeoutMs?: number;
|
|
33
40
|
timestamp?: string;
|
|
34
41
|
}
|
|
35
42
|
export interface ApprovalResolvedEvent {
|
|
@@ -51,28 +58,101 @@ export interface ApprovalExpiredEvent {
|
|
|
51
58
|
requestId: number | string;
|
|
52
59
|
timestamp?: string;
|
|
53
60
|
}
|
|
61
|
+
/** 审批决策(bridge ApprovalCoordinator → runner.respondApproval 的响应载荷)。 */
|
|
62
|
+
export type ApprovalAction = {
|
|
63
|
+
action: 'accept';
|
|
64
|
+
} | {
|
|
65
|
+
action: 'accept_for_session';
|
|
66
|
+
} | {
|
|
67
|
+
action: 'accept_with_execpolicy_amendment';
|
|
68
|
+
}
|
|
69
|
+
/** Claude:允许当前请求 + 本会话后续所有权限请求自动放行(允许所有)。 */
|
|
70
|
+
| {
|
|
71
|
+
action: 'accept_all';
|
|
72
|
+
} | {
|
|
73
|
+
action: 'decline';
|
|
74
|
+
} | {
|
|
75
|
+
action: 'cancel';
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* AskUserQuestion 答案(question → label 或 label[])。
|
|
79
|
+
* notes:Codex user_note 补充说明(question → 文本),runner 编码为
|
|
80
|
+
* "user_note: <text>" 条目;其他 agent 忽略该字段。
|
|
81
|
+
*/
|
|
82
|
+
| {
|
|
83
|
+
action: 'answer';
|
|
84
|
+
answers: Record<string, string | string[]>;
|
|
85
|
+
notes?: Record<string, string>;
|
|
86
|
+
};
|
|
87
|
+
/** AskUserQuestion 公共契约(Agent 无关)的单个选项。 */
|
|
88
|
+
export interface UserQuestionOption {
|
|
89
|
+
label: string;
|
|
90
|
+
description?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* AskUserQuestion 公共契约(Agent 无关)的单个问题。
|
|
94
|
+
*
|
|
95
|
+
* 接入约定(新 agent 接入 AskUserQuestion 时在这里扩展,禁止在 coordinator /
|
|
96
|
+
* renderer / router 里写 agent 分支):
|
|
97
|
+
* 1. 各 agent runner 把协议提问翻译为 `ApprovalView{ kind:'question', questions }`;
|
|
98
|
+
* 2. 用户回答经 ApprovalCoordinator 收集,以 `ApprovalAction{action:'answer',
|
|
99
|
+
* answers:{问题文本: string|string[]}}` 回传 runner;
|
|
100
|
+
* 3. runner 侧把文本 key 答案翻译回自己协议的 shape(Claude 直接用文本 key;
|
|
101
|
+
* Codex 需按问题 id 映射)。
|
|
102
|
+
*/
|
|
103
|
+
export interface UserQuestion {
|
|
104
|
+
/** Agent 侧问题唯一标识(Codex request_user_input 的 id 预留;Claude 无此字段)。 */
|
|
105
|
+
id?: string;
|
|
106
|
+
question: string;
|
|
107
|
+
header?: string;
|
|
108
|
+
multiSelect?: boolean;
|
|
109
|
+
options: UserQuestionOption[];
|
|
110
|
+
/** 是否允许自定义答案(Codex isOther 预留;当前单选渲染层恒提供 Other 输入)。 */
|
|
111
|
+
isOther?: boolean;
|
|
112
|
+
/** 敏感输入(Codex isSecret 预留)。 */
|
|
113
|
+
isSecret?: boolean;
|
|
114
|
+
/** 自由文本题的输入框占位提示(渲染层自由文本题 input)。 */
|
|
115
|
+
placeholder?: string;
|
|
116
|
+
/**
|
|
117
|
+
* 是否渲染「补充说明(可选)」输入(Codex user_note;数据驱动无 agent 分支)。
|
|
118
|
+
* note 是选项之外的附加文本,随答案提交,不单独构成答案。
|
|
119
|
+
*/
|
|
120
|
+
allowNote?: boolean;
|
|
121
|
+
/** 当前已填写的补充说明(卡片回显;coordinator answerNote 回流)。 */
|
|
122
|
+
note?: string;
|
|
123
|
+
/**
|
|
124
|
+
* 当前已选选项 label(卡片渲染与多选切换用;单选在协调器内即时提交)。
|
|
125
|
+
* 与 permissions.items.selected 同模式:协调器原地更新后以
|
|
126
|
+
* approval_view_updated 重新渲染。
|
|
127
|
+
*/
|
|
128
|
+
selected?: string[];
|
|
129
|
+
}
|
|
54
130
|
export interface ApprovalView {
|
|
55
131
|
requestId: number | string;
|
|
56
|
-
kind: 'command' | 'file' | 'permissions';
|
|
132
|
+
kind: 'command' | 'file' | 'permissions' | 'question' | 'tool';
|
|
57
133
|
reason?: string;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
134
|
+
/**
|
|
135
|
+
* 提问卡顶部概要行(数据驱动,无 agent 分支):Kimi elicitation form 的
|
|
136
|
+
* 题面只在 form 级 message 里合并出现,逐字段 title 可能只是短 header,
|
|
137
|
+
* 概要行用于展示完整题干。
|
|
138
|
+
*/
|
|
139
|
+
intro?: string;
|
|
61
140
|
command?: string;
|
|
62
141
|
commandCwd?: string;
|
|
142
|
+
/**
|
|
143
|
+
* 被审批的工具名(kind === 'tool' 时展示,如 ExitPlanMode)。非命令工具的
|
|
144
|
+
* 权限请求(plan 退出/通知型工具)input 无 command 语义,用工具名 + reason
|
|
145
|
+
* 表达审批内容,避免落入 command 槽位显示无意义 `{}`。
|
|
146
|
+
*/
|
|
147
|
+
toolName?: string;
|
|
148
|
+
/** 原始 input 的 JSON 字符串(kind === 'tool' 且 input 非空时展示)。 */
|
|
149
|
+
toolInput?: string;
|
|
63
150
|
fileChanges?: Array<{
|
|
64
151
|
path: string;
|
|
65
152
|
kind: 'add' | 'update' | 'delete';
|
|
66
153
|
diff?: string;
|
|
67
154
|
}>;
|
|
68
|
-
network?: {
|
|
69
|
-
host: string;
|
|
70
|
-
protocol: string;
|
|
71
|
-
};
|
|
72
155
|
permissions?: {
|
|
73
|
-
networkEnabled?: boolean;
|
|
74
|
-
fileSystemRead?: string[];
|
|
75
|
-
fileSystemWrite?: string[];
|
|
76
156
|
items: Array<{
|
|
77
157
|
id: string;
|
|
78
158
|
label: string;
|
|
@@ -85,10 +165,11 @@ export interface ApprovalView {
|
|
|
85
165
|
selected: boolean;
|
|
86
166
|
}>;
|
|
87
167
|
};
|
|
168
|
+
/** Claude AskUserQuestion 问题列表(kind === 'question' 时存在)。 */
|
|
169
|
+
questions?: UserQuestion[];
|
|
88
170
|
availableDecisions: string[];
|
|
89
171
|
/** Raw payloads for structured decisions (e.g. acceptWithExecpolicyAmendment). */
|
|
90
172
|
decisionPayloads?: Record<string, unknown>;
|
|
91
|
-
pendingTotal: number;
|
|
92
173
|
}
|
|
93
174
|
interface ThinkingContent {
|
|
94
175
|
type: 'thinking';
|
|
@@ -253,12 +334,14 @@ export interface Runner {
|
|
|
253
334
|
*/
|
|
254
335
|
unregisterExitHandlers?(): void;
|
|
255
336
|
}
|
|
256
|
-
export type AgentKind = 'claude' | 'codex' | 'opencode' | 'pi' | 'kimi';
|
|
337
|
+
export type AgentKind = 'claude' | 'codex' | 'opencode' | 'pi' | 'kimi' | 'dsh';
|
|
257
338
|
/** Unified session descriptor returned by every AgentSessionReader. */
|
|
258
339
|
export interface AgentSession {
|
|
259
340
|
sessionId: string;
|
|
260
341
|
summary: string;
|
|
261
342
|
mtime: number;
|
|
343
|
+
/** DSH:session 创建时固定的 preset;其他 agent 无此概念(undefined)。 */
|
|
344
|
+
agentPreset?: string;
|
|
262
345
|
}
|
|
263
346
|
/** A single renderable event from session history. */
|
|
264
347
|
export interface AgentSessionContentEvent {
|
|
@@ -2,7 +2,6 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { scanJsonlLines } from '../common/jsonl.js';
|
|
4
4
|
import { extractContentBlocks } from '../common/content-blocks.js';
|
|
5
|
-
import { truncate } from '../../card/card-shared.js';
|
|
6
5
|
import { getLogger } from '../../logger/index.js';
|
|
7
6
|
// ─── Claude content block mapping (shared with sessions.ts) ─
|
|
8
7
|
/** Claude-specific field-name mapping for content block extraction. */
|
|
@@ -224,7 +223,7 @@ export class SessionIndex {
|
|
|
224
223
|
path: p,
|
|
225
224
|
fingerprint: currentFp,
|
|
226
225
|
mtimeMs: Number(st.mtimeMs),
|
|
227
|
-
summary:
|
|
226
|
+
summary: parsed.summary.replace(/\s+/g, ' ').trim(),
|
|
228
227
|
cwdSet: parsed.cwdSet,
|
|
229
228
|
};
|
|
230
229
|
this.updateEntry(p, updated);
|
|
@@ -302,7 +301,7 @@ export class SessionIndex {
|
|
|
302
301
|
path: fullPath,
|
|
303
302
|
fingerprint: fpAfter,
|
|
304
303
|
mtimeMs: Number(fileStat.mtimeMs),
|
|
305
|
-
summary:
|
|
304
|
+
summary: parsed.summary.replace(/\s+/g, ' ').trim(),
|
|
306
305
|
cwdSet: parsed.cwdSet,
|
|
307
306
|
};
|
|
308
307
|
this.updateEntry(fullPath, newEntry);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { paginate } from '../common/pagination.js';
|
|
1
2
|
import { listClaudeSessions, getNewestSession, readSessionContent, isClaudeSessionActive, } from '../../session/claude/sessions.js';
|
|
2
3
|
/**
|
|
3
4
|
* Adapter that exposes Claude Code's session-reading functions through the
|
|
@@ -22,12 +23,8 @@ export class ClaudeSessionReader {
|
|
|
22
23
|
// 先拿全集(不传 limit → listClaudeSessions 不切片),total 用全集长度,
|
|
23
24
|
// 再由 reader 按 [offset, offset+limit) 切片。
|
|
24
25
|
const all = listClaudeSessions(cwd, this.readerOpts());
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
sessions: limit === undefined ? all.slice(offset) : all.slice(offset, offset + limit),
|
|
29
|
-
total: all.length,
|
|
30
|
-
};
|
|
26
|
+
const { items, total } = paginate(all, opts ?? {});
|
|
27
|
+
return { sessions: items, total };
|
|
31
28
|
}
|
|
32
29
|
getNewestSession(cwd) {
|
|
33
30
|
const session = getNewestSession(cwd, this.readerOpts());
|
|
@@ -3,9 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import { findJsonlLine, readLastJsonlLine, scanJsonlLines, readJsonlLinesFromOffset, } from '../common/jsonl.js';
|
|
5
5
|
import { STALE_MS } from '../common/constants.js';
|
|
6
|
+
import { capEvents } from '../common/pagination.js';
|
|
6
7
|
import { extractContentBlocks } from '../common/content-blocks.js';
|
|
7
8
|
import { UsageAccumulator } from '../common/usage-accumulator.js';
|
|
8
|
-
import { truncate } from '../../card/card-shared.js';
|
|
9
9
|
import { SessionIndex, extractText, isTaskNotificationText, CLAUDE_MAPPING, } from './session-index.js';
|
|
10
10
|
/**
|
|
11
11
|
* Directory Claude Code uses to store session transcripts for a given cwd.
|
|
@@ -154,7 +154,7 @@ function isSessionActive(filePath, mtimeMs, now = Date.now()) {
|
|
|
154
154
|
// Explicit terminal markers — regardless of mtime. Claude CLI 2.x uses
|
|
155
155
|
// `last-prompt` / `mode` (no `result` event) to mark turn end, so a
|
|
156
156
|
// 24-minute-old session with a last-prompt tail is already done
|
|
157
|
-
// (regression 2026-06-21:
|
|
157
|
+
// (regression 2026-06-21: previously falsely reported as active).
|
|
158
158
|
const TERMINAL_TYPES = new Set(['result', 'last-prompt', 'mode', 'permission-mode']);
|
|
159
159
|
if (typeof obj.type === 'string' && TERMINAL_TYPES.has(obj.type))
|
|
160
160
|
return false;
|
|
@@ -224,7 +224,16 @@ export function isClaudeSessionActive(sessionId, cwd, opts = {}) {
|
|
|
224
224
|
*/
|
|
225
225
|
function scalarScan(filePath) {
|
|
226
226
|
const acc = new UsageAccumulator();
|
|
227
|
-
|
|
227
|
+
// Per-message-id best usage record (per-field max). A streaming assistant
|
|
228
|
+
// message spans multiple jsonl lines sharing the same message id; some
|
|
229
|
+
// backends (third-party gateways, e.g. DeepSeek) write all-zero usage on
|
|
230
|
+
// the early placeholder lines (empty thinking block) and the real usage
|
|
231
|
+
// only on the final line carrying stop_reason. First-occurrence-wins dedup
|
|
232
|
+
// would pin the zero record and discard the real one (regression
|
|
233
|
+
// 2026-08-19: auto-resume card per-run stats all 0). Per-field max
|
|
234
|
+
// reconstructs the full usage regardless of line order — on the official
|
|
235
|
+
// API every line repeats identical usage, so max is a no-op there.
|
|
236
|
+
const usageByMessageId = new Map();
|
|
228
237
|
let lastPostTokens = 0;
|
|
229
238
|
let tailOffset = -1;
|
|
230
239
|
let lastAiTitle;
|
|
@@ -244,13 +253,13 @@ function scalarScan(filePath) {
|
|
|
244
253
|
const usage = msg?.usage;
|
|
245
254
|
if (usage) {
|
|
246
255
|
const msgId = msg?.id;
|
|
247
|
-
if (msgId
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
input: usage.input_tokens ?? 0,
|
|
251
|
-
output: usage.output_tokens ?? 0,
|
|
252
|
-
cacheRead: usage.cache_read_input_tokens ?? 0,
|
|
253
|
-
cacheCreation: usage.cache_creation_input_tokens ?? 0,
|
|
256
|
+
if (msgId) {
|
|
257
|
+
const prev = usageByMessageId.get(msgId);
|
|
258
|
+
usageByMessageId.set(msgId, {
|
|
259
|
+
input: Math.max(prev?.input ?? 0, usage.input_tokens ?? 0),
|
|
260
|
+
output: Math.max(prev?.output ?? 0, usage.output_tokens ?? 0),
|
|
261
|
+
cacheRead: Math.max(prev?.cacheRead ?? 0, usage.cache_read_input_tokens ?? 0),
|
|
262
|
+
cacheCreation: Math.max(prev?.cacheCreation ?? 0, usage.cache_creation_input_tokens ?? 0),
|
|
254
263
|
});
|
|
255
264
|
}
|
|
256
265
|
}
|
|
@@ -262,7 +271,7 @@ function scalarScan(filePath) {
|
|
|
262
271
|
lastPostTokens = cm.postTokens;
|
|
263
272
|
}
|
|
264
273
|
}
|
|
265
|
-
// --- last user message offset
|
|
274
|
+
// --- last user message offset ---
|
|
266
275
|
// Record the byte offset where the tail should start: the beginning of
|
|
267
276
|
// the NEXT line after this user message. We compute it as this line's
|
|
268
277
|
// start offset + its byte length + 1 (the trailing '\n').
|
|
@@ -305,6 +314,12 @@ function scalarScan(filePath) {
|
|
|
305
314
|
}
|
|
306
315
|
}
|
|
307
316
|
});
|
|
317
|
+
// Feed one best record per message id, in first-appearance order (Map
|
|
318
|
+
// preserves insertion order), so acc.last is the LAST message's full usage
|
|
319
|
+
// and totals sum each API response exactly once.
|
|
320
|
+
for (const record of usageByMessageId.values()) {
|
|
321
|
+
acc.add(record);
|
|
322
|
+
}
|
|
308
323
|
// Build usage result (same logic as old aggregateSessionUsage)
|
|
309
324
|
const t = acc.totals;
|
|
310
325
|
const l = acc.last;
|
|
@@ -319,14 +334,19 @@ function scalarScan(filePath) {
|
|
|
319
334
|
if (contextLength === 0 || lastWindow > contextLength) {
|
|
320
335
|
contextLength = lastWindow;
|
|
321
336
|
}
|
|
337
|
+
// 非累计字段 = 末轮(本 run)scope,累计字段 = session 总和(所有 run)。
|
|
338
|
+
// 对齐 codex reader 语义(§9.21:`last_token_usage`=单 turn 增量、
|
|
339
|
+
// `total_token_usage`=session 累计)——否则 jsonl 兜底路径会把 session 累计
|
|
340
|
+
// 当成"本 run"显示,与卡片"本 run ≤ 累计"不变量冲突(累计反而更小)。
|
|
341
|
+
const lastTotal = l ? l.input + l.output + l.cacheRead + l.cacheCreation : 0;
|
|
322
342
|
const usage = {
|
|
323
|
-
inputTokens:
|
|
324
|
-
outputTokens:
|
|
343
|
+
inputTokens: l ? l.input : 0,
|
|
344
|
+
outputTokens: l ? l.output : 0,
|
|
325
345
|
contextLength,
|
|
326
346
|
compactCount: acc.compactCount,
|
|
327
|
-
cacheReadTokens:
|
|
328
|
-
cacheCreationTokens:
|
|
329
|
-
totalTokens:
|
|
347
|
+
cacheReadTokens: l && l.cacheRead > 0 ? l.cacheRead : undefined,
|
|
348
|
+
cacheCreationTokens: l && l.cacheCreation > 0 ? l.cacheCreation : undefined,
|
|
349
|
+
totalTokens: lastTotal,
|
|
330
350
|
cumulativeTotalTokens: t.input + t.output + t.cacheRead + t.cacheCreation,
|
|
331
351
|
cumulativeInputTokens: t.input,
|
|
332
352
|
cumulativeOutputTokens: t.output,
|
|
@@ -382,12 +402,7 @@ function extractEventsFromTail(tailLines, maxEvents) {
|
|
|
382
402
|
events.push({ type: role, content: `(${role} event)`, timestamp });
|
|
383
403
|
}
|
|
384
404
|
}
|
|
385
|
-
|
|
386
|
-
if (maxEvents <= 0)
|
|
387
|
-
return [];
|
|
388
|
-
return events.slice(-maxEvents);
|
|
389
|
-
}
|
|
390
|
-
return events;
|
|
405
|
+
return capEvents(events, maxEvents);
|
|
391
406
|
}
|
|
392
407
|
export function readSessionContent(sessionId, cwd, opts = {}) {
|
|
393
408
|
const { maxEvents } = opts;
|
|
@@ -440,18 +455,18 @@ export function readSessionContent(sessionId, cwd, opts = {}) {
|
|
|
440
455
|
// ~3×). Total parse count adds the index-miss fallback guard's fixed
|
|
441
456
|
// early-stop overhead (~2 parses, independent of line count).
|
|
442
457
|
const scan = scalarScan(filePath);
|
|
443
|
-
|
|
458
|
+
// 有 usage 即返回:非累计字段已是末轮 scope,命中判定用 session 累计兜底
|
|
459
|
+
// (末轮可能 input/output 为 0 而仍有 cacheRead,累计口径不会被末轮遮挡)。
|
|
460
|
+
const usage = (scan.usage.cumulativeTotalTokens ?? 0) > 0 ? scan.usage : undefined;
|
|
444
461
|
// Extract events AFTER the last user message by re-reading + re-parsing
|
|
445
462
|
// only the tail. If no user message was found (tailOffset === -1), fall
|
|
446
463
|
// back to re-reading the whole file so the card still has something to
|
|
447
464
|
// show.
|
|
448
465
|
const tailLines = readJsonlLinesFromOffset(filePath, scan.tailOffset >= 0 ? scan.tailOffset : 0);
|
|
449
466
|
const events = extractEventsFromTail(tailLines, maxEvents);
|
|
450
|
-
// Use aiTitle if available, otherwise fallback to last user message
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
? truncate(scan.lastUserMessage, 200, { normalizeWhitespace: true })
|
|
454
|
-
: undefined);
|
|
467
|
+
// Use aiTitle if available, otherwise fallback to last user message.
|
|
468
|
+
// Truncation is deferred to the consumer (router card building).
|
|
469
|
+
const displayTitle = scan.aiTitle ?? scan.lastUserMessage ?? undefined;
|
|
455
470
|
return {
|
|
456
471
|
events,
|
|
457
472
|
usage,
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
* ```
|
|
12
12
|
*
|
|
13
13
|
* Note: This handles the **rollout file format** (historical logging), NOT the
|
|
14
|
-
* `codex exec --json` stdout format
|
|
15
|
-
* (see design doc appendix B vs C).
|
|
14
|
+
* `codex exec --json` stdout format(已随 exec 模式移除)。
|
|
16
15
|
*/
|
|
17
16
|
import type { AgentSessionContentEvent, SessionContent, AgentSessionUsage } from '../../runner/index.js';
|
|
18
17
|
interface CodexRolloutEntry {
|
|
@@ -83,6 +82,7 @@ export declare function readCodexSessionContent(sessionId: string, opts?: {
|
|
|
83
82
|
export declare function isCodexSessionActive(sessionId: string, opts?: {
|
|
84
83
|
codexHome?: string;
|
|
85
84
|
activeThresholdMs?: number;
|
|
85
|
+
cwd?: string;
|
|
86
86
|
}): boolean;
|
|
87
87
|
/** Clear the session index cache. Exposed for tests. */
|
|
88
88
|
export declare function clearSessionIndexCache(): void;
|