adhdev 0.6.53 → 0.6.55

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.js CHANGED
@@ -3173,6 +3173,9 @@ var init_builders = __esm({
3173
3173
  });
3174
3174
 
3175
3175
  // ../daemon-core/src/commands/chat-commands.ts
3176
+ function getTargetedCliAdapter(h, args, providerType) {
3177
+ return h.getCliAdapter(args?._targetInstance || h.currentIdeType || providerType);
3178
+ }
3176
3179
  async function handleChatHistory(h, args) {
3177
3180
  const { agentType, offset, limit, instanceId } = args;
3178
3181
  try {
@@ -3185,10 +3188,10 @@ async function handleChatHistory(h, args) {
3185
3188
  }
3186
3189
  }
3187
3190
  async function handleReadChat(h, args) {
3188
- const provider = h.getProvider();
3191
+ const provider = h.getProvider(args?.agentType);
3189
3192
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
3190
3193
  if (provider?.category === "cli" || provider?.category === "acp") {
3191
- const adapter = h.getCliAdapter(provider.type);
3194
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3192
3195
  if (adapter) {
3193
3196
  _log(`${provider.category} adapter: ${adapter.cliType}`);
3194
3197
  const status = adapter.getStatus?.();
@@ -3304,7 +3307,7 @@ async function handleSendChat(h, args) {
3304
3307
  const text = args?.text || args?.message;
3305
3308
  if (!text) return { success: false, error: "text required" };
3306
3309
  const _log = (msg) => LOG.debug("Command", `[send_chat] ${msg}`);
3307
- const provider = h.getProvider();
3310
+ const provider = h.getProvider(args?.agentType);
3308
3311
  const _logSendSuccess = (method, targetAgent) => {
3309
3312
  h.historyWriter.appendNewMessages(
3310
3313
  targetAgent || provider?.type || h.currentIdeType || "unknown_agent",
@@ -3316,7 +3319,7 @@ async function handleSendChat(h, args) {
3316
3319
  return { success: true, sent: true, method, targetAgent };
3317
3320
  };
3318
3321
  if (provider?.category === "cli" || provider?.category === "acp") {
3319
- const adapter = h.getCliAdapter(provider.type);
3322
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3320
3323
  if (adapter) {
3321
3324
  _log(`${provider.category} adapter: ${adapter.cliType}`);
3322
3325
  try {
@@ -3469,7 +3472,7 @@ async function handleSendChat(h, args) {
3469
3472
  return { success: false, error: "No provider method could send the message" };
3470
3473
  }
3471
3474
  async function handleListChats(h, args) {
3472
- const provider = h.getProvider();
3475
+ const provider = h.getProvider(args?.agentType);
3473
3476
  if (provider?.category === "extension" && h.agentStream && h.getCdp()) {
3474
3477
  try {
3475
3478
  const chats = await h.agentStream.listAgentChats(h.getCdp(), provider.type);
@@ -3521,7 +3524,16 @@ async function handleListChats(h, args) {
3521
3524
  return { success: false, error: "listSessions script not available for this provider" };
3522
3525
  }
3523
3526
  async function handleNewChat(h, args) {
3524
- const provider = h.getProvider();
3527
+ const provider = h.getProvider(args?.agentType);
3528
+ if (provider?.category === "cli") {
3529
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3530
+ if (!adapter) return { success: false, error: "CLI adapter not running" };
3531
+ if (typeof adapter.clearHistory === "function") {
3532
+ adapter.clearHistory();
3533
+ return { success: true, cleared: true };
3534
+ }
3535
+ return { success: false, error: "new_chat not supported by this CLI provider" };
3536
+ }
3525
3537
  if (provider?.category === "extension" && h.agentStream && h.getCdp()) {
3526
3538
  const ok = await h.agentStream.newAgentSession(h.getCdp(), provider.type, h.currentIdeType);
3527
3539
  return { success: ok };
@@ -3546,7 +3558,7 @@ async function handleNewChat(h, args) {
3546
3558
  return { success: false, error: "newSession script not available for this provider" };
3547
3559
  }
3548
3560
  async function handleSwitchChat(h, args) {
3549
- const provider = h.getProvider();
3561
+ const provider = h.getProvider(args?.agentType);
3550
3562
  const ideType = h.currentIdeType;
3551
3563
  const sessionId = args?.sessionId || args?.id || args?.chatId;
3552
3564
  if (!sessionId) return { success: false, error: "sessionId required" };
@@ -3640,10 +3652,10 @@ async function handleSwitchChat(h, args) {
3640
3652
  }
3641
3653
  }
3642
3654
  async function handleSetMode(h, args) {
3643
- const provider = h.getProvider();
3655
+ const provider = h.getProvider(args?.agentType);
3644
3656
  const mode = args?.mode || "agent";
3645
3657
  if (provider?.category === "acp") {
3646
- const adapter = h.getCliAdapter(provider.type);
3658
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3647
3659
  if (adapter) {
3648
3660
  const acpInstance = adapter._acpInstance;
3649
3661
  if (acpInstance && typeof acpInstance.onEvent === "function") {
@@ -3695,11 +3707,11 @@ async function handleSetMode(h, args) {
3695
3707
  return { success: false, error: `setMode '${mode}' not supported by this provider` };
3696
3708
  }
3697
3709
  async function handleChangeModel(h, args) {
3698
- const provider = h.getProvider();
3710
+ const provider = h.getProvider(args?.agentType);
3699
3711
  const model = args?.model;
3700
3712
  LOG.info("Command", `[change_model] model=${model} provider=${provider?.type} category=${provider?.category} ideType=${h.currentIdeType} providerType=${h.currentProviderType}`);
3701
3713
  if (provider?.category === "acp") {
3702
- const adapter = h.getCliAdapter(provider.type);
3714
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3703
3715
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
3704
3716
  if (adapter) {
3705
3717
  const acpInstance = adapter._acpInstance;
@@ -3756,11 +3768,11 @@ async function handleSetThoughtLevel(h, args) {
3756
3768
  const configId = args?.configId;
3757
3769
  const value = args?.value;
3758
3770
  if (!configId || !value) return { success: false, error: "configId and value required" };
3759
- const provider = h.getProvider();
3771
+ const provider = h.getProvider(args?.agentType);
3760
3772
  if (!provider || provider.category !== "acp") {
3761
3773
  return { success: false, error: "set_thought_level only for ACP providers" };
3762
3774
  }
3763
- const adapter = h.getCliAdapter(provider.type);
3775
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3764
3776
  const acpInstance = adapter?._acpInstance;
3765
3777
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
3766
3778
  try {
@@ -3772,13 +3784,22 @@ async function handleSetThoughtLevel(h, args) {
3772
3784
  }
3773
3785
  }
3774
3786
  async function handleResolveAction(h, args) {
3775
- const provider = h.getProvider();
3787
+ const provider = h.getProvider(args?.agentType);
3776
3788
  const action = args?.action || "approve";
3777
3789
  const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
3778
3790
  LOG.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider?.type}`);
3779
3791
  if (provider?.category === "cli") {
3780
- const adapter = h.getCliAdapter(provider.type);
3792
+ const adapter = getTargetedCliAdapter(h, args, provider.type);
3781
3793
  if (!adapter) return { success: false, error: "CLI adapter not running" };
3794
+ if (args?.data && typeof adapter.resolveAction === "function") {
3795
+ try {
3796
+ await adapter.resolveAction(args.data);
3797
+ LOG.info("Command", `[resolveAction] CLI PTY \u2192 resolveAction triggered with data payload`);
3798
+ return { success: true, method: "cli-resolve-action" };
3799
+ } catch (e) {
3800
+ return { success: false, error: `CLI resolveAction failed: ${e.message}` };
3801
+ }
3802
+ }
3782
3803
  const status = adapter.getStatus?.();
3783
3804
  if (status?.status !== "waiting_approval") {
3784
3805
  return { success: false, error: "Not in approval state" };
@@ -6015,8 +6036,9 @@ var init_provider_loader = __esm({
6015
6036
  }
6016
6037
  }
6017
6038
  compareVersions(a, b) {
6018
- const pa = a.split(".").map(Number);
6019
- const pb = b.split(".").map(Number);
6039
+ const normalize2 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
6040
+ const pa = normalize2(a);
6041
+ const pb = normalize2(b);
6020
6042
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
6021
6043
  const va = pa[i] || 0;
6022
6044
  const vb = pb[i] || 0;
@@ -7040,6 +7062,246 @@ var init_reporter = __esm({
7040
7062
  }
7041
7063
  });
7042
7064
 
7065
+ // ../daemon-core/src/cli-adapters/terminal-screen.ts
7066
+ function clamp(value, min, max) {
7067
+ return Math.max(min, Math.min(max, value));
7068
+ }
7069
+ var TerminalScreen;
7070
+ var init_terminal_screen = __esm({
7071
+ "../daemon-core/src/cli-adapters/terminal-screen.ts"() {
7072
+ "use strict";
7073
+ TerminalScreen = class {
7074
+ rows;
7075
+ cols;
7076
+ cursorRow = 0;
7077
+ cursorCol = 0;
7078
+ savedRow = 0;
7079
+ savedCol = 0;
7080
+ lines;
7081
+ constructor(rows = 40, cols = 120) {
7082
+ this.rows = rows;
7083
+ this.cols = cols;
7084
+ this.lines = this.makeLines(rows, cols);
7085
+ }
7086
+ reset(rows = this.rows, cols = this.cols) {
7087
+ this.rows = rows;
7088
+ this.cols = cols;
7089
+ this.cursorRow = 0;
7090
+ this.cursorCol = 0;
7091
+ this.savedRow = 0;
7092
+ this.savedCol = 0;
7093
+ this.lines = this.makeLines(rows, cols);
7094
+ }
7095
+ resize(rows, cols) {
7096
+ const nextRows = Math.max(1, rows | 0);
7097
+ const nextCols = Math.max(1, cols | 0);
7098
+ const next = this.makeLines(nextRows, nextCols);
7099
+ const copyRows = Math.min(this.rows, nextRows);
7100
+ const copyCols = Math.min(this.cols, nextCols);
7101
+ for (let r = 0; r < copyRows; r++) {
7102
+ for (let c = 0; c < copyCols; c++) {
7103
+ next[r][c] = this.lines[r][c];
7104
+ }
7105
+ }
7106
+ this.rows = nextRows;
7107
+ this.cols = nextCols;
7108
+ this.lines = next;
7109
+ this.cursorRow = clamp(this.cursorRow, 0, this.rows - 1);
7110
+ this.cursorCol = clamp(this.cursorCol, 0, this.cols - 1);
7111
+ this.savedRow = clamp(this.savedRow, 0, this.rows - 1);
7112
+ this.savedCol = clamp(this.savedCol, 0, this.cols - 1);
7113
+ }
7114
+ write(data) {
7115
+ let i = 0;
7116
+ while (i < data.length) {
7117
+ const ch = data[i];
7118
+ if (ch === "\x1B") {
7119
+ const consumed = this.consumeEscape(data, i);
7120
+ i = consumed > i ? consumed : i + 1;
7121
+ continue;
7122
+ }
7123
+ if (ch === "\r") {
7124
+ this.cursorCol = 0;
7125
+ i++;
7126
+ continue;
7127
+ }
7128
+ if (ch === "\n") {
7129
+ this.newLine();
7130
+ i++;
7131
+ continue;
7132
+ }
7133
+ if (ch === "\b") {
7134
+ this.cursorCol = Math.max(0, this.cursorCol - 1);
7135
+ i++;
7136
+ continue;
7137
+ }
7138
+ if (ch === " ") {
7139
+ const nextStop = Math.min(this.cols - 1, this.cursorCol + (8 - (this.cursorCol % 8 || 8)));
7140
+ while (this.cursorCol < nextStop) this.putChar(" ");
7141
+ i++;
7142
+ continue;
7143
+ }
7144
+ if (ch >= " " && ch !== "\x7F") {
7145
+ this.putChar(ch);
7146
+ }
7147
+ i++;
7148
+ }
7149
+ }
7150
+ getText() {
7151
+ const raw = this.lines.map((line) => line.join("").replace(/\s+$/, ""));
7152
+ let start = 0;
7153
+ let end = raw.length;
7154
+ while (start < end && raw[start] === "") start++;
7155
+ while (end > start && raw[end - 1] === "") end--;
7156
+ return raw.slice(start, end).join("\n");
7157
+ }
7158
+ consumeEscape(data, start) {
7159
+ const next = data[start + 1];
7160
+ if (!next) return start + 1;
7161
+ if (next === "[") {
7162
+ let end = start + 2;
7163
+ while (end < data.length && !/[@-~]/.test(data[end])) end++;
7164
+ if (end >= data.length) return data.length;
7165
+ this.applyCsi(data.slice(start + 2, end), data[end]);
7166
+ return end + 1;
7167
+ }
7168
+ if (next === "]") {
7169
+ let end = start + 2;
7170
+ while (end < data.length) {
7171
+ if (data[end] === "\x07") return end + 1;
7172
+ if (data[end] === "\x1B" && data[end + 1] === "\\") return end + 2;
7173
+ end++;
7174
+ }
7175
+ return data.length;
7176
+ }
7177
+ if (next === "7") {
7178
+ this.savedRow = this.cursorRow;
7179
+ this.savedCol = this.cursorCol;
7180
+ return start + 2;
7181
+ }
7182
+ if (next === "8") {
7183
+ this.cursorRow = this.savedRow;
7184
+ this.cursorCol = this.savedCol;
7185
+ return start + 2;
7186
+ }
7187
+ return start + 2;
7188
+ }
7189
+ applyCsi(paramText, finalChar) {
7190
+ const privateMode = paramText.startsWith("?");
7191
+ const normalized = privateMode ? paramText.slice(1) : paramText;
7192
+ const params = normalized.length > 0 ? normalized.split(";").map((p) => parseInt(p || "0", 10) || 0) : [0];
7193
+ switch (finalChar) {
7194
+ case "A":
7195
+ this.cursorRow = clamp(this.cursorRow - (params[0] || 1), 0, this.rows - 1);
7196
+ return;
7197
+ case "B":
7198
+ this.cursorRow = clamp(this.cursorRow + (params[0] || 1), 0, this.rows - 1);
7199
+ return;
7200
+ case "C":
7201
+ this.cursorCol = clamp(this.cursorCol + (params[0] || 1), 0, this.cols - 1);
7202
+ return;
7203
+ case "D":
7204
+ this.cursorCol = clamp(this.cursorCol - (params[0] || 1), 0, this.cols - 1);
7205
+ return;
7206
+ case "E":
7207
+ this.cursorRow = clamp(this.cursorRow + (params[0] || 1), 0, this.rows - 1);
7208
+ this.cursorCol = 0;
7209
+ return;
7210
+ case "F":
7211
+ this.cursorRow = clamp(this.cursorRow - (params[0] || 1), 0, this.rows - 1);
7212
+ this.cursorCol = 0;
7213
+ return;
7214
+ case "G":
7215
+ this.cursorCol = clamp((params[0] || 1) - 1, 0, this.cols - 1);
7216
+ return;
7217
+ case "H":
7218
+ case "f": {
7219
+ const row = (params[0] || 1) - 1;
7220
+ const col = (params[1] || 1) - 1;
7221
+ this.cursorRow = clamp(row, 0, this.rows - 1);
7222
+ this.cursorCol = clamp(col, 0, this.cols - 1);
7223
+ return;
7224
+ }
7225
+ case "J": {
7226
+ const mode = params[0] || 0;
7227
+ if (mode === 2 || mode === 3) {
7228
+ this.reset(this.rows, this.cols);
7229
+ } else if (mode === 0) {
7230
+ this.clearToEndOfScreen();
7231
+ } else if (mode === 1) {
7232
+ this.clearToStartOfScreen();
7233
+ }
7234
+ return;
7235
+ }
7236
+ case "K": {
7237
+ const mode = params[0] || 0;
7238
+ if (mode === 2) this.clearLine(this.cursorRow, 0, this.cols - 1);
7239
+ else if (mode === 1) this.clearLine(this.cursorRow, 0, this.cursorCol);
7240
+ else this.clearLine(this.cursorRow, this.cursorCol, this.cols - 1);
7241
+ return;
7242
+ }
7243
+ case "m":
7244
+ return;
7245
+ case "s":
7246
+ this.savedRow = this.cursorRow;
7247
+ this.savedCol = this.cursorCol;
7248
+ return;
7249
+ case "u":
7250
+ this.cursorRow = this.savedRow;
7251
+ this.cursorCol = this.savedCol;
7252
+ return;
7253
+ case "h":
7254
+ case "l":
7255
+ if (privateMode && (normalized === "1049" || normalized === "47")) {
7256
+ this.reset(this.rows, this.cols);
7257
+ }
7258
+ return;
7259
+ default:
7260
+ return;
7261
+ }
7262
+ }
7263
+ putChar(ch) {
7264
+ if (this.cursorRow < 0 || this.cursorRow >= this.rows) return;
7265
+ if (this.cursorCol < 0) this.cursorCol = 0;
7266
+ if (this.cursorCol >= this.cols) this.newLine();
7267
+ this.lines[this.cursorRow][this.cursorCol] = ch;
7268
+ this.cursorCol++;
7269
+ if (this.cursorCol >= this.cols) this.newLine();
7270
+ }
7271
+ newLine() {
7272
+ this.cursorCol = 0;
7273
+ if (this.cursorRow >= this.rows - 1) {
7274
+ this.lines.shift();
7275
+ this.lines.push(Array.from({ length: this.cols }, () => " "));
7276
+ } else {
7277
+ this.cursorRow++;
7278
+ }
7279
+ }
7280
+ clearLine(row, start, end) {
7281
+ if (row < 0 || row >= this.rows) return;
7282
+ for (let c = clamp(start, 0, this.cols - 1); c <= clamp(end, 0, this.cols - 1); c++) {
7283
+ this.lines[row][c] = " ";
7284
+ }
7285
+ }
7286
+ clearToEndOfScreen() {
7287
+ this.clearLine(this.cursorRow, this.cursorCol, this.cols - 1);
7288
+ for (let r = this.cursorRow + 1; r < this.rows; r++) {
7289
+ this.clearLine(r, 0, this.cols - 1);
7290
+ }
7291
+ }
7292
+ clearToStartOfScreen() {
7293
+ for (let r = 0; r < this.cursorRow; r++) {
7294
+ this.clearLine(r, 0, this.cols - 1);
7295
+ }
7296
+ this.clearLine(this.cursorRow, 0, this.cursorCol);
7297
+ }
7298
+ makeLines(rows, cols) {
7299
+ return Array.from({ length: rows }, () => Array.from({ length: cols }, () => " "));
7300
+ }
7301
+ };
7302
+ }
7303
+ });
7304
+
7043
7305
  // ../daemon-core/src/cli-adapters/provider-cli-adapter.ts
7044
7306
  var provider_cli_adapter_exports = {};
7045
7307
  __export(provider_cli_adapter_exports, {
@@ -7112,28 +7374,19 @@ function parsePatternEntry(x) {
7112
7374
  }
7113
7375
  return null;
7114
7376
  }
7115
- function coercePatternArray(raw, fallbacks) {
7116
- if (!Array.isArray(raw)) return [...fallbacks];
7117
- const parsed = raw.map(parsePatternEntry).filter((r) => r != null);
7118
- return parsed.length > 0 ? parsed : [...fallbacks];
7119
- }
7120
- function defaultCleanOutput(raw, _lastUserInput) {
7121
- return stripAnsi(raw).trim();
7377
+ function coercePatternArray(raw) {
7378
+ if (!Array.isArray(raw)) return [];
7379
+ return raw.map(parsePatternEntry).filter((r) => r != null);
7122
7380
  }
7123
7381
  function normalizeCliProviderForRuntime(raw) {
7124
7382
  const patterns = raw?.patterns || {};
7125
7383
  return {
7126
- ...raw,
7127
7384
  patterns: {
7128
- prompt: coercePatternArray(patterns.prompt, FALLBACK_PROMPT),
7129
- generating: coercePatternArray(patterns.generating, FALLBACK_GENERATING),
7130
- approval: coercePatternArray(patterns.approval, FALLBACK_APPROVAL),
7131
- ready: coercePatternArray(patterns.ready, [])
7132
- },
7133
- cleanOutput: typeof raw?.cleanOutput === "function" ? raw.cleanOutput : defaultCleanOutput
7385
+ approval: coercePatternArray(patterns.approval)
7386
+ }
7134
7387
  };
7135
7388
  }
7136
- var os11, path9, import_child_process5, pty, FALLBACK_PROMPT, FALLBACK_GENERATING, FALLBACK_APPROVAL, ProviderCliAdapter;
7389
+ var os11, path9, import_child_process5, pty, ProviderCliAdapter;
7137
7390
  var init_provider_cli_adapter = __esm({
7138
7391
  "../daemon-core/src/cli-adapters/provider-cli-adapter.ts"() {
7139
7392
  "use strict";
@@ -7141,6 +7394,7 @@ var init_provider_cli_adapter = __esm({
7141
7394
  path9 = __toESM(require("path"));
7142
7395
  import_child_process5 = require("child_process");
7143
7396
  init_logger();
7397
+ init_terminal_screen();
7144
7398
  try {
7145
7399
  pty = require("node-pty");
7146
7400
  if (os11.platform() !== "win32") {
@@ -7162,40 +7416,10 @@ var init_provider_cli_adapter = __esm({
7162
7416
  } catch {
7163
7417
  LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Terminal features disabled.");
7164
7418
  }
7165
- FALLBACK_PROMPT = [
7166
- /Type your message/i,
7167
- /for\s*shortcuts/i,
7168
- // Claude Code prompt
7169
- /\?\s*for\s*help/i,
7170
- // Claude Code help prompt
7171
- /Press enter/i,
7172
- /^[>›❯]\s*$/i,
7173
- // Prompt char as the complete evaluated string
7174
- /[>›❯]\s*$/
7175
- // Prompt char at the very end of evaluated string
7176
- ];
7177
- FALLBACK_GENERATING = [
7178
- /[\u2800-\u28ff]/,
7179
- // Braille spinner blocks (universal TUI)
7180
- /esc to (cancel|interrupt|stop)/i,
7181
- // Common TUI generation status line
7182
- /generating\.\.\./i,
7183
- /Claude is (?:thinking|processing|working)/i
7184
- // Specific Claude Code status
7185
- ];
7186
- FALLBACK_APPROVAL = [
7187
- /Allow\s*once/i,
7188
- // ANSI strip may remove spaces
7189
- /Always\s*allow/i,
7190
- /\(y\/n\)/i,
7191
- /\[Y\/n\]/i,
7192
- /Yes,?\s*don'?t\s*ask/i
7193
- // "Yes, don't ask again" (Claude Code)
7194
- ];
7195
- ProviderCliAdapter = class {
7419
+ ProviderCliAdapter = class _ProviderCliAdapter {
7196
7420
  constructor(provider, workingDir, extraArgs = []) {
7197
7421
  this.extraArgs = extraArgs;
7198
- this.provider = normalizeCliProviderForRuntime(provider);
7422
+ this.provider = provider;
7199
7423
  this.cliType = provider.type;
7200
7424
  this.cliName = provider.name;
7201
7425
  this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os11.homedir()) : workingDir;
@@ -7212,6 +7436,13 @@ var init_provider_cli_adapter = __esm({
7212
7436
  };
7213
7437
  const rawKeys = provider.approvalKeys;
7214
7438
  this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
7439
+ this.cliScripts = provider.scripts || {};
7440
+ const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
7441
+ if (scriptNames.length > 0) {
7442
+ LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
7443
+ } else {
7444
+ LOG.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js`);
7445
+ }
7215
7446
  }
7216
7447
  cliType;
7217
7448
  cliName;
@@ -7219,6 +7450,7 @@ var init_provider_cli_adapter = __esm({
7219
7450
  provider;
7220
7451
  ptyProcess = null;
7221
7452
  messages = [];
7453
+ structuredMessages = [];
7222
7454
  currentStatus = "starting";
7223
7455
  onStatusChange = null;
7224
7456
  responseBuffer = "";
@@ -7229,7 +7461,6 @@ var init_provider_cli_adapter = __esm({
7229
7461
  idleTimeout = null;
7230
7462
  ready = false;
7231
7463
  startupBuffer = "";
7232
- /** After spawn: briefly skip generating/settle so splash/redraw does not flip status; not used to gate sendMessage */
7233
7464
  startupParseGate = false;
7234
7465
  spawnAt = 0;
7235
7466
  // PTY I/O
@@ -7247,11 +7478,20 @@ var init_provider_cli_adapter = __esm({
7247
7478
  // Output settle debounce — fires after PTY output goes quiet
7248
7479
  settleTimer = null;
7249
7480
  settledBuffer = "";
7250
- // snapshot of recentOutputBuffer at settle time
7251
7481
  // Resize redraw suppression
7252
7482
  resizeSuppressUntil = 0;
7253
7483
  // Debug: status transition history
7254
7484
  statusHistory = [];
7485
+ // ─── CLI Scripts (script-based parsing) ───
7486
+ cliScripts;
7487
+ /** Full accumulated ANSI-stripped PTY output */
7488
+ accumulatedBuffer = "";
7489
+ /** Full accumulated raw PTY output (with ANSI) */
7490
+ accumulatedRawBuffer = "";
7491
+ /** Current visible terminal screen snapshot */
7492
+ terminalScreen = new TerminalScreen(40, 120);
7493
+ /** Max accumulated buffer size (last 50KB) */
7494
+ static MAX_ACCUMULATED_BUFFER = 5e4;
7255
7495
  setStatus(status, trigger) {
7256
7496
  const prev = this.currentStatus;
7257
7497
  if (prev === status) return;
@@ -7260,10 +7500,16 @@ var init_provider_cli_adapter = __esm({
7260
7500
  if (this.statusHistory.length > 50) this.statusHistory.shift();
7261
7501
  LOG.info("CLI", `[${this.cliType}] status: ${prev} \u2192 ${status}${trigger ? ` (${trigger})` : ""}`);
7262
7502
  }
7263
- // Resolved timeouts (provider defaults + overrides)
7503
+ // Resolved timeouts
7264
7504
  timeouts;
7265
- // Provider approval key mapping (e.g. { 0: '1', 1: '2', 2: '3' }) — loaded from provider.json
7505
+ // Provider approval key mapping
7266
7506
  approvalKeys;
7507
+ /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
7508
+ setCliScripts(scripts) {
7509
+ this.cliScripts = scripts;
7510
+ const scriptNames = Object.keys(scripts).filter((k) => typeof scripts[k] === "function");
7511
+ LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
7512
+ }
7267
7513
  // ─── Lifecycle ─────────────────────────────────
7268
7514
  setServerConn(serverConn) {
7269
7515
  this.serverConn = serverConn;
@@ -7352,15 +7598,19 @@ var init_provider_cli_adapter = __esm({
7352
7598
  this.spawnAt = Date.now();
7353
7599
  this.startupParseGate = true;
7354
7600
  this.startupBuffer = "";
7601
+ this.terminalScreen.reset(40, 120);
7355
7602
  this.ready = true;
7356
7603
  this.setStatus("idle", "pty_ready");
7357
7604
  this.onStatusChange?.();
7358
7605
  }
7359
- // ─── Output state machine ────────────────────────────
7606
+ // ─── Output Handling ────────────────────────────
7360
7607
  handleOutput(rawData) {
7361
7608
  if (Date.now() < this.resizeSuppressUntil) return;
7609
+ this.terminalScreen.write(rawData);
7362
7610
  const cleanData = stripAnsi(rawData);
7363
- const { patterns } = this.provider;
7611
+ if (this.isWaitingForResponse && cleanData) {
7612
+ this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
7613
+ }
7364
7614
  if (cleanData.trim()) {
7365
7615
  if (this.serverConn) {
7366
7616
  this.serverConn.sendMessage("log", { message: cleanData.trim(), level: "info" });
@@ -7369,9 +7619,10 @@ var init_provider_cli_adapter = __esm({
7369
7619
  }
7370
7620
  }
7371
7621
  this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1e3);
7622
+ this.accumulatedBuffer = (this.accumulatedBuffer + cleanData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
7623
+ this.accumulatedRawBuffer = (this.accumulatedRawBuffer + rawData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
7372
7624
  if (this.startupParseGate) {
7373
7625
  this.startupBuffer += cleanData;
7374
- LOG.info("CLI", `[${this.cliType}] startup chunk (${cleanData.length} chars): ${cleanData.slice(0, 200).replace(/\n/g, "\\n")}`);
7375
7626
  const dialogPatterns = [
7376
7627
  /Do you want to connect/i,
7377
7628
  /Do you trust the files/i,
@@ -7386,60 +7637,17 @@ var init_provider_cli_adapter = __esm({
7386
7637
  }
7387
7638
  const elapsed = Date.now() - this.spawnAt;
7388
7639
  const bufCap = this.startupBuffer.length > 12e3;
7389
- const promptMatched = patterns.prompt.some((p) => p.test(this.startupBuffer));
7390
- if (promptMatched || elapsed > 8e3 || bufCap) {
7640
+ const scriptStatus = this.runDetectStatus(this.startupBuffer);
7641
+ const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
7642
+ if (isReady) {
7391
7643
  this.startupParseGate = false;
7392
- if (promptMatched) {
7393
- LOG.info("CLI", `[${this.cliType}] \u2713 Startup gate end (prompt matched)`);
7394
- } else {
7395
- LOG.info("CLI", `[${this.cliType}] startup gate end (${elapsed}ms, cap=${bufCap}, prompt=${promptMatched})`);
7396
- }
7644
+ LOG.info("CLI", `[${this.cliType}] Startup gate end (${elapsed}ms, scriptStatus=${scriptStatus})`);
7397
7645
  } else {
7398
7646
  return;
7399
7647
  }
7400
7648
  }
7401
- if (cleanData.trim().length > 5) {
7402
- LOG.debug("CLI", `[${this.cliType}] output chunk (${cleanData.length}): ${cleanData.slice(0, 300).replace(/\n/g, "\\n")}`);
7403
- }
7404
- if (!this.isWaitingForResponse) {
7405
- if (patterns.generating.some((p) => p.test(cleanData))) {
7406
- if (this.settleTimer) {
7407
- clearTimeout(this.settleTimer);
7408
- this.settleTimer = null;
7409
- }
7410
- this.isWaitingForResponse = true;
7411
- this.responseBuffer = "";
7412
- this.setStatus("generating", "autonomous_gen");
7413
- this.onStatusChange?.();
7414
- }
7415
- }
7416
- if (this.isWaitingForResponse) {
7417
- this.responseBuffer += cleanData;
7418
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
7419
- if (patterns.generating.some((p) => p.test(cleanData))) {
7420
- this.setStatus("generating", "still_generating");
7421
- this.idleTimeout = setTimeout(() => {
7422
- if (this.isWaitingForResponse) this.finishResponse();
7423
- }, this.timeouts.generatingIdle);
7424
- this.onStatusChange?.();
7425
- if (this.settleTimer) {
7426
- clearTimeout(this.settleTimer);
7427
- this.settleTimer = null;
7428
- }
7429
- return;
7430
- }
7431
- }
7432
- if (this.currentStatus === "waiting_approval") {
7433
- this.approvalTransitionBuffer = (this.approvalTransitionBuffer + cleanData).slice(-500);
7434
- this.scheduleSettle();
7435
- return;
7436
- }
7437
7649
  this.scheduleSettle();
7438
7650
  }
7439
- /**
7440
- * Fired after output goes quiet for outputSettle ms.
7441
- * Evaluates the stabilised buffer for approval, prompt (idle), or timeout.
7442
- */
7443
7651
  scheduleSettle() {
7444
7652
  if (this.settleTimer) clearTimeout(this.settleTimer);
7445
7653
  this.settleTimer = setTimeout(() => {
@@ -7449,59 +7657,25 @@ var init_provider_cli_adapter = __esm({
7449
7657
  }, this.timeouts.outputSettle);
7450
7658
  }
7451
7659
  evaluateSettled() {
7452
- const { patterns } = this.provider;
7453
- const buf = this.settledBuffer;
7454
- if (this.currentStatus === "waiting_approval") {
7455
- const genResume = patterns.generating.some((p) => p.test(this.approvalTransitionBuffer));
7456
- const promptResume = patterns.prompt.some((p) => p.test(this.approvalTransitionBuffer));
7457
- if (genResume) {
7458
- if (this.approvalExitTimeout) {
7459
- clearTimeout(this.approvalExitTimeout);
7460
- this.approvalExitTimeout = null;
7461
- }
7462
- this.setStatus("generating", "approval_gen_resume");
7463
- this.activeModal = null;
7464
- this.recentOutputBuffer = "";
7465
- this.approvalTransitionBuffer = "";
7466
- this.lastApprovalResolvedAt = Date.now();
7467
- this.onStatusChange?.();
7468
- } else if (promptResume) {
7469
- if (this.approvalExitTimeout) {
7470
- clearTimeout(this.approvalExitTimeout);
7471
- this.approvalExitTimeout = null;
7472
- }
7473
- this.activeModal = null;
7474
- this.recentOutputBuffer = "";
7475
- this.approvalTransitionBuffer = "";
7476
- this.lastApprovalResolvedAt = Date.now();
7477
- this.finishResponse();
7478
- }
7479
- return;
7480
- }
7481
- const hasApproval = patterns.approval.some((p) => p.test(buf));
7482
- if (hasApproval) {
7660
+ const tail = this.settledBuffer;
7661
+ const scriptStatus = this.runDetectStatus(tail);
7662
+ if (!scriptStatus) return;
7663
+ const prevStatus = this.currentStatus;
7664
+ if (scriptStatus === "waiting_approval") {
7483
7665
  const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
7484
7666
  if (!inCooldown) {
7485
- const ctxLines = buf.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
7486
7667
  this.isWaitingForResponse = true;
7487
- this.setStatus("waiting_approval", "approval_pattern");
7488
- this.recentOutputBuffer = "";
7489
- this.approvalTransitionBuffer = "";
7490
- this.activeModal = {
7491
- message: ctxLines.slice(-5).join(" ").slice(0, 200) || "Approval required",
7492
- buttons: this.cliType === "claude-cli" ? ["Yes (y)", "Always allow (a)", "Deny (Esc)"] : ["Allow once", "Always allow", "Deny"]
7493
- };
7668
+ this.setStatus("waiting_approval", "script_detect");
7669
+ const modal = this.runParseApproval(tail);
7670
+ this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
7494
7671
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
7495
7672
  if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
7496
7673
  this.approvalExitTimeout = setTimeout(() => {
7497
7674
  if (this.currentStatus === "waiting_approval") {
7498
- LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-exiting waiting_approval`);
7675
+ LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
7499
7676
  this.activeModal = null;
7500
7677
  this.lastApprovalResolvedAt = Date.now();
7501
- this.recentOutputBuffer = "";
7502
- this.approvalTransitionBuffer = "";
7503
- this.approvalExitTimeout = null;
7504
- this.setStatus(this.isWaitingForResponse ? "generating" : "idle", "approval_cleared");
7678
+ this.setStatus("idle", "approval_timeout");
7505
7679
  this.onStatusChange?.();
7506
7680
  }
7507
7681
  }, 6e4);
@@ -7509,19 +7683,42 @@ var init_provider_cli_adapter = __esm({
7509
7683
  return;
7510
7684
  }
7511
7685
  }
7512
- if (this.isWaitingForResponse) {
7513
- const trailingLines = buf.split("\n").slice(-3).join("\n");
7514
- if (patterns.prompt.some((p) => p.test(trailingLines)) && !hasApproval) {
7515
- this.finishResponse();
7516
- } else if (!patterns.generating.some((p) => p.test(buf))) {
7517
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
7518
- this.idleTimeout = setTimeout(() => {
7519
- if (this.isWaitingForResponse && this.responseBuffer.trim()) {
7520
- this.finishResponse();
7521
- }
7522
- }, this.timeouts.idleFinish);
7686
+ if (scriptStatus === "generating") {
7687
+ if (prevStatus === "waiting_approval") {
7688
+ if (this.approvalExitTimeout) {
7689
+ clearTimeout(this.approvalExitTimeout);
7690
+ this.approvalExitTimeout = null;
7691
+ }
7692
+ this.activeModal = null;
7693
+ this.lastApprovalResolvedAt = Date.now();
7523
7694
  }
7695
+ if (!this.isWaitingForResponse) {
7696
+ this.isWaitingForResponse = true;
7697
+ this.responseBuffer = "";
7698
+ }
7699
+ this.setStatus("generating", "script_detect");
7700
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
7701
+ this.idleTimeout = setTimeout(() => {
7702
+ if (this.isWaitingForResponse) this.finishResponse();
7703
+ }, this.timeouts.generatingIdle);
7524
7704
  this.onStatusChange?.();
7705
+ return;
7706
+ }
7707
+ if (scriptStatus === "idle") {
7708
+ if (prevStatus === "waiting_approval") {
7709
+ if (this.approvalExitTimeout) {
7710
+ clearTimeout(this.approvalExitTimeout);
7711
+ this.approvalExitTimeout = null;
7712
+ }
7713
+ this.activeModal = null;
7714
+ this.lastApprovalResolvedAt = Date.now();
7715
+ }
7716
+ if (this.isWaitingForResponse) {
7717
+ this.finishResponse();
7718
+ } else if (prevStatus !== "idle") {
7719
+ this.setStatus("idle", "script_detect");
7720
+ this.onStatusChange?.();
7721
+ }
7525
7722
  }
7526
7723
  }
7527
7724
  finishResponse() {
@@ -7537,25 +7734,50 @@ var init_provider_cli_adapter = __esm({
7537
7734
  clearTimeout(this.approvalExitTimeout);
7538
7735
  this.approvalExitTimeout = null;
7539
7736
  }
7540
- const lastUserText = this.messages.filter((m) => m.role === "user").pop()?.content;
7541
- let response = this.provider.cleanOutput(this.responseBuffer, lastUserText);
7542
- if (lastUserText && response) {
7543
- const userTrimmed = lastUserText.trim();
7544
- response = response.split("\n").filter((l) => l.trim() !== userTrimmed).join("\n").trim();
7545
- }
7546
- if (response) {
7547
- this.messages.push({ role: "assistant", content: response, timestamp: Date.now() });
7548
- if (this.messages.length > 200) this.messages = this.messages.slice(-200);
7549
- LOG.info("CLI", `[${this.cliType}] Response (${response.length} chars)`);
7550
- }
7551
7737
  this.responseBuffer = "";
7552
7738
  this.isWaitingForResponse = false;
7553
7739
  this.activeModal = null;
7554
7740
  this.setStatus("idle", "response_finished");
7555
7741
  this.onStatusChange?.();
7556
7742
  }
7557
- // ─── Public API (CliAdapter interface) ──────────
7743
+ // ─── Script Execution ──────────────────────────
7744
+ runDetectStatus(text) {
7745
+ if (!this.cliScripts?.detectStatus) return null;
7746
+ try {
7747
+ return this.cliScripts.detectStatus({ tail: text.slice(-500) });
7748
+ } catch (e) {
7749
+ LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
7750
+ return null;
7751
+ }
7752
+ }
7753
+ runParseApproval(tail) {
7754
+ if (!this.cliScripts?.parseApproval) return null;
7755
+ try {
7756
+ return this.cliScripts.parseApproval({
7757
+ buffer: this.terminalScreen.getText() || this.accumulatedBuffer,
7758
+ rawBuffer: this.accumulatedRawBuffer,
7759
+ tail
7760
+ });
7761
+ } catch (e) {
7762
+ LOG.warn("CLI", `[${this.cliType}] parseApproval error: ${e.message}`);
7763
+ return null;
7764
+ }
7765
+ }
7766
+ // ─── Public API (CliAdapter) ───────────────────
7558
7767
  getStatus() {
7768
+ const scriptResult = this.getScriptParsedStatus();
7769
+ if (scriptResult) {
7770
+ return {
7771
+ status: this.currentStatus,
7772
+ messages: (scriptResult.messages || []).map((m) => ({
7773
+ role: m.role,
7774
+ content: m.content,
7775
+ timestamp: m.timestamp
7776
+ })),
7777
+ workingDir: this.workingDir,
7778
+ activeModal: this.activeModal
7779
+ };
7780
+ }
7559
7781
  return {
7560
7782
  status: this.currentStatus,
7561
7783
  messages: [...this.messages],
@@ -7563,11 +7785,71 @@ var init_provider_cli_adapter = __esm({
7563
7785
  activeModal: this.activeModal
7564
7786
  };
7565
7787
  }
7788
+ /**
7789
+ * Script-based full parse — returns ReadChatResult.
7790
+ * Called by command handler / dashboard for rich content rendering.
7791
+ */
7792
+ getScriptParsedStatus() {
7793
+ if (!this.cliScripts?.parseOutput) return null;
7794
+ try {
7795
+ const input = {
7796
+ buffer: this.accumulatedBuffer,
7797
+ rawBuffer: this.accumulatedRawBuffer,
7798
+ recentBuffer: this.recentOutputBuffer,
7799
+ screenText: this.terminalScreen.getText(),
7800
+ messages: [...this.structuredMessages.length > 0 ? this.structuredMessages : this.messages],
7801
+ partialResponse: this.responseBuffer
7802
+ };
7803
+ const result = this.cliScripts.parseOutput(input);
7804
+ if (result && typeof result === "object") {
7805
+ if (Array.isArray(result.messages)) {
7806
+ this.structuredMessages = result.messages.map((m) => ({
7807
+ role: m.role,
7808
+ content: m.content,
7809
+ timestamp: m.timestamp
7810
+ }));
7811
+ }
7812
+ return result;
7813
+ }
7814
+ } catch (e) {
7815
+ LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${e.message}`);
7816
+ }
7817
+ return null;
7818
+ }
7819
+ /** Whether this adapter has CLI scripts loaded */
7820
+ hasCliScripts() {
7821
+ return typeof this.cliScripts?.detectStatus === "function";
7822
+ }
7823
+ /**
7824
+ * Resolves an action (like 'fix' lint error) from the dashboard.
7825
+ * Uses resolveAction script if available, otherwise falls back to standard text.
7826
+ */
7827
+ async resolveAction(data) {
7828
+ let promptText = "";
7829
+ if (this.cliScripts && typeof this.cliScripts.resolveAction === "function") {
7830
+ try {
7831
+ promptText = this.cliScripts.resolveAction(data);
7832
+ } catch (e) {
7833
+ LOG.warn("CLI", `[${this.cliType}] resolveAction error: ${e.message}`);
7834
+ }
7835
+ }
7836
+ if (!promptText && data) {
7837
+ promptText = `Please fix the following issue:
7838
+ ${data.title || ""}
7839
+ ${data.explanation || ""}
7840
+
7841
+ ${data.message || ""}`.trim();
7842
+ }
7843
+ if (promptText) {
7844
+ await this.sendMessage(promptText);
7845
+ }
7846
+ }
7566
7847
  async sendMessage(text) {
7567
7848
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
7568
7849
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
7569
7850
  if (this.isWaitingForResponse) return;
7570
7851
  this.messages.push({ role: "user", content: text, timestamp: Date.now() });
7852
+ this.structuredMessages.push({ role: "user", content: text, timestamp: Date.now() });
7571
7853
  this.isWaitingForResponse = true;
7572
7854
  this.responseBuffer = "";
7573
7855
  this.setStatus("generating", "sendMessage");
@@ -7579,8 +7861,7 @@ var init_provider_cli_adapter = __esm({
7579
7861
  }
7580
7862
  getPartialResponse() {
7581
7863
  if (!this.isWaitingForResponse) return "";
7582
- const partial2 = this.provider.cleanOutput(this.responseBuffer);
7583
- return partial2 || (this.isWaitingForResponse ? "(generating...)" : "");
7864
+ return this.responseBuffer;
7584
7865
  }
7585
7866
  cancel() {
7586
7867
  this.shutdown();
@@ -7612,6 +7893,10 @@ var init_provider_cli_adapter = __esm({
7612
7893
  }
7613
7894
  clearHistory() {
7614
7895
  this.messages = [];
7896
+ this.structuredMessages = [];
7897
+ this.accumulatedBuffer = "";
7898
+ this.accumulatedRawBuffer = "";
7899
+ this.terminalScreen.reset();
7615
7900
  this.onStatusChange?.();
7616
7901
  }
7617
7902
  isProcessing() {
@@ -7623,11 +7908,6 @@ var init_provider_cli_adapter = __esm({
7623
7908
  writeRaw(data) {
7624
7909
  this.ptyProcess?.write(data);
7625
7910
  }
7626
- /**
7627
- * Resolve an approval modal by navigating to the button at `buttonIndex` and pressing Enter.
7628
- * Index 0 = first option (already selected by default — just Enter).
7629
- * Index N = press Arrow Down N times, then Enter.
7630
- */
7631
7911
  resolveModal(buttonIndex) {
7632
7912
  if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
7633
7913
  if (buttonIndex in this.approvalKeys) {
@@ -7642,25 +7922,13 @@ var init_provider_cli_adapter = __esm({
7642
7922
  if (this.ptyProcess) {
7643
7923
  try {
7644
7924
  this.ptyProcess.resize(cols, rows);
7925
+ this.terminalScreen.resize(rows, cols);
7645
7926
  this.resizeSuppressUntil = Date.now() + 300;
7646
7927
  } catch {
7647
7928
  }
7648
7929
  }
7649
7930
  }
7650
- /**
7651
- * Full debug state — exposes all internal buffers, status, and patterns for debugging.
7652
- * Used by DevServer /api/cli/debug endpoint.
7653
- */
7654
7931
  getDebugState() {
7655
- const sb = this.startupBuffer;
7656
- const testOnStartup = (p) => {
7657
- const flags = p.flags.includes("g") ? p.flags.replace(/g/g, "") : p.flags;
7658
- return new RegExp(p.source, flags).test(sb);
7659
- };
7660
- const promptDiagnostics = this.provider.patterns.prompt.map((p) => ({
7661
- pattern: p.toString(),
7662
- matchedAgainstStartupBuffer: testOnStartup(p)
7663
- }));
7664
7932
  return {
7665
7933
  type: this.cliType,
7666
7934
  name: this.cliName,
@@ -7670,32 +7938,20 @@ var init_provider_cli_adapter = __esm({
7670
7938
  spawnAt: this.spawnAt,
7671
7939
  workingDir: this.workingDir,
7672
7940
  messages: this.messages.slice(-20),
7941
+ structuredMessages: this.structuredMessages.slice(-20),
7673
7942
  messageCount: this.messages.length,
7674
- // Buffers (longer tails here than in periodic logs — for matching provider.json patterns)
7675
- startupBuffer: sb.slice(-4e3),
7676
- startupBufferLength: sb.length,
7677
- promptDiagnostics,
7943
+ startupBuffer: this.startupBuffer.slice(-4e3),
7678
7944
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
7679
7945
  settledBuffer: this.settledBuffer.slice(-500),
7680
- responseBuffer: this.responseBuffer.slice(-500),
7681
- approvalTransitionBuffer: this.approvalTransitionBuffer.slice(-500),
7682
- // State
7946
+ accumulatedBufferLength: this.accumulatedBuffer.length,
7683
7947
  isWaitingForResponse: this.isWaitingForResponse,
7684
7948
  activeModal: this.activeModal,
7685
7949
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
7686
7950
  resizeSuppressUntil: this.resizeSuppressUntil,
7687
- // Provider patterns (serialized)
7688
- patterns: {
7689
- prompt: this.provider.patterns.prompt.map((p) => p.toString()),
7690
- generating: this.provider.patterns.generating.map((p) => p.toString()),
7691
- approval: this.provider.patterns.approval.map((p) => p.toString()),
7692
- ready: this.provider.patterns.ready.map((p) => p.toString())
7693
- },
7694
- // Status history
7951
+ hasCliScripts: this.hasCliScripts(),
7952
+ scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
7695
7953
  statusHistory: this.statusHistory.slice(-30),
7696
- // Timeouts config
7697
7954
  timeouts: this.timeouts,
7698
- // PTY alive
7699
7955
  ptyAlive: !!this.ptyProcess
7700
7956
  };
7701
7957
  }
@@ -7761,21 +8017,27 @@ var init_cli_provider_instance = __esm({
7761
8017
  async onTick() {
7762
8018
  }
7763
8019
  getState() {
7764
- const adapterStatus = this.adapter.getStatus();
8020
+ const rawStatus = this.adapter.getStatus();
8021
+ const parsedStatus = this.adapter.getScriptParsedStatus();
8022
+ const adapterStatus = parsedStatus ? {
8023
+ ...rawStatus,
8024
+ messages: parsedStatus.messages || rawStatus.messages,
8025
+ activeModal: parsedStatus.activeModal || rawStatus.activeModal
8026
+ } : rawStatus;
7765
8027
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
7766
- const recentMessages = adapterStatus.messages.slice(-50).map((m) => ({
7767
- role: m.role,
7768
- content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content,
7769
- timestamp: m.timestamp
7770
- }));
8028
+ const recentMessages = adapterStatus.messages.slice(-50).map((m) => {
8029
+ const content = typeof m.content === "string" && m.content.length > 8e3 ? m.content.slice(0, 8e3) + "\n... (truncated)" : m.content;
8030
+ return { ...m, content };
8031
+ });
7771
8032
  const partial2 = this.adapter.getPartialResponse();
7772
8033
  if (adapterStatus.status === "generating" && partial2) {
7773
8034
  const cleaned = partial2.trim();
7774
8035
  if (cleaned && cleaned !== "(generating...)") {
7775
8036
  recentMessages.push({
7776
8037
  role: "assistant",
7777
- content: (cleaned.length > 2e3 ? cleaned.slice(0, 2e3) + "..." : cleaned) + "...",
7778
- timestamp: Date.now()
8038
+ content: (cleaned.length > 8e3 ? cleaned.slice(0, 8e3) + "..." : cleaned) + "...",
8039
+ timestamp: Date.now(),
8040
+ meta: { streaming: true }
7779
8041
  });
7780
8042
  }
7781
8043
  }
@@ -7814,6 +8076,8 @@ var init_cli_provider_instance = __esm({
7814
8076
  this.adapter.sendMessage(data.text);
7815
8077
  } else if (event === "server_connected" && data?.serverConn) {
7816
8078
  this.adapter.setServerConn(data.serverConn);
8079
+ } else if (event === "resolve_action" && data) {
8080
+ this.adapter.resolveAction(data);
7817
8081
  }
7818
8082
  }
7819
8083
  dispose() {
@@ -25200,7 +25464,8 @@ var init_cli_manager = __esm({
25200
25464
  const provider = this.providerLoader.getMeta(normalizedType);
25201
25465
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
25202
25466
  console.log(import_chalk.default.cyan(` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
25203
- return new ProviderCliAdapter(provider, workingDir, cliArgs);
25467
+ const resolvedProvider = this.providerLoader.resolve(normalizedType) || provider;
25468
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs);
25204
25469
  }
25205
25470
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
25206
25471
  }
@@ -25285,7 +25550,8 @@ ${installInfo}`
25285
25550
  }
25286
25551
  const instanceManager = this.deps.getInstanceManager();
25287
25552
  if (provider && instanceManager) {
25288
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key);
25553
+ const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
25554
+ const cliInstance = new CliProviderInstance(resolvedProvider, resolvedDir, cliArgs, key);
25289
25555
  try {
25290
25556
  await instanceManager.addInstance(key, cliInstance, {
25291
25557
  serverConn: this.deps.getServerConn(),
@@ -28549,6 +28815,46 @@ var init_dev_server = __esm({
28549
28815
  }
28550
28816
  }
28551
28817
  // ─── Phase 2: Auto-Implement Backend ───
28818
+ getDefaultAutoImplReference(category, type) {
28819
+ if (category === "cli") {
28820
+ return type === "codex-cli" ? "claude-cli" : "codex-cli";
28821
+ }
28822
+ return "antigravity";
28823
+ }
28824
+ resolveAutoImplReference(category, requestedReference, targetType) {
28825
+ const desired = requestedReference || this.getDefaultAutoImplReference(category, targetType);
28826
+ const ref = this.providerLoader.resolve(desired) || this.providerLoader.getMeta(desired);
28827
+ if (ref?.category === category) return desired;
28828
+ const all = this.providerLoader.getAll();
28829
+ const fallback = all.find((p) => p.category === category && p.type !== targetType);
28830
+ return fallback?.type || null;
28831
+ }
28832
+ loadAutoImplReferenceScripts(category, referenceType) {
28833
+ if (!referenceType) return {};
28834
+ const builtinDir = this.providerLoader.getPrimaryBuiltinDir();
28835
+ const refDir = path12.join(builtinDir, category, referenceType);
28836
+ if (!fs9.existsSync(refDir)) return {};
28837
+ const referenceScripts = {};
28838
+ const scriptsDir = path12.join(refDir, "scripts");
28839
+ if (!fs9.existsSync(scriptsDir)) return referenceScripts;
28840
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
28841
+ try {
28842
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
28843
+ } catch {
28844
+ return false;
28845
+ }
28846
+ }).sort().reverse();
28847
+ if (versions.length === 0) return referenceScripts;
28848
+ const latestDir = path12.join(scriptsDir, versions[0]);
28849
+ for (const file2 of fs9.readdirSync(latestDir)) {
28850
+ if (!file2.endsWith(".js")) continue;
28851
+ try {
28852
+ referenceScripts[file2] = fs9.readFileSync(path12.join(latestDir, file2), "utf-8");
28853
+ } catch {
28854
+ }
28855
+ }
28856
+ return referenceScripts;
28857
+ }
28552
28858
  async handleAutoImplement(type, req, res) {
28553
28859
  const body = await this.readBody(req);
28554
28860
  const { agent = "claude-cli", functions, reference = "antigravity", model, comment } = body;
@@ -28571,36 +28877,26 @@ var init_dev_server = __esm({
28571
28877
  return;
28572
28878
  }
28573
28879
  try {
28574
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "analyzing", message: "\uC5D0\uC774\uC804\uD2B8 \uCD08\uAE30\uD654 (DOM \uD0D0\uC0C9 \uAD8C\uD55C \uBD80\uC5EC)..." } });
28880
+ const resolvedReference = this.resolveAutoImplReference(provider.category, reference, type);
28881
+ this.sendAutoImplSSE({
28882
+ event: "progress",
28883
+ data: {
28884
+ function: "_init",
28885
+ status: "analyzing",
28886
+ message: provider.category === "cli" ? "Initializing agent (granting CLI PTY debug access)..." : "Initializing agent (granting DOM access)..."
28887
+ }
28888
+ });
28575
28889
  const domContext = null;
28576
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
28577
- let referenceScripts = {};
28578
- const builtinDir = this.providerLoader.getPrimaryBuiltinDir();
28579
- const refDir = path12.join(builtinDir, "ide", reference);
28580
- if (fs9.existsSync(refDir)) {
28581
- const scriptsDir = path12.join(refDir, "scripts");
28582
- if (fs9.existsSync(scriptsDir)) {
28583
- const versions = fs9.readdirSync(scriptsDir).filter((d) => {
28584
- try {
28585
- return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
28586
- } catch {
28587
- return false;
28588
- }
28589
- }).sort().reverse();
28590
- if (versions.length > 0) {
28591
- const latestDir = path12.join(scriptsDir, versions[0]);
28592
- for (const file2 of fs9.readdirSync(latestDir)) {
28593
- if (file2.endsWith(".js")) {
28594
- try {
28595
- referenceScripts[file2] = fs9.readFileSync(path12.join(latestDir, file2), "utf-8");
28596
- } catch {
28597
- }
28598
- }
28599
- }
28600
- }
28890
+ this.sendAutoImplSSE({
28891
+ event: "progress",
28892
+ data: {
28893
+ function: "_init",
28894
+ status: "loading_reference",
28895
+ message: `Loading reference script (${resolvedReference || "none"})...`
28601
28896
  }
28602
- }
28603
- const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment);
28897
+ });
28898
+ const referenceScripts = this.loadAutoImplReferenceScripts(provider.category, resolvedReference);
28899
+ const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
28604
28900
  const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
28605
28901
  if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
28606
28902
  const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
@@ -28618,7 +28914,7 @@ var init_dev_server = __esm({
28618
28914
  }
28619
28915
  const agentCategory = agentProvider?.category;
28620
28916
  if (agentCategory === "acp") {
28621
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `ACP \uC5D0\uC774\uC804\uD2B8 \uC2E4\uD589 \uC911: ${spawn3.command} ${(spawn3.args || []).join(" ")}` } });
28917
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${spawn3.command} ${(spawn3.args || []).join(" ")}` } });
28622
28918
  this.autoImplStatus = { running: true, type, progress: [] };
28623
28919
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
28624
28920
  const { Readable: Readable2, Writable: Writable2 } = await import("stream");
@@ -28705,7 +29001,7 @@ var init_dev_server = __esm({
28705
29001
  this.autoImplProcess = null;
28706
29002
  this.autoImplStatus.running = false;
28707
29003
  const success2 = code === 0;
28708
- this.sendAutoImplSSE({ event: "complete", data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 ACP Auto-implement \uC644\uB8CC" : `\u274C ACP \uC5D0\uC774\uC804\uD2B8 \uC885\uB8CC (code: ${code})` } });
29004
+ this.sendAutoImplSSE({ event: "complete", data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 ACP Auto-implement complete" : `\u274C ACP agent exited (code: ${code})` } });
28709
29005
  try {
28710
29006
  this.providerLoader.reload();
28711
29007
  } catch {
@@ -28720,16 +29016,16 @@ var init_dev_server = __esm({
28720
29016
  try {
28721
29017
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "initializing", message: "ACP initialize..." } });
28722
29018
  await connection.initialize({ protocolVersion: PROTOCOL_VERSION2, clientCapabilities: {} });
28723
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "session", message: "ACP session \uC0DD\uC131 \uC911..." } });
29019
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "session", message: "Creating ACP session..." } });
28724
29020
  const session = await connection.newSession({ cwd: providerDir, mcpServers: [] });
28725
29021
  const sessionId = session?.sessionId;
28726
29022
  if (!sessionId) throw new Error("No sessionId returned from session/new");
28727
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "prompting", message: `\uD504\uB86C\uD504\uD2B8 \uC804\uC1A1 \uC911 (${prompt.length} chars)...` } });
29023
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "prompting", message: `Sending prompt (${prompt.length} chars)...` } });
28728
29024
  await connection.prompt({
28729
29025
  sessionId,
28730
29026
  prompt: [{ type: "text", text: prompt }]
28731
29027
  });
28732
- this.sendAutoImplSSE({ event: "progress", data: { function: "_done", status: "complete", message: "\u2705 ACP \uD504\uB86C\uD504\uD2B8 \uCC98\uB9AC \uC644\uB8CC" } });
29028
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_done", status: "complete", message: "\u2705 ACP prompt processing complete" } });
28733
29029
  } catch (e) {
28734
29030
  this.sendAutoImplSSE({ event: "output", data: { chunk: `[ACP Error] ${e.message}
28735
29031
  `, stream: "stderr" } });
@@ -28781,7 +29077,7 @@ var init_dev_server = __esm({
28781
29077
  const escapedArgs = baseArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
28782
29078
  shellCmd = `cat '${promptFile}' | ${command} ${escapedArgs}`;
28783
29079
  }
28784
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `\uC5D0\uC774\uC804\uD2B8 \uC2E4\uD589 \uC911: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
29080
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `Spawning agent: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
28785
29081
  this.autoImplStatus = { running: true, type, progress: [] };
28786
29082
  const spawnedAt = Date.now();
28787
29083
  let child;
@@ -28877,7 +29173,7 @@ var init_dev_server = __esm({
28877
29173
  const success2 = code === 0;
28878
29174
  this.sendAutoImplSSE({
28879
29175
  event: "complete",
28880
- data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 Auto-implement \uC644\uB8CC" : `\u274C \uC5D0\uC774\uC804\uD2B8 \uC885\uB8CC (code: ${code})` }
29176
+ data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})` }
28881
29177
  });
28882
29178
  try {
28883
29179
  this.providerLoader.reload();
@@ -28912,7 +29208,7 @@ var init_dev_server = __esm({
28912
29208
  success: success2,
28913
29209
  exitCode: code,
28914
29210
  functions,
28915
- message: success2 ? "\u2705 Auto-implement \uC644\uB8CC" : `\u274C \uC5D0\uC774\uC804\uD2B8 \uC885\uB8CC (code: ${code})`
29211
+ message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`
28916
29212
  }
28917
29213
  });
28918
29214
  try {
@@ -28940,7 +29236,10 @@ var init_dev_server = __esm({
28940
29236
  this.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
28941
29237
  }
28942
29238
  }
28943
- buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, userComment) {
29239
+ buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType) {
29240
+ if (provider.category === "cli") {
29241
+ return this.buildCliAutoImplPrompt(type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
29242
+ }
28944
29243
  const lines = [];
28945
29244
  lines.push("You are implementing browser automation scripts for an IDE provider.");
28946
29245
  lines.push("Be concise. Do NOT explain your reasoning. Just edit files directly.");
@@ -29003,7 +29302,7 @@ var init_dev_server = __esm({
29003
29302
  setMode: "set_mode.js"
29004
29303
  };
29005
29304
  if (Object.keys(referenceScripts).length > 0) {
29006
- lines.push("## Reference Implementation (from Antigravity provider)");
29305
+ lines.push(`## Reference Implementation (from ${referenceType || "antigravity"} provider)`);
29007
29306
  lines.push("These are WORKING scripts from another IDE. Adapt the PATTERNS (not selectors) for the target IDE.");
29008
29307
  lines.push("");
29009
29308
  for (const fn of functions) {
@@ -29152,6 +29451,150 @@ var init_dev_server = __esm({
29152
29451
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
29153
29452
  return lines.join("\n");
29154
29453
  }
29454
+ buildCliAutoImplPrompt(type, provider, providerDir, functions, referenceScripts, userComment, referenceType) {
29455
+ const lines = [];
29456
+ lines.push("You are implementing PTY parsing scripts for a CLI provider.");
29457
+ lines.push("Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.");
29458
+ lines.push("");
29459
+ lines.push(`# Target: ${provider.name || type} (${type})`);
29460
+ lines.push(`Provider directory: \`${providerDir}\``);
29461
+ lines.push("Provider category: `cli`");
29462
+ lines.push("");
29463
+ lines.push("## Current Target Files");
29464
+ lines.push("These are the files you need to edit. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
29465
+ lines.push("");
29466
+ const scriptsDir = path12.join(providerDir, "scripts");
29467
+ if (fs9.existsSync(scriptsDir)) {
29468
+ const versions = fs9.readdirSync(scriptsDir).filter((d) => {
29469
+ try {
29470
+ return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
29471
+ } catch {
29472
+ return false;
29473
+ }
29474
+ }).sort().reverse();
29475
+ if (versions.length > 0) {
29476
+ const vDir = path12.join(scriptsDir, versions[0]);
29477
+ lines.push(`Scripts version directory: \`${vDir}\``);
29478
+ lines.push("");
29479
+ for (const file2 of fs9.readdirSync(vDir)) {
29480
+ if (!file2.endsWith(".js")) continue;
29481
+ try {
29482
+ const content = fs9.readFileSync(path12.join(vDir, file2), "utf-8");
29483
+ lines.push(`### \`${file2}\``);
29484
+ lines.push("```javascript");
29485
+ lines.push(content);
29486
+ lines.push("```");
29487
+ lines.push("");
29488
+ } catch {
29489
+ }
29490
+ }
29491
+ }
29492
+ }
29493
+ const funcToFile = {
29494
+ parseOutput: "parse_output.js",
29495
+ detectStatus: "detect_status.js",
29496
+ parseApproval: "parse_approval.js"
29497
+ };
29498
+ if (Object.keys(referenceScripts).length > 0) {
29499
+ lines.push(`## Reference Implementation (from ${referenceType || "another CLI"} provider)`);
29500
+ lines.push("These are working CLI PTY parser scripts. Reuse the parsing shape and runtime contract, but adapt to the target CLI screen.");
29501
+ lines.push("");
29502
+ for (const fn of functions) {
29503
+ const fileName = funcToFile[fn];
29504
+ if (fileName && referenceScripts[fileName]) {
29505
+ lines.push(`### ${fn} \u2192 \`${fileName}\``);
29506
+ lines.push("```javascript");
29507
+ lines.push(referenceScripts[fileName]);
29508
+ lines.push("```");
29509
+ lines.push("");
29510
+ }
29511
+ }
29512
+ if (referenceScripts["scripts.js"]) {
29513
+ lines.push("### Router \u2192 `scripts.js`");
29514
+ lines.push("```javascript");
29515
+ lines.push(referenceScripts["scripts.js"]);
29516
+ lines.push("```");
29517
+ lines.push("");
29518
+ }
29519
+ }
29520
+ lines.push("## Runtime Contract");
29521
+ lines.push("The daemon runtime is already implemented in `packages/daemon-core/src/cli-adapters/provider-cli-adapter.ts`.");
29522
+ lines.push("Your scripts receive PTY-derived input and must return plain JS objects.");
29523
+ lines.push("");
29524
+ lines.push("| Function | Input | Return |");
29525
+ lines.push("|---|---|---|");
29526
+ lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
29527
+ lines.push("| `detectStatus` | `{ tail }` | `idle`, `generating`, `waiting_approval`, or `error` |");
29528
+ lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
29529
+ lines.push("");
29530
+ lines.push("## Rules");
29531
+ lines.push("1. These scripts run in Node.js CommonJS, not in the browser. Do NOT use DOM APIs.");
29532
+ lines.push("2. Prefer `screenText` for current visible UI state. That is the PTY equivalent of parsing the current IDE DOM.");
29533
+ lines.push("3. Use `messages` as prior transcript state so redraws do not duplicate old turns on every parse.");
29534
+ lines.push("4. Use `partialResponse` for the actively streaming assistant text when status is `generating`.");
29535
+ lines.push("5. `detectStatus` must stay lightweight and tail-based. Do not scan the entire history there.");
29536
+ lines.push("6. `parseApproval` should understand the live approval area and return clean button labels.");
29537
+ lines.push("7. Use `rawBuffer` only when ANSI/control-sequence artifacts matter. Do not depend on raw escape noise unless necessary.");
29538
+ lines.push("8. Keep exports compatible with the existing `scripts.js` router (`module.exports = function ...`).");
29539
+ lines.push("9. Do not rewrite unrelated provider config. Only touch the scripts needed for this task unless a tiny supporting change is required.");
29540
+ lines.push("");
29541
+ lines.push("## Task");
29542
+ lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
29543
+ lines.push("");
29544
+ lines.push("## Verification API");
29545
+ lines.push("Use the DevServer CLI debug endpoints, not DOM/CDP routes.");
29546
+ lines.push("");
29547
+ lines.push("### 1. Launch the target CLI");
29548
+ lines.push("```bash");
29549
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
29550
+ lines.push(' -H "Content-Type: application/json" \\');
29551
+ lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
29552
+ lines.push("```");
29553
+ lines.push("");
29554
+ lines.push("### 2. Inspect parsed + raw adapter state");
29555
+ lines.push("```bash");
29556
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
29557
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
29558
+ lines.push("```");
29559
+ lines.push("");
29560
+ lines.push("### 3. Send a rich test prompt");
29561
+ lines.push("```bash");
29562
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
29563
+ lines.push(' -H "Content-Type: application/json" \\');
29564
+ lines.push(` -d '{"type":"${type}","text":"Write a short python snippet, include a markdown table, and briefly explain what you did."}'`);
29565
+ lines.push("```");
29566
+ lines.push("");
29567
+ lines.push("### 4. If approval appears, resolve it");
29568
+ lines.push("```bash");
29569
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
29570
+ lines.push(' -H "Content-Type: application/json" \\');
29571
+ lines.push(` -d '{"type":"${type}","buttonIndex":0}'`);
29572
+ lines.push("```");
29573
+ lines.push("");
29574
+ lines.push("### 5. Stop the CLI when finished");
29575
+ lines.push("```bash");
29576
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/stop \\`);
29577
+ lines.push(' -H "Content-Type: application/json" \\');
29578
+ lines.push(` -d '{"type":"${type}"}'`);
29579
+ lines.push("```");
29580
+ lines.push("");
29581
+ lines.push("## Required Validation");
29582
+ lines.push("1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.");
29583
+ lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
29584
+ lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
29585
+ lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
29586
+ lines.push("5. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
29587
+ lines.push("");
29588
+ if (userComment) {
29589
+ lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
29590
+ lines.push("The user has provided the following additional instructions. Follow them strictly:");
29591
+ lines.push("");
29592
+ lines.push(userComment);
29593
+ lines.push("");
29594
+ }
29595
+ lines.push("Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.");
29596
+ return lines.join("\n");
29597
+ }
29155
29598
  handleAutoImplSSE(type, req, res) {
29156
29599
  res.writeHead(200, {
29157
29600
  "Content-Type": "text/event-stream",
@@ -29179,7 +29622,7 @@ data: ${JSON.stringify(p.data)}
29179
29622
  setTimeout(() => {
29180
29623
  if (this.autoImplProcess) this.autoImplProcess.kill("SIGKILL");
29181
29624
  }, 3e3);
29182
- this.sendAutoImplSSE({ event: "complete", data: { success: false, exitCode: -1, message: "\u26D4 \uC0AC\uC6A9\uC790\uC5D0 \uC758\uD574 \uC911\uB2E8\uB428" } });
29625
+ this.sendAutoImplSSE({ event: "complete", data: { success: false, exitCode: -1, message: "\u26D4 Aborted by user" } });
29183
29626
  this.autoImplProcess = null;
29184
29627
  this.autoImplStatus.running = false;
29185
29628
  this.json(res, 200, { cancelled: true });
@@ -30748,11 +31191,12 @@ ${e?.stack || ""}`);
30748
31191
  });
30749
31192
 
30750
31193
  // src/screenshot-controller.ts
30751
- var ScreenshotController;
31194
+ var import_sharp, ScreenshotController;
30752
31195
  var init_screenshot_controller = __esm({
30753
31196
  "src/screenshot-controller.ts"() {
30754
31197
  "use strict";
30755
31198
  init_src();
31199
+ import_sharp = __toESM(require("sharp"));
30756
31200
  ScreenshotController = class _ScreenshotController {
30757
31201
  deps;
30758
31202
  timer = null;
@@ -30779,12 +31223,16 @@ var init_screenshot_controller = __esm({
30779
31223
  this.profileDirect = {
30780
31224
  minInterval: Math.max(300, planMinIntervalMs),
30781
31225
  maxInterval: Math.max(2e3, planMinIntervalMs),
30782
- quality: 25
31226
+ quality: 25,
31227
+ maxLongEdge: 1728,
31228
+ firstFrameLongEdge: 1920
30783
31229
  };
30784
31230
  this.profileRelay = {
30785
31231
  minInterval: Math.max(700, planMinIntervalMs),
30786
31232
  maxInterval: Math.max(3e3, planMinIntervalMs),
30787
- quality: 12
31233
+ quality: 12,
31234
+ maxLongEdge: 1152,
31235
+ firstFrameLongEdge: 1280
30788
31236
  };
30789
31237
  this.currentInterval = this.profileDirect.maxInterval;
30790
31238
  this.dailyBudgetMinutes = planLimits?.dailyScreenshotMinutes ?? -1;
@@ -30857,6 +31305,7 @@ var init_screenshot_controller = __esm({
30857
31305
  const sizeMatch = buf.length === this.lastSize;
30858
31306
  const hashMatch = hash2 === this.lastHash;
30859
31307
  const anyNeedsFirstFrame = this.deps.hasAnyNeedingFirstFrame();
31308
+ const resizeTarget = anyNeedsFirstFrame ? profile.firstFrameLongEdge : profile.maxLongEdge;
30860
31309
  if (sizeMatch && hashMatch && !anyNeedsFirstFrame) {
30861
31310
  this.staticFrameCount++;
30862
31311
  if (this.staticFrameCount >= this.STATIC_THRESHOLD) {
@@ -30866,13 +31315,14 @@ var init_screenshot_controller = __esm({
30866
31315
  LOG.debug("Screenshot", `skip (unchanged, static=${this.staticFrameCount}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"})`);
30867
31316
  }
30868
31317
  } else {
31318
+ const normalizedBuf = await this.normalizeBuffer(buf, resizeTarget, profile.quality);
30869
31319
  this.lastSize = buf.length;
30870
31320
  this.lastHash = hash2;
30871
31321
  this.staticFrameCount = 0;
30872
31322
  this.currentInterval = profile.minInterval;
30873
- const sent = this.deps.sendScreenshotBuffer(buf);
31323
+ const sent = this.deps.sendScreenshotBuffer(normalizedBuf);
30874
31324
  if (this.debugCount <= 3 || anyNeedsFirstFrame) {
30875
- LOG.debug("Screenshot", `sent: ${buf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
31325
+ LOG.debug("Screenshot", `sent: ${normalizedBuf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
30876
31326
  }
30877
31327
  }
30878
31328
  } else {
@@ -30920,6 +31370,28 @@ var init_screenshot_controller = __esm({
30920
31370
  }
30921
31371
  return h;
30922
31372
  }
31373
+ /** Normalize screenshot resolution before transport so UX feels consistent across machines/DPI. */
31374
+ async normalizeBuffer(buf, maxLongEdge, quality) {
31375
+ try {
31376
+ const image = (0, import_sharp.default)(buf, { failOn: "none" });
31377
+ const meta3 = await image.metadata();
31378
+ const width = meta3.width || 0;
31379
+ const height = meta3.height || 0;
31380
+ if (!width || !height) return buf;
31381
+ const longEdge = Math.max(width, height);
31382
+ if (longEdge <= maxLongEdge) return buf;
31383
+ return await image.resize({
31384
+ width: width >= height ? maxLongEdge : void 0,
31385
+ height: height > width ? maxLongEdge : void 0,
31386
+ fit: "inside",
31387
+ withoutEnlargement: true,
31388
+ kernel: import_sharp.default.kernel.lanczos3
31389
+ }).webp({ quality, effort: 4 }).toBuffer();
31390
+ } catch (e) {
31391
+ LOG.debug("Screenshot", `normalize skipped: ${e?.message || e}`);
31392
+ return buf;
31393
+ }
31394
+ }
30923
31395
  };
30924
31396
  }
30925
31397
  });
@@ -30982,7 +31454,7 @@ var init_adhdev_daemon = __esm({
30982
31454
  fs11 = __toESM(require("fs"));
30983
31455
  path14 = __toESM(require("path"));
30984
31456
  import_chalk2 = __toESM(require("chalk"));
30985
- pkgVersion = "0.6.53";
31457
+ pkgVersion = "0.6.55";
30986
31458
  if (pkgVersion === "unknown") {
30987
31459
  try {
30988
31460
  const possiblePaths = [