@adhdev/daemon-core 0.5.3 → 0.5.6

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.
Files changed (45) hide show
  1. package/dist/index.d.ts +88 -2
  2. package/dist/index.js +1230 -439
  3. package/dist/index.js.map +1 -1
  4. package/package.json +1 -1
  5. package/providers/_builtin/extension/cline/scripts/read_chat.js +14 -1
  6. package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +24 -1
  7. package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +24 -1
  8. package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +3 -3
  9. package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +1 -1
  10. package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +1 -1
  11. package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +4 -4
  12. package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +5 -1
  13. package/providers/_builtin/ide/cursor/scripts/0.49.bak/dismiss_notification.js +30 -0
  14. package/providers/_builtin/ide/cursor/scripts/0.49.bak/focus_editor.js +13 -0
  15. package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_models.js +78 -0
  16. package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_modes.js +40 -0
  17. package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_notifications.js +23 -0
  18. package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_sessions.js +42 -0
  19. package/providers/_builtin/ide/cursor/scripts/0.49.bak/new_session.js +20 -0
  20. package/providers/_builtin/ide/cursor/scripts/0.49.bak/open_panel.js +23 -0
  21. package/providers/_builtin/ide/cursor/scripts/0.49.bak/read_chat.js +79 -0
  22. package/providers/_builtin/ide/cursor/scripts/0.49.bak/resolve_action.js +19 -0
  23. package/providers/_builtin/ide/cursor/scripts/0.49.bak/scripts.js +78 -0
  24. package/providers/_builtin/ide/cursor/scripts/0.49.bak/send_message.js +23 -0
  25. package/providers/_builtin/ide/cursor/scripts/0.49.bak/set_mode.js +38 -0
  26. package/providers/_builtin/ide/cursor/scripts/0.49.bak/set_model.js +81 -0
  27. package/providers/_builtin/ide/cursor/scripts/0.49.bak/switch_session.js +28 -0
  28. package/providers/_builtin/ide/windsurf/scripts/read_chat.js +18 -1
  29. package/src/cli-adapters/provider-cli-adapter.ts +231 -12
  30. package/src/commands/chat-commands.ts +36 -0
  31. package/src/commands/cli-manager.ts +128 -30
  32. package/src/commands/handler.ts +47 -3
  33. package/src/commands/router.ts +32 -2
  34. package/src/commands/workspace-commands.ts +108 -0
  35. package/src/config/config.ts +29 -1
  36. package/src/config/workspace-activity.ts +65 -0
  37. package/src/config/workspaces.ts +250 -0
  38. package/src/daemon/dev-server.ts +1 -1
  39. package/src/index.ts +5 -0
  40. package/src/launch.ts +1 -1
  41. package/src/providers/cli-provider-instance.ts +7 -2
  42. package/src/providers/ide-provider-instance.ts +11 -0
  43. package/src/status/reporter.ts +23 -4
  44. package/src/system/host-memory.ts +65 -0
  45. package/src/types.ts +8 -1
