@co0ontty/wand 1.9.0 → 1.14.2

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/storage.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import { existsSync, mkdirSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { DatabaseSync } from "node:sqlite";
4
- function parseStoredMessages(raw) {
5
- if (!raw) {
4
+ function safeJsonParse(raw) {
5
+ if (!raw)
6
6
  return undefined;
7
- }
8
7
  try {
9
8
  return JSON.parse(raw);
10
9
  }
@@ -13,27 +12,8 @@ function parseStoredMessages(raw) {
13
12
  }
14
13
  }
15
14
  function parseQueuedMessages(raw) {
16
- if (!raw) {
17
- return undefined;
18
- }
19
- try {
20
- const parsed = JSON.parse(raw);
21
- return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : undefined;
22
- }
23
- catch {
24
- return undefined;
25
- }
26
- }
27
- function parseStructuredState(raw) {
28
- if (!raw) {
29
- return undefined;
30
- }
31
- try {
32
- return JSON.parse(raw);
33
- }
34
- catch {
35
- return undefined;
36
- }
15
+ const parsed = safeJsonParse(raw);
16
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : undefined;
37
17
  }
38
18
  function inferSessionProvider(row) {
39
19
  if (row.provider === "claude" || row.provider === "codex") {
@@ -45,37 +25,14 @@ function inferSessionProvider(row) {
45
25
  return /^claude\b/.test(row.command.trim()) ? "claude" : undefined;
46
26
  }
47
27
  function parseWorktreeInfo(raw) {
48
- if (!raw) {
49
- return undefined;
50
- }
51
- try {
52
- const parsed = JSON.parse(raw);
53
- if (parsed
54
- && typeof parsed === "object"
55
- && typeof parsed.branch === "string"
56
- && typeof parsed.path === "string") {
57
- return parsed;
58
- }
59
- }
60
- catch {
61
- return undefined;
28
+ const parsed = safeJsonParse(raw);
29
+ if (parsed && typeof parsed.branch === "string" && typeof parsed.path === "string") {
30
+ return { branch: parsed.branch, path: parsed.path };
62
31
  }
63
32
  return undefined;
64
33
  }
65
34
  function parseWorktreeMergeInfo(raw) {
66
- if (!raw) {
67
- return undefined;
68
- }
69
- try {
70
- const parsed = JSON.parse(raw);
71
- if (parsed && typeof parsed === "object") {
72
- return parsed;
73
- }
74
- }
75
- catch {
76
- return undefined;
77
- }
78
- return undefined;
35
+ return safeJsonParse(raw);
79
36
  }
80
37
  function serializeWorktreeMergeInfo(info) {
81
38
  return info ? JSON.stringify(info) : null;
@@ -89,15 +46,6 @@ function normalizeWorktreeMergeStatus(raw) {
89
46
  }
90
47
  return undefined;
91
48
  }
92
- function getWorktreeMergeStatusValue(snapshot) {
93
- return snapshot.worktreeMergeStatus ?? null;
94
- }
95
- function getWorktreeMergeInfoValue(snapshot) {
96
- return serializeWorktreeMergeInfo(snapshot.worktreeMergeInfo);
97
- }
98
- function getWorktreeInfoValue(snapshot) {
99
- return serializeWorktreeInfo(snapshot.worktree);
100
- }
101
49
  function mapWorktreeMergeFields(row) {
102
50
  return {
103
51
  worktreeMergeStatus: normalizeWorktreeMergeStatus(row.worktree_merge_status),
@@ -171,9 +119,9 @@ function sessionPersistValues(snapshot) {
171
119
  snapshot.resumedToSessionId ?? null,
172
120
  snapshot.autoRecovered ? 1 : 0,
173
121
  snapshot.worktreeEnabled ? 1 : 0,
174
- getWorktreeInfoValue(snapshot),
175
- getWorktreeMergeStatusValue(snapshot),
176
- getWorktreeMergeInfoValue(snapshot),
122
+ serializeWorktreeInfo(snapshot.worktree),
123
+ snapshot.worktreeMergeStatus ?? null,
124
+ serializeWorktreeMergeInfo(snapshot.worktreeMergeInfo),
177
125
  ];
178
126
  }
179
127
  function sessionMetadataValues(snapshot) {
@@ -197,9 +145,9 @@ function sessionMetadataValues(snapshot) {
197
145
  snapshot.resumedToSessionId ?? null,
198
146
  snapshot.autoRecovered ? 1 : 0,
199
147
  snapshot.worktreeEnabled ? 1 : 0,
200
- getWorktreeInfoValue(snapshot),
201
- getWorktreeMergeStatusValue(snapshot),
202
- getWorktreeMergeInfoValue(snapshot),
148
+ serializeWorktreeInfo(snapshot.worktree),
149
+ snapshot.worktreeMergeStatus ?? null,
150
+ serializeWorktreeMergeInfo(snapshot.worktreeMergeInfo),
203
151
  snapshot.id,
204
152
  ];
205
153
  }
@@ -221,9 +169,9 @@ function mapSessionCore(row) {
221
169
  archived: Boolean(row.archived),
222
170
  archivedAt: row.archived_at,
223
171
  claudeSessionId: row.claude_session_id,
224
- messages: parseStoredMessages(row.messages),
172
+ messages: safeJsonParse(row.messages),
225
173
  queuedMessages: parseQueuedMessages(row.queued_messages),
226
- structuredState: parseStructuredState(row.structured_state),
174
+ structuredState: safeJsonParse(row.structured_state),
227
175
  resumedFromSessionId: row.resumed_from_session_id ?? undefined,
228
176
  resumedToSessionId: row.resumed_to_session_id ?? undefined,
229
177
  autoRecovered: Boolean(row.auto_recovered),
@@ -430,52 +378,30 @@ export class WandStorage {
430
378
  this.db.prepare("DELETE FROM command_sessions WHERE id = ?").run(id);
431
379
  }
432
380
  }
381
+ const SCHEMA_MIGRATIONS = [
382
+ ["archived", "ALTER TABLE command_sessions ADD COLUMN archived INTEGER NOT NULL DEFAULT 0"],
383
+ ["archived_at", "ALTER TABLE command_sessions ADD COLUMN archived_at TEXT"],
384
+ ["claude_session_id", "ALTER TABLE command_sessions ADD COLUMN claude_session_id TEXT"],
385
+ ["provider", "ALTER TABLE command_sessions ADD COLUMN provider TEXT"],
386
+ ["session_kind", "ALTER TABLE command_sessions ADD COLUMN session_kind TEXT NOT NULL DEFAULT 'pty'"],
387
+ ["runner", "ALTER TABLE command_sessions ADD COLUMN runner TEXT"],
388
+ ["messages", "ALTER TABLE command_sessions ADD COLUMN messages TEXT"],
389
+ ["queued_messages", "ALTER TABLE command_sessions ADD COLUMN queued_messages TEXT"],
390
+ ["structured_state", "ALTER TABLE command_sessions ADD COLUMN structured_state TEXT"],
391
+ ["resumed_from_session_id", "ALTER TABLE command_sessions ADD COLUMN resumed_from_session_id TEXT"],
392
+ ["resumed_to_session_id", "ALTER TABLE command_sessions ADD COLUMN resumed_to_session_id TEXT"],
393
+ ["auto_recovered", "ALTER TABLE command_sessions ADD COLUMN auto_recovered INTEGER NOT NULL DEFAULT 0"],
394
+ ["worktree_enabled", "ALTER TABLE command_sessions ADD COLUMN worktree_enabled INTEGER NOT NULL DEFAULT 0"],
395
+ ["worktree_info", "ALTER TABLE command_sessions ADD COLUMN worktree_info TEXT"],
396
+ ["worktree_merge_status", "ALTER TABLE command_sessions ADD COLUMN worktree_merge_status TEXT"],
397
+ ["worktree_merge_info", "ALTER TABLE command_sessions ADD COLUMN worktree_merge_info TEXT"],
398
+ ];
433
399
  function ensureCommandSessionSchema(db) {
434
400
  const columns = db.prepare("PRAGMA table_info(command_sessions)").all();
435
401
  const names = new Set(columns.map((column) => column.name));
436
- if (!names.has("archived")) {
437
- db.exec("ALTER TABLE command_sessions ADD COLUMN archived INTEGER NOT NULL DEFAULT 0");
438
- }
439
- if (!names.has("archived_at")) {
440
- db.exec("ALTER TABLE command_sessions ADD COLUMN archived_at TEXT");
441
- }
442
- if (!names.has("claude_session_id")) {
443
- db.exec("ALTER TABLE command_sessions ADD COLUMN claude_session_id TEXT");
444
- }
445
- if (!names.has("provider")) {
446
- db.exec("ALTER TABLE command_sessions ADD COLUMN provider TEXT");
447
- }
448
- if (!names.has("session_kind")) {
449
- db.exec("ALTER TABLE command_sessions ADD COLUMN session_kind TEXT NOT NULL DEFAULT 'pty'");
450
- }
451
- if (!names.has("runner")) {
452
- db.exec("ALTER TABLE command_sessions ADD COLUMN runner TEXT");
453
- }
454
- if (!names.has("messages")) {
455
- db.exec("ALTER TABLE command_sessions ADD COLUMN messages TEXT");
456
- }
457
- if (!names.has("queued_messages")) {
458
- db.exec("ALTER TABLE command_sessions ADD COLUMN queued_messages TEXT");
459
- }
460
- if (!names.has("structured_state")) {
461
- db.exec("ALTER TABLE command_sessions ADD COLUMN structured_state TEXT");
462
- }
463
- if (!names.has("resumed_from_session_id")) {
464
- db.exec("ALTER TABLE command_sessions ADD COLUMN resumed_from_session_id TEXT");
465
- }
466
- if (!names.has("resumed_to_session_id")) {
467
- db.exec("ALTER TABLE command_sessions ADD COLUMN resumed_to_session_id TEXT");
468
- }
469
- if (!names.has("worktree_enabled")) {
470
- db.exec("ALTER TABLE command_sessions ADD COLUMN worktree_enabled INTEGER NOT NULL DEFAULT 0");
471
- }
472
- if (!names.has("worktree_info")) {
473
- db.exec("ALTER TABLE command_sessions ADD COLUMN worktree_info TEXT");
474
- }
475
- if (!names.has("worktree_merge_status")) {
476
- db.exec("ALTER TABLE command_sessions ADD COLUMN worktree_merge_status TEXT");
477
- }
478
- if (!names.has("worktree_merge_info")) {
479
- db.exec("ALTER TABLE command_sessions ADD COLUMN worktree_merge_info TEXT");
402
+ for (const [column, sql] of SCHEMA_MIGRATIONS) {
403
+ if (!names.has(column)) {
404
+ db.exec(sql);
405
+ }
480
406
  }
481
407
  }
@@ -16,6 +16,8 @@ export declare class StructuredSessionManager {
16
16
  constructor(storage: WandStorage, config: WandConfig);
17
17
  setEventEmitter(emitEvent: (event: ProcessEvent) => void): void;
18
18
  list(): SessionSnapshot[];
19
+ /** Return lightweight snapshots for the session list (no output/messages). */
20
+ listSlim(): SessionSnapshot[];
19
21
  get(id: string): SessionSnapshot | null;
20
22
  createSession(options: CreateStructuredSessionOptions): SessionSnapshot;
21
23
  sendMessage(id: string, input: string): Promise<SessionSnapshot>;
@@ -80,6 +80,16 @@ export class StructuredSessionManager {
80
80
  .map(withSummary)
81
81
  .sort((a, b) => b.startedAt.localeCompare(a.startedAt));
82
82
  }
83
+ /** Return lightweight snapshots for the session list (no output/messages). */
84
+ listSlim() {
85
+ return Array.from(this.sessions.values())
86
+ .map((s) => {
87
+ const enriched = withSummary(s);
88
+ const { output: _o, messages: _m, ...slim } = enriched;
89
+ return { ...slim, output: "" };
90
+ })
91
+ .sort((a, b) => b.startedAt.localeCompare(a.startedAt));
92
+ }
83
93
  get(id) {
84
94
  const s = this.sessions.get(id);
85
95
  return s ? withSummary(s) : null;
package/dist/types.d.ts CHANGED
@@ -47,20 +47,22 @@ export interface StructuredChatPersonaConfig {
47
47
  user?: StructuredChatPersonaRoleConfig;
48
48
  assistant?: StructuredChatPersonaRoleConfig;
49
49
  }
50
- export interface DefaultPanelStateConfig {
51
- sessionsDrawerOpen?: boolean;
52
- filePanelOpen?: boolean;
53
- shortcutsExpanded?: boolean;
54
- claudeHistoryExpanded?: boolean;
55
- chatMessageExpanded?: boolean;
56
- structuredThinkingExpanded?: boolean;
57
- structuredToolGroupExpanded?: boolean;
58
- structuredInlineToolExpanded?: boolean;
59
- structuredTerminalExpanded?: boolean;
60
- structuredToolCardExpanded?: boolean;
61
- }
62
- export interface UiPreferencesConfig {
63
- defaultPanelState?: DefaultPanelStateConfig;
50
+ export interface CardExpandDefaults {
51
+ /** Edit/Write/MultiEdit diff cards (default: false) */
52
+ editCards?: boolean;
53
+ /** Read/Glob/Grep/WebFetch/WebSearch inline tools (default: false) */
54
+ inlineTools?: boolean;
55
+ /** Bash terminal output (default: false) */
56
+ terminal?: boolean;
57
+ /** Thinking blocks (default: false) */
58
+ thinking?: boolean;
59
+ /** Tool groups (default: false) */
60
+ toolGroup?: boolean;
61
+ }
62
+ export interface AndroidApkConfig {
63
+ enabled?: boolean;
64
+ apkDir?: string;
65
+ currentApkFile?: string;
64
66
  }
65
67
  export interface WandConfig {
66
68
  host: string;
@@ -79,8 +81,11 @@ export interface WandConfig {
79
81
  shortcutLogMaxBytes?: number;
80
82
  /** Preferred response language for Claude (e.g. "中文", "English"). Empty string means no override. */
81
83
  language?: string;
82
- /** UI defaults used for initializing panel open/expanded state. */
83
- uiPreferences?: UiPreferencesConfig;
84
+ /** Per-instance secret for app connection code encryption. Auto-generated on first run. */
85
+ appSecret?: string;
86
+ android?: AndroidApkConfig;
87
+ /** Default expand/collapse state for card types in structured chat view */
88
+ cardDefaults?: CardExpandDefaults;
84
89
  }
85
90
  interface WorktreeInfo {
86
91
  branch: string;
@@ -184,6 +189,10 @@ export interface ToolResultBlock {
184
189
  [key: string]: unknown;
185
190
  }>;
186
191
  is_error?: boolean;
192
+ /** When true, content has been truncated for transport. Client should fetch full content via API. */
193
+ _truncated?: boolean;
194
+ /** Original content size in bytes, provided when truncated. */
195
+ _originalSize?: number;
187
196
  }
188
197
  export type ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock;
189
198
  export interface ConversationTurn {
@@ -264,6 +273,8 @@ export interface SessionSnapshot {
264
273
  };
265
274
  /** 会话摘要:从首条用户消息或当前任务提取 */
266
275
  summary?: string;
276
+ /** 当前正在执行的任务标题(用于会话列表展示) */
277
+ currentTaskTitle?: string;
267
278
  }
268
279
  export type SessionLifecycleState = "initializing" | "running" | "idle" | "thinking" | "waiting-input" | "archived";
269
280
  export interface SessionLifecycle {