@co0ontty/wand 1.3.6 → 1.5.1
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/auth.js +2 -1
- package/dist/claude-pty-bridge.d.ts +6 -0
- package/dist/claude-pty-bridge.js +38 -1
- package/dist/cli.js +2 -2
- package/dist/config.js +3 -2
- package/dist/middleware/rate-limit.js +2 -1
- package/dist/process-manager.d.ts +1 -0
- package/dist/process-manager.js +44 -5
- package/dist/server-session-routes.d.ts +2 -1
- package/dist/server-session-routes.js +113 -7
- package/dist/server.js +13 -9
- package/dist/storage.js +42 -8
- package/dist/structured-session-manager.d.ts +56 -0
- package/dist/structured-session-manager.js +730 -0
- package/dist/types.d.ts +17 -2
- package/dist/web-ui/content/scripts.js +730 -137
- package/dist/web-ui/content/styles.css +288 -79
- package/dist/web-ui/index.js +1 -1
- package/package.json +5 -4
package/dist/storage.js
CHANGED
|
@@ -12,6 +12,17 @@ function parseStoredMessages(raw) {
|
|
|
12
12
|
return undefined;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
function parseStructuredState(raw) {
|
|
16
|
+
if (!raw) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(raw);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
15
26
|
export const DEFAULT_DB_FILE = "wand.db";
|
|
16
27
|
export function resolveDatabasePath(configPath) {
|
|
17
28
|
return path.resolve(path.dirname(configPath), DEFAULT_DB_FILE);
|
|
@@ -34,7 +45,14 @@ const INIT_SQL = `
|
|
|
34
45
|
output TEXT NOT NULL,
|
|
35
46
|
archived INTEGER NOT NULL DEFAULT 0,
|
|
36
47
|
archived_at TEXT,
|
|
37
|
-
claude_session_id TEXT
|
|
48
|
+
claude_session_id TEXT,
|
|
49
|
+
session_kind TEXT NOT NULL DEFAULT 'pty',
|
|
50
|
+
runner TEXT,
|
|
51
|
+
messages TEXT,
|
|
52
|
+
structured_state TEXT,
|
|
53
|
+
resumed_from_session_id TEXT,
|
|
54
|
+
resumed_to_session_id TEXT,
|
|
55
|
+
auto_recovered INTEGER NOT NULL DEFAULT 0
|
|
38
56
|
);
|
|
39
57
|
|
|
40
58
|
CREATE TABLE IF NOT EXISTS app_config (
|
|
@@ -125,9 +143,9 @@ export class WandStorage {
|
|
|
125
143
|
this.db
|
|
126
144
|
.prepare(`INSERT INTO command_sessions (
|
|
127
145
|
id, command, cwd, mode, status, exit_code, started_at, ended_at, output
|
|
128
|
-
, archived, archived_at, claude_session_id, messages
|
|
146
|
+
, archived, archived_at, claude_session_id, session_kind, runner, messages, structured_state
|
|
129
147
|
, resumed_from_session_id, resumed_to_session_id, auto_recovered
|
|
130
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
148
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
131
149
|
ON CONFLICT(id) DO UPDATE SET
|
|
132
150
|
command = excluded.command,
|
|
133
151
|
cwd = excluded.cwd,
|
|
@@ -140,11 +158,14 @@ export class WandStorage {
|
|
|
140
158
|
archived = excluded.archived,
|
|
141
159
|
archived_at = excluded.archived_at,
|
|
142
160
|
claude_session_id = excluded.claude_session_id,
|
|
161
|
+
session_kind = excluded.session_kind,
|
|
162
|
+
runner = excluded.runner,
|
|
143
163
|
messages = excluded.messages,
|
|
164
|
+
structured_state = excluded.structured_state,
|
|
144
165
|
resumed_from_session_id = excluded.resumed_from_session_id,
|
|
145
166
|
resumed_to_session_id = excluded.resumed_to_session_id,
|
|
146
167
|
auto_recovered = excluded.auto_recovered`)
|
|
147
|
-
.run(snapshot.id, snapshot.command, snapshot.cwd, snapshot.mode, snapshot.status, snapshot.exitCode, snapshot.startedAt, snapshot.endedAt, snapshot.output, snapshot.archived ? 1 : 0, snapshot.archivedAt, snapshot.claudeSessionId, snapshot.messages ? JSON.stringify(snapshot.messages) : null, snapshot.resumedFromSessionId ?? null, snapshot.resumedToSessionId ?? null, snapshot.autoRecovered ? 1 : 0);
|
|
168
|
+
.run(snapshot.id, snapshot.command, snapshot.cwd, snapshot.mode, snapshot.status, snapshot.exitCode, snapshot.startedAt, snapshot.endedAt, snapshot.output, snapshot.archived ? 1 : 0, snapshot.archivedAt, snapshot.claudeSessionId, snapshot.sessionKind ?? "pty", snapshot.runner ?? null, snapshot.messages ? JSON.stringify(snapshot.messages) : null, snapshot.structuredState ? JSON.stringify(snapshot.structuredState) : null, snapshot.resumedFromSessionId ?? null, snapshot.resumedToSessionId ?? null, snapshot.autoRecovered ? 1 : 0);
|
|
148
169
|
this.db.exec("COMMIT");
|
|
149
170
|
}
|
|
150
171
|
catch (error) {
|
|
@@ -163,13 +184,14 @@ export class WandStorage {
|
|
|
163
184
|
command = ?, cwd = ?, mode = ?, status = ?, exit_code = ?,
|
|
164
185
|
started_at = ?, ended_at = ?, output = ?,
|
|
165
186
|
archived = ?, archived_at = ?, claude_session_id = ?,
|
|
187
|
+
session_kind = ?, runner = ?, structured_state = ?,
|
|
166
188
|
resumed_from_session_id = ?, resumed_to_session_id = ?, auto_recovered = ?
|
|
167
189
|
WHERE id = ?`)
|
|
168
|
-
.run(snapshot.command, snapshot.cwd, snapshot.mode, snapshot.status, snapshot.exitCode, snapshot.startedAt, snapshot.endedAt, snapshot.output, snapshot.archived ? 1 : 0, snapshot.archivedAt, snapshot.claudeSessionId, snapshot.resumedFromSessionId ?? null, snapshot.resumedToSessionId ?? null, snapshot.autoRecovered ? 1 : 0, snapshot.id);
|
|
190
|
+
.run(snapshot.command, snapshot.cwd, snapshot.mode, snapshot.status, snapshot.exitCode, snapshot.startedAt, snapshot.endedAt, snapshot.output, snapshot.archived ? 1 : 0, snapshot.archivedAt, snapshot.claudeSessionId, snapshot.sessionKind ?? "pty", snapshot.runner ?? null, snapshot.structuredState ? JSON.stringify(snapshot.structuredState) : null, snapshot.resumedFromSessionId ?? null, snapshot.resumedToSessionId ?? null, snapshot.autoRecovered ? 1 : 0, snapshot.id);
|
|
169
191
|
}
|
|
170
192
|
getSession(id) {
|
|
171
193
|
const row = this.db
|
|
172
|
-
.prepare(`SELECT id, command, cwd, mode, status, exit_code, started_at, ended_at, output, archived, archived_at, claude_session_id, messages
|
|
194
|
+
.prepare(`SELECT id, session_kind, runner, command, cwd, mode, status, exit_code, started_at, ended_at, output, archived, archived_at, claude_session_id, messages, structured_state
|
|
173
195
|
, resumed_from_session_id, resumed_to_session_id, auto_recovered
|
|
174
196
|
FROM command_sessions
|
|
175
197
|
WHERE id = ?`)
|
|
@@ -178,7 +200,7 @@ export class WandStorage {
|
|
|
178
200
|
}
|
|
179
201
|
getLatestSessionByClaudeSessionId(claudeSessionId) {
|
|
180
202
|
const row = this.db
|
|
181
|
-
.prepare(`SELECT id, command, cwd, mode, status, exit_code, started_at, ended_at, output, archived, archived_at, claude_session_id, messages
|
|
203
|
+
.prepare(`SELECT id, session_kind, runner, command, cwd, mode, status, exit_code, started_at, ended_at, output, archived, archived_at, claude_session_id, messages, structured_state
|
|
182
204
|
, resumed_from_session_id, resumed_to_session_id, auto_recovered
|
|
183
205
|
FROM command_sessions
|
|
184
206
|
WHERE claude_session_id = ?
|
|
@@ -189,7 +211,7 @@ export class WandStorage {
|
|
|
189
211
|
}
|
|
190
212
|
loadSessions() {
|
|
191
213
|
const rows = this.db
|
|
192
|
-
.prepare(`SELECT id, command, cwd, mode, status, exit_code, started_at, ended_at, output, archived, archived_at, claude_session_id, messages
|
|
214
|
+
.prepare(`SELECT id, session_kind, runner, command, cwd, mode, status, exit_code, started_at, ended_at, output, archived, archived_at, claude_session_id, messages, structured_state
|
|
193
215
|
, resumed_from_session_id, resumed_to_session_id, auto_recovered
|
|
194
216
|
FROM command_sessions
|
|
195
217
|
ORDER BY started_at DESC`)
|
|
@@ -199,6 +221,8 @@ export class WandStorage {
|
|
|
199
221
|
mapSessionRow(row) {
|
|
200
222
|
return {
|
|
201
223
|
id: row.id,
|
|
224
|
+
sessionKind: row.session_kind ?? "pty",
|
|
225
|
+
runner: row.runner ?? undefined,
|
|
202
226
|
command: row.command,
|
|
203
227
|
cwd: row.cwd,
|
|
204
228
|
mode: row.mode,
|
|
@@ -211,6 +235,7 @@ export class WandStorage {
|
|
|
211
235
|
archivedAt: row.archived_at,
|
|
212
236
|
claudeSessionId: row.claude_session_id,
|
|
213
237
|
messages: parseStoredMessages(row.messages),
|
|
238
|
+
structuredState: parseStructuredState(row.structured_state),
|
|
214
239
|
resumedFromSessionId: row.resumed_from_session_id ?? undefined,
|
|
215
240
|
resumedToSessionId: row.resumed_to_session_id ?? undefined,
|
|
216
241
|
autoRecovered: Boolean(row.auto_recovered)
|
|
@@ -232,9 +257,18 @@ function ensureCommandSessionSchema(db) {
|
|
|
232
257
|
if (!names.has("claude_session_id")) {
|
|
233
258
|
db.exec("ALTER TABLE command_sessions ADD COLUMN claude_session_id TEXT");
|
|
234
259
|
}
|
|
260
|
+
if (!names.has("session_kind")) {
|
|
261
|
+
db.exec("ALTER TABLE command_sessions ADD COLUMN session_kind TEXT NOT NULL DEFAULT 'pty'");
|
|
262
|
+
}
|
|
263
|
+
if (!names.has("runner")) {
|
|
264
|
+
db.exec("ALTER TABLE command_sessions ADD COLUMN runner TEXT");
|
|
265
|
+
}
|
|
235
266
|
if (!names.has("messages")) {
|
|
236
267
|
db.exec("ALTER TABLE command_sessions ADD COLUMN messages TEXT");
|
|
237
268
|
}
|
|
269
|
+
if (!names.has("structured_state")) {
|
|
270
|
+
db.exec("ALTER TABLE command_sessions ADD COLUMN structured_state TEXT");
|
|
271
|
+
}
|
|
238
272
|
if (!names.has("resumed_from_session_id")) {
|
|
239
273
|
db.exec("ALTER TABLE command_sessions ADD COLUMN resumed_from_session_id TEXT");
|
|
240
274
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { WandStorage } from "./storage.js";
|
|
2
|
+
import { ExecutionMode, SessionRunner, SessionSnapshot, WandConfig } from "./types.js";
|
|
3
|
+
import { ProcessEvent } from "./ws-broadcast.js";
|
|
4
|
+
interface CreateStructuredSessionOptions {
|
|
5
|
+
cwd: string;
|
|
6
|
+
mode: ExecutionMode;
|
|
7
|
+
prompt?: string;
|
|
8
|
+
runner?: SessionRunner;
|
|
9
|
+
}
|
|
10
|
+
export declare class StructuredSessionManager {
|
|
11
|
+
private readonly storage;
|
|
12
|
+
private readonly config;
|
|
13
|
+
private readonly sessions;
|
|
14
|
+
private readonly pendingChildren;
|
|
15
|
+
private emitEvent;
|
|
16
|
+
constructor(storage: WandStorage, config: WandConfig);
|
|
17
|
+
setEventEmitter(emitEvent: (event: ProcessEvent) => void): void;
|
|
18
|
+
list(): SessionSnapshot[];
|
|
19
|
+
get(id: string): SessionSnapshot | null;
|
|
20
|
+
createSession(options: CreateStructuredSessionOptions): SessionSnapshot;
|
|
21
|
+
sendMessage(id: string, input: string): Promise<SessionSnapshot>;
|
|
22
|
+
/** Approve a pending permission request. */
|
|
23
|
+
approvePermission(sessionId: string): SessionSnapshot;
|
|
24
|
+
/** Deny a pending permission request. */
|
|
25
|
+
denyPermission(sessionId: string): SessionSnapshot;
|
|
26
|
+
/** Toggle auto-approve for the session. */
|
|
27
|
+
toggleAutoApprove(sessionId: string): SessionSnapshot;
|
|
28
|
+
/** Resolve a specific escalation by requestId. */
|
|
29
|
+
resolveEscalation(sessionId: string, requestId: string, resolution?: "approve_once" | "approve_turn" | "deny"): SessionSnapshot;
|
|
30
|
+
stop(id: string): SessionSnapshot;
|
|
31
|
+
delete(id: string): void;
|
|
32
|
+
private requireSession;
|
|
33
|
+
private emit;
|
|
34
|
+
private resolvePermission;
|
|
35
|
+
private incrementApprovalStats;
|
|
36
|
+
private buildPermissionArgs;
|
|
37
|
+
/**
|
|
38
|
+
* Spawn `claude -p --output-format stream-json` and parse NDJSON lines as
|
|
39
|
+
* they arrive, emitting incremental WebSocket events so the UI can render
|
|
40
|
+
* text / thinking / tool_use blocks in real-time.
|
|
41
|
+
*
|
|
42
|
+
* Permission handling:
|
|
43
|
+
* - Non-root + full-access/managed: --permission-mode bypassPermissions
|
|
44
|
+
* - Non-root + auto-edit: --permission-mode acceptEdits
|
|
45
|
+
* - Root: --permission-mode acceptEdits + --allowedTools (extends approval
|
|
46
|
+
* outside CWD). stdin is always "ignore" — no ACP bidirectional control.
|
|
47
|
+
*/
|
|
48
|
+
private runClaudeStreaming;
|
|
49
|
+
private extractAssistantMessage;
|
|
50
|
+
private compactContentBlocks;
|
|
51
|
+
private normalizeToolInput;
|
|
52
|
+
private normalizeToolResultContent;
|
|
53
|
+
private extractModelName;
|
|
54
|
+
private extractUsage;
|
|
55
|
+
}
|
|
56
|
+
export {};
|