lark-remote 0.1.0
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 +52 -0
- package/LICENSE +21 -0
- package/README.en.md +162 -0
- package/README.md +161 -0
- package/dist/binder.d.ts +57 -0
- package/dist/binder.js +105 -0
- package/dist/bridge/index.d.ts +338 -0
- package/dist/bridge/index.js +1281 -0
- package/dist/bridge/queue-manager.d.ts +277 -0
- package/dist/bridge/queue-manager.js +729 -0
- package/dist/card/bash-card-session.d.ts +78 -0
- package/dist/card/bash-card-session.js +174 -0
- package/dist/card/bash-renderer.d.ts +24 -0
- package/dist/card/bash-renderer.js +187 -0
- package/dist/card/card-budget.d.ts +31 -0
- package/dist/card/card-budget.js +280 -0
- package/dist/card/card-session.d.ts +83 -0
- package/dist/card/card-session.js +185 -0
- package/dist/card/card-shared.d.ts +28 -0
- package/dist/card/card-shared.js +99 -0
- package/dist/card/collapsible.d.ts +26 -0
- package/dist/card/collapsible.js +87 -0
- package/dist/card/run-card-session.d.ts +78 -0
- package/dist/card/run-card-session.js +165 -0
- package/dist/card/run-renderer.d.ts +66 -0
- package/dist/card/run-renderer.js +841 -0
- package/dist/card/run-state.d.ts +103 -0
- package/dist/card/run-state.js +313 -0
- package/dist/card/text-truncate.d.ts +56 -0
- package/dist/card/text-truncate.js +184 -0
- package/dist/card/time.d.ts +1 -0
- package/dist/card/time.js +14 -0
- package/dist/card/tool-render.d.ts +25 -0
- package/dist/card/tool-render.js +176 -0
- package/dist/cli.d.ts +28 -0
- package/dist/cli.js +89 -0
- package/dist/common/guards.d.ts +37 -0
- package/dist/common/guards.js +65 -0
- package/dist/config/codex-config.d.ts +113 -0
- package/dist/config/codex-config.js +428 -0
- package/dist/config/dir.d.ts +17 -0
- package/dist/config/dir.js +81 -0
- package/dist/config/index.d.ts +219 -0
- package/dist/config/index.js +388 -0
- package/dist/config/kimi-config.d.ts +33 -0
- package/dist/config/kimi-config.js +111 -0
- package/dist/config/opencode-config.d.ts +20 -0
- package/dist/config/opencode-config.js +124 -0
- package/dist/config/pi-config.d.ts +49 -0
- package/dist/config/pi-config.js +151 -0
- package/dist/config/wizard.d.ts +12 -0
- package/dist/config/wizard.js +84 -0
- package/dist/connector/file-limits.d.ts +7 -0
- package/dist/connector/file-limits.js +8 -0
- package/dist/connector/index.d.ts +86 -0
- package/dist/connector/index.js +340 -0
- package/dist/error-classification.d.ts +15 -0
- package/dist/error-classification.js +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +580 -0
- package/dist/instance-lock.d.ts +30 -0
- package/dist/instance-lock.js +184 -0
- package/dist/logger/index.d.ts +57 -0
- package/dist/logger/index.js +178 -0
- package/dist/order/index.d.ts +27 -0
- package/dist/order/index.js +90 -0
- package/dist/persistence/atomic-write.d.ts +10 -0
- package/dist/persistence/atomic-write.js +65 -0
- package/dist/persistence/load-json-file.d.ts +9 -0
- package/dist/persistence/load-json-file.js +23 -0
- package/dist/restart.d.ts +24 -0
- package/dist/restart.js +73 -0
- package/dist/router/card-helpers.d.ts +28 -0
- package/dist/router/card-helpers.js +65 -0
- package/dist/router/config/claude.d.ts +14 -0
- package/dist/router/config/claude.js +72 -0
- package/dist/router/config/codex.d.ts +22 -0
- package/dist/router/config/codex.js +100 -0
- package/dist/router/config/common/render.d.ts +16 -0
- package/dist/router/config/common/render.js +158 -0
- package/dist/router/config/index.d.ts +18 -0
- package/dist/router/config/index.js +38 -0
- package/dist/router/config/kimi.d.ts +21 -0
- package/dist/router/config/kimi.js +63 -0
- package/dist/router/config/opencode.d.ts +12 -0
- package/dist/router/config/opencode.js +44 -0
- package/dist/router/config/pi.d.ts +12 -0
- package/dist/router/config/pi.js +50 -0
- package/dist/router/config/types.d.ts +43 -0
- package/dist/router/config/types.js +8 -0
- package/dist/router/index.d.ts +318 -0
- package/dist/router/index.js +2715 -0
- package/dist/router/order-exec-dispatch.d.ts +30 -0
- package/dist/router/order-exec-dispatch.js +48 -0
- package/dist/router/utils.d.ts +44 -0
- package/dist/router/utils.js +116 -0
- package/dist/runner/bash/index.d.ts +4 -0
- package/dist/runner/bash/index.js +5 -0
- package/dist/runner/bash/runner.d.ts +55 -0
- package/dist/runner/bash/runner.js +213 -0
- package/dist/runner/claude/index.d.ts +4 -0
- package/dist/runner/claude/index.js +5 -0
- package/dist/runner/claude/runner.d.ts +29 -0
- package/dist/runner/claude/runner.js +83 -0
- package/dist/runner/codex/argv.d.ts +33 -0
- package/dist/runner/codex/argv.js +40 -0
- package/dist/runner/codex/index.d.ts +1 -0
- package/dist/runner/codex/index.js +2 -0
- package/dist/runner/codex/jsonl.d.ts +37 -0
- package/dist/runner/codex/jsonl.js +221 -0
- package/dist/runner/codex/runner.d.ts +65 -0
- package/dist/runner/codex/runner.js +124 -0
- package/dist/runner/common/exec-translator.d.ts +73 -0
- package/dist/runner/common/exec-translator.js +105 -0
- package/dist/runner/common/jsonl-stream.d.ts +39 -0
- package/dist/runner/common/jsonl-stream.js +203 -0
- package/dist/runner/common/process-stopper.d.ts +28 -0
- package/dist/runner/common/process-stopper.js +79 -0
- package/dist/runner/common/runner-utils.d.ts +21 -0
- package/dist/runner/common/runner-utils.js +65 -0
- package/dist/runner/common/spawn-heartbeat.d.ts +33 -0
- package/dist/runner/common/spawn-heartbeat.js +51 -0
- package/dist/runner/common/spawning-runner.d.ts +321 -0
- package/dist/runner/common/spawning-runner.js +634 -0
- package/dist/runner/common/usage.d.ts +31 -0
- package/dist/runner/common/usage.js +29 -0
- package/dist/runner/index.d.ts +19 -0
- package/dist/runner/index.js +24 -0
- package/dist/runner/kimi/index.d.ts +1 -0
- package/dist/runner/kimi/index.js +2 -0
- package/dist/runner/kimi/jsonl.d.ts +28 -0
- package/dist/runner/kimi/jsonl.js +143 -0
- package/dist/runner/kimi/runner.d.ts +50 -0
- package/dist/runner/kimi/runner.js +105 -0
- package/dist/runner/opencode/argv.d.ts +32 -0
- package/dist/runner/opencode/argv.js +35 -0
- package/dist/runner/opencode/index.d.ts +1 -0
- package/dist/runner/opencode/index.js +2 -0
- package/dist/runner/opencode/jsonl.d.ts +68 -0
- package/dist/runner/opencode/jsonl.js +295 -0
- package/dist/runner/opencode/runner.d.ts +63 -0
- package/dist/runner/opencode/runner.js +93 -0
- package/dist/runner/pi/index.d.ts +1 -0
- package/dist/runner/pi/index.js +2 -0
- package/dist/runner/pi/jsonl.d.ts +128 -0
- package/dist/runner/pi/jsonl.js +249 -0
- package/dist/runner/pi/runner.d.ts +37 -0
- package/dist/runner/pi/runner.js +76 -0
- package/dist/runner/registry.d.ts +54 -0
- package/dist/runner/registry.js +75 -0
- package/dist/runner/resolve-agent-choices.d.ts +7 -0
- package/dist/runner/resolve-agent-choices.js +76 -0
- package/dist/runner/sync-agent-choices.d.ts +6 -0
- package/dist/runner/sync-agent-choices.js +73 -0
- package/dist/runner/types.d.ts +250 -0
- package/dist/runner/types.js +8 -0
- package/dist/session/claude/index.d.ts +1 -0
- package/dist/session/claude/index.js +2 -0
- package/dist/session/claude/session-reader.d.ts +34 -0
- package/dist/session/claude/session-reader.js +46 -0
- package/dist/session/claude/sessions.d.ts +53 -0
- package/dist/session/claude/sessions.js +528 -0
- package/dist/session/codex/index.d.ts +1 -0
- package/dist/session/codex/index.js +2 -0
- package/dist/session/codex/rollout-reader.d.ts +88 -0
- package/dist/session/codex/rollout-reader.js +473 -0
- package/dist/session/codex/sessions.d.ts +21 -0
- package/dist/session/codex/sessions.js +40 -0
- package/dist/session/common/catch-up.d.ts +12 -0
- package/dist/session/common/catch-up.js +31 -0
- package/dist/session/common/constants.d.ts +11 -0
- package/dist/session/common/constants.js +12 -0
- package/dist/session/common/content-blocks.d.ts +37 -0
- package/dist/session/common/content-blocks.js +68 -0
- package/dist/session/common/jsonl.d.ts +77 -0
- package/dist/session/common/jsonl.js +351 -0
- package/dist/session/common/usage-accumulator.d.ts +58 -0
- package/dist/session/common/usage-accumulator.js +72 -0
- package/dist/session/index.d.ts +7 -0
- package/dist/session/index.js +11 -0
- package/dist/session/kimi/index.d.ts +1 -0
- package/dist/session/kimi/index.js +2 -0
- package/dist/session/kimi/sessions.d.ts +81 -0
- package/dist/session/kimi/sessions.js +527 -0
- package/dist/session/opencode/index.d.ts +1 -0
- package/dist/session/opencode/index.js +2 -0
- package/dist/session/opencode/sessions.d.ts +81 -0
- package/dist/session/opencode/sessions.js +388 -0
- package/dist/session/pi/index.d.ts +1 -0
- package/dist/session/pi/index.js +2 -0
- package/dist/session/pi/sessions.d.ts +27 -0
- package/dist/session/pi/sessions.js +399 -0
- package/dist/session/registry.d.ts +12 -0
- package/dist/session/registry.js +20 -0
- package/dist/session/session-store.d.ts +86 -0
- package/dist/session/session-store.js +450 -0
- package/dist/startup-contact.d.ts +18 -0
- package/dist/startup-contact.js +51 -0
- package/dist/workspace/index.d.ts +19 -0
- package/dist/workspace/index.js +53 -0
- package/package.json +93 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
import type { Readable } from 'node:stream';
|
|
3
|
+
import { ProcessStopper } from './process-stopper.js';
|
|
4
|
+
import { SpawnHeartbeat } from './spawn-heartbeat.js';
|
|
5
|
+
import type { AgentEvent, SpawnOptions } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* 进程级退出监听单例分发(P1-1 修复,2026-08-02)。
|
|
8
|
+
*
|
|
9
|
+
* 背景:5 个 runner(claude/codex/opencode/pi/kimi)的 registerExitHandlers 曾是
|
|
10
|
+
* 同构复制,每个实例 process.on('exit'|'SIGINT'|'SIGTERM') 注册 3 个永不移除的
|
|
11
|
+
* 闭包(捕获整个 runner 实例 + sessionReader + pidFilePath)。Bridge 每次 run
|
|
12
|
+
* 结束淘汰 (cwd, kind) 槽位、下次 run cache miss 新建实例再注册 → 约第 4 个 run
|
|
13
|
+
* 起 MaxListenersExceededWarning 刷屏,历史实例被闭包永久持有,内存无界增长。
|
|
14
|
+
*
|
|
15
|
+
* 现在:进程级监听只注册一次,内部 Set<SpawningRunner> 管理注册实例;
|
|
16
|
+
* registerExitHandlers() 只把实例加入集合(幂等),桥接层在淘汰槽位时调
|
|
17
|
+
* unregisterExitHandlers() 移除实例,让 runner 可被 GC。SIGINT/SIGTERM 语义
|
|
18
|
+
* 保持原样:cleanup 全部已注册实例后 exit 130/143。
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Exit-cleanup contract: anything that spawns a child process group and wants
|
|
22
|
+
* process-level cleanup (agent runners via SpawningRunner, and BashProcessRunner
|
|
23
|
+
* for `!` commands, P1-22) registers with the singleton dispatcher.
|
|
24
|
+
*/
|
|
25
|
+
interface ExitCleanupHandler {
|
|
26
|
+
cleanupOnExit(): void;
|
|
27
|
+
}
|
|
28
|
+
/** Register a process-exit cleanup handler (installs listeners at most once). */
|
|
29
|
+
export declare function registerExitCleanup(handler: ExitCleanupHandler): void;
|
|
30
|
+
/** Remove a handler so it can be GC'd (agent slots / finished bash runs). */
|
|
31
|
+
export declare function unregisterExitCleanup(handler: ExitCleanupHandler): void;
|
|
32
|
+
/**
|
|
33
|
+
* Stateful translator contract for runners that need per-run translation state
|
|
34
|
+
* (codex/opencode/pi/kimi). Subclasses return an instance from
|
|
35
|
+
* `createTranslator(opts)`; the base `run()` loop calls `translate(raw)` per
|
|
36
|
+
* event, then folds terminal state into `buildResultEvent(...)` at the end.
|
|
37
|
+
*
|
|
38
|
+
* `translate()` returns `AgentEvent | AgentEvent[] | null` (single event,
|
|
39
|
+
* multiple events, or filtered-out). `isTerminal()` / `finish()` / `getTerminalError()`
|
|
40
|
+
* / `hasAgentTerminalError()` are folded into the unified result event via
|
|
41
|
+
* `resolveTranslatorError()`.
|
|
42
|
+
*
|
|
43
|
+
* `getSessionId()` / `getLastUsage()` are optional because ClaudeRunner uses
|
|
44
|
+
* the stateless `translate()` hook (no translator object) and reads neither.
|
|
45
|
+
*/
|
|
46
|
+
export interface RunnerTranslator {
|
|
47
|
+
translate(raw: unknown): AgentEvent | AgentEvent[] | null;
|
|
48
|
+
isTerminal(): boolean;
|
|
49
|
+
finish(reason: 'failed' | 'interrupted' | 'timeout'): void;
|
|
50
|
+
getTerminalError(): string | undefined;
|
|
51
|
+
hasAgentTerminalError(): boolean;
|
|
52
|
+
getSessionId?(): string | undefined;
|
|
53
|
+
getLastUsage?(): Record<string, unknown> | undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Abstract base class for runners that spawn a child process per turn.
|
|
57
|
+
*
|
|
58
|
+
* Encapsulates the spawn + completion + cleanup orchestration shared by
|
|
59
|
+
* Claude/Codex/OpenCode/Pi/Kimi runners. Subclasses override:
|
|
60
|
+
* - buildArgv(opts) → agent-specific CLI flags (required)
|
|
61
|
+
* - createTranslator(opts) → stateful translator (codex/opencode/pi/kimi)
|
|
62
|
+
* OR translate(raw, ctx) → stateless passthrough (claude)
|
|
63
|
+
*
|
|
64
|
+
* Optional hooks (with sensible defaults):
|
|
65
|
+
* - getStdio() → stdio config (default ['ignore','pipe','pipe'])
|
|
66
|
+
* - getSpawnEnv(opts) → env vars (default process.env)
|
|
67
|
+
* - setupStdin(proc, message) → write prompt to stdin (default no-op)
|
|
68
|
+
* - createStreamReader(stdout) → JSONL or readline parser (default createJSONLStream)
|
|
69
|
+
* - validateBeforeRun(opts) → pre-spawn validation (default no-op)
|
|
70
|
+
* - awaitCompletion(proc, p) → wait for exit (default return p; kimi adds 5s race)
|
|
71
|
+
* - awaitSpawnError(proc) → wait for spawn error (default once('error'); kimi adds 5s race)
|
|
72
|
+
* - resolveTranslatorError(t, c) → translatorError precedence (default honors agent errors)
|
|
73
|
+
*
|
|
74
|
+
* The base class always emits a unified result event at the end of `run()`
|
|
75
|
+
* via `buildResultEvent(...)` — never throws on non-zero exit. This matches
|
|
76
|
+
* the contract pinned by codex/opencode/pi/kimi subclass anchors and the
|
|
77
|
+
* bridge's `runAgentStreamToEnd` error handling (which accepts both thrown
|
|
78
|
+
* errors and yielded error-result events).
|
|
79
|
+
*/
|
|
80
|
+
export declare abstract class SpawningRunner {
|
|
81
|
+
protected currentProcess: ChildProcess | null;
|
|
82
|
+
protected readonly pidFilePath: string;
|
|
83
|
+
protected readonly stopper: ProcessStopper;
|
|
84
|
+
protected readonly spawnHeartbeat: SpawnHeartbeat;
|
|
85
|
+
protected binary: string;
|
|
86
|
+
protected stopGraceMs: number;
|
|
87
|
+
/**
|
|
88
|
+
* Log prefix used in all operational log lines emitted by this runner
|
|
89
|
+
* (spawn, pid file, non-zero exit, stderr, killOrphan, stop cleanup) and
|
|
90
|
+
* as the SpawnHeartbeat label. Subclasses pass their own tag (e.g.
|
|
91
|
+
* 'claude-runner') so operators can grep agent-specific logs; the default
|
|
92
|
+
* 'spawning-runner' keeps the base-class anchor tests' neutral identity.
|
|
93
|
+
*/
|
|
94
|
+
protected readonly logTag: string;
|
|
95
|
+
/**
|
|
96
|
+
* The `message` argument from the most recent `run(message, opts)` call.
|
|
97
|
+
* Set in `run()` before `buildArgv(opts)` is invoked so subclasses can
|
|
98
|
+
* embed the message in their agent-specific argv (e.g. claude's `-p
|
|
99
|
+
* <message>`). This avoids changing the `buildArgv(opts)` signature,
|
|
100
|
+
* which would break existing anchor subclasses.
|
|
101
|
+
*/
|
|
102
|
+
protected currentMessage: string;
|
|
103
|
+
/**
|
|
104
|
+
* Whether the current run was interrupted by user-initiated stop().
|
|
105
|
+
* Set to true by stop() when a running process is being terminated;
|
|
106
|
+
* reset to false at the top of run(). `resolveTranslatorError()` and
|
|
107
|
+
* `buildResultEvent()` read this to decide result event subtype
|
|
108
|
+
* (error vs success) and the error message precedence.
|
|
109
|
+
*/
|
|
110
|
+
protected stoppedByUser: boolean;
|
|
111
|
+
constructor(opts: {
|
|
112
|
+
binary?: string;
|
|
113
|
+
pidDir?: string;
|
|
114
|
+
workspace: string;
|
|
115
|
+
stopGraceMs?: number;
|
|
116
|
+
spawnHeartbeatMs?: number;
|
|
117
|
+
/**
|
|
118
|
+
* Filename prefix for the pid file. Defaults to 'spawning'. Each
|
|
119
|
+
* subclass should pass its own prefix (e.g. 'claude', 'codex') so
|
|
120
|
+
* multiple runners sharing the same pidDir do not clobber each
|
|
121
|
+
* other's pid files.
|
|
122
|
+
*/
|
|
123
|
+
pidFilePrefix?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Log prefix for operational log lines and the SpawnHeartbeat label.
|
|
126
|
+
* Defaults to 'spawning-runner'. Subclasses pass their own tag (e.g.
|
|
127
|
+
* 'claude-runner') so operators can grep agent-specific logs and the
|
|
128
|
+
* spawn-stage-stalled WARN identifies the right agent.
|
|
129
|
+
*/
|
|
130
|
+
logTag?: string;
|
|
131
|
+
});
|
|
132
|
+
get isRunning(): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* stdio config for spawn. Default: stdin ignored (claude/kimi/pi pass the
|
|
135
|
+
* prompt via argv). codex/opencode override to ['pipe','pipe','pipe'] so
|
|
136
|
+
* they can write the prompt to stdin via `setupStdin`.
|
|
137
|
+
*/
|
|
138
|
+
protected getStdio(): ('ignore' | 'pipe')[];
|
|
139
|
+
/**
|
|
140
|
+
* Env vars for spawn. Default: process.env. opencode overrides to sync
|
|
141
|
+
* PWD=opts.cwd (opencode's directory detection reads PWD, not cwd).
|
|
142
|
+
*/
|
|
143
|
+
protected getSpawnEnv(_opts: SpawnOptions): NodeJS.ProcessEnv;
|
|
144
|
+
/**
|
|
145
|
+
* Write the prompt to the child's stdin (called after spawn succeeds).
|
|
146
|
+
* Default: no-op. codex/opencode override to `proc.stdin.end(message)`.
|
|
147
|
+
*/
|
|
148
|
+
protected setupStdin(_proc: ChildProcess, _message: string): void;
|
|
149
|
+
/**
|
|
150
|
+
* Create an async iterator over the child's stdout. Default: createJSONLStream
|
|
151
|
+
* (claude/kimi/pi) with P1-4 backpressure enabled (pauseThreshold=100).
|
|
152
|
+
* Subclasses that need to silently skip non-JSON lines should override
|
|
153
|
+
* `handleBadStreamLine` instead of this method.
|
|
154
|
+
*/
|
|
155
|
+
protected createStreamReader(stdout: Readable): AsyncGenerator<unknown>;
|
|
156
|
+
/**
|
|
157
|
+
* Hook called when createJSONLStream encounters a line that cannot be parsed
|
|
158
|
+
* as JSON. Default: log a warning via getLogger().warn (same format as
|
|
159
|
+
* jsonl-stream's built-in warning). Subclasses override to change behavior
|
|
160
|
+
* (e.g. codex/opencode silently skip by providing an empty override).
|
|
161
|
+
*/
|
|
162
|
+
protected handleBadStreamLine(line: string): void;
|
|
163
|
+
/**
|
|
164
|
+
* Create a stateful translator for this run. Default: null (uses the
|
|
165
|
+
* stateless `translate(raw, ctx)` hook). codex/opencode/pi/kimi override to
|
|
166
|
+
* return their translator instance.
|
|
167
|
+
*/
|
|
168
|
+
protected createTranslator(_opts: SpawnOptions): RunnerTranslator | null;
|
|
169
|
+
/**
|
|
170
|
+
* Pre-spawn validation. Return an AgentEvent to yield it and abort run()
|
|
171
|
+
* (e.g. codex's API key check yields an error result and returns).
|
|
172
|
+
* Default: null (no validation).
|
|
173
|
+
*/
|
|
174
|
+
protected validateBeforeRun(_opts: SpawnOptions): AgentEvent | null;
|
|
175
|
+
/**
|
|
176
|
+
* Await process completion. Default: return the completion promise as-is.
|
|
177
|
+
* kimi overrides to add a 5s timeout race + SIGKILL fallback (kimi
|
|
178
|
+
* sometimes hangs after stdout closes).
|
|
179
|
+
*/
|
|
180
|
+
protected awaitCompletion(_proc: ChildProcess, completion: Promise<{
|
|
181
|
+
code: number | null;
|
|
182
|
+
signal: NodeJS.Signals | null;
|
|
183
|
+
}>): Promise<{
|
|
184
|
+
code: number | null;
|
|
185
|
+
signal: NodeJS.Signals | null;
|
|
186
|
+
}>;
|
|
187
|
+
/**
|
|
188
|
+
* Await the spawn 'error' event when proc.pid === undefined. Races a
|
|
189
|
+
* finite timeout (review P2-11) against the 'error' event: Node guarantees
|
|
190
|
+
* 'error' for ENOENT/EACCES, but some binaries fail silently without ever
|
|
191
|
+
* emitting it (kimi's CLI is documented to do so). Without the race, run()
|
|
192
|
+
* hangs forever → the workspace serial queue never settles → permanent
|
|
193
|
+
* deadlock, and /stop can't recover (ProcessStopper returns early when
|
|
194
|
+
* pid === undefined). The timeout keeps the deadlock bounded.
|
|
195
|
+
*/
|
|
196
|
+
protected awaitSpawnError(proc: ChildProcess): Promise<Error | undefined>;
|
|
197
|
+
/**
|
|
198
|
+
* Resolve the translatorError to pass to buildResultEvent. Default
|
|
199
|
+
* precedence (most-specific first):
|
|
200
|
+
* - agent-reported terminal error (translator.hasAgentTerminalError()):
|
|
201
|
+
* always wins — the agent error is the root cause, signal/code is a
|
|
202
|
+
* consequence. E.g. codex `turn.failed` then non-zero exit.
|
|
203
|
+
* - stream-ended-early symptom (translator.getTerminalError() set by
|
|
204
|
+
* finish('failed')): ONLY surfaces when there is no external cause
|
|
205
|
+
* (signal / non-zero code / user stop). The signal/code is the root
|
|
206
|
+
* cause; the early stream-end is a symptom.
|
|
207
|
+
* - otherwise: undefined (signal/code/stoppedByUser drives the message).
|
|
208
|
+
*
|
|
209
|
+
* Subclasses can override for custom precedence but the default matches
|
|
210
|
+
* the contract pinned by codex/opencode subclass anchors.
|
|
211
|
+
*/
|
|
212
|
+
protected resolveTranslatorError(translator: RunnerTranslator | null, ctx: {
|
|
213
|
+
code: number | null;
|
|
214
|
+
signal: NodeJS.Signals | null;
|
|
215
|
+
}): string | undefined;
|
|
216
|
+
/**
|
|
217
|
+
* Spawn the agent binary with argv built by buildArgv(opts), iterate its
|
|
218
|
+
* stdout stream, and yield translated events. Always emits a unified
|
|
219
|
+
* result event at the end via `buildResultEvent(...)` — never throws on
|
|
220
|
+
* non-zero exit (the bridge accepts both thrown errors and yielded
|
|
221
|
+
* error-result events, and the latter carries richer diagnostic info).
|
|
222
|
+
*
|
|
223
|
+
* Spawn failures (binary missing, pid undefined) yield an `authErrorEvent`
|
|
224
|
+
* instead of throwing, so the user sees a friendly error card.
|
|
225
|
+
*/
|
|
226
|
+
run(message: string, opts: SpawnOptions): AsyncGenerator<AgentEvent>;
|
|
227
|
+
/**
|
|
228
|
+
* Stop the current process if one is running. Delegates the actual
|
|
229
|
+
* SIGTERM → grace → SIGKILL sequence to `this.stopper.stop(proc, opts)`
|
|
230
|
+
* (see `src/runner/common/process-stopper.ts`), forwarding the `immediate`
|
|
231
|
+
* flag verbatim so all 5 subclasses inherit identical stop semantics.
|
|
232
|
+
*/
|
|
233
|
+
stop(opts?: {
|
|
234
|
+
immediate?: boolean;
|
|
235
|
+
}): Promise<void>;
|
|
236
|
+
killOrphan(): void;
|
|
237
|
+
/**
|
|
238
|
+
* P1-10: verify the process behind a stale pid file is actually ours before
|
|
239
|
+
* sending any signal. `ps -o command=` (not `comm=`) is used because agent
|
|
240
|
+
* binaries may be bash-wrapped scripts whose comm is the interpreter name
|
|
241
|
+
* (`/bin/bash`); the full command line contains the binary path/basename.
|
|
242
|
+
*
|
|
243
|
+
* Returns:
|
|
244
|
+
* 'match' — ps succeeded and the command line contains this.binary
|
|
245
|
+
* (absolute path) or its basename (PATH lookup).
|
|
246
|
+
* 'mismatch' — ps succeeded but the command line is clearly a different
|
|
247
|
+
* process (pid was recycled to an unrelated process).
|
|
248
|
+
* 'unknown' — ps failed / process gone / output unreadable: cannot tell.
|
|
249
|
+
*/
|
|
250
|
+
private matchPidToBinary;
|
|
251
|
+
/**
|
|
252
|
+
* Register this runner with the process-level exit dispatcher (singleton).
|
|
253
|
+
* Process listeners are installed at most once; subsequent calls only add
|
|
254
|
+
* the instance to the internal Set (idempotent — no listener accumulation).
|
|
255
|
+
* Bridge evicts the (cwd, kind) slot after each run; call
|
|
256
|
+
* `unregisterExitHandlers()` there so the instance can be GC'd.
|
|
257
|
+
*/
|
|
258
|
+
registerExitHandlers(): void;
|
|
259
|
+
/**
|
|
260
|
+
* Remove this runner from the process-level exit dispatcher. Called when
|
|
261
|
+
* the bridge evicts the runner cache slot (finalizeRun / interruptCurrentRun
|
|
262
|
+
* / clearRunners) so the instance is no longer retained by the dispatcher.
|
|
263
|
+
*/
|
|
264
|
+
unregisterExitHandlers(): void;
|
|
265
|
+
/**
|
|
266
|
+
* Current number of runners registered with the process-level exit
|
|
267
|
+
* dispatcher. Diagnostics / test-support introspection (P1-1 anchor asserts
|
|
268
|
+
* the count returns to baseline after bridge eviction).
|
|
269
|
+
*/
|
|
270
|
+
static getRegisteredExitHandlerCount(): number;
|
|
271
|
+
/**
|
|
272
|
+
* Shared process-exit cleanup: SIGTERM the still-running child process and
|
|
273
|
+
* remove the pid file. Called by the singleton dispatcher for every
|
|
274
|
+
* registered runner; previously duplicated verbatim in all 5 runner
|
|
275
|
+
* subclasses.
|
|
276
|
+
*/
|
|
277
|
+
cleanupOnExit(): void;
|
|
278
|
+
/**
|
|
279
|
+
* Build a unified result event from process exit state. Centralizes the
|
|
280
|
+
* result-event semantics specified in Candidate 2:
|
|
281
|
+
* - stoppedByUser → error ("interrupted by user")
|
|
282
|
+
* - translatorError set → error (translator-supplied message, e.g. codex
|
|
283
|
+
* `turn.failed` or "stream ended before a terminal event")
|
|
284
|
+
* - code !== 0 && code !== null → error (exit code + stderr tail)
|
|
285
|
+
* - signal !== null → error (killed by signal)
|
|
286
|
+
* - otherwise → success (with optional usage)
|
|
287
|
+
*
|
|
288
|
+
* Error message precedence (most-specific first):
|
|
289
|
+
* - stoppedByUser: "{binary} interrupted by user"
|
|
290
|
+
* - translatorError: verbatim translator-supplied message
|
|
291
|
+
* - signal: "{binary} killed by signal {signal}{stderr tail}"
|
|
292
|
+
* - non-zero code: "{binary} exited code={code}{stderr tail}"
|
|
293
|
+
*
|
|
294
|
+
* @param opts.code - Process exit code (null if killed by signal)
|
|
295
|
+
* @param opts.signal - Process signal code (null if exited normally)
|
|
296
|
+
* @param opts.stderr - Accumulated stderr (tail included in code/signal errors)
|
|
297
|
+
* @param opts.sessionId - Session ID to include in the result event
|
|
298
|
+
* @param opts.usage - Token usage to include on success
|
|
299
|
+
* @param opts.translatorError - Agent-specific terminal error message (e.g.
|
|
300
|
+
* codex turn.failed, or "stream ended early")
|
|
301
|
+
* @returns AgentEvent with type='result'
|
|
302
|
+
*/
|
|
303
|
+
protected buildResultEvent(opts: {
|
|
304
|
+
code: number | null;
|
|
305
|
+
signal: NodeJS.Signals | null;
|
|
306
|
+
stderr?: string;
|
|
307
|
+
sessionId?: string;
|
|
308
|
+
usage?: Record<string, unknown>;
|
|
309
|
+
translatorError?: string;
|
|
310
|
+
}): AgentEvent;
|
|
311
|
+
protected abstract buildArgv(opts: SpawnOptions): string[];
|
|
312
|
+
/**
|
|
313
|
+
* Stateless passthrough translator hook. Used by ClaudeRunner
|
|
314
|
+
* which does not need per-run translation state. Subclasses that return
|
|
315
|
+
* a translator from `createTranslator(opts)` leave this as the default
|
|
316
|
+
* no-op — the base `run()` loop only calls `translate()` when
|
|
317
|
+
* `createTranslator()` returns null.
|
|
318
|
+
*/
|
|
319
|
+
protected translate(_rawEvent: unknown, _ctx: unknown): AgentEvent | AgentEvent[] | null;
|
|
320
|
+
}
|
|
321
|
+
export {};
|