lark-remote 0.4.3 → 0.4.5
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 +21 -0
- package/dist/binder.d.ts +11 -10
- package/dist/binder.js +17 -16
- package/dist/bridge/inbound-media.d.ts +1 -27
- package/dist/bridge/inbound-media.js +13 -14
- package/dist/bridge/index.d.ts +49 -49
- package/dist/bridge/index.js +99 -92
- package/dist/bridge/queue-manager.d.ts +33 -26
- package/dist/bridge/queue-manager.js +117 -117
- package/dist/card/bash-renderer.js +4 -4
- package/dist/card/card-shared.d.ts +1 -1
- package/dist/card/card-shared.js +2 -2
- package/dist/card/run-renderer.js +8 -8
- package/dist/card/run-state.js +81 -31
- package/dist/card/tool-render.js +6 -2
- package/dist/cli.js +5 -6
- package/dist/clone.d.ts +1 -6
- package/dist/clone.js +4 -4
- 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/config/dir.d.ts +4 -5
- package/dist/config/dir.js +7 -8
- package/dist/config/wizard.js +2 -2
- package/dist/connector/index.d.ts +0 -2
- package/dist/connector/index.js +5 -5
- 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 +30 -22
- package/dist/instance-lock.js +4 -4
- package/dist/persistence/atomic-write.js +3 -3
- package/dist/platform/agent-stopper.d.ts +1 -1
- package/dist/platform/terminator-posix.js +5 -5
- package/dist/platform/terminator-win32.js +1 -1
- package/dist/router/card-helpers.d.ts +1 -3
- package/dist/router/card-helpers.js +2 -2
- package/dist/router/config/codex.js +1 -1
- 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 +1 -1
- package/dist/router/config/pi.js +1 -1
- package/dist/router/index.d.ts +22 -22
- package/dist/router/index.js +71 -52
- package/dist/router/order-exec-dispatch.d.ts +3 -10
- package/dist/router/order-exec-dispatch.js +3 -3
- 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/claude/runner.d.ts +1 -1
- package/dist/runner/claude/runner.js +1 -2
- package/dist/runner/claude/session.d.ts +2 -4
- package/dist/runner/claude/session.js +7 -9
- package/dist/runner/common/acp/{protocol-helpers.d.ts → acp-approval.d.ts} +2 -8
- package/dist/runner/common/acp/{protocol-helpers.js → acp-approval.js} +4 -3
- package/dist/runner/common/acp/base-acp-runner.d.ts +1 -1
- package/dist/runner/common/acp/base-acp-runner.js +1 -1
- package/dist/runner/common/acp/base-translator.d.ts +43 -0
- package/dist/runner/common/acp/base-translator.js +83 -18
- package/dist/runner/common/connection-based-runner.d.ts +4 -4
- package/dist/runner/common/connection-based-runner.js +3 -3
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +12 -12
- package/dist/runner/common/jsonrpc/connection-manager.js +36 -36
- 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 +2 -2
- package/dist/runner/common/spawning-runner.js +8 -8
- 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 +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.js +1 -1
- package/dist/runner/kimi/acp/translator.js +1 -1
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +1 -1
- package/dist/runner/opencode/acp/translator.d.ts +22 -1
- package/dist/runner/opencode/acp/translator.js +61 -1
- package/dist/runner/pi/rpc/runner.d.ts +1 -1
- package/dist/runner/pi/rpc/translator.d.ts +0 -1
- package/dist/runner/pi/rpc/translator.js +0 -2
- package/dist/runner/registry.d.ts +3 -3
- package/dist/runner/registry.js +3 -3
- package/dist/session/claude/session-index.d.ts +1 -1
- package/dist/session/claude/session-index.js +1 -1
- package/dist/session/claude/session-reader.d.ts +1 -1
- package/dist/session/claude/session-reader.js +1 -1
- package/dist/session/codex/rollout-reader.js +2 -2
- package/dist/session/dsh/sessions.d.ts +1 -1
- package/dist/session/dsh/sessions.js +1 -1
- package/dist/session/kimi/sessions.d.ts +0 -4
- package/dist/session/kimi/sessions.js +2 -8
- package/dist/session/opencode/sessions.js +3 -3
- package/dist/session/registry.d.ts +1 -1
- package/dist/session/registry.js +1 -1
- package/dist/session/session-store.d.ts +2 -3
- package/dist/session/session-store.js +2 -4
- 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
|
@@ -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';
|
|
@@ -120,7 +120,7 @@ export class SpawningRunner {
|
|
|
120
120
|
this.logTag = opts.logTag ?? 'spawning-runner';
|
|
121
121
|
this.agent = opts.agent;
|
|
122
122
|
const pidDir = opts.pidDir ?? path.join(os.homedir(), '.lark-remote');
|
|
123
|
-
const workspaceSuffix = `-${opts.
|
|
123
|
+
const workspaceSuffix = `-${opts.cwd.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
124
124
|
const pidFilePrefix = opts.pidFilePrefix ?? 'spawning';
|
|
125
125
|
this.pidFilePath = path.join(pidDir, `${pidFilePrefix}${workspaceSuffix}.pid`);
|
|
126
126
|
this.terminator =
|
|
@@ -158,7 +158,7 @@ export class SpawningRunner {
|
|
|
158
158
|
* finite timeout (review P2-11) against the 'error' event: Node guarantees
|
|
159
159
|
* 'error' for ENOENT/EACCES, but some binaries fail silently without ever
|
|
160
160
|
* emitting it. Without the race, the spawn lead-in hangs forever → the
|
|
161
|
-
*
|
|
161
|
+
* cwd serial queue never settles → permanent deadlock, and /stop
|
|
162
162
|
* can't recover (Terminator.stop returns early when pid === undefined).
|
|
163
163
|
* The timeout keeps the deadlock bounded.
|
|
164
164
|
*/
|
|
@@ -298,7 +298,7 @@ export class SpawningRunner {
|
|
|
298
298
|
// (immediate 路径不查表,但一并注销同样正确——进程已进入终止流程)。
|
|
299
299
|
this.unregisterStopper();
|
|
300
300
|
this.currentProcess = null;
|
|
301
|
-
|
|
301
|
+
bestEffortUnlink(this.pidFilePath);
|
|
302
302
|
getLogger().debug(`[${this.logTag}] cleaned pid file ${this.pidFilePath}`);
|
|
303
303
|
}
|
|
304
304
|
/**
|
|
@@ -324,7 +324,7 @@ export class SpawningRunner {
|
|
|
324
324
|
const pidStr = fs.readFileSync(this.pidFilePath, 'utf-8').trim();
|
|
325
325
|
const pid = Number(pidStr);
|
|
326
326
|
if (isNaN(pid) || pid <= 0) {
|
|
327
|
-
|
|
327
|
+
bestEffortUnlink(this.pidFilePath);
|
|
328
328
|
return;
|
|
329
329
|
}
|
|
330
330
|
const expectedBinary = binaryName(this.binary);
|
|
@@ -339,7 +339,7 @@ export class SpawningRunner {
|
|
|
339
339
|
if (verdict !== 'match') {
|
|
340
340
|
getLogger().warn(`[${this.logTag}] killOrphan: pid ${pid} not confirmed as ${expectedBinary} ` +
|
|
341
341
|
`(${verdict}), skipping kill`);
|
|
342
|
-
|
|
342
|
+
bestEffortUnlink(this.pidFilePath);
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
345
345
|
// 身份匹配:杀整个进程组(detached:true 下 agent 是组长),与
|
|
@@ -351,7 +351,7 @@ export class SpawningRunner {
|
|
|
351
351
|
catch {
|
|
352
352
|
// process may have exited
|
|
353
353
|
}
|
|
354
|
-
|
|
354
|
+
bestEffortUnlink(this.pidFilePath);
|
|
355
355
|
}
|
|
356
356
|
catch {
|
|
357
357
|
// ignore
|
|
@@ -401,7 +401,7 @@ export class SpawningRunner {
|
|
|
401
401
|
catch { }
|
|
402
402
|
}
|
|
403
403
|
this.unregisterStopper();
|
|
404
|
-
|
|
404
|
+
bestEffortUnlink(this.pidFilePath);
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
407
|
//# 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
|
|
@@ -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') {
|
|
@@ -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;
|
|
@@ -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';
|
|
@@ -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
|
/**
|
|
@@ -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;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { ConnectionManager, } from '../../common/jsonrpc/connection-manager.js';
|
|
23
23
|
import { OpencodeAcpTranslator } from './translator.js';
|
|
24
24
|
import { RpcErrorCode, } from '../../common/acp/protocol-types.js';
|
|
25
|
-
import { OPENCODE_APPROVAL_KINDS, buildAcpPermissionOutcome, } from '../../common/acp/
|
|
25
|
+
import { OPENCODE_APPROVAL_KINDS, buildAcpPermissionOutcome, } from '../../common/acp/acp-approval.js';
|
|
26
26
|
import { getLogger } from '../../../logger/index.js';
|
|
27
27
|
import { BaseAcpRunner } from '../../common/acp/base-acp-runner.js';
|
|
28
28
|
import { OpencodeLogErrorMonitor, resolveOpencodeLogPath } from './error-monitor.js';
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
* prompt other stopReason/error → result error
|
|
25
25
|
* session/request_permission → approval_requested (optionId echo)
|
|
26
26
|
*/
|
|
27
|
-
import type {
|
|
27
|
+
import type { AgentEvent } from '../../types.js';
|
|
28
|
+
import type { RequestPermissionParams, AgentMessageChunkEvent, AgentThoughtChunkEvent, ToolCallEvent, ToolCallUpdateEvent, UsageUpdateEvent } from '../../common/acp/protocol-types.js';
|
|
28
29
|
import { BaseAcpTranslator, type AcpTranslatorEvent } from '../../common/acp/base-translator.js';
|
|
29
30
|
export declare class OpencodeAcpTranslator extends BaseAcpTranslator {
|
|
30
31
|
protected readonly logTag = "opencode-acp-translator";
|
|
@@ -36,6 +37,26 @@ export declare class OpencodeAcpTranslator extends BaseAcpTranslator {
|
|
|
36
37
|
* content[] with shell output snapshot.
|
|
37
38
|
*/
|
|
38
39
|
protected extractToolResultContent(event: ToolCallUpdateEvent): unknown;
|
|
40
|
+
/**
|
|
41
|
+
* opencode tool args always arrive as rawInput (`XC`/`BP`), never as content
|
|
42
|
+
* text. A tool_call_update's content is the shell OUTPUT snapshot (`WP`), so
|
|
43
|
+
* inheriting the base args-tracking would record output as if it were the
|
|
44
|
+
* command — the corruption this override prevents. Return undefined: nothing
|
|
45
|
+
* to track from content (rawInput tracking in the base still applies).
|
|
46
|
+
*/
|
|
47
|
+
protected extractToolCallArgsText(_event: ToolCallEvent | ToolCallUpdateEvent): string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* opencode emits the tool_call while args are still streaming: the part is
|
|
50
|
+
* created with `state:{status:'pending',input:{}}` (decompiled acp service),
|
|
51
|
+
* so the initial title falls back to the tool name (e.g. `bash`) and the card
|
|
52
|
+
* shows no command. The real identity arrives in later tool_call_updates:
|
|
53
|
+
* - running (`BP`): full rawInput + title = command/path
|
|
54
|
+
* - completed (`HP`): title only (no kind, no rawInput)
|
|
55
|
+
* Emit a tool_use patch when either carries usable data; the reducer merges
|
|
56
|
+
* it into the existing block by id. Name resolves from kind (`BP`) or the
|
|
57
|
+
* name recorded at tool_call time (`HP`).
|
|
58
|
+
*/
|
|
59
|
+
protected buildToolUseUpdate(event: ToolCallUpdateEvent): AgentEvent | null;
|
|
39
60
|
/** opencode usage_update also carries session cost: {cost:{amount}} (USD). */
|
|
40
61
|
protected onUsageSample(event: UsageUpdateEvent): void;
|
|
41
62
|
protected handleRequestPermission(requestId: number | string, params: RequestPermissionParams): AcpTranslatorEvent[];
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* prompt other stopReason/error → result error
|
|
25
25
|
* session/request_permission → approval_requested (optionId echo)
|
|
26
26
|
*/
|
|
27
|
-
import { deriveAcpAvailableDecisions, truncateWithEllipsis, } from '../../common/acp/
|
|
27
|
+
import { deriveAcpAvailableDecisions, truncateWithEllipsis, } from '../../common/acp/acp-approval.js';
|
|
28
28
|
import { getLogger } from '../../../logger/index.js';
|
|
29
29
|
import { BaseAcpTranslator } from '../../common/acp/base-translator.js';
|
|
30
30
|
// =============================================================================
|
|
@@ -92,6 +92,66 @@ export class OpencodeAcpTranslator extends BaseAcpTranslator {
|
|
|
92
92
|
}
|
|
93
93
|
return '';
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* opencode tool args always arrive as rawInput (`XC`/`BP`), never as content
|
|
97
|
+
* text. A tool_call_update's content is the shell OUTPUT snapshot (`WP`), so
|
|
98
|
+
* inheriting the base args-tracking would record output as if it were the
|
|
99
|
+
* command — the corruption this override prevents. Return undefined: nothing
|
|
100
|
+
* to track from content (rawInput tracking in the base still applies).
|
|
101
|
+
*/
|
|
102
|
+
extractToolCallArgsText(_event) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* opencode emits the tool_call while args are still streaming: the part is
|
|
107
|
+
* created with `state:{status:'pending',input:{}}` (decompiled acp service),
|
|
108
|
+
* so the initial title falls back to the tool name (e.g. `bash`) and the card
|
|
109
|
+
* shows no command. The real identity arrives in later tool_call_updates:
|
|
110
|
+
* - running (`BP`): full rawInput + title = command/path
|
|
111
|
+
* - completed (`HP`): title only (no kind, no rawInput)
|
|
112
|
+
* Emit a tool_use patch when either carries usable data; the reducer merges
|
|
113
|
+
* it into the existing block by id. Name resolves from kind (`BP`) or the
|
|
114
|
+
* name recorded at tool_call time (`HP`).
|
|
115
|
+
*/
|
|
116
|
+
buildToolUseUpdate(event) {
|
|
117
|
+
const raw = event.rawInput;
|
|
118
|
+
let input = {};
|
|
119
|
+
if (raw !== undefined && raw !== null) {
|
|
120
|
+
if (typeof raw === 'string') {
|
|
121
|
+
try {
|
|
122
|
+
input = JSON.parse(raw);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
input = raw;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
input = raw;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const inputHasKeys = input !== null && typeof input === 'object' && Object.keys(input).length > 0;
|
|
133
|
+
const title = typeof event.title === 'string' && event.title.length > 0 ? event.title : undefined;
|
|
134
|
+
if (!inputHasKeys && !title)
|
|
135
|
+
return null;
|
|
136
|
+
const kind = typeof event.kind === 'string' ? event.kind : undefined;
|
|
137
|
+
const name = this.toolNameFromKind(kind) ?? this.getToolCallName(event.toolCallId) ?? '';
|
|
138
|
+
const summary = title && title !== name ? title : undefined;
|
|
139
|
+
return {
|
|
140
|
+
type: 'assistant',
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
message: {
|
|
143
|
+
content: [
|
|
144
|
+
{
|
|
145
|
+
type: 'tool_use',
|
|
146
|
+
id: event.toolCallId,
|
|
147
|
+
name,
|
|
148
|
+
input: inputHasKeys ? input : {},
|
|
149
|
+
...(summary !== undefined ? { summary } : {}),
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
95
155
|
/** opencode usage_update also carries session cost: {cost:{amount}} (USD). */
|
|
96
156
|
onUsageSample(event) {
|
|
97
157
|
const cost = event.cost;
|
|
@@ -15,7 +15,6 @@ export class PiRpcTranslator {
|
|
|
15
15
|
currentContentIndex = -1;
|
|
16
16
|
sessionId = '';
|
|
17
17
|
operationKind = 'turn';
|
|
18
|
-
currentTurnId = '';
|
|
19
18
|
// ccusage-aligned usage accumulation (per-message, summed across the turn).
|
|
20
19
|
accInput = 0;
|
|
21
20
|
accOutput = 0;
|
|
@@ -134,7 +133,6 @@ export class PiRpcTranslator {
|
|
|
134
133
|
/** Self-produced turn_started (no wire equivalent). */
|
|
135
134
|
produceTurnStarted(sessionId, turnId) {
|
|
136
135
|
this.sessionId = sessionId;
|
|
137
|
-
this.currentTurnId = turnId;
|
|
138
136
|
return {
|
|
139
137
|
type: 'turn_started',
|
|
140
138
|
threadId: sessionId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentKind, Runner } from './index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Registry of agent factories, keyed by `AgentKind`. `index.ts` registers one
|
|
4
|
-
* factory per available agent at startup; `Bridge.getRunner(
|
|
4
|
+
* factory per available agent at startup; `Bridge.getRunner(cwd)` looks
|
|
5
5
|
* up `config.defaultAgent` here to pick the concrete runner.
|
|
6
6
|
*
|
|
7
7
|
* Singleton caching: the factory MAY cache its instance internally. All
|
|
@@ -17,7 +17,7 @@ export declare class AgentRegistry {
|
|
|
17
17
|
private readonly displayNames;
|
|
18
18
|
/** Container for runtime config updates (pi provider dynamic reload). */
|
|
19
19
|
private configContainer?;
|
|
20
|
-
register(kind: AgentKind, factory: (
|
|
20
|
+
register(kind: AgentKind, factory: (cwd: string) => Runner): void;
|
|
21
21
|
/**
|
|
22
22
|
* 注册 agent 的显示名。应在 register(kind, factory) 后调用。
|
|
23
23
|
* 用于 agentDisplayName 等全局查询,实现单点真相。
|
|
@@ -50,5 +50,5 @@ export declare class AgentRegistry {
|
|
|
50
50
|
getConfigContainer(): {
|
|
51
51
|
current: unknown;
|
|
52
52
|
} | undefined;
|
|
53
|
-
get(kind: AgentKind,
|
|
53
|
+
get(kind: AgentKind, cwd: string): Runner;
|
|
54
54
|
}
|
package/dist/runner/registry.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
let globalRegistry;
|
|
6
6
|
/**
|
|
7
7
|
* Registry of agent factories, keyed by `AgentKind`. `index.ts` registers one
|
|
8
|
-
* factory per available agent at startup; `Bridge.getRunner(
|
|
8
|
+
* factory per available agent at startup; `Bridge.getRunner(cwd)` looks
|
|
9
9
|
* up `config.defaultAgent` here to pick the concrete runner.
|
|
10
10
|
*
|
|
11
11
|
* Singleton caching: the factory MAY cache its instance internally. All
|
|
@@ -64,12 +64,12 @@ export class AgentRegistry {
|
|
|
64
64
|
getConfigContainer() {
|
|
65
65
|
return this.configContainer;
|
|
66
66
|
}
|
|
67
|
-
get(kind,
|
|
67
|
+
get(kind, cwd) {
|
|
68
68
|
const factory = this.factories.get(kind);
|
|
69
69
|
if (!factory) {
|
|
70
70
|
throw new Error(`agent not registered: ${kind}`);
|
|
71
71
|
}
|
|
72
|
-
return factory(
|
|
72
|
+
return factory(cwd);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
//# sourceMappingURL=registry.js.map
|
|
@@ -36,7 +36,7 @@ export interface ParsedSession {
|
|
|
36
36
|
/**
|
|
37
37
|
* Unified parser: single streaming scan of a JSONL file producing both
|
|
38
38
|
* the complete set of cwd values AND the first real user message summary.
|
|
39
|
-
* Replaces the split readCwdFromJsonl (first-cwd) +
|
|
39
|
+
* Replaces the split readCwdFromJsonl (first-cwd) + fileContainsCwd (any-cwd).
|
|
40
40
|
*/
|
|
41
41
|
export declare function parseSessionJsonl(filePath: string): ParsedSession;
|
|
42
42
|
/**
|
|
@@ -42,7 +42,7 @@ export function extractText(content) {
|
|
|
42
42
|
/**
|
|
43
43
|
* Unified parser: single streaming scan of a JSONL file producing both
|
|
44
44
|
* the complete set of cwd values AND the first real user message summary.
|
|
45
|
-
* Replaces the split readCwdFromJsonl (first-cwd) +
|
|
45
|
+
* Replaces the split readCwdFromJsonl (first-cwd) + fileContainsCwd (any-cwd).
|
|
46
46
|
*/
|
|
47
47
|
export function parseSessionJsonl(filePath) {
|
|
48
48
|
const cwdSet = new Set();
|
|
@@ -8,7 +8,7 @@ import type { AgentSession, AgentSessionReader, SessionContent } from '../../run
|
|
|
8
8
|
* injects a reader configured with its test `projectsDir`; production code
|
|
9
9
|
* uses the default (`~/.claude/projects/`).
|
|
10
10
|
*
|
|
11
|
-
* All methods are thin wrappers around `
|
|
11
|
+
* All methods are thin wrappers around `sessions.ts` exports — zero
|
|
12
12
|
* behavior change. Router and bridge reach session data exclusively through
|
|
13
13
|
* this reader (via `SessionReaderRegistry`); the underlying functions remain
|
|
14
14
|
* exported for tests and the reader itself.
|
|
@@ -9,7 +9,7 @@ import { listClaudeSessions, getNewestSession, readSessionContent, isClaudeSessi
|
|
|
9
9
|
* injects a reader configured with its test `projectsDir`; production code
|
|
10
10
|
* uses the default (`~/.claude/projects/`).
|
|
11
11
|
*
|
|
12
|
-
* All methods are thin wrappers around `
|
|
12
|
+
* All methods are thin wrappers around `sessions.ts` exports — zero
|
|
13
13
|
* behavior change. Router and bridge reach session data exclusively through
|
|
14
14
|
* this reader (via `SessionReaderRegistry`); the underlying functions remain
|
|
15
15
|
* exported for tests and the reader itself.
|
|
@@ -399,9 +399,9 @@ export function readCodexSessionContent(sessionId, opts = {}) {
|
|
|
399
399
|
}
|
|
400
400
|
// Cwd guard: when a cwd is provided, the session's working directory must
|
|
401
401
|
// match. Without this, /resume <id> finds sessions by global ID lookup and
|
|
402
|
-
// allows resuming a session from
|
|
402
|
+
// allows resuming a session from cwd B while the user is in cwd A.
|
|
403
403
|
// Codex has no relocation (no EnterWorktree equivalent), so a simple equality
|
|
404
|
-
// check suffices — unlike claude which needs
|
|
404
|
+
// check suffices — unlike claude which needs fileContainsCwd to handle
|
|
405
405
|
// relocated sessions with multiple cwd values.
|
|
406
406
|
if (opts.cwd && !samePath(entry.cwd, opts.cwd)) {
|
|
407
407
|
return { events: [] };
|
|
@@ -36,7 +36,7 @@ export declare class DshSessionReader implements AgentSessionReader {
|
|
|
36
36
|
total: number;
|
|
37
37
|
};
|
|
38
38
|
getNewestSession(cwd: string): AgentSession | null;
|
|
39
|
-
readSessionContent(sessionId: string,
|
|
39
|
+
readSessionContent(sessionId: string, _cwd: string, opts?: {
|
|
40
40
|
maxEvents?: number;
|
|
41
41
|
}): SessionContent;
|
|
42
42
|
isSessionActive(sessionId: string, cwd: string): boolean;
|
|
@@ -102,7 +102,7 @@ export class DshSessionReader {
|
|
|
102
102
|
getNewestSession(cwd) {
|
|
103
103
|
return this.listSessions(cwd, { limit: 1 }).sessions[0] ?? null;
|
|
104
104
|
}
|
|
105
|
-
readSessionContent(sessionId,
|
|
105
|
+
readSessionContent(sessionId, _cwd, opts) {
|
|
106
106
|
try {
|
|
107
107
|
const value = this.unary('session.history', {
|
|
108
108
|
sessionId,
|
|
@@ -66,10 +66,6 @@ export declare class KimiSessionReader implements AgentSessionReader {
|
|
|
66
66
|
* Find a single index entry by sessionId, or undefined if not found.
|
|
67
67
|
*/
|
|
68
68
|
private findSessionIndexEntry;
|
|
69
|
-
/**
|
|
70
|
-
* Convenience wrapper: find sessionDir from index, or null if not found.
|
|
71
|
-
*/
|
|
72
|
-
private findSessionDirFromIndex;
|
|
73
69
|
/**
|
|
74
70
|
* Extract the last turn.prompt text from a wire.jsonl file.
|
|
75
71
|
* Used as a fallback summary source when state.json has no title/lastPrompt
|
|
@@ -163,12 +163,6 @@ export class KimiSessionReader {
|
|
|
163
163
|
findSessionIndexEntry(sessionId) {
|
|
164
164
|
return this.scanSessionIndex().find((e) => e.sessionId === sessionId);
|
|
165
165
|
}
|
|
166
|
-
/**
|
|
167
|
-
* Convenience wrapper: find sessionDir from index, or null if not found.
|
|
168
|
-
*/
|
|
169
|
-
findSessionDirFromIndex(sessionId) {
|
|
170
|
-
return this.findSessionIndexEntry(sessionId)?.sessionDir ?? null;
|
|
171
|
-
}
|
|
172
166
|
/**
|
|
173
167
|
* Extract the last turn.prompt text from a wire.jsonl file.
|
|
174
168
|
* Used as a fallback summary source when state.json has no title/lastPrompt
|
|
@@ -596,7 +590,7 @@ export class KimiSessionReader {
|
|
|
596
590
|
// Fallback: when state.json is missing, unparseable, or has no workDir/cwd,
|
|
597
591
|
// use the workDir from the session index entry as a secondary guard.
|
|
598
592
|
// This prevents /resume <id> from accessing a session belonging to a
|
|
599
|
-
// different
|
|
593
|
+
// different cwd when state.json is unavailable.
|
|
600
594
|
if (!cwdGuardPassed) {
|
|
601
595
|
const indexWorkDir = indexEntry?.workDir;
|
|
602
596
|
if (indexWorkDir && indexWorkDir !== realCwd) {
|
|
@@ -604,7 +598,7 @@ export class KimiSessionReader {
|
|
|
604
598
|
}
|
|
605
599
|
// v2 sessions have empty index workDir (v1-only field) and may lack
|
|
606
600
|
// state.json cwd. When no cwd source can verify the session belongs to
|
|
607
|
-
// the requested
|
|
601
|
+
// the requested cwd, fail-closed to prevent cross-workspace access
|
|
608
602
|
// (aligned with claude's fail-closed cwd guard).
|
|
609
603
|
if (!indexWorkDir) {
|
|
610
604
|
getLogger().warn(`[kimi-session-reader] no cwd source (state.json + index) for session ${sessionId}, rejecting (fail-closed)`);
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { spawnProcessSync } from '../../platform/spawn.js';
|
|
17
17
|
import fs from 'node:fs';
|
|
18
|
-
import {
|
|
18
|
+
import { bestEffortUnlink } from '../../common/fs.js';
|
|
19
19
|
import os from 'node:os';
|
|
20
20
|
import path from 'node:path';
|
|
21
21
|
import { truncateUtf8, TOOL_RESULT_MAX_BYTES } from '../../common/truncate.js';
|
|
22
|
-
import { getLogger } from '../../logger/index.js';
|
|
23
22
|
import { isStale } from '../common/constants.js';
|
|
24
23
|
import { samePath } from '../../platform/path.js';
|
|
25
24
|
import { paginate, capEvents } from '../common/pagination.js';
|
|
26
25
|
import { sortByRecencyDesc } from '../common/recency.js';
|
|
27
26
|
import { TtlCache } from '../../common/ttl-cache.js';
|
|
27
|
+
import { getLogger } from '../../logger/index.js';
|
|
28
28
|
export class OpencodeSessionReader {
|
|
29
29
|
binary;
|
|
30
30
|
cacheTtlMs;
|
|
@@ -401,7 +401,7 @@ export class OpencodeSessionReader {
|
|
|
401
401
|
}
|
|
402
402
|
catch { }
|
|
403
403
|
}
|
|
404
|
-
|
|
404
|
+
bestEffortUnlink(tmp);
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
407
|
}
|
|
@@ -3,7 +3,7 @@ import type { AgentKind, AgentSessionReader } from '../runner/index.js';
|
|
|
3
3
|
* Registry of `AgentSessionReader` instances, keyed by `AgentKind`. Mirrors
|
|
4
4
|
* `AgentRegistry` but for session-history reads. `index.ts` registers one
|
|
5
5
|
* reader per available agent at startup; router/bridge look up readers here
|
|
6
|
-
* instead of importing `
|
|
6
|
+
* instead of importing `sessions.ts` directly.
|
|
7
7
|
*/
|
|
8
8
|
export declare class SessionReaderRegistry {
|
|
9
9
|
private readonly readers;
|
package/dist/session/registry.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Registry of `AgentSessionReader` instances, keyed by `AgentKind`. Mirrors
|
|
3
3
|
* `AgentRegistry` but for session-history reads. `index.ts` registers one
|
|
4
4
|
* reader per available agent at startup; router/bridge look up readers here
|
|
5
|
-
* instead of importing `
|
|
5
|
+
* instead of importing `sessions.ts` directly.
|
|
6
6
|
*/
|
|
7
7
|
export class SessionReaderRegistry {
|
|
8
8
|
readers = new Map();
|
|
@@ -13,7 +13,7 @@ interface SessionEntry {
|
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Per-user session store. Persists cwd + per-agent sessions to disk so that
|
|
16
|
-
* the last
|
|
16
|
+
* the last cwd AND the last-used sessionId per agent are restored after
|
|
17
17
|
* a lark-remote restart.
|
|
18
18
|
*
|
|
19
19
|
* Persistence strategy:
|
|
@@ -29,7 +29,6 @@ interface SessionEntry {
|
|
|
29
29
|
export declare class SessionStore {
|
|
30
30
|
private sessions;
|
|
31
31
|
private readonly persistPath?;
|
|
32
|
-
private readonly defaultAgent?;
|
|
33
32
|
/**
|
|
34
33
|
* 进程内会话代际(2026-08-09 /new 被在途 run init 写回撤销事故):
|
|
35
34
|
* 每次「用户意图移动 session 指针」+1。system.init 写回通道不 bump。
|
|
@@ -47,7 +46,7 @@ export declare class SessionStore {
|
|
|
47
46
|
bumpSessionEpoch(userId: string, agent: AgentKind): void;
|
|
48
47
|
/** 用户意图移动了全部 agent 的 session 指针(/cd、/ws use 的 setCwd)。 */
|
|
49
48
|
private bumpUserEpoch;
|
|
50
|
-
constructor(persistPath?: string
|
|
49
|
+
constructor(persistPath?: string);
|
|
51
50
|
/** A fresh, empty session entry (default factory). */
|
|
52
51
|
private static emptyEntry;
|
|
53
52
|
/**
|
|
@@ -3,7 +3,7 @@ import { getLogger } from '../logger/index.js';
|
|
|
3
3
|
import { atomicWriteJson } from '../persistence/atomic-write.js';
|
|
4
4
|
/**
|
|
5
5
|
* Per-user session store. Persists cwd + per-agent sessions to disk so that
|
|
6
|
-
* the last
|
|
6
|
+
* the last cwd AND the last-used sessionId per agent are restored after
|
|
7
7
|
* a lark-remote restart.
|
|
8
8
|
*
|
|
9
9
|
* Persistence strategy:
|
|
@@ -19,7 +19,6 @@ import { atomicWriteJson } from '../persistence/atomic-write.js';
|
|
|
19
19
|
export class SessionStore {
|
|
20
20
|
sessions = new Map();
|
|
21
21
|
persistPath;
|
|
22
|
-
defaultAgent;
|
|
23
22
|
/**
|
|
24
23
|
* 进程内会话代际(2026-08-09 /new 被在途 run init 写回撤销事故):
|
|
25
24
|
* 每次「用户意图移动 session 指针」+1。system.init 写回通道不 bump。
|
|
@@ -47,9 +46,8 @@ export class SessionStore {
|
|
|
47
46
|
bumpUserEpoch(userId) {
|
|
48
47
|
this.userEpochs.set(userId, (this.userEpochs.get(userId) ?? 0) + 1);
|
|
49
48
|
}
|
|
50
|
-
constructor(persistPath
|
|
49
|
+
constructor(persistPath) {
|
|
51
50
|
this.persistPath = persistPath;
|
|
52
|
-
this.defaultAgent = defaultAgent;
|
|
53
51
|
if (persistPath)
|
|
54
52
|
this.load();
|
|
55
53
|
}
|
package/dist/update/index.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* package installation (detect package manager + global install),
|
|
6
6
|
* and the combined workflow for the /update command and --update CLI flag.
|
|
7
7
|
*/
|
|
8
|
-
export {
|
|
8
|
+
export { compareVersions, checkLatestVersion, formatUpdateHint, type VersionCheckResult, } from './version-check.js';
|
|
9
9
|
export { runInstallLatest, type InstallResult } from './install.js';
|