adhdev 0.5.3 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16369,6 +16369,190 @@ var require_dist = __commonJS({
16369
16369
  mod
16370
16370
  ));
16371
16371
  var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
16372
+ function expandPath(p) {
16373
+ const t = (p || "").trim();
16374
+ if (!t) return "";
16375
+ if (t.startsWith("~")) return path3.join(os3.homedir(), t.slice(1).replace(/^\//, ""));
16376
+ return path3.resolve(t);
16377
+ }
16378
+ function validateWorkspacePath(absPath) {
16379
+ try {
16380
+ if (!absPath) return { ok: false, error: "Path required" };
16381
+ if (!fs3.existsSync(absPath)) return { ok: false, error: "Path does not exist" };
16382
+ const st = fs3.statSync(absPath);
16383
+ if (!st.isDirectory()) return { ok: false, error: "Not a directory" };
16384
+ return { ok: true };
16385
+ } catch (e) {
16386
+ return { ok: false, error: e?.message || "Invalid path" };
16387
+ }
16388
+ }
16389
+ function defaultWorkspaceLabel(absPath) {
16390
+ const base = path3.basename(absPath) || absPath;
16391
+ return base;
16392
+ }
16393
+ function migrateWorkspacesFromRecent(config2) {
16394
+ if (!config2.workspaces) config2.workspaces = [];
16395
+ if (config2.workspaces.length > 0) return config2;
16396
+ const recent = config2.recentCliWorkspaces || [];
16397
+ const now = Date.now();
16398
+ for (const raw of recent) {
16399
+ const abs = expandPath(raw);
16400
+ if (!abs || validateWorkspacePath(abs).ok !== true) continue;
16401
+ if (config2.workspaces.some((w) => path3.resolve(w.path) === abs)) continue;
16402
+ config2.workspaces.push({
16403
+ id: (0, import_crypto.randomUUID)(),
16404
+ path: abs,
16405
+ label: defaultWorkspaceLabel(abs),
16406
+ addedAt: now
16407
+ });
16408
+ if (config2.workspaces.length >= MAX_WORKSPACES) break;
16409
+ }
16410
+ return config2;
16411
+ }
16412
+ function getDefaultWorkspacePath(config2) {
16413
+ const id = config2.defaultWorkspaceId;
16414
+ if (!id) return null;
16415
+ const w = (config2.workspaces || []).find((x) => x.id === id);
16416
+ if (!w) return null;
16417
+ const abs = expandPath(w.path);
16418
+ if (validateWorkspacePath(abs).ok !== true) return null;
16419
+ return abs;
16420
+ }
16421
+ function getWorkspaceState(config2) {
16422
+ const workspaces = [...config2.workspaces || []].sort((a, b) => b.addedAt - a.addedAt);
16423
+ const defaultWorkspacePath = getDefaultWorkspacePath(config2);
16424
+ return {
16425
+ workspaces,
16426
+ defaultWorkspaceId: config2.defaultWorkspaceId ?? null,
16427
+ defaultWorkspacePath
16428
+ };
16429
+ }
16430
+ function resolveLaunchDirectory(args, config2) {
16431
+ const a = args || {};
16432
+ if (a.dir != null && String(a.dir).trim()) {
16433
+ const abs = expandPath(String(a.dir).trim());
16434
+ if (abs && validateWorkspacePath(abs).ok === true) {
16435
+ return { ok: true, path: abs, source: "dir" };
16436
+ }
16437
+ return {
16438
+ ok: false,
16439
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
16440
+ message: abs ? "Directory path is not valid or does not exist" : "Invalid directory path"
16441
+ };
16442
+ }
16443
+ if (a.workspaceId) {
16444
+ const w = (config2.workspaces || []).find((x) => x.id === a.workspaceId);
16445
+ if (w) {
16446
+ const abs = expandPath(w.path);
16447
+ if (validateWorkspacePath(abs).ok === true) {
16448
+ return { ok: true, path: abs, source: "workspaceId" };
16449
+ }
16450
+ }
16451
+ return {
16452
+ ok: false,
16453
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
16454
+ message: "Saved workspace not found or path is no longer valid"
16455
+ };
16456
+ }
16457
+ if (a.useDefaultWorkspace === true) {
16458
+ const d = getDefaultWorkspacePath(config2);
16459
+ if (d) return { ok: true, path: d, source: "defaultWorkspace" };
16460
+ return {
16461
+ ok: false,
16462
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
16463
+ message: "No default workspace is set"
16464
+ };
16465
+ }
16466
+ if (a.useHome === true) {
16467
+ return { ok: true, path: os3.homedir(), source: "home" };
16468
+ }
16469
+ return {
16470
+ ok: false,
16471
+ code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
16472
+ message: "Choose a directory, saved workspace, default workspace, or home before launching."
16473
+ };
16474
+ }
16475
+ function resolveIdeWorkspaceFromArgs(args, config2) {
16476
+ const ar = args || {};
16477
+ if (ar.workspace) {
16478
+ const abs = expandPath(ar.workspace);
16479
+ if (abs && validateWorkspacePath(abs).ok === true) return abs;
16480
+ }
16481
+ if (ar.workspaceId) {
16482
+ const w = (config2.workspaces || []).find((x) => x.id === ar.workspaceId);
16483
+ if (w) {
16484
+ const abs = expandPath(w.path);
16485
+ if (validateWorkspacePath(abs).ok === true) return abs;
16486
+ }
16487
+ }
16488
+ if (ar.useDefaultWorkspace === true) {
16489
+ return getDefaultWorkspacePath(config2) || void 0;
16490
+ }
16491
+ return void 0;
16492
+ }
16493
+ function resolveIdeLaunchWorkspace(args, config2) {
16494
+ const direct = resolveIdeWorkspaceFromArgs(args, config2);
16495
+ if (direct) return direct;
16496
+ if (args?.useDefaultWorkspace === false) return void 0;
16497
+ return getDefaultWorkspacePath(config2) || void 0;
16498
+ }
16499
+ function findWorkspaceByPath(config2, rawPath) {
16500
+ const abs = path3.resolve(expandPath(rawPath));
16501
+ if (!abs) return void 0;
16502
+ return (config2.workspaces || []).find((w) => path3.resolve(expandPath(w.path)) === abs);
16503
+ }
16504
+ function addWorkspaceEntry(config2, rawPath, label) {
16505
+ const abs = expandPath(rawPath);
16506
+ const v = validateWorkspacePath(abs);
16507
+ if (!v.ok) return { error: v.error };
16508
+ const list = [...config2.workspaces || []];
16509
+ if (list.some((w) => path3.resolve(w.path) === abs)) {
16510
+ return { error: "Workspace already in list" };
16511
+ }
16512
+ if (list.length >= MAX_WORKSPACES) {
16513
+ return { error: `Maximum ${MAX_WORKSPACES} workspaces` };
16514
+ }
16515
+ const entry = {
16516
+ id: (0, import_crypto.randomUUID)(),
16517
+ path: abs,
16518
+ label: (label || "").trim() || defaultWorkspaceLabel(abs),
16519
+ addedAt: Date.now()
16520
+ };
16521
+ list.push(entry);
16522
+ return { config: { ...config2, workspaces: list }, entry };
16523
+ }
16524
+ function removeWorkspaceEntry(config2, id) {
16525
+ const list = (config2.workspaces || []).filter((w) => w.id !== id);
16526
+ if (list.length === (config2.workspaces || []).length) return { error: "Workspace not found" };
16527
+ let defaultWorkspaceId = config2.defaultWorkspaceId;
16528
+ if (defaultWorkspaceId === id) defaultWorkspaceId = null;
16529
+ return { config: { ...config2, workspaces: list, defaultWorkspaceId } };
16530
+ }
16531
+ function setDefaultWorkspaceId(config2, id) {
16532
+ if (id === null) {
16533
+ return { config: { ...config2, defaultWorkspaceId: null } };
16534
+ }
16535
+ const w = (config2.workspaces || []).find((x) => x.id === id);
16536
+ if (!w) return { error: "Workspace not found" };
16537
+ const abs = expandPath(w.path);
16538
+ if (validateWorkspacePath(abs).ok !== true) return { error: "Workspace path is no longer valid" };
16539
+ return { config: { ...config2, defaultWorkspaceId: id } };
16540
+ }
16541
+ var fs3;
16542
+ var os3;
16543
+ var path3;
16544
+ var import_crypto;
16545
+ var MAX_WORKSPACES;
16546
+ var init_workspaces = __esm2({
16547
+ "src/config/workspaces.ts"() {
16548
+ "use strict";
16549
+ fs3 = __toESM2(require("fs"));
16550
+ os3 = __toESM2(require("os"));
16551
+ path3 = __toESM2(require("path"));
16552
+ import_crypto = require("crypto");
16553
+ MAX_WORKSPACES = 50;
16554
+ }
16555
+ });
16372
16556
  var config_exports = {};
16373
16557
  __export2(config_exports, {
16374
16558
  addCliHistory: () => addCliHistory,
@@ -16399,7 +16583,20 @@ var require_dist = __commonJS({
16399
16583
  try {
16400
16584
  const raw = (0, import_fs2.readFileSync)(configPath, "utf-8");
16401
16585
  const parsed = JSON.parse(raw);
16402
- return { ...DEFAULT_CONFIG, ...parsed };
16586
+ const merged = { ...DEFAULT_CONFIG, ...parsed };
16587
+ if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
16588
+ merged.defaultWorkspaceId = merged.activeWorkspaceId;
16589
+ }
16590
+ delete merged.activeWorkspaceId;
16591
+ const hadStoredWorkspaces = Array.isArray(parsed.workspaces) && parsed.workspaces.length > 0;
16592
+ migrateWorkspacesFromRecent(merged);
16593
+ if (!hadStoredWorkspaces && (merged.workspaces?.length || 0) > 0) {
16594
+ try {
16595
+ saveConfig2(merged);
16596
+ } catch {
16597
+ }
16598
+ }
16599
+ return merged;
16403
16600
  } catch {
16404
16601
  return { ...DEFAULT_CONFIG };
16405
16602
  }
@@ -16473,6 +16670,7 @@ var require_dist = __commonJS({
16473
16670
  import_os = require("os");
16474
16671
  import_path2 = require("path");
16475
16672
  import_fs2 = require("fs");
16673
+ init_workspaces();
16476
16674
  DEFAULT_CONFIG = {
16477
16675
  serverUrl: "https://api.adhf.dev",
16478
16676
  apiToken: null,
@@ -16489,6 +16687,9 @@ var require_dist = __commonJS({
16489
16687
  configuredCLIs: [],
16490
16688
  enabledIdes: [],
16491
16689
  recentCliWorkspaces: [],
16690
+ workspaces: [],
16691
+ defaultWorkspaceId: null,
16692
+ recentWorkspaceActivity: [],
16492
16693
  machineNickname: null,
16493
16694
  cliHistory: [],
16494
16695
  providerSettings: {},
@@ -16526,9 +16727,12 @@ var require_dist = __commonJS({
16526
16727
  detectIDEs: () => detectIDEs3,
16527
16728
  getAIExtensions: () => getAIExtensions2,
16528
16729
  getAvailableIdeIds: () => getAvailableIdeIds2,
16730
+ getHostMemorySnapshot: () => getHostMemorySnapshot,
16529
16731
  getLogLevel: () => getLogLevel,
16530
16732
  getRecentCommands: () => getRecentCommands,
16531
16733
  getRecentLogs: () => getRecentLogs,
16734
+ getWorkspaceActivity: () => getWorkspaceActivity,
16735
+ getWorkspaceState: () => getWorkspaceState,
16532
16736
  initDaemonComponents: () => initDaemonComponents2,
16533
16737
  installExtensions: () => installExtensions2,
16534
16738
  installGlobalInterceptor: () => installGlobalInterceptor,
@@ -16551,6 +16755,45 @@ var require_dist = __commonJS({
16551
16755
  });
16552
16756
  module2.exports = __toCommonJS2(index_exports);
16553
16757
  init_config();
16758
+ init_workspaces();
16759
+ var path22 = __toESM2(require("path"));
16760
+ init_workspaces();
16761
+ var MAX_ACTIVITY = 30;
16762
+ function normWorkspacePath(p) {
16763
+ try {
16764
+ return path22.resolve(expandPath(p));
16765
+ } catch {
16766
+ return path22.resolve(p);
16767
+ }
16768
+ }
16769
+ function appendWorkspaceActivity(config2, rawPath, meta3) {
16770
+ const abs = normWorkspacePath(rawPath);
16771
+ if (!abs) return config2;
16772
+ const prev = config2.recentWorkspaceActivity || [];
16773
+ const filtered = prev.filter((e) => normWorkspacePath(e.path) !== abs);
16774
+ const entry = {
16775
+ path: abs,
16776
+ lastUsedAt: Date.now(),
16777
+ kind: meta3?.kind,
16778
+ agentType: meta3?.agentType
16779
+ };
16780
+ const recentWorkspaceActivity = [entry, ...filtered].slice(0, MAX_ACTIVITY);
16781
+ return { ...config2, recentWorkspaceActivity };
16782
+ }
16783
+ function getWorkspaceActivity(config2, limit = 20) {
16784
+ const list = [...config2.recentWorkspaceActivity || []];
16785
+ list.sort((a, b) => b.lastUsedAt - a.lastUsedAt);
16786
+ return list.slice(0, limit);
16787
+ }
16788
+ function removeActivityForPath(config2, rawPath) {
16789
+ const n = normWorkspacePath(rawPath);
16790
+ return {
16791
+ ...config2,
16792
+ recentWorkspaceActivity: (config2.recentWorkspaceActivity || []).filter(
16793
+ (e) => normWorkspacePath(e.path) !== n
16794
+ )
16795
+ };
16796
+ }
16554
16797
  var import_child_process = require("child_process");
16555
16798
  var import_fs22 = require("fs");
16556
16799
  var import_os2 = require("os");
@@ -16608,20 +16851,20 @@ var require_dist = __commonJS({
16608
16851
  return null;
16609
16852
  }
16610
16853
  async function detectIDEs3() {
16611
- const os13 = (0, import_os2.platform)();
16854
+ const os15 = (0, import_os2.platform)();
16612
16855
  const results = [];
16613
16856
  for (const def of getMergedDefinitions()) {
16614
16857
  const cliPath = findCliCommand(def.cli);
16615
- const appPath = checkPathExists(def.paths[os13] || []);
16858
+ const appPath = checkPathExists(def.paths[os15] || []);
16616
16859
  const installed = !!(cliPath || appPath);
16617
16860
  let resolvedCli = cliPath;
16618
- if (!resolvedCli && appPath && os13 === "darwin") {
16861
+ if (!resolvedCli && appPath && os15 === "darwin") {
16619
16862
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
16620
16863
  if ((0, import_fs22.existsSync)(bundledCli)) resolvedCli = bundledCli;
16621
16864
  }
16622
- if (!resolvedCli && appPath && os13 === "win32") {
16623
- const { dirname: dirname5 } = await import("path");
16624
- const appDir = dirname5(appPath);
16865
+ if (!resolvedCli && appPath && os15 === "win32") {
16866
+ const { dirname: dirname6 } = await import("path");
16867
+ const appDir = dirname6(appPath);
16625
16868
  const candidates = [
16626
16869
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
16627
16870
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -16652,22 +16895,22 @@ var require_dist = __commonJS({
16652
16895
  return results;
16653
16896
  }
16654
16897
  var import_child_process2 = require("child_process");
16655
- var os3 = __toESM2(require("os"));
16898
+ var os22 = __toESM2(require("os"));
16656
16899
  function execAsync(cmd, timeoutMs = 5e3) {
16657
- return new Promise((resolve5) => {
16900
+ return new Promise((resolve7) => {
16658
16901
  const child = (0, import_child_process2.exec)(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
16659
16902
  if (err || !stdout?.trim()) {
16660
- resolve5(null);
16903
+ resolve7(null);
16661
16904
  } else {
16662
- resolve5(stdout.trim());
16905
+ resolve7(stdout.trim());
16663
16906
  }
16664
16907
  });
16665
- child.on("error", () => resolve5(null));
16908
+ child.on("error", () => resolve7(null));
16666
16909
  });
16667
16910
  }
16668
16911
  async function detectCLIs2(providerLoader) {
16669
- const platform7 = os3.platform();
16670
- const whichCmd = platform7 === "win32" ? "where" : "which";
16912
+ const platform8 = os22.platform();
16913
+ const whichCmd = platform8 === "win32" ? "where" : "which";
16671
16914
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
16672
16915
  const results = await Promise.all(
16673
16916
  cliList.map(async (cli) => {
@@ -16697,11 +16940,51 @@ var require_dist = __commonJS({
16697
16940
  const all = await detectCLIs2(providerLoader);
16698
16941
  return all.find((c) => c.id === resolvedId && c.installed) || null;
16699
16942
  }
16943
+ var os32 = __toESM2(require("os"));
16944
+ var import_child_process3 = require("child_process");
16945
+ function parseDarwinAvailableBytes(totalMem) {
16946
+ if (os32.platform() !== "darwin") return null;
16947
+ try {
16948
+ const out = (0, import_child_process3.execSync)("vm_stat", {
16949
+ encoding: "utf-8",
16950
+ timeout: 4e3,
16951
+ maxBuffer: 256 * 1024
16952
+ });
16953
+ const pageSizeMatch = out.match(/page size of (\d+)\s*bytes/i);
16954
+ const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 4096;
16955
+ const counts = {};
16956
+ for (const line of out.split("\n")) {
16957
+ const m = line.match(/^\s*Pages\s+([^:]+):\s+([\d,]+)\s*\.?/);
16958
+ if (!m) continue;
16959
+ const key = m[1].trim().toLowerCase().replace(/\s+/g, "_");
16960
+ const n = parseInt(m[2].replace(/,/g, ""), 10);
16961
+ if (!Number.isNaN(n)) counts[key] = n;
16962
+ }
16963
+ const free = counts["free"] ?? 0;
16964
+ const inactive = counts["inactive"] ?? 0;
16965
+ const speculative = counts["speculative"] ?? 0;
16966
+ const purgeable = counts["purgeable"] ?? 0;
16967
+ const fileBacked = counts["file_backed"] ?? 0;
16968
+ const availPages = free + inactive + speculative + purgeable + fileBacked;
16969
+ const bytes = availPages * pageSize;
16970
+ if (!Number.isFinite(bytes) || bytes < 0) return null;
16971
+ return Math.min(bytes, totalMem);
16972
+ } catch {
16973
+ return null;
16974
+ }
16975
+ }
16976
+ function getHostMemorySnapshot() {
16977
+ const totalMem = os32.totalmem();
16978
+ const freeMem = os32.freemem();
16979
+ const darwinAvail = parseDarwinAvailableBytes(totalMem);
16980
+ const availableMem = darwinAvail != null ? darwinAvail : freeMem;
16981
+ return { totalMem, freeMem, availableMem };
16982
+ }
16700
16983
  var import_ws2 = __toESM2(require("ws"));
16701
16984
  var http = __toESM2(require("http"));
16702
- var fs3 = __toESM2(require("fs"));
16703
- var path3 = __toESM2(require("path"));
16704
- var os22 = __toESM2(require("os"));
16985
+ var fs22 = __toESM2(require("fs"));
16986
+ var path32 = __toESM2(require("path"));
16987
+ var os4 = __toESM2(require("os"));
16705
16988
  var LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
16706
16989
  var LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
16707
16990
  var currentLevel = "info";
@@ -16712,29 +16995,29 @@ var require_dist = __commonJS({
16712
16995
  function getLogLevel() {
16713
16996
  return currentLevel;
16714
16997
  }
16715
- var LOG_DIR = process.platform === "darwin" ? path3.join(os22.homedir(), "Library", "Logs", "adhdev") : path3.join(os22.homedir(), ".local", "share", "adhdev", "logs");
16998
+ var LOG_DIR = process.platform === "darwin" ? path32.join(os4.homedir(), "Library", "Logs", "adhdev") : path32.join(os4.homedir(), ".local", "share", "adhdev", "logs");
16716
16999
  var MAX_LOG_SIZE = 5 * 1024 * 1024;
16717
17000
  var MAX_LOG_DAYS = 7;
16718
17001
  try {
16719
- fs3.mkdirSync(LOG_DIR, { recursive: true });
17002
+ fs22.mkdirSync(LOG_DIR, { recursive: true });
16720
17003
  } catch {
16721
17004
  }
16722
17005
  function getDateStr() {
16723
17006
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
16724
17007
  }
16725
17008
  var currentDate = getDateStr();
16726
- var currentLogFile = path3.join(LOG_DIR, `daemon-${currentDate}.log`);
17009
+ var currentLogFile = path32.join(LOG_DIR, `daemon-${currentDate}.log`);
16727
17010
  function checkDateRotation() {
16728
17011
  const today = getDateStr();
16729
17012
  if (today !== currentDate) {
16730
17013
  currentDate = today;
16731
- currentLogFile = path3.join(LOG_DIR, `daemon-${currentDate}.log`);
17014
+ currentLogFile = path32.join(LOG_DIR, `daemon-${currentDate}.log`);
16732
17015
  cleanOldLogs();
16733
17016
  }
16734
17017
  }
16735
17018
  function cleanOldLogs() {
16736
17019
  try {
16737
- const files = fs3.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
17020
+ const files = fs22.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
16738
17021
  const cutoff = /* @__PURE__ */ new Date();
16739
17022
  cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
16740
17023
  const cutoffStr = cutoff.toISOString().slice(0, 10);
@@ -16742,7 +17025,7 @@ var require_dist = __commonJS({
16742
17025
  const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
16743
17026
  if (dateMatch && dateMatch[1] < cutoffStr) {
16744
17027
  try {
16745
- fs3.unlinkSync(path3.join(LOG_DIR, file2));
17028
+ fs22.unlinkSync(path32.join(LOG_DIR, file2));
16746
17029
  } catch {
16747
17030
  }
16748
17031
  }
@@ -16752,29 +17035,29 @@ var require_dist = __commonJS({
16752
17035
  }
16753
17036
  function rotateSizeIfNeeded() {
16754
17037
  try {
16755
- const stat = fs3.statSync(currentLogFile);
17038
+ const stat = fs22.statSync(currentLogFile);
16756
17039
  if (stat.size > MAX_LOG_SIZE) {
16757
17040
  const backup = currentLogFile.replace(".log", ".1.log");
16758
17041
  try {
16759
- fs3.unlinkSync(backup);
17042
+ fs22.unlinkSync(backup);
16760
17043
  } catch {
16761
17044
  }
16762
- fs3.renameSync(currentLogFile, backup);
17045
+ fs22.renameSync(currentLogFile, backup);
16763
17046
  }
16764
17047
  } catch {
16765
17048
  }
16766
17049
  }
16767
17050
  cleanOldLogs();
16768
17051
  try {
16769
- const oldLog = path3.join(LOG_DIR, "daemon.log");
16770
- if (fs3.existsSync(oldLog)) {
16771
- const stat = fs3.statSync(oldLog);
17052
+ const oldLog = path32.join(LOG_DIR, "daemon.log");
17053
+ if (fs22.existsSync(oldLog)) {
17054
+ const stat = fs22.statSync(oldLog);
16772
17055
  const oldDate = stat.mtime.toISOString().slice(0, 10);
16773
- fs3.renameSync(oldLog, path3.join(LOG_DIR, `daemon-${oldDate}.log`));
17056
+ fs22.renameSync(oldLog, path32.join(LOG_DIR, `daemon-${oldDate}.log`));
16774
17057
  }
16775
- const oldLogBackup = path3.join(LOG_DIR, "daemon.log.old");
16776
- if (fs3.existsSync(oldLogBackup)) {
16777
- fs3.unlinkSync(oldLogBackup);
17058
+ const oldLogBackup = path32.join(LOG_DIR, "daemon.log.old");
17059
+ if (fs22.existsSync(oldLogBackup)) {
17060
+ fs22.unlinkSync(oldLogBackup);
16778
17061
  }
16779
17062
  } catch {
16780
17063
  }
@@ -16785,7 +17068,7 @@ var require_dist = __commonJS({
16785
17068
  checkDateRotation();
16786
17069
  rotateSizeIfNeeded();
16787
17070
  }
16788
- fs3.appendFileSync(currentLogFile, line + "\n");
17071
+ fs22.appendFileSync(currentLogFile, line + "\n");
16789
17072
  } catch {
16790
17073
  }
16791
17074
  }
@@ -16899,7 +17182,7 @@ var require_dist = __commonJS({
16899
17182
  writeToFile(`Log file: ${currentLogFile}`);
16900
17183
  writeToFile(`Log level: ${currentLevel}`);
16901
17184
  }
16902
- var LOG_PATH = path3.join(LOG_DIR, `daemon-${getDateStr()}.log`);
17185
+ var LOG_PATH = path32.join(LOG_DIR, `daemon-${getDateStr()}.log`);
16903
17186
  var DaemonCdpManager2 = class {
16904
17187
  ws = null;
16905
17188
  browserWs = null;
@@ -16972,7 +17255,7 @@ var require_dist = __commonJS({
16972
17255
  * Returns multiple entries if multiple IDE windows are open on same port
16973
17256
  */
16974
17257
  static listAllTargets(port) {
16975
- return new Promise((resolve5) => {
17258
+ return new Promise((resolve7) => {
16976
17259
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
16977
17260
  let data = "";
16978
17261
  res.on("data", (chunk) => data += chunk.toString());
@@ -16988,16 +17271,16 @@ var require_dist = __commonJS({
16988
17271
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
16989
17272
  );
16990
17273
  const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
16991
- resolve5(mainPages.length > 0 ? mainPages : fallbackPages);
17274
+ resolve7(mainPages.length > 0 ? mainPages : fallbackPages);
16992
17275
  } catch {
16993
- resolve5([]);
17276
+ resolve7([]);
16994
17277
  }
16995
17278
  });
16996
17279
  });
16997
- req.on("error", () => resolve5([]));
17280
+ req.on("error", () => resolve7([]));
16998
17281
  req.setTimeout(2e3, () => {
16999
17282
  req.destroy();
17000
- resolve5([]);
17283
+ resolve7([]);
17001
17284
  });
17002
17285
  });
17003
17286
  }
@@ -17037,7 +17320,7 @@ var require_dist = __commonJS({
17037
17320
  }
17038
17321
  }
17039
17322
  findTargetOnPort(port) {
17040
- return new Promise((resolve5) => {
17323
+ return new Promise((resolve7) => {
17041
17324
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
17042
17325
  let data = "";
17043
17326
  res.on("data", (chunk) => data += chunk.toString());
@@ -17048,7 +17331,7 @@ var require_dist = __commonJS({
17048
17331
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
17049
17332
  );
17050
17333
  if (pages.length === 0) {
17051
- resolve5(targets.find((t) => t.webSocketDebuggerUrl) || null);
17334
+ resolve7(targets.find((t) => t.webSocketDebuggerUrl) || null);
17052
17335
  return;
17053
17336
  }
17054
17337
  const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
@@ -17058,24 +17341,24 @@ var require_dist = __commonJS({
17058
17341
  const specific = list.find((t) => t.id === this._targetId);
17059
17342
  if (specific) {
17060
17343
  this._pageTitle = specific.title || "";
17061
- resolve5(specific);
17344
+ resolve7(specific);
17062
17345
  } else {
17063
17346
  this.log(`[CDP] Target ${this._targetId} not found in page list`);
17064
- resolve5(null);
17347
+ resolve7(null);
17065
17348
  }
17066
17349
  return;
17067
17350
  }
17068
17351
  this._pageTitle = list[0]?.title || "";
17069
- resolve5(list[0]);
17352
+ resolve7(list[0]);
17070
17353
  } catch {
17071
- resolve5(null);
17354
+ resolve7(null);
17072
17355
  }
17073
17356
  });
17074
17357
  });
17075
- req.on("error", () => resolve5(null));
17358
+ req.on("error", () => resolve7(null));
17076
17359
  req.setTimeout(2e3, () => {
17077
17360
  req.destroy();
17078
- resolve5(null);
17361
+ resolve7(null);
17079
17362
  });
17080
17363
  });
17081
17364
  }
@@ -17086,7 +17369,7 @@ var require_dist = __commonJS({
17086
17369
  this.extensionProviders = providers;
17087
17370
  }
17088
17371
  connectToTarget(wsUrl) {
17089
- return new Promise((resolve5) => {
17372
+ return new Promise((resolve7) => {
17090
17373
  this.ws = new import_ws2.default(wsUrl);
17091
17374
  this.ws.on("open", async () => {
17092
17375
  this._connected = true;
@@ -17096,17 +17379,17 @@ var require_dist = __commonJS({
17096
17379
  }
17097
17380
  this.connectBrowserWs().catch(() => {
17098
17381
  });
17099
- resolve5(true);
17382
+ resolve7(true);
17100
17383
  });
17101
17384
  this.ws.on("message", (data) => {
17102
17385
  try {
17103
17386
  const msg = JSON.parse(data.toString());
17104
17387
  if (msg.id && this.pending.has(msg.id)) {
17105
- const { resolve: resolve6, reject } = this.pending.get(msg.id);
17388
+ const { resolve: resolve8, reject } = this.pending.get(msg.id);
17106
17389
  this.pending.delete(msg.id);
17107
17390
  this.failureCount = 0;
17108
17391
  if (msg.error) reject(new Error(msg.error.message));
17109
- else resolve6(msg.result);
17392
+ else resolve8(msg.result);
17110
17393
  } else if (msg.method === "Runtime.executionContextCreated") {
17111
17394
  this.contexts.add(msg.params.context.id);
17112
17395
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -17129,7 +17412,7 @@ var require_dist = __commonJS({
17129
17412
  this.ws.on("error", (err) => {
17130
17413
  this.log(`[CDP] WebSocket error: ${err.message}`);
17131
17414
  this._connected = false;
17132
- resolve5(false);
17415
+ resolve7(false);
17133
17416
  });
17134
17417
  });
17135
17418
  }
@@ -17143,7 +17426,7 @@ var require_dist = __commonJS({
17143
17426
  return;
17144
17427
  }
17145
17428
  this.log(`[CDP] Connecting browser WS for target discovery...`);
17146
- await new Promise((resolve5, reject) => {
17429
+ await new Promise((resolve7, reject) => {
17147
17430
  this.browserWs = new import_ws2.default(browserWsUrl);
17148
17431
  this.browserWs.on("open", async () => {
17149
17432
  this._browserConnected = true;
@@ -17153,16 +17436,16 @@ var require_dist = __commonJS({
17153
17436
  } catch (e) {
17154
17437
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
17155
17438
  }
17156
- resolve5();
17439
+ resolve7();
17157
17440
  });
17158
17441
  this.browserWs.on("message", (data) => {
17159
17442
  try {
17160
17443
  const msg = JSON.parse(data.toString());
17161
17444
  if (msg.id && this.browserPending.has(msg.id)) {
17162
- const { resolve: resolve6, reject: reject2 } = this.browserPending.get(msg.id);
17445
+ const { resolve: resolve8, reject: reject2 } = this.browserPending.get(msg.id);
17163
17446
  this.browserPending.delete(msg.id);
17164
17447
  if (msg.error) reject2(new Error(msg.error.message));
17165
- else resolve6(msg.result);
17448
+ else resolve8(msg.result);
17166
17449
  }
17167
17450
  } catch {
17168
17451
  }
@@ -17182,31 +17465,31 @@ var require_dist = __commonJS({
17182
17465
  }
17183
17466
  }
17184
17467
  getBrowserWsUrl() {
17185
- return new Promise((resolve5) => {
17468
+ return new Promise((resolve7) => {
17186
17469
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
17187
17470
  let data = "";
17188
17471
  res.on("data", (chunk) => data += chunk.toString());
17189
17472
  res.on("end", () => {
17190
17473
  try {
17191
17474
  const info = JSON.parse(data);
17192
- resolve5(info.webSocketDebuggerUrl || null);
17475
+ resolve7(info.webSocketDebuggerUrl || null);
17193
17476
  } catch {
17194
- resolve5(null);
17477
+ resolve7(null);
17195
17478
  }
17196
17479
  });
17197
17480
  });
17198
- req.on("error", () => resolve5(null));
17481
+ req.on("error", () => resolve7(null));
17199
17482
  req.setTimeout(3e3, () => {
17200
17483
  req.destroy();
17201
- resolve5(null);
17484
+ resolve7(null);
17202
17485
  });
17203
17486
  });
17204
17487
  }
17205
17488
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
17206
- return new Promise((resolve5, reject) => {
17489
+ return new Promise((resolve7, reject) => {
17207
17490
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
17208
17491
  const id = this.browserMsgId++;
17209
- this.browserPending.set(id, { resolve: resolve5, reject });
17492
+ this.browserPending.set(id, { resolve: resolve7, reject });
17210
17493
  this.browserWs.send(JSON.stringify({ id, method, params }));
17211
17494
  setTimeout(() => {
17212
17495
  if (this.browserPending.has(id)) {
@@ -17246,11 +17529,11 @@ var require_dist = __commonJS({
17246
17529
  }
17247
17530
  // ─── CDP Protocol ────────────────────────────────────────
17248
17531
  sendInternal(method, params = {}, timeoutMs = 15e3) {
17249
- return new Promise((resolve5, reject) => {
17532
+ return new Promise((resolve7, reject) => {
17250
17533
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
17251
17534
  if (this.ws.readyState !== import_ws2.default.OPEN) return reject(new Error("WebSocket not open"));
17252
17535
  const id = this.msgId++;
17253
- this.pending.set(id, { resolve: resolve5, reject });
17536
+ this.pending.set(id, { resolve: resolve7, reject });
17254
17537
  this.ws.send(JSON.stringify({ id, method, params }));
17255
17538
  setTimeout(() => {
17256
17539
  if (this.pending.has(id)) {
@@ -17459,7 +17742,7 @@ var require_dist = __commonJS({
17459
17742
  const browserWs = this.browserWs;
17460
17743
  let msgId = this.browserMsgId;
17461
17744
  const sendWs = (method, params = {}, sessionId) => {
17462
- return new Promise((resolve5, reject) => {
17745
+ return new Promise((resolve7, reject) => {
17463
17746
  const mid = msgId++;
17464
17747
  this.browserMsgId = msgId;
17465
17748
  const handler = (raw) => {
@@ -17468,7 +17751,7 @@ var require_dist = __commonJS({
17468
17751
  if (msg.id === mid) {
17469
17752
  browserWs.removeListener("message", handler);
17470
17753
  if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
17471
- else resolve5(msg.result);
17754
+ else resolve7(msg.result);
17472
17755
  }
17473
17756
  } catch {
17474
17757
  }
@@ -17642,14 +17925,14 @@ var require_dist = __commonJS({
17642
17925
  if (!ws || ws.readyState !== import_ws2.default.OPEN) {
17643
17926
  throw new Error("CDP not connected");
17644
17927
  }
17645
- return new Promise((resolve5, reject) => {
17928
+ return new Promise((resolve7, reject) => {
17646
17929
  const id = getNextId();
17647
17930
  pendingMap.set(id, {
17648
17931
  resolve: (result) => {
17649
17932
  if (result?.result?.subtype === "error") {
17650
17933
  reject(new Error(result.result.description));
17651
17934
  } else {
17652
- resolve5(result?.result?.value);
17935
+ resolve7(result?.result?.value);
17653
17936
  }
17654
17937
  },
17655
17938
  reject
@@ -18220,10 +18503,10 @@ var require_dist = __commonJS({
18220
18503
  return events;
18221
18504
  }
18222
18505
  };
18223
- var fs22 = __toESM2(require("fs"));
18224
- var path22 = __toESM2(require("path"));
18225
- var os32 = __toESM2(require("os"));
18226
- var HISTORY_DIR = path22.join(os32.homedir(), ".adhdev", "history");
18506
+ var fs32 = __toESM2(require("fs"));
18507
+ var path4 = __toESM2(require("path"));
18508
+ var os5 = __toESM2(require("os"));
18509
+ var HISTORY_DIR = path4.join(os5.homedir(), ".adhdev", "history");
18227
18510
  var RETAIN_DAYS = 30;
18228
18511
  var ChatHistoryWriter = class {
18229
18512
  /** Last seen message count per agent (deduplication) */
@@ -18264,13 +18547,13 @@ var require_dist = __commonJS({
18264
18547
  });
18265
18548
  }
18266
18549
  if (newMessages.length === 0) return;
18267
- const dir = path22.join(HISTORY_DIR, this.sanitize(agentType));
18268
- fs22.mkdirSync(dir, { recursive: true });
18550
+ const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
18551
+ fs32.mkdirSync(dir, { recursive: true });
18269
18552
  const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
18270
18553
  const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
18271
- const filePath = path22.join(dir, `${filePrefix}${date5}.jsonl`);
18554
+ const filePath = path4.join(dir, `${filePrefix}${date5}.jsonl`);
18272
18555
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
18273
- fs22.appendFileSync(filePath, lines, "utf-8");
18556
+ fs32.appendFileSync(filePath, lines, "utf-8");
18274
18557
  const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
18275
18558
  if (messages.length < prevCount * 0.5 && prevCount > 3) {
18276
18559
  seenHashes.clear();
@@ -18295,17 +18578,17 @@ var require_dist = __commonJS({
18295
18578
  /** Delete history files older than 30 days */
18296
18579
  async rotateOldFiles() {
18297
18580
  try {
18298
- if (!fs22.existsSync(HISTORY_DIR)) return;
18581
+ if (!fs32.existsSync(HISTORY_DIR)) return;
18299
18582
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
18300
- const agentDirs = fs22.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
18583
+ const agentDirs = fs32.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
18301
18584
  for (const dir of agentDirs) {
18302
- const dirPath = path22.join(HISTORY_DIR, dir.name);
18303
- const files = fs22.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
18585
+ const dirPath = path4.join(HISTORY_DIR, dir.name);
18586
+ const files = fs32.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
18304
18587
  for (const file2 of files) {
18305
- const filePath = path22.join(dirPath, file2);
18306
- const stat = fs22.statSync(filePath);
18588
+ const filePath = path4.join(dirPath, file2);
18589
+ const stat = fs32.statSync(filePath);
18307
18590
  if (stat.mtimeMs < cutoff) {
18308
- fs22.unlinkSync(filePath);
18591
+ fs32.unlinkSync(filePath);
18309
18592
  }
18310
18593
  }
18311
18594
  }
@@ -18320,10 +18603,10 @@ var require_dist = __commonJS({
18320
18603
  function readChatHistory2(agentType, offset = 0, limit = 30, instanceId) {
18321
18604
  try {
18322
18605
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
18323
- const dir = path22.join(HISTORY_DIR, sanitized);
18324
- if (!fs22.existsSync(dir)) return { messages: [], hasMore: false };
18606
+ const dir = path4.join(HISTORY_DIR, sanitized);
18607
+ if (!fs32.existsSync(dir)) return { messages: [], hasMore: false };
18325
18608
  const sanitizedInstance = instanceId?.replace(/[^a-zA-Z0-9_-]/g, "_");
18326
- const files = fs22.readdirSync(dir).filter((f) => {
18609
+ const files = fs32.readdirSync(dir).filter((f) => {
18327
18610
  if (!f.endsWith(".jsonl")) return false;
18328
18611
  if (sanitizedInstance) {
18329
18612
  return f.startsWith(`${sanitizedInstance}_`);
@@ -18334,8 +18617,8 @@ var require_dist = __commonJS({
18334
18617
  const needed = offset + limit + 1;
18335
18618
  for (const file2 of files) {
18336
18619
  if (allMessages.length >= needed) break;
18337
- const filePath = path22.join(dir, file2);
18338
- const content = fs22.readFileSync(filePath, "utf-8");
18620
+ const filePath = path4.join(dir, file2);
18621
+ const content = fs32.readFileSync(filePath, "utf-8");
18339
18622
  const lines = content.trim().split("\n").filter(Boolean);
18340
18623
  for (let i = lines.length - 1; i >= 0; i--) {
18341
18624
  if (allMessages.length >= needed) break;
@@ -18573,6 +18856,15 @@ var require_dist = __commonJS({
18573
18856
  const h = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
18574
18857
  msg.receivedAt = prevByHash.get(h) || now;
18575
18858
  }
18859
+ if (raw.messages?.length > 0) {
18860
+ const hiddenKinds = /* @__PURE__ */ new Set();
18861
+ if (this.settings.showThinking === false) hiddenKinds.add("thought");
18862
+ if (this.settings.showToolCalls === false) hiddenKinds.add("tool");
18863
+ if (this.settings.showTerminal === false) hiddenKinds.add("terminal");
18864
+ if (hiddenKinds.size > 0) {
18865
+ raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
18866
+ }
18867
+ }
18576
18868
  this.cachedChat = { ...raw, activeModal };
18577
18869
  this.detectAgentTransitions(raw, now);
18578
18870
  if (raw.messages?.length > 0) {
@@ -19581,6 +19873,39 @@ var require_dist = __commonJS({
19581
19873
  const action = args?.action || "approve";
19582
19874
  const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
19583
19875
  LOG5.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider2?.type}`);
19876
+ if (provider2?.category === "cli") {
19877
+ const adapter = h.getCliAdapter(provider2.type);
19878
+ if (!adapter) return { success: false, error: "CLI adapter not running" };
19879
+ const status = adapter.getStatus?.();
19880
+ if (status?.status !== "waiting_approval") {
19881
+ return { success: false, error: "Not in approval state" };
19882
+ }
19883
+ const buttons = status.activeModal?.buttons || ["Allow once", "Always allow", "Deny"];
19884
+ let buttonIndex = typeof args?.buttonIndex === "number" ? args.buttonIndex : -1;
19885
+ if (buttonIndex < 0) {
19886
+ const btnLower = button.toLowerCase();
19887
+ buttonIndex = buttons.findIndex((b) => b.toLowerCase().includes(btnLower));
19888
+ }
19889
+ if (buttonIndex < 0) {
19890
+ if (action === "reject" || action === "deny") {
19891
+ buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
19892
+ if (buttonIndex < 0) buttonIndex = buttons.length - 1;
19893
+ } else if (action === "always" || /always/i.test(button)) {
19894
+ buttonIndex = buttons.findIndex((b) => /always/i.test(b));
19895
+ if (buttonIndex < 0) buttonIndex = 1;
19896
+ } else {
19897
+ buttonIndex = 0;
19898
+ }
19899
+ }
19900
+ if (typeof adapter.resolveModal === "function") {
19901
+ adapter.resolveModal(buttonIndex);
19902
+ } else {
19903
+ const keys = "\x1B[B".repeat(Math.max(0, buttonIndex)) + "\r";
19904
+ adapter.writeRaw?.(keys);
19905
+ }
19906
+ LOG5.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
19907
+ return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
19908
+ }
19584
19909
  if (provider2?.category === "extension" && h.agentStream && h.getCdp()) {
19585
19910
  const ok = await h.agentStream.resolveAgentAction(
19586
19911
  h.getCdp(),
@@ -19665,9 +19990,9 @@ var require_dist = __commonJS({
19665
19990
  }
19666
19991
  return { success: false, error: "resolveAction script not available for this provider" };
19667
19992
  }
19668
- var fs32 = __toESM2(require("fs"));
19669
- var path32 = __toESM2(require("path"));
19670
- var os4 = __toESM2(require("os"));
19993
+ var fs4 = __toESM2(require("fs"));
19994
+ var path5 = __toESM2(require("path"));
19995
+ var os6 = __toESM2(require("os"));
19671
19996
  async function handleCdpEval(h, args) {
19672
19997
  if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19673
19998
  const expression = args?.expression || args?.script;
@@ -19819,21 +20144,21 @@ var require_dist = __commonJS({
19819
20144
  return { success: true, agents };
19820
20145
  }
19821
20146
  function resolveSafePath(requestedPath) {
19822
- const home = os4.homedir();
20147
+ const home = os6.homedir();
19823
20148
  let resolved;
19824
20149
  if (requestedPath.startsWith("~")) {
19825
- resolved = path32.join(home, requestedPath.slice(1));
19826
- } else if (path32.isAbsolute(requestedPath)) {
20150
+ resolved = path5.join(home, requestedPath.slice(1));
20151
+ } else if (path5.isAbsolute(requestedPath)) {
19827
20152
  resolved = requestedPath;
19828
20153
  } else {
19829
- resolved = path32.resolve(requestedPath);
20154
+ resolved = path5.resolve(requestedPath);
19830
20155
  }
19831
20156
  return resolved;
19832
20157
  }
19833
20158
  async function handleFileRead(h, args) {
19834
20159
  try {
19835
20160
  const filePath = resolveSafePath(args?.path);
19836
- const content = fs32.readFileSync(filePath, "utf-8");
20161
+ const content = fs4.readFileSync(filePath, "utf-8");
19837
20162
  return { success: true, content, path: filePath };
19838
20163
  } catch (e) {
19839
20164
  return { success: false, error: e.message };
@@ -19842,8 +20167,8 @@ var require_dist = __commonJS({
19842
20167
  async function handleFileWrite(h, args) {
19843
20168
  try {
19844
20169
  const filePath = resolveSafePath(args?.path);
19845
- fs32.mkdirSync(path32.dirname(filePath), { recursive: true });
19846
- fs32.writeFileSync(filePath, args?.content || "", "utf-8");
20170
+ fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
20171
+ fs4.writeFileSync(filePath, args?.content || "", "utf-8");
19847
20172
  return { success: true, path: filePath };
19848
20173
  } catch (e) {
19849
20174
  return { success: false, error: e.message };
@@ -19852,11 +20177,11 @@ var require_dist = __commonJS({
19852
20177
  async function handleFileList(h, args) {
19853
20178
  try {
19854
20179
  const dirPath = resolveSafePath(args?.path || ".");
19855
- const entries = fs32.readdirSync(dirPath, { withFileTypes: true });
20180
+ const entries = fs4.readdirSync(dirPath, { withFileTypes: true });
19856
20181
  const files = entries.map((e) => ({
19857
20182
  name: e.name,
19858
20183
  type: e.isDirectory() ? "directory" : "file",
19859
- size: e.isFile() ? fs32.statSync(path32.join(dirPath, e.name)).size : void 0
20184
+ size: e.isFile() ? fs4.statSync(path5.join(dirPath, e.name)).size : void 0
19860
20185
  }));
19861
20186
  return { success: true, files, path: dirPath };
19862
20187
  } catch (e) {
@@ -20143,6 +20468,92 @@ var require_dist = __commonJS({
20143
20468
  }
20144
20469
  return { success: false, error: "Failed to save setting" };
20145
20470
  }
20471
+ init_config();
20472
+ init_workspaces();
20473
+ function handleWorkspaceList() {
20474
+ const config2 = loadConfig4();
20475
+ const state = getWorkspaceState(config2);
20476
+ return {
20477
+ success: true,
20478
+ workspaces: state.workspaces,
20479
+ defaultWorkspaceId: state.defaultWorkspaceId,
20480
+ defaultWorkspacePath: state.defaultWorkspacePath,
20481
+ legacyRecentPaths: config2.recentCliWorkspaces || [],
20482
+ activity: getWorkspaceActivity(config2, 25)
20483
+ };
20484
+ }
20485
+ function handleWorkspaceAdd(args) {
20486
+ const rawPath = (args?.path || args?.dir || "").trim();
20487
+ const label = (args?.label || "").trim() || void 0;
20488
+ if (!rawPath) return { success: false, error: "path required" };
20489
+ const config2 = loadConfig4();
20490
+ const result = addWorkspaceEntry(config2, rawPath, label);
20491
+ if ("error" in result) return { success: false, error: result.error };
20492
+ let cfg = appendWorkspaceActivity(result.config, result.entry.path, {});
20493
+ saveConfig2(cfg);
20494
+ const state = getWorkspaceState(cfg);
20495
+ return { success: true, entry: result.entry, ...state, activity: getWorkspaceActivity(cfg, 25) };
20496
+ }
20497
+ function handleWorkspaceRemove(args) {
20498
+ const id = (args?.id || "").trim();
20499
+ if (!id) return { success: false, error: "id required" };
20500
+ const config2 = loadConfig4();
20501
+ const removed = (config2.workspaces || []).find((w) => w.id === id);
20502
+ const result = removeWorkspaceEntry(config2, id);
20503
+ if ("error" in result) return { success: false, error: result.error };
20504
+ let cfg = result.config;
20505
+ if (removed) {
20506
+ cfg = removeActivityForPath(cfg, removed.path);
20507
+ }
20508
+ saveConfig2(cfg);
20509
+ const state = getWorkspaceState(cfg);
20510
+ return { success: true, removedId: id, ...state, activity: getWorkspaceActivity(cfg, 25) };
20511
+ }
20512
+ function handleWorkspaceSetDefault(args) {
20513
+ const clear = args?.clear === true || args?.id === null || args?.id === "";
20514
+ if (clear) {
20515
+ const config22 = loadConfig4();
20516
+ const result2 = setDefaultWorkspaceId(config22, null);
20517
+ if ("error" in result2) return { success: false, error: result2.error };
20518
+ saveConfig2(result2.config);
20519
+ const state2 = getWorkspaceState(result2.config);
20520
+ return {
20521
+ success: true,
20522
+ ...state2,
20523
+ activity: getWorkspaceActivity(result2.config, 25)
20524
+ };
20525
+ }
20526
+ const pathArg = args?.path != null && String(args.path).trim() ? String(args.path).trim() : "";
20527
+ const idArg = args?.id !== void 0 && args?.id !== null && String(args.id).trim() ? String(args.id).trim() : "";
20528
+ if (!pathArg && !idArg) {
20529
+ return { success: false, error: "id or path required (or clear: true)" };
20530
+ }
20531
+ let config2 = loadConfig4();
20532
+ let nextId;
20533
+ if (pathArg) {
20534
+ let w = findWorkspaceByPath(config2, pathArg);
20535
+ if (!w) {
20536
+ const add = addWorkspaceEntry(config2, pathArg);
20537
+ if ("error" in add) return { success: false, error: add.error };
20538
+ config2 = add.config;
20539
+ w = add.entry;
20540
+ }
20541
+ nextId = w.id;
20542
+ } else {
20543
+ nextId = idArg;
20544
+ }
20545
+ const result = setDefaultWorkspaceId(config2, nextId);
20546
+ if ("error" in result) return { success: false, error: result.error };
20547
+ let out = result.config;
20548
+ const ap = getDefaultWorkspacePath(out);
20549
+ if (ap) {
20550
+ out = appendWorkspaceActivity(out, ap, { kind: "default" });
20551
+ }
20552
+ saveConfig2(out);
20553
+ const state = getWorkspaceState(out);
20554
+ return { success: true, ...state, activity: getWorkspaceActivity(out, 25) };
20555
+ }
20556
+ init_workspaces();
20146
20557
  var DaemonCommandHandler = class {
20147
20558
  _ctx;
20148
20559
  _agentStream = null;
@@ -20251,6 +20662,9 @@ var require_dist = __commonJS({
20251
20662
  }
20252
20663
  /** Extract ideType from _targetInstance */
20253
20664
  extractIdeType(args) {
20665
+ if (args?.ideType && this._ctx.cdpManagers.has(args.ideType)) {
20666
+ return args.ideType;
20667
+ }
20254
20668
  if (args?._targetInstance) {
20255
20669
  let raw = args._targetInstance;
20256
20670
  const ideMatch = raw.match(/:ide:(.+)$/);
@@ -20262,8 +20676,19 @@ var require_dist = __commonJS({
20262
20676
  if (this._ctx.instanceIdMap?.has(raw)) {
20263
20677
  return this._ctx.instanceIdMap.get(raw);
20264
20678
  }
20679
+ if (this._ctx.cdpManagers.has(raw)) {
20680
+ return raw;
20681
+ }
20682
+ if (!ideMatch && !cliMatch && !acpMatch) {
20683
+ for (const [key, mgr] of this._ctx.cdpManagers.entries()) {
20684
+ if (mgr.isConnected) return key;
20685
+ }
20686
+ }
20265
20687
  const lastUnderscore = raw.lastIndexOf("_");
20266
- if (lastUnderscore > 0) return raw.substring(0, lastUnderscore);
20688
+ if (lastUnderscore > 0) {
20689
+ const stripped = raw.substring(0, lastUnderscore);
20690
+ if (this._ctx.cdpManagers.has(stripped)) return stripped;
20691
+ }
20267
20692
  return raw;
20268
20693
  }
20269
20694
  return void 0;
@@ -20359,6 +20784,19 @@ var require_dist = __commonJS({
20359
20784
  return { success: false, error: `${cmd} requires bridge-extension (removed)` };
20360
20785
  case "get_recent_workspaces":
20361
20786
  return this.handleGetRecentWorkspaces(args);
20787
+ case "get_cli_history": {
20788
+ const config2 = loadConfig4();
20789
+ return { success: true, history: config2.cliHistory || [] };
20790
+ }
20791
+ case "workspace_list":
20792
+ return handleWorkspaceList();
20793
+ case "workspace_add":
20794
+ return handleWorkspaceAdd(args);
20795
+ case "workspace_remove":
20796
+ return handleWorkspaceRemove(args);
20797
+ case "workspace_set_default":
20798
+ case "workspace_set_active":
20799
+ return handleWorkspaceSetDefault(args);
20362
20800
  // ─── Script manage ───────────────────
20363
20801
  case "refresh_scripts":
20364
20802
  return this.handleRefreshScripts(args);
@@ -20408,10 +20846,18 @@ var require_dist = __commonJS({
20408
20846
  }
20409
20847
  }
20410
20848
  // ─── Misc (kept in handler — too small to extract) ───────
20411
- async handleGetRecentWorkspaces(args) {
20849
+ async handleGetRecentWorkspaces(_args) {
20412
20850
  const config2 = loadConfig4();
20413
20851
  const cliRecent = config2.recentCliWorkspaces || [];
20414
- return { success: true, result: cliRecent };
20852
+ const ws = getWorkspaceState(config2);
20853
+ return {
20854
+ success: true,
20855
+ result: cliRecent,
20856
+ workspaces: ws.workspaces,
20857
+ defaultWorkspaceId: ws.defaultWorkspaceId,
20858
+ defaultWorkspacePath: ws.defaultWorkspacePath,
20859
+ activity: getWorkspaceActivity(config2, 25)
20860
+ };
20415
20861
  }
20416
20862
  async handleRefreshScripts(_args) {
20417
20863
  if (this._ctx.providerLoader) {
@@ -20421,13 +20867,13 @@ var require_dist = __commonJS({
20421
20867
  return { success: false, error: "ProviderLoader not initialized" };
20422
20868
  }
20423
20869
  };
20424
- var import_child_process3 = require("child_process");
20870
+ var import_child_process4 = require("child_process");
20425
20871
  var net = __toESM2(require("net"));
20426
- var os6 = __toESM2(require("os"));
20427
- var path5 = __toESM2(require("path"));
20428
- var fs4 = __toESM2(require("fs"));
20429
- var path4 = __toESM2(require("path"));
20430
- var os5 = __toESM2(require("os"));
20872
+ var os8 = __toESM2(require("os"));
20873
+ var path7 = __toESM2(require("path"));
20874
+ var fs5 = __toESM2(require("fs"));
20875
+ var path6 = __toESM2(require("path"));
20876
+ var os7 = __toESM2(require("os"));
20431
20877
  var ProviderLoader3 = class _ProviderLoader {
20432
20878
  providers = /* @__PURE__ */ new Map();
20433
20879
  builtinDirs;
@@ -20447,10 +20893,10 @@ var require_dist = __commonJS({
20447
20893
  if (options?.builtinDir) {
20448
20894
  this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
20449
20895
  } else {
20450
- this.builtinDirs = [path4.resolve(__dirname, "../providers/_builtin")];
20896
+ this.builtinDirs = [path6.resolve(__dirname, "../providers/_builtin")];
20451
20897
  }
20452
- this.userDir = options?.userDir || path4.join(os5.homedir(), ".adhdev", "providers");
20453
- this.upstreamDir = path4.join(this.userDir, ".upstream");
20898
+ this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
20899
+ this.upstreamDir = path6.join(this.userDir, ".upstream");
20454
20900
  this.logFn = options?.logFn || LOG5.forComponent("Provider").asLogFn();
20455
20901
  }
20456
20902
  log(msg) {
@@ -20468,19 +20914,19 @@ var require_dist = __commonJS({
20468
20914
  this.providers.clear();
20469
20915
  let builtinCount = 0;
20470
20916
  for (const dir of this.builtinDirs) {
20471
- if (fs4.existsSync(dir)) {
20917
+ if (fs5.existsSync(dir)) {
20472
20918
  builtinCount += this.loadDir(dir);
20473
20919
  }
20474
20920
  }
20475
20921
  this.log(`Loaded ${builtinCount} builtin providers`);
20476
20922
  let upstreamCount = 0;
20477
- if (fs4.existsSync(this.upstreamDir)) {
20923
+ if (fs5.existsSync(this.upstreamDir)) {
20478
20924
  upstreamCount = this.loadDir(this.upstreamDir);
20479
20925
  if (upstreamCount > 0) {
20480
20926
  this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
20481
20927
  }
20482
20928
  }
20483
- if (fs4.existsSync(this.userDir)) {
20929
+ if (fs5.existsSync(this.userDir)) {
20484
20930
  const userCount = this.loadDir(this.userDir, [".upstream"]);
20485
20931
  if (userCount > 0) {
20486
20932
  this.log(`Loaded ${userCount} user custom providers (never auto-updated)`);
@@ -20784,15 +21230,15 @@ var require_dist = __commonJS({
20784
21230
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
20785
21231
  return null;
20786
21232
  }
20787
- const dir = path4.join(providerDir, scriptDir);
20788
- if (!fs4.existsSync(dir)) {
21233
+ const dir = path6.join(providerDir, scriptDir);
21234
+ if (!fs5.existsSync(dir)) {
20789
21235
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
20790
21236
  return null;
20791
21237
  }
20792
21238
  const cached2 = this.scriptsCache.get(dir);
20793
21239
  if (cached2) return cached2;
20794
- const scriptsJs = path4.join(dir, "scripts.js");
20795
- if (fs4.existsSync(scriptsJs)) {
21240
+ const scriptsJs = path6.join(dir, "scripts.js");
21241
+ if (fs5.existsSync(scriptsJs)) {
20796
21242
  try {
20797
21243
  delete require.cache[require.resolve(scriptsJs)];
20798
21244
  const loaded = require(scriptsJs);
@@ -20814,15 +21260,15 @@ var require_dist = __commonJS({
20814
21260
  watch() {
20815
21261
  this.stopWatch();
20816
21262
  const watchDir = (dir) => {
20817
- if (!fs4.existsSync(dir)) {
21263
+ if (!fs5.existsSync(dir)) {
20818
21264
  try {
20819
- fs4.mkdirSync(dir, { recursive: true });
21265
+ fs5.mkdirSync(dir, { recursive: true });
20820
21266
  } catch {
20821
21267
  return;
20822
21268
  }
20823
21269
  }
20824
21270
  try {
20825
- const watcher = fs4.watch(dir, { recursive: true }, (event, filename) => {
21271
+ const watcher = fs5.watch(dir, { recursive: true }, (event, filename) => {
20826
21272
  if (filename?.endsWith(".js") || filename?.endsWith(".json")) {
20827
21273
  this.log(`File changed: ${filename}, reloading...`);
20828
21274
  this.loadAll();
@@ -20872,13 +21318,13 @@ var require_dist = __commonJS({
20872
21318
  */
20873
21319
  async fetchLatest() {
20874
21320
  const https = require("https");
20875
- const { execSync: execSync6 } = require("child_process");
20876
- const metaPath = path4.join(this.upstreamDir, _ProviderLoader.META_FILE);
21321
+ const { execSync: execSync7 } = require("child_process");
21322
+ const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
20877
21323
  let prevEtag = "";
20878
21324
  let prevTimestamp = 0;
20879
21325
  try {
20880
- if (fs4.existsSync(metaPath)) {
20881
- const meta3 = JSON.parse(fs4.readFileSync(metaPath, "utf-8"));
21326
+ if (fs5.existsSync(metaPath)) {
21327
+ const meta3 = JSON.parse(fs5.readFileSync(metaPath, "utf-8"));
20882
21328
  prevEtag = meta3.etag || "";
20883
21329
  prevTimestamp = meta3.timestamp || 0;
20884
21330
  }
@@ -20890,7 +21336,7 @@ var require_dist = __commonJS({
20890
21336
  return { updated: false };
20891
21337
  }
20892
21338
  try {
20893
- const etag = await new Promise((resolve5, reject) => {
21339
+ const etag = await new Promise((resolve7, reject) => {
20894
21340
  const options = {
20895
21341
  method: "HEAD",
20896
21342
  hostname: "github.com",
@@ -20908,7 +21354,7 @@ var require_dist = __commonJS({
20908
21354
  headers: { "User-Agent": "adhdev-launcher" },
20909
21355
  timeout: 1e4
20910
21356
  }, (res2) => {
20911
- resolve5(res2.headers.etag || res2.headers["last-modified"] || "");
21357
+ resolve7(res2.headers.etag || res2.headers["last-modified"] || "");
20912
21358
  });
20913
21359
  req2.on("error", reject);
20914
21360
  req2.on("timeout", () => {
@@ -20917,7 +21363,7 @@ var require_dist = __commonJS({
20917
21363
  });
20918
21364
  req2.end();
20919
21365
  } else {
20920
- resolve5(res.headers.etag || res.headers["last-modified"] || "");
21366
+ resolve7(res.headers.etag || res.headers["last-modified"] || "");
20921
21367
  }
20922
21368
  });
20923
21369
  req.on("error", reject);
@@ -20933,39 +21379,39 @@ var require_dist = __commonJS({
20933
21379
  return { updated: false };
20934
21380
  }
20935
21381
  this.log("Downloading latest providers from GitHub...");
20936
- const tmpTar = path4.join(os5.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
20937
- const tmpExtract = path4.join(os5.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
21382
+ const tmpTar = path6.join(os7.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
21383
+ const tmpExtract = path6.join(os7.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
20938
21384
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
20939
- fs4.mkdirSync(tmpExtract, { recursive: true });
20940
- execSync6(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
20941
- const extracted = fs4.readdirSync(tmpExtract);
21385
+ fs5.mkdirSync(tmpExtract, { recursive: true });
21386
+ execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
21387
+ const extracted = fs5.readdirSync(tmpExtract);
20942
21388
  const rootDir = extracted.find(
20943
- (d) => fs4.statSync(path4.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
21389
+ (d) => fs5.statSync(path6.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
20944
21390
  );
20945
21391
  if (!rootDir) throw new Error("Unexpected tarball structure");
20946
- const sourceDir = path4.join(tmpExtract, rootDir);
21392
+ const sourceDir = path6.join(tmpExtract, rootDir);
20947
21393
  const backupDir = this.upstreamDir + ".bak";
20948
- if (fs4.existsSync(this.upstreamDir)) {
20949
- if (fs4.existsSync(backupDir)) fs4.rmSync(backupDir, { recursive: true, force: true });
20950
- fs4.renameSync(this.upstreamDir, backupDir);
21394
+ if (fs5.existsSync(this.upstreamDir)) {
21395
+ if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
21396
+ fs5.renameSync(this.upstreamDir, backupDir);
20951
21397
  }
20952
21398
  try {
20953
21399
  this.copyDirRecursive(sourceDir, this.upstreamDir);
20954
21400
  this.writeMeta(metaPath, etag || `ts-${Date.now()}`, Date.now());
20955
- if (fs4.existsSync(backupDir)) fs4.rmSync(backupDir, { recursive: true, force: true });
21401
+ if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
20956
21402
  } catch (e) {
20957
- if (fs4.existsSync(backupDir)) {
20958
- if (fs4.existsSync(this.upstreamDir)) fs4.rmSync(this.upstreamDir, { recursive: true, force: true });
20959
- fs4.renameSync(backupDir, this.upstreamDir);
21403
+ if (fs5.existsSync(backupDir)) {
21404
+ if (fs5.existsSync(this.upstreamDir)) fs5.rmSync(this.upstreamDir, { recursive: true, force: true });
21405
+ fs5.renameSync(backupDir, this.upstreamDir);
20960
21406
  }
20961
21407
  throw e;
20962
21408
  }
20963
21409
  try {
20964
- fs4.rmSync(tmpTar, { force: true });
21410
+ fs5.rmSync(tmpTar, { force: true });
20965
21411
  } catch {
20966
21412
  }
20967
21413
  try {
20968
- fs4.rmSync(tmpExtract, { recursive: true, force: true });
21414
+ fs5.rmSync(tmpExtract, { recursive: true, force: true });
20969
21415
  } catch {
20970
21416
  }
20971
21417
  const upstreamCount = this.countProviders(this.upstreamDir);
@@ -20981,7 +21427,7 @@ var require_dist = __commonJS({
20981
21427
  downloadFile(url2, destPath) {
20982
21428
  const https = require("https");
20983
21429
  const http3 = require("http");
20984
- return new Promise((resolve5, reject) => {
21430
+ return new Promise((resolve7, reject) => {
20985
21431
  const doRequest = (reqUrl, redirectCount = 0) => {
20986
21432
  if (redirectCount > 5) {
20987
21433
  reject(new Error("Too many redirects"));
@@ -20997,11 +21443,11 @@ var require_dist = __commonJS({
20997
21443
  reject(new Error(`HTTP ${res.statusCode}`));
20998
21444
  return;
20999
21445
  }
21000
- const ws = fs4.createWriteStream(destPath);
21446
+ const ws = fs5.createWriteStream(destPath);
21001
21447
  res.pipe(ws);
21002
21448
  ws.on("finish", () => {
21003
21449
  ws.close();
21004
- resolve5();
21450
+ resolve7();
21005
21451
  });
21006
21452
  ws.on("error", reject);
21007
21453
  });
@@ -21016,22 +21462,22 @@ var require_dist = __commonJS({
21016
21462
  }
21017
21463
  /** Recursive directory copy */
21018
21464
  copyDirRecursive(src, dest) {
21019
- fs4.mkdirSync(dest, { recursive: true });
21020
- for (const entry of fs4.readdirSync(src, { withFileTypes: true })) {
21021
- const srcPath = path4.join(src, entry.name);
21022
- const destPath = path4.join(dest, entry.name);
21465
+ fs5.mkdirSync(dest, { recursive: true });
21466
+ for (const entry of fs5.readdirSync(src, { withFileTypes: true })) {
21467
+ const srcPath = path6.join(src, entry.name);
21468
+ const destPath = path6.join(dest, entry.name);
21023
21469
  if (entry.isDirectory()) {
21024
21470
  this.copyDirRecursive(srcPath, destPath);
21025
21471
  } else {
21026
- fs4.copyFileSync(srcPath, destPath);
21472
+ fs5.copyFileSync(srcPath, destPath);
21027
21473
  }
21028
21474
  }
21029
21475
  }
21030
21476
  /** .meta.json save */
21031
21477
  writeMeta(metaPath, etag, timestamp) {
21032
21478
  try {
21033
- fs4.mkdirSync(path4.dirname(metaPath), { recursive: true });
21034
- fs4.writeFileSync(metaPath, JSON.stringify({
21479
+ fs5.mkdirSync(path6.dirname(metaPath), { recursive: true });
21480
+ fs5.writeFileSync(metaPath, JSON.stringify({
21035
21481
  etag,
21036
21482
  timestamp,
21037
21483
  lastCheck: new Date(timestamp).toISOString(),
@@ -21042,12 +21488,12 @@ var require_dist = __commonJS({
21042
21488
  }
21043
21489
  /** Count provider files (provider.js or provider.json) */
21044
21490
  countProviders(dir) {
21045
- if (!fs4.existsSync(dir)) return 0;
21491
+ if (!fs5.existsSync(dir)) return 0;
21046
21492
  let count = 0;
21047
21493
  const scan = (d) => {
21048
21494
  try {
21049
- for (const entry of fs4.readdirSync(d, { withFileTypes: true })) {
21050
- if (entry.isDirectory()) scan(path4.join(d, entry.name));
21495
+ for (const entry of fs5.readdirSync(d, { withFileTypes: true })) {
21496
+ if (entry.isDirectory()) scan(path6.join(d, entry.name));
21051
21497
  else if (entry.name === "provider.json") count++;
21052
21498
  }
21053
21499
  } catch {
@@ -21144,20 +21590,20 @@ var require_dist = __commonJS({
21144
21590
  const cat = provider2.category;
21145
21591
  const searchRoots = [this.userDir, this.upstreamDir, ...this.builtinDirs];
21146
21592
  for (const root of searchRoots) {
21147
- if (!fs4.existsSync(root)) continue;
21148
- for (const candidate of [path4.join(root, type), path4.join(root, cat, type)]) {
21149
- if (fs4.existsSync(path4.join(candidate, "provider.json"))) return candidate;
21593
+ if (!fs5.existsSync(root)) continue;
21594
+ for (const candidate of [path6.join(root, type), path6.join(root, cat, type)]) {
21595
+ if (fs5.existsSync(path6.join(candidate, "provider.json"))) return candidate;
21150
21596
  }
21151
- const catDir = path4.join(root, cat);
21152
- if (fs4.existsSync(catDir)) {
21597
+ const catDir = path6.join(root, cat);
21598
+ if (fs5.existsSync(catDir)) {
21153
21599
  try {
21154
- for (const entry of fs4.readdirSync(catDir, { withFileTypes: true })) {
21600
+ for (const entry of fs5.readdirSync(catDir, { withFileTypes: true })) {
21155
21601
  if (!entry.isDirectory()) continue;
21156
- const jsonPath = path4.join(catDir, entry.name, "provider.json");
21157
- if (fs4.existsSync(jsonPath)) {
21602
+ const jsonPath = path6.join(catDir, entry.name, "provider.json");
21603
+ if (fs5.existsSync(jsonPath)) {
21158
21604
  try {
21159
- const data = JSON.parse(fs4.readFileSync(jsonPath, "utf-8"));
21160
- if (data.type === type) return path4.join(catDir, entry.name);
21605
+ const data = JSON.parse(fs5.readFileSync(jsonPath, "utf-8"));
21606
+ if (data.type === type) return path6.join(catDir, entry.name);
21161
21607
  } catch {
21162
21608
  }
21163
21609
  }
@@ -21174,8 +21620,8 @@ var require_dist = __commonJS({
21174
21620
  * (template substitution is NOT applied here — scripts.js handles that)
21175
21621
  */
21176
21622
  buildScriptWrappersFromDir(dir) {
21177
- const scriptsJs = path4.join(dir, "scripts.js");
21178
- if (fs4.existsSync(scriptsJs)) {
21623
+ const scriptsJs = path6.join(dir, "scripts.js");
21624
+ if (fs5.existsSync(scriptsJs)) {
21179
21625
  try {
21180
21626
  delete require.cache[require.resolve(scriptsJs)];
21181
21627
  return require(scriptsJs);
@@ -21185,13 +21631,13 @@ var require_dist = __commonJS({
21185
21631
  const toCamel = (name) => name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
21186
21632
  const result = {};
21187
21633
  try {
21188
- for (const file2 of fs4.readdirSync(dir)) {
21634
+ for (const file2 of fs5.readdirSync(dir)) {
21189
21635
  if (!file2.endsWith(".js")) continue;
21190
21636
  const scriptName = toCamel(file2.replace(".js", ""));
21191
- const filePath = path4.join(dir, file2);
21637
+ const filePath = path6.join(dir, file2);
21192
21638
  result[scriptName] = (..._args) => {
21193
21639
  try {
21194
- return fs4.readFileSync(filePath, "utf-8");
21640
+ return fs5.readFileSync(filePath, "utf-8");
21195
21641
  } catch {
21196
21642
  return "";
21197
21643
  }
@@ -21209,20 +21655,20 @@ var require_dist = __commonJS({
21209
21655
  * Structure: dir/category/agent-name/provider.{json,js}
21210
21656
  */
21211
21657
  loadDir(dir, excludeDirs) {
21212
- if (!fs4.existsSync(dir)) return 0;
21658
+ if (!fs5.existsSync(dir)) return 0;
21213
21659
  let count = 0;
21214
21660
  const scan = (d) => {
21215
21661
  let entries;
21216
21662
  try {
21217
- entries = fs4.readdirSync(d, { withFileTypes: true });
21663
+ entries = fs5.readdirSync(d, { withFileTypes: true });
21218
21664
  } catch {
21219
21665
  return;
21220
21666
  }
21221
21667
  const hasJson = entries.some((e) => e.name === "provider.json");
21222
21668
  if (hasJson) {
21223
- const jsonPath = path4.join(d, "provider.json");
21669
+ const jsonPath = path6.join(d, "provider.json");
21224
21670
  try {
21225
- const raw = fs4.readFileSync(jsonPath, "utf-8");
21671
+ const raw = fs5.readFileSync(jsonPath, "utf-8");
21226
21672
  const mod = JSON.parse(raw);
21227
21673
  if (!mod.type || !mod.name || !mod.category) {
21228
21674
  this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
@@ -21233,8 +21679,8 @@ var require_dist = __commonJS({
21233
21679
  delete mod.extensionIdPattern_flags;
21234
21680
  }
21235
21681
  const hasCompatibility = Array.isArray(mod.compatibility);
21236
- const scriptsPath = path4.join(d, "scripts.js");
21237
- if (!hasCompatibility && fs4.existsSync(scriptsPath)) {
21682
+ const scriptsPath = path6.join(d, "scripts.js");
21683
+ if (!hasCompatibility && fs5.existsSync(scriptsPath)) {
21238
21684
  try {
21239
21685
  delete require.cache[require.resolve(scriptsPath)];
21240
21686
  const scripts = require(scriptsPath);
@@ -21259,7 +21705,7 @@ var require_dist = __commonJS({
21259
21705
  if (!entry.isDirectory()) continue;
21260
21706
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
21261
21707
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
21262
- scan(path4.join(d, entry.name));
21708
+ scan(path6.join(d, entry.name));
21263
21709
  }
21264
21710
  }
21265
21711
  };
@@ -21336,17 +21782,17 @@ var require_dist = __commonJS({
21336
21782
  throw new Error("No free port found");
21337
21783
  }
21338
21784
  function checkPortFree(port) {
21339
- return new Promise((resolve5) => {
21785
+ return new Promise((resolve7) => {
21340
21786
  const server = net.createServer();
21341
21787
  server.unref();
21342
- server.on("error", () => resolve5(false));
21788
+ server.on("error", () => resolve7(false));
21343
21789
  server.listen(port, "127.0.0.1", () => {
21344
- server.close(() => resolve5(true));
21790
+ server.close(() => resolve7(true));
21345
21791
  });
21346
21792
  });
21347
21793
  }
21348
21794
  async function isCdpActive(port) {
21349
- return new Promise((resolve5) => {
21795
+ return new Promise((resolve7) => {
21350
21796
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
21351
21797
  timeout: 2e3
21352
21798
  }, (res) => {
@@ -21355,52 +21801,52 @@ var require_dist = __commonJS({
21355
21801
  res.on("end", () => {
21356
21802
  try {
21357
21803
  const info = JSON.parse(data);
21358
- resolve5(!!info["WebKit-Version"] || !!info["Browser"]);
21804
+ resolve7(!!info["WebKit-Version"] || !!info["Browser"]);
21359
21805
  } catch {
21360
- resolve5(false);
21806
+ resolve7(false);
21361
21807
  }
21362
21808
  });
21363
21809
  });
21364
- req.on("error", () => resolve5(false));
21810
+ req.on("error", () => resolve7(false));
21365
21811
  req.on("timeout", () => {
21366
21812
  req.destroy();
21367
- resolve5(false);
21813
+ resolve7(false);
21368
21814
  });
21369
21815
  });
21370
21816
  }
21371
21817
  async function killIdeProcess(ideId) {
21372
- const plat = os6.platform();
21818
+ const plat = os8.platform();
21373
21819
  const appName = getMacAppIdentifiers()[ideId];
21374
21820
  const winProcesses = getWinProcessNames()[ideId];
21375
21821
  try {
21376
21822
  if (plat === "darwin" && appName) {
21377
21823
  try {
21378
- (0, import_child_process3.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
21824
+ (0, import_child_process4.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
21379
21825
  timeout: 5e3
21380
21826
  });
21381
21827
  } catch {
21382
21828
  try {
21383
- (0, import_child_process3.execSync)(`pkill -f "${appName}" 2>/dev/null`);
21829
+ (0, import_child_process4.execSync)(`pkill -f "${appName}" 2>/dev/null`);
21384
21830
  } catch {
21385
21831
  }
21386
21832
  }
21387
21833
  } else if (plat === "win32" && winProcesses) {
21388
21834
  for (const proc of winProcesses) {
21389
21835
  try {
21390
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
21836
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
21391
21837
  } catch {
21392
21838
  }
21393
21839
  }
21394
21840
  try {
21395
21841
  const exeName = winProcesses[0].replace(".exe", "");
21396
- (0, import_child_process3.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
21842
+ (0, import_child_process4.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
21397
21843
  timeout: 1e4
21398
21844
  });
21399
21845
  } catch {
21400
21846
  }
21401
21847
  } else {
21402
21848
  try {
21403
- (0, import_child_process3.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
21849
+ (0, import_child_process4.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
21404
21850
  } catch {
21405
21851
  }
21406
21852
  }
@@ -21410,13 +21856,13 @@ var require_dist = __commonJS({
21410
21856
  }
21411
21857
  if (plat === "darwin" && appName) {
21412
21858
  try {
21413
- (0, import_child_process3.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
21859
+ (0, import_child_process4.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
21414
21860
  } catch {
21415
21861
  }
21416
21862
  } else if (plat === "win32" && winProcesses) {
21417
21863
  for (const proc of winProcesses) {
21418
21864
  try {
21419
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
21865
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
21420
21866
  } catch {
21421
21867
  }
21422
21868
  }
@@ -21428,26 +21874,26 @@ var require_dist = __commonJS({
21428
21874
  }
21429
21875
  }
21430
21876
  function isIdeRunning(ideId) {
21431
- const plat = os6.platform();
21877
+ const plat = os8.platform();
21432
21878
  try {
21433
21879
  if (plat === "darwin") {
21434
21880
  const appName = getMacAppIdentifiers()[ideId];
21435
21881
  if (!appName) return false;
21436
- const result = (0, import_child_process3.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
21882
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
21437
21883
  return result.trim().length > 0;
21438
21884
  } else if (plat === "win32") {
21439
21885
  const winProcesses = getWinProcessNames()[ideId];
21440
21886
  if (!winProcesses) return false;
21441
21887
  for (const proc of winProcesses) {
21442
21888
  try {
21443
- const result = (0, import_child_process3.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
21889
+ const result = (0, import_child_process4.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
21444
21890
  if (result.includes(proc)) return true;
21445
21891
  } catch {
21446
21892
  }
21447
21893
  }
21448
21894
  try {
21449
21895
  const exeName = winProcesses[0].replace(".exe", "");
21450
- const result = (0, import_child_process3.execSync)(
21896
+ const result = (0, import_child_process4.execSync)(
21451
21897
  `powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
21452
21898
  { encoding: "utf-8", timeout: 5e3 }
21453
21899
  );
@@ -21456,7 +21902,7 @@ var require_dist = __commonJS({
21456
21902
  }
21457
21903
  return false;
21458
21904
  } else {
21459
- const result = (0, import_child_process3.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
21905
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
21460
21906
  return result.trim().length > 0;
21461
21907
  }
21462
21908
  } catch {
@@ -21464,12 +21910,12 @@ var require_dist = __commonJS({
21464
21910
  }
21465
21911
  }
21466
21912
  function detectCurrentWorkspace(ideId) {
21467
- const plat = os6.platform();
21913
+ const plat = os8.platform();
21468
21914
  if (plat === "darwin") {
21469
21915
  try {
21470
21916
  const appName = getMacAppIdentifiers()[ideId];
21471
21917
  if (!appName) return void 0;
21472
- const result = (0, import_child_process3.execSync)(
21918
+ const result = (0, import_child_process4.execSync)(
21473
21919
  `lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
21474
21920
  { encoding: "utf-8", timeout: 3e3 }
21475
21921
  );
@@ -21479,17 +21925,17 @@ var require_dist = __commonJS({
21479
21925
  }
21480
21926
  } else if (plat === "win32") {
21481
21927
  try {
21482
- const fs9 = require("fs");
21928
+ const fs10 = require("fs");
21483
21929
  const appNameMap = getMacAppIdentifiers();
21484
21930
  const appName = appNameMap[ideId];
21485
21931
  if (appName) {
21486
- const storagePath = path5.join(
21487
- process.env.APPDATA || path5.join(os6.homedir(), "AppData", "Roaming"),
21932
+ const storagePath = path7.join(
21933
+ process.env.APPDATA || path7.join(os8.homedir(), "AppData", "Roaming"),
21488
21934
  appName,
21489
21935
  "storage.json"
21490
21936
  );
21491
- if (fs9.existsSync(storagePath)) {
21492
- const data = JSON.parse(fs9.readFileSync(storagePath, "utf-8"));
21937
+ if (fs10.existsSync(storagePath)) {
21938
+ const data = JSON.parse(fs10.readFileSync(storagePath, "utf-8"));
21493
21939
  const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
21494
21940
  if (workspaces.length > 0) {
21495
21941
  const recent = workspaces[0];
@@ -21506,7 +21952,7 @@ var require_dist = __commonJS({
21506
21952
  return void 0;
21507
21953
  }
21508
21954
  async function launchWithCdp2(options = {}) {
21509
- const platform7 = os6.platform();
21955
+ const platform8 = os8.platform();
21510
21956
  let targetIde;
21511
21957
  const ides = await detectIDEs3();
21512
21958
  if (options.ideId) {
@@ -21575,9 +22021,9 @@ var require_dist = __commonJS({
21575
22021
  }
21576
22022
  const port = await findFreePort(portPair);
21577
22023
  try {
21578
- if (platform7 === "darwin") {
22024
+ if (platform8 === "darwin") {
21579
22025
  await launchMacOS(targetIde, port, workspace, options.newWindow);
21580
- } else if (platform7 === "win32") {
22026
+ } else if (platform8 === "win32") {
21581
22027
  await launchWindows(targetIde, port, workspace, options.newWindow);
21582
22028
  } else {
21583
22029
  await launchLinux(targetIde, port, workspace, options.newWindow);
@@ -21617,9 +22063,9 @@ var require_dist = __commonJS({
21617
22063
  if (workspace) args.push(workspace);
21618
22064
  if (appName) {
21619
22065
  const openArgs = ["-a", appName, "--args", ...args];
21620
- (0, import_child_process3.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
22066
+ (0, import_child_process4.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
21621
22067
  } else if (ide.cliCommand) {
21622
- (0, import_child_process3.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
22068
+ (0, import_child_process4.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
21623
22069
  } else {
21624
22070
  throw new Error(`No app identifier or CLI for ${ide.displayName}`);
21625
22071
  }
@@ -21645,19 +22091,21 @@ var require_dist = __commonJS({
21645
22091
  const args = ["--remote-debugging-port=" + port];
21646
22092
  if (newWindow) args.push("--new-window");
21647
22093
  if (workspace) args.push(workspace);
21648
- (0, import_child_process3.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
22094
+ (0, import_child_process4.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
21649
22095
  }
21650
22096
  function getAvailableIdeIds2() {
21651
22097
  return getProviderLoader().getAvailableIdeTypes();
21652
22098
  }
21653
- var fs5 = __toESM2(require("fs"));
21654
- var path6 = __toESM2(require("path"));
21655
- var os7 = __toESM2(require("os"));
21656
- var LOG_DIR2 = process.platform === "darwin" ? path6.join(os7.homedir(), "Library", "Logs", "adhdev") : path6.join(os7.homedir(), ".local", "share", "adhdev", "logs");
22099
+ init_config();
22100
+ init_workspaces();
22101
+ var fs6 = __toESM2(require("fs"));
22102
+ var path8 = __toESM2(require("path"));
22103
+ var os9 = __toESM2(require("os"));
22104
+ var LOG_DIR2 = process.platform === "darwin" ? path8.join(os9.homedir(), "Library", "Logs", "adhdev") : path8.join(os9.homedir(), ".local", "share", "adhdev", "logs");
21657
22105
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
21658
22106
  var MAX_DAYS = 7;
21659
22107
  try {
21660
- fs5.mkdirSync(LOG_DIR2, { recursive: true });
22108
+ fs6.mkdirSync(LOG_DIR2, { recursive: true });
21661
22109
  } catch {
21662
22110
  }
21663
22111
  var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
@@ -21691,19 +22139,19 @@ var require_dist = __commonJS({
21691
22139
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
21692
22140
  }
21693
22141
  var currentDate2 = getDateStr2();
21694
- var currentFile = path6.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
22142
+ var currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
21695
22143
  var writeCount2 = 0;
21696
22144
  function checkRotation() {
21697
22145
  const today = getDateStr2();
21698
22146
  if (today !== currentDate2) {
21699
22147
  currentDate2 = today;
21700
- currentFile = path6.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
22148
+ currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
21701
22149
  cleanOldFiles();
21702
22150
  }
21703
22151
  }
21704
22152
  function cleanOldFiles() {
21705
22153
  try {
21706
- const files = fs5.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
22154
+ const files = fs6.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
21707
22155
  const cutoff = /* @__PURE__ */ new Date();
21708
22156
  cutoff.setDate(cutoff.getDate() - MAX_DAYS);
21709
22157
  const cutoffStr = cutoff.toISOString().slice(0, 10);
@@ -21711,7 +22159,7 @@ var require_dist = __commonJS({
21711
22159
  const dateMatch = file2.match(/commands-(\d{4}-\d{2}-\d{2})/);
21712
22160
  if (dateMatch && dateMatch[1] < cutoffStr) {
21713
22161
  try {
21714
- fs5.unlinkSync(path6.join(LOG_DIR2, file2));
22162
+ fs6.unlinkSync(path8.join(LOG_DIR2, file2));
21715
22163
  } catch {
21716
22164
  }
21717
22165
  }
@@ -21721,14 +22169,14 @@ var require_dist = __commonJS({
21721
22169
  }
21722
22170
  function checkSize() {
21723
22171
  try {
21724
- const stat = fs5.statSync(currentFile);
22172
+ const stat = fs6.statSync(currentFile);
21725
22173
  if (stat.size > MAX_FILE_SIZE) {
21726
22174
  const backup = currentFile.replace(".jsonl", ".1.jsonl");
21727
22175
  try {
21728
- fs5.unlinkSync(backup);
22176
+ fs6.unlinkSync(backup);
21729
22177
  } catch {
21730
22178
  }
21731
- fs5.renameSync(currentFile, backup);
22179
+ fs6.renameSync(currentFile, backup);
21732
22180
  }
21733
22181
  } catch {
21734
22182
  }
@@ -21753,14 +22201,14 @@ var require_dist = __commonJS({
21753
22201
  ...entry.error ? { err: entry.error } : {},
21754
22202
  ...entry.durationMs !== void 0 ? { ms: entry.durationMs } : {}
21755
22203
  });
21756
- fs5.appendFileSync(currentFile, line + "\n");
22204
+ fs6.appendFileSync(currentFile, line + "\n");
21757
22205
  } catch {
21758
22206
  }
21759
22207
  }
21760
22208
  function getRecentCommands(count = 50) {
21761
22209
  try {
21762
- if (!fs5.existsSync(currentFile)) return [];
21763
- const content = fs5.readFileSync(currentFile, "utf-8");
22210
+ if (!fs6.existsSync(currentFile)) return [];
22211
+ const content = fs6.readFileSync(currentFile, "utf-8");
21764
22212
  const lines = content.trim().split("\n").filter(Boolean);
21765
22213
  return lines.slice(-count).map((line) => {
21766
22214
  try {
@@ -21783,7 +22231,7 @@ var require_dist = __commonJS({
21783
22231
  }
21784
22232
  }
21785
22233
  cleanOldFiles();
21786
- var fs6 = __toESM2(require("fs"));
22234
+ var fs7 = __toESM2(require("fs"));
21787
22235
  var CHAT_COMMANDS = [
21788
22236
  "send_chat",
21789
22237
  "new_chat",
@@ -21853,8 +22301,8 @@ var require_dist = __commonJS({
21853
22301
  if (logs.length > 0) {
21854
22302
  return { success: true, logs, totalBuffered: logs.length };
21855
22303
  }
21856
- if (fs6.existsSync(LOG_PATH)) {
21857
- const content = fs6.readFileSync(LOG_PATH, "utf-8");
22304
+ if (fs7.existsSync(LOG_PATH)) {
22305
+ const content = fs7.readFileSync(LOG_PATH, "utf-8");
21858
22306
  const allLines = content.split("\n");
21859
22307
  const recent = allLines.slice(-count).join("\n");
21860
22308
  return { success: true, logs: recent, totalLines: allLines.length };
@@ -21893,8 +22341,20 @@ var require_dist = __commonJS({
21893
22341
  }
21894
22342
  // ─── IDE launch + CDP connect ───
21895
22343
  case "launch_ide": {
21896
- const launchArgs = { ...args, ideId: args?.ideId || args?.ideType };
21897
- const ideKey = launchArgs.ideId;
22344
+ const ideKey = args?.ideId || args?.ideType;
22345
+ const resolvedWorkspace = resolveIdeLaunchWorkspace(
22346
+ {
22347
+ workspace: args?.workspace,
22348
+ workspaceId: args?.workspaceId,
22349
+ useDefaultWorkspace: args?.useDefaultWorkspace
22350
+ },
22351
+ loadConfig4()
22352
+ );
22353
+ const launchArgs = {
22354
+ ideId: ideKey,
22355
+ workspace: resolvedWorkspace,
22356
+ newWindow: args?.newWindow
22357
+ };
21898
22358
  LOG5.info("LaunchIDE", `target=${ideKey || "auto"}`);
21899
22359
  const result = await launchWithCdp2(launchArgs);
21900
22360
  if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
@@ -21911,6 +22371,15 @@ var require_dist = __commonJS({
21911
22371
  }
21912
22372
  }
21913
22373
  this.deps.onIdeConnected?.();
22374
+ if (result.success && resolvedWorkspace) {
22375
+ try {
22376
+ saveConfig2(appendWorkspaceActivity(loadConfig4(), resolvedWorkspace, {
22377
+ kind: "ide",
22378
+ agentType: result.ideId
22379
+ }));
22380
+ } catch {
22381
+ }
22382
+ }
21914
22383
  return { success: result.success, ...result };
21915
22384
  }
21916
22385
  // ─── IDE detection ───
@@ -21918,6 +22387,12 @@ var require_dist = __commonJS({
21918
22387
  this.deps.detectedIdes.value = await detectIDEs3();
21919
22388
  return { success: true, ides: this.deps.detectedIdes.value };
21920
22389
  }
22390
+ // ─── Machine Settings ───
22391
+ case "set_machine_nickname": {
22392
+ const nickname = args?.nickname;
22393
+ updateConfig2({ machineNickname: nickname || null });
22394
+ return { success: true };
22395
+ }
21921
22396
  }
21922
22397
  return null;
21923
22398
  }
@@ -21952,8 +22427,9 @@ var require_dist = __commonJS({
21952
22427
  LOG5.info("StopIDE", `IDE stopped: ${ideType}`);
21953
22428
  }
21954
22429
  };
21955
- var os8 = __toESM2(require("os"));
22430
+ var os10 = __toESM2(require("os"));
21956
22431
  init_config();
22432
+ init_workspaces();
21957
22433
  var DaemonStatusReporter2 = class {
21958
22434
  deps;
21959
22435
  log;
@@ -22020,6 +22496,10 @@ var require_dist = __commonJS({
22020
22496
  // (agent-stream polling backward compat)
22021
22497
  updateAgentStreams(_ideType, _streams) {
22022
22498
  }
22499
+ /** Reset P2P dedup hash — forces next send to transmit even if content unchanged */
22500
+ resetP2PHash() {
22501
+ this.lastP2PStatusHash = "";
22502
+ }
22023
22503
  // ─── Core ────────────────────────────────────────
22024
22504
  ts() {
22025
22505
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
@@ -22099,18 +22579,26 @@ var require_dist = __commonJS({
22099
22579
  acpConfigOptions: s.acpConfigOptions,
22100
22580
  acpModes: s.acpModes
22101
22581
  }));
22582
+ const cfg = loadConfig4();
22583
+ const wsState = getWorkspaceState(cfg);
22584
+ const memSnap = getHostMemorySnapshot();
22102
22585
  const payload = {
22103
22586
  daemonMode: true,
22104
- machineNickname: loadConfig4().machineNickname || null,
22587
+ machineNickname: cfg.machineNickname || null,
22588
+ workspaces: wsState.workspaces,
22589
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
22590
+ defaultWorkspacePath: wsState.defaultWorkspacePath,
22591
+ workspaceActivity: getWorkspaceActivity(cfg, 15),
22105
22592
  machine: {
22106
- hostname: os8.hostname(),
22107
- platform: os8.platform(),
22108
- arch: os8.arch(),
22109
- cpus: os8.cpus().length,
22110
- totalMem: os8.totalmem(),
22111
- freeMem: os8.freemem(),
22112
- loadavg: os8.loadavg(),
22113
- uptime: os8.uptime()
22593
+ hostname: os10.hostname(),
22594
+ platform: os10.platform(),
22595
+ arch: os10.arch(),
22596
+ cpus: os10.cpus().length,
22597
+ totalMem: memSnap.totalMem,
22598
+ freeMem: memSnap.freeMem,
22599
+ availableMem: memSnap.availableMem,
22600
+ loadavg: os10.loadavg(),
22601
+ uptime: os10.uptime()
22114
22602
  },
22115
22603
  managedIdes,
22116
22604
  managedClis,
@@ -22142,6 +22630,8 @@ var require_dist = __commonJS({
22142
22630
  const wsPayload = {
22143
22631
  daemonMode: true,
22144
22632
  machineNickname: payload.machineNickname,
22633
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
22634
+ workspaceCount: (wsState.workspaces || []).length,
22145
22635
  // managedIdes: server only saves id, type, cdpConnected
22146
22636
  managedIdes: managedIdes.map((ide) => ({
22147
22637
  ideType: ide.ideType,
@@ -22172,7 +22662,7 @@ var require_dist = __commonJS({
22172
22662
  sendP2PPayload(payload) {
22173
22663
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
22174
22664
  if (hashTarget.machine) {
22175
- const { freeMem: _f, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
22665
+ const { freeMem: _f, availableMem: _a2, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
22176
22666
  hashTarget.machine = stableMachine;
22177
22667
  }
22178
22668
  const h = this.simpleHash(JSON.stringify(hashTarget));
@@ -22192,15 +22682,32 @@ var require_dist = __commonJS({
22192
22682
  return h.toString(36);
22193
22683
  }
22194
22684
  };
22195
- var os10 = __toESM2(require("os"));
22196
- var path7 = __toESM2(require("path"));
22685
+ var os12 = __toESM2(require("os"));
22686
+ var path10 = __toESM2(require("path"));
22197
22687
  var crypto4 = __toESM2(require("crypto"));
22198
22688
  var import_chalk4 = __toESM2(require("chalk"));
22199
- var os9 = __toESM2(require("os"));
22200
- var import_child_process4 = require("child_process");
22689
+ var os11 = __toESM2(require("os"));
22690
+ var path9 = __toESM2(require("path"));
22691
+ var import_child_process5 = require("child_process");
22201
22692
  var pty;
22202
22693
  try {
22203
22694
  pty = require("node-pty");
22695
+ if (os11.platform() !== "win32") {
22696
+ try {
22697
+ const fs10 = require("fs");
22698
+ const ptyDir = path9.dirname(require.resolve("node-pty"));
22699
+ const arch3 = os11.arch() === "arm64" ? "darwin-arm64" : "darwin-x64";
22700
+ const helper = path9.join(ptyDir, "prebuilds", arch3, "spawn-helper");
22701
+ if (fs10.existsSync(helper)) {
22702
+ const stat = fs10.statSync(helper);
22703
+ if (!(stat.mode & 73)) {
22704
+ fs10.chmodSync(helper, stat.mode | 493);
22705
+ LOG5.info("CLI", "[node-pty] Fixed spawn-helper permissions");
22706
+ }
22707
+ }
22708
+ } catch {
22709
+ }
22710
+ }
22204
22711
  } catch {
22205
22712
  LOG5.error("CLI", "[ProviderCliAdapter] node-pty not found. Install: npm install node-pty@1.0.0");
22206
22713
  }
@@ -22208,21 +22715,125 @@ var require_dist = __commonJS({
22208
22715
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
22209
22716
  }
22210
22717
  function findBinary(name) {
22211
- const isWin = os9.platform() === "win32";
22718
+ const isWin = os11.platform() === "win32";
22212
22719
  try {
22213
22720
  const cmd = isWin ? `where ${name}` : `which ${name}`;
22214
- return (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
22721
+ return (0, import_child_process5.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
22215
22722
  } catch {
22216
22723
  return isWin ? `${name}.cmd` : name;
22217
22724
  }
22218
22725
  }
22726
+ function isScriptBinary(binaryPath) {
22727
+ if (!path9.isAbsolute(binaryPath)) return false;
22728
+ try {
22729
+ const fs10 = require("fs");
22730
+ const resolved = fs10.realpathSync(binaryPath);
22731
+ const head = Buffer.alloc(8);
22732
+ const fd = fs10.openSync(resolved, "r");
22733
+ fs10.readSync(fd, head, 0, 8, 0);
22734
+ fs10.closeSync(fd);
22735
+ let i = 0;
22736
+ if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
22737
+ return head[i] === 35 && head[i + 1] === 33;
22738
+ } catch {
22739
+ return false;
22740
+ }
22741
+ }
22742
+ function looksLikeMachOOrElf(filePath) {
22743
+ if (!path9.isAbsolute(filePath)) return false;
22744
+ try {
22745
+ const fs10 = require("fs");
22746
+ const resolved = fs10.realpathSync(filePath);
22747
+ const buf = Buffer.alloc(8);
22748
+ const fd = fs10.openSync(resolved, "r");
22749
+ fs10.readSync(fd, buf, 0, 8, 0);
22750
+ fs10.closeSync(fd);
22751
+ let i = 0;
22752
+ if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
22753
+ const b = buf.subarray(i);
22754
+ if (b.length < 4) return false;
22755
+ if (b[0] === 127 && b[1] === 69 && b[2] === 76 && b[3] === 70) return true;
22756
+ const le = b.readUInt32LE(0);
22757
+ const be = b.readUInt32BE(0);
22758
+ const magics = [4277009102, 4277009103, 3405691582, 3199925962];
22759
+ return magics.some((m) => m === le || m === be);
22760
+ } catch {
22761
+ return false;
22762
+ }
22763
+ }
22764
+ function shSingleQuote(arg) {
22765
+ if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
22766
+ return `'${arg.replace(/'/g, `'\\''`)}'`;
22767
+ }
22768
+ function parsePatternEntry(x) {
22769
+ if (x instanceof RegExp) return x;
22770
+ if (x && typeof x === "object" && typeof x.source === "string") {
22771
+ try {
22772
+ const s = x;
22773
+ return new RegExp(s.source, s.flags || "");
22774
+ } catch {
22775
+ return null;
22776
+ }
22777
+ }
22778
+ return null;
22779
+ }
22780
+ function coercePatternArray(raw, fallbacks) {
22781
+ if (!Array.isArray(raw)) return [...fallbacks];
22782
+ const parsed = raw.map(parsePatternEntry).filter((r) => r != null);
22783
+ return parsed.length > 0 ? parsed : [...fallbacks];
22784
+ }
22785
+ var FALLBACK_PROMPT = [
22786
+ /Type your message/i,
22787
+ /^>\s*$/m,
22788
+ // '>' alone on its own line
22789
+ /[›➤]\s*$/,
22790
+ /for shortcuts/i,
22791
+ /\?\s*for help/i,
22792
+ /Press enter/i
22793
+ // NOTE: removed /^[\s\u2500-\u257f]*>\s*$/m — the box-drawing char range is too wide and
22794
+ // can match dialog-clearing ANSI output, causing false prompt detection in approval state.
22795
+ ];
22796
+ var FALLBACK_GENERATING = [
22797
+ /[\u2800-\u28ff]/,
22798
+ // Braille spinner blocks (universal TUI)
22799
+ /esc to (cancel|interrupt|stop)/i,
22800
+ // Common TUI generation status line
22801
+ /generating\.\.\./i,
22802
+ /Claude is (?:thinking|processing|working)/i
22803
+ // Specific Claude Code status
22804
+ ];
22805
+ var FALLBACK_APPROVAL = [
22806
+ /Allow\s+once/i,
22807
+ /Always\s+allow/i,
22808
+ /\(y\/n\)/i,
22809
+ /\[Y\/n\]/i,
22810
+ /Run\s+this\s+command/i
22811
+ // NOTE: removed /Do you want to (?:run|execute|allow)/i — too broad, matches AI explanation
22812
+ // text like "Do you want to allow this feature?" causing false approval notifications.
22813
+ ];
22814
+ function defaultCleanOutput(raw, _lastUserInput) {
22815
+ return stripAnsi(raw).trim();
22816
+ }
22817
+ function normalizeCliProviderForRuntime(raw) {
22818
+ const patterns = raw?.patterns || {};
22819
+ return {
22820
+ ...raw,
22821
+ patterns: {
22822
+ prompt: coercePatternArray(patterns.prompt, FALLBACK_PROMPT),
22823
+ generating: coercePatternArray(patterns.generating, FALLBACK_GENERATING),
22824
+ approval: coercePatternArray(patterns.approval, FALLBACK_APPROVAL),
22825
+ ready: coercePatternArray(patterns.ready, [])
22826
+ },
22827
+ cleanOutput: typeof raw?.cleanOutput === "function" ? raw.cleanOutput : defaultCleanOutput
22828
+ };
22829
+ }
22219
22830
  var ProviderCliAdapter = class {
22220
22831
  constructor(provider2, workingDir, extraArgs = []) {
22221
22832
  this.extraArgs = extraArgs;
22222
- this.provider = provider2;
22833
+ this.provider = normalizeCliProviderForRuntime(provider2);
22223
22834
  this.cliType = provider2.type;
22224
22835
  this.cliName = provider2.name;
22225
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os9.homedir()) : workingDir;
22836
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os11.homedir()) : workingDir;
22226
22837
  const t = provider2.timeouts || {};
22227
22838
  this.timeouts = {
22228
22839
  ptyFlush: t.ptyFlush ?? 50,
@@ -22259,6 +22870,11 @@ var require_dist = __commonJS({
22259
22870
  logBuffer = [];
22260
22871
  // Approval cooldown
22261
22872
  lastApprovalResolvedAt = 0;
22873
+ // Approval state machine
22874
+ approvalTransitionBuffer = "";
22875
+ approvalExitTimeout = null;
22876
+ // Resize redraw suppression
22877
+ resizeSuppressUntil = 0;
22262
22878
  // Resolved timeouts (provider defaults + overrides)
22263
22879
  timeouts;
22264
22880
  // ─── Lifecycle ─────────────────────────────────
@@ -22280,20 +22896,25 @@ var require_dist = __commonJS({
22280
22896
  if (!pty) throw new Error("node-pty is not installed");
22281
22897
  const { spawn: spawnConfig } = this.provider;
22282
22898
  const binaryPath = findBinary(spawnConfig.command);
22283
- const isWin = os9.platform() === "win32";
22899
+ const isWin = os11.platform() === "win32";
22284
22900
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
22285
22901
  LOG5.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
22286
22902
  let shellCmd;
22287
22903
  let shellArgs;
22288
- if (spawnConfig.shell) {
22904
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
22905
+ const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
22906
+ if (useShell) {
22907
+ if (!spawnConfig.shell && !isWin) {
22908
+ LOG5.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
22909
+ }
22289
22910
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
22290
- const fullCmd = [binaryPath, ...allArgs].join(" ");
22911
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
22291
22912
  shellArgs = isWin ? ["/c", fullCmd] : ["-l", "-c", fullCmd];
22292
22913
  } else {
22293
22914
  shellCmd = binaryPath;
22294
22915
  shellArgs = allArgs;
22295
22916
  }
22296
- this.ptyProcess = pty.spawn(shellCmd, shellArgs, {
22917
+ const ptyOpts = {
22297
22918
  name: "xterm-256color",
22298
22919
  cols: 120,
22299
22920
  rows: 40,
@@ -22302,7 +22923,21 @@ var require_dist = __commonJS({
22302
22923
  ...process.env,
22303
22924
  ...spawnConfig.env
22304
22925
  }
22305
- });
22926
+ };
22927
+ try {
22928
+ this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
22929
+ } catch (err) {
22930
+ const msg = err?.message || String(err);
22931
+ if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
22932
+ LOG5.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
22933
+ shellCmd = process.env.SHELL || "/bin/zsh";
22934
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
22935
+ shellArgs = ["-l", "-c", fullCmd];
22936
+ this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
22937
+ } else {
22938
+ throw err;
22939
+ }
22940
+ }
22306
22941
  this.ptyProcess.onData((data) => {
22307
22942
  this.handleOutput(data);
22308
22943
  if (this.onPtyDataCallback) {
@@ -22330,6 +22965,7 @@ var require_dist = __commonJS({
22330
22965
  }
22331
22966
  // ─── Output state machine ────────────────────────────
22332
22967
  handleOutput(rawData) {
22968
+ if (Date.now() < this.resizeSuppressUntil) return;
22333
22969
  const cleanData = stripAnsi(rawData);
22334
22970
  const { patterns } = this.provider;
22335
22971
  if (cleanData.trim()) {
@@ -22362,30 +22998,55 @@ var require_dist = __commonJS({
22362
22998
  const hasApproval = patterns.approval.some((p) => p.test(this.recentOutputBuffer));
22363
22999
  if (hasApproval && this.currentStatus !== "waiting_approval") {
22364
23000
  if (this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown) return;
23001
+ const ctxLines = this.recentOutputBuffer.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
22365
23002
  this.isWaitingForResponse = true;
22366
23003
  this.currentStatus = "waiting_approval";
22367
23004
  this.recentOutputBuffer = "";
22368
- const ctxLines = cleanData.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
23005
+ this.approvalTransitionBuffer = "";
22369
23006
  this.activeModal = {
22370
23007
  message: ctxLines.slice(-5).join(" ").slice(0, 200) || "Approval required",
22371
23008
  buttons: ["Allow once", "Always allow", "Deny"]
22372
23009
  };
22373
23010
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
23011
+ if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
23012
+ this.approvalExitTimeout = setTimeout(() => {
23013
+ if (this.currentStatus === "waiting_approval") {
23014
+ LOG5.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-exiting waiting_approval`);
23015
+ this.activeModal = null;
23016
+ this.lastApprovalResolvedAt = Date.now();
23017
+ this.recentOutputBuffer = "";
23018
+ this.approvalTransitionBuffer = "";
23019
+ this.approvalExitTimeout = null;
23020
+ this.currentStatus = this.isWaitingForResponse ? "generating" : "idle";
23021
+ this.onStatusChange?.();
23022
+ }
23023
+ }, 6e4);
22374
23024
  this.onStatusChange?.();
22375
23025
  return;
22376
23026
  }
22377
23027
  if (this.currentStatus === "waiting_approval") {
22378
- const genResume = patterns.generating.some((p) => p.test(cleanData));
22379
- const promptResume = patterns.prompt.some((p) => p.test(cleanData));
23028
+ this.approvalTransitionBuffer = (this.approvalTransitionBuffer + cleanData).slice(-500);
23029
+ const genResume = patterns.generating.some((p) => p.test(this.approvalTransitionBuffer));
23030
+ const promptResume = patterns.prompt.some((p) => p.test(this.approvalTransitionBuffer));
22380
23031
  if (genResume) {
23032
+ if (this.approvalExitTimeout) {
23033
+ clearTimeout(this.approvalExitTimeout);
23034
+ this.approvalExitTimeout = null;
23035
+ }
22381
23036
  this.currentStatus = "generating";
22382
23037
  this.activeModal = null;
22383
23038
  this.recentOutputBuffer = "";
23039
+ this.approvalTransitionBuffer = "";
22384
23040
  this.lastApprovalResolvedAt = Date.now();
22385
23041
  this.onStatusChange?.();
22386
23042
  } else if (promptResume) {
23043
+ if (this.approvalExitTimeout) {
23044
+ clearTimeout(this.approvalExitTimeout);
23045
+ this.approvalExitTimeout = null;
23046
+ }
22387
23047
  this.activeModal = null;
22388
23048
  this.recentOutputBuffer = "";
23049
+ this.approvalTransitionBuffer = "";
22389
23050
  this.lastApprovalResolvedAt = Date.now();
22390
23051
  this.finishResponse();
22391
23052
  }
@@ -22411,7 +23072,8 @@ var require_dist = __commonJS({
22411
23072
  this.onStatusChange?.();
22412
23073
  return;
22413
23074
  }
22414
- if (patterns.prompt.some((p) => p.test(this.responseBuffer))) {
23075
+ const trailingLines = cleanData.split("\n").slice(-2).join("\n");
23076
+ if (patterns.prompt.some((p) => p.test(trailingLines))) {
22415
23077
  this.finishResponse();
22416
23078
  } else {
22417
23079
  this.idleTimeout = setTimeout(() => {
@@ -22432,6 +23094,10 @@ var require_dist = __commonJS({
22432
23094
  clearTimeout(this.idleTimeout);
22433
23095
  this.idleTimeout = null;
22434
23096
  }
23097
+ if (this.approvalExitTimeout) {
23098
+ clearTimeout(this.approvalExitTimeout);
23099
+ this.approvalExitTimeout = null;
23100
+ }
22435
23101
  const lastUserText = this.messages.filter((m) => m.role === "user").pop()?.content;
22436
23102
  let response = this.provider.cleanOutput(this.responseBuffer, lastUserText);
22437
23103
  if (lastUserText && response) {
@@ -22481,6 +23147,10 @@ var require_dist = __commonJS({
22481
23147
  this.shutdown();
22482
23148
  }
22483
23149
  shutdown() {
23150
+ if (this.approvalExitTimeout) {
23151
+ clearTimeout(this.approvalExitTimeout);
23152
+ this.approvalExitTimeout = null;
23153
+ }
22484
23154
  if (this.ptyProcess) {
22485
23155
  this.ptyProcess.write("");
22486
23156
  setTimeout(() => {
@@ -22508,16 +23178,29 @@ var require_dist = __commonJS({
22508
23178
  writeRaw(data) {
22509
23179
  this.ptyProcess?.write(data);
22510
23180
  }
23181
+ /**
23182
+ * Resolve an approval modal by navigating to the button at `buttonIndex` and pressing Enter.
23183
+ * Index 0 = first option (already selected by default — just Enter).
23184
+ * Index N = press Arrow Down N times, then Enter.
23185
+ */
23186
+ resolveModal(buttonIndex) {
23187
+ if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
23188
+ const DOWN = "\x1B[B";
23189
+ const keys = DOWN.repeat(Math.max(0, buttonIndex)) + "\r";
23190
+ this.ptyProcess.write(keys);
23191
+ }
22511
23192
  resize(cols, rows) {
22512
23193
  if (this.ptyProcess) {
22513
23194
  try {
22514
23195
  this.ptyProcess.resize(cols, rows);
23196
+ this.resizeSuppressUntil = Date.now() + 300;
22515
23197
  } catch {
22516
23198
  }
22517
23199
  }
22518
23200
  }
22519
23201
  };
22520
23202
  init_config();
23203
+ init_workspaces();
22521
23204
  var crypto3 = __toESM2(require("crypto"));
22522
23205
  var CliProviderInstance = class {
22523
23206
  constructor(provider2, workingDir, cliArgs = [], instanceId) {
@@ -22631,20 +23314,24 @@ var require_dist = __commonJS({
22631
23314
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
22632
23315
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
22633
23316
  if (newStatus !== this.lastStatus) {
23317
+ LOG5.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
22634
23318
  if (this.lastStatus === "idle" && newStatus === "generating") {
22635
23319
  this.generatingStartedAt = now;
22636
23320
  this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now });
22637
23321
  } else if (newStatus === "waiting_approval") {
22638
23322
  if (!this.generatingStartedAt) this.generatingStartedAt = now;
23323
+ const modal = adapterStatus.activeModal;
23324
+ LOG5.info("CLI", `[${this.type}] approval modal: "${modal?.message?.slice(0, 80) ?? "none"}"`);
22639
23325
  this.pushEvent({
22640
23326
  event: "agent:waiting_approval",
22641
23327
  chatTitle,
22642
23328
  timestamp: now,
22643
- modalMessage: adapterStatus.activeModal?.message,
22644
- modalButtons: adapterStatus.activeModal?.buttons
23329
+ modalMessage: modal?.message,
23330
+ modalButtons: modal?.buttons
22645
23331
  });
22646
23332
  } else if (newStatus === "idle" && (this.lastStatus === "generating" || this.lastStatus === "waiting_approval")) {
22647
23333
  const duration3 = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
23334
+ LOG5.info("CLI", `[${this.type}] completed in ${duration3}s`);
22648
23335
  this.pushEvent({ event: "agent:generating_completed", chatTitle, duration: duration3, timestamp: now });
22649
23336
  this.generatingStartedAt = 0;
22650
23337
  } else if (newStatus === "stopped") {
@@ -22679,7 +23366,7 @@ var require_dist = __commonJS({
22679
23366
  }
22680
23367
  };
22681
23368
  var import_stream = require("stream");
22682
- var import_child_process5 = require("child_process");
23369
+ var import_child_process6 = require("child_process");
22683
23370
  var import_sdk = (init_acp(), __toCommonJS(acp_exports));
22684
23371
  function flattenContent(content) {
22685
23372
  if (typeof content === "string") return content;
@@ -22996,7 +23683,7 @@ var require_dist = __commonJS({
22996
23683
  this.errorMessage = null;
22997
23684
  this.errorReason = null;
22998
23685
  this.stderrBuffer = [];
22999
- this.process = (0, import_child_process5.spawn)(command, args, {
23686
+ this.process = (0, import_child_process6.spawn)(command, args, {
23000
23687
  cwd: this.workingDir,
23001
23688
  env,
23002
23689
  stdio: ["pipe", "pipe", "pipe"],
@@ -23100,13 +23787,13 @@ var require_dist = __commonJS({
23100
23787
  }
23101
23788
  this.currentStatus = "waiting_approval";
23102
23789
  this.detectStatusTransition();
23103
- const approved = await new Promise((resolve5) => {
23104
- this.permissionResolvers.push(resolve5);
23790
+ const approved = await new Promise((resolve7) => {
23791
+ this.permissionResolvers.push(resolve7);
23105
23792
  setTimeout(() => {
23106
- const idx = this.permissionResolvers.indexOf(resolve5);
23793
+ const idx = this.permissionResolvers.indexOf(resolve7);
23107
23794
  if (idx >= 0) {
23108
23795
  this.permissionResolvers.splice(idx, 1);
23109
- resolve5(false);
23796
+ resolve7(false);
23110
23797
  }
23111
23798
  }, 3e5);
23112
23799
  });
@@ -23574,6 +24261,24 @@ var require_dist = __commonJS({
23574
24261
  const hash2 = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
23575
24262
  return `${cliType}_${hash2}`;
23576
24263
  }
24264
+ persistRecentDir(cliType, dir) {
24265
+ try {
24266
+ const normalizedType = this.providerLoader.resolveAlias(cliType);
24267
+ const provider2 = this.providerLoader.getByAlias(cliType);
24268
+ const actKind = provider2?.category === "acp" ? "acp" : "cli";
24269
+ let next = loadConfig4();
24270
+ console.log(import_chalk4.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
24271
+ const recent = next.recentCliWorkspaces || [];
24272
+ if (!recent.includes(dir)) {
24273
+ next = { ...next, recentCliWorkspaces: [dir, ...recent].slice(0, 10) };
24274
+ }
24275
+ next = appendWorkspaceActivity(next, dir, { kind: actKind, agentType: normalizedType });
24276
+ saveConfig2(next);
24277
+ console.log(import_chalk4.default.green(` \u2713 Recent workspace saved: ${dir}`));
24278
+ } catch (e) {
24279
+ console.error(import_chalk4.default.red(` \u2717 Failed to save recent workspace: ${e}`));
24280
+ }
24281
+ }
23577
24282
  createAdapter(cliType, workingDir, cliArgs) {
23578
24283
  const normalizedType = this.providerLoader.resolveAlias(cliType);
23579
24284
  const provider2 = this.providerLoader.getMeta(normalizedType);
@@ -23585,8 +24290,9 @@ var require_dist = __commonJS({
23585
24290
  }
23586
24291
  // ─── Session start/management ──────────────────────────────
23587
24292
  async startSession(cliType, workingDir, cliArgs, initialModel) {
23588
- const trimmed = (workingDir || os10.homedir()).trim();
23589
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path7.resolve(trimmed);
24293
+ const trimmed = (workingDir || "").trim();
24294
+ if (!trimmed) throw new Error("working directory required");
24295
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path10.resolve(trimmed);
23590
24296
  const normalizedType = this.providerLoader.resolveAlias(cliType);
23591
24297
  const provider2 = this.providerLoader.getByAlias(cliType);
23592
24298
  const key = crypto4.randomUUID();
@@ -23596,8 +24302,8 @@ var require_dist = __commonJS({
23596
24302
  const spawnCmd = provider2.spawn?.command;
23597
24303
  if (spawnCmd) {
23598
24304
  try {
23599
- const { execSync: execSync6 } = require("child_process");
23600
- execSync6(`which ${spawnCmd}`, { stdio: "ignore" });
24305
+ const { execSync: execSync7 } = require("child_process");
24306
+ execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
23601
24307
  } catch {
23602
24308
  const installInfo = provider2.install || `Install: check ${provider2.displayName || provider2.name} documentation`;
23603
24309
  throw new Error(
@@ -23664,18 +24370,52 @@ ${installInfo}`
23664
24370
  const instanceManager = this.deps.getInstanceManager();
23665
24371
  if (provider2 && instanceManager) {
23666
24372
  const cliInstance = new CliProviderInstance(provider2, resolvedDir, cliArgs, key);
23667
- await instanceManager.addInstance(key, cliInstance, {
23668
- serverConn: this.deps.getServerConn(),
23669
- settings: {},
23670
- onPtyData: (data) => {
23671
- this.deps.getP2p()?.broadcastPtyOutput(key, data);
23672
- }
23673
- });
24373
+ try {
24374
+ await instanceManager.addInstance(key, cliInstance, {
24375
+ serverConn: this.deps.getServerConn(),
24376
+ settings: {},
24377
+ onPtyData: (data) => {
24378
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
24379
+ }
24380
+ });
24381
+ } catch (spawnErr) {
24382
+ LOG5.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
24383
+ instanceManager.removeInstance(key);
24384
+ throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
24385
+ }
23674
24386
  this.adapters.set(key, cliInstance.getAdapter());
23675
24387
  console.log(import_chalk4.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
24388
+ const checkStopped = setInterval(() => {
24389
+ try {
24390
+ const adapter = this.adapters.get(key);
24391
+ if (!adapter) {
24392
+ clearInterval(checkStopped);
24393
+ return;
24394
+ }
24395
+ const status = adapter.getStatus?.();
24396
+ if (status?.status === "stopped" || status?.status === "error") {
24397
+ clearInterval(checkStopped);
24398
+ setTimeout(() => {
24399
+ if (this.adapters.has(key)) {
24400
+ this.adapters.delete(key);
24401
+ this.deps.removeAgentTracking(key);
24402
+ instanceManager.removeInstance(key);
24403
+ LOG5.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${cliType}`);
24404
+ this.deps.onStatusChange();
24405
+ }
24406
+ }, 5e3);
24407
+ }
24408
+ } catch {
24409
+ }
24410
+ }, 3e3);
23676
24411
  } else {
23677
24412
  const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
23678
- await adapter.spawn();
24413
+ try {
24414
+ await adapter.spawn();
24415
+ } catch (spawnErr) {
24416
+ LOG5.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
24417
+ throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
24418
+ }
23679
24419
  const serverConn = this.deps.getServerConn();
23680
24420
  if (serverConn && typeof adapter.setServerConn === "function") {
23681
24421
  adapter.setServerConn(serverConn);
@@ -23683,12 +24423,12 @@ ${installInfo}`
23683
24423
  adapter.setOnStatusChange(() => {
23684
24424
  this.deps.onStatusChange();
23685
24425
  const status = adapter.getStatus?.();
23686
- if (status?.status === "stopped") {
24426
+ if (status?.status === "stopped" || status?.status === "error") {
23687
24427
  setTimeout(() => {
23688
24428
  if (this.adapters.get(key) === adapter) {
23689
24429
  this.adapters.delete(key);
23690
24430
  this.deps.removeAgentTracking(key);
23691
- console.log(import_chalk4.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
24431
+ LOG5.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${adapter.cliType}`);
23692
24432
  this.deps.onStatusChange();
23693
24433
  }
23694
24434
  }, 3e3);
@@ -23712,12 +24452,24 @@ ${installInfo}`
23712
24452
  async stopSession(key) {
23713
24453
  const adapter = this.adapters.get(key);
23714
24454
  if (adapter) {
23715
- adapter.shutdown();
24455
+ try {
24456
+ adapter.shutdown();
24457
+ } catch (e) {
24458
+ LOG5.warn("CLI", `Shutdown error for ${adapter.cliType}: ${e?.message} (force-cleaning)`);
24459
+ }
23716
24460
  this.adapters.delete(key);
23717
24461
  this.deps.removeAgentTracking(key);
23718
24462
  this.deps.getInstanceManager()?.removeInstance(key);
23719
- console.log(import_chalk4.default.yellow(` \u{1F6D1} CLI Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`));
24463
+ LOG5.info("CLI", `\u{1F6D1} Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
23720
24464
  this.deps.onStatusChange();
24465
+ } else {
24466
+ const im = this.deps.getInstanceManager();
24467
+ if (im) {
24468
+ im.removeInstance(key);
24469
+ this.deps.removeAgentTracking(key);
24470
+ LOG5.warn("CLI", `\u{1F9F9} Force-removed orphan entry: ${key}`);
24471
+ this.deps.onStatusChange();
24472
+ }
23721
24473
  }
23722
24474
  }
23723
24475
  shutdownAll() {
@@ -23758,8 +24510,28 @@ ${installInfo}`
23758
24510
  switch (cmd) {
23759
24511
  case "launch_cli": {
23760
24512
  const cliType = args?.cliType;
23761
- const defaultedToHome = !args?.dir;
23762
- const dir = args?.dir || os10.homedir();
24513
+ const config2 = loadConfig4();
24514
+ const resolved = resolveLaunchDirectory(
24515
+ {
24516
+ dir: args?.dir,
24517
+ workspaceId: args?.workspaceId,
24518
+ useDefaultWorkspace: args?.useDefaultWorkspace === true,
24519
+ useHome: args?.useHome === true
24520
+ },
24521
+ config2
24522
+ );
24523
+ if (!resolved.ok) {
24524
+ const ws = getWorkspaceState(config2);
24525
+ return {
24526
+ success: false,
24527
+ error: resolved.message,
24528
+ code: resolved.code,
24529
+ workspaces: ws.workspaces,
24530
+ defaultWorkspacePath: ws.defaultWorkspacePath
24531
+ };
24532
+ }
24533
+ const dir = resolved.path;
24534
+ const launchSource = resolved.source;
23763
24535
  if (!cliType) throw new Error("cliType required");
23764
24536
  await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
23765
24537
  let newKey = null;
@@ -23768,19 +24540,8 @@ ${installInfo}`
23768
24540
  newKey = k;
23769
24541
  }
23770
24542
  }
23771
- try {
23772
- const config2 = loadConfig4();
23773
- console.log(import_chalk4.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
23774
- const recent = config2.recentCliWorkspaces || [];
23775
- if (!recent.includes(dir)) {
23776
- const updated = [dir, ...recent].slice(0, 10);
23777
- saveConfig2({ ...config2, recentCliWorkspaces: updated });
23778
- console.log(import_chalk4.default.green(` \u2713 Recent workspace saved: ${dir}`));
23779
- }
23780
- } catch (e) {
23781
- console.error(import_chalk4.default.red(` \u2717 Failed to save recent workspace: ${e}`));
23782
- }
23783
- return { success: true, cliType, dir, id: newKey, defaultedToHome };
24543
+ this.persistRecentDir(cliType, dir);
24544
+ return { success: true, cliType, dir, id: newKey, launchSource };
23784
24545
  }
23785
24546
  case "stop_cli": {
23786
24547
  const cliType = args?.cliType;
@@ -23796,11 +24557,32 @@ ${installInfo}`
23796
24557
  }
23797
24558
  case "restart_session": {
23798
24559
  const cliType = args?.cliType || args?.agentType || args?.ideType;
23799
- const dir = args?.dir || process.cwd();
24560
+ const cfg = loadConfig4();
24561
+ const rdir = resolveLaunchDirectory(
24562
+ {
24563
+ dir: args?.dir,
24564
+ workspaceId: args?.workspaceId,
24565
+ useDefaultWorkspace: args?.useDefaultWorkspace === true,
24566
+ useHome: args?.useHome === true
24567
+ },
24568
+ cfg
24569
+ );
24570
+ if (!rdir.ok) {
24571
+ const ws = getWorkspaceState(cfg);
24572
+ return {
24573
+ success: false,
24574
+ error: rdir.message,
24575
+ code: rdir.code,
24576
+ workspaces: ws.workspaces,
24577
+ defaultWorkspacePath: ws.defaultWorkspacePath
24578
+ };
24579
+ }
24580
+ const dir = rdir.path;
23800
24581
  if (!cliType) throw new Error("cliType required");
23801
24582
  const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
23802
24583
  if (found) await this.stopSession(found.key);
23803
24584
  await this.startSession(cliType, dir);
24585
+ this.persistRecentDir(cliType, dir);
23804
24586
  return { success: true, restarted: true };
23805
24587
  }
23806
24588
  case "agent_command": {
@@ -24428,12 +25210,12 @@ ${installInfo}`
24428
25210
  this.eventListeners = [];
24429
25211
  }
24430
25212
  };
24431
- var fs7 = __toESM2(require("fs"));
24432
- var path8 = __toESM2(require("path"));
24433
- var os11 = __toESM2(require("os"));
24434
- var import_child_process6 = require("child_process");
25213
+ var fs8 = __toESM2(require("fs"));
25214
+ var path11 = __toESM2(require("path"));
25215
+ var os13 = __toESM2(require("os"));
25216
+ var import_child_process7 = require("child_process");
24435
25217
  var import_os3 = require("os");
24436
- var ARCHIVE_PATH = path8.join(os11.homedir(), ".adhdev", "version-history.json");
25218
+ var ARCHIVE_PATH = path11.join(os13.homedir(), ".adhdev", "version-history.json");
24437
25219
  var MAX_ENTRIES_PER_PROVIDER = 20;
24438
25220
  var VersionArchive2 = class {
24439
25221
  history = {};
@@ -24442,8 +25224,8 @@ ${installInfo}`
24442
25224
  }
24443
25225
  load() {
24444
25226
  try {
24445
- if (fs7.existsSync(ARCHIVE_PATH)) {
24446
- this.history = JSON.parse(fs7.readFileSync(ARCHIVE_PATH, "utf-8"));
25227
+ if (fs8.existsSync(ARCHIVE_PATH)) {
25228
+ this.history = JSON.parse(fs8.readFileSync(ARCHIVE_PATH, "utf-8"));
24447
25229
  }
24448
25230
  } catch {
24449
25231
  this.history = {};
@@ -24480,15 +25262,15 @@ ${installInfo}`
24480
25262
  }
24481
25263
  save() {
24482
25264
  try {
24483
- fs7.mkdirSync(path8.dirname(ARCHIVE_PATH), { recursive: true });
24484
- fs7.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
25265
+ fs8.mkdirSync(path11.dirname(ARCHIVE_PATH), { recursive: true });
25266
+ fs8.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
24485
25267
  } catch {
24486
25268
  }
24487
25269
  }
24488
25270
  };
24489
25271
  function runCommand(cmd, timeout = 1e4) {
24490
25272
  try {
24491
- return (0, import_child_process6.execSync)(cmd, {
25273
+ return (0, import_child_process7.execSync)(cmd, {
24492
25274
  encoding: "utf-8",
24493
25275
  timeout,
24494
25276
  stdio: ["pipe", "pipe", "pipe"]
@@ -24520,19 +25302,19 @@ ${installInfo}`
24520
25302
  function checkPathExists2(paths) {
24521
25303
  for (const p of paths) {
24522
25304
  if (p.includes("*")) {
24523
- const home = os11.homedir();
24524
- const resolved = p.replace(/\*/g, home.split(path8.sep).pop() || "");
24525
- if (fs7.existsSync(resolved)) return resolved;
25305
+ const home = os13.homedir();
25306
+ const resolved = p.replace(/\*/g, home.split(path11.sep).pop() || "");
25307
+ if (fs8.existsSync(resolved)) return resolved;
24526
25308
  } else {
24527
- if (fs7.existsSync(p)) return p;
25309
+ if (fs8.existsSync(p)) return p;
24528
25310
  }
24529
25311
  }
24530
25312
  return null;
24531
25313
  }
24532
25314
  function getMacAppVersion(appPath) {
24533
25315
  if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
24534
- const plistPath = path8.join(appPath, "Contents", "Info.plist");
24535
- if (!fs7.existsSync(plistPath)) return null;
25316
+ const plistPath = path11.join(appPath, "Contents", "Info.plist");
25317
+ if (!fs8.existsSync(plistPath)) return null;
24536
25318
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
24537
25319
  return raw || null;
24538
25320
  }
@@ -24557,8 +25339,8 @@ ${installInfo}`
24557
25339
  const cliBin = provider2.cli ? findBinary2(provider2.cli) : null;
24558
25340
  let resolvedBin = cliBin;
24559
25341
  if (!resolvedBin && appPath && currentOs === "darwin") {
24560
- const bundled = path8.join(appPath, "Contents", "Resources", "app", "bin", provider2.cli || "");
24561
- if (provider2.cli && fs7.existsSync(bundled)) resolvedBin = bundled;
25342
+ const bundled = path11.join(appPath, "Contents", "Resources", "app", "bin", provider2.cli || "");
25343
+ if (provider2.cli && fs8.existsSync(bundled)) resolvedBin = bundled;
24562
25344
  }
24563
25345
  info.installed = !!(appPath || resolvedBin);
24564
25346
  info.path = appPath || null;
@@ -24595,9 +25377,9 @@ ${installInfo}`
24595
25377
  return results;
24596
25378
  }
24597
25379
  var http2 = __toESM2(require("http"));
24598
- var fs8 = __toESM2(require("fs"));
24599
- var path9 = __toESM2(require("path"));
24600
- var os12 = __toESM2(require("os"));
25380
+ var fs9 = __toESM2(require("fs"));
25381
+ var path12 = __toESM2(require("path"));
25382
+ var os14 = __toESM2(require("os"));
24601
25383
  function generateFiles(type, name, category, opts = {}) {
24602
25384
  const { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 = "0.1" } = opts;
24603
25385
  if (category === "cli" || category === "acp") {
@@ -24996,8 +25778,8 @@ async (params) => {
24996
25778
  }
24997
25779
  getEndpointList() {
24998
25780
  return this.routes.map((r) => {
24999
- const path10 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
25000
- return `${r.method.padEnd(5)} ${path10}`;
25781
+ const path13 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
25782
+ return `${r.method.padEnd(5)} ${path13}`;
25001
25783
  });
25002
25784
  }
25003
25785
  async start(port = DEV_SERVER_PORT) {
@@ -25028,15 +25810,15 @@ async (params) => {
25028
25810
  this.json(res, 500, { error: e.message });
25029
25811
  }
25030
25812
  });
25031
- return new Promise((resolve5, reject) => {
25813
+ return new Promise((resolve7, reject) => {
25032
25814
  this.server.listen(port, "127.0.0.1", () => {
25033
25815
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
25034
- resolve5();
25816
+ resolve7();
25035
25817
  });
25036
25818
  this.server.on("error", (e) => {
25037
25819
  if (e.code === "EADDRINUSE") {
25038
25820
  this.log(`Port ${port} in use, skipping dev server`);
25039
- resolve5();
25821
+ resolve7();
25040
25822
  } else {
25041
25823
  reject(e);
25042
25824
  }
@@ -25119,20 +25901,20 @@ async (params) => {
25119
25901
  child.stderr?.on("data", (d) => {
25120
25902
  stderr += d.toString().slice(0, 2e3);
25121
25903
  });
25122
- await new Promise((resolve5) => {
25904
+ await new Promise((resolve7) => {
25123
25905
  const timer = setTimeout(() => {
25124
25906
  child.kill();
25125
- resolve5();
25907
+ resolve7();
25126
25908
  }, 3e3);
25127
25909
  child.on("exit", () => {
25128
25910
  clearTimeout(timer);
25129
- resolve5();
25911
+ resolve7();
25130
25912
  });
25131
25913
  child.stdout?.once("data", () => {
25132
25914
  setTimeout(() => {
25133
25915
  child.kill();
25134
25916
  clearTimeout(timer);
25135
- resolve5();
25917
+ resolve7();
25136
25918
  }, 500);
25137
25919
  });
25138
25920
  });
@@ -25342,12 +26124,12 @@ async (params) => {
25342
26124
  // ─── DevConsole SPA ───
25343
26125
  getConsoleDistDir() {
25344
26126
  const candidates = [
25345
- path9.resolve(__dirname, "../../web-devconsole/dist"),
25346
- path9.resolve(__dirname, "../../../web-devconsole/dist"),
25347
- path9.join(process.cwd(), "packages/web-devconsole/dist")
26127
+ path12.resolve(__dirname, "../../web-devconsole/dist"),
26128
+ path12.resolve(__dirname, "../../../web-devconsole/dist"),
26129
+ path12.join(process.cwd(), "packages/web-devconsole/dist")
25348
26130
  ];
25349
26131
  for (const dir of candidates) {
25350
- if (fs8.existsSync(path9.join(dir, "index.html"))) return dir;
26132
+ if (fs9.existsSync(path12.join(dir, "index.html"))) return dir;
25351
26133
  }
25352
26134
  return null;
25353
26135
  }
@@ -25357,9 +26139,9 @@ async (params) => {
25357
26139
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
25358
26140
  return;
25359
26141
  }
25360
- const htmlPath = path9.join(distDir, "index.html");
26142
+ const htmlPath = path12.join(distDir, "index.html");
25361
26143
  try {
25362
- const html = fs8.readFileSync(htmlPath, "utf-8");
26144
+ const html = fs9.readFileSync(htmlPath, "utf-8");
25363
26145
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
25364
26146
  res.end(html);
25365
26147
  } catch (e) {
@@ -25382,15 +26164,15 @@ async (params) => {
25382
26164
  this.json(res, 404, { error: "Not found" });
25383
26165
  return;
25384
26166
  }
25385
- const safePath = path9.normalize(pathname).replace(/^\.\.\//, "");
25386
- const filePath = path9.join(distDir, safePath);
26167
+ const safePath = path12.normalize(pathname).replace(/^\.\.\//, "");
26168
+ const filePath = path12.join(distDir, safePath);
25387
26169
  if (!filePath.startsWith(distDir)) {
25388
26170
  this.json(res, 403, { error: "Forbidden" });
25389
26171
  return;
25390
26172
  }
25391
26173
  try {
25392
- const content = fs8.readFileSync(filePath);
25393
- const ext = path9.extname(filePath);
26174
+ const content = fs9.readFileSync(filePath);
26175
+ const ext = path12.extname(filePath);
25394
26176
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
25395
26177
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
25396
26178
  res.end(content);
@@ -25489,26 +26271,26 @@ async (params) => {
25489
26271
  const provider2 = this.providerLoader.getMeta(type);
25490
26272
  if (!provider2) return null;
25491
26273
  const cat = provider2.category;
25492
- const builtinDir = this.providerLoader.builtinDir || path9.resolve(__dirname, "../providers/_builtin");
25493
- const userDir = path9.join(os12.homedir(), ".adhdev", "providers");
26274
+ const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
26275
+ const userDir = path12.join(os14.homedir(), ".adhdev", "providers");
25494
26276
  const directCandidates = [
25495
- path9.join(userDir, type),
25496
- path9.join(builtinDir, cat, type),
25497
- path9.join(builtinDir, type)
26277
+ path12.join(userDir, type),
26278
+ path12.join(builtinDir, cat, type),
26279
+ path12.join(builtinDir, type)
25498
26280
  ];
25499
26281
  for (const d of directCandidates) {
25500
- if (fs8.existsSync(path9.join(d, "provider.json"))) return d;
26282
+ if (fs9.existsSync(path12.join(d, "provider.json"))) return d;
25501
26283
  }
25502
- const catDir = path9.join(builtinDir, cat);
25503
- if (fs8.existsSync(catDir)) {
26284
+ const catDir = path12.join(builtinDir, cat);
26285
+ if (fs9.existsSync(catDir)) {
25504
26286
  try {
25505
- for (const entry of fs8.readdirSync(catDir, { withFileTypes: true })) {
26287
+ for (const entry of fs9.readdirSync(catDir, { withFileTypes: true })) {
25506
26288
  if (!entry.isDirectory()) continue;
25507
- const jsonPath = path9.join(catDir, entry.name, "provider.json");
25508
- if (fs8.existsSync(jsonPath)) {
26289
+ const jsonPath = path12.join(catDir, entry.name, "provider.json");
26290
+ if (fs9.existsSync(jsonPath)) {
25509
26291
  try {
25510
- const data = JSON.parse(fs8.readFileSync(jsonPath, "utf-8"));
25511
- if (data.type === type) return path9.join(catDir, entry.name);
26292
+ const data = JSON.parse(fs9.readFileSync(jsonPath, "utf-8"));
26293
+ if (data.type === type) return path12.join(catDir, entry.name);
25512
26294
  } catch {
25513
26295
  }
25514
26296
  }
@@ -25528,14 +26310,14 @@ async (params) => {
25528
26310
  const files = [];
25529
26311
  const scan = (d, prefix) => {
25530
26312
  try {
25531
- for (const entry of fs8.readdirSync(d, { withFileTypes: true })) {
26313
+ for (const entry of fs9.readdirSync(d, { withFileTypes: true })) {
25532
26314
  if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
25533
26315
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
25534
26316
  if (entry.isDirectory()) {
25535
26317
  files.push({ path: rel, size: 0, type: "dir" });
25536
- scan(path9.join(d, entry.name), rel);
26318
+ scan(path12.join(d, entry.name), rel);
25537
26319
  } else {
25538
- const stat = fs8.statSync(path9.join(d, entry.name));
26320
+ const stat = fs9.statSync(path12.join(d, entry.name));
25539
26321
  files.push({ path: rel, size: stat.size, type: "file" });
25540
26322
  }
25541
26323
  }
@@ -25558,16 +26340,16 @@ async (params) => {
25558
26340
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
25559
26341
  return;
25560
26342
  }
25561
- const fullPath = path9.resolve(dir, path9.normalize(filePath));
26343
+ const fullPath = path12.resolve(dir, path12.normalize(filePath));
25562
26344
  if (!fullPath.startsWith(dir)) {
25563
26345
  this.json(res, 403, { error: "Forbidden" });
25564
26346
  return;
25565
26347
  }
25566
- if (!fs8.existsSync(fullPath) || fs8.statSync(fullPath).isDirectory()) {
26348
+ if (!fs9.existsSync(fullPath) || fs9.statSync(fullPath).isDirectory()) {
25567
26349
  this.json(res, 404, { error: `File not found: ${filePath}` });
25568
26350
  return;
25569
26351
  }
25570
- const content = fs8.readFileSync(fullPath, "utf-8");
26352
+ const content = fs9.readFileSync(fullPath, "utf-8");
25571
26353
  this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
25572
26354
  }
25573
26355
  /** POST /api/providers/:type/file — write a file { path, content } */
@@ -25583,15 +26365,15 @@ async (params) => {
25583
26365
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
25584
26366
  return;
25585
26367
  }
25586
- const fullPath = path9.resolve(dir, path9.normalize(filePath));
26368
+ const fullPath = path12.resolve(dir, path12.normalize(filePath));
25587
26369
  if (!fullPath.startsWith(dir)) {
25588
26370
  this.json(res, 403, { error: "Forbidden" });
25589
26371
  return;
25590
26372
  }
25591
26373
  try {
25592
- if (fs8.existsSync(fullPath)) fs8.copyFileSync(fullPath, fullPath + ".bak");
25593
- fs8.mkdirSync(path9.dirname(fullPath), { recursive: true });
25594
- fs8.writeFileSync(fullPath, content, "utf-8");
26374
+ if (fs9.existsSync(fullPath)) fs9.copyFileSync(fullPath, fullPath + ".bak");
26375
+ fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
26376
+ fs9.writeFileSync(fullPath, content, "utf-8");
25595
26377
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
25596
26378
  this.providerLoader.reload();
25597
26379
  this.json(res, 200, { saved: true, path: filePath, chars: content.length });
@@ -25607,9 +26389,9 @@ async (params) => {
25607
26389
  return;
25608
26390
  }
25609
26391
  for (const name of ["scripts.js", "provider.json"]) {
25610
- const p = path9.join(dir, name);
25611
- if (fs8.existsSync(p)) {
25612
- const source = fs8.readFileSync(p, "utf-8");
26392
+ const p = path12.join(dir, name);
26393
+ if (fs9.existsSync(p)) {
26394
+ const source = fs9.readFileSync(p, "utf-8");
25613
26395
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
25614
26396
  return;
25615
26397
  }
@@ -25628,11 +26410,11 @@ async (params) => {
25628
26410
  this.json(res, 404, { error: `Provider not found: ${type}` });
25629
26411
  return;
25630
26412
  }
25631
- const target = fs8.existsSync(path9.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
25632
- const targetPath = path9.join(dir, target);
26413
+ const target = fs9.existsSync(path12.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
26414
+ const targetPath = path12.join(dir, target);
25633
26415
  try {
25634
- if (fs8.existsSync(targetPath)) fs8.copyFileSync(targetPath, targetPath + ".bak");
25635
- fs8.writeFileSync(targetPath, source, "utf-8");
26416
+ if (fs9.existsSync(targetPath)) fs9.copyFileSync(targetPath, targetPath + ".bak");
26417
+ fs9.writeFileSync(targetPath, source, "utf-8");
25636
26418
  this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
25637
26419
  this.providerLoader.reload();
25638
26420
  this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
@@ -25647,18 +26429,18 @@ async (params) => {
25647
26429
  return;
25648
26430
  }
25649
26431
  let scriptsPath = "";
25650
- const directScripts = path9.join(dir, "scripts.js");
25651
- if (fs8.existsSync(directScripts)) {
26432
+ const directScripts = path12.join(dir, "scripts.js");
26433
+ if (fs9.existsSync(directScripts)) {
25652
26434
  scriptsPath = directScripts;
25653
26435
  } else {
25654
- const scriptsDir = path9.join(dir, "scripts");
25655
- if (fs8.existsSync(scriptsDir)) {
25656
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
25657
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
26436
+ const scriptsDir = path12.join(dir, "scripts");
26437
+ if (fs9.existsSync(scriptsDir)) {
26438
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
26439
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
25658
26440
  }).sort().reverse();
25659
26441
  for (const ver of versions) {
25660
- const p = path9.join(scriptsDir, ver, "scripts.js");
25661
- if (fs8.existsSync(p)) {
26442
+ const p = path12.join(scriptsDir, ver, "scripts.js");
26443
+ if (fs9.existsSync(p)) {
25662
26444
  scriptsPath = p;
25663
26445
  break;
25664
26446
  }
@@ -25670,7 +26452,7 @@ async (params) => {
25670
26452
  return;
25671
26453
  }
25672
26454
  try {
25673
- const source = fs8.readFileSync(scriptsPath, "utf-8");
26455
+ const source = fs9.readFileSync(scriptsPath, "utf-8");
25674
26456
  const hints = {};
25675
26457
  const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
25676
26458
  let match;
@@ -25814,14 +26596,14 @@ async (params) => {
25814
26596
  child.stderr?.on("data", (d) => {
25815
26597
  stderr += d.toString();
25816
26598
  });
25817
- await new Promise((resolve5) => {
26599
+ await new Promise((resolve7) => {
25818
26600
  const timer = setTimeout(() => {
25819
26601
  child.kill();
25820
- resolve5();
26602
+ resolve7();
25821
26603
  }, timeout);
25822
26604
  child.on("exit", () => {
25823
26605
  clearTimeout(timer);
25824
- resolve5();
26606
+ resolve7();
25825
26607
  });
25826
26608
  });
25827
26609
  const elapsed = Date.now() - start;
@@ -25871,26 +26653,26 @@ async (params) => {
25871
26653
  }
25872
26654
  let targetDir;
25873
26655
  if (location === "user") {
25874
- targetDir = path9.join(os12.homedir(), ".adhdev", "providers", type);
26656
+ targetDir = path12.join(os14.homedir(), ".adhdev", "providers", type);
25875
26657
  } else {
25876
- const builtinDir = path9.resolve(__dirname, "../providers/_builtin");
25877
- targetDir = path9.join(builtinDir, category, type);
26658
+ const builtinDir = path12.resolve(__dirname, "../providers/_builtin");
26659
+ targetDir = path12.join(builtinDir, category, type);
25878
26660
  }
25879
- const jsonPath = path9.join(targetDir, "provider.json");
25880
- if (fs8.existsSync(jsonPath)) {
26661
+ const jsonPath = path12.join(targetDir, "provider.json");
26662
+ if (fs9.existsSync(jsonPath)) {
25881
26663
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
25882
26664
  return;
25883
26665
  }
25884
26666
  try {
25885
26667
  const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 });
25886
- fs8.mkdirSync(targetDir, { recursive: true });
25887
- fs8.writeFileSync(jsonPath, result["provider.json"], "utf-8");
26668
+ fs9.mkdirSync(targetDir, { recursive: true });
26669
+ fs9.writeFileSync(jsonPath, result["provider.json"], "utf-8");
25888
26670
  const createdFiles = ["provider.json"];
25889
26671
  if (result.files) {
25890
26672
  for (const [relPath, content] of Object.entries(result.files)) {
25891
- const fullPath = path9.join(targetDir, relPath);
25892
- fs8.mkdirSync(path9.dirname(fullPath), { recursive: true });
25893
- fs8.writeFileSync(fullPath, content, "utf-8");
26673
+ const fullPath = path12.join(targetDir, relPath);
26674
+ fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
26675
+ fs9.writeFileSync(fullPath, content, "utf-8");
25894
26676
  createdFiles.push(relPath);
25895
26677
  }
25896
26678
  }
@@ -26725,24 +27507,24 @@ async (params) => {
26725
27507
  }
26726
27508
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
26727
27509
  let referenceScripts = {};
26728
- const builtinDir = this.providerLoader.builtinDir || path9.resolve(__dirname, "../providers/_builtin");
26729
- const refDir = path9.join(builtinDir, "ide", reference);
26730
- if (fs8.existsSync(refDir)) {
26731
- const scriptsDir = path9.join(refDir, "scripts");
26732
- if (fs8.existsSync(scriptsDir)) {
26733
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
27510
+ const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
27511
+ const refDir = path12.join(builtinDir, "ide", reference);
27512
+ if (fs9.existsSync(refDir)) {
27513
+ const scriptsDir = path12.join(refDir, "scripts");
27514
+ if (fs9.existsSync(scriptsDir)) {
27515
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
26734
27516
  try {
26735
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
27517
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
26736
27518
  } catch {
26737
27519
  return false;
26738
27520
  }
26739
27521
  }).sort().reverse();
26740
27522
  if (versions.length > 0) {
26741
- const latestDir = path9.join(scriptsDir, versions[0]);
26742
- for (const file2 of fs8.readdirSync(latestDir)) {
27523
+ const latestDir = path12.join(scriptsDir, versions[0]);
27524
+ for (const file2 of fs9.readdirSync(latestDir)) {
26743
27525
  if (file2.endsWith(".js")) {
26744
27526
  try {
26745
- referenceScripts[file2] = fs8.readFileSync(path9.join(latestDir, file2), "utf-8");
27527
+ referenceScripts[file2] = fs9.readFileSync(path12.join(latestDir, file2), "utf-8");
26746
27528
  } catch {
26747
27529
  }
26748
27530
  }
@@ -26751,16 +27533,16 @@ async (params) => {
26751
27533
  }
26752
27534
  }
26753
27535
  const prompt = this.buildAutoImplPrompt(type, provider2, providerDir, functions, domContext, referenceScripts);
26754
- const tmpDir = path9.join(os12.tmpdir(), "adhdev-autoimpl");
26755
- if (!fs8.existsSync(tmpDir)) fs8.mkdirSync(tmpDir, { recursive: true });
26756
- const promptFile = path9.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
26757
- fs8.writeFileSync(promptFile, prompt, "utf-8");
27536
+ const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
27537
+ if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
27538
+ const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
27539
+ fs9.writeFileSync(promptFile, prompt, "utf-8");
26758
27540
  this.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
26759
27541
  const agentProvider = this.providerLoader.resolve(agent) || this.providerLoader.getMeta(agent);
26760
27542
  const spawn3 = agentProvider?.spawn;
26761
27543
  if (!spawn3?.command) {
26762
27544
  try {
26763
- fs8.unlinkSync(promptFile);
27545
+ fs9.unlinkSync(promptFile);
26764
27546
  } catch {
26765
27547
  }
26766
27548
  this.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
@@ -26861,7 +27643,7 @@ async (params) => {
26861
27643
  } catch {
26862
27644
  }
26863
27645
  try {
26864
- fs8.unlinkSync(promptFile);
27646
+ fs9.unlinkSync(promptFile);
26865
27647
  } catch {
26866
27648
  }
26867
27649
  this.log(`Auto-implement (ACP) ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -26917,12 +27699,12 @@ async (params) => {
26917
27699
  } else {
26918
27700
  args = [...baseArgs];
26919
27701
  }
26920
- const { execSync: execSync6 } = await import("child_process");
27702
+ const { execSync: execSync7 } = await import("child_process");
26921
27703
  try {
26922
- execSync6(`which ${command}`, { stdio: "pipe" });
27704
+ execSync7(`which ${command}`, { stdio: "pipe" });
26923
27705
  } catch {
26924
27706
  try {
26925
- fs8.unlinkSync(promptFile);
27707
+ fs9.unlinkSync(promptFile);
26926
27708
  } catch {
26927
27709
  }
26928
27710
  this.json(res, 400, { error: `Agent binary '${command}' not found on PATH. Install it first: ${agentProvider?.install || "check provider docs"}` });
@@ -26978,7 +27760,7 @@ async (params) => {
26978
27760
  } catch {
26979
27761
  }
26980
27762
  try {
26981
- fs8.unlinkSync(promptFile);
27763
+ fs9.unlinkSync(promptFile);
26982
27764
  } catch {
26983
27765
  }
26984
27766
  this.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -27008,23 +27790,23 @@ async (params) => {
27008
27790
  lines.push("## Current Target Files");
27009
27791
  lines.push("These are the files you need to EDIT. They contain TODO stubs \u2014 replace them with working implementations.");
27010
27792
  lines.push("");
27011
- const scriptsDir = path9.join(providerDir, "scripts");
27012
- if (fs8.existsSync(scriptsDir)) {
27013
- const versions = fs8.readdirSync(scriptsDir).filter((d) => {
27793
+ const scriptsDir = path12.join(providerDir, "scripts");
27794
+ if (fs9.existsSync(scriptsDir)) {
27795
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
27014
27796
  try {
27015
- return fs8.statSync(path9.join(scriptsDir, d)).isDirectory();
27797
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
27016
27798
  } catch {
27017
27799
  return false;
27018
27800
  }
27019
27801
  }).sort().reverse();
27020
27802
  if (versions.length > 0) {
27021
- const vDir = path9.join(scriptsDir, versions[0]);
27803
+ const vDir = path12.join(scriptsDir, versions[0]);
27022
27804
  lines.push(`Scripts version directory: \`${vDir}\``);
27023
27805
  lines.push("");
27024
- for (const file2 of fs8.readdirSync(vDir)) {
27806
+ for (const file2 of fs9.readdirSync(vDir)) {
27025
27807
  if (file2.endsWith(".js")) {
27026
27808
  try {
27027
- const content = fs8.readFileSync(path9.join(vDir, file2), "utf-8");
27809
+ const content = fs9.readFileSync(path12.join(vDir, file2), "utf-8");
27028
27810
  lines.push(`### \`${file2}\``);
27029
27811
  lines.push("```javascript");
27030
27812
  lines.push(content);
@@ -27095,7 +27877,7 @@ async (params) => {
27095
27877
  lines.push("## Required Return Format");
27096
27878
  lines.push("| Function | Return JSON |");
27097
27879
  lines.push("|---|---|");
27098
- lines.push("| readChat | `{ id, status, title, messages: [{role, content, index}], inputContent, activeModal }` |");
27880
+ 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 |");
27099
27881
  lines.push("| sendMessage | `{ sent: false, needsTypeAndSend: true, selector }` |");
27100
27882
  lines.push("| resolveAction | `{ resolved: true/false, clicked? }` |");
27101
27883
  lines.push("| listSessions | `{ sessions: [{ id, title, active, index }] }` |");
@@ -27219,20 +28001,20 @@ data: ${JSON.stringify(msg.data)}
27219
28001
  res.end(JSON.stringify(data, null, 2));
27220
28002
  }
27221
28003
  async readBody(req) {
27222
- return new Promise((resolve5) => {
28004
+ return new Promise((resolve7) => {
27223
28005
  let body = "";
27224
28006
  req.on("data", (chunk) => body += chunk);
27225
28007
  req.on("end", () => {
27226
28008
  try {
27227
- resolve5(JSON.parse(body));
28009
+ resolve7(JSON.parse(body));
27228
28010
  } catch {
27229
- resolve5({});
28011
+ resolve7({});
27230
28012
  }
27231
28013
  });
27232
28014
  });
27233
28015
  }
27234
28016
  };
27235
- var import_child_process7 = require("child_process");
28017
+ var import_child_process8 = require("child_process");
27236
28018
  var EXTENSION_CATALOG = [
27237
28019
  // AI Agent extensions
27238
28020
  {
@@ -27309,7 +28091,7 @@ data: ${JSON.stringify(msg.data)}
27309
28091
  function isExtensionInstalled(ide, marketplaceId) {
27310
28092
  if (!ide.cliCommand) return false;
27311
28093
  try {
27312
- const result = (0, import_child_process7.execSync)(`"${ide.cliCommand}" --list-extensions`, {
28094
+ const result = (0, import_child_process8.execSync)(`"${ide.cliCommand}" --list-extensions`, {
27313
28095
  encoding: "utf-8",
27314
28096
  timeout: 15e3,
27315
28097
  stdio: ["pipe", "pipe", "pipe"]
@@ -27346,12 +28128,12 @@ data: ${JSON.stringify(msg.data)}
27346
28128
  const res = await fetch(extension.vsixUrl);
27347
28129
  if (res.ok) {
27348
28130
  const buffer = Buffer.from(await res.arrayBuffer());
27349
- const fs9 = await import("fs");
27350
- fs9.writeFileSync(vsixPath, buffer);
27351
- return new Promise((resolve5) => {
28131
+ const fs10 = await import("fs");
28132
+ fs10.writeFileSync(vsixPath, buffer);
28133
+ return new Promise((resolve7) => {
27352
28134
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
27353
- (0, import_child_process7.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
27354
- resolve5({
28135
+ (0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
28136
+ resolve7({
27355
28137
  extensionId: extension.id,
27356
28138
  marketplaceId: extension.marketplaceId,
27357
28139
  success: !error48,
@@ -27364,11 +28146,11 @@ data: ${JSON.stringify(msg.data)}
27364
28146
  } catch (e) {
27365
28147
  }
27366
28148
  }
27367
- return new Promise((resolve5) => {
28149
+ return new Promise((resolve7) => {
27368
28150
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
27369
- (0, import_child_process7.exec)(cmd, { timeout: 6e4 }, (error48, stdout, stderr) => {
28151
+ (0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error48, stdout, stderr) => {
27370
28152
  if (error48) {
27371
- resolve5({
28153
+ resolve7({
27372
28154
  extensionId: extension.id,
27373
28155
  marketplaceId: extension.marketplaceId,
27374
28156
  success: false,
@@ -27376,7 +28158,7 @@ data: ${JSON.stringify(msg.data)}
27376
28158
  error: stderr || error48.message
27377
28159
  });
27378
28160
  } else {
27379
- resolve5({
28161
+ resolve7({
27380
28162
  extensionId: extension.id,
27381
28163
  marketplaceId: extension.marketplaceId,
27382
28164
  success: true,
@@ -27403,7 +28185,7 @@ data: ${JSON.stringify(msg.data)}
27403
28185
  if (!ide.cliCommand) return false;
27404
28186
  try {
27405
28187
  const args = workspacePath ? `"${workspacePath}"` : "";
27406
- (0, import_child_process7.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
28188
+ (0, import_child_process8.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
27407
28189
  return true;
27408
28190
  } catch {
27409
28191
  return false;
@@ -27762,7 +28544,7 @@ var init_server_connection = __esm({
27762
28544
  });
27763
28545
 
27764
28546
  // src/daemon-p2p.ts
27765
- var fs, import_daemon_core2, path, os, logFile, log, logDebug, DaemonP2PSender;
28547
+ var fs, import_daemon_core2, path, os, import_node_module, import_meta, esmRequire, logFile, log, logDebug, DaemonP2PSender;
27766
28548
  var init_daemon_p2p = __esm({
27767
28549
  "src/daemon-p2p.ts"() {
27768
28550
  "use strict";
@@ -27770,6 +28552,9 @@ var init_daemon_p2p = __esm({
27770
28552
  import_daemon_core2 = __toESM(require_dist());
27771
28553
  path = __toESM(require("path"));
27772
28554
  os = __toESM(require("os"));
28555
+ import_node_module = require("module");
28556
+ import_meta = {};
28557
+ esmRequire = (0, import_node_module.createRequire)(import_meta.url);
27773
28558
  logFile = path.join(os.tmpdir(), "adhdev_daemon_p2p.log");
27774
28559
  log = (msg) => {
27775
28560
  import_daemon_core2.LOG.info("P2P", `[${(/* @__PURE__ */ new Date()).toISOString()}] [P2P] ${msg}`);
@@ -27814,12 +28599,13 @@ var init_daemon_p2p = __esm({
27814
28599
  /** node-datachannel Load */
27815
28600
  tryLoadNodeDatachannel() {
27816
28601
  try {
27817
- this.nodeDatachannel = require("node-datachannel");
28602
+ this.nodeDatachannel = esmRequire("node-datachannel");
27818
28603
  const keys = Object.keys(this.nodeDatachannel).join(",");
27819
28604
  log(`node-datachannel loaded \u2705 (keys: ${keys.substring(0, 100)})`);
27820
28605
  return;
27821
28606
  } catch (e) {
27822
- log(`node-datachannel not found: ${e?.message}`);
28607
+ log(`node-datachannel not found: ${e?.message}
28608
+ ${e?.stack || ""}`);
27823
28609
  }
27824
28610
  const platform2 = process.platform;
27825
28611
  const arch = process.arch;
@@ -27838,10 +28624,10 @@ var init_daemon_p2p = __esm({
27838
28624
  fs.mkdirSync(targetDir, { recursive: true });
27839
28625
  fs.copyFileSync(prebuildPath, targetPath);
27840
28626
  try {
27841
- delete require.cache[require.resolve("node-datachannel")];
28627
+ delete esmRequire.cache[esmRequire.resolve("node-datachannel")];
27842
28628
  } catch {
27843
28629
  }
27844
- this.nodeDatachannel = require("node-datachannel");
28630
+ this.nodeDatachannel = esmRequire("node-datachannel");
27845
28631
  log(`node-datachannel loaded from prebuild (${prebuildKey}) \u2705`);
27846
28632
  return;
27847
28633
  }
@@ -27917,7 +28703,7 @@ var init_daemon_p2p = __esm({
27917
28703
  token = config2.connectionToken || "";
27918
28704
  } catch {
27919
28705
  }
27920
- const http = require("https");
28706
+ const http = esmRequire("https");
27921
28707
  const data = await new Promise((resolve, reject) => {
27922
28708
  const req = http.get(`${serverUrl}/api/v1/turn/credentials`, {
27923
28709
  headers: { "Authorization": `Bearer ${token}` }
@@ -28015,14 +28801,27 @@ var init_daemon_p2p = __esm({
28015
28801
  converted.push(url2);
28016
28802
  } else if ((url2.startsWith("turn:") || url2.startsWith("turns:")) && server.username && server.credential) {
28017
28803
  const cleanUrl = url2.split("?")[0];
28018
- const parts = cleanUrl.split(":");
28019
- converted.push(`${parts[0]}:${parts[1]}:${parts[2] || "3478"}:${server.username}:${server.credential}`);
28804
+ const transport = url2.includes("transport=tcp") ? "tcp" : "udp";
28805
+ const isTls = url2.startsWith("turns:");
28806
+ const parts = cleanUrl.replace(/^turns?:/, "").split(":");
28807
+ const hostname4 = parts[0];
28808
+ const port = parseInt(parts[1]) || (isTls ? 5349 : 3478);
28809
+ let relayType = "TurnUdp";
28810
+ if (isTls) relayType = "TurnTls";
28811
+ else if (transport === "tcp") relayType = "TurnTcp";
28812
+ converted.push({
28813
+ hostname: hostname4,
28814
+ port,
28815
+ username: server.username,
28816
+ password: server.credential,
28817
+ relayType
28818
+ });
28020
28819
  }
28021
28820
  }
28022
28821
  }
28023
28822
  if (converted.length > 0) {
28024
28823
  iceServers = converted;
28025
- const hasTurn = converted.some((s) => s.startsWith("turn"));
28824
+ const hasTurn = converted.some((s) => typeof s === "object");
28026
28825
  log(`ICE servers from auth: ${converted.length} (TURN: ${hasTurn ? "\u2705" : "\u274C"})`);
28027
28826
  }
28028
28827
  }
@@ -28046,17 +28845,18 @@ var init_daemon_p2p = __esm({
28046
28845
  const timeout = setTimeout(() => {
28047
28846
  const peer = this.peers.get(pid);
28048
28847
  if (peer?.state === "connecting") {
28049
- log(`connection timeout (15s) for peer ${pid}`);
28848
+ log(`connection timeout (30s) for peer ${pid}`);
28050
28849
  peer.state = "failed";
28051
28850
  this.notifyStateChange();
28052
28851
  }
28053
- }, 15e3);
28852
+ }, 3e4);
28054
28853
  try {
28055
28854
  pc.onLocalDescription((sdp, type) => {
28056
28855
  log(`onLocalDescription for peer ${pid}: type=${type}`);
28057
28856
  this.serverConn.sendMessage("p2p_offer", { sdp, type, peerId: pid });
28058
28857
  });
28059
28858
  pc.onLocalCandidate((candidate, mid) => {
28859
+ log(`onLocalCandidate for peer ${pid}: ${candidate.substring(0, 80)}`);
28060
28860
  this.serverConn.sendMessage("p2p_ice", { candidate, mid, peerId: pid });
28061
28861
  });
28062
28862
  pc.onStateChange((pcState) => {
@@ -28401,6 +29201,10 @@ var init_daemon_p2p = __esm({
28401
29201
  log(`p2p_answer for unknown peer ${peerId} \u2014 ignoring`);
28402
29202
  return;
28403
29203
  }
29204
+ if (peer.remoteDescriptionSet) {
29205
+ log(`p2p_answer ignored: already applied for peer ${peerId} (duplicate relay)`);
29206
+ return;
29207
+ }
28404
29208
  const pcState = peer.pc.state();
28405
29209
  if (pcState === "closed" || pcState === "failed") {
28406
29210
  log(`p2p_answer ignored: peer ${peerId} PC state is ${pcState}`);
@@ -28433,11 +29237,13 @@ var init_daemon_p2p = __esm({
28433
29237
  }
28434
29238
  const peer = this.peers.get(peerId);
28435
29239
  if (peer?.pc && payload.candidate) {
29240
+ log(`p2p_ice received from peer ${peerId}: ${String(payload.candidate).substring(0, 80)}`);
28436
29241
  if (!peer.remoteDescriptionSet) {
28437
29242
  peer.pendingCandidates.push({
28438
29243
  candidate: payload.candidate,
28439
29244
  mid: payload.mid || payload.sdpMid || "0"
28440
29245
  });
29246
+ log(`Queued ICE candidate (remoteDesc not set yet), queue size: ${peer.pendingCandidates.length}`);
28441
29247
  } else {
28442
29248
  try {
28443
29249
  peer.pc.addRemoteCandidate(payload.candidate, payload.mid || payload.sdpMid || "0");
@@ -28445,6 +29251,8 @@ var init_daemon_p2p = __esm({
28445
29251
  log(`ICE candidate error for peer ${peerId}: ${e?.message}`);
28446
29252
  }
28447
29253
  }
29254
+ } else {
29255
+ log(`p2p_ice ignored: peer=${!!peer}, pc=${!!peer?.pc}, candidate=${!!payload.candidate}`);
28448
29256
  }
28449
29257
  return;
28450
29258
  }
@@ -28865,8 +29673,10 @@ var init_adhdev_daemon = __esm({
28865
29673
  this.p2p.onStateChange((state) => {
28866
29674
  if (state === "connected") {
28867
29675
  import_daemon_core4.LOG.info("P2P", "Peer connected \u2192 sending immediate full status report");
29676
+ this.statusReporter?.resetP2PHash();
28868
29677
  this.statusReporter?.sendUnifiedStatusReport().catch((e) => import_daemon_core4.LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
28869
29678
  setTimeout(() => {
29679
+ this.statusReporter?.resetP2PHash();
28870
29680
  this.statusReporter?.sendUnifiedStatusReport().catch(() => {
28871
29681
  });
28872
29682
  }, 2e3);
@@ -28998,6 +29808,7 @@ var init_adhdev_daemon = __esm({
28998
29808
  "open_recent",
28999
29809
  "get_commands",
29000
29810
  "get_recent_workspaces",
29811
+ "get_cli_history",
29001
29812
  "open_panel",
29002
29813
  "open_file",
29003
29814
  "create_terminal",
@@ -29054,6 +29865,7 @@ var init_adhdev_daemon = __esm({
29054
29865
  return;
29055
29866
  }
29056
29867
  const result = await this.components.router.execute(cmd, args, source);
29868
+ if (cmd.startsWith("workspace_")) this.statusReporter?.throttledReport();
29057
29869
  this.sendResult(msg, result.success, result);
29058
29870
  } catch (e) {
29059
29871
  console.error(import_chalk.default.red(` \u2717 Command failed: ${e.message}`));
@@ -29085,7 +29897,9 @@ var init_adhdev_daemon = __esm({
29085
29897
  return { success: true, history };
29086
29898
  }
29087
29899
  }
29088
- return await this.components.router.execute(cmdType, data, "p2p");
29900
+ const routed = await this.components.router.execute(cmdType, data, "p2p");
29901
+ if (cmdType.startsWith("workspace_")) this.statusReporter?.throttledReport();
29902
+ return routed;
29089
29903
  } catch (e) {
29090
29904
  (0, import_daemon_core4.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", success: false, error: e.message, durationMs: Date.now() - cmdStart });
29091
29905
  return { success: false, error: e.message };
@@ -29146,9 +29960,16 @@ var init_adhdev_daemon = __esm({
29146
29960
  }
29147
29961
  return null;
29148
29962
  }
29149
- /** Return CDP manager for specific IDE */
29963
+ /** Return CDP manager for specific IDE (exact match first, then prefix match for multi-window keys) */
29150
29964
  getCdpFor(ideType) {
29151
- return this.components?.cdpManagers.get(ideType.toLowerCase()) || null;
29965
+ if (!this.components) return null;
29966
+ const key = ideType.toLowerCase();
29967
+ const exact = this.components.cdpManagers.get(key);
29968
+ if (exact) return exact;
29969
+ for (const [k, m] of this.components.cdpManagers.entries()) {
29970
+ if (k.startsWith(key + "_") && m.isConnected) return m;
29971
+ }
29972
+ return null;
29152
29973
  }
29153
29974
  };
29154
29975
  }
@@ -29693,7 +30514,7 @@ program.name("adhdev").description("\u{1F9A6} ADHDev \u2014 Agent Dashboard Hub
29693
30514
  program.command("setup").description("Run the interactive setup wizard (detect IDEs, login)").option("-f, --force", "Force re-run setup even if already configured").action(async (options) => {
29694
30515
  await runWizard({ force: options.force });
29695
30516
  });
29696
- program.command("launch [target]").description("Launch IDE with CDP or start CLI agent (e.g. cursor, gemini, claude)").option("-w, --workspace <path>", "Workspace/folder to open").option("-n, --new-window", "Open in a new window").option("-d, --dir <path>", "Working directory for CLI agent", process.cwd()).action(async (targetArg, options) => {
30517
+ program.command("launch [target]").description("Launch IDE with CDP or start CLI agent (e.g. cursor, gemini, claude)").option("-w, --workspace <path>", "Workspace directory to open").option("-n, --new-window", "Open in a new window").option("-d, --dir <path>", "Working directory for CLI agent", process.cwd()).action(async (targetArg, options) => {
29697
30518
  const resolvedType = targetArg ? _cliProviderLoader.resolveAlias(targetArg.toLowerCase()) : null;
29698
30519
  const resolvedProvider = resolvedType ? _cliProviderLoader.get(resolvedType) : null;
29699
30520
  const cliType = resolvedProvider && (resolvedProvider.category === "cli" || resolvedProvider.category === "acp") ? resolvedType : null;