@adhdev/daemon-core 0.6.55 → 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 CHANGED
@@ -2575,6 +2575,8 @@ interface CliScripts {
2575
2575
  /** Lightweight status detection (high-frequency polling) → AgentStatus string */
2576
2576
  detectStatus?: (input: {
2577
2577
  tail: string;
2578
+ screenText?: string;
2579
+ rawBuffer?: string;
2578
2580
  }) => string | null;
2579
2581
  /** Parse approval modal from PTY output → ModalInfo | null */
2580
2582
  parseApproval?: (input: {
@@ -2603,6 +2605,8 @@ interface CliProviderModule {
2603
2605
  name: string;
2604
2606
  category: 'cli';
2605
2607
  binary: string;
2608
+ sendDelayMs?: number;
2609
+ sendKey?: string;
2606
2610
  spawn: {
2607
2611
  command: string;
2608
2612
  args: string[];
@@ -2659,6 +2663,7 @@ declare class ProviderCliAdapter implements CliAdapter {
2659
2663
  private approvalExitTimeout;
2660
2664
  private settleTimer;
2661
2665
  private settledBuffer;
2666
+ private submitPendingUntil;
2662
2667
  private resizeSuppressUntil;
2663
2668
  private statusHistory;
2664
2669
  private cliScripts;
@@ -2673,6 +2678,8 @@ declare class ProviderCliAdapter implements CliAdapter {
2673
2678
  private setStatus;
2674
2679
  private readonly timeouts;
2675
2680
  private readonly approvalKeys;
2681
+ private readonly sendDelayMs;
2682
+ private readonly sendKey;
2676
2683
  constructor(provider: CliProviderModule, workingDir: string, extraArgs?: string[]);
2677
2684
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
2678
2685
  setCliScripts(scripts: CliScripts): void;
@@ -2957,6 +2964,7 @@ declare class DevServer {
2957
2964
  private readBody;
2958
2965
  /** GET /api/cli/status — list all running CLI/ACP instances with state */
2959
2966
  private handleCliStatus;
2967
+ private findCliTarget;
2960
2968
  /** POST /api/cli/launch — launch a CLI agent { type, workingDir?, args? } */
2961
2969
  private handleCliLaunch;
2962
2970
  /** POST /api/cli/send — send message to a running CLI { type, text } */
package/dist/index.js CHANGED
@@ -592,240 +592,67 @@ var init_logger = __esm({
592
592
  });
593
593
 
594
594
  // src/cli-adapters/terminal-screen.ts
595
- function clamp(value, min, max) {
596
- return Math.max(min, Math.min(max, value));
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;
597
604
  }
598
- var TerminalScreen;
605
+ var TerminalCtor, TerminalScreen;
599
606
  var init_terminal_screen = __esm({
600
607
  "src/cli-adapters/terminal-screen.ts"() {
601
608
  "use strict";
609
+ TerminalCtor = null;
602
610
  TerminalScreen = class {
603
611
  rows;
604
612
  cols;
605
- cursorRow = 0;
606
- cursorCol = 0;
607
- savedRow = 0;
608
- savedCol = 0;
609
- lines;
613
+ terminal;
610
614
  constructor(rows = 40, cols = 120) {
611
- this.rows = rows;
612
- this.cols = cols;
613
- this.lines = this.makeLines(rows, cols);
615
+ this.rows = Math.max(1, rows | 0);
616
+ this.cols = Math.max(1, cols | 0);
617
+ this.terminal = this.createTerminal();
614
618
  }
615
619
  reset(rows = this.rows, cols = this.cols) {
616
- this.rows = rows;
617
- this.cols = cols;
618
- this.cursorRow = 0;
619
- this.cursorCol = 0;
620
- this.savedRow = 0;
621
- this.savedCol = 0;
622
- this.lines = this.makeLines(rows, 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();
623
624
  }
624
625
  resize(rows, cols) {
625
- const nextRows = Math.max(1, rows | 0);
626
- const nextCols = Math.max(1, cols | 0);
627
- const next = this.makeLines(nextRows, nextCols);
628
- const copyRows = Math.min(this.rows, nextRows);
629
- const copyCols = Math.min(this.cols, nextCols);
630
- for (let r = 0; r < copyRows; r++) {
631
- for (let c = 0; c < copyCols; c++) {
632
- next[r][c] = this.lines[r][c];
633
- }
634
- }
635
- this.rows = nextRows;
636
- this.cols = nextCols;
637
- this.lines = next;
638
- this.cursorRow = clamp(this.cursorRow, 0, this.rows - 1);
639
- this.cursorCol = clamp(this.cursorCol, 0, this.cols - 1);
640
- this.savedRow = clamp(this.savedRow, 0, this.rows - 1);
641
- this.savedCol = clamp(this.savedCol, 0, this.cols - 1);
626
+ this.rows = Math.max(1, rows | 0);
627
+ this.cols = Math.max(1, cols | 0);
628
+ this.terminal.resize(this.cols, this.rows);
642
629
  }
643
630
  write(data) {
644
- let i = 0;
645
- while (i < data.length) {
646
- const ch = data[i];
647
- if (ch === "\x1B") {
648
- const consumed = this.consumeEscape(data, i);
649
- i = consumed > i ? consumed : i + 1;
650
- continue;
651
- }
652
- if (ch === "\r") {
653
- this.cursorCol = 0;
654
- i++;
655
- continue;
656
- }
657
- if (ch === "\n") {
658
- this.newLine();
659
- i++;
660
- continue;
661
- }
662
- if (ch === "\b") {
663
- this.cursorCol = Math.max(0, this.cursorCol - 1);
664
- i++;
665
- continue;
666
- }
667
- if (ch === " ") {
668
- const nextStop = Math.min(this.cols - 1, this.cursorCol + (8 - (this.cursorCol % 8 || 8)));
669
- while (this.cursorCol < nextStop) this.putChar(" ");
670
- i++;
671
- continue;
672
- }
673
- if (ch >= " " && ch !== "\x7F") {
674
- this.putChar(ch);
675
- }
676
- i++;
677
- }
631
+ if (!data) return;
632
+ this.terminal.write(data);
678
633
  }
679
634
  getText() {
680
- const raw = this.lines.map((line) => line.join("").replace(/\s+$/, ""));
681
- let start = 0;
682
- let end = raw.length;
683
- while (start < end && raw[start] === "") start++;
684
- while (end > start && raw[end - 1] === "") end--;
685
- return raw.slice(start, end).join("\n");
686
- }
687
- consumeEscape(data, start) {
688
- const next = data[start + 1];
689
- if (!next) return start + 1;
690
- if (next === "[") {
691
- let end = start + 2;
692
- while (end < data.length && !/[@-~]/.test(data[end])) end++;
693
- if (end >= data.length) return data.length;
694
- this.applyCsi(data.slice(start + 2, end), data[end]);
695
- return end + 1;
696
- }
697
- if (next === "]") {
698
- let end = start + 2;
699
- while (end < data.length) {
700
- if (data[end] === "\x07") return end + 1;
701
- if (data[end] === "\x1B" && data[end + 1] === "\\") return end + 2;
702
- end++;
703
- }
704
- return data.length;
705
- }
706
- if (next === "7") {
707
- this.savedRow = this.cursorRow;
708
- this.savedCol = this.cursorCol;
709
- return start + 2;
710
- }
711
- if (next === "8") {
712
- this.cursorRow = this.savedRow;
713
- this.cursorCol = this.savedCol;
714
- return start + 2;
715
- }
716
- return start + 2;
717
- }
718
- applyCsi(paramText, finalChar) {
719
- const privateMode = paramText.startsWith("?");
720
- const normalized = privateMode ? paramText.slice(1) : paramText;
721
- const params = normalized.length > 0 ? normalized.split(";").map((p) => parseInt(p || "0", 10) || 0) : [0];
722
- switch (finalChar) {
723
- case "A":
724
- this.cursorRow = clamp(this.cursorRow - (params[0] || 1), 0, this.rows - 1);
725
- return;
726
- case "B":
727
- this.cursorRow = clamp(this.cursorRow + (params[0] || 1), 0, this.rows - 1);
728
- return;
729
- case "C":
730
- this.cursorCol = clamp(this.cursorCol + (params[0] || 1), 0, this.cols - 1);
731
- return;
732
- case "D":
733
- this.cursorCol = clamp(this.cursorCol - (params[0] || 1), 0, this.cols - 1);
734
- return;
735
- case "E":
736
- this.cursorRow = clamp(this.cursorRow + (params[0] || 1), 0, this.rows - 1);
737
- this.cursorCol = 0;
738
- return;
739
- case "F":
740
- this.cursorRow = clamp(this.cursorRow - (params[0] || 1), 0, this.rows - 1);
741
- this.cursorCol = 0;
742
- return;
743
- case "G":
744
- this.cursorCol = clamp((params[0] || 1) - 1, 0, this.cols - 1);
745
- return;
746
- case "H":
747
- case "f": {
748
- const row = (params[0] || 1) - 1;
749
- const col = (params[1] || 1) - 1;
750
- this.cursorRow = clamp(row, 0, this.rows - 1);
751
- this.cursorCol = clamp(col, 0, this.cols - 1);
752
- return;
753
- }
754
- case "J": {
755
- const mode = params[0] || 0;
756
- if (mode === 2 || mode === 3) {
757
- this.reset(this.rows, this.cols);
758
- } else if (mode === 0) {
759
- this.clearToEndOfScreen();
760
- } else if (mode === 1) {
761
- this.clearToStartOfScreen();
762
- }
763
- return;
764
- }
765
- case "K": {
766
- const mode = params[0] || 0;
767
- if (mode === 2) this.clearLine(this.cursorRow, 0, this.cols - 1);
768
- else if (mode === 1) this.clearLine(this.cursorRow, 0, this.cursorCol);
769
- else this.clearLine(this.cursorRow, this.cursorCol, this.cols - 1);
770
- return;
771
- }
772
- case "m":
773
- return;
774
- case "s":
775
- this.savedRow = this.cursorRow;
776
- this.savedCol = this.cursorCol;
777
- return;
778
- case "u":
779
- this.cursorRow = this.savedRow;
780
- this.cursorCol = this.savedCol;
781
- return;
782
- case "h":
783
- case "l":
784
- if (privateMode && (normalized === "1049" || normalized === "47")) {
785
- this.reset(this.rows, this.cols);
786
- }
787
- return;
788
- default:
789
- return;
790
- }
791
- }
792
- putChar(ch) {
793
- if (this.cursorRow < 0 || this.cursorRow >= this.rows) return;
794
- if (this.cursorCol < 0) this.cursorCol = 0;
795
- if (this.cursorCol >= this.cols) this.newLine();
796
- this.lines[this.cursorRow][this.cursorCol] = ch;
797
- this.cursorCol++;
798
- if (this.cursorCol >= this.cols) this.newLine();
799
- }
800
- newLine() {
801
- this.cursorCol = 0;
802
- if (this.cursorRow >= this.rows - 1) {
803
- this.lines.shift();
804
- this.lines.push(Array.from({ length: this.cols }, () => " "));
805
- } else {
806
- this.cursorRow++;
807
- }
808
- }
809
- clearLine(row, start, end) {
810
- if (row < 0 || row >= this.rows) return;
811
- for (let c = clamp(start, 0, this.cols - 1); c <= clamp(end, 0, this.cols - 1); c++) {
812
- this.lines[row][c] = " ";
813
- }
814
- }
815
- clearToEndOfScreen() {
816
- this.clearLine(this.cursorRow, this.cursorCol, this.cols - 1);
817
- for (let r = this.cursorRow + 1; r < this.rows; r++) {
818
- this.clearLine(r, 0, this.cols - 1);
819
- }
820
- }
821
- clearToStartOfScreen() {
822
- for (let r = 0; r < this.cursorRow; r++) {
823
- this.clearLine(r, 0, this.cols - 1);
824
- }
825
- this.clearLine(this.cursorRow, 0, this.cursorCol);
826
- }
827
- makeLines(rows, cols) {
828
- return Array.from({ length: rows }, () => Array.from({ length: cols }, () => " "));
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
+ });
829
656
  }
830
657
  };
831
658
  }
@@ -965,6 +792,8 @@ var init_provider_cli_adapter = __esm({
965
792
  };
966
793
  const rawKeys = provider.approvalKeys;
967
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";
968
797
  this.cliScripts = provider.scripts || {};
969
798
  const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
970
799
  if (scriptNames.length > 0) {
@@ -1007,6 +836,7 @@ var init_provider_cli_adapter = __esm({
1007
836
  // Output settle debounce — fires after PTY output goes quiet
1008
837
  settleTimer = null;
1009
838
  settledBuffer = "";
839
+ submitPendingUntil = 0;
1010
840
  // Resize redraw suppression
1011
841
  resizeSuppressUntil = 0;
1012
842
  // Debug: status transition history
@@ -1033,6 +863,8 @@ var init_provider_cli_adapter = __esm({
1033
863
  timeouts;
1034
864
  // Provider approval key mapping
1035
865
  approvalKeys;
866
+ sendDelayMs;
867
+ sendKey;
1036
868
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
1037
869
  setCliScripts(scripts) {
1038
870
  this.cliScripts = scripts;
@@ -1135,6 +967,9 @@ var init_provider_cli_adapter = __esm({
1135
967
  // ─── Output Handling ────────────────────────────
1136
968
  handleOutput(rawData) {
1137
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
+ }
1138
973
  this.terminalScreen.write(rawData);
1139
974
  const cleanData = stripAnsi(rawData);
1140
975
  if (this.isWaitingForResponse && cleanData) {
@@ -1179,11 +1014,15 @@ var init_provider_cli_adapter = __esm({
1179
1014
  }
1180
1015
  scheduleSettle() {
1181
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
+ );
1182
1021
  this.settleTimer = setTimeout(() => {
1183
1022
  this.settleTimer = null;
1184
1023
  this.settledBuffer = this.recentOutputBuffer;
1185
1024
  this.evaluateSettled();
1186
- }, this.timeouts.outputSettle);
1025
+ }, delay);
1187
1026
  }
1188
1027
  evaluateSettled() {
1189
1028
  const tail = this.settledBuffer;
@@ -1273,7 +1112,11 @@ var init_provider_cli_adapter = __esm({
1273
1112
  runDetectStatus(text) {
1274
1113
  if (!this.cliScripts?.detectStatus) return null;
1275
1114
  try {
1276
- return this.cliScripts.detectStatus({ tail: text.slice(-500) });
1115
+ return this.cliScripts.detectStatus({
1116
+ tail: text.slice(-500),
1117
+ screenText: this.terminalScreen.getText(),
1118
+ rawBuffer: this.accumulatedRawBuffer
1119
+ });
1277
1120
  } catch (e) {
1278
1121
  LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
1279
1122
  return null;
@@ -1383,10 +1226,21 @@ ${data.message || ""}`.trim();
1383
1226
  this.responseBuffer = "";
1384
1227
  this.setStatus("generating", "sendMessage");
1385
1228
  this.onStatusChange?.();
1386
- this.ptyProcess.write(text + "\r");
1387
- this.responseTimeout = setTimeout(() => {
1388
- if (this.isWaitingForResponse) this.finishResponse();
1389
- }, 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
+ }
1390
1244
  }
1391
1245
  getPartialResponse() {
1392
1246
  if (!this.isWaitingForResponse) return "";
@@ -1469,10 +1323,14 @@ ${data.message || ""}`.trim();
1469
1323
  messages: this.messages.slice(-20),
1470
1324
  structuredMessages: this.structuredMessages.slice(-20),
1471
1325
  messageCount: this.messages.length,
1326
+ screenText: this.terminalScreen.getText().slice(-4e3),
1472
1327
  startupBuffer: this.startupBuffer.slice(-4e3),
1473
1328
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
1474
1329
  settledBuffer: this.settledBuffer.slice(-500),
1475
1330
  accumulatedBufferLength: this.accumulatedBuffer.length,
1331
+ accumulatedRawBufferLength: this.accumulatedRawBuffer.length,
1332
+ rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
1333
+ responseBuffer: this.responseBuffer.slice(-1e3),
1476
1334
  isWaitingForResponse: this.isWaitingForResponse,
1477
1335
  activeModal: this.activeModal,
1478
1336
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
@@ -8137,7 +7995,8 @@ var CliProviderInstance = class {
8137
7995
  return { ...m, content };
8138
7996
  });
8139
7997
  const partial = this.adapter.getPartialResponse();
8140
- if (adapterStatus.status === "generating" && partial) {
7998
+ const shouldAppendRawPartial = !parsedStatus;
7999
+ if (shouldAppendRawPartial && adapterStatus.status === "generating" && partial) {
8141
8000
  const cleaned = partial.trim();
8142
8001
  if (cleaned && cleaned !== "(generating...)") {
8143
8002
  recentMessages.push({
@@ -13236,7 +13095,7 @@ var DevServer = class _DevServer {
13236
13095
  lines.push("| Function | Input | Return |");
13237
13096
  lines.push("|---|---|---|");
13238
13097
  lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
13239
- lines.push("| `detectStatus` | `{ tail }` | `idle`, `generating`, `waiting_approval`, or `error` |");
13098
+ lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
13240
13099
  lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
13241
13100
  lines.push("");
13242
13101
  lines.push("## Rules");
@@ -13249,6 +13108,7 @@ var DevServer = class _DevServer {
13249
13108
  lines.push("7. Use `rawBuffer` only when ANSI/control-sequence artifacts matter. Do not depend on raw escape noise unless necessary.");
13250
13109
  lines.push("8. Keep exports compatible with the existing `scripts.js` router (`module.exports = function ...`).");
13251
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.");
13252
13112
  lines.push("");
13253
13113
  lines.push("## Task");
13254
13114
  lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
@@ -13269,25 +13129,38 @@ var DevServer = class _DevServer {
13269
13129
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
13270
13130
  lines.push("```");
13271
13131
  lines.push("");
13272
- lines.push("### 3. Send a rich test prompt");
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");
13273
13135
  lines.push("```bash");
13274
13136
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
13275
13137
  lines.push(' -H "Content-Type: application/json" \\');
13276
- lines.push(` -d '{"type":"${type}","text":"Write a short python snippet, include a markdown table, and briefly explain what you did."}'`);
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."}'`);
13277
13139
  lines.push("```");
13278
13140
  lines.push("");
13279
- lines.push("### 4. If approval appears, resolve it");
13141
+ lines.push("### 4. If approval appears, resolve it until the CLI reaches idle");
13280
13142
  lines.push("```bash");
13281
13143
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
13282
13144
  lines.push(' -H "Content-Type: application/json" \\');
13283
- lines.push(` -d '{"type":"${type}","buttonIndex":0}'`);
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");
13284
13157
  lines.push("```");
13285
13158
  lines.push("");
13286
- lines.push("### 5. Stop the CLI when finished");
13159
+ lines.push("### 6. Stop the CLI when finished");
13287
13160
  lines.push("```bash");
13288
13161
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/stop \\`);
13289
13162
  lines.push(' -H "Content-Type: application/json" \\');
13290
- lines.push(` -d '{"type":"${type}"}'`);
13163
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>"}'`);
13291
13164
  lines.push("```");
13292
13165
  lines.push("");
13293
13166
  lines.push("## Required Validation");
@@ -13295,7 +13168,9 @@ var DevServer = class _DevServer {
13295
13168
  lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
13296
13169
  lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
13297
13170
  lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
13298
- lines.push("5. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
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.");
13299
13174
  lines.push("");
13300
13175
  if (userComment) {
13301
13176
  lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
@@ -13417,6 +13292,14 @@ data: ${JSON.stringify(msg.data)}
13417
13292
  }));
13418
13293
  this.json(res, 200, { instances: result, count: result.length });
13419
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
+ }
13420
13303
  /** POST /api/cli/launch — launch a CLI agent { type, workingDir?, args? } */
13421
13304
  async handleCliLaunch(req, res) {
13422
13305
  if (!this.cliManager) {
@@ -13448,10 +13331,7 @@ data: ${JSON.stringify(msg.data)}
13448
13331
  this.json(res, 400, { error: "text required" });
13449
13332
  return;
13450
13333
  }
13451
- const allStates = this.instanceManager.collectAllStates();
13452
- const target = allStates.find(
13453
- (s) => (s.category === "cli" || s.category === "acp") && (instanceId ? s.instanceId === instanceId : s.type === type)
13454
- );
13334
+ const target = this.findCliTarget(type, instanceId);
13455
13335
  if (!target) {
13456
13336
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
13457
13337
  return;
@@ -13471,10 +13351,7 @@ data: ${JSON.stringify(msg.data)}
13471
13351
  }
13472
13352
  const body = await this.readBody(req);
13473
13353
  const { type, instanceId } = body;
13474
- const allStates = this.instanceManager.collectAllStates();
13475
- const target = allStates.find(
13476
- (s) => (s.category === "cli" || s.category === "acp") && (instanceId ? s.instanceId === instanceId : s.type === type)
13477
- );
13354
+ const target = this.findCliTarget(type, instanceId);
13478
13355
  if (!target) {
13479
13356
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
13480
13357
  return;
@@ -13529,11 +13406,9 @@ data: ${JSON.stringify(msg.data)}
13529
13406
  this.json(res, 503, { error: "InstanceManager not available" });
13530
13407
  return;
13531
13408
  }
13532
- const allStates = this.instanceManager.collectAllStates();
13533
- const target = allStates.find(
13534
- (s) => (s.category === "cli" || s.category === "acp") && s.type === type
13535
- );
13409
+ const target = this.findCliTarget(type);
13536
13410
  if (!target) {
13411
+ const allStates = this.instanceManager.collectAllStates();
13537
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) });
13538
13413
  return;
13539
13414
  }
@@ -13580,21 +13455,25 @@ data: ${JSON.stringify(msg.data)}
13580
13455
  this.json(res, 503, { error: "CliManager not available" });
13581
13456
  return;
13582
13457
  }
13583
- let adapter = null;
13584
- for (const [, a] of this.cliManager.adapters) {
13585
- if (type && a.cliType === type) {
13586
- adapter = a;
13587
- break;
13588
- }
13458
+ if (!this.instanceManager) {
13459
+ this.json(res, 503, { error: "InstanceManager not available" });
13460
+ return;
13589
13461
  }
13590
- if (!adapter) {
13462
+ const target = this.findCliTarget(type, instanceId);
13463
+ if (!target) {
13591
13464
  this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
13592
13465
  return;
13593
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
+ }
13594
13473
  try {
13595
13474
  if (typeof adapter.resolveModal === "function") {
13596
13475
  adapter.resolveModal(buttonIndex);
13597
- this.json(res, 200, { resolved: true, type, buttonIndex });
13476
+ this.json(res, 200, { resolved: true, type: target.type, instanceId: target.instanceId, buttonIndex });
13598
13477
  } else {
13599
13478
  this.json(res, 400, { error: "resolveModal not available on this adapter" });
13600
13479
  }
@@ -13614,21 +13493,25 @@ data: ${JSON.stringify(msg.data)}
13614
13493
  this.json(res, 503, { error: "CliManager not available" });
13615
13494
  return;
13616
13495
  }
13617
- let adapter = null;
13618
- for (const [, a] of this.cliManager.adapters) {
13619
- if (type && a.cliType === type) {
13620
- adapter = a;
13621
- break;
13622
- }
13496
+ if (!this.instanceManager) {
13497
+ this.json(res, 503, { error: "InstanceManager not available" });
13498
+ return;
13623
13499
  }
13624
- if (!adapter) {
13500
+ const target = this.findCliTarget(type, instanceId);
13501
+ if (!target) {
13625
13502
  this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
13626
13503
  return;
13627
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
+ }
13628
13511
  try {
13629
13512
  if (typeof adapter.writeRaw === "function") {
13630
13513
  adapter.writeRaw(keys);
13631
- 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 });
13632
13515
  } else {
13633
13516
  this.json(res, 400, { error: "writeRaw not available on this adapter" });
13634
13517
  }