lark-remote 0.5.13 → 0.5.15
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 +31 -0
- package/dist/agent-kinds.d.ts +27 -0
- package/dist/agent-kinds.js +38 -0
- package/dist/bridge/approval-actions.d.ts +95 -0
- package/dist/bridge/approval-actions.js +104 -0
- package/dist/bridge/approval-coordinator.d.ts +13 -0
- package/dist/bridge/approval-coordinator.js +18 -0
- package/dist/bridge/final-usage.d.ts +8 -17
- package/dist/bridge/final-usage.js +1 -18
- package/dist/bridge/index.d.ts +46 -39
- package/dist/bridge/index.js +269 -240
- package/dist/bridge/queue-manager.d.ts +25 -1
- package/dist/bridge/queue-manager.js +179 -160
- package/dist/bridge/run-approval.d.ts +2 -1
- package/dist/bridge/run-usage.d.ts +21 -30
- package/dist/bridge/run-usage.js +47 -51
- package/dist/bridge/session-writeback.d.ts +3 -2
- package/dist/card/approval-render.d.ts +3 -2
- package/dist/card/approval-render.js +3 -2
- package/dist/{router → card}/card-helpers.d.ts +7 -7
- package/dist/{router → card}/card-helpers.js +8 -8
- package/dist/card/card-session.d.ts +4 -2
- package/dist/card/card-session.js +8 -6
- package/dist/card/card-shared.d.ts +1 -1
- package/dist/card/card-shared.js +1 -1
- package/dist/card/final-answer-overflow.d.ts +0 -6
- package/dist/card/final-answer-overflow.js +1 -1
- package/dist/card/run-card-session.d.ts +2 -2
- package/dist/card/run-card-session.js +2 -2
- package/dist/card/run-renderer.js +29 -30
- package/dist/card/run-state.d.ts +28 -50
- package/dist/card/run-state.js +23 -0
- package/dist/card/usage-format.d.ts +30 -0
- package/dist/{router → card}/usage-format.js +3 -10
- package/dist/clone.js +6 -1
- package/dist/config/index.d.ts +16 -20
- package/dist/config/index.js +0 -16
- package/dist/config/pi-config.js +6 -4
- package/dist/connector/index.d.ts +2 -4
- package/dist/connector/index.js +7 -11
- package/dist/{runner/dsh → dsh}/auth.js +1 -1
- package/dist/dsh/protocol.d.ts +9 -0
- package/dist/dsh/protocol.js +61 -0
- package/dist/index.js +10 -5
- package/dist/model-catalog.d.ts +14 -0
- package/dist/model-catalog.js +25 -0
- package/dist/platform/path.d.ts +9 -0
- package/dist/platform/path.js +18 -0
- package/dist/router/active-run-usage.d.ts +4 -0
- package/dist/router/active-run-usage.js +12 -0
- package/dist/router/commands/ls.js +1 -1
- package/dist/router/commands/order.js +1 -1
- package/dist/router/commands/resume.d.ts +5 -4
- package/dist/router/commands/resume.js +4 -4
- package/dist/router/commands/ws.js +1 -1
- package/dist/router/config/claude.js +2 -1
- package/dist/router/config/common/render.d.ts +5 -1
- package/dist/router/config/common/render.js +6 -13
- package/dist/router/config/dsh.d.ts +1 -1
- package/dist/router/config/index.d.ts +1 -1
- package/dist/router/config/types.d.ts +11 -3
- package/dist/router/index.d.ts +41 -11
- package/dist/router/index.js +169 -233
- package/dist/runner/agent-choices-common.d.ts +1 -1
- package/dist/runner/claude/runner.d.ts +20 -2
- package/dist/runner/claude/runner.js +2 -15
- package/dist/runner/codex/app-server/runner.d.ts +3 -1
- package/dist/runner/codex/app-server/translator.d.ts +11 -0
- package/dist/runner/codex/app-server/translator.js +56 -149
- package/dist/runner/common/acp/base-acp-runner.d.ts +19 -1
- package/dist/runner/common/acp/base-acp-runner.js +37 -3
- package/dist/runner/common/connection-based-runner.d.ts +3 -1
- package/dist/runner/common/jsonrpc/transport.js +17 -7
- package/dist/runner/dsh/client.d.ts +1 -4
- package/dist/runner/dsh/client.js +7 -55
- package/dist/runner/dsh/daemon.js +9 -2
- package/dist/runner/dsh/exit-cancel.js +1 -1
- package/dist/runner/dsh/mux-stream.js +21 -2
- package/dist/runner/dsh/runner.d.ts +21 -1
- package/dist/runner/dsh/runner.js +97 -78
- package/dist/runner/dsh/translator.d.ts +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +22 -1
- package/dist/runner/kimi/acp/runner.js +83 -60
- package/dist/runner/opencode/acp/error-monitor.d.ts +11 -0
- package/dist/runner/opencode/acp/error-monitor.js +31 -2
- package/dist/runner/opencode/acp/runner.d.ts +14 -1
- package/dist/runner/opencode/acp/runner.js +13 -2
- package/dist/runner/pi/rpc/runner.d.ts +2 -1
- package/dist/runner/probe.d.ts +1 -1
- package/dist/runner/probe.js +10 -9
- package/dist/runner/registry.d.ts +2 -1
- package/dist/runner/types.d.ts +20 -154
- package/dist/runner/types.js +4 -24
- package/dist/session/claude/session-index.d.ts +11 -4
- package/dist/session/claude/session-index.js +30 -8
- package/dist/session/claude/session-reader.d.ts +1 -1
- package/dist/session/claude/sessions.d.ts +2 -2
- package/dist/session/claude/sessions.js +41 -26
- package/dist/session/codex/rollout-reader.d.ts +1 -1
- package/dist/session/codex/rollout-reader.js +14 -13
- package/dist/session/codex/sessions.d.ts +1 -1
- package/dist/session/codex/sessions.js +4 -2
- package/dist/session/common/jsonl.js +7 -1
- package/dist/session/common/pagination.d.ts +2 -0
- package/dist/session/common/pagination.js +1 -1
- package/dist/session/common/recency.d.ts +6 -0
- package/dist/session/common/recency.js +7 -5
- package/dist/session/common/two-pass.d.ts +1 -1
- package/dist/session/common/usage-accumulator.d.ts +1 -1
- package/dist/session/dsh/sessions.d.ts +1 -1
- package/dist/session/dsh/sessions.js +37 -12
- package/dist/session/kimi/sessions.d.ts +1 -1
- package/dist/session/kimi/sessions.js +72 -27
- package/dist/session/opencode/sessions.d.ts +1 -1
- package/dist/session/opencode/sessions.js +164 -81
- package/dist/session/pi/sessions.d.ts +1 -1
- package/dist/session/pi/sessions.js +20 -7
- package/dist/session/registry.d.ts +2 -1
- package/dist/session/session-store.d.ts +1 -2
- package/dist/session/session-store.js +14 -7
- package/dist/session-contract.d.ts +178 -0
- package/dist/session-contract.js +9 -0
- package/package.json +1 -1
- package/dist/router/usage-format.d.ts +0 -60
- /package/dist/{runner/dsh → dsh}/auth.d.ts +0 -0
- /package/dist/{runner/dsh → dsh}/home.d.ts +0 -0
- /package/dist/{runner/dsh → dsh}/home.js +0 -0
- /package/dist/{runner/dsh → dsh}/types.d.ts +0 -0
- /package/dist/{runner/dsh → dsh}/types.js +0 -0
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Claude Runner 实现
|
|
3
|
+
*
|
|
4
|
+
* ClaudeRunner 从「一次一跑」(claude -p <msg> --permission-mode
|
|
5
|
+
* bypassPermissions)升级为长驻交互会话(--input-format stream-json 双向
|
|
6
|
+
* 通道),同时复用本项目已有的 ApprovalCoordinator + run 卡审批区。
|
|
7
|
+
*
|
|
8
|
+
* 架构:ClaudeRunner 是 workspace-lifetime 的薄包装,进程与协议细节在
|
|
9
|
+
* ClaudeSession(src/runner/claude/session.ts,extends SpawningRunner 复用
|
|
10
|
+
* pid 文件/killOrphan/Terminator/心跳/退出分发器机制)。每次 run() 委托
|
|
11
|
+
* session:确保进程(可 --resume)→ 写 user 消息 → 消费事件直到本 turn result。
|
|
12
|
+
*/
|
|
13
|
+
import type { AgentSessionReader } from '../../session-contract.js';
|
|
14
|
+
import { type AgentEvent, type SpawnOptions, type AgentRunner, type AgentStatusInfo } from '../types.js';
|
|
2
15
|
/**
|
|
3
16
|
* Claude Agent Runner(长驻交互模式)。
|
|
4
17
|
*
|
|
@@ -23,7 +36,12 @@ export declare class ClaudeRunner implements AgentRunner {
|
|
|
23
36
|
pidDir?: string;
|
|
24
37
|
cwd: string;
|
|
25
38
|
spawnHeartbeatMs?: number;
|
|
26
|
-
|
|
39
|
+
/**
|
|
40
|
+
* 由组合根(`src/index.ts`)注入,与 sessionReaderRegistry 里的**同一个**实例。
|
|
41
|
+
* claude 不在此处自己 new:那会让 runner 反向依赖 session 层(runner ↔ session
|
|
42
|
+
* 循环的一半);其余 agent 从一开始就是注入的。
|
|
43
|
+
*/
|
|
44
|
+
sessionReader: AgentSessionReader;
|
|
27
45
|
/** Claude 权限模式(官方 --permission-mode 枚举;'default'=省略参数)。 */
|
|
28
46
|
permissionMode?: string;
|
|
29
47
|
/** 会话级空闲回收 TTL(ms);0=禁用。 */
|
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Runner 实现
|
|
3
|
-
*
|
|
4
|
-
* ClaudeRunner 从「一次一跑」(claude -p <msg> --permission-mode
|
|
5
|
-
* bypassPermissions)升级为长驻交互会话(--input-format stream-json 双向
|
|
6
|
-
* 通道),同时复用本项目已有的 ApprovalCoordinator + run 卡审批区。
|
|
7
|
-
*
|
|
8
|
-
* 架构:ClaudeRunner 是 workspace-lifetime 的薄包装,进程与协议细节在
|
|
9
|
-
* ClaudeSession(src/runner/claude/session.ts,extends SpawningRunner 复用
|
|
10
|
-
* pid 文件/killOrphan/Terminator/心跳/退出分发器机制)。每次 run() 委托
|
|
11
|
-
* session:确保进程(可 --resume)→ 写 user 消息 → 消费事件直到本 turn result。
|
|
12
|
-
*/
|
|
13
|
-
import { ClaudeSessionReader } from '../../session/claude/index.js';
|
|
14
1
|
import { ClaudeSession } from './session.js';
|
|
15
|
-
import { MODEL_ID_TO_ALIAS } from '../../
|
|
2
|
+
import { MODEL_ID_TO_ALIAS } from '../../model-catalog.js';
|
|
16
3
|
/**
|
|
17
4
|
* Claude 内建压缩命令。stream-json 输入模式下该文本会被 CLI 本地拦截为
|
|
18
5
|
* slash 命令(不会作为模型提示词转发),压缩 turn 以普通 result 收尾
|
|
@@ -40,7 +27,7 @@ export class ClaudeRunner {
|
|
|
40
27
|
this.defaultModel = opts.model ?? 'claude-opus-4-8';
|
|
41
28
|
this.defaultEffort = opts.effort ?? 'medium';
|
|
42
29
|
this.permissionMode = opts.permissionMode ?? 'auto';
|
|
43
|
-
this.sessionReader = opts.sessionReader
|
|
30
|
+
this.sessionReader = opts.sessionReader;
|
|
44
31
|
this.session = new ClaudeSession({
|
|
45
32
|
pidDir: opts.pidDir,
|
|
46
33
|
cwd: opts.cwd,
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* queue + waitResolve pump, forceFinish/stopRequested semantics, turn idle
|
|
11
11
|
* watchdog, and ConnectionLostError respawn-and-retry-once.
|
|
12
12
|
*/
|
|
13
|
-
import type { AgentKind
|
|
13
|
+
import type { AgentKind } from '../../../agent-kinds.js';
|
|
14
|
+
import type { AgentSessionReader } from '../../../session-contract.js';
|
|
15
|
+
import type { AgentEvent, AgentStatusInfo, SpawnOptions } from '../../types.js';
|
|
14
16
|
import { JsonRpcClient } from '../../common/jsonrpc/client.js';
|
|
15
17
|
import { type TranslatorEvent } from './translator.js';
|
|
16
18
|
import { type AskForApproval, type SandboxMode, type InitializeResult } from './protocol-types.js';
|
|
@@ -105,6 +105,17 @@ export declare class CodexAppServerTranslator {
|
|
|
105
105
|
private handleCommandApproval;
|
|
106
106
|
private handleFileApproval;
|
|
107
107
|
private handleItemStarted;
|
|
108
|
+
/**
|
|
109
|
+
* turn_diff 的统一信封:`type` + threadId/turnId/timestamp 三个公共字段在此
|
|
110
|
+
* 一次装配(十余个构造点原本各抄一遍,还得挂 `as TurnDiffEvent`)。
|
|
111
|
+
*/
|
|
112
|
+
private turnDiffEvent;
|
|
113
|
+
/**
|
|
114
|
+
* 工具型 item 的 started 处理(commandExecution / webSearch / mcpToolCall /
|
|
115
|
+
* dynamicToolCall 四个分支同形):登记「已开始」锚点 + 记录工具身份 meta,
|
|
116
|
+
* 再发一帧空的 turn_diff 把工具块按真实时序插进卡片。
|
|
117
|
+
*/
|
|
118
|
+
private beginToolItem;
|
|
108
119
|
private handlePermissionsApproval;
|
|
109
120
|
private buildPermissionItems;
|
|
110
121
|
/** Get (or lazily create) the reasoning accumulator for one item. */
|
|
@@ -152,15 +152,10 @@ export class CodexAppServerTranslator {
|
|
|
152
152
|
complete: true,
|
|
153
153
|
timestamp: this.now(),
|
|
154
154
|
}
|
|
155
|
-
: {
|
|
156
|
-
type: 'turn_diff',
|
|
157
|
-
text,
|
|
158
|
-
itemId: item.id,
|
|
159
|
-
complete: true,
|
|
155
|
+
: this.turnDiffEvent({
|
|
160
156
|
threadId: params?.threadId ?? this.threadId,
|
|
161
157
|
turnId: params?.turn?.id ?? this.turnId,
|
|
162
|
-
|
|
163
|
-
});
|
|
158
|
+
}, { text, itemId: item.id, complete: true }));
|
|
164
159
|
}
|
|
165
160
|
}
|
|
166
161
|
else if (item.type === 'plan') {
|
|
@@ -169,15 +164,10 @@ export class CodexAppServerTranslator {
|
|
|
169
164
|
const planText = item.text ?? '';
|
|
170
165
|
if (planText && this.planByItem.get(item.id) !== planText) {
|
|
171
166
|
this.planByItem.set(item.id, planText);
|
|
172
|
-
events.push({
|
|
173
|
-
type: 'turn_diff',
|
|
174
|
-
plan: planText,
|
|
175
|
-
itemId: item.id,
|
|
176
|
-
complete: true,
|
|
167
|
+
events.push(this.turnDiffEvent({
|
|
177
168
|
threadId: params?.threadId ?? this.threadId,
|
|
178
169
|
turnId: params?.turn?.id ?? this.turnId,
|
|
179
|
-
|
|
180
|
-
});
|
|
170
|
+
}, { plan: planText, itemId: item.id, complete: true }));
|
|
181
171
|
}
|
|
182
172
|
}
|
|
183
173
|
}
|
|
@@ -272,30 +262,17 @@ export class CodexAppServerTranslator {
|
|
|
272
262
|
},
|
|
273
263
|
];
|
|
274
264
|
}
|
|
275
|
-
return [
|
|
276
|
-
{
|
|
277
|
-
type: 'turn_diff',
|
|
278
|
-
text: next,
|
|
279
|
-
itemId: params.itemId,
|
|
280
|
-
threadId: params.threadId,
|
|
281
|
-
turnId: params.turnId,
|
|
282
|
-
timestamp: this.now(),
|
|
283
|
-
},
|
|
284
|
-
];
|
|
265
|
+
return [this.turnDiffEvent(params, { text: next, itemId: params.itemId })];
|
|
285
266
|
}
|
|
286
267
|
handleReasoningDelta(params) {
|
|
287
268
|
// summaryTextDelta 流的是摘要文本;与 content 段落分开累积,避免段落交错。
|
|
288
269
|
const entry = this.reasoningEntry(params.itemId);
|
|
289
270
|
entry.summary += params.delta;
|
|
290
271
|
return [
|
|
291
|
-
{
|
|
292
|
-
type: 'turn_diff',
|
|
272
|
+
this.turnDiffEvent(params, {
|
|
293
273
|
reasoning: this.reasoningSnapshotFor(entry),
|
|
294
274
|
itemId: params.itemId,
|
|
295
|
-
|
|
296
|
-
turnId: params.turnId,
|
|
297
|
-
timestamp: this.now(),
|
|
298
|
-
},
|
|
275
|
+
}),
|
|
299
276
|
];
|
|
300
277
|
}
|
|
301
278
|
handleReasoningPartAdded() {
|
|
@@ -310,15 +287,11 @@ export class CodexAppServerTranslator {
|
|
|
310
287
|
// 权威文件变更(含聚合后的 diff);以快照语义替换本 item 的变更列表。
|
|
311
288
|
this.fileChangeItems.set(item.id, item.changes);
|
|
312
289
|
return [
|
|
313
|
-
{
|
|
314
|
-
type: 'turn_diff',
|
|
290
|
+
this.turnDiffEvent(params, {
|
|
315
291
|
fileChanges: normalizeFileChanges(item.changes),
|
|
316
292
|
itemId: item.id,
|
|
317
293
|
complete: true,
|
|
318
|
-
|
|
319
|
-
turnId: params.turnId,
|
|
320
|
-
timestamp: this.now(),
|
|
321
|
-
},
|
|
294
|
+
}),
|
|
322
295
|
];
|
|
323
296
|
}
|
|
324
297
|
if (item.type === 'reasoning') {
|
|
@@ -330,15 +303,11 @@ export class CodexAppServerTranslator {
|
|
|
330
303
|
entry.content = new Map(content.map((c, i) => [i, c]));
|
|
331
304
|
entry.summary = summary.join('\n');
|
|
332
305
|
return [
|
|
333
|
-
{
|
|
334
|
-
type: 'turn_diff',
|
|
306
|
+
this.turnDiffEvent(params, {
|
|
335
307
|
reasoning: this.reasoningSnapshotFor(entry),
|
|
336
308
|
itemId: item.id,
|
|
337
309
|
complete: true,
|
|
338
|
-
|
|
339
|
-
turnId: params.turnId,
|
|
340
|
-
timestamp: this.now(),
|
|
341
|
-
},
|
|
310
|
+
}),
|
|
342
311
|
];
|
|
343
312
|
}
|
|
344
313
|
}
|
|
@@ -358,17 +327,13 @@ export class CodexAppServerTranslator {
|
|
|
358
327
|
const meta = this.toolItemMeta.get(item.id);
|
|
359
328
|
this.toolItemMeta.delete(item.id);
|
|
360
329
|
return [
|
|
361
|
-
{
|
|
362
|
-
type: 'turn_diff',
|
|
330
|
+
this.turnDiffEvent(params, {
|
|
363
331
|
toolOutput: authoritative,
|
|
364
332
|
...meta,
|
|
365
333
|
itemId: item.id,
|
|
366
334
|
complete: true,
|
|
367
335
|
toolStatus: commandExecutionStatusToToolStatus(item.status),
|
|
368
|
-
|
|
369
|
-
turnId: params.turnId,
|
|
370
|
-
timestamp: this.now(),
|
|
371
|
-
},
|
|
336
|
+
}),
|
|
372
337
|
];
|
|
373
338
|
}
|
|
374
339
|
if (item.type === 'agentMessage') {
|
|
@@ -395,15 +360,11 @@ export class CodexAppServerTranslator {
|
|
|
395
360
|
];
|
|
396
361
|
}
|
|
397
362
|
return [
|
|
398
|
-
{
|
|
399
|
-
type: 'turn_diff',
|
|
363
|
+
this.turnDiffEvent(params, {
|
|
400
364
|
text: finalText,
|
|
401
365
|
itemId: item.id,
|
|
402
366
|
complete: true,
|
|
403
|
-
|
|
404
|
-
turnId: params.turnId,
|
|
405
|
-
timestamp: this.now(),
|
|
406
|
-
},
|
|
367
|
+
}),
|
|
407
368
|
];
|
|
408
369
|
}
|
|
409
370
|
}
|
|
@@ -412,15 +373,11 @@ export class CodexAppServerTranslator {
|
|
|
412
373
|
if (text) {
|
|
413
374
|
this.planByItem.set(item.id, text);
|
|
414
375
|
return [
|
|
415
|
-
{
|
|
416
|
-
type: 'turn_diff',
|
|
376
|
+
this.turnDiffEvent(params, {
|
|
417
377
|
plan: text,
|
|
418
378
|
itemId: item.id,
|
|
419
379
|
complete: true,
|
|
420
|
-
|
|
421
|
-
turnId: params.turnId,
|
|
422
|
-
timestamp: this.now(),
|
|
423
|
-
},
|
|
380
|
+
}),
|
|
424
381
|
];
|
|
425
382
|
}
|
|
426
383
|
}
|
|
@@ -432,16 +389,12 @@ export class CodexAppServerTranslator {
|
|
|
432
389
|
this.toolItemMeta.delete(item.id);
|
|
433
390
|
this.startedToolItems.delete(item.id);
|
|
434
391
|
return [
|
|
435
|
-
{
|
|
436
|
-
type: 'turn_diff',
|
|
392
|
+
this.turnDiffEvent(params, {
|
|
437
393
|
toolOutput: this.toolOutputByItem.get(item.id) ?? '',
|
|
438
394
|
...meta,
|
|
439
395
|
itemId: item.id,
|
|
440
396
|
complete: true,
|
|
441
|
-
|
|
442
|
-
turnId: params.turnId,
|
|
443
|
-
timestamp: this.now(),
|
|
444
|
-
},
|
|
397
|
+
}),
|
|
445
398
|
];
|
|
446
399
|
}
|
|
447
400
|
return [];
|
|
@@ -452,14 +405,10 @@ export class CodexAppServerTranslator {
|
|
|
452
405
|
const prev = entry.content.get(index) ?? '';
|
|
453
406
|
entry.content.set(index, prev + params.delta);
|
|
454
407
|
return [
|
|
455
|
-
{
|
|
456
|
-
type: 'turn_diff',
|
|
408
|
+
this.turnDiffEvent(params, {
|
|
457
409
|
reasoning: this.reasoningSnapshotFor(entry),
|
|
458
410
|
itemId: params.itemId,
|
|
459
|
-
|
|
460
|
-
turnId: params.turnId,
|
|
461
|
-
timestamp: this.now(),
|
|
462
|
-
},
|
|
411
|
+
}),
|
|
463
412
|
];
|
|
464
413
|
}
|
|
465
414
|
handleCommandOutputDelta(params) {
|
|
@@ -467,15 +416,11 @@ export class CodexAppServerTranslator {
|
|
|
467
416
|
const next = prev + params.delta;
|
|
468
417
|
this.toolOutputByItem.set(params.itemId, next);
|
|
469
418
|
return [
|
|
470
|
-
{
|
|
471
|
-
type: 'turn_diff',
|
|
419
|
+
this.turnDiffEvent(params, {
|
|
472
420
|
toolOutput: next,
|
|
473
421
|
...this.toolItemMeta.get(params.itemId),
|
|
474
422
|
itemId: params.itemId,
|
|
475
|
-
|
|
476
|
-
turnId: params.turnId,
|
|
477
|
-
timestamp: this.now(),
|
|
478
|
-
},
|
|
423
|
+
}),
|
|
479
424
|
];
|
|
480
425
|
}
|
|
481
426
|
handlePlanUpdated(params) {
|
|
@@ -485,14 +430,10 @@ export class CodexAppServerTranslator {
|
|
|
485
430
|
const next = prev + params.delta;
|
|
486
431
|
this.planByItem.set(params.itemId, next);
|
|
487
432
|
return [
|
|
488
|
-
{
|
|
489
|
-
type: 'turn_diff',
|
|
433
|
+
this.turnDiffEvent(params, {
|
|
490
434
|
plan: next,
|
|
491
435
|
itemId: params.itemId,
|
|
492
|
-
|
|
493
|
-
turnId: params.turnId,
|
|
494
|
-
timestamp: this.now(),
|
|
495
|
-
},
|
|
436
|
+
}),
|
|
496
437
|
];
|
|
497
438
|
}
|
|
498
439
|
handleTokenUsageUpdated(params) {
|
|
@@ -705,112 +646,78 @@ export class CodexAppServerTranslator {
|
|
|
705
646
|
view: { ...pending.view, fileChanges },
|
|
706
647
|
timestamp: new Date().toISOString(),
|
|
707
648
|
},
|
|
708
|
-
{
|
|
709
|
-
type: 'turn_diff',
|
|
649
|
+
this.turnDiffEvent(params, {
|
|
710
650
|
fileChanges,
|
|
711
651
|
itemId: item.id,
|
|
712
|
-
|
|
713
|
-
turnId: params.turnId,
|
|
714
|
-
timestamp: this.now(),
|
|
715
|
-
},
|
|
652
|
+
}),
|
|
716
653
|
];
|
|
717
654
|
}
|
|
718
655
|
}
|
|
719
656
|
return [
|
|
720
|
-
{
|
|
721
|
-
type: 'turn_diff',
|
|
657
|
+
this.turnDiffEvent(params, {
|
|
722
658
|
fileChanges: normalizeFileChanges(item.changes),
|
|
723
659
|
itemId: item.id,
|
|
724
|
-
|
|
725
|
-
turnId: params.turnId,
|
|
726
|
-
timestamp: this.now(),
|
|
727
|
-
},
|
|
660
|
+
}),
|
|
728
661
|
];
|
|
729
662
|
}
|
|
730
663
|
if (item.type === 'commandExecution') {
|
|
731
664
|
// item/started 锚定工具块位置(真实时序):命令开始时即创建工具块,
|
|
732
665
|
// 而不是等到首个输出 delta——否则后续 reasoning item 会插到 command 之前。
|
|
733
|
-
this.
|
|
734
|
-
// 信息保真 记录工具身份,随 turn_diff 透传(run-state 首见时写入)。
|
|
735
|
-
this.toolItemMeta.set(item.id, {
|
|
666
|
+
return this.beginToolItem(item.id, params, {
|
|
736
667
|
toolName: 'Bash',
|
|
737
668
|
toolInput: { command: item.command, ...(item.cwd ? { cwd: item.cwd } : {}) },
|
|
738
669
|
toolHint: 'shell',
|
|
739
670
|
});
|
|
740
|
-
return [
|
|
741
|
-
{
|
|
742
|
-
type: 'turn_diff',
|
|
743
|
-
toolOutput: '',
|
|
744
|
-
...this.toolItemMeta.get(item.id),
|
|
745
|
-
itemId: item.id,
|
|
746
|
-
threadId: params.threadId,
|
|
747
|
-
turnId: params.turnId,
|
|
748
|
-
timestamp: this.now(),
|
|
749
|
-
},
|
|
750
|
-
];
|
|
751
671
|
}
|
|
752
672
|
if (item.type === 'webSearch') {
|
|
753
|
-
this.
|
|
754
|
-
this.toolItemMeta.set(item.id, {
|
|
673
|
+
return this.beginToolItem(item.id, params, {
|
|
755
674
|
toolName: 'WebSearch',
|
|
756
675
|
toolInput: { query: item.query },
|
|
757
676
|
toolHint: 'web',
|
|
758
677
|
});
|
|
759
|
-
return [
|
|
760
|
-
{
|
|
761
|
-
type: 'turn_diff',
|
|
762
|
-
toolOutput: '',
|
|
763
|
-
...this.toolItemMeta.get(item.id),
|
|
764
|
-
itemId: item.id,
|
|
765
|
-
threadId: params.threadId,
|
|
766
|
-
turnId: params.turnId,
|
|
767
|
-
timestamp: this.now(),
|
|
768
|
-
},
|
|
769
|
-
];
|
|
770
678
|
}
|
|
771
679
|
if (item.type === 'mcpToolCall') {
|
|
772
680
|
// ThreadItem union 含 catch-all 成员,判别收窄会与泛型成员并集;
|
|
773
681
|
// 显式断言到具体 interface(字段名已经 v2 schema 确认)。
|
|
774
682
|
const mcpItem = item;
|
|
775
|
-
this.
|
|
776
|
-
this.toolItemMeta.set(item.id, {
|
|
683
|
+
return this.beginToolItem(item.id, params, {
|
|
777
684
|
toolName: `mcp__${mcpItem.server}__${mcpItem.tool}`,
|
|
778
685
|
toolInput: mcpItem.arguments ?? {},
|
|
779
686
|
toolHint: 'search',
|
|
780
687
|
});
|
|
781
|
-
return [
|
|
782
|
-
{
|
|
783
|
-
type: 'turn_diff',
|
|
784
|
-
toolOutput: '',
|
|
785
|
-
...this.toolItemMeta.get(item.id),
|
|
786
|
-
itemId: item.id,
|
|
787
|
-
threadId: params.threadId,
|
|
788
|
-
turnId: params.turnId,
|
|
789
|
-
timestamp: this.now(),
|
|
790
|
-
},
|
|
791
|
-
];
|
|
792
688
|
}
|
|
793
689
|
if (item.type === 'dynamicToolCall') {
|
|
794
690
|
const dynItem = item;
|
|
795
|
-
this.
|
|
796
|
-
this.toolItemMeta.set(item.id, {
|
|
691
|
+
return this.beginToolItem(item.id, params, {
|
|
797
692
|
toolName: dynItem.tool,
|
|
798
693
|
toolInput: dynItem.arguments ?? {},
|
|
799
694
|
});
|
|
800
|
-
return [
|
|
801
|
-
{
|
|
802
|
-
type: 'turn_diff',
|
|
803
|
-
toolOutput: '',
|
|
804
|
-
...this.toolItemMeta.get(item.id),
|
|
805
|
-
itemId: item.id,
|
|
806
|
-
threadId: params.threadId,
|
|
807
|
-
turnId: params.turnId,
|
|
808
|
-
timestamp: this.now(),
|
|
809
|
-
},
|
|
810
|
-
];
|
|
811
695
|
}
|
|
812
696
|
return [];
|
|
813
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* turn_diff 的统一信封:`type` + threadId/turnId/timestamp 三个公共字段在此
|
|
700
|
+
* 一次装配(十余个构造点原本各抄一遍,还得挂 `as TurnDiffEvent`)。
|
|
701
|
+
*/
|
|
702
|
+
turnDiffEvent(ids, fields) {
|
|
703
|
+
return {
|
|
704
|
+
type: 'turn_diff',
|
|
705
|
+
...fields,
|
|
706
|
+
threadId: ids.threadId,
|
|
707
|
+
turnId: ids.turnId,
|
|
708
|
+
timestamp: this.now(),
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* 工具型 item 的 started 处理(commandExecution / webSearch / mcpToolCall /
|
|
713
|
+
* dynamicToolCall 四个分支同形):登记「已开始」锚点 + 记录工具身份 meta,
|
|
714
|
+
* 再发一帧空的 turn_diff 把工具块按真实时序插进卡片。
|
|
715
|
+
*/
|
|
716
|
+
beginToolItem(itemId, params, meta) {
|
|
717
|
+
this.startedToolItems.add(itemId);
|
|
718
|
+
this.toolItemMeta.set(itemId, meta);
|
|
719
|
+
return [this.turnDiffEvent(params, { toolOutput: '', ...meta, itemId })];
|
|
720
|
+
}
|
|
814
721
|
handlePermissionsApproval(requestId, params) {
|
|
815
722
|
const permItems = this.buildPermissionItems(params.permissions);
|
|
816
723
|
const view = {
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
* Bash notifications and serves terminal/* reverse RPC; opencode is plain
|
|
19
19
|
* - getStatusInfo / updateApprovalMode: agent-specific extras & mode vocab
|
|
20
20
|
*/
|
|
21
|
-
import type {
|
|
21
|
+
import type { AgentKind } from '../../../agent-kinds.js';
|
|
22
|
+
import type { AgentSessionReader } from '../../../session-contract.js';
|
|
23
|
+
import type { AgentEvent, SpawnOptions } from '../../types.js';
|
|
22
24
|
import { ConnectionManager } from '../jsonrpc/connection-manager.js';
|
|
23
25
|
import { JsonRpcClient } from '../jsonrpc/client.js';
|
|
24
26
|
import { type SessionNewResult, type SessionResumeResult, type SessionPromptResult, type RequestPermissionParams } from './protocol-types.js';
|
|
@@ -71,6 +73,22 @@ export declare abstract class BaseAcpRunner<TTranslator extends BaseAcpTranslato
|
|
|
71
73
|
*/
|
|
72
74
|
protected abstract onCompactPromptFired(promptPromise: Promise<SessionPromptResult>, translator: TTranslator, sessionId: string, opts: SpawnOptions, baselineTotalCount: number): void;
|
|
73
75
|
private withSessionSetupRetry;
|
|
76
|
+
/**
|
|
77
|
+
* 建立会话(session/new|resume),重试耗尽后丢弃该 cwd 缓存的连接。
|
|
78
|
+
*
|
|
79
|
+
* 「服务端未就绪」类错误(isRetryableSessionSetupError)说明这个 agent server
|
|
80
|
+
* 自身半死:opencode v2 的 location 在每轮拉起的 `opencode acp` 子进程里 boot,
|
|
81
|
+
* boot 期间后台服务不可用会让它长期停在未激活,后续轮次复用同一连接只会重复
|
|
82
|
+
* 失败——用户重启 opencode service 也治不好,因为连接缓存在本进程里
|
|
83
|
+
* (2026-10-30 现场:4 次重试全失败,重启服务与 lark-remote 都无效)。丢掉连接
|
|
84
|
+
* 后下一轮重新 spawn,拿到的是新进程的新状态。
|
|
85
|
+
*
|
|
86
|
+
* 只对声明为可重试的错误生效:kimi 等沿用默认 `isRetryableSessionSetupError`
|
|
87
|
+
* = false,行为不变(session id 不存在之类的确定性失败不踢连接)。
|
|
88
|
+
*/
|
|
89
|
+
private setupSessionWithRetry;
|
|
90
|
+
/** Dispose the cached connection for `cwd`; never mask the setup error. */
|
|
91
|
+
private discardConnection;
|
|
74
92
|
protected currentSessionId(): string | null;
|
|
75
93
|
protected cancelCurrentTurn(): Promise<void>;
|
|
76
94
|
protected clearTurnState(): void;
|
|
@@ -58,6 +58,40 @@ export class BaseAcpRunner extends ConnectionBasedRunner {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* 建立会话(session/new|resume),重试耗尽后丢弃该 cwd 缓存的连接。
|
|
63
|
+
*
|
|
64
|
+
* 「服务端未就绪」类错误(isRetryableSessionSetupError)说明这个 agent server
|
|
65
|
+
* 自身半死:opencode v2 的 location 在每轮拉起的 `opencode acp` 子进程里 boot,
|
|
66
|
+
* boot 期间后台服务不可用会让它长期停在未激活,后续轮次复用同一连接只会重复
|
|
67
|
+
* 失败——用户重启 opencode service 也治不好,因为连接缓存在本进程里
|
|
68
|
+
* (2026-10-30 现场:4 次重试全失败,重启服务与 lark-remote 都无效)。丢掉连接
|
|
69
|
+
* 后下一轮重新 spawn,拿到的是新进程的新状态。
|
|
70
|
+
*
|
|
71
|
+
* 只对声明为可重试的错误生效:kimi 等沿用默认 `isRetryableSessionSetupError`
|
|
72
|
+
* = false,行为不变(session id 不存在之类的确定性失败不踢连接)。
|
|
73
|
+
*/
|
|
74
|
+
async setupSessionWithRetry(cwd, fn) {
|
|
75
|
+
try {
|
|
76
|
+
return await this.withSessionSetupRetry(fn);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
if (this.isRetryableSessionSetupError(err)) {
|
|
80
|
+
await this.discardConnection(cwd);
|
|
81
|
+
}
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Dispose the cached connection for `cwd`; never mask the setup error. */
|
|
86
|
+
async discardConnection(cwd) {
|
|
87
|
+
try {
|
|
88
|
+
await this.connectionManager.release(cwd);
|
|
89
|
+
getLogger().warn(`[${this.logTag}] dropped cached connection after session setup failure cwd=${cwd}`);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
getLogger().warn(`[${this.logTag}] failed to drop cached connection cwd=${cwd}: ${err.message}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
61
95
|
currentSessionId() {
|
|
62
96
|
return this.activeSessionId;
|
|
63
97
|
}
|
|
@@ -203,13 +237,13 @@ export class BaseAcpRunner extends ConnectionBasedRunner {
|
|
|
203
237
|
sessionId: opts.sessionId,
|
|
204
238
|
cwd: opts.cwd,
|
|
205
239
|
};
|
|
206
|
-
const resumeResult = await this.
|
|
240
|
+
const resumeResult = await this.setupSessionWithRetry(opts.cwd, () => client.request('session/resume', resumeParams));
|
|
207
241
|
this.onSessionEstablished(resumeResult);
|
|
208
242
|
sessionId = opts.sessionId;
|
|
209
243
|
}
|
|
210
244
|
else {
|
|
211
245
|
const newParams = { cwd: opts.cwd, mcpServers: [] };
|
|
212
|
-
const newResult = await this.
|
|
246
|
+
const newResult = await this.setupSessionWithRetry(opts.cwd, () => client.request('session/new', newParams));
|
|
213
247
|
this.onSessionEstablished(newResult);
|
|
214
248
|
sessionId = newResult.sessionId;
|
|
215
249
|
}
|
|
@@ -286,7 +320,7 @@ export class BaseAcpRunner extends ConnectionBasedRunner {
|
|
|
286
320
|
// memory. On a reused connection the session is already loaded —
|
|
287
321
|
// resume is idempotent and harmless.
|
|
288
322
|
const resumeParams = { sessionId, cwd: opts.cwd };
|
|
289
|
-
const resumeResult = await this.
|
|
323
|
+
const resumeResult = await this.setupSessionWithRetry(opts.cwd, () => client.request('session/resume', resumeParams));
|
|
290
324
|
this.onSessionEstablished(resumeResult);
|
|
291
325
|
const translator = this.createTranslator();
|
|
292
326
|
translator.setOperationKind('compact');
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* handleNotification/handleServerRequest, respondApproval, pendingApprovals,
|
|
15
15
|
* updateApprovalMode, getStatusInfo) and provide the small abstract hooks below.
|
|
16
16
|
*/
|
|
17
|
-
import type { AgentKind
|
|
17
|
+
import type { AgentKind } from '../../agent-kinds.js';
|
|
18
|
+
import type { AgentSessionReader } from '../../session-contract.js';
|
|
19
|
+
import type { AgentEvent, AgentRunner, AgentStatusInfo, SpawnOptions } from '../types.js';
|
|
18
20
|
import type { AgentStopper } from '../../platform/agent-stopper.js';
|
|
19
21
|
export declare abstract class ConnectionBasedRunner<TClient, TEvent = AgentEvent> implements AgentRunner {
|
|
20
22
|
readonly kind: AgentKind;
|
|
@@ -12,6 +12,10 @@ import { binaryName } from '../../../platform/identity.js';
|
|
|
12
12
|
import { createTerminator } from '../../../platform/terminator.js';
|
|
13
13
|
import { agentStopperRegistry, } from '../../../platform/agent-stopper.js';
|
|
14
14
|
import { getLogger } from '../../../logger/index.js';
|
|
15
|
+
/** 日志用的错误摘要(onClose 的 reason 仍是稳定分类码)。 */
|
|
16
|
+
function describeErr(err) {
|
|
17
|
+
return err instanceof Error ? err.message : String(err);
|
|
18
|
+
}
|
|
15
19
|
/** Max bytes for a single line before we disconnect (10MB). */
|
|
16
20
|
const MAX_LINE_BYTES = 10 * 1024 * 1024;
|
|
17
21
|
/** Max bytes retained from stderr for diagnostics (64KB). */
|
|
@@ -205,8 +209,8 @@ export class JsonlRpcTransport {
|
|
|
205
209
|
this.writeQueue.push(Buffer.from(JSON.stringify(msg) + '\n', 'utf8'));
|
|
206
210
|
this.flush();
|
|
207
211
|
}
|
|
208
|
-
catch {
|
|
209
|
-
this.handleClose('epipe');
|
|
212
|
+
catch (err) {
|
|
213
|
+
this.handleClose('epipe', describeErr(err));
|
|
210
214
|
}
|
|
211
215
|
}
|
|
212
216
|
/** Send queued lines to stdin, pausing on backpressure until drain. */
|
|
@@ -229,7 +233,7 @@ export class JsonlRpcTransport {
|
|
|
229
233
|
try {
|
|
230
234
|
const ok = stdin.write(chunk, (err) => {
|
|
231
235
|
if (err) {
|
|
232
|
-
this.handleClose('epipe');
|
|
236
|
+
this.handleClose('epipe', describeErr(err));
|
|
233
237
|
}
|
|
234
238
|
});
|
|
235
239
|
if (!ok) {
|
|
@@ -240,8 +244,8 @@ export class JsonlRpcTransport {
|
|
|
240
244
|
next();
|
|
241
245
|
}
|
|
242
246
|
}
|
|
243
|
-
catch {
|
|
244
|
-
this.handleClose('epipe');
|
|
247
|
+
catch (err) {
|
|
248
|
+
this.handleClose('epipe', describeErr(err));
|
|
245
249
|
}
|
|
246
250
|
};
|
|
247
251
|
next();
|
|
@@ -288,10 +292,11 @@ export class JsonlRpcTransport {
|
|
|
288
292
|
this.registration = null;
|
|
289
293
|
this.stoppers.unregister(this.agent, reg.pid, reg.stopper);
|
|
290
294
|
}
|
|
291
|
-
handleClose(reason) {
|
|
295
|
+
handleClose(reason, detail) {
|
|
292
296
|
if (this._closed)
|
|
293
297
|
return;
|
|
294
298
|
this._closed = true;
|
|
299
|
+
const dropped = this.writeQueue.length;
|
|
295
300
|
this.writeQueue = [];
|
|
296
301
|
// Remove the exit listener to avoid double-firing
|
|
297
302
|
if (this.proc) {
|
|
@@ -319,7 +324,12 @@ export class JsonlRpcTransport {
|
|
|
319
324
|
// 统一关闭出口:EPIPE/超长行/进程 error 都必须通知上层(connection-manager
|
|
320
325
|
// 靠 onClose 删除 slot、client 靠它 failPending),否则 slot 悬挂死连接。
|
|
321
326
|
this.events?.onClose(reason);
|
|
322
|
-
|
|
327
|
+
// reason 是给上层的稳定分类码;原始 err 与被丢弃的排队条数只进日志,
|
|
328
|
+
// 否则「stdin 写失败」到底写了什么、丢了什么都查不出来。
|
|
329
|
+
const suffix = [detail, dropped > 0 ? `${dropped} queued message(s) dropped` : undefined]
|
|
330
|
+
.filter(Boolean)
|
|
331
|
+
.join('; ');
|
|
332
|
+
getLogger().info(`[jsonrpc-transport] closed: ${reason}${suffix ? ` (${suffix})` : ''}`);
|
|
323
333
|
}
|
|
324
334
|
}
|
|
325
335
|
//# sourceMappingURL=transport.js.map
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* `sessionEvents()` adds per-session filtering, reconnect + follow-snapshot
|
|
20
20
|
* replay, and seq-based dedup.
|
|
21
21
|
*/
|
|
22
|
-
import type { DshApprovalStreamItem, DshCommandResult, DshModelCatalogValue, DshModelSelection, DshOpenTurnState, DshPermissionCatalogValue, DshJobView, DshPresetListValue, DshProjectionItem, DshProjectionSnapshot, DshQuestion, DshRemoteEventOutcome, DshSessionPageValue, DshStreamItem, DshTokenUsage } from '
|
|
22
|
+
import type { DshApprovalStreamItem, DshCommandResult, DshModelCatalogValue, DshModelSelection, DshOpenTurnState, DshPermissionCatalogValue, DshJobView, DshPresetListValue, DshProjectionItem, DshProjectionSnapshot, DshQuestion, DshRemoteEventOutcome, DshSessionPageValue, DshStreamItem, DshTokenUsage } from '../../dsh/types.js';
|
|
23
23
|
import type { GoalView } from '../types.js';
|
|
24
24
|
export { DshError } from './errors.js';
|
|
25
25
|
interface WebSocketMessageEvent {
|
|
@@ -72,9 +72,6 @@ export interface DshClientOptions {
|
|
|
72
72
|
*/
|
|
73
73
|
requestTimeoutMs?: number;
|
|
74
74
|
}
|
|
75
|
-
/** Extract the `token` query parameter from a pasted `dsh web` URL. */
|
|
76
|
-
export declare function extractDshToken(raw: string | undefined): string;
|
|
77
|
-
export declare function dshArgs(method: string, payload: unknown): Record<string, unknown>;
|
|
78
75
|
export declare class DshClient {
|
|
79
76
|
readonly baseUrl: string;
|
|
80
77
|
private readonly token;
|