@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.
- package/dist/index.d.ts +84 -34
- package/dist/index.js +631 -305
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/providers/_builtin/_helpers/index.js +26 -26
- package/providers/_builtin/cli/aider-cli/provider.json +37 -0
- package/providers/_builtin/cli/aider-cli/scripts/1.0/detect_status.js +20 -0
- package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_approval.js +10 -0
- package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_output.js +49 -0
- package/providers/_builtin/cli/aider-cli/scripts/1.0/scripts.js +7 -0
- package/providers/_builtin/cli/claude-cli/provider.json +9 -2
- package/providers/_builtin/cli/claude-cli/scripts/1.0/detect_status.js +31 -0
- package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_approval.js +38 -0
- package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_output.js +164 -0
- package/providers/_builtin/cli/claude-cli/scripts/1.0/scripts.js +42 -0
- package/providers/_builtin/cli/codex-cli/provider.json +9 -2
- package/providers/_builtin/cli/codex-cli/scripts/1.0/detect_status.js +20 -0
- package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_approval.js +15 -0
- package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_output.js +68 -0
- package/providers/_builtin/cli/codex-cli/scripts/1.0/scripts.js +11 -0
- package/providers/_builtin/cli/cursor-cli/provider.json +37 -0
- package/providers/_builtin/cli/cursor-cli/scripts/1.0/detect_status.js +19 -0
- package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_approval.js +10 -0
- package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_output.js +48 -0
- package/providers/_builtin/cli/cursor-cli/scripts/1.0/scripts.js +7 -0
- package/providers/_builtin/cli/gemini-cli/provider.json +9 -2
- package/providers/_builtin/cli/gemini-cli/scripts/1.0/detect_status.js +26 -0
- package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_approval.js +22 -0
- package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_output.js +71 -0
- package/providers/_builtin/cli/gemini-cli/scripts/1.0/scripts.js +12 -0
- package/providers/_builtin/cli/github-copilot-cli/provider.json +37 -0
- package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/detect_status.js +19 -0
- package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_approval.js +9 -0
- package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_output.js +48 -0
- package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/scripts.js +7 -0
- package/providers/_builtin/cli/goose-cli/provider.json +37 -0
- package/providers/_builtin/cli/goose-cli/scripts/1.0/detect_status.js +20 -0
- package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_approval.js +10 -0
- package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_output.js +48 -0
- package/providers/_builtin/cli/goose-cli/scripts/1.0/scripts.js +7 -0
- package/providers/_builtin/cli/opencode-cli/provider.json +37 -0
- package/providers/_builtin/cli/opencode-cli/scripts/1.0/detect_status.js +15 -0
- package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_approval.js +9 -0
- package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_output.js +48 -0
- package/providers/_builtin/cli/opencode-cli/scripts/1.0/scripts.js +7 -0
- package/providers/_builtin/extension/cline/scripts/1.0/focus_editor.js +5 -5
- package/providers/_builtin/extension/cline/scripts/1.0/list_chats.js +11 -11
- package/providers/_builtin/extension/cline/scripts/1.0/list_models.js +6 -6
- package/providers/_builtin/extension/cline/scripts/1.0/list_modes.js +5 -5
- package/providers/_builtin/extension/cline/scripts/1.0/new_session.js +12 -12
- package/providers/_builtin/extension/cline/scripts/1.0/open_panel.js +7 -7
- package/providers/_builtin/extension/cline/scripts/1.0/read_chat.js +29 -29
- package/providers/_builtin/extension/cline/scripts/1.0/resolve_action.js +19 -19
- package/providers/_builtin/extension/cline/scripts/1.0/send_message.js +15 -15
- package/providers/_builtin/extension/cline/scripts/1.0/set_mode.js +4 -4
- package/providers/_builtin/extension/cline/scripts/1.0/set_model.js +4 -4
- package/providers/_builtin/extension/cline/scripts/1.0/switch_session.js +21 -21
- package/providers/_builtin/extension/codex/scripts/1.0/explore_controls_webview.js +2 -2
- package/providers/_builtin/extension/codex/scripts/1.0/list_models.js +1 -1
- package/providers/_builtin/extension/codex/scripts/1.0/list_modes.js +1 -1
- package/providers/_builtin/extension/codex/scripts/1.0/new_session.js +2 -2
- package/providers/_builtin/extension/codex/scripts/1.0/read_chat.js +6 -6
- package/providers/_builtin/extension/codex/scripts/1.0/resolve_action.js +3 -3
- package/providers/_builtin/extension/codex/scripts/1.0/set_model.js +1 -1
- package/providers/_builtin/ide/antigravity/scripts/1.0/focus_editor.js +2 -2
- package/providers/_builtin/ide/antigravity/scripts/1.0/list_chats.js +19 -19
- package/providers/_builtin/ide/antigravity/scripts/1.0/list_models.js +1 -1
- package/providers/_builtin/ide/antigravity/scripts/1.0/list_modes.js +1 -1
- package/providers/_builtin/ide/antigravity/scripts/1.0/new_session.js +17 -17
- package/providers/_builtin/ide/antigravity/scripts/1.0/read_chat.js +41 -41
- package/providers/_builtin/ide/antigravity/scripts/1.0/resolve_action.js +6 -6
- package/providers/_builtin/ide/antigravity/scripts/1.0/send_message.js +13 -13
- package/providers/_builtin/ide/antigravity/scripts/1.0/set_model.js +1 -1
- package/providers/_builtin/ide/antigravity/scripts/1.0/switch_session.js +13 -13
- package/providers/_builtin/ide/cursor/scripts/1.0/dismiss_notification.js +3 -3
- package/providers/_builtin/ide/cursor/scripts/1.0/focus_editor.js +1 -1
- package/providers/_builtin/ide/cursor/scripts/1.0/list_models.js +12 -12
- package/providers/_builtin/ide/cursor/scripts/1.0/list_modes.js +5 -5
- package/providers/_builtin/ide/cursor/scripts/1.0/list_notifications.js +2 -2
- package/providers/_builtin/ide/cursor/scripts/1.0/list_sessions.js +5 -5
- package/providers/_builtin/ide/cursor/scripts/1.0/new_session.js +1 -1
- package/providers/_builtin/ide/cursor/scripts/1.0/open_panel.js +3 -3
- package/providers/_builtin/ide/cursor/scripts/1.0/read_chat.js +9 -9
- package/providers/_builtin/ide/cursor/scripts/1.0/resolve_action.js +4 -4
- package/providers/_builtin/ide/cursor/scripts/1.0/send_message.js +5 -5
- package/providers/_builtin/ide/cursor/scripts/1.0/set_mode.js +4 -4
- package/providers/_builtin/ide/cursor/scripts/1.0/set_model.js +12 -12
- package/providers/_builtin/ide/cursor/scripts/1.0/switch_session.js +2 -2
- package/providers/_builtin/ide/kiro/scripts/1.0/focus_editor.js +2 -2
- package/providers/_builtin/ide/kiro/scripts/1.0/open_panel.js +7 -7
- package/providers/_builtin/ide/kiro/scripts/1.0/resolve_action.js +3 -3
- package/providers/_builtin/ide/kiro/scripts/1.0/send_message.js +4 -4
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_list_sessions.js +2 -2
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_new_session.js +5 -5
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_read_chat.js +13 -13
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_resolve_action.js +1 -1
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_send_message.js +8 -8
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_mode.js +1 -1
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_model.js +1 -1
- package/providers/_builtin/ide/kiro/scripts/1.0/webview_switch_session.js +3 -3
- package/providers/_builtin/ide/pearai/.tmp/after_rich.json +157 -0
- package/providers/_builtin/ide/pearai/.tmp/after_rich_raw.json +161 -0
- package/providers/_builtin/ide/pearai/.tmp/after_switch.json +592 -0
- package/providers/_builtin/ide/pearai/.tmp/after_switch_raw.json +596 -0
- package/providers/_builtin/ide/pearai/.tmp/home_dump_raw.json +176 -0
- package/providers/_builtin/ide/pearai/.tmp/items_raw.json +778 -0
- package/providers/_builtin/ide/pearai/.tmp/webview_dump.json +157 -0
- package/providers/_builtin/ide/pearai/.tmp/webview_dump_raw.json +161 -0
- package/providers/_builtin/ide/pearai/provider.json +1 -3
- package/providers/_builtin/ide/pearai/scripts/1.0/focus_editor.js +12 -16
- package/providers/_builtin/ide/pearai/scripts/1.0/list_models.js +45 -0
- package/providers/_builtin/ide/pearai/scripts/1.0/list_modes.js +44 -0
- package/providers/_builtin/ide/pearai/scripts/1.0/list_sessions.js +82 -27
- package/providers/_builtin/ide/pearai/scripts/1.0/new_session.js +26 -43
- package/providers/_builtin/ide/pearai/scripts/1.0/open_panel.js +10 -33
- package/providers/_builtin/ide/pearai/scripts/1.0/read_chat.js +169 -0
- package/providers/_builtin/ide/pearai/scripts/1.0/resolve_action.js +47 -41
- package/providers/_builtin/ide/pearai/scripts/1.0/scripts.js +36 -7
- package/providers/_builtin/ide/pearai/scripts/1.0/send_message.js +97 -22
- package/providers/_builtin/ide/pearai/scripts/1.0/set_mode.js +51 -0
- package/providers/_builtin/ide/pearai/scripts/1.0/set_model.js +54 -0
- package/providers/_builtin/ide/pearai/scripts/1.0/switch_session.js +81 -0
- package/providers/_builtin/ide/trae/scripts/1.0/focus_editor.js +2 -2
- package/providers/_builtin/ide/trae/scripts/1.0/list_chats.js +2 -2
- package/providers/_builtin/ide/trae/scripts/1.0/new_session.js +4 -4
- package/providers/_builtin/ide/trae/scripts/1.0/open_panel.js +6 -6
- package/providers/_builtin/ide/trae/scripts/1.0/read_chat.js +13 -13
- package/providers/_builtin/ide/trae/scripts/1.0/resolve_action.js +3 -3
- package/providers/_builtin/ide/trae/scripts/1.0/send_message.js +11 -11
- package/providers/_builtin/ide/trae/scripts/1.0/switch_session.js +2 -2
- package/providers/_builtin/ide/windsurf/scripts/1.0/focus_editor.js +6 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_chats.js +4 -4
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_sessions.js +6 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/new_session.js +9 -9
- package/providers/_builtin/ide/windsurf/scripts/1.0/open_panel.js +6 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/resolve_action.js +8 -8
- package/providers/_builtin/ide/windsurf/scripts/1.0/switch_session.js +8 -8
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/focus_editor.js +6 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_chats.js +12 -12
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/new_session.js +15 -15
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/open_panel.js +10 -10
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/read_chat.js +33 -33
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/resolve_action.js +6 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/send_message.js +16 -16
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/switch_session.js +7 -7
- package/providers/_builtin/registry.json +76 -3
- package/src/cli-adapters/provider-cli-adapter.ts +312 -258
- package/src/cli-adapters/terminal-screen.ts +95 -0
- package/src/commands/chat-commands.ts +41 -15
- package/src/commands/cli-manager.ts +4 -2
- package/src/daemon/dev-server.ts +306 -62
- package/src/providers/acp-provider-instance.ts +1 -1
- package/src/providers/cli-provider-instance.ts +23 -9
- package/src/providers/provider-loader.ts +3 -2
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_models.js +0 -43
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_modes.js +0 -35
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_sessions.js +0 -62
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_new_session.js +0 -49
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_read_chat.js +0 -92
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_resolve_action.js +0 -59
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_send_message.js +0 -72
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_mode.js +0 -36
- package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_model.js +0 -36
- 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
|
|
667
|
-
if (!Array.isArray(raw)) return [
|
|
668
|
-
|
|
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
|
-
|
|
680
|
-
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
862
|
+
// Resolved timeouts
|
|
815
863
|
timeouts;
|
|
816
|
-
// Provider approval key mapping
|
|
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
|
|
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
|
-
|
|
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
|
|
941
|
-
|
|
1004
|
+
const scriptStatus = this.runDetectStatus(this.startupBuffer);
|
|
1005
|
+
const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
|
|
1006
|
+
if (isReady) {
|
|
942
1007
|
this.startupParseGate = false;
|
|
943
|
-
|
|
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
|
-
},
|
|
1025
|
+
}, delay);
|
|
1001
1026
|
}
|
|
1002
1027
|
evaluateSettled() {
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
if (
|
|
1006
|
-
|
|
1007
|
-
|
|
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", "
|
|
1039
|
-
|
|
1040
|
-
this.
|
|
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-
|
|
1043
|
+
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1050
1044
|
this.activeModal = null;
|
|
1051
1045
|
this.lastApprovalResolvedAt = Date.now();
|
|
1052
|
-
this.
|
|
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 (
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
this.
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
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
|
-
// ───
|
|
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
|
|
1127
|
-
|
|
1128
|
-
if (this.
|
|
1129
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1226
|
-
startupBuffer:
|
|
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
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
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
|
-
|
|
1239
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
6794
|
-
const
|
|
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
|
|
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
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
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
|
-
|
|
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 >
|
|
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
|
-
|
|
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
|
|
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.
|
|
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({
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13143
|
-
adapter = a;
|
|
13144
|
-
break;
|
|
13145
|
-
}
|
|
13458
|
+
if (!this.instanceManager) {
|
|
13459
|
+
this.json(res, 503, { error: "InstanceManager not available" });
|
|
13460
|
+
return;
|
|
13146
13461
|
}
|
|
13147
|
-
|
|
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
|
-
|
|
13175
|
-
|
|
13176
|
-
|
|
13177
|
-
adapter = a;
|
|
13178
|
-
break;
|
|
13179
|
-
}
|
|
13496
|
+
if (!this.instanceManager) {
|
|
13497
|
+
this.json(res, 503, { error: "InstanceManager not available" });
|
|
13498
|
+
return;
|
|
13180
13499
|
}
|
|
13181
|
-
|
|
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
|
}
|