@co0ontty/wand 1.20.4 → 1.21.4
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 +8 -0
- package/dist/claude-pty-bridge.js +34 -11
- package/dist/git-quick-commit.js +12 -4
- package/dist/models.d.ts +3 -1
- package/dist/models.js +45 -7
- package/dist/process-manager.d.ts +2 -0
- package/dist/process-manager.js +80 -17
- package/dist/pty-text-utils.d.ts +25 -1
- package/dist/pty-text-utils.js +158 -2
- package/dist/server-session-routes.d.ts +1 -1
- package/dist/server-session-routes.js +22 -8
- package/dist/server.d.ts +3 -0
- package/dist/server.js +49 -12
- package/dist/session-logger.d.ts +15 -4
- package/dist/session-logger.js +52 -4
- package/dist/structured-session-manager.d.ts +12 -2
- package/dist/structured-session-manager.js +465 -22
- package/dist/types.d.ts +13 -2
- package/dist/web-ui/content/scripts.js +680 -178
- package/dist/web-ui/content/styles.css +137 -41
- package/dist/web-ui/content/vendor/wterm/wterm.bundle.js +1 -1
- package/dist/ws-broadcast.js +74 -12
- package/package.json +1 -1
|
@@ -4,5 +4,5 @@ import { StructuredSessionManager } from "./structured-session-manager.js";
|
|
|
4
4
|
import { WandStorage } from "./storage.js";
|
|
5
5
|
import { ExecutionMode, WandConfig } from "./types.js";
|
|
6
6
|
export declare function getErrorMessage(error: unknown, fallback: string): string;
|
|
7
|
-
export declare function registerSessionRoutes(app: Express, processes: ProcessManager, structured: StructuredSessionManager, storage: WandStorage, defaultMode: ExecutionMode, config: WandConfig): void;
|
|
7
|
+
export declare function registerSessionRoutes(app: Express, processes: ProcessManager, structured: StructuredSessionManager, storage: WandStorage, defaultMode: ExecutionMode, config: WandConfig, onSessionCreated?: (cwd: string | undefined | null) => void): void;
|
|
8
8
|
export declare function registerClaudeHistoryRoutes(app: Express, processes: ProcessManager, storage: WandStorage): void;
|
|
@@ -136,7 +136,7 @@ function canMergeSession(snapshot) {
|
|
|
136
136
|
function isMergeActionAllowed(snapshot) {
|
|
137
137
|
return snapshot.status !== "running";
|
|
138
138
|
}
|
|
139
|
-
export function registerSessionRoutes(app, processes, structured, storage, defaultMode, config) {
|
|
139
|
+
export function registerSessionRoutes(app, processes, structured, storage, defaultMode, config, onSessionCreated) {
|
|
140
140
|
app.get("/api/sessions", (_req, res) => {
|
|
141
141
|
const all = listAllSessionsSlim(processes, structured);
|
|
142
142
|
console.log("[WAND] GET /api/sessions count:", all.length, "sessions:", all.map(s => ({ id: s.id.substring(0, 8), kind: s.sessionKind, runner: s.runner, status: s.status })));
|
|
@@ -146,19 +146,27 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
146
146
|
const body = req.body;
|
|
147
147
|
console.log("[WAND] POST /api/structured-sessions body:", JSON.stringify({ cwd: body.cwd, mode: body.mode, runner: body.runner, provider: body.provider, worktreeEnabled: body.worktreeEnabled === true, hasPrompt: !!body.prompt, model: body.model }));
|
|
148
148
|
try {
|
|
149
|
-
if (body.provider && body.provider !== "claude") {
|
|
150
|
-
res.status(400).json({ error: "结构化会话当前仅支持 Claude provider。" });
|
|
149
|
+
if (body.provider && body.provider !== "claude" && body.provider !== "codex") {
|
|
150
|
+
res.status(400).json({ error: "结构化会话当前仅支持 Claude 或 Codex provider。" });
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
|
+
const provider = body.provider === "codex" ? "codex" : "claude";
|
|
153
154
|
const snapshot = structured.createSession({
|
|
154
155
|
cwd: body.cwd?.trim() || process.cwd(),
|
|
155
156
|
mode: normalizeMode(body.mode, defaultMode),
|
|
156
|
-
|
|
157
|
-
runner: body.runner ?? "claude-cli-print",
|
|
157
|
+
provider,
|
|
158
|
+
runner: body.runner ?? (provider === "codex" ? "codex-cli-exec" : "claude-cli-print"),
|
|
158
159
|
worktreeEnabled: body.worktreeEnabled === true,
|
|
159
160
|
model: typeof body.model === "string" ? body.model.trim() : undefined,
|
|
160
161
|
});
|
|
161
162
|
console.log("[WAND] structured session created:", JSON.stringify({ id: snapshot.id, sessionKind: snapshot.sessionKind, runner: snapshot.runner, status: snapshot.status }));
|
|
163
|
+
onSessionCreated?.(body.cwd ?? snapshot.cwd);
|
|
164
|
+
const prompt = body.prompt?.trim();
|
|
165
|
+
if (prompt) {
|
|
166
|
+
const finished = await structured.sendMessage(snapshot.id, prompt);
|
|
167
|
+
res.status(201).json(finished);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
162
170
|
res.status(201).json(snapshot);
|
|
163
171
|
}
|
|
164
172
|
catch (error) {
|
|
@@ -472,7 +480,9 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
472
480
|
}
|
|
473
481
|
const newMode = body.mode ? normalizeMode(body.mode, defaultMode) : normalizeMode(existingSession.mode, defaultMode);
|
|
474
482
|
const resumeCommand = `${command} --resume ${claudeSessionId}`;
|
|
475
|
-
const
|
|
483
|
+
const reqCols = typeof body.cols === "number" && Number.isFinite(body.cols) ? body.cols : undefined;
|
|
484
|
+
const reqRows = typeof body.rows === "number" && Number.isFinite(body.rows) ? body.rows : undefined;
|
|
485
|
+
const newSnapshot = processes.start(resumeCommand, existingSession.cwd, newMode, undefined, { reuseId: sessionId, cols: reqCols, rows: reqRows });
|
|
476
486
|
res.status(201).json(newSnapshot);
|
|
477
487
|
}
|
|
478
488
|
catch (error) {
|
|
@@ -509,7 +519,9 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
509
519
|
}
|
|
510
520
|
const newMode = body.mode ? normalizeMode(body.mode, defaultMode) : normalizeMode(existingSession.mode, defaultMode);
|
|
511
521
|
const resumeCommand = `${command} --resume ${claudeSessionId}`;
|
|
512
|
-
const
|
|
522
|
+
const reqCols = typeof body.cols === "number" && Number.isFinite(body.cols) ? body.cols : undefined;
|
|
523
|
+
const reqRows = typeof body.rows === "number" && Number.isFinite(body.rows) ? body.rows : undefined;
|
|
524
|
+
const newSnapshot = processes.start(resumeCommand, existingSession.cwd, newMode, undefined, { reuseId: existingSession.id, cols: reqCols, rows: reqRows });
|
|
513
525
|
res.status(201).json({ resumedClaudeSessionId: claudeSessionId, ...newSnapshot });
|
|
514
526
|
}
|
|
515
527
|
else {
|
|
@@ -520,7 +532,9 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
520
532
|
}
|
|
521
533
|
const newMode = normalizeMode(body.mode, defaultMode);
|
|
522
534
|
const resumeCommand = `claude --resume ${claudeSessionId}`;
|
|
523
|
-
const
|
|
535
|
+
const reqCols = typeof body.cols === "number" && Number.isFinite(body.cols) ? body.cols : undefined;
|
|
536
|
+
const reqRows = typeof body.rows === "number" && Number.isFinite(body.rows) ? body.rows : undefined;
|
|
537
|
+
const newSnapshot = processes.start(resumeCommand, cwd, newMode, undefined, { cols: reqCols, rows: reqRows });
|
|
524
538
|
res.status(201).json({ resumedClaudeSessionId: claudeSessionId, ...newSnapshot });
|
|
525
539
|
}
|
|
526
540
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ProcessManager } from "./process-manager.js";
|
|
2
2
|
import { StructuredSessionManager } from "./structured-session-manager.js";
|
|
3
|
+
import { WandStorage } from "./storage.js";
|
|
3
4
|
import { WandConfig } from "./types.js";
|
|
5
|
+
/** Persist a cwd to recent paths. Used by both REST and session creation hooks. */
|
|
6
|
+
export declare function recordRecentPath(storage: WandStorage, cwd: string | undefined | null): void;
|
|
4
7
|
export interface ServerUrl {
|
|
5
8
|
url: string;
|
|
6
9
|
scheme: "HTTP" | "HTTPS";
|
package/dist/server.js
CHANGED
|
@@ -16,6 +16,7 @@ import { ensureCertificates } from "./cert.js";
|
|
|
16
16
|
import { isExecutionMode, normalizeCardDefaults, resolveConfigDir, saveConfig } from "./config.js";
|
|
17
17
|
import { getCachedModels, refreshModels } from "./models.js";
|
|
18
18
|
import { ProcessManager } from "./process-manager.js";
|
|
19
|
+
import { SessionLogger } from "./session-logger.js";
|
|
19
20
|
import { StructuredSessionManager } from "./structured-session-manager.js";
|
|
20
21
|
import { generatePwaManifest, generateServiceWorker } from "./pwa.js";
|
|
21
22
|
import { getErrorMessage, registerClaudeHistoryRoutes, registerSessionRoutes } from "./server-session-routes.js";
|
|
@@ -481,6 +482,33 @@ function parseStoredPathList(raw) {
|
|
|
481
482
|
}
|
|
482
483
|
}
|
|
483
484
|
const MAX_RECENT_PATHS = 10;
|
|
485
|
+
/** Persist a cwd to recent paths. Used by both REST and session creation hooks. */
|
|
486
|
+
export function recordRecentPath(storage, cwd) {
|
|
487
|
+
if (!cwd)
|
|
488
|
+
return;
|
|
489
|
+
const trimmed = cwd.trim();
|
|
490
|
+
if (!trimmed)
|
|
491
|
+
return;
|
|
492
|
+
let resolved;
|
|
493
|
+
try {
|
|
494
|
+
resolved = normalizeFolderPath(trimmed);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (isBlockedFolderPath(resolved))
|
|
500
|
+
return;
|
|
501
|
+
const stored = storage.getConfigValue("recent_paths");
|
|
502
|
+
let recent = parseStoredPathList(stored);
|
|
503
|
+
recent = recent.filter((r) => normalizeFolderPath(r.path) !== resolved);
|
|
504
|
+
recent.unshift({
|
|
505
|
+
path: resolved,
|
|
506
|
+
name: path.basename(resolved),
|
|
507
|
+
lastUsedAt: new Date().toISOString(),
|
|
508
|
+
});
|
|
509
|
+
recent = recent.slice(0, MAX_RECENT_PATHS);
|
|
510
|
+
storage.setConfigValue("recent_paths", JSON.stringify(recent));
|
|
511
|
+
}
|
|
484
512
|
// ── File language detection ──
|
|
485
513
|
function getLanguageFromExt(ext, filePath) {
|
|
486
514
|
const map = {
|
|
@@ -514,7 +542,8 @@ export async function startServer(config, configPath) {
|
|
|
514
542
|
const configDir = resolveConfigDir(configPath);
|
|
515
543
|
const avatarSeed = await ensureAvatarSeed(configDir);
|
|
516
544
|
const processes = new ProcessManager(config, storage, configDir);
|
|
517
|
-
const
|
|
545
|
+
const structuredLogger = new SessionLogger(configDir, config.shortcutLogMaxBytes);
|
|
546
|
+
const structuredSessions = new StructuredSessionManager(storage, config, structuredLogger);
|
|
518
547
|
const useHttps = config.https === true;
|
|
519
548
|
const protocol = useHttps ? "https" : "http";
|
|
520
549
|
const nodeModulesDir = path.join(RUNTIME_ROOT_DIR, "node_modules");
|
|
@@ -695,7 +724,10 @@ export async function startServer(config, configPath) {
|
|
|
695
724
|
defaultMode: config.defaultMode,
|
|
696
725
|
defaultCwd: config.defaultCwd,
|
|
697
726
|
commandPresets: config.commandPresets,
|
|
698
|
-
structuredRunners: [
|
|
727
|
+
structuredRunners: [
|
|
728
|
+
{ label: "Claude Structured", runner: "claude-cli-print" },
|
|
729
|
+
{ label: "Codex Structured", runner: "codex-cli-exec" },
|
|
730
|
+
],
|
|
699
731
|
structuredChatPersona,
|
|
700
732
|
cardDefaults: config.cardDefaults,
|
|
701
733
|
updateAvailable: cachedUpdateInfo?.updateAvailable ?? false,
|
|
@@ -847,6 +879,7 @@ export async function startServer(config, configPath) {
|
|
|
847
879
|
const cached = getCachedModels();
|
|
848
880
|
res.json({
|
|
849
881
|
models: cached.models,
|
|
882
|
+
codexModels: cached.codexModels,
|
|
850
883
|
claudeVersion: cached.claudeVersion,
|
|
851
884
|
refreshedAt: cached.refreshedAt,
|
|
852
885
|
defaultModel: config.defaultModel ?? "",
|
|
@@ -857,6 +890,7 @@ export async function startServer(config, configPath) {
|
|
|
857
890
|
const refreshed = await refreshModels();
|
|
858
891
|
res.json({
|
|
859
892
|
models: refreshed.models,
|
|
893
|
+
codexModels: refreshed.codexModels,
|
|
860
894
|
claudeVersion: refreshed.claudeVersion,
|
|
861
895
|
refreshedAt: refreshed.refreshedAt,
|
|
862
896
|
defaultModel: config.defaultModel ?? "",
|
|
@@ -919,7 +953,9 @@ export async function startServer(config, configPath) {
|
|
|
919
953
|
updateInFlight = false;
|
|
920
954
|
}
|
|
921
955
|
});
|
|
922
|
-
registerSessionRoutes(app, processes, structuredSessions, storage, config.defaultMode, config)
|
|
956
|
+
registerSessionRoutes(app, processes, structuredSessions, storage, config.defaultMode, config, (cwd) => {
|
|
957
|
+
recordRecentPath(storage, cwd);
|
|
958
|
+
});
|
|
923
959
|
registerClaudeHistoryRoutes(app, processes, storage);
|
|
924
960
|
registerUploadRoutes(app, processes);
|
|
925
961
|
app.post("/api/optimize-prompt", express.json({ limit: "256kb" }), async (req, res) => {
|
|
@@ -1098,18 +1134,12 @@ export async function startServer(config, configPath) {
|
|
|
1098
1134
|
res.status(403).json({ error: "访问被拒绝:无法保存系统敏感目录。" });
|
|
1099
1135
|
return;
|
|
1100
1136
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
recent = recent.filter((r) => normalizeFolderPath(r.path) !== resolvedRecentPath);
|
|
1104
|
-
const newRecent = {
|
|
1137
|
+
recordRecentPath(storage, resolvedRecentPath);
|
|
1138
|
+
res.json({
|
|
1105
1139
|
path: resolvedRecentPath,
|
|
1106
1140
|
name: path.basename(resolvedRecentPath),
|
|
1107
1141
|
lastUsedAt: new Date().toISOString(),
|
|
1108
|
-
};
|
|
1109
|
-
recent.unshift(newRecent);
|
|
1110
|
-
recent = recent.slice(0, MAX_RECENT_PATHS);
|
|
1111
|
-
storage.setConfigValue("recent_paths", JSON.stringify(recent));
|
|
1112
|
-
res.json(newRecent);
|
|
1142
|
+
});
|
|
1113
1143
|
});
|
|
1114
1144
|
app.get("/api/validate-path", async (req, res) => {
|
|
1115
1145
|
const inputPath = typeof req.query.path === "string" ? req.query.path : "";
|
|
@@ -1215,11 +1245,16 @@ export async function startServer(config, configPath) {
|
|
|
1215
1245
|
try {
|
|
1216
1246
|
const rawModel = typeof body.model === "string" ? body.model.trim() : "";
|
|
1217
1247
|
const effectiveModel = rawModel || (config.defaultModel ?? "").trim() || undefined;
|
|
1248
|
+
const reqCols = typeof body.cols === "number" && Number.isFinite(body.cols) ? body.cols : undefined;
|
|
1249
|
+
const reqRows = typeof body.rows === "number" && Number.isFinite(body.rows) ? body.rows : undefined;
|
|
1218
1250
|
const snapshot = processes.start(body.command, body.cwd, normalizeMode(body.mode, config.defaultMode), initialInput || undefined, {
|
|
1219
1251
|
worktreeEnabled: body.worktreeEnabled === true,
|
|
1220
1252
|
provider: body.provider,
|
|
1221
1253
|
model: effectiveModel,
|
|
1254
|
+
cols: reqCols,
|
|
1255
|
+
rows: reqRows,
|
|
1222
1256
|
});
|
|
1257
|
+
recordRecentPath(storage, body.cwd ?? snapshot.cwd);
|
|
1223
1258
|
res.status(201).json(snapshot);
|
|
1224
1259
|
}
|
|
1225
1260
|
catch (error) {
|
|
@@ -1304,6 +1339,8 @@ export async function startServer(config, configPath) {
|
|
|
1304
1339
|
}
|
|
1305
1340
|
// Start configured background sessions after the server is already reachable.
|
|
1306
1341
|
processes.runStartupCommands();
|
|
1342
|
+
// Pre-warm model cache (probes claude --version + codex debug models).
|
|
1343
|
+
refreshModels().catch(() => { });
|
|
1307
1344
|
// ── Auto-update endpoints ──
|
|
1308
1345
|
app.get("/api/auto-update", (_req, res) => {
|
|
1309
1346
|
const web = storage.getConfigValue("autoUpdateWeb") === "true";
|
package/dist/session-logger.d.ts
CHANGED
|
@@ -24,10 +24,13 @@ export interface ShortcutLogContext {
|
|
|
24
24
|
* SessionLogger saves raw session content to local files for debugging and analysis.
|
|
25
25
|
*
|
|
26
26
|
* Directory structure: .wand/sessions/{sessionId}/
|
|
27
|
-
* - pty-output.log
|
|
28
|
-
* - pty-output.log.1..3
|
|
29
|
-
* - stream-events.jsonl
|
|
30
|
-
* - messages.json
|
|
27
|
+
* - pty-output.log Raw PTY output (current, rotated when > 50 MB)
|
|
28
|
+
* - pty-output.log.1..3 Rotated PTY output backups
|
|
29
|
+
* - stream-events.jsonl NDJSON events from native mode (append-only)
|
|
30
|
+
* - messages.json Final structured messages (overwritten on each update)
|
|
31
|
+
* - structured-stdout.log Raw stdout from `codex exec` / `claude -p` child (append-only)
|
|
32
|
+
* - structured-stderr.log Raw stderr from the same child (append-only)
|
|
33
|
+
* - structured-spawns.jsonl One line per spawn: args/pid/cwd/exit/error metadata
|
|
31
34
|
*/
|
|
32
35
|
export declare class SessionLogger {
|
|
33
36
|
private readonly baseDir;
|
|
@@ -48,6 +51,14 @@ export declare class SessionLogger {
|
|
|
48
51
|
readPtyOutput(sessionId: string): string | null;
|
|
49
52
|
/** Append a native mode NDJSON event */
|
|
50
53
|
appendStreamEvent(sessionId: string, event: unknown): void;
|
|
54
|
+
/** Append raw stdout chunk from a structured-mode child process. */
|
|
55
|
+
appendStructuredStdout(sessionId: string, chunk: string): void;
|
|
56
|
+
/** Append raw stderr chunk from a structured-mode child process. */
|
|
57
|
+
appendStructuredStderr(sessionId: string, chunk: string): void;
|
|
58
|
+
/** Append a spawn metadata record (args, pid, cwd, exit, errors, …) for a structured run. */
|
|
59
|
+
appendStructuredSpawn(sessionId: string, meta: Record<string, unknown>): void;
|
|
60
|
+
/** Read recent stderr tail (for surfacing in failure messages). */
|
|
61
|
+
readStructuredStderrTail(sessionId: string, maxBytes?: number): string;
|
|
51
62
|
/** Save the current structured messages snapshot */
|
|
52
63
|
saveMessages(sessionId: string, messages: ConversationTurn[]): void;
|
|
53
64
|
/** Save session metadata */
|
package/dist/session-logger.js
CHANGED
|
@@ -12,10 +12,13 @@ const DEFAULT_SHORTCUT_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
12
12
|
* SessionLogger saves raw session content to local files for debugging and analysis.
|
|
13
13
|
*
|
|
14
14
|
* Directory structure: .wand/sessions/{sessionId}/
|
|
15
|
-
* - pty-output.log
|
|
16
|
-
* - pty-output.log.1..3
|
|
17
|
-
* - stream-events.jsonl
|
|
18
|
-
* - messages.json
|
|
15
|
+
* - pty-output.log Raw PTY output (current, rotated when > 50 MB)
|
|
16
|
+
* - pty-output.log.1..3 Rotated PTY output backups
|
|
17
|
+
* - stream-events.jsonl NDJSON events from native mode (append-only)
|
|
18
|
+
* - messages.json Final structured messages (overwritten on each update)
|
|
19
|
+
* - structured-stdout.log Raw stdout from `codex exec` / `claude -p` child (append-only)
|
|
20
|
+
* - structured-stderr.log Raw stderr from the same child (append-only)
|
|
21
|
+
* - structured-spawns.jsonl One line per spawn: args/pid/cwd/exit/error metadata
|
|
19
22
|
*/
|
|
20
23
|
export class SessionLogger {
|
|
21
24
|
baseDir;
|
|
@@ -122,6 +125,51 @@ export class SessionLogger {
|
|
|
122
125
|
// Non-critical
|
|
123
126
|
}
|
|
124
127
|
}
|
|
128
|
+
/** Append raw stdout chunk from a structured-mode child process. */
|
|
129
|
+
appendStructuredStdout(sessionId, chunk) {
|
|
130
|
+
try {
|
|
131
|
+
const dir = this.ensureDir(sessionId);
|
|
132
|
+
appendFileSync(path.join(dir, "structured-stdout.log"), chunk);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Non-critical
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Append raw stderr chunk from a structured-mode child process. */
|
|
139
|
+
appendStructuredStderr(sessionId, chunk) {
|
|
140
|
+
try {
|
|
141
|
+
const dir = this.ensureDir(sessionId);
|
|
142
|
+
appendFileSync(path.join(dir, "structured-stderr.log"), chunk);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Non-critical
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** Append a spawn metadata record (args, pid, cwd, exit, errors, …) for a structured run. */
|
|
149
|
+
appendStructuredSpawn(sessionId, meta) {
|
|
150
|
+
try {
|
|
151
|
+
const dir = this.ensureDir(sessionId);
|
|
152
|
+
const entry = JSON.stringify({ ts: new Date().toISOString(), ...meta }) + "\n";
|
|
153
|
+
appendFileSync(path.join(dir, "structured-spawns.jsonl"), entry);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Non-critical
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Read recent stderr tail (for surfacing in failure messages). */
|
|
160
|
+
readStructuredStderrTail(sessionId, maxBytes = 4096) {
|
|
161
|
+
try {
|
|
162
|
+
const dir = this.ensureDir(sessionId);
|
|
163
|
+
const filePath = path.join(dir, "structured-stderr.log");
|
|
164
|
+
if (!existsSync(filePath))
|
|
165
|
+
return "";
|
|
166
|
+
const content = readFileSync(filePath, "utf8");
|
|
167
|
+
return content.length <= maxBytes ? content : content.slice(content.length - maxBytes);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
125
173
|
/** Save the current structured messages snapshot */
|
|
126
174
|
saveMessages(sessionId, messages) {
|
|
127
175
|
try {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { SessionLogger } from "./session-logger.js";
|
|
1
2
|
import { WandStorage } from "./storage.js";
|
|
2
|
-
import { ExecutionMode, ProcessEvent, SessionRunner, SessionSnapshot, WandConfig } from "./types.js";
|
|
3
|
+
import { ExecutionMode, ProcessEvent, SessionProvider, SessionRunner, SessionSnapshot, WandConfig } from "./types.js";
|
|
3
4
|
interface CreateStructuredSessionOptions {
|
|
4
5
|
cwd: string;
|
|
5
6
|
mode: ExecutionMode;
|
|
6
7
|
prompt?: string;
|
|
8
|
+
provider?: SessionProvider;
|
|
7
9
|
runner?: SessionRunner;
|
|
8
10
|
worktreeEnabled?: boolean;
|
|
9
11
|
/** 用户指定的 Claude 模型(别名或完整 ID)。留空则 spawn 时不加 --model。 */
|
|
@@ -12,12 +14,13 @@ interface CreateStructuredSessionOptions {
|
|
|
12
14
|
export declare class StructuredSessionManager {
|
|
13
15
|
private readonly storage;
|
|
14
16
|
private readonly config;
|
|
17
|
+
private readonly logger;
|
|
15
18
|
private readonly sessions;
|
|
16
19
|
private readonly pendingChildren;
|
|
17
20
|
private readonly interruptedWith;
|
|
18
21
|
private emitEvent;
|
|
19
22
|
private archiveTimer;
|
|
20
|
-
constructor(storage: WandStorage, config: WandConfig);
|
|
23
|
+
constructor(storage: WandStorage, config: WandConfig, logger?: SessionLogger | null);
|
|
21
24
|
private archiveExpiredSessions;
|
|
22
25
|
setEventEmitter(emitEvent: (event: ProcessEvent) => void): void;
|
|
23
26
|
list(): SessionSnapshot[];
|
|
@@ -49,6 +52,8 @@ export declare class StructuredSessionManager {
|
|
|
49
52
|
private resolvePermission;
|
|
50
53
|
private incrementApprovalStats;
|
|
51
54
|
private buildPermissionArgs;
|
|
55
|
+
private buildCodexArgs;
|
|
56
|
+
private runCodexStreaming;
|
|
52
57
|
/**
|
|
53
58
|
* Spawn `claude -p --output-format stream-json` and parse NDJSON lines as
|
|
54
59
|
* they arrive, emitting incremental WebSocket events so the UI can render
|
|
@@ -65,7 +70,12 @@ export declare class StructuredSessionManager {
|
|
|
65
70
|
private compactContentBlocks;
|
|
66
71
|
private normalizeToolInput;
|
|
67
72
|
private normalizeToolResultContent;
|
|
73
|
+
private extractCodexText;
|
|
74
|
+
private extractCodexItemBlock;
|
|
75
|
+
private upsertCodexBlock;
|
|
76
|
+
private finishStructuredFailure;
|
|
68
77
|
private extractModelName;
|
|
69
78
|
private extractUsage;
|
|
79
|
+
private extractCodexUsage;
|
|
70
80
|
}
|
|
71
81
|
export {};
|