@adhdev/daemon-core 0.6.53 → 0.6.56

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 (164) hide show
  1. package/dist/index.d.ts +84 -34
  2. package/dist/index.js +631 -305
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -1
  5. package/providers/_builtin/_helpers/index.js +26 -26
  6. package/providers/_builtin/cli/aider-cli/provider.json +37 -0
  7. package/providers/_builtin/cli/aider-cli/scripts/1.0/detect_status.js +20 -0
  8. package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_approval.js +10 -0
  9. package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_output.js +49 -0
  10. package/providers/_builtin/cli/aider-cli/scripts/1.0/scripts.js +7 -0
  11. package/providers/_builtin/cli/claude-cli/provider.json +9 -2
  12. package/providers/_builtin/cli/claude-cli/scripts/1.0/detect_status.js +31 -0
  13. package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_approval.js +38 -0
  14. package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_output.js +164 -0
  15. package/providers/_builtin/cli/claude-cli/scripts/1.0/scripts.js +42 -0
  16. package/providers/_builtin/cli/codex-cli/provider.json +9 -2
  17. package/providers/_builtin/cli/codex-cli/scripts/1.0/detect_status.js +20 -0
  18. package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_approval.js +15 -0
  19. package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_output.js +68 -0
  20. package/providers/_builtin/cli/codex-cli/scripts/1.0/scripts.js +11 -0
  21. package/providers/_builtin/cli/cursor-cli/provider.json +37 -0
  22. package/providers/_builtin/cli/cursor-cli/scripts/1.0/detect_status.js +19 -0
  23. package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_approval.js +10 -0
  24. package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_output.js +48 -0
  25. package/providers/_builtin/cli/cursor-cli/scripts/1.0/scripts.js +7 -0
  26. package/providers/_builtin/cli/gemini-cli/provider.json +9 -2
  27. package/providers/_builtin/cli/gemini-cli/scripts/1.0/detect_status.js +26 -0
  28. package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_approval.js +22 -0
  29. package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_output.js +71 -0
  30. package/providers/_builtin/cli/gemini-cli/scripts/1.0/scripts.js +12 -0
  31. package/providers/_builtin/cli/github-copilot-cli/provider.json +37 -0
  32. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/detect_status.js +19 -0
  33. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_approval.js +9 -0
  34. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_output.js +48 -0
  35. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/scripts.js +7 -0
  36. package/providers/_builtin/cli/goose-cli/provider.json +37 -0
  37. package/providers/_builtin/cli/goose-cli/scripts/1.0/detect_status.js +20 -0
  38. package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_approval.js +10 -0
  39. package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_output.js +48 -0
  40. package/providers/_builtin/cli/goose-cli/scripts/1.0/scripts.js +7 -0
  41. package/providers/_builtin/cli/opencode-cli/provider.json +37 -0
  42. package/providers/_builtin/cli/opencode-cli/scripts/1.0/detect_status.js +15 -0
  43. package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_approval.js +9 -0
  44. package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_output.js +48 -0
  45. package/providers/_builtin/cli/opencode-cli/scripts/1.0/scripts.js +7 -0
  46. package/providers/_builtin/extension/cline/scripts/1.0/focus_editor.js +5 -5
  47. package/providers/_builtin/extension/cline/scripts/1.0/list_chats.js +11 -11
  48. package/providers/_builtin/extension/cline/scripts/1.0/list_models.js +6 -6
  49. package/providers/_builtin/extension/cline/scripts/1.0/list_modes.js +5 -5
  50. package/providers/_builtin/extension/cline/scripts/1.0/new_session.js +12 -12
  51. package/providers/_builtin/extension/cline/scripts/1.0/open_panel.js +7 -7
  52. package/providers/_builtin/extension/cline/scripts/1.0/read_chat.js +29 -29
  53. package/providers/_builtin/extension/cline/scripts/1.0/resolve_action.js +19 -19
  54. package/providers/_builtin/extension/cline/scripts/1.0/send_message.js +15 -15
  55. package/providers/_builtin/extension/cline/scripts/1.0/set_mode.js +4 -4
  56. package/providers/_builtin/extension/cline/scripts/1.0/set_model.js +4 -4
  57. package/providers/_builtin/extension/cline/scripts/1.0/switch_session.js +21 -21
  58. package/providers/_builtin/extension/codex/scripts/1.0/explore_controls_webview.js +2 -2
  59. package/providers/_builtin/extension/codex/scripts/1.0/list_models.js +1 -1
  60. package/providers/_builtin/extension/codex/scripts/1.0/list_modes.js +1 -1
  61. package/providers/_builtin/extension/codex/scripts/1.0/new_session.js +2 -2
  62. package/providers/_builtin/extension/codex/scripts/1.0/read_chat.js +6 -6
  63. package/providers/_builtin/extension/codex/scripts/1.0/resolve_action.js +3 -3
  64. package/providers/_builtin/extension/codex/scripts/1.0/set_model.js +1 -1
  65. package/providers/_builtin/ide/antigravity/scripts/1.0/focus_editor.js +2 -2
  66. package/providers/_builtin/ide/antigravity/scripts/1.0/list_chats.js +19 -19
  67. package/providers/_builtin/ide/antigravity/scripts/1.0/list_models.js +1 -1
  68. package/providers/_builtin/ide/antigravity/scripts/1.0/list_modes.js +1 -1
  69. package/providers/_builtin/ide/antigravity/scripts/1.0/new_session.js +17 -17
  70. package/providers/_builtin/ide/antigravity/scripts/1.0/read_chat.js +41 -41
  71. package/providers/_builtin/ide/antigravity/scripts/1.0/resolve_action.js +6 -6
  72. package/providers/_builtin/ide/antigravity/scripts/1.0/send_message.js +13 -13
  73. package/providers/_builtin/ide/antigravity/scripts/1.0/set_model.js +1 -1
  74. package/providers/_builtin/ide/antigravity/scripts/1.0/switch_session.js +13 -13
  75. package/providers/_builtin/ide/cursor/scripts/1.0/dismiss_notification.js +3 -3
  76. package/providers/_builtin/ide/cursor/scripts/1.0/focus_editor.js +1 -1
  77. package/providers/_builtin/ide/cursor/scripts/1.0/list_models.js +12 -12
  78. package/providers/_builtin/ide/cursor/scripts/1.0/list_modes.js +5 -5
  79. package/providers/_builtin/ide/cursor/scripts/1.0/list_notifications.js +2 -2
  80. package/providers/_builtin/ide/cursor/scripts/1.0/list_sessions.js +5 -5
  81. package/providers/_builtin/ide/cursor/scripts/1.0/new_session.js +1 -1
  82. package/providers/_builtin/ide/cursor/scripts/1.0/open_panel.js +3 -3
  83. package/providers/_builtin/ide/cursor/scripts/1.0/read_chat.js +9 -9
  84. package/providers/_builtin/ide/cursor/scripts/1.0/resolve_action.js +4 -4
  85. package/providers/_builtin/ide/cursor/scripts/1.0/send_message.js +5 -5
  86. package/providers/_builtin/ide/cursor/scripts/1.0/set_mode.js +4 -4
  87. package/providers/_builtin/ide/cursor/scripts/1.0/set_model.js +12 -12
  88. package/providers/_builtin/ide/cursor/scripts/1.0/switch_session.js +2 -2
  89. package/providers/_builtin/ide/kiro/scripts/1.0/focus_editor.js +2 -2
  90. package/providers/_builtin/ide/kiro/scripts/1.0/open_panel.js +7 -7
  91. package/providers/_builtin/ide/kiro/scripts/1.0/resolve_action.js +3 -3
  92. package/providers/_builtin/ide/kiro/scripts/1.0/send_message.js +4 -4
  93. package/providers/_builtin/ide/kiro/scripts/1.0/webview_list_sessions.js +2 -2
  94. package/providers/_builtin/ide/kiro/scripts/1.0/webview_new_session.js +5 -5
  95. package/providers/_builtin/ide/kiro/scripts/1.0/webview_read_chat.js +13 -13
  96. package/providers/_builtin/ide/kiro/scripts/1.0/webview_resolve_action.js +1 -1
  97. package/providers/_builtin/ide/kiro/scripts/1.0/webview_send_message.js +8 -8
  98. package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_mode.js +1 -1
  99. package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_model.js +1 -1
  100. package/providers/_builtin/ide/kiro/scripts/1.0/webview_switch_session.js +3 -3
  101. package/providers/_builtin/ide/pearai/.tmp/after_rich.json +157 -0
  102. package/providers/_builtin/ide/pearai/.tmp/after_rich_raw.json +161 -0
  103. package/providers/_builtin/ide/pearai/.tmp/after_switch.json +592 -0
  104. package/providers/_builtin/ide/pearai/.tmp/after_switch_raw.json +596 -0
  105. package/providers/_builtin/ide/pearai/.tmp/home_dump_raw.json +176 -0
  106. package/providers/_builtin/ide/pearai/.tmp/items_raw.json +778 -0
  107. package/providers/_builtin/ide/pearai/.tmp/webview_dump.json +157 -0
  108. package/providers/_builtin/ide/pearai/.tmp/webview_dump_raw.json +161 -0
  109. package/providers/_builtin/ide/pearai/provider.json +1 -3
  110. package/providers/_builtin/ide/pearai/scripts/1.0/focus_editor.js +12 -16
  111. package/providers/_builtin/ide/pearai/scripts/1.0/list_models.js +45 -0
  112. package/providers/_builtin/ide/pearai/scripts/1.0/list_modes.js +44 -0
  113. package/providers/_builtin/ide/pearai/scripts/1.0/list_sessions.js +82 -27
  114. package/providers/_builtin/ide/pearai/scripts/1.0/new_session.js +26 -43
  115. package/providers/_builtin/ide/pearai/scripts/1.0/open_panel.js +10 -33
  116. package/providers/_builtin/ide/pearai/scripts/1.0/read_chat.js +169 -0
  117. package/providers/_builtin/ide/pearai/scripts/1.0/resolve_action.js +47 -41
  118. package/providers/_builtin/ide/pearai/scripts/1.0/scripts.js +36 -7
  119. package/providers/_builtin/ide/pearai/scripts/1.0/send_message.js +97 -22
  120. package/providers/_builtin/ide/pearai/scripts/1.0/set_mode.js +51 -0
  121. package/providers/_builtin/ide/pearai/scripts/1.0/set_model.js +54 -0
  122. package/providers/_builtin/ide/pearai/scripts/1.0/switch_session.js +81 -0
  123. package/providers/_builtin/ide/trae/scripts/1.0/focus_editor.js +2 -2
  124. package/providers/_builtin/ide/trae/scripts/1.0/list_chats.js +2 -2
  125. package/providers/_builtin/ide/trae/scripts/1.0/new_session.js +4 -4
  126. package/providers/_builtin/ide/trae/scripts/1.0/open_panel.js +6 -6
  127. package/providers/_builtin/ide/trae/scripts/1.0/read_chat.js +13 -13
  128. package/providers/_builtin/ide/trae/scripts/1.0/resolve_action.js +3 -3
  129. package/providers/_builtin/ide/trae/scripts/1.0/send_message.js +11 -11
  130. package/providers/_builtin/ide/trae/scripts/1.0/switch_session.js +2 -2
  131. package/providers/_builtin/ide/windsurf/scripts/1.0/focus_editor.js +6 -6
  132. package/providers/_builtin/ide/windsurf/scripts/1.0/list_chats.js +4 -4
  133. package/providers/_builtin/ide/windsurf/scripts/1.0/list_sessions.js +6 -6
  134. package/providers/_builtin/ide/windsurf/scripts/1.0/new_session.js +9 -9
  135. package/providers/_builtin/ide/windsurf/scripts/1.0/open_panel.js +6 -6
  136. package/providers/_builtin/ide/windsurf/scripts/1.0/resolve_action.js +8 -8
  137. package/providers/_builtin/ide/windsurf/scripts/1.0/switch_session.js +8 -8
  138. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/focus_editor.js +6 -6
  139. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_chats.js +12 -12
  140. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/new_session.js +15 -15
  141. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/open_panel.js +10 -10
  142. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/read_chat.js +33 -33
  143. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/resolve_action.js +6 -6
  144. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/send_message.js +16 -16
  145. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/switch_session.js +7 -7
  146. package/providers/_builtin/registry.json +76 -3
  147. package/src/cli-adapters/provider-cli-adapter.ts +312 -258
  148. package/src/cli-adapters/terminal-screen.ts +95 -0
  149. package/src/commands/chat-commands.ts +41 -15
  150. package/src/commands/cli-manager.ts +4 -2
  151. package/src/daemon/dev-server.ts +306 -62
  152. package/src/providers/acp-provider-instance.ts +1 -1
  153. package/src/providers/cli-provider-instance.ts +23 -9
  154. package/src/providers/provider-loader.ts +3 -2
  155. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_models.js +0 -43
  156. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_modes.js +0 -35
  157. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_sessions.js +0 -62
  158. package/providers/_builtin/ide/pearai/scripts/1.0/webview_new_session.js +0 -49
  159. package/providers/_builtin/ide/pearai/scripts/1.0/webview_read_chat.js +0 -92
  160. package/providers/_builtin/ide/pearai/scripts/1.0/webview_resolve_action.js +0 -59
  161. package/providers/_builtin/ide/pearai/scripts/1.0/webview_send_message.js +0 -72
  162. package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_mode.js +0 -36
  163. package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_model.js +0 -36
  164. package/providers/_builtin/ide/pearai/scripts/1.0/webview_switch_session.js +0 -34
