adhdev 0.1.36 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +325 -39
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -696,6 +696,16 @@ var init_chunk_BFUPGBW2 = __esm({
696
696
  }
697
697
  });
698
698
 
699
+ // ../core/dist/chunk-SVQNBQ2O.js
700
+ var DEFAULT_DAEMON_PORT, DAEMON_WS_PATH;
701
+ var init_chunk_SVQNBQ2O = __esm({
702
+ "../core/dist/chunk-SVQNBQ2O.js"() {
703
+ "use strict";
704
+ DEFAULT_DAEMON_PORT = 19222;
705
+ DAEMON_WS_PATH = "/ipc";
706
+ }
707
+ });
708
+
699
709
  // ../core/dist/index.js
700
710
  var dist_exports = {};
701
711
  __export(dist_exports, {
@@ -711,15 +721,13 @@ __export(dist_exports, {
711
721
  getInstalledIDEs: () => getInstalledIDEs,
712
722
  isIdeInstalled: () => isIdeInstalled
713
723
  });
714
- var DEFAULT_DAEMON_PORT, DAEMON_WS_PATH;
715
724
  var init_dist = __esm({
716
725
  "../core/dist/index.js"() {
717
726
  "use strict";
718
727
  init_chunk_PP6RFM75();
719
728
  init_chunk_ZZGGFYGY();
720
729
  init_chunk_BFUPGBW2();
721
- DEFAULT_DAEMON_PORT = 19222;
722
- DAEMON_WS_PATH = "/ipc";
730
+ init_chunk_SVQNBQ2O();
723
731
  }
724
732
  });
725
733
 
@@ -786,6 +794,22 @@ function isSetupComplete() {
786
794
  function resetConfig() {
787
795
  saveConfig({ ...DEFAULT_CONFIG });
788
796
  }
797
+ function addCliHistory(entry) {
798
+ const config = loadConfig();
799
+ const history = config.cliHistory || [];
800
+ const argsKey = (entry.cliArgs || []).join(" ");
801
+ const filtered = history.filter((h) => {
802
+ const hArgsKey = (h.cliArgs || []).join(" ");
803
+ return !(h.cliType === entry.cliType && h.dir === entry.dir && hArgsKey === argsKey);
804
+ });
805
+ filtered.unshift({
806
+ ...entry,
807
+ timestamp: Date.now(),
808
+ label: entry.label || `${entry.cliType} \xB7 ${entry.dir.split("/").filter(Boolean).pop() || "root"}${argsKey ? ` (${argsKey})` : ""}`
809
+ });
810
+ config.cliHistory = filtered.slice(0, 20);
811
+ saveConfig(config);
812
+ }
789
813
  var import_os2, import_path, import_fs2, DEFAULT_CONFIG;
790
814
  var init_config = __esm({
791
815
  "src/config.ts"() {
@@ -808,7 +832,9 @@ var init_config = __esm({
808
832
  setupDate: null,
809
833
  configuredCLIs: [],
810
834
  enabledIdes: [],
811
- recentCliWorkspaces: []
835
+ recentCliWorkspaces: [],
836
+ machineNickname: null,
837
+ cliHistory: []
812
838
  };
813
839
  }
814
840
  });
@@ -1466,7 +1492,7 @@ function findGeminiBinary() {
1466
1492
  return isWin ? "gemini.cmd" : "gemini";
1467
1493
  }
1468
1494
  }
1469
- var os3, import_child_process5, pty, PROMPT_PATTERNS, STARTUP_DIALOG_PATTERNS, GeminiCliAdapter;
1495
+ var os3, import_child_process5, pty, PROMPT_PATTERNS, STARTUP_DIALOG_PATTERNS, GENERATING_PATTERNS, APPROVAL_PATTERNS, GeminiCliAdapter;
1470
1496
  var init_gemini_cli = __esm({
1471
1497
  "src/cli-adapters/gemini-cli.ts"() {
1472
1498
  "use strict";
@@ -1490,6 +1516,24 @@ var init_gemini_cli = __esm({
1490
1516
  /● 1\. Yes/,
1491
1517
  /2\. No/
1492
1518
  ];
1519
+ GENERATING_PATTERNS = [
1520
+ /esc\s+to\s+interrupt/i,
1521
+ /⎋\s*to\s+interrupt/i,
1522
+ /press\s+esc\s+to\s+interrupt/i,
1523
+ /accept\s+edits\s+on/i,
1524
+ // ⏵⏵ accept edits on (shift+tab to cycle) · esc to interrupt
1525
+ /shift\+tab\s+to\s+cycle/i,
1526
+ /ctrl\+c\s+to\s+(cancel|interrupt|stop)/i
1527
+ ];
1528
+ APPROVAL_PATTERNS = [
1529
+ /allow\s+once/i,
1530
+ /always\s+allow/i,
1531
+ /\(y\)es\s*\/\s*\(n\)o/i,
1532
+ /\[y\/n\/a\]/i,
1533
+ /do\s+you\s+want\s+to\s+(run|proceed|allow|execute)/i,
1534
+ /do\s+you\s+want\s+to\s+proceed/i,
1535
+ /proceed\?/i
1536
+ ];
1493
1537
  GeminiCliAdapter = class {
1494
1538
  cliType = "gemini-cli";
1495
1539
  cliName = "Gemini CLI";
@@ -1500,7 +1544,10 @@ var init_gemini_cli = __esm({
1500
1544
  onStatusChange = null;
1501
1545
  // 응답 버퍼링
1502
1546
  responseBuffer = "";
1547
+ recentOutputBuffer = "";
1548
+ // 최근 ~1000자 rolling buffer (청크 경계 패턴 감지용)
1503
1549
  isWaitingForResponse = false;
1550
+ activeModal = null;
1504
1551
  responseTimeout = null;
1505
1552
  idleTimeout = null;
1506
1553
  ready = false;
@@ -1569,6 +1616,7 @@ var init_gemini_cli = __esm({
1569
1616
  }
1570
1617
  handleOutput(rawData) {
1571
1618
  const cleanData = stripAnsi(rawData);
1619
+ this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1e3);
1572
1620
  if (!this.ready) {
1573
1621
  this.startupBuffer += cleanData;
1574
1622
  const preview = cleanData.trim().slice(0, 100);
@@ -1593,9 +1641,45 @@ var init_gemini_cli = __esm({
1593
1641
  }
1594
1642
  return;
1595
1643
  }
1644
+ const hasApprovalSignal = APPROVAL_PATTERNS.some((p) => p.test(this.recentOutputBuffer));
1645
+ if (hasApprovalSignal && this.currentStatus !== "waiting_approval") {
1646
+ console.log("[GeminiAdapter] \u23F3 Approval required");
1647
+ this.isWaitingForResponse = true;
1648
+ this.currentStatus = "waiting_approval";
1649
+ const ctxLines = cleanData.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
1650
+ const ctxMsg = ctxLines.slice(-5).join(" ").slice(0, 200);
1651
+ this.activeModal = { message: ctxMsg || "Approval required", buttons: ["Yes", "No"] };
1652
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
1653
+ this.onStatusChange?.();
1654
+ return;
1655
+ }
1656
+ if (this.currentStatus === "waiting_approval") {
1657
+ const hasGeneratingResume = GENERATING_PATTERNS.some((p) => p.test(cleanData));
1658
+ const hasPromptResume = PROMPT_PATTERNS.some((p) => p.test(cleanData));
1659
+ if (hasGeneratingResume) {
1660
+ console.log("[GeminiAdapter] \u2705 Approval granted, generating resumed");
1661
+ this.currentStatus = "generating";
1662
+ this.activeModal = null;
1663
+ this.onStatusChange?.();
1664
+ } else if (hasPromptResume) {
1665
+ console.log("[GeminiAdapter] \u{1F6AB} Approval denied or skipped");
1666
+ this.activeModal = null;
1667
+ this.finishResponse();
1668
+ }
1669
+ return;
1670
+ }
1596
1671
  if (this.isWaitingForResponse) {
1597
1672
  this.responseBuffer += cleanData;
1598
1673
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
1674
+ const stillGenerating = GENERATING_PATTERNS.some((p) => p.test(cleanData));
1675
+ if (stillGenerating) {
1676
+ this.currentStatus = "generating";
1677
+ this.idleTimeout = setTimeout(() => {
1678
+ if (this.isWaitingForResponse) this.finishResponse();
1679
+ }, 4e3);
1680
+ this.onStatusChange?.();
1681
+ return;
1682
+ }
1599
1683
  const hasPrompt = PROMPT_PATTERNS.some((p) => p.test(this.responseBuffer));
1600
1684
  if (hasPrompt) {
1601
1685
  this.finishResponse();
@@ -1649,6 +1733,7 @@ var init_gemini_cli = __esm({
1649
1733
  }
1650
1734
  this.responseBuffer = "";
1651
1735
  this.isWaitingForResponse = false;
1736
+ this.activeModal = null;
1652
1737
  this.currentStatus = "idle";
1653
1738
  this.onStatusChange?.();
1654
1739
  }
@@ -1657,7 +1742,7 @@ var init_gemini_cli = __esm({
1657
1742
  status: this.currentStatus,
1658
1743
  messages: [...this.messages],
1659
1744
  workingDir: this.workingDir,
1660
- activeModal: null
1745
+ activeModal: this.activeModal
1661
1746
  };
1662
1747
  }
1663
1748
  /**
@@ -1793,13 +1878,17 @@ var init_claude_cli = __esm({
1793
1878
  workingDir;
1794
1879
  onStatusChange = null;
1795
1880
  responseBuffer = "";
1881
+ recentOutputBuffer = "";
1882
+ // 최근 ~1000자 rolling buffer (청크 경계 패턴 감지용)
1796
1883
  isWaitingForResponse = false;
1884
+ activeModal = null;
1797
1885
  idleTimeout = null;
1798
1886
  ready = false;
1799
1887
  startupBuffer = "";
1800
1888
  bridge = null;
1801
1889
  logBuffer = [];
1802
1890
  onPtyDataCallback = null;
1891
+ extraArgs = [];
1803
1892
  // Patterns for Claude Code
1804
1893
  PROMPT_PATTERNS = [
1805
1894
  /❯\s*$/,
@@ -1808,14 +1897,40 @@ var init_claude_cli = __esm({
1808
1897
  /➜\s+.*\s*$/,
1809
1898
  /\s+✗\s*$/
1810
1899
  ];
1900
+ // "Esc to interrupt" 표시 → Claude Code가 자율적으로 생성 중임을 감지
1901
+ GENERATING_PATTERNS = [
1902
+ /esc\s+to\s+interrupt/i,
1903
+ /⎋\s*to\s+interrupt/i,
1904
+ /press\s+esc\s+to\s+interrupt/i,
1905
+ /accept\s+edits\s+on/i,
1906
+ // ⏵⏵ accept edits on (shift+tab to cycle) · esc to interrupt
1907
+ /shift\+tab\s+to\s+cycle/i
1908
+ ];
1909
+ // Approval 요청 패턴 — Claude Code가 툴 실행 전 사용자 허가를 요청할 때
1910
+ APPROVAL_PATTERNS = [
1911
+ /allow\s+once/i,
1912
+ /always\s+allow/i,
1913
+ /\(y\)es\s*\/\s*\(n\)o/i,
1914
+ /\[y\/n\/a\]/i,
1915
+ /do\s+you\s+want\s+to\s+(run|proceed|allow|execute|make|create|delete|write|edit)/i,
1916
+ /do\s+you\s+want\s+to\s+proceed/i,
1917
+ /proceed\?/i,
1918
+ /esc\s+to\s+cancel/i,
1919
+ // Claude Code 파일 편집 승인 UI
1920
+ /tab\s+to\s+amend/i,
1921
+ // Claude Code 파일 편집 승인 UI
1922
+ /yes,\s+allow\s+all\s+edits/i
1923
+ // "Yes, allow all edits during this session"
1924
+ ];
1811
1925
  DIALOG_PATTERNS = [
1812
1926
  /Do you trust the files in this folder/i,
1813
1927
  /Please log in to Anthropic/i,
1814
1928
  /Your one-time login code is/i,
1815
1929
  /Wait for login to complete/i
1816
1930
  ];
1817
- constructor(workingDir) {
1931
+ constructor(workingDir, cliArgs = []) {
1818
1932
  this.workingDir = workingDir;
1933
+ this.extraArgs = cliArgs;
1819
1934
  }
1820
1935
  setBridge(bridge) {
1821
1936
  this.bridge = bridge;
@@ -1834,8 +1949,8 @@ var init_claude_cli = __esm({
1834
1949
  if (this.ptyProcess) return;
1835
1950
  if (!pty2) throw new Error("node-pty is not installed");
1836
1951
  const claudeBin = findClaudeBinary();
1837
- console.log(`[ClaudeAdapter] Spawning Claude Code in ${this.workingDir}`);
1838
- this.ptyProcess = pty2.spawn(claudeBin, [], {
1952
+ console.log(`[ClaudeAdapter] Spawning Claude Code in ${this.workingDir}${this.extraArgs.length ? ` with args: ${this.extraArgs.join(" ")}` : ""}`);
1953
+ this.ptyProcess = pty2.spawn(claudeBin, this.extraArgs, {
1839
1954
  name: "xterm-256color",
1840
1955
  cols: 120,
1841
1956
  rows: 40,
@@ -1868,6 +1983,7 @@ var init_claude_cli = __esm({
1868
1983
  this.logBuffer.push({ message: cleanData.trim(), level: "info" });
1869
1984
  }
1870
1985
  }
1986
+ this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1e3);
1871
1987
  if (!this.ready) {
1872
1988
  this.startupBuffer += cleanData;
1873
1989
  const hasDialog = this.DIALOG_PATTERNS.some((p) => p.test(this.startupBuffer));
@@ -1889,9 +2005,55 @@ var init_claude_cli = __esm({
1889
2005
  }
1890
2006
  return;
1891
2007
  }
2008
+ const hasApprovalSignal = this.APPROVAL_PATTERNS.some((p) => p.test(this.recentOutputBuffer));
2009
+ if (hasApprovalSignal && this.currentStatus !== "waiting_approval") {
2010
+ console.log('[ClaudeAdapter] \u23F3 Approval required ("Allow once" / y/n detected)');
2011
+ this.isWaitingForResponse = true;
2012
+ this.currentStatus = "waiting_approval";
2013
+ const ctxLines = cleanData.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
2014
+ const ctxMsg = ctxLines.slice(-5).join(" ").slice(0, 200);
2015
+ this.activeModal = { message: ctxMsg || "Approval required", buttons: ["Allow once", "Always allow", "Deny"] };
2016
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
2017
+ this.onStatusChange?.();
2018
+ return;
2019
+ }
2020
+ if (this.currentStatus === "waiting_approval") {
2021
+ const hasGeneratingResume = this.GENERATING_PATTERNS.some((p) => p.test(cleanData));
2022
+ const hasPromptResume = this.PROMPT_PATTERNS.some((p) => p.test(cleanData));
2023
+ if (hasGeneratingResume) {
2024
+ console.log("[ClaudeAdapter] \u2705 Approval granted, generating resumed");
2025
+ this.currentStatus = "generating";
2026
+ this.activeModal = null;
2027
+ this.onStatusChange?.();
2028
+ } else if (hasPromptResume) {
2029
+ console.log("[ClaudeAdapter] \u{1F6AB} Approval denied or skipped, returning to idle");
2030
+ this.activeModal = null;
2031
+ this.finishResponse();
2032
+ }
2033
+ return;
2034
+ }
2035
+ if (!this.isWaitingForResponse) {
2036
+ const hasGeneratingSignal = this.GENERATING_PATTERNS.some((p) => p.test(cleanData));
2037
+ if (hasGeneratingSignal) {
2038
+ console.log('[ClaudeAdapter] \u26A1 Autonomous generating detected ("Esc to interrupt")');
2039
+ this.isWaitingForResponse = true;
2040
+ this.responseBuffer = "";
2041
+ this.currentStatus = "generating";
2042
+ this.onStatusChange?.();
2043
+ }
2044
+ }
1892
2045
  if (this.isWaitingForResponse) {
1893
2046
  this.responseBuffer += cleanData;
1894
2047
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
2048
+ const stillGenerating = this.GENERATING_PATTERNS.some((p) => p.test(cleanData));
2049
+ if (stillGenerating) {
2050
+ this.currentStatus = "generating";
2051
+ this.idleTimeout = setTimeout(() => {
2052
+ if (this.isWaitingForResponse) this.finishResponse();
2053
+ }, 4e3);
2054
+ this.onStatusChange?.();
2055
+ return;
2056
+ }
1895
2057
  const hasPrompt = this.PROMPT_PATTERNS.some((p) => p.test(this.responseBuffer));
1896
2058
  if (hasPrompt) {
1897
2059
  this.finishResponse();
@@ -1917,6 +2079,7 @@ var init_claude_cli = __esm({
1917
2079
  }
1918
2080
  this.responseBuffer = "";
1919
2081
  this.isWaitingForResponse = false;
2082
+ this.activeModal = null;
1920
2083
  this.currentStatus = "idle";
1921
2084
  this.onStatusChange?.();
1922
2085
  }
@@ -1925,7 +2088,7 @@ var init_claude_cli = __esm({
1925
2088
  status: this.currentStatus,
1926
2089
  messages: [...this.messages],
1927
2090
  workingDir: this.workingDir,
1928
- activeModal: null
2091
+ activeModal: this.activeModal
1929
2092
  };
1930
2093
  }
1931
2094
  async sendMessage(text) {
@@ -4461,9 +4624,71 @@ var init_daemon_commands = __esm({
4461
4624
  const script = loader.getCapabilityWithParams("switch_session", { SESSION_ID: JSON.stringify(sessionId) });
4462
4625
  if (!script) return { success: false, error: "switch_session script not available" };
4463
4626
  try {
4464
- const result = await cdp2.evaluate(script, 15e3);
4465
- console.log(`[switch_chat] result:`, result);
4466
- return { success: true, result };
4627
+ const raw = await cdp2.evaluate(script, 15e3);
4628
+ console.log(`[switch_chat] result:`, raw);
4629
+ let parsed = null;
4630
+ try {
4631
+ parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
4632
+ } catch {
4633
+ }
4634
+ if (parsed?.action === "click" && parsed.clickX && parsed.clickY) {
4635
+ const x = Math.round(parsed.clickX);
4636
+ const y = Math.round(parsed.clickY);
4637
+ console.log(`[switch_chat] CDP click at (${x}, ${y}) for "${parsed.title}"`);
4638
+ await cdp2.send("Input.dispatchMouseEvent", {
4639
+ type: "mousePressed",
4640
+ x,
4641
+ y,
4642
+ button: "left",
4643
+ clickCount: 1
4644
+ });
4645
+ await cdp2.send("Input.dispatchMouseEvent", {
4646
+ type: "mouseReleased",
4647
+ x,
4648
+ y,
4649
+ button: "left",
4650
+ clickCount: 1
4651
+ });
4652
+ await new Promise((r) => setTimeout(r, 2e3));
4653
+ const wsResult = await cdp2.evaluate(`
4654
+ (() => {
4655
+ const inp = Array.from(document.querySelectorAll('input[type="text"]'))
4656
+ .find(i => i.offsetWidth > 0 && (i.placeholder || '').includes('Select where'));
4657
+ if (!inp) return null;
4658
+ const rows = inp.closest('[class*="quickInput"]')?.querySelectorAll('[class*="cursor-pointer"]');
4659
+ if (rows && rows.length > 0) {
4660
+ const r = rows[0].getBoundingClientRect();
4661
+ return JSON.stringify({ x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) });
4662
+ }
4663
+ return null;
4664
+ })()
4665
+ `, 5e3);
4666
+ if (wsResult) {
4667
+ try {
4668
+ const ws = JSON.parse(wsResult);
4669
+ await cdp2.send("Input.dispatchMouseEvent", {
4670
+ type: "mousePressed",
4671
+ x: ws.x,
4672
+ y: ws.y,
4673
+ button: "left",
4674
+ clickCount: 1
4675
+ });
4676
+ await cdp2.send("Input.dispatchMouseEvent", {
4677
+ type: "mouseReleased",
4678
+ x: ws.x,
4679
+ y: ws.y,
4680
+ button: "left",
4681
+ clickCount: 1
4682
+ });
4683
+ } catch {
4684
+ }
4685
+ }
4686
+ return { success: true, result: "switched" };
4687
+ }
4688
+ if (parsed?.error) {
4689
+ return { success: false, error: parsed.error };
4690
+ }
4691
+ return { success: true, result: raw };
4467
4692
  } catch (e) {
4468
4693
  console.error(`[switch_chat] error:`, e.message);
4469
4694
  return { success: false, error: e.message };
@@ -5990,9 +6215,12 @@ var init_adhdev_daemon = __esm({
5990
6215
  this.commandHandler.setAgentStreamManager(this.agentStreamManager);
5991
6216
  this.startAgentStreamPolling();
5992
6217
  if (options.cliType) {
5993
- await this.startCliSession(options.cliType, workingDir).catch((e) => {
5994
- console.log(import_chalk2.default.yellow(` \u26A0 Failed to start CLI ${options.cliType}: ${e.message}`));
5995
- });
6218
+ const cliTypes = Array.isArray(options.cliType) ? options.cliType : options.cliType.split(",").map((s) => s.trim()).filter(Boolean);
6219
+ for (const ct of cliTypes) {
6220
+ await this.startCliSession(ct, workingDir, options.cliArgs).catch((e) => {
6221
+ console.log(import_chalk2.default.yellow(` \u26A0 Failed to start CLI ${ct}: ${e.message}`));
6222
+ });
6223
+ }
5996
6224
  }
5997
6225
  const machineId = os9.hostname().replace(/[^a-zA-Z0-9]/g, "_");
5998
6226
  const machineHash = crypto2.createHash("md5").update(os9.hostname() + os9.homedir()).digest("hex").slice(0, 8);
@@ -6029,17 +6257,27 @@ var init_adhdev_daemon = __esm({
6029
6257
  return { id: req.id, success: result.success, entries: result.files, error: result.error };
6030
6258
  }
6031
6259
  });
6032
- this.p2p.onPtyInput((cliType, data) => {
6260
+ this.p2p.onPtyInput((cliId, data) => {
6261
+ const directAdapter = this.adapters.get(cliId);
6262
+ if (directAdapter && typeof directAdapter.writeRaw === "function") {
6263
+ directAdapter.writeRaw(data);
6264
+ return;
6265
+ }
6033
6266
  for (const [, adapter] of this.adapters) {
6034
- if (adapter.cliType === cliType && typeof adapter.writeRaw === "function") {
6267
+ if (adapter.cliType === cliId && typeof adapter.writeRaw === "function") {
6035
6268
  adapter.writeRaw(data);
6036
6269
  return;
6037
6270
  }
6038
6271
  }
6039
6272
  });
6040
- this.p2p.onPtyResize((cliType, cols, rows) => {
6273
+ this.p2p.onPtyResize((cliId, cols, rows) => {
6274
+ const directAdapter = this.adapters.get(cliId);
6275
+ if (directAdapter && typeof directAdapter.resize === "function") {
6276
+ directAdapter.resize(cols, rows);
6277
+ return;
6278
+ }
6041
6279
  for (const [, adapter] of this.adapters) {
6042
- if (adapter.cliType === cliType && typeof adapter.resize === "function") {
6280
+ if (adapter.cliType === cliId && typeof adapter.resize === "function") {
6043
6281
  adapter.resize(cols, rows);
6044
6282
  return;
6045
6283
  }
@@ -6206,7 +6444,7 @@ var init_adhdev_daemon = __esm({
6206
6444
  if (!cliType) throw new Error("cliType required");
6207
6445
  const key = this.getCliKey(cliType, dir);
6208
6446
  if (!this.adapters.has(key)) {
6209
- await this.startCliSession(cliType, dir);
6447
+ await this.startCliSession(cliType, dir, args?.cliArgs);
6210
6448
  try {
6211
6449
  const config = loadConfig();
6212
6450
  console.log(import_chalk2.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
@@ -6416,14 +6654,17 @@ var init_adhdev_daemon = __esm({
6416
6654
  case "stop_cli": {
6417
6655
  const cliType = data.cliType || "gemini-cli";
6418
6656
  const dir = data.dir || "";
6419
- const key = `${cliType}:${dir}`;
6657
+ const key = this.getCliKey(cliType, dir);
6420
6658
  const adapter = this.adapters.get(key);
6421
6659
  if (adapter) {
6422
- try {
6423
- adapter.destroy?.();
6424
- } catch {
6660
+ await this.stopCliSession(key);
6661
+ } else {
6662
+ for (const [k, a] of this.adapters) {
6663
+ if (a.cliType === cliType) {
6664
+ await this.stopCliSession(k);
6665
+ break;
6666
+ }
6425
6667
  }
6426
- this.adapters.delete(key);
6427
6668
  }
6428
6669
  return { success: true, stopped: true };
6429
6670
  }
@@ -6442,6 +6683,34 @@ var init_adhdev_daemon = __esm({
6442
6683
  await this.startCliSession(cliType, dir);
6443
6684
  return { success: true, restarted: true };
6444
6685
  }
6686
+ // ─── P2P/Local only: 민감 데이터 (서버 경유 X) ─────
6687
+ case "get_cli_history": {
6688
+ const config = loadConfig();
6689
+ return { success: true, history: config.cliHistory || [] };
6690
+ }
6691
+ case "set_machine_nickname": {
6692
+ const nickname = data.nickname?.trim() || null;
6693
+ const config = loadConfig();
6694
+ config.machineNickname = nickname;
6695
+ saveConfig(config);
6696
+ return { success: true, nickname };
6697
+ }
6698
+ case "get_daemon_logs": {
6699
+ const lines = parseInt(data.lines) || 100;
6700
+ try {
6701
+ const logPath = require("path").join(require("os").tmpdir(), "adhdev-daemon.log");
6702
+ const fs6 = require("fs");
6703
+ if (fs6.existsSync(logPath)) {
6704
+ const content = fs6.readFileSync(logPath, "utf-8");
6705
+ const allLines = content.split("\n");
6706
+ const recent = allLines.slice(-lines).join("\n");
6707
+ return { success: true, logs: recent, totalLines: allLines.length };
6708
+ }
6709
+ return { success: true, logs: "", totalLines: 0 };
6710
+ } catch (e) {
6711
+ return { success: false, error: e.message };
6712
+ }
6713
+ }
6445
6714
  }
6446
6715
  if (this.commandHandler) {
6447
6716
  return this.commandHandler.handle(cmdType, data);
@@ -6452,17 +6721,18 @@ var init_adhdev_daemon = __esm({
6452
6721
  }
6453
6722
  }
6454
6723
  // ─── CLI 세션 관리 ──────────────────────────────
6455
- createAdapter(cliType, workingDir) {
6724
+ createAdapter(cliType, workingDir, cliArgs) {
6456
6725
  if (cliType === "claude-cli" || cliType === "claude-code") {
6457
- return new ClaudeCliAdapter(workingDir);
6726
+ return new ClaudeCliAdapter(workingDir, cliArgs);
6458
6727
  } else if (cliType === "codex-cli" || cliType === "codex") {
6459
6728
  return new CodexCliAdapter(workingDir);
6460
6729
  } else {
6461
6730
  return new GeminiCliAdapter(workingDir);
6462
6731
  }
6463
6732
  }
6464
- async startCliSession(cliType, workingDir) {
6465
- const resolvedDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os9.homedir()) : workingDir;
6733
+ async startCliSession(cliType, workingDir, cliArgs) {
6734
+ const trimmed = (workingDir || process.cwd()).trim();
6735
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os9.homedir()) : require("path").resolve(trimmed);
6466
6736
  const cliInfo = await detectCLI(cliType);
6467
6737
  if (!cliInfo) throw new Error(`${cliType} not found`);
6468
6738
  const key = this.getCliKey(cliType, resolvedDir);
@@ -6471,7 +6741,7 @@ var init_adhdev_daemon = __esm({
6471
6741
  return;
6472
6742
  }
6473
6743
  console.log(import_chalk2.default.yellow(` \u26A1 Starting CLI ${cliType} in ${resolvedDir}...`));
6474
- const adapter = this.createAdapter(cliType, resolvedDir);
6744
+ const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
6475
6745
  await adapter.spawn();
6476
6746
  if (this.bridge && typeof adapter.setBridge === "function") {
6477
6747
  adapter.setBridge(this.bridge);
@@ -6479,10 +6749,11 @@ var init_adhdev_daemon = __esm({
6479
6749
  adapter.setOnStatusChange(() => this.sendUnifiedStatusReport());
6480
6750
  if (typeof adapter.setOnPtyData === "function") {
6481
6751
  adapter.setOnPtyData((data) => {
6482
- const sentViaP2P = this.p2p?.broadcastPtyOutput(adapter.cliType, data);
6752
+ const sentViaP2P = this.p2p?.broadcastPtyOutput(key, data);
6483
6753
  if (!sentViaP2P && this.bridge) {
6484
6754
  this.bridge.sendMessage("pty_output", {
6485
- cliType: adapter.cliType,
6755
+ cliType: key,
6756
+ // adapter key (cliType_hash)
6486
6757
  data
6487
6758
  });
6488
6759
  }
@@ -6491,6 +6762,10 @@ var init_adhdev_daemon = __esm({
6491
6762
  this.adapters.set(key, adapter);
6492
6763
  this.lastAgentStatus.set(key, "idle");
6493
6764
  console.log(import_chalk2.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6765
+ try {
6766
+ addCliHistory({ cliType, dir: resolvedDir, cliArgs });
6767
+ } catch {
6768
+ }
6494
6769
  this.sendUnifiedStatusReport();
6495
6770
  }
6496
6771
  async stopCliSession(key) {
@@ -6594,9 +6869,12 @@ var init_adhdev_daemon = __esm({
6594
6869
  console.log(`[StatusReport] ${ideType} inline fallback: ${inlineResult?.messages?.length || 0} msgs`);
6595
6870
  if (inlineResult?.messages?.length > 0) {
6596
6871
  this._cachedActiveChatMap.set(ideType, { ...inlineResult, activeModal });
6872
+ } else {
6873
+ this._cachedActiveChatMap.set(ideType, { ...raw, messages: [], activeModal });
6597
6874
  }
6598
6875
  } catch (e2) {
6599
6876
  console.log(`[StatusReport] ${ideType} inline error: ${e2.message}`);
6877
+ this._cachedActiveChatMap.set(ideType, { ...raw, messages: [], activeModal });
6600
6878
  }
6601
6879
  }
6602
6880
  } else {
@@ -6683,19 +6961,28 @@ var init_adhdev_daemon = __esm({
6683
6961
  const cliStatus = adapterStatus.status;
6684
6962
  let lastStatus = this.lastAgentStatus.get(key) || "idle";
6685
6963
  if (cliStatus !== lastStatus) {
6964
+ const chatTitle = `${adapter.cliName} \xB7 ${adapter.workingDir.split("/").filter(Boolean).pop() || "session"}`;
6686
6965
  if (lastStatus === "idle" && cliStatus === "generating") {
6687
6966
  this.generatingStartedAt.set(key, now);
6688
6967
  this.bridge?.sendMessage("status_event", {
6689
6968
  event: "agent:generating_started",
6690
- chatTitle: `${adapter.cliName} \xB7 ${adapter.workingDir.split("/").filter(Boolean).pop() || "session"}`,
6969
+ chatTitle,
6970
+ timestamp: now
6971
+ });
6972
+ } else if (cliStatus === "waiting_approval") {
6973
+ if (!this.generatingStartedAt.has(key)) this.generatingStartedAt.set(key, now);
6974
+ this.bridge?.sendMessage("status_event", {
6975
+ event: "agent:approval_requested",
6976
+ chatTitle,
6691
6977
  timestamp: now
6692
6978
  });
6693
- } else if (lastStatus === "generating" && cliStatus === "idle") {
6979
+ } else if (lastStatus === "waiting_approval" && cliStatus === "generating") {
6980
+ } else if (cliStatus === "idle" && (lastStatus === "generating" || lastStatus === "waiting_approval")) {
6694
6981
  const startedAt = this.generatingStartedAt.get(key);
6695
6982
  const duration = startedAt ? Math.round((now - startedAt) / 1e3) : 0;
6696
6983
  this.bridge?.sendMessage("status_event", {
6697
6984
  event: "agent:generating_completed",
6698
- chatTitle: `${adapter.cliName} \xB7 ${adapter.workingDir.split("/").filter(Boolean).pop() || "session"}`,
6985
+ chatTitle,
6699
6986
  duration,
6700
6987
  timestamp: now
6701
6988
  });
@@ -6734,6 +7021,7 @@ var init_adhdev_daemon = __esm({
6734
7021
  const payload = {
6735
7022
  // Machine 정보
6736
7023
  daemonMode: true,
7024
+ machineNickname: loadConfig().machineNickname || null,
6737
7025
  machine: {
6738
7026
  hostname: os9.hostname(),
6739
7027
  platform: os9.platform(),
@@ -8550,13 +8838,11 @@ program.command("reset").description("Reset ADHDev configuration").action(async
8550
8838
  console.log(import_chalk4.default.gray(" Run `adhdev setup` to reconfigure.\n"));
8551
8839
  }
8552
8840
  });
8553
- program.command("daemon").description("Start ADHDev Daemon \u2014 unified local hub for Extensions, CLIs, and IDEs").option("-p, --port <port>", "Local WS server port", "19222").option("--cli <type>", "Also start a CLI agent (gemini-cli, claude-code, codex-cli)").option("-d, --dir <path>", "Working directory for CLI sessions", process.cwd()).option("--server <url>", "Override server URL for testing").action(async (options) => {
8841
+ program.command("daemon").description("Start ADHDev Daemon \u2014 unified local hub for Extensions, CLIs, and IDEs").option("-p, --port <port>", "Local WS server port", "19222").option("--server <url>", "Override server URL for testing").action(async (options) => {
8554
8842
  const { AdhdevDaemon: AdhdevDaemon2 } = await Promise.resolve().then(() => (init_adhdev_daemon(), adhdev_daemon_exports));
8555
8843
  const daemon = new AdhdevDaemon2();
8556
8844
  await daemon.start({
8557
8845
  localPort: parseInt(options.port) || 19222,
8558
- cliType: options.cli,
8559
- workingDir: options.dir,
8560
8846
  serverUrl: options.server,
8561
8847
  foreground: true
8562
8848
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adhdev",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "ADHDev CLI — Detect, install and configure your IDE + AI agent extensions",
5
5
  "main": "dist/index.js",
6
6
  "bin": {