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.
Files changed (188) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/README.en.md +9 -1
  3. package/README.md +14 -2
  4. package/dist/bridge/approval-coordinator.d.ts +57 -34
  5. package/dist/bridge/approval-coordinator.js +191 -40
  6. package/dist/bridge/inbound-media.d.ts +62 -0
  7. package/dist/bridge/inbound-media.js +282 -0
  8. package/dist/bridge/index.d.ts +78 -7
  9. package/dist/bridge/index.js +202 -79
  10. package/dist/bridge/queue-manager.d.ts +2 -1
  11. package/dist/bridge/queue-manager.js +1 -0
  12. package/dist/card/approval-render.js +152 -36
  13. package/dist/card/bash-card-session.d.ts +2 -24
  14. package/dist/card/bash-card-session.js +6 -73
  15. package/dist/card/bash-renderer.js +2 -3
  16. package/dist/card/card-budget.js +29 -75
  17. package/dist/card/card-session.d.ts +48 -0
  18. package/dist/card/card-session.js +86 -0
  19. package/dist/card/card-shared.d.ts +1 -12
  20. package/dist/card/card-shared.js +1 -26
  21. package/dist/card/run-card-session.d.ts +2 -55
  22. package/dist/card/run-card-session.js +6 -104
  23. package/dist/card/run-renderer.js +99 -232
  24. package/dist/card/run-state.d.ts +13 -0
  25. package/dist/card/run-state.js +25 -16
  26. package/dist/card/text-truncate.d.ts +13 -12
  27. package/dist/card/text-truncate.js +13 -63
  28. package/dist/common/fs.d.ts +8 -0
  29. package/dist/common/fs.js +17 -0
  30. package/dist/common/guards.d.ts +0 -20
  31. package/dist/common/guards.js +0 -43
  32. package/dist/common/sleep.d.ts +2 -0
  33. package/dist/common/sleep.js +5 -0
  34. package/dist/common/truncate.d.ts +39 -0
  35. package/dist/common/truncate.js +92 -0
  36. package/dist/config/codex-config.d.ts +1 -1
  37. package/dist/config/codex-config.js +1 -1
  38. package/dist/config/index.d.ts +88 -23
  39. package/dist/config/index.js +105 -34
  40. package/dist/connector/index.d.ts +69 -2
  41. package/dist/connector/index.js +107 -1
  42. package/dist/index.js +123 -105
  43. package/dist/instance-lock.js +4 -12
  44. package/dist/order/alias-resolve.d.ts +13 -0
  45. package/dist/order/alias-resolve.js +22 -0
  46. package/dist/order/alias-store.d.ts +38 -0
  47. package/dist/order/alias-store.js +106 -0
  48. package/dist/persistence/atomic-write.d.ts +8 -2
  49. package/dist/persistence/atomic-write.js +23 -7
  50. package/dist/restart.js +2 -1
  51. package/dist/router/card-helpers.d.ts +63 -0
  52. package/dist/router/card-helpers.js +146 -0
  53. package/dist/router/config/claude.js +25 -1
  54. package/dist/router/config/codex.js +29 -50
  55. package/dist/router/config/common/model-patch.d.ts +22 -0
  56. package/dist/router/config/common/model-patch.js +26 -0
  57. package/dist/router/config/common/render.js +5 -4
  58. package/dist/router/config/index.d.ts +12 -0
  59. package/dist/router/config/index.js +25 -1
  60. package/dist/router/config/kimi.d.ts +4 -1
  61. package/dist/router/config/kimi.js +27 -0
  62. package/dist/router/config/opencode.js +18 -5
  63. package/dist/router/config/pi.js +4 -5
  64. package/dist/router/config/types.d.ts +11 -2
  65. package/dist/router/index.d.ts +56 -21
  66. package/dist/router/index.js +373 -548
  67. package/dist/router/utils.d.ts +2 -0
  68. package/dist/router/utils.js +4 -0
  69. package/dist/runner/agent-choices-common.d.ts +16 -0
  70. package/dist/runner/agent-choices-common.js +31 -0
  71. package/dist/runner/claude/runner.d.ts +47 -10
  72. package/dist/runner/claude/runner.js +117 -46
  73. package/dist/runner/claude/session.d.ts +166 -0
  74. package/dist/runner/claude/session.js +749 -0
  75. package/dist/runner/codex/app-server/protocol-types.d.ts +31 -39
  76. package/dist/runner/codex/app-server/protocol-types.js +1 -12
  77. package/dist/runner/codex/app-server/runner.d.ts +42 -59
  78. package/dist/runner/codex/app-server/runner.js +160 -337
  79. package/dist/runner/codex/app-server/translator.d.ts +1 -21
  80. package/dist/runner/codex/app-server/translator.js +0 -18
  81. package/dist/runner/codex/index.d.ts +0 -2
  82. package/dist/runner/codex/index.js +0 -2
  83. package/dist/runner/common/acp/protocol-helpers.d.ts +14 -0
  84. package/dist/runner/common/acp/protocol-helpers.js +21 -0
  85. package/dist/runner/common/acp/protocol-types.d.ts +238 -0
  86. package/dist/runner/common/acp/protocol-types.js +75 -0
  87. package/dist/runner/common/connection-based-runner.d.ts +111 -0
  88. package/dist/runner/common/connection-based-runner.js +261 -0
  89. package/dist/runner/{codex/app-server → common/jsonrpc}/client.d.ts +14 -7
  90. package/dist/runner/{codex/app-server → common/jsonrpc}/client.js +27 -18
  91. package/dist/runner/common/jsonrpc/connection-manager.d.ts +125 -0
  92. package/dist/runner/{codex/app-server → common/jsonrpc}/connection-manager.js +63 -28
  93. package/dist/runner/{codex/app-server → common/jsonrpc}/transport.d.ts +5 -4
  94. package/dist/runner/{codex/app-server → common/jsonrpc}/transport.js +18 -19
  95. package/dist/runner/common/jsonrpc/types.d.ts +32 -0
  96. package/dist/runner/common/jsonrpc/types.js +9 -0
  97. package/dist/runner/common/process-stopper.d.ts +2 -1
  98. package/dist/runner/common/process-stopper.js +1 -0
  99. package/dist/runner/common/runner-utils.d.ts +6 -13
  100. package/dist/runner/common/runner-utils.js +6 -47
  101. package/dist/runner/common/spawning-runner.d.ts +24 -70
  102. package/dist/runner/common/spawning-runner.js +98 -152
  103. package/dist/runner/index.d.ts +4 -4
  104. package/dist/runner/index.js +4 -4
  105. package/dist/runner/kimi/acp/runner.d.ts +106 -0
  106. package/dist/runner/kimi/acp/runner.js +448 -0
  107. package/dist/runner/kimi/acp/translator.d.ts +124 -0
  108. package/dist/runner/kimi/acp/translator.js +336 -0
  109. package/dist/runner/kimi/index.d.ts +1 -1
  110. package/dist/runner/kimi/index.js +1 -1
  111. package/dist/runner/opencode/acp/index.d.ts +1 -0
  112. package/dist/runner/opencode/acp/index.js +2 -0
  113. package/dist/runner/opencode/acp/runner.d.ts +121 -0
  114. package/dist/runner/opencode/acp/runner.js +429 -0
  115. package/dist/runner/opencode/acp/translator.d.ts +119 -0
  116. package/dist/runner/opencode/acp/translator.js +345 -0
  117. package/dist/runner/opencode/index.d.ts +1 -1
  118. package/dist/runner/opencode/index.js +1 -1
  119. package/dist/runner/pi/index.d.ts +1 -1
  120. package/dist/runner/pi/index.js +1 -1
  121. package/dist/runner/pi/rpc/client.d.ts +52 -0
  122. package/dist/runner/pi/rpc/client.js +114 -0
  123. package/dist/runner/pi/rpc/index.d.ts +4 -0
  124. package/dist/runner/pi/rpc/index.js +4 -0
  125. package/dist/runner/pi/rpc/protocol-types.d.ts +127 -0
  126. package/dist/runner/pi/rpc/protocol-types.js +21 -0
  127. package/dist/runner/pi/rpc/runner.d.ts +80 -0
  128. package/dist/runner/pi/rpc/runner.js +199 -0
  129. package/dist/runner/pi/rpc/translator.d.ts +55 -0
  130. package/dist/runner/pi/rpc/translator.js +258 -0
  131. package/dist/runner/registry.d.ts +7 -8
  132. package/dist/runner/registry.js +3 -4
  133. package/dist/runner/resolve-agent-choices.js +18 -59
  134. package/dist/runner/sync-agent-choices.js +16 -67
  135. package/dist/runner/types.d.ts +43 -13
  136. package/dist/session/claude/session-index.js +2 -3
  137. package/dist/session/claude/session-reader.js +3 -6
  138. package/dist/session/claude/sessions.js +6 -13
  139. package/dist/session/codex/rollout-reader.d.ts +2 -2
  140. package/dist/session/codex/rollout-reader.js +14 -17
  141. package/dist/session/codex/sessions.d.ts +1 -1
  142. package/dist/session/codex/sessions.js +2 -2
  143. package/dist/session/common/content-blocks.d.ts +7 -0
  144. package/dist/session/common/content-blocks.js +13 -9
  145. package/dist/session/common/jsonl.d.ts +8 -25
  146. package/dist/session/common/jsonl.js +126 -261
  147. package/dist/session/common/pagination.d.ts +28 -0
  148. package/dist/session/common/pagination.js +33 -0
  149. package/dist/session/kimi/sessions.d.ts +34 -1
  150. package/dist/session/kimi/sessions.js +208 -98
  151. package/dist/session/opencode/sessions.d.ts +17 -3
  152. package/dist/session/opencode/sessions.js +29 -29
  153. package/dist/session/pi/sessions.d.ts +5 -1
  154. package/dist/session/pi/sessions.js +12 -16
  155. package/dist/session/session-store.d.ts +11 -1
  156. package/dist/session/session-store.js +75 -178
  157. package/dist/update/index.d.ts +2 -2
  158. package/dist/update/index.js +2 -2
  159. package/dist/update/install.d.ts +20 -2
  160. package/dist/update/install.js +51 -7
  161. package/package.json +1 -1
  162. package/dist/runner/codex/app-server/connection-manager.d.ts +0 -56
  163. package/dist/runner/codex/argv.d.ts +0 -33
  164. package/dist/runner/codex/argv.js +0 -40
  165. package/dist/runner/codex/factory.d.ts +0 -29
  166. package/dist/runner/codex/factory.js +0 -39
  167. package/dist/runner/codex/jsonl.d.ts +0 -37
  168. package/dist/runner/codex/jsonl.js +0 -221
  169. package/dist/runner/codex/runner.d.ts +0 -66
  170. package/dist/runner/codex/runner.js +0 -129
  171. package/dist/runner/common/exec-translator.d.ts +0 -73
  172. package/dist/runner/common/exec-translator.js +0 -105
  173. package/dist/runner/kimi/jsonl.d.ts +0 -28
  174. package/dist/runner/kimi/jsonl.js +0 -143
  175. package/dist/runner/kimi/runner.d.ts +0 -49
  176. package/dist/runner/kimi/runner.js +0 -105
  177. package/dist/runner/opencode/argv.d.ts +0 -32
  178. package/dist/runner/opencode/argv.js +0 -35
  179. package/dist/runner/opencode/jsonl.d.ts +0 -68
  180. package/dist/runner/opencode/jsonl.js +0 -295
  181. package/dist/runner/opencode/runner.d.ts +0 -61
  182. package/dist/runner/opencode/runner.js +0 -93
  183. package/dist/runner/pi/jsonl.d.ts +0 -128
  184. package/dist/runner/pi/jsonl.js +0 -249
  185. package/dist/runner/pi/runner.d.ts +0 -36
  186. package/dist/runner/pi/runner.js +0 -76
  187. package/dist/session/common/catch-up.d.ts +0 -12
  188. package/dist/session/common/catch-up.js +0 -31