package/dist/index.js CHANGED
@@ -591,6 +591,73 @@ var init_logger = __esm({
591
591
  }
592
592
  });
593
593
 
594
+ // src/cli-adapters/terminal-screen.ts
595
+ function loadTerminalCtor() {
596
+ if (!TerminalCtor) {
597
+ const mod = require("@xterm/xterm");
598
+ TerminalCtor = mod.Terminal || mod.default?.Terminal || mod.default;
599
+ if (!TerminalCtor) {
600
+ throw new Error("@xterm/xterm Terminal export not found");
601
+ }
602
+ }
603
+ return TerminalCtor;
604
+ }
605
+ var TerminalCtor, TerminalScreen;
606
+ var init_terminal_screen = __esm({
607
+ "src/cli-adapters/terminal-screen.ts"() {
608
+ "use strict";
609
+ TerminalCtor = null;
610
+ TerminalScreen = class {
611
+ rows;
612
+ cols;
613
+ terminal;
614
+ constructor(rows = 40, cols = 120) {
615
+ this.rows = Math.max(1, rows | 0);
616
+ this.cols = Math.max(1, cols | 0);
617
+ this.terminal = this.createTerminal();
618
+ }
619
+ reset(rows = this.rows, cols = this.cols) {
620
+ this.rows = Math.max(1, rows | 0);
621
+ this.cols = Math.max(1, cols | 0);
622
+ this.terminal.dispose();
623
+ this.terminal = this.createTerminal();
624
+ }
625
+ resize(rows, cols) {
626
+ this.rows = Math.max(1, rows | 0);
627
+ this.cols = Math.max(1, cols | 0);
628
+ this.terminal.resize(this.cols, this.rows);
629
+ }
630
+ write(data) {
631
+ if (!data) return;
632
+ this.terminal.write(data);
633
+ }
634
+ getText() {
635
+ const buffer = this.terminal.buffer.active;
636
+ const start = Math.max(0, buffer.viewportY || 0);
637
+ const end = Math.max(start, Math.min(buffer.length || 0, start + this.rows));
638
+ const lines = [];
639
+ for (let i = start; i < end; i++) {
640
+ const line = buffer.getLine(i);
641
+ lines.push(line ? line.translateToString(true) : "");
642
+ }
643
+ let first = 0;
644
+ let last = lines.length;
645
+ while (first < last && !lines[first]?.trim()) first++;
646
+ while (last > first && !lines[last - 1]?.trim()) last--;
647
+ return lines.slice(first, last).join("\n");
648
+ }
649
+ createTerminal() {
650
+ const Terminal = loadTerminalCtor();
651
+ return new Terminal({
652
+ cols: this.cols,
653
+ rows: this.rows,
654
+ scrollback: 2e3
655
+ });
656
+ }
657
+ };
658
+ }
659
+ });
660
+
594
661
  // src/cli-adapters/provider-cli-adapter.ts
595
662
  var provider_cli_adapter_exports = {};
