@adhdev/daemon-core 0.5.3 → 0.5.5

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 (43) hide show
  1. package/dist/index.d.ts +79 -2
  2. package/dist/index.js +1131 -433
  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 +167 -7
  30. package/src/commands/cli-manager.ts +128 -30
  31. package/src/commands/handler.ts +47 -3
  32. package/src/commands/router.ts +32 -2
  33. package/src/commands/workspace-commands.ts +108 -0
  34. package/src/config/config.ts +29 -1
  35. package/src/config/workspace-activity.ts +65 -0
  36. package/src/config/workspaces.ts +250 -0
  37. package/src/daemon/dev-server.ts +1 -1
  38. package/src/index.ts +5 -0
  39. package/src/launch.ts +1 -1
  40. package/src/providers/ide-provider-instance.ts +11 -0
  41. package/src/status/reporter.ts +23 -4
  42. package/src/system/host-memory.ts +65 -0
  43. 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) {
@@ -3360,9 +3654,9 @@ async function handleResolveAction(h, args) {
3360
3654
  }
3361
3655
 
3362
3656
  // src/commands/cdp-commands.ts
3363
- var fs3 = __toESM(require("fs"));
3364
- var path3 = __toESM(require("path"));
3365
- var os4 = __toESM(require("os"));
3657
+ var fs4 = __toESM(require("fs"));
3658
+ var path5 = __toESM(require("path"));
3659
+ var os6 = __toESM(require("os"));
3366
3660
  async function handleCdpEval(h, args) {
3367
3661
  if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
3368
3662
  const expression = args?.expression || args?.script;
@@ -3514,21 +3808,21 @@ async function handleDiscoverAgents(h, args) {
3514
3808
  return { success: true, agents };
3515
3809
  }
3516
3810
  function resolveSafePath(requestedPath) {
3517
- const home = os4.homedir();
3811
+ const home = os6.homedir();
3518
3812
  let resolved;
3519
3813
  if (requestedPath.startsWith("~")) {
3520
- resolved = path3.join(home, requestedPath.slice(1));
3521
- } else if (path3.isAbsolute(requestedPath)) {
3814
+ resolved = path5.join(home, requestedPath.slice(1));
3815
+ } else if (path5.isAbsolute(requestedPath)) {
3522
3816
  resolved = requestedPath;
3523
3817
  } else {
3524
- resolved = path3.resolve(requestedPath);
3818
+ resolved = path5.resolve(requestedPath);
3525
3819
  }
3526
3820
  return resolved;
3527
3821
  }
3528
3822
  async function handleFileRead(h, args) {
3529
3823
  try {
3530
3824
  const filePath = resolveSafePath(args?.path);
3531
- const content = fs3.readFileSync(filePath, "utf-8");
3825
+ const content = fs4.readFileSync(filePath, "utf-8");
3532
3826
  return { success: true, content, path: filePath };
3533
3827
  } catch (e) {
3534
3828
  return { success: false, error: e.message };
@@ -3537,8 +3831,8 @@ async function handleFileRead(h, args) {
3537
3831
  async function handleFileWrite(h, args) {
3538
3832
  try {
3539
3833
  const filePath = resolveSafePath(args?.path);
3540
- fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
3541
- fs3.writeFileSync(filePath, args?.content || "", "utf-8");
3834
+ fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
3835
+ fs4.writeFileSync(filePath, args?.content || "", "utf-8");
3542
3836
  return { success: true, path: filePath };
3543
3837
  } catch (e) {
3544
3838
  return { success: false, error: e.message };
@@ -3547,11 +3841,11 @@ async function handleFileWrite(h, args) {
3547
3841
  async function handleFileList(h, args) {
3548
3842
  try {
3549
3843
  const dirPath = resolveSafePath(args?.path || ".");
3550
- const entries = fs3.readdirSync(dirPath, { withFileTypes: true });
3844
+ const entries = fs4.readdirSync(dirPath, { withFileTypes: true });
3551
3845
  const files = entries.map((e) => ({
3552
3846
  name: e.name,
3553
3847
  type: e.isDirectory() ? "directory" : "file",
3554
- size: e.isFile() ? fs3.statSync(path3.join(dirPath, e.name)).size : void 0
3848
+ size: e.isFile() ? fs4.statSync(path5.join(dirPath, e.name)).size : void 0
3555
3849
  }));
3556
3850
  return { success: true, files, path: dirPath };
3557
3851
  } catch (e) {
@@ -3841,7 +4135,95 @@ function handleSetIdeExtension(h, args) {
3841
4135
  return { success: false, error: "Failed to save setting" };
3842
4136
  }
3843
4137
 
4138
+ // src/commands/workspace-commands.ts
4139
+ init_config();
4140
+ init_workspaces();
4141
+ function handleWorkspaceList() {
4142
+ const config = loadConfig();
4143
+ const state = getWorkspaceState(config);
4144
+ return {
4145
+ success: true,
4146
+ workspaces: state.workspaces,
4147
+ defaultWorkspaceId: state.defaultWorkspaceId,
4148
+ defaultWorkspacePath: state.defaultWorkspacePath,
4149
+ legacyRecentPaths: config.recentCliWorkspaces || [],
4150
+ activity: getWorkspaceActivity(config, 25)
4151
+ };
4152
+ }
4153
+ function handleWorkspaceAdd(args) {
4154
+ const rawPath = (args?.path || args?.dir || "").trim();
4155
+ const label = (args?.label || "").trim() || void 0;
4156
+ if (!rawPath) return { success: false, error: "path required" };
4157
+ const config = loadConfig();
4158
+ const result = addWorkspaceEntry(config, rawPath, label);
4159
+ if ("error" in result) return { success: false, error: result.error };
4160
+ let cfg = appendWorkspaceActivity(result.config, result.entry.path, {});
4161
+ saveConfig(cfg);
4162
+ const state = getWorkspaceState(cfg);
4163
+ return { success: true, entry: result.entry, ...state, activity: getWorkspaceActivity(cfg, 25) };
4164
+ }
4165
+ function handleWorkspaceRemove(args) {
4166
+ const id = (args?.id || "").trim();
4167
+ if (!id) return { success: false, error: "id required" };
4168
+ const config = loadConfig();
4169
+ const removed = (config.workspaces || []).find((w) => w.id === id);
4170
+ const result = removeWorkspaceEntry(config, id);
4171
+ if ("error" in result) return { success: false, error: result.error };
4172
+ let cfg = result.config;
4173
+ if (removed) {
4174
+ cfg = removeActivityForPath(cfg, removed.path);
4175
+ }
4176
+ saveConfig(cfg);
4177
+ const state = getWorkspaceState(cfg);
4178
+ return { success: true, removedId: id, ...state, activity: getWorkspaceActivity(cfg, 25) };
4179
+ }
4180
+ function handleWorkspaceSetDefault(args) {
4181
+ const clear = args?.clear === true || args?.id === null || args?.id === "";
4182
+ if (clear) {
4183
+ const config2 = loadConfig();
4184
+ const result2 = setDefaultWorkspaceId(config2, null);
4185
+ if ("error" in result2) return { success: false, error: result2.error };
4186
+ saveConfig(result2.config);
4187
+ const state2 = getWorkspaceState(result2.config);
4188
+ return {
4189
+ success: true,
4190
+ ...state2,
4191
+ activity: getWorkspaceActivity(result2.config, 25)
4192
+ };
4193
+ }
4194
+ const pathArg = args?.path != null && String(args.path).trim() ? String(args.path).trim() : "";
4195
+ const idArg = args?.id !== void 0 && args?.id !== null && String(args.id).trim() ? String(args.id).trim() : "";
4196
+ if (!pathArg && !idArg) {
4197
+ return { success: false, error: "id or path required (or clear: true)" };
4198
+ }
4199
+ let config = loadConfig();
4200
+ let nextId;
4201
+ if (pathArg) {
4202
+ let w = findWorkspaceByPath(config, pathArg);
4203
+ if (!w) {
4204
+ const add = addWorkspaceEntry(config, pathArg);
4205
+ if ("error" in add) return { success: false, error: add.error };
4206
+ config = add.config;
4207
+ w = add.entry;
4208
+ }
4209
+ nextId = w.id;
4210
+ } else {
4211
+ nextId = idArg;
4212
+ }
4213
+ const result = setDefaultWorkspaceId(config, nextId);
4214
+ if ("error" in result) return { success: false, error: result.error };
4215
+ let out = result.config;
4216
+ const ap = getDefaultWorkspacePath(out);
4217
+ if (ap) {
4218
+ out = appendWorkspaceActivity(out, ap, { kind: "default" });
4219
+ }
4220
+ saveConfig(out);
4221
+ const state = getWorkspaceState(out);
4222
+ return { success: true, ...state, activity: getWorkspaceActivity(out, 25) };
4223
+ }
4224
+
3844
4225
  // src/commands/handler.ts
4226
+ init_workspaces();
3845
4227
  var DaemonCommandHandler = class {
3846
4228
  _ctx;
3847
4229
  _agentStream = null;
@@ -3950,6 +4332,9 @@ var DaemonCommandHandler = class {
3950
4332
  }
3951
4333
  /** Extract ideType from _targetInstance */
3952
4334
  extractIdeType(args) {
4335
+ if (args?.ideType && this._ctx.cdpManagers.has(args.ideType)) {
4336
+ return args.ideType;
4337
+ }
3953
4338
  if (args?._targetInstance) {
3954
4339
  let raw = args._targetInstance;
3955
4340
  const ideMatch = raw.match(/:ide:(.+)$/);
@@ -3961,8 +4346,19 @@ var DaemonCommandHandler = class {
3961
4346
  if (this._ctx.instanceIdMap?.has(raw)) {
3962
4347
  return this._ctx.instanceIdMap.get(raw);
3963
4348
  }
4349
+ if (this._ctx.cdpManagers.has(raw)) {
4350
+ return raw;
4351
+ }
4352
+ if (!ideMatch && !cliMatch && !acpMatch) {
4353
+ for (const [key, mgr] of this._ctx.cdpManagers.entries()) {
4354
+ if (mgr.isConnected) return key;
4355
+ }
4356
+ }
3964
4357
  const lastUnderscore = raw.lastIndexOf("_");
3965
- if (lastUnderscore > 0) return raw.substring(0, lastUnderscore);
4358
+ if (lastUnderscore > 0) {
4359
+ const stripped = raw.substring(0, lastUnderscore);
4360
+ if (this._ctx.cdpManagers.has(stripped)) return stripped;
4361
+ }
3966
4362
  return raw;
3967
4363
  }
3968
4364
  return void 0;
@@ -4058,6 +4454,19 @@ var DaemonCommandHandler = class {
4058
4454
  return { success: false, error: `${cmd} requires bridge-extension (removed)` };
4059
4455
  case "get_recent_workspaces":
4060
4456
  return this.handleGetRecentWorkspaces(args);
4457
+ case "get_cli_history": {
4458
+ const config = loadConfig();
4459
+ return { success: true, history: config.cliHistory || [] };
4460
+ }
4461
+ case "workspace_list":
4462
+ return handleWorkspaceList();
4463
+ case "workspace_add":
4464
+ return handleWorkspaceAdd(args);
4465
+ case "workspace_remove":
4466
+ return handleWorkspaceRemove(args);
4467
+ case "workspace_set_default":
4468
+ case "workspace_set_active":
4469
+ return handleWorkspaceSetDefault(args);
4061
4470
  // ─── Script manage ───────────────────
4062
4471
  case "refresh_scripts":
4063
4472
  return this.handleRefreshScripts(args);
@@ -4107,10 +4516,18 @@ var DaemonCommandHandler = class {
4107
4516
  }
4108
4517
  }
4109
4518
  // ─── Misc (kept in handler — too small to extract) ───────
4110
- async handleGetRecentWorkspaces(args) {
4519
+ async handleGetRecentWorkspaces(_args) {
4111
4520
  const config = loadConfig();
4112
4521
  const cliRecent = config.recentCliWorkspaces || [];
4113
- return { success: true, result: cliRecent };
4522
+ const ws = getWorkspaceState(config);
4523
+ return {
4524
+ success: true,
4525
+ result: cliRecent,
4526
+ workspaces: ws.workspaces,
4527
+ defaultWorkspaceId: ws.defaultWorkspaceId,
4528
+ defaultWorkspacePath: ws.defaultWorkspacePath,
4529
+ activity: getWorkspaceActivity(config, 25)
4530
+ };
4114
4531
  }
4115
4532
  async handleRefreshScripts(_args) {
4116
4533
  if (this._ctx.providerLoader) {
@@ -4122,15 +4539,15 @@ var DaemonCommandHandler = class {
4122
4539
  };
4123
4540
 
4124
4541
  // src/launch.ts
4125
- var import_child_process3 = require("child_process");
4542
+ var import_child_process4 = require("child_process");
4126
4543
  var net = __toESM(require("net"));
4127
- var os6 = __toESM(require("os"));
4128
- var path5 = __toESM(require("path"));
4544
+ var os8 = __toESM(require("os"));
4545
+ var path7 = __toESM(require("path"));
4129
4546
 
4130
4547
  // src/providers/provider-loader.ts
4131
- var fs4 = __toESM(require("fs"));
4132
- var path4 = __toESM(require("path"));
4133
- var os5 = __toESM(require("os"));
4548
+ var fs5 = __toESM(require("fs"));
4549
+ var path6 = __toESM(require("path"));
4550
+ var os7 = __toESM(require("os"));
4134
4551
  var ProviderLoader = class _ProviderLoader {
4135
4552
  providers = /* @__PURE__ */ new Map();
4136
4553
  builtinDirs;
@@ -4150,10 +4567,10 @@ var ProviderLoader = class _ProviderLoader {
4150
4567
  if (options?.builtinDir) {
4151
4568
  this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
4152
4569
  } else {
4153
- this.builtinDirs = [path4.resolve(__dirname, "../providers/_builtin")];
4570
+ this.builtinDirs = [path6.resolve(__dirname, "../providers/_builtin")];
4154
4571
  }
4155
- this.userDir = options?.userDir || path4.join(os5.homedir(), ".adhdev", "providers");
4156
- this.upstreamDir = path4.join(this.userDir, ".upstream");
4572
+ this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
4573
+ this.upstreamDir = path6.join(this.userDir, ".upstream");
4157
4574
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
4158
4575
  }
4159
4576
  log(msg) {
@@ -4171,19 +4588,19 @@ var ProviderLoader = class _ProviderLoader {
4171
4588
  this.providers.clear();
4172
4589
  let builtinCount = 0;
4173
4590
  for (const dir of this.builtinDirs) {
4174
- if (fs4.existsSync(dir)) {
4591
+ if (fs5.existsSync(dir)) {
4175
4592
  builtinCount += this.loadDir(dir);
4176
4593
  }
4177
4594
  }
4178
4595
  this.log(`Loaded ${builtinCount} builtin providers`);
4179
4596
  let upstreamCount = 0;
4180
- if (fs4.existsSync(this.upstreamDir)) {
4597
+ if (fs5.existsSync(this.upstreamDir)) {
4181
4598
  upstreamCount = this.loadDir(this.upstreamDir);
4182
4599
  if (upstreamCount > 0) {
4183
4600
  this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
4184
4601
  }
4185
4602
  }
4186
- if (fs4.existsSync(this.userDir)) {
4603
+ if (fs5.existsSync(this.userDir)) {
4187
4604
  const userCount = this.loadDir(this.userDir, [".upstream"]);
4188
4605
  if (userCount > 0) {
4189
4606
  this.log(`Loaded ${userCount} user custom providers (never auto-updated)`);
@@ -4487,15 +4904,15 @@ var ProviderLoader = class _ProviderLoader {
4487
4904
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
4488
4905
  return null;
4489
4906
  }
4490
- const dir = path4.join(providerDir, scriptDir);
4491
- if (!fs4.existsSync(dir)) {
4907
+ const dir = path6.join(providerDir, scriptDir);
4908
+ if (!fs5.existsSync(dir)) {
4492
4909
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
4493
4910
  return null;
4494
4911
  }
4495
4912
  const cached = this.scriptsCache.get(dir);
4496
4913
  if (cached) return cached;
4497
- const scriptsJs = path4.join(dir, "scripts.js");
4498
- if (fs4.existsSync(scriptsJs)) {
4914
+ const scriptsJs = path6.join(dir, "scripts.js");
4915
+ if (fs5.existsSync(scriptsJs)) {
4499
4916
  try {
4500
4917
  delete require.cache[require.resolve(scriptsJs)];
4501
4918
  const loaded = require(scriptsJs);
@@ -4517,15 +4934,15 @@ var ProviderLoader = class _ProviderLoader {
4517
4934
  watch() {
4518
4935
  this.stopWatch();
4519
4936
  const watchDir = (dir) => {
4520
- if (!fs4.existsSync(dir)) {
4937
+ if (!fs5.existsSync(dir)) {
4521
4938
  try {
4522
- fs4.mkdirSync(dir, { recursive: true });
4939
+ fs5.mkdirSync(dir, { recursive: true });
4523
4940
  } catch {
4524
4941
  return;
4525
4942
  }
4526
4943
  }
4527
4944
  try {
4528
- const watcher = fs4.watch(dir, { recursive: true }, (event, filename) => {
4945
+ const watcher = fs5.watch(dir, { recursive: true }, (event, filename) => {
4529
4946
  if (filename?.endsWith(".js") || filename?.endsWith(".json")) {
4530
4947
  this.log(`File changed: ${filename}, reloading...`);
4531
4948
  this.loadAll();
@@ -4575,13 +4992,13 @@ var ProviderLoader = class _ProviderLoader {
4575
4992
  */
4576
4993
  async fetchLatest() {
4577
4994
  const https = require("https");
4578
- const { execSync: execSync6 } = require("child_process");
4579
- const metaPath = path4.join(this.upstreamDir, _ProviderLoader.META_FILE);
4995
+ const { execSync: execSync7 } = require("child_process");
4996
+ const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
4580
4997
  let prevEtag = "";
4581
4998
  let prevTimestamp = 0;
4582
4999
  try {
4583
- if (fs4.existsSync(metaPath)) {
4584
- const meta = JSON.parse(fs4.readFileSync(metaPath, "utf-8"));
5000
+ if (fs5.existsSync(metaPath)) {
5001
+ const meta = JSON.parse(fs5.readFileSync(metaPath, "utf-8"));
4585
5002
  prevEtag = meta.etag || "";
4586
5003
  prevTimestamp = meta.timestamp || 0;
4587
5004
  }
@@ -4593,7 +5010,7 @@ var ProviderLoader = class _ProviderLoader {
4593
5010
  return { updated: false };
4594
5011
  }
4595
5012
  try {
4596
- const etag = await new Promise((resolve5, reject) => {
5013
+ const etag = await new Promise((resolve7, reject) => {
4597
5014
  const options = {
4598
5015
  method: "HEAD",
4599
5016
  hostname: "github.com",
@@ -4611,7 +5028,7 @@ var ProviderLoader = class _ProviderLoader {
4611
5028
  headers: { "User-Agent": "adhdev-launcher" },
4612
5029
  timeout: 1e4
4613
5030
  }, (res2) => {
4614
- resolve5(res2.headers.etag || res2.headers["last-modified"] || "");
5031
+ resolve7(res2.headers.etag || res2.headers["last-modified"] || "");
4615
5032
  });
4616
5033
  req2.on("error", reject);
4617
5034
  req2.on("timeout", () => {
@@ -4620,7 +5037,7 @@ var ProviderLoader = class _ProviderLoader {
4620
5037
  });
4621
5038
  req2.end();
4622
5039
  } else {
4623
- resolve5(res.headers.etag || res.headers["last-modified"] || "");
5040
+ resolve7(res.headers.etag || res.headers["last-modified"] || "");
4624
5041
  }
4625
5042
  });
4626
5043
  req.on("error", reject);
@@ -4636,39 +5053,39 @@ var ProviderLoader = class _ProviderLoader {
4636
5053
  return { updated: false };
4637
5054
  }
4638
5055
  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()}`);
5056
+ const tmpTar = path6.join(os7.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
5057
+ const tmpExtract = path6.join(os7.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
4641
5058
  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);
5059
+ fs5.mkdirSync(tmpExtract, { recursive: true });
5060
+ execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
5061
+ const extracted = fs5.readdirSync(tmpExtract);
4645
5062
  const rootDir = extracted.find(
4646
- (d) => fs4.statSync(path4.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
5063
+ (d) => fs5.statSync(path6.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
4647
5064
  );
4648
5065
  if (!rootDir) throw new Error("Unexpected tarball structure");
4649
- const sourceDir = path4.join(tmpExtract, rootDir);
5066
+ const sourceDir = path6.join(tmpExtract, rootDir);
4650
5067
  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);
5068
+ if (fs5.existsSync(this.upstreamDir)) {
5069
+ if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
5070
+ fs5.renameSync(this.upstreamDir, backupDir);
4654
5071
  }
4655
5072
  try {
4656
5073
  this.copyDirRecursive(sourceDir, this.upstreamDir);
4657
5074
  this.writeMeta(metaPath, etag || `ts-${Date.now()}`, Date.now());
4658
- if (fs4.existsSync(backupDir)) fs4.rmSync(backupDir, { recursive: true, force: true });
5075
+ if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
4659
5076
  } 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);
5077
+ if (fs5.existsSync(backupDir)) {
5078
+ if (fs5.existsSync(this.upstreamDir)) fs5.rmSync(this.upstreamDir, { recursive: true, force: true });
5079
+ fs5.renameSync(backupDir, this.upstreamDir);
4663
5080
  }
4664
5081
  throw e;
4665
5082
  }
4666
5083
  try {
4667
- fs4.rmSync(tmpTar, { force: true });
5084
+ fs5.rmSync(tmpTar, { force: true });
4668
5085
  } catch {
4669
5086
  }
4670
5087
  try {
4671
- fs4.rmSync(tmpExtract, { recursive: true, force: true });
5088
+ fs5.rmSync(tmpExtract, { recursive: true, force: true });
4672
5089
  } catch {
4673
5090
  }
4674
5091
  const upstreamCount = this.countProviders(this.upstreamDir);
@@ -4684,7 +5101,7 @@ var ProviderLoader = class _ProviderLoader {
4684
5101
  downloadFile(url, destPath) {
4685
5102
  const https = require("https");
4686
5103
  const http3 = require("http");
4687
- return new Promise((resolve5, reject) => {
5104
+ return new Promise((resolve7, reject) => {
4688
5105
  const doRequest = (reqUrl, redirectCount = 0) => {
4689
5106
  if (redirectCount > 5) {
4690
5107
  reject(new Error("Too many redirects"));
@@ -4700,11 +5117,11 @@ var ProviderLoader = class _ProviderLoader {
4700
5117
  reject(new Error(`HTTP ${res.statusCode}`));
4701
5118
  return;
4702
5119
  }
4703
- const ws = fs4.createWriteStream(destPath);
5120
+ const ws = fs5.createWriteStream(destPath);
4704
5121
  res.pipe(ws);
4705
5122
  ws.on("finish", () => {
4706
5123
  ws.close();
4707
- resolve5();
5124
+ resolve7();
4708
5125
  });
4709
5126
  ws.on("error", reject);
4710
5127
  });
@@ -4719,22 +5136,22 @@ var ProviderLoader = class _ProviderLoader {
4719
5136
  }
4720
5137
  /** Recursive directory copy */
4721
5138
  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);
5139
+ fs5.mkdirSync(dest, { recursive: true });
5140
+ for (const entry of fs5.readdirSync(src, { withFileTypes: true })) {
5141
+ const srcPath = path6.join(src, entry.name);
5142
+ const destPath = path6.join(dest, entry.name);
4726
5143
  if (entry.isDirectory()) {
4727
5144
  this.copyDirRecursive(srcPath, destPath);
4728
5145
  } else {
4729
- fs4.copyFileSync(srcPath, destPath);
5146
+ fs5.copyFileSync(srcPath, destPath);
4730
5147
  }
4731
5148
  }
4732
5149
  }
4733
5150
  /** .meta.json save */
4734
5151
  writeMeta(metaPath, etag, timestamp) {
4735
5152
  try {
4736
- fs4.mkdirSync(path4.dirname(metaPath), { recursive: true });
4737
- fs4.writeFileSync(metaPath, JSON.stringify({
5153
+ fs5.mkdirSync(path6.dirname(metaPath), { recursive: true });
5154
+ fs5.writeFileSync(metaPath, JSON.stringify({
4738
5155
  etag,
4739
5156
  timestamp,
4740
5157
  lastCheck: new Date(timestamp).toISOString(),
@@ -4745,12 +5162,12 @@ var ProviderLoader = class _ProviderLoader {
4745
5162
  }
4746
5163
  /** Count provider files (provider.js or provider.json) */
4747
5164
  countProviders(dir) {
4748
- if (!fs4.existsSync(dir)) return 0;
5165
+ if (!fs5.existsSync(dir)) return 0;
4749
5166
  let count = 0;
4750
5167
  const scan = (d) => {
4751
5168
  try {
4752
- for (const entry of fs4.readdirSync(d, { withFileTypes: true })) {
4753
- if (entry.isDirectory()) scan(path4.join(d, entry.name));
5169
+ for (const entry of fs5.readdirSync(d, { withFileTypes: true })) {
5170
+ if (entry.isDirectory()) scan(path6.join(d, entry.name));
4754
5171
  else if (entry.name === "provider.json") count++;
4755
5172
  }
4756
5173
  } catch {
@@ -4847,20 +5264,20 @@ var ProviderLoader = class _ProviderLoader {
4847
5264
  const cat = provider.category;
4848
5265
  const searchRoots = [this.userDir, this.upstreamDir, ...this.builtinDirs];
4849
5266
  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;
5267
+ if (!fs5.existsSync(root)) continue;
5268
+ for (const candidate of [path6.join(root, type), path6.join(root, cat, type)]) {
5269
+ if (fs5.existsSync(path6.join(candidate, "provider.json"))) return candidate;
4853
5270
  }
4854
- const catDir = path4.join(root, cat);
4855
- if (fs4.existsSync(catDir)) {
5271
+ const catDir = path6.join(root, cat);
5272
+ if (fs5.existsSync(catDir)) {
4856
5273
  try {
4857
- for (const entry of fs4.readdirSync(catDir, { withFileTypes: true })) {
5274
+ for (const entry of fs5.readdirSync(catDir, { withFileTypes: true })) {
4858
5275
  if (!entry.isDirectory()) continue;
4859
- const jsonPath = path4.join(catDir, entry.name, "provider.json");
4860
- if (fs4.existsSync(jsonPath)) {
5276
+ const jsonPath = path6.join(catDir, entry.name, "provider.json");
5277
+ if (fs5.existsSync(jsonPath)) {
4861
5278
  try {
4862
- const data = JSON.parse(fs4.readFileSync(jsonPath, "utf-8"));
4863
- if (data.type === type) return path4.join(catDir, entry.name);
5279
+ const data = JSON.parse(fs5.readFileSync(jsonPath, "utf-8"));
5280
+ if (data.type === type) return path6.join(catDir, entry.name);
4864
5281
  } catch {
4865
5282
  }
4866
5283
  }
@@ -4877,8 +5294,8 @@ var ProviderLoader = class _ProviderLoader {
4877
5294
  * (template substitution is NOT applied here — scripts.js handles that)
4878
5295
  */
4879
5296
  buildScriptWrappersFromDir(dir) {
4880
- const scriptsJs = path4.join(dir, "scripts.js");
4881
- if (fs4.existsSync(scriptsJs)) {
5297
+ const scriptsJs = path6.join(dir, "scripts.js");
5298
+ if (fs5.existsSync(scriptsJs)) {
4882
5299
  try {
4883
5300
  delete require.cache[require.resolve(scriptsJs)];
4884
5301
  return require(scriptsJs);
@@ -4888,13 +5305,13 @@ var ProviderLoader = class _ProviderLoader {
4888
5305
  const toCamel = (name) => name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
4889
5306
  const result = {};
4890
5307
  try {
4891
- for (const file of fs4.readdirSync(dir)) {
5308
+ for (const file of fs5.readdirSync(dir)) {
4892
5309
  if (!file.endsWith(".js")) continue;
4893
5310
  const scriptName = toCamel(file.replace(".js", ""));
4894
- const filePath = path4.join(dir, file);
5311
+ const filePath = path6.join(dir, file);
4895
5312
  result[scriptName] = (..._args) => {
4896
5313
  try {
4897
- return fs4.readFileSync(filePath, "utf-8");
5314
+ return fs5.readFileSync(filePath, "utf-8");
4898
5315
  } catch {
4899
5316
  return "";
4900
5317
  }
@@ -4912,20 +5329,20 @@ var ProviderLoader = class _ProviderLoader {
4912
5329
  * Structure: dir/category/agent-name/provider.{json,js}
4913
5330
  */
4914
5331
  loadDir(dir, excludeDirs) {
4915
- if (!fs4.existsSync(dir)) return 0;
5332
+ if (!fs5.existsSync(dir)) return 0;
4916
5333
  let count = 0;
4917
5334
  const scan = (d) => {
4918
5335
  let entries;
4919
5336
  try {
4920
- entries = fs4.readdirSync(d, { withFileTypes: true });
5337
+ entries = fs5.readdirSync(d, { withFileTypes: true });
4921
5338
  } catch {
4922
5339
  return;
4923
5340
  }
4924
5341
  const hasJson = entries.some((e) => e.name === "provider.json");
4925
5342
  if (hasJson) {
4926
- const jsonPath = path4.join(d, "provider.json");
5343
+ const jsonPath = path6.join(d, "provider.json");
4927
5344
  try {
4928
- const raw = fs4.readFileSync(jsonPath, "utf-8");
5345
+ const raw = fs5.readFileSync(jsonPath, "utf-8");
4929
5346
  const mod = JSON.parse(raw);
4930
5347
  if (!mod.type || !mod.name || !mod.category) {
4931
5348
  this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
@@ -4936,8 +5353,8 @@ var ProviderLoader = class _ProviderLoader {
4936
5353
  delete mod.extensionIdPattern_flags;
4937
5354
  }
4938
5355
  const hasCompatibility = Array.isArray(mod.compatibility);
4939
- const scriptsPath = path4.join(d, "scripts.js");
4940
- if (!hasCompatibility && fs4.existsSync(scriptsPath)) {
5356
+ const scriptsPath = path6.join(d, "scripts.js");
5357
+ if (!hasCompatibility && fs5.existsSync(scriptsPath)) {
4941
5358
  try {
4942
5359
  delete require.cache[require.resolve(scriptsPath)];
4943
5360
  const scripts = require(scriptsPath);
@@ -4962,7 +5379,7 @@ var ProviderLoader = class _ProviderLoader {
4962
5379
  if (!entry.isDirectory()) continue;
4963
5380
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
4964
5381
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
4965
- scan(path4.join(d, entry.name));
5382
+ scan(path6.join(d, entry.name));
4966
5383
  }
4967
5384
  }
4968
5385
  };
@@ -5041,17 +5458,17 @@ async function findFreePort(ports) {
5041
5458
  throw new Error("No free port found");
5042
5459
  }
5043
5460
  function checkPortFree(port) {
5044
- return new Promise((resolve5) => {
5461
+ return new Promise((resolve7) => {
5045
5462
  const server = net.createServer();
5046
5463
  server.unref();
5047
- server.on("error", () => resolve5(false));
5464
+ server.on("error", () => resolve7(false));
5048
5465
  server.listen(port, "127.0.0.1", () => {
5049
- server.close(() => resolve5(true));
5466
+ server.close(() => resolve7(true));
5050
5467
  });
5051
5468
  });
5052
5469
  }
5053
5470
  async function isCdpActive(port) {
5054
- return new Promise((resolve5) => {
5471
+ return new Promise((resolve7) => {
5055
5472
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
5056
5473
  timeout: 2e3
5057
5474
  }, (res) => {
@@ -5060,52 +5477,52 @@ async function isCdpActive(port) {
5060
5477
  res.on("end", () => {
5061
5478
  try {
5062
5479
  const info = JSON.parse(data);
5063
- resolve5(!!info["WebKit-Version"] || !!info["Browser"]);
5480
+ resolve7(!!info["WebKit-Version"] || !!info["Browser"]);
5064
5481
  } catch {
5065
- resolve5(false);
5482
+ resolve7(false);
5066
5483
  }
5067
5484
  });
5068
5485
  });
5069
- req.on("error", () => resolve5(false));
5486
+ req.on("error", () => resolve7(false));
5070
5487
  req.on("timeout", () => {
5071
5488
  req.destroy();
5072
- resolve5(false);
5489
+ resolve7(false);
5073
5490
  });
5074
5491
  });
5075
5492
  }
5076
5493
  async function killIdeProcess(ideId) {
5077
- const plat = os6.platform();
5494
+ const plat = os8.platform();
5078
5495
  const appName = getMacAppIdentifiers()[ideId];
5079
5496
  const winProcesses = getWinProcessNames()[ideId];
5080
5497
  try {
5081
5498
  if (plat === "darwin" && appName) {
5082
5499
  try {
5083
- (0, import_child_process3.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
5500
+ (0, import_child_process4.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
5084
5501
  timeout: 5e3
5085
5502
  });
5086
5503
  } catch {
5087
5504
  try {
5088
- (0, import_child_process3.execSync)(`pkill -f "${appName}" 2>/dev/null`);
5505
+ (0, import_child_process4.execSync)(`pkill -f "${appName}" 2>/dev/null`);
5089
5506
  } catch {
5090
5507
  }
5091
5508
  }
5092
5509
  } else if (plat === "win32" && winProcesses) {
5093
5510
  for (const proc of winProcesses) {
5094
5511
  try {
5095
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
5512
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
5096
5513
  } catch {
5097
5514
  }
5098
5515
  }
5099
5516
  try {
5100
5517
  const exeName = winProcesses[0].replace(".exe", "");
5101
- (0, import_child_process3.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
5518
+ (0, import_child_process4.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
5102
5519
  timeout: 1e4
5103
5520
  });
5104
5521
  } catch {
5105
5522
  }
5106
5523
  } else {
5107
5524
  try {
5108
- (0, import_child_process3.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
5525
+ (0, import_child_process4.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
5109
5526
  } catch {
5110
5527
  }
5111
5528
  }
@@ -5115,13 +5532,13 @@ async function killIdeProcess(ideId) {
5115
5532
  }
5116
5533
  if (plat === "darwin" && appName) {
5117
5534
  try {
5118
- (0, import_child_process3.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
5535
+ (0, import_child_process4.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
5119
5536
  } catch {
5120
5537
  }
5121
5538
  } else if (plat === "win32" && winProcesses) {
5122
5539
  for (const proc of winProcesses) {
5123
5540
  try {
5124
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
5541
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
5125
5542
  } catch {
5126
5543
  }
5127
5544
  }
@@ -5133,26 +5550,26 @@ async function killIdeProcess(ideId) {
5133
5550
  }
5134
5551
  }
5135
5552
  function isIdeRunning(ideId) {
5136
- const plat = os6.platform();
5553
+ const plat = os8.platform();
5137
5554
  try {
5138
5555
  if (plat === "darwin") {
5139
5556
  const appName = getMacAppIdentifiers()[ideId];
5140
5557
  if (!appName) return false;
5141
- const result = (0, import_child_process3.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
5558
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
5142
5559
  return result.trim().length > 0;
5143
5560
  } else if (plat === "win32") {
5144
5561
  const winProcesses = getWinProcessNames()[ideId];
5145
5562
  if (!winProcesses) return false;
5146
5563
  for (const proc of winProcesses) {
5147
5564
  try {
5148
- const result = (0, import_child_process3.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
5565
+ const result = (0, import_child_process4.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
5149
5566
  if (result.includes(proc)) return true;
5150
5567
  } catch {
5151
5568
  }
5152
5569
  }
5153
5570
  try {
5154
5571
  const exeName = winProcesses[0].replace(".exe", "");
5155
- const result = (0, import_child_process3.execSync)(
5572
+ const result = (0, import_child_process4.execSync)(
5156
5573
  `powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
5157
5574
  { encoding: "utf-8", timeout: 5e3 }
5158
5575
  );
@@ -5161,7 +5578,7 @@ function isIdeRunning(ideId) {
5161
5578
  }
5162
5579
  return false;
5163
5580
  } else {
5164
- const result = (0, import_child_process3.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
5581
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
5165
5582
  return result.trim().length > 0;
5166
5583
  }
5167
5584
  } catch {
@@ -5169,12 +5586,12 @@ function isIdeRunning(ideId) {
5169
5586
  }
5170
5587
  }
5171
5588
  function detectCurrentWorkspace(ideId) {
5172
- const plat = os6.platform();
5589
+ const plat = os8.platform();
5173
5590
  if (plat === "darwin") {
5174
5591
  try {
5175
5592
  const appName = getMacAppIdentifiers()[ideId];
5176
5593
  if (!appName) return void 0;
5177
- const result = (0, import_child_process3.execSync)(
5594
+ const result = (0, import_child_process4.execSync)(
5178
5595
  `lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
5179
5596
  { encoding: "utf-8", timeout: 3e3 }
5180
5597
  );
@@ -5184,17 +5601,17 @@ function detectCurrentWorkspace(ideId) {
5184
5601
  }
5185
5602
  } else if (plat === "win32") {
5186
5603
  try {
5187
- const fs9 = require("fs");
5604
+ const fs10 = require("fs");
5188
5605
  const appNameMap = getMacAppIdentifiers();
5189
5606
  const appName = appNameMap[ideId];
5190
5607
  if (appName) {
5191
- const storagePath = path5.join(
5192
- process.env.APPDATA || path5.join(os6.homedir(), "AppData", "Roaming"),
5608
+ const storagePath = path7.join(
5609
+ process.env.APPDATA || path7.join(os8.homedir(), "AppData", "Roaming"),
5193
5610
  appName,
5194
5611
  "storage.json"
5195
5612
  );
5196
- if (fs9.existsSync(storagePath)) {
5197
- const data = JSON.parse(fs9.readFileSync(storagePath, "utf-8"));
5613
+ if (fs10.existsSync(storagePath)) {
5614
+ const data = JSON.parse(fs10.readFileSync(storagePath, "utf-8"));
5198
5615
  const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
5199
5616
  if (workspaces.length > 0) {
5200
5617
  const recent = workspaces[0];
@@ -5211,7 +5628,7 @@ function detectCurrentWorkspace(ideId) {
5211
5628
  return void 0;
5212
5629
  }
5213
5630
  async function launchWithCdp(options = {}) {
5214
- const platform7 = os6.platform();
5631
+ const platform8 = os8.platform();
5215
5632
  let targetIde;
5216
5633
  const ides = await detectIDEs();
5217
5634
  if (options.ideId) {
@@ -5280,9 +5697,9 @@ async function launchWithCdp(options = {}) {
5280
5697
  }
5281
5698
  const port = await findFreePort(portPair);
5282
5699
  try {
5283
- if (platform7 === "darwin") {
5700
+ if (platform8 === "darwin") {
5284
5701
  await launchMacOS(targetIde, port, workspace, options.newWindow);
5285
- } else if (platform7 === "win32") {
5702
+ } else if (platform8 === "win32") {
5286
5703
  await launchWindows(targetIde, port, workspace, options.newWindow);
5287
5704
  } else {
5288
5705
  await launchLinux(targetIde, port, workspace, options.newWindow);
@@ -5322,9 +5739,9 @@ async function launchMacOS(ide, port, workspace, newWindow) {
5322
5739
  if (workspace) args.push(workspace);
5323
5740
  if (appName) {
5324
5741
  const openArgs = ["-a", appName, "--args", ...args];
5325
- (0, import_child_process3.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
5742
+ (0, import_child_process4.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
5326
5743
  } else if (ide.cliCommand) {
5327
- (0, import_child_process3.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
5744
+ (0, import_child_process4.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
5328
5745
  } else {
5329
5746
  throw new Error(`No app identifier or CLI for ${ide.displayName}`);
5330
5747
  }
@@ -5350,21 +5767,25 @@ async function launchLinux(ide, port, workspace, newWindow) {
5350
5767
  const args = ["--remote-debugging-port=" + port];
5351
5768
  if (newWindow) args.push("--new-window");
5352
5769
  if (workspace) args.push(workspace);
5353
- (0, import_child_process3.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
5770
+ (0, import_child_process4.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
5354
5771
  }
5355
5772
  function getAvailableIdeIds() {
5356
5773
  return getProviderLoader().getAvailableIdeTypes();
5357
5774
  }
5358
5775
 
5776
+ // src/commands/router.ts
5777
+ init_config();
5778
+ init_workspaces();
5779
+
5359
5780
  // 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");
5781
+ var fs6 = __toESM(require("fs"));
5782
+ var path8 = __toESM(require("path"));
5783
+ var os9 = __toESM(require("os"));
5784
+ var LOG_DIR2 = process.platform === "darwin" ? path8.join(os9.homedir(), "Library", "Logs", "adhdev") : path8.join(os9.homedir(), ".local", "share", "adhdev", "logs");
5364
5785
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
5365
5786
  var MAX_DAYS = 7;
5366
5787
  try {
5367
- fs5.mkdirSync(LOG_DIR2, { recursive: true });
5788
+ fs6.mkdirSync(LOG_DIR2, { recursive: true });
5368
5789
  } catch {
5369
5790
  }
5370
5791
  var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
@@ -5398,19 +5819,19 @@ function getDateStr2() {
5398
5819
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5399
5820
  }
5400
5821
  var currentDate2 = getDateStr2();
5401
- var currentFile = path6.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5822
+ var currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5402
5823
  var writeCount2 = 0;
5403
5824
  function checkRotation() {
5404
5825
  const today = getDateStr2();
5405
5826
  if (today !== currentDate2) {
5406
5827
  currentDate2 = today;
5407
- currentFile = path6.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5828
+ currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
5408
5829
  cleanOldFiles();
5409
5830
  }
5410
5831
  }
5411
5832
  function cleanOldFiles() {
5412
5833
  try {
5413
- const files = fs5.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
5834
+ const files = fs6.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
5414
5835
  const cutoff = /* @__PURE__ */ new Date();
5415
5836
  cutoff.setDate(cutoff.getDate() - MAX_DAYS);
5416
5837
  const cutoffStr = cutoff.toISOString().slice(0, 10);
@@ -5418,7 +5839,7 @@ function cleanOldFiles() {
5418
5839
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
5419
5840
  if (dateMatch && dateMatch[1] < cutoffStr) {
5420
5841
  try {
5421
- fs5.unlinkSync(path6.join(LOG_DIR2, file));
5842
+ fs6.unlinkSync(path8.join(LOG_DIR2, file));
5422
5843
  } catch {
5423
5844
  }
5424
5845
  }
@@ -5428,14 +5849,14 @@ function cleanOldFiles() {
5428
5849
  }
5429
5850
  function checkSize() {
5430
5851
  try {
5431
- const stat = fs5.statSync(currentFile);
5852
+ const stat = fs6.statSync(currentFile);
5432
5853
  if (stat.size > MAX_FILE_SIZE) {
5433
5854
  const backup = currentFile.replace(".jsonl", ".1.jsonl");
5434
5855
  try {
5435
- fs5.unlinkSync(backup);
5856
+ fs6.unlinkSync(backup);
5436
5857
  } catch {
5437
5858
  }
5438
- fs5.renameSync(currentFile, backup);
5859
+ fs6.renameSync(currentFile, backup);
5439
5860
  }
5440
5861
  } catch {
5441
5862
  }
@@ -5460,14 +5881,14 @@ function logCommand(entry) {
5460
5881
  ...entry.error ? { err: entry.error } : {},
5461
5882
  ...entry.durationMs !== void 0 ? { ms: entry.durationMs } : {}
5462
5883
  });
5463
- fs5.appendFileSync(currentFile, line + "\n");
5884
+ fs6.appendFileSync(currentFile, line + "\n");
5464
5885
  } catch {
5465
5886
  }
5466
5887
  }
5467
5888
  function getRecentCommands(count = 50) {
5468
5889
  try {
5469
- if (!fs5.existsSync(currentFile)) return [];
5470
- const content = fs5.readFileSync(currentFile, "utf-8");
5890
+ if (!fs6.existsSync(currentFile)) return [];
5891
+ const content = fs6.readFileSync(currentFile, "utf-8");
5471
5892
  const lines = content.trim().split("\n").filter(Boolean);
5472
5893
  return lines.slice(-count).map((line) => {
5473
5894
  try {
@@ -5492,7 +5913,7 @@ function getRecentCommands(count = 50) {
5492
5913
  cleanOldFiles();
5493
5914
 
5494
5915
  // src/commands/router.ts
5495
- var fs6 = __toESM(require("fs"));
5916
+ var fs7 = __toESM(require("fs"));
5496
5917
  var CHAT_COMMANDS = [
5497
5918
  "send_chat",
5498
5919
  "new_chat",
@@ -5562,8 +5983,8 @@ var DaemonCommandRouter = class {
5562
5983
  if (logs.length > 0) {
5563
5984
  return { success: true, logs, totalBuffered: logs.length };
5564
5985
  }
5565
- if (fs6.existsSync(LOG_PATH)) {
5566
- const content = fs6.readFileSync(LOG_PATH, "utf-8");
5986
+ if (fs7.existsSync(LOG_PATH)) {
5987
+ const content = fs7.readFileSync(LOG_PATH, "utf-8");
5567
5988
  const allLines = content.split("\n");
5568
5989
  const recent = allLines.slice(-count).join("\n");
5569
5990
  return { success: true, logs: recent, totalLines: allLines.length };
@@ -5602,8 +6023,20 @@ var DaemonCommandRouter = class {
5602
6023
  }
5603
6024
  // ─── IDE launch + CDP connect ───
5604
6025
  case "launch_ide": {
5605
- const launchArgs = { ...args, ideId: args?.ideId || args?.ideType };
5606
- const ideKey = launchArgs.ideId;
6026
+ const ideKey = args?.ideId || args?.ideType;
6027
+ const resolvedWorkspace = resolveIdeLaunchWorkspace(
6028
+ {
6029
+ workspace: args?.workspace,
6030
+ workspaceId: args?.workspaceId,
6031
+ useDefaultWorkspace: args?.useDefaultWorkspace
6032
+ },
6033
+ loadConfig()
6034
+ );
6035
+ const launchArgs = {
6036
+ ideId: ideKey,
6037
+ workspace: resolvedWorkspace,
6038
+ newWindow: args?.newWindow
6039
+ };
5607
6040
  LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
5608
6041
  const result = await launchWithCdp(launchArgs);
5609
6042
  if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
@@ -5620,6 +6053,15 @@ var DaemonCommandRouter = class {
5620
6053
  }
5621
6054
  }
5622
6055
  this.deps.onIdeConnected?.();
6056
+ if (result.success && resolvedWorkspace) {
6057
+ try {
6058
+ saveConfig(appendWorkspaceActivity(loadConfig(), resolvedWorkspace, {
6059
+ kind: "ide",
6060
+ agentType: result.ideId
6061
+ }));
6062
+ } catch {
6063
+ }
6064
+ }
5623
6065
  return { success: result.success, ...result };
5624
6066
  }
5625
6067
  // ─── IDE detection ───
@@ -5627,6 +6069,12 @@ var DaemonCommandRouter = class {
5627
6069
  this.deps.detectedIdes.value = await detectIDEs();
5628
6070
  return { success: true, ides: this.deps.detectedIdes.value };
5629
6071
  }
6072
+ // ─── Machine Settings ───
6073
+ case "set_machine_nickname": {
6074
+ const nickname = args?.nickname;
6075
+ updateConfig({ machineNickname: nickname || null });
6076
+ return { success: true };
6077
+ }
5630
6078
  }
5631
6079
  return null;
5632
6080
  }
@@ -5663,8 +6111,9 @@ var DaemonCommandRouter = class {
5663
6111
  };
5664
6112
 
5665
6113
  // src/status/reporter.ts
5666
- var os8 = __toESM(require("os"));
6114
+ var os10 = __toESM(require("os"));
5667
6115
  init_config();
6116
+ init_workspaces();
5668
6117
  var DaemonStatusReporter = class {
5669
6118
  deps;
5670
6119
  log;
@@ -5731,6 +6180,10 @@ var DaemonStatusReporter = class {
5731
6180
  // (agent-stream polling backward compat)
5732
6181
  updateAgentStreams(_ideType, _streams) {
5733
6182
  }
6183
+ /** Reset P2P dedup hash — forces next send to transmit even if content unchanged */
6184
+ resetP2PHash() {
6185
+ this.lastP2PStatusHash = "";
6186
+ }
5734
6187
  // ─── Core ────────────────────────────────────────
5735
6188
  ts() {
5736
6189
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
@@ -5810,18 +6263,26 @@ var DaemonStatusReporter = class {
5810
6263
  acpConfigOptions: s.acpConfigOptions,
5811
6264
  acpModes: s.acpModes
5812
6265
  }));
6266
+ const cfg = loadConfig();
6267
+ const wsState = getWorkspaceState(cfg);
6268
+ const memSnap = getHostMemorySnapshot();
5813
6269
  const payload = {
5814
6270
  daemonMode: true,
5815
- machineNickname: loadConfig().machineNickname || null,
6271
+ machineNickname: cfg.machineNickname || null,
6272
+ workspaces: wsState.workspaces,
6273
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
6274
+ defaultWorkspacePath: wsState.defaultWorkspacePath,
6275
+ workspaceActivity: getWorkspaceActivity(cfg, 15),
5816
6276
  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()
6277
+ hostname: os10.hostname(),
6278
+ platform: os10.platform(),
6279
+ arch: os10.arch(),
6280
+ cpus: os10.cpus().length,
6281
+ totalMem: memSnap.totalMem,
6282
+ freeMem: memSnap.freeMem,
6283
+ availableMem: memSnap.availableMem,
6284
+ loadavg: os10.loadavg(),
6285
+ uptime: os10.uptime()
5825
6286
  },
5826
6287
  managedIdes,
5827
6288
  managedClis,
@@ -5853,6 +6314,8 @@ var DaemonStatusReporter = class {
5853
6314
  const wsPayload = {
5854
6315
  daemonMode: true,
5855
6316
  machineNickname: payload.machineNickname,
6317
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
6318
+ workspaceCount: (wsState.workspaces || []).length,
5856
6319
  // managedIdes: server only saves id, type, cdpConnected
5857
6320
  managedIdes: managedIdes.map((ide) => ({
5858
6321
  ideType: ide.ideType,
@@ -5883,7 +6346,7 @@ var DaemonStatusReporter = class {
5883
6346
  sendP2PPayload(payload) {
5884
6347
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
5885
6348
  if (hashTarget.machine) {
5886
- const { freeMem: _f, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
6349
+ const { freeMem: _f, availableMem: _a, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
5887
6350
  hashTarget.machine = stableMachine;
5888
6351
  }
5889
6352
  const h = this.simpleHash(JSON.stringify(hashTarget));
@@ -5905,17 +6368,34 @@ var DaemonStatusReporter = class {
5905
6368
  };
5906
6369
 
5907
6370
  // src/commands/cli-manager.ts
5908
- var os10 = __toESM(require("os"));
5909
- var path7 = __toESM(require("path"));
6371
+ var os12 = __toESM(require("os"));
6372
+ var path10 = __toESM(require("path"));
5910
6373
  var crypto4 = __toESM(require("crypto"));
5911
6374
  var import_chalk = __toESM(require("chalk"));
5912
6375
 
5913
6376
  // src/cli-adapters/provider-cli-adapter.ts
5914
- var os9 = __toESM(require("os"));
5915
- var import_child_process4 = require("child_process");
6377
+ var os11 = __toESM(require("os"));
6378
+ var path9 = __toESM(require("path"));
6379
+ var import_child_process5 = require("child_process");
5916
6380
  var pty;
5917
6381
  try {
5918
6382
  pty = require("node-pty");
6383
+ if (os11.platform() !== "win32") {
6384
+ try {
6385
+ const fs10 = require("fs");
6386
+ const ptyDir = path9.dirname(require.resolve("node-pty"));
6387
+ const arch3 = os11.arch() === "arm64" ? "darwin-arm64" : "darwin-x64";
6388
+ const helper = path9.join(ptyDir, "prebuilds", arch3, "spawn-helper");
6389
+ if (fs10.existsSync(helper)) {
6390
+ const stat = fs10.statSync(helper);
6391
+ if (!(stat.mode & 73)) {
6392
+ fs10.chmodSync(helper, stat.mode | 493);
6393
+ LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
6394
+ }
6395
+ }
6396
+ } catch {
6397
+ }
6398
+ }
5919
6399
  } catch {
5920
6400
  LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Install: npm install node-pty@1.0.0");
5921
6401
  }
@@ -5923,21 +6403,121 @@ function stripAnsi(str) {
5923
6403
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
5924
6404
  }
5925
6405
  function findBinary(name) {
5926
- const isWin = os9.platform() === "win32";
6406
+ const isWin = os11.platform() === "win32";
5927
6407
  try {
5928
6408
  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();
6409
+ return (0, import_child_process5.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
5930
6410
  } catch {
5931
6411
  return isWin ? `${name}.cmd` : name;
5932
6412
  }
5933
6413
  }
6414
+ function isScriptBinary(binaryPath) {
6415
+ if (!path9.isAbsolute(binaryPath)) return false;
6416
+ try {
6417
+ const fs10 = require("fs");
6418
+ const resolved = fs10.realpathSync(binaryPath);
6419
+ const head = Buffer.alloc(8);
6420
+ const fd = fs10.openSync(resolved, "r");
6421
+ fs10.readSync(fd, head, 0, 8, 0);
6422
+ fs10.closeSync(fd);
6423
+ let i = 0;
6424
+ if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
6425
+ return head[i] === 35 && head[i + 1] === 33;
6426
+ } catch {
6427
+ return false;
6428
+ }
6429
+ }
6430
+ function looksLikeMachOOrElf(filePath) {
6431
+ if (!path9.isAbsolute(filePath)) return false;
6432
+ try {
6433
+ const fs10 = require("fs");
6434
+ const resolved = fs10.realpathSync(filePath);
6435
+ const buf = Buffer.alloc(8);
6436
+ const fd = fs10.openSync(resolved, "r");
6437
+ fs10.readSync(fd, buf, 0, 8, 0);
6438
+ fs10.closeSync(fd);
6439
+ let i = 0;
6440
+ if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
6441
+ const b = buf.subarray(i);
6442
+ if (b.length < 4) return false;
6443
+ if (b[0] === 127 && b[1] === 69 && b[2] === 76 && b[3] === 70) return true;
6444
+ const le = b.readUInt32LE(0);
6445
+ const be = b.readUInt32BE(0);
6446
+ const magics = [4277009102, 4277009103, 3405691582, 3199925962];
6447
+ return magics.some((m) => m === le || m === be);
6448
+ } catch {
6449
+ return false;
6450
+ }
6451
+ }
6452
+ function shSingleQuote(arg) {
6453
+ if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
6454
+ return `'${arg.replace(/'/g, `'\\''`)}'`;
6455
+ }
6456
+ function parsePatternEntry(x) {
6457
+ if (x instanceof RegExp) return x;
6458
+ if (x && typeof x === "object" && typeof x.source === "string") {
6459
+ try {
6460
+ const s = x;
6461
+ return new RegExp(s.source, s.flags || "");
6462
+ } catch {
6463
+ return null;
6464
+ }
6465
+ }
6466
+ return null;
6467
+ }
6468
+ function coercePatternArray(raw, fallbacks) {
6469
+ if (!Array.isArray(raw)) return [...fallbacks];
6470
+ const parsed = raw.map(parsePatternEntry).filter((r) => r != null);
6471
+ return parsed.length > 0 ? parsed : [...fallbacks];
6472
+ }
6473
+ var FALLBACK_PROMPT = [
6474
+ /Type your message/i,
6475
+ />\s*$/,
6476
+ /[›➤]\s*$/,
6477
+ /for shortcuts/i,
6478
+ /\?\s*for help/i,
6479
+ /Press enter/i,
6480
+ /^[\s\u2500-\u257f]*>\s*$/m
6481
+ ];
6482
+ var FALLBACK_GENERATING = [
6483
+ /thinking/i,
6484
+ /writing/i,
6485
+ /Claude is/i,
6486
+ /Opus|Sonnet|Haiku/i,
6487
+ /[\u2800-\u28ff]/
6488
+ // Braille spinner blocks
6489
+ ];
6490
+ var FALLBACK_APPROVAL = [
6491
+ /approve/i,
6492
+ /Allow( once)?/i,
6493
+ /\(y\/n\)/i,
6494
+ /\[Y\/n\]/i,
6495
+ /continue\?/i,
6496
+ /Run this command/i
6497
+ ];
6498
+ function defaultCleanOutput(raw, _lastUserInput) {
6499
+ return stripAnsi(raw).trim();
6500
+ }
6501
+ function normalizeCliProviderForRuntime(raw) {
6502
+ const patterns = raw?.patterns || {};
6503
+ return {
6504
+ ...raw,
6505
+ patterns: {
6506
+ prompt: coercePatternArray(patterns.prompt, FALLBACK_PROMPT),
6507
+ generating: coercePatternArray(patterns.generating, FALLBACK_GENERATING),
6508
+ approval: coercePatternArray(patterns.approval, FALLBACK_APPROVAL),
6509
+ ready: coercePatternArray(patterns.ready, [])
6510
+ },
6511
+ cleanOutput: typeof raw?.cleanOutput === "function" ? raw.cleanOutput : defaultCleanOutput
6512
+ };
6513
+ }
5934
6514
  var ProviderCliAdapter = class {
5935
6515
  constructor(provider, workingDir, extraArgs = []) {
5936
6516
  this.extraArgs = extraArgs;
5937
- this.provider = provider;
6517
+ this.provider = normalizeCliProviderForRuntime(provider);
5938
6518
  this.cliType = provider.type;
5939
6519
  this.cliName = provider.name;
5940
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os9.homedir()) : workingDir;
6520
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os11.homedir()) : workingDir;
5941
6521
  const t = provider.timeouts || {};
5942
6522
  this.timeouts = {
5943
6523
  ptyFlush: t.ptyFlush ?? 50,
@@ -5995,20 +6575,25 @@ var ProviderCliAdapter = class {
5995
6575
  if (!pty) throw new Error("node-pty is not installed");
5996
6576
  const { spawn: spawnConfig } = this.provider;
5997
6577
  const binaryPath = findBinary(spawnConfig.command);
5998
- const isWin = os9.platform() === "win32";
6578
+ const isWin = os11.platform() === "win32";
5999
6579
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
6000
6580
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
6001
6581
  let shellCmd;
6002
6582
  let shellArgs;
6003
- if (spawnConfig.shell) {
6583
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
6584
+ const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
6585
+ if (useShell) {
6586
+ if (!spawnConfig.shell && !isWin) {
6587
+ LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
6588
+ }
6004
6589
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
6005
- const fullCmd = [binaryPath, ...allArgs].join(" ");
6590
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
6006
6591
  shellArgs = isWin ? ["/c", fullCmd] : ["-l", "-c", fullCmd];
6007
6592
  } else {
6008
6593
  shellCmd = binaryPath;
6009
6594
  shellArgs = allArgs;
6010
6595
  }
6011
- this.ptyProcess = pty.spawn(shellCmd, shellArgs, {
6596
+ const ptyOpts = {
6012
6597
  name: "xterm-256color",
6013
6598
  cols: 120,
6014
6599
  rows: 40,
@@ -6017,7 +6602,21 @@ var ProviderCliAdapter = class {
6017
6602
  ...process.env,
6018
6603
  ...spawnConfig.env
6019
6604
  }
6020
- });
6605
+ };
6606
+ try {
6607
+ this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
6608
+ } catch (err) {
6609
+ const msg = err?.message || String(err);
6610
+ if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
6611
+ LOG.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
6612
+ shellCmd = process.env.SHELL || "/bin/zsh";
6613
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
6614
+ shellArgs = ["-l", "-c", fullCmd];
6615
+ this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
6616
+ } else {
6617
+ throw err;
6618
+ }
6619
+ }
6021
6620
  this.ptyProcess.onData((data) => {
6022
6621
  this.handleOutput(data);
6023
6622
  if (this.onPtyDataCallback) {
@@ -6235,6 +6834,7 @@ var ProviderCliAdapter = class {
6235
6834
 
6236
6835
  // src/commands/cli-manager.ts
6237
6836
  init_config();
6837
+ init_workspaces();
6238
6838
 
6239
6839
  // src/providers/cli-provider-instance.ts
6240
6840
  var crypto3 = __toESM(require("crypto"));
@@ -6400,7 +7000,7 @@ var CliProviderInstance = class {
6400
7000
 
6401
7001
  // src/providers/acp-provider-instance.ts
6402
7002
  var import_stream = require("stream");
6403
- var import_child_process5 = require("child_process");
7003
+ var import_child_process6 = require("child_process");
6404
7004
  var import_sdk = require("@agentclientprotocol/sdk");
6405
7005
 
6406
7006
  // src/providers/contracts.ts
@@ -6721,7 +7321,7 @@ var AcpProviderInstance = class {
6721
7321
  this.errorMessage = null;
6722
7322
  this.errorReason = null;
6723
7323
  this.stderrBuffer = [];
6724
- this.process = (0, import_child_process5.spawn)(command, args, {
7324
+ this.process = (0, import_child_process6.spawn)(command, args, {
6725
7325
  cwd: this.workingDir,
6726
7326
  env,
6727
7327
  stdio: ["pipe", "pipe", "pipe"],
@@ -6825,13 +7425,13 @@ var AcpProviderInstance = class {
6825
7425
  }
6826
7426
  this.currentStatus = "waiting_approval";
6827
7427
  this.detectStatusTransition();
6828
- const approved = await new Promise((resolve5) => {
6829
- this.permissionResolvers.push(resolve5);
7428
+ const approved = await new Promise((resolve7) => {
7429
+ this.permissionResolvers.push(resolve7);
6830
7430
  setTimeout(() => {
6831
- const idx = this.permissionResolvers.indexOf(resolve5);
7431
+ const idx = this.permissionResolvers.indexOf(resolve7);
6832
7432
  if (idx >= 0) {
6833
7433
  this.permissionResolvers.splice(idx, 1);
6834
- resolve5(false);
7434
+ resolve7(false);
6835
7435
  }
6836
7436
  }, 3e5);
6837
7437
  });
@@ -7301,6 +7901,24 @@ var DaemonCliManager = class {
7301
7901
  const hash = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
7302
7902
  return `${cliType}_${hash}`;
7303
7903
  }
7904
+ persistRecentDir(cliType, dir) {
7905
+ try {
7906
+ const normalizedType = this.providerLoader.resolveAlias(cliType);
7907
+ const provider = this.providerLoader.getByAlias(cliType);
7908
+ const actKind = provider?.category === "acp" ? "acp" : "cli";
7909
+ let next = loadConfig();
7910
+ console.log(import_chalk.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
7911
+ const recent = next.recentCliWorkspaces || [];
7912
+ if (!recent.includes(dir)) {
7913
+ next = { ...next, recentCliWorkspaces: [dir, ...recent].slice(0, 10) };
7914
+ }
7915
+ next = appendWorkspaceActivity(next, dir, { kind: actKind, agentType: normalizedType });
7916
+ saveConfig(next);
7917
+ console.log(import_chalk.default.green(` \u2713 Recent workspace saved: ${dir}`));
7918
+ } catch (e) {
7919
+ console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
7920
+ }
7921
+ }
7304
7922
  createAdapter(cliType, workingDir, cliArgs) {
7305
7923
  const normalizedType = this.providerLoader.resolveAlias(cliType);
7306
7924
  const provider = this.providerLoader.getMeta(normalizedType);
@@ -7312,8 +7930,9 @@ var DaemonCliManager = class {
7312
7930
  }
7313
7931
  // ─── Session start/management ──────────────────────────────
7314
7932
  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);
7933
+ const trimmed = (workingDir || "").trim();
7934
+ if (!trimmed) throw new Error("working directory required");
7935
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path10.resolve(trimmed);
7317
7936
  const normalizedType = this.providerLoader.resolveAlias(cliType);
7318
7937
  const provider = this.providerLoader.getByAlias(cliType);
7319
7938
  const key = crypto4.randomUUID();
@@ -7323,8 +7942,8 @@ var DaemonCliManager = class {
7323
7942
  const spawnCmd = provider.spawn?.command;
7324
7943
  if (spawnCmd) {
7325
7944
  try {
7326
- const { execSync: execSync6 } = require("child_process");
7327
- execSync6(`which ${spawnCmd}`, { stdio: "ignore" });
7945
+ const { execSync: execSync7 } = require("child_process");
7946
+ execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
7328
7947
  } catch {
7329
7948
  const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
7330
7949
  throw new Error(
@@ -7391,18 +8010,52 @@ ${installInfo}`
7391
8010
  const instanceManager = this.deps.getInstanceManager();
7392
8011
  if (provider && instanceManager) {
7393
8012
  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
- });
8013
+ try {
8014
+ await instanceManager.addInstance(key, cliInstance, {
8015
+ serverConn: this.deps.getServerConn(),
8016
+ settings: {},
8017
+ onPtyData: (data) => {
8018
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
8019
+ }
8020
+ });
8021
+ } catch (spawnErr) {
8022
+ LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
8023
+ instanceManager.removeInstance(key);
8024
+ throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
8025
+ }
7401
8026
  this.adapters.set(key, cliInstance.getAdapter());
7402
8027
  console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
8028
+ const checkStopped = setInterval(() => {
8029
+ try {
8030
+ const adapter = this.adapters.get(key);
8031
+ if (!adapter) {
8032
+ clearInterval(checkStopped);
8033
+ return;
8034
+ }
8035
+ const status = adapter.getStatus?.();
8036
+ if (status?.status === "stopped" || status?.status === "error") {
8037
+ clearInterval(checkStopped);
8038
+ setTimeout(() => {
8039
+ if (this.adapters.has(key)) {
8040
+ this.adapters.delete(key);
8041
+ this.deps.removeAgentTracking(key);
8042
+ instanceManager.removeInstance(key);
8043
+ LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${cliType}`);
8044
+ this.deps.onStatusChange();
8045
+ }
8046
+ }, 5e3);
8047
+ }
8048
+ } catch {
8049
+ }
8050
+ }, 3e3);
7403
8051
  } else {
7404
8052
  const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
7405
- await adapter.spawn();
8053
+ try {
8054
+ await adapter.spawn();
8055
+ } catch (spawnErr) {
8056
+ LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
8057
+ throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
8058
+ }
7406
8059
  const serverConn = this.deps.getServerConn();
7407
8060
  if (serverConn && typeof adapter.setServerConn === "function") {
7408
8061
  adapter.setServerConn(serverConn);
@@ -7410,12 +8063,12 @@ ${installInfo}`
7410
8063
  adapter.setOnStatusChange(() => {
7411
8064
  this.deps.onStatusChange();
7412
8065
  const status = adapter.getStatus?.();
7413
- if (status?.status === "stopped") {
8066
+ if (status?.status === "stopped" || status?.status === "error") {
7414
8067
  setTimeout(() => {
7415
8068
  if (this.adapters.get(key) === adapter) {
7416
8069
  this.adapters.delete(key);
7417
8070
  this.deps.removeAgentTracking(key);
7418
- console.log(import_chalk.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
8071
+ LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${adapter.cliType}`);
7419
8072
  this.deps.onStatusChange();
7420
8073
  }
7421
8074
  }, 3e3);
@@ -7439,12 +8092,24 @@ ${installInfo}`
7439
8092
  async stopSession(key) {
7440
8093
  const adapter = this.adapters.get(key);
7441
8094
  if (adapter) {
7442
- adapter.shutdown();
8095
+ try {
8096
+ adapter.shutdown();
8097
+ } catch (e) {
8098
+ LOG.warn("CLI", `Shutdown error for ${adapter.cliType}: ${e?.message} (force-cleaning)`);
8099
+ }
7443
8100
  this.adapters.delete(key);
7444
8101
  this.deps.removeAgentTracking(key);
7445
8102
  this.deps.getInstanceManager()?.removeInstance(key);
7446
- console.log(import_chalk.default.yellow(` \u{1F6D1} CLI Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`));
8103
+ LOG.info("CLI", `\u{1F6D1} Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
7447
8104
  this.deps.onStatusChange();
8105
+ } else {
8106
+ const im = this.deps.getInstanceManager();
8107
+ if (im) {
8108
+ im.removeInstance(key);
8109
+ this.deps.removeAgentTracking(key);
8110
+ LOG.warn("CLI", `\u{1F9F9} Force-removed orphan entry: ${key}`);
8111
+ this.deps.onStatusChange();
8112
+ }
7448
8113
  }
7449
8114
  }
7450
8115
  shutdownAll() {
@@ -7485,8 +8150,28 @@ ${installInfo}`
7485
8150
  switch (cmd) {
7486
8151
  case "launch_cli": {
7487
8152
  const cliType = args?.cliType;
7488
- const defaultedToHome = !args?.dir;
7489
- const dir = args?.dir || os10.homedir();
8153
+ const config = loadConfig();
8154
+ const resolved = resolveLaunchDirectory(
8155
+ {
8156
+ dir: args?.dir,
8157
+ workspaceId: args?.workspaceId,
8158
+ useDefaultWorkspace: args?.useDefaultWorkspace === true,
8159
+ useHome: args?.useHome === true
8160
+ },
8161
+ config
8162
+ );
8163
+ if (!resolved.ok) {
8164
+ const ws = getWorkspaceState(config);
8165
+ return {
8166
+ success: false,
8167
+ error: resolved.message,
8168
+ code: resolved.code,
8169
+ workspaces: ws.workspaces,
8170
+ defaultWorkspacePath: ws.defaultWorkspacePath
8171
+ };
8172
+ }
8173
+ const dir = resolved.path;
8174
+ const launchSource = resolved.source;
7490
8175
  if (!cliType) throw new Error("cliType required");
7491
8176
  await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
7492
8177
  let newKey = null;
@@ -7495,19 +8180,8 @@ ${installInfo}`
7495
8180
  newKey = k;
7496
8181
  }
7497
8182
  }
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 };
8183
+ this.persistRecentDir(cliType, dir);
8184
+ return { success: true, cliType, dir, id: newKey, launchSource };
7511
8185
  }
7512
8186
  case "stop_cli": {
7513
8187
  const cliType = args?.cliType;
@@ -7523,11 +8197,32 @@ ${installInfo}`
7523
8197
  }
7524
8198
  case "restart_session": {
7525
8199
  const cliType = args?.cliType || args?.agentType || args?.ideType;
7526
- const dir = args?.dir || process.cwd();
8200
+ const cfg = loadConfig();
8201
+ const rdir = resolveLaunchDirectory(
8202
+ {
8203
+ dir: args?.dir,
8204
+ workspaceId: args?.workspaceId,
8205
+ useDefaultWorkspace: args?.useDefaultWorkspace === true,
8206
+ useHome: args?.useHome === true
8207
+ },
8208
+ cfg
8209
+ );
8210
+ if (!rdir.ok) {
8211
+ const ws = getWorkspaceState(cfg);
8212
+ return {
8213
+ success: false,
8214
+ error: rdir.message,
8215
+ code: rdir.code,
8216
+ workspaces: ws.workspaces,
8217
+ defaultWorkspacePath: ws.defaultWorkspacePath
8218
+ };
8219
+ }
8220
+ const dir = rdir.path;
7527
8221
  if (!cliType) throw new Error("cliType required");
7528
8222
  const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
7529
8223
  if (found) await this.stopSession(found.key);
7530
8224
  await this.startSession(cliType, dir);
8225
+ this.persistRecentDir(cliType, dir);
7531
8226
  return { success: true, restarted: true };
7532
8227
  }
7533
8228
  case "agent_command": {
@@ -8167,12 +8862,12 @@ var ProviderInstanceManager = class {
8167
8862
  };
8168
8863
 
8169
8864
  // 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");
8865
+ var fs8 = __toESM(require("fs"));
8866
+ var path11 = __toESM(require("path"));
8867
+ var os13 = __toESM(require("os"));
8868
+ var import_child_process7 = require("child_process");
8174
8869
  var import_os3 = require("os");
8175
- var ARCHIVE_PATH = path8.join(os11.homedir(), ".adhdev", "version-history.json");
8870
+ var ARCHIVE_PATH = path11.join(os13.homedir(), ".adhdev", "version-history.json");
8176
8871
  var MAX_ENTRIES_PER_PROVIDER = 20;
8177
8872
  var VersionArchive = class {
8178
8873
  history = {};
@@ -8181,8 +8876,8 @@ var VersionArchive = class {
8181
8876
  }
8182
8877
  load() {
8183
8878
  try {
8184
- if (fs7.existsSync(ARCHIVE_PATH)) {
8185
- this.history = JSON.parse(fs7.readFileSync(ARCHIVE_PATH, "utf-8"));
8879
+ if (fs8.existsSync(ARCHIVE_PATH)) {
8880
+ this.history = JSON.parse(fs8.readFileSync(ARCHIVE_PATH, "utf-8"));
8186
8881
  }
8187
8882
  } catch {
8188
8883
  this.history = {};
@@ -8219,15 +8914,15 @@ var VersionArchive = class {
8219
8914
  }
8220
8915
  save() {
8221
8916
  try {
8222
- fs7.mkdirSync(path8.dirname(ARCHIVE_PATH), { recursive: true });
8223
- fs7.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
8917
+ fs8.mkdirSync(path11.dirname(ARCHIVE_PATH), { recursive: true });
8918
+ fs8.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
8224
8919
  } catch {
8225
8920
  }
8226
8921
  }
8227
8922
  };
8228
8923
  function runCommand(cmd, timeout = 1e4) {
8229
8924
  try {
8230
- return (0, import_child_process6.execSync)(cmd, {
8925
+ return (0, import_child_process7.execSync)(cmd, {
8231
8926
  encoding: "utf-8",
8232
8927
  timeout,
8233
8928
  stdio: ["pipe", "pipe", "pipe"]
@@ -8259,19 +8954,19 @@ function getVersion(binary, versionCommand) {
8259
8954
  function checkPathExists2(paths) {
8260
8955
  for (const p of paths) {
8261
8956
  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;
8957
+ const home = os13.homedir();
8958
+ const resolved = p.replace(/\*/g, home.split(path11.sep).pop() || "");
8959
+ if (fs8.existsSync(resolved)) return resolved;
8265
8960
  } else {
8266
- if (fs7.existsSync(p)) return p;
8961
+ if (fs8.existsSync(p)) return p;
8267
8962
  }
8268
8963
  }
8269
8964
  return null;
8270
8965
  }
8271
8966
  function getMacAppVersion(appPath) {
8272
8967
  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;
8968
+ const plistPath = path11.join(appPath, "Contents", "Info.plist");
8969
+ if (!fs8.existsSync(plistPath)) return null;
8275
8970
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
8276
8971
  return raw || null;
8277
8972
  }
@@ -8296,8 +8991,8 @@ async function detectAllVersions(loader, archive) {
8296
8991
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
8297
8992
  let resolvedBin = cliBin;
8298
8993
  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;
8994
+ const bundled = path11.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
8995
+ if (provider.cli && fs8.existsSync(bundled)) resolvedBin = bundled;
8301
8996
  }
8302
8997
  info.installed = !!(appPath || resolvedBin);
8303
8998
  info.path = appPath || null;
@@ -8336,9 +9031,9 @@ async function detectAllVersions(loader, archive) {
8336
9031
 
8337
9032
  // src/daemon/dev-server.ts
8338
9033
  var http2 = __toESM(require("http"));
8339
- var fs8 = __toESM(require("fs"));
8340
- var path9 = __toESM(require("path"));
8341
- var os12 = __toESM(require("os"));
9034
+ var fs9 = __toESM(require("fs"));
9035
+ var path12 = __toESM(require("path"));
9036
+ var os14 = __toESM(require("os"));
8342
9037
 
8343
9038
  // src/daemon/scaffold-template.ts
8344
9039
  function generateFiles(type, name, category, opts = {}) {
@@ -8741,8 +9436,8 @@ var DevServer = class _DevServer {
8741
9436
  }
8742
9437
  getEndpointList() {
8743
9438
  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}`;
9439
+ const path13 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
9440
+ return `${r.method.padEnd(5)} ${path13}`;
8746
9441
  });
8747
9442
  }
8748
9443
  async start(port = DEV_SERVER_PORT) {
@@ -8773,15 +9468,15 @@ var DevServer = class _DevServer {
8773
9468
  this.json(res, 500, { error: e.message });
8774
9469
  }
8775
9470
  });
8776
- return new Promise((resolve5, reject) => {
9471
+ return new Promise((resolve7, reject) => {
8777
9472
  this.server.listen(port, "127.0.0.1", () => {
8778
9473
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
8779
- resolve5();
9474
+ resolve7();
8780
9475
  });
8781
9476
  this.server.on("error", (e) => {
8782
9477
  if (e.code === "EADDRINUSE") {
8783
9478
  this.log(`Port ${port} in use, skipping dev server`);
8784
- resolve5();
9479
+ resolve7();
8785
9480
  } else {
8786
9481
  reject(e);
8787
9482
  }
@@ -8864,20 +9559,20 @@ var DevServer = class _DevServer {
8864
9559
  child.stderr?.on("data", (d) => {
8865
9560
  stderr += d.toString().slice(0, 2e3);
8866
9561
  });
8867
- await new Promise((resolve5) => {
9562
+ await new Promise((resolve7) => {
8868
9563
  const timer = setTimeout(() => {
8869
9564
  child.kill();
8870
- resolve5();
9565
+ resolve7();
8871
9566
  }, 3e3);
8872
9567
  child.on("exit", () => {
8873
9568
  clearTimeout(timer);
8874
- resolve5();
9569
+ resolve7();
8875
9570
  });
8876
9571
  child.stdout?.once("data", () => {
8877
9572
  setTimeout(() => {
8878
9573
  child.kill();
8879
9574
  clearTimeout(timer);
8880
- resolve5();
9575
+ resolve7();
8881
9576
  }, 500);
8882
9577
  });
8883
9578
  });
@@ -9087,12 +9782,12 @@ var DevServer = class _DevServer {
9087
9782
  // ─── DevConsole SPA ───
9088
9783
  getConsoleDistDir() {
9089
9784
  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")
9785
+ path12.resolve(__dirname, "../../web-devconsole/dist"),
9786
+ path12.resolve(__dirname, "../../../web-devconsole/dist"),
9787
+ path12.join(process.cwd(), "packages/web-devconsole/dist")
9093
9788
  ];
9094
9789
  for (const dir of candidates) {
9095
- if (fs8.existsSync(path9.join(dir, "index.html"))) return dir;
9790
+ if (fs9.existsSync(path12.join(dir, "index.html"))) return dir;
9096
9791
  }
9097
9792
  return null;
9098
9793
  }
@@ -9102,9 +9797,9 @@ var DevServer = class _DevServer {
9102
9797
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
9103
9798
  return;
9104
9799
  }
9105
- const htmlPath = path9.join(distDir, "index.html");
9800
+ const htmlPath = path12.join(distDir, "index.html");
9106
9801
  try {
9107
- const html = fs8.readFileSync(htmlPath, "utf-8");
9802
+ const html = fs9.readFileSync(htmlPath, "utf-8");
9108
9803
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
9109
9804
  res.end(html);
9110
9805
  } catch (e) {
@@ -9127,15 +9822,15 @@ var DevServer = class _DevServer {
9127
9822
  this.json(res, 404, { error: "Not found" });
9128
9823
  return;
9129
9824
  }
9130
- const safePath = path9.normalize(pathname).replace(/^\.\.\//, "");
9131
- const filePath = path9.join(distDir, safePath);
9825
+ const safePath = path12.normalize(pathname).replace(/^\.\.\//, "");
9826
+ const filePath = path12.join(distDir, safePath);
9132
9827
  if (!filePath.startsWith(distDir)) {
9133
9828
  this.json(res, 403, { error: "Forbidden" });
9134
9829
  return;
9135
9830
  }
9136
9831
  try {
9137
- const content = fs8.readFileSync(filePath);
9138
- const ext = path9.extname(filePath);
9832
+ const content = fs9.readFileSync(filePath);
9833
+ const ext = path12.extname(filePath);
9139
9834
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
9140
9835
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
9141
9836
  res.end(content);
@@ -9234,26 +9929,26 @@ var DevServer = class _DevServer {
9234
9929
  const provider = this.providerLoader.getMeta(type);
9235
9930
  if (!provider) return null;
9236
9931
  const cat = provider.category;
9237
- const builtinDir = this.providerLoader.builtinDir || path9.resolve(__dirname, "../providers/_builtin");
9238
- const userDir = path9.join(os12.homedir(), ".adhdev", "providers");
9932
+ const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
9933
+ const userDir = path12.join(os14.homedir(), ".adhdev", "providers");
9239
9934
  const directCandidates = [
9240
- path9.join(userDir, type),
9241
- path9.join(builtinDir, cat, type),
9242
- path9.join(builtinDir, type)
9935
+ path12.join(userDir, type),
9936
+ path12.join(builtinDir, cat, type),
9937
+ path12.join(builtinDir, type)
9243
9938
  ];
9244
9939
  for (const d of directCandidates) {
9245
- if (fs8.existsSync(path9.join(d, "provider.json"))) return d;
9940
+ if (fs9.existsSync(path12.join(d, "provider.json"))) return d;
9246
9941
  }
9247
- const catDir = path9.join(builtinDir, cat);
9248
- if (fs8.existsSync(catDir)) {
9942
+ const catDir = path12.join(builtinDir, cat);
9943
+ if (fs9.existsSync(catDir)) {
9249
9944
  try {
9250
- for (const entry of fs8.readdirSync(catDir, { withFileTypes: true })) {
9945
+ for (const entry of fs9.readdirSync(catDir, { withFileTypes: true })) {
9251
9946
  if (!entry.isDirectory()) continue;
9252
- const jsonPath = path9.join(catDir, entry.name, "provider.json");
9253
- if (fs8.existsSync(jsonPath)) {
9947
+ const jsonPath = path12.join(catDir, entry.name, "provider.json");
9948
+ if (fs9.existsSync(jsonPath)) {
9254
9949
  try {
9255
- const data = JSON.parse(fs8.readFileSync(jsonPath, "utf-8"));
9256
- if (data.type === type) return path9.join(catDir, entry.name);
9950
+ const data = JSON.parse(fs9.readFileSync(jsonPath, "utf-8"));
9951
+ if (data.type === type) return path12.join(catDir, entry.name);
9257
9952
  } catch {
9258
9953
  }
9259
9954
  }
@@ -9273,14 +9968,14 @@ var DevServer = class _DevServer {
9273
9968
  const files = [];
9274
9969
  const scan = (d, prefix) => {
9275
9970
  try {
9276
- for (const entry of fs8.readdirSync(d, { withFileTypes: true })) {
9971
+ for (const entry of fs9.readdirSync(d, { withFileTypes: true })) {
9277
9972
  if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
9278
9973
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
9279
9974
  if (entry.isDirectory()) {
9280
9975
  files.push({ path: rel, size: 0, type: "dir" });
9281
- scan(path9.join(d, entry.name), rel);
9976
+ scan(path12.join(d, entry.name), rel);
9282
9977
  } else {
9283
- const stat = fs8.statSync(path9.join(d, entry.name));
9978
+ const stat = fs9.statSync(path12.join(d, entry.name));
9284
9979
  files.push({ path: rel, size: stat.size, type: "file" });
9285
9980
  }
9286
9981
  }
@@ -9303,16 +9998,16 @@ var DevServer = class _DevServer {
9303
9998
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
9304
9999
  return;
9305
10000
  }
9306
- const fullPath = path9.resolve(dir, path9.normalize(filePath));
10001
+ const fullPath = path12.resolve(dir, path12.normalize(filePath));
9307
10002
  if (!fullPath.startsWith(dir)) {
9308
10003
  this.json(res, 403, { error: "Forbidden" });
9309
10004
  return;
9310
10005
  }
9311
- if (!fs8.existsSync(fullPath) || fs8.statSync(fullPath).isDirectory()) {
10006
+ if (!fs9.existsSync(fullPath) || fs9.statSync(fullPath).isDirectory()) {
9312
10007
  this.json(res, 404, { error: `File not found: ${filePath}` });
9313
10008
  return;
9314
10009
  }
9315
- const content = fs8.readFileSync(fullPath, "utf-8");
10010
+ const content = fs9.readFileSync(fullPath, "utf-8");
9316
10011
  this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
9317
10012
  }
9318
10013
  /** POST /api/providers/:type/file — write a file { path, content } */
@@ -9328,15 +10023,15 @@ var DevServer = class _DevServer {
9328
10023
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
9329
10024
  return;
9330
10025
  }
9331
- const fullPath = path9.resolve(dir, path9.normalize(filePath));
10026
+ const fullPath = path12.resolve(dir, path12.normalize(filePath));
9332
10027
  if (!fullPath.startsWith(dir)) {
9333
10028
  this.json(res, 403, { error: "Forbidden" });
9334
10029
  return;
9335
10030
  }
9336
10031
  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");
10032
+ if (fs9.existsSync(fullPath)) fs9.copyFileSync(fullPath, fullPath + ".bak");
10033
+ fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
10034
+ fs9.writeFileSync(fullPath, content, "utf-8");
9340
10035
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
9341
10036
  this.providerLoader.reload();
9342
10037
  this.json(res, 200, { saved: true, path: filePath, chars: content.length });
@@ -9352,9 +10047,9 @@ var DevServer = class _DevServer {
9352
10047
  return;
9353
10048
  }
9354
10049
  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");
10050
+ const p = path12.join(dir, name);
10051
+ if (fs9.existsSync(p)) {
10052
+ const source = fs9.readFileSync(p, "utf-8");
9358
10053
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
9359
10054
  return;
9360
10055
  }
@@ -9373,11 +10068,11 @@ var DevServer = class _DevServer {
9373
10068
  this.json(res, 404, { error: `Provider not found: ${type}` });
9374
10069
  return;
9375
10070
  }
9376
- const target = fs8.existsSync(path9.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
9377
- const targetPath = path9.join(dir, target);
10071
+ const target = fs9.existsSync(path12.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
10072
+ const targetPath = path12.join(dir, target);
9378
10073
  try {
9379
- if (fs8.existsSync(targetPath)) fs8.copyFileSync(targetPath, targetPath + ".bak");
9380
- fs8.writeFileSync(targetPath, source, "utf-8");
10074
+ if (fs9.existsSync(targetPath)) fs9.copyFileSync(targetPath, targetPath + ".bak");
10075
+ fs9.writeFileSync(targetPath, source, "utf-8");
9381
10076
  this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
9382
10077
  this.providerLoader.reload();
9383
10078
  this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
@@ -9392,18 +10087,18 @@ var DevServer = class _DevServer {
9392
10087
  return;
9393
10088
  }
9394
10089
  let scriptsPath = "";
9395
- const directScripts = path9.join(dir, "scripts.js");
9396
- if (fs8.existsSync(directScripts)) {
10090
+ const directScripts = path12.join(dir, "scripts.js");
10091
+ if (fs9.existsSync(directScripts)) {
9397
10092
  scriptsPath = directScripts;
9398
10093
  } 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();
10094
+ const scriptsDir = path12.join(dir, "scripts");
10095
+ if (fs9.existsSync(scriptsDir)) {
10096
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
10097
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
9403
10098
  }).sort().reverse();
9404
10099
  for (const ver of versions) {
9405
- const p = path9.join(scriptsDir, ver, "scripts.js");
9406
- if (fs8.existsSync(p)) {
10100
+ const p = path12.join(scriptsDir, ver, "scripts.js");
10101
+ if (fs9.existsSync(p)) {
9407
10102
  scriptsPath = p;
9408
10103
  break;
9409
10104
  }
@@ -9415,7 +10110,7 @@ var DevServer = class _DevServer {
9415
10110
  return;
9416
10111
  }
9417
10112
  try {
9418
- const source = fs8.readFileSync(scriptsPath, "utf-8");
10113
+ const source = fs9.readFileSync(scriptsPath, "utf-8");
9419
10114
  const hints = {};
9420
10115
  const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
9421
10116
  let match;
@@ -9559,14 +10254,14 @@ var DevServer = class _DevServer {
9559
10254
  child.stderr?.on("data", (d) => {
9560
10255
  stderr += d.toString();
9561
10256
  });
9562
- await new Promise((resolve5) => {
10257
+ await new Promise((resolve7) => {
9563
10258
  const timer = setTimeout(() => {
9564
10259
  child.kill();
9565
- resolve5();
10260
+ resolve7();
9566
10261
  }, timeout);
9567
10262
  child.on("exit", () => {
9568
10263
  clearTimeout(timer);
9569
- resolve5();
10264
+ resolve7();
9570
10265
  });
9571
10266
  });
9572
10267
  const elapsed = Date.now() - start;
@@ -9616,26 +10311,26 @@ var DevServer = class _DevServer {
9616
10311
  }
9617
10312
  let targetDir;
9618
10313
  if (location === "user") {
9619
- targetDir = path9.join(os12.homedir(), ".adhdev", "providers", type);
10314
+ targetDir = path12.join(os14.homedir(), ".adhdev", "providers", type);
9620
10315
  } else {
9621
- const builtinDir = path9.resolve(__dirname, "../providers/_builtin");
9622
- targetDir = path9.join(builtinDir, category, type);
10316
+ const builtinDir = path12.resolve(__dirname, "../providers/_builtin");
10317
+ targetDir = path12.join(builtinDir, category, type);
9623
10318
  }
9624
- const jsonPath = path9.join(targetDir, "provider.json");
9625
- if (fs8.existsSync(jsonPath)) {
10319
+ const jsonPath = path12.join(targetDir, "provider.json");
10320
+ if (fs9.existsSync(jsonPath)) {
9626
10321
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
9627
10322
  return;
9628
10323
  }
9629
10324
  try {
9630
10325
  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");
10326
+ fs9.mkdirSync(targetDir, { recursive: true });
10327
+ fs9.writeFileSync(jsonPath, result["provider.json"], "utf-8");
9633
10328
  const createdFiles = ["provider.json"];
9634
10329
  if (result.files) {
9635
10330
  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");
10331
+ const fullPath = path12.join(targetDir, relPath);
10332
+ fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
10333
+ fs9.writeFileSync(fullPath, content, "utf-8");
9639
10334
  createdFiles.push(relPath);
9640
10335
  }
9641
10336
  }
@@ -10470,24 +11165,24 @@ var DevServer = class _DevServer {
10470
11165
  }
10471
11166
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
10472
11167
  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) => {
11168
+ const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
11169
+ const refDir = path12.join(builtinDir, "ide", reference);
11170
+ if (fs9.existsSync(refDir)) {
11171
+ const scriptsDir = path12.join(refDir, "scripts");
11172
+ if (fs9.existsSync(scriptsDir)) {
11173
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
10479
11174
  try {
10480
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
11175
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
10481
11176
  } catch {
10482
11177
  return false;
10483
11178
  }
10484
11179
  }).sort().reverse();
10485
11180
  if (versions.length > 0) {
10486
- const latestDir = path9.join(scriptsDir, versions[0]);
10487
- for (const file of fs8.readdirSync(latestDir)) {
11181
+ const latestDir = path12.join(scriptsDir, versions[0]);
11182
+ for (const file of fs9.readdirSync(latestDir)) {
10488
11183
  if (file.endsWith(".js")) {
10489
11184
  try {
10490
- referenceScripts[file] = fs8.readFileSync(path9.join(latestDir, file), "utf-8");
11185
+ referenceScripts[file] = fs9.readFileSync(path12.join(latestDir, file), "utf-8");
10491
11186
  } catch {
10492
11187
  }
10493
11188
  }
@@ -10496,16 +11191,16 @@ var DevServer = class _DevServer {
10496
11191
  }
10497
11192
  }
10498
11193
  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");
11194
+ const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
11195
+ if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
11196
+ const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
11197
+ fs9.writeFileSync(promptFile, prompt, "utf-8");
10503
11198
  this.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
10504
11199
  const agentProvider = this.providerLoader.resolve(agent) || this.providerLoader.getMeta(agent);
10505
11200
  const spawn3 = agentProvider?.spawn;
10506
11201
  if (!spawn3?.command) {
10507
11202
  try {
10508
- fs8.unlinkSync(promptFile);
11203
+ fs9.unlinkSync(promptFile);
10509
11204
  } catch {
10510
11205
  }
10511
11206
  this.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
@@ -10606,7 +11301,7 @@ var DevServer = class _DevServer {
10606
11301
  } catch {
10607
11302
  }
10608
11303
  try {
10609
- fs8.unlinkSync(promptFile);
11304
+ fs9.unlinkSync(promptFile);
10610
11305
  } catch {
10611
11306
  }
10612
11307
  this.log(`Auto-implement (ACP) ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -10662,12 +11357,12 @@ var DevServer = class _DevServer {
10662
11357
  } else {
10663
11358
  args = [...baseArgs];
10664
11359
  }
10665
- const { execSync: execSync6 } = await import("child_process");
11360
+ const { execSync: execSync7 } = await import("child_process");
10666
11361
  try {
10667
- execSync6(`which ${command}`, { stdio: "pipe" });
11362
+ execSync7(`which ${command}`, { stdio: "pipe" });
10668
11363
  } catch {
10669
11364
  try {
10670
- fs8.unlinkSync(promptFile);
11365
+ fs9.unlinkSync(promptFile);
10671
11366
  } catch {
10672
11367
  }
10673
11368
  this.json(res, 400, { error: `Agent binary '${command}' not found on PATH. Install it first: ${agentProvider?.install || "check provider docs"}` });
@@ -10723,7 +11418,7 @@ var DevServer = class _DevServer {
10723
11418
  } catch {
10724
11419
  }
10725
11420
  try {
10726
- fs8.unlinkSync(promptFile);
11421
+ fs9.unlinkSync(promptFile);
10727
11422
  } catch {
10728
11423
  }
10729
11424
  this.log(`Auto-implement ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -10753,23 +11448,23 @@ var DevServer = class _DevServer {
10753
11448
  lines.push("## Current Target Files");
10754
11449
  lines.push("These are the files you need to EDIT. They contain TODO stubs \u2014 replace them with working implementations.");
10755
11450
  lines.push("");
10756
- const scriptsDir = path9.join(providerDir, "scripts");
10757
- if (fs8.existsSync(scriptsDir)) {
10758
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
11451
+ const scriptsDir = path12.join(providerDir, "scripts");
11452
+ if (fs9.existsSync(scriptsDir)) {
11453
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
10759
11454
  try {
10760
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
11455
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
10761
11456
  } catch {
10762
11457
  return false;
10763
11458
  }
10764
11459
  }).sort().reverse();
10765
11460
  if (versions.length > 0) {
10766
- const vDir = path9.join(scriptsDir, versions[0]);
11461
+ const vDir = path12.join(scriptsDir, versions[0]);
10767
11462
  lines.push(`Scripts version directory: \`${vDir}\``);
10768
11463
  lines.push("");
10769
- for (const file of fs8.readdirSync(vDir)) {
11464
+ for (const file of fs9.readdirSync(vDir)) {
10770
11465
  if (file.endsWith(".js")) {
10771
11466
  try {
10772
- const content = fs8.readFileSync(path9.join(vDir, file), "utf-8");
11467
+ const content = fs9.readFileSync(path12.join(vDir, file), "utf-8");
10773
11468
  lines.push(`### \`${file}\``);
10774
11469
  lines.push("```javascript");
10775
11470
  lines.push(content);
@@ -10840,7 +11535,7 @@ var DevServer = class _DevServer {
10840
11535
  lines.push("## Required Return Format");
10841
11536
  lines.push("| Function | Return JSON |");
10842
11537
  lines.push("|---|---|");
10843
- lines.push("| readChat | `{ id, status, title, messages: [{role, content, index}], inputContent, activeModal }` |");
11538
+ 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
11539
  lines.push("| sendMessage | `{ sent: false, needsTypeAndSend: true, selector }` |");
10845
11540
  lines.push("| resolveAction | `{ resolved: true/false, clicked? }` |");
10846
11541
  lines.push("| listSessions | `{ sessions: [{ id, title, active, index }] }` |");
@@ -10964,14 +11659,14 @@ data: ${JSON.stringify(msg.data)}
10964
11659
  res.end(JSON.stringify(data, null, 2));
10965
11660
  }
10966
11661
  async readBody(req) {
10967
- return new Promise((resolve5) => {
11662
+ return new Promise((resolve7) => {
10968
11663
  let body = "";
10969
11664
  req.on("data", (chunk) => body += chunk);
10970
11665
  req.on("end", () => {
10971
11666
  try {
10972
- resolve5(JSON.parse(body));
11667
+ resolve7(JSON.parse(body));
10973
11668
  } catch {
10974
- resolve5({});
11669
+ resolve7({});
10975
11670
  }
10976
11671
  });
10977
11672
  });
@@ -10979,7 +11674,7 @@ data: ${JSON.stringify(msg.data)}
10979
11674
  };
10980
11675
 
10981
11676
  // src/installer.ts
10982
- var import_child_process7 = require("child_process");
11677
+ var import_child_process8 = require("child_process");
10983
11678
  var EXTENSION_CATALOG = [
10984
11679
  // AI Agent extensions
10985
11680
  {
@@ -11056,7 +11751,7 @@ var EXTENSION_CATALOG = [
11056
11751
  function isExtensionInstalled(ide, marketplaceId) {
11057
11752
  if (!ide.cliCommand) return false;
11058
11753
  try {
11059
- const result = (0, import_child_process7.execSync)(`"${ide.cliCommand}" --list-extensions`, {
11754
+ const result = (0, import_child_process8.execSync)(`"${ide.cliCommand}" --list-extensions`, {
11060
11755
  encoding: "utf-8",
11061
11756
  timeout: 15e3,
11062
11757
  stdio: ["pipe", "pipe", "pipe"]
@@ -11093,12 +11788,12 @@ async function installExtension(ide, extension) {
11093
11788
  const res = await fetch(extension.vsixUrl);
11094
11789
  if (res.ok) {
11095
11790
  const buffer = Buffer.from(await res.arrayBuffer());
11096
- const fs9 = await import("fs");
11097
- fs9.writeFileSync(vsixPath, buffer);
11098
- return new Promise((resolve5) => {
11791
+ const fs10 = await import("fs");
11792
+ fs10.writeFileSync(vsixPath, buffer);
11793
+ return new Promise((resolve7) => {
11099
11794
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
11100
- (0, import_child_process7.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
11101
- resolve5({
11795
+ (0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
11796
+ resolve7({
11102
11797
  extensionId: extension.id,
11103
11798
  marketplaceId: extension.marketplaceId,
11104
11799
  success: !error,
@@ -11111,11 +11806,11 @@ async function installExtension(ide, extension) {
11111
11806
  } catch (e) {
11112
11807
  }
11113
11808
  }
11114
- return new Promise((resolve5) => {
11809
+ return new Promise((resolve7) => {
11115
11810
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
11116
- (0, import_child_process7.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
11811
+ (0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
11117
11812
  if (error) {
11118
- resolve5({
11813
+ resolve7({
11119
11814
  extensionId: extension.id,
11120
11815
  marketplaceId: extension.marketplaceId,
11121
11816
  success: false,
@@ -11123,7 +11818,7 @@ async function installExtension(ide, extension) {
11123
11818
  error: stderr || error.message
11124
11819
  });
11125
11820
  } else {
11126
- resolve5({
11821
+ resolve7({
11127
11822
  extensionId: extension.id,
11128
11823
  marketplaceId: extension.marketplaceId,
11129
11824
  success: true,
@@ -11150,7 +11845,7 @@ function launchIDE(ide, workspacePath) {
11150
11845
  if (!ide.cliCommand) return false;
11151
11846
  try {
11152
11847
  const args = workspacePath ? `"${workspacePath}"` : "";
11153
- (0, import_child_process7.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
11848
+ (0, import_child_process8.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
11154
11849
  return true;
11155
11850
  } catch {
11156
11851
  return false;
@@ -11315,9 +12010,12 @@ async function shutdownDaemonComponents(components) {
11315
12010
  detectIDEs,
11316
12011
  getAIExtensions,
11317
12012
  getAvailableIdeIds,
12013
+ getHostMemorySnapshot,
11318
12014
  getLogLevel,
11319
12015
  getRecentCommands,
11320
12016
  getRecentLogs,
12017
+ getWorkspaceActivity,
12018
+ getWorkspaceState,
11321
12019
  initDaemonComponents,
11322
12020
  installExtensions,
11323
12021
  installGlobalInterceptor,