@@ -1,40 +0,0 @@
1
- /**
2
- * Builds `codex exec` command-line arguments.
3
- *
4
- * Key design decisions:
5
- * - `approval_policy="never"` eliminates the approval handshake (root cause ①).
6
- * - Prompt goes via stdin (`-` flag) to avoid argv escaping issues.
7
- * - `--skip-git-repo-check`: lark-remote's cwd may not be a git repo.
8
- * - User's `~/.codex/config.toml` and project rules are preserved
9
- * (no `--ignore-user-config` / `--ignore-rules`).
10
- */
11
- /**
12
- * Construct the argv array for `codex exec --json`.
13
- *
14
- * New session:
15
- * `codex exec --json --sandbox danger-full-access -c approval_policy="never" ... -`
16
- * Resume session:
17
- * `codex exec --sandbox danger-full-access ... resume --json <threadId> -`
18
- */
19
- export function buildCodexExecArgs(input) {
20
- const sandbox = 'danger-full-access';
21
- const globalFlags = [
22
- '--sandbox',
23
- sandbox,
24
- '-c',
25
- 'approval_policy="never"',
26
- '-c',
27
- 'shell_environment_policy.inherit="all"',
28
- '--skip-git-repo-check',
29
- '-C',
30
- input.cwd,
31
- ...(input.model ? ['-m', input.model] : []),
32
- ...(input.modelProvider ? ['-c', `model_provider="${input.modelProvider}"`] : []),
33
- ...(input.reasoningEffort ? ['-c', `model_reasoning_effort="${input.reasoningEffort}"`] : []),
34
- ];
35
- if (input.threadId) {
36
- return ['exec', ...globalFlags, 'resume', '--json', input.threadId, '-'];
37
- }
38
- return ['exec', '--json', ...globalFlags, '-'];
39
- }
40
- //# sourceMappingURL=argv.js.map
@@ -1,29 +0,0 @@
1
- /**
2
- * Codex runner factory: selects the concrete runner based on `serviceMode`.
3
- *
4
- * `exec` (default) → CodexExecRunner (spawn-per-message `codex exec`).
5
- * `app-server` → CodexAppServerRunner (persistent `codex app-server` JSON-RPC
6
- * connection with approval support and sandbox enforcement).
7
- */
8
- import type { AgentSessionReader } from '../types.js';
9
- import { CodexExecRunner } from './runner.js';
10
- import { CodexAppServerRunner } from './app-server/runner.js';
11
- import type { AskForApproval, SandboxMode } from './app-server/protocol-types.js';
12
- export interface CreateCodexRunnerOptions {
13
- model?: string;
14
- modelProvider?: string;
15
- reasoningEffort?: string;
16
- stopGraceMs?: number;
17
- pidDir: string;
18
- workspace: string;
19
- sessionReader: AgentSessionReader;
20
- serviceMode?: 'exec' | 'app-server';
21
- sandbox?: SandboxMode;
22
- approvalPolicy?: AskForApproval;
23
- appServerBinary?: string;
24
- appServerArgs?: string[];
25
- appServerRequestTimeoutMs?: number;
26
- appServerIdleTtlMs?: number;
27
- appServerTurnIdleTimeoutMinutes?: number;
28
- }
29
- export declare function createCodexRunner(opts: CreateCodexRunnerOptions): CodexExecRunner | CodexAppServerRunner;
@@ -1,39 +0,0 @@
1
- /**
2
- * Codex runner factory: selects the concrete runner based on `serviceMode`.
3
- *
4
- * `exec` (default) → CodexExecRunner (spawn-per-message `codex exec`).
5
- * `app-server` → CodexAppServerRunner (persistent `codex app-server` JSON-RPC
6
- * connection with approval support and sandbox enforcement).
7
- */
8
- import { CodexExecRunner } from './runner.js';
9
- import { CodexAppServerRunner } from './app-server/runner.js';
10
- export function createCodexRunner(opts) {
11
- if (opts.serviceMode === 'app-server') {
12
- return new CodexAppServerRunner({
13
- kind: 'codex',
14
- sessionReader: opts.sessionReader,
15
- binary: opts.appServerBinary ?? 'codex',
16
- appServerArgs: opts.appServerArgs,
17
- requestTimeoutMs: opts.appServerRequestTimeoutMs,
18
- idleTtlMs: opts.appServerIdleTtlMs,
19
- turnTimeoutMs: opts.appServerTurnIdleTimeoutMinutes != null
20
- ? opts.appServerTurnIdleTimeoutMinutes * 60_000
21
- : undefined,
22
- model: opts.model,
23
- modelProvider: opts.modelProvider,
24
- reasoningEffort: opts.reasoningEffort,
25
- sandbox: opts.sandbox,
26
- approvalPolicy: opts.approvalPolicy,
27
- });
28
- }
29
- return new CodexExecRunner({
30
- model: opts.model,
31
- modelProvider: opts.modelProvider,
32
- reasoningEffort: opts.reasoningEffort,
33
- stopGraceMs: opts.stopGraceMs,
34
- pidDir: opts.pidDir,
35
- workspace: opts.workspace,
36
- sessionReader: opts.sessionReader,
37
- });
38
- }
39
- //# sourceMappingURL=factory.js.map
@@ -1,37 +0,0 @@
1
- /**
2
- * Translates codex `exec --json` ndjson output into lark-remote `AgentEvent`s.
3
- *
4
- * Key design decisions:
5
- * - Fail-fast: unknown types and missing fields return [] (no event emitted),
6
- * never throw, never write back to codex (root cause ② tolerance).
7
- * - Stream ending before a terminal event records a terminal error via `finish()`
8
- * (root cause ③ fail-fast); the runner's `buildResultEvent` emits the result.
9
- * - Each `run()` must create a new translator instance (stateful: sessionId/terminal/startedTools).
10
- *
11
- * Terminal state (sessionId, lastUsage, terminalErrorMessage) is stored on
12
- * the instance and exposed via getters; `CodexExecRunner.run()` folds this
13
- * state into `SpawningRunner.buildResultEvent(...)` so result-event
14
- * semantics are uniform across all 5 agents.
15
- *
16
- * Two jsonl formats exist; this translator handles
17
- * the `codex exec --json` stdout format ONLY. The rollout file format is handled
18
- * separately by `codex-rollout-reader.ts`.
19
- */
20
- import type { AgentEvent, ResultEvent } from '../types.js';
21
- import { ExecTranslator } from '../common/exec-translator.js';
22
- type ResultUsage = NonNullable<ResultEvent['usage']>;
23
- export declare class CodexExecTranslator extends ExecTranslator {
24
- protected readonly logTag = "[codex-exec-translator]";
25
- protected streamEndedMessage(): string;
26
- /** Token usage captured from `turn.completed` (for the success result event). */
27
- getLastUsage: () => ResultUsage | undefined;
28
- protected translateEvent(raw: Record<string, unknown>): AgentEvent[] | null;
29
- private onThreadStarted;
30
- private onItemStarted;
31
- private onItemCompleted;
32
- private onAgentMessage;
33
- private onTurnCompleted;
34
- private onTerminalError;
35
- private onNonTerminalError;
36
- }
37
- export {};
@@ -1,221 +0,0 @@
1
- /**
2
- * Translates codex `exec --json` ndjson output into lark-remote `AgentEvent`s.
3
- *
4
- * Key design decisions:
5
- * - Fail-fast: unknown types and missing fields return [] (no event emitted),
6
- * never throw, never write back to codex (root cause ② tolerance).
7
- * - Stream ending before a terminal event records a terminal error via `finish()`
8
- * (root cause ③ fail-fast); the runner's `buildResultEvent` emits the result.
9
- * - Each `run()` must create a new translator instance (stateful: sessionId/terminal/startedTools).
10
- *
11
- * Terminal state (sessionId, lastUsage, terminalErrorMessage) is stored on
12
- * the instance and exposed via getters; `CodexExecRunner.run()` folds this
13
- * state into `SpawningRunner.buildResultEvent(...)` so result-event
14
- * semantics are uniform across all 5 agents.
15
- *
16
- * Two jsonl formats exist; this translator handles
17
- * the `codex exec --json` stdout format ONLY. The rollout file format is handled
18
- * separately by `codex-rollout-reader.ts`.
19
- */
20
- import { getLogger } from '../../logger/index.js';
21
- import { recordValue, stringValue, numberValue, extractErrorMessage } from '../../common/guards.js';
22
- import { ExecTranslator } from '../common/exec-translator.js';
23
- export class CodexExecTranslator extends ExecTranslator {
24
- logTag = '[codex-exec-translator]';
25
- streamEndedMessage() {
26
- return 'codex stream ended before a terminal event';
27
- }
28
- // --- translateEvent: codex-specific dispatch ---
29
- translateEvent(raw) {
30
- switch (raw.type) {
31
- case 'thread.started':
32
- return this.onThreadStarted(raw);
33
- case 'turn.started':
34
- return []; // internal marker, no lark-remote event
35
- case 'item.started':
36
- return this.onItemStarted(raw);
37
- case 'item.completed':
38
- return this.onItemCompleted(raw);
39
- case 'agent_message':
40
- return this.onAgentMessage(raw);
41
- case 'turn.completed':
42
- return this.onTurnCompleted(raw);
43
- case 'turn.failed':
44
- return this.onTerminalError(raw, 'codex turn failed');
45
- case 'error':
46
- return this.onNonTerminalError(raw);
47
- default:
48
- return this.recordUnknownEvent(raw.type);
49
- }
50
- }
51
- // --- Private handlers ---
52
- onThreadStarted(raw) {
53
- const threadId = stringValue(raw.thread_id);
54
- if (!threadId) {
55
- return [];
56
- }
57
- this.sessionId = threadId;
58
- return [
59
- {
60
- type: 'system',
61
- subtype: 'init',
62
- session_id: threadId,
63
- cwd: stringValue(raw.cwd) ?? '',
64
- model: stringValue(raw.model) ?? '',
65
- timestamp: new Date().toISOString(),
66
- },
67
- ];
68
- }
69
- onItemStarted(raw) {
70
- const item = recordValue(raw.item);
71
- if (!item || item.type !== 'command_execution')
72
- return [];
73
- const id = stringValue(item.id);
74
- if (!id) {
75
- return [];
76
- }
77
- this.startedTools.add(id);
78
- return [
79
- {
80
- type: 'assistant',
81
- message: {
82
- content: [
83
- {
84
- type: 'tool_use',
85
- id,
86
- name: 'command_execution',
87
- input: { command: stringValue(item.command) ?? '' },
88
- },
89
- ],
90
- },
91
- timestamp: new Date().toISOString(),
92
- },
93
- ];
94
- }
95
- onItemCompleted(raw) {
96
- const item = recordValue(raw.item);
97
- if (!item)
98
- return [];
99
- // agent_message → assistant text
100
- if (item.type === 'agent_message') {
101
- const text = stringValue(item.text ?? item.message);
102
- if (!text)
103
- return [];
104
- return [
105
- {
106
- type: 'assistant',
107
- message: {
108
- content: [{ type: 'text', text }],
109
- },
110
- timestamp: new Date().toISOString(),
111
- },
112
- ];
113
- }
114
- // reasoning → thinking content, so output.showThinking
115
- // applies to codex the same way it does for claude/pi/opencode.
116
- // Shape: {"type":"item.completed","item":{"id":"item_1","type":"reasoning","text":"..."}}
117
- if (item.type === 'reasoning') {
118
- const text = stringValue(item.text);
119
- if (!text)
120
- return [];
121
- return [
122
- {
123
- type: 'assistant',
124
- message: {
125
- content: [{ type: 'thinking', thinking: text }],
126
- },
127
- timestamp: new Date().toISOString(),
128
- },
129
- ];
130
- }
131
- // command_execution → tool result
132
- if (item.type === 'command_execution') {
133
- const id = stringValue(item.id);
134
- if (!id) {
135
- return [];
136
- }
137
- this.startedTools.delete(id);
138
- const exitCode = numberValue(item.exit_code);
139
- const output = stringValue(item.output ?? item.aggregated_output ?? item.stdout) ?? '';
140
- return [
141
- {
142
- type: 'user',
143
- message: {
144
- content: [
145
- {
146
- type: 'tool_result',
147
- tool_use_id: id,
148
- content: output,
149
- is_error: exitCode !== undefined && exitCode !== 0,
150
- },
151
- ],
152
- },
153
- timestamp: new Date().toISOString(),
154
- },
155
- ];
156
- }
157
- return [];
158
- }
159
- onAgentMessage(raw) {
160
- const message = stringValue(raw.message ?? raw.text);
161
- if (!message)
162
- return [];
163
- return [
164
- {
165
- type: 'assistant',
166
- message: {
167
- content: [{ type: 'text', text: message }],
168
- },
169
- timestamp: new Date().toISOString(),
170
- },
171
- ];
172
- }
173
- onTurnCompleted(raw) {
174
- // mark terminal and stash usage; the runner emits the result event
175
- // via buildResultEvent({...usage}) so success/error is uniform across agents.
176
- this.terminal = true;
177
- const usage = recordValue(raw.usage);
178
- if (usage) {
179
- // ccusage-aligned: for codex, cached_input_tokens is a subset of
180
- // input_tokens, so the non-cached (displayed) input = raw - cached.
181
- // Codex has no separate cache-write, so cache_creation is always 0.
182
- const rawInput = numberValue(usage.input_tokens ?? usage.inputTokens) ?? 0;
183
- const cached = numberValue(usage.cached_input_tokens ?? usage.cachedInputTokens) ?? 0;
184
- const total = numberValue(usage.total_tokens ?? usage.totalTokens);
185
- this.lastUsage = {
186
- input_tokens: rawInput - Math.min(cached, rawInput),
187
- output_tokens: numberValue(usage.output_tokens ?? usage.outputTokens) ?? 0,
188
- cache_read_tokens: cached,
189
- cache_creation_tokens: 0,
190
- ...(total !== undefined ? { total_tokens: total } : {}),
191
- };
192
- }
193
- return [];
194
- }
195
- onTerminalError(raw, fallback) {
196
- // mark terminal and stash the error message; the runner folds it
197
- // into buildResultEvent({translatorError}) so the result subtype is 'error'
198
- // with the agent-specific reason (e.g. codex turn.failed).
199
- this.terminal = true;
200
- this.terminalErrorMessage = extractErrorMessage(raw, fallback);
201
- this.terminalErrorFromAgent = true;
202
- return [];
203
- }
204
- onNonTerminalError(raw) {
205
- const message = extractErrorMessage(raw, 'codex error');
206
- this.lastError = message;
207
- getLogger().warn(`[codex-exec-translator] non-terminal error: ${message.slice(0, 500)}`);
208
- // 将非终止错误作为 assistant 文本输出,让用户在 Run 卡片上看到进度
209
- // (如 404/401 重连、provider 不匹配等错误),而非静默等待。
210
- return [
211
- {
212
- type: 'assistant',
213
- message: {
214
- content: [{ type: 'text', text: `⚠️ ${message}` }],
215
- },
216
- timestamp: new Date().toISOString(),
217
- },
218
- ];
219
- }
220
- }
221
- //# sourceMappingURL=jsonl.js.map
@@ -1,66 +0,0 @@
1
- /**
2
- * CodexExecRunner: spawn-per-message runner using `codex exec --json`.
3
- *
4
- * Architecture:
5
- * - Each `run()` spawns a fresh `codex exec` process, writes prompt to stdin,
6
- * reads ndjson from stdout, translates to AgentEvent via CodexExecTranslator.
7
- * - No singleton, no long-lived process, no JSON-RPC, no approval handshake.
8
- * - Structurally identical to ClaudeRunner (spawn-per-message + ProcessStopper + SpawnHeartbeat).
9
- *
10
- * The entire spawn + completion + cleanup orchestration is inherited
11
- * from SpawningRunner. This subclass overrides only the 5 hooks:
12
- * - getStdio() → ['pipe','pipe','pipe'] (writes prompt to stdin)
13
- * - setupStdin(proc, msg) → proc.stdin.end(msg, 'utf-8')
14
- * - handleBadStreamLine() → empty override (silently skip non-JSON lines)
15
- * - createTranslator(opts) → new CodexExecTranslator()
16
- * - validateBeforeRun(opts) → API key check (yields error result if missing)
17
- *
18
- * Key invariants:
19
- * 1. argv includes `approval_policy="never"` (root cause ①).
20
- * 2. stdin is written once via `stdin.end(prompt)` and never written again (root cause ②).
21
- * 3. Translator parse failures → return [] (no event), never throw, never write back (root cause ②).
22
- * 4. Stream ending early → finish() yields terminal event, never leaves consumer waiting (root cause ③).
23
- */
24
- import type { ChildProcess } from 'node:child_process';
25
- import type { AgentKind, AgentSessionReader, AgentEvent, AgentRunner, AgentStatusInfo } from '../types.js';
26
- import type { SpawnOptions } from '../types.js';
27
- import { SpawningRunner, type RunnerTranslator } from '../common/spawning-runner.js';
28
- interface CodexExecRunnerOptions {
29
- /** Model override. Omitted → codex reads from its config.toml. */
30
- model?: string;
31
- /** Model provider override. Omitted → codex reads from its config.toml. */
32
- modelProvider?: string;
33
- /** Reasoning effort level: low/medium/high/xhigh/max/ultra */
34
- reasoningEffort?: string;
35
- /** Grace period (ms) for SIGTERM→SIGKILL. Default: 5000. */
36
- stopGraceMs?: number;
37
- /** Directory for pid files. Default: `~/.lark-remote`. */
38
- pidDir?: string;
39
- /** Workspace identifier, scoped into the pid file name so concurrent
40
- * workspaces do not share one `<prefix>.pid` (P1-9). */
41
- workspace: string;
42
- /** Spawn heartbeat interval (ms). Default: 30_000. */
43
- spawnHeartbeatMs?: number;
44
- /** Injected session reader (file-based CodexSessionReader). */
45
- sessionReader: AgentSessionReader;
46
- }
47
- export declare class CodexExecRunner extends SpawningRunner implements AgentRunner {
48
- readonly kind: AgentKind;
49
- readonly sessionReader: AgentSessionReader;
50
- private readonly defaultModel?;
51
- private readonly modelProvider?;
52
- private readonly reasoningEffort?;
53
- constructor(opts: CodexExecRunnerOptions);
54
- getStatusInfo(): AgentStatusInfo;
55
- /** exec 模式的 turn.completed.usage 是会话累计值,flow 字段必须 jsonl 优先
56
- * (review P3-7:桥侧统一走本接口,替代 agentKind 硬编码)。 */
57
- getUsageAuthority(): 'jsonl';
58
- protected buildArgv(opts: SpawnOptions): string[];
59
- protected getStdio(): ('ignore' | 'pipe')[];
60
- protected setupStdin(proc: ChildProcess, message: string): void;
61
- /** Silently skip non-JSON lines from codex stdout (e.g. warnings). */
62
- protected handleBadStreamLine(_line: string): void;
63
- protected createTranslator(_opts: SpawnOptions): RunnerTranslator;
64
- protected validateBeforeRun(opts: SpawnOptions): AgentEvent | null;
65
- }
66
- export {};
@@ -1,129 +0,0 @@
1
- /**
2
- * CodexExecRunner: spawn-per-message runner using `codex exec --json`.
3
- *
4
- * Architecture:
5
- * - Each `run()` spawns a fresh `codex exec` process, writes prompt to stdin,
6
- * reads ndjson from stdout, translates to AgentEvent via CodexExecTranslator.
7
- * - No singleton, no long-lived process, no JSON-RPC, no approval handshake.
8
- * - Structurally identical to ClaudeRunner (spawn-per-message + ProcessStopper + SpawnHeartbeat).
9
- *
10
- * The entire spawn + completion + cleanup orchestration is inherited
11
- * from SpawningRunner. This subclass overrides only the 5 hooks:
12
- * - getStdio() → ['pipe','pipe','pipe'] (writes prompt to stdin)
13
- * - setupStdin(proc, msg) → proc.stdin.end(msg, 'utf-8')
14
- * - handleBadStreamLine() → empty override (silently skip non-JSON lines)
15
- * - createTranslator(opts) → new CodexExecTranslator()
16
- * - validateBeforeRun(opts) → API key check (yields error result if missing)
17
- *
18
- * Key invariants:
19
- * 1. argv includes `approval_policy="never"` (root cause ①).
20
- * 2. stdin is written once via `stdin.end(prompt)` and never written again (root cause ②).
21
- * 3. Translator parse failures → return [] (no event), never throw, never write back (root cause ②).
22
- * 4. Stream ending early → finish() yields terminal event, never leaves consumer waiting (root cause ③).
23
- */
24
- import { SpawningRunner } from '../common/spawning-runner.js';
25
- import { pipeAllStdio, endStdinWithPrompt } from '../common/runner-utils.js';
26
- import { buildCodexExecArgs } from './argv.js';
27
- import { CodexExecTranslator } from './jsonl.js';
28
- import { loadCodexConfig } from '../../config/codex-config.js';
29
- export class CodexExecRunner extends SpawningRunner {
30
- kind = 'codex';
31
- sessionReader;
32
- defaultModel;
33
- modelProvider;
34
- reasoningEffort;
35
- constructor(opts) {
36
- super({
37
- pidDir: opts.pidDir,
38
- workspace: opts.workspace,
39
- stopGraceMs: opts.stopGraceMs,
40
- spawnHeartbeatMs: opts.spawnHeartbeatMs,
41
- pidFilePrefix: 'codex',
42
- logTag: 'codex-exec-runner',
43
- });
44
- this.binary = 'codex';
45
- this.defaultModel = opts.model;
46
- this.modelProvider = opts.modelProvider;
47
- this.reasoningEffort = opts.reasoningEffort;
48
- this.sessionReader = opts.sessionReader;
49
- }
50
- getStatusInfo() {
51
- // If model not explicitly set, fallback to codex config.toml
52
- let model = this.defaultModel;
53
- let provider = this.modelProvider;
54
- if (!model || !provider) {
55
- try {
56
- const codexConfig = loadCodexConfig();
57
- if (!model) {
58
- model = codexConfig.currentModel;
59
- }
60
- if (!provider) {
61
- provider = codexConfig.currentProvider;
62
- }
63
- }
64
- catch {
65
- // Ignore errors reading codex config
66
- }
67
- }
68
- return {
69
- kind: 'codex',
70
- model: model ?? '(未配置)',
71
- provider: provider,
72
- extras: { sandbox: 'danger-full-access' },
73
- };
74
- }
75
- /** exec 模式的 turn.completed.usage 是会话累计值,flow 字段必须 jsonl 优先
76
- * (review P3-7:桥侧统一走本接口,替代 agentKind 硬编码)。 */
77
- getUsageAuthority() {
78
- return 'jsonl';
79
- }
80
- buildArgv(opts) {
81
- return buildCodexExecArgs({
82
- cwd: opts.cwd,
83
- model: opts.model ?? this.defaultModel,
84
- modelProvider: this.modelProvider,
85
- threadId: opts.sessionId,
86
- reasoningEffort: opts.reasoningEffort ?? this.reasoningEffort,
87
- });
88
- }
89
- // --- Hooks ---
90
- getStdio() {
91
- // ['pipe','pipe','pipe'] so we can write the prompt to stdin via setupStdin.
92
- return pipeAllStdio();
93
- }
94
- setupStdin(proc, message) {
95
- // Write prompt once and close (invariant: write once, never again).
96
- endStdinWithPrompt(proc, message);
97
- }
98
- /** Silently skip non-JSON lines from codex stdout (e.g. warnings). */
99
- handleBadStreamLine(_line) { }
100
- createTranslator(_opts) {
101
- // Fresh translator per run (stateful: threadId/terminal/startedTools).
102
- return new CodexExecTranslator();
103
- }
104
- validateBeforeRun(opts) {
105
- // Pre-spawn API key check: yield an error result and abort run() if the
106
- // configured provider requires an env var that is not set.
107
- const provider = this.modelProvider;
108
- if (!provider)
109
- return null;
110
- try {
111
- const codexConfig = loadCodexConfig();
112
- const envKey = codexConfig.providerEnvKeys[provider];
113
- if (envKey && !process.env[envKey]) {
114
- return {
115
- type: 'result',
116
- subtype: 'error',
117
- session_id: opts.sessionId ?? '',
118
- errorMessage: `Provider "${provider}" 需要环境变量 ${envKey},但该变量未设置。请在系统环境变量或 .env 文件中配置。`,
119
- timestamp: new Date().toISOString(),
120
- };
121
- }
122
- }
123
- catch {
124
- // Ignore config read errors — let codex handle the missing config.
125
- }
126
- return null;
127
- }
128
- }
129
- //# sourceMappingURL=runner.js.map
@@ -1,73 +0,0 @@
1
- /**
2
- * Abstract base class for exec-stream translators (codex, opencode, pi, kimi).
3
- *
4
- * Encapsulates the shared state machine and guard logic that was duplicated
5
- * across every concrete translator:
6
- * - Terminal-state tracking (idempotent `finish()`)
7
- * - `translate()` guard (terminal → []; non-record / non-string-type → anomaly)
8
- * - `recordUnknownEvent()` helper (warn-logs unknown event types)
9
- * - Session / usage / error getters
10
- *
11
- * Subclasses provide:
12
- * - `logTag` — prefix for warn logs
13
- * - `streamEndedMessage()` — agent-specific "stream ended early" message
14
- * - `translateEvent(raw)` — agent-specific event dispatch
15
- *
16
- * @see SpawningRunner for the runner that consumes translators
17
- */
18
- import type { AgentEvent, ResultEvent } from '../types.js';
19
- /** Why the stream ended without a natural terminal event. */
20
- type ExecFinishReason = 'failed' | 'interrupted' | 'timeout';
21
- export declare abstract class ExecTranslator {
22
- protected terminal: boolean;
23
- protected lastError: string | undefined;
24
- protected lastUsage: NonNullable<ResultEvent['usage']> | undefined;
25
- protected terminalErrorMessage: string | undefined;
26
- protected terminalErrorFromAgent: boolean;
27
- protected sessionId: string | undefined;
28
- protected readonly startedTools: Set<string>;
29
- /** Log prefix, e.g. `'[codex-exec-translator]'`. */
30
- protected abstract readonly logTag: string;
31
- /** Human-readable message when the stream ends before a terminal event. */
32
- protected abstract streamEndedMessage(): string;
33
- /** Agent-specific event dispatch. Called only for valid records with a string `type`. */
34
- protected abstract translateEvent(raw: Record<string, unknown>): AgentEvent[] | null;
35
- /** Translate a single parsed ndjson line into zero or more `AgentEvent`s.
36
- * P3-3: filter paths (terminal / non-record / non-string-type) return `null`
37
- * instead of `[]` to avoid a throwaway array allocation per non-emitting
38
- * event on codex/opencode hot paths. The consumer (SpawningRunner) already
39
- * handles `null` via `Array.isArray` + null guards. */
40
- translate(raw: unknown): AgentEvent[] | null;
41
- /** Warn-log an unknown event type and return `null` (P3-3: no throwaway []). */
42
- protected recordUnknownEvent(type: string): AgentEvent[] | null;
43
- /**
44
- * Called when the stream ends without a natural terminal event.
45
- *
46
- * - Marks the translator terminal (idempotent — second call returns `[]`).
47
- * - For `reason='failed'`, stores `terminalErrorMessage` so the runner can
48
- * surface it via `buildResultEvent({translatorError})`.
49
- * - Returns `[]` — the runner is responsible for emitting the result event.
50
- */
51
- finish(reason?: ExecFinishReason): AgentEvent[];
52
- /** Whether a terminal event has already been seen. */
53
- isTerminal(): boolean;
54
- /** Session ID captured from the agent stream (for the result event). */
55
- getSessionId(): string | undefined;
56
- /** Token usage captured from the terminal event (for the success result event). */
57
- getLastUsage(): NonNullable<ResultEvent['usage']> | undefined;
58
- /**
59
- * Terminal error message captured from an agent-reported error or
60
- * `finish('failed')`. Returns `undefined` if no terminal error occurred.
61
- */
62
- getTerminalError(): string | undefined;
63
- /**
64
- * True iff `getTerminalError()` was populated by an agent-reported terminal
65
- * error (e.g. codex `turn.failed`). The runner uses this to pick the correct
66
- * root cause for `buildResultEvent`: agent errors override signal/non-zero-code
67
- * (the agent error is the root cause), but stream-ended-early errors
68
- * (`finish('failed')`) yield to signal/non-zero-code (the signal is the root
69
- * cause and the early stream-end is a symptom).
70
- */
71
- hasAgentTerminalError(): boolean;
72
- }
73
- export {};