package/dist/index.js CHANGED
@@ -30,6 +30,188 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
+ // src/config/workspaces.ts
34
+ function expandPath(p) {
35
+ const t = (p || "").trim();
36
+ if (!t) return "";
37
+ if (t.startsWith("~")) return path.join(os.homedir(), t.slice(1).replace(/^\//, ""));
38
+ return path.resolve(t);
39
+ }
40
+ function validateWorkspacePath(absPath) {
41
+ try {
42
+ if (!absPath) return { ok: false, error: "Path required" };
43
+ if (!fs.existsSync(absPath)) return { ok: false, error: "Path does not exist" };
44
+ const st = fs.statSync(absPath);
45
+ if (!st.isDirectory()) return { ok: false, error: "Not a directory" };
46
+ return { ok: true };
47
+ } catch (e) {
48
+ return { ok: false, error: e?.message || "Invalid path" };
49
+ }
50
+ }
51
+ function defaultWorkspaceLabel(absPath) {
52
+ const base = path.basename(absPath) || absPath;
53
+ return base;
54
+ }
55
+ function migrateWorkspacesFromRecent(config) {
56
+ if (!config.workspaces) config.workspaces = [];
57
+ if (config.workspaces.length > 0) return config;
58
+ const recent = config.recentCliWorkspaces || [];
59
+ const now = Date.now();
60
+ for (const raw of recent) {
61
+ const abs = expandPath(raw);
62
+ if (!abs || validateWorkspacePath(abs).ok !== true) continue;
63
+ if (config.workspaces.some((w) => path.resolve(w.path) === abs)) continue;
64
+ config.workspaces.push({
65
+ id: (0, import_crypto.randomUUID)(),
66
+ path: abs,
67
+ label: defaultWorkspaceLabel(abs),
68
+ addedAt: now
69
+ });
70
+ if (config.workspaces.length >= MAX_WORKSPACES) break;
71
+ }
72
+ return config;
73
+ }
74
+ function getDefaultWorkspacePath(config) {
75
+ const id = config.defaultWorkspaceId;
76
+ if (!id) return null;
77
+ const w = (config.workspaces || []).find((x) => x.id === id);
78
+ if (!w) return null;
79
+ const abs = expandPath(w.path);
80
+ if (validateWorkspacePath(abs).ok !== true) return null;
81
+ return abs;
82
+ }
83
+ function getWorkspaceState(config) {
84
+ const workspaces = [...config.workspaces || []].sort((a, b) => b.addedAt - a.addedAt);
85
+ const defaultWorkspacePath = getDefaultWorkspacePath(config);
86
+ return {
87
+ workspaces,
88
+ defaultWorkspaceId: config.defaultWorkspaceId ?? null,
89
+ defaultWorkspacePath
90
+ };
91
+ }
92
+ function resolveLaunchDirectory(args, config) {
93
+ const a = args || {};
94
+ if (a.dir != null && String(a.dir).trim()) {
95
+ const abs = expandPath(String(a.dir).trim());
96
+ if (abs && validateWorkspacePath(abs).ok === true) {
97
+ return { ok: true, path: abs, source: "dir" };
98
+ }
99
+ return {
100
+ ok: false,
101
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
102
+ message: abs ? "Directory path is not valid or does not exist" : "Invalid directory path"
103
+ };
104
+ }
105
+ if (a.workspaceId) {
106
+ const w = (config.workspaces || []).find((x) => x.id === a.workspaceId);
107
+ if (w) {
108
+ const abs = expandPath(w.path);
109
+ if (validateWorkspacePath(abs).ok === true) {
110
+ return { ok: true, path: abs, source: "workspaceId" };
111
+ }
112
+ }
113
+ return {
114
+ ok: false,
115
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
116
+ message: "Saved workspace not found or path is no longer valid"
117
+ };
118
+ }
119
+ if (a.useDefaultWorkspace === true) {
120
+ const d = getDefaultWorkspacePath(config);
121
+ if (d) return { ok: true, path: d, source: "defaultWorkspace" };
122
+ return {
123
+ ok: false,
124
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
125
+ message: "No default workspace is set"
126
+ };
127
+ }
128
+ if (a.useHome === true) {
129
+ return { ok: true, path: os.homedir(), source: "home" };
130
+ }
131
+ return {
132
+ ok: false,
133
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
134
+ message: "Choose a directory, saved workspace, default workspace, or home before launching."
135
+ };
136
+ }
137
+ function resolveIdeWorkspaceFromArgs(args, config) {
138
+ const ar = args || {};
139
+ if (ar.workspace) {
140
+ const abs = expandPath(ar.workspace);
141
+ if (abs && validateWorkspacePath(abs).ok === true) return abs;
142
+ }
143
+ if (ar.workspaceId) {
144
+ const w = (config.workspaces || []).find((x) => x.id === ar.workspaceId);
145
+ if (w) {
146
+ const abs = expandPath(w.path);
147
+ if (validateWorkspacePath(abs).ok === true) return abs;
148
+ }
149
+ }
150
+ if (ar.useDefaultWorkspace === true) {
151
+ return getDefaultWorkspacePath(config) || void 0;
152
+ }
153
+ return void 0;
154
+ }
155
+ function resolveIdeLaunchWorkspace(args, config) {
156
+ const direct = resolveIdeWorkspaceFromArgs(args, config);
157
+ if (direct) return direct;
158
+ if (args?.useDefaultWorkspace === false) return void 0;
159
+ return getDefaultWorkspacePath(config) || void 0;
160
+ }
161
+ function findWorkspaceByPath(config, rawPath) {
162
+ const abs = path.resolve(expandPath(rawPath));
163
+ if (!abs) return void 0;
164
+ return (config.workspaces || []).find((w) => path.resolve(expandPath(w.path)) === abs);
165
+ }
166
+ function addWorkspaceEntry(config, rawPath, label) {
167
+ const abs = expandPath(rawPath);
168
+ const v = validateWorkspacePath(abs);
169
+ if (!v.ok) return { error: v.error };
170
+ const list = [...config.workspaces || []];
171
+ if (list.some((w) => path.resolve(w.path) === abs)) {
172
+ return { error: "Workspace already in list" };
173
+ }
174
+ if (list.length >= MAX_WORKSPACES) {
175
+ return { error: `Maximum ${MAX_WORKSPACES} workspaces` };
176
+ }
177
+ const entry = {
178
+ id: (0, import_crypto.randomUUID)(),
179
+ path: abs,
180
+ label: (label || "").trim() || defaultWorkspaceLabel(abs),
181
+ addedAt: Date.now()
182
+ };
183
+ list.push(entry);
184
+ return { config: { ...config, workspaces: list }, entry };
185
+ }
186
+ function removeWorkspaceEntry(config, id) {
187
+ const list = (config.workspaces || []).filter((w) => w.id !== id);
188
+ if (list.length === (config.workspaces || []).length) return { error: "Workspace not found" };
189
+ let defaultWorkspaceId = config.defaultWorkspaceId;
190
+ if (defaultWorkspaceId === id) defaultWorkspaceId = null;
191
+ return { config: { ...config, workspaces: list, defaultWorkspaceId } };
192
+ }
193
+ function setDefaultWorkspaceId(config, id) {
194
+ if (id === null) {
195
+ return { config: { ...config, defaultWorkspaceId: null } };
196
+ }
197
+ const w = (config.workspaces || []).find((x) => x.id === id);
198
+ if (!w) return { error: "Workspace not found" };
199
+ const abs = expandPath(w.path);
200
+ if (validateWorkspacePath(abs).ok !== true) return { error: "Workspace path is no longer valid" };
201
+ return { config: { ...config, defaultWorkspaceId: id } };
202
+ }
203
+ var fs, os, path, import_crypto, MAX_WORKSPACES;
204
+ var init_workspaces = __esm({
205
+ "src/config/workspaces.ts"() {
206
+ "use strict";
207
+ fs = __toESM(require("fs"));
208
+ os = __toESM(require("os"));
209
+ path = __toESM(require("path"));
210
+ import_crypto = require("crypto");
211
+ MAX_WORKSPACES = 50;
212
+ }
213
+ });
214
+
33
215
  // src/config/config.ts
34
216
  var config_exports = {};
35
217
  __export(config_exports, {
@@ -61,7 +243,20 @@ function loadConfig() {
61
243
  try {
62
244
  const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
63
245
  const parsed = JSON.parse(raw);
64
- return { ...DEFAULT_CONFIG, ...parsed };
246
+ const merged = { ...DEFAULT_CONFIG, ...parsed };
247
+ if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
248
+ merged.defaultWorkspaceId = merged.activeWorkspaceId;
249
+ }
250
+ delete merged.activeWorkspaceId;
251
+ const hadStoredWorkspaces = Array.isArray(parsed.workspaces) && parsed.workspaces.length > 0;
252
+ migrateWorkspacesFromRecent(merged);
253
+ if (!hadStoredWorkspaces && (merged.workspaces?.length || 0) > 0) {
254
+ try {
255
+ saveConfig(merged);
256
+ } catch {
257
+ }
258
+ }
259
+ return merged;
65
260
  } catch {
66
261
  return { ...DEFAULT_CONFIG };
67
262
  }
@@ -132,6 +327,7 @@ var init_config = __esm({
132
327
  import_os = require("os");
133
328
  import_path = require("path");
134
329
  import_fs = require("fs");
330
+ init_workspaces();
135
331
  DEFAULT_CONFIG = {
136
332
  serverUrl: "https://api.adhf.dev",
137
333
  apiToken: null,
@@ -148,6 +344,9 @@ var init_config = __esm({
148
344
  configuredCLIs: [],
149
345
  enabledIdes: [],
150
346
  recentCliWorkspaces: [],
347
+ workspaces: [],
348
+ defaultWorkspaceId: null,
349
+ recentWorkspaceActivity: [],
151
350
  machineNickname: null,
152
351
  cliHistory: [],
153
352
  providerSettings: {},
@@ -187,9 +386,12 @@ __export(index_exports, {
187
386
  detectIDEs: () => detectIDEs,
188
387
  getAIExtensions: () => getAIExtensions,
189
388
  getAvailableIdeIds: () => getAvailableIdeIds,
389
+ getHostMemorySnapshot: () => getHostMemorySnapshot,
190
390
  getLogLevel: () => getLogLevel,
191
391
  getRecentCommands: () => getRecentCommands,
192
392
  getRecentLogs: () => getRecentLogs,
393
+ getWorkspaceActivity: () => getWorkspaceActivity,
394
+ getWorkspaceState: () => getWorkspaceState,
193
395
  initDaemonComponents: () => initDaemonComponents,
194
396
  installExtensions: () => installExtensions,
195
397
  installGlobalInterceptor: () => installGlobalInterceptor,
@@ -212,6 +414,47 @@ __export(index_exports, {
212
414
  });
213
415
  module.exports = __toCommonJS(index_exports);
214
416
  init_config();
417
+ init_workspaces();
418
+
419
+ // src/config/workspace-activity.ts
420
+ var path2 = __toESM(require("path"));
421
+ init_workspaces();
422
+ var MAX_ACTIVITY = 30;
423
+ function normWorkspacePath(p) {
424
+ try {
425
+ return path2.resolve(expandPath(p));
426
+ } catch {
427
+ return path2.resolve(p);
428
+ }
429
+ }
430
+ function appendWorkspaceActivity(config, rawPath, meta) {
431
+ const abs = normWorkspacePath(rawPath);
432
+ if (!abs) return config;
433
+ const prev = config.recentWorkspaceActivity || [];
434
+ const filtered = prev.filter((e) => normWorkspacePath(e.path) !== abs);
435
+ const entry = {
436
+ path: abs,
437
+ lastUsedAt: Date.now(),
438
+ kind: meta?.kind,
439
+ agentType: meta?.agentType
440
+ };
441
+ const recentWorkspaceActivity = [entry, ...filtered].slice(0, MAX_ACTIVITY);
442
+ return { ...config, recentWorkspaceActivity };
443
+ }
444
+ function getWorkspaceActivity(config, limit = 20) {
445
+ const list = [...config.recentWorkspaceActivity || []];
446
+ list.sort((a, b) => b.lastUsedAt - a.lastUsedAt);
447
+ return list.slice(0, limit);
448
+ }
449
+ function removeActivityForPath(config, rawPath) {
450
+ const n = normWorkspacePath(rawPath);
451
+ return {
452
+ ...config,
453
+ recentWorkspaceActivity: (config.recentWorkspaceActivity || []).filter(
454
+ (e) => normWorkspacePath(e.path) !== n
455
+ )
456
+ };
457
+ }
215
458
 
216
459
  // src/detection/ide-detector.ts
217
460
  var import_child_process = require("child_process");
@@ -271,20 +514,20 @@ function checkPathExists(paths) {
271
514
  return null;
272
515
  }
273
516
  async function detectIDEs() {
274
- const os13 = (0, import_os2.platform)();
517
+ const os15 = (0, import_os2.platform)();
275
518
  const results = [];
276
519
  for (const def of getMergedDefinitions()) {
277
520
  const cliPath = findCliCommand(def.cli);
278
- const appPath = checkPathExists(def.paths[os13] || []);
521
+ const appPath = checkPathExists(def.paths[os15] || []);
279
522
  const installed = !!(cliPath || appPath);
280
523
  let resolvedCli = cliPath;
281
- if (!resolvedCli && appPath && os13 === "darwin") {
524
+ if (!resolvedCli && appPath && os15 === "darwin") {
282
525
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
283
526
  if ((0, import_fs2.existsSync)(bundledCli)) resolvedCli = bundledCli;
284
527
  }
285
- if (!resolvedCli && appPath && os13 === "win32") {
286
- const { dirname: dirname5 } = await import("path");
287
- const appDir = dirname5(appPath);
528
+ if (!resolvedCli && appPath && os15 === "win32") {
529
+ const { dirname: dirname6 } = await import("path");
530
+ const appDir = dirname6(appPath);
288
531
  const candidates = [
289
532
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
290
533
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -317,22 +560,22 @@ async function detectIDEs() {
317
560
 
318
561
  // src/detection/cli-detector.ts
319
562
  var import_child_process2 = require("child_process");
320
- var os = __toESM(require("os"));
563
+ var os2 = __toESM(require("os"));
321
564
  function execAsync(cmd, timeoutMs = 5e3) {
322
- return new Promise((resolve5) => {
565
+ return new Promise((resolve7) => {
323
566
  const child = (0, import_child_process2.exec)(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
324
567
  if (err || !stdout?.trim()) {
325
- resolve5(null);
568
+ resolve7(null);
326
569
  } else {
327
- resolve5(stdout.trim());
570
+ resolve7(stdout.trim());
328
571
  }
329
572
  });
330
- child.on("error", () => resolve5(null));
573
+ child.on("error", () => resolve7(null));
331
574
  });
332
575
  }
333
576
  async function detectCLIs(providerLoader) {
334
- const platform7 = os.platform();
335
- const whichCmd = platform7 === "win32" ? "where" : "which";
577
+ const platform8 = os2.platform();
578
+ const whichCmd = platform8 === "win32" ? "where" : "which";
336
579
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
337
580
  const results = await Promise.all(
338
581
  cliList.map(async (cli) => {
@@ -363,14 +606,56 @@ async function detectCLI(cliId, providerLoader) {
363
606
  return all.find((c) => c.id === resolvedId && c.installed) || null;
364
607
  }
365
608
 
609
+ // src/system/host-memory.ts
610
+ var os3 = __toESM(require("os"));
611
+ var import_child_process3 = require("child_process");
612
+ function parseDarwinAvailableBytes(totalMem) {
613
+ if (os3.platform() !== "darwin") return null;
614
+ try {
615
+ const out = (0, import_child_process3.execSync)("vm_stat", {
616
+ encoding: "utf-8",
617
+ timeout: 4e3,
618
+ maxBuffer: 256 * 1024
619
+ });
620
+ const pageSizeMatch = out.match(/page size of (\d+)\s*bytes/i);
621
+ const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 4096;
622
+ const counts = {};
623
+ for (const line of out.split("\n")) {
624
+ const m = line.match(/^\s*Pages\s+([^:]+):\s+([\d,]+)\s*\.?/);
625
+ if (!m) continue;
626
+ const key = m[1].trim().toLowerCase().replace(/\s+/g, "_");
627
+ const n = parseInt(m[2].replace(/,/g, ""), 10);
628
+ if (!Number.isNaN(n)) counts[key] = n;
629
+ }
630
+ const free = counts["free"] ?? 0;
631
+ const inactive = counts["inactive"] ?? 0;
632
+ const speculative = counts["speculative"] ?? 0;
633
+ const purgeable = counts["purgeable"] ?? 0;
634
+ const fileBacked = counts["file_backed"] ?? 0;
635
+ const availPages = free + inactive + speculative + purgeable + fileBacked;
636
+ const bytes = availPages * pageSize;
637
+ if (!Number.isFinite(bytes) || bytes < 0) return null;
638
+ return Math.min(bytes, totalMem);
639
+ } catch {
640
+ return null;
641
+ }
642
+ }
643
+ function getHostMemorySnapshot() {
644
+ const totalMem = os3.totalmem();
645
+ const freeMem = os3.freemem();
646
+ const darwinAvail = parseDarwinAvailableBytes(totalMem);
647
+ const availableMem = darwinAvail != null ? darwinAvail : freeMem;
648
+ return { totalMem, freeMem, availableMem };
649
+ }
650
+
366
651
  // src/cdp/manager.ts
367
652
  var import_ws = __toESM(require("ws"));
368
653
  var http = __toESM(require("http"));
369
654
 
370
655
  // src/logging/logger.ts
371
- var fs = __toESM(require("fs"));
372
- var path = __toESM(require("path"));
373
- var os2 = __toESM(require("os"));
656
+ var fs2 = __toESM(require("fs"));
657
+ var path3 = __toESM(require("path"));
658
+ var os4 = __toESM(require("os"));
374
659
  var LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
375
660
  var LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
376
661
  var currentLevel = "info";
@@ -381,29 +666,29 @@ function setLogLevel(level) {
381
666
  function getLogLevel() {
382
667
  return currentLevel;
383
668
  }
384
- var LOG_DIR = process.platform === "darwin" ? path.join(os2.homedir(), "Library", "Logs", "adhdev") : path.join(os2.homedir(), ".local", "share", "adhdev", "logs");
669
+ var LOG_DIR = process.platform === "darwin" ? path3.join(os4.homedir(), "Library", "Logs", "adhdev") : path3.join(os4.homedir(), ".local", "share", "adhdev", "logs");
385
670
  var MAX_LOG_SIZE = 5 * 1024 * 1024;
386
671
  var MAX_LOG_DAYS = 7;
387
672
  try {
388
- fs.mkdirSync(LOG_DIR, { recursive: true });
673
+ fs2.mkdirSync(LOG_DIR, { recursive: true });
389
674
  } catch {
390
675
  }
391
676
  function getDateStr() {
392
677
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
393
678
  }
394
679
  var currentDate = getDateStr();
395
- var currentLogFile = path.join(LOG_DIR, `daemon-${currentDate}.log`);
680
+ var currentLogFile = path3.join(LOG_DIR, `daemon-${currentDate}.log`);
396
681
  function checkDateRotation() {
397
682
  const today = getDateStr();
398
683
  if (today !== currentDate) {
399
684
  currentDate = today;
400
- currentLogFile = path.join(LOG_DIR, `daemon-${currentDate}.log`);
685
+ currentLogFile = path3.join(LOG_DIR, `daemon-${currentDate}.log`);
401
686
  cleanOldLogs();
402
687
  }
403
688
  }
404
689
  function cleanOldLogs() {
405
690
  try {
406
- const files = fs.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
691
+ const files = fs2.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
407
692
  const cutoff = /* @__PURE__ */ new Date();
408
693
  cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
409
694
  const cutoffStr = cutoff.toISOString().slice(0, 10);
@@ -411,7 +696,7 @@ function cleanOldLogs() {
411
696
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
412
697
  if (dateMatch && dateMatch[1] < cutoffStr) {
413
698
  try {
414
- fs.unlinkSync(path.join(LOG_DIR, file));
699
+ fs2.unlinkSync(path3.join(LOG_DIR, file));
415
700
  } catch {
416
701
  }
417
702
  }
@@ -421,29 +706,29 @@ function cleanOldLogs() {
421
706
  }
422
707
  function rotateSizeIfNeeded() {
423
708
  try {
424
- const stat = fs.statSync(currentLogFile);
709
+ const stat = fs2.statSync(currentLogFile);
425
710
  if (stat.size > MAX_LOG_SIZE) {
426
711
  const backup = currentLogFile.replace(".log", ".1.log");
427
712
  try {
428
- fs.unlinkSync(backup);
713
+ fs2.unlinkSync(backup);
429
714
  } catch {
430
715
  }
431
- fs.renameSync(currentLogFile, backup);
716
+ fs2.renameSync(currentLogFile, backup);
432
717
  }
433
718
  } catch {
434
719
  }
435
720
  }
436
721
  cleanOldLogs();
437
722
  try {
438
- const oldLog = path.join(LOG_DIR, "daemon.log");
439
- if (fs.existsSync(oldLog)) {
440
- const stat = fs.statSync(oldLog);
723
+ const oldLog = path3.join(LOG_DIR, "daemon.log");
724
+ if (fs2.existsSync(oldLog)) {
725
+ const stat = fs2.statSync(oldLog);
441
726
  const oldDate = stat.mtime.toISOString().slice(0, 10);
442
- fs.renameSync(oldLog, path.join(LOG_DIR, `daemon-${oldDate}.log`));
727
+ fs2.renameSync(oldLog, path3.join(LOG_DIR, `daemon-${oldDate}.log`));
443
728
  }
444
- const oldLogBackup = path.join(LOG_DIR, "daemon.log.old");
445
- if (fs.existsSync(oldLogBackup)) {
446
- fs.unlinkSync(oldLogBackup);
729
+ const oldLogBackup = path3.join(LOG_DIR, "daemon.log.old");
730
+ if (fs2.existsSync(oldLogBackup)) {
731
+ fs2.unlinkSync(oldLogBackup);
447
732
  }
448
733
  } catch {
449
734
  }
@@ -454,7 +739,7 @@ function writeToFile(line) {
454
739
  checkDateRotation();
455
740
  rotateSizeIfNeeded();
456
741
  }
457
- fs.appendFileSync(currentLogFile, line + "\n");
742
+ fs2.appendFileSync(currentLogFile, line + "\n");
458
743
  } catch {
459
744
  }
460
745
  }
@@ -568,7 +853,7 @@ function installGlobalInterceptor() {
568
853
  writeToFile(`Log file: ${currentLogFile}`);
569
854
  writeToFile(`Log level: ${currentLevel}`);
570
855
  }
571
- var LOG_PATH = path.join(LOG_DIR, `daemon-${getDateStr()}.log`);
856
+ var LOG_PATH = path3.join(LOG_DIR, `daemon-${getDateStr()}.log`);
572
857
 
573
858
  // src/cdp/manager.ts
574
859
  var DaemonCdpManager = class {
@@ -643,7 +928,7 @@ var DaemonCdpManager = class {
643
928
  * Returns multiple entries if multiple IDE windows are open on same port
644
929
  */
645
930
  static listAllTargets(port) {
646
- return new Promise((resolve5) => {
931
+ return new Promise((resolve7) => {
647
932
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
648
933
  let data = "";
649
934
  res.on("data", (chunk) => data += chunk.toString());
@@ -659,16 +944,16 @@ var DaemonCdpManager = class {
659
944
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
660
945
  );
661
946
  const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
662
- resolve5(mainPages.length > 0 ? mainPages : fallbackPages);
947
+ resolve7(mainPages.length > 0 ? mainPages : fallbackPages);
663
948
  } catch {
664
- resolve5([]);
949
+ resolve7([]);
665
950
  }
666
951
  });
667
952
  });
668
- req.on("error", () => resolve5([]));
953
+ req.on("error", () => resolve7([]));
669
954
  req.setTimeout(2e3, () => {
670
955
  req.destroy();
671
- resolve5([]);
956
+ resolve7([]);
672
957
  });
673
958
  });
674
959
  }
@@ -708,7 +993,7 @@ var DaemonCdpManager = class {
708
993
  }
709
994
  }
710
995
  findTargetOnPort(port) {
711
- return new Promise((resolve5) => {
996
+ return new Promise((resolve7) => {
712
997
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
713
998
  let data = "";
714
999
  res.on("data", (chunk) => data += chunk.toString());
@@ -719,7 +1004,7 @@ var DaemonCdpManager = class {
719
1004
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
720
1005
  );
721
1006
  if (pages.length === 0) {
722
- resolve5(targets.find((t) => t.webSocketDebuggerUrl) || null);
1007
+ resolve7(targets.find((t) => t.webSocketDebuggerUrl) || null);
723
1008
  return;
724
1009
  }
725
1010
  const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
@@ -729,24 +1014,24 @@ var DaemonCdpManager = class {
729
1014
  const specific = list.find((t) => t.id === this._targetId);
730
1015
  if (specific) {
731
1016
  this._pageTitle = specific.title || "";
732
- resolve5(specific);
1017
+ resolve7(specific);
733
1018
  } else {
734
1019
  this.log(`[CDP] Target ${this._targetId} not found in page list`);
735
- resolve5(null);
1020
+ resolve7(null);
736
1021
  }
737
1022
  return;
738
1023
  }
739
1024
  this._pageTitle = list[0]?.title || "";
740
- resolve5(list[0]);
1025
+ resolve7(list[0]);
741
1026
  } catch {
742
- resolve5(null);
1027
+ resolve7(null);
743
1028
  }
744
1029
  });
745
1030
  });
746
- req.on("error", () => resolve5(null));
1031
+ req.on("error", () => resolve7(null));
747
1032
  req.setTimeout(2e3, () => {
748
1033
  req.destroy();
749
- resolve5(null);
1034
+ resolve7(null);
750
1035
  });
751
1036
  });
752
1037
  }
@@ -757,7 +1042,7 @@ var DaemonCdpManager = class {
757
1042
  this.extensionProviders = providers;
758
1043
  }
759
1044
  connectToTarget(wsUrl) {
760
- return new Promise((resolve5) => {
1045
+ return new Promise((resolve7) => {
761
1046
  this.ws = new import_ws.default(wsUrl);
762
1047
  this.ws.on("open", async () => {
763
1048
  this._connected = true;
@@ -767,17 +1052,17 @@ var DaemonCdpManager = class {
767
1052
  }
768
1053
  this.connectBrowserWs().catch(() => {
769
1054
  });
770
- resolve5(true);
1055
+ resolve7(true);
771
1056
  });
772
1057
  this.ws.on("message", (data) => {
773
1058
  try {
774
1059
  const msg = JSON.parse(data.toString());
775
1060
  if (msg.id && this.pending.has(msg.id)) {
776
- const { resolve: resolve6, reject } = this.pending.get(msg.id);
1061
+ const { resolve: resolve8, reject } = this.pending.get(msg.id);
777
1062
  this.pending.delete(msg.id);
778
1063
  this.failureCount = 0;
779
1064
  if (msg.error) reject(new Error(msg.error.message));
780
- else resolve6(msg.result);
1065
+ else resolve8(msg.result);
781
1066
  } else if (msg.method === "Runtime.executionContextCreated") {
782
1067
  this.contexts.add(msg.params.context.id);
783
1068
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -800,7 +1085,7 @@ var DaemonCdpManager = class {
800
1085
  this.ws.on("error", (err) => {
801
1086
  this.log(`[CDP] WebSocket error: ${err.message}`);
802
1087
  this._connected = false;
803
- resolve5(false);
1088
+ resolve7(false);
804
1089
  });
805
1090
  });
806
1091
  }
@@ -814,7 +1099,7 @@ var DaemonCdpManager = class {
814
1099
  return;
815
1100
  }
816
1101
  this.log(`[CDP] Connecting browser WS for target discovery...`);
817
- await new Promise((resolve5, reject) => {
1102
+ await new Promise((resolve7, reject) => {
818
1103
  this.browserWs = new import_ws.default(browserWsUrl);
819
1104
  this.browserWs.on("open", async () => {
820
1105
  this._browserConnected = true;
@@ -824,16 +1109,16 @@ var DaemonCdpManager = class {
824
1109
  } catch (e) {
825
1110
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
826
1111
  }
827
- resolve5();
1112
+ resolve7();
828
1113
  });
829
1114
  this.browserWs.on("message", (data) => {
830
1115
  try {
831
1116
  const msg = JSON.parse(data.toString());
832
1117
  if (msg.id && this.browserPending.has(msg.id)) {
833
- const { resolve: resolve6, reject: reject2 } = this.browserPending.get(msg.id);
1118
+ const { resolve: resolve8, reject: reject2 } = this.browserPending.get(msg.id);
834
1119
  this.browserPending.delete(msg.id);
835
1120
  if (msg.error) reject2(new Error(msg.error.message));
836
- else resolve6(msg.result);
1121
+ else resolve8(msg.result);
837
1122
  }
838
1123
  } catch {
839
1124
  }
@@ -853,31 +1138,31 @@ var DaemonCdpManager = class {
853
1138
  }
854
1139
  }
855
1140
  getBrowserWsUrl() {
856
- return new Promise((resolve5) => {
1141
+ return new Promise((resolve7) => {
857
1142
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
858
1143
  let data = "";
859
1144
  res.on("data", (chunk) => data += chunk.toString());
860
1145
  res.on("end", () => {
861
1146
  try {
862
1147
  const info = JSON.parse(data);
863
- resolve5(info.webSocketDebuggerUrl || null);
1148
+ resolve7(info.webSocketDebuggerUrl || null);
864
1149
  } catch {
865
- resolve5(null);
1150
+ resolve7(null);
866
1151
  }
867
1152
  });
868
1153
  });
869
- req.on("error", () => resolve5(null));
1154
+ req.on("error", () => resolve7(null));
870
1155
  req.setTimeout(3e3, () => {
871
1156
  req.destroy();
872
- resolve5(null);
1157
+ resolve7(null);
873
1158
  });
874
1159
  });
875
1160
  }
876
1161
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
877
- return new Promise((resolve5, reject) => {
1162
+ return new Promise((resolve7, reject) => {
878
1163
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
879
1164
  const id = this.browserMsgId++;
880
- this.browserPending.set(id, { resolve: resolve5, reject });
1165
+ this.browserPending.set(id, { resolve: resolve7, reject });
881
1166
  this.browserWs.send(JSON.stringify({ id, method, params }));
882
1167
  setTimeout(() => {
883
1168
  if (this.browserPending.has(id)) {
@@ -917,11 +1202,11 @@ var DaemonCdpManager = class {
917
1202
  }
918
1203
  // ─── CDP Protocol ────────────────────────────────────────
919
1204
  sendInternal(method, params = {}, timeoutMs = 15e3) {
920
- return new Promise((resolve5, reject) => {
1205
+ return new Promise((resolve7, reject) => {
921
1206
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
922
1207
  if (this.ws.readyState !== import_ws.default.OPEN) return reject(new Error("WebSocket not open"));
923
1208
  const id = this.msgId++;
924
- this.pending.set(id, { resolve: resolve5, reject });
1209
+ this.pending.set(id, { resolve: resolve7, reject });
925
1210
  this.ws.send(JSON.stringify({ id, method, params }));
926
1211
  setTimeout(() => {
927
1212
  if (this.pending.has(id)) {
@@ -1130,7 +1415,7 @@ var DaemonCdpManager = class {
1130
1415
  const browserWs = this.browserWs;
1131
1416
  let msgId = this.browserMsgId;
1132
1417
  const sendWs = (method, params = {}, sessionId) => {
1133
- return new Promise((resolve5, reject) => {
1418
+ return new Promise((resolve7, reject) => {
1134
1419
  const mid = msgId++;
1135
1420
  this.browserMsgId = msgId;
1136
1421
  const handler = (raw) => {
@@ -1139,7 +1424,7 @@ var DaemonCdpManager = class {
1139
1424
  if (msg.id === mid) {
1140
1425
  browserWs.removeListener("message", handler);
1141
1426
  if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
1142
- else resolve5(msg.result);
1427
+ else resolve7(msg.result);
1143
1428
  }
1144
1429
  } catch {
1145
1430
  }
@@ -1313,14 +1598,14 @@ var DaemonCdpManager = class {
1313
1598
  if (!ws || ws.readyState !== import_ws.default.OPEN) {
1314
1599
  throw new Error("CDP not connected");
1315
1600
  }
1316
- return new Promise((resolve5, reject) => {
1601
+ return new Promise((resolve7, reject) => {
1317
1602
  const id = getNextId();
1318
1603
  pendingMap.set(id, {
1319
1604
  resolve: (result) => {
1320
1605
  if (result?.result?.subtype === "error") {
1321
1606
  reject(new Error(result.result.description));
1322
1607
  } else {
1323
- resolve5(result?.result?.value);
1608
+ resolve7(result?.result?.value);
1324
1609
  }
1325
1610
  },
1326
1611
  reject
@@ -1901,10 +2186,10 @@ var ExtensionProviderInstance = class {
1901
2186
  };
1902
2187
 
1903
2188
  // src/config/chat-history.ts
1904
- var fs2 = __toESM(require("fs"));
1905
- var path2 = __toESM(require("path"));
1906
- var os3 = __toESM(require("os"));
1907
- var HISTORY_DIR = path2.join(os3.homedir(), ".adhdev", "history");
2189
+ var fs3 = __toESM(require("fs"));
2190
+ var path4 = __toESM(require("path"));
2191
+ var os5 = __toESM(require("os"));
2192
+ var HISTORY_DIR = path4.join(os5.homedir(), ".adhdev", "history");
1908
2193
  var RETAIN_DAYS = 30;
1909
2194
  var ChatHistoryWriter = class {
1910
2195
  /** Last seen message count per agent (deduplication) */
@@ -1945,13 +2230,13 @@ var ChatHistoryWriter = class {
1945
2230
  });
1946
2231
  }
1947
2232
  if (newMessages.length === 0) return;
1948
- const dir = path2.join(HISTORY_DIR, this.sanitize(agentType));
1949
- fs2.mkdirSync(dir, { recursive: true });
2233
+ const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
2234
+ fs3.mkdirSync(dir, { recursive: true });
1950
2235
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1951
2236
  const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
1952
- const filePath = path2.join(dir, `${filePrefix}${date}.jsonl`);
2237
+ const filePath = path4.join(dir, `${filePrefix}${date}.jsonl`);
1953
2238
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
1954
- fs2.appendFileSync(filePath, lines, "utf-8");
2239
+ fs3.appendFileSync(filePath, lines, "utf-8");
1955
2240
  const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
1956
2241
  if (messages.length < prevCount * 0.5 && prevCount > 3) {
1957
2242
  seenHashes.clear();
@@ -1976,17 +2261,17 @@ var ChatHistoryWriter = class {
1976
2261
  /** Delete history files older than 30 days */
1977
2262
  async rotateOldFiles() {
1978
2263
  try {
1979
- if (!fs2.existsSync(HISTORY_DIR)) return;
2264
+ if (!fs3.existsSync(HISTORY_DIR)) return;
1980
2265
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
1981
- const agentDirs = fs2.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
2266
+ const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
1982
2267
  for (const dir of agentDirs) {
1983
- const dirPath = path2.join(HISTORY_DIR, dir.name);
1984
- const files = fs2.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
2268
+ const dirPath = path4.join(HISTORY_DIR, dir.name);
2269
+ const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1985
2270
  for (const file of files) {
1986
- const filePath = path2.join(dirPath, file);
1987
- const stat = fs2.statSync(filePath);
2271
+ const filePath = path4.join(dirPath, file);
2272
+ const stat = fs3.statSync(filePath);
1988
2273
  if (stat.mtimeMs < cutoff) {
1989
- fs2.unlinkSync(filePath);
2274
+ fs3.unlinkSync(filePath);
1990
2275
  }
1991
2276
  }
1992
2277
  }
@@ -2001,10 +2286,10 @@ var ChatHistoryWriter = class {
2001
2286
  function readChatHistory(agentType, offset = 0, limit = 30, instanceId) {
2002
2287
  try {
2003
2288
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
2004
- const dir = path2.join(HISTORY_DIR, sanitized);
2005
- if (!fs2.existsSync(dir)) return { messages: [], hasMore: false };
2289
+ const dir = path4.join(HISTORY_DIR, sanitized);
2290
+ if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
2006
2291
  const sanitizedInstance = instanceId?.replace(/[^a-zA-Z0-9_-]/g, "_");
2007
- const files = fs2.readdirSync(dir).filter((f) => {
2292
+ const files = fs3.readdirSync(dir).filter((f) => {
2008
2293
  if (!f.endsWith(".jsonl")) return false;
2009
2294
  if (sanitizedInstance) {
2010
2295
  return f.startsWith(`${sanitizedInstance}_`);
@@ -2015,8 +2300,8 @@ function readChatHistory(agentType, offset = 0, limit = 30, instanceId) {
2015
2300
  const needed = offset + limit + 1;
2016
2301
  for (const file of files) {
2017
2302
  if (allMessages.length >= needed) break;
2018
- const filePath = path2.join(dir, file);
2019
- const content = fs2.readFileSync(filePath, "utf-8");
2303
+ const filePath = path4.join(dir, file);
2304
+ const content = fs3.readFileSync(filePath, "utf-8");
2020
2305
  const lines = content.trim().split("\n").filter(Boolean);
2021
2306
  for (let i = lines.length - 1; i >= 0; i--) {
2022
2307
  if (allMessages.length >= needed) break;
@@ -2256,6 +2541,15 @@ var IdeProviderInstance = class {
2256
2541
  const h = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
2257
2542
  msg.receivedAt = prevByHash.get(h) || now;
2258
2543
  }
2544
+ if (raw.messages?.length > 0) {
2545
+ const hiddenKinds = /* @__PURE__ */ new Set();
2546
+ if (this.settings.showThinking === false) hiddenKinds.add("thought");
2547
+ if (this.settings.showToolCalls === false) hiddenKinds.add("tool");
2548
+ if (this.settings.showTerminal === false) hiddenKinds.add("terminal");
2549
+ if (hiddenKinds.size > 0) {
2550
+ raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
2551
+ }
2552
+ }
2259
2553
  this.cachedChat = { ...raw, activeModal };
2260
2554
  this.detectAgentTransitions(raw, now);
2261
2555
  if (raw.messages?.length > 0) {
@@ -3274,6 +3568,39 @@ async function handleResolveAction(h, args) {
3274
3568
  const action = args?.action || "approve";
3275
3569
  const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
3276
3570
  LOG.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider?.type}`);
3571
+ if (provider?.category === "cli") {
3572
+ const adapter = h.getCliAdapter(provider.type);
3573
+ if (!adapter) return { success: false, error: "CLI adapter not running" };
3574
+ const status = adapter.getStatus?.();
3575
+ if (status?.status !== "waiting_approval") {
3576
+ return { success: false, error: "Not in approval state" };
3577
+ }
3578
+ const buttons = status.activeModal?.buttons || ["Allow once", "Always allow", "Deny"];
3579
+ let buttonIndex = typeof args?.buttonIndex === "number" ? args.buttonIndex : -1;
3580
+ if (buttonIndex < 0) {
3581
+ const btnLower = button.toLowerCase();
3582
+ buttonIndex = buttons.findIndex((b) => b.toLowerCase().includes(btnLower));
3583
+ }
3584
+ if (buttonIndex < 0) {
3585
+ if (action === "reject" || action === "deny") {
3586
+ buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
3587
+ if (buttonIndex < 0) buttonIndex = buttons.length - 1;
3588
+ } else if (action === "always" || /always/i.test(button)) {
3589
+ buttonIndex = buttons.findIndex((b) => /always/i.test(b));
3590
+ if (buttonIndex < 0) buttonIndex = 1;
3591
+ } else {
3592
+ buttonIndex = 0;
3593
+ }
3594
+ }
3595
+ if (typeof adapter.resolveModal === "function") {
3596
+ adapter.resolveModal(buttonIndex);
3597
+ } else {
3598
+ const keys = "\x1B[B".repeat(Math.max(0, buttonIndex)) + "\r";
3599
+ adapter.writeRaw?.(keys);
3600
+ }
3601
+ LOG.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
3602
+ return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
3603
+ }
3277
3604
  if (provider?.category === "extension" && h.agentStream && h.getCdp()) {
3278
3605
  const ok = await h.agentStream.resolveAgentAction(
3279
3606
  h.getCdp(),
@@ -3360,9 +3687,9 @@ async function handleResolveAction(h, args) {
3360
3687
  }
3361
3688
 
3362
3689
  // src/commands/cdp-commands.ts
3363
- var fs3 = __toESM(require("fs"));
3364
- var path3 = __toESM(require("path"));
3365
- var os4 = __toESM(require("os"));
3690
+ var fs4 = __toESM(require("fs"));
3691
+ var path5 = __toESM(require("path"));
3692
+ var os6 = __toESM(require("os"));
3366
3693
  async function handleCdpEval(h, args) {
3367
3694
  if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
3368
3695
  const expression = args?.expression || args?.script;
@@ -3514,21 +3841,21 @@ async function handleDiscoverAgents(h, args) {
3514
3841
  return { success: true, agents };
3515
3842
  }
3516
3843
  function resolveSafePath(requestedPath) {
3517
- const home = os4.homedir();
3844
+ const home = os6.homedir();
3518
3845
  let resolved;
3519
3846
  if (requestedPath.startsWith("~")) {
3520
- resolved = path3.join(home, requestedPath.slice(1));
3521
- } else if (path3.isAbsolute(requestedPath)) {
3847
+ resolved = path5.join(home, requestedPath.slice(1));
3848
+ } else if (path5.isAbsolute(requestedPath)) {
3522
3849
  resolved = requestedPath;
3523
3850
  } else {
3524
- resolved = path3.resolve(requestedPath);
3851
+ resolved = path5.resolve(requestedPath);
3525
3852
  }
3526
3853
  return resolved;
3527
3854
  }
3528
3855
  async function handleFileRead(h, args) {
3529
3856
  try {
3530
3857
  const filePath = resolveSafePath(args?.path);
3531
- const content = fs3.readFileSync(filePath, "utf-8");
3858
+ const content = fs4.readFileSync(filePath, "utf-8");
3532
3859
  return { success: true, content, path: filePath };
3533
3860
  } catch (e) {
3534
3861
  return { success: false, error: e.message };
@@ -3537,8 +3864,8 @@ async function handleFileRead(h, args) {
3537
3864
  async function handleFileWrite(h, args) {
3538
3865
  try {
3539
3866
  const filePath = resolveSafePath(args?.path);
3540
- fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
3541
- fs3.writeFileSync(filePath, args?.content || "", "utf-8");
3867
+ fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
3868
+ fs4.writeFileSync(filePath, args?.content || "", "utf-8");
3542
3869
  return { success: true, path: filePath };
3543
3870
  } catch (e) {
3544
3871
  return { success: false, error: e.message };
@@ -3547,11 +3874,11 @@ async function handleFileWrite(h, args) {
3547
3874
  async function handleFileList(h, args) {
3548
3875
  try {
3549
3876
  const dirPath = resolveSafePath(args?.path || ".");
3550
- const entries = fs3.readdirSync(dirPath, { withFileTypes: true });
3877
+ const entries = fs4.readdirSync(dirPath, { withFileTypes: true });
3551
3878
  const files = entries.map((e) => ({
3552
3879
  name: e.name,
3553
3880
  type: e.isDirectory() ? "directory" : "file",
3554
- size: e.isFile() ? fs3.statSync(path3.join(dirPath, e.name)).size : void 0
3881
+ size: e.isFile() ? fs4.statSync(path5.join(dirPath, e.name)).size : void 0
3555
3882
  }));
3556
3883
  return { success: true, files, path: dirPath };
3557
3884
  } catch (e) {
@@ -3841,7 +4168,95 @@ function handleSetIdeExtension(h, args) {
3841
4168
  return { success: false, error: "Failed to save setting" };
3842
4169
  }
3843
4170
 
4171
+ // src/commands/workspace-commands.ts
4172
+ init_config();
4173
+ init_workspaces();
4174
+ function handleWorkspaceList() {
4175
+ const config = loadConfig();
4176
+ const state = getWorkspaceState(config);
4177
+ return {
4178
+ success: true,
4179
+ workspaces: state.workspaces,
4180
+ defaultWorkspaceId: state.defaultWorkspaceId,
4181
+ defaultWorkspacePath: state.defaultWorkspacePath,
4182
+ legacyRecentPaths: config.recentCliWorkspaces || [],
4183
+ activity: getWorkspaceActivity(config, 25)
4184
+ };
4185
+ }
4186
+ function handleWorkspaceAdd(args) {
4187
+ const rawPath = (args?.path || args?.dir || "").trim();
4188
+ const label = (args?.label || "").trim() || void 0;
4189
+ if (!rawPath) return { success: false, error: "path required" };
4190
+ const config = loadConfig();
4191
+ const result = addWorkspaceEntry(config, rawPath, label);
4192
+ if ("error" in result) return { success: false, error: result.error };
4193
+ let cfg = appendWorkspaceActivity(result.config, result.entry.path, {});
4194
+ saveConfig(cfg);
4195
+ const state = getWorkspaceState(cfg);
4196
+ return { success: true, entry: result.entry, ...state, activity: getWorkspaceActivity(cfg, 25) };
4197
+ }
4198
+ function handleWorkspaceRemove(args) {
4199
+ const id = (args?.id || "").trim();
4200
+ if (!id) return { success: false, error: "id required" };
4201
+ const config = loadConfig();
4202
+ const removed = (config.workspaces || []).find((w) => w.id === id);
4203
+ const result = removeWorkspaceEntry(config, id);
4204
+ if ("error" in result) return { success: false, error: result.error };
4205
+ let cfg = result.config;
4206
+ if (removed) {
4207
+ cfg = removeActivityForPath(cfg, removed.path);
4208
+ }
4209
+ saveConfig(cfg);
4210
+ const state = getWorkspaceState(cfg);
4211
+ return { success: true, removedId: id, ...state, activity: getWorkspaceActivity(cfg, 25) };
4212
+ }
4213
+ function handleWorkspaceSetDefault(args) {
4214
+ const clear = args?.clear === true || args?.id === null || args?.id === "";
4215
+ if (clear) {
4216
+ const config2 = loadConfig();
4217
+ const result2 = setDefaultWorkspaceId(config2, null);
4218
+ if ("error" in result2) return { success: false, error: result2.error };
4219
+ saveConfig(result2.config);
4220
+ const state2 = getWorkspaceState(result2.config);
4221
+ return {
4222
+ success: true,
4223
+ ...state2,
4224
+ activity: getWorkspaceActivity(result2.config, 25)
4225
+ };
4226
+ }
4227
+ const pathArg = args?.path != null && String(args.path).trim() ? String(args.path).trim() : "";
4228
+ const idArg = args?.id !== void 0 && args?.id !== null && String(args.id).trim() ? String(args.id).trim() : "";
4229
+ if (!pathArg && !idArg) {
4230
+ return { success: false, error: "id or path required (or clear: true)" };
4231
+ }
4232
+ let config = loadConfig();
4233
+ let nextId;
4234
+ if (pathArg) {
4235
+ let w = findWorkspaceByPath(config, pathArg);
4236
+ if (!w) {
4237
+ const add = addWorkspaceEntry(config, pathArg);
4238
+ if ("error" in add) return { success: false, error: add.error };
4239
+ config = add.config;
4240
+ w = add.entry;
4241
+ }
4242
+ nextId = w.id;
4243
+ } else {
4244
+ nextId = idArg;
4245
+ }
4246
+ const result = setDefaultWorkspaceId(config, nextId);
4247
+ if ("error" in result) return { success: false, error: result.error };
4248
+ let out = result.config;
4249
+ const ap = getDefaultWorkspacePath(out);
4250
+ if (ap) {
4251
+ out = appendWorkspaceActivity(out, ap, { kind: "default" });
4252
+ }
4253
+ saveConfig(out);
4254
+ const state = getWorkspaceState(out);
4255
+ return { success: true, ...state, activity: getWorkspaceActivity(out, 25) };
4256
+ }
4257
+
3844
4258
  // src/commands/handler.ts
4259
+ init_workspaces();
3845
4260
  var DaemonCommandHandler = class {
3846
4261
  _ctx;
3847
4262
  _agentStream = null;
@@ -3950,6 +4365,9 @@ var DaemonCommandHandler = class {
3950
4365
  }
3951
4366
  /** Extract ideType from _targetInstance */
3952
4367
  extractIdeType(args) {
4368
+ if (args?.ideType && this._ctx.cdpManagers.has(args.ideType)) {
4369
+ return args.ideType;
4370
+ }
3953
4371
  if (args?._targetInstance) {
3954
4372
  let raw = args._targetInstance;
3955
4373
  const ideMatch = raw.match(/:ide:(.+)$/);
@@ -3961,8 +4379,19 @@ var DaemonCommandHandler = class {
3961
4379
  if (this._ctx.instanceIdMap?.has(raw)) {
3962
4380
  return this._ctx.instanceIdMap.get(raw);
3963
4381
  }
4382
+ if (this._ctx.cdpManagers.has(raw)) {
4383
+ return raw;
4384
+ }
4385
+ if (!ideMatch && !cliMatch && !acpMatch) {
4386
+ for (const [key, mgr] of this._ctx.cdpManagers.entries()) {
4387
+ if (mgr.isConnected) return key;
4388
+ }
4389
+ }
3964
4390
  const lastUnderscore = raw.lastIndexOf("_");
3965
- if (lastUnderscore > 0) return raw.substring(0, lastUnderscore);
4391
+ if (lastUnderscore > 0) {
4392
+ const stripped = raw.substring(0, lastUnderscore);
4393
+ if (this._ctx.cdpManagers.has(stripped)) return stripped;
4394
+ }
3966
4395
  return raw;
3967
4396
  }
3968
4397
  return void 0;
@@ -4058,6 +4487,19 @@ var DaemonCommandHandler = class {
4058
4487
  return { success: false, error: `${cmd} requires bridge-extension (removed)` };
4059
4488
  case "get_recent_workspaces":
4060
4489
  return this.handleGetRecentWorkspaces(args);
4490
+ case "get_cli_history": {
4491
+ const config = loadConfig();
4492
+ return { success: true, history: config.cliHistory || [] };
4493
+ }
4494
+ case "workspace_list":
4495
+ return handleWorkspaceList();
4496
+ case "workspace_add":
4497
+ return handleWorkspaceAdd(args);
4498
+ case "workspace_remove":
4499
+ return handleWorkspaceRemove(args);
4500
+ case "workspace_set_default":
4501
+ case "workspace_set_active":
4502
+ return handleWorkspaceSetDefault(args);
4061
4503
  // ─── Script manage ───────────────────
4062
4504
  case "refresh_scripts":
4063
4505
  return this.handleRefreshScripts(args);
@@ -4107,10 +4549,18 @@ var DaemonCommandHandler = class {
4107
4549
  }
4108
4550
  }
4109
4551
  // ─── Misc (kept in handler — too small to extract) ───────
4110
- async handleGetRecentWorkspaces(args) {
4552
+ async handleGetRecentWorkspaces(_args) {
4111
4553
  const config = loadConfig();
4112
4554
  const cliRecent = config.recentCliWorkspaces || [];
4113
- return { success: true, result: cliRecent };
4555
+ const ws = getWorkspaceState(config);
4556
+ return {
4557
+ success: true,
4558
+ result: cliRecent,
4559
+ workspaces: ws.workspaces,
4560
+ defaultWorkspaceId: ws.defaultWorkspaceId,
4561
+ defaultWorkspacePath: ws.defaultWorkspacePath,
4562
+ activity: getWorkspaceActivity(config, 25)
4563
+ };
4114
4564
  }
4115
4565
  async handleRefreshScripts(_args) {
4116
4566
  if (this._ctx.providerLoader) {
@@ -4122,15 +4572,15 @@ var DaemonCommandHandler = class {
4122
4572
  };
4123
4573
 
4124
4574
  // src/launch.ts
4125
- var import_child_process3 = require("child_process");
4575
+ var import_child_process4 = require("child_process");
4126
4576
  var net = __toESM(require("net"));
4127
- var os6 = __toESM(require("os"));
4128
- var path5 = __toESM(require("path"));
4577
+ var os8 = __toESM(require("os"));
4578
+ var path7 = __toESM(require("path"));
4129
4579
 
4130
4580
  // src/providers/provider-loader.ts
4131
- var fs4 = __toESM(require("fs"));
4132
- var path4 = __toESM(require("path"));
4133
- var os5 = __toESM(require("os"));
4581
+ var fs5 = __toESM(require("fs"));
4582
+ var path6 = __toESM(require("path"));
4583
+ var os7 = __toESM(require("os"));
4134
4584
  var ProviderLoader = class _ProviderLoader {
4135
4585
  providers = /* @__PURE__ */ new Map();
4136
4586
  builtinDirs;
@@ -4150,10 +4600,10 @@ var ProviderLoader = class _ProviderLoader {
4150
4600
  if (options?.builtinDir) {
4151
4601
  this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
4152
4602
  } else {
4153
- this.builtinDirs = [path4.resolve(__dirname, "../providers/_builtin")];
4603
+ this.builtinDirs = [path6.resolve(__dirname, "../providers/_builtin")];
4154
4604
  }
4155
- this.userDir = options?.userDir || path4.join(os5.homedir(), ".adhdev", "providers");
4156
- this.upstreamDir = path4.join(this.userDir, ".upstream");
4605
+ this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
4606
+ this.upstreamDir = path6.join(this.userDir, ".upstream");
4157
4607
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
4158
4608
  }
4159
4609
  log(msg) {
@@ -4171,19 +4621,19 @@ var ProviderLoader = class _ProviderLoader {
4171
4621
  this.providers.clear();
4172
4622
  let builtinCount = 0;
4173
4623
  for (const dir of this.builtinDirs) {
4174
- if (fs4.existsSync(dir)) {
4624
+ if (fs5.existsSync(dir)) {
4175
4625
  builtinCount += this.loadDir(dir);
4176
4626
  }
4177
4627
  }
4178
4628
  this.log(`Loaded ${builtinCount} builtin providers`);
4179
4629
  let upstreamCount = 0;
4180
- if (fs4.existsSync(this.upstreamDir)) {
4630
+ if (fs5.existsSync(this.upstreamDir)) {
4181
4631
  upstreamCount = this.loadDir(this.upstreamDir);
4182
4632
  if (upstreamCount > 0) {
4183
4633
  this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
4184
4634
  }
4185
4635
  }
4186
- if (fs4.existsSync(this.userDir)) {
4636
+ if (fs5.existsSync(this.userDir)) {
4187
4637
  const userCount = this.loadDir(this.userDir, [".upstream"]);
4188
4638
  if (userCount > 0) {
4189
4639
  this.log(`Loaded ${userCount} user custom providers (never auto-updated)`);
@@ -4487,15 +4937,15 @@ var ProviderLoader = class _ProviderLoader {
4487
4937
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
4488
4938
  return null;
4489
4939
  }
4490
- const dir = path4.join(providerDir, scriptDir);
4491
- if (!fs4.existsSync(dir)) {
4940
+ const dir = path6.join(providerDir, scriptDir);
4941
+ if (!fs5.existsSync(dir)) {
4492
4942
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
4493
4943
  return null;
4494
4944
  }
4495
4945
  const cached = this.scriptsCache.get(dir);
4496
4946
  if (cached) return cached;
4497
- const scriptsJs = path4.join(dir, "scripts.js");
4498
- if (fs4.existsSync(scriptsJs)) {
4947
+ const scriptsJs = path6.join(dir, "scripts.js");
4948
+ if (fs5.existsSync(scriptsJs)) {
4499
4949
  try {
4500
4950
  delete require.cache[require.resolve(scriptsJs)];
4501
4951
  const loaded = require(scriptsJs);
@@ -4517,15 +4967,15 @@ var ProviderLoader = class _ProviderLoader {
4517
4967
  watch() {
4518
4968
  this.stopWatch();
4519
4969
  const watchDir = (dir) => {
4520
- if (!fs4.existsSync(dir)) {
4970
+ if (!fs5.existsSync(dir)) {
4521
4971
  try {
4522
- fs4.mkdirSync(dir, { recursive: true });
4972
+ fs5.mkdirSync(dir, { recursive: true });
4523
4973
  } catch {
4524
4974
  return;
4525
4975
  }
4526
4976
  }
4527
4977
  try {
4528
- const watcher = fs4.watch(dir, { recursive: true }, (event, filename) => {
4978
+ const watcher = fs5.watch(dir, { recursive: true }, (event, filename) => {
4529
4979
  if (filename?.endsWith(".js") || filename?.endsWith(".json")) {
4530
4980
  this.log(`File changed: ${filename}, reloading...`);
4531
4981
  this.loadAll();
@@ -4575,13 +5025,13 @@ var ProviderLoader = class _ProviderLoader {
4575
5025
  */
4576
5026
  async fetchLatest() {
4577
5027
  const https = require("https");
4578
- const { execSync: execSync6 } = require("child_process");
4579
- const metaPath = path4.join(this.upstreamDir, _ProviderLoader.META_FILE);
5028
+ const { execSync: execSync7 } = require("child_process");
5029
+ const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
4580
5030
  let prevEtag = "";
4581
5031
  let prevTimestamp = 0;
4582
5032
  try {
4583
- if (fs4.existsSync(metaPath)) {
4584
- const meta = JSON.parse(fs4.readFileSync(metaPath, "utf-8"));
5033
+ if (fs5.existsSync(metaPath)) {
5034
+ const meta = JSON.parse(fs5.readFileSync(metaPath, "utf-8"));
4585
5035
  prevEtag = meta.etag || "";
4586
5036
  prevTimestamp = meta.timestamp || 0;
4587
5037
  }
@@ -4593,7 +5043,7 @@ var ProviderLoader = class _ProviderLoader {
4593
5043
  return { updated: false };
4594
5044
  }
4595
5045
  try {
4596
- const etag = await new Promise((resolve5, reject) => {
5046
+ const etag = await new Promise((resolve7, reject) => {
4597
5047
  const options = {
4598
5048
  method: "HEAD",
4599
5049
  hostname: "github.com",
@@ -4611,7 +5061,7 @@ var ProviderLoader = class _ProviderLoader {
4611
5061
  headers: { "User-Agent": "adhdev-launcher" },
4612
5062
  timeout: 1e4
4613
5063
  }, (res2) => {
4614
- resolve5(res2.headers.etag || res2.headers["last-modified"] || "");
5064
+ resolve7(res2.headers.etag || res2.headers["last-modified"] || "");
4615
5065
  });
4616
5066
  req2.on("error", reject);
4617
5067
  req2.on("timeout", () => {
@@ -4620,7 +5070,7 @@ var ProviderLoader = class _ProviderLoader {
4620
5070
  });
4621
5071
  req2.end();
4622
5072
  } else {
4623
- resolve5(res.headers.etag || res.headers["last-modified"] || "");
5073
+ resolve7(res.headers.etag || res.headers["last-modified"] || "");
4624
5074
  }
4625
5075
  });
4626
5076
  req.on("error", reject);
@@ -4636,39 +5086,39 @@ var ProviderLoader = class _ProviderLoader {
4636
5086
  return { updated: false };
4637
5087
  }
4638
5088
  this.log("Downloading latest providers from GitHub...");
4639
- const tmpTar = path4.join(os5.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
4640
- const tmpExtract = path4.join(os5.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
5089
+ const tmpTar = path6.join(os7.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
5090
+ const tmpExtract = path6.join(os7.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
4641
5091
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
4642
- fs4.mkdirSync(tmpExtract, { recursive: true });
4643
- execSync6(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
4644
- const extracted = fs4.readdirSync(tmpExtract);
5092
+ fs5.mkdirSync(tmpExtract, { recursive: true });
5093
+ execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
5094
+ const extracted = fs5.readdirSync(tmpExtract);
4645
5095
  const rootDir = extracted.find(
4646
- (d) => fs4.statSync(path4.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
5096
+ (d) => fs5.statSync(path6.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
4647
5097
  );
4648
5098
  if (!rootDir) throw new Error("Unexpected tarball structure");
4649
- const sourceDir = path4.join(tmpExtract, rootDir);
5099
+ const sourceDir = path6.join(tmpExtract, rootDir);
4650
5100
  const backupDir = this.upstreamDir + ".bak";
4651
- if (fs4.existsSync(this.upstreamDir)) {
4652
- if (fs4.existsSync(backupDir)) fs4.rmSync(backupDir, { recursive: true, force: true });
4653
- fs4.renameSync(this.upstreamDir, backupDir);
5101
+ if (fs5.existsSync(this.upstreamDir)) {
5102
+ if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
5103
+ fs5.renameSync(this.upstreamDir, backupDir);
4654
5104
  }
4655
5105
  try {
4656
5106
  this.copyDirRecursive(sourceDir, this.upstreamDir);
4657
5107
  this.writeMeta(metaPath, etag || `ts-${Date.now()}`, Date.now());
4658
- if (fs4.existsSync(backupDir)) fs4.rmSync(backupDir, { recursive: true, force: true });
5108
+ if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
4659
5109
  } catch (e) {
4660
- if (fs4.existsSync(backupDir)) {
4661
- if (fs4.existsSync(this.upstreamDir)) fs4.rmSync(this.upstreamDir, { recursive: true, force: true });
4662
- fs4.renameSync(backupDir, this.upstreamDir);
5110
+ if (fs5.existsSync(backupDir)) {
5111
+ if (fs5.existsSync(this.upstreamDir)) fs5.rmSync(this.upstreamDir, { recursive: true, force: true });
5112
+ fs5.renameSync(backupDir, this.upstreamDir);
4663
5113
  }
4664
5114
  throw e;
4665
5115
  }
4666
5116
  try {
4667
- fs4.rmSync(tmpTar, { force: true });
5117
+ fs5.rmSync(tmpTar, { force: true });
4668
5118
  } catch {
4669
5119
  }
4670
5120
  try {
4671
- fs4.rmSync(tmpExtract, { recursive: true, force: true });
5121
+ fs5.rmSync(tmpExtract, { recursive: true, force: true });
4672
5122
  } catch {
4673
5123
  }
4674
5124
  const upstreamCount = this.countProviders(this.upstreamDir);
@@ -4684,7 +5134,7 @@ var ProviderLoader = class _ProviderLoader {
4684
5134
  downloadFile(url, destPath) {
4685
5135
  const https = require("https");
4686
5136
  const http3 = require("http");
4687
- return new Promise((resolve5, reject) => {
5137
+ return new Promise((resolve7, reject) => {
4688
5138
  const doRequest = (reqUrl, redirectCount = 0) => {
4689
5139
  if (redirectCount > 5) {
4690
5140
  reject(new Error("Too many redirects"));
@@ -4700,11 +5150,11 @@ var ProviderLoader = class _ProviderLoader {
4700
5150
  reject(new Error(`HTTP ${res.statusCode}`));
4701
5151
  return;
4702
5152
  }
4703
- const ws = fs4.createWriteStream(destPath);
5153
+ const ws = fs5.createWriteStream(destPath);
4704
5154
  res.pipe(ws);
4705
5155
  ws.on("finish", () => {
4706
5156
  ws.close();
4707
- resolve5();
5157
+ resolve7();
4708
5158
  });
4709
5159
  ws.on("error", reject);
4710
5160
  });
@@ -4719,22 +5169,22 @@ var ProviderLoader = class _ProviderLoader {
4719
5169
  }
4720
5170
  /** Recursive directory copy */
4721
5171
  copyDirRecursive(src, dest) {
4722
- fs4.mkdirSync(dest, { recursive: true });
4723
- for (const entry of fs4.readdirSync(src, { withFileTypes: true })) {
4724
- const srcPath = path4.join(src, entry.name);
4725
- const destPath = path4.join(dest, entry.name);
5172
+ fs5.mkdirSync(dest, { recursive: true });
5173
+ for (const entry of fs5.readdirSync(src, { withFileTypes: true })) {
5174
+ const srcPath = path6.join(src, entry.name);
5175
+ const destPath = path6.join(dest, entry.name);
4726
5176
  if (entry.isDirectory()) {
4727
5177
  this.copyDirRecursive(srcPath, destPath);
4728
5178
  } else {
4729
- fs4.copyFileSync(srcPath, destPath);
5179
+ fs5.copyFileSync(srcPath, destPath);
4730
5180
  }
4731
5181
  }
4732
5182
  }
4733
5183
  /** .meta.json save */
4734
5184
  writeMeta(metaPath, etag, timestamp) {
4735
5185
  try {
4736
- fs4.mkdirSync(path4.dirname(metaPath), { recursive: true });
4737
- fs4.writeFileSync(metaPath, JSON.stringify({
5186
+ fs5.mkdirSync(path6.dirname(metaPath), { recursive: true });
5187
+ fs5.writeFileSync(metaPath, JSON.stringify({
4738
5188
  etag,
4739
5189
  timestamp,
4740
5190
  lastCheck: new Date(timestamp).toISOString(),
@@ -4745,12 +5195,12 @@ var ProviderLoader = class _ProviderLoader {
4745
5195
  }
4746
5196
  /** Count provider files (provider.js or provider.json) */
4747
5197
  countProviders(dir) {
4748
- if (!fs4.existsSync(dir)) return 0;
5198
+ if (!fs5.existsSync(dir)) return 0;
4749
5199
  let count = 0;
4750
5200
  const scan = (d) => {
4751
5201
  try {
4752
- for (const entry of fs4.readdirSync(d, { withFileTypes: true })) {
4753
- if (entry.isDirectory()) scan(path4.join(d, entry.name));
5202
+ for (const entry of fs5.readdirSync(d, { withFileTypes: true })) {
5203
+ if (entry.isDirectory()) scan(path6.join(d, entry.name));
4754
5204
  else if (entry.name === "provider.json") count++;
4755
5205
  }
4756
5206
  } catch {
@@ -4847,20 +5297,20 @@ var ProviderLoader = class _ProviderLoader {
4847
5297
  const cat = provider.category;
4848
5298
  const searchRoots = [this.userDir, this.upstreamDir, ...this.builtinDirs];
4849
5299
  for (const root of searchRoots) {
4850
- if (!fs4.existsSync(root)) continue;
4851
- for (const candidate of [path4.join(root, type), path4.join(root, cat, type)]) {
4852
- if (fs4.existsSync(path4.join(candidate, "provider.json"))) return candidate;
5300
+ if (!fs5.existsSync(root)) continue;
5301
+ for (const candidate of [path6.join(root, type), path6.join(root, cat, type)]) {
5302
+ if (fs5.existsSync(path6.join(candidate, "provider.json"))) return candidate;
4853
5303
  }
4854
- const catDir = path4.join(root, cat);
4855
- if (fs4.existsSync(catDir)) {
5304
+ const catDir = path6.join(root, cat);
5305
+ if (fs5.existsSync(catDir)) {
4856
5306
  try {
4857
- for (const entry of fs4.readdirSync(catDir, { withFileTypes: true })) {
5307
+ for (const entry of fs5.readdirSync(catDir, { withFileTypes: true })) {
4858
5308
  if (!entry.isDirectory()) continue;
4859
- const jsonPath = path4.join(catDir, entry.name, "provider.json");
4860
- if (fs4.existsSync(jsonPath)) {
5309
+ const jsonPath = path6.join(catDir, entry.name, "provider.json");
5310
+ if (fs5.existsSync(jsonPath)) {
4861
5311
  try {
4862
- const data = JSON.parse(fs4.readFileSync(jsonPath, "utf-8"));
4863
- if (data.type === type) return path4.join(catDir, entry.name);
5312
+ const data = JSON.parse(fs5.readFileSync(jsonPath, "utf-8"));
5313
+ if (data.type === type) return path6.join(catDir, entry.name);
4864
5314
  } catch {
4865
5315
  }
4866
5316
  }
@@ -4877,8 +5327,8 @@ var ProviderLoader = class _ProviderLoader {
4877
5327
  * (template substitution is NOT applied here — scripts.js handles that)
4878
5328
  */
4879
5329
  buildScriptWrappersFromDir(dir) {
4880
- const scriptsJs = path4.join(dir, "scripts.js");
4881
- if (fs4.existsSync(scriptsJs)) {
5330
+ const scriptsJs = path6.join(dir, "scripts.js");
5331
+ if (fs5.existsSync(scriptsJs)) {
4882
5332
  try {
4883
5333
  delete require.cache[require.resolve(scriptsJs)];
4884
5334
  return require(scriptsJs);
@@ -4888,13 +5338,13 @@ var ProviderLoader = class _ProviderLoader {
4888
5338
  const toCamel = (name) => name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
4889
5339
  const result = {};
4890
5340
  try {
4891
- for (const file of fs4.readdirSync(dir)) {
5341
+ for (const file of fs5.readdirSync(dir)) {
4892
5342
  if (!file.endsWith(".js")) continue;
4893
5343
  const scriptName = toCamel(file.replace(".js", ""));
4894
- const filePath = path4.join(dir, file);
5344
+ const filePath = path6.join(dir, file);
4895
5345
  result[scriptName] = (..._args) => {
4896
5346
  try {
4897
- return fs4.readFileSync(filePath, "utf-8");
5347
+ return fs5.readFileSync(filePath, "utf-8");
4898
5348
  } catch {
4899
5349
  return "";
4900
5350
  }
@@ -4912,20 +5362,20 @@ var ProviderLoader = class _ProviderLoader {
4912
5362
  * Structure: dir/category/agent-name/provider.{json,js}
4913
5363
  */
4914
5364
  loadDir(dir, excludeDirs) {
4915
- if (!fs4.existsSync(dir)) return 0;
5365
+ if (!fs5.existsSync(dir)) return 0;
4916
5366
  let count = 0;
4917
5367
  const scan = (d) => {
4918
5368
  let entries;
4919
5369
  try {
4920
- entries = fs4.readdirSync(d, { withFileTypes: true });
5370
+ entries = fs5.readdirSync(d, { withFileTypes: true });
4921
5371
  } catch {
4922
5372
  return;
4923
5373
  }
4924
5374
  const hasJson = entries.some((e) => e.name === "provider.json");
4925
5375
  if (hasJson) {
4926
- const jsonPath = path4.join(d, "provider.json");
5376
+ const jsonPath = path6.join(d, "provider.json");
4927
5377
  try {
4928
- const raw = fs4.readFileSync(jsonPath, "utf-8");
5378
+ const raw = fs5.readFileSync(jsonPath, "utf-8");
4929
5379
  const mod = JSON.parse(raw);
4930
5380
  if (!mod.type || !mod.name || !mod.category) {
4931
5381
  this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
@@ -4936,8 +5386,8 @@ var ProviderLoader = class _ProviderLoader {
4936
5386
  delete mod.extensionIdPattern_flags;
4937
5387
  }
4938
5388
  const hasCompatibility = Array.isArray(mod.compatibility);
4939
- const scriptsPath = path4.join(d, "scripts.js");
4940
- if (!hasCompatibility && fs4.existsSync(scriptsPath)) {
5389
+ const scriptsPath = path6.join(d, "scripts.js");
5390
+ if (!hasCompatibility && fs5.existsSync(scriptsPath)) {
4941
5391
  try {
4942
5392
  delete require.cache[require.resolve(scriptsPath)];
4943
5393
  const scripts = require(scriptsPath);
@@ -4962,7 +5412,7 @@ var ProviderLoader = class _ProviderLoader {
4962
5412
  if (!entry.isDirectory()) continue;
4963
5413
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
4964
5414
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
4965
- scan(path4.join(d, entry.name));
5415
+ scan(path6.join(d, entry.name));
4966
5416
  }
4967
5417
  }
4968
5418
  };
@@ -5041,17 +5491,17 @@ async function findFreePort(ports) {
5041
5491
  throw new Error("No free port found");
5042
5492
  }
5043
5493
  function checkPortFree(port) {
5044
- return new Promise((resolve5) => {
5494
+ return new Promise((resolve7) => {
5045
5495
  const server = net.createServer();
5046
5496
  server.unref();
5047
- server.on("error", () => resolve5(false));
5497
+ server.on("error", () => resolve7(false));
5048
5498
  server.listen(port, "127.0.0.1", () => {
5049
- server.close(() => resolve5(true));
5499
+ server.close(() => resolve7(true));
5050
5500
  });
5051
5501
  });
5052
5502
  }
5053
5503
  async function isCdpActive(port) {
5054
- return new Promise((resolve5) => {
5504
+ return new Promise((resolve7) => {
5055
5505
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
5056
5506
  timeout: 2e3
5057
5507
  }, (res) => {
@@ -5060,52 +5510,52 @@ async function isCdpActive(port) {
5060
5510
  res.on("end", () => {
5061
5511
  try {
5062
5512
  const info = JSON.parse(data);
5063
- resolve5(!!info["WebKit-Version"] || !!info["Browser"]);
5513
+ resolve7(!!info["WebKit-Version"] || !!info["Browser"]);
5064
5514
  } catch {
5065
- resolve5(false);
5515
+ resolve7(false);
5066
5516
  }
5067
5517
  });
5068
5518
  });
5069
- req.on("error", () => resolve5(false));
5519
+ req.on("error", () => resolve7(false));
5070
5520
  req.on("timeout", () => {
5071
5521
  req.destroy();
5072
- resolve5(false);
5522
+ resolve7(false);
5073
5523
  });
5074
5524
  });
5075
5525
  }
5076
5526
  async function killIdeProcess(ideId) {
5077
- const plat = os6.platform();
5527
+ const plat = os8.platform();
5078
5528
  const appName = getMacAppIdentifiers()[ideId];
5079
5529
  const winProcesses = getWinProcessNames()[ideId];
5080
5530
  try {
5081
5531
  if (plat === "darwin" && appName) {
5082
5532
  try {
5083
- (0, import_child_process3.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
5533
+ (0, import_child_process4.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
5084
5534
  timeout: 5e3
5085
5535
  });
5086
5536
  } catch {
5087
5537
  try {
5088
- (0, import_child_process3.execSync)(`pkill -f "${appName}" 2>/dev/null`);
5538
+ (0, import_child_process4.execSync)(`pkill -f "${appName}" 2>/dev/null`);
5089
5539
  } catch {
5090
5540
  }
5091
5541
  }
5092
5542
  } else if (plat === "win32" && winProcesses) {
5093
5543
  for (const proc of winProcesses) {
5094
5544
  try {
5095
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
5545
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
5096
5546
  } catch {
5097
5547
  }
5098
5548
  }
5099
5549
  try {
5100
5550
  const exeName = winProcesses[0].replace(".exe", "");
5101
- (0, import_child_process3.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
5551
+ (0, import_child_process4.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
5102
5552
  timeout: 1e4
5103
5553
  });
5104
5554
  } catch {
5105
5555
  }
5106
5556
  } else {
5107
5557
  try {
5108
- (0, import_child_process3.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
5558
+ (0, import_child_process4.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
5109
5559
  } catch {
5110
5560
  }
5111
5561
  }
@@ -5115,13 +5565,13 @@ async function killIdeProcess(ideId) {
5115
5565
  }
5116
5566
  if (plat === "darwin" && appName) {
5117
5567
  try {
5118
- (0, import_child_process3.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
5568
+ (0, import_child_process4.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
5119
5569
  } catch {
5120
5570
  }
5121
5571
  } else if (plat === "win32" && winProcesses) {
5122
5572
  for (const proc of winProcesses) {
5123
5573
  try {
5124
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
5574
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
5125
5575
  } catch {
5126
5576
  }
5127
5577
  }
@@ -5133,26 +5583,26 @@ async function killIdeProcess(ideId) {
5133
5583
  }
5134
5584
  }
5135
5585
  function isIdeRunning(ideId) {
5136
- const plat = os6.platform();
5586
+ const plat = os8.platform();
5137
5587
  try {
5138
5588
  if (plat === "darwin") {
5139
5589
  const appName = getMacAppIdentifiers()[ideId];
5140
5590
  if (!appName) return false;
5141
- const result = (0, import_child_process3.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
5591
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
5142
5592
  return result.trim().length > 0;
5143
5593
  } else if (plat === "win32") {
5144
5594
  const winProcesses = getWinProcessNames()[ideId];
5145
5595
  if (!winProcesses) return false;
5146
5596
  for (const proc of winProcesses) {
5147
5597
  try {
5148
- const result = (0, import_child_process3.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
5598
+ const result = (0, import_child_process4.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
5149
5599
  if (result.includes(proc)) return true;
5150
5600
  } catch {
5151
5601
  }
5152
5602
  }
5153
5603
  try {
5154
5604
  const exeName = winProcesses[0].replace(".exe", "");
5155
- const result = (0, import_child_process3.execSync)(
5605
+ const result = (0, import_child_process4.execSync)(
5156
5606
  `powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
5157
5607
  { encoding: "utf-8", timeout: 5e3 }
5158
5608
  );
@@ -5161,7 +5611,7 @@ function isIdeRunning(ideId) {
5161
5611
  }
5162
5612
  return false;
5163
5613
  } else {
5164
- const result = (0, import_child_process3.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
5614
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
5165
5615
  return result.trim().length > 0;
5166
5616
  }
5167
5617
  } catch {
@@ -5169,12 +5619,12 @@ function isIdeRunning(ideId) {
5169
5619
  }
5170
5620
  }
5171
5621
  function detectCurrentWorkspace(ideId) {
5172
- const plat = os6.platform();
5622
+ const plat = os8.platform();
5173
5623
  if (plat === "darwin") {
5174
5624
  try {
5175
5625
  const appName = getMacAppIdentifiers()[ideId];
5176
5626
  if (!appName) return void 0;
5177
- const result = (0, import_child_process3.execSync)(
5627
+ const result = (0, import_child_process4.execSync)(
5178
5628
  `lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
5179
5629
  { encoding: "utf-8", timeout: 3e3 }
5180
5630
  );
@@ -5184,17 +5634,17 @@ function detectCurrentWorkspace(ideId) {
5184
5634
  }
5185
5635
  } else if (plat === "win32") {
5186
5636
  try {
5187
- const fs9 = require("fs");
5637
+ const fs10 = require("fs");
5188
5638
  const appNameMap = getMacAppIdentifiers();
5189
5639
  const appName = appNameMap[ideId];
5190
5640
  if (appName) {
5191
- const storagePath = path5.join(
5192
- process.env.APPDATA || path5.join(os6.homedir(), "AppData", "Roaming"),
5641
+ const storagePath = path7.join(
5642
+ process.env.APPDATA || path7.join(os8.homedir(), "AppData", "Roaming"),
5193
5643
  appName,
5194
5644
  "storage.json"
5195
5645
  );
5196
- if (fs9.existsSync(storagePath)) {
5197
- const data = JSON.parse(fs9.readFileSync(storagePath, "utf-8"));
5646
+ if (fs10.existsSync(storagePath)) {
5647
+ const data = JSON.parse(fs10.readFileSync(storagePath, "utf-8"));
5198
5648
  const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
5199
5649
  if (workspaces.length > 0) {
5200
5650
  const recent = workspaces[0];
@@ -5211,7 +5661,7 @@ function detectCurrentWorkspace(ideId) {
5211
5661
  return void 0;
5212
5662
  }
5213
5663
  async function launchWithCdp(options = {}) {
5214
- const platform7 = os6.platform();
5664
+ const platform8 = os8.platform();
5215
5665
  let targetIde;
5216
5666
  const ides = await detectIDEs();
5217
5667
  if (options.ideId) {
@@ -5280,9 +5730,9 @@ async function launchWithCdp(options = {}) {
5280
5730
  }
5281
5731
  const port = await findFreePort(portPair);
5282
5732
  try {
5283
- if (platform7 === "darwin") {
5733
+ if (platform8 === "darwin") {
5284
5734
  await launchMacOS(targetIde, port, workspace, options.newWindow);
5285
- } else if (platform7 === "win32") {
5735
+ } else if (platform8 === "win32") {
5286
5736
  await launchWindows(targetIde, port, workspace, options.newWindow);
5287
5737
  } else {
5288
5738
  await launchLinux(targetIde, port, workspace, options.newWindow);
@@ -5322,9 +5772,9 @@ async function launchMacOS(ide, port, workspace, newWindow) {
5322
5772
  if (workspace) args.push(workspace);
5323
5773
  if (appName) {
5324
5774
  const openArgs = ["-a", appName, "--args", ...args];
5325
- (0, import_child_process3.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
5775
+ (0, import_child_process4.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
5326
5776
  } else if (ide.cliCommand) {
5327
- (0, import_child_process3.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
5777
+ (0, import_child_process4.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
5328
5778
  } else {
5329
5779
  throw new Error(`No app identifier or CLI for ${ide.displayName}`);
5330
5780
  }
@@ -5350,21 +5800,25 @@ async function launchLinux(ide, port, workspace, newWindow) {
5350
5800
  const args = ["--remote-debugging-port=" + port];
5351
5801
  if (newWindow) args.push("--new-window");
5352
5802
  if (workspace) args.push(workspace);
5353
- (0, import_child_process3.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
5803
+ (0, import_child_process4.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
5354
5804
  }
5355
5805
  function getAvailableIdeIds() {
5356
5806
  return getProviderLoader().getAvailableIdeTypes();
5357
5807
  }
5358
5808
 
5809
+ // src/commands/router.ts
5810
+ init_config();
5811
+ init_workspaces();
5812
+
5359
5813
  // src/logging/command-log.ts
5360
- var fs5 = __toESM(require("fs"));
5361
- var path6 = __toESM(require("path"));
5362
- var os7 = __toESM(require("os"));
5363
- var LOG_DIR2 = process.platform === "darwin" ? path6.join(os7.homedir(), "Library", "Logs", "adhdev") : path6.join(os7.homedir(), ".local", "share", "adhdev", "logs");
5814
+ var fs6 = __toESM(require("fs"));
5815
+ var path8 = __toESM(require("path"));
5816
+ var os9 = __toESM(require("os"));
5817
+ var LOG_DIR2 = process.platform === "darwin" ? path8.join(os9.homedir(), "Library", "Logs", "adhdev") : path8.join(os9.homedir(), ".local", "share", "adhdev", "logs");
5364
5818
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
5365
5819
  var MAX_DAYS = 7;
5366
5820
  try {
5367
- fs5.mkdirSync(LOG_DIR2, { recursive: true });
5821
+ fs6.mkdirSync(LOG_DIR2, { recursive: true });
5368
5822
  } catch {
5369
5823
  }
5370
5824
  var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
@@ -5398,19 +5852,19 @@ function getDateStr2() {
5398
5852
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5399
5853
  }
5400
5854
  var currentDate2 = getDateStr2();
5401
- var currentFile = path6.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5855
+ var currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5402
5856
  var writeCount2 = 0;
5403
5857
  function checkRotation() {
5404
5858
  const today = getDateStr2();
5405
5859
  if (today !== currentDate2) {
5406
5860
  currentDate2 = today;
5407
- currentFile = path6.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5861
+ currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5408
5862
  cleanOldFiles();
5409
5863
  }
5410
5864
  }
5411
5865
  function cleanOldFiles() {
5412
5866
  try {
5413
- const files = fs5.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
5867
+ const files = fs6.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
5414
5868
  const cutoff = /* @__PURE__ */ new Date();
5415
5869
  cutoff.setDate(cutoff.getDate() - MAX_DAYS);
5416
5870
  const cutoffStr = cutoff.toISOString().slice(0, 10);
@@ -5418,7 +5872,7 @@ function cleanOldFiles() {
5418
5872
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
5419
5873
  if (dateMatch && dateMatch[1] < cutoffStr) {
5420
5874
  try {
5421
- fs5.unlinkSync(path6.join(LOG_DIR2, file));
5875
+ fs6.unlinkSync(path8.join(LOG_DIR2, file));
5422
5876
  } catch {
5423
5877
  }
5424
5878
  }
@@ -5428,14 +5882,14 @@ function cleanOldFiles() {
5428
5882
  }
5429
5883
  function checkSize() {
5430
5884
  try {
5431
- const stat = fs5.statSync(currentFile);
5885
+ const stat = fs6.statSync(currentFile);
5432
5886
  if (stat.size > MAX_FILE_SIZE) {
5433
5887
  const backup = currentFile.replace(".jsonl", ".1.jsonl");
5434
5888
  try {
5435
- fs5.unlinkSync(backup);
5889
+ fs6.unlinkSync(backup);
5436
5890
  } catch {
5437
5891
  }
5438
- fs5.renameSync(currentFile, backup);
5892
+ fs6.renameSync(currentFile, backup);
5439
5893
  }
5440
5894
  } catch {
5441
5895
  }
@@ -5460,14 +5914,14 @@ function logCommand(entry) {
5460
5914
  ...entry.error ? { err: entry.error } : {},
5461
5915
  ...entry.durationMs !== void 0 ? { ms: entry.durationMs } : {}
5462
5916
  });
5463
- fs5.appendFileSync(currentFile, line + "\n");
5917
+ fs6.appendFileSync(currentFile, line + "\n");
5464
5918
  } catch {
5465
5919
  }
5466
5920
  }
5467
5921
  function getRecentCommands(count = 50) {
5468
5922
  try {
5469
- if (!fs5.existsSync(currentFile)) return [];
5470
- const content = fs5.readFileSync(currentFile, "utf-8");
5923
+ if (!fs6.existsSync(currentFile)) return [];
5924
+ const content = fs6.readFileSync(currentFile, "utf-8");
5471
5925
  const lines = content.trim().split("\n").filter(Boolean);
5472
5926
  return lines.slice(-count).map((line) => {
5473
5927
  try {
@@ -5492,7 +5946,7 @@ function getRecentCommands(count = 50) {
5492
5946
  cleanOldFiles();
5493
5947
 
5494
5948
  // src/commands/router.ts
5495
- var fs6 = __toESM(require("fs"));
5949
+ var fs7 = __toESM(require("fs"));
5496
5950
  var CHAT_COMMANDS = [
5497
5951
  "send_chat",
5498
5952
  "new_chat",
@@ -5562,8 +6016,8 @@ var DaemonCommandRouter = class {
5562
6016
  if (logs.length > 0) {
5563
6017
  return { success: true, logs, totalBuffered: logs.length };
5564
6018
  }
5565
- if (fs6.existsSync(LOG_PATH)) {
5566
- const content = fs6.readFileSync(LOG_PATH, "utf-8");
6019
+ if (fs7.existsSync(LOG_PATH)) {
6020
+ const content = fs7.readFileSync(LOG_PATH, "utf-8");
5567
6021
  const allLines = content.split("\n");
5568
6022
  const recent = allLines.slice(-count).join("\n");
5569
6023
  return { success: true, logs: recent, totalLines: allLines.length };
@@ -5602,8 +6056,20 @@ var DaemonCommandRouter = class {
5602
6056
  }
5603
6057
  // ─── IDE launch + CDP connect ───
5604
6058
  case "launch_ide": {
5605
- const launchArgs = { ...args, ideId: args?.ideId || args?.ideType };
5606
- const ideKey = launchArgs.ideId;
6059
+ const ideKey = args?.ideId || args?.ideType;
6060
+ const resolvedWorkspace = resolveIdeLaunchWorkspace(
6061
+ {
6062
+ workspace: args?.workspace,
6063
+ workspaceId: args?.workspaceId,
6064
+ useDefaultWorkspace: args?.useDefaultWorkspace
6065
+ },
6066
+ loadConfig()
6067
+ );
6068
+ const launchArgs = {
6069
+ ideId: ideKey,
6070
+ workspace: resolvedWorkspace,
6071
+ newWindow: args?.newWindow
6072
+ };
5607
6073
  LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
5608
6074
  const result = await launchWithCdp(launchArgs);
5609
6075
  if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
@@ -5620,6 +6086,15 @@ var DaemonCommandRouter = class {
5620
6086
  }
5621
6087
  }
5622
6088
  this.deps.onIdeConnected?.();
6089
+ if (result.success && resolvedWorkspace) {
6090
+ try {
6091
+ saveConfig(appendWorkspaceActivity(loadConfig(), resolvedWorkspace, {
6092
+ kind: "ide",
6093
+ agentType: result.ideId
6094
+ }));
6095
+ } catch {
6096
+ }
6097
+ }
5623
6098
  return { success: result.success, ...result };
5624
6099
  }
5625
6100
  // ─── IDE detection ───
@@ -5627,6 +6102,12 @@ var DaemonCommandRouter = class {
5627
6102
  this.deps.detectedIdes.value = await detectIDEs();
5628
6103
  return { success: true, ides: this.deps.detectedIdes.value };
5629
6104
  }
6105
+ // ─── Machine Settings ───
6106
+ case "set_machine_nickname": {
6107
+ const nickname = args?.nickname;
6108
+ updateConfig({ machineNickname: nickname || null });
6109
+ return { success: true };
6110
+ }
5630
6111
  }
5631
6112
  return null;
5632
6113
  }
@@ -5663,8 +6144,9 @@ var DaemonCommandRouter = class {
5663
6144
  };
5664
6145
 
5665
6146
  // src/status/reporter.ts
5666
- var os8 = __toESM(require("os"));
6147
+ var os10 = __toESM(require("os"));
5667
6148
  init_config();
6149
+ init_workspaces();
5668
6150
  var DaemonStatusReporter = class {
5669
6151
  deps;
5670
6152
  log;
@@ -5731,6 +6213,10 @@ var DaemonStatusReporter = class {
5731
6213
  // (agent-stream polling backward compat)
5732
6214
  updateAgentStreams(_ideType, _streams) {
5733
6215
  }
6216
+ /** Reset P2P dedup hash — forces next send to transmit even if content unchanged */
6217
+ resetP2PHash() {
6218
+ this.lastP2PStatusHash = "";
6219
+ }
5734
6220
  // ─── Core ────────────────────────────────────────
5735
6221
  ts() {
5736
6222
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
@@ -5810,18 +6296,26 @@ var DaemonStatusReporter = class {
5810
6296
  acpConfigOptions: s.acpConfigOptions,
5811
6297
  acpModes: s.acpModes
5812
6298
  }));
6299
+ const cfg = loadConfig();
6300
+ const wsState = getWorkspaceState(cfg);
6301
+ const memSnap = getHostMemorySnapshot();
5813
6302
  const payload = {
5814
6303
  daemonMode: true,
5815
- machineNickname: loadConfig().machineNickname || null,
6304
+ machineNickname: cfg.machineNickname || null,
6305
+ workspaces: wsState.workspaces,
6306
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
6307
+ defaultWorkspacePath: wsState.defaultWorkspacePath,
6308
+ workspaceActivity: getWorkspaceActivity(cfg, 15),
5816
6309
  machine: {
5817
- hostname: os8.hostname(),
5818
- platform: os8.platform(),
5819
- arch: os8.arch(),
5820
- cpus: os8.cpus().length,
5821
- totalMem: os8.totalmem(),
5822
- freeMem: os8.freemem(),
5823
- loadavg: os8.loadavg(),
5824
- uptime: os8.uptime()
6310
+ hostname: os10.hostname(),
6311
+ platform: os10.platform(),
6312
+ arch: os10.arch(),
6313
+ cpus: os10.cpus().length,
6314
+ totalMem: memSnap.totalMem,
6315
+ freeMem: memSnap.freeMem,
6316
+ availableMem: memSnap.availableMem,
6317
+ loadavg: os10.loadavg(),
6318
+ uptime: os10.uptime()
5825
6319
  },
5826
6320
  managedIdes,
5827
6321
  managedClis,
@@ -5853,6 +6347,8 @@ var DaemonStatusReporter = class {
5853
6347
  const wsPayload = {
5854
6348
  daemonMode: true,
5855
6349
  machineNickname: payload.machineNickname,
6350
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
6351
+ workspaceCount: (wsState.workspaces || []).length,
5856
6352
  // managedIdes: server only saves id, type, cdpConnected
5857
6353
  managedIdes: managedIdes.map((ide) => ({
5858
6354
  ideType: ide.ideType,
@@ -5883,7 +6379,7 @@ var DaemonStatusReporter = class {
5883
6379
  sendP2PPayload(payload) {
5884
6380
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
5885
6381
  if (hashTarget.machine) {
5886
- const { freeMem: _f, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
6382
+ const { freeMem: _f, availableMem: _a, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
5887
6383
  hashTarget.machine = stableMachine;
5888
6384
  }
5889
6385
  const h = this.simpleHash(JSON.stringify(hashTarget));
@@ -5905,17 +6401,34 @@ var DaemonStatusReporter = class {
5905
6401
  };
5906
6402
 
5907
6403
  // src/commands/cli-manager.ts
5908
- var os10 = __toESM(require("os"));
5909
- var path7 = __toESM(require("path"));
6404
+ var os12 = __toESM(require("os"));
6405
+ var path10 = __toESM(require("path"));
5910
6406
  var crypto4 = __toESM(require("crypto"));
5911
6407
  var import_chalk = __toESM(require("chalk"));
5912
6408
 
5913
6409
  // src/cli-adapters/provider-cli-adapter.ts
5914
- var os9 = __toESM(require("os"));
5915
- var import_child_process4 = require("child_process");
6410
+ var os11 = __toESM(require("os"));
6411
+ var path9 = __toESM(require("path"));
6412
+ var import_child_process5 = require("child_process");
5916
6413
  var pty;
5917
6414
  try {
5918
6415
  pty = require("node-pty");
6416
+ if (os11.platform() !== "win32") {
6417
+ try {
6418
+ const fs10 = require("fs");
6419
+ const ptyDir = path9.dirname(require.resolve("node-pty"));
6420
+ const arch3 = os11.arch() === "arm64" ? "darwin-arm64" : "darwin-x64";
6421
+ const helper = path9.join(ptyDir, "prebuilds", arch3, "spawn-helper");
6422
+ if (fs10.existsSync(helper)) {
6423
+ const stat = fs10.statSync(helper);
6424
+ if (!(stat.mode & 73)) {
6425
+ fs10.chmodSync(helper, stat.mode | 493);
6426
+ LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
6427
+ }
6428
+ }
6429
+ } catch {
6430
+ }
6431
+ }
5919
6432
  } catch {
5920
6433
  LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Install: npm install node-pty@1.0.0");
5921
6434
  }
@@ -5923,21 +6436,125 @@ function stripAnsi(str) {
5923
6436
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
5924
6437
  }
5925
6438
  function findBinary(name) {
5926
- const isWin = os9.platform() === "win32";
6439
+ const isWin = os11.platform() === "win32";
5927
6440
  try {
5928
6441
  const cmd = isWin ? `where ${name}` : `which ${name}`;
5929
- return (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
6442
+ return (0, import_child_process5.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
5930
6443
  } catch {
5931
6444
  return isWin ? `${name}.cmd` : name;
5932
6445
  }
5933
6446
  }
6447
+ function isScriptBinary(binaryPath) {
6448
+ if (!path9.isAbsolute(binaryPath)) return false;
6449
+ try {
6450
+ const fs10 = require("fs");
6451
+ const resolved = fs10.realpathSync(binaryPath);
6452
+ const head = Buffer.alloc(8);
6453
+ const fd = fs10.openSync(resolved, "r");
6454
+ fs10.readSync(fd, head, 0, 8, 0);
6455
+ fs10.closeSync(fd);
6456
+ let i = 0;
6457
+ if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
6458
+ return head[i] === 35 && head[i + 1] === 33;
6459
+ } catch {
6460
+ return false;
6461
+ }
6462
+ }
6463
+ function looksLikeMachOOrElf(filePath) {
6464
+ if (!path9.isAbsolute(filePath)) return false;
6465
+ try {
6466
+ const fs10 = require("fs");
6467
+ const resolved = fs10.realpathSync(filePath);
6468
+ const buf = Buffer.alloc(8);
6469
+ const fd = fs10.openSync(resolved, "r");
6470
+ fs10.readSync(fd, buf, 0, 8, 0);
6471
+ fs10.closeSync(fd);
6472
+ let i = 0;
6473
+ if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
6474
+ const b = buf.subarray(i);
6475
+ if (b.length < 4) return false;
6476
+ if (b[0] === 127 && b[1] === 69 && b[2] === 76 && b[3] === 70) return true;
6477
+ const le = b.readUInt32LE(0);
6478
+ const be = b.readUInt32BE(0);
6479
+ const magics = [4277009102, 4277009103, 3405691582, 3199925962];
6480
+ return magics.some((m) => m === le || m === be);
6481
+ } catch {
6482
+ return false;
6483
+ }
6484
+ }
6485
+ function shSingleQuote(arg) {
6486
+ if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
6487
+ return `'${arg.replace(/'/g, `'\\''`)}'`;
6488
+ }
6489
+ function parsePatternEntry(x) {
6490
+ if (x instanceof RegExp) return x;
6491
+ if (x && typeof x === "object" && typeof x.source === "string") {
6492
+ try {
6493
+ const s = x;
6494
+ return new RegExp(s.source, s.flags || "");
6495
+ } catch {
6496
+ return null;
6497
+ }
6498
+ }
6499
+ return null;
6500
+ }
6501
+ function coercePatternArray(raw, fallbacks) {
6502
+ if (!Array.isArray(raw)) return [...fallbacks];
6503
+ const parsed = raw.map(parsePatternEntry).filter((r) => r != null);
6504
+ return parsed.length > 0 ? parsed : [...fallbacks];
6505
+ }
6506
+ var FALLBACK_PROMPT = [
6507
+ /Type your message/i,
6508
+ /^>\s*$/m,
6509
+ // '>' alone on its own line
6510
+ /[›➤]\s*$/,
6511
+ /for shortcuts/i,
6512
+ /\?\s*for help/i,
6513
+ /Press enter/i
6514
+ // NOTE: removed /^[\s\u2500-\u257f]*>\s*$/m — the box-drawing char range is too wide and
6515
+ // can match dialog-clearing ANSI output, causing false prompt detection in approval state.
6516
+ ];
6517
+ var FALLBACK_GENERATING = [
6518
+ /[\u2800-\u28ff]/,
6519
+ // Braille spinner blocks (universal TUI)
6520
+ /esc to (cancel|interrupt|stop)/i,
6521
+ // Common TUI generation status line
6522
+ /generating\.\.\./i,
6523
+ /Claude is (?:thinking|processing|working)/i
6524
+ // Specific Claude Code status
6525
+ ];
6526
+ var FALLBACK_APPROVAL = [
6527
+ /Allow\s+once/i,
6528
+ /Always\s+allow/i,
6529
+ /\(y\/n\)/i,
6530
+ /\[Y\/n\]/i,
6531
+ /Run\s+this\s+command/i
6532
+ // NOTE: removed /Do you want to (?:run|execute|allow)/i — too broad, matches AI explanation
6533
+ // text like "Do you want to allow this feature?" causing false approval notifications.
6534
+ ];
6535
+ function defaultCleanOutput(raw, _lastUserInput) {
6536
+ return stripAnsi(raw).trim();
6537
+ }
6538
+ function normalizeCliProviderForRuntime(raw) {
6539
+ const patterns = raw?.patterns || {};
6540
+ return {
6541
+ ...raw,
6542
+ patterns: {
6543
+ prompt: coercePatternArray(patterns.prompt, FALLBACK_PROMPT),
6544
+ generating: coercePatternArray(patterns.generating, FALLBACK_GENERATING),
6545
+ approval: coercePatternArray(patterns.approval, FALLBACK_APPROVAL),
6546
+ ready: coercePatternArray(patterns.ready, [])
6547
+ },
6548
+ cleanOutput: typeof raw?.cleanOutput === "function" ? raw.cleanOutput : defaultCleanOutput
6549
+ };
6550
+ }
5934
6551
  var ProviderCliAdapter = class {
5935
6552
  constructor(provider, workingDir, extraArgs = []) {
5936
6553
  this.extraArgs = extraArgs;
5937
- this.provider = provider;
6554
+ this.provider = normalizeCliProviderForRuntime(provider);
5938
6555
  this.cliType = provider.type;
5939
6556
  this.cliName = provider.name;
5940
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os9.homedir()) : workingDir;
6557
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os11.homedir()) : workingDir;
5941
6558
  const t = provider.timeouts || {};
5942
6559
  this.timeouts = {
5943
6560
  ptyFlush: t.ptyFlush ?? 50,
@@ -5974,6 +6591,11 @@ var ProviderCliAdapter = class {
5974
6591
  logBuffer = [];
5975
6592
  // Approval cooldown
5976
6593
  lastApprovalResolvedAt = 0;
6594
+ // Approval state machine
6595
+ approvalTransitionBuffer = "";
6596
+ approvalExitTimeout = null;
6597
+ // Resize redraw suppression
6598
+ resizeSuppressUntil = 0;
5977
6599
  // Resolved timeouts (provider defaults + overrides)
5978
6600
  timeouts;
5979
6601
  // ─── Lifecycle ─────────────────────────────────
@@ -5995,20 +6617,25 @@ var ProviderCliAdapter = class {
5995
6617
  if (!pty) throw new Error("node-pty is not installed");
5996
6618
  const { spawn: spawnConfig } = this.provider;
5997
6619
  const binaryPath = findBinary(spawnConfig.command);
5998
- const isWin = os9.platform() === "win32";
6620
+ const isWin = os11.platform() === "win32";
5999
6621
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
6000
6622
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
6001
6623
  let shellCmd;
6002
6624
  let shellArgs;
6003
- if (spawnConfig.shell) {
6625
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
6626
+ const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
6627
+ if (useShell) {
6628
+ if (!spawnConfig.shell && !isWin) {
6629
+ LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
6630
+ }
6004
6631
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
6005
- const fullCmd = [binaryPath, ...allArgs].join(" ");
6632
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
6006
6633
  shellArgs = isWin ? ["/c", fullCmd] : ["-l", "-c", fullCmd];
6007
6634
  } else {
6008
6635
  shellCmd = binaryPath;
6009
6636
  shellArgs = allArgs;
6010
6637
  }
6011
- this.ptyProcess = pty.spawn(shellCmd, shellArgs, {
6638
+ const ptyOpts = {
6012
6639
  name: "xterm-256color",
6013
6640
  cols: 120,
6014
6641
  rows: 40,
@@ -6017,7 +6644,21 @@ var ProviderCliAdapter = class {
6017
6644
  ...process.env,
6018
6645
  ...spawnConfig.env
6019
6646
  }
6020
- });
6647
+ };
6648
+ try {
6649
+ this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
6650
+ } catch (err) {
6651
+ const msg = err?.message || String(err);
6652
+ if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
6653
+ LOG.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
6654
+ shellCmd = process.env.SHELL || "/bin/zsh";
6655
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
6656
+ shellArgs = ["-l", "-c", fullCmd];
6657
+ this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
6658
+ } else {
6659
+ throw err;
6660
+ }
6661
+ }
6021
6662
  this.ptyProcess.onData((data) => {
6022
6663
  this.handleOutput(data);
6023
6664
  if (this.onPtyDataCallback) {
@@ -6045,6 +6686,7 @@ var ProviderCliAdapter = class {
6045
6686
  }
6046
6687
  // ─── Output state machine ────────────────────────────
6047
6688
  handleOutput(rawData) {
6689
+ if (Date.now() < this.resizeSuppressUntil) return;
6048
6690
  const cleanData = stripAnsi(rawData);
6049
6691
  const { patterns } = this.provider;
6050
6692
  if (cleanData.trim()) {
@@ -6077,30 +6719,55 @@ var ProviderCliAdapter = class {
6077
6719
  const hasApproval = patterns.approval.some((p) => p.test(this.recentOutputBuffer));
6078
6720
  if (hasApproval && this.currentStatus !== "waiting_approval") {
6079
6721
  if (this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown) return;
6722
+ const ctxLines = this.recentOutputBuffer.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
6080
6723
  this.isWaitingForResponse = true;
6081
6724
  this.currentStatus = "waiting_approval";
6082
6725
  this.recentOutputBuffer = "";
6083
- const ctxLines = cleanData.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
6726
+ this.approvalTransitionBuffer = "";
6084
6727
  this.activeModal = {
6085
6728
  message: ctxLines.slice(-5).join(" ").slice(0, 200) || "Approval required",
6086
6729
  buttons: ["Allow once", "Always allow", "Deny"]
6087
6730
  };
6088
6731
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
6732
+ if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
6733
+ this.approvalExitTimeout = setTimeout(() => {
6734
+ if (this.currentStatus === "waiting_approval") {
6735
+ LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-exiting waiting_approval`);
6736
+ this.activeModal = null;
6737
+ this.lastApprovalResolvedAt = Date.now();
6738
+ this.recentOutputBuffer = "";
6739
+ this.approvalTransitionBuffer = "";
6740
+ this.approvalExitTimeout = null;
6741
+ this.currentStatus = this.isWaitingForResponse ? "generating" : "idle";
6742
+ this.onStatusChange?.();
6743
+ }
6744
+ }, 6e4);
6089
6745
  this.onStatusChange?.();
6090
6746
  return;
6091
6747
  }
6092
6748
  if (this.currentStatus === "waiting_approval") {
6093
- const genResume = patterns.generating.some((p) => p.test(cleanData));
6094
- const promptResume = patterns.prompt.some((p) => p.test(cleanData));
6749
+ this.approvalTransitionBuffer = (this.approvalTransitionBuffer + cleanData).slice(-500);
6750
+ const genResume = patterns.generating.some((p) => p.test(this.approvalTransitionBuffer));
6751
+ const promptResume = patterns.prompt.some((p) => p.test(this.approvalTransitionBuffer));
6095
6752
  if (genResume) {
6753
+ if (this.approvalExitTimeout) {
6754
+ clearTimeout(this.approvalExitTimeout);
6755
+ this.approvalExitTimeout = null;
6756
+ }
6096
6757
  this.currentStatus = "generating";
6097
6758
  this.activeModal = null;
6098
6759
  this.recentOutputBuffer = "";
6760
+ this.approvalTransitionBuffer = "";
6099
6761
  this.lastApprovalResolvedAt = Date.now();
6100
6762
  this.onStatusChange?.();
6101
6763
  } else if (promptResume) {
6764
+ if (this.approvalExitTimeout) {
6765
+ clearTimeout(this.approvalExitTimeout);
6766
+ this.approvalExitTimeout = null;
6767
+ }
6102
6768
  this.activeModal = null;
6103
6769
  this.recentOutputBuffer = "";
6770
+ this.approvalTransitionBuffer = "";
6104
6771
  this.lastApprovalResolvedAt = Date.now();
6105
6772
  this.finishResponse();
6106
6773
  }
@@ -6126,7 +6793,8 @@ var ProviderCliAdapter = class {
6126
6793
  this.onStatusChange?.();
6127
6794
  return;
6128
6795
  }
6129
- if (patterns.prompt.some((p) => p.test(this.responseBuffer))) {
6796
+ const trailingLines = cleanData.split("\n").slice(-2).join("\n");
6797
+ if (patterns.prompt.some((p) => p.test(trailingLines))) {
6130
6798
  this.finishResponse();
6131
6799
  } else {
6132
6800
  this.idleTimeout = setTimeout(() => {
@@ -6147,6 +6815,10 @@ var ProviderCliAdapter = class {
6147
6815
  clearTimeout(this.idleTimeout);
6148
6816
  this.idleTimeout = null;
6149
6817
  }
6818
+ if (this.approvalExitTimeout) {
6819
+ clearTimeout(this.approvalExitTimeout);
6820
+ this.approvalExitTimeout = null;
6821
+ }
6150
6822
  const lastUserText = this.messages.filter((m) => m.role === "user").pop()?.content;
6151
6823
  let response = this.provider.cleanOutput(this.responseBuffer, lastUserText);
6152
6824
  if (lastUserText && response) {
@@ -6196,6 +6868,10 @@ var ProviderCliAdapter = class {
6196
6868
  this.shutdown();
6197
6869
  }
6198
6870
  shutdown() {
6871
+ if (this.approvalExitTimeout) {
6872
+ clearTimeout(this.approvalExitTimeout);
6873
+ this.approvalExitTimeout = null;
6874
+ }
6199
6875
  if (this.ptyProcess) {
6200
6876
  this.ptyProcess.write("");
6201
6877
  setTimeout(() => {
@@ -6223,10 +6899,22 @@ var ProviderCliAdapter = class {
6223
6899
  writeRaw(data) {
6224
6900
  this.ptyProcess?.write(data);
6225
6901
  }
6902
+ /**
6903
+ * Resolve an approval modal by navigating to the button at `buttonIndex` and pressing Enter.
6904
+ * Index 0 = first option (already selected by default — just Enter).
6905
+ * Index N = press Arrow Down N times, then Enter.
6906
+ */
6907
+ resolveModal(buttonIndex) {
6908
+ if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
6909
+ const DOWN = "\x1B[B";
6910
+ const keys = DOWN.repeat(Math.max(0, buttonIndex)) + "\r";
6911
+ this.ptyProcess.write(keys);
6912
+ }
6226
6913
  resize(cols, rows) {
6227
6914
  if (this.ptyProcess) {
6228
6915
  try {
6229
6916
  this.ptyProcess.resize(cols, rows);
6917
+ this.resizeSuppressUntil = Date.now() + 300;
6230
6918
  } catch {
6231
6919
  }
6232
6920
  }
@@ -6235,6 +6923,7 @@ var ProviderCliAdapter = class {
6235
6923
 
6236
6924
  // src/commands/cli-manager.ts
6237
6925
  init_config();
6926
+ init_workspaces();
6238
6927
 
6239
6928
  // src/providers/cli-provider-instance.ts
6240
6929
  var crypto3 = __toESM(require("crypto"));
@@ -6350,20 +7039,24 @@ var CliProviderInstance = class {
6350
7039
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
6351
7040
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
6352
7041
  if (newStatus !== this.lastStatus) {
7042
+ LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
6353
7043
  if (this.lastStatus === "idle" && newStatus === "generating") {
6354
7044
  this.generatingStartedAt = now;
6355
7045
  this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now });
6356
7046
  } else if (newStatus === "waiting_approval") {
6357
7047
  if (!this.generatingStartedAt) this.generatingStartedAt = now;
7048
+ const modal = adapterStatus.activeModal;
7049
+ LOG.info("CLI", `[${this.type}] approval modal: "${modal?.message?.slice(0, 80) ?? "none"}"`);
6358
7050
  this.pushEvent({
6359
7051
  event: "agent:waiting_approval",
6360
7052
  chatTitle,
6361
7053
  timestamp: now,
6362
- modalMessage: adapterStatus.activeModal?.message,
6363
- modalButtons: adapterStatus.activeModal?.buttons
7054
+ modalMessage: modal?.message,
7055
+ modalButtons: modal?.buttons
6364
7056
  });
6365
7057
  } else if (newStatus === "idle" && (this.lastStatus === "generating" || this.lastStatus === "waiting_approval")) {
6366
7058
  const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
7059
+ LOG.info("CLI", `[${this.type}] completed in ${duration}s`);
6367
7060
  this.pushEvent({ event: "agent:generating_completed", chatTitle, duration, timestamp: now });
6368
7061
  this.generatingStartedAt = 0;
6369
7062
  } else if (newStatus === "stopped") {
@@ -6400,7 +7093,7 @@ var CliProviderInstance = class {
6400
7093
 
6401
7094
  // src/providers/acp-provider-instance.ts
6402
7095
  var import_stream = require("stream");
6403
- var import_child_process5 = require("child_process");
7096
+ var import_child_process6 = require("child_process");
6404
7097
  var import_sdk = require("@agentclientprotocol/sdk");
6405
7098
 
6406
7099
  // src/providers/contracts.ts
@@ -6721,7 +7414,7 @@ var AcpProviderInstance = class {
6721
7414
  this.errorMessage = null;
6722
7415
  this.errorReason = null;
6723
7416
  this.stderrBuffer = [];
6724
- this.process = (0, import_child_process5.spawn)(command, args, {
7417
+ this.process = (0, import_child_process6.spawn)(command, args, {
6725
7418
  cwd: this.workingDir,
6726
7419
  env,
6727
7420
  stdio: ["pipe", "pipe", "pipe"],
@@ -6825,13 +7518,13 @@ var AcpProviderInstance = class {
6825
7518
  }
6826
7519
  this.currentStatus = "waiting_approval";
6827
7520
  this.detectStatusTransition();
6828
- const approved = await new Promise((resolve5) => {
6829
- this.permissionResolvers.push(resolve5);
7521
+ const approved = await new Promise((resolve7) => {
7522
+ this.permissionResolvers.push(resolve7);
6830
7523
  setTimeout(() => {
6831
- const idx = this.permissionResolvers.indexOf(resolve5);
7524
+ const idx = this.permissionResolvers.indexOf(resolve7);
6832
7525
  if (idx >= 0) {
6833
7526
  this.permissionResolvers.splice(idx, 1);
6834
- resolve5(false);
7527
+ resolve7(false);
6835
7528
  }
6836
7529
  }, 3e5);
6837
7530
  });
@@ -7301,6 +7994,24 @@ var DaemonCliManager = class {
7301
7994
  const hash = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
7302
7995
  return `${cliType}_${hash}`;
7303
7996
  }
7997
+ persistRecentDir(cliType, dir) {
7998
+ try {
7999
+ const normalizedType = this.providerLoader.resolveAlias(cliType);
8000
+ const provider = this.providerLoader.getByAlias(cliType);
8001
+ const actKind = provider?.category === "acp" ? "acp" : "cli";
8002
+ let next = loadConfig();
8003
+ console.log(import_chalk.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
8004
+ const recent = next.recentCliWorkspaces || [];
8005
+ if (!recent.includes(dir)) {
8006
+ next = { ...next, recentCliWorkspaces: [dir, ...recent].slice(0, 10) };
8007
+ }
8008
+ next = appendWorkspaceActivity(next, dir, { kind: actKind, agentType: normalizedType });
8009
+ saveConfig(next);
8010
+ console.log(import_chalk.default.green(` \u2713 Recent workspace saved: ${dir}`));
8011
+ } catch (e) {
8012
+ console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
8013
+ }
8014
+ }
7304
8015
  createAdapter(cliType, workingDir, cliArgs) {
7305
8016
  const normalizedType = this.providerLoader.resolveAlias(cliType);
7306
8017
  const provider = this.providerLoader.getMeta(normalizedType);
@@ -7312,8 +8023,9 @@ var DaemonCliManager = class {
7312
8023
  }
7313
8024
  // ─── Session start/management ──────────────────────────────
7314
8025
  async startSession(cliType, workingDir, cliArgs, initialModel) {
7315
- const trimmed = (workingDir || os10.homedir()).trim();
7316
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path7.resolve(trimmed);
8026
+ const trimmed = (workingDir || "").trim();
8027
+ if (!trimmed) throw new Error("working directory required");
8028
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path10.resolve(trimmed);
7317
8029
  const normalizedType = this.providerLoader.resolveAlias(cliType);
7318
8030
  const provider = this.providerLoader.getByAlias(cliType);
7319
8031
  const key = crypto4.randomUUID();
@@ -7323,8 +8035,8 @@ var DaemonCliManager = class {
7323
8035
  const spawnCmd = provider.spawn?.command;
7324
8036
  if (spawnCmd) {
7325
8037
  try {
7326
- const { execSync: execSync6 } = require("child_process");
7327
- execSync6(`which ${spawnCmd}`, { stdio: "ignore" });
8038
+ const { execSync: execSync7 } = require("child_process");
8039
+ execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
7328
8040
  } catch {
7329
8041
  const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
7330
8042
  throw new Error(
@@ -7391,18 +8103,52 @@ ${installInfo}`
7391
8103
  const instanceManager = this.deps.getInstanceManager();
7392
8104
  if (provider && instanceManager) {
7393
8105
  const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key);
7394
- await instanceManager.addInstance(key, cliInstance, {
7395
- serverConn: this.deps.getServerConn(),
7396
- settings: {},
7397
- onPtyData: (data) => {
7398
- this.deps.getP2p()?.broadcastPtyOutput(key, data);
7399
- }
7400
- });
8106
+ try {
8107
+ await instanceManager.addInstance(key, cliInstance, {
8108
+ serverConn: this.deps.getServerConn(),
8109
+ settings: {},
8110
+ onPtyData: (data) => {
8111
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
8112
+ }
8113
+ });
8114
+ } catch (spawnErr) {
8115
+ LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
8116
+ instanceManager.removeInstance(key);
8117
+ throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
8118
+ }
7401
8119
  this.adapters.set(key, cliInstance.getAdapter());
7402
8120
  console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
8121
+ const checkStopped = setInterval(() => {
8122
+ try {
8123
+ const adapter = this.adapters.get(key);
8124
+ if (!adapter) {
8125
+ clearInterval(checkStopped);
8126
+ return;
8127
+ }
8128
+ const status = adapter.getStatus?.();
8129
+ if (status?.status === "stopped" || status?.status === "error") {
8130
+ clearInterval(checkStopped);
8131
+ setTimeout(() => {
8132
+ if (this.adapters.has(key)) {
8133
+ this.adapters.delete(key);
8134
+ this.deps.removeAgentTracking(key);
8135
+ instanceManager.removeInstance(key);
8136
+ LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${cliType}`);
8137
+ this.deps.onStatusChange();
8138
+ }
8139
+ }, 5e3);
8140
+ }
8141
+ } catch {
8142
+ }
8143
+ }, 3e3);
7403
8144
  } else {
7404
8145
  const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
7405
- await adapter.spawn();
8146
+ try {
8147
+ await adapter.spawn();
8148
+ } catch (spawnErr) {
8149
+ LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
8150
+ throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
8151
+ }
7406
8152
  const serverConn = this.deps.getServerConn();
7407
8153
  if (serverConn && typeof adapter.setServerConn === "function") {
7408
8154
  adapter.setServerConn(serverConn);
@@ -7410,12 +8156,12 @@ ${installInfo}`
7410
8156
  adapter.setOnStatusChange(() => {
7411
8157
  this.deps.onStatusChange();
7412
8158
  const status = adapter.getStatus?.();
7413
- if (status?.status === "stopped") {
8159
+ if (status?.status === "stopped" || status?.status === "error") {
7414
8160
  setTimeout(() => {
7415
8161
  if (this.adapters.get(key) === adapter) {
7416
8162
  this.adapters.delete(key);
7417
8163
  this.deps.removeAgentTracking(key);
7418
- console.log(import_chalk.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
8164
+ LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${adapter.cliType}`);
7419
8165
  this.deps.onStatusChange();
7420
8166
  }
7421
8167
  }, 3e3);
@@ -7439,12 +8185,24 @@ ${installInfo}`
7439
8185
  async stopSession(key) {
7440
8186
  const adapter = this.adapters.get(key);
7441
8187
  if (adapter) {
7442
- adapter.shutdown();
8188
+ try {
8189
+ adapter.shutdown();
8190
+ } catch (e) {
8191
+ LOG.warn("CLI", `Shutdown error for ${adapter.cliType}: ${e?.message} (force-cleaning)`);
8192
+ }
7443
8193
  this.adapters.delete(key);
7444
8194
  this.deps.removeAgentTracking(key);
7445
8195
  this.deps.getInstanceManager()?.removeInstance(key);
7446
- console.log(import_chalk.default.yellow(` \u{1F6D1} CLI Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`));
8196
+ LOG.info("CLI", `\u{1F6D1} Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
7447
8197
  this.deps.onStatusChange();
8198
+ } else {
8199
+ const im = this.deps.getInstanceManager();
8200
+ if (im) {
8201
+ im.removeInstance(key);
8202
+ this.deps.removeAgentTracking(key);
8203
+ LOG.warn("CLI", `\u{1F9F9} Force-removed orphan entry: ${key}`);
8204
+ this.deps.onStatusChange();
8205
+ }
7448
8206
  }
7449
8207
  }
7450
8208
  shutdownAll() {
@@ -7485,8 +8243,28 @@ ${installInfo}`
7485
8243
  switch (cmd) {
7486
8244
  case "launch_cli": {
7487
8245
  const cliType = args?.cliType;
7488
- const defaultedToHome = !args?.dir;
7489
- const dir = args?.dir || os10.homedir();
8246
+ const config = loadConfig();
8247
+ const resolved = resolveLaunchDirectory(
8248
+ {
8249
+ dir: args?.dir,
8250
+ workspaceId: args?.workspaceId,
8251
+ useDefaultWorkspace: args?.useDefaultWorkspace === true,
8252
+ useHome: args?.useHome === true
8253
+ },
8254
+ config
8255
+ );
8256
+ if (!resolved.ok) {
8257
+ const ws = getWorkspaceState(config);
8258
+ return {
8259
+ success: false,
8260
+ error: resolved.message,
8261
+ code: resolved.code,
8262
+ workspaces: ws.workspaces,
8263
+ defaultWorkspacePath: ws.defaultWorkspacePath
8264
+ };
8265
+ }
8266
+ const dir = resolved.path;
8267
+ const launchSource = resolved.source;
7490
8268
  if (!cliType) throw new Error("cliType required");
7491
8269
  await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
7492
8270
  let newKey = null;
@@ -7495,19 +8273,8 @@ ${installInfo}`
7495
8273
  newKey = k;
7496
8274
  }
7497
8275
  }
7498
- try {
7499
- const config = loadConfig();
7500
- console.log(import_chalk.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
7501
- const recent = config.recentCliWorkspaces || [];
7502
- if (!recent.includes(dir)) {
7503
- const updated = [dir, ...recent].slice(0, 10);
7504
- saveConfig({ ...config, recentCliWorkspaces: updated });
7505
- console.log(import_chalk.default.green(` \u2713 Recent workspace saved: ${dir}`));
7506
- }
7507
- } catch (e) {
7508
- console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
7509
- }
7510
- return { success: true, cliType, dir, id: newKey, defaultedToHome };
8276
+ this.persistRecentDir(cliType, dir);
8277
+ return { success: true, cliType, dir, id: newKey, launchSource };
7511
8278
  }
7512
8279
  case "stop_cli": {
7513
8280
  const cliType = args?.cliType;
@@ -7523,11 +8290,32 @@ ${installInfo}`
7523
8290
  }
7524
8291
  case "restart_session": {
7525
8292
  const cliType = args?.cliType || args?.agentType || args?.ideType;
7526
- const dir = args?.dir || process.cwd();
8293
+ const cfg = loadConfig();
8294
+ const rdir = resolveLaunchDirectory(
8295
+ {
8296
+ dir: args?.dir,
8297
+ workspaceId: args?.workspaceId,
8298
+ useDefaultWorkspace: args?.useDefaultWorkspace === true,
8299
+ useHome: args?.useHome === true
8300
+ },
8301
+ cfg
8302
+ );
8303
+ if (!rdir.ok) {
8304
+ const ws = getWorkspaceState(cfg);
8305
+ return {
8306
+ success: false,
8307
+ error: rdir.message,
8308
+ code: rdir.code,
8309
+ workspaces: ws.workspaces,
8310
+ defaultWorkspacePath: ws.defaultWorkspacePath
8311
+ };
8312
+ }
8313
+ const dir = rdir.path;
7527
8314
  if (!cliType) throw new Error("cliType required");
7528
8315
  const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
7529
8316
  if (found) await this.stopSession(found.key);
7530
8317
  await this.startSession(cliType, dir);
8318
+ this.persistRecentDir(cliType, dir);
7531
8319
  return { success: true, restarted: true };
7532
8320
  }
7533
8321
  case "agent_command": {
@@ -8167,12 +8955,12 @@ var ProviderInstanceManager = class {
8167
8955
  };
8168
8956
 
8169
8957
  // src/providers/version-archive.ts
8170
- var fs7 = __toESM(require("fs"));
8171
- var path8 = __toESM(require("path"));
8172
- var os11 = __toESM(require("os"));
8173
- var import_child_process6 = require("child_process");
8958
+ var fs8 = __toESM(require("fs"));
8959
+ var path11 = __toESM(require("path"));
8960
+ var os13 = __toESM(require("os"));
8961
+ var import_child_process7 = require("child_process");
8174
8962
  var import_os3 = require("os");
8175
- var ARCHIVE_PATH = path8.join(os11.homedir(), ".adhdev", "version-history.json");
8963
+ var ARCHIVE_PATH = path11.join(os13.homedir(), ".adhdev", "version-history.json");
8176
8964
  var MAX_ENTRIES_PER_PROVIDER = 20;
8177
8965
  var VersionArchive = class {
8178
8966
  history = {};
@@ -8181,8 +8969,8 @@ var VersionArchive = class {
8181
8969
  }
8182
8970
  load() {
8183
8971
  try {
8184
- if (fs7.existsSync(ARCHIVE_PATH)) {
8185
- this.history = JSON.parse(fs7.readFileSync(ARCHIVE_PATH, "utf-8"));
8972
+ if (fs8.existsSync(ARCHIVE_PATH)) {
8973
+ this.history = JSON.parse(fs8.readFileSync(ARCHIVE_PATH, "utf-8"));
8186
8974
  }
8187
8975
  } catch {
8188
8976
  this.history = {};
@@ -8219,15 +9007,15 @@ var VersionArchive = class {
8219
9007
  }
8220
9008
  save() {
8221
9009
  try {
8222
- fs7.mkdirSync(path8.dirname(ARCHIVE_PATH), { recursive: true });
8223
- fs7.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
9010
+ fs8.mkdirSync(path11.dirname(ARCHIVE_PATH), { recursive: true });
9011
+ fs8.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
8224
9012
  } catch {
8225
9013
  }
8226
9014
  }
8227
9015
  };
8228
9016
  function runCommand(cmd, timeout = 1e4) {
8229
9017
  try {
8230
- return (0, import_child_process6.execSync)(cmd, {
9018
+ return (0, import_child_process7.execSync)(cmd, {
8231
9019
  encoding: "utf-8",
8232
9020
  timeout,
8233
9021
  stdio: ["pipe", "pipe", "pipe"]
@@ -8259,19 +9047,19 @@ function getVersion(binary, versionCommand) {
8259
9047
  function checkPathExists2(paths) {
8260
9048
  for (const p of paths) {
8261
9049
  if (p.includes("*")) {
8262
- const home = os11.homedir();
8263
- const resolved = p.replace(/\*/g, home.split(path8.sep).pop() || "");
8264
- if (fs7.existsSync(resolved)) return resolved;
9050
+ const home = os13.homedir();
9051
+ const resolved = p.replace(/\*/g, home.split(path11.sep).pop() || "");
9052
+ if (fs8.existsSync(resolved)) return resolved;
8265
9053
  } else {
8266
- if (fs7.existsSync(p)) return p;
9054
+ if (fs8.existsSync(p)) return p;
8267
9055
  }
8268
9056
  }
8269
9057
  return null;
8270
9058
  }
8271
9059
  function getMacAppVersion(appPath) {
8272
9060
  if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
8273
- const plistPath = path8.join(appPath, "Contents", "Info.plist");
8274
- if (!fs7.existsSync(plistPath)) return null;
9061
+ const plistPath = path11.join(appPath, "Contents", "Info.plist");
9062
+ if (!fs8.existsSync(plistPath)) return null;
8275
9063
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
8276
9064
  return raw || null;
8277
9065
  }
@@ -8296,8 +9084,8 @@ async function detectAllVersions(loader, archive) {
8296
9084
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
8297
9085
  let resolvedBin = cliBin;
8298
9086
  if (!resolvedBin && appPath && currentOs === "darwin") {
8299
- const bundled = path8.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
8300
- if (provider.cli && fs7.existsSync(bundled)) resolvedBin = bundled;
9087
+ const bundled = path11.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
9088
+ if (provider.cli && fs8.existsSync(bundled)) resolvedBin = bundled;
8301
9089
  }
8302
9090
  info.installed = !!(appPath || resolvedBin);
8303
9091
  info.path = appPath || null;
@@ -8336,9 +9124,9 @@ async function detectAllVersions(loader, archive) {
8336
9124
 
8337
9125
  // src/daemon/dev-server.ts
8338
9126
  var http2 = __toESM(require("http"));
8339
- var fs8 = __toESM(require("fs"));
8340
- var path9 = __toESM(require("path"));
8341
- var os12 = __toESM(require("os"));
9127
+ var fs9 = __toESM(require("fs"));
9128
+ var path12 = __toESM(require("path"));
9129
+ var os14 = __toESM(require("os"));
8342
9130
 
8343
9131
  // src/daemon/scaffold-template.ts
8344
9132
  function generateFiles(type, name, category, opts = {}) {
@@ -8741,8 +9529,8 @@ var DevServer = class _DevServer {
8741
9529
  }
8742
9530
  getEndpointList() {
8743
9531
  return this.routes.map((r) => {
8744
- const path10 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
8745
- return `${r.method.padEnd(5)} ${path10}`;
9532
+ const path13 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
9533
+ return `${r.method.padEnd(5)} ${path13}`;
8746
9534
  });
8747
9535
  }
8748
9536
  async start(port = DEV_SERVER_PORT) {
@@ -8773,15 +9561,15 @@ var DevServer = class _DevServer {
8773
9561
  this.json(res, 500, { error: e.message });
8774
9562
  }
8775
9563
  });
8776
- return new Promise((resolve5, reject) => {
9564
+ return new Promise((resolve7, reject) => {
8777
9565
  this.server.listen(port, "127.0.0.1", () => {
8778
9566
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
8779
- resolve5();
9567
+ resolve7();
8780
9568
  });
8781
9569
  this.server.on("error", (e) => {
8782
9570
  if (e.code === "EADDRINUSE") {
8783
9571
  this.log(`Port ${port} in use, skipping dev server`);
8784
- resolve5();
9572
+ resolve7();
8785
9573
  } else {
8786
9574
  reject(e);
8787
9575
  }
@@ -8864,20 +9652,20 @@ var DevServer = class _DevServer {
8864
9652
  child.stderr?.on("data", (d) => {
8865
9653
  stderr += d.toString().slice(0, 2e3);
8866
9654
  });
8867
- await new Promise((resolve5) => {
9655
+ await new Promise((resolve7) => {
8868
9656
  const timer = setTimeout(() => {
8869
9657
  child.kill();
8870
- resolve5();
9658
+ resolve7();
8871
9659
  }, 3e3);
8872
9660
  child.on("exit", () => {
8873
9661
  clearTimeout(timer);
8874
- resolve5();
9662
+ resolve7();
8875
9663
  });
8876
9664
  child.stdout?.once("data", () => {
8877
9665
  setTimeout(() => {
8878
9666
  child.kill();
8879
9667
  clearTimeout(timer);
8880
- resolve5();
9668
+ resolve7();
8881
9669
  }, 500);
8882
9670
  });
8883
9671
  });
@@ -9087,12 +9875,12 @@ var DevServer = class _DevServer {
9087
9875
  // ─── DevConsole SPA ───
9088
9876
  getConsoleDistDir() {
9089
9877
  const candidates = [
9090
- path9.resolve(__dirname, "../../web-devconsole/dist"),
9091
- path9.resolve(__dirname, "../../../web-devconsole/dist"),
9092
- path9.join(process.cwd(), "packages/web-devconsole/dist")
9878
+ path12.resolve(__dirname, "../../web-devconsole/dist"),
9879
+ path12.resolve(__dirname, "../../../web-devconsole/dist"),
9880
+ path12.join(process.cwd(), "packages/web-devconsole/dist")
9093
9881
  ];
9094
9882
  for (const dir of candidates) {
9095
- if (fs8.existsSync(path9.join(dir, "index.html"))) return dir;
9883
+ if (fs9.existsSync(path12.join(dir, "index.html"))) return dir;
9096
9884
  }
9097
9885
  return null;
9098
9886
  }
@@ -9102,9 +9890,9 @@ var DevServer = class _DevServer {
9102
9890
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
9103
9891
  return;
9104
9892
  }
9105
- const htmlPath = path9.join(distDir, "index.html");
9893
+ const htmlPath = path12.join(distDir, "index.html");
9106
9894
  try {
9107
- const html = fs8.readFileSync(htmlPath, "utf-8");
9895
+ const html = fs9.readFileSync(htmlPath, "utf-8");
9108
9896
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
9109
9897
  res.end(html);
9110
9898
  } catch (e) {
@@ -9127,15 +9915,15 @@ var DevServer = class _DevServer {
9127
9915
  this.json(res, 404, { error: "Not found" });
9128
9916
  return;
9129
9917
  }
9130
- const safePath = path9.normalize(pathname).replace(/^\.\.\//, "");
9131
- const filePath = path9.join(distDir, safePath);
9918
+ const safePath = path12.normalize(pathname).replace(/^\.\.\//, "");
9919
+ const filePath = path12.join(distDir, safePath);
9132
9920
  if (!filePath.startsWith(distDir)) {
9133
9921
  this.json(res, 403, { error: "Forbidden" });
9134
9922
  return;
9135
9923
  }
9136
9924
  try {
9137
- const content = fs8.readFileSync(filePath);
9138
- const ext = path9.extname(filePath);
9925
+ const content = fs9.readFileSync(filePath);
9926
+ const ext = path12.extname(filePath);
9139
9927
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
9140
9928
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
9141
9929
  res.end(content);
@@ -9234,26 +10022,26 @@ var DevServer = class _DevServer {
9234
10022
  const provider = this.providerLoader.getMeta(type);
9235
10023
  if (!provider) return null;
9236
10024
  const cat = provider.category;
9237
- const builtinDir = this.providerLoader.builtinDir || path9.resolve(__dirname, "../providers/_builtin");
9238
- const userDir = path9.join(os12.homedir(), ".adhdev", "providers");
10025
+ const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
10026
+ const userDir = path12.join(os14.homedir(), ".adhdev", "providers");
9239
10027
  const directCandidates = [
9240
- path9.join(userDir, type),
9241
- path9.join(builtinDir, cat, type),
9242
- path9.join(builtinDir, type)
10028
+ path12.join(userDir, type),
10029
+ path12.join(builtinDir, cat, type),
10030
+ path12.join(builtinDir, type)
9243
10031
  ];
9244
10032
  for (const d of directCandidates) {
9245
- if (fs8.existsSync(path9.join(d, "provider.json"))) return d;
10033
+ if (fs9.existsSync(path12.join(d, "provider.json"))) return d;
9246
10034
  }
9247
- const catDir = path9.join(builtinDir, cat);
9248
- if (fs8.existsSync(catDir)) {
10035
+ const catDir = path12.join(builtinDir, cat);
10036
+ if (fs9.existsSync(catDir)) {
9249
10037
  try {
9250
- for (const entry of fs8.readdirSync(catDir, { withFileTypes: true })) {
10038
+ for (const entry of fs9.readdirSync(catDir, { withFileTypes: true })) {
9251
10039
  if (!entry.isDirectory()) continue;
9252
- const jsonPath = path9.join(catDir, entry.name, "provider.json");
9253
- if (fs8.existsSync(jsonPath)) {
10040
+ const jsonPath = path12.join(catDir, entry.name, "provider.json");
10041
+ if (fs9.existsSync(jsonPath)) {
9254
10042
  try {
9255
- const data = JSON.parse(fs8.readFileSync(jsonPath, "utf-8"));
9256
- if (data.type === type) return path9.join(catDir, entry.name);
10043
+ const data = JSON.parse(fs9.readFileSync(jsonPath, "utf-8"));
10044
+ if (data.type === type) return path12.join(catDir, entry.name);
9257
10045
  } catch {
9258
10046
  }
9259
10047
  }
@@ -9273,14 +10061,14 @@ var DevServer = class _DevServer {
9273
10061
  const files = [];
9274
10062
  const scan = (d, prefix) => {
9275
10063
  try {
9276
- for (const entry of fs8.readdirSync(d, { withFileTypes: true })) {
10064
+ for (const entry of fs9.readdirSync(d, { withFileTypes: true })) {
9277
10065
  if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
9278
10066
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
9279
10067
  if (entry.isDirectory()) {
9280
10068
  files.push({ path: rel, size: 0, type: "dir" });
9281
- scan(path9.join(d, entry.name), rel);
10069
+ scan(path12.join(d, entry.name), rel);
9282
10070
  } else {
9283
- const stat = fs8.statSync(path9.join(d, entry.name));
10071
+ const stat = fs9.statSync(path12.join(d, entry.name));
9284
10072
  files.push({ path: rel, size: stat.size, type: "file" });
9285
10073
  }
9286
10074
  }
@@ -9303,16 +10091,16 @@ var DevServer = class _DevServer {
9303
10091
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
9304
10092
  return;
9305
10093
  }
9306
- const fullPath = path9.resolve(dir, path9.normalize(filePath));
10094
+ const fullPath = path12.resolve(dir, path12.normalize(filePath));
9307
10095
  if (!fullPath.startsWith(dir)) {
9308
10096
  this.json(res, 403, { error: "Forbidden" });
9309
10097
  return;
9310
10098
  }
9311
- if (!fs8.existsSync(fullPath) || fs8.statSync(fullPath).isDirectory()) {
10099
+ if (!fs9.existsSync(fullPath) || fs9.statSync(fullPath).isDirectory()) {
9312
10100
  this.json(res, 404, { error: `File not found: ${filePath}` });
9313
10101
  return;
9314
10102
  }
9315
- const content = fs8.readFileSync(fullPath, "utf-8");
10103
+ const content = fs9.readFileSync(fullPath, "utf-8");
9316
10104
  this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
9317
10105
  }
9318
10106
  /** POST /api/providers/:type/file — write a file { path, content } */
@@ -9328,15 +10116,15 @@ var DevServer = class _DevServer {
9328
10116
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
9329
10117
  return;
9330
10118
  }
9331
- const fullPath = path9.resolve(dir, path9.normalize(filePath));
10119
+ const fullPath = path12.resolve(dir, path12.normalize(filePath));
9332
10120
  if (!fullPath.startsWith(dir)) {
9333
10121
  this.json(res, 403, { error: "Forbidden" });
9334
10122
  return;
9335
10123
  }
9336
10124
  try {
9337
- if (fs8.existsSync(fullPath)) fs8.copyFileSync(fullPath, fullPath + ".bak");
9338
- fs8.mkdirSync(path9.dirname(fullPath), { recursive: true });
9339
- fs8.writeFileSync(fullPath, content, "utf-8");
10125
+ if (fs9.existsSync(fullPath)) fs9.copyFileSync(fullPath, fullPath + ".bak");
10126
+ fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
10127
+ fs9.writeFileSync(fullPath, content, "utf-8");
9340
10128
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
9341
10129
  this.providerLoader.reload();
9342
10130
  this.json(res, 200, { saved: true, path: filePath, chars: content.length });
@@ -9352,9 +10140,9 @@ var DevServer = class _DevServer {
9352
10140
  return;
9353
10141
  }
9354
10142
  for (const name of ["scripts.js", "provider.json"]) {
9355
- const p = path9.join(dir, name);
9356
- if (fs8.existsSync(p)) {
9357
- const source = fs8.readFileSync(p, "utf-8");
10143
+ const p = path12.join(dir, name);
10144
+ if (fs9.existsSync(p)) {
10145
+ const source = fs9.readFileSync(p, "utf-8");
9358
10146
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
9359
10147
  return;
9360
10148
  }
@@ -9373,11 +10161,11 @@ var DevServer = class _DevServer {
9373
10161
  this.json(res, 404, { error: `Provider not found: ${type}` });
9374
10162
  return;
9375
10163
  }
9376
- const target = fs8.existsSync(path9.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
9377
- const targetPath = path9.join(dir, target);
10164
+ const target = fs9.existsSync(path12.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
10165
+ const targetPath = path12.join(dir, target);
9378
10166
  try {
9379
- if (fs8.existsSync(targetPath)) fs8.copyFileSync(targetPath, targetPath + ".bak");
9380
- fs8.writeFileSync(targetPath, source, "utf-8");
10167
+ if (fs9.existsSync(targetPath)) fs9.copyFileSync(targetPath, targetPath + ".bak");
10168
+ fs9.writeFileSync(targetPath, source, "utf-8");
9381
10169
  this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
9382
10170
  this.providerLoader.reload();
9383
10171
  this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
@@ -9392,18 +10180,18 @@ var DevServer = class _DevServer {
9392
10180
  return;
9393
10181
  }
9394
10182
  let scriptsPath = "";
9395
- const directScripts = path9.join(dir, "scripts.js");
9396
- if (fs8.existsSync(directScripts)) {
10183
+ const directScripts = path12.join(dir, "scripts.js");
10184
+ if (fs9.existsSync(directScripts)) {
9397
10185
  scriptsPath = directScripts;
9398
10186
  } else {
9399
- const scriptsDir = path9.join(dir, "scripts");
9400
- if (fs8.existsSync(scriptsDir)) {
9401
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
9402
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
10187
+ const scriptsDir = path12.join(dir, "scripts");
10188
+ if (fs9.existsSync(scriptsDir)) {
10189
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
10190
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
9403
10191
  }).sort().reverse();
9404
10192
  for (const ver of versions) {
9405
- const p = path9.join(scriptsDir, ver, "scripts.js");
9406
- if (fs8.existsSync(p)) {
10193
+ const p = path12.join(scriptsDir, ver, "scripts.js");
10194
+ if (fs9.existsSync(p)) {
9407
10195
  scriptsPath = p;
9408
10196
  break;
9409
10197
  }
@@ -9415,7 +10203,7 @@ var DevServer = class _DevServer {
9415
10203
  return;
9416
10204
  }
9417
10205
  try {
9418
- const source = fs8.readFileSync(scriptsPath, "utf-8");
10206
+ const source = fs9.readFileSync(scriptsPath, "utf-8");
9419
10207
  const hints = {};
9420
10208
  const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
9421
10209
  let match;
@@ -9559,14 +10347,14 @@ var DevServer = class _DevServer {
9559
10347
  child.stderr?.on("data", (d) => {
9560
10348
  stderr += d.toString();
9561
10349
  });
9562
- await new Promise((resolve5) => {
10350
+ await new Promise((resolve7) => {
9563
10351
  const timer = setTimeout(() => {
9564
10352
  child.kill();
9565
- resolve5();
10353
+ resolve7();
9566
10354
  }, timeout);
9567
10355
  child.on("exit", () => {
9568
10356
  clearTimeout(timer);
9569
- resolve5();
10357
+ resolve7();
9570
10358
  });
9571
10359
  });
9572
10360
  const elapsed = Date.now() - start;
@@ -9616,26 +10404,26 @@ var DevServer = class _DevServer {
9616
10404
  }
9617
10405
  let targetDir;
9618
10406
  if (location === "user") {
9619
- targetDir = path9.join(os12.homedir(), ".adhdev", "providers", type);
10407
+ targetDir = path12.join(os14.homedir(), ".adhdev", "providers", type);
9620
10408
  } else {
9621
- const builtinDir = path9.resolve(__dirname, "../providers/_builtin");
9622
- targetDir = path9.join(builtinDir, category, type);
10409
+ const builtinDir = path12.resolve(__dirname, "../providers/_builtin");
10410
+ targetDir = path12.join(builtinDir, category, type);
9623
10411
  }
9624
- const jsonPath = path9.join(targetDir, "provider.json");
9625
- if (fs8.existsSync(jsonPath)) {
10412
+ const jsonPath = path12.join(targetDir, "provider.json");
10413
+ if (fs9.existsSync(jsonPath)) {
9626
10414
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
9627
10415
  return;
9628
10416
  }
9629
10417
  try {
9630
10418
  const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version });
9631
- fs8.mkdirSync(targetDir, { recursive: true });
9632
- fs8.writeFileSync(jsonPath, result["provider.json"], "utf-8");
10419
+ fs9.mkdirSync(targetDir, { recursive: true });
10420
+ fs9.writeFileSync(jsonPath, result["provider.json"], "utf-8");
9633
10421
  const createdFiles = ["provider.json"];
9634
10422
  if (result.files) {
9635
10423
  for (const [relPath, content] of Object.entries(result.files)) {
9636
- const fullPath = path9.join(targetDir, relPath);
9637
- fs8.mkdirSync(path9.dirname(fullPath), { recursive: true });
9638
- fs8.writeFileSync(fullPath, content, "utf-8");
10424
+ const fullPath = path12.join(targetDir, relPath);
10425
+ fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
10426
+ fs9.writeFileSync(fullPath, content, "utf-8");
9639
10427
  createdFiles.push(relPath);
9640
10428
  }
9641
10429
  }
@@ -10470,24 +11258,24 @@ var DevServer = class _DevServer {
10470
11258
  }
10471
11259
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
10472
11260
  let referenceScripts = {};
10473
- const builtinDir = this.providerLoader.builtinDir || path9.resolve(__dirname, "../providers/_builtin");
10474
- const refDir = path9.join(builtinDir, "ide", reference);
10475
- if (fs8.existsSync(refDir)) {
10476
- const scriptsDir = path9.join(refDir, "scripts");
10477
- if (fs8.existsSync(scriptsDir)) {
10478
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
11261
+ const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
11262
+ const refDir = path12.join(builtinDir, "ide", reference);
11263
+ if (fs9.existsSync(refDir)) {
11264
+ const scriptsDir = path12.join(refDir, "scripts");
11265
+ if (fs9.existsSync(scriptsDir)) {
11266
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
10479
11267
  try {
10480
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
11268
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
10481
11269
  } catch {
10482
11270
  return false;
10483
11271
  }
10484
11272
  }).sort().reverse();
10485
11273
  if (versions.length > 0) {
10486
- const latestDir = path9.join(scriptsDir, versions[0]);
10487
- for (const file of fs8.readdirSync(latestDir)) {
11274
+ const latestDir = path12.join(scriptsDir, versions[0]);
11275
+ for (const file of fs9.readdirSync(latestDir)) {
10488
11276
  if (file.endsWith(".js")) {
10489
11277
  try {
10490
- referenceScripts[file] = fs8.readFileSync(path9.join(latestDir, file), "utf-8");
11278
+ referenceScripts[file] = fs9.readFileSync(path12.join(latestDir, file), "utf-8");
10491
11279
  } catch {
10492
11280
  }
10493
11281
  }
@@ -10496,16 +11284,16 @@ var DevServer = class _DevServer {
10496
11284
  }
10497
11285
  }
10498
11286
  const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts);
10499
- const tmpDir = path9.join(os12.tmpdir(), "adhdev-autoimpl");
10500
- if (!fs8.existsSync(tmpDir)) fs8.mkdirSync(tmpDir, { recursive: true });
10501
- const promptFile = path9.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
10502
- fs8.writeFileSync(promptFile, prompt, "utf-8");
11287
+ const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
11288
+ if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
11289
+ const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
11290
+ fs9.writeFileSync(promptFile, prompt, "utf-8");
10503
11291
  this.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
10504
11292
  const agentProvider = this.providerLoader.resolve(agent) || this.providerLoader.getMeta(agent);
10505
11293
  const spawn3 = agentProvider?.spawn;
10506
11294
  if (!spawn3?.command) {
10507
11295
  try {
10508
- fs8.unlinkSync(promptFile);
11296
+ fs9.unlinkSync(promptFile);
10509
11297
  } catch {
10510
11298
  }
10511
11299
  this.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
@@ -10606,7 +11394,7 @@ var DevServer = class _DevServer {
10606
11394
  } catch {
10607
11395
  }
10608
11396
  try {
10609
- fs8.unlinkSync(promptFile);
11397
+ fs9.unlinkSync(promptFile);
10610
11398
  } catch {
10611
11399
  }
10612
11400
  this.log(`Auto-implement (ACP) ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -10662,12 +11450,12 @@ var DevServer = class _DevServer {
10662
11450
  } else {
10663
11451
  args = [...baseArgs];
10664
11452
  }
10665
- const { execSync: execSync6 } = await import("child_process");
11453
+ const { execSync: execSync7 } = await import("child_process");
10666
11454
  try {
10667
- execSync6(`which ${command}`, { stdio: "pipe" });
11455
+ execSync7(`which ${command}`, { stdio: "pipe" });
10668
11456
  } catch {
10669
11457
  try {
10670
- fs8.unlinkSync(promptFile);
11458
+ fs9.unlinkSync(promptFile);
10671
11459
  } catch {
10672
11460
  }
10673
11461
  this.json(res, 400, { error: `Agent binary '${command}' not found on PATH. Install it first: ${agentProvider?.install || "check provider docs"}` });
@@ -10723,7 +11511,7 @@ var DevServer = class _DevServer {
10723
11511
  } catch {
10724
11512
  }
10725
11513
  try {
10726
- fs8.unlinkSync(promptFile);
11514
+ fs9.unlinkSync(promptFile);
10727
11515
  } catch {
10728
11516
  }
10729
11517
  this.log(`Auto-implement ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -10753,23 +11541,23 @@ var DevServer = class _DevServer {
10753
11541
  lines.push("## Current Target Files");
10754
11542
  lines.push("These are the files you need to EDIT. They contain TODO stubs \u2014 replace them with working implementations.");
10755
11543
  lines.push("");
10756
- const scriptsDir = path9.join(providerDir, "scripts");
10757
- if (fs8.existsSync(scriptsDir)) {
10758
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
11544
+ const scriptsDir = path12.join(providerDir, "scripts");
11545
+ if (fs9.existsSync(scriptsDir)) {
11546
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
10759
11547
  try {
10760
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
11548
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
10761
11549
  } catch {
10762
11550
  return false;
10763
11551
  }
10764
11552
  }).sort().reverse();
10765
11553
  if (versions.length > 0) {
10766
- const vDir = path9.join(scriptsDir, versions[0]);
11554
+ const vDir = path12.join(scriptsDir, versions[0]);
10767
11555
  lines.push(`Scripts version directory: \`${vDir}\``);
10768
11556
  lines.push("");
10769
- for (const file of fs8.readdirSync(vDir)) {
11557
+ for (const file of fs9.readdirSync(vDir)) {
10770
11558
  if (file.endsWith(".js")) {
10771
11559
  try {
10772
- const content = fs8.readFileSync(path9.join(vDir, file), "utf-8");
11560
+ const content = fs9.readFileSync(path12.join(vDir, file), "utf-8");
10773
11561
  lines.push(`### \`${file}\``);
10774
11562
  lines.push("```javascript");
10775
11563
  lines.push(content);
@@ -10840,7 +11628,7 @@ var DevServer = class _DevServer {
10840
11628
  lines.push("## Required Return Format");
10841
11629
  lines.push("| Function | Return JSON |");
10842
11630
  lines.push("|---|---|");
10843
- lines.push("| readChat | `{ id, status, title, messages: [{role, content, index}], inputContent, activeModal }` |");
11631
+ lines.push("| readChat | `{ id, status, title, messages: [{role, content, index, kind?, meta?}], inputContent, activeModal }` \u2014 optional `kind`: standard, thought, tool, terminal; optional `meta`: e.g. `{ label, isRunning }` for dashboard |");
10844
11632
  lines.push("| sendMessage | `{ sent: false, needsTypeAndSend: true, selector }` |");
10845
11633
  lines.push("| resolveAction | `{ resolved: true/false, clicked? }` |");
10846
11634
  lines.push("| listSessions | `{ sessions: [{ id, title, active, index }] }` |");
@@ -10964,14 +11752,14 @@ data: ${JSON.stringify(msg.data)}
10964
11752
  res.end(JSON.stringify(data, null, 2));
10965
11753
  }
10966
11754
  async readBody(req) {
10967
- return new Promise((resolve5) => {
11755
+ return new Promise((resolve7) => {
10968
11756
  let body = "";
10969
11757
  req.on("data", (chunk) => body += chunk);
10970
11758
  req.on("end", () => {
10971
11759
  try {
10972
- resolve5(JSON.parse(body));
11760
+ resolve7(JSON.parse(body));
10973
11761
  } catch {
10974
- resolve5({});
11762
+ resolve7({});
10975
11763
  }
10976
11764
  });
10977
11765
  });
@@ -10979,7 +11767,7 @@ data: ${JSON.stringify(msg.data)}
10979
11767
  };
10980
11768
 
10981
11769
  // src/installer.ts
10982
- var import_child_process7 = require("child_process");
11770
+ var import_child_process8 = require("child_process");
10983
11771
  var EXTENSION_CATALOG = [
10984
11772
  // AI Agent extensions
10985
11773
  {
@@ -11056,7 +11844,7 @@ var EXTENSION_CATALOG = [
11056
11844
  function isExtensionInstalled(ide, marketplaceId) {
11057
11845
  if (!ide.cliCommand) return false;
11058
11846
  try {
11059
- const result = (0, import_child_process7.execSync)(`"${ide.cliCommand}" --list-extensions`, {
11847
+ const result = (0, import_child_process8.execSync)(`"${ide.cliCommand}" --list-extensions`, {
11060
11848
  encoding: "utf-8",
11061
11849
  timeout: 15e3,
11062
11850
  stdio: ["pipe", "pipe", "pipe"]
@@ -11093,12 +11881,12 @@ async function installExtension(ide, extension) {
11093
11881
  const res = await fetch(extension.vsixUrl);
11094
11882
  if (res.ok) {
11095
11883
  const buffer = Buffer.from(await res.arrayBuffer());
11096
- const fs9 = await import("fs");
11097
- fs9.writeFileSync(vsixPath, buffer);
11098
- return new Promise((resolve5) => {
11884
+ const fs10 = await import("fs");
11885
+ fs10.writeFileSync(vsixPath, buffer);
11886
+ return new Promise((resolve7) => {
11099
11887
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
11100
- (0, import_child_process7.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
11101
- resolve5({
11888
+ (0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
11889
+ resolve7({
11102
11890
  extensionId: extension.id,
11103
11891
  marketplaceId: extension.marketplaceId,
11104
11892
  success: !error,
@@ -11111,11 +11899,11 @@ async function installExtension(ide, extension) {
11111
11899
  } catch (e) {
11112
11900
  }
11113
11901
  }
11114
- return new Promise((resolve5) => {
11902
+ return new Promise((resolve7) => {
11115
11903
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
11116
- (0, import_child_process7.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
11904
+ (0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
11117
11905
  if (error) {
11118
- resolve5({
11906
+ resolve7({
11119
11907
  extensionId: extension.id,
11120
11908
  marketplaceId: extension.marketplaceId,
11121
11909
  success: false,
@@ -11123,7 +11911,7 @@ async function installExtension(ide, extension) {
11123
11911
  error: stderr || error.message
11124
11912
  });
11125
11913
  } else {
11126
- resolve5({
11914
+ resolve7({
11127
11915
  extensionId: extension.id,
11128
11916
  marketplaceId: extension.marketplaceId,
11129
11917
  success: true,
@@ -11150,7 +11938,7 @@ function launchIDE(ide, workspacePath) {
11150
11938
  if (!ide.cliCommand) return false;
11151
11939
  try {
11152
11940
  const args = workspacePath ? `"${workspacePath}"` : "";
11153
- (0, import_child_process7.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
11941
+ (0, import_child_process8.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
11154
11942
  return true;
11155
11943
  } catch {
11156
11944
  return false;
@@ -11315,9 +12103,12 @@ async function shutdownDaemonComponents(components) {
11315
12103
  detectIDEs,
11316
12104
  getAIExtensions,
11317
12105
  getAvailableIdeIds,
12106
+ getHostMemorySnapshot,
11318
12107
  getLogLevel,
11319
12108
  getRecentCommands,
11320
12109
  getRecentLogs,
12110
+ getWorkspaceActivity,
12111
+ getWorkspaceState,
11321
12112
  initDaemonComponents,
11322
12113
  installExtensions,
11323
12114
  installGlobalInterceptor,