lark-remote 0.5.12 → 0.5.13
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 +13 -2
- package/README.en.md +1 -14
- package/README.md +1 -14
- package/dist/bridge/approval-coordinator.d.ts +1 -0
- package/dist/bridge/approval-coordinator.js +12 -24
- package/dist/bridge/index.d.ts +7 -0
- package/dist/bridge/index.js +77 -227
- package/dist/bridge/run-approval.d.ts +15 -0
- package/dist/bridge/run-approval.js +41 -0
- package/dist/bridge/run-usage.d.ts +46 -0
- package/dist/bridge/run-usage.js +96 -0
- package/dist/bridge/session-writeback.d.ts +18 -0
- package/dist/bridge/session-writeback.js +36 -0
- package/dist/card/bash-card-session.js +2 -5
- package/dist/card/card-session.d.ts +2 -0
- package/dist/card/card-session.js +20 -22
- package/dist/card/card-shared.d.ts +4 -4
- package/dist/card/card-shared.js +3 -9
- package/dist/card/collapsible.js +3 -2
- package/dist/card/final-answer-overflow.d.ts +7 -0
- package/dist/card/final-answer-overflow.js +46 -0
- package/dist/card/run-card-session.js +2 -7
- package/dist/card/run-renderer.d.ts +14 -0
- package/dist/card/run-renderer.js +119 -1
- package/dist/card/run-state.d.ts +12 -1
- package/dist/card/run-state.js +73 -34
- package/dist/config/codex-config.js +4 -4
- package/dist/config/index.d.ts +4 -2
- package/dist/config/index.js +6 -4
- package/dist/inbound/turn-assembler.js +6 -0
- package/dist/index.js +15 -409
- package/dist/message-handlers.d.ts +26 -0
- package/dist/message-handlers.js +275 -0
- package/dist/router/card-action-payload.d.ts +1 -1
- package/dist/router/card-action-payload.js +1 -1
- package/dist/router/commands/ls.d.ts +9 -0
- package/dist/router/commands/ls.js +243 -0
- package/dist/router/commands/order.d.ts +12 -0
- package/dist/router/commands/order.js +178 -0
- package/dist/router/commands/resume.d.ts +47 -0
- package/dist/router/commands/resume.js +246 -0
- package/dist/router/commands/ws.d.ts +15 -0
- package/dist/router/commands/ws.js +189 -0
- package/dist/router/config/claude.js +3 -3
- package/dist/router/config/codex.js +2 -6
- package/dist/router/config/common/turn-idle.d.ts +2 -0
- package/dist/router/config/common/turn-idle.js +9 -0
- package/dist/router/config/kimi.js +2 -6
- package/dist/router/config/opencode.js +2 -6
- package/dist/router/index.d.ts +14 -22
- package/dist/router/index.js +70 -1152
- package/dist/router/paging.d.ts +13 -0
- package/dist/router/paging.js +20 -0
- package/dist/router/path-validation.d.ts +27 -0
- package/dist/router/path-validation.js +45 -0
- package/dist/runner/claude/runner.d.ts +3 -4
- package/dist/runner/claude/runner.js +4 -5
- package/dist/runner/claude/session.js +1 -1
- package/dist/runner/codex/app-server/translator.d.ts +2 -0
- package/dist/runner/codex/app-server/translator.js +65 -9
- package/dist/runner/common/acp/base-translator.d.ts +3 -8
- package/dist/runner/common/acp/base-translator.js +16 -7
- package/dist/runner/common/spawning-runner.js +10 -4
- package/dist/runner/common/turn-started.d.ts +2 -0
- package/dist/runner/common/turn-started.js +10 -0
- package/dist/runner/dsh/auth.js +2 -3
- package/dist/runner/dsh/client.d.ts +1 -6
- package/dist/runner/dsh/client.js +11 -165
- package/dist/runner/dsh/daemon.d.ts +0 -2
- package/dist/runner/dsh/daemon.js +1 -6
- package/dist/runner/dsh/errors.d.ts +5 -0
- package/dist/runner/dsh/errors.js +11 -0
- package/dist/runner/dsh/exit-cancel.d.ts +0 -2
- package/dist/runner/dsh/exit-cancel.js +1 -1
- package/dist/runner/dsh/home.d.ts +2 -0
- package/dist/runner/dsh/home.js +8 -0
- package/dist/runner/dsh/inflight.d.ts +0 -2
- package/dist/runner/dsh/inflight.js +1 -1
- package/dist/runner/dsh/mux-stream.d.ts +26 -0
- package/dist/runner/dsh/mux-stream.js +157 -0
- package/dist/runner/dsh/translator.d.ts +0 -10
- package/dist/runner/dsh/translator.js +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/translator.js +1 -12
- package/dist/runner/opencode/acp/translator.js +1 -12
- package/dist/runner/pi/rpc/translator.d.ts +2 -8
- package/dist/runner/pi/rpc/translator.js +2 -7
- package/dist/runner/registry.d.ts +0 -19
- package/dist/runner/registry.js +0 -32
- package/dist/runner/types.d.ts +17 -1
- package/dist/session/claude/session-index.js +4 -2
- package/dist/session/kimi/sessions.js +2 -2
- package/dist/session/opencode/sessions.js +2 -1
- package/dist/session/pi/sessions.js +3 -2
- package/package.json +1 -1
|
@@ -12,8 +12,6 @@
|
|
|
12
12
|
* curl transport the session reader already uses: bounded by `timeoutMs` and
|
|
13
13
|
* never throws.
|
|
14
14
|
*/
|
|
15
|
-
/** Upper bound on the exit-path cancel:退出不能被一个卡住的 host 拖住。 */
|
|
16
|
-
export declare const EXIT_CANCEL_TIMEOUT_MS = 2000;
|
|
17
15
|
export interface SyncCancelOptions {
|
|
18
16
|
baseUrl: string;
|
|
19
17
|
sessionId: string;
|
|
@@ -20,7 +20,7 @@ import { isWin32 } from '../../platform/select.js';
|
|
|
20
20
|
import { spawnProcessSync } from '../../platform/spawn.js';
|
|
21
21
|
import { DSH_COOKIE_LIFETIME_MS, mintDshBrowserCookie, readDshBrowserSecretSync, resolveDshCredentialsFile, } from './auth.js';
|
|
22
22
|
/** Upper bound on the exit-path cancel:退出不能被一个卡住的 host 拖住。 */
|
|
23
|
-
|
|
23
|
+
const EXIT_CANCEL_TIMEOUT_MS = 2_000;
|
|
24
24
|
/**
|
|
25
25
|
* Fire one `session/cancel` synchronously. Never throws: a failed cancel must
|
|
26
26
|
* not block the exit path or mask the real exit reason.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/** Resolve the same DSH home DSH itself uses: configured, env, then ~/.dsh. */
|
|
4
|
+
export function resolveDshHome(configured, env = process.env) {
|
|
5
|
+
const value = configured?.trim() || env.DSH_HOME?.trim();
|
|
6
|
+
return path.resolve(value && value.length > 0 ? value : path.join(os.homedir(), '.dsh'));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=home.js.map
|
|
@@ -58,5 +58,3 @@ export interface DshInflightReconcileResult {
|
|
|
58
58
|
* entries are left in the file so a later startup can retry.
|
|
59
59
|
*/
|
|
60
60
|
export declare function reconcileInflightDshRuns(opts: DshInflightReconcileOptions): Promise<DshInflightReconcileResult>;
|
|
61
|
-
/** One short owner-facing notice; session ids are truncated, not paths. */
|
|
62
|
-
export declare function formatInflightWarning(entries: DshInflightEntry[]): string;
|
|
@@ -126,7 +126,7 @@ export async function reconcileInflightDshRuns(opts) {
|
|
|
126
126
|
return { removed, open: open.length, skipped: false };
|
|
127
127
|
}
|
|
128
128
|
/** One short owner-facing notice; session ids are truncated, not paths. */
|
|
129
|
-
|
|
129
|
+
function formatInflightWarning(entries) {
|
|
130
130
|
const lines = entries.slice(0, 3).map((entry) => {
|
|
131
131
|
const id = entry.sessionId.length > 8 ? entry.sessionId.slice(0, 8) : entry.sessionId;
|
|
132
132
|
return `- session ${id}(${entry.cwd ?? '未知目录'})`;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface MuxSocket {
|
|
2
|
+
onopen: ((event: unknown) => void) | null;
|
|
3
|
+
onmessage: ((event: {
|
|
4
|
+
data: unknown;
|
|
5
|
+
}) => void) | null;
|
|
6
|
+
onerror: ((event: unknown) => void) | null;
|
|
7
|
+
onclose: ((event: unknown) => void) | null;
|
|
8
|
+
onunexpectedresponse?: ((event: {
|
|
9
|
+
statusCode?: number;
|
|
10
|
+
}) => void) | null;
|
|
11
|
+
send(data: string): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
export interface OpenMuxStreamOptions {
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
endpoint: string;
|
|
17
|
+
payload: unknown;
|
|
18
|
+
signal: AbortSignal;
|
|
19
|
+
requestTimeoutMs: number;
|
|
20
|
+
authCookie(): Promise<string | undefined>;
|
|
21
|
+
webSocketFactory(url: string, options?: {
|
|
22
|
+
headers?: Record<string, string>;
|
|
23
|
+
}): MuxSocket;
|
|
24
|
+
}
|
|
25
|
+
export declare function openMuxStream(opts: OpenMuxStreamOptions): AsyncGenerator<unknown>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { getLogger } from '../../logger/index.js';
|
|
2
|
+
import { DshError } from './errors.js';
|
|
3
|
+
export async function* openMuxStream(opts) {
|
|
4
|
+
const cookie = await opts.authCookie();
|
|
5
|
+
const socket = opts.webSocketFactory(`${opts.baseUrl.replace(/^http/, 'ws')}/api/remote.mux`, cookie ? { headers: { cookie } } : undefined);
|
|
6
|
+
const streamId = `lr-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
7
|
+
const queue = [];
|
|
8
|
+
let waiter = null;
|
|
9
|
+
let ended = false;
|
|
10
|
+
let failure;
|
|
11
|
+
let opened = false;
|
|
12
|
+
const settle = (frame) => {
|
|
13
|
+
if (waiter) {
|
|
14
|
+
const resolve = waiter;
|
|
15
|
+
waiter = null;
|
|
16
|
+
resolve(frame);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (frame)
|
|
20
|
+
queue.push(frame);
|
|
21
|
+
else
|
|
22
|
+
ended = true;
|
|
23
|
+
};
|
|
24
|
+
const connectTimer = setTimeout(() => {
|
|
25
|
+
if (opened || ended)
|
|
26
|
+
return;
|
|
27
|
+
failure = new DshError('transport', 'DSH remote mux WebSocket connect timeout');
|
|
28
|
+
ended = true;
|
|
29
|
+
settle(undefined);
|
|
30
|
+
try {
|
|
31
|
+
socket.close();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
/* ignore close error */
|
|
35
|
+
}
|
|
36
|
+
}, opts.requestTimeoutMs);
|
|
37
|
+
connectTimer.unref?.();
|
|
38
|
+
socket.onopen = () => {
|
|
39
|
+
opened = true;
|
|
40
|
+
clearTimeout(connectTimer);
|
|
41
|
+
if (ended)
|
|
42
|
+
return;
|
|
43
|
+
try {
|
|
44
|
+
socket.send(JSON.stringify({
|
|
45
|
+
type: 'open',
|
|
46
|
+
streamId,
|
|
47
|
+
endpoint: opts.endpoint,
|
|
48
|
+
payload: opts.payload,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
failure = new DshError('transport', `DSH remote mux send error: ${err.message}`);
|
|
53
|
+
ended = true;
|
|
54
|
+
settle(undefined);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
socket.onmessage = (event) => {
|
|
58
|
+
if (ended)
|
|
59
|
+
return;
|
|
60
|
+
const text = typeof event.data === 'string'
|
|
61
|
+
? event.data
|
|
62
|
+
: Buffer.isBuffer(event.data)
|
|
63
|
+
? event.data.toString('utf8')
|
|
64
|
+
: String(event.data);
|
|
65
|
+
let message;
|
|
66
|
+
try {
|
|
67
|
+
message = JSON.parse(text);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
getLogger().warn('[dsh] dropped malformed remote mux frame');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (message.streamId !== streamId)
|
|
74
|
+
return;
|
|
75
|
+
if (message.type === 'item' && message.value) {
|
|
76
|
+
settle(message.value);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (message.type === 'end') {
|
|
80
|
+
ended = true;
|
|
81
|
+
settle(undefined);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (message.type === 'error') {
|
|
85
|
+
failure = new DshError(message.error?.code ?? 'stream', message.error?.message ?? 'DSH remote stream failed', message.error?.details ?? {});
|
|
86
|
+
ended = true;
|
|
87
|
+
settle(undefined);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
socket.onerror = () => {
|
|
91
|
+
if (ended)
|
|
92
|
+
return;
|
|
93
|
+
failure = new DshError('transport', 'DSH remote mux WebSocket error');
|
|
94
|
+
ended = true;
|
|
95
|
+
settle(undefined);
|
|
96
|
+
};
|
|
97
|
+
socket.onunexpectedresponse = (event) => {
|
|
98
|
+
if (ended)
|
|
99
|
+
return;
|
|
100
|
+
const status = event.statusCode;
|
|
101
|
+
failure = new DshError('http', `DSH remote mux WebSocket HTTP ${status === undefined ? 'error' : status}`, status === undefined ? {} : { status });
|
|
102
|
+
ended = true;
|
|
103
|
+
settle(undefined);
|
|
104
|
+
};
|
|
105
|
+
socket.onclose = () => {
|
|
106
|
+
if (ended)
|
|
107
|
+
return;
|
|
108
|
+
ended = true;
|
|
109
|
+
settle(undefined);
|
|
110
|
+
};
|
|
111
|
+
const onAbort = () => {
|
|
112
|
+
if (ended)
|
|
113
|
+
return;
|
|
114
|
+
ended = true;
|
|
115
|
+
settle(undefined);
|
|
116
|
+
try {
|
|
117
|
+
socket.close();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
/* ignore close error */
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
opts.signal.addEventListener('abort', onAbort, { once: true });
|
|
124
|
+
const next = () => new Promise((resolve) => {
|
|
125
|
+
if (queue.length > 0) {
|
|
126
|
+
resolve(queue.shift());
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (ended) {
|
|
130
|
+
resolve(undefined);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
waiter = resolve;
|
|
134
|
+
});
|
|
135
|
+
try {
|
|
136
|
+
while (!opts.signal.aborted) {
|
|
137
|
+
const frame = await next();
|
|
138
|
+
if (frame === undefined) {
|
|
139
|
+
if (failure && !opts.signal.aborted)
|
|
140
|
+
throw failure;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
yield frame;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
clearTimeout(connectTimer);
|
|
148
|
+
opts.signal.removeEventListener('abort', onAbort);
|
|
149
|
+
try {
|
|
150
|
+
socket.close();
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* ignore close error */
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=mux-stream.js.map
|
|
@@ -25,13 +25,6 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import type { AgentEvent, ResultEvent } from '../types.js';
|
|
27
27
|
import type { DshAssistantStreamFrame, DshSessionEvent, DshTokenUsage } from './types.js';
|
|
28
|
-
/** 本 turn 各采样用量之和(input 是非缓存输入,与 ccusage/ResultEvent 口径一致)。 */
|
|
29
|
-
interface UsageTotals {
|
|
30
|
-
input: number;
|
|
31
|
-
output: number;
|
|
32
|
-
cacheRead: number;
|
|
33
|
-
cacheWrite: number;
|
|
34
|
-
}
|
|
35
28
|
export declare class DshTranslator {
|
|
36
29
|
/** 本 turn 累计用量:DSH 每次模型调用(step)一条 usage,工具往返 = 多条。 */
|
|
37
30
|
private turnUsage;
|
|
@@ -63,6 +56,3 @@ export declare class DshTranslator {
|
|
|
63
56
|
}
|
|
64
57
|
/** Map DSH TokenUsage → ResultEvent.usage (cacheWrite = cache creation). */
|
|
65
58
|
export declare function mapUsage(u: DshTokenUsage): NonNullable<ResultEvent['usage']>;
|
|
66
|
-
/** Map a turn's summed usage → ResultEvent.usage (cacheWrite = cache creation). */
|
|
67
|
-
export declare function mapAggregatedUsage(t: UsageTotals): NonNullable<ResultEvent['usage']>;
|
|
68
|
-
export {};
|
|
@@ -265,7 +265,7 @@ export function mapUsage(u) {
|
|
|
265
265
|
});
|
|
266
266
|
}
|
|
267
267
|
/** Map a turn's summed usage → ResultEvent.usage (cacheWrite = cache creation). */
|
|
268
|
-
|
|
268
|
+
function mapAggregatedUsage(t) {
|
|
269
269
|
return {
|
|
270
270
|
input_tokens: t.input,
|
|
271
271
|
output_tokens: t.output,
|
package/dist/runner/index.d.ts
CHANGED
|
@@ -15,6 +15,6 @@ export { KimiAcpRunner } from './kimi/index.js';
|
|
|
15
15
|
export { DshRunner } from './dsh/index.js';
|
|
16
16
|
export { BashProcessRunner, type BashRunner } from './bash/index.js';
|
|
17
17
|
export { AgentRegistry } from './registry.js';
|
|
18
|
-
export type { ResultEvent, PlanEvent, FileChangeEvent, AgentEvent, Runner, RunnerLifetime, AgentKind, AgentSession, AgentSessionContentEvent, AgentSessionUsage, SessionContent, SessionSummary, AgentSessionReader, AgentRunner, TurnStartedEvent, TurnDiffEvent, NoticeEvent, SessionInfoEvent, ToolHint, ApprovalView, ApprovalRequestedEvent, ApprovalResolvedEvent, GoalView, GoalStateEvent, } from './types.js';
|
|
18
|
+
export type { ResultEvent, PlanEvent, FileChangeEvent, AgentEvent, Runner, RunnerLifetime, AgentKind, AgentSession, AgentSessionContentEvent, AgentSessionUsage, SessionContent, SessionSummary, AgentSessionReader, AgentRunner, TurnStartedEvent, TurnDiffEvent, FinalAnswerEvent, NoticeEvent, SessionInfoEvent, ToolHint, ApprovalView, ApprovalRequestedEvent, ApprovalResolvedEvent, GoalView, GoalStateEvent, } from './types.js';
|
|
19
19
|
export { resolveAgentChoices } from './resolve-agent-choices.js';
|
|
20
20
|
export { syncAgentChoices } from './sync-agent-choices.js';
|
|
@@ -159,18 +159,7 @@ export class KimiAcpTranslator extends BaseAcpTranslator {
|
|
|
159
159
|
// 才提供「本会话总是允许」(acceptForSession);否则与旧行为一致。
|
|
160
160
|
availableDecisions: deriveAcpAvailableDecisions(params.options ?? []),
|
|
161
161
|
};
|
|
162
|
-
return
|
|
163
|
-
{
|
|
164
|
-
type: 'approval_requested',
|
|
165
|
-
requestId,
|
|
166
|
-
kind: 'command',
|
|
167
|
-
threadId: params.sessionId,
|
|
168
|
-
turnId: '',
|
|
169
|
-
itemId: '',
|
|
170
|
-
view,
|
|
171
|
-
timestamp: new Date().toISOString(),
|
|
172
|
-
},
|
|
173
|
-
];
|
|
162
|
+
return this.approvalRequestedEvents(requestId, params.sessionId, view);
|
|
174
163
|
}
|
|
175
164
|
handleOtherServerRequest(requestId, method, params) {
|
|
176
165
|
if (method !== ServerRequestMethod.ELICITATION_CREATE) {
|
|
@@ -189,18 +189,7 @@ export class OpencodeAcpTranslator extends BaseAcpTranslator {
|
|
|
189
189
|
// 才提供「本会话总是允许」(acceptForSession)。
|
|
190
190
|
availableDecisions: deriveAcpAvailableDecisions(params.options ?? []),
|
|
191
191
|
};
|
|
192
|
-
return
|
|
193
|
-
{
|
|
194
|
-
type: 'approval_requested',
|
|
195
|
-
requestId,
|
|
196
|
-
kind: 'command',
|
|
197
|
-
threadId: params.sessionId,
|
|
198
|
-
turnId: '',
|
|
199
|
-
itemId: '',
|
|
200
|
-
view,
|
|
201
|
-
timestamp: new Date().toISOString(),
|
|
202
|
-
},
|
|
203
|
-
];
|
|
192
|
+
return this.approvalRequestedEvents(requestId, params.sessionId, view);
|
|
204
193
|
}
|
|
205
194
|
}
|
|
206
195
|
// =============================================================================
|
|
@@ -10,15 +10,9 @@
|
|
|
10
10
|
* `result` from that response.
|
|
11
11
|
* - `agent_settled` is ignored for compaction turns (no double result).
|
|
12
12
|
*/
|
|
13
|
-
import type { AgentEvent, ResultEvent } from '../../types.js';
|
|
13
|
+
import type { AgentEvent, ResultEvent, TurnStartedEvent } from '../../types.js';
|
|
14
14
|
import { type PiRpcEvent, type PiRpcResponse } from './protocol-types.js';
|
|
15
|
-
export
|
|
16
|
-
type: 'turn_started';
|
|
17
|
-
threadId: string;
|
|
18
|
-
turnId: string;
|
|
19
|
-
operationKind: 'turn' | 'compaction';
|
|
20
|
-
timestamp?: string;
|
|
21
|
-
}
|
|
15
|
+
export type PiRpcTurnStartedEvent = TurnStartedEvent;
|
|
22
16
|
export type PiRpcTranslatorEvent = AgentEvent | PiRpcTurnStartedEvent;
|
|
23
17
|
export declare class PiRpcTranslator {
|
|
24
18
|
private content;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* `result` from that response.
|
|
11
11
|
* - `agent_settled` is ignored for compaction turns (no double result).
|
|
12
12
|
*/
|
|
13
|
+
import { makeTurnStartedEvent } from '../../common/turn-started.js';
|
|
13
14
|
export class PiRpcTranslator {
|
|
14
15
|
content = [];
|
|
15
16
|
currentContentIndex = -1;
|
|
@@ -135,13 +136,7 @@ export class PiRpcTranslator {
|
|
|
135
136
|
/** Self-produced turn_started (no wire equivalent). */
|
|
136
137
|
produceTurnStarted(sessionId, turnId) {
|
|
137
138
|
this.sessionId = sessionId;
|
|
138
|
-
return
|
|
139
|
-
type: 'turn_started',
|
|
140
|
-
threadId: sessionId,
|
|
141
|
-
turnId,
|
|
142
|
-
operationKind: this.operationKind === 'compact' ? 'compaction' : 'turn',
|
|
143
|
-
timestamp: new Date().toISOString(),
|
|
144
|
-
};
|
|
139
|
+
return makeTurnStartedEvent(sessionId, turnId, this.operationKind);
|
|
145
140
|
}
|
|
146
141
|
/** Result for a completed normal turn (agent_settled). */
|
|
147
142
|
produceResultFromSettled() {
|
|
@@ -14,28 +14,9 @@ import type { AgentKind, Runner } from './index.js';
|
|
|
14
14
|
*/
|
|
15
15
|
export declare class AgentRegistry {
|
|
16
16
|
private readonly factories;
|
|
17
|
-
private readonly displayNames;
|
|
18
17
|
/** Container for runtime config updates (pi provider dynamic reload). */
|
|
19
18
|
private configContainer?;
|
|
20
19
|
register(kind: AgentKind, factory: (cwd: string) => Runner): void;
|
|
21
|
-
/**
|
|
22
|
-
* 注册 agent 的显示名。应在 register(kind, factory) 后调用。
|
|
23
|
-
* 用于 agentDisplayName 等全局查询,实现单点真相。
|
|
24
|
-
*/
|
|
25
|
-
registerDisplayName(kind: AgentKind, displayName: string): void;
|
|
26
|
-
/**
|
|
27
|
-
* 获取 agent 显示名。未注册时返回原始 kind。
|
|
28
|
-
*/
|
|
29
|
-
getDisplayName(kind: AgentKind): string;
|
|
30
|
-
/**
|
|
31
|
-
* 设置全局 registry 实例,供 agentDisplayName 等全局函数使用。
|
|
32
|
-
* 在 index.ts 初始化所有 agents 后调用。
|
|
33
|
-
*/
|
|
34
|
-
static setGlobalInstance(reg: AgentRegistry | undefined): void;
|
|
35
|
-
/**
|
|
36
|
-
* 获取全局 registry 实例。
|
|
37
|
-
*/
|
|
38
|
-
static getGlobalInstance(): AgentRegistry | undefined;
|
|
39
20
|
/**
|
|
40
21
|
* Set config container reference. Call after bridge config is updated.
|
|
41
22
|
* Factory functions can read latest config from here.
|
package/dist/runner/registry.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 单例 registry 实例,供 agentDisplayName 等全局查询使用。
|
|
3
|
-
* 在 index.ts 初始化后设置。
|
|
4
|
-
*/
|
|
5
|
-
let globalRegistry;
|
|
6
1
|
/**
|
|
7
2
|
* Registry of agent factories, keyed by `AgentKind`. `index.ts` registers one
|
|
8
3
|
* factory per available agent at startup; `Bridge.getRunner(cwd)` looks
|
|
@@ -18,38 +13,11 @@ let globalRegistry;
|
|
|
18
13
|
*/
|
|
19
14
|
export class AgentRegistry {
|
|
20
15
|
factories = new Map();
|
|
21
|
-
displayNames = new Map();
|
|
22
16
|
/** Container for runtime config updates (pi provider dynamic reload). */
|
|
23
17
|
configContainer;
|
|
24
18
|
register(kind, factory) {
|
|
25
19
|
this.factories.set(kind, factory);
|
|
26
20
|
}
|
|
27
|
-
/**
|
|
28
|
-
* 注册 agent 的显示名。应在 register(kind, factory) 后调用。
|
|
29
|
-
* 用于 agentDisplayName 等全局查询,实现单点真相。
|
|
30
|
-
*/
|
|
31
|
-
registerDisplayName(kind, displayName) {
|
|
32
|
-
this.displayNames.set(kind, displayName);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* 获取 agent 显示名。未注册时返回原始 kind。
|
|
36
|
-
*/
|
|
37
|
-
getDisplayName(kind) {
|
|
38
|
-
return this.displayNames.get(kind) ?? kind;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* 设置全局 registry 实例,供 agentDisplayName 等全局函数使用。
|
|
42
|
-
* 在 index.ts 初始化所有 agents 后调用。
|
|
43
|
-
*/
|
|
44
|
-
static setGlobalInstance(reg) {
|
|
45
|
-
globalRegistry = reg;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* 获取全局 registry 实例。
|
|
49
|
-
*/
|
|
50
|
-
static getGlobalInstance() {
|
|
51
|
-
return globalRegistry;
|
|
52
|
-
}
|
|
53
21
|
/**
|
|
54
22
|
* Set config container reference. Call after bridge config is updated.
|
|
55
23
|
* Factory functions can read latest config from here.
|
package/dist/runner/types.d.ts
CHANGED
|
@@ -263,6 +263,22 @@ export interface AssistantEvent {
|
|
|
263
263
|
content: AssistantContent[];
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Authoritative final answer from an agent protocol.
|
|
268
|
+
*
|
|
269
|
+
* This is deliberately separate from ordinary assistant text: progress
|
|
270
|
+
* narration and tool-loop messages have lower display priority than the answer
|
|
271
|
+
* the user actually asked for. Agents without an explicit protocol marker
|
|
272
|
+
* promote their last text block when the turn finishes.
|
|
273
|
+
*/
|
|
274
|
+
export interface FinalAnswerEvent {
|
|
275
|
+
type: 'final_answer';
|
|
276
|
+
text: string;
|
|
277
|
+
/** Source item id, used to remove the streamed progress copy of the answer. */
|
|
278
|
+
itemId?: string;
|
|
279
|
+
complete?: boolean;
|
|
280
|
+
timestamp?: string;
|
|
281
|
+
}
|
|
266
282
|
export interface UserEvent {
|
|
267
283
|
type: 'user';
|
|
268
284
|
timestamp?: string;
|
|
@@ -470,7 +486,7 @@ export interface TurnDiffEvent {
|
|
|
470
486
|
export type RunnerLifetime = 'turn' | 'workspace';
|
|
471
487
|
/** 工具渲染 hint:runner 自愿声明,渲染层只消费不推断。 */
|
|
472
488
|
export type ToolHint = 'shell' | 'file' | 'search' | 'web' | 'patch';
|
|
473
|
-
export type AgentEvent = SystemInitEvent | SystemCompactEvent | ApprovalRequestedEvent | ApprovalResolvedEvent | ApprovalViewUpdatedEvent | ApprovalExpiredEvent | AssistantEvent | UserEvent | ResultEvent | PlanEvent | FileChangeEvent | TurnStartedEvent | TurnDiffEvent | NoticeEvent | SessionInfoEvent | RunStatusEvent | BackgroundJobsEvent | GoalStateEvent;
|
|
489
|
+
export type AgentEvent = SystemInitEvent | SystemCompactEvent | ApprovalRequestedEvent | ApprovalResolvedEvent | ApprovalViewUpdatedEvent | ApprovalExpiredEvent | AssistantEvent | FinalAnswerEvent | UserEvent | ResultEvent | PlanEvent | FileChangeEvent | TurnStartedEvent | TurnDiffEvent | NoticeEvent | SessionInfoEvent | RunStatusEvent | BackgroundJobsEvent | GoalStateEvent;
|
|
474
490
|
export interface SpawnOptions {
|
|
475
491
|
cwd: string;
|
|
476
492
|
sessionId?: string;
|
|
@@ -277,14 +277,16 @@ export class SessionIndex {
|
|
|
277
277
|
if (!st.isDirectory())
|
|
278
278
|
continue;
|
|
279
279
|
}
|
|
280
|
-
catch {
|
|
280
|
+
catch (err) {
|
|
281
|
+
getLogger().debug(`[session-index] skipped unreadable project dir ${subdir}: ${err?.message ?? String(err)}`);
|
|
281
282
|
continue;
|
|
282
283
|
}
|
|
283
284
|
let files;
|
|
284
285
|
try {
|
|
285
286
|
files = fs.readdirSync(subdir).filter((f) => f.endsWith('.jsonl'));
|
|
286
287
|
}
|
|
287
|
-
catch {
|
|
288
|
+
catch (err) {
|
|
289
|
+
getLogger().debug(`[session-index] skipped unreadable project subdir ${subdir}: ${err?.message ?? String(err)}`);
|
|
288
290
|
continue;
|
|
289
291
|
}
|
|
290
292
|
for (const f of files) {
|
|
@@ -215,8 +215,8 @@ export class KimiSessionReader {
|
|
|
215
215
|
state = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
|
|
216
216
|
stateParsed = true;
|
|
217
217
|
}
|
|
218
|
-
catch {
|
|
219
|
-
|
|
218
|
+
catch (err) {
|
|
219
|
+
getLogger().debug(`[kimi-session-reader] corrupt state.json skipped session=${entry.sessionId}: ${err?.message ?? String(err)}`);
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
// Index workDir is v1-only; v2 sessions may have empty/missing workDir.
|
|
@@ -510,7 +510,8 @@ export class OpencodeSessionReader {
|
|
|
510
510
|
// Check if updated within STALE_MS
|
|
511
511
|
return !isStale(entry.updated);
|
|
512
512
|
}
|
|
513
|
-
catch {
|
|
513
|
+
catch (err) {
|
|
514
|
+
getLogger().debug(`[opencode-session-reader] isSessionActive failed session=${sessionId}: ${err?.message ?? String(err)}`);
|
|
514
515
|
return false;
|
|
515
516
|
}
|
|
516
517
|
}
|
|
@@ -10,6 +10,7 @@ import { encodeProjectDirName, samePath } from '../../platform/path.js';
|
|
|
10
10
|
import { paginate } from '../common/pagination.js';
|
|
11
11
|
import { sortByRecencyDesc } from '../common/recency.js';
|
|
12
12
|
import { TtlCache } from '../../common/ttl-cache.js';
|
|
13
|
+
import { getLogger } from '../../logger/index.js';
|
|
13
14
|
function defaultPiDir() {
|
|
14
15
|
return path.join(os.homedir(), '.pi', 'agent');
|
|
15
16
|
}
|
|
@@ -356,8 +357,8 @@ export class PiSessionReader {
|
|
|
356
357
|
mtime: st.mtimeMs,
|
|
357
358
|
});
|
|
358
359
|
}
|
|
359
|
-
catch {
|
|
360
|
-
|
|
360
|
+
catch (err) {
|
|
361
|
+
getLogger().debug(`[pi-session-reader] skipped ${full}: ${err?.message ?? String(err)}`);
|
|
361
362
|
}
|
|
362
363
|
}
|
|
363
364
|
// Same-mtime ties: secondary key keeps the full order deterministic.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lark-remote",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.13",
|
|
4
4
|
"description": "Feishu (Lark) private-chat bridge to local coding agents — Claude Code / Codex / opencode / pi / kimi, with live-streaming CardKit 2.0 cards",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|