lark-remote 0.4.4 → 0.5.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 +28 -0
- package/dist/binder.d.ts +11 -10
- package/dist/binder.js +17 -16
- package/dist/bridge/approval-coordinator.d.ts +1 -1
- package/dist/bridge/approval-coordinator.js +3 -3
- package/dist/bridge/inbound-media.d.ts +1 -27
- package/dist/bridge/inbound-media.js +23 -21
- package/dist/bridge/index.d.ts +57 -57
- package/dist/bridge/index.js +136 -129
- package/dist/bridge/queue-manager.d.ts +45 -38
- package/dist/bridge/queue-manager.js +136 -136
- package/dist/card/approval-render.d.ts +1 -1
- package/dist/card/approval-render.js +6 -6
- package/dist/card/bash-card-session.d.ts +3 -3
- package/dist/card/bash-card-session.js +3 -3
- package/dist/card/bash-renderer.js +5 -5
- package/dist/card/card-session.d.ts +4 -4
- package/dist/card/card-session.js +6 -6
- package/dist/card/card-shared.d.ts +1 -1
- package/dist/card/card-shared.js +2 -2
- package/dist/card/run-card-session.js +2 -2
- package/dist/card/run-renderer.d.ts +1 -1
- package/dist/card/run-renderer.js +22 -22
- package/dist/card/run-state.d.ts +2 -2
- package/dist/card/run-state.js +3 -3
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +6 -6
- package/dist/cli.js +5 -6
- package/dist/clone.d.ts +6 -9
- package/dist/clone.js +12 -8
- package/dist/common/clamp.d.ts +2 -0
- package/dist/common/clamp.js +5 -0
- package/dist/common/fs.d.ts +4 -3
- package/dist/common/fs.js +5 -4
- package/dist/common/truncate.d.ts +1 -1
- package/dist/common/truncate.js +2 -2
- package/dist/common/ttl-cache.d.ts +2 -2
- package/dist/common/ttl-cache.js +2 -2
- package/dist/config/codex-config.d.ts +9 -9
- package/dist/config/codex-config.js +18 -18
- package/dist/config/dir.d.ts +4 -5
- package/dist/config/dir.js +12 -10
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +6 -6
- package/dist/config/opencode-config.js +3 -3
- package/dist/config/wizard.js +2 -2
- package/dist/connector/index.d.ts +5 -7
- package/dist/connector/index.js +29 -16
- package/dist/inbound/event.d.ts +1 -1
- package/dist/inbound/event.js +1 -1
- package/dist/inbound/placeholder.d.ts +2 -2
- package/dist/inbound/placeholder.js +2 -2
- package/dist/inbound/receipt.d.ts +1 -3
- package/dist/inbound/receipt.js +2 -2
- package/dist/inbound/turn-assembler.d.ts +1 -3
- package/dist/inbound/turn-assembler.js +2 -2
- package/dist/index.js +38 -30
- package/dist/instance-lock.js +8 -7
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.js +4 -4
- package/dist/persistence/atomic-write.d.ts +1 -1
- package/dist/persistence/atomic-write.js +9 -5
- package/dist/platform/agent-stopper.d.ts +2 -2
- package/dist/platform/identity.d.ts +7 -1
- package/dist/platform/identity.js +2 -2
- package/dist/platform/path.d.ts +6 -0
- package/dist/platform/path.js +14 -8
- package/dist/platform/select.d.ts +1 -1
- package/dist/platform/select.js +1 -1
- package/dist/platform/shell.d.ts +2 -3
- package/dist/platform/spawn.d.ts +2 -2
- package/dist/platform/spawn.js +2 -2
- package/dist/platform/terminator-posix.js +6 -6
- package/dist/platform/terminator-win32.js +3 -3
- package/dist/platform/terminator.d.ts +3 -3
- package/dist/platform/terminator.js +2 -2
- package/dist/platform/types.d.ts +1 -1
- package/dist/restart.d.ts +1 -1
- package/dist/restart.js +5 -3
- package/dist/router/card-helpers.d.ts +1 -3
- package/dist/router/card-helpers.js +2 -2
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +3 -3
- package/dist/router/config/common/model-patch.d.ts +1 -2
- package/dist/router/config/common/model-patch.js +1 -2
- package/dist/router/config/opencode.js +2 -2
- package/dist/router/config/pi.js +1 -1
- package/dist/router/index.d.ts +30 -30
- package/dist/router/index.js +103 -84
- package/dist/router/order-exec-dispatch.d.ts +3 -10
- package/dist/router/order-exec-dispatch.js +5 -5
- package/dist/router/{utils.d.ts → usage-format.d.ts} +2 -4
- package/dist/router/{utils.js → usage-format.js} +3 -8
- package/dist/runner/bash/runner.d.ts +2 -2
- package/dist/runner/bash/runner.js +6 -6
- package/dist/runner/claude/runner.d.ts +1 -1
- package/dist/runner/claude/runner.js +2 -3
- package/dist/runner/claude/session.d.ts +4 -6
- package/dist/runner/claude/session.js +21 -23
- package/dist/runner/codex/app-server/runner.js +3 -3
- package/dist/runner/codex/app-server/translator.d.ts +2 -2
- package/dist/runner/codex/app-server/translator.js +5 -5
- package/dist/runner/common/acp/{protocol-helpers.d.ts → acp-approval.d.ts} +4 -10
- package/dist/runner/common/acp/{protocol-helpers.js → acp-approval.js} +7 -6
- package/dist/runner/common/acp/base-acp-runner.d.ts +1 -1
- package/dist/runner/common/acp/base-acp-runner.js +2 -2
- package/dist/runner/common/acp/base-translator.d.ts +3 -3
- package/dist/runner/common/acp/base-translator.js +4 -4
- package/dist/runner/common/acp/protocol-types.js +1 -1
- package/dist/runner/common/connection-based-runner.d.ts +5 -5
- package/dist/runner/common/connection-based-runner.js +5 -5
- package/dist/runner/common/jsonl-stream.d.ts +2 -2
- package/dist/runner/common/jsonl-stream.js +12 -12
- package/dist/runner/common/jsonrpc/client.d.ts +1 -1
- package/dist/runner/common/jsonrpc/client.js +1 -1
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +13 -13
- package/dist/runner/common/jsonrpc/connection-manager.js +37 -37
- package/dist/runner/common/jsonrpc/transport.d.ts +1 -1
- package/dist/runner/common/jsonrpc/transport.js +2 -2
- package/dist/runner/common/{usage.d.ts → result-usage.d.ts} +1 -1
- package/dist/runner/common/{usage.js → result-usage.js} +2 -2
- package/dist/runner/common/spawning-runner.d.ts +23 -10
- package/dist/runner/common/spawning-runner.js +48 -22
- package/dist/runner/common/{runner-utils.d.ts → synthetic-events.d.ts} +4 -4
- package/dist/runner/common/{runner-utils.js → synthetic-events.js} +5 -5
- package/dist/runner/dsh/client.d.ts +1 -1
- package/dist/runner/dsh/client.js +1 -1
- package/dist/runner/dsh/runner.js +3 -3
- package/dist/runner/kimi/acp/runner.d.ts +4 -4
- package/dist/runner/kimi/acp/runner.js +10 -10
- package/dist/runner/kimi/acp/translator.d.ts +2 -2
- package/dist/runner/kimi/acp/translator.js +5 -5
- package/dist/runner/opencode/acp/runner.d.ts +4 -4
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/opencode/acp/translator.js +2 -2
- package/dist/runner/pi/rpc/runner.d.ts +1 -1
- package/dist/runner/pi/rpc/runner.js +2 -2
- package/dist/runner/pi/rpc/translator.d.ts +1 -2
- package/dist/runner/pi/rpc/translator.js +4 -6
- package/dist/runner/registry.d.ts +3 -3
- package/dist/runner/registry.js +3 -3
- package/dist/runner/types.d.ts +1 -1
- package/dist/session/claude/session-index.d.ts +13 -1
- package/dist/session/claude/session-index.js +21 -6
- package/dist/session/claude/session-reader.d.ts +1 -1
- package/dist/session/claude/session-reader.js +1 -1
- package/dist/session/claude/sessions.js +10 -10
- package/dist/session/codex/rollout-reader.d.ts +4 -4
- package/dist/session/codex/rollout-reader.js +14 -14
- package/dist/session/common/two-pass.js +2 -2
- package/dist/session/common/usage-accumulator.d.ts +2 -2
- package/dist/session/common/usage-accumulator.js +2 -2
- package/dist/session/dsh/sessions.d.ts +1 -1
- package/dist/session/dsh/sessions.js +3 -3
- package/dist/session/kimi/sessions.d.ts +2 -6
- package/dist/session/kimi/sessions.js +13 -19
- package/dist/session/opencode/sessions.d.ts +3 -3
- package/dist/session/opencode/sessions.js +15 -13
- package/dist/session/pi/sessions.js +13 -12
- package/dist/session/registry.d.ts +1 -1
- package/dist/session/registry.js +1 -1
- package/dist/session/session-store.d.ts +3 -4
- package/dist/session/session-store.js +3 -5
- package/dist/update/index.d.ts +1 -1
- package/dist/update/index.js +1 -1
- package/dist/update/version-check.d.ts +5 -3
- package/dist/update/version-check.js +10 -8
- package/dist/workspace/index.d.ts +4 -4
- package/dist/workspace/index.js +5 -5
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { type Terminator } from '../../platform/terminator.js';
|
|
|
4
4
|
import { SpawnHeartbeat } from './spawn-heartbeat.js';
|
|
5
5
|
import type { SpawnOptions } from '../types.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 进程级退出监听单例分发(修复,2026-08-02)。
|
|
8
8
|
*
|
|
9
9
|
* 背景:各 agent runner 的 registerExitHandlers 曾是同构复制,每个实例
|
|
10
10
|
* process.on('exit'|'SIGINT'|'SIGTERM') 注册 3 个永不移除的闭包(捕获整个
|
|
@@ -20,13 +20,26 @@ import type { SpawnOptions } from '../types.js';
|
|
|
20
20
|
/**
|
|
21
21
|
* Exit-cleanup contract: anything that spawns a child process group and wants
|
|
22
22
|
* process-level cleanup (agent runners via SpawningRunner, and BashProcessRunner
|
|
23
|
-
* for `!` commands
|
|
23
|
+
* for `!` commands) registers with the singleton dispatcher.
|
|
24
24
|
*/
|
|
25
25
|
interface ExitCleanupHandler {
|
|
26
26
|
cleanupOnExit(): void;
|
|
27
27
|
}
|
|
28
28
|
/** Register a process-exit cleanup handler (installs listeners at most once). */
|
|
29
29
|
export declare function registerExitCleanup(handler: ExitCleanupHandler): void;
|
|
30
|
+
/**
|
|
31
|
+
* pid 文件名的 workspace 后缀:`-<消毒 cwd>-<cwd hash>`。
|
|
32
|
+
*
|
|
33
|
+
* 消毒段(非字母数字 → `_`)只是可读性;不同 cwd 可能消毒出同一段
|
|
34
|
+
* (`/w/a+b` 与 `/w/a_b`),而 killOrphan 的身份校验只比对二进制名——
|
|
35
|
+
* 不掺 hash 时两个 workspace 会共用同一个 pid 文件,启动时的孤儿回收
|
|
36
|
+
* 可能误杀对方 workspace 存活的同名 agent。hash 段按**原始 cwd** 计算,
|
|
37
|
+
* 与消毒无关,消除碰撞。消毒段截到 96 字符,深路径下给 MAX_PATH 留余量。
|
|
38
|
+
*
|
|
39
|
+
* 导出给测试/anchor 复用:任何「手工构造 runner 会写出的 pid 文件路径」的
|
|
40
|
+
* 代码都必须走这里,自己拼一份就是自造半迁移。
|
|
41
|
+
*/
|
|
42
|
+
export declare function pidFileSuffix(cwd: string): string;
|
|
30
43
|
/** Remove a handler so it can be GC'd (agent slots / finished bash runs). */
|
|
31
44
|
export declare function unregisterExitCleanup(handler: ExitCleanupHandler): void;
|
|
32
45
|
/**
|
|
@@ -86,7 +99,7 @@ export declare abstract class SpawningRunner {
|
|
|
86
99
|
private stopperRegistration;
|
|
87
100
|
constructor(opts: {
|
|
88
101
|
pidDir?: string;
|
|
89
|
-
|
|
102
|
+
cwd: string;
|
|
90
103
|
stopGraceMs?: number;
|
|
91
104
|
spawnHeartbeatMs?: number;
|
|
92
105
|
/**
|
|
@@ -119,15 +132,15 @@ export declare abstract class SpawningRunner {
|
|
|
119
132
|
protected getStdio(): ('ignore' | 'pipe')[];
|
|
120
133
|
/**
|
|
121
134
|
* Create an async iterator over the child's stdout. Default: createJSONLStream
|
|
122
|
-
*
|
|
135
|
+
* withbackpressure enabled (pauseThreshold=100).
|
|
123
136
|
*/
|
|
124
137
|
protected createStreamReader(stdout: Readable): AsyncGenerator<unknown>;
|
|
125
138
|
/**
|
|
126
139
|
* Await the spawn 'error' event when proc.pid === undefined. Races a
|
|
127
|
-
* finite timeout
|
|
140
|
+
* finite timeout against the 'error' event: Node guarantees
|
|
128
141
|
* 'error' for ENOENT/EACCES, but some binaries fail silently without ever
|
|
129
142
|
* emitting it. Without the race, the spawn lead-in hangs forever → the
|
|
130
|
-
*
|
|
143
|
+
* cwd serial queue never settles → permanent deadlock, and /stop
|
|
131
144
|
* can't recover (Terminator.stop returns early when pid === undefined).
|
|
132
145
|
* The timeout keeps the deadlock bounded.
|
|
133
146
|
*/
|
|
@@ -143,7 +156,7 @@ export declare abstract class SpawningRunner {
|
|
|
143
156
|
*/
|
|
144
157
|
protected spawnChild(opts: SpawnOptions): Promise<ChildProcess>;
|
|
145
158
|
/**
|
|
146
|
-
*
|
|
159
|
+
* 登记本进程的协议停止通道:win32 上没有可拦截的跨进程
|
|
147
160
|
* SIGTERM,「优雅停止」只能经 agent 自有通道请求对方自行退出。stdio 型 agent
|
|
148
161
|
* CLI 的通道就是关 stdin(cc-connect 已验证 claude:关 stdin → 干净退出并跑
|
|
149
162
|
* Stop hooks)。
|
|
@@ -166,12 +179,12 @@ export declare abstract class SpawningRunner {
|
|
|
166
179
|
immediate?: boolean;
|
|
167
180
|
}): Promise<void>;
|
|
168
181
|
/**
|
|
169
|
-
*
|
|
182
|
+
* 杀掉上一次崩溃留下的孤儿 agent 进程。**身份校验是动手的前置条件**:
|
|
170
183
|
* pid 文件里的 pid 可能已被系统回收给无关进程,`kill(pid, 0)` 存活探测分不出来。
|
|
171
184
|
*
|
|
172
185
|
* 判定单源 = `platform/identity`(posix `ps -o command=` / win32 CIM),三态:
|
|
173
186
|
* - match → 杀整个进程组(detached:true 下 agent 是组长,与 Terminator
|
|
174
|
-
* posix 路径的 kill(-pid)
|
|
187
|
+
* posix 路径的 kill(-pid) 同语义,子进程不孤儿化);
|
|
175
188
|
* - mismatch → pid 已被无关进程占用:绝不杀,文件是陈旧垃圾,清除自愈;
|
|
176
189
|
* - unknown → 查不到身份(ps 不可用/超时/CIM 被拒):同样不杀,清文件。
|
|
177
190
|
* 统一原则:只有身份匹配才杀,验证失败一律不杀(fail-closed)。
|
|
@@ -198,7 +211,7 @@ export declare abstract class SpawningRunner {
|
|
|
198
211
|
unregisterExitHandlers(): void;
|
|
199
212
|
/**
|
|
200
213
|
* Current number of runners registered with the process-level exit
|
|
201
|
-
* dispatcher. Diagnostics / test-support introspection (
|
|
214
|
+
* dispatcher. Diagnostics / test-support introspection (asserts
|
|
202
215
|
* the count returns to baseline after bridge eviction).
|
|
203
216
|
*/
|
|
204
217
|
static getRegisteredExitHandlerCount(): number;
|
|
@@ -2,7 +2,7 @@ import { spawnProcess, isWindowsCommandNotFoundLine, useDetachedProcessGroup, }
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
|
-
import {
|
|
5
|
+
import { bestEffortUnlink } from '../../common/fs.js';
|
|
6
6
|
import { getLogger } from '../../logger/index.js';
|
|
7
7
|
import { binaryName, verifyPidIdentityVerdictSync } from '../../platform/identity.js';
|
|
8
8
|
import { createTerminator } from '../../platform/terminator.js';
|
|
@@ -11,7 +11,7 @@ import { SpawnHeartbeat } from './spawn-heartbeat.js';
|
|
|
11
11
|
import { createJSONLStream } from './jsonl-stream.js';
|
|
12
12
|
import { DEFAULT_STOP_GRACE_MS } from '../../config/index.js';
|
|
13
13
|
/**
|
|
14
|
-
* Magic-number constants (Clean Code
|
|
14
|
+
* Magic-number constants (Clean Code G25 Replace Magic Numbers with
|
|
15
15
|
* Named Constants). Centralized here so the truncation budgets are visible
|
|
16
16
|
* and adjustable in one place rather than scattered as raw literals.
|
|
17
17
|
*/
|
|
@@ -22,7 +22,7 @@ class SpawnChildError extends Error {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Timeout (ms) for awaiting the spawn 'error' event when proc.pid === undefined
|
|
25
|
-
*
|
|
25
|
+
* Node guarantees 'error' for ENOENT/EACCES, but some binaries
|
|
26
26
|
* fail silently; the race keeps a silent failure from hanging the spawn lead-in
|
|
27
27
|
* forever. Matches the 5s race kimi's override used before it was hoisted to
|
|
28
28
|
* the base.
|
|
@@ -54,6 +54,33 @@ export function registerExitCleanup(handler) {
|
|
|
54
54
|
installExitListenersOnce();
|
|
55
55
|
registeredRunners.add(handler);
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* FNV-1a 32 位哈希(hex,平台无关确定性):pid 文件后缀的消歧段。
|
|
59
|
+
*/
|
|
60
|
+
function fnv1aHex(text) {
|
|
61
|
+
let hash = 0x811c9dc5;
|
|
62
|
+
for (let i = 0; i < text.length; i++) {
|
|
63
|
+
hash ^= text.charCodeAt(i);
|
|
64
|
+
hash = Math.imul(hash, 0x01000193);
|
|
65
|
+
}
|
|
66
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* pid 文件名的 workspace 后缀:`-<消毒 cwd>-<cwd hash>`。
|
|
70
|
+
*
|
|
71
|
+
* 消毒段(非字母数字 → `_`)只是可读性;不同 cwd 可能消毒出同一段
|
|
72
|
+
* (`/w/a+b` 与 `/w/a_b`),而 killOrphan 的身份校验只比对二进制名——
|
|
73
|
+
* 不掺 hash 时两个 workspace 会共用同一个 pid 文件,启动时的孤儿回收
|
|
74
|
+
* 可能误杀对方 workspace 存活的同名 agent。hash 段按**原始 cwd** 计算,
|
|
75
|
+
* 与消毒无关,消除碰撞。消毒段截到 96 字符,深路径下给 MAX_PATH 留余量。
|
|
76
|
+
*
|
|
77
|
+
* 导出给测试/anchor 复用:任何「手工构造 runner 会写出的 pid 文件路径」的
|
|
78
|
+
* 代码都必须走这里,自己拼一份就是自造半迁移。
|
|
79
|
+
*/
|
|
80
|
+
export function pidFileSuffix(cwd) {
|
|
81
|
+
const sanitized = cwd.replace(/[^a-zA-Z0-9]/g, '_').slice(0, 96);
|
|
82
|
+
return `-${sanitized}-${fnv1aHex(cwd)}`;
|
|
83
|
+
}
|
|
57
84
|
/** Remove a handler so it can be GC'd (agent slots / finished bash runs). */
|
|
58
85
|
export function unregisterExitCleanup(handler) {
|
|
59
86
|
registeredRunners.delete(handler);
|
|
@@ -120,9 +147,8 @@ export class SpawningRunner {
|
|
|
120
147
|
this.logTag = opts.logTag ?? 'spawning-runner';
|
|
121
148
|
this.agent = opts.agent;
|
|
122
149
|
const pidDir = opts.pidDir ?? path.join(os.homedir(), '.lark-remote');
|
|
123
|
-
const workspaceSuffix = `-${opts.workspace.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
124
150
|
const pidFilePrefix = opts.pidFilePrefix ?? 'spawning';
|
|
125
|
-
this.pidFilePath = path.join(pidDir, `${pidFilePrefix}${
|
|
151
|
+
this.pidFilePath = path.join(pidDir, `${pidFilePrefix}${pidFileSuffix(opts.cwd)}.pid`);
|
|
126
152
|
this.terminator =
|
|
127
153
|
opts.terminator ?? createTerminator({ graceMs: this.stopGraceMs, agent: opts.agent });
|
|
128
154
|
this.spawnHeartbeat = new SpawnHeartbeat(opts.spawnHeartbeatMs ?? 30_000, this.logTag);
|
|
@@ -142,7 +168,7 @@ export class SpawningRunner {
|
|
|
142
168
|
}
|
|
143
169
|
/**
|
|
144
170
|
* Create an async iterator over the child's stdout. Default: createJSONLStream
|
|
145
|
-
*
|
|
171
|
+
* withbackpressure enabled (pauseThreshold=100).
|
|
146
172
|
*/
|
|
147
173
|
createStreamReader(stdout) {
|
|
148
174
|
return createJSONLStream(stdout, {
|
|
@@ -155,10 +181,10 @@ export class SpawningRunner {
|
|
|
155
181
|
}
|
|
156
182
|
/**
|
|
157
183
|
* Await the spawn 'error' event when proc.pid === undefined. Races a
|
|
158
|
-
* finite timeout
|
|
184
|
+
* finite timeout against the 'error' event: Node guarantees
|
|
159
185
|
* 'error' for ENOENT/EACCES, but some binaries fail silently without ever
|
|
160
186
|
* emitting it. Without the race, the spawn lead-in hangs forever → the
|
|
161
|
-
*
|
|
187
|
+
* cwd serial queue never settles → permanent deadlock, and /stop
|
|
162
188
|
* can't recover (Terminator.stop returns early when pid === undefined).
|
|
163
189
|
* The timeout keeps the deadlock bounded.
|
|
164
190
|
*/
|
|
@@ -203,7 +229,7 @@ export class SpawningRunner {
|
|
|
203
229
|
}
|
|
204
230
|
this.currentProcess = null;
|
|
205
231
|
this.spawnHeartbeat.clear();
|
|
206
|
-
//
|
|
232
|
+
// surface the real spawn error cause instead of a fixed "binary
|
|
207
233
|
// not found" message. ENOENT (binary missing) keeps the friendly hint,
|
|
208
234
|
// but EMFILE/EACCES/ENOMEM/bad-cwd failures must name the actual reason
|
|
209
235
|
// so the user is not misdiagnosed into reinstalling the binary.
|
|
@@ -219,7 +245,7 @@ export class SpawningRunner {
|
|
|
219
245
|
proc.stdout?.once('data', () => {
|
|
220
246
|
this.spawnHeartbeat.notifyStdout();
|
|
221
247
|
});
|
|
222
|
-
//
|
|
248
|
+
// 协议停止通道登记:子进程起来后立刻登记,win32 上
|
|
223
249
|
// Terminator 停这个 pid 时才能取到通道;进程退出/被停后注销。
|
|
224
250
|
this.registerStopper(proc);
|
|
225
251
|
this.spawnStderr = '';
|
|
@@ -235,7 +261,7 @@ export class SpawningRunner {
|
|
|
235
261
|
this.commandNotFoundSeen = true;
|
|
236
262
|
getLogger().error(`[${this.logTag}] command not found suspected (win32 shim): ${text}`);
|
|
237
263
|
}
|
|
238
|
-
//
|
|
264
|
+
// most agent CLIs emit progress/warnings/deprecation notices on
|
|
239
265
|
// stderr, not real errors. Logging each chunk at error level drowns out
|
|
240
266
|
// genuine errors. Downgrade to warn — the accumulated stderr is already
|
|
241
267
|
// surfaced at error level in the non-zero-exit result path.
|
|
@@ -245,7 +271,7 @@ export class SpawningRunner {
|
|
|
245
271
|
return proc;
|
|
246
272
|
}
|
|
247
273
|
/**
|
|
248
|
-
*
|
|
274
|
+
* 登记本进程的协议停止通道:win32 上没有可拦截的跨进程
|
|
249
275
|
* SIGTERM,「优雅停止」只能经 agent 自有通道请求对方自行退出。stdio 型 agent
|
|
250
276
|
* CLI 的通道就是关 stdin(cc-connect 已验证 claude:关 stdin → 干净退出并跑
|
|
251
277
|
* Stop hooks)。
|
|
@@ -298,16 +324,16 @@ export class SpawningRunner {
|
|
|
298
324
|
// (immediate 路径不查表,但一并注销同样正确——进程已进入终止流程)。
|
|
299
325
|
this.unregisterStopper();
|
|
300
326
|
this.currentProcess = null;
|
|
301
|
-
|
|
327
|
+
bestEffortUnlink(this.pidFilePath);
|
|
302
328
|
getLogger().debug(`[${this.logTag}] cleaned pid file ${this.pidFilePath}`);
|
|
303
329
|
}
|
|
304
330
|
/**
|
|
305
|
-
*
|
|
331
|
+
* 杀掉上一次崩溃留下的孤儿 agent 进程。**身份校验是动手的前置条件**:
|
|
306
332
|
* pid 文件里的 pid 可能已被系统回收给无关进程,`kill(pid, 0)` 存活探测分不出来。
|
|
307
333
|
*
|
|
308
334
|
* 判定单源 = `platform/identity`(posix `ps -o command=` / win32 CIM),三态:
|
|
309
335
|
* - match → 杀整个进程组(detached:true 下 agent 是组长,与 Terminator
|
|
310
|
-
* posix 路径的 kill(-pid)
|
|
336
|
+
* posix 路径的 kill(-pid) 同语义,子进程不孤儿化);
|
|
311
337
|
* - mismatch → pid 已被无关进程占用:绝不杀,文件是陈旧垃圾,清除自愈;
|
|
312
338
|
* - unknown → 查不到身份(ps 不可用/超时/CIM 被拒):同样不杀,清文件。
|
|
313
339
|
* 统一原则:只有身份匹配才杀,验证失败一律不杀(fail-closed)。
|
|
@@ -324,7 +350,7 @@ export class SpawningRunner {
|
|
|
324
350
|
const pidStr = fs.readFileSync(this.pidFilePath, 'utf-8').trim();
|
|
325
351
|
const pid = Number(pidStr);
|
|
326
352
|
if (isNaN(pid) || pid <= 0) {
|
|
327
|
-
|
|
353
|
+
bestEffortUnlink(this.pidFilePath);
|
|
328
354
|
return;
|
|
329
355
|
}
|
|
330
356
|
const expectedBinary = binaryName(this.binary);
|
|
@@ -339,11 +365,11 @@ export class SpawningRunner {
|
|
|
339
365
|
if (verdict !== 'match') {
|
|
340
366
|
getLogger().warn(`[${this.logTag}] killOrphan: pid ${pid} not confirmed as ${expectedBinary} ` +
|
|
341
367
|
`(${verdict}), skipping kill`);
|
|
342
|
-
|
|
368
|
+
bestEffortUnlink(this.pidFilePath);
|
|
343
369
|
return;
|
|
344
370
|
}
|
|
345
371
|
// 身份匹配:杀整个进程组(detached:true 下 agent 是组长),与
|
|
346
|
-
// Terminator 的 kill(-pid)
|
|
372
|
+
// Terminator 的 kill(-pid) 语义对齐,子进程不会孤儿化。
|
|
347
373
|
getLogger().info(`[${this.logTag}] killing orphan process group ${-pid}`);
|
|
348
374
|
try {
|
|
349
375
|
process.kill(-pid, 'SIGTERM');
|
|
@@ -351,7 +377,7 @@ export class SpawningRunner {
|
|
|
351
377
|
catch {
|
|
352
378
|
// process may have exited
|
|
353
379
|
}
|
|
354
|
-
|
|
380
|
+
bestEffortUnlink(this.pidFilePath);
|
|
355
381
|
}
|
|
356
382
|
catch {
|
|
357
383
|
// ignore
|
|
@@ -377,7 +403,7 @@ export class SpawningRunner {
|
|
|
377
403
|
}
|
|
378
404
|
/**
|
|
379
405
|
* Current number of runners registered with the process-level exit
|
|
380
|
-
* dispatcher. Diagnostics / test-support introspection (
|
|
406
|
+
* dispatcher. Diagnostics / test-support introspection (asserts
|
|
381
407
|
* the count returns to baseline after bridge eviction).
|
|
382
408
|
*/
|
|
383
409
|
static getRegisteredExitHandlerCount() {
|
|
@@ -392,7 +418,7 @@ export class SpawningRunner {
|
|
|
392
418
|
cleanupOnExit() {
|
|
393
419
|
if (this.currentProcess && this.currentProcess.exitCode === null) {
|
|
394
420
|
try {
|
|
395
|
-
//
|
|
421
|
+
// 只杀组长会让组内子进程(工具调用起的后台进程)reparent 成孤儿。
|
|
396
422
|
// Terminator.cleanupOnExit 在两种平台上都是「fire-and-forget 强杀整个
|
|
397
423
|
// 进程组/进程树」(posix kill(-pgid, SIGKILL) / win32 taskkill /T /F),
|
|
398
424
|
// 退出路径上无法等待,也不需要优雅段。
|
|
@@ -401,7 +427,7 @@ export class SpawningRunner {
|
|
|
401
427
|
catch { }
|
|
402
428
|
}
|
|
403
429
|
this.unregisterStopper();
|
|
404
|
-
|
|
430
|
+
bestEffortUnlink(this.pidFilePath);
|
|
405
431
|
}
|
|
406
432
|
}
|
|
407
433
|
//# sourceMappingURL=spawning-runner.js.map
|
|
@@ -12,10 +12,10 @@ import type { AgentEvent } from '../types.js';
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function syntheticInitEvent(sessionId?: string): AgentEvent;
|
|
14
14
|
/**
|
|
15
|
-
* Build a standardized
|
|
15
|
+
* Build a standardized setup-failure result event for yield.
|
|
16
16
|
*
|
|
17
|
-
* Used when
|
|
18
|
-
* session creation
|
|
17
|
+
* Used when setup fails before a turn can run — process spawn errors
|
|
18
|
+
* (e.g. ENOENT), not-logged-in, or session creation failure. Produces a
|
|
19
19
|
* `result`/`error` event so the bridge can render a card instead of crashing.
|
|
20
20
|
*/
|
|
21
|
-
export declare function
|
|
21
|
+
export declare function setupErrorEvent(errorMessage: string, sessionId?: string): AgentEvent;
|
|
@@ -20,13 +20,13 @@ export function syntheticInitEvent(sessionId = '') {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Build a standardized
|
|
23
|
+
* Build a standardized setup-failure result event for yield.
|
|
24
24
|
*
|
|
25
|
-
* Used when
|
|
26
|
-
* session creation
|
|
25
|
+
* Used when setup fails before a turn can run — process spawn errors
|
|
26
|
+
* (e.g. ENOENT), not-logged-in, or session creation failure. Produces a
|
|
27
27
|
* `result`/`error` event so the bridge can render a card instead of crashing.
|
|
28
28
|
*/
|
|
29
|
-
export function
|
|
29
|
+
export function setupErrorEvent(errorMessage, sessionId = '') {
|
|
30
30
|
return {
|
|
31
31
|
type: 'result',
|
|
32
32
|
subtype: 'error',
|
|
@@ -35,4 +35,4 @@ export function authErrorEvent(errorMessage, sessionId = '') {
|
|
|
35
35
|
timestamp: new Date().toISOString(),
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
-
//# sourceMappingURL=
|
|
38
|
+
//# sourceMappingURL=synthetic-events.js.map
|
|
@@ -86,7 +86,7 @@ export declare class DshClient {
|
|
|
86
86
|
* `session.history` to fill the gap (dedup by seq). Terminates on turn/end
|
|
87
87
|
* or `signal` abort.
|
|
88
88
|
*/
|
|
89
|
-
sessionEvents(sessionId: string,
|
|
89
|
+
sessionEvents(sessionId: string, signal: AbortSignal, initialSeq?: number): AsyncGenerator<DshStreamItem>;
|
|
90
90
|
/** Extract TokenUsage from an assistant/message data payload (absent → undefined). */
|
|
91
91
|
static usageOf(data: Record<string, unknown>): DshTokenUsage | undefined;
|
|
92
92
|
}
|
|
@@ -320,7 +320,7 @@ export class DshClient {
|
|
|
320
320
|
* `session.history` to fill the gap (dedup by seq). Terminates on turn/end
|
|
321
321
|
* or `signal` abort.
|
|
322
322
|
*/
|
|
323
|
-
async *sessionEvents(sessionId,
|
|
323
|
+
async *sessionEvents(sessionId, signal, initialSeq = -1) {
|
|
324
324
|
const state = { lastSeq: initialSeq };
|
|
325
325
|
// Initial baseline: before opening the first live mux subscription, replay
|
|
326
326
|
// history once so events produced between prompt-accept and the mux opening
|
|
@@ -67,7 +67,7 @@ export class DshRunner {
|
|
|
67
67
|
let sessionId = opts.sessionId;
|
|
68
68
|
let terminalEmitted = false;
|
|
69
69
|
try {
|
|
70
|
-
//
|
|
70
|
+
// session.create 必须包进同一 try/finally,否则创建失败(服务端不可达/报错)
|
|
71
71
|
// 会在进入旧 try 之前抛异常,finally 不执行 → running 恒 true、activeAbort 残留。
|
|
72
72
|
if (!sessionId) {
|
|
73
73
|
const created = await this.client.createSession({
|
|
@@ -135,7 +135,7 @@ export class DshRunner {
|
|
|
135
135
|
});
|
|
136
136
|
const translator = new DshTranslator();
|
|
137
137
|
try {
|
|
138
|
-
for await (const item of this.client.sessionEvents(sessionId,
|
|
138
|
+
for await (const item of this.client.sessionEvents(sessionId, abort.signal, prePromptSeq)) {
|
|
139
139
|
if (abort.signal.aborted)
|
|
140
140
|
break;
|
|
141
141
|
if (item.kind === 'approval') {
|
|
@@ -188,7 +188,7 @@ export class DshRunner {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
catch (err) {
|
|
191
|
-
//
|
|
191
|
+
// createSession 等启动期失败也产出 error result(而非抛异常),
|
|
192
192
|
// 由本 catch 统一转 error result;state 清理在 finally。
|
|
193
193
|
if (!abort.signal.aborted) {
|
|
194
194
|
yield {
|
|
@@ -21,7 +21,7 @@ import type { AgentKind, AgentSessionReader, AgentStatusInfo, SpawnOptions } fro
|
|
|
21
21
|
import { JsonRpcClient } from '../../common/jsonrpc/client.js';
|
|
22
22
|
import { KimiAcpTranslator } from './translator.js';
|
|
23
23
|
import { type SessionPromptResult } from '../../common/acp/protocol-types.js';
|
|
24
|
-
import { type AcpPendingApproval } from '../../common/acp/
|
|
24
|
+
import { type AcpPendingApproval } from '../../common/acp/acp-approval.js';
|
|
25
25
|
import { BaseAcpRunner } from '../../common/acp/base-acp-runner.js';
|
|
26
26
|
export interface KimiAcpRunnerOptions {
|
|
27
27
|
kind: AgentKind;
|
|
@@ -83,7 +83,7 @@ export declare class KimiAcpRunner extends BaseAcpRunner<KimiAcpTranslator> {
|
|
|
83
83
|
*/
|
|
84
84
|
private readonly terminator;
|
|
85
85
|
/**
|
|
86
|
-
* shell seam:terminal/create
|
|
86
|
+
* shell seam:terminal/create 的可执行解析走这里。kimi 的
|
|
87
87
|
* ACP 服务端固定要 `bash -c`,win32 上没有 Git Bash 时必须在 seam 里变成
|
|
88
88
|
* 明确错误,而不是一个语焉不详的 spawn ENOENT。
|
|
89
89
|
*/
|
|
@@ -105,7 +105,7 @@ export declare class KimiAcpRunner extends BaseAcpRunner<KimiAcpTranslator> {
|
|
|
105
105
|
* before producing the result. There is NO total timeout — silence beyond
|
|
106
106
|
* compactIdleTimeoutMs yields 'unknown' (never a fake success). Keeps the
|
|
107
107
|
* connection alive while the background compaction finishes — otherwise
|
|
108
|
-
* dispose/exit kills it and the record never lands (
|
|
108
|
+
* dispose/exit kills it and the record never lands (打回复现 /
|
|
109
109
|
* 2026-08-31 事故).
|
|
110
110
|
*/
|
|
111
111
|
protected compactBaseline(sessionId: string, opts: SpawnOptions): number;
|
|
@@ -113,7 +113,7 @@ export declare class KimiAcpRunner extends BaseAcpRunner<KimiAcpTranslator> {
|
|
|
113
113
|
protected buildApprovalOutcome(action: string, pending: AcpPendingApproval, response: unknown): unknown;
|
|
114
114
|
getStatusInfo(): AgentStatusInfo;
|
|
115
115
|
/**
|
|
116
|
-
* Hot-apply a permission-mode change to the live ACP session
|
|
116
|
+
* Hot-apply a permission-mode change to the live ACP session.
|
|
117
117
|
*
|
|
118
118
|
* The local cache is always updated so `getStatusInfo()` (and therefore
|
|
119
119
|
* `/s`) reflects the new mode immediately. When a session is connected,
|
|
@@ -23,7 +23,7 @@ import { StringDecoder } from 'node:string_decoder';
|
|
|
23
23
|
import { ConnectionManager, } from '../../common/jsonrpc/connection-manager.js';
|
|
24
24
|
import { KimiAcpTranslator } from './translator.js';
|
|
25
25
|
import { NotificationMethod, RpcErrorCode, ServerRequestMethod, } from '../../common/acp/protocol-types.js';
|
|
26
|
-
import { KIMI_APPROVAL_KINDS, buildAcpPermissionOutcome, } from '../../common/acp/
|
|
26
|
+
import { KIMI_APPROVAL_KINDS, buildAcpPermissionOutcome, } from '../../common/acp/acp-approval.js';
|
|
27
27
|
import { mapAnswersByIndex } from '../../question-common.js';
|
|
28
28
|
import { getLogger } from '../../../logger/index.js';
|
|
29
29
|
import { BaseAcpRunner } from '../../common/acp/base-acp-runner.js';
|
|
@@ -163,7 +163,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
163
163
|
*/
|
|
164
164
|
terminator = createTerminator({ graceMs: 2_000, agent: 'kimi' });
|
|
165
165
|
/**
|
|
166
|
-
* shell seam:terminal/create
|
|
166
|
+
* shell seam:terminal/create 的可执行解析走这里。kimi 的
|
|
167
167
|
* ACP 服务端固定要 `bash -c`,win32 上没有 Git Bash 时必须在 seam 里变成
|
|
168
168
|
* 明确错误,而不是一个语焉不详的 spawn ENOENT。
|
|
169
169
|
*/
|
|
@@ -224,7 +224,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
224
224
|
return new KimiAcpTranslator();
|
|
225
225
|
}
|
|
226
226
|
async applyTurnSettings(client, sessionId) {
|
|
227
|
-
//
|
|
227
|
+
// 下发配置的模型(provider/model)。session/new|resume 只带 cwd/mcpServers,
|
|
228
228
|
// 不带 model;不主动下发则实际跑 kimi 服务端默认模型。
|
|
229
229
|
// 仿 opencode 用 session/set_config_option。失败仅告警不阻断。
|
|
230
230
|
if (this.model) {
|
|
@@ -239,7 +239,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
239
239
|
getLogger().warn(`[${this.logTag}] set_config_option model failed (non-fatal): ${err.message}`);
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
|
-
//
|
|
242
|
+
// 下发配置的思考强度。configId 与取值不是猜的——kimi 真机(0.43.1)
|
|
243
243
|
// `session/new` 就通告 `{id:'thinking', category:'thought_level',
|
|
244
244
|
// options:[low|high|max]}`,set 成功后响应里 `currentValue` 变成新值;
|
|
245
245
|
// 未知 configId / 非法取值回 -32602(不静默接受),所以失败告警即可判定。
|
|
@@ -283,7 +283,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
283
283
|
* before producing the result. There is NO total timeout — silence beyond
|
|
284
284
|
* compactIdleTimeoutMs yields 'unknown' (never a fake success). Keeps the
|
|
285
285
|
* connection alive while the background compaction finishes — otherwise
|
|
286
|
-
* dispose/exit kills it and the record never lands (
|
|
286
|
+
* dispose/exit kills it and the record never lands (打回复现 /
|
|
287
287
|
* 2026-08-31 事故).
|
|
288
288
|
*/
|
|
289
289
|
compactBaseline(sessionId, opts) {
|
|
@@ -300,7 +300,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
300
300
|
const baselineTerminalCount = this.compactBaselineRecords.filter(isCompactionTerminalLike).length;
|
|
301
301
|
let promptRejected = false;
|
|
302
302
|
// prompt 结算只供两样东西:成功 result 的翻译素材(stopReason/usage)与 §5.4
|
|
303
|
-
//
|
|
303
|
+
// 探针。终态判定不再挂在它后面。
|
|
304
304
|
const promptSettled = promptPromise.then((result) => {
|
|
305
305
|
this.promptSettled = true;
|
|
306
306
|
if (compactionReader) {
|
|
@@ -326,7 +326,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
326
326
|
});
|
|
327
327
|
return;
|
|
328
328
|
}
|
|
329
|
-
//
|
|
329
|
+
// 语义等待在 prompt 触发的那一刻武装。引擎静默超过 compactIdleTimeoutMs
|
|
330
330
|
// 就给出 compact 语义终态,不等 session/prompt 结算——否则挂住的 prompt 会把
|
|
331
331
|
// 用户拖到通用 turnIdleTimeout(默认 30min),拿到的还是一个语义泛化的 turn
|
|
332
332
|
// 超时,而不是「压缩状态未知 / 可重试」。
|
|
@@ -372,7 +372,7 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
372
372
|
};
|
|
373
373
|
}
|
|
374
374
|
/**
|
|
375
|
-
* Hot-apply a permission-mode change to the live ACP session
|
|
375
|
+
* Hot-apply a permission-mode change to the live ACP session.
|
|
376
376
|
*
|
|
377
377
|
* The local cache is always updated so `getStatusInfo()` (and therefore
|
|
378
378
|
* `/s`) reflects the new mode immediately. When a session is connected,
|
|
@@ -553,14 +553,14 @@ export class KimiAcpRunner extends BaseAcpRunner {
|
|
|
553
553
|
: undefined;
|
|
554
554
|
const cwd = params.cwd ?? this.activeCwd ?? undefined;
|
|
555
555
|
const outputLimit = params.outputByteLimit ?? TERMINAL_DEFAULT_OUTPUT_LIMIT;
|
|
556
|
-
// 走 shell seam
|
|
556
|
+
// 走 shell seam:argv 逐 token 保留,只把「可执行文件在哪」
|
|
557
557
|
// 收口——win32 上 Git Bash 缺失时在这里抛 ShellUnavailableError,由
|
|
558
558
|
// handleTerminalRequest 转成明确的 Terminal request failed 回执,而不是一个
|
|
559
559
|
// 语焉不详的 spawn ENOENT。
|
|
560
560
|
const proc = this.shell.spawnArgv(params.command, params.args ?? [], {
|
|
561
561
|
cwd,
|
|
562
562
|
options: {
|
|
563
|
-
// env 覆盖大小写不敏感合并(win32 PATH/Path
|
|
563
|
+
// env 覆盖大小写不敏感合并(win32 PATH/Path 双键防护)
|
|
564
564
|
env: env ? mergeProcessEnv(process.env, env) : undefined,
|
|
565
565
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
566
566
|
// Terminator 用负 PID 杀进程组(kill(-pgid));子进程必须是组长
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
* accumulates text/thinking deltas and emits turn_diff snapshots (NOT
|
|
9
9
|
* assistant deltas — see handleAgentMessageChunk), plus question elicitation.
|
|
10
10
|
*
|
|
11
|
-
* Wire envelope (
|
|
11
|
+
* Wire envelope (source: kimi-code packages/acp-server/src/events-map.ts,
|
|
12
12
|
* verified live 2026-08-15/16 against kimi 0.36.0):
|
|
13
13
|
* session/update params = {sessionId, update: {sessionUpdate: '<kind>', ...}}
|
|
14
14
|
* — the discriminator is `update.sessionUpdate`, NOT a nested `event.type`.
|
|
15
15
|
*
|
|
16
|
-
* Event mapping
|
|
16
|
+
* Event mapping:
|
|
17
17
|
* agent_message_chunk → turn_diff text snapshot (content.text accumulation)
|
|
18
18
|
* agent_thought_chunk → turn_diff reasoning snapshot (content.text accumulation)
|
|
19
19
|
* tool_call / tool_call_update / usage_update / plan / control-plane noise →
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
* accumulates text/thinking deltas and emits turn_diff snapshots (NOT
|
|
9
9
|
* assistant deltas — see handleAgentMessageChunk), plus question elicitation.
|
|
10
10
|
*
|
|
11
|
-
* Wire envelope (
|
|
11
|
+
* Wire envelope (source: kimi-code packages/acp-server/src/events-map.ts,
|
|
12
12
|
* verified live 2026-08-15/16 against kimi 0.36.0):
|
|
13
13
|
* session/update params = {sessionId, update: {sessionUpdate: '<kind>', ...}}
|
|
14
14
|
* — the discriminator is `update.sessionUpdate`, NOT a nested `event.type`.
|
|
15
15
|
*
|
|
16
|
-
* Event mapping
|
|
16
|
+
* Event mapping:
|
|
17
17
|
* agent_message_chunk → turn_diff text snapshot (content.text accumulation)
|
|
18
18
|
* agent_thought_chunk → turn_diff reasoning snapshot (content.text accumulation)
|
|
19
19
|
* tool_call / tool_call_update / usage_update / plan / control-plane noise →
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import { makeQuestionApprovalEvent } from '../../question-common.js';
|
|
29
29
|
import { ServerRequestMethod, } from '../../common/acp/protocol-types.js';
|
|
30
|
-
import { deriveAcpAvailableDecisions, truncateWithEllipsis, } from '../../common/acp/
|
|
30
|
+
import { deriveAcpAvailableDecisions, truncateWithEllipsis, } from '../../common/acp/acp-approval.js';
|
|
31
31
|
import { getLogger } from '../../../logger/index.js';
|
|
32
32
|
import { BaseAcpTranslator } from '../../common/acp/base-translator.js';
|
|
33
33
|
/**
|
|
@@ -53,7 +53,7 @@ export class KimiAcpTranslator extends BaseAcpTranslator {
|
|
|
53
53
|
// Use a stable key for the current text stream. Kimi ACP doesn't
|
|
54
54
|
// provide an itemId in agent_message_chunk; we use 'text' as the
|
|
55
55
|
// single logical text accumulator (one text stream per turn).
|
|
56
|
-
//
|
|
56
|
+
// wire chunk text lives at content.text and is a DELTA
|
|
57
57
|
// (kimi-code events-map.ts assistantDeltaToSessionUpdate:
|
|
58
58
|
// content.text = event.delta), so we accumulate here into a full-text
|
|
59
59
|
// snapshot and emit it as turn_diff. The card reducer's turn_diff path
|
|
@@ -145,7 +145,7 @@ export class KimiAcpTranslator extends BaseAcpTranslator {
|
|
|
145
145
|
: summary
|
|
146
146
|
? truncateWithEllipsis(summary, 200)
|
|
147
147
|
: undefined,
|
|
148
|
-
//
|
|
148
|
+
// 从服务端 options kind 派生——带 approve_always(或 allow_always)
|
|
149
149
|
// 才提供「本会话总是允许」(acceptForSession);否则与旧行为一致。
|
|
150
150
|
availableDecisions: deriveAcpAvailableDecisions(params.options ?? []),
|
|
151
151
|
};
|
|
@@ -23,7 +23,7 @@ import type { AgentKind, AgentSessionReader, AgentStatusInfo } from '../../types
|
|
|
23
23
|
import { JsonRpcClient } from '../../common/jsonrpc/client.js';
|
|
24
24
|
import { OpencodeAcpTranslator } from './translator.js';
|
|
25
25
|
import { type SessionNewResult, type SessionResumeResult, type SessionPromptResult } from '../../common/acp/protocol-types.js';
|
|
26
|
-
import { type AcpPendingApproval } from '../../common/acp/
|
|
26
|
+
import { type AcpPendingApproval } from '../../common/acp/acp-approval.js';
|
|
27
27
|
import { BaseAcpRunner } from '../../common/acp/base-acp-runner.js';
|
|
28
28
|
export interface OpencodeAcpRunnerOptions {
|
|
29
29
|
kind: AgentKind;
|
|
@@ -34,7 +34,7 @@ export interface OpencodeAcpRunnerOptions {
|
|
|
34
34
|
env?: Record<string, string | undefined>;
|
|
35
35
|
/** Args to spawn the ACP server with. Defaults to `['acp']`. Note: no
|
|
36
36
|
* explicit `--cwd` — opencode acp defaults --cwd to the process cwd, which
|
|
37
|
-
* the transport already sets to the
|
|
37
|
+
* the transport already sets to the cwd (cli/cmd/acp.ts:13-17). */
|
|
38
38
|
acpArgs?: string[];
|
|
39
39
|
/** Request timeout in milliseconds. */
|
|
40
40
|
requestTimeoutMs?: number;
|
|
@@ -51,7 +51,7 @@ export interface OpencodeAcpRunnerOptions {
|
|
|
51
51
|
errorMonitorPollIntervalMs?: number;
|
|
52
52
|
}
|
|
53
53
|
export declare class OpencodeAcpRunner extends BaseAcpRunner<OpencodeAcpTranslator> {
|
|
54
|
-
/** Configured session mode applied via session/set_mode
|
|
54
|
+
/** Configured session mode applied via session/set_mode. */
|
|
55
55
|
private configuredMode;
|
|
56
56
|
/** Current session mode id, parsed from session/new|resume configOptions. */
|
|
57
57
|
private currentModeId?;
|
|
@@ -86,7 +86,7 @@ export declare class OpencodeAcpRunner extends BaseAcpRunner<OpencodeAcpTranslat
|
|
|
86
86
|
protected buildApprovalOutcome(action: string, pending: AcpPendingApproval, _response: unknown): unknown;
|
|
87
87
|
getStatusInfo(): AgentStatusInfo;
|
|
88
88
|
/**
|
|
89
|
-
* Hot-apply a mode change to the live ACP session
|
|
89
|
+
* Hot-apply a mode change to the live ACP session.
|
|
90
90
|
*
|
|
91
91
|
* opencode's session/set_mode sends no notification — the client refreshes
|
|
92
92
|
* the local mode view itself. The local mode is always updated so
|