lark-remote 0.1.6 → 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 +23 -1
- package/README.en.md +9 -1
- package/README.md +14 -2
- package/dist/bridge/approval-coordinator.d.ts +57 -34
- package/dist/bridge/approval-coordinator.js +191 -40
- package/dist/bridge/inbound-media.d.ts +62 -0
- package/dist/bridge/inbound-media.js +282 -0
- package/dist/bridge/index.d.ts +78 -7
- package/dist/bridge/index.js +202 -79
- package/dist/bridge/queue-manager.d.ts +2 -1
- package/dist/bridge/queue-manager.js +1 -0
- package/dist/card/approval-render.js +152 -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 +1 -12
- package/dist/card/card-shared.js +1 -26
- 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 +99 -232
- 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 +88 -23
- package/dist/config/index.js +105 -34
- package/dist/connector/index.d.ts +69 -2
- package/dist/connector/index.js +107 -1
- package/dist/index.js +123 -105
- 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.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/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 +11 -2
- package/dist/router/index.d.ts +56 -21
- package/dist/router/index.js +373 -548
- package/dist/router/utils.d.ts +2 -0
- package/dist/router/utils.js +4 -0
- 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 +31 -39
- package/dist/runner/codex/app-server/protocol-types.js +1 -12
- package/dist/runner/codex/app-server/runner.d.ts +42 -59
- package/dist/runner/codex/app-server/runner.js +160 -337
- package/dist/runner/codex/app-server/translator.d.ts +1 -21
- package/dist/runner/codex/app-server/translator.js +0 -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 +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/{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/index.d.ts +4 -4
- 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 +43 -13
- 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 +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/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/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
|
@@ -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,7 +25,7 @@ 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';
|
|
29
29
|
threadId: string;
|
|
30
30
|
turnId: string;
|
|
31
31
|
itemId: string;
|
|
@@ -51,13 +51,49 @@ export interface ApprovalExpiredEvent {
|
|
|
51
51
|
requestId: number | string;
|
|
52
52
|
timestamp?: string;
|
|
53
53
|
}
|
|
54
|
+
/** 审批决策(bridge ApprovalCoordinator → runner.respondApproval 的响应载荷)。 */
|
|
55
|
+
export type ApprovalAction = {
|
|
56
|
+
action: 'accept';
|
|
57
|
+
} | {
|
|
58
|
+
action: 'accept_for_session';
|
|
59
|
+
} | {
|
|
60
|
+
action: 'accept_with_execpolicy_amendment';
|
|
61
|
+
}
|
|
62
|
+
/** Claude:允许当前请求 + 本会话后续所有权限请求自动放行(允许所有)。 */
|
|
63
|
+
| {
|
|
64
|
+
action: 'accept_all';
|
|
65
|
+
} | {
|
|
66
|
+
action: 'decline';
|
|
67
|
+
} | {
|
|
68
|
+
action: 'cancel';
|
|
69
|
+
}
|
|
70
|
+
/** Claude AskUserQuestion 答案(question → label 或 label[])。 */
|
|
71
|
+
| {
|
|
72
|
+
action: 'answer';
|
|
73
|
+
answers: Record<string, string | string[]>;
|
|
74
|
+
};
|
|
75
|
+
/** Claude Code AskUserQuestion 的单个选项(control_request input.questions[].options[])。 */
|
|
76
|
+
export interface ClaudeUserQuestionOption {
|
|
77
|
+
label: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
}
|
|
80
|
+
/** Claude Code AskUserQuestion 的单个问题(control_request input.questions[])。 */
|
|
81
|
+
export interface ClaudeUserQuestion {
|
|
82
|
+
question: string;
|
|
83
|
+
header?: string;
|
|
84
|
+
multiSelect?: boolean;
|
|
85
|
+
options: ClaudeUserQuestionOption[];
|
|
86
|
+
/**
|
|
87
|
+
* 当前已选选项 label(卡片渲染与多选切换用;单选在协调器内即时提交)。
|
|
88
|
+
* 与 permissions.items.selected 同模式:协调器原地更新后以
|
|
89
|
+
* approval_view_updated 重新渲染。
|
|
90
|
+
*/
|
|
91
|
+
selected?: string[];
|
|
92
|
+
}
|
|
54
93
|
export interface ApprovalView {
|
|
55
94
|
requestId: number | string;
|
|
56
|
-
kind: 'command' | 'file' | 'permissions';
|
|
95
|
+
kind: 'command' | 'file' | 'permissions' | 'question';
|
|
57
96
|
reason?: string;
|
|
58
|
-
threadShort: string;
|
|
59
|
-
turnShort: string;
|
|
60
|
-
workspace: string;
|
|
61
97
|
command?: string;
|
|
62
98
|
commandCwd?: string;
|
|
63
99
|
fileChanges?: Array<{
|
|
@@ -65,14 +101,7 @@ export interface ApprovalView {
|
|
|
65
101
|
kind: 'add' | 'update' | 'delete';
|
|
66
102
|
diff?: string;
|
|
67
103
|
}>;
|
|
68
|
-
network?: {
|
|
69
|
-
host: string;
|
|
70
|
-
protocol: string;
|
|
71
|
-
};
|
|
72
104
|
permissions?: {
|
|
73
|
-
networkEnabled?: boolean;
|
|
74
|
-
fileSystemRead?: string[];
|
|
75
|
-
fileSystemWrite?: string[];
|
|
76
105
|
items: Array<{
|
|
77
106
|
id: string;
|
|
78
107
|
label: string;
|
|
@@ -85,10 +114,11 @@ export interface ApprovalView {
|
|
|
85
114
|
selected: boolean;
|
|
86
115
|
}>;
|
|
87
116
|
};
|
|
117
|
+
/** Claude AskUserQuestion 问题列表(kind === 'question' 时存在)。 */
|
|
118
|
+
questions?: ClaudeUserQuestion[];
|
|
88
119
|
availableDecisions: string[];
|
|
89
120
|
/** Raw payloads for structured decisions (e.g. acceptWithExecpolicyAmendment). */
|
|
90
121
|
decisionPayloads?: Record<string, unknown>;
|
|
91
|
-
pendingTotal: number;
|
|
92
122
|
}
|
|
93
123
|
interface ThinkingContent {
|
|
94
124
|
type: 'thinking';
|
|
@@ -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.
|
|
@@ -262,7 +262,7 @@ function scalarScan(filePath) {
|
|
|
262
262
|
lastPostTokens = cm.postTokens;
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
-
// --- last user message offset
|
|
265
|
+
// --- last user message offset ---
|
|
266
266
|
// Record the byte offset where the tail should start: the beginning of
|
|
267
267
|
// the NEXT line after this user message. We compute it as this line's
|
|
268
268
|
// start offset + its byte length + 1 (the trailing '\n').
|
|
@@ -382,12 +382,7 @@ function extractEventsFromTail(tailLines, maxEvents) {
|
|
|
382
382
|
events.push({ type: role, content: `(${role} event)`, timestamp });
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
|
-
|
|
386
|
-
if (maxEvents <= 0)
|
|
387
|
-
return [];
|
|
388
|
-
return events.slice(-maxEvents);
|
|
389
|
-
}
|
|
390
|
-
return events;
|
|
385
|
+
return capEvents(events, maxEvents);
|
|
391
386
|
}
|
|
392
387
|
export function readSessionContent(sessionId, cwd, opts = {}) {
|
|
393
388
|
const { maxEvents } = opts;
|
|
@@ -447,11 +442,9 @@ export function readSessionContent(sessionId, cwd, opts = {}) {
|
|
|
447
442
|
// show.
|
|
448
443
|
const tailLines = readJsonlLinesFromOffset(filePath, scan.tailOffset >= 0 ? scan.tailOffset : 0);
|
|
449
444
|
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);
|
|
445
|
+
// Use aiTitle if available, otherwise fallback to last user message.
|
|
446
|
+
// Truncation is deferred to the consumer (router card building).
|
|
447
|
+
const displayTitle = scan.aiTitle ?? scan.lastUserMessage ?? undefined;
|
|
455
448
|
return {
|
|
456
449
|
events,
|
|
457
450
|
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;
|
|
@@ -11,12 +11,13 @@
|
|
|
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 fs from 'node:fs';
|
|
18
17
|
import path from 'node:path';
|
|
19
18
|
import { readJsonlLines, findJsonlLine } from '../common/jsonl.js';
|
|
19
|
+
import { STALE_MS } from '../common/constants.js';
|
|
20
|
+
import { paginate, capEvents } from '../common/pagination.js';
|
|
20
21
|
import { getLogger } from '../../logger/index.js';
|
|
21
22
|
import { isRecord, stringValue } from '../../common/guards.js';
|
|
22
23
|
import { resolveCodexHome } from '../../config/codex-config.js';
|
|
@@ -243,8 +244,6 @@ export function readCodexRollout(filePath) {
|
|
|
243
244
|
*/
|
|
244
245
|
export function listCodexRollouts(opts = {}) {
|
|
245
246
|
const codexHome = resolveCodexHome(opts.codexHome);
|
|
246
|
-
const limit = opts.limit ?? 20;
|
|
247
|
-
const offset = Math.max(0, opts.offset ?? 0);
|
|
248
247
|
const filterCwd = opts.cwd;
|
|
249
248
|
// Full index: every rollout file's session_meta + mtime, no early break.
|
|
250
249
|
const index = getSessionIndex(codexHome);
|
|
@@ -263,8 +262,7 @@ export function listCodexRollouts(opts = {}) {
|
|
|
263
262
|
// Same-mtime ties use filePath as a deterministic secondary key so index
|
|
264
263
|
// rebuilds / walk order changes never reorder the page.
|
|
265
264
|
matched.sort((a, b) => b.mtimeMs - a.mtimeMs || a.filePath.localeCompare(b.filePath));
|
|
266
|
-
const total = matched.
|
|
267
|
-
const page = matched.slice(offset, offset + limit);
|
|
265
|
+
const { items: page, total } = paginate(matched, { limit: opts.limit, offset: opts.offset });
|
|
268
266
|
// Full-parse only the page being returned (summary/usage).
|
|
269
267
|
const entries = [];
|
|
270
268
|
for (const item of page) {
|
|
@@ -317,22 +315,14 @@ export function readCodexSessionContent(sessionId, opts = {}) {
|
|
|
317
315
|
}
|
|
318
316
|
// Apply maxEvents cap: keep the LAST N events (most recent).
|
|
319
317
|
// See function docstring for rationale.
|
|
320
|
-
|
|
321
|
-
// full-array trap (no caller passes 0 today, but the contract must hold).
|
|
322
|
-
const events = opts.maxEvents !== undefined && opts.maxEvents > 0 && rollout.events.length > opts.maxEvents
|
|
323
|
-
? rollout.events.slice(-opts.maxEvents)
|
|
324
|
-
: opts.maxEvents !== undefined && opts.maxEvents <= 0
|
|
325
|
-
? []
|
|
326
|
-
: rollout.events;
|
|
318
|
+
const events = capEvents(rollout.events, opts.maxEvents);
|
|
327
319
|
return {
|
|
328
320
|
events,
|
|
329
321
|
// displayTitle = LAST real user message (matches the
|
|
330
322
|
// "最近输入" label). recap is undefined: codex has no
|
|
331
323
|
// compact-summary concept, so never fake one from a user
|
|
332
324
|
// message (was: firstUserMessage = injected project rules).
|
|
333
|
-
displayTitle: rollout.lastRealUserMessage
|
|
334
|
-
? rollout.lastRealUserMessage.slice(0, 50)
|
|
335
|
-
: undefined,
|
|
325
|
+
displayTitle: rollout.lastRealUserMessage || undefined,
|
|
336
326
|
recap: undefined,
|
|
337
327
|
usage: rollout.usage,
|
|
338
328
|
};
|
|
@@ -347,7 +337,9 @@ export function readCodexSessionContent(sessionId, opts = {}) {
|
|
|
347
337
|
*/
|
|
348
338
|
export function isCodexSessionActive(sessionId, opts = {}) {
|
|
349
339
|
const codexHome = resolveCodexHome(opts.codexHome);
|
|
350
|
-
|
|
340
|
+
// Unify with the other readers' 1-hour stale window (claude/pi/opencode/kimi
|
|
341
|
+
// all use STALE_MS). Previously codex used a divergent 10-minute default.
|
|
342
|
+
const threshold = opts.activeThresholdMs ?? STALE_MS;
|
|
351
343
|
// P2-4: Use session index for direct file lookup + mtime check
|
|
352
344
|
let index = getSessionIndex(codexHome);
|
|
353
345
|
let entry = index.get(sessionId);
|
|
@@ -366,6 +358,11 @@ export function isCodexSessionActive(sessionId, opts = {}) {
|
|
|
366
358
|
if (entry.isSubagent) {
|
|
367
359
|
return false;
|
|
368
360
|
}
|
|
361
|
+
// Cwd guard: when a cwd is provided, the session's working directory must
|
|
362
|
+
// match (align with claude/pi/opencode which validate cwd).
|
|
363
|
+
if (opts.cwd && entry.cwd !== opts.cwd) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
369
366
|
// Re-stat to get fresh mtime (index may be up to INDEX_TTL_MS stale)
|
|
370
367
|
try {
|
|
371
368
|
const stat = fs.statSync(entry.filePath);
|
|
@@ -16,6 +16,6 @@ export declare class CodexSessionReader implements AgentSessionReader {
|
|
|
16
16
|
readSessionContent(sessionId: string, cwd: string, opts?: {
|
|
17
17
|
maxEvents?: number;
|
|
18
18
|
}): SessionContent;
|
|
19
|
-
isSessionActive(sessionId: string,
|
|
19
|
+
isSessionActive(sessionId: string, cwd: string): boolean;
|
|
20
20
|
}
|
|
21
21
|
export {};
|
|
@@ -34,8 +34,8 @@ export class CodexSessionReader {
|
|
|
34
34
|
cwd,
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
-
isSessionActive(sessionId,
|
|
38
|
-
return isCodexSessionActive(sessionId, { codexHome: this.codexHome });
|
|
37
|
+
isSessionActive(sessionId, cwd) {
|
|
38
|
+
return isCodexSessionActive(sessionId, { codexHome: this.codexHome, cwd });
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
//# sourceMappingURL=sessions.js.map
|
|
@@ -10,6 +10,13 @@ interface ContentBlock {
|
|
|
10
10
|
type: 'text' | 'thinking' | 'tool_use' | 'tool_result';
|
|
11
11
|
content: string;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Truncate a serialized tool-input string to 200 chars, collapsing newlines.
|
|
15
|
+
* Shared by content-block extraction and standalone wire-event readers (kimi
|
|
16
|
+
* tool.call) so the resume card never exceeds its 28KB budget on pathological
|
|
17
|
+
* args (e.g. whole-file writes / long prompts).
|
|
18
|
+
*/
|
|
19
|
+
export declare function truncateToolInput(inputStr: string): string;
|
|
13
20
|
/** Maps agent-specific field names to the generic extraction logic. */
|
|
14
21
|
export interface ContentBlockMapping {
|
|
15
22
|
/** The `type` value that identifies a tool-use block (e.g. 'tool_use' or 'toolCall'). */
|
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
* tool_result blocks. The {@link ContentBlockMapping} type captures those
|
|
6
6
|
* differences so a single implementation can serve all readers.
|
|
7
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* Truncate a serialized tool-input string to 200 chars, collapsing newlines.
|
|
10
|
+
* Shared by content-block extraction and standalone wire-event readers (kimi
|
|
11
|
+
* tool.call) so the resume card never exceeds its 28KB budget on pathological
|
|
12
|
+
* args (e.g. whole-file writes / long prompts).
|
|
13
|
+
*/
|
|
14
|
+
export function truncateToolInput(inputStr) {
|
|
15
|
+
if (inputStr.length <= 200)
|
|
16
|
+
return inputStr;
|
|
17
|
+
return inputStr.replace(/\n/g, ' ').slice(0, 197) + '...';
|
|
18
|
+
}
|
|
8
19
|
/**
|
|
9
20
|
* Extract content blocks from a message content array.
|
|
10
21
|
*
|
|
@@ -34,16 +45,9 @@ export function extractContentBlocks(content, mapping) {
|
|
|
34
45
|
// tool_use block (parameterized type name + input field)
|
|
35
46
|
if (p.type === mapping.toolUseType && typeof p.name === 'string') {
|
|
36
47
|
const rawInput = p[mapping.toolInputField] ?? {};
|
|
37
|
-
const inputStr = JSON.stringify(rawInput, null, 2);
|
|
48
|
+
const inputStr = truncateToolInput(JSON.stringify(rawInput, null, 2));
|
|
38
49
|
const label = `🔧 ${p.name}`;
|
|
39
|
-
|
|
40
|
-
if (inputStr.length > 200) {
|
|
41
|
-
body = inputStr.replace(/\n/g, ' ').slice(0, 197) + '...';
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
body = inputStr;
|
|
45
|
-
}
|
|
46
|
-
blocks.push({ type: 'tool_use', content: `${label}: ${body}` });
|
|
50
|
+
blocks.push({ type: 'tool_use', content: `${label}: ${inputStr}` });
|
|
47
51
|
}
|
|
48
52
|
// tool_result block (parameterized type name + error field)
|
|
49
53
|
if (p.type === mapping.toolResultType) {
|
|
@@ -18,14 +18,7 @@ export declare function readLastJsonlLine(filePath: string): string | null;
|
|
|
18
18
|
* Read the last N non-empty lines from a JSONL file using streaming reads.
|
|
19
19
|
*
|
|
20
20
|
* Unlike `readJsonlLines` (which materializes the entire file into a `string[]`),
|
|
21
|
-
* this only retains the last `n` lines — memory is O(n), not O(whole file).
|
|
22
|
-
* file is still read front-to-back in chunks (no reverse seek), but earlier
|
|
23
|
-
* lines are discarded as soon as the buffer exceeds `n`, so a multi-MB file
|
|
24
|
-
* costs only ~`n` line strings of resident memory.
|
|
25
|
-
*
|
|
26
|
-
* Used by tail-only read paths (P2-5) such as `isSessionActive`, which only
|
|
27
|
-
* need to inspect the file's tail (e.g. the last ~20 loop events) but were
|
|
28
|
-
* previously full-slurping the whole wire log.
|
|
21
|
+
* this only retains the last `n` lines — memory is O(n), not O(whole file).
|
|
29
22
|
*
|
|
30
23
|
* @param filePath Absolute path to a `.jsonl` file.
|
|
31
24
|
* @param n Maximum number of trailing non-empty lines to retain.
|
|
@@ -37,32 +30,23 @@ export declare function readLastNJsonlLines(filePath: string, n: number): string
|
|
|
37
30
|
* Stream-scan a JSONL file once, invoking `onLine` for each non-empty line
|
|
38
31
|
* with the line's raw string and its **starting byte offset** within the file.
|
|
39
32
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* only the tail from that offset via `readJsonlLinesFromOffset` (P2-5
|
|
44
|
-
* byte-offset two-pass: full-file scalar scan without materializing a
|
|
45
|
-
* `string[]`, then tail-only re-parse for events).
|
|
33
|
+
* Memory is O(chunk), not O(whole file). The callback receives the byte offset
|
|
34
|
+
* so callers can record where a line of interest begins, then re-read only the
|
|
35
|
+
* tail from that offset via `readJsonlLinesFromOffset`.
|
|
46
36
|
*
|
|
47
37
|
* @param filePath Absolute path to a `.jsonl` file.
|
|
48
|
-
* @param onLine Called for each non-empty line with `(line, offset)
|
|
49
|
-
* `offset` is the byte offset of the line's first character.
|
|
38
|
+
* @param onLine Called for each non-empty line with `(line, offset)`.
|
|
50
39
|
* @returns `true` if the file was opened and scanned, `false` on open error.
|
|
51
40
|
*/
|
|
52
41
|
export declare function scanJsonlLines(filePath: string, onLine: (line: string, offset: number) => void): boolean;
|
|
53
42
|
/**
|
|
54
43
|
* Read all non-empty lines starting from a byte `offset` in a JSONL file.
|
|
55
44
|
*
|
|
56
|
-
* Companion to `scanJsonlLines` for the
|
|
57
|
-
* pass 1 records the offset where the tail begins (e.g. the byte right after
|
|
58
|
-
* the last user message); pass 2 seeks there and reads/parses only the tail,
|
|
59
|
-
* so raw line-string memory is O(tail) instead of O(whole file).
|
|
45
|
+
* Companion to `scanJsonlLines` for the byte-offset two-pass pattern.
|
|
60
46
|
*
|
|
61
47
|
* @param filePath Absolute path to a `.jsonl` file.
|
|
62
48
|
* @param offset Byte offset to seek to before reading. **Must fall on a line
|
|
63
|
-
* boundary
|
|
64
|
-
* user message as recorded by `scanJsonlLines`); a mid-line
|
|
65
|
-
* offset will include a leading partial line.
|
|
49
|
+
* boundary**; a mid-line offset will include a leading partial line.
|
|
66
50
|
* @returns Array of raw line strings from `offset` to EOF (empty lines
|
|
67
51
|
* excluded). Empty array on open/seek error or `offset` past EOF.
|
|
68
52
|
*/
|
|
@@ -71,7 +55,6 @@ export declare function readJsonlLinesFromOffset(filePath: string, offset: numbe
|
|
|
71
55
|
* Read all non-empty lines from a JSONL file using streaming reads.
|
|
72
56
|
*
|
|
73
57
|
* @param filePath Absolute path to a `.jsonl` file.
|
|
74
|
-
* @param chunkSize Buffer size for each `fs.readSync` call (default 65536).
|
|
75
58
|
* @returns Array of raw line strings (empty lines excluded).
|
|
76
59
|
*/
|
|
77
|
-
export declare function readJsonlLines(filePath: string
|
|
60
|
+
export declare function readJsonlLines(filePath: string): string[];
|