@co0ontty/wand 2.13.0 → 3.0.0

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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "f1b77e3be3f2f0b4a1a158e3fc2020ccbc590c68",
3
- "builtAt": "2026-07-12T10:02:57.593Z",
4
- "version": "2.13.0",
2
+ "commit": "433a1530c708f09aa78cf17e229b0c372f63b246",
3
+ "builtAt": "2026-07-12T12:10:18.456Z",
4
+ "version": "3.0.0",
5
5
  "channel": "stable"
6
6
  }
package/dist/cert.js CHANGED
@@ -9,9 +9,6 @@ function getCertificatePaths(configDir) {
9
9
  certPath: path.join(configDir, "server.crt")
10
10
  };
11
11
  }
12
- function certificatesExist(paths) {
13
- return existsSync(paths.keyPath) && existsSync(paths.certPath);
14
- }
15
12
  function readPair(keyPath, certPath) {
16
13
  try {
17
14
  if (!existsSync(keyPath) || !existsSync(certPath))
@@ -7,7 +7,7 @@
7
7
  * 2. Structured messages for chat view (parsed)
8
8
  */
9
9
  import { EventEmitter } from "node:events";
10
- import type { ApprovalPolicy, ConversationTurn, EscalationScope, TaskData } from "./types.js";
10
+ import type { ConversationTurn, EscalationScope } from "./types.js";
11
11
  interface PermissionState {
12
12
  /** Rolling window for prompt detection */
13
13
  window: string;
@@ -48,8 +48,6 @@ export interface ClaudePtyBridgeOptions {
48
48
  isClaudeCommand?: boolean;
49
49
  /** Whether to auto-approve permission prompts */
50
50
  autoApprove?: boolean;
51
- /** Approval policy for permission handling */
52
- approvalPolicy?: ApprovalPolicy;
53
51
  /** PTY write function for sending approval input */
54
52
  ptyWrite?: (input: string) => void;
55
53
  }
@@ -63,7 +61,6 @@ export interface ClaudePtyBridgeOptions {
63
61
  * - "permission.prompt" - Permission request detected
64
62
  * - "permission.resolved" - Permission resolved
65
63
  * - "session.id" - Claude session ID captured
66
- * - "task" - Task info update
67
64
  * - "ended" - Session ended
68
65
  */
69
66
  export declare class ClaudePtyBridge extends EventEmitter {
@@ -74,12 +71,8 @@ export declare class ClaudePtyBridge extends EventEmitter {
74
71
  private permissionState;
75
72
  private sessionIdWindow;
76
73
  private claudeSessionId;
77
- private currentTask;
78
- private taskDebounceTimer;
79
- private lastEmittedTask;
80
74
  private isClaudeCommand;
81
75
  private autoApprove;
82
- private approvalPolicy;
83
76
  private ptyWrite;
84
77
  /** Set to true once onExit() has been called; guards against post-exit method calls */
85
78
  private _exited;
@@ -112,7 +105,6 @@ export declare class ClaudePtyBridge extends EventEmitter {
112
105
  getClaudeSessionId(): string | null;
113
106
  isPermissionBlocked(): boolean;
114
107
  getPermissionState(): PermissionState;
115
- getCurrentTask(): TaskData | null;
116
108
  /**
117
109
  * Set the PTY write function for sending approval input.
118
110
  */
@@ -40,7 +40,6 @@ function normalizePtyOutput(value) {
40
40
  * - "permission.prompt" - Permission request detected
41
41
  * - "permission.resolved" - Permission resolved
42
42
  * - "session.id" - Claude session ID captured
43
- * - "task" - Task info update
44
43
  * - "ended" - Session ended
45
44
  */
46
45
  export class ClaudePtyBridge extends EventEmitter {
@@ -55,14 +54,9 @@ export class ClaudePtyBridge extends EventEmitter {
55
54
  // Session ID capture
56
55
  sessionIdWindow;
57
56
  claudeSessionId = null;
58
- // Task tracking
59
- currentTask = null;
60
- taskDebounceTimer = null;
61
- lastEmittedTask = null;
62
57
  // Options
63
58
  isClaudeCommand;
64
59
  autoApprove;
65
- approvalPolicy;
66
60
  ptyWrite;
67
61
  /** Set to true once onExit() has been called; guards against post-exit method calls */
68
62
  _exited = false;
@@ -84,7 +78,6 @@ export class ClaudePtyBridge extends EventEmitter {
84
78
  this.rawOutput = options.initialOutput ?? "";
85
79
  this.isClaudeCommand = options.isClaudeCommand ?? false;
86
80
  this.autoApprove = options.autoApprove ?? false;
87
- this.approvalPolicy = options.approvalPolicy ?? "ask-every-time";
88
81
  this.ptyWrite = options.ptyWrite ?? null;
89
82
  this.chatState = {
90
83
  phase: "idle",
@@ -200,11 +193,6 @@ export class ClaudePtyBridge extends EventEmitter {
200
193
  this.chatState.echoSkipped = true; // Force skip echo on exit
201
194
  this.finalizeResponse();
202
195
  }
203
- // Clear task debounce timer
204
- if (this.taskDebounceTimer) {
205
- clearTimeout(this.taskDebounceTimer);
206
- this.taskDebounceTimer = null;
207
- }
208
196
  // Flush pending chat emit
209
197
  if (this.chatEmitTimer) {
210
198
  clearTimeout(this.chatEmitTimer);
@@ -240,9 +228,6 @@ export class ClaudePtyBridge extends EventEmitter {
240
228
  getPermissionState() {
241
229
  return this.permissionState;
242
230
  }
243
- getCurrentTask() {
244
- return this.currentTask;
245
- }
246
231
  /**
247
232
  * Set the PTY write function for sending approval input.
248
233
  */
@@ -445,11 +430,9 @@ export class ClaudePtyBridge extends EventEmitter {
445
430
  if (!blocked && !this.permissionState.isBlocked && this.autoApprove) {
446
431
  const { score, matched } = scorePermissionLikelihood(normalized);
447
432
  if (score >= FALLBACK_SCORE_THRESHOLD) {
448
- const target = this.extractPermissionTarget(normalized);
449
- const scope = this.inferScope(normalized, target);
450
433
  const lines = normalized.split("\n");
451
434
  const tailText = lines.slice(-8).join("\n");
452
- this.scheduleFallbackAutoApprove(scope, target, { score, matched, text: tailText });
435
+ this.scheduleFallbackAutoApprove({ score, matched, text: tailText });
453
436
  return;
454
437
  }
455
438
  }
@@ -460,7 +443,7 @@ export class ClaudePtyBridge extends EventEmitter {
460
443
  if (prompt !== this.permissionState.lastPrompt) {
461
444
  // New permission prompt while already blocked — update and re-process
462
445
  const target = this.extractPermissionTarget(normalized);
463
- const scope = this.inferScope(normalized, target);
446
+ const scope = this.inferScope(normalized);
464
447
  this.permissionState.lastPrompt = prompt;
465
448
  this.permissionState.lastScope = scope;
466
449
  this.permissionState.lastTarget = target ?? null;
@@ -484,7 +467,7 @@ export class ClaudePtyBridge extends EventEmitter {
484
467
  if (blocked) {
485
468
  const prompt = this.extractPromptText(normalized);
486
469
  const target = this.extractPermissionTarget(normalized);
487
- const scope = this.inferScope(normalized, target);
470
+ const scope = this.inferScope(normalized);
488
471
  this.permissionState.lastPrompt = prompt;
489
472
  this.permissionState.lastScope = scope;
490
473
  this.permissionState.lastTarget = target ?? null;
@@ -569,7 +552,7 @@ export class ClaudePtyBridge extends EventEmitter {
569
552
  * Schedule a fallback auto-approve with false-positive verification.
570
553
  * Similar to scheduleAutoApprove but sets up post-approve monitoring.
571
554
  */
572
- scheduleFallbackAutoApprove(scope, target, context) {
555
+ scheduleFallbackAutoApprove(context) {
573
556
  const now = Date.now();
574
557
  if (now - this.permissionState.lastAutoConfirmAt < 500)
575
558
  return;
@@ -702,7 +685,7 @@ export class ClaudePtyBridge extends EventEmitter {
702
685
  || normalized.match(/execute\s+([^,.\n]+)/i);
703
686
  return match?.[1]?.trim();
704
687
  }
705
- inferScope(normalized, target) {
688
+ inferScope(normalized) {
706
689
  const lower = normalized.toLowerCase();
707
690
  if (lower.includes("write") || lower.includes("redirection") || lower.includes("output redirection")) {
708
691
  return "write_file";
@@ -9,10 +9,7 @@ export function isPathWithinBase(targetPath, basePath) {
9
9
  const BLOCKED_FOLDER_PATHS = ["/etc", "/root", "/boot"];
10
10
  /** Check if targetPath is inside any blocked system folder. */
11
11
  export function isBlockedFolderPath(targetPath) {
12
- return BLOCKED_FOLDER_PATHS.some((blockedPath) => {
13
- const relativePath = path.relative(blockedPath, targetPath);
14
- return relativePath === "" || (!relativePath.startsWith("..") && !path.isAbsolute(relativePath));
15
- });
12
+ return BLOCKED_FOLDER_PATHS.some((blockedPath) => isPathWithinBase(targetPath, blockedPath));
16
13
  }
17
14
  /** Expand shell-style home shortcuts accepted by the UI. */
18
15
  export function expandHomePath(inputPath) {
@@ -58,8 +58,9 @@ export declare function requiredUpdateFreeBytes(currentInstallBytes: number): nu
58
58
  * @param pkg 包名带版本,例如 `@co0ontty/wand@latest`
59
59
  * @param timeoutMs 单次 npm 调用超时
60
60
  * @param log 可选 logger,用来把过程写入控制台或前端日志
61
+ * @returns 与本次安装使用同一个 npm root 校验出的 dist/cli.js 绝对路径
61
62
  */
62
- export declare function installPackageGloballyAsync(pkg: string, timeoutMs: number, log?: (line: string) => void): Promise<void>;
63
+ export declare function installPackageGloballyAsync(pkg: string, timeoutMs: number, log?: (line: string) => void): Promise<string>;
63
64
  /**
64
65
  * 同步版本,给 TUI installUpdate 用。
65
66
  *
@@ -402,6 +402,7 @@ function assertGlobalWandInstallComplete() {
402
402
  if (!result.ok) {
403
403
  throw new Error(result.message);
404
404
  }
405
+ return path.join(result.packageDir, "dist", "cli.js");
405
406
  }
406
407
  function createGlobalInstallBackup(note) {
407
408
  const packageDir = getGlobalPackageDir();
@@ -641,6 +642,7 @@ function releaseGlobalUpdateLock(lock) {
641
642
  * @param pkg 包名带版本,例如 `@co0ontty/wand@latest`
642
643
  * @param timeoutMs 单次 npm 调用超时
643
644
  * @param log 可选 logger,用来把过程写入控制台或前端日志
645
+ * @returns 与本次安装使用同一个 npm root 校验出的 dist/cli.js 绝对路径
644
646
  */
645
647
  export async function installPackageGloballyAsync(pkg, timeoutMs, log) {
646
648
  const note = (line) => {
@@ -658,9 +660,9 @@ export async function installPackageGloballyAsync(pkg, timeoutMs, log) {
658
660
  }
659
661
  try {
660
662
  await npmInstallGlobalAsync(pkg, timeoutMs);
661
- assertGlobalWandInstallComplete();
663
+ const installedCli = assertGlobalWandInstallComplete();
662
664
  success = true;
663
- return;
665
+ return installedCli;
664
666
  }
665
667
  catch (error) {
666
668
  const msg = getErrorMessage(error);
@@ -675,9 +677,9 @@ export async function installPackageGloballyAsync(pkg, timeoutMs, log) {
675
677
  cleanupNpmLeftovers();
676
678
  try {
677
679
  await npmInstallGlobalAsync(pkg, timeoutMs);
678
- assertGlobalWandInstallComplete();
680
+ const installedCli = assertGlobalWandInstallComplete();
679
681
  success = true;
680
- return;
682
+ return installedCli;
681
683
  }
682
684
  catch (retryError) {
683
685
  const retryMsg = getErrorMessage(retryError);
@@ -699,8 +701,9 @@ export async function installPackageGloballyAsync(pkg, timeoutMs, log) {
699
701
  }
700
702
  cleanupNpmLeftovers();
701
703
  await npmInstallGlobalAsync(pkg, timeoutMs, ["--force"]);
702
- assertGlobalWandInstallComplete();
704
+ const installedCli = assertGlobalWandInstallComplete();
703
705
  success = true;
706
+ return installedCli;
704
707
  }
705
708
  finally {
706
709
  try {
package/dist/pidfile.d.ts CHANGED
@@ -34,5 +34,3 @@ export declare function readPidfile(configPath: string): PidInfo | null;
34
34
  export declare function isPidAlive(pid: number): boolean;
35
35
  export declare function removePidfile(configPath: string): void;
36
36
  export declare function removeSocketFile(configPath: string): void;
37
- /** 读取 pidfile 并校验进程是否还活着。Stale 文件会自动清理。 */
38
- export declare function readLiveInstance(configPath: string): PidInfo | null;
package/dist/pidfile.js CHANGED
@@ -98,24 +98,6 @@ export function removeSocketFile(configPath) {
98
98
  /* noop */
99
99
  }
100
100
  }
101
- /** 读取 pidfile 并校验进程是否还活着。Stale 文件会自动清理。 */
102
- export function readLiveInstance(configPath) {
103
- const info = readPidfile(configPath);
104
- if (!info)
105
- return null;
106
- if (info.pid === process.pid)
107
- return null; // 自身(防御性)
108
- if (!isPidAlive(info.pid)) {
109
- // stale,顺手清理
110
- removePidfile(configPath);
111
- removeSocketFile(configPath);
112
- return null;
113
- }
114
- // 进程活着但 socket 不在 → 多半是异常崩溃后被某种监控拉起。视为不可用。
115
- if (info.socket && !existsSync(info.socket))
116
- return null;
117
- return info;
118
- }
119
101
  function applyConfigDirOwnership(filePath, configPath, mode) {
120
102
  try {
121
103
  const owner = statSync(path.dirname(configPath));
@@ -2,11 +2,6 @@ import { EventEmitter } from "node:events";
2
2
  import { WandStorage } from "./storage.js";
3
3
  import { ExecutionMode, ProcessEventHandler, SessionProvider, SessionSnapshot, SessionSource, WandConfig } from "./types.js";
4
4
  export type { ProcessEvent, ProcessEventHandler } from "./types.js";
5
- /** Human-readable task information for the UI */
6
- export interface TaskInfo {
7
- title: string;
8
- tool?: string;
9
- }
10
5
  export declare class SessionInputError extends Error {
11
6
  readonly code: "SESSION_NOT_FOUND" | "SESSION_NOT_RUNNING" | "SESSION_NO_PTY";
12
7
  readonly sessionId: string;
@@ -53,7 +48,7 @@ export declare class ProcessManager extends EventEmitter {
53
48
  private orphanRecoveredCount;
54
49
  private readonly topicRequests;
55
50
  constructor(config: WandConfig, storage: WandStorage, configDir?: string);
56
- on(event: "process", listener: ProcessEventHandler): this;
51
+ on(_event: "process", listener: ProcessEventHandler): this;
57
52
  /** 启动时被识别为孤儿 PTY 并标记为 exited 的旧会话数量(仅用于启动摘要展示)。 */
58
53
  getOrphanRecoveredCount(): number;
59
54
  private emitEvent;
@@ -110,8 +105,6 @@ export declare class ProcessManager extends EventEmitter {
110
105
  */
111
106
  setSessionMode(id: string, mode: ExecutionMode): SessionSnapshot;
112
107
  sendInput(id: string, input: string, view?: "chat" | "terminal", shortcutKey?: string): SessionSnapshot;
113
- /** Emit a task event for a session, debounced to avoid flooding */
114
- private emitTask;
115
108
  resize(id: string, cols: number, rows: number): SessionSnapshot;
116
109
  stop(id: string): SessionSnapshot;
117
110
  private cleanupRecord;
@@ -568,20 +568,7 @@ function snapshotMessages(record) {
568
568
  const MAX_SESSIONS = 200;
569
569
  const ARCHIVE_AFTER_MS = 1000 * 60 * 60 * 24;
570
570
  const CONFIRM_WINDOW_SIZE = 800;
571
- // Claude 会话 ID 格式:UUID v4
572
- const CLAUDE_SESSION_ID_PATTERN = /"session_id"\s*:\s*"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"/i;
573
571
  const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
574
- function listClaudeTaskIds() {
575
- const tasksDir = path.join(os.homedir(), ".claude", "tasks");
576
- try {
577
- return readdirSync(tasksDir, { withFileTypes: true })
578
- .filter((entry) => entry.isDirectory() && UUID_V4_PATTERN.test(entry.name))
579
- .map((entry) => entry.name);
580
- }
581
- catch {
582
- return [];
583
- }
584
- }
585
572
  function getClaudeProjectDir(cwd) {
586
573
  // Claude Code encodes the project dir by replacing every non-alphanumeric
587
574
  // character (slash, dot, underscore, etc.) with "-", not just "/". Mirroring
@@ -590,23 +577,6 @@ function getClaudeProjectDir(cwd) {
590
577
  const normalized = path.resolve(cwd).replace(/[^a-zA-Z0-9]/g, "-");
591
578
  return path.join(os.homedir(), ".claude", "projects", normalized);
592
579
  }
593
- function getLatestClaudeTaskId(excludeIds) {
594
- const tasksDir = path.join(os.homedir(), ".claude", "tasks");
595
- try {
596
- const candidates = readdirSync(tasksDir, { withFileTypes: true })
597
- .filter((entry) => entry.isDirectory() && UUID_V4_PATTERN.test(entry.name) && !excludeIds.has(entry.name))
598
- .map((entry) => {
599
- const fullPath = path.join(tasksDir, entry.name);
600
- const stats = statSync(fullPath);
601
- return { id: entry.name, mtimeMs: stats.mtimeMs };
602
- })
603
- .sort((a, b) => b.mtimeMs - a.mtimeMs);
604
- return candidates[0]?.id ?? null;
605
- }
606
- catch {
607
- return null;
608
- }
609
- }
610
580
  /** Derive a short summary for a session from user messages or current task. */
611
581
  function getLastMessageSignature(messages) {
612
582
  const last = messages[messages.length - 1];
@@ -634,7 +604,7 @@ function shouldPersistMessages(lastState, nextMessages) {
634
604
  function recoverMessagesFromSnapshot(snapshot) {
635
605
  return snapshot.messages ?? [];
636
606
  }
637
- function deriveSessionSummary(messages, currentTaskTitle) {
607
+ function deriveSessionSummary(messages) {
638
608
  // Prefer first user message as summary
639
609
  for (const msg of messages) {
640
610
  if (msg.role !== "user")
@@ -646,8 +616,6 @@ function deriveSessionSummary(messages, currentTaskTitle) {
646
616
  }
647
617
  break;
648
618
  }
649
- if (currentTaskTitle)
650
- return currentTaskTitle.slice(0, 120);
651
619
  return undefined;
652
620
  }
653
621
  export class ProcessManager extends EventEmitter {
@@ -739,9 +707,6 @@ export class ProcessManager extends EventEmitter {
739
707
  messages: snapshot.messages ?? [],
740
708
  childProcess: null,
741
709
  ptyBridge: null,
742
- currentTask: null,
743
- taskDebounceTimer: null,
744
- lastEmittedTask: null,
745
710
  knownClaudeTaskIds: undefined,
746
711
  claudeTaskDiscoveryTimer: null,
747
712
  knownClaudeProjectMtimes: isClaudeCmd ? listClaudeProjectSessionMtimes(updated.cwd) : undefined,
@@ -785,9 +750,6 @@ export class ProcessManager extends EventEmitter {
785
750
  messages: snapshot.messages ?? [],
786
751
  childProcess: null,
787
752
  ptyBridge: null,
788
- currentTask: null,
789
- taskDebounceTimer: null,
790
- lastEmittedTask: null,
791
753
  knownClaudeTaskIds: undefined,
792
754
  claudeTaskDiscoveryTimer: null,
793
755
  knownClaudeProjectMtimes: isClaudeCmd ? listClaudeProjectSessionMtimes(updated.cwd) : undefined,
@@ -811,7 +773,7 @@ export class ProcessManager extends EventEmitter {
811
773
  }, 60 * 1000);
812
774
  this.archiveTimer.unref?.();
813
775
  }
814
- on(event, listener) {
776
+ on(_event, listener) {
815
777
  return super.on("process", listener);
816
778
  }
817
779
  /** 启动时被识别为孤儿 PTY 并标记为 exited 的旧会话数量(仅用于启动摘要展示)。 */
@@ -956,9 +918,6 @@ export class ProcessManager extends EventEmitter {
956
918
  messages: priorMessages,
957
919
  childProcess: null,
958
920
  ptyBridge: null,
959
- currentTask: null,
960
- taskDebounceTimer: null,
961
- lastEmittedTask: null,
962
921
  knownClaudeTaskIds: knownClaudeTaskIds ?? undefined,
963
922
  claudeTaskDiscoveryTimer: null,
964
923
  knownClaudeProjectMtimes: knownClaudeProjectMtimes ?? undefined,
@@ -978,7 +937,6 @@ export class ProcessManager extends EventEmitter {
978
937
  sessionId: id,
979
938
  isClaudeCommand: true,
980
939
  autoApprove: record.autoApprovePermissions,
981
- approvalPolicy: record.approvalPolicy,
982
940
  initialMessages: priorMessages,
983
941
  });
984
942
  record.ptyBridge.on("event", (event) => {
@@ -1454,33 +1412,6 @@ export class ProcessManager extends EventEmitter {
1454
1412
  this.persist(record);
1455
1413
  return this.snapshot(record);
1456
1414
  }
1457
- /** Emit a task event for a session, debounced to avoid flooding */
1458
- emitTask(record, task) {
1459
- // Clear existing debounce timer
1460
- if (record.taskDebounceTimer) {
1461
- clearTimeout(record.taskDebounceTimer);
1462
- record.taskDebounceTimer = null;
1463
- }
1464
- // Don't re-emit the same task
1465
- if (task && task.title === record.lastEmittedTask)
1466
- return;
1467
- if (task === null) {
1468
- // Clear task after a delay — allows a brief display of "idle" state
1469
- record.taskDebounceTimer = setTimeout(() => {
1470
- record.currentTask = null;
1471
- record.lastEmittedTask = null;
1472
- this.emitEvent({ type: "task", sessionId: record.id, data: null });
1473
- }, 2000);
1474
- return;
1475
- }
1476
- // Debounce task changes by 100ms to avoid flickering on rapid tool switches
1477
- record.taskDebounceTimer = setTimeout(() => {
1478
- record.taskDebounceTimer = null;
1479
- record.currentTask = task;
1480
- record.lastEmittedTask = task.title;
1481
- this.emitEvent({ type: "task", sessionId: record.id, data: task });
1482
- }, 100);
1483
- }
1484
1415
  resize(id, cols, rows) {
1485
1416
  const record = this.mustGet(id);
1486
1417
  if (!record.ptyProcess || record.status !== "running") {
@@ -1509,11 +1440,6 @@ export class ProcessManager extends EventEmitter {
1509
1440
  if (record.status !== "running") {
1510
1441
  return this.snapshot(record);
1511
1442
  }
1512
- // Clear any pending task debounce timer
1513
- if (record.taskDebounceTimer) {
1514
- clearTimeout(record.taskDebounceTimer);
1515
- record.taskDebounceTimer = null;
1516
- }
1517
1443
  if (record.claudeTaskDiscoveryTimer) {
1518
1444
  clearTimeout(record.claudeTaskDiscoveryTimer);
1519
1445
  record.claudeTaskDiscoveryTimer = null;
@@ -1555,10 +1481,6 @@ export class ProcessManager extends EventEmitter {
1555
1481
  return this.snapshot(record);
1556
1482
  }
1557
1483
  cleanupRecord(record) {
1558
- if (record.taskDebounceTimer) {
1559
- clearTimeout(record.taskDebounceTimer);
1560
- record.taskDebounceTimer = null;
1561
- }
1562
1484
  if (record.claudeTaskDiscoveryTimer) {
1563
1485
  clearTimeout(record.claudeTaskDiscoveryTimer);
1564
1486
  record.claudeTaskDiscoveryTimer = null;
@@ -1595,10 +1517,6 @@ export class ProcessManager extends EventEmitter {
1595
1517
  delete(id) {
1596
1518
  const record = this.mustGet(id);
1597
1519
  // Always clear pending timers
1598
- if (record.taskDebounceTimer) {
1599
- clearTimeout(record.taskDebounceTimer);
1600
- record.taskDebounceTimer = null;
1601
- }
1602
1520
  if (record.claudeTaskDiscoveryTimer) {
1603
1521
  clearTimeout(record.claudeTaskDiscoveryTimer);
1604
1522
  record.claudeTaskDiscoveryTimer = null;
@@ -1721,10 +1639,9 @@ export class ProcessManager extends EventEmitter {
1721
1639
  autoRecovered: record.autoRecovered ?? false,
1722
1640
  autoApprovePermissions: record.autoApprovePermissions || undefined,
1723
1641
  approvalStats: record.approvalStats.total > 0 ? record.approvalStats : undefined,
1724
- summary: record.description ?? deriveSessionSummary(messages, record.currentTask?.title ?? null),
1642
+ summary: record.description ?? deriveSessionSummary(messages),
1725
1643
  title: record.title,
1726
1644
  description: record.description,
1727
- currentTaskTitle: record.status === "running" ? record.currentTask?.title ?? undefined : undefined,
1728
1645
  selectedModel: record.selectedModel ?? null,
1729
1646
  thinkingEffort: record.thinkingEffort ?? null,
1730
1647
  ptyCols: record.ptyCols,
@@ -1,10 +1,8 @@
1
- import { Express } from "express";
1
+ import type { Express } from "express";
2
2
  import { ProcessManager } from "./process-manager.js";
3
3
  import { StructuredSessionManager } from "./structured-session-manager.js";
4
4
  import { WandStorage } from "./storage.js";
5
5
  import { ExecutionMode, SessionSource, WandConfig } from "./types.js";
6
- import { getErrorMessage } from "./error-utils.js";
7
- export { getErrorMessage };
8
6
  export declare function parseSessionCreationOrigin(body: {
9
7
  sessionSource?: unknown;
10
8
  automationId?: unknown;