lark-remote 0.5.13 → 0.5.14
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 +15 -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/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 +201 -229
- 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 +16 -30
- package/dist/bridge/run-usage.js +41 -50
- 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 +7 -22
- 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 +165 -226
- 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 +3 -1
- 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 +2 -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 +76 -73
- 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 +3 -1
- 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 +35 -8
- package/dist/session/opencode/sessions.d.ts +1 -1
- package/dist/session/opencode/sessions.js +51 -47
- 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,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';
|
|
@@ -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;
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { randomUUID } from 'node:crypto';
|
|
23
23
|
import WebSocket from 'ws';
|
|
24
|
+
import { dshArgs, extractDshToken } from '../../dsh/protocol.js';
|
|
24
25
|
import { getLogger } from '../../logger/index.js';
|
|
25
|
-
import { DSH_COOKIE_LIFETIME_MS, isDshCredentialsNotFound, mintDshBrowserCookie, readDshBrowserSecret, resolveDshCredentialsFile, } from '
|
|
26
|
+
import { DSH_COOKIE_LIFETIME_MS, isDshCredentialsNotFound, mintDshBrowserCookie, readDshBrowserSecret, resolveDshCredentialsFile, } from '../../dsh/auth.js';
|
|
26
27
|
import { DEFAULT_REQUEST_TIMEOUT_MS } from '../common/defaults.js';
|
|
27
28
|
import { goalFromProjection } from './goal-view.js';
|
|
28
29
|
import { DshError } from './errors.js';
|
|
@@ -111,60 +112,6 @@ function inboxItemsOf(values) {
|
|
|
111
112
|
}
|
|
112
113
|
return out;
|
|
113
114
|
}
|
|
114
|
-
/** Extract the `token` query parameter from a pasted `dsh web` URL. */
|
|
115
|
-
export function extractDshToken(raw) {
|
|
116
|
-
const value = (raw ?? '').trim();
|
|
117
|
-
if (!value)
|
|
118
|
-
return '';
|
|
119
|
-
if (!value.includes('token=') && !value.includes('://'))
|
|
120
|
-
return value;
|
|
121
|
-
try {
|
|
122
|
-
const url = new URL(value.startsWith('?') ? `http://dsh.invalid/${value}` : value);
|
|
123
|
-
const token = url.searchParams.get('token');
|
|
124
|
-
if (token)
|
|
125
|
-
return token;
|
|
126
|
-
// 带 scheme 却没有 token 参数的输入是误贴的 host URL(如
|
|
127
|
-
// `http://127.0.0.1:3080`):整串不是合法 token,参与握手只会得到
|
|
128
|
-
// 指向性缺失的 401。返回空串让上游走「token 缺失」的诊断路径。
|
|
129
|
-
if (value.includes('://'))
|
|
130
|
-
return '';
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
return value;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Remote methods take named parameters. Most session methods call their single
|
|
139
|
-
* argument `request`; `session/list` reserves `_request`; catalog methods take
|
|
140
|
-
* no arguments. `commands/*` address the receiving agent by its wire field
|
|
141
|
-
* `agentId`, so their payload is already in wire shape (pass-through).
|
|
142
|
-
* The gateway rejects any other `args` shape.
|
|
143
|
-
*/
|
|
144
|
-
const DSH_ARGS_KEY = {
|
|
145
|
-
'session/list': '_request',
|
|
146
|
-
'session/create': 'request',
|
|
147
|
-
'session/prompt': 'request',
|
|
148
|
-
'session/cancel': 'request',
|
|
149
|
-
'session/selectModel': 'request',
|
|
150
|
-
'session/projections': 'request',
|
|
151
|
-
'session/page': 'request',
|
|
152
|
-
'session/follow': 'request',
|
|
153
|
-
'session/updateQueue': 'request',
|
|
154
|
-
'job/list': 'request',
|
|
155
|
-
'job/kill': 'request',
|
|
156
|
-
'session/modelCatalog': null,
|
|
157
|
-
'agentPresets/list': null,
|
|
158
|
-
'permissionPresets/catalog': null,
|
|
159
|
-
};
|
|
160
|
-
export function dshArgs(method, payload) {
|
|
161
|
-
const key = DSH_ARGS_KEY[method];
|
|
162
|
-
if (key === null)
|
|
163
|
-
return {};
|
|
164
|
-
if (key === undefined)
|
|
165
|
-
return payload;
|
|
166
|
-
return { [key]: payload };
|
|
167
|
-
}
|
|
168
115
|
export class DshClient {
|
|
169
116
|
baseUrl;
|
|
170
117
|
token;
|
|
@@ -15,7 +15,8 @@ import fsp from 'node:fs/promises';
|
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { DEFAULT_DSH_HOST } from '../../config/index.js';
|
|
17
17
|
import { mergeProcessEnv, spawnProcess } from '../../platform/spawn.js';
|
|
18
|
-
import {
|
|
18
|
+
import { getLogger } from '../../logger/index.js';
|
|
19
|
+
import { resolveDshHome } from '../../dsh/home.js';
|
|
19
20
|
const DEFAULT_START_TIMEOUT_MS = 30_000;
|
|
20
21
|
const READY_POLL_MS = 100;
|
|
21
22
|
/** User-facing daemon failure; the bridge renders `message` in the chat card. */
|
|
@@ -174,7 +175,13 @@ export class DshDaemon {
|
|
|
174
175
|
const stats = await fsp.stat(lockDir);
|
|
175
176
|
return Date.now() - stats.mtimeMs > this.startTimeoutMs() * 2;
|
|
176
177
|
}
|
|
177
|
-
catch {
|
|
178
|
+
catch (err) {
|
|
179
|
+
// ENOENT = 锁目录刚被持有者清掉(正常,等下一轮重查)。
|
|
180
|
+
// 其余(EACCES/EPERM…)= 无法判断是否陈旧:保守判「不陈旧」继续等,
|
|
181
|
+
// 但必须留痕,否则超时文案会误报成「等待其他 lark-remote」。
|
|
182
|
+
if (err.code !== 'ENOENT') {
|
|
183
|
+
getLogger().warn(`[dsh] cannot stat start lock ${lockDir}: ${err?.message ?? String(err)}`);
|
|
184
|
+
}
|
|
178
185
|
return false;
|
|
179
186
|
}
|
|
180
187
|
}
|
|
@@ -18,7 +18,7 @@ import path from 'node:path';
|
|
|
18
18
|
import { getLogger } from '../../logger/index.js';
|
|
19
19
|
import { isWin32 } from '../../platform/select.js';
|
|
20
20
|
import { spawnProcessSync } from '../../platform/spawn.js';
|
|
21
|
-
import { DSH_COOKIE_LIFETIME_MS, mintDshBrowserCookie, readDshBrowserSecretSync, resolveDshCredentialsFile, } from '
|
|
21
|
+
import { DSH_COOKIE_LIFETIME_MS, mintDshBrowserCookie, readDshBrowserSecretSync, resolveDshCredentialsFile, } from '../../dsh/auth.js';
|
|
22
22
|
/** Upper bound on the exit-path cancel:退出不能被一个卡住的 host 拖住。 */
|
|
23
23
|
const EXIT_CANCEL_TIMEOUT_MS = 2_000;
|
|
24
24
|
/**
|