lark-remote 0.5.19 → 0.5.21
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 +29 -0
- package/dist/bridge/approval-actions.d.ts +1 -1
- package/dist/bridge/approval-actions.js +1 -1
- package/dist/bridge/bash-run.d.ts +71 -0
- package/dist/bridge/bash-run.js +217 -0
- package/dist/bridge/compact.d.ts +155 -0
- package/dist/bridge/compact.js +450 -0
- package/dist/bridge/final-usage.js +4 -4
- package/dist/bridge/inbound-media.js +72 -46
- package/dist/bridge/index.d.ts +106 -153
- package/dist/bridge/index.js +400 -1000
- package/dist/bridge/job-watch.d.ts +68 -0
- package/dist/bridge/job-watch.js +146 -0
- package/dist/bridge/queue-manager.d.ts +3 -3
- package/dist/bridge/queue-manager.js +10 -29
- package/dist/card/approval-render.d.ts +2 -2
- package/dist/card/approval-render.js +141 -130
- package/dist/card/card-budget.js +123 -98
- package/dist/card/card-helpers.d.ts +3 -3
- package/dist/card/card-helpers.js +6 -6
- package/dist/card/final-answer-file.js +1 -1
- package/dist/card/run-renderer.d.ts +3 -3
- package/dist/card/run-renderer.js +114 -159
- package/dist/card/run-state.d.ts +1 -15
- package/dist/card/run-state.js +358 -292
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +21 -17
- package/dist/card/usage-format.d.ts +22 -7
- package/dist/card/usage-format.js +119 -100
- package/dist/cli.js +15 -3
- package/dist/clone.js +2 -2
- package/dist/common/text-width.js +36 -24
- package/dist/common/tool-summary.js +132 -90
- package/dist/config/codex-config.js +130 -106
- package/dist/config/index.d.ts +16 -2
- package/dist/config/index.js +23 -8
- package/dist/connector/index.js +6 -6
- package/dist/error-classification.js +3 -2
- package/dist/inbound/placeholder.d.ts +1 -1
- package/dist/inbound/placeholder.js +1 -1
- package/dist/index.js +387 -281
- package/dist/logger/index.js +6 -6
- package/dist/message-handlers.d.ts +0 -5
- package/dist/message-handlers.js +254 -237
- package/dist/model-catalog.d.ts +2 -2
- package/dist/model-catalog.js +3 -8
- package/dist/platform/identity.js +1 -1
- package/dist/platform/path.d.ts +1 -1
- package/dist/platform/path.js +1 -1
- package/dist/platform/sleep-blocker.js +1 -1
- package/dist/platform/terminator-win32.js +2 -1
- package/dist/router/commands/ls.d.ts +3 -0
- package/dist/router/commands/ls.js +256 -175
- package/dist/router/commands/order.js +184 -159
- package/dist/router/commands/resume.js +190 -152
- package/dist/router/commands/ws.js +219 -174
- package/dist/router/config/dsh.d.ts +4 -8
- package/dist/router/config/dsh.js +3 -10
- package/dist/router/config/kimi.js +1 -1
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/config-diff.js +1 -1
- package/dist/router/index.d.ts +56 -11
- package/dist/router/index.js +401 -391
- package/dist/runner/bash/runner.js +2 -4
- package/dist/runner/claude/session.d.ts +1 -1
- package/dist/runner/claude/session.js +6 -4
- package/dist/runner/codex/app-server/runner.d.ts +9 -2
- package/dist/runner/codex/app-server/runner.js +30 -25
- package/dist/runner/codex/app-server/translator.d.ts +2 -5
- package/dist/runner/codex/app-server/translator.js +291 -238
- package/dist/runner/common/acp/acp-approval.d.ts +1 -1
- package/dist/runner/common/acp/acp-approval.js +1 -1
- package/dist/runner/common/acp/base-acp-runner.d.ts +5 -2
- package/dist/runner/common/acp/base-acp-runner.js +26 -65
- package/dist/runner/common/acp/base-translator.d.ts +12 -2
- package/dist/runner/common/acp/base-translator.js +50 -26
- package/dist/runner/common/acp/protocol-types.d.ts +1 -1
- package/dist/runner/common/acp/protocol-types.js +2 -2
- package/dist/runner/common/connection-based-runner.d.ts +32 -1
- package/dist/runner/common/connection-based-runner.js +32 -2
- package/dist/runner/common/jsonl-stream.js +154 -187
- package/dist/runner/common/jsonrpc/client.d.ts +29 -0
- package/dist/runner/common/jsonrpc/client.js +43 -12
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +2 -2
- package/dist/runner/common/jsonrpc/connection-manager.js +4 -4
- package/dist/runner/common/spawning-runner.d.ts +6 -1
- package/dist/runner/common/spawning-runner.js +9 -4
- package/dist/runner/common/turn-started.d.ts +8 -0
- package/dist/runner/common/turn-started.js +11 -0
- package/dist/runner/dsh/approval.js +84 -51
- package/dist/runner/dsh/catalog-probe.d.ts +17 -0
- package/dist/runner/dsh/catalog-probe.js +10 -0
- package/dist/runner/dsh/client.d.ts +7 -11
- package/dist/runner/dsh/client.js +356 -289
- package/dist/runner/dsh/exit-cancel.d.ts +2 -2
- package/dist/runner/dsh/exit-cancel.js +2 -2
- package/dist/runner/dsh/inflight.d.ts +1 -1
- package/dist/runner/dsh/inflight.js +1 -1
- package/dist/runner/dsh/mux-stream.js +28 -8
- package/dist/runner/dsh/runner.d.ts +44 -4
- package/dist/runner/dsh/runner.js +296 -199
- package/dist/runner/dsh/translator.d.ts +1 -31
- package/dist/runner/dsh/translator.js +180 -178
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +1 -2
- package/dist/runner/kimi/acp/runner.js +82 -46
- package/dist/runner/kimi/acp/translator.d.ts +1 -1
- package/dist/runner/kimi/acp/translator.js +3 -4
- package/dist/runner/opencode/acp/error-monitor.js +5 -5
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/pi/rpc/client.js +4 -13
- package/dist/runner/pi/rpc/protocol-types.d.ts +1 -1
- package/dist/runner/pi/rpc/protocol-types.js +1 -1
- package/dist/runner/pi/rpc/runner.d.ts +3 -0
- package/dist/runner/pi/rpc/runner.js +27 -42
- package/dist/runner/pi/rpc/translator.js +61 -60
- package/dist/runner/types.d.ts +2 -2
- package/dist/runner/types.js +1 -1
- package/dist/session/claude/sessions.d.ts +45 -0
- package/dist/session/claude/sessions.js +160 -122
- package/dist/session/codex/rollout-reader.js +181 -182
- package/dist/session/common/throw-session-list-error.d.ts +10 -0
- package/dist/session/common/throw-session-list-error.js +16 -0
- package/dist/session/dsh/sessions.js +291 -235
- package/dist/session/kimi/sessions.d.ts +40 -8
- package/dist/session/kimi/sessions.js +373 -301
- package/dist/session/opencode/sessions.d.ts +142 -1
- package/dist/session/opencode/sessions.js +378 -321
- package/dist/session/pi/sessions.js +4 -5
- package/dist/session/session-store.d.ts +9 -1
- package/dist/session/session-store.js +99 -99
- package/dist/update/version-check.js +2 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.js +1 -1
- package/package.json +1 -1
|
@@ -32,6 +32,49 @@ import { summarizeToolInput } from '../../common/tool-summary.js';
|
|
|
32
32
|
* (若 DSH 支持分页 cursor 可改成分页,当前用有界大拉取)
|
|
33
33
|
*/
|
|
34
34
|
const DSH_HISTORY_FETCH_LIMIT = 10_000;
|
|
35
|
+
/** curl 传输层失败(spawn error / 非零退出)→ 统一错误;成功返回 undefined。 */
|
|
36
|
+
function dshSpawnFailure(prefix, res) {
|
|
37
|
+
if (res.error || res.status !== 0) {
|
|
38
|
+
return new Error(`${prefix}: ${(res.error?.message ?? res.stderr) || 'unknown'}`);
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
/** 从 curl stdout 拆出末尾 HTTP 状态码与 body(`--write-out \n%{http_code}`)。 */
|
|
43
|
+
function splitDshHttpResponse(raw) {
|
|
44
|
+
const statusMatch = /\n(\d{3})$/.exec(raw);
|
|
45
|
+
const httpStatus = statusMatch ? Number(statusMatch[1]) : undefined;
|
|
46
|
+
const bodyText = statusMatch ? raw.slice(0, statusMatch.index) : raw;
|
|
47
|
+
return { httpStatus, bodyText };
|
|
48
|
+
}
|
|
49
|
+
/** 解析 result 信封;非 JSON / ok!==true 按原文案抛错。 */
|
|
50
|
+
function parseDshResult(method, bodyText) {
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(bodyText);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
throw new Error(`DSH ${method} returned non-JSON: ${err.message}`, {
|
|
57
|
+
cause: err,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (parsed.result?.ok !== true) {
|
|
61
|
+
throw new Error(parsed.result?.error?.message ?? `DSH ${method} failed`);
|
|
62
|
+
}
|
|
63
|
+
return parsed.result.value;
|
|
64
|
+
}
|
|
65
|
+
/** 从 `-D -` 响应头里取第一条 set-cookie 的 name=value 段。 */
|
|
66
|
+
function firstSetCookie(header) {
|
|
67
|
+
const match = header.match(/^set-cookie:\s*(.+)$/im);
|
|
68
|
+
return match?.[1]?.split(';')[0]?.trim();
|
|
69
|
+
}
|
|
70
|
+
/** 重试仍失败:二次错为 cause,首错(cookie 失效)作为根因写进 message。 */
|
|
71
|
+
function cookieRefreshFailure(method, first, second) {
|
|
72
|
+
const firstMsg = first?.message ?? String(first);
|
|
73
|
+
const secondMsg = second?.message ?? String(second);
|
|
74
|
+
// 重试仍失败:首错(cookie 失效)才是根因。`cause` 必须是本次捕获的 err
|
|
75
|
+
// (lint preserve-caught-error),所以根因写进 message 一并留痕。
|
|
76
|
+
return new Error(`DSH ${method} failed after cookie refresh: ${secondMsg} (root cause: ${firstMsg})`, { cause: second });
|
|
77
|
+
}
|
|
35
78
|
/** Synchronous unary POST via curl (the reader interface is synchronous). */
|
|
36
79
|
function defaultSyncRequest(baseUrl, method, payload, cookie) {
|
|
37
80
|
const body = JSON.stringify({
|
|
@@ -54,40 +97,23 @@ function defaultSyncRequest(baseUrl, method, payload, cookie) {
|
|
|
54
97
|
'--write-out',
|
|
55
98
|
'\n%{http_code}',
|
|
56
99
|
], { encoding: 'utf-8', timeout: 15_000, maxBuffer: 64 * 1024 * 1024 });
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
const statusMatch = /\n(\d{3})$/.exec(raw);
|
|
62
|
-
const httpStatus = statusMatch ? Number(statusMatch[1]) : undefined;
|
|
63
|
-
const bodyText = statusMatch ? raw.slice(0, statusMatch.index) : raw;
|
|
100
|
+
const failure = dshSpawnFailure(`DSH ${method} failed`, res);
|
|
101
|
+
if (failure)
|
|
102
|
+
throw failure;
|
|
103
|
+
const { httpStatus, bodyText } = splitDshHttpResponse(String(res.stdout));
|
|
64
104
|
if (httpStatus === 401 || httpStatus === 403) {
|
|
65
105
|
throw new Error(`DSH ${method} unauthorized (HTTP ${httpStatus})`);
|
|
66
106
|
}
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
parsed = JSON.parse(bodyText);
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
throw new Error(`DSH ${method} returned non-JSON: ${err.message}`, {
|
|
73
|
-
cause: err,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
if (parsed.result?.ok !== true) {
|
|
77
|
-
throw new Error(parsed.result?.error?.message ?? `DSH ${method} failed`);
|
|
78
|
-
}
|
|
79
|
-
return parsed.result.value;
|
|
107
|
+
return parseDshResult(method, bodyText);
|
|
80
108
|
}
|
|
81
109
|
/** Synchronous index bootstrap; returns the v1 `name=value` cookie pair. */
|
|
82
110
|
function defaultSyncConnect(baseUrl, token) {
|
|
83
111
|
const url = `${baseUrl}/?token=${encodeURIComponent(token)}`;
|
|
84
112
|
const res = spawnProcessSync('curl', ['-sS', '-D', '-', '-o', isWin32() ? 'NUL' : '/dev/null', '--max-time', '5', url], { encoding: 'utf-8', timeout: 10_000, maxBuffer: 1024 * 1024 });
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
const match = header.match(/^set-cookie:\s*(.+)$/im);
|
|
90
|
-
const cookie = match?.[1]?.split(';')[0]?.trim();
|
|
113
|
+
const failure = dshSpawnFailure('DSH auth failed', res);
|
|
114
|
+
if (failure)
|
|
115
|
+
throw failure;
|
|
116
|
+
const cookie = firstSetCookie(String(res.stdout));
|
|
91
117
|
if (!cookie)
|
|
92
118
|
throw new Error('DSH auth failed: index handshake did not return a cookie');
|
|
93
119
|
return cookie;
|
|
@@ -149,11 +175,7 @@ export class DshSessionReader {
|
|
|
149
175
|
return this.syncRequest(baseUrl, method, payload, this.resolveCookie());
|
|
150
176
|
}
|
|
151
177
|
catch (second) {
|
|
152
|
-
|
|
153
|
-
// (lint preserve-caught-error),所以根因写进 message 一并留痕。
|
|
154
|
-
const firstMsg = first?.message ?? String(first);
|
|
155
|
-
const secondMsg = second?.message ?? String(second);
|
|
156
|
-
throw new Error(`DSH ${method} failed after cookie refresh: ${secondMsg} (root cause: ${firstMsg})`, { cause: second });
|
|
178
|
+
throw cookieRefreshFailure(method, first, second);
|
|
157
179
|
}
|
|
158
180
|
}
|
|
159
181
|
}
|
|
@@ -211,8 +233,12 @@ export class DshSessionReader {
|
|
|
211
233
|
return { sessions: page, total };
|
|
212
234
|
}
|
|
213
235
|
catch (error) {
|
|
214
|
-
|
|
215
|
-
|
|
236
|
+
// 远端 RPC 没有真空态:daemon 未启动 / cookie 失效 / 超时全是故障态。
|
|
237
|
+
// error 日志 + 上抛,router 显示「列表失败」——静默 [] 会让用户误以为
|
|
238
|
+
// 没有 session,与真空不可区分(与 kimi/opencode 同口径)。
|
|
239
|
+
getLogger().error(`[dsh-session-reader] listSessions failed: ${error}`);
|
|
240
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
241
|
+
throw new Error(`dsh session list 读取失败: ${msg}`, { cause: error });
|
|
216
242
|
}
|
|
217
243
|
}
|
|
218
244
|
getNewestSession(cwd) {
|
|
@@ -237,128 +263,12 @@ export class DshSessionReader {
|
|
|
237
263
|
throughSeq,
|
|
238
264
|
maxMessages: DSH_HISTORY_FETCH_LIMIT,
|
|
239
265
|
});
|
|
240
|
-
|
|
241
|
-
let displayTitle;
|
|
242
|
-
let cumInput = 0;
|
|
243
|
-
let cumOutput = 0;
|
|
244
|
-
let cumCacheRead = 0;
|
|
245
|
-
let cumCacheWrite = 0;
|
|
246
|
-
let lastUsage;
|
|
247
|
-
// 末个 turn 内各采样用量之和("本 run / 末轮" scope)。DSH 每次模型调用
|
|
248
|
-
// 一条 usage,工具往返的 turn 会写多条 assistant/message;只取末条会把
|
|
249
|
-
// 多步 run 低报(实测 231/689 显示成整轮真实消耗)。turn 边界取
|
|
250
|
-
// turn/start–turn/end,与 codex `task_started` 汇总同一口径(§9.21)。
|
|
251
|
-
// null = 历史里没有 turn 标记(旧数据/截断)→ 退回末条 usage 语义。
|
|
252
|
-
let turnUsage = null;
|
|
253
|
-
let lastTurnUsage = null;
|
|
254
|
-
/** 等结果的工具调用(见 MappedEvent.pendingTool)。 */
|
|
255
|
-
let pendingTool;
|
|
256
|
-
for (const entry of value.records ?? []) {
|
|
257
|
-
const ev = entry.event;
|
|
258
|
-
if (!ev)
|
|
259
|
-
continue;
|
|
260
|
-
if (ev.type === 'turn/start') {
|
|
261
|
-
turnUsage = emptyUsageTotals();
|
|
262
|
-
}
|
|
263
|
-
else if (ev.type === 'turn/end') {
|
|
264
|
-
if (turnUsage)
|
|
265
|
-
lastTurnUsage = turnUsage;
|
|
266
|
-
turnUsage = null;
|
|
267
|
-
}
|
|
268
|
-
const contentEvents = mapEvent(ev);
|
|
269
|
-
if (contentEvents.pendingTool) {
|
|
270
|
-
// 未完成的工具调用最多同时一个(DSH 按 step 串行执行;并行调用时按
|
|
271
|
-
// 到达顺序配对,最坏情况是两次调用共用一个面板,不会丢信息)。
|
|
272
|
-
if (pendingTool)
|
|
273
|
-
events.push(pendingTool);
|
|
274
|
-
pendingTool = contentEvents.pendingTool;
|
|
275
|
-
}
|
|
276
|
-
else if (ev.type === 'tool/result' && pendingTool && contentEvents.events[0]) {
|
|
277
|
-
const result = contentEvents.events[0];
|
|
278
|
-
// 标题沿用调用的 `🔧 name — summary`,失败改成 ❌(折叠态一眼看出结果)。
|
|
279
|
-
const failed = result.title?.startsWith('🔴') === true;
|
|
280
|
-
events.push({
|
|
281
|
-
type: 'tool_use',
|
|
282
|
-
title: failed
|
|
283
|
-
? (pendingTool.title ?? '❌ 工具').replace('🔧', '❌')
|
|
284
|
-
: pendingTool.title,
|
|
285
|
-
content: result.content,
|
|
286
|
-
timestamp: pendingTool.timestamp,
|
|
287
|
-
});
|
|
288
|
-
pendingTool = undefined;
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
events.push(...contentEvents.events);
|
|
292
|
-
}
|
|
293
|
-
if (contentEvents.title)
|
|
294
|
-
displayTitle = contentEvents.title;
|
|
295
|
-
const u = contentEvents.usage;
|
|
296
|
-
if (u) {
|
|
297
|
-
// Cumulative (session-wide): sum across ALL assistant/message usage.
|
|
298
|
-
cumInput += u.inputTokens ?? 0;
|
|
299
|
-
cumOutput += u.outputTokens ?? 0;
|
|
300
|
-
cumCacheRead += u.cacheReadTokens ?? 0;
|
|
301
|
-
cumCacheWrite += u.cacheWriteTokens ?? 0;
|
|
302
|
-
// 本 run 的 flow 字段 = 末个 turn 的采样之和;contextLength 用末次采样
|
|
303
|
-
// 的窗口占用(input + cacheRead + cacheWrite,不含 output)。
|
|
304
|
-
if (turnUsage) {
|
|
305
|
-
turnUsage.input += u.inputTokens ?? 0;
|
|
306
|
-
turnUsage.output += u.outputTokens ?? 0;
|
|
307
|
-
turnUsage.cacheRead += u.cacheReadTokens ?? 0;
|
|
308
|
-
turnUsage.cacheWrite += u.cacheWriteTokens ?? 0;
|
|
309
|
-
}
|
|
310
|
-
lastUsage = u;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
let sessionUsage;
|
|
314
|
-
if (lastUsage) {
|
|
315
|
-
const input = lastUsage.inputTokens ?? 0;
|
|
316
|
-
const cacheRead = lastUsage.cacheReadTokens ?? 0;
|
|
317
|
-
const cacheWrite = lastUsage.cacheWriteTokens ?? 0;
|
|
318
|
-
// 在途 turn(turn/start 无 turn/end,run 进行中读历史)的采样优先于
|
|
319
|
-
// 上一轮:旧实现只认已结算的 lastTurnUsage,mid-run 读取会把当前 turn
|
|
320
|
-
// 已消耗的量显示成上一个完整 turn 的数字。
|
|
321
|
-
const flow = turnUsage ??
|
|
322
|
-
lastTurnUsage ?? {
|
|
323
|
-
input,
|
|
324
|
-
output: lastUsage.outputTokens ?? 0,
|
|
325
|
-
cacheRead,
|
|
326
|
-
cacheWrite,
|
|
327
|
-
};
|
|
328
|
-
sessionUsage = {
|
|
329
|
-
inputTokens: flow.input,
|
|
330
|
-
outputTokens: flow.output,
|
|
331
|
-
// §9.21 口径:context 是末次采样的窗口水位(input + 末次 output +
|
|
332
|
-
// cache),不把整 turn 的 output 求和(前几步 output 已进入后续 input)。
|
|
333
|
-
contextLength: input + (lastUsage.outputTokens ?? 0) + cacheRead + cacheWrite,
|
|
334
|
-
cacheReadTokens: flow.cacheRead,
|
|
335
|
-
cacheCreationTokens: flow.cacheWrite,
|
|
336
|
-
totalTokens: flow.input + flow.output + flow.cacheRead + flow.cacheWrite,
|
|
337
|
-
...cumulativeUsageFields({
|
|
338
|
-
input: cumInput,
|
|
339
|
-
output: cumOutput,
|
|
340
|
-
cacheRead: cumCacheRead,
|
|
341
|
-
cacheCreation: cumCacheWrite,
|
|
342
|
-
}),
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
// 中断/仍在执行的调用没有结果:把它当独立事件留下,别让这一条消失。
|
|
346
|
-
if (pendingTool)
|
|
347
|
-
events.push(pendingTool);
|
|
348
|
-
// 头部信息口径:最近输入优先用服务端末轮 prompt(事件里可能只是当前 turn
|
|
349
|
-
// 的一部分),标题用服务端 title;两者都缺时保持原行为。
|
|
350
|
-
const headerLastInput = preview.lastUserMessage ?? displayTitle;
|
|
351
|
-
return {
|
|
352
|
-
// 展示仍按 maxEvents 尾截断(默认 50,保持原行为),usage 已在上面基于
|
|
353
|
-
// 完整 history 累加。
|
|
354
|
-
events: capEvents(events, opts?.maxEvents ?? 50),
|
|
355
|
-
...(sessionUsage ? { usage: sessionUsage } : {}),
|
|
356
|
-
...(headerLastInput ? { displayTitle: headerLastInput } : {}),
|
|
357
|
-
...(preview.title ? { aiTitle: preview.title } : {}),
|
|
358
|
-
};
|
|
266
|
+
return buildDshSessionContent(value, preview, opts);
|
|
359
267
|
}
|
|
360
268
|
catch (error) {
|
|
361
|
-
|
|
269
|
+
// 降级为空卡(与 claude/pi 同口径),但完整错误对象入日志保留 stack,
|
|
270
|
+
// 否则 wire 截断 / 权限问题只剩一句 message 无法定位。
|
|
271
|
+
getLogger().error(`[dsh-session-reader] readSessionContent failed: ${error}`);
|
|
362
272
|
return { events: [] };
|
|
363
273
|
}
|
|
364
274
|
}
|
|
@@ -367,7 +277,7 @@ export class DshSessionReader {
|
|
|
367
277
|
return this.resolveSession(sessionId, cwd)?.running === true;
|
|
368
278
|
}
|
|
369
279
|
catch (error) {
|
|
370
|
-
getLogger().error(`[dsh-session-reader] isSessionActive
|
|
280
|
+
getLogger().error(`[dsh-session-reader] isSessionActive failed: ${error}`);
|
|
371
281
|
return false;
|
|
372
282
|
}
|
|
373
283
|
}
|
|
@@ -502,97 +412,107 @@ function asBlocks(value) {
|
|
|
502
412
|
return [];
|
|
503
413
|
return value.filter((b) => !!b && typeof b === 'object');
|
|
504
414
|
}
|
|
505
|
-
function
|
|
415
|
+
function mapUserMessage(ev) {
|
|
416
|
+
const out = { events: [] };
|
|
417
|
+
const content = asBlocks(ev.data.content);
|
|
418
|
+
const text = content
|
|
419
|
+
.filter((c) => c.type === 'text')
|
|
420
|
+
.map((c) => c.text ?? '')
|
|
421
|
+
.join('');
|
|
422
|
+
if (!text.trim())
|
|
423
|
+
return out;
|
|
424
|
+
// DSH 把上下文注入也写成 user/message,靠 `source.kind` 区分。真实会话里
|
|
425
|
+
// 30 条 user/message 中只有 8 条是用户本人说的(其余是 time-context /
|
|
426
|
+
// agent-instructions / skill-catalog / goal / tool-jobs…)——照单全收会让
|
|
427
|
+
// 回顾卡里塞满"Time sampled while preparing turn…",还把系统提示标成 👤 你。
|
|
428
|
+
const source = ev.data.source;
|
|
429
|
+
const kind = typeof source?.kind === 'string' ? source.kind : undefined;
|
|
430
|
+
if (kind && CONTEXT_INJECTION_KINDS.has(kind))
|
|
431
|
+
return out;
|
|
432
|
+
const isNotice = kind !== undefined && kind !== 'user';
|
|
433
|
+
out.events.push({
|
|
434
|
+
type: isNotice ? 'notice' : 'user',
|
|
435
|
+
...(isNotice ? { title: '🔔 通知' } : {}),
|
|
436
|
+
content: isNotice ? truncateUtf8(text.trim(), NOTICE_MAX_BYTES) : text,
|
|
437
|
+
timestamp: safeEventTimestamp(ev.time),
|
|
438
|
+
});
|
|
439
|
+
return out;
|
|
440
|
+
}
|
|
441
|
+
function mapAssistantMessage(ev) {
|
|
506
442
|
const out = { events: [] };
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
// agent-instructions / skill-catalog / goal / tool-jobs…)——照单全收会让
|
|
519
|
-
// 回顾卡里塞满"Time sampled while preparing turn…",还把系统提示标成 👤 你。
|
|
520
|
-
const source = ev.data.source;
|
|
521
|
-
const kind = typeof source?.kind === 'string' ? source.kind : undefined;
|
|
522
|
-
if (kind && CONTEXT_INJECTION_KINDS.has(kind))
|
|
523
|
-
break;
|
|
524
|
-
const isNotice = kind !== undefined && kind !== 'user';
|
|
443
|
+
const content = asBlocks(ev.data.message?.content);
|
|
444
|
+
const timestamp = safeEventTimestamp(ev.time);
|
|
445
|
+
// DSH 的块类型是 text / reasoning / tool-call(不是 Anthropic 的
|
|
446
|
+
// thinking)。只认 text 会让 resume 卡"只有工具调用、没有思考与输出"
|
|
447
|
+
// (一个 31 turn 的会话里 reasoning 块 371 个、text 12 个,
|
|
448
|
+
// 全被丢掉)。tool-call 块不在这里取——独立的 `tool/call` 事件带完整参数。
|
|
449
|
+
for (const block of content) {
|
|
450
|
+
const text = typeof block.text === 'string' ? block.text.trim() : '';
|
|
451
|
+
if (!text)
|
|
452
|
+
continue;
|
|
453
|
+
if (block.type === 'text') {
|
|
525
454
|
out.events.push({
|
|
526
|
-
type:
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
timestamp: safeEventTimestamp(ev.time),
|
|
455
|
+
type: 'assistant',
|
|
456
|
+
content: truncateUtf8(text, TEXT_MAX_BYTES),
|
|
457
|
+
timestamp,
|
|
530
458
|
});
|
|
531
|
-
break;
|
|
532
|
-
}
|
|
533
|
-
case 'assistant/message': {
|
|
534
|
-
const content = asBlocks(ev.data.message?.content);
|
|
535
|
-
const timestamp = safeEventTimestamp(ev.time);
|
|
536
|
-
// DSH 的块类型是 text / reasoning / tool-call(不是 Anthropic 的
|
|
537
|
-
// thinking)。只认 text 会让 resume 卡"只有工具调用、没有思考与输出"
|
|
538
|
-
// (2026-10-19 反馈:一个 31 turn 的会话里 reasoning 块 371 个、text 12 个,
|
|
539
|
-
// 全被丢掉)。tool-call 块不在这里取——独立的 `tool/call` 事件带完整参数。
|
|
540
|
-
for (const block of content) {
|
|
541
|
-
const text = typeof block.text === 'string' ? block.text.trim() : '';
|
|
542
|
-
if (!text)
|
|
543
|
-
continue;
|
|
544
|
-
if (block.type === 'text') {
|
|
545
|
-
out.events.push({
|
|
546
|
-
type: 'assistant',
|
|
547
|
-
content: truncateUtf8(text, TEXT_MAX_BYTES),
|
|
548
|
-
timestamp,
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
else if (block.type === 'reasoning') {
|
|
552
|
-
out.events.push({
|
|
553
|
-
type: 'thinking',
|
|
554
|
-
// 思考是过程信息:resume 卡里留头几百字足够判断"当时在想什么"。
|
|
555
|
-
content: truncateUtf8(text, REASONING_MAX_BYTES),
|
|
556
|
-
timestamp,
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
const usage = ev.data.usage;
|
|
561
|
-
if (usage && typeof usage === 'object')
|
|
562
|
-
out.usage = usage;
|
|
563
|
-
break;
|
|
564
459
|
}
|
|
565
|
-
|
|
566
|
-
// 调用本身先不产出事件:DSH 的 tool/call 与 tool/result 是一对,resume 卡
|
|
567
|
-
// 里合成一个面板(`🔧 bash — cmd` + 输出),而不是两个各占一屏。
|
|
568
|
-
const name = String(ev.data.name ?? '');
|
|
569
|
-
const args = typeof ev.data.arguments === 'string' ? ev.data.arguments : '';
|
|
570
|
-
const summary = summarizeToolInput(name, args);
|
|
571
|
-
out.pendingTool = {
|
|
572
|
-
type: 'tool_use',
|
|
573
|
-
title: summary ? `🔧 ${name} — ${summary}` : `🔧 ${name}`,
|
|
574
|
-
content: truncateUtf8(args, TOOL_INPUT_MAX_BYTES),
|
|
575
|
-
timestamp: safeEventTimestamp(ev.time),
|
|
576
|
-
};
|
|
577
|
-
break;
|
|
578
|
-
}
|
|
579
|
-
case 'tool/result': {
|
|
580
|
-
const msg = ev.data.message;
|
|
581
|
-
const raw = stringifyContent(msg?.content);
|
|
582
|
-
const isError = msg?.isError === true;
|
|
460
|
+
else if (block.type === 'reasoning') {
|
|
583
461
|
out.events.push({
|
|
584
|
-
type: '
|
|
585
|
-
|
|
586
|
-
content: truncateUtf8(
|
|
587
|
-
timestamp
|
|
462
|
+
type: 'thinking',
|
|
463
|
+
// 思考是过程信息:resume 卡里留头几百字足够判断"当时在想什么"。
|
|
464
|
+
content: truncateUtf8(text, REASONING_MAX_BYTES),
|
|
465
|
+
timestamp,
|
|
588
466
|
});
|
|
589
|
-
break;
|
|
590
467
|
}
|
|
591
|
-
default:
|
|
592
|
-
break;
|
|
593
468
|
}
|
|
469
|
+
const usage = ev.data.usage;
|
|
470
|
+
if (usage && typeof usage === 'object')
|
|
471
|
+
out.usage = usage;
|
|
472
|
+
return out;
|
|
473
|
+
}
|
|
474
|
+
function mapToolCall(ev) {
|
|
475
|
+
const out = { events: [] };
|
|
476
|
+
// 调用本身先不产出事件:DSH 的 tool/call 与 tool/result 是一对,resume 卡
|
|
477
|
+
// 里合成一个面板(`🔧 bash — cmd` + 输出),而不是两个各占一屏。
|
|
478
|
+
const name = String(ev.data.name ?? '');
|
|
479
|
+
const args = typeof ev.data.arguments === 'string' ? ev.data.arguments : '';
|
|
480
|
+
const summary = summarizeToolInput(name, args);
|
|
481
|
+
out.pendingTool = {
|
|
482
|
+
type: 'tool_use',
|
|
483
|
+
title: summary ? `🔧 ${name} — ${summary}` : `🔧 ${name}`,
|
|
484
|
+
content: truncateUtf8(args, TOOL_INPUT_MAX_BYTES),
|
|
485
|
+
timestamp: safeEventTimestamp(ev.time),
|
|
486
|
+
};
|
|
487
|
+
return out;
|
|
488
|
+
}
|
|
489
|
+
function mapToolResult(ev) {
|
|
490
|
+
const out = { events: [] };
|
|
491
|
+
const msg = ev.data.message;
|
|
492
|
+
const raw = stringifyContent(msg?.content);
|
|
493
|
+
const isError = msg?.isError === true;
|
|
494
|
+
out.events.push({
|
|
495
|
+
type: 'tool_result',
|
|
496
|
+
title: isError ? '🔴 结果(失败)' : '🟢 结果',
|
|
497
|
+
content: truncateUtf8(raw, TOOL_RESULT_MAX_BYTES),
|
|
498
|
+
timestamp: safeEventTimestamp(ev.time),
|
|
499
|
+
});
|
|
594
500
|
return out;
|
|
595
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* 事件类型 → 命名 handler。用 Map 而非对象字面量 / switch:`constructor` /
|
|
504
|
+
* `toString` 这类外来 type 会命中 Object.prototype,查表会拿到非函数值。
|
|
505
|
+
*/
|
|
506
|
+
const EVENT_MAPPERS = new Map([
|
|
507
|
+
['user/message', mapUserMessage],
|
|
508
|
+
['assistant/message', mapAssistantMessage],
|
|
509
|
+
['tool/call', mapToolCall],
|
|
510
|
+
['tool/result', mapToolResult],
|
|
511
|
+
]);
|
|
512
|
+
function mapEvent(ev) {
|
|
513
|
+
const mapper = EVENT_MAPPERS.get(ev.type);
|
|
514
|
+
return mapper ? mapper(ev) : { events: [] };
|
|
515
|
+
}
|
|
596
516
|
function stringifyContent(content) {
|
|
597
517
|
if (content == null)
|
|
598
518
|
return '[tool result]';
|
|
@@ -607,4 +527,140 @@ function stringifyContent(content) {
|
|
|
607
527
|
}
|
|
608
528
|
return JSON.stringify(content);
|
|
609
529
|
}
|
|
530
|
+
function newDshContentAccumulator() {
|
|
531
|
+
return {
|
|
532
|
+
events: [],
|
|
533
|
+
cumInput: 0,
|
|
534
|
+
cumOutput: 0,
|
|
535
|
+
cumCacheRead: 0,
|
|
536
|
+
cumCacheWrite: 0,
|
|
537
|
+
turnUsage: null,
|
|
538
|
+
lastTurnUsage: null,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
/** turn 边界标记推进:turn/start 开新账本,turn/end 结算为「上一轮」。 */
|
|
542
|
+
function advanceTurnMarker(acc, ev) {
|
|
543
|
+
if (ev.type === 'turn/start') {
|
|
544
|
+
acc.turnUsage = emptyUsageTotals();
|
|
545
|
+
}
|
|
546
|
+
else if (ev.type === 'turn/end') {
|
|
547
|
+
if (acc.turnUsage)
|
|
548
|
+
acc.lastTurnUsage = acc.turnUsage;
|
|
549
|
+
acc.turnUsage = null;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/** 工具调用/结果配对:一对合成一个面板;未配对的分支按原顺序推入。 */
|
|
553
|
+
function pushMappedContentEvents(acc, ev, contentEvents) {
|
|
554
|
+
if (contentEvents.pendingTool) {
|
|
555
|
+
// 未完成的工具调用最多同时一个(DSH 按 step 串行执行;并行调用时按
|
|
556
|
+
// 到达顺序配对,最坏情况是两次调用共用一个面板,不会丢信息)。
|
|
557
|
+
if (acc.pendingTool)
|
|
558
|
+
acc.events.push(acc.pendingTool);
|
|
559
|
+
acc.pendingTool = contentEvents.pendingTool;
|
|
560
|
+
}
|
|
561
|
+
else if (ev.type === 'tool/result' && acc.pendingTool && contentEvents.events[0]) {
|
|
562
|
+
const result = contentEvents.events[0];
|
|
563
|
+
// 标题沿用调用的 `🔧 name — summary`,失败改成 ❌(折叠态一眼看出结果)。
|
|
564
|
+
const failed = result.title?.startsWith('🔴') === true;
|
|
565
|
+
acc.events.push({
|
|
566
|
+
type: 'tool_use',
|
|
567
|
+
title: failed
|
|
568
|
+
? (acc.pendingTool.title ?? '❌ 工具').replace('🔧', '❌')
|
|
569
|
+
: acc.pendingTool.title,
|
|
570
|
+
content: result.content,
|
|
571
|
+
timestamp: acc.pendingTool.timestamp,
|
|
572
|
+
});
|
|
573
|
+
acc.pendingTool = undefined;
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
acc.events.push(...contentEvents.events);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/** 单条 usage:会话累计 + 在途 turn 累计 + 末次采样水位。 */
|
|
580
|
+
function accumulateUsage(acc, u) {
|
|
581
|
+
// Cumulative (session-wide): sum across ALL assistant/message usage.
|
|
582
|
+
acc.cumInput += u.inputTokens ?? 0;
|
|
583
|
+
acc.cumOutput += u.outputTokens ?? 0;
|
|
584
|
+
acc.cumCacheRead += u.cacheReadTokens ?? 0;
|
|
585
|
+
acc.cumCacheWrite += u.cacheWriteTokens ?? 0;
|
|
586
|
+
// 本 run 的 flow 字段 = 末个 turn 的采样之和;contextLength 用末次采样
|
|
587
|
+
// 的窗口占用(input + cacheRead + cacheWrite,不含 output)。
|
|
588
|
+
if (acc.turnUsage) {
|
|
589
|
+
acc.turnUsage.input += u.inputTokens ?? 0;
|
|
590
|
+
acc.turnUsage.output += u.outputTokens ?? 0;
|
|
591
|
+
acc.turnUsage.cacheRead += u.cacheReadTokens ?? 0;
|
|
592
|
+
acc.turnUsage.cacheWrite += u.cacheWriteTokens ?? 0;
|
|
593
|
+
}
|
|
594
|
+
acc.lastUsage = u;
|
|
595
|
+
}
|
|
596
|
+
/** 单条 record → 更新累积状态(无闭包留在 readSessionContent 内)。 */
|
|
597
|
+
function accumulateDshEvent(acc, ev) {
|
|
598
|
+
advanceTurnMarker(acc, ev);
|
|
599
|
+
const contentEvents = mapEvent(ev);
|
|
600
|
+
pushMappedContentEvents(acc, ev, contentEvents);
|
|
601
|
+
if (contentEvents.title)
|
|
602
|
+
acc.displayTitle = contentEvents.title;
|
|
603
|
+
if (contentEvents.usage)
|
|
604
|
+
accumulateUsage(acc, contentEvents.usage);
|
|
605
|
+
}
|
|
606
|
+
/** 末轮 flow + 会话累计 → AgentSessionUsage(§9.21 口径)。 */
|
|
607
|
+
function finalizeDshSessionUsage(acc) {
|
|
608
|
+
const lastUsage = acc.lastUsage;
|
|
609
|
+
if (!lastUsage)
|
|
610
|
+
return undefined;
|
|
611
|
+
const input = lastUsage.inputTokens ?? 0;
|
|
612
|
+
const cacheRead = lastUsage.cacheReadTokens ?? 0;
|
|
613
|
+
const cacheWrite = lastUsage.cacheWriteTokens ?? 0;
|
|
614
|
+
// 在途 turn(turn/start 无 turn/end,run 进行中读历史)的采样优先于
|
|
615
|
+
// 上一轮:旧实现只认已结算的 lastTurnUsage,mid-run 读取会把当前 turn
|
|
616
|
+
// 已消耗的量显示成上一个完整 turn 的数字。
|
|
617
|
+
const flow = acc.turnUsage ??
|
|
618
|
+
acc.lastTurnUsage ?? {
|
|
619
|
+
input,
|
|
620
|
+
output: lastUsage.outputTokens ?? 0,
|
|
621
|
+
cacheRead,
|
|
622
|
+
cacheWrite,
|
|
623
|
+
};
|
|
624
|
+
return {
|
|
625
|
+
inputTokens: flow.input,
|
|
626
|
+
outputTokens: flow.output,
|
|
627
|
+
// §9.21 口径:context 是末次采样的窗口水位(input + 末次 output +
|
|
628
|
+
// cache),不把整 turn 的 output 求和(前几步 output 已进入后续 input)。
|
|
629
|
+
contextLength: input + (lastUsage.outputTokens ?? 0) + cacheRead + cacheWrite,
|
|
630
|
+
cacheReadTokens: flow.cacheRead,
|
|
631
|
+
cacheCreationTokens: flow.cacheWrite,
|
|
632
|
+
totalTokens: flow.input + flow.output + flow.cacheRead + flow.cacheWrite,
|
|
633
|
+
...cumulativeUsageFields({
|
|
634
|
+
input: acc.cumInput,
|
|
635
|
+
output: acc.cumOutput,
|
|
636
|
+
cacheRead: acc.cumCacheRead,
|
|
637
|
+
cacheCreation: acc.cumCacheWrite,
|
|
638
|
+
}),
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
/** session/page 响应 + 服务端预览 → 详情卡内容(纯结构装配)。 */
|
|
642
|
+
function buildDshSessionContent(value, preview, opts) {
|
|
643
|
+
const acc = newDshContentAccumulator();
|
|
644
|
+
for (const entry of value.records ?? []) {
|
|
645
|
+
const ev = entry.event;
|
|
646
|
+
if (!ev)
|
|
647
|
+
continue;
|
|
648
|
+
accumulateDshEvent(acc, ev);
|
|
649
|
+
}
|
|
650
|
+
const sessionUsage = finalizeDshSessionUsage(acc);
|
|
651
|
+
// 中断/仍在执行的调用没有结果:把它当独立事件留下,别让这一条消失。
|
|
652
|
+
if (acc.pendingTool)
|
|
653
|
+
acc.events.push(acc.pendingTool);
|
|
654
|
+
// 头部信息口径:最近输入优先用服务端末轮 prompt(事件里可能只是当前 turn
|
|
655
|
+
// 的一部分),标题用服务端 title;两者都缺时保持原行为。
|
|
656
|
+
const headerLastInput = preview.lastUserMessage ?? acc.displayTitle;
|
|
657
|
+
return {
|
|
658
|
+
// 展示仍按 maxEvents 尾截断(默认 50,保持原行为),usage 已在上面基于
|
|
659
|
+
// 完整 history 累加。
|
|
660
|
+
events: capEvents(acc.events, opts?.maxEvents ?? 50),
|
|
661
|
+
...(sessionUsage ? { usage: sessionUsage } : {}),
|
|
662
|
+
...(headerLastInput ? { displayTitle: headerLastInput } : {}),
|
|
663
|
+
...(preview.title ? { aiTitle: preview.title } : {}),
|
|
664
|
+
};
|
|
665
|
+
}
|
|
610
666
|
//# sourceMappingURL=sessions.js.map
|
|
@@ -12,7 +12,7 @@ export interface KimiSessionState {
|
|
|
12
12
|
/**
|
|
13
13
|
* Compaction completion record in wire.jsonl (§6.3 / kimi-code wire-manifest).
|
|
14
14
|
*
|
|
15
|
-
* REAL shape
|
|
15
|
+
* REAL shape(真实 wire.jsonl + kimi-code 源码):
|
|
16
16
|
* - `context.apply_compaction`:带 `compactedCount` / `tokensBefore` /
|
|
17
17
|
* `tokensAfter`(以及 summary 等);
|
|
18
18
|
* - `full_compaction.complete`:只有 `{type, time}`。
|
|
@@ -50,6 +50,39 @@ export type CwdGuardResult = 'verified' | 'failed' | 'unverifiable';
|
|
|
50
50
|
* cwd guard semantics.
|
|
51
51
|
*/
|
|
52
52
|
export declare function checkCwdGuard(state: KimiSessionState, realCwd: string): CwdGuardResult;
|
|
53
|
+
/** 逐字段 token 累计(usage.record 的四个分量;缺字段按 0 计)。 */
|
|
54
|
+
interface KimiUsageTotals {
|
|
55
|
+
input: number;
|
|
56
|
+
output: number;
|
|
57
|
+
cacheRead: number;
|
|
58
|
+
cacheCreation: number;
|
|
59
|
+
}
|
|
60
|
+
/** kimi 主 wire usage 扫描累积器结果(纯数据)。 */
|
|
61
|
+
export interface KimiWireUsageScan {
|
|
62
|
+
/** 会话累计:主 wire 全部 usage.record 逐字段求和(子 agent 由调用方并入)。 */
|
|
63
|
+
totals: KimiUsageTotals;
|
|
64
|
+
/**
|
|
65
|
+
* 末个 turn(最后一个 turn.prompt 之后)的主 wire 记录之和(本 run flow);
|
|
66
|
+
* 整份 wire 无 turn.prompt(旧数据/截断)= undefined,由装配段回退全会话。
|
|
67
|
+
*/
|
|
68
|
+
turn: KimiUsageTotals | undefined;
|
|
69
|
+
/** 主 wire 末条 usage.record 的上下文水位(§9.21;子 agent 独立窗口不进)。 */
|
|
70
|
+
mainContextLength: number;
|
|
71
|
+
/** §6.3 展示计数:只数 context.apply_compaction(一次手动 /compact 只写一条)。 */
|
|
72
|
+
compactCount: number;
|
|
73
|
+
/** 最近一次压缩的 tokensBefore 水位。 */
|
|
74
|
+
compactPreContextLength: number | undefined;
|
|
75
|
+
/** 主 wire 出现过 usage.record(畸形 record 也算有数据,全零照实返回)。 */
|
|
76
|
+
hasUsageRecord: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* kimi 主 wire usage 扫描累积器(纯函数):单遍解析,产出会话累计、末 turn
|
|
80
|
+
* flow、上下文水位与压缩统计。
|
|
81
|
+
*
|
|
82
|
+
* 产生:KimiWireUsageScan。依赖:入参 lines(已解析前的原始行)。不改任何
|
|
83
|
+
* 外部状态;畸形行跳过,畸形 usage.record 按字段 0 计但记为「有数据」。
|
|
84
|
+
*/
|
|
85
|
+
export declare function scanKimiUsage(lines: readonly string[]): KimiWireUsageScan;
|
|
53
86
|
/**
|
|
54
87
|
* Kimi Session Reader
|
|
55
88
|
* Reads session history from ~/.kimi-code/
|
|
@@ -66,13 +99,6 @@ export declare class KimiSessionReader implements AgentSessionReader {
|
|
|
66
99
|
* Find a single index entry by sessionId, or undefined if not found.
|
|
67
100
|
*/
|
|
68
101
|
private findSessionIndexEntry;
|
|
69
|
-
/**
|
|
70
|
-
* Extract the last turn.prompt text from a wire.jsonl file.
|
|
71
|
-
* Used as a fallback summary source when state.json has no title/lastPrompt
|
|
72
|
-
* (v2 sessions). Scans the tail of the file for efficiency.
|
|
73
|
-
* Returns undefined if no turn.prompt is found.
|
|
74
|
-
*/
|
|
75
|
-
private extractLastPromptFromWire;
|
|
76
102
|
/**
|
|
77
103
|
* List all sessions for a given working directory
|
|
78
104
|
*/
|
|
@@ -89,6 +115,11 @@ export declare class KimiSessionReader implements AgentSessionReader {
|
|
|
89
115
|
getNewestSession(cwd: string): AgentSession | null;
|
|
90
116
|
/**
|
|
91
117
|
* Read session content (events + usage)
|
|
118
|
+
*
|
|
119
|
+
* 编排:cwd 守卫定位主 wire(resolveSessionWirePath,与 isSessionActive
|
|
120
|
+
* 共用 verifySessionCwd 单源)→ 主 wire 两遍只读扫描(scanKimiEvents 出
|
|
121
|
+
* 展示流 + displayTitle,scanKimiUsage 出累计/flow/水位/压缩统计)→ 子
|
|
122
|
+
* agent wire 只进 usage 累计 → assembleKimiUsage 组装。
|
|
92
123
|
*/
|
|
93
124
|
readSessionContent(sessionId: string, cwd: string, opts?: {
|
|
94
125
|
maxEvents?: number;
|
|
@@ -130,3 +161,4 @@ export declare class KimiSessionReader implements AgentSessionReader {
|
|
|
130
161
|
*/
|
|
131
162
|
isSessionActive(sessionId: string, cwd: string): boolean;
|
|
132
163
|
}
|
|
164
|
+
export {};
|