596
663
  __export(provider_cli_adapter_exports, {
@@ -663,28 +730,19 @@ function parsePatternEntry(x) {
663
730
  }
664
731
  return null;
665
732
  }
666
- function coercePatternArray(raw, fallbacks) {
667
- if (!Array.isArray(raw)) return [...fallbacks];
668
- const parsed = raw.map(parsePatternEntry).filter((r) => r != null);
669
- return parsed.length > 0 ? parsed : [...fallbacks];
670
- }
671
- function defaultCleanOutput(raw, _lastUserInput) {
672
- return stripAnsi(raw).trim();
733
+ function coercePatternArray(raw) {
734
+ if (!Array.isArray(raw)) return [];
735
+ return raw.map(parsePatternEntry).filter((r) => r != null);
673
736
  }
674
737
  function normalizeCliProviderForRuntime(raw) {
675
738
  const patterns = raw?.patterns || {};
676
739
  return {
677
- ...raw,
678
740
  patterns: {
679
- prompt: coercePatternArray(patterns.prompt, FALLBACK_PROMPT),
680
- generating: coercePatternArray(patterns.generating, FALLBACK_GENERATING),
681
- approval: coercePatternArray(patterns.approval, FALLBACK_APPROVAL),
682
- ready: coercePatternArray(patterns.ready, [])
683
- },
684
- cleanOutput: typeof raw?.cleanOutput === "function" ? raw.cleanOutput : defaultCleanOutput
741
+ approval: coercePatternArray(patterns.approval)
742
+ }
685
743
  };
686
744
  }
687
- var os11, path9, import_child_process5, pty, FALLBACK_PROMPT, FALLBACK_GENERATING, FALLBACK_APPROVAL, ProviderCliAdapter;
745
+ var os11, path9, import_child_process5, pty, ProviderCliAdapter;
688
746
  var init_provider_cli_adapter = __esm({
689
747
  "src/cli-adapters/provider-cli-adapter.ts"() {
690
748
  "use strict";
@@ -692,6 +750,7 @@ var init_provider_cli_adapter = __esm({
692
750
  path9 = __toESM(require("path"));
693
751
  import_child_process5 = require("child_process");
694
752
  init_logger();
753
+ init_terminal_screen();
695
754
  try {
696
755
  pty = require("node-pty");
697
756
  if (os11.platform() !== "win32") {
@@ -713,40 +772,10 @@ var init_provider_cli_adapter = __esm({
713
772
  } catch {
714
773
  LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Terminal features disabled.");
715
774
  }
716
- FALLBACK_PROMPT = [
717
- /Type your message/i,
718
- /for\s*shortcuts/i,
719
- // Claude Code prompt
720
- /\?\s*for\s*help/i,
721
- // Claude Code help prompt
722
- /Press enter/i,
723
- /^[>›❯]\s*$/i,
724
- // Prompt char as the complete evaluated string
725
- /[>›❯]\s*$/
726
- // Prompt char at the very end of evaluated string
727
- ];
728
- FALLBACK_GENERATING = [
729
- /[\u2800-\u28ff]/,
730
- // Braille spinner blocks (universal TUI)
731
- /esc to (cancel|interrupt|stop)/i,
732
- // Common TUI generation status line
733
- /generating\.\.\./i,
734
- /Claude is (?:thinking|processing|working)/i
735
- // Specific Claude Code status
736
- ];
737
- FALLBACK_APPROVAL = [
738
- /Allow\s*once/i,
739
- // ANSI strip may remove spaces
740
- /Always\s*allow/i,
741
- /\(y\/n\)/i,
742
- /\[Y\/n\]/i,
743
- /Yes,?\s*don'?t\s*ask/i
744
- // "Yes, don't ask again" (Claude Code)
745
- ];
746
- ProviderCliAdapter = class {
775
+ ProviderCliAdapter = class _ProviderCliAdapter {
747
776
  constructor(provider, workingDir, extraArgs = []) {
748
777
  this.extraArgs = extraArgs;
749
- this.provider = normalizeCliProviderForRuntime(provider);
778
+ this.provider = provider;
750
779
  this.cliType = provider.type;
751
780
  this.cliName = provider.name;
752
781
  this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os11.homedir()) : workingDir;
@@ -763,6 +792,15 @@ var init_provider_cli_adapter = __esm({
763
792
  };
764
793
  const rawKeys = provider.approvalKeys;
765
794
  this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
795
+ this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
796
+ this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
797
+ this.cliScripts = provider.scripts || {};
798
+ const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
799
+ if (scriptNames.length > 0) {
800
+ LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
801
+ } else {
802
+ LOG.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js`);
803
+ }
766
804
  }
767
805
  cliType;
768
806
  cliName;
@@ -770,6 +808,7 @@ var init_provider_cli_adapter = __esm({
770
808
  provider;
771
809
  ptyProcess = null;
772
810
  messages = [];
811
+ structuredMessages = [];
773
812
  currentStatus = "starting";
774
813
  onStatusChange = null;
775
814
  responseBuffer = "";
@@ -780,7 +819,6 @@ var init_provider_cli_adapter = __esm({
780
819
  idleTimeout = null;
781
820
  ready = false;
782
821
  startupBuffer = "";
783
- /** After spawn: briefly skip generating/settle so splash/redraw does not flip status; not used to gate sendMessage */
784
822
  startupParseGate = false;
785
823
  spawnAt = 0;
786
824
  // PTY I/O
@@ -798,11 +836,21 @@ var init_provider_cli_adapter = __esm({
798
836
  // Output settle debounce — fires after PTY output goes quiet
799
837
  settleTimer = null;
800
838
  settledBuffer = "";
801
- // snapshot of recentOutputBuffer at settle time
839
+ submitPendingUntil = 0;
802
840
  // Resize redraw suppression
803
841
  resizeSuppressUntil = 0;
804
842
  // Debug: status transition history
805
843
  statusHistory = [];
844
+ // ─── CLI Scripts (script-based parsing) ───
845
+ cliScripts;
846
+ /** Full accumulated ANSI-stripped PTY output */
847
+ accumulatedBuffer = "";
848
+ /** Full accumulated raw PTY output (with ANSI) */
849
+ accumulatedRawBuffer = "";
850
+ /** Current visible terminal screen snapshot */
851
+ terminalScreen = new TerminalScreen(40, 120);
852
+ /** Max accumulated buffer size (last 50KB) */
853
+ static MAX_ACCUMULATED_BUFFER = 5e4;
806
854
  setStatus(status, trigger) {
807
855
  const prev = this.currentStatus;
808
856
  if (prev === status) return;
@@ -811,10 +859,18 @@ var init_provider_cli_adapter = __esm({
811
859
  if (this.statusHistory.length > 50) this.statusHistory.shift();
812
860
  LOG.info("CLI", `[${this.cliType}] status: ${prev} \u2192 ${status}${trigger ? ` (${trigger})` : ""}`);
813
861
  }
814
- // Resolved timeouts (provider defaults + overrides)
862
+ // Resolved timeouts
815
863
  timeouts;
816
- // Provider approval key mapping (e.g. { 0: '1', 1: '2', 2: '3' }) — loaded from provider.json
864
+ // Provider approval key mapping
817
865
  approvalKeys;
866
+ sendDelayMs;
867
+ sendKey;
868
+ /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
869
+ setCliScripts(scripts) {
870
+ this.cliScripts = scripts;
871
+ const scriptNames = Object.keys(scripts).filter((k) => typeof scripts[k] === "function");
872
+ LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
873
+ }
818
874
  // ─── Lifecycle ─────────────────────────────────
819
875
  setServerConn(serverConn) {
820
876
  this.serverConn = serverConn;
@@ -903,15 +959,22 @@ var init_provider_cli_adapter = __esm({
903
959
  this.spawnAt = Date.now();
904
960
  this.startupParseGate = true;
905
961
  this.startupBuffer = "";
962
+ this.terminalScreen.reset(40, 120);
906
963
  this.ready = true;
907
964
  this.setStatus("idle", "pty_ready");
908
965
  this.onStatusChange?.();
909
966
  }
910
- // ─── Output state machine ────────────────────────────
967
+ // ─── Output Handling ────────────────────────────
911
968
  handleOutput(rawData) {
912
969
  if (Date.now() < this.resizeSuppressUntil) return;
970
+ if (rawData.includes("\x1B[6n") || rawData.includes("\x1B[?6n")) {
971
+ this.ptyProcess?.write("\x1B[1;1R");
972
+ }
973
+ this.terminalScreen.write(rawData);
913
974
  const cleanData = stripAnsi(rawData);
914
- const { patterns } = this.provider;
975
+ if (this.isWaitingForResponse && cleanData) {
976
+ this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
977
+ }
915
978
  if (cleanData.trim()) {
916
979
  if (this.serverConn) {
917
980
  this.serverConn.sendMessage("log", { message: cleanData.trim(), level: "info" });
@@ -920,9 +983,10 @@ var init_provider_cli_adapter = __esm({
920
983
  }
921
984
  }
922
985
  this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1e3);
986
+ this.accumulatedBuffer = (this.accumulatedBuffer + cleanData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
987
+ this.accumulatedRawBuffer = (this.accumulatedRawBuffer + rawData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
923
988
  if (this.startupParseGate) {
924
989
  this.startupBuffer += cleanData;
925
- LOG.info("CLI", `[${this.cliType}] startup chunk (${cleanData.length} chars): ${cleanData.slice(0, 200).replace(/\n/g, "\\n")}`);
926
990
  const dialogPatterns = [
927
991
  /Do you want to connect/i,
928
992
  /Do you trust the files/i,
@@ -937,122 +1001,49 @@ var init_provider_cli_adapter = __esm({
937
1001
  }
938
1002
  const elapsed = Date.now() - this.spawnAt;
939
1003
  const bufCap = this.startupBuffer.length > 12e3;
940
- const promptMatched = patterns.prompt.some((p) => p.test(this.startupBuffer));
941
- if (promptMatched || elapsed > 8e3 || bufCap) {
1004
+ const scriptStatus = this.runDetectStatus(this.startupBuffer);
1005
+ const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
1006
+ if (isReady) {
942
1007
  this.startupParseGate = false;
943
- if (promptMatched) {
944
- LOG.info("CLI", `[${this.cliType}] \u2713 Startup gate end (prompt matched)`);
945
- } else {
946
- LOG.info("CLI", `[${this.cliType}] startup gate end (${elapsed}ms, cap=${bufCap}, prompt=${promptMatched})`);
947
- }
1008
+ LOG.info("CLI", `[${this.cliType}] Startup gate end (${elapsed}ms, scriptStatus=${scriptStatus})`);
948
1009
  } else {
949
1010
  return;
950
1011
  }
951
1012
  }
952
- if (cleanData.trim().length > 5) {
953
- LOG.debug("CLI", `[${this.cliType}] output chunk (${cleanData.length}): ${cleanData.slice(0, 300).replace(/\n/g, "\\n")}`);
954
- }
955
- if (!this.isWaitingForResponse) {
956
- if (patterns.generating.some((p) => p.test(cleanData))) {
957
- if (this.settleTimer) {
958
- clearTimeout(this.settleTimer);
959
- this.settleTimer = null;
960
- }
961
- this.isWaitingForResponse = true;
962
- this.responseBuffer = "";
963
- this.setStatus("generating", "autonomous_gen");
964
- this.onStatusChange?.();
965
- }
966
- }
967
- if (this.isWaitingForResponse) {
968
- this.responseBuffer += cleanData;
969
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
970
- if (patterns.generating.some((p) => p.test(cleanData))) {
971
- this.setStatus("generating", "still_generating");
972
- this.idleTimeout = setTimeout(() => {
973
- if (this.isWaitingForResponse) this.finishResponse();
974
- }, this.timeouts.generatingIdle);
975
- this.onStatusChange?.();
976
- if (this.settleTimer) {
977
- clearTimeout(this.settleTimer);
978
- this.settleTimer = null;
979
- }
980
- return;
981
- }
982
- }
983
- if (this.currentStatus === "waiting_approval") {
984
- this.approvalTransitionBuffer = (this.approvalTransitionBuffer + cleanData).slice(-500);
985
- this.scheduleSettle();
986
- return;
987
- }
988
1013
  this.scheduleSettle();
989
1014
  }
990
- /**
991
- * Fired after output goes quiet for outputSettle ms.
992
- * Evaluates the stabilised buffer for approval, prompt (idle), or timeout.
993
- */
994
1015
  scheduleSettle() {
995
1016
  if (this.settleTimer) clearTimeout(this.settleTimer);
1017
+ const delay = Math.max(
1018
+ this.timeouts.outputSettle,
1019
+ this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
1020
+ );
996
1021
  this.settleTimer = setTimeout(() => {
997
1022
  this.settleTimer = null;
998
1023
  this.settledBuffer = this.recentOutputBuffer;
999
1024
  this.evaluateSettled();
1000
- }, this.timeouts.outputSettle);
1025
+ }, delay);
1001
1026
  }
1002
1027
  evaluateSettled() {
1003
- const { patterns } = this.provider;
1004
- const buf = this.settledBuffer;
1005
- if (this.currentStatus === "waiting_approval") {
1006
- const genResume = patterns.generating.some((p) => p.test(this.approvalTransitionBuffer));
1007
- const promptResume = patterns.prompt.some((p) => p.test(this.approvalTransitionBuffer));
1008
- if (genResume) {
1009
- if (this.approvalExitTimeout) {
1010
- clearTimeout(this.approvalExitTimeout);
1011
- this.approvalExitTimeout = null;
1012
- }
1013
- this.setStatus("generating", "approval_gen_resume");
1014
- this.activeModal = null;
1015
- this.recentOutputBuffer = "";
1016
- this.approvalTransitionBuffer = "";
1017
- this.lastApprovalResolvedAt = Date.now();
1018
- this.onStatusChange?.();
1019
- } else if (promptResume) {
1020
- if (this.approvalExitTimeout) {
1021
- clearTimeout(this.approvalExitTimeout);
1022
- this.approvalExitTimeout = null;
1023
- }
1024
- this.activeModal = null;
1025
- this.recentOutputBuffer = "";
1026
- this.approvalTransitionBuffer = "";
1027
- this.lastApprovalResolvedAt = Date.now();
1028
- this.finishResponse();
1029
- }
1030
- return;
1031
- }
1032
- const hasApproval = patterns.approval.some((p) => p.test(buf));
1033
- if (hasApproval) {
1028
+ const tail = this.settledBuffer;
1029
+ const scriptStatus = this.runDetectStatus(tail);
1030
+ if (!scriptStatus) return;
1031
+ const prevStatus = this.currentStatus;
1032
+ if (scriptStatus === "waiting_approval") {
1034
1033
  const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
1035
1034
  if (!inCooldown) {
1036
- const ctxLines = buf.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
1037
1035
  this.isWaitingForResponse = true;
1038
- this.setStatus("waiting_approval", "approval_pattern");
1039
- this.recentOutputBuffer = "";
1040
- this.approvalTransitionBuffer = "";
1041
- this.activeModal = {
1042
- message: ctxLines.slice(-5).join(" ").slice(0, 200) || "Approval required",
1043
- buttons: this.cliType === "claude-cli" ? ["Yes (y)", "Always allow (a)", "Deny (Esc)"] : ["Allow once", "Always allow", "Deny"]
1044
- };
1036
+ this.setStatus("waiting_approval", "script_detect");
1037
+ const modal = this.runParseApproval(tail);
1038
+ this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
1045
1039
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
1046
1040
  if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
1047
1041
  this.approvalExitTimeout = setTimeout(() => {
1048
1042
  if (this.currentStatus === "waiting_approval") {
1049
- LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-exiting waiting_approval`);
1043
+ LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
1050
1044
  this.activeModal = null;
1051
1045
  this.lastApprovalResolvedAt = Date.now();
1052
- this.recentOutputBuffer = "";
1053
- this.approvalTransitionBuffer = "";
1054
- this.approvalExitTimeout = null;
1055
- this.setStatus(this.isWaitingForResponse ? "generating" : "idle", "approval_cleared");
1046
+ this.setStatus("idle", "approval_timeout");
1056
1047
  this.onStatusChange?.();
1057
1048
  }
1058
1049
  }, 6e4);
@@ -1060,19 +1051,42 @@ var init_provider_cli_adapter = __esm({
1060
1051
  return;
1061
1052
  }
1062
1053
  }
1063
- if (this.isWaitingForResponse) {
1064
- const trailingLines = buf.split("\n").slice(-3).join("\n");
1065
- if (patterns.prompt.some((p) => p.test(trailingLines)) && !hasApproval) {
1066
- this.finishResponse();
1067
- } else if (!patterns.generating.some((p) => p.test(buf))) {
1068
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
1069
- this.idleTimeout = setTimeout(() => {
1070
- if (this.isWaitingForResponse && this.responseBuffer.trim()) {
1071
- this.finishResponse();
1072
- }
1073
- }, this.timeouts.idleFinish);
1054
+ if (scriptStatus === "generating") {
1055
+ if (prevStatus === "waiting_approval") {
1056
+ if (this.approvalExitTimeout) {
1057
+ clearTimeout(this.approvalExitTimeout);
1058
+ this.approvalExitTimeout = null;
1059
+ }
1060
+ this.activeModal = null;
1061
+ this.lastApprovalResolvedAt = Date.now();
1062
+ }
1063
+ if (!this.isWaitingForResponse) {
1064
+ this.isWaitingForResponse = true;
1065
+ this.responseBuffer = "";
1074
1066
  }
1067
+ this.setStatus("generating", "script_detect");
1068
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
1069
+ this.idleTimeout = setTimeout(() => {
1070
+ if (this.isWaitingForResponse) this.finishResponse();
1071
+ }, this.timeouts.generatingIdle);
1075
1072
  this.onStatusChange?.();
1073
+ return;
1074
+ }
1075
+ if (scriptStatus === "idle") {
1076
+ if (prevStatus === "waiting_approval") {
1077
+ if (this.approvalExitTimeout) {
1078
+ clearTimeout(this.approvalExitTimeout);
1079
+ this.approvalExitTimeout = null;
1080
+ }
1081
+ this.activeModal = null;
1082
+ this.lastApprovalResolvedAt = Date.now();
1083
+ }
1084
+ if (this.isWaitingForResponse) {
1085
+ this.finishResponse();
1086
+ } else if (prevStatus !== "idle") {
1087
+ this.setStatus("idle", "script_detect");
1088
+ this.onStatusChange?.();
1089
+ }
1076
1090
  }
1077
1091
  }
1078
1092
  finishResponse() {
@@ -1088,25 +1102,54 @@ var init_provider_cli_adapter = __esm({
1088
1102
  clearTimeout(this.approvalExitTimeout);
1089
1103
  this.approvalExitTimeout = null;
1090
1104
  }
1091
- const lastUserText = this.messages.filter((m) => m.role === "user").pop()?.content;
1092
- let response = this.provider.cleanOutput(this.responseBuffer, lastUserText);
1093
- if (lastUserText && response) {
1094
- const userTrimmed = lastUserText.trim();
1095
- response = response.split("\n").filter((l) => l.trim() !== userTrimmed).join("\n").trim();
1096
- }
1097
- if (response) {
1098
- this.messages.push({ role: "assistant", content: response, timestamp: Date.now() });
1099
- if (this.messages.length > 200) this.messages = this.messages.slice(-200);
1100
- LOG.info("CLI", `[${this.cliType}] Response (${response.length} chars)`);
1101
- }
1102
1105
  this.responseBuffer = "";
1103
1106
  this.isWaitingForResponse = false;
1104
1107
  this.activeModal = null;
1105
1108
  this.setStatus("idle", "response_finished");
1106
1109
  this.onStatusChange?.();
1107
1110
  }
1108
- // ─── Public API (CliAdapter interface) ──────────
1111
+ // ─── Script Execution ──────────────────────────
1112
+ runDetectStatus(text) {
1113
+ if (!this.cliScripts?.detectStatus) return null;
1114
+ try {
1115
+ return this.cliScripts.detectStatus({
1116
+ tail: text.slice(-500),
1117
+ screenText: this.terminalScreen.getText(),
1118
+ rawBuffer: this.accumulatedRawBuffer
1119
+ });
1120
+ } catch (e) {
1121
+ LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
1122
+ return null;
1123
+ }
1124
+ }
1125
+ runParseApproval(tail) {
1126
+ if (!this.cliScripts?.parseApproval) return null;
1127
+ try {
1128
+ return this.cliScripts.parseApproval({
1129
+ buffer: this.terminalScreen.getText() || this.accumulatedBuffer,
1130
+ rawBuffer: this.accumulatedRawBuffer,
1131
+ tail
1132
+ });
1133
+ } catch (e) {
1134
+ LOG.warn("CLI", `[${this.cliType}] parseApproval error: ${e.message}`);
1135
+ return null;
1136
+ }
1137
+ }
1138
+ // ─── Public API (CliAdapter) ───────────────────
1109
1139
  getStatus() {
1140
+ const scriptResult = this.getScriptParsedStatus();
1141
+ if (scriptResult) {
1142
+ return {
1143
+ status: this.currentStatus,
1144
+ messages: (scriptResult.messages || []).map((m) => ({
1145
+ role: m.role,
1146
+ content: m.content,
1147
+ timestamp: m.timestamp
1148
+ })),
1149
+ workingDir: this.workingDir,
1150
+ activeModal: this.activeModal
1151
+ };
1152
+ }
1110
1153
  return {
1111
1154
  status: this.currentStatus,
1112
1155
  messages: [...this.messages],
@@ -1114,24 +1157,94 @@ var init_provider_cli_adapter = __esm({
1114
1157
  activeModal: this.activeModal
1115
1158
  };
1116
1159
  }
1160
+ /**
1161
+ * Script-based full parse — returns ReadChatResult.
1162
+ * Called by command handler / dashboard for rich content rendering.
1163
+ */
1164
+ getScriptParsedStatus() {
1165
+ if (!this.cliScripts?.parseOutput) return null;
1166
+ try {
1167
+ const input = {
1168
+ buffer: this.accumulatedBuffer,
1169
+ rawBuffer: this.accumulatedRawBuffer,
1170
+ recentBuffer: this.recentOutputBuffer,
1171
+ screenText: this.terminalScreen.getText(),
1172
+ messages: [...this.structuredMessages.length > 0 ? this.structuredMessages : this.messages],
1173
+ partialResponse: this.responseBuffer
1174
+ };
1175
+ const result = this.cliScripts.parseOutput(input);
1176
+ if (result && typeof result === "object") {
1177
+ if (Array.isArray(result.messages)) {
1178
+ this.structuredMessages = result.messages.map((m) => ({
1179
+ role: m.role,
1180
+ content: m.content,
1181
+ timestamp: m.timestamp
1182
+ }));
1183
+ }
1184
+ return result;
1185
+ }
1186
+ } catch (e) {
1187
+ LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${e.message}`);
1188
+ }
1189
+ return null;
1190
+ }
1191
+ /** Whether this adapter has CLI scripts loaded */
1192
+ hasCliScripts() {
1193
+ return typeof this.cliScripts?.detectStatus === "function";
1194
+ }
1195
+ /**
1196
+ * Resolves an action (like 'fix' lint error) from the dashboard.
1197
+ * Uses resolveAction script if available, otherwise falls back to standard text.
1198
+ */
1199
+ async resolveAction(data) {
1200
+ let promptText = "";
1201
+ if (this.cliScripts && typeof this.cliScripts.resolveAction === "function") {
1202
+ try {
1203
+ promptText = this.cliScripts.resolveAction(data);
1204
+ } catch (e) {
1205
+ LOG.warn("CLI", `[${this.cliType}] resolveAction error: ${e.message}`);
1206
+ }
1207
+ }
1208
+ if (!promptText && data) {
1209
+ promptText = `Please fix the following issue:
1210
+ ${data.title || ""}
1211
+ ${data.explanation || ""}
1212
+
1213
+ ${data.message || ""}`.trim();
1214
+ }
1215
+ if (promptText) {
1216
+ await this.sendMessage(promptText);
1217
+ }
1218
+ }
1117
1219
  async sendMessage(text) {
1118
1220
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
1119
1221
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
1120
1222
  if (this.isWaitingForResponse) return;
1121
1223
  this.messages.push({ role: "user", content: text, timestamp: Date.now() });
1224
+ this.structuredMessages.push({ role: "user", content: text, timestamp: Date.now() });
1122
1225
  this.isWaitingForResponse = true;
1123
1226
  this.responseBuffer = "";
1124
1227
  this.setStatus("generating", "sendMessage");
1125
1228
  this.onStatusChange?.();
1126
- this.ptyProcess.write(text + "\r");
1127
- this.responseTimeout = setTimeout(() => {
1128
- if (this.isWaitingForResponse) this.finishResponse();
1129
- }, this.timeouts.maxResponse);
1229
+ this.ptyProcess.write(text);
1230
+ const submit = () => {
1231
+ if (!this.ptyProcess) return;
1232
+ this.submitPendingUntil = 0;
1233
+ this.ptyProcess.write(this.sendKey);
1234
+ this.responseTimeout = setTimeout(() => {
1235
+ if (this.isWaitingForResponse) this.finishResponse();
1236
+ }, this.timeouts.maxResponse);
1237
+ };
1238
+ if (this.sendDelayMs > 0) {
1239
+ this.submitPendingUntil = Date.now() + this.sendDelayMs;
1240
+ setTimeout(submit, this.sendDelayMs);
1241
+ } else {
1242
+ submit();
1243
+ }
1130
1244
  }
1131
1245
  getPartialResponse() {
1132
1246
  if (!this.isWaitingForResponse) return "";
1133
- const partial = this.provider.cleanOutput(this.responseBuffer);
1134
- return partial || (this.isWaitingForResponse ? "(generating...)" : "");
1247
+ return this.responseBuffer;
1135
1248
  }
1136
1249
  cancel() {
1137
1250
  this.shutdown();
@@ -1163,6 +1276,10 @@ var init_provider_cli_adapter = __esm({
1163
1276
  }
1164
1277
  clearHistory() {
1165
1278
  this.messages = [];
1279
+ this.structuredMessages = [];
1280
+ this.accumulatedBuffer = "";
1281
+ this.accumulatedRawBuffer = "";
1282
+ this.terminalScreen.reset();
1166
1283
  this.onStatusChange?.();
1167
1284
  }
1168
1285
  isProcessing() {
@@ -1174,11 +1291,6 @@ var init_provider_cli_adapter = __esm({
1174
1291
  writeRaw(data) {
1175
1292
  this.ptyProcess?.write(data);
1176
1293
  }
1177
- /**
1178
- * Resolve an approval modal by navigating to the button at `buttonIndex` and pressing Enter.
1179
- * Index 0 = first option (already selected by default — just Enter).
1180
- * Index N = press Arrow Down N times, then Enter.
1181
- */
1182
1294
  resolveModal(buttonIndex) {
1183
1295
  if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
1184
1296
  if (buttonIndex in this.approvalKeys) {
@@ -1193,25 +1305,13 @@ var init_provider_cli_adapter = __esm({
1193
1305
  if (this.ptyProcess) {
1194
1306
  try {
1195
1307
  this.ptyProcess.resize(cols, rows);
1308
+ this.terminalScreen.resize(rows, cols);
1196
1309
  this.resizeSuppressUntil = Date.now() + 300;
1197
1310
  } catch {
1198
1311
  }
1199
1312
  }
1200
1313
  }
1201
- /**
1202
- * Full debug state — exposes all internal buffers, status, and patterns for debugging.
1203
- * Used by DevServer /api/cli/debug endpoint.
1204
- */
1205
1314
  getDebugState() {
1206
- const sb = this.startupBuffer;
1207
- const testOnStartup = (p) => {
1208
- const flags = p.flags.includes("g") ? p.flags.replace(/g/g, "") : p.flags;
1209
- return new RegExp(p.source, flags).test(sb);
1210
- };
1211
- const promptDiagnostics = this.provider.patterns.prompt.map((p) => ({
1212
- pattern: p.toString(),
1213
- matchedAgainstStartupBuffer: testOnStartup(p)
1214
- }));
1215
1315
  return {
1216
1316
  type: this.cliType,
1217
1317
  name: this.cliName,
@@ -1221,32 +1321,24 @@ var init_provider_cli_adapter = __esm({
1221
1321
  spawnAt: this.spawnAt,
1222
1322
  workingDir: this.workingDir,
1223
1323
  messages: this.messages.slice(-20),
1324
+ structuredMessages: this.structuredMessages.slice(-20),
1224
1325
  messageCount: this.messages.length,
1225
- // Buffers (longer tails here than in periodic logs — for matching provider.json patterns)
1226
- startupBuffer: sb.slice(-4e3),
1227
- startupBufferLength: sb.length,
1228
- promptDiagnostics,
1326
+ screenText: this.terminalScreen.getText().slice(-4e3),
1327
+ startupBuffer: this.startupBuffer.slice(-4e3),
1229
1328
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
1230
1329
  settledBuffer: this.settledBuffer.slice(-500),
1231
- responseBuffer: this.responseBuffer.slice(-500),
1232
- approvalTransitionBuffer: this.approvalTransitionBuffer.slice(-500),
1233
- // State
1330
+ accumulatedBufferLength: this.accumulatedBuffer.length,
1331
+ accumulatedRawBufferLength: this.accumulatedRawBuffer.length,
1332
+ rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
1333
+ responseBuffer: this.responseBuffer.slice(-1e3),
1234
1334
  isWaitingForResponse: this.isWaitingForResponse,
1235
1335
  activeModal: this.activeModal,
1236
1336
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
1237
1337
  resizeSuppressUntil: this.resizeSuppressUntil,
1238
- // Provider patterns (serialized)
1239
- patterns: {
1240
- prompt: this.provider.patterns.prompt.map((p) => p.toString()),
1241
- generating: this.provider.patterns.generating.map((p) => p.toString()),
1242
- approval: this.provider.patterns.approval.map((p) => p.toString()),
1243
- ready: this.provider.patterns.ready.map((p) => p.toString())
1244
- },
1245
- // Status history
1338
+ hasCliScripts: this.hasCliScripts(),
1339
+ scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
1246
1340
  statusHistory: this.statusHistory.slice(-30),
1247
- // Timeouts config
1248
1341
  timeouts: this.timeouts,
1249
- // PTY alive
1250
1342
  ptyAlive: !!this.ptyProcess
1251
1343
  };
1252
1344
  }
@@ -3987,6 +4079,9 @@ init_logger();
3987
4079
 
3988
4080
  // src/commands/chat-commands.ts
3989
4081
  init_logger();
4082
+ function getTargetedCliAdapter(h, args, providerType) {
4083
+ return h.getCliAdapter(args?._targetInstance || h.currentIdeType || providerType);
4084
+ }
3990
4085
  async function handleChatHistory(h, args) {
3991
4086
  const { agentType, offset, limit, instanceId } = args;
3992
4087
  try {
@@ -3999,10 +4094,10 @@ async function handleChatHistory(h, args) {
3999
4094
  }
4000
4095
  }
4001
4096
  async function handleReadChat(h, args) {
4002
- const provider = h.getProvider();
4097
+ const provider = h.getProvider(args?.agentType);
4003
4098
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
4004
4099
  if (provider?.category === "cli" || provider?.category === "acp") {
4005
- const adapter = h.getCliAdapter(provider.type);
4100
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4006
4101
  if (adapter) {
4007
4102
  _log(`${provider.category} adapter: ${adapter.cliType}`);
4008
4103
  const status = adapter.getStatus?.();
@@ -4118,7 +4213,7 @@ async function handleSendChat(h, args) {
4118
4213
  const text = args?.text || args?.message;
4119
4214
  if (!text) return { success: false, error: "text required" };
4120
4215
  const _log = (msg) => LOG.debug("Command", `[send_chat] ${msg}`);
4121
- const provider = h.getProvider();
4216
+ const provider = h.getProvider(args?.agentType);
4122
4217
  const _logSendSuccess = (method, targetAgent) => {
4123
4218
  h.historyWriter.appendNewMessages(
4124
4219
  targetAgent || provider?.type || h.currentIdeType || "unknown_agent",
@@ -4130,7 +4225,7 @@ async function handleSendChat(h, args) {
4130
4225
  return { success: true, sent: true, method, targetAgent };
4131
4226
  };
4132
4227
  if (provider?.category === "cli" || provider?.category === "acp") {
4133
- const adapter = h.getCliAdapter(provider.type);
4228
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4134
4229
  if (adapter) {
4135
4230
  _log(`${provider.category} adapter: ${adapter.cliType}`);
4136
4231
  try {
@@ -4283,7 +4378,7 @@ async function handleSendChat(h, args) {
4283
4378
  return { success: false, error: "No provider method could send the message" };
4284
4379
  }
4285
4380
  async function handleListChats(h, args) {
4286
- const provider = h.getProvider();
4381
+ const provider = h.getProvider(args?.agentType);
4287
4382
  if (provider?.category === "extension" && h.agentStream && h.getCdp()) {
4288
4383
  try {
4289
4384
  const chats = await h.agentStream.listAgentChats(h.getCdp(), provider.type);
@@ -4335,7 +4430,16 @@ async function handleListChats(h, args) {
4335
4430
  return { success: false, error: "listSessions script not available for this provider" };
4336
4431
  }
4337
4432
  async function handleNewChat(h, args) {
4338
- const provider = h.getProvider();
4433
+ const provider = h.getProvider(args?.agentType);
4434
+ if (provider?.category === "cli") {
4435
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4436
+ if (!adapter) return { success: false, error: "CLI adapter not running" };
4437
+ if (typeof adapter.clearHistory === "function") {
4438
+ adapter.clearHistory();
4439
+ return { success: true, cleared: true };
4440
+ }
4441
+ return { success: false, error: "new_chat not supported by this CLI provider" };
4442
+ }
4339
4443
  if (provider?.category === "extension" && h.agentStream && h.getCdp()) {
4340
4444
  const ok = await h.agentStream.newAgentSession(h.getCdp(), provider.type, h.currentIdeType);
4341
4445
  return { success: ok };
@@ -4360,7 +4464,7 @@ async function handleNewChat(h, args) {
4360
4464
  return { success: false, error: "newSession script not available for this provider" };
4361
4465
  }
4362
4466
  async function handleSwitchChat(h, args) {
4363
- const provider = h.getProvider();
4467
+ const provider = h.getProvider(args?.agentType);
4364
4468
  const ideType = h.currentIdeType;
4365
4469
  const sessionId = args?.sessionId || args?.id || args?.chatId;
4366
4470
  if (!sessionId) return { success: false, error: "sessionId required" };
@@ -4454,10 +4558,10 @@ async function handleSwitchChat(h, args) {
4454
4558
  }
4455
4559
  }
4456
4560
  async function handleSetMode(h, args) {
4457
- const provider = h.getProvider();
4561
+ const provider = h.getProvider(args?.agentType);
4458
4562
  const mode = args?.mode || "agent";
4459
4563
  if (provider?.category === "acp") {
4460
- const adapter = h.getCliAdapter(provider.type);
4564
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4461
4565
  if (adapter) {
4462
4566
  const acpInstance = adapter._acpInstance;
4463
4567
  if (acpInstance && typeof acpInstance.onEvent === "function") {
@@ -4509,11 +4613,11 @@ async function handleSetMode(h, args) {
4509
4613
  return { success: false, error: `setMode '${mode}' not supported by this provider` };
4510
4614
  }
4511
4615
  async function handleChangeModel(h, args) {
4512
- const provider = h.getProvider();
4616
+ const provider = h.getProvider(args?.agentType);
4513
4617
  const model = args?.model;
4514
4618
  LOG.info("Command", `[change_model] model=${model} provider=${provider?.type} category=${provider?.category} ideType=${h.currentIdeType} providerType=${h.currentProviderType}`);
4515
4619
  if (provider?.category === "acp") {
4516
- const adapter = h.getCliAdapter(provider.type);
4620
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4517
4621
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
4518
4622
  if (adapter) {
4519
4623
  const acpInstance = adapter._acpInstance;
@@ -4570,11 +4674,11 @@ async function handleSetThoughtLevel(h, args) {
4570
4674
  const configId = args?.configId;
4571
4675
  const value = args?.value;
4572
4676
  if (!configId || !value) return { success: false, error: "configId and value required" };
4573
- const provider = h.getProvider();
4677
+ const provider = h.getProvider(args?.agentType);
4574
4678
  if (!provider || provider.category !== "acp") {
4575
4679
  return { success: false, error: "set_thought_level only for ACP providers" };
4576
4680
  }
4577
- const adapter = h.getCliAdapter(provider.type);
4681
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4578
4682
  const acpInstance = adapter?._acpInstance;
4579
4683
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
4580
4684
  try {
@@ -4586,13 +4690,22 @@ async function handleSetThoughtLevel(h, args) {
4586
4690
  }
4587
4691
  }
4588
4692
  async function handleResolveAction(h, args) {
4589
- const provider = h.getProvider();
4693
+ const provider = h.getProvider(args?.agentType);
4590
4694
  const action = args?.action || "approve";
4591
4695
  const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
4592
4696
  LOG.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider?.type}`);
4593
4697
  if (provider?.category === "cli") {
4594
- const adapter = h.getCliAdapter(provider.type);
4698
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
4595
4699
  if (!adapter) return { success: false, error: "CLI adapter not running" };
4700
+ if (args?.data && typeof adapter.resolveAction === "function") {
4701
+ try {
4702
+ await adapter.resolveAction(args.data);
4703
+ LOG.info("Command", `[resolveAction] CLI PTY \u2192 resolveAction triggered with data payload`);
4704
+ return { success: true, method: "cli-resolve-action" };
4705
+ } catch (e) {
4706
+ return { success: false, error: `CLI resolveAction failed: ${e.message}` };
4707
+ }
4708
+ }
4596
4709
  const status = adapter.getStatus?.();
4597
4710
  if (status?.status !== "waiting_approval") {
4598
4711
  return { success: false, error: "Not in approval state" };
@@ -6790,8 +6903,9 @@ var ProviderLoader = class _ProviderLoader {
6790
6903
  }
6791
6904
  }
6792
6905
  compareVersions(a, b) {
6793
- const pa = a.split(".").map(Number);
6794
- const pb = b.split(".").map(Number);
6906
+ const normalize2 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
6907
+ const pa = normalize2(a);
6908
+ const pb = normalize2(b);
6795
6909
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
6796
6910
  const va = pa[i] || 0;
6797
6911
  const vb = pb[i] || 0;
@@ -7868,21 +7982,28 @@ var CliProviderInstance = class {
7868
7982
  async onTick() {
7869
7983
  }
7870
7984
  getState() {
7871
- const adapterStatus = this.adapter.getStatus();
7985
+ const rawStatus = this.adapter.getStatus();
7986
+ const parsedStatus = this.adapter.getScriptParsedStatus();
7987
+ const adapterStatus = parsedStatus ? {
7988
+ ...rawStatus,
7989
+ messages: parsedStatus.messages || rawStatus.messages,
7990
+ activeModal: parsedStatus.activeModal || rawStatus.activeModal
7991
+ } : rawStatus;
7872
7992
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
7873
- const recentMessages = adapterStatus.messages.slice(-50).map((m) => ({
7874
- role: m.role,
7875
- content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content,
7876
- timestamp: m.timestamp
7877
- }));
7993
+ const recentMessages = adapterStatus.messages.slice(-50).map((m) => {
7994
+ const content = typeof m.content === "string" && m.content.length > 8e3 ? m.content.slice(0, 8e3) + "\n... (truncated)" : m.content;
7995
+ return { ...m, content };
7996
+ });
7878
7997
  const partial = this.adapter.getPartialResponse();
7879
- if (adapterStatus.status === "generating" && partial) {
7998
+ const shouldAppendRawPartial = !parsedStatus;
7999
+ if (shouldAppendRawPartial && adapterStatus.status === "generating" && partial) {
7880
8000
  const cleaned = partial.trim();
7881
8001
  if (cleaned && cleaned !== "(generating...)") {
7882
8002
  recentMessages.push({
7883
8003
  role: "assistant",
7884
- content: (cleaned.length > 2e3 ? cleaned.slice(0, 2e3) + "..." : cleaned) + "...",
7885
- timestamp: Date.now()
8004
+ content: (cleaned.length > 8e3 ? cleaned.slice(0, 8e3) + "..." : cleaned) + "...",
8005
+ timestamp: Date.now(),
8006
+ meta: { streaming: true }
7886
8007
  });
7887
8008
  }
7888
8009
  }
@@ -7921,6 +8042,8 @@ var CliProviderInstance = class {
7921
8042
  this.adapter.sendMessage(data.text);
7922
8043
  } else if (event === "server_connected" && data?.serverConn) {
7923
8044
  this.adapter.setServerConn(data.serverConn);
8045
+ } else if (event === "resolve_action" && data) {
8046
+ this.adapter.resolveAction(data);
7924
8047
  }
7925
8048
  }
7926
8049
  dispose() {
@@ -8978,7 +9101,8 @@ var DaemonCliManager = class {
8978
9101
  const provider = this.providerLoader.getMeta(normalizedType);
8979
9102
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
8980
9103
  console.log(import_chalk.default.cyan(` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
8981
- return new ProviderCliAdapter(provider, workingDir, cliArgs);
9104
+ const resolvedProvider = this.providerLoader.resolve(normalizedType) || provider;
9105
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs);
8982
9106
  }
8983
9107
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
8984
9108
  }
@@ -9063,7 +9187,8 @@ ${installInfo}`
9063
9187
  }
9064
9188
  const instanceManager = this.deps.getInstanceManager();
9065
9189
  if (provider && instanceManager) {
9066
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key);
9190
+ const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
9191
+ const cliInstance = new CliProviderInstance(resolvedProvider, resolvedDir, cliArgs, key);
9067
9192
  try {
9068
9193
  await instanceManager.addInstance(key, cliInstance, {
9069
9194
  serverConn: this.deps.getServerConn(),
@@ -12261,6 +12386,46 @@ var DevServer = class _DevServer {
12261
12386
  }
12262
12387
  }
12263
12388
  // ─── Phase 2: Auto-Implement Backend ───
12389
+ getDefaultAutoImplReference(category, type) {
12390
+ if (category === "cli") {
12391
+ return type === "codex-cli" ? "claude-cli" : "codex-cli";
12392
+ }
12393
+ return "antigravity";
12394
+ }
12395
+ resolveAutoImplReference(category, requestedReference, targetType) {
12396
+ const desired = requestedReference || this.getDefaultAutoImplReference(category, targetType);
12397
+ const ref = this.providerLoader.resolve(desired) || this.providerLoader.getMeta(desired);
12398
+ if (ref?.category === category) return desired;
12399
+ const all = this.providerLoader.getAll();
12400
+ const fallback = all.find((p) => p.category === category && p.type !== targetType);
12401
+ return fallback?.type || null;
12402
+ }
12403
+ loadAutoImplReferenceScripts(category, referenceType) {
12404
+ if (!referenceType) return {};
12405
+ const builtinDir = this.providerLoader.getPrimaryBuiltinDir();
12406
+ const refDir = path12.join(builtinDir, category, referenceType);
12407
+ if (!fs9.existsSync(refDir)) return {};
12408
+ const referenceScripts = {};
12409
+ const scriptsDir = path12.join(refDir, "scripts");
12410
+ if (!fs9.existsSync(scriptsDir)) return referenceScripts;
12411
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
12412
+ try {
12413
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
12414
+ } catch {
12415
+ return false;
12416
+ }
12417
+ }).sort().reverse();
12418
+ if (versions.length === 0) return referenceScripts;
12419
+ const latestDir = path12.join(scriptsDir, versions[0]);
12420
+ for (const file of fs9.readdirSync(latestDir)) {
12421
+ if (!file.endsWith(".js")) continue;
12422
+ try {
12423
+ referenceScripts[file] = fs9.readFileSync(path12.join(latestDir, file), "utf-8");
12424
+ } catch {
12425
+ }
12426
+ }
12427
+ return referenceScripts;
12428
+ }
12264
12429
  async handleAutoImplement(type, req, res) {
12265
12430
  const body = await this.readBody(req);
12266
12431
  const { agent = "claude-cli", functions, reference = "antigravity", model, comment } = body;
@@ -12283,36 +12448,26 @@ var DevServer = class _DevServer {
12283
12448
  return;
12284
12449
  }
12285
12450
  try {
12286
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "analyzing", message: "\uC5D0\uC774\uC804\uD2B8 \uCD08\uAE30\uD654 (DOM \uD0D0\uC0C9 \uAD8C\uD55C \uBD80\uC5EC)..." } });
12451
+ const resolvedReference = this.resolveAutoImplReference(provider.category, reference, type);
12452
+ this.sendAutoImplSSE({
12453
+ event: "progress",
12454
+ data: {
12455
+ function: "_init",
12456
+ status: "analyzing",
12457
+ message: provider.category === "cli" ? "Initializing agent (granting CLI PTY debug access)..." : "Initializing agent (granting DOM access)..."
12458
+ }
12459
+ });
12287
12460
  const domContext = null;
12288
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
12289
- let referenceScripts = {};
12290
- const builtinDir = this.providerLoader.getPrimaryBuiltinDir();
12291
- const refDir = path12.join(builtinDir, "ide", reference);
12292
- if (fs9.existsSync(refDir)) {
12293
- const scriptsDir = path12.join(refDir, "scripts");
12294
- if (fs9.existsSync(scriptsDir)) {
12295
- const versions = fs9.readdirSync(scriptsDir).filter((d) => {
12296
- try {
12297
- return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
12298
- } catch {
12299
- return false;
12300
- }
12301
- }).sort().reverse();
12302
- if (versions.length > 0) {
12303
- const latestDir = path12.join(scriptsDir, versions[0]);
12304
- for (const file of fs9.readdirSync(latestDir)) {
12305
- if (file.endsWith(".js")) {
12306
- try {
12307
- referenceScripts[file] = fs9.readFileSync(path12.join(latestDir, file), "utf-8");
12308
- } catch {
12309
- }
12310
- }
12311
- }
12312
- }
12461
+ this.sendAutoImplSSE({
12462
+ event: "progress",
12463
+ data: {
12464
+ function: "_init",
12465
+ status: "loading_reference",
12466
+ message: `Loading reference script (${resolvedReference || "none"})...`
12313
12467
  }
12314
- }
12315
- const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment);
12468
+ });
12469
+ const referenceScripts = this.loadAutoImplReferenceScripts(provider.category, resolvedReference);
12470
+ const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
12316
12471
  const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
12317
12472
  if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
12318
12473
  const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
@@ -12330,7 +12485,7 @@ var DevServer = class _DevServer {
12330
12485
  }
12331
12486
  const agentCategory = agentProvider?.category;
12332
12487
  if (agentCategory === "acp") {
12333
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `ACP \uC5D0\uC774\uC804\uD2B8 \uC2E4\uD589 \uC911: ${spawn3.command} ${(spawn3.args || []).join(" ")}` } });
12488
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${spawn3.command} ${(spawn3.args || []).join(" ")}` } });
12334
12489
  this.autoImplStatus = { running: true, type, progress: [] };
12335
12490
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await import("@agentclientprotocol/sdk");
12336
12491
  const { Readable: Readable2, Writable: Writable2 } = await import("stream");
@@ -12417,7 +12572,7 @@ var DevServer = class _DevServer {
12417
12572
  this.autoImplProcess = null;
12418
12573
  this.autoImplStatus.running = false;
12419
12574
  const success = code === 0;
12420
- this.sendAutoImplSSE({ event: "complete", data: { success, exitCode: code, functions, message: success ? "\u2705 ACP Auto-implement \uC644\uB8CC" : `\u274C ACP \uC5D0\uC774\uC804\uD2B8 \uC885\uB8CC (code: ${code})` } });
12575
+ this.sendAutoImplSSE({ event: "complete", data: { success, exitCode: code, functions, message: success ? "\u2705 ACP Auto-implement complete" : `\u274C ACP agent exited (code: ${code})` } });
12421
12576
  try {
12422
12577
  this.providerLoader.reload();
12423
12578
  } catch {
@@ -12432,16 +12587,16 @@ var DevServer = class _DevServer {
12432
12587
  try {
12433
12588
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "initializing", message: "ACP initialize..." } });
12434
12589
  await connection.initialize({ protocolVersion: PROTOCOL_VERSION2, clientCapabilities: {} });
12435
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "session", message: "ACP session \uC0DD\uC131 \uC911..." } });
12590
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "session", message: "Creating ACP session..." } });
12436
12591
  const session = await connection.newSession({ cwd: providerDir, mcpServers: [] });
12437
12592
  const sessionId = session?.sessionId;
12438
12593
  if (!sessionId) throw new Error("No sessionId returned from session/new");
12439
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "prompting", message: `\uD504\uB86C\uD504\uD2B8 \uC804\uC1A1 \uC911 (${prompt.length} chars)...` } });
12594
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "prompting", message: `Sending prompt (${prompt.length} chars)...` } });
12440
12595
  await connection.prompt({
12441
12596
  sessionId,
12442
12597
  prompt: [{ type: "text", text: prompt }]
12443
12598
  });
12444
- this.sendAutoImplSSE({ event: "progress", data: { function: "_done", status: "complete", message: "\u2705 ACP \uD504\uB86C\uD504\uD2B8 \uCC98\uB9AC \uC644\uB8CC" } });
12599
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_done", status: "complete", message: "\u2705 ACP prompt processing complete" } });
12445
12600
  } catch (e) {
12446
12601
  this.sendAutoImplSSE({ event: "output", data: { chunk: `[ACP Error] ${e.message}
12447
12602
  `, stream: "stderr" } });
@@ -12493,7 +12648,7 @@ var DevServer = class _DevServer {
12493
12648
  const escapedArgs = baseArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
12494
12649
  shellCmd = `cat '${promptFile}' | ${command} ${escapedArgs}`;
12495
12650
  }
12496
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `\uC5D0\uC774\uC804\uD2B8 \uC2E4\uD589 \uC911: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
12651
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `Spawning agent: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
12497
12652
  this.autoImplStatus = { running: true, type, progress: [] };
12498
12653
  const spawnedAt = Date.now();
12499
12654
  let child;
@@ -12589,7 +12744,7 @@ var DevServer = class _DevServer {
12589
12744
  const success = code === 0;
12590
12745
  this.sendAutoImplSSE({
12591
12746
  event: "complete",
12592
- data: { success, exitCode: code, functions, message: success ? "\u2705 Auto-implement \uC644\uB8CC" : `\u274C \uC5D0\uC774\uC804\uD2B8 \uC885\uB8CC (code: ${code})` }
12747
+ data: { success, exitCode: code, functions, message: success ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})` }
12593
12748
  });
12594
12749
  try {
12595
12750
  this.providerLoader.reload();
@@ -12624,7 +12779,7 @@ var DevServer = class _DevServer {
12624
12779
  success,
12625
12780
  exitCode: code,
12626
12781
  functions,
12627
- message: success ? "\u2705 Auto-implement \uC644\uB8CC" : `\u274C \uC5D0\uC774\uC804\uD2B8 \uC885\uB8CC (code: ${code})`
12782
+ message: success ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`
12628
12783
  }
12629
12784
  });
12630
12785
  try {
@@ -12652,7 +12807,10 @@ var DevServer = class _DevServer {
12652
12807
  this.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
12653
12808
  }
12654
12809
  }
12655
- buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, userComment) {
12810
+ buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType) {
12811
+ if (provider.category === "cli") {
12812
+ return this.buildCliAutoImplPrompt(type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
12813
+ }
12656
12814
  const lines = [];
12657
12815
  lines.push("You are implementing browser automation scripts for an IDE provider.");
12658
12816
  lines.push("Be concise. Do NOT explain your reasoning. Just edit files directly.");
@@ -12715,7 +12873,7 @@ var DevServer = class _DevServer {
12715
12873
  setMode: "set_mode.js"
12716
12874
  };
12717
12875
  if (Object.keys(referenceScripts).length > 0) {
12718
- lines.push("## Reference Implementation (from Antigravity provider)");
12876
+ lines.push(`## Reference Implementation (from ${referenceType || "antigravity"} provider)`);
12719
12877
  lines.push("These are WORKING scripts from another IDE. Adapt the PATTERNS (not selectors) for the target IDE.");
12720
12878
  lines.push("");
12721
12879
  for (const fn of functions) {
@@ -12864,6 +13022,166 @@ var DevServer = class _DevServer {
12864
13022
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
12865
13023
  return lines.join("\n");
12866
13024
  }
13025
+ buildCliAutoImplPrompt(type, provider, providerDir, functions, referenceScripts, userComment, referenceType) {
13026
+ const lines = [];
13027
+ lines.push("You are implementing PTY parsing scripts for a CLI provider.");
13028
+ lines.push("Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.");
13029
+ lines.push("");
13030
+ lines.push(`# Target: ${provider.name || type} (${type})`);
13031
+ lines.push(`Provider directory: \`${providerDir}\``);
13032
+ lines.push("Provider category: `cli`");
13033
+ lines.push("");
13034
+ lines.push("## Current Target Files");
13035
+ lines.push("These are the files you need to edit. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
13036
+ lines.push("");
13037
+ const scriptsDir = path12.join(providerDir, "scripts");
13038
+ if (fs9.existsSync(scriptsDir)) {
13039
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
13040
+ try {
13041
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
13042
+ } catch {
13043
+ return false;
13044
+ }
13045
+ }).sort().reverse();
13046
+ if (versions.length > 0) {
13047
+ const vDir = path12.join(scriptsDir, versions[0]);
13048
+ lines.push(`Scripts version directory: \`${vDir}\``);
13049
+ lines.push("");
13050
+ for (const file of fs9.readdirSync(vDir)) {
13051
+ if (!file.endsWith(".js")) continue;
13052
+ try {
13053
+ const content = fs9.readFileSync(path12.join(vDir, file), "utf-8");
13054
+ lines.push(`### \`${file}\``);
13055
+ lines.push("```javascript");
13056
+ lines.push(content);
13057
+ lines.push("```");
13058
+ lines.push("");
13059
+ } catch {
13060
+ }
13061
+ }
13062
+ }
13063
+ }
13064
+ const funcToFile = {
13065
+ parseOutput: "parse_output.js",
13066
+ detectStatus: "detect_status.js",
13067
+ parseApproval: "parse_approval.js"
13068
+ };
13069
+ if (Object.keys(referenceScripts).length > 0) {
13070
+ lines.push(`## Reference Implementation (from ${referenceType || "another CLI"} provider)`);
13071
+ lines.push("These are working CLI PTY parser scripts. Reuse the parsing shape and runtime contract, but adapt to the target CLI screen.");
13072
+ lines.push("");
13073
+ for (const fn of functions) {
13074
+ const fileName = funcToFile[fn];
13075
+ if (fileName && referenceScripts[fileName]) {
13076
+ lines.push(`### ${fn} \u2192 \`${fileName}\``);
13077
+ lines.push("```javascript");
13078
+ lines.push(referenceScripts[fileName]);
13079
+ lines.push("```");
13080
+ lines.push("");
13081
+ }
13082
+ }
13083
+ if (referenceScripts["scripts.js"]) {
13084
+ lines.push("### Router \u2192 `scripts.js`");
13085
+ lines.push("```javascript");
13086
+ lines.push(referenceScripts["scripts.js"]);
13087
+ lines.push("```");
13088
+ lines.push("");
13089
+ }
13090
+ }
13091
+ lines.push("## Runtime Contract");
13092
+ lines.push("The daemon runtime is already implemented in `packages/daemon-core/src/cli-adapters/provider-cli-adapter.ts`.");
13093
+ lines.push("Your scripts receive PTY-derived input and must return plain JS objects.");
13094
+ lines.push("");
13095
+ lines.push("| Function | Input | Return |");
13096
+ lines.push("|---|---|---|");
13097
+ lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
13098
+ lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
13099
+ lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
13100
+ lines.push("");
13101
+ lines.push("## Rules");
13102
+ lines.push("1. These scripts run in Node.js CommonJS, not in the browser. Do NOT use DOM APIs.");
13103
+ lines.push("2. Prefer `screenText` for current visible UI state. That is the PTY equivalent of parsing the current IDE DOM.");
13104
+ lines.push("3. Use `messages` as prior transcript state so redraws do not duplicate old turns on every parse.");
13105
+ lines.push("4. Use `partialResponse` for the actively streaming assistant text when status is `generating`.");
13106
+ lines.push("5. `detectStatus` must stay lightweight and tail-based. Do not scan the entire history there.");
13107
+ lines.push("6. `parseApproval` should understand the live approval area and return clean button labels.");
13108
+ lines.push("7. Use `rawBuffer` only when ANSI/control-sequence artifacts matter. Do not depend on raw escape noise unless necessary.");
13109
+ lines.push("8. Keep exports compatible with the existing `scripts.js` router (`module.exports = function ...`).");
13110
+ lines.push("9. Do not rewrite unrelated provider config. Only touch the scripts needed for this task unless a tiny supporting change is required.");
13111
+ lines.push("10. When the verification API returns `instanceId`, keep using that exact instance for follow-up `send`, `resolve`, `raw`, and `stop` calls. Do not assume type-only routing is safe if multiple sessions exist.");
13112
+ lines.push("");
13113
+ lines.push("## Task");
13114
+ lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
13115
+ lines.push("");
13116
+ lines.push("## Verification API");
13117
+ lines.push("Use the DevServer CLI debug endpoints, not DOM/CDP routes.");
13118
+ lines.push("");
13119
+ lines.push("### 1. Launch the target CLI");
13120
+ lines.push("```bash");
13121
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
13122
+ lines.push(' -H "Content-Type: application/json" \\');
13123
+ lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
13124
+ lines.push("```");
13125
+ lines.push("");
13126
+ lines.push("### 2. Inspect parsed + raw adapter state");
13127
+ lines.push("```bash");
13128
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
13129
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
13130
+ lines.push("```");
13131
+ lines.push("");
13132
+ lines.push("Extract the current `instanceId` from the launch or status response and keep using it below.");
13133
+ lines.push("");
13134
+ lines.push("### 3. Send a realistic approval-triggering prompt");
13135
+ lines.push("```bash");
13136
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
13137
+ lines.push(' -H "Content-Type: application/json" \\');
13138
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","text":"Create a file at tmp/adhdev_provider_fix_test.py that prints the current working directory and the squares of 1 through 5, then run python3 tmp/adhdev_provider_fix_test.py and tell me the exact output."}'`);
13139
+ lines.push("```");
13140
+ lines.push("");
13141
+ lines.push("### 4. If approval appears, resolve it until the CLI reaches idle");
13142
+ lines.push("```bash");
13143
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
13144
+ lines.push(' -H "Content-Type: application/json" \\');
13145
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","buttonIndex":0}'`);
13146
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/raw \\`);
13147
+ lines.push(' -H "Content-Type: application/json" \\');
13148
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
13149
+ lines.push("```");
13150
+ lines.push("");
13151
+ lines.push("Use `resolve` when the parsed modal buttons are correct. Use `raw` when the CLI expects a literal keystroke like `1`, `y`, or Enter. Repeat until idle.");
13152
+ lines.push("");
13153
+ lines.push("### 5. Verify the side effects outside the CLI");
13154
+ lines.push("```bash");
13155
+ lines.push("test -f tmp/adhdev_provider_fix_test.py");
13156
+ lines.push("python3 tmp/adhdev_provider_fix_test.py");
13157
+ lines.push("```");
13158
+ lines.push("");
13159
+ lines.push("### 6. Stop the CLI when finished");
13160
+ lines.push("```bash");
13161
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/stop \\`);
13162
+ lines.push(' -H "Content-Type: application/json" \\');
13163
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>"}'`);
13164
+ lines.push("```");
13165
+ lines.push("");
13166
+ lines.push("## Required Validation");
13167
+ lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
13168
+ lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
13169
+ lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
13170
+ lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
13171
+ lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");
13172
+ lines.push("6. Confirm the final assistant transcript includes the exact Python output, including the working directory line and the five square numbers.");
13173
+ lines.push("7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
13174
+ lines.push("");
13175
+ if (userComment) {
13176
+ lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
13177
+ lines.push("The user has provided the following additional instructions. Follow them strictly:");
13178
+ lines.push("");
13179
+ lines.push(userComment);
13180
+ lines.push("");
13181
+ }
13182
+ lines.push("Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.");
13183
+ return lines.join("\n");
13184
+ }
12867
13185
  handleAutoImplSSE(type, req, res) {
12868
13186
  res.writeHead(200, {
12869
13187
  "Content-Type": "text/event-stream",
@@ -12891,7 +13209,7 @@ data: ${JSON.stringify(p.data)}
12891
13209
  setTimeout(() => {
12892
13210
  if (this.autoImplProcess) this.autoImplProcess.kill("SIGKILL");
12893
13211
  }, 3e3);
12894
- this.sendAutoImplSSE({ event: "complete", data: { success: false, exitCode: -1, message: "\u26D4 \uC0AC\uC6A9\uC790\uC5D0 \uC758\uD574 \uC911\uB2E8\uB428" } });
13212
+ this.sendAutoImplSSE({ event: "complete", data: { success: false, exitCode: -1, message: "\u26D4 Aborted by user" } });
12895
13213
  this.autoImplProcess = null;
12896
13214
  this.autoImplStatus.running = false;
12897
13215
  this.json(res, 200, { cancelled: true });
@@ -12974,6 +13292,14 @@ data: ${JSON.stringify(msg.data)}
12974
13292
  }));
12975
13293
  this.json(res, 200, { instances: result, count: result.length });
12976
13294
  }
13295
+ findCliTarget(type, instanceId) {
13296
+ if (!this.instanceManager) return null;
13297
+ const cliStates = this.instanceManager.collectAllStates().filter((s) => s.category === "cli" || s.category === "acp");
13298
+ if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
13299
+ if (!type) return cliStates[cliStates.length - 1] || null;
13300
+ const matches = cliStates.filter((s) => s.type === type);
13301
+ return matches[matches.length - 1] || null;
13302
+ }
12977
13303
  /** POST /api/cli/launch — launch a CLI agent { type, workingDir?, args? } */
12978
13304
  async handleCliLaunch(req, res) {
12979
13305
  if (!this.cliManager) {
@@ -13005,10 +13331,7 @@ data: ${JSON.stringify(msg.data)}
13005
13331
  this.json(res, 400, { error: "text required" });
13006
13332
  return;
13007
13333
  }
13008
- const allStates = this.instanceManager.collectAllStates();
13009
- const target = allStates.find(
13010
- (s) => (s.category === "cli" || s.category === "acp") && (instanceId ? s.instanceId === instanceId : s.type === type)
13011
- );
13334
+ const target = this.findCliTarget(type, instanceId);
13012
13335
  if (!target) {
13013
13336
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
13014
13337
  return;
@@ -13028,10 +13351,7 @@ data: ${JSON.stringify(msg.data)}
13028
13351
  }
13029
13352
  const body = await this.readBody(req);
13030
13353
  const { type, instanceId } = body;
13031
- const allStates = this.instanceManager.collectAllStates();
13032
- const target = allStates.find(
13033
- (s) => (s.category === "cli" || s.category === "acp") && (instanceId ? s.instanceId === instanceId : s.type === type)
13034
- );
13354
+ const target = this.findCliTarget(type, instanceId);
13035
13355
  if (!target) {
13036
13356
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
13037
13357
  return;
@@ -13086,11 +13406,9 @@ data: ${JSON.stringify(msg.data)}
13086
13406
  this.json(res, 503, { error: "InstanceManager not available" });
13087
13407
  return;
13088
13408
  }
13089
- const allStates = this.instanceManager.collectAllStates();
13090
- const target = allStates.find(
13091
- (s) => (s.category === "cli" || s.category === "acp") && s.type === type
13092
- );
13409
+ const target = this.findCliTarget(type);
13093
13410
  if (!target) {
13411
+ const allStates = this.instanceManager.collectAllStates();
13094
13412
  this.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s) => s.category === "cli" || s.category === "acp").map((s) => s.type) });
13095
13413
  return;
13096
13414
  }
@@ -13137,21 +13455,25 @@ data: ${JSON.stringify(msg.data)}
13137
13455
  this.json(res, 503, { error: "CliManager not available" });
13138
13456
  return;
13139
13457
  }
13140
- let adapter = null;
13141
- for (const [, a] of this.cliManager.adapters) {
13142
- if (type && a.cliType === type) {
13143
- adapter = a;
13144
- break;
13145
- }
13458
+ if (!this.instanceManager) {
13459
+ this.json(res, 503, { error: "InstanceManager not available" });
13460
+ return;
13146
13461
  }
13147
- if (!adapter) {
13462
+ const target = this.findCliTarget(type, instanceId);
13463
+ if (!target) {
13148
13464
  this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
13149
13465
  return;
13150
13466
  }
13467
+ const instance = this.instanceManager.getInstance(target.instanceId);
13468
+ const adapter = instance?.getAdapter?.() || instance?.adapter;
13469
+ if (!adapter) {
13470
+ this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
13471
+ return;
13472
+ }
13151
13473
  try {
13152
13474
  if (typeof adapter.resolveModal === "function") {
13153
13475
  adapter.resolveModal(buttonIndex);
13154
- this.json(res, 200, { resolved: true, type, buttonIndex });
13476
+ this.json(res, 200, { resolved: true, type: target.type, instanceId: target.instanceId, buttonIndex });
13155
13477
  } else {
13156
13478
  this.json(res, 400, { error: "resolveModal not available on this adapter" });
13157
13479
  }
@@ -13171,21 +13493,25 @@ data: ${JSON.stringify(msg.data)}
13171
13493
  this.json(res, 503, { error: "CliManager not available" });
13172
13494
  return;
13173
13495
  }
13174
- let adapter = null;
13175
- for (const [, a] of this.cliManager.adapters) {
13176
- if (type && a.cliType === type) {
13177
- adapter = a;
13178
- break;
13179
- }
13496
+ if (!this.instanceManager) {
13497
+ this.json(res, 503, { error: "InstanceManager not available" });
13498
+ return;
13180
13499
  }
13181
- if (!adapter) {
13500
+ const target = this.findCliTarget(type, instanceId);
13501
+ if (!target) {
13182
13502
  this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
13183
13503
  return;
13184
13504
  }
13505
+ const instance = this.instanceManager.getInstance(target.instanceId);
13506
+ const adapter = instance?.getAdapter?.() || instance?.adapter;
13507
+ if (!adapter) {
13508
+ this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
13509
+ return;
13510
+ }
13185
13511
  try {
13186
13512
  if (typeof adapter.writeRaw === "function") {
13187
13513
  adapter.writeRaw(keys);
13188
- this.json(res, 200, { sent: true, type, keysLength: keys.length });
13514
+ this.json(res, 200, { sent: true, type: target.type, instanceId: target.instanceId, keysLength: keys.length });
13189
13515
  } else {
13190
13516
  this.json(res, 400, { error: "writeRaw not available on this adapter" });
13191
13517
  }