@co0ontty/wand 1.21.4 → 1.21.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/dist/claude-pty-bridge.d.ts +4 -9
- package/dist/claude-pty-bridge.js +6 -16
- package/dist/config.js +2 -0
- package/dist/process-manager.js +2 -2
- package/dist/pty-text-utils.d.ts +6 -0
- package/dist/pty-text-utils.js +6 -0
- package/dist/server-session-routes.js +9 -3
- package/dist/server.js +5 -1
- package/dist/session-logger.d.ts +3 -1
- package/dist/session-logger.js +29 -16
- package/dist/structured-session-manager.d.ts +33 -0
- package/dist/structured-session-manager.js +560 -28
- package/dist/types.d.ts +3 -1
- package/dist/web-ui/content/scripts.js +178 -133
- package/dist/ws-broadcast.d.ts +6 -0
- package/dist/ws-broadcast.js +25 -38
- package/package.json +2 -1
|
@@ -177,16 +177,11 @@ export declare class ClaudePtyBridge extends EventEmitter {
|
|
|
177
177
|
private finalizeResponse;
|
|
178
178
|
/**
|
|
179
179
|
* Find the end index of the echoed user input in the PTY buffer.
|
|
180
|
-
*
|
|
181
|
-
* Returns the index after the last character of the echo.
|
|
180
|
+
* Returns 0 if the echo cannot be fully matched.
|
|
182
181
|
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* common symbols like `/`, `(`, `:`, space — which made commands such as
|
|
187
|
-
* `ls /tmp` mismatch and start parsing the chat response from a wrong offset.
|
|
188
|
-
* - In the buffer, skip ANSI escape sequences entirely, and skip whitespace
|
|
189
|
-
* so wrapped echoes (line continuation, padded columns) still align.
|
|
182
|
+
* Why: ANSI escapes and whitespace can interleave the echoed characters
|
|
183
|
+
* (line wrapping, padding, color codes), so matching skips them while
|
|
184
|
+
* comparing every printable codepoint of `userInput` in order.
|
|
190
185
|
*/
|
|
191
186
|
private findEchoEndIndex;
|
|
192
187
|
private cleanForChat;
|
|
@@ -7,14 +7,9 @@
|
|
|
7
7
|
* 2. Structured messages for chat view (parsed)
|
|
8
8
|
*/
|
|
9
9
|
import { EventEmitter } from "node:events";
|
|
10
|
-
import { stripAnsi, isNoiseLine, appendWindow, normalizePromptText, hasExplicitConfirmSyntax, hasPermissionActionContext, scorePermissionLikelihood, FALLBACK_SCORE_THRESHOLD, isSlashCommandMenu, stripForEchoMatch, skipAnsiSequence } from "./pty-text-utils.js";
|
|
10
|
+
import { stripAnsi, isNoiseLine, appendWindow, normalizePromptText, hasExplicitConfirmSyntax, hasPermissionActionContext, scorePermissionLikelihood, FALLBACK_SCORE_THRESHOLD, isSlashCommandMenu, stripForEchoMatch, skipAnsiSequence, PTY_OUTPUT_MAX_SIZE } from "./pty-text-utils.js";
|
|
11
11
|
// ── Constants ──
|
|
12
|
-
|
|
13
|
-
* Hard cap on the in-memory PTY replay buffer. Aligned with the non-bridge
|
|
14
|
-
* branch of `ProcessManager.start()` so a session keeps the same amount of
|
|
15
|
-
* history regardless of which capture path is active.
|
|
16
|
-
*/
|
|
17
|
-
const OUTPUT_MAX_SIZE = 200000;
|
|
12
|
+
const OUTPUT_MAX_SIZE = PTY_OUTPUT_MAX_SIZE;
|
|
18
13
|
const SESSION_ID_WINDOW_SIZE = 16384;
|
|
19
14
|
const PERMISSION_WINDOW_SIZE = 2000;
|
|
20
15
|
const AUTO_APPROVE_DELAY_MS = 350;
|
|
@@ -835,16 +830,11 @@ export class ClaudePtyBridge extends EventEmitter {
|
|
|
835
830
|
// ── Text Processing Utilities ──
|
|
836
831
|
/**
|
|
837
832
|
* Find the end index of the echoed user input in the PTY buffer.
|
|
838
|
-
*
|
|
839
|
-
* Returns the index after the last character of the echo.
|
|
833
|
+
* Returns 0 if the echo cannot be fully matched.
|
|
840
834
|
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
* common symbols like `/`, `(`, `:`, space — which made commands such as
|
|
845
|
-
* `ls /tmp` mismatch and start parsing the chat response from a wrong offset.
|
|
846
|
-
* - In the buffer, skip ANSI escape sequences entirely, and skip whitespace
|
|
847
|
-
* so wrapped echoes (line continuation, padded columns) still align.
|
|
835
|
+
* Why: ANSI escapes and whitespace can interleave the echoed characters
|
|
836
|
+
* (line wrapping, padding, color codes), so matching skips them while
|
|
837
|
+
* comparing every printable codepoint of `userInput` in order.
|
|
848
838
|
*/
|
|
849
839
|
findEchoEndIndex(buffer, userInput) {
|
|
850
840
|
const inputChars = stripForEchoMatch(userInput);
|
package/dist/config.js
CHANGED
|
@@ -20,6 +20,7 @@ export const defaultConfig = () => ({
|
|
|
20
20
|
android: defaultAndroidApkConfig(),
|
|
21
21
|
cardDefaults: defaultCardExpandDefaults(),
|
|
22
22
|
defaultModel: "",
|
|
23
|
+
structuredRunner: "cli",
|
|
23
24
|
commandPresets: [
|
|
24
25
|
{
|
|
25
26
|
label: "Claude",
|
|
@@ -185,6 +186,7 @@ function mergeWithDefaults(input) {
|
|
|
185
186
|
android: normalizeAndroidApkConfig(input.android) ?? defaults.android,
|
|
186
187
|
cardDefaults: normalizeCardDefaults(input.cardDefaults),
|
|
187
188
|
defaultModel: typeof input.defaultModel === "string" ? input.defaultModel.trim() : defaults.defaultModel,
|
|
189
|
+
structuredRunner: (input.structuredRunner === "sdk" || input.structuredRunner === "cli") ? input.structuredRunner : defaults.structuredRunner,
|
|
188
190
|
};
|
|
189
191
|
}
|
|
190
192
|
export function isExecutionMode(value) {
|
package/dist/process-manager.js
CHANGED
|
@@ -8,7 +8,7 @@ import pty from "node-pty";
|
|
|
8
8
|
import { SessionLogger } from "./session-logger.js";
|
|
9
9
|
import { ClaudePtyBridge } from "./claude-pty-bridge.js";
|
|
10
10
|
import { truncateMessagesForTransport } from "./message-truncator.js";
|
|
11
|
-
import { appendWindow, hasExplicitConfirmSyntax, hasPermissionActionContext, normalizePromptText } from "./pty-text-utils.js";
|
|
11
|
+
import { appendWindow, hasExplicitConfirmSyntax, hasPermissionActionContext, normalizePromptText, PTY_OUTPUT_MAX_SIZE } from "./pty-text-utils.js";
|
|
12
12
|
import { prepareSessionWorktree } from "./git-worktree.js";
|
|
13
13
|
import { getResumeCommandSessionId } from "./resume-policy.js";
|
|
14
14
|
function resolveProviderFromCommand(command) {
|
|
@@ -744,7 +744,7 @@ export class ProcessManager extends EventEmitter {
|
|
|
744
744
|
rec.output = rec.ptyBridge.getRawOutput();
|
|
745
745
|
}
|
|
746
746
|
else {
|
|
747
|
-
rec.output = appendWindow(rec.output, chunk,
|
|
747
|
+
rec.output = appendWindow(rec.output, chunk, PTY_OUTPUT_MAX_SIZE);
|
|
748
748
|
}
|
|
749
749
|
this.logger.appendPtyOutput(id, chunk);
|
|
750
750
|
if (!rec.ptyBridge) {
|
package/dist/pty-text-utils.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared PTY text processing utilities for consistent ANSI stripping and noise filtering.
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Hard cap on the in-memory PTY replay buffer. Shared between ProcessManager
|
|
6
|
+
* and ClaudePtyBridge so a session keeps the same amount of history regardless
|
|
7
|
+
* of which capture path is active.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PTY_OUTPUT_MAX_SIZE = 200000;
|
|
4
10
|
/** Strip ANSI escape sequences and control characters from raw PTY output. */
|
|
5
11
|
export declare function stripAnsi(text: string): string;
|
|
6
12
|
/** Lines considered as UI noise that should be excluded from chat view. */
|
package/dist/pty-text-utils.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared PTY text processing utilities for consistent ANSI stripping and noise filtering.
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Hard cap on the in-memory PTY replay buffer. Shared between ProcessManager
|
|
6
|
+
* and ClaudePtyBridge so a session keeps the same amount of history regardless
|
|
7
|
+
* of which capture path is active.
|
|
8
|
+
*/
|
|
9
|
+
export const PTY_OUTPUT_MAX_SIZE = 200_000;
|
|
4
10
|
/** Strip ANSI escape sequences and control characters from raw PTY output. */
|
|
5
11
|
export function stripAnsi(text) {
|
|
6
12
|
return text
|
|
@@ -207,13 +207,19 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
207
207
|
app.post("/api/structured-sessions/:id/messages", express.json(), async (req, res) => {
|
|
208
208
|
const input = String(req.body?.input ?? "");
|
|
209
209
|
const interrupt = !!req.body?.interrupt;
|
|
210
|
-
|
|
210
|
+
const idempotencyKey = typeof req.body?.idempotencyKey === "string" ? req.body.idempotencyKey : undefined;
|
|
211
|
+
console.log("[WAND] POST /api/structured-sessions/:id/messages id:", req.params.id, "input:", input.substring(0, 50), "interrupt:", interrupt, "idempotencyKey:", idempotencyKey);
|
|
211
212
|
try {
|
|
212
|
-
const snapshot = await structured.sendMessage(req.params.id, input, { interrupt });
|
|
213
|
+
const snapshot = await structured.sendMessage(req.params.id, input, { interrupt, idempotencyKey });
|
|
213
214
|
res.json(snapshot);
|
|
214
215
|
}
|
|
215
216
|
catch (error) {
|
|
216
|
-
|
|
217
|
+
const errorCode = error?.code;
|
|
218
|
+
const status = errorCode === "duplicate_idempotency_key" ? 409 : 400;
|
|
219
|
+
res.status(status).json({
|
|
220
|
+
error: getErrorMessage(error, "无法发送结构化消息。"),
|
|
221
|
+
errorCode,
|
|
222
|
+
});
|
|
217
223
|
}
|
|
218
224
|
});
|
|
219
225
|
// ── Tool content lazy-load endpoint ──
|
package/dist/server.js
CHANGED
|
@@ -724,6 +724,7 @@ export async function startServer(config, configPath) {
|
|
|
724
724
|
defaultMode: config.defaultMode,
|
|
725
725
|
defaultCwd: config.defaultCwd,
|
|
726
726
|
commandPresets: config.commandPresets,
|
|
727
|
+
structuredRunner: config.structuredRunner ?? "cli",
|
|
727
728
|
structuredRunners: [
|
|
728
729
|
{ label: "Claude Structured", runner: "claude-cli-print" },
|
|
729
730
|
{ label: "Codex Structured", runner: "codex-cli-exec" },
|
|
@@ -815,7 +816,7 @@ export async function startServer(config, configPath) {
|
|
|
815
816
|
});
|
|
816
817
|
app.post("/api/settings/config", async (req, res) => {
|
|
817
818
|
const body = req.body;
|
|
818
|
-
const allowedFields = ["host", "port", "https", "defaultMode", "defaultCwd", "shell", "language", "defaultModel"];
|
|
819
|
+
const allowedFields = ["host", "port", "https", "defaultMode", "defaultCwd", "shell", "language", "defaultModel", "structuredRunner"];
|
|
819
820
|
let changed = false;
|
|
820
821
|
for (const field of allowedFields) {
|
|
821
822
|
if (field in body && body[field] !== undefined) {
|
|
@@ -852,6 +853,9 @@ export async function startServer(config, configPath) {
|
|
|
852
853
|
else if (field === "defaultModel") {
|
|
853
854
|
config.defaultModel = typeof body.defaultModel === "string" ? body.defaultModel.trim() : "";
|
|
854
855
|
}
|
|
856
|
+
else if (field === "structuredRunner") {
|
|
857
|
+
config.structuredRunner = body.structuredRunner === "sdk" ? "sdk" : "cli";
|
|
858
|
+
}
|
|
855
859
|
changed = true;
|
|
856
860
|
}
|
|
857
861
|
}
|
package/dist/session-logger.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export interface ShortcutLogContext {
|
|
|
35
35
|
export declare class SessionLogger {
|
|
36
36
|
private readonly baseDir;
|
|
37
37
|
private readonly dirs;
|
|
38
|
+
/** Cached on-disk size of hot-path log files so we can rotate without stat'ing on every chunk. */
|
|
39
|
+
private readonly logSizes;
|
|
38
40
|
private readonly shortcutLogMaxBytes;
|
|
39
41
|
constructor(configDir: string, shortcutLogMaxBytes?: number);
|
|
40
42
|
private ensureDir;
|
|
@@ -67,6 +69,6 @@ export declare class SessionLogger {
|
|
|
67
69
|
deleteSession(sessionId: string): void;
|
|
68
70
|
/** Append a shortcut key interaction log entry (for analyzing auto-confirm gaps) */
|
|
69
71
|
appendShortcutLog(sessionId: string, shortcutKey: string, tailLines: string, ctx?: ShortcutLogContext): void;
|
|
70
|
-
/** Truncate shortcut log by keeping only the most recent half of entries */
|
|
72
|
+
/** Truncate shortcut log by keeping only the most recent half of entries. Returns the new on-disk size. */
|
|
71
73
|
private truncateShortcutLog;
|
|
72
74
|
}
|
package/dist/session-logger.js
CHANGED
|
@@ -23,6 +23,8 @@ const DEFAULT_SHORTCUT_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
23
23
|
export class SessionLogger {
|
|
24
24
|
baseDir;
|
|
25
25
|
dirs = new Map();
|
|
26
|
+
/** Cached on-disk size of hot-path log files so we can rotate without stat'ing on every chunk. */
|
|
27
|
+
logSizes = new Map();
|
|
26
28
|
shortcutLogMaxBytes;
|
|
27
29
|
constructor(configDir, shortcutLogMaxBytes) {
|
|
28
30
|
this.baseDir = path.join(configDir, "sessions");
|
|
@@ -46,6 +48,10 @@ export class SessionLogger {
|
|
|
46
48
|
// ignore
|
|
47
49
|
}
|
|
48
50
|
this.dirs.set(sessionId, dir);
|
|
51
|
+
// Seed the size cache from disk on first use; subsequent appends maintain
|
|
52
|
+
// the counter in memory so the hot path no longer touches stat/exists.
|
|
53
|
+
const sizes = { pty: tryStatSize(path.join(dir, "pty-output.log")), shortcut: tryStatSize(path.join(dir, "shortcut-interactions.jsonl")) };
|
|
54
|
+
this.logSizes.set(sessionId, sizes);
|
|
49
55
|
return dir;
|
|
50
56
|
}
|
|
51
57
|
/**
|
|
@@ -78,15 +84,14 @@ export class SessionLogger {
|
|
|
78
84
|
appendPtyOutput(sessionId, chunk) {
|
|
79
85
|
try {
|
|
80
86
|
const dir = this.ensureDir(sessionId);
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (stats.size >= PTY_LOG_MAX_SIZE) {
|
|
86
|
-
this.rotatePtyLog(dir);
|
|
87
|
-
}
|
|
87
|
+
const sizes = this.logSizes.get(sessionId);
|
|
88
|
+
if (sizes.pty >= PTY_LOG_MAX_SIZE) {
|
|
89
|
+
this.rotatePtyLog(dir);
|
|
90
|
+
sizes.pty = 0;
|
|
88
91
|
}
|
|
92
|
+
const logPath = path.join(dir, "pty-output.log");
|
|
89
93
|
appendFileSync(logPath, chunk);
|
|
94
|
+
sizes.pty += Buffer.byteLength(chunk);
|
|
90
95
|
}
|
|
91
96
|
catch {
|
|
92
97
|
// Non-critical — don't let logging failures affect main flow
|
|
@@ -200,6 +205,7 @@ export class SessionLogger {
|
|
|
200
205
|
// Non-critical
|
|
201
206
|
}
|
|
202
207
|
this.dirs.delete(sessionId);
|
|
208
|
+
this.logSizes.delete(sessionId);
|
|
203
209
|
}
|
|
204
210
|
/** Append a shortcut key interaction log entry (for analyzing auto-confirm gaps) */
|
|
205
211
|
appendShortcutLog(sessionId, shortcutKey, tailLines, ctx) {
|
|
@@ -207,6 +213,7 @@ export class SessionLogger {
|
|
|
207
213
|
return;
|
|
208
214
|
try {
|
|
209
215
|
const dir = this.ensureDir(sessionId);
|
|
216
|
+
const sizes = this.logSizes.get(sessionId);
|
|
210
217
|
const logPath = path.join(dir, "shortcut-interactions.jsonl");
|
|
211
218
|
const entry = JSON.stringify({
|
|
212
219
|
ts: new Date().toISOString(),
|
|
@@ -217,35 +224,41 @@ export class SessionLogger {
|
|
|
217
224
|
input: ctx?.input,
|
|
218
225
|
tail: tailLines,
|
|
219
226
|
}) + "\n";
|
|
220
|
-
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
if (size + entry.length > this.shortcutLogMaxBytes) {
|
|
224
|
-
this.truncateShortcutLog(logPath);
|
|
225
|
-
}
|
|
227
|
+
const entryBytes = Buffer.byteLength(entry);
|
|
228
|
+
if (sizes.shortcut + entryBytes > this.shortcutLogMaxBytes) {
|
|
229
|
+
sizes.shortcut = this.truncateShortcutLog(logPath);
|
|
226
230
|
}
|
|
227
231
|
appendFileSync(logPath, entry);
|
|
232
|
+
sizes.shortcut += entryBytes;
|
|
228
233
|
}
|
|
229
234
|
catch {
|
|
230
235
|
// Non-critical
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
|
-
/** Truncate shortcut log by keeping only the most recent half of entries */
|
|
238
|
+
/** Truncate shortcut log by keeping only the most recent half of entries. Returns the new on-disk size. */
|
|
234
239
|
truncateShortcutLog(logPath) {
|
|
235
240
|
try {
|
|
236
241
|
const content = readFileSync(logPath, "utf8");
|
|
237
242
|
const lines = content.split("\n").filter(Boolean);
|
|
238
|
-
// Keep the latter half
|
|
239
243
|
const keepFrom = Math.floor(lines.length / 2);
|
|
240
244
|
const trimmed = lines.slice(keepFrom).join("\n") + "\n";
|
|
241
245
|
writeFileSync(logPath, trimmed);
|
|
246
|
+
return Buffer.byteLength(trimmed);
|
|
242
247
|
}
|
|
243
248
|
catch {
|
|
244
|
-
// If truncation fails, delete the file to prevent unbounded growth
|
|
245
249
|
try {
|
|
246
250
|
unlinkSync(logPath);
|
|
247
251
|
}
|
|
248
252
|
catch { /* ignore */ }
|
|
253
|
+
return 0;
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
}
|
|
257
|
+
function tryStatSize(filePath) {
|
|
258
|
+
try {
|
|
259
|
+
return existsSync(filePath) ? statSync(filePath).size : 0;
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -17,12 +17,30 @@ export declare class StructuredSessionManager {
|
|
|
17
17
|
private readonly logger;
|
|
18
18
|
private readonly sessions;
|
|
19
19
|
private readonly pendingChildren;
|
|
20
|
+
private readonly pendingSdkAbort;
|
|
20
21
|
private readonly interruptedWith;
|
|
22
|
+
/** Last wall-clock time (ms) we did a full saveSession for a streaming session. */
|
|
23
|
+
private readonly lastStreamSaveAt;
|
|
24
|
+
/**
|
|
25
|
+
* Idempotency keys we've already accepted, mapped to their wall-clock timestamp.
|
|
26
|
+
* Android WebView 在进程恢复时偶尔会重发上一个未收到响应的 POST(HTTP/2 stream
|
|
27
|
+
* reset 等场景),客户端 JS 没有重试逻辑也拦不住。这里用 (sessionId, key) 永
|
|
28
|
+
* 久去重,重复就抛错让前端弹 toast 提示,**不**做任何处理。timestamp 仅用于
|
|
29
|
+
* map 大小溢出时按时间裁剪。
|
|
30
|
+
*/
|
|
31
|
+
private readonly seenIdempotencyKeys;
|
|
21
32
|
private emitEvent;
|
|
22
33
|
private archiveTimer;
|
|
23
34
|
constructor(storage: WandStorage, config: WandConfig, logger?: SessionLogger | null);
|
|
24
35
|
private archiveExpiredSessions;
|
|
25
36
|
setEventEmitter(emitEvent: (event: ProcessEvent) => void): void;
|
|
37
|
+
/**
|
|
38
|
+
* In-memory snapshot is updated unconditionally; the SQLite write is rate-
|
|
39
|
+
* limited to once per STREAM_SAVE_THROTTLE_MS. Caller must still invoke
|
|
40
|
+
* `storage.saveSession` directly at terminal events (close / failure) so the
|
|
41
|
+
* final state is durable.
|
|
42
|
+
*/
|
|
43
|
+
private saveStreamingSnapshot;
|
|
26
44
|
list(): SessionSnapshot[];
|
|
27
45
|
/** Return lightweight snapshots for the session list (no output/messages). */
|
|
28
46
|
listSlim(): SessionSnapshot[];
|
|
@@ -30,6 +48,7 @@ export declare class StructuredSessionManager {
|
|
|
30
48
|
createSession(options: CreateStructuredSessionOptions): SessionSnapshot;
|
|
31
49
|
sendMessage(id: string, input: string, opts?: {
|
|
32
50
|
interrupt?: boolean;
|
|
51
|
+
idempotencyKey?: string;
|
|
33
52
|
}): Promise<SessionSnapshot>;
|
|
34
53
|
/** Approve a pending permission request. */
|
|
35
54
|
approvePermission(sessionId: string): SessionSnapshot;
|
|
@@ -66,6 +85,18 @@ export declare class StructuredSessionManager {
|
|
|
66
85
|
* outside CWD). stdin is always "ignore" — no ACP bidirectional control.
|
|
67
86
|
*/
|
|
68
87
|
private runClaudeStreaming;
|
|
88
|
+
/**
|
|
89
|
+
* Use @anthropic-ai/claude-agent-sdk instead of spawning claude -p directly.
|
|
90
|
+
* The SDK still spawns the claude binary but provides typed AsyncGenerator<SDKMessage>
|
|
91
|
+
* messages, so we skip NDJSON parsing. Options are 1:1 with the CLI flags.
|
|
92
|
+
*
|
|
93
|
+
* Streaming is enabled via includePartialMessages: true — the SDK emits
|
|
94
|
+
* SDKPartialAssistantMessage (type: "stream_event") with BetaRawMessageStreamEvent
|
|
95
|
+
* payloads for incremental text/thinking/tool_use updates, followed by a final
|
|
96
|
+
* SDKAssistantMessage with the authoritative complete content.
|
|
97
|
+
*/
|
|
98
|
+
private runClaudeSdkStreaming;
|
|
99
|
+
private _runClaudeSdkStreamingAsync;
|
|
69
100
|
private extractAssistantMessage;
|
|
70
101
|
private compactContentBlocks;
|
|
71
102
|
private normalizeToolInput;
|
|
@@ -76,6 +107,8 @@ export declare class StructuredSessionManager {
|
|
|
76
107
|
private finishStructuredFailure;
|
|
77
108
|
private extractModelName;
|
|
78
109
|
private extractUsage;
|
|
110
|
+
/** Extract usage from an SDKResultSuccess message (sdk runner). */
|
|
111
|
+
private extractSdkUsage;
|
|
79
112
|
private extractCodexUsage;
|
|
80
113
|
}
|
|
81
114
|
export {};
|