adhdev 0.7.46 → 0.8.0

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/cli/index.js CHANGED
@@ -2694,6 +2694,7 @@ var init_chat_history = __esm({
2694
2694
  role: msg.role,
2695
2695
  content: msg.content || "",
2696
2696
  kind: typeof msg.kind === "string" ? msg.kind : void 0,
2697
+ senderName: typeof msg.senderName === "string" ? msg.senderName : void 0,
2697
2698
  agent: agentType,
2698
2699
  instanceId,
2699
2700
  historySessionId: effectiveHistoryKey,
@@ -2732,6 +2733,7 @@ var init_chat_history = __esm({
2732
2733
  kind: "system",
2733
2734
  content,
2734
2735
  receivedAt: options.receivedAt,
2736
+ senderName: options.senderName,
2735
2737
  historyDedupKey: options.dedupKey
2736
2738
  }],
2737
2739
  options.sessionTitle,
@@ -4021,6 +4023,12 @@ function getCurrentManagerKey(h) {
4021
4023
  function getTargetedCliAdapter(h, args, providerType) {
4022
4024
  return h.getCliAdapter(args?.targetSessionId || providerType || h.currentSession?.providerType || h.currentManagerKey);
4023
4025
  }
4026
+ function getTargetInstance(h, args) {
4027
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
4028
+ const sessionId = targetSessionId || h.currentSession?.sessionId || "";
4029
+ if (!sessionId) return null;
4030
+ return h.ctx.instanceManager?.getInstance(sessionId);
4031
+ }
4024
4032
  function getTargetTransport(h, provider) {
4025
4033
  if (h.currentSession?.transport) return h.currentSession.transport;
4026
4034
  switch (provider?.category) {
@@ -4763,6 +4771,7 @@ async function handleResolveAction(h, args) {
4763
4771
  adapter.writeRaw?.(keys);
4764
4772
  }
4765
4773
  LOG.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
4774
+ getTargetInstance(h, args)?.recordApprovalSelection?.(buttons[buttonIndex] ?? button);
4766
4775
  return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
4767
4776
  }
4768
4777
  if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
@@ -15337,10 +15346,10 @@ __export(provider_cli_adapter_exports, {
15337
15346
  normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
15338
15347
  });
15339
15348
  function stripAnsi(str) {
15340
- return str.replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "").replace(/ +/g, " ");
15349
+ return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
15341
15350
  }
15342
15351
  function stripTerminalNoise(str) {
15343
- return String(str || "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, "").replace(/(^|[\s([])(?:\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\[\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d{1,4};\?)(?=$|[\s)\]])/g, "$1").replace(/\r+/g, "\n").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/ {2,}/g, " ");
15352
+ return String(str || "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, "").replace(/(^|[\s([])(?:\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\[\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d{1,4};\?)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d+\$r[0-9;\" ]*[A-Za-z]?)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:>\|[A-Za-z0-9_.:-]+(?:\([^)]*\))?)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:[A-Z]\d(?:\s+[A-Z]\d)+)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d+;[^\s)\]]+)(?=$|[\s)\]])/g, "$1").replace(/\r+/g, "\n").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/ {2,}/g, " ");
15344
15353
  }
15345
15354
  function sanitizeTerminalText(str) {
15346
15355
  return stripTerminalNoise(stripAnsi(str));
@@ -15383,12 +15392,12 @@ function findBinary(name) {
15383
15392
  function isScriptBinary(binaryPath) {
15384
15393
  if (!path7.isAbsolute(binaryPath)) return false;
15385
15394
  try {
15386
- const fs18 = require("fs");
15387
- const resolved = fs18.realpathSync(binaryPath);
15395
+ const fs19 = require("fs");
15396
+ const resolved = fs19.realpathSync(binaryPath);
15388
15397
  const head = Buffer.alloc(8);
15389
- const fd = fs18.openSync(resolved, "r");
15390
- fs18.readSync(fd, head, 0, 8, 0);
15391
- fs18.closeSync(fd);
15398
+ const fd = fs19.openSync(resolved, "r");
15399
+ fs19.readSync(fd, head, 0, 8, 0);
15400
+ fs19.closeSync(fd);
15392
15401
  let i = 0;
15393
15402
  if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
15394
15403
  return head[i] === 35 && head[i + 1] === 33;
@@ -15399,12 +15408,12 @@ function isScriptBinary(binaryPath) {
15399
15408
  function looksLikeMachOOrElf(filePath) {
15400
15409
  if (!path7.isAbsolute(filePath)) return false;
15401
15410
  try {
15402
- const fs18 = require("fs");
15403
- const resolved = fs18.realpathSync(filePath);
15411
+ const fs19 = require("fs");
15412
+ const resolved = fs19.realpathSync(filePath);
15404
15413
  const buf = Buffer.alloc(8);
15405
- const fd = fs18.openSync(resolved, "r");
15406
- fs18.readSync(fd, buf, 0, 8, 0);
15407
- fs18.closeSync(fd);
15414
+ const fd = fs19.openSync(resolved, "r");
15415
+ fs19.readSync(fd, buf, 0, 8, 0);
15416
+ fs19.closeSync(fd);
15408
15417
  let i = 0;
15409
15418
  if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
15410
15419
  const b2 = buf.subarray(i);
@@ -15457,6 +15466,9 @@ function promptLikelyVisible(screenText, promptSnippet) {
15457
15466
  ).length;
15458
15467
  return matched >= required2;
15459
15468
  }
15469
+ function normalizeScreenSnapshot(text) {
15470
+ return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
15471
+ }
15460
15472
  function parsePatternEntry(x) {
15461
15473
  if (x instanceof RegExp) return x;
15462
15474
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -15495,14 +15507,14 @@ var init_provider_cli_adapter = __esm({
15495
15507
  pty2 = require("node-pty");
15496
15508
  if (os9.platform() !== "win32") {
15497
15509
  try {
15498
- const fs18 = require("fs");
15510
+ const fs19 = require("fs");
15499
15511
  const ptyDir = path7.resolve(path7.dirname(require.resolve("node-pty")), "..");
15500
15512
  const platformArch = `${os9.platform()}-${os9.arch()}`;
15501
15513
  const helper = path7.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
15502
- if (fs18.existsSync(helper)) {
15503
- const stat4 = fs18.statSync(helper);
15514
+ if (fs19.existsSync(helper)) {
15515
+ const stat4 = fs19.statSync(helper);
15504
15516
  if (!(stat4.mode & 73)) {
15505
- fs18.chmodSync(helper, stat4.mode | 493);
15517
+ fs19.chmodSync(helper, stat4.mode | 493);
15506
15518
  LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
15507
15519
  }
15508
15520
  }
@@ -15536,10 +15548,25 @@ var init_provider_cli_adapter = __esm({
15536
15548
  this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
15537
15549
  this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
15538
15550
  this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
15551
+ this.providerResolutionMeta = {
15552
+ type: provider.type,
15553
+ name: provider.name,
15554
+ resolvedVersion: provider._resolvedVersion || null,
15555
+ resolvedOs: provider._resolvedOs || null,
15556
+ providerDir: provider._resolvedProviderDir || null,
15557
+ scriptDir: provider._resolvedScriptDir || null,
15558
+ scriptsPath: provider._resolvedScriptsPath || null,
15559
+ scriptsSource: provider._resolvedScriptsSource || null,
15560
+ versionWarning: provider._versionWarning || null
15561
+ };
15539
15562
  this.cliScripts = provider.scripts || {};
15540
15563
  const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
15541
15564
  if (scriptNames.length > 0) {
15542
15565
  LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
15566
+ LOG.info(
15567
+ "CLI",
15568
+ `[${this.cliType}] Provider resolution: providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"} source=${this.providerResolutionMeta.scriptsSource || "-"} version=${this.providerResolutionMeta.resolvedVersion || "-"}`
15569
+ );
15543
15570
  } else {
15544
15571
  LOG.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js`);
15545
15572
  }
@@ -15572,6 +15599,10 @@ var init_provider_cli_adapter = __esm({
15572
15599
  ptyOutputBuffer = "";
15573
15600
  ptyOutputFlushTimer = null;
15574
15601
  pendingTerminalQueryTail = "";
15602
+ lastOutputAt = 0;
15603
+ lastNonEmptyOutputAt = 0;
15604
+ lastScreenChangeAt = 0;
15605
+ lastScreenSnapshot = "";
15575
15606
  // Server log forwarding
15576
15607
  serverConn = null;
15577
15608
  logBuffer = [];
@@ -15592,6 +15623,7 @@ var init_provider_cli_adapter = __esm({
15592
15623
  submitRetryTimer = null;
15593
15624
  submitRetryUsed = false;
15594
15625
  submitRetryPromptSnippet = "";
15626
+ idleFinishCandidate = null;
15595
15627
  // Resize redraw suppression
15596
15628
  resizeSuppressUntil = 0;
15597
15629
  // Debug: status transition history
@@ -15607,6 +15639,12 @@ var init_provider_cli_adapter = __esm({
15607
15639
  /** Max accumulated buffer size (last 50KB) */
15608
15640
  static MAX_ACCUMULATED_BUFFER = 5e4;
15609
15641
  currentTurnScope = null;
15642
+ traceEntries = [];
15643
+ traceSeq = 0;
15644
+ traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
15645
+ static MAX_TRACE_ENTRIES = 250;
15646
+ providerResolutionMeta;
15647
+ static IDLE_FINISH_CONFIRM_MS = 900;
15610
15648
  syncMessageViews() {
15611
15649
  this.messages = [...this.committedMessages];
15612
15650
  this.structuredMessages = [...this.committedMessages];
@@ -15642,8 +15680,89 @@ var init_provider_cli_adapter = __esm({
15642
15680
  this.currentStatus = status;
15643
15681
  this.statusHistory.push({ status, at: Date.now(), trigger });
15644
15682
  if (this.statusHistory.length > 50) this.statusHistory.shift();
15683
+ this.recordTrace("status", {
15684
+ previousStatus: prev,
15685
+ trigger: trigger || null
15686
+ });
15645
15687
  LOG.info("CLI", `[${this.cliType}] status: ${prev} \u2192 ${status}${trigger ? ` (${trigger})` : ""}`);
15646
15688
  }
15689
+ clearIdleFinishCandidate(reason) {
15690
+ if (!this.idleFinishCandidate) return;
15691
+ this.recordTrace("idle_candidate_reset", {
15692
+ reason,
15693
+ candidate: this.idleFinishCandidate
15694
+ });
15695
+ this.idleFinishCandidate = null;
15696
+ }
15697
+ armIdleFinishCandidate(assistantLength) {
15698
+ const now = Date.now();
15699
+ this.idleFinishCandidate = {
15700
+ armedAt: now,
15701
+ lastOutputAt: this.lastOutputAt,
15702
+ lastScreenChangeAt: this.lastScreenChangeAt,
15703
+ responseEpoch: this.responseEpoch,
15704
+ assistantLength
15705
+ };
15706
+ this.recordTrace("idle_candidate_armed", {
15707
+ confirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
15708
+ candidate: this.idleFinishCandidate,
15709
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
15710
+ });
15711
+ if (this.settleTimer) clearTimeout(this.settleTimer);
15712
+ this.settleTimer = setTimeout(() => {
15713
+ this.settleTimer = null;
15714
+ this.settledBuffer = this.recentOutputBuffer;
15715
+ this.evaluateSettled();
15716
+ }, _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS);
15717
+ }
15718
+ summarizeTraceText(text, max = 800) {
15719
+ const value = sanitizeTerminalText(String(text || ""));
15720
+ if (value.length <= max) return value;
15721
+ return `\u2026${value.slice(-max)}`;
15722
+ }
15723
+ summarizeTraceMessages(messages, limit = 3) {
15724
+ return messages.slice(-limit).map((message) => ({
15725
+ role: message.role,
15726
+ content: this.summarizeTraceText(message.content, 240),
15727
+ timestamp: message.timestamp
15728
+ }));
15729
+ }
15730
+ buildTraceParseSnapshot(scope, partialResponse = "") {
15731
+ const scopedBuffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
15732
+ const scopedRawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
15733
+ return {
15734
+ currentTurnScope: scope || null,
15735
+ responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
15736
+ partialResponse: this.summarizeTraceText(partialResponse || this.responseBuffer, 1200),
15737
+ turnBuffer: this.summarizeTraceText(scopedBuffer, 1600),
15738
+ turnRawPreview: this.summarizeTraceText(scopedRawBuffer, 1600),
15739
+ turnSanitizedRawPreview: this.summarizeTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
15740
+ };
15741
+ }
15742
+ recordTrace(type, payload = {}) {
15743
+ const entry = {
15744
+ id: ++this.traceSeq,
15745
+ at: Date.now(),
15746
+ type,
15747
+ status: this.currentStatus,
15748
+ isWaitingForResponse: this.isWaitingForResponse,
15749
+ activeModal: this.activeModal ? { message: this.activeModal.message, buttons: [...this.activeModal.buttons] } : null,
15750
+ payload
15751
+ };
15752
+ this.traceEntries.push(entry);
15753
+ if (this.traceEntries.length > _ProviderCliAdapter.MAX_TRACE_ENTRIES) {
15754
+ this.traceEntries.splice(0, this.traceEntries.length - _ProviderCliAdapter.MAX_TRACE_ENTRIES);
15755
+ }
15756
+ }
15757
+ resetTraceSession() {
15758
+ this.traceEntries = [];
15759
+ this.traceSeq = 0;
15760
+ this.traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
15761
+ this.recordTrace("session_start", {
15762
+ providerType: this.cliType,
15763
+ workingDir: this.workingDir
15764
+ });
15765
+ }
15647
15766
  // Resolved timeouts
15648
15767
  timeouts;
15649
15768
  // Provider approval key mapping
@@ -15689,6 +15808,7 @@ var init_provider_cli_adapter = __esm({
15689
15808
  const isWin = os9.platform() === "win32";
15690
15809
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
15691
15810
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
15811
+ this.resetTraceSession();
15692
15812
  let shellCmd;
15693
15813
  let shellArgs;
15694
15814
  const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
@@ -15714,6 +15834,14 @@ var init_provider_cli_adapter = __esm({
15714
15834
  cwd: this.workingDir,
15715
15835
  env: buildCliSpawnEnv(process.env, spawnConfig.env)
15716
15836
  };
15837
+ this.recordTrace("spawn", {
15838
+ shellCommand: shellCmd,
15839
+ shellArgs,
15840
+ cwd: ptyOpts.cwd,
15841
+ cols: ptyOpts.cols,
15842
+ rows: ptyOpts.rows,
15843
+ providerResolution: this.providerResolutionMeta
15844
+ });
15717
15845
  try {
15718
15846
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
15719
15847
  } catch (err) {
@@ -15756,6 +15884,7 @@ var init_provider_cli_adapter = __esm({
15756
15884
  this.ptyProcess.onExit(({ exitCode }) => {
15757
15885
  LOG.info("CLI", `[${this.cliType}] Exit code ${exitCode}`);
15758
15886
  this.flushPendingOutputParse();
15887
+ this.recordTrace("exit", { exitCode });
15759
15888
  this.ptyProcess = null;
15760
15889
  this.setStatus("stopped", "pty_exit");
15761
15890
  this.ready = false;
@@ -15771,6 +15900,9 @@ var init_provider_cli_adapter = __esm({
15771
15900
  this.currentTurnScope = null;
15772
15901
  this.ready = false;
15773
15902
  await this.ptyProcess.ready;
15903
+ this.recordTrace("ready", {
15904
+ runtimeMeta: this.getRuntimeMetadata()
15905
+ });
15774
15906
  this.setStatus("idle", "pty_ready");
15775
15907
  this.onStatusChange?.();
15776
15908
  }
@@ -15778,6 +15910,24 @@ var init_provider_cli_adapter = __esm({
15778
15910
  handleOutput(rawData) {
15779
15911
  this.terminalScreen.write(rawData);
15780
15912
  const cleanData = sanitizeTerminalText(rawData);
15913
+ const now = Date.now();
15914
+ const normalizedScreenSnapshot = normalizeScreenSnapshot(this.terminalScreen.getText());
15915
+ this.lastOutputAt = now;
15916
+ if (cleanData.trim()) this.lastNonEmptyOutputAt = now;
15917
+ if (normalizedScreenSnapshot !== this.lastScreenSnapshot) {
15918
+ this.lastScreenSnapshot = normalizedScreenSnapshot;
15919
+ this.lastScreenChangeAt = now;
15920
+ }
15921
+ if (this.idleFinishCandidate && (rawData.length > 0 || cleanData.length > 0)) {
15922
+ this.clearIdleFinishCandidate("new_output");
15923
+ }
15924
+ this.recordTrace("output", {
15925
+ rawLength: rawData.length,
15926
+ cleanLength: cleanData.length,
15927
+ rawPreview: this.summarizeTraceText(rawData, 300),
15928
+ cleanPreview: this.summarizeTraceText(cleanData, 300),
15929
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
15930
+ });
15781
15931
  if (this.isWaitingForResponse && cleanData) {
15782
15932
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
15783
15933
  }
@@ -15795,11 +15945,17 @@ var init_provider_cli_adapter = __esm({
15795
15945
  this.startupBuffer += cleanData;
15796
15946
  const elapsed = Date.now() - this.spawnAt;
15797
15947
  const scriptStatus = this.runDetectStatus(this.startupBuffer);
15798
- const isReady = scriptStatus === "idle" || scriptStatus === "waiting_approval" || elapsed > 8e3 || this.startupBuffer.length > 12e3;
15948
+ const screenText = this.terminalScreen.getText() || "";
15949
+ const hasInteractivePrompt = this.looksLikeVisibleIdlePrompt(screenText);
15950
+ const startupStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
15951
+ const isReady = (scriptStatus === "idle" || scriptStatus === "waiting_approval") && hasInteractivePrompt && startupStableMs >= 700 || elapsed > 8e3 || this.startupBuffer.length > 12e3;
15799
15952
  if (isReady) {
15800
15953
  this.startupParseGate = false;
15801
15954
  this.ready = true;
15802
- LOG.info("CLI", `[${this.cliType}] Startup ready (${elapsed}ms, scriptStatus=${scriptStatus})`);
15955
+ LOG.info(
15956
+ "CLI",
15957
+ `[${this.cliType}] Startup ready (${elapsed}ms, scriptStatus=${scriptStatus}, prompt=${hasInteractivePrompt}, stableMs=${startupStableMs}) providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
15958
+ );
15803
15959
  this.onStatusChange?.();
15804
15960
  }
15805
15961
  }
@@ -15844,6 +16000,41 @@ var init_provider_cli_adapter = __esm({
15844
16000
  if (!text.trim()) return false;
15845
16001
  return /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(text) || /⏎\s+send/i.test(text) || /\?\s*for\s*shortcuts/i.test(text) || /Type your message(?:\s+or\s+@path\/to\/file)?/i.test(text) || /workspace\s*\(\/directory\)/i.test(text) || /for\s*shortcuts/i.test(text);
15846
16002
  }
16003
+ async waitForInteractivePrompt(maxWaitMs = 5e3) {
16004
+ const startedAt = Date.now();
16005
+ let loggedWait = false;
16006
+ while (Date.now() - startedAt < maxWaitMs) {
16007
+ const screenText = this.terminalScreen.getText() || "";
16008
+ const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
16009
+ const stableMs = this.lastScreenChangeAt ? Date.now() - this.lastScreenChangeAt : 0;
16010
+ const recentlyOutput = this.lastNonEmptyOutputAt ? Date.now() - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
16011
+ const status = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
16012
+ const startupLikelyActive = /Welcome back|Tips for getting|Recent activity|Claude Code v\d/i.test(screenText);
16013
+ const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "starting" && status !== "generating";
16014
+ if (interactiveReady) {
16015
+ if (loggedWait) {
16016
+ LOG.info(
16017
+ "CLI",
16018
+ `[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput}, startup=${startupLikelyActive})`
16019
+ );
16020
+ }
16021
+ return;
16022
+ }
16023
+ if (!loggedWait && Date.now() - startedAt >= 400) {
16024
+ loggedWait = true;
16025
+ LOG.info(
16026
+ "CLI",
16027
+ `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)}`
16028
+ );
16029
+ }
16030
+ await new Promise((resolve13) => setTimeout(resolve13, 50));
16031
+ }
16032
+ const finalScreenText = this.terminalScreen.getText() || "";
16033
+ LOG.warn(
16034
+ "CLI",
16035
+ `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(this.summarizeTraceText(finalScreenText, 240)).slice(0, 280)}`
16036
+ );
16037
+ }
15847
16038
  evaluateSettled() {
15848
16039
  const now = Date.now();
15849
16040
  if (this.submitPendingUntil > now || this.responseSettleIgnoreUntil > now) {
@@ -15861,6 +16052,30 @@ var init_provider_cli_adapter = __esm({
15861
16052
  const modal = this.runParseApproval(tail);
15862
16053
  const rawScriptStatus = this.runDetectStatus(tail);
15863
16054
  const scriptStatus = rawScriptStatus;
16055
+ const parsedTranscript = this.parseCurrentTranscript(
16056
+ this.committedMessages,
16057
+ this.responseBuffer,
16058
+ this.currentTurnScope
16059
+ );
16060
+ const parsedMessages = Array.isArray(parsedTranscript?.messages) ? this.normalizeParsedMessages(parsedTranscript.messages) : [];
16061
+ const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
16062
+ this.recordTrace("settled", {
16063
+ tail: this.summarizeTraceText(tail, 500),
16064
+ screenText: this.summarizeTraceText(screenText, 1200),
16065
+ detectStatus: scriptStatus,
16066
+ parsedStatus: parsedTranscript?.status || null,
16067
+ parsedMessageCount: parsedMessages.length,
16068
+ parsedLastAssistant: lastParsedAssistant ? this.summarizeTraceText(lastParsedAssistant.content, 280) : "",
16069
+ parsedActiveModal: parsedTranscript?.activeModal ?? null,
16070
+ approval: modal,
16071
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16072
+ });
16073
+ if (this.currentTurnScope && !lastParsedAssistant) {
16074
+ LOG.info(
16075
+ "CLI",
16076
+ `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
16077
+ );
16078
+ }
15864
16079
  if (!scriptStatus) return;
15865
16080
  const prevStatus = this.currentStatus;
15866
16081
  const clearPendingScriptStatus = () => {
@@ -15896,6 +16111,7 @@ var init_provider_cli_adapter = __esm({
15896
16111
  clearPendingScriptStatus();
15897
16112
  }
15898
16113
  if (scriptStatus === "waiting_approval") {
16114
+ this.clearIdleFinishCandidate("waiting_approval");
15899
16115
  const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
15900
16116
  const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
15901
16117
  if ((inCooldown || visibleIdlePrompt) && !modal) {
@@ -15929,6 +16145,7 @@ var init_provider_cli_adapter = __esm({
15929
16145
  }
15930
16146
  }
15931
16147
  if (scriptStatus === "generating") {
16148
+ this.clearIdleFinishCandidate("generating");
15932
16149
  const effectiveScreenText = screenText || this.accumulatedBuffer;
15933
16150
  const noActiveTurn = !this.currentTurnScope;
15934
16151
  const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText) || /accept edits on/i.test(effectiveScreenText) && (/Update available!/i.test(screenText) || /\/effort/i.test(screenText) || /^.*➜\s+\S+/m.test(effectiveScreenText));
@@ -15965,13 +16182,58 @@ var init_provider_cli_adapter = __esm({
15965
16182
  this.lastApprovalResolvedAt = Date.now();
15966
16183
  }
15967
16184
  if (this.isWaitingForResponse) {
16185
+ const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
16186
+ const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
16187
+ const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
16188
+ const hasAssistantTurn = !!lastParsedAssistant;
16189
+ const assistantLength = lastParsedAssistant?.content?.length || 0;
16190
+ const idleQuietThresholdMs = Math.max(220, this.timeouts.outputSettle);
16191
+ const idleStableThresholdMs = Math.max(120, Math.min(220, this.timeouts.outputSettle));
16192
+ const idleReady = visibleIdlePrompt && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
16193
+ const candidate = this.idleFinishCandidate;
16194
+ const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS;
16195
+ const canFinishImmediately = idleReady && candidateQuiet;
16196
+ this.recordTrace("idle_decision", {
16197
+ visibleIdlePrompt,
16198
+ quietForMs,
16199
+ screenStableMs,
16200
+ hasAssistantTurn,
16201
+ assistantLength,
16202
+ hasModal: !!modal,
16203
+ idleQuietThresholdMs,
16204
+ idleStableThresholdMs,
16205
+ idleReady,
16206
+ idleFinishConfirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
16207
+ idleFinishCandidate: candidate,
16208
+ candidateQuiet,
16209
+ canFinishImmediately,
16210
+ submitPendingUntil: this.submitPendingUntil,
16211
+ responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
16212
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16213
+ });
16214
+ if (canFinishImmediately) {
16215
+ this.clearIdleFinishCandidate("finish_response");
16216
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
16217
+ this.finishResponse();
16218
+ return;
16219
+ }
16220
+ if (idleReady) {
16221
+ if (!candidate) {
16222
+ this.armIdleFinishCandidate(assistantLength);
16223
+ return;
16224
+ }
16225
+ } else {
16226
+ this.clearIdleFinishCandidate("idle_not_ready");
16227
+ }
15968
16228
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
15969
16229
  this.idleTimeout = setTimeout(() => {
15970
16230
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
16231
+ this.clearIdleFinishCandidate("idle_timeout_finish");
15971
16232
  this.finishResponse();
15972
16233
  }
15973
16234
  }, this.timeouts.idleFinish);
15974
16235
  } else if (prevStatus !== "idle") {
16236
+ this.clearIdleFinishCandidate("idle_without_response");
15975
16237
  this.setStatus("idle", "script_detect");
15976
16238
  this.onStatusChange?.();
15977
16239
  }
@@ -15980,6 +16242,10 @@ var init_provider_cli_adapter = __esm({
15980
16242
  finishResponse() {
15981
16243
  if (this.submitPendingUntil > Date.now()) return;
15982
16244
  if (this.responseSettleIgnoreUntil > Date.now()) return;
16245
+ this.clearIdleFinishCandidate("finish_response_enter");
16246
+ this.recordTrace("finish_response", {
16247
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16248
+ });
15983
16249
  this.commitCurrentTranscript();
15984
16250
  if (this.responseTimeout) {
15985
16251
  clearTimeout(this.responseTimeout);
@@ -16016,6 +16282,20 @@ var init_provider_cli_adapter = __esm({
16016
16282
  if (parsed && Array.isArray(parsed.messages)) {
16017
16283
  this.committedMessages = this.normalizeParsedMessages(parsed.messages);
16018
16284
  this.syncMessageViews();
16285
+ const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
16286
+ this.recordTrace("commit_transcript", {
16287
+ parsedStatus: parsed.status || null,
16288
+ messageCount: this.committedMessages.length,
16289
+ lastAssistant: lastAssistant ? this.summarizeTraceText(lastAssistant.content, 320) : "",
16290
+ messages: this.summarizeTraceMessages(this.committedMessages),
16291
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16292
+ });
16293
+ if (!lastAssistant && this.currentTurnScope) {
16294
+ LOG.warn(
16295
+ "CLI",
16296
+ `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
16297
+ );
16298
+ }
16019
16299
  }
16020
16300
  }
16021
16301
  // ─── Script Execution ──────────────────────────
@@ -16139,16 +16419,23 @@ ${data.message || ""}`.trim();
16139
16419
  }
16140
16420
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
16141
16421
  if (this.isWaitingForResponse) return;
16422
+ await this.waitForInteractivePrompt();
16142
16423
  this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
16143
16424
  this.syncMessageViews();
16144
16425
  this.isWaitingForResponse = true;
16145
16426
  this.responseBuffer = "";
16427
+ this.clearIdleFinishCandidate("send_message");
16146
16428
  this.currentTurnScope = {
16147
16429
  prompt: text,
16148
16430
  startedAt: Date.now(),
16149
16431
  bufferStart: this.accumulatedBuffer.length,
16150
16432
  rawBufferStart: this.accumulatedRawBuffer.length
16151
16433
  };
16434
+ this.recordTrace("send_message", {
16435
+ text: this.summarizeTraceText(text, 500),
16436
+ estimatedLines: estimatePromptDisplayLines(text),
16437
+ turnScope: this.currentTurnScope
16438
+ });
16152
16439
  LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
16153
16440
  this.submitRetryUsed = false;
16154
16441
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
@@ -16178,6 +16465,11 @@ ${data.message || ""}`.trim();
16178
16465
  const submit = () => {
16179
16466
  if (!this.ptyProcess) return;
16180
16467
  this.submitPendingUntil = 0;
16468
+ this.recordTrace("submit_write", {
16469
+ mode: "submit_key",
16470
+ sendKey: this.sendKey,
16471
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
16472
+ });
16181
16473
  this.ptyProcess.write(this.sendKey);
16182
16474
  const retrySubmitIfStuck = (attempt) => {
16183
16475
  this.submitRetryTimer = null;
@@ -16189,6 +16481,12 @@ ${data.message || ""}`.trim();
16189
16481
  if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
16190
16482
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
16191
16483
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
16484
+ this.recordTrace("submit_write", {
16485
+ mode: "submit_retry",
16486
+ attempt,
16487
+ sendKey: this.sendKey,
16488
+ screenText: this.summarizeTraceText(screenText, 500)
16489
+ });
16192
16490
  this.ptyProcess.write(this.sendKey);
16193
16491
  if (attempt >= 3) {
16194
16492
  this.submitRetryUsed = true;
@@ -16201,6 +16499,12 @@ ${data.message || ""}`.trim();
16201
16499
  };
16202
16500
  if (this.submitStrategy === "immediate") {
16203
16501
  this.submitPendingUntil = 0;
16502
+ this.recordTrace("submit_write", {
16503
+ mode: "immediate",
16504
+ text: this.summarizeTraceText(text, 500),
16505
+ sendKey: this.sendKey,
16506
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
16507
+ });
16204
16508
  this.ptyProcess.write(text + this.sendKey);
16205
16509
  this.submitRetryTimer = setTimeout(() => {
16206
16510
  this.submitRetryTimer = null;
@@ -16211,6 +16515,12 @@ ${data.message || ""}`.trim();
16211
16515
  if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
16212
16516
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
16213
16517
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
16518
+ this.recordTrace("submit_write", {
16519
+ mode: "immediate_retry",
16520
+ attempt: 1,
16521
+ sendKey: this.sendKey,
16522
+ screenText: this.summarizeTraceText(screenText, 500)
16523
+ });
16214
16524
  this.ptyProcess.write(this.sendKey);
16215
16525
  this.submitRetryUsed = true;
16216
16526
  }, retryDelayMs);
@@ -16221,6 +16531,12 @@ ${data.message || ""}`.trim();
16221
16531
  this.submitPendingUntil = Date.now() + submitDelayMs;
16222
16532
  }
16223
16533
  this.ptyProcess.write(text);
16534
+ this.recordTrace("submit_write", {
16535
+ mode: "type_then_submit",
16536
+ text: this.summarizeTraceText(text, 500),
16537
+ sendKey: this.sendKey,
16538
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
16539
+ });
16224
16540
  const submitStartedAt = Date.now();
16225
16541
  let lastNormalizedScreen = "";
16226
16542
  let lastScreenChangeAt = submitStartedAt;
@@ -16321,6 +16637,7 @@ ${data.message || ""}`.trim();
16321
16637
  });
16322
16638
  }
16323
16639
  shutdown() {
16640
+ this.clearIdleFinishCandidate("shutdown");
16324
16641
  if (this.settleTimer) {
16325
16642
  clearTimeout(this.settleTimer);
16326
16643
  this.settleTimer = null;
@@ -16361,6 +16678,7 @@ ${data.message || ""}`.trim();
16361
16678
  }
16362
16679
  }
16363
16680
  detach() {
16681
+ this.clearIdleFinishCandidate("detach");
16364
16682
  if (this.settleTimer) {
16365
16683
  clearTimeout(this.settleTimer);
16366
16684
  this.settleTimer = null;
@@ -16401,6 +16719,7 @@ ${data.message || ""}`.trim();
16401
16719
  this.onStatusChange?.();
16402
16720
  }
16403
16721
  clearHistory() {
16722
+ this.clearIdleFinishCandidate("clear_history");
16404
16723
  this.committedMessages = [];
16405
16724
  this.syncMessageViews();
16406
16725
  this.accumulatedBuffer = "";
@@ -16430,10 +16749,19 @@ ${data.message || ""}`.trim();
16430
16749
  return this.ready;
16431
16750
  }
16432
16751
  writeRaw(data) {
16752
+ this.recordTrace("write_raw", {
16753
+ keys: JSON.stringify(data),
16754
+ length: data.length
16755
+ });
16433
16756
  this.ptyProcess?.write(data);
16434
16757
  }
16435
16758
  resolveModal(buttonIndex) {
16436
16759
  if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
16760
+ this.clearIdleFinishCandidate("resolve_modal");
16761
+ this.recordTrace("resolve_modal", {
16762
+ buttonIndex,
16763
+ activeModal: this.activeModal
16764
+ });
16437
16765
  this.activeModal = null;
16438
16766
  this.lastApprovalResolvedAt = Date.now();
16439
16767
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
@@ -16465,6 +16793,7 @@ ${data.message || ""}`.trim();
16465
16793
  return {
16466
16794
  type: this.cliType,
16467
16795
  name: this.cliName,
16796
+ providerResolution: this.providerResolutionMeta,
16468
16797
  status: this.currentStatus,
16469
16798
  ready: this.ready,
16470
16799
  startupParseGate: this.startupParseGate,
@@ -16484,6 +16813,10 @@ ${data.message || ""}`.trim();
16484
16813
  rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
16485
16814
  sanitizedRawPreview: sanitizeTerminalText(this.accumulatedRawBuffer).slice(-1e3),
16486
16815
  responseBuffer: this.responseBuffer.slice(-1e3),
16816
+ lastOutputAt: this.lastOutputAt,
16817
+ lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
16818
+ lastScreenChangeAt: this.lastScreenChangeAt,
16819
+ lastScreenSnapshot: this.lastScreenSnapshot.slice(-500),
16487
16820
  isWaitingForResponse: this.isWaitingForResponse,
16488
16821
  activeModal: this.activeModal,
16489
16822
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
@@ -16495,6 +16828,8 @@ ${data.message || ""}`.trim();
16495
16828
  resizeSuppressUntil: this.resizeSuppressUntil,
16496
16829
  hasCliScripts: this.hasCliScripts(),
16497
16830
  scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
16831
+ traceSessionId: this.traceSessionId,
16832
+ traceEntryCount: this.traceEntries.length,
16498
16833
  statusHistory: this.statusHistory.slice(-30),
16499
16834
  timeouts: this.timeouts,
16500
16835
  pendingOutputParseBufferLength: this.pendingOutputParseBuffer.length,
@@ -16502,6 +16837,25 @@ ${data.message || ""}`.trim();
16502
16837
  ptyAlive: !!this.ptyProcess
16503
16838
  };
16504
16839
  }
16840
+ getTraceState(limit = 120) {
16841
+ const cappedLimit = Math.max(1, Math.min(500, Number.isFinite(limit) ? Math.floor(limit) : 120));
16842
+ return {
16843
+ sessionId: this.traceSessionId,
16844
+ providerResolution: this.providerResolutionMeta,
16845
+ entryCount: this.traceEntries.length,
16846
+ entries: this.traceEntries.slice(-cappedLimit),
16847
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 4e3),
16848
+ recentOutputBuffer: this.summarizeTraceText(this.recentOutputBuffer, 1e3),
16849
+ responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
16850
+ status: this.currentStatus,
16851
+ activeModal: this.activeModal,
16852
+ currentTurnScope: this.currentTurnScope,
16853
+ messages: this.summarizeTraceMessages(this.committedMessages, 5)
16854
+ };
16855
+ }
16856
+ getProviderResolutionMeta() {
16857
+ return { ...this.providerResolutionMeta };
16858
+ }
16505
16859
  respondToTerminalQueries(data) {
16506
16860
  if (!this.ptyProcess || !data) return;
16507
16861
  const combined = this.pendingTerminalQueryTail + data;
@@ -16573,6 +16927,7 @@ var init_cli_provider_instance = __esm({
16573
16927
  generatingDebouncePending = null;
16574
16928
  lastApprovalEventAt = 0;
16575
16929
  historyWriter;
16930
+ runtimeMessages = [];
16576
16931
  instanceId;
16577
16932
  presentationMode;
16578
16933
  providerSessionId;
@@ -16635,6 +16990,7 @@ var init_cli_provider_instance = __esm({
16635
16990
  }
16636
16991
  const runtime = this.adapter.getRuntimeMetadata();
16637
16992
  const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
16993
+ const mergedMessages = this.mergeConversationMessages(parsedMessages);
16638
16994
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
16639
16995
  if (parsedMessages.length > 0) {
16640
16996
  let messagesToSave = parsedMessages;
@@ -16664,7 +17020,7 @@ var init_cli_provider_instance = __esm({
16664
17020
  id: `${this.type}_${this.workingDir}`,
16665
17021
  title: parsedStatus?.title || dirName,
16666
17022
  status: parsedStatus?.status || adapterStatus.status,
16667
- messages: parsedMessages,
17023
+ messages: mergedMessages,
16668
17024
  activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
16669
17025
  inputContent: ""
16670
17026
  },
@@ -16763,6 +17119,11 @@ var init_cli_provider_instance = __esm({
16763
17119
  const approvalCooldown = 5e3;
16764
17120
  if (this.lastStatus !== "waiting_approval" && (!this.lastApprovalEventAt || now - this.lastApprovalEventAt > approvalCooldown)) {
16765
17121
  this.lastApprovalEventAt = now;
17122
+ this.appendRuntimeSystemMessage(
17123
+ this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
17124
+ `approval_request:${now}`,
17125
+ now
17126
+ );
16766
17127
  this.pushEvent({
16767
17128
  event: "agent:waiting_approval",
16768
17129
  chatTitle,
@@ -16834,11 +17195,71 @@ var init_cli_provider_instance = __esm({
16834
17195
  get cliName() {
16835
17196
  return this.provider.name;
16836
17197
  }
17198
+ recordApprovalSelection(buttonText) {
17199
+ const cleanButton = String(buttonText || "").trim();
17200
+ if (!cleanButton) return;
17201
+ const now = Date.now();
17202
+ this.appendRuntimeSystemMessage(
17203
+ `Approval selected: ${cleanButton}`,
17204
+ `approval_selection:${now}:${cleanButton}`,
17205
+ now
17206
+ );
17207
+ }
16837
17208
  formatMarkerTimestamp(timestamp) {
16838
17209
  const date5 = new Date(timestamp);
16839
17210
  const pad = (value) => String(value).padStart(2, "0");
16840
17211
  return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
16841
17212
  }
17213
+ appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
17214
+ const normalizedContent = String(content || "").trim();
17215
+ if (!normalizedContent) return;
17216
+ if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
17217
+ this.runtimeMessages.push({
17218
+ key: dedupKey,
17219
+ message: {
17220
+ role: "system",
17221
+ senderName: "System",
17222
+ content: normalizedContent,
17223
+ receivedAt,
17224
+ timestamp: receivedAt
17225
+ }
17226
+ });
17227
+ if (this.runtimeMessages.length > 50) {
17228
+ this.runtimeMessages = this.runtimeMessages.slice(-50);
17229
+ }
17230
+ this.historyWriter.appendNewMessages(
17231
+ this.type,
17232
+ [{
17233
+ role: "system",
17234
+ senderName: "System",
17235
+ content: normalizedContent,
17236
+ receivedAt,
17237
+ historyDedupKey: dedupKey
17238
+ }],
17239
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
17240
+ this.instanceId,
17241
+ this.providerSessionId
17242
+ );
17243
+ }
17244
+ mergeConversationMessages(parsedMessages) {
17245
+ if (this.runtimeMessages.length === 0) return parsedMessages;
17246
+ return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b2) => {
17247
+ const aTime = a.message.receivedAt || a.message.timestamp || 0;
17248
+ const bTime = b2.message.receivedAt || b2.message.timestamp || 0;
17249
+ if (aTime !== bTime) return aTime - bTime;
17250
+ return a.index - b2.index;
17251
+ }).map((entry) => entry.message);
17252
+ }
17253
+ formatApprovalRequestMessage(modalMessage, buttons) {
17254
+ const lines = ["Approval requested"];
17255
+ const cleanMessage = String(modalMessage || "").trim();
17256
+ if (cleanMessage) lines.push(cleanMessage);
17257
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
17258
+ if (labels.length > 0) {
17259
+ lines.push(labels.map((label) => `[${label}]`).join(" "));
17260
+ }
17261
+ return lines.join("\n");
17262
+ }
16842
17263
  promoteProviderSessionId(sessionId) {
16843
17264
  const nextSessionId = String(sessionId || "").trim();
16844
17265
  if (!nextSessionId || nextSessionId === this.providerSessionId) return;
@@ -17175,10 +17596,10 @@ function mergeDefs(...defs) {
17175
17596
  function cloneDef(schema) {
17176
17597
  return mergeDefs(schema._zod.def);
17177
17598
  }
17178
- function getElementAtPath(obj, path21) {
17179
- if (!path21)
17599
+ function getElementAtPath(obj, path23) {
17600
+ if (!path23)
17180
17601
  return obj;
17181
- return path21.reduce((acc, key) => acc?.[key], obj);
17602
+ return path23.reduce((acc, key) => acc?.[key], obj);
17182
17603
  }
17183
17604
  function promiseAllObject(promisesObj) {
17184
17605
  const keys = Object.keys(promisesObj);
@@ -17490,11 +17911,11 @@ function aborted(x, startIndex = 0) {
17490
17911
  }
17491
17912
  return false;
17492
17913
  }
17493
- function prefixIssues(path21, issues) {
17914
+ function prefixIssues(path23, issues) {
17494
17915
  return issues.map((iss) => {
17495
17916
  var _a2;
17496
17917
  (_a2 = iss).path ?? (_a2.path = []);
17497
- iss.path.unshift(path21);
17918
+ iss.path.unshift(path23);
17498
17919
  return iss;
17499
17920
  });
17500
17921
  }
@@ -17737,7 +18158,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
17737
18158
  }
17738
18159
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
17739
18160
  const result = { errors: [] };
17740
- const processError = (error49, path21 = []) => {
18161
+ const processError = (error49, path23 = []) => {
17741
18162
  var _a2, _b;
17742
18163
  for (const issue2 of error49.issues) {
17743
18164
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -17747,7 +18168,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
17747
18168
  } else if (issue2.code === "invalid_element") {
17748
18169
  processError({ issues: issue2.issues }, issue2.path);
17749
18170
  } else {
17750
- const fullpath = [...path21, ...issue2.path];
18171
+ const fullpath = [...path23, ...issue2.path];
17751
18172
  if (fullpath.length === 0) {
17752
18173
  result.errors.push(mapper(issue2));
17753
18174
  continue;
@@ -17779,8 +18200,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
17779
18200
  }
17780
18201
  function toDotPath(_path) {
17781
18202
  const segs = [];
17782
- const path21 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17783
- for (const seg of path21) {
18203
+ const path23 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
18204
+ for (const seg of path23) {
17784
18205
  if (typeof seg === "number")
17785
18206
  segs.push(`[${seg}]`);
17786
18207
  else if (typeof seg === "symbol")
@@ -30544,13 +30965,13 @@ function resolveRef(ref, ctx) {
30544
30965
  if (!ref.startsWith("#")) {
30545
30966
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
30546
30967
  }
30547
- const path21 = ref.slice(1).split("/").filter(Boolean);
30548
- if (path21.length === 0) {
30968
+ const path23 = ref.slice(1).split("/").filter(Boolean);
30969
+ if (path23.length === 0) {
30549
30970
  return ctx.rootSchema;
30550
30971
  }
30551
30972
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
30552
- if (path21[0] === defsKey) {
30553
- const key = path21[1];
30973
+ if (path23[0] === defsKey) {
30974
+ const key = path23[1];
30554
30975
  if (!key || !ctx.defs[key]) {
30555
30976
  throw new Error(`Reference not found: ${ref}`);
30556
30977
  }
@@ -34938,7 +35359,7 @@ var init_readdirp = __esm({
34938
35359
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
34939
35360
  const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
34940
35361
  if (wantBigintFsStats) {
34941
- this._stat = (path21) => statMethod(path21, { bigint: true });
35362
+ this._stat = (path23) => statMethod(path23, { bigint: true });
34942
35363
  } else {
34943
35364
  this._stat = statMethod;
34944
35365
  }
@@ -34963,8 +35384,8 @@ var init_readdirp = __esm({
34963
35384
  const par = this.parent;
34964
35385
  const fil = par && par.files;
34965
35386
  if (fil && fil.length > 0) {
34966
- const { path: path21, depth } = par;
34967
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path21));
35387
+ const { path: path23, depth } = par;
35388
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path23));
34968
35389
  const awaited = await Promise.all(slice);
34969
35390
  for (const entry of awaited) {
34970
35391
  if (!entry)
@@ -35004,20 +35425,20 @@ var init_readdirp = __esm({
35004
35425
  this.reading = false;
35005
35426
  }
35006
35427
  }
35007
- async _exploreDir(path21, depth) {
35428
+ async _exploreDir(path23, depth) {
35008
35429
  let files;
35009
35430
  try {
35010
- files = await (0, import_promises.readdir)(path21, this._rdOptions);
35431
+ files = await (0, import_promises.readdir)(path23, this._rdOptions);
35011
35432
  } catch (error48) {
35012
35433
  this._onError(error48);
35013
35434
  }
35014
- return { files, depth, path: path21 };
35435
+ return { files, depth, path: path23 };
35015
35436
  }
35016
- async _formatEntry(dirent, path21) {
35437
+ async _formatEntry(dirent, path23) {
35017
35438
  let entry;
35018
35439
  const basename7 = this._isDirent ? dirent.name : dirent;
35019
35440
  try {
35020
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path21, basename7));
35441
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path23, basename7));
35021
35442
  entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename7 };
35022
35443
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
35023
35444
  } catch (err) {
@@ -35074,16 +35495,16 @@ var init_readdirp = __esm({
35074
35495
  });
35075
35496
 
35076
35497
  // ../../oss/packages/daemon-core/node_modules/chokidar/handler.js
35077
- function createFsWatchInstance(path21, options, listener, errHandler, emitRaw) {
35498
+ function createFsWatchInstance(path23, options, listener, errHandler, emitRaw) {
35078
35499
  const handleEvent = (rawEvent, evPath) => {
35079
- listener(path21);
35080
- emitRaw(rawEvent, evPath, { watchedPath: path21 });
35081
- if (evPath && path21 !== evPath) {
35082
- fsWatchBroadcast(sp.resolve(path21, evPath), KEY_LISTENERS, sp.join(path21, evPath));
35500
+ listener(path23);
35501
+ emitRaw(rawEvent, evPath, { watchedPath: path23 });
35502
+ if (evPath && path23 !== evPath) {
35503
+ fsWatchBroadcast(sp.resolve(path23, evPath), KEY_LISTENERS, sp.join(path23, evPath));
35083
35504
  }
35084
35505
  };
35085
35506
  try {
35086
- return (0, import_node_fs.watch)(path21, {
35507
+ return (0, import_node_fs.watch)(path23, {
35087
35508
  persistent: options.persistent
35088
35509
  }, handleEvent);
35089
35510
  } catch (error48) {
@@ -35432,12 +35853,12 @@ var init_handler2 = __esm({
35432
35853
  listener(val1, val2, val3);
35433
35854
  });
35434
35855
  };
35435
- setFsWatchListener = (path21, fullPath, options, handlers) => {
35856
+ setFsWatchListener = (path23, fullPath, options, handlers) => {
35436
35857
  const { listener, errHandler, rawEmitter } = handlers;
35437
35858
  let cont = FsWatchInstances.get(fullPath);
35438
35859
  let watcher;
35439
35860
  if (!options.persistent) {
35440
- watcher = createFsWatchInstance(path21, options, listener, errHandler, rawEmitter);
35861
+ watcher = createFsWatchInstance(path23, options, listener, errHandler, rawEmitter);
35441
35862
  if (!watcher)
35442
35863
  return;
35443
35864
  return watcher.close.bind(watcher);
@@ -35448,7 +35869,7 @@ var init_handler2 = __esm({
35448
35869
  addAndConvert(cont, KEY_RAW, rawEmitter);
35449
35870
  } else {
35450
35871
  watcher = createFsWatchInstance(
35451
- path21,
35872
+ path23,
35452
35873
  options,
35453
35874
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
35454
35875
  errHandler,
@@ -35463,7 +35884,7 @@ var init_handler2 = __esm({
35463
35884
  cont.watcherUnusable = true;
35464
35885
  if (isWindows && error48.code === "EPERM") {
35465
35886
  try {
35466
- const fd = await (0, import_promises2.open)(path21, "r");
35887
+ const fd = await (0, import_promises2.open)(path23, "r");
35467
35888
  await fd.close();
35468
35889
  broadcastErr(error48);
35469
35890
  } catch (err) {
@@ -35494,7 +35915,7 @@ var init_handler2 = __esm({
35494
35915
  };
35495
35916
  };
35496
35917
  FsWatchFileInstances = /* @__PURE__ */ new Map();
35497
- setFsWatchFileListener = (path21, fullPath, options, handlers) => {
35918
+ setFsWatchFileListener = (path23, fullPath, options, handlers) => {
35498
35919
  const { listener, rawEmitter } = handlers;
35499
35920
  let cont = FsWatchFileInstances.get(fullPath);
35500
35921
  const copts = cont && cont.options;
@@ -35516,7 +35937,7 @@ var init_handler2 = __esm({
35516
35937
  });
35517
35938
  const currmtime = curr.mtimeMs;
35518
35939
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
35519
- foreach(cont.listeners, (listener2) => listener2(path21, curr));
35940
+ foreach(cont.listeners, (listener2) => listener2(path23, curr));
35520
35941
  }
35521
35942
  })
35522
35943
  };
@@ -35546,13 +35967,13 @@ var init_handler2 = __esm({
35546
35967
  * @param listener on fs change
35547
35968
  * @returns closer for the watcher instance
35548
35969
  */
35549
- _watchWithNodeFs(path21, listener) {
35970
+ _watchWithNodeFs(path23, listener) {
35550
35971
  const opts = this.fsw.options;
35551
- const directory = sp.dirname(path21);
35552
- const basename7 = sp.basename(path21);
35972
+ const directory = sp.dirname(path23);
35973
+ const basename7 = sp.basename(path23);
35553
35974
  const parent = this.fsw._getWatchedDir(directory);
35554
35975
  parent.add(basename7);
35555
- const absolutePath = sp.resolve(path21);
35976
+ const absolutePath = sp.resolve(path23);
35556
35977
  const options = {
35557
35978
  persistent: opts.persistent
35558
35979
  };
@@ -35562,12 +35983,12 @@ var init_handler2 = __esm({
35562
35983
  if (opts.usePolling) {
35563
35984
  const enableBin = opts.interval !== opts.binaryInterval;
35564
35985
  options.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
35565
- closer = setFsWatchFileListener(path21, absolutePath, options, {
35986
+ closer = setFsWatchFileListener(path23, absolutePath, options, {
35566
35987
  listener,
35567
35988
  rawEmitter: this.fsw._emitRaw
35568
35989
  });
35569
35990
  } else {
35570
- closer = setFsWatchListener(path21, absolutePath, options, {
35991
+ closer = setFsWatchListener(path23, absolutePath, options, {
35571
35992
  listener,
35572
35993
  errHandler: this._boundHandleError,
35573
35994
  rawEmitter: this.fsw._emitRaw
@@ -35589,7 +36010,7 @@ var init_handler2 = __esm({
35589
36010
  let prevStats = stats;
35590
36011
  if (parent.has(basename7))
35591
36012
  return;
35592
- const listener = async (path21, newStats) => {
36013
+ const listener = async (path23, newStats) => {
35593
36014
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
35594
36015
  return;
35595
36016
  if (!newStats || newStats.mtimeMs === 0) {
@@ -35603,11 +36024,11 @@ var init_handler2 = __esm({
35603
36024
  this.fsw._emit(EV.CHANGE, file2, newStats2);
35604
36025
  }
35605
36026
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
35606
- this.fsw._closeFile(path21);
36027
+ this.fsw._closeFile(path23);
35607
36028
  prevStats = newStats2;
35608
36029
  const closer2 = this._watchWithNodeFs(file2, listener);
35609
36030
  if (closer2)
35610
- this.fsw._addPathCloser(path21, closer2);
36031
+ this.fsw._addPathCloser(path23, closer2);
35611
36032
  } else {
35612
36033
  prevStats = newStats2;
35613
36034
  }
@@ -35639,7 +36060,7 @@ var init_handler2 = __esm({
35639
36060
  * @param item basename of this item
35640
36061
  * @returns true if no more processing is needed for this entry.
35641
36062
  */
35642
- async _handleSymlink(entry, directory, path21, item) {
36063
+ async _handleSymlink(entry, directory, path23, item) {
35643
36064
  if (this.fsw.closed) {
35644
36065
  return;
35645
36066
  }
@@ -35649,7 +36070,7 @@ var init_handler2 = __esm({
35649
36070
  this.fsw._incrReadyCount();
35650
36071
  let linkPath;
35651
36072
  try {
35652
- linkPath = await (0, import_promises2.realpath)(path21);
36073
+ linkPath = await (0, import_promises2.realpath)(path23);
35653
36074
  } catch (e) {
35654
36075
  this.fsw._emitReady();
35655
36076
  return true;
@@ -35659,12 +36080,12 @@ var init_handler2 = __esm({
35659
36080
  if (dir.has(item)) {
35660
36081
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
35661
36082
  this.fsw._symlinkPaths.set(full, linkPath);
35662
- this.fsw._emit(EV.CHANGE, path21, entry.stats);
36083
+ this.fsw._emit(EV.CHANGE, path23, entry.stats);
35663
36084
  }
35664
36085
  } else {
35665
36086
  dir.add(item);
35666
36087
  this.fsw._symlinkPaths.set(full, linkPath);
35667
- this.fsw._emit(EV.ADD, path21, entry.stats);
36088
+ this.fsw._emit(EV.ADD, path23, entry.stats);
35668
36089
  }
35669
36090
  this.fsw._emitReady();
35670
36091
  return true;
@@ -35694,9 +36115,9 @@ var init_handler2 = __esm({
35694
36115
  return;
35695
36116
  }
35696
36117
  const item = entry.path;
35697
- let path21 = sp.join(directory, item);
36118
+ let path23 = sp.join(directory, item);
35698
36119
  current.add(item);
35699
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path21, item)) {
36120
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path23, item)) {
35700
36121
  return;
35701
36122
  }
35702
36123
  if (this.fsw.closed) {
@@ -35705,8 +36126,8 @@ var init_handler2 = __esm({
35705
36126
  }
35706
36127
  if (item === target || !target && !previous.has(item)) {
35707
36128
  this.fsw._incrReadyCount();
35708
- path21 = sp.join(dir, sp.relative(dir, path21));
35709
- this._addToNodeFs(path21, initialAdd, wh, depth + 1);
36129
+ path23 = sp.join(dir, sp.relative(dir, path23));
36130
+ this._addToNodeFs(path23, initialAdd, wh, depth + 1);
35710
36131
  }
35711
36132
  }).on(EV.ERROR, this._boundHandleError);
35712
36133
  return new Promise((resolve13, reject) => {
@@ -35775,13 +36196,13 @@ var init_handler2 = __esm({
35775
36196
  * @param depth Child path actually targeted for watch
35776
36197
  * @param target Child path actually targeted for watch
35777
36198
  */
35778
- async _addToNodeFs(path21, initialAdd, priorWh, depth, target) {
36199
+ async _addToNodeFs(path23, initialAdd, priorWh, depth, target) {
35779
36200
  const ready = this.fsw._emitReady;
35780
- if (this.fsw._isIgnored(path21) || this.fsw.closed) {
36201
+ if (this.fsw._isIgnored(path23) || this.fsw.closed) {
35781
36202
  ready();
35782
36203
  return false;
35783
36204
  }
35784
- const wh = this.fsw._getWatchHelpers(path21);
36205
+ const wh = this.fsw._getWatchHelpers(path23);
35785
36206
  if (priorWh) {
35786
36207
  wh.filterPath = (entry) => priorWh.filterPath(entry);
35787
36208
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -35797,8 +36218,8 @@ var init_handler2 = __esm({
35797
36218
  const follow = this.fsw.options.followSymlinks;
35798
36219
  let closer;
35799
36220
  if (stats.isDirectory()) {
35800
- const absPath = sp.resolve(path21);
35801
- const targetPath = follow ? await (0, import_promises2.realpath)(path21) : path21;
36221
+ const absPath = sp.resolve(path23);
36222
+ const targetPath = follow ? await (0, import_promises2.realpath)(path23) : path23;
35802
36223
  if (this.fsw.closed)
35803
36224
  return;
35804
36225
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -35808,29 +36229,29 @@ var init_handler2 = __esm({
35808
36229
  this.fsw._symlinkPaths.set(absPath, targetPath);
35809
36230
  }
35810
36231
  } else if (stats.isSymbolicLink()) {
35811
- const targetPath = follow ? await (0, import_promises2.realpath)(path21) : path21;
36232
+ const targetPath = follow ? await (0, import_promises2.realpath)(path23) : path23;
35812
36233
  if (this.fsw.closed)
35813
36234
  return;
35814
36235
  const parent = sp.dirname(wh.watchPath);
35815
36236
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
35816
36237
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
35817
- closer = await this._handleDir(parent, stats, initialAdd, depth, path21, wh, targetPath);
36238
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path23, wh, targetPath);
35818
36239
  if (this.fsw.closed)
35819
36240
  return;
35820
36241
  if (targetPath !== void 0) {
35821
- this.fsw._symlinkPaths.set(sp.resolve(path21), targetPath);
36242
+ this.fsw._symlinkPaths.set(sp.resolve(path23), targetPath);
35822
36243
  }
35823
36244
  } else {
35824
36245
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
35825
36246
  }
35826
36247
  ready();
35827
36248
  if (closer)
35828
- this.fsw._addPathCloser(path21, closer);
36249
+ this.fsw._addPathCloser(path23, closer);
35829
36250
  return false;
35830
36251
  } catch (error48) {
35831
36252
  if (this.fsw._handleError(error48)) {
35832
36253
  ready();
35833
- return path21;
36254
+ return path23;
35834
36255
  }
35835
36256
  }
35836
36257
  }
@@ -35865,24 +36286,24 @@ function createPattern(matcher) {
35865
36286
  }
35866
36287
  return () => false;
35867
36288
  }
35868
- function normalizePath(path21) {
35869
- if (typeof path21 !== "string")
36289
+ function normalizePath(path23) {
36290
+ if (typeof path23 !== "string")
35870
36291
  throw new Error("string expected");
35871
- path21 = sp2.normalize(path21);
35872
- path21 = path21.replace(/\\/g, "/");
36292
+ path23 = sp2.normalize(path23);
36293
+ path23 = path23.replace(/\\/g, "/");
35873
36294
  let prepend = false;
35874
- if (path21.startsWith("//"))
36295
+ if (path23.startsWith("//"))
35875
36296
  prepend = true;
35876
- path21 = path21.replace(DOUBLE_SLASH_RE, "/");
36297
+ path23 = path23.replace(DOUBLE_SLASH_RE, "/");
35877
36298
  if (prepend)
35878
- path21 = "/" + path21;
35879
- return path21;
36299
+ path23 = "/" + path23;
36300
+ return path23;
35880
36301
  }
35881
36302
  function matchPatterns(patterns, testString, stats) {
35882
- const path21 = normalizePath(testString);
36303
+ const path23 = normalizePath(testString);
35883
36304
  for (let index = 0; index < patterns.length; index++) {
35884
36305
  const pattern = patterns[index];
35885
- if (pattern(path21, stats)) {
36306
+ if (pattern(path23, stats)) {
35886
36307
  return true;
35887
36308
  }
35888
36309
  }
@@ -35945,19 +36366,19 @@ var init_chokidar = __esm({
35945
36366
  }
35946
36367
  return str;
35947
36368
  };
35948
- normalizePathToUnix = (path21) => toUnix(sp2.normalize(toUnix(path21)));
35949
- normalizeIgnored = (cwd = "") => (path21) => {
35950
- if (typeof path21 === "string") {
35951
- return normalizePathToUnix(sp2.isAbsolute(path21) ? path21 : sp2.join(cwd, path21));
36369
+ normalizePathToUnix = (path23) => toUnix(sp2.normalize(toUnix(path23)));
36370
+ normalizeIgnored = (cwd = "") => (path23) => {
36371
+ if (typeof path23 === "string") {
36372
+ return normalizePathToUnix(sp2.isAbsolute(path23) ? path23 : sp2.join(cwd, path23));
35952
36373
  } else {
35953
- return path21;
36374
+ return path23;
35954
36375
  }
35955
36376
  };
35956
- getAbsolutePath = (path21, cwd) => {
35957
- if (sp2.isAbsolute(path21)) {
35958
- return path21;
36377
+ getAbsolutePath = (path23, cwd) => {
36378
+ if (sp2.isAbsolute(path23)) {
36379
+ return path23;
35959
36380
  }
35960
- return sp2.join(cwd, path21);
36381
+ return sp2.join(cwd, path23);
35961
36382
  };
35962
36383
  EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
35963
36384
  DirEntry = class {
@@ -36022,10 +36443,10 @@ var init_chokidar = __esm({
36022
36443
  dirParts;
36023
36444
  followSymlinks;
36024
36445
  statMethod;
36025
- constructor(path21, follow, fsw) {
36446
+ constructor(path23, follow, fsw) {
36026
36447
  this.fsw = fsw;
36027
- const watchPath = path21;
36028
- this.path = path21 = path21.replace(REPLACER_RE, "");
36448
+ const watchPath = path23;
36449
+ this.path = path23 = path23.replace(REPLACER_RE, "");
36029
36450
  this.watchPath = watchPath;
36030
36451
  this.fullWatchPath = sp2.resolve(watchPath);
36031
36452
  this.dirParts = [];
@@ -36165,20 +36586,20 @@ var init_chokidar = __esm({
36165
36586
  this._closePromise = void 0;
36166
36587
  let paths = unifyPaths(paths_);
36167
36588
  if (cwd) {
36168
- paths = paths.map((path21) => {
36169
- const absPath = getAbsolutePath(path21, cwd);
36589
+ paths = paths.map((path23) => {
36590
+ const absPath = getAbsolutePath(path23, cwd);
36170
36591
  return absPath;
36171
36592
  });
36172
36593
  }
36173
- paths.forEach((path21) => {
36174
- this._removeIgnoredPath(path21);
36594
+ paths.forEach((path23) => {
36595
+ this._removeIgnoredPath(path23);
36175
36596
  });
36176
36597
  this._userIgnored = void 0;
36177
36598
  if (!this._readyCount)
36178
36599
  this._readyCount = 0;
36179
36600
  this._readyCount += paths.length;
36180
- Promise.all(paths.map(async (path21) => {
36181
- const res = await this._nodeFsHandler._addToNodeFs(path21, !_internal, void 0, 0, _origAdd);
36601
+ Promise.all(paths.map(async (path23) => {
36602
+ const res = await this._nodeFsHandler._addToNodeFs(path23, !_internal, void 0, 0, _origAdd);
36182
36603
  if (res)
36183
36604
  this._emitReady();
36184
36605
  return res;
@@ -36200,17 +36621,17 @@ var init_chokidar = __esm({
36200
36621
  return this;
36201
36622
  const paths = unifyPaths(paths_);
36202
36623
  const { cwd } = this.options;
36203
- paths.forEach((path21) => {
36204
- if (!sp2.isAbsolute(path21) && !this._closers.has(path21)) {
36624
+ paths.forEach((path23) => {
36625
+ if (!sp2.isAbsolute(path23) && !this._closers.has(path23)) {
36205
36626
  if (cwd)
36206
- path21 = sp2.join(cwd, path21);
36207
- path21 = sp2.resolve(path21);
36627
+ path23 = sp2.join(cwd, path23);
36628
+ path23 = sp2.resolve(path23);
36208
36629
  }
36209
- this._closePath(path21);
36210
- this._addIgnoredPath(path21);
36211
- if (this._watched.has(path21)) {
36630
+ this._closePath(path23);
36631
+ this._addIgnoredPath(path23);
36632
+ if (this._watched.has(path23)) {
36212
36633
  this._addIgnoredPath({
36213
- path: path21,
36634
+ path: path23,
36214
36635
  recursive: true
36215
36636
  });
36216
36637
  }
@@ -36274,38 +36695,38 @@ var init_chokidar = __esm({
36274
36695
  * @param stats arguments to be passed with event
36275
36696
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
36276
36697
  */
36277
- async _emit(event, path21, stats) {
36698
+ async _emit(event, path23, stats) {
36278
36699
  if (this.closed)
36279
36700
  return;
36280
36701
  const opts = this.options;
36281
36702
  if (isWindows)
36282
- path21 = sp2.normalize(path21);
36703
+ path23 = sp2.normalize(path23);
36283
36704
  if (opts.cwd)
36284
- path21 = sp2.relative(opts.cwd, path21);
36285
- const args = [path21];
36705
+ path23 = sp2.relative(opts.cwd, path23);
36706
+ const args = [path23];
36286
36707
  if (stats != null)
36287
36708
  args.push(stats);
36288
36709
  const awf = opts.awaitWriteFinish;
36289
36710
  let pw;
36290
- if (awf && (pw = this._pendingWrites.get(path21))) {
36711
+ if (awf && (pw = this._pendingWrites.get(path23))) {
36291
36712
  pw.lastChange = /* @__PURE__ */ new Date();
36292
36713
  return this;
36293
36714
  }
36294
36715
  if (opts.atomic) {
36295
36716
  if (event === EVENTS.UNLINK) {
36296
- this._pendingUnlinks.set(path21, [event, ...args]);
36717
+ this._pendingUnlinks.set(path23, [event, ...args]);
36297
36718
  setTimeout(() => {
36298
- this._pendingUnlinks.forEach((entry, path23) => {
36719
+ this._pendingUnlinks.forEach((entry, path24) => {
36299
36720
  this.emit(...entry);
36300
36721
  this.emit(EVENTS.ALL, ...entry);
36301
- this._pendingUnlinks.delete(path23);
36722
+ this._pendingUnlinks.delete(path24);
36302
36723
  });
36303
36724
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
36304
36725
  return this;
36305
36726
  }
36306
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path21)) {
36727
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path23)) {
36307
36728
  event = EVENTS.CHANGE;
36308
- this._pendingUnlinks.delete(path21);
36729
+ this._pendingUnlinks.delete(path23);
36309
36730
  }
36310
36731
  }
36311
36732
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -36323,16 +36744,16 @@ var init_chokidar = __esm({
36323
36744
  this.emitWithAll(event, args);
36324
36745
  }
36325
36746
  };
36326
- this._awaitWriteFinish(path21, awf.stabilityThreshold, event, awfEmit);
36747
+ this._awaitWriteFinish(path23, awf.stabilityThreshold, event, awfEmit);
36327
36748
  return this;
36328
36749
  }
36329
36750
  if (event === EVENTS.CHANGE) {
36330
- const isThrottled = !this._throttle(EVENTS.CHANGE, path21, 50);
36751
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path23, 50);
36331
36752
  if (isThrottled)
36332
36753
  return this;
36333
36754
  }
36334
36755
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
36335
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path21) : path21;
36756
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path23) : path23;
36336
36757
  let stats2;
36337
36758
  try {
36338
36759
  stats2 = await (0, import_promises3.stat)(fullPath);
@@ -36363,23 +36784,23 @@ var init_chokidar = __esm({
36363
36784
  * @param timeout duration of time to suppress duplicate actions
36364
36785
  * @returns tracking object or false if action should be suppressed
36365
36786
  */
36366
- _throttle(actionType, path21, timeout) {
36787
+ _throttle(actionType, path23, timeout) {
36367
36788
  if (!this._throttled.has(actionType)) {
36368
36789
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
36369
36790
  }
36370
36791
  const action = this._throttled.get(actionType);
36371
36792
  if (!action)
36372
36793
  throw new Error("invalid throttle");
36373
- const actionPath = action.get(path21);
36794
+ const actionPath = action.get(path23);
36374
36795
  if (actionPath) {
36375
36796
  actionPath.count++;
36376
36797
  return false;
36377
36798
  }
36378
36799
  let timeoutObject;
36379
36800
  const clear = () => {
36380
- const item = action.get(path21);
36801
+ const item = action.get(path23);
36381
36802
  const count = item ? item.count : 0;
36382
- action.delete(path21);
36803
+ action.delete(path23);
36383
36804
  clearTimeout(timeoutObject);
36384
36805
  if (item)
36385
36806
  clearTimeout(item.timeoutObject);
@@ -36387,7 +36808,7 @@ var init_chokidar = __esm({
36387
36808
  };
36388
36809
  timeoutObject = setTimeout(clear, timeout);
36389
36810
  const thr = { timeoutObject, clear, count: 0 };
36390
- action.set(path21, thr);
36811
+ action.set(path23, thr);
36391
36812
  return thr;
36392
36813
  }
36393
36814
  _incrReadyCount() {
@@ -36401,44 +36822,44 @@ var init_chokidar = __esm({
36401
36822
  * @param event
36402
36823
  * @param awfEmit Callback to be called when ready for event to be emitted.
36403
36824
  */
36404
- _awaitWriteFinish(path21, threshold, event, awfEmit) {
36825
+ _awaitWriteFinish(path23, threshold, event, awfEmit) {
36405
36826
  const awf = this.options.awaitWriteFinish;
36406
36827
  if (typeof awf !== "object")
36407
36828
  return;
36408
36829
  const pollInterval = awf.pollInterval;
36409
36830
  let timeoutHandler;
36410
- let fullPath = path21;
36411
- if (this.options.cwd && !sp2.isAbsolute(path21)) {
36412
- fullPath = sp2.join(this.options.cwd, path21);
36831
+ let fullPath = path23;
36832
+ if (this.options.cwd && !sp2.isAbsolute(path23)) {
36833
+ fullPath = sp2.join(this.options.cwd, path23);
36413
36834
  }
36414
36835
  const now = /* @__PURE__ */ new Date();
36415
36836
  const writes = this._pendingWrites;
36416
36837
  function awaitWriteFinishFn(prevStat) {
36417
36838
  (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
36418
- if (err || !writes.has(path21)) {
36839
+ if (err || !writes.has(path23)) {
36419
36840
  if (err && err.code !== "ENOENT")
36420
36841
  awfEmit(err);
36421
36842
  return;
36422
36843
  }
36423
36844
  const now2 = Number(/* @__PURE__ */ new Date());
36424
36845
  if (prevStat && curStat.size !== prevStat.size) {
36425
- writes.get(path21).lastChange = now2;
36846
+ writes.get(path23).lastChange = now2;
36426
36847
  }
36427
- const pw = writes.get(path21);
36848
+ const pw = writes.get(path23);
36428
36849
  const df = now2 - pw.lastChange;
36429
36850
  if (df >= threshold) {
36430
- writes.delete(path21);
36851
+ writes.delete(path23);
36431
36852
  awfEmit(void 0, curStat);
36432
36853
  } else {
36433
36854
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
36434
36855
  }
36435
36856
  });
36436
36857
  }
36437
- if (!writes.has(path21)) {
36438
- writes.set(path21, {
36858
+ if (!writes.has(path23)) {
36859
+ writes.set(path23, {
36439
36860
  lastChange: now,
36440
36861
  cancelWait: () => {
36441
- writes.delete(path21);
36862
+ writes.delete(path23);
36442
36863
  clearTimeout(timeoutHandler);
36443
36864
  return event;
36444
36865
  }
@@ -36449,8 +36870,8 @@ var init_chokidar = __esm({
36449
36870
  /**
36450
36871
  * Determines whether user has asked to ignore this path.
36451
36872
  */
36452
- _isIgnored(path21, stats) {
36453
- if (this.options.atomic && DOT_RE.test(path21))
36873
+ _isIgnored(path23, stats) {
36874
+ if (this.options.atomic && DOT_RE.test(path23))
36454
36875
  return true;
36455
36876
  if (!this._userIgnored) {
36456
36877
  const { cwd } = this.options;
@@ -36460,17 +36881,17 @@ var init_chokidar = __esm({
36460
36881
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
36461
36882
  this._userIgnored = anymatch(list, void 0);
36462
36883
  }
36463
- return this._userIgnored(path21, stats);
36884
+ return this._userIgnored(path23, stats);
36464
36885
  }
36465
- _isntIgnored(path21, stat4) {
36466
- return !this._isIgnored(path21, stat4);
36886
+ _isntIgnored(path23, stat4) {
36887
+ return !this._isIgnored(path23, stat4);
36467
36888
  }
36468
36889
  /**
36469
36890
  * Provides a set of common helpers and properties relating to symlink handling.
36470
36891
  * @param path file or directory pattern being watched
36471
36892
  */
36472
- _getWatchHelpers(path21) {
36473
- return new WatchHelper(path21, this.options.followSymlinks, this);
36893
+ _getWatchHelpers(path23) {
36894
+ return new WatchHelper(path23, this.options.followSymlinks, this);
36474
36895
  }
36475
36896
  // Directory helpers
36476
36897
  // -----------------
@@ -36502,63 +36923,63 @@ var init_chokidar = __esm({
36502
36923
  * @param item base path of item/directory
36503
36924
  */
36504
36925
  _remove(directory, item, isDirectory) {
36505
- const path21 = sp2.join(directory, item);
36506
- const fullPath = sp2.resolve(path21);
36507
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path21) || this._watched.has(fullPath);
36508
- if (!this._throttle("remove", path21, 100))
36926
+ const path23 = sp2.join(directory, item);
36927
+ const fullPath = sp2.resolve(path23);
36928
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path23) || this._watched.has(fullPath);
36929
+ if (!this._throttle("remove", path23, 100))
36509
36930
  return;
36510
36931
  if (!isDirectory && this._watched.size === 1) {
36511
36932
  this.add(directory, item, true);
36512
36933
  }
36513
- const wp = this._getWatchedDir(path21);
36934
+ const wp = this._getWatchedDir(path23);
36514
36935
  const nestedDirectoryChildren = wp.getChildren();
36515
- nestedDirectoryChildren.forEach((nested) => this._remove(path21, nested));
36936
+ nestedDirectoryChildren.forEach((nested) => this._remove(path23, nested));
36516
36937
  const parent = this._getWatchedDir(directory);
36517
36938
  const wasTracked = parent.has(item);
36518
36939
  parent.remove(item);
36519
36940
  if (this._symlinkPaths.has(fullPath)) {
36520
36941
  this._symlinkPaths.delete(fullPath);
36521
36942
  }
36522
- let relPath = path21;
36943
+ let relPath = path23;
36523
36944
  if (this.options.cwd)
36524
- relPath = sp2.relative(this.options.cwd, path21);
36945
+ relPath = sp2.relative(this.options.cwd, path23);
36525
36946
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
36526
36947
  const event = this._pendingWrites.get(relPath).cancelWait();
36527
36948
  if (event === EVENTS.ADD)
36528
36949
  return;
36529
36950
  }
36530
- this._watched.delete(path21);
36951
+ this._watched.delete(path23);
36531
36952
  this._watched.delete(fullPath);
36532
36953
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
36533
- if (wasTracked && !this._isIgnored(path21))
36534
- this._emit(eventName, path21);
36535
- this._closePath(path21);
36954
+ if (wasTracked && !this._isIgnored(path23))
36955
+ this._emit(eventName, path23);
36956
+ this._closePath(path23);
36536
36957
  }
36537
36958
  /**
36538
36959
  * Closes all watchers for a path
36539
36960
  */
36540
- _closePath(path21) {
36541
- this._closeFile(path21);
36542
- const dir = sp2.dirname(path21);
36543
- this._getWatchedDir(dir).remove(sp2.basename(path21));
36961
+ _closePath(path23) {
36962
+ this._closeFile(path23);
36963
+ const dir = sp2.dirname(path23);
36964
+ this._getWatchedDir(dir).remove(sp2.basename(path23));
36544
36965
  }
36545
36966
  /**
36546
36967
  * Closes only file-specific watchers
36547
36968
  */
36548
- _closeFile(path21) {
36549
- const closers = this._closers.get(path21);
36969
+ _closeFile(path23) {
36970
+ const closers = this._closers.get(path23);
36550
36971
  if (!closers)
36551
36972
  return;
36552
36973
  closers.forEach((closer) => closer());
36553
- this._closers.delete(path21);
36974
+ this._closers.delete(path23);
36554
36975
  }
36555
- _addPathCloser(path21, closer) {
36976
+ _addPathCloser(path23, closer) {
36556
36977
  if (!closer)
36557
36978
  return;
36558
- let list = this._closers.get(path21);
36979
+ let list = this._closers.get(path23);
36559
36980
  if (!list) {
36560
36981
  list = [];
36561
- this._closers.set(path21, list);
36982
+ this._closers.set(path23, list);
36562
36983
  }
36563
36984
  list.push(closer);
36564
36985
  }
@@ -36934,6 +37355,7 @@ var init_provider_loader = __esm({
36934
37355
  resolve(type, context) {
36935
37356
  const base = this.providers.get(type);
36936
37357
  if (!base) return void 0;
37358
+ const providerDir = this.findProviderDirInternal(type) || void 0;
36937
37359
  const currentOs = context?.os || process.platform;
36938
37360
  const currentVersion = context?.version ?? this.versionArchive?.getLatest(type) ?? void 0;
36939
37361
  const resolved = JSON.parse(JSON.stringify(base));
@@ -36943,6 +37365,9 @@ var init_provider_loader = __esm({
36943
37365
  if (base.scripts) {
36944
37366
  resolved.scripts = { ...base.scripts };
36945
37367
  }
37368
+ if (providerDir) {
37369
+ resolved._resolvedProviderDir = providerDir;
37370
+ }
36946
37371
  if (base.os?.[currentOs]) {
36947
37372
  const osOverride = base.os[currentOs];
36948
37373
  if (osOverride.scripts) {
@@ -36963,6 +37388,12 @@ var init_provider_loader = __esm({
36963
37388
  if (loaded) {
36964
37389
  resolved.scripts = loaded;
36965
37390
  this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
37391
+ resolved._resolvedScriptDir = entry.scriptDir;
37392
+ resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
37393
+ if (providerDir) {
37394
+ const fullDir = path10.join(providerDir, entry.scriptDir);
37395
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37396
+ }
36966
37397
  matched = true;
36967
37398
  }
36968
37399
  break;
@@ -36973,6 +37404,12 @@ var init_provider_loader = __esm({
36973
37404
  if (loaded) {
36974
37405
  resolved.scripts = loaded;
36975
37406
  this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
37407
+ resolved._resolvedScriptDir = base.defaultScriptDir;
37408
+ resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
37409
+ if (providerDir) {
37410
+ const fullDir = path10.join(providerDir, base.defaultScriptDir);
37411
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37412
+ }
36976
37413
  }
36977
37414
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
36978
37415
  }
@@ -36985,6 +37422,12 @@ var init_provider_loader = __esm({
36985
37422
  if (loaded) {
36986
37423
  resolved.scripts = loaded;
36987
37424
  this.log(` [version override] ${type} ${range} \u2192 ${dirOverride}`);
37425
+ resolved._resolvedScriptDir = dirOverride;
37426
+ resolved._resolvedScriptsSource = `versions:${range}`;
37427
+ if (providerDir) {
37428
+ const fullDir = path10.join(providerDir, dirOverride);
37429
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37430
+ }
36988
37431
  }
36989
37432
  } else if (override.scripts) {
36990
37433
  resolved.scripts = { ...resolved.scripts, ...override.scripts };
@@ -36996,6 +37439,12 @@ var init_provider_loader = __esm({
36996
37439
  if (loaded) {
36997
37440
  resolved.scripts = loaded;
36998
37441
  this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
37442
+ resolved._resolvedScriptDir = base.defaultScriptDir;
37443
+ resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
37444
+ if (providerDir) {
37445
+ const fullDir = path10.join(providerDir, base.defaultScriptDir);
37446
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37447
+ }
36999
37448
  }
37000
37449
  }
37001
37450
  if (base.overrides) {
@@ -37064,6 +37513,9 @@ var init_provider_loader = __esm({
37064
37513
  awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
37065
37514
  });
37066
37515
  const handleChange = (filePath) => {
37516
+ if (/[\/\\]fixtures[\/\\]/.test(filePath)) {
37517
+ return;
37518
+ }
37067
37519
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
37068
37520
  this.log(`File changed: ${path10.basename(filePath)}, reloading...`);
37069
37521
  this.reload();
@@ -37757,7 +38209,7 @@ function detectCurrentWorkspace(ideId) {
37757
38209
  }
37758
38210
  } else if (plat === "win32") {
37759
38211
  try {
37760
- const fs18 = require("fs");
38212
+ const fs19 = require("fs");
37761
38213
  const appNameMap = getMacAppIdentifiers();
37762
38214
  const appName = appNameMap[ideId];
37763
38215
  if (appName) {
@@ -37766,8 +38218,8 @@ function detectCurrentWorkspace(ideId) {
37766
38218
  appName,
37767
38219
  "storage.json"
37768
38220
  );
37769
- if (fs18.existsSync(storagePath)) {
37770
- const data = JSON.parse(fs18.readFileSync(storagePath, "utf-8"));
38221
+ if (fs19.existsSync(storagePath)) {
38222
+ const data = JSON.parse(fs19.readFileSync(storagePath, "utf-8"));
37771
38223
  const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
37772
38224
  if (workspaces.length > 0) {
37773
38225
  const recent = workspaces[0];
@@ -41422,6 +41874,160 @@ var init_dev_cdp_handlers = __esm({
41422
41874
  });
41423
41875
 
41424
41876
  // ../../oss/packages/daemon-core/src/daemon/dev-cli-debug.ts
41877
+ function slugifyFixtureName(value) {
41878
+ const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
41879
+ return normalized || `fixture-${Date.now()}`;
41880
+ }
41881
+ function getCliFixtureDir(ctx, type) {
41882
+ const providerDir = ctx.providerLoader.findProviderDir(type);
41883
+ if (!providerDir) {
41884
+ throw new Error(`Provider directory not found for '${type}'`);
41885
+ }
41886
+ return path16.join(providerDir, "fixtures");
41887
+ }
41888
+ function readCliFixture(ctx, type, name) {
41889
+ const fixtureDir = getCliFixtureDir(ctx, type);
41890
+ const filePath = path16.join(fixtureDir, `${name}.json`);
41891
+ if (!fs13.existsSync(filePath)) {
41892
+ throw new Error(`Fixture not found: ${filePath}`);
41893
+ }
41894
+ return JSON.parse(fs13.readFileSync(filePath, "utf-8"));
41895
+ }
41896
+ function getExerciseTranscriptText(result) {
41897
+ const parts = [];
41898
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41899
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41900
+ for (const message of [...debugMessages, ...traceMessages]) {
41901
+ if (!message || typeof message.content !== "string") continue;
41902
+ parts.push(message.content);
41903
+ }
41904
+ if (typeof result?.debug?.partialResponse === "string") parts.push(result.debug.partialResponse);
41905
+ if (typeof result?.trace?.responseBuffer === "string") parts.push(result.trace.responseBuffer);
41906
+ return parts.join("\n");
41907
+ }
41908
+ function getExerciseLastAssistant(result) {
41909
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41910
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41911
+ for (const messages of [debugMessages, traceMessages]) {
41912
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
41913
+ const message = messages[i];
41914
+ if (message?.role === "assistant" && typeof message.content === "string" && message.content.trim()) {
41915
+ return message.content;
41916
+ }
41917
+ }
41918
+ }
41919
+ return "";
41920
+ }
41921
+ function getExerciseMessageCount(result) {
41922
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41923
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41924
+ return Math.max(debugMessages.length, traceMessages.length);
41925
+ }
41926
+ function compileFixtureRegex(source) {
41927
+ const value = String(source || "").trim();
41928
+ if (!value) return null;
41929
+ const delimited = value.match(/^\/([\s\S]+)\/([dgimsuvy]*)$/);
41930
+ try {
41931
+ if (delimited) {
41932
+ return new RegExp(delimited[1], delimited[2]);
41933
+ }
41934
+ return new RegExp(value, "m");
41935
+ } catch {
41936
+ return null;
41937
+ }
41938
+ }
41939
+ function statusesContainSequence(actual, expected) {
41940
+ if (!expected.length) return true;
41941
+ let index = 0;
41942
+ for (const status of actual) {
41943
+ if (status === expected[index]) index += 1;
41944
+ if (index >= expected.length) return true;
41945
+ }
41946
+ return false;
41947
+ }
41948
+ function validateCliFixtureResult(result, assertions) {
41949
+ const failures = [];
41950
+ const transcriptText = getExerciseTranscriptText(result);
41951
+ const lastAssistant = getExerciseLastAssistant(result);
41952
+ const mustContainAny = assertions.mustContainAny || [];
41953
+ const mustNotContainAny = assertions.mustNotContainAny || [];
41954
+ const mustMatchAny = assertions.mustMatchAny || [];
41955
+ const mustNotMatchAny = assertions.mustNotMatchAny || [];
41956
+ const lastAssistantMustContainAny = assertions.lastAssistantMustContainAny || [];
41957
+ const lastAssistantMustNotContainAny = assertions.lastAssistantMustNotContainAny || [];
41958
+ const lastAssistantMustMatchAny = assertions.lastAssistantMustMatchAny || [];
41959
+ const lastAssistantMustNotMatchAny = assertions.lastAssistantMustNotMatchAny || [];
41960
+ const statusesSeen = Array.isArray(result?.statusesSeen) ? result.statusesSeen.map((value) => String(value)) : [];
41961
+ if (assertions.requireNotTimedOut !== false && result?.timedOut) {
41962
+ failures.push("Exercise timed out");
41963
+ }
41964
+ const missingRequired = mustContainAny.filter((value) => !transcriptText.includes(value));
41965
+ if (missingRequired.length > 0) {
41966
+ failures.push(`Missing required substrings: ${missingRequired.join(", ")}`);
41967
+ }
41968
+ const presentBanned = mustNotContainAny.filter((value) => transcriptText.includes(value));
41969
+ if (presentBanned.length > 0) {
41970
+ failures.push(`Found banned substrings: ${presentBanned.join(", ")}`);
41971
+ }
41972
+ const missingRegex = mustMatchAny.filter((value) => {
41973
+ const regex = compileFixtureRegex(value);
41974
+ return !regex || !regex.test(transcriptText);
41975
+ });
41976
+ if (missingRegex.length > 0) {
41977
+ failures.push(`Missing required regex matches: ${missingRegex.join(", ")}`);
41978
+ }
41979
+ const presentBannedRegex = mustNotMatchAny.filter((value) => {
41980
+ const regex = compileFixtureRegex(value);
41981
+ return !!regex && regex.test(transcriptText);
41982
+ });
41983
+ if (presentBannedRegex.length > 0) {
41984
+ failures.push(`Found banned regex matches: ${presentBannedRegex.join(", ")}`);
41985
+ }
41986
+ const missingLastAssistant = lastAssistantMustContainAny.filter((value) => !lastAssistant.includes(value));
41987
+ if (missingLastAssistant.length > 0) {
41988
+ failures.push(`Missing required lastAssistant substrings: ${missingLastAssistant.join(", ")}`);
41989
+ }
41990
+ const presentBannedLastAssistant = lastAssistantMustNotContainAny.filter((value) => lastAssistant.includes(value));
41991
+ if (presentBannedLastAssistant.length > 0) {
41992
+ failures.push(`Found banned lastAssistant substrings: ${presentBannedLastAssistant.join(", ")}`);
41993
+ }
41994
+ const missingLastAssistantRegex = lastAssistantMustMatchAny.filter((value) => {
41995
+ const regex = compileFixtureRegex(value);
41996
+ return !regex || !regex.test(lastAssistant);
41997
+ });
41998
+ if (missingLastAssistantRegex.length > 0) {
41999
+ failures.push(`Missing required lastAssistant regex matches: ${missingLastAssistantRegex.join(", ")}`);
42000
+ }
42001
+ const presentBannedLastAssistantRegex = lastAssistantMustNotMatchAny.filter((value) => {
42002
+ const regex = compileFixtureRegex(value);
42003
+ return !!regex && regex.test(lastAssistant);
42004
+ });
42005
+ if (presentBannedLastAssistantRegex.length > 0) {
42006
+ failures.push(`Found banned lastAssistant regex matches: ${presentBannedLastAssistantRegex.join(", ")}`);
42007
+ }
42008
+ if (assertions.statusesSeen?.length && !statusesContainSequence(statusesSeen, assertions.statusesSeen)) {
42009
+ failures.push(`Expected statuses sequence not observed: ${assertions.statusesSeen.join(" -> ")}`);
42010
+ }
42011
+ if (result && typeof result === "object") {
42012
+ result.lastAssistant = lastAssistant;
42013
+ }
42014
+ return failures;
42015
+ }
42016
+ function getCliProviderResolutionMeta(ctx, type, adapter) {
42017
+ const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
42018
+ const resolvedProvider = ctx.providerLoader.resolve(type);
42019
+ if (!adapterMeta && !resolvedProvider) return null;
42020
+ return {
42021
+ type,
42022
+ providerDir: adapterMeta?.providerDir || resolvedProvider?._resolvedProviderDir || ctx.providerLoader.findProviderDir(type),
42023
+ scriptDir: adapterMeta?.scriptDir || resolvedProvider?._resolvedScriptDir || null,
42024
+ scriptsPath: adapterMeta?.scriptsPath || resolvedProvider?._resolvedScriptsPath || null,
42025
+ scriptsSource: adapterMeta?.scriptsSource || resolvedProvider?._resolvedScriptsSource || null,
42026
+ resolvedVersion: adapterMeta?.resolvedVersion || resolvedProvider?._resolvedVersion || null,
42027
+ resolvedOs: adapterMeta?.resolvedOs || resolvedProvider?._resolvedOs || null,
42028
+ versionWarning: adapterMeta?.versionWarning || resolvedProvider?._versionWarning || null
42029
+ };
42030
+ }
41425
42031
  function findCliTarget(ctx, type, instanceId) {
41426
42032
  if (!ctx.instanceManager) return null;
41427
42033
  const cliStates = ctx.instanceManager.collectAllStates().filter((s15) => s15.category === "cli" || s15.category === "acp");
@@ -41430,6 +42036,331 @@ function findCliTarget(ctx, type, instanceId) {
41430
42036
  const matches = cliStates.filter((s15) => s15.type === type);
41431
42037
  return matches[matches.length - 1] || null;
41432
42038
  }
42039
+ function getCliTargetBundle(ctx, type, instanceId) {
42040
+ if (!ctx.instanceManager) return null;
42041
+ const target = findCliTarget(ctx, type, instanceId);
42042
+ if (!target) return null;
42043
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
42044
+ if (!instance) return null;
42045
+ const adapter = instance.getAdapter?.() || instance.adapter;
42046
+ if (!adapter) return null;
42047
+ return { target, instance, adapter };
42048
+ }
42049
+ function sleep(ms2) {
42050
+ return new Promise((resolve13) => setTimeout(resolve13, ms2));
42051
+ }
42052
+ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
42053
+ const startedAt = Date.now();
42054
+ while (Date.now() - startedAt < timeoutMs) {
42055
+ const bundle = getCliTargetBundle(ctx, type, instanceId);
42056
+ if (bundle) {
42057
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42058
+ const startupParseGate = !!debug?.startupParseGate;
42059
+ const adapterReady = !!debug?.ready;
42060
+ const visibleStatusReady = bundle.target.status === "generating" || bundle.target.status === "waiting_approval";
42061
+ const idleReady = bundle.target.status === "idle" && !startupParseGate;
42062
+ if (adapterReady || visibleStatusReady || idleReady) {
42063
+ return bundle;
42064
+ }
42065
+ }
42066
+ await sleep(100);
42067
+ }
42068
+ return getCliTargetBundle(ctx, type, instanceId);
42069
+ }
42070
+ async function runCliExerciseInternal(ctx, body) {
42071
+ if (!ctx.cliManager) {
42072
+ throw new Error("CliManager not available");
42073
+ }
42074
+ if (!ctx.instanceManager) {
42075
+ throw new Error("InstanceManager not available");
42076
+ }
42077
+ const {
42078
+ type,
42079
+ text,
42080
+ instanceId: requestedInstanceId,
42081
+ workingDir,
42082
+ args,
42083
+ autoLaunch = true,
42084
+ freshSession = true,
42085
+ autoResolveApprovals = true,
42086
+ approvalButtonIndex = 0,
42087
+ timeoutMs = 45e3,
42088
+ readyTimeoutMs = 15e3,
42089
+ idleSettledMs = 1200,
42090
+ traceLimit = 160,
42091
+ stopWhenDone = false
42092
+ } = body || {};
42093
+ if (!type) {
42094
+ throw new Error("type required (e.g. claude-cli, codex-cli)");
42095
+ }
42096
+ if (!text || typeof text !== "string") {
42097
+ throw new Error("text required (prompt to send to the CLI)");
42098
+ }
42099
+ let resolvedInstanceId = requestedInstanceId;
42100
+ if (freshSession) {
42101
+ const staleTargets = ctx.instanceManager.collectAllStates().filter((state) => (state.category === "cli" || state.category === "acp") && state.type === type).map((state) => state.instanceId);
42102
+ for (const staleId of staleTargets) {
42103
+ ctx.instanceManager.removeInstance(staleId);
42104
+ }
42105
+ resolvedInstanceId = void 0;
42106
+ }
42107
+ let bundle = getCliTargetBundle(ctx, type, resolvedInstanceId);
42108
+ if (!bundle && autoLaunch) {
42109
+ const launchArgs = [type, workingDir || process.cwd(), Array.isArray(args) ? args : []];
42110
+ let launched = null;
42111
+ let lastLaunchError = null;
42112
+ for (let attempt = 1; attempt <= 2; attempt += 1) {
42113
+ try {
42114
+ launched = await ctx.cliManager.startSession(...launchArgs);
42115
+ lastLaunchError = null;
42116
+ break;
42117
+ } catch (error48) {
42118
+ lastLaunchError = error48 instanceof Error ? error48 : new Error(String(error48?.message || error48));
42119
+ const message = String(lastLaunchError.message || "");
42120
+ const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
42121
+ if (!retryable || attempt === 2) break;
42122
+ await sleep(1e3);
42123
+ }
42124
+ }
42125
+ if (!launched) {
42126
+ throw lastLaunchError || new Error(`Failed to start ${type}`);
42127
+ }
42128
+ resolvedInstanceId = launched.runtimeSessionId;
42129
+ bundle = await waitForCliReady(ctx, type, resolvedInstanceId, Math.max(1e3, readyTimeoutMs));
42130
+ }
42131
+ if (!bundle) {
42132
+ throw new Error(`No running instance found for: ${resolvedInstanceId || type}`);
42133
+ }
42134
+ const initialDebug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42135
+ const initialTrace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
42136
+ const providerResolution = getCliProviderResolutionMeta(ctx, bundle.target.type, bundle.adapter);
42137
+ const preTraceCount = Number(initialTrace?.entryCount || 0);
42138
+ const startAt = Date.now();
42139
+ const statusesSeen = [];
42140
+ const approvalsResolved = [];
42141
+ let lastStatus = "";
42142
+ let lastModalKey = "";
42143
+ let idleSince = 0;
42144
+ let sawBusy = false;
42145
+ ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
42146
+ while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
42147
+ await sleep(150);
42148
+ bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
42149
+ if (!bundle) {
42150
+ throw new Error("CLI instance disappeared during exercise");
42151
+ }
42152
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42153
+ const trace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
42154
+ const status = String(debug?.status || bundle.target.status || "unknown");
42155
+ const traceEntries = Array.isArray(trace?.entries) ? trace.entries : [];
42156
+ const sawSendMessage = traceEntries.some((entry) => entry?.type === "send_message");
42157
+ const sawSubmitWrite = traceEntries.some((entry) => entry?.type === "submit_write");
42158
+ const hasTurnStarted = sawSendMessage || sawSubmitWrite || !!debug?.currentTurnScope;
42159
+ if (status !== lastStatus) {
42160
+ statusesSeen.push(status);
42161
+ lastStatus = status;
42162
+ }
42163
+ if (status === "generating" || status === "waiting_approval") {
42164
+ sawBusy = true;
42165
+ idleSince = 0;
42166
+ }
42167
+ const modal = debug?.activeModal || trace?.activeModal || null;
42168
+ if (autoResolveApprovals && status === "waiting_approval" && modal && Array.isArray(modal.buttons) && modal.buttons.length > 0) {
42169
+ const clampedIndex = Math.max(0, Math.min(Number(approvalButtonIndex) || 0, modal.buttons.length - 1));
42170
+ const modalKey = JSON.stringify({
42171
+ message: modal.message || "",
42172
+ buttons: modal.buttons,
42173
+ index: clampedIndex
42174
+ });
42175
+ if (modalKey !== lastModalKey && typeof bundle.adapter.resolveModal === "function") {
42176
+ lastModalKey = modalKey;
42177
+ approvalsResolved.push({
42178
+ at: Date.now(),
42179
+ buttonIndex: clampedIndex,
42180
+ label: modal.buttons[clampedIndex] || null
42181
+ });
42182
+ bundle.adapter.resolveModal(clampedIndex);
42183
+ continue;
42184
+ }
42185
+ }
42186
+ const traceCount = Number(trace?.entryCount || 0);
42187
+ const hasProgress = hasTurnStarted && (traceCount > preTraceCount || statusesSeen.length > 1 || approvalsResolved.length > 0);
42188
+ if (status === "idle" && hasProgress && sawBusy) {
42189
+ if (!idleSince) idleSince = Date.now();
42190
+ if (Date.now() - idleSince >= Math.max(200, idleSettledMs)) {
42191
+ const payload2 = {
42192
+ exercised: true,
42193
+ instanceId: bundle.target.instanceId,
42194
+ providerState: {
42195
+ type: bundle.target.type,
42196
+ name: bundle.target.name,
42197
+ status: bundle.target.status,
42198
+ mode: "mode" in bundle.target ? bundle.target.mode : void 0
42199
+ },
42200
+ providerResolution,
42201
+ initialDebug,
42202
+ initialTrace,
42203
+ debug,
42204
+ trace,
42205
+ statusesSeen,
42206
+ approvalsResolved,
42207
+ elapsedMs: Date.now() - startAt,
42208
+ timedOut: false
42209
+ };
42210
+ payload2.lastAssistant = getExerciseLastAssistant(payload2);
42211
+ payload2.messageCount = getExerciseMessageCount(payload2);
42212
+ if (stopWhenDone) {
42213
+ ctx.instanceManager.removeInstance(bundle.target.instanceId);
42214
+ }
42215
+ return payload2;
42216
+ }
42217
+ } else if (status === "idle" && hasProgress) {
42218
+ if (!idleSince) idleSince = Date.now();
42219
+ if (Date.now() - idleSince >= Math.max(500, idleSettledMs) && Date.now() - startAt >= 750) {
42220
+ const payload2 = {
42221
+ exercised: true,
42222
+ instanceId: bundle.target.instanceId,
42223
+ providerState: {
42224
+ type: bundle.target.type,
42225
+ name: bundle.target.name,
42226
+ status: bundle.target.status,
42227
+ mode: "mode" in bundle.target ? bundle.target.mode : void 0
42228
+ },
42229
+ providerResolution,
42230
+ initialDebug,
42231
+ initialTrace,
42232
+ debug,
42233
+ trace,
42234
+ statusesSeen,
42235
+ approvalsResolved,
42236
+ elapsedMs: Date.now() - startAt,
42237
+ timedOut: false
42238
+ };
42239
+ payload2.lastAssistant = getExerciseLastAssistant(payload2);
42240
+ payload2.messageCount = getExerciseMessageCount(payload2);
42241
+ if (stopWhenDone) {
42242
+ ctx.instanceManager.removeInstance(bundle.target.instanceId);
42243
+ }
42244
+ return payload2;
42245
+ }
42246
+ } else {
42247
+ idleSince = 0;
42248
+ }
42249
+ }
42250
+ const finalBundle = getCliTargetBundle(ctx, type, bundle.target.instanceId) || bundle;
42251
+ const finalDebug = typeof finalBundle.adapter.getDebugState === "function" ? finalBundle.adapter.getDebugState() : null;
42252
+ const finalTrace = typeof finalBundle.adapter.getTraceState === "function" ? finalBundle.adapter.getTraceState(traceLimit) : null;
42253
+ if (stopWhenDone) {
42254
+ ctx.instanceManager.removeInstance(finalBundle.target.instanceId);
42255
+ }
42256
+ const payload = {
42257
+ exercised: true,
42258
+ instanceId: finalBundle.target.instanceId,
42259
+ providerState: {
42260
+ type: finalBundle.target.type,
42261
+ name: finalBundle.target.name,
42262
+ status: finalBundle.target.status,
42263
+ mode: "mode" in finalBundle.target ? finalBundle.target.mode : void 0
42264
+ },
42265
+ providerResolution: getCliProviderResolutionMeta(ctx, finalBundle.target.type, finalBundle.adapter),
42266
+ initialDebug,
42267
+ initialTrace,
42268
+ debug: finalDebug,
42269
+ trace: finalTrace,
42270
+ statusesSeen,
42271
+ approvalsResolved,
42272
+ elapsedMs: Date.now() - startAt,
42273
+ timedOut: true
42274
+ };
42275
+ payload.lastAssistant = getExerciseLastAssistant(payload);
42276
+ payload.messageCount = getExerciseMessageCount(payload);
42277
+ return payload;
42278
+ }
42279
+ async function runCliAutoImplVerification(ctx, type, verification) {
42280
+ const assertions = {
42281
+ mustContainAny: verification?.mustContainAny || [],
42282
+ mustNotContainAny: verification?.mustNotContainAny || [],
42283
+ mustMatchAny: verification?.mustMatchAny || [],
42284
+ mustNotMatchAny: verification?.mustNotMatchAny || [],
42285
+ lastAssistantMustContainAny: verification?.lastAssistantMustContainAny || [],
42286
+ lastAssistantMustNotContainAny: verification?.lastAssistantMustNotContainAny || [],
42287
+ lastAssistantMustMatchAny: verification?.lastAssistantMustMatchAny || [],
42288
+ lastAssistantMustNotMatchAny: verification?.lastAssistantMustNotMatchAny || [],
42289
+ requireNotTimedOut: true
42290
+ };
42291
+ const rawFixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
42292
+ if (rawFixtureNames.length > 0) {
42293
+ const results = [];
42294
+ for (const rawFixtureName2 of rawFixtureNames) {
42295
+ const name = slugifyFixtureName(rawFixtureName2);
42296
+ const fixture = readCliFixture(ctx, type, name);
42297
+ const mergedAssertions = {
42298
+ ...fixture.assertions,
42299
+ ...assertions
42300
+ };
42301
+ const result2 = await runCliExerciseInternal(ctx, {
42302
+ ...fixture.request,
42303
+ type
42304
+ });
42305
+ const failures2 = validateCliFixtureResult(result2, mergedAssertions);
42306
+ results.push({
42307
+ fixtureName: name,
42308
+ pass: failures2.length === 0,
42309
+ failures: failures2,
42310
+ result: result2,
42311
+ assertions: mergedAssertions,
42312
+ fixture
42313
+ });
42314
+ }
42315
+ const firstFailure = results.find((item) => !item.pass) || results[results.length - 1];
42316
+ return {
42317
+ mode: "fixture_replay_suite",
42318
+ pass: results.every((item) => item.pass),
42319
+ failures: results.flatMap((item) => item.failures.map((failure) => `${item.fixtureName}: ${failure}`)),
42320
+ result: firstFailure.result,
42321
+ assertions: firstFailure.assertions,
42322
+ fixture: firstFailure.fixture,
42323
+ results
42324
+ };
42325
+ }
42326
+ const rawFixtureName = String(verification?.fixtureName || "").trim();
42327
+ if (rawFixtureName) {
42328
+ const name = slugifyFixtureName(rawFixtureName);
42329
+ try {
42330
+ const fixture = readCliFixture(ctx, type, name);
42331
+ const mergedAssertions = {
42332
+ ...fixture.assertions,
42333
+ ...assertions
42334
+ };
42335
+ const result2 = await runCliExerciseInternal(ctx, {
42336
+ ...fixture.request,
42337
+ type
42338
+ });
42339
+ const failures2 = validateCliFixtureResult(result2, mergedAssertions);
42340
+ return {
42341
+ mode: "fixture_replay",
42342
+ pass: failures2.length === 0,
42343
+ failures: failures2,
42344
+ result: result2,
42345
+ assertions: mergedAssertions,
42346
+ fixture
42347
+ };
42348
+ } catch {
42349
+ }
42350
+ }
42351
+ const result = await runCliExerciseInternal(ctx, {
42352
+ ...verification?.request || {},
42353
+ type
42354
+ });
42355
+ const failures = validateCliFixtureResult(result, assertions);
42356
+ return {
42357
+ mode: "exercise",
42358
+ pass: failures.length === 0,
42359
+ failures,
42360
+ result,
42361
+ assertions
42362
+ };
42363
+ }
41433
42364
  async function handleCliStatus(ctx, _req, res) {
41434
42365
  if (!ctx.instanceManager) {
41435
42366
  ctx.json(res, 503, { error: "InstanceManager not available (daemon not fully initialized)" });
@@ -41568,12 +42499,14 @@ async function handleCliDebug(ctx, type, _req, res) {
41568
42499
  status: target.status,
41569
42500
  mode: "mode" in target ? target.mode : void 0
41570
42501
  },
42502
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
41571
42503
  debug: debugState
41572
42504
  });
41573
42505
  } else {
41574
42506
  ctx.json(res, 200, {
41575
42507
  instanceId: target.instanceId,
41576
42508
  providerState: target,
42509
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
41577
42510
  debug: null,
41578
42511
  message: "No debug state available (adapter.getDebugState not found)"
41579
42512
  });
@@ -41582,6 +42515,191 @@ async function handleCliDebug(ctx, type, _req, res) {
41582
42515
  ctx.json(res, 500, { error: `Debug state failed: ${e.message}` });
41583
42516
  }
41584
42517
  }
42518
+ async function handleCliTrace(ctx, type, req, res) {
42519
+ if (!ctx.instanceManager) {
42520
+ ctx.json(res, 503, { error: "InstanceManager not available" });
42521
+ return;
42522
+ }
42523
+ const target = findCliTarget(ctx, type);
42524
+ if (!target) {
42525
+ const allStates = ctx.instanceManager.collectAllStates();
42526
+ ctx.json(res, 404, {
42527
+ error: `No running instance for: ${type}`,
42528
+ available: allStates.filter((s15) => s15.category === "cli" || s15.category === "acp").map((s15) => s15.type)
42529
+ });
42530
+ return;
42531
+ }
42532
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
42533
+ if (!instance) {
42534
+ ctx.json(res, 404, { error: `Instance not found: ${target.instanceId}` });
42535
+ return;
42536
+ }
42537
+ try {
42538
+ const adapter = instance.getAdapter?.() || instance.adapter;
42539
+ const url2 = new URL(req.url || "/", "http://127.0.0.1");
42540
+ const limit = parseInt(url2.searchParams.get("limit") || "120", 10);
42541
+ if (adapter && typeof adapter.getTraceState === "function") {
42542
+ const trace = adapter.getTraceState(limit);
42543
+ const debug = typeof adapter.getDebugState === "function" ? adapter.getDebugState() : null;
42544
+ ctx.json(res, 200, {
42545
+ instanceId: target.instanceId,
42546
+ providerState: {
42547
+ type: target.type,
42548
+ name: target.name,
42549
+ status: target.status,
42550
+ mode: "mode" in target ? target.mode : void 0
42551
+ },
42552
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
42553
+ debug,
42554
+ trace
42555
+ });
42556
+ } else {
42557
+ ctx.json(res, 200, {
42558
+ instanceId: target.instanceId,
42559
+ providerState: target,
42560
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
42561
+ debug: typeof adapter?.getDebugState === "function" ? adapter.getDebugState() : null,
42562
+ trace: null,
42563
+ message: "No trace state available (adapter.getTraceState not found)"
42564
+ });
42565
+ }
42566
+ } catch (e) {
42567
+ ctx.json(res, 500, { error: `Trace state failed: ${e.message}` });
42568
+ }
42569
+ }
42570
+ async function handleCliExercise(ctx, req, res) {
42571
+ try {
42572
+ const body = await ctx.readBody(req);
42573
+ const result = await runCliExerciseInternal(ctx, body || {});
42574
+ ctx.json(res, 200, result);
42575
+ } catch (e) {
42576
+ ctx.json(res, 500, { error: `Exercise failed: ${e.message}` });
42577
+ }
42578
+ }
42579
+ async function handleCliFixtureCapture(ctx, req, res) {
42580
+ try {
42581
+ const body = await ctx.readBody(req);
42582
+ const type = String(body?.type || "");
42583
+ const request = body?.request || {};
42584
+ if (!type) {
42585
+ ctx.json(res, 400, { error: "type required" });
42586
+ return;
42587
+ }
42588
+ if (!request?.text) {
42589
+ ctx.json(res, 400, { error: "request.text required" });
42590
+ return;
42591
+ }
42592
+ const fixtureDir = getCliFixtureDir(ctx, type);
42593
+ fs13.mkdirSync(fixtureDir, { recursive: true });
42594
+ const name = slugifyFixtureName(String(body?.name || `${type}-${Date.now()}`));
42595
+ const result = await runCliExerciseInternal(ctx, { ...request, type });
42596
+ const fixture = {
42597
+ version: 1,
42598
+ kind: "cli-exercise-fixture",
42599
+ name,
42600
+ type,
42601
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
42602
+ providerDir: ctx.providerLoader.findProviderDir(type),
42603
+ providerResolution: result?.providerResolution || null,
42604
+ request: { ...request, type },
42605
+ result,
42606
+ assertions: {
42607
+ mustContainAny: Array.isArray(body?.assertions?.mustContainAny) ? body.assertions.mustContainAny : [],
42608
+ mustNotContainAny: Array.isArray(body?.assertions?.mustNotContainAny) ? body.assertions.mustNotContainAny : [],
42609
+ mustMatchAny: Array.isArray(body?.assertions?.mustMatchAny) ? body.assertions.mustMatchAny : [],
42610
+ mustNotMatchAny: Array.isArray(body?.assertions?.mustNotMatchAny) ? body.assertions.mustNotMatchAny : [],
42611
+ lastAssistantMustContainAny: Array.isArray(body?.assertions?.lastAssistantMustContainAny) ? body.assertions.lastAssistantMustContainAny : [],
42612
+ lastAssistantMustNotContainAny: Array.isArray(body?.assertions?.lastAssistantMustNotContainAny) ? body.assertions.lastAssistantMustNotContainAny : [],
42613
+ lastAssistantMustMatchAny: Array.isArray(body?.assertions?.lastAssistantMustMatchAny) ? body.assertions.lastAssistantMustMatchAny : [],
42614
+ lastAssistantMustNotMatchAny: Array.isArray(body?.assertions?.lastAssistantMustNotMatchAny) ? body.assertions.lastAssistantMustNotMatchAny : [],
42615
+ statusesSeen: Array.isArray(body?.assertions?.statusesSeen) ? body.assertions.statusesSeen : void 0,
42616
+ requireNotTimedOut: body?.assertions?.requireNotTimedOut !== false
42617
+ },
42618
+ notes: typeof body?.notes === "string" ? body.notes : void 0
42619
+ };
42620
+ const filePath = path16.join(fixtureDir, `${name}.json`);
42621
+ fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
42622
+ ctx.json(res, 200, {
42623
+ saved: true,
42624
+ name,
42625
+ path: filePath,
42626
+ fixture,
42627
+ verification: {
42628
+ pass: validateCliFixtureResult(result, fixture.assertions).length === 0,
42629
+ failures: validateCliFixtureResult(result, fixture.assertions)
42630
+ }
42631
+ });
42632
+ } catch (e) {
42633
+ ctx.json(res, 500, { error: `Fixture capture failed: ${e.message}` });
42634
+ }
42635
+ }
42636
+ async function handleCliFixtureList(ctx, type, _req, res) {
42637
+ try {
42638
+ const fixtureDir = getCliFixtureDir(ctx, type);
42639
+ if (!fs13.existsSync(fixtureDir)) {
42640
+ ctx.json(res, 200, { fixtures: [], count: 0 });
42641
+ return;
42642
+ }
42643
+ const fixtures = fs13.readdirSync(fixtureDir).filter((file2) => file2.endsWith(".json")).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file2) => {
42644
+ const fullPath = path16.join(fixtureDir, file2);
42645
+ try {
42646
+ const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
42647
+ return {
42648
+ name: raw.name || file2.replace(/\.json$/i, ""),
42649
+ path: fullPath,
42650
+ createdAt: raw.createdAt || null,
42651
+ notes: raw.notes || null,
42652
+ requestText: raw.request?.text || "",
42653
+ assertions: raw.assertions || {}
42654
+ };
42655
+ } catch {
42656
+ return {
42657
+ name: file2.replace(/\.json$/i, ""),
42658
+ path: fullPath,
42659
+ createdAt: null,
42660
+ notes: "Unreadable fixture",
42661
+ requestText: "",
42662
+ assertions: {}
42663
+ };
42664
+ }
42665
+ });
42666
+ ctx.json(res, 200, { fixtures, count: fixtures.length });
42667
+ } catch (e) {
42668
+ ctx.json(res, 500, { error: `Fixture list failed: ${e.message}` });
42669
+ }
42670
+ }
42671
+ async function handleCliFixtureReplay(ctx, req, res) {
42672
+ try {
42673
+ const body = await ctx.readBody(req);
42674
+ const type = String(body?.type || "");
42675
+ const rawName = String(body?.name || "").trim();
42676
+ if (!type || !rawName) {
42677
+ ctx.json(res, 400, { error: "type and name required" });
42678
+ return;
42679
+ }
42680
+ const name = slugifyFixtureName(rawName);
42681
+ const fixture = readCliFixture(ctx, type, name);
42682
+ const result = await runCliExerciseInternal(ctx, {
42683
+ ...fixture.request,
42684
+ type
42685
+ });
42686
+ const assertions = {
42687
+ ...fixture.assertions,
42688
+ ...body?.assertions || {}
42689
+ };
42690
+ const failures = validateCliFixtureResult(result, assertions);
42691
+ ctx.json(res, 200, {
42692
+ replayed: true,
42693
+ pass: failures.length === 0,
42694
+ failures,
42695
+ fixture,
42696
+ result,
42697
+ assertions
42698
+ });
42699
+ } catch (e) {
42700
+ ctx.json(res, 500, { error: `Fixture replay failed: ${e.message}` });
42701
+ }
42702
+ }
41585
42703
  async function handleCliResolve(ctx, req, res) {
41586
42704
  const body = await ctx.readBody(req);
41587
42705
  const { type, buttonIndex, instanceId } = body;
@@ -41656,13 +42774,36 @@ async function handleCliRaw(ctx, req, res) {
41656
42774
  ctx.json(res, 500, { error: `Raw send failed: ${e.message}` });
41657
42775
  }
41658
42776
  }
42777
+ var fs13, path16;
41659
42778
  var init_dev_cli_debug = __esm({
41660
42779
  "../../oss/packages/daemon-core/src/daemon/dev-cli-debug.ts"() {
41661
42780
  "use strict";
42781
+ fs13 = __toESM(require("fs"));
42782
+ path16 = __toESM(require("path"));
41662
42783
  }
41663
42784
  });
41664
42785
 
41665
42786
  // ../../oss/packages/daemon-core/src/daemon/dev-auto-implement.ts
42787
+ function getAutoImplPid(ctx) {
42788
+ const proc = ctx.autoImplProcess;
42789
+ return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
42790
+ }
42791
+ function isPidAlive(pid) {
42792
+ try {
42793
+ process.kill(pid, 0);
42794
+ return true;
42795
+ } catch (error48) {
42796
+ return error48?.code === "EPERM";
42797
+ }
42798
+ }
42799
+ function clearStaleAutoImplState(ctx, reason) {
42800
+ if (!ctx.autoImplStatus.running && !ctx.autoImplProcess) return;
42801
+ const pid = getAutoImplPid(ctx);
42802
+ if (pid && isPidAlive(pid)) return;
42803
+ ctx.log(`Clearing stale auto-implement state: ${reason}${pid ? ` (pid ${pid})` : ""}`);
42804
+ ctx.autoImplProcess = null;
42805
+ ctx.autoImplStatus.running = false;
42806
+ }
41666
42807
  function getDefaultAutoImplReference(ctx, category, type) {
41667
42808
  if (category === "cli") {
41668
42809
  return type === "codex-cli" ? "claude-cli" : "codex-cli";
@@ -41678,45 +42819,45 @@ function resolveAutoImplReference(ctx, category, requestedReference, targetType)
41678
42819
  return fallback?.type || null;
41679
42820
  }
41680
42821
  function getLatestScriptVersionDir(scriptsDir) {
41681
- if (!fs13.existsSync(scriptsDir)) return null;
41682
- const versions = fs13.readdirSync(scriptsDir).filter((d) => {
42822
+ if (!fs14.existsSync(scriptsDir)) return null;
42823
+ const versions = fs14.readdirSync(scriptsDir).filter((d) => {
41683
42824
  try {
41684
- return fs13.statSync(path16.join(scriptsDir, d)).isDirectory();
42825
+ return fs14.statSync(path17.join(scriptsDir, d)).isDirectory();
41685
42826
  } catch {
41686
42827
  return false;
41687
42828
  }
41688
42829
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
41689
42830
  if (versions.length === 0) return null;
41690
- return path16.join(scriptsDir, versions[0]);
42831
+ return path17.join(scriptsDir, versions[0]);
41691
42832
  }
41692
42833
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
41693
- const canonicalUserDir = path16.resolve(ctx.providerLoader.getUserProviderDir(category, type));
41694
- const desiredDir = requestedDir ? path16.resolve(requestedDir) : canonicalUserDir;
41695
- const upstreamRoot = path16.resolve(ctx.providerLoader.getUpstreamDir());
41696
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path16.sep}`)) {
42834
+ const canonicalUserDir = path17.resolve(ctx.providerLoader.getUserProviderDir(category, type));
42835
+ const desiredDir = requestedDir ? path17.resolve(requestedDir) : canonicalUserDir;
42836
+ const upstreamRoot = path17.resolve(ctx.providerLoader.getUpstreamDir());
42837
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path17.sep}`)) {
41697
42838
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
41698
42839
  }
41699
- if (path16.basename(desiredDir) !== type) {
42840
+ if (path17.basename(desiredDir) !== type) {
41700
42841
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
41701
42842
  }
41702
42843
  const sourceDir = ctx.findProviderDir(type);
41703
42844
  if (!sourceDir) {
41704
42845
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
41705
42846
  }
41706
- if (!fs13.existsSync(desiredDir)) {
41707
- fs13.mkdirSync(path16.dirname(desiredDir), { recursive: true });
41708
- fs13.cpSync(sourceDir, desiredDir, { recursive: true });
42847
+ if (!fs14.existsSync(desiredDir)) {
42848
+ fs14.mkdirSync(path17.dirname(desiredDir), { recursive: true });
42849
+ fs14.cpSync(sourceDir, desiredDir, { recursive: true });
41709
42850
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
41710
42851
  }
41711
- const providerJson = path16.join(desiredDir, "provider.json");
41712
- if (!fs13.existsSync(providerJson)) {
42852
+ const providerJson = path17.join(desiredDir, "provider.json");
42853
+ if (!fs14.existsSync(providerJson)) {
41713
42854
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
41714
42855
  }
41715
42856
  try {
41716
- const providerData = JSON.parse(fs13.readFileSync(providerJson, "utf-8"));
42857
+ const providerData = JSON.parse(fs14.readFileSync(providerJson, "utf-8"));
41717
42858
  if (providerData.disableUpstream !== true) {
41718
42859
  providerData.disableUpstream = true;
41719
- fs13.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
42860
+ fs14.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
41720
42861
  }
41721
42862
  } catch (error48) {
41722
42863
  return {
@@ -41729,15 +42870,15 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
41729
42870
  function loadAutoImplReferenceScripts(ctx, referenceType) {
41730
42871
  if (!referenceType) return {};
41731
42872
  const refDir = ctx.findProviderDir(referenceType);
41732
- if (!refDir || !fs13.existsSync(refDir)) return {};
42873
+ if (!refDir || !fs14.existsSync(refDir)) return {};
41733
42874
  const referenceScripts = {};
41734
- const scriptsDir = path16.join(refDir, "scripts");
42875
+ const scriptsDir = path17.join(refDir, "scripts");
41735
42876
  const latestDir = getLatestScriptVersionDir(scriptsDir);
41736
42877
  if (!latestDir) return referenceScripts;
41737
- for (const file2 of fs13.readdirSync(latestDir)) {
42878
+ for (const file2 of fs14.readdirSync(latestDir)) {
41738
42879
  if (!file2.endsWith(".js")) continue;
41739
42880
  try {
41740
- referenceScripts[file2] = fs13.readFileSync(path16.join(latestDir, file2), "utf-8");
42881
+ referenceScripts[file2] = fs14.readFileSync(path17.join(latestDir, file2), "utf-8");
41741
42882
  } catch {
41742
42883
  }
41743
42884
  }
@@ -41745,11 +42886,20 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
41745
42886
  }
41746
42887
  async function handleAutoImplement(ctx, type, req, res) {
41747
42888
  const body = await ctx.readBody(req);
41748
- const { agent = "claude-cli", functions, reference, model, comment, providerDir: requestedProviderDir } = body;
42889
+ const {
42890
+ agent = "claude-cli",
42891
+ functions,
42892
+ reference,
42893
+ model,
42894
+ comment,
42895
+ providerDir: requestedProviderDir,
42896
+ verification
42897
+ } = body;
41749
42898
  if (!functions || !Array.isArray(functions) || functions.length === 0) {
41750
42899
  ctx.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
41751
42900
  return;
41752
42901
  }
42902
+ clearStaleAutoImplState(ctx, "new auto-implement request");
41753
42903
  if (ctx.autoImplStatus.running) {
41754
42904
  ctx.json(res, 409, { error: "Auto-implement already in progress", type: ctx.autoImplStatus.type });
41755
42905
  return;
@@ -41767,7 +42917,55 @@ async function handleAutoImplement(ctx, type, req, res) {
41767
42917
  return;
41768
42918
  }
41769
42919
  const providerDir = writableProvider.dir;
42920
+ ctx.autoImplStatus = { running: false, type, progress: [] };
42921
+ if (provider.category === "cli" && verification && (verification.fixtureName || verification.fixtureNames && verification.fixtureNames.length > 0)) {
42922
+ sendAutoImplSSE(ctx, {
42923
+ event: "progress",
42924
+ data: {
42925
+ function: "_preflight",
42926
+ status: "verifying",
42927
+ message: "Running preflight verification before spawning agent..."
42928
+ }
42929
+ });
42930
+ try {
42931
+ const preflight = await runCliAutoImplVerification(ctx, type, verification);
42932
+ sendAutoImplSSE(ctx, { event: "verification", data: preflight });
42933
+ if (preflight.pass) {
42934
+ sendAutoImplSSE(ctx, {
42935
+ event: "complete",
42936
+ data: {
42937
+ success: true,
42938
+ exitCode: 0,
42939
+ functions,
42940
+ message: `\u2705 No-op: exact ${preflight.mode} already passes`,
42941
+ verification: preflight,
42942
+ skipped: true
42943
+ }
42944
+ });
42945
+ ctx.json(res, 200, {
42946
+ started: false,
42947
+ skipped: true,
42948
+ type,
42949
+ functions,
42950
+ providerDir,
42951
+ verification: preflight,
42952
+ message: "Preflight verification already passes. No auto-implement run needed."
42953
+ });
42954
+ return;
42955
+ }
42956
+ } catch (error48) {
42957
+ sendAutoImplSSE(ctx, {
42958
+ event: "progress",
42959
+ data: {
42960
+ function: "_preflight",
42961
+ status: "verify_failed",
42962
+ message: `Preflight verification errored, continuing to agent run: ${error48?.message || error48}`
42963
+ }
42964
+ });
42965
+ }
42966
+ }
41770
42967
  try {
42968
+ ctx.autoImplStatus = { running: true, type, progress: ctx.autoImplStatus.progress };
41771
42969
  const resolvedReference = resolveAutoImplReference(ctx, provider.category, reference, type);
41772
42970
  sendAutoImplSSE(ctx, {
41773
42971
  event: "progress",
@@ -41787,17 +42985,17 @@ async function handleAutoImplement(ctx, type, req, res) {
41787
42985
  }
41788
42986
  });
41789
42987
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
41790
- const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
41791
- const tmpDir = path16.join(os18.tmpdir(), "adhdev-autoimpl");
41792
- if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
41793
- const promptFile = path16.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
41794
- fs13.writeFileSync(promptFile, prompt, "utf-8");
42988
+ const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
42989
+ const tmpDir = path17.join(os18.tmpdir(), "adhdev-autoimpl");
42990
+ if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
42991
+ const promptFile = path17.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
42992
+ fs14.writeFileSync(promptFile, prompt, "utf-8");
41795
42993
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
41796
42994
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
41797
42995
  const spawn5 = agentProvider?.spawn;
41798
42996
  if (!spawn5?.command) {
41799
42997
  try {
41800
- fs13.unlinkSync(promptFile);
42998
+ fs14.unlinkSync(promptFile);
41801
42999
  } catch {
41802
43000
  }
41803
43001
  ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
@@ -41806,7 +43004,8 @@ async function handleAutoImplement(ctx, type, req, res) {
41806
43004
  const agentCategory = agentProvider?.category;
41807
43005
  if (agentCategory === "acp") {
41808
43006
  sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${spawn5.command} ${(spawn5.args || []).join(" ")}` } });
41809
- ctx.autoImplStatus = { running: true, type, progress: [] };
43007
+ ctx.autoImplStatus.running = true;
43008
+ ctx.autoImplStatus.type = type;
41810
43009
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
41811
43010
  const { Readable: Readable3, Writable: Writable2 } = await import("stream");
41812
43011
  const { spawn: spawnFn2 } = await import("child_process");
@@ -41898,7 +43097,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41898
43097
  } catch {
41899
43098
  }
41900
43099
  try {
41901
- fs13.unlinkSync(promptFile);
43100
+ fs14.unlinkSync(promptFile);
41902
43101
  } catch {
41903
43102
  }
41904
43103
  ctx.log(`Auto-implement (ACP) ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -41976,7 +43175,8 @@ async function handleAutoImplement(ctx, type, req, res) {
41976
43175
  }
41977
43176
  }
41978
43177
  sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning agent: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
41979
- ctx.autoImplStatus = { running: true, type, progress: [] };
43178
+ ctx.autoImplStatus.running = true;
43179
+ ctx.autoImplStatus.type = type;
41980
43180
  const spawnedAt = Date.now();
41981
43181
  let child;
41982
43182
  let isPty = false;
@@ -42019,6 +43219,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42019
43219
  let approvalKeys = { 0: "y\r" };
42020
43220
  let approvalBuffer = "";
42021
43221
  let lastApprovalTime = 0;
43222
+ let completionSignalSeen = false;
42022
43223
  try {
42023
43224
  const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
42024
43225
  const normalized = normalizeCliProviderForRuntime2(agentProvider);
@@ -42032,6 +43233,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42032
43233
  approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
42033
43234
  const elapsed = Date.now() - spawnedAt;
42034
43235
  if (elapsed > 15e3 && cleanData.includes("_PIPELINE_COMPLETE_SIGNAL_")) {
43236
+ completionSignalSeen = true;
42035
43237
  ctx.log(`Agent finished task after ${Math.round(elapsed / 1e3)}s. Terminating interactive CLI session to unblock pipeline.`);
42036
43238
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: `
42037
43239
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
@@ -42055,6 +43257,55 @@ async function handleAutoImplement(ctx, type, req, res) {
42055
43257
  lastApprovalTime = Date.now();
42056
43258
  }
42057
43259
  };
43260
+ const finalizeCliAutoImpl = async (code) => {
43261
+ ctx.autoImplProcess = null;
43262
+ let success2 = completionSignalSeen || code === 0;
43263
+ let message = success2 ? completionSignalSeen && code !== 0 ? "\u2705 Auto-implement complete (completion signal)" : "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`;
43264
+ let verificationSummary = null;
43265
+ try {
43266
+ ctx.providerLoader.reload();
43267
+ } catch {
43268
+ }
43269
+ if (provider.category === "cli" && verification) {
43270
+ sendAutoImplSSE(ctx, {
43271
+ event: "progress",
43272
+ data: {
43273
+ function: "_verify",
43274
+ status: "running",
43275
+ message: "Running exact post-patch verification..."
43276
+ }
43277
+ });
43278
+ try {
43279
+ verificationSummary = await runCliAutoImplVerification(ctx, type, verification);
43280
+ sendAutoImplSSE(ctx, { event: "verification", data: verificationSummary });
43281
+ success2 = verificationSummary.pass;
43282
+ message = verificationSummary.pass ? `\u2705 Auto-implement complete (${verificationSummary.mode})` : `\u274C Post-patch verification failed (${verificationSummary.mode}): ${verificationSummary.failures.join("; ") || "unknown failure"}`;
43283
+ } catch (error48) {
43284
+ success2 = false;
43285
+ message = `\u274C Post-patch verification error: ${error48?.message || error48}`;
43286
+ sendAutoImplSSE(ctx, {
43287
+ event: "verification",
43288
+ data: { pass: false, error: error48?.message || String(error48) }
43289
+ });
43290
+ }
43291
+ }
43292
+ ctx.autoImplStatus.running = false;
43293
+ sendAutoImplSSE(ctx, {
43294
+ event: "complete",
43295
+ data: {
43296
+ success: success2,
43297
+ exitCode: code,
43298
+ functions,
43299
+ message,
43300
+ verification: verificationSummary
43301
+ }
43302
+ });
43303
+ try {
43304
+ fs14.unlinkSync(promptFile);
43305
+ } catch {
43306
+ }
43307
+ ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})${verificationSummary ? ` verify=${verificationSummary.pass ? "pass" : "fail"}` : ""}`);
43308
+ };
42058
43309
  if (isPty) {
42059
43310
  child.onData((data) => {
42060
43311
  stdout += data;
@@ -42066,21 +43317,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42066
43317
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
42067
43318
  });
42068
43319
  child.onExit(({ exitCode: code }) => {
42069
- ctx.autoImplProcess = null;
42070
- ctx.autoImplStatus.running = false;
42071
- const success2 = code === 0;
42072
- sendAutoImplSSE(ctx, {
42073
- event: "complete",
42074
- data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})` }
42075
- });
42076
- try {
42077
- ctx.providerLoader.reload();
42078
- } catch {
42079
- }
42080
- try {
42081
- fs13.unlinkSync(promptFile);
42082
- } catch {
42083
- }
43320
+ void finalizeCliAutoImpl(code);
42084
43321
  });
42085
43322
  } else {
42086
43323
  child.stdout?.on("data", (d) => {
@@ -42097,27 +43334,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42097
43334
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
42098
43335
  });
42099
43336
  child.on("exit", (code) => {
42100
- ctx.autoImplProcess = null;
42101
- ctx.autoImplStatus.running = false;
42102
- const success2 = code === 0;
42103
- sendAutoImplSSE(ctx, {
42104
- event: "complete",
42105
- data: {
42106
- success: success2,
42107
- exitCode: code,
42108
- functions,
42109
- message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`
42110
- }
42111
- });
42112
- try {
42113
- ctx.providerLoader.reload();
42114
- } catch {
42115
- }
42116
- try {
42117
- fs13.unlinkSync(promptFile);
42118
- } catch {
42119
- }
42120
- ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
43337
+ void finalizeCliAutoImpl(code);
42121
43338
  });
42122
43339
  }
42123
43340
  ctx.json(res, 202, {
@@ -42134,9 +43351,9 @@ async function handleAutoImplement(ctx, type, req, res) {
42134
43351
  ctx.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
42135
43352
  }
42136
43353
  }
42137
- function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType) {
43354
+ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType, verification) {
42138
43355
  if (provider.category === "cli") {
42139
- return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
43356
+ return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification);
42140
43357
  }
42141
43358
  const lines = [];
42142
43359
  lines.push("You are implementing browser automation scripts for an IDE provider.");
@@ -42161,7 +43378,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42161
43378
  setMode: "set_mode.js"
42162
43379
  };
42163
43380
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
42164
- const scriptsDir = path16.join(providerDir, "scripts");
43381
+ const scriptsDir = path17.join(providerDir, "scripts");
42165
43382
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
42166
43383
  if (latestScriptsDir) {
42167
43384
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -42169,10 +43386,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42169
43386
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
42170
43387
  lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
42171
43388
  lines.push("");
42172
- for (const file2 of fs13.readdirSync(latestScriptsDir)) {
43389
+ for (const file2 of fs14.readdirSync(latestScriptsDir)) {
42173
43390
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
42174
43391
  try {
42175
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43392
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42176
43393
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
42177
43394
  lines.push("```javascript");
42178
43395
  lines.push(content);
@@ -42182,14 +43399,14 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42182
43399
  }
42183
43400
  }
42184
43401
  }
42185
- const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43402
+ const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
42186
43403
  if (refFiles.length > 0) {
42187
43404
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
42188
43405
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
42189
43406
  lines.push("");
42190
43407
  for (const file2 of refFiles) {
42191
43408
  try {
42192
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43409
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42193
43410
  lines.push(`### \`${file2}\` \u{1F512}`);
42194
43411
  lines.push("```javascript");
42195
43412
  lines.push(content);
@@ -42230,11 +43447,11 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42230
43447
  lines.push("");
42231
43448
  }
42232
43449
  }
42233
- const docsDir = path16.join(providerDir, "../../docs");
43450
+ const docsDir = path17.join(providerDir, "../../docs");
42234
43451
  const loadGuide = (name) => {
42235
43452
  try {
42236
- const p = path16.join(docsDir, name);
42237
- if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
43453
+ const p = path17.join(docsDir, name);
43454
+ if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
42238
43455
  } catch {
42239
43456
  }
42240
43457
  return null;
@@ -42392,8 +43609,69 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42392
43609
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
42393
43610
  return lines.join("\n");
42394
43611
  }
42395
- function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType) {
43612
+ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification) {
42396
43613
  const lines = [];
43614
+ const defaultExercisePayload = {
43615
+ type,
43616
+ workingDir: providerDir,
43617
+ freshSession: true,
43618
+ autoLaunch: true,
43619
+ autoResolveApprovals: true,
43620
+ approvalButtonIndex: 0,
43621
+ timeoutMs: 45e3,
43622
+ traceLimit: 200,
43623
+ 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."
43624
+ };
43625
+ const exercisePayload = {
43626
+ ...defaultExercisePayload,
43627
+ ...verification?.request || {},
43628
+ type,
43629
+ workingDir: providerDir
43630
+ };
43631
+ const exerciseJson = JSON.stringify(exercisePayload).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43632
+ const verificationInspectFields = verification?.inspectFields?.length ? verification.inspectFields : [
43633
+ "debug.messages",
43634
+ "trace.entries[].payload.parsedLastAssistant",
43635
+ "trace.entries[].payload.lastAssistant"
43636
+ ];
43637
+ const verificationMustContainAny = verification?.mustContainAny || [];
43638
+ const verificationMustNotContainAny = verification?.mustNotContainAny || [];
43639
+ const verificationMustMatchAny = verification?.mustMatchAny || [];
43640
+ const verificationMustNotMatchAny = verification?.mustNotMatchAny || [];
43641
+ const verificationLastAssistantMustContainAny = verification?.lastAssistantMustContainAny || [];
43642
+ const verificationLastAssistantMustNotContainAny = verification?.lastAssistantMustNotContainAny || [];
43643
+ const verificationLastAssistantMustMatchAny = verification?.lastAssistantMustMatchAny || [];
43644
+ const verificationLastAssistantMustNotMatchAny = verification?.lastAssistantMustNotMatchAny || [];
43645
+ const quotedMustContain = verificationMustContainAny.map((value) => JSON.stringify(value)).join(", ");
43646
+ const quotedMustNotContain = verificationMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
43647
+ const quotedMustMatch = verificationMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
43648
+ const quotedMustNotMatch = verificationMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
43649
+ const quotedLastAssistantMustContain = verificationLastAssistantMustContainAny.map((value) => JSON.stringify(value)).join(", ");
43650
+ const quotedLastAssistantMustNotContain = verificationLastAssistantMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
43651
+ const quotedLastAssistantMustMatch = verificationLastAssistantMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
43652
+ const quotedLastAssistantMustNotMatch = verificationLastAssistantMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
43653
+ const fixtureName = verification?.fixtureName || `${type}-provider-fix`;
43654
+ const fixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
43655
+ const fixtureCaptureJson = JSON.stringify({
43656
+ type,
43657
+ name: fixtureName,
43658
+ request: exercisePayload,
43659
+ assertions: {
43660
+ mustContainAny: verificationMustContainAny,
43661
+ mustNotContainAny: verificationMustNotContainAny,
43662
+ mustMatchAny: verificationMustMatchAny,
43663
+ mustNotMatchAny: verificationMustNotMatchAny,
43664
+ lastAssistantMustContainAny: verificationLastAssistantMustContainAny,
43665
+ lastAssistantMustNotContainAny: verificationLastAssistantMustNotContainAny,
43666
+ lastAssistantMustMatchAny: verificationLastAssistantMustMatchAny,
43667
+ lastAssistantMustNotMatchAny: verificationLastAssistantMustNotMatchAny,
43668
+ requireNotTimedOut: true
43669
+ }
43670
+ }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43671
+ const fixtureReplayJson = JSON.stringify({
43672
+ type,
43673
+ name: fixtureName
43674
+ }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
42397
43675
  lines.push("You are implementing PTY parsing scripts for a CLI provider.");
42398
43676
  lines.push("Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.");
42399
43677
  lines.push("");
@@ -42407,7 +43685,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42407
43685
  parseApproval: "parse_approval.js"
42408
43686
  };
42409
43687
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
42410
- const scriptsDir = path16.join(providerDir, "scripts");
43688
+ const scriptsDir = path17.join(providerDir, "scripts");
42411
43689
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
42412
43690
  if (latestScriptsDir) {
42413
43691
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -42415,11 +43693,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42415
43693
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
42416
43694
  lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
42417
43695
  lines.push("");
42418
- for (const file2 of fs13.readdirSync(latestScriptsDir)) {
43696
+ for (const file2 of fs14.readdirSync(latestScriptsDir)) {
42419
43697
  if (!file2.endsWith(".js")) continue;
42420
43698
  if (!targetFileNames.has(file2)) continue;
42421
43699
  try {
42422
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43700
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42423
43701
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
42424
43702
  lines.push("```javascript");
42425
43703
  lines.push(content);
@@ -42428,14 +43706,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42428
43706
  } catch {
42429
43707
  }
42430
43708
  }
42431
- const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43709
+ const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
42432
43710
  if (refFiles.length > 0) {
42433
43711
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
42434
43712
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
42435
43713
  lines.push("");
42436
43714
  for (const file2 of refFiles) {
42437
43715
  try {
42438
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43716
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42439
43717
  lines.push(`### \`${file2}\` \u{1F512}`);
42440
43718
  lines.push("```javascript");
42441
43719
  lines.push(content);
@@ -42468,17 +43746,17 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42468
43746
  lines.push("");
42469
43747
  }
42470
43748
  }
42471
- const docsDir = path16.join(providerDir, "../../docs");
43749
+ const docsDir = path17.join(providerDir, "../../docs");
42472
43750
  const loadGuide = (name) => {
42473
43751
  try {
42474
- const p = path16.join(docsDir, name);
42475
- if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
43752
+ const p = path17.join(docsDir, name);
43753
+ if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
42476
43754
  } catch {
42477
43755
  }
42478
43756
  return null;
42479
43757
  };
42480
43758
  const providerGuide = loadGuide("PROVIDER_GUIDE.md");
42481
- if (providerGuide) {
43759
+ if (providerGuide && provider.category !== "cli") {
42482
43760
  lines.push("## Documentation: PROVIDER_GUIDE.md");
42483
43761
  lines.push("```markdown");
42484
43762
  lines.push(providerGuide);
@@ -42520,6 +43798,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42520
43798
  lines.push("13. After the first successful live repro, stop broad diagnosis. Edit the scripts, reload, and verify. Do not burn tokens on repeated re-inspection without code changes.");
42521
43799
  lines.push("14. If the visible current screen is clean and sufficient, do NOT fall back to complex buffer heuristics. Simpler current-screen parsing is preferred.");
42522
43800
  lines.push("15. Before changing parser logic, verify whether `provider.json` submit/approval behavior (`sendDelayMs`, `approvalKeys`, submit strategy) is the simpler and more correct fix.");
43801
+ lines.push('16. Do NOT patch transcript bugs by piling up one-off literal string exceptions (`includes("foo")`, `=== "bar"`, ad hoc allowlists/denylists) for every observed variant. Model the UI as PATTERN FAMILIES using reusable regex classifiers and normalization first.');
43802
+ lines.push("17. If you find yourself adding a second or third near-duplicate literal check for spinner words, tool headers, approval prompts, footer chrome, or OSC residue, STOP and replace them with a broader regex or helper classifier.");
43803
+ lines.push('18. Prefer a small number of named classifiers such as "status line", "tool header", "tool detail", "footer chrome", "approval cue", "prompt line", and "OSC residue" over a long chain of unrelated string checks.');
43804
+ lines.push("19. Literal string checks are allowed only for stable proper nouns or exact product chrome that cannot be expressed safely as a broader pattern. Everything else should generalize.");
43805
+ lines.push("20. When a bug comes from noisy PTY text, first normalize and classify the line family; do NOT just append another special-case substring to the parser.");
42523
43806
  lines.push("");
42524
43807
  lines.push("## Task");
42525
43808
  lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
@@ -42527,35 +43810,145 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42527
43810
  lines.push("## Verification API");
42528
43811
  lines.push("Use the DevServer CLI debug endpoints, not DOM/CDP routes.");
42529
43812
  lines.push("");
42530
- lines.push("### 1. Launch the target CLI");
43813
+ lines.push("### 1. Preferred: run a full autonomous repro");
43814
+ lines.push("Use the exercise endpoint first. It launches a fresh CLI session, sends the repro prompt, auto-resolves approvals, waits for the session to settle, and returns the final debug + trace payload in one response.");
42531
43815
  lines.push("```bash");
42532
- lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
43816
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
42533
43817
  lines.push(' -H "Content-Type: application/json" \\');
42534
- lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
43818
+ lines.push(` -d '${exerciseJson}'`);
43819
+ lines.push("```");
43820
+ lines.push("");
43821
+ if (verification?.description) {
43822
+ lines.push("Verification intent:");
43823
+ lines.push(verification.description);
43824
+ lines.push("");
43825
+ }
43826
+ lines.push("Read the JSON response carefully. It already includes:");
43827
+ lines.push("1. `instanceId`");
43828
+ lines.push("2. `statusesSeen` and `approvalsResolved`");
43829
+ lines.push("3. `debug` for the final settled state");
43830
+ lines.push("4. `trace.entries` for the repro turn");
43831
+ lines.push("");
43832
+ lines.push("Save the response to a temp file and inspect the exact parsed transcript fields before editing:");
43833
+ lines.push("```bash");
43834
+ lines.push(`EXERCISE_JSON=$(mktemp)`);
43835
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
43836
+ lines.push(' -H "Content-Type: application/json" \\');
43837
+ lines.push(` -d '${exerciseJson}' > "$EXERCISE_JSON"`);
43838
+ lines.push(`jq '{timedOut,statusesSeen,approvalsResolved,inspect:{${verificationInspectFields.map((field, index) => `f${index + 1}: .${field}`).join(", ")}}}' "$EXERCISE_JSON"`);
42535
43839
  lines.push("```");
42536
43840
  lines.push("");
43841
+ if (verificationMustContainAny.length > 0 || verificationMustNotContainAny.length > 0 || verificationMustMatchAny.length > 0 || verificationMustNotMatchAny.length > 0 || verificationLastAssistantMustContainAny.length > 0 || verificationLastAssistantMustNotContainAny.length > 0 || verificationLastAssistantMustMatchAny.length > 0 || verificationLastAssistantMustNotMatchAny.length > 0) {
43842
+ lines.push("The exact repro below is mandatory. Do NOT declare success unless these transcript assertions pass on the exercise JSON from the PATCHED provider.");
43843
+ lines.push("```bash");
43844
+ if (verificationMustContainAny.length > 0) {
43845
+ lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const required=[${quotedMustContain}];const missing=required.filter(v=>!text.includes(v));if(missing.length){console.error("Missing required substrings:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43846
+ }
43847
+ if (verificationMustNotContainAny.length > 0) {
43848
+ lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const banned=[${quotedMustNotContain}];const hits=banned.filter(v=>text.includes(v));if(hits.length){console.error("Found banned substrings:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43849
+ }
43850
+ if (verificationMustMatchAny.length > 0) {
43851
+ lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const required=[${quotedMustMatch}].map(v=>new RegExp(v,"m"));const missing=required.filter(v=>!v.test(text)).map(v=>String(v));if(missing.length){console.error("Missing required regex matches:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43852
+ }
43853
+ if (verificationMustNotMatchAny.length > 0) {
43854
+ lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const banned=[${quotedMustNotMatch}].map(v=>new RegExp(v,"m"));const hits=banned.filter(v=>v.test(text)).map(v=>String(v));if(hits.length){console.error("Found banned regex matches:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43855
+ }
43856
+ if (verificationLastAssistantMustContainAny.length > 0) {
43857
+ lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const required=[${quotedLastAssistantMustContain}];const missing=required.filter(v=>!text.includes(v));if(missing.length){console.error("Missing required lastAssistant substrings:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43858
+ }
43859
+ if (verificationLastAssistantMustNotContainAny.length > 0) {
43860
+ lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const banned=[${quotedLastAssistantMustNotContain}];const hits=banned.filter(v=>text.includes(v));if(hits.length){console.error("Found banned lastAssistant substrings:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43861
+ }
43862
+ if (verificationLastAssistantMustMatchAny.length > 0) {
43863
+ lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const required=[${quotedLastAssistantMustMatch}].map(v=>new RegExp(v,"m"));const missing=required.filter(v=>!v.test(text)).map(v=>String(v));if(missing.length){console.error("Missing required lastAssistant regex matches:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43864
+ }
43865
+ if (verificationLastAssistantMustNotMatchAny.length > 0) {
43866
+ lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const banned=[${quotedLastAssistantMustNotMatch}].map(v=>new RegExp(v,"m"));const hits=banned.filter(v=>v.test(text)).map(v=>String(v));if(hits.length){console.error("Found banned lastAssistant regex matches:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
43867
+ }
43868
+ lines.push("```");
43869
+ lines.push("");
43870
+ }
43871
+ lines.push("If you need a manual follow-up repro after patching, use the SAME endpoint again with the SAME prompt and compare the new trace to the previous one.");
43872
+ lines.push("");
43873
+ lines.push("### 1b. Persist or replay the exact repro as a reusable fixture");
43874
+ if (fixtureNames.length > 0) {
43875
+ lines.push(`Replay this exact fixture suite before editing, and replay the SAME suite again after patching. Do not declare success unless EVERY fixture passes: ${fixtureNames.map((name) => `\`${name}\``).join(", ")}.`);
43876
+ for (const name of fixtureNames) {
43877
+ const replayJson = JSON.stringify({ type, name }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43878
+ lines.push("```bash");
43879
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43880
+ lines.push(' -H "Content-Type: application/json" \\');
43881
+ lines.push(` -d '${replayJson}'`);
43882
+ lines.push("```");
43883
+ lines.push("");
43884
+ }
43885
+ lines.push("Do not create new fixtures unless one of the listed fixtures is missing or stale.");
43886
+ } else if (verification?.fixtureName) {
43887
+ lines.push(`Replay the EXISTING saved fixture \`${fixtureName}\` before editing, and replay the SAME fixture again after patching. Do not declare success unless that exact fixture passes.`);
43888
+ lines.push("```bash");
43889
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43890
+ lines.push(' -H "Content-Type: application/json" \\');
43891
+ lines.push(` -d '${fixtureReplayJson}'`);
43892
+ lines.push("```");
43893
+ lines.push("");
43894
+ lines.push("Only if the named fixture is missing or outdated should you recapture it. Prefer replaying the existing failing fixture over creating a new one.");
43895
+ lines.push("```bash");
43896
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
43897
+ lines.push(' -H "Content-Type: application/json" \\');
43898
+ lines.push(` -d '${fixtureCaptureJson}'`);
43899
+ lines.push("```");
43900
+ } else {
43901
+ lines.push("Capture the exact exercise once before editing. After patching, replay THIS fixture and do not declare success unless replay passes.");
43902
+ lines.push("```bash");
43903
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
43904
+ lines.push(' -H "Content-Type: application/json" \\');
43905
+ lines.push(` -d '${fixtureCaptureJson}'`);
43906
+ lines.push("");
43907
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43908
+ lines.push(' -H "Content-Type: application/json" \\');
43909
+ lines.push(` -d '${fixtureReplayJson}'`);
43910
+ lines.push("```");
43911
+ }
43912
+ lines.push("");
43913
+ lines.push("The capture endpoint saves the exact request, initial result, and transcript assertions into the provider directory. The replay endpoint reruns the SAME exercise against your patched scripts and returns pass/fail.");
43914
+ lines.push("");
42537
43915
  lines.push("### 2. Inspect parsed + raw adapter state");
42538
43916
  lines.push("```bash");
43917
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
43918
+ lines.push(' -H "Content-Type: application/json" \\');
43919
+ lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
42539
43920
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
43921
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
42540
43922
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
42541
43923
  lines.push("```");
42542
43924
  lines.push("");
43925
+ lines.push("The CLI trace endpoint is the primary debugging source. Read it BEFORE editing any parser code.");
43926
+ lines.push("Use the trace timeline to find the latest `settled` or `commit_transcript` frame for the repro turn and inspect these fields first:");
43927
+ lines.push("1. `payload.screenText`");
43928
+ lines.push("2. `payload.detectStatus` and `payload.parsedStatus`");
43929
+ lines.push("3. `payload.parsedLastAssistant`");
43930
+ lines.push("4. `payload.approval` / `payload.parsedActiveModal`");
43931
+ lines.push("5. `payload.rawPreview` only when control-sequence residue matters");
43932
+ lines.push("");
42543
43933
  lines.push("The debug payload should be read in this priority order:");
42544
43934
  lines.push("1. `screenText` / current visible state");
42545
43935
  lines.push("2. parsed `status`, `messages`, `activeModal`");
42546
43936
  lines.push("3. `rawBuffer` only for style/control-sequence cues");
42547
43937
  lines.push("4. `buffer` only when the current screen is insufficient");
42548
43938
  lines.push("");
42549
- lines.push("Extract the current `instanceId` from the launch or status response and keep using it below.");
43939
+ lines.push("If the bug is transcript corruption, quote the exact bad `parsedLastAssistant` or bad committed assistant message from the trace and patch against that concrete failure.");
43940
+ lines.push("Do NOT guess based only on the final chat bubble or a truncated UI preview.");
43941
+ lines.push("");
43942
+ lines.push("Extract the current `instanceId` from the exercise, launch, or status response and keep using it below.");
42550
43943
  lines.push("");
42551
- lines.push("### 3. Send a realistic approval-triggering prompt");
43944
+ lines.push("### 3. Manual fallback only: send a realistic approval-triggering prompt");
42552
43945
  lines.push("```bash");
42553
43946
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
42554
43947
  lines.push(' -H "Content-Type: application/json" \\');
42555
43948
  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."}'`);
42556
43949
  lines.push("```");
42557
43950
  lines.push("");
42558
- lines.push("### 4. If approval appears, resolve it until the CLI reaches idle");
43951
+ lines.push("### 4. Manual fallback only: if approval appears, resolve it until the CLI reaches idle");
42559
43952
  lines.push("```bash");
42560
43953
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
42561
43954
  lines.push(' -H "Content-Type: application/json" \\');
@@ -42565,10 +43958,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42565
43958
  lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
42566
43959
  lines.push("```");
42567
43960
  lines.push("");
42568
- 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.");
43961
+ 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. Prefer the exercise endpoint instead of doing this by hand.");
42569
43962
  lines.push("");
42570
43963
  lines.push("### Patch Discipline");
42571
43964
  lines.push("Once the repro is confirmed, immediately edit the target files. Avoid loops where you keep re-reading long files or re-running the same debug commands without changing code.");
43965
+ lines.push("For CLI transcript bugs, reproduce once with the exercise endpoint, inspect the returned trace once, patch immediately, then re-run the SAME exercise and compare the new `commit_transcript` frame.");
43966
+ lines.push("If the patched run still fails the exact required/banned substring checks above, the task is NOT complete even if the CLI exits normally.");
43967
+ lines.push("When you patch, write down the pattern family you are fixing: e.g. spinner/status, tool block, approval modal, footer chrome, OSC/control residue, prompt echo, or long-output continuation. Patch that family once instead of adding case-by-case literals.");
43968
+ lines.push('Bad fix pattern: add another `includes("Drizzling")` or `includes("Show more (")` check. Good fix pattern: broaden the regex/helper that recognizes spinner words, collapsed tool overflow lines, or footer chrome as a family.');
42572
43969
  lines.push("");
42573
43970
  lines.push("### 5. Verify the side effects outside the CLI");
42574
43971
  lines.push("```bash");
@@ -42593,6 +43990,8 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42593
43990
  lines.push("7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
42594
43991
  lines.push("8. Confirm the parser still works after a redraw or scroll change without duplicating transcript history.");
42595
43992
  lines.push("9. Confirm the implementation prefers current-screen signals over stale history when both are present.");
43993
+ lines.push("10. For transcript-cleanliness bugs, confirm the latest `commit_transcript` trace frame no longer contains tool headers, approval prompts, OSC residue like `0;`, or footer chrome unless they are truly user-facing answer content.");
43994
+ lines.push("11. Confirm the implementation uses generalized pattern classifiers or regexes for noisy UI families instead of accumulating one-off literal string exceptions for each observed sample.");
42596
43995
  lines.push("");
42597
43996
  if (userComment) {
42598
43997
  lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
@@ -42601,10 +44000,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42601
44000
  lines.push(userComment);
42602
44001
  lines.push("");
42603
44002
  }
42604
- lines.push("Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.");
44003
+ lines.push("Start NOW. Launch the CLI, inspect the trace and PTY state, edit the scripts, and verify via the CLI debug + trace endpoints.");
42605
44004
  return lines.join("\n");
42606
44005
  }
42607
44006
  function handleAutoImplSSE(ctx, type, req, res) {
44007
+ clearStaleAutoImplState(ctx, "SSE connection opened");
42608
44008
  res.writeHead(200, {
42609
44009
  "Content-Type": "text/event-stream",
42610
44010
  "Cache-Control": "no-cache",
@@ -42626,6 +44026,7 @@ data: ${JSON.stringify(p.data)}
42626
44026
  });
42627
44027
  }
42628
44028
  function handleAutoImplCancel(ctx, _type, _req, res) {
44029
+ clearStaleAutoImplState(ctx, "cancel request");
42629
44030
  if (ctx.autoImplProcess) {
42630
44031
  ctx.autoImplProcess.kill("SIGTERM");
42631
44032
  setTimeout(() => {
@@ -42653,25 +44054,26 @@ data: ${JSON.stringify(msg.data)}
42653
44054
  }
42654
44055
  }
42655
44056
  }
42656
- var fs13, path16, os18;
44057
+ var fs14, path17, os18;
42657
44058
  var init_dev_auto_implement = __esm({
42658
44059
  "../../oss/packages/daemon-core/src/daemon/dev-auto-implement.ts"() {
42659
44060
  "use strict";
42660
- fs13 = __toESM(require("fs"));
42661
- path16 = __toESM(require("path"));
44061
+ fs14 = __toESM(require("fs"));
44062
+ path17 = __toESM(require("path"));
42662
44063
  os18 = __toESM(require("os"));
42663
44064
  init_dev_server();
44065
+ init_dev_cli_debug();
42664
44066
  }
42665
44067
  });
42666
44068
 
42667
44069
  // ../../oss/packages/daemon-core/src/daemon/dev-server.ts
42668
- var http2, fs14, path17, DEV_SERVER_PORT, DevServer;
44070
+ var http2, fs15, path18, DEV_SERVER_PORT, DevServer;
42669
44071
  var init_dev_server = __esm({
42670
44072
  "../../oss/packages/daemon-core/src/daemon/dev-server.ts"() {
42671
44073
  "use strict";
42672
44074
  http2 = __toESM(require("http"));
42673
- fs14 = __toESM(require("fs"));
42674
- path17 = __toESM(require("path"));
44075
+ fs15 = __toESM(require("fs"));
44076
+ path18 = __toESM(require("path"));
42675
44077
  init_scaffold_template();
42676
44078
  init_version_archive();
42677
44079
  init_logger();
@@ -42732,11 +44134,16 @@ var init_dev_server = __esm({
42732
44134
  { method: "GET", pattern: "/api/cli/status", handler: (q2, s15) => this.handleCliStatus(q2, s15) },
42733
44135
  { method: "POST", pattern: "/api/cli/launch", handler: (q2, s15) => this.handleCliLaunch(q2, s15) },
42734
44136
  { method: "POST", pattern: "/api/cli/send", handler: (q2, s15) => this.handleCliSend(q2, s15) },
44137
+ { method: "POST", pattern: "/api/cli/exercise", handler: (q2, s15) => this.handleCliExercise(q2, s15) },
44138
+ { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q2, s15) => this.handleCliFixtureCapture(q2, s15) },
44139
+ { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q2, s15) => this.handleCliFixtureReplay(q2, s15) },
42735
44140
  { method: "POST", pattern: "/api/cli/resolve", handler: (q2, s15) => this.handleCliResolve(q2, s15) },
42736
44141
  { method: "POST", pattern: "/api/cli/raw", handler: (q2, s15) => this.handleCliRaw(q2, s15) },
42737
44142
  { method: "POST", pattern: "/api/cli/stop", handler: (q2, s15) => this.handleCliStop(q2, s15) },
42738
44143
  { method: "GET", pattern: "/api/cli/events", handler: (q2, s15) => this.handleCliSSE(q2, s15) },
42739
44144
  { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliDebug(p[0], q2, s15) },
44145
+ { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliTrace(p[0], q2, s15) },
44146
+ { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliFixtureList(p[0], q2, s15) },
42740
44147
  // Dynamic routes (provider :type param)
42741
44148
  { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q2, s15, p) => this.handleRunScript(p[0], q2, s15) },
42742
44149
  { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q2, s15, p) => this.handleListFiles(p[0], q2, s15) },
@@ -42770,8 +44177,8 @@ var init_dev_server = __esm({
42770
44177
  }
42771
44178
  getEndpointList() {
42772
44179
  return this.routes.map((r) => {
42773
- const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
42774
- return `${r.method.padEnd(5)} ${path21}`;
44180
+ const path23 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
44181
+ return `${r.method.padEnd(5)} ${path23}`;
42775
44182
  });
42776
44183
  }
42777
44184
  async start(port = DEV_SERVER_PORT) {
@@ -43053,12 +44460,12 @@ var init_dev_server = __esm({
43053
44460
  // ─── DevConsole SPA ───
43054
44461
  getConsoleDistDir() {
43055
44462
  const candidates = [
43056
- path17.resolve(__dirname, "../../web-devconsole/dist"),
43057
- path17.resolve(__dirname, "../../../web-devconsole/dist"),
43058
- path17.join(process.cwd(), "packages/web-devconsole/dist")
44463
+ path18.resolve(__dirname, "../../web-devconsole/dist"),
44464
+ path18.resolve(__dirname, "../../../web-devconsole/dist"),
44465
+ path18.join(process.cwd(), "packages/web-devconsole/dist")
43059
44466
  ];
43060
44467
  for (const dir of candidates) {
43061
- if (fs14.existsSync(path17.join(dir, "index.html"))) return dir;
44468
+ if (fs15.existsSync(path18.join(dir, "index.html"))) return dir;
43062
44469
  }
43063
44470
  return null;
43064
44471
  }
@@ -43068,9 +44475,9 @@ var init_dev_server = __esm({
43068
44475
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
43069
44476
  return;
43070
44477
  }
43071
- const htmlPath = path17.join(distDir, "index.html");
44478
+ const htmlPath = path18.join(distDir, "index.html");
43072
44479
  try {
43073
- const html = fs14.readFileSync(htmlPath, "utf-8");
44480
+ const html = fs15.readFileSync(htmlPath, "utf-8");
43074
44481
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
43075
44482
  res.end(html);
43076
44483
  } catch (e) {
@@ -43093,15 +44500,15 @@ var init_dev_server = __esm({
43093
44500
  this.json(res, 404, { error: "Not found" });
43094
44501
  return;
43095
44502
  }
43096
- const safePath = path17.normalize(pathname).replace(/^\.\.\//, "");
43097
- const filePath = path17.join(distDir, safePath);
44503
+ const safePath = path18.normalize(pathname).replace(/^\.\.\//, "");
44504
+ const filePath = path18.join(distDir, safePath);
43098
44505
  if (!filePath.startsWith(distDir)) {
43099
44506
  this.json(res, 403, { error: "Forbidden" });
43100
44507
  return;
43101
44508
  }
43102
44509
  try {
43103
- const content = fs14.readFileSync(filePath);
43104
- const ext = path17.extname(filePath);
44510
+ const content = fs15.readFileSync(filePath);
44511
+ const ext = path18.extname(filePath);
43105
44512
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
43106
44513
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
43107
44514
  res.end(content);
@@ -43209,14 +44616,14 @@ var init_dev_server = __esm({
43209
44616
  const files = [];
43210
44617
  const scan = (d, prefix) => {
43211
44618
  try {
43212
- for (const entry of fs14.readdirSync(d, { withFileTypes: true })) {
44619
+ for (const entry of fs15.readdirSync(d, { withFileTypes: true })) {
43213
44620
  if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
43214
44621
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
43215
44622
  if (entry.isDirectory()) {
43216
44623
  files.push({ path: rel, size: 0, type: "dir" });
43217
- scan(path17.join(d, entry.name), rel);
44624
+ scan(path18.join(d, entry.name), rel);
43218
44625
  } else {
43219
- const stat4 = fs14.statSync(path17.join(d, entry.name));
44626
+ const stat4 = fs15.statSync(path18.join(d, entry.name));
43220
44627
  files.push({ path: rel, size: stat4.size, type: "file" });
43221
44628
  }
43222
44629
  }
@@ -43239,16 +44646,16 @@ var init_dev_server = __esm({
43239
44646
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
43240
44647
  return;
43241
44648
  }
43242
- const fullPath = path17.resolve(dir, path17.normalize(filePath));
44649
+ const fullPath = path18.resolve(dir, path18.normalize(filePath));
43243
44650
  if (!fullPath.startsWith(dir)) {
43244
44651
  this.json(res, 403, { error: "Forbidden" });
43245
44652
  return;
43246
44653
  }
43247
- if (!fs14.existsSync(fullPath) || fs14.statSync(fullPath).isDirectory()) {
44654
+ if (!fs15.existsSync(fullPath) || fs15.statSync(fullPath).isDirectory()) {
43248
44655
  this.json(res, 404, { error: `File not found: ${filePath}` });
43249
44656
  return;
43250
44657
  }
43251
- const content = fs14.readFileSync(fullPath, "utf-8");
44658
+ const content = fs15.readFileSync(fullPath, "utf-8");
43252
44659
  this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
43253
44660
  }
43254
44661
  /** POST /api/providers/:type/file — write a file { path, content } */
@@ -43264,15 +44671,15 @@ var init_dev_server = __esm({
43264
44671
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
43265
44672
  return;
43266
44673
  }
43267
- const fullPath = path17.resolve(dir, path17.normalize(filePath));
44674
+ const fullPath = path18.resolve(dir, path18.normalize(filePath));
43268
44675
  if (!fullPath.startsWith(dir)) {
43269
44676
  this.json(res, 403, { error: "Forbidden" });
43270
44677
  return;
43271
44678
  }
43272
44679
  try {
43273
- if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
43274
- fs14.mkdirSync(path17.dirname(fullPath), { recursive: true });
43275
- fs14.writeFileSync(fullPath, content, "utf-8");
44680
+ if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
44681
+ fs15.mkdirSync(path18.dirname(fullPath), { recursive: true });
44682
+ fs15.writeFileSync(fullPath, content, "utf-8");
43276
44683
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
43277
44684
  this.providerLoader.reload();
43278
44685
  this.json(res, 200, { saved: true, path: filePath, chars: content.length });
@@ -43288,9 +44695,9 @@ var init_dev_server = __esm({
43288
44695
  return;
43289
44696
  }
43290
44697
  for (const name of ["scripts.js", "provider.json"]) {
43291
- const p = path17.join(dir, name);
43292
- if (fs14.existsSync(p)) {
43293
- const source = fs14.readFileSync(p, "utf-8");
44698
+ const p = path18.join(dir, name);
44699
+ if (fs15.existsSync(p)) {
44700
+ const source = fs15.readFileSync(p, "utf-8");
43294
44701
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
43295
44702
  return;
43296
44703
  }
@@ -43309,11 +44716,11 @@ var init_dev_server = __esm({
43309
44716
  this.json(res, 404, { error: `Provider not found: ${type}` });
43310
44717
  return;
43311
44718
  }
43312
- const target = fs14.existsSync(path17.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
43313
- const targetPath = path17.join(dir, target);
44719
+ const target = fs15.existsSync(path18.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
44720
+ const targetPath = path18.join(dir, target);
43314
44721
  try {
43315
- if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
43316
- fs14.writeFileSync(targetPath, source, "utf-8");
44722
+ if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
44723
+ fs15.writeFileSync(targetPath, source, "utf-8");
43317
44724
  this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
43318
44725
  this.providerLoader.reload();
43319
44726
  this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
@@ -43470,21 +44877,21 @@ var init_dev_server = __esm({
43470
44877
  }
43471
44878
  let targetDir;
43472
44879
  targetDir = this.providerLoader.getUserProviderDir(category, type);
43473
- const jsonPath = path17.join(targetDir, "provider.json");
43474
- if (fs14.existsSync(jsonPath)) {
44880
+ const jsonPath = path18.join(targetDir, "provider.json");
44881
+ if (fs15.existsSync(jsonPath)) {
43475
44882
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
43476
44883
  return;
43477
44884
  }
43478
44885
  try {
43479
44886
  const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2, osPaths, processNames });
43480
- fs14.mkdirSync(targetDir, { recursive: true });
43481
- fs14.writeFileSync(jsonPath, result["provider.json"], "utf-8");
44887
+ fs15.mkdirSync(targetDir, { recursive: true });
44888
+ fs15.writeFileSync(jsonPath, result["provider.json"], "utf-8");
43482
44889
  const createdFiles = ["provider.json"];
43483
44890
  if (result.files) {
43484
44891
  for (const [relPath, content] of Object.entries(result.files)) {
43485
- const fullPath = path17.join(targetDir, relPath);
43486
- fs14.mkdirSync(path17.dirname(fullPath), { recursive: true });
43487
- fs14.writeFileSync(fullPath, content, "utf-8");
44892
+ const fullPath = path18.join(targetDir, relPath);
44893
+ fs15.mkdirSync(path18.dirname(fullPath), { recursive: true });
44894
+ fs15.writeFileSync(fullPath, content, "utf-8");
43488
44895
  createdFiles.push(relPath);
43489
44896
  }
43490
44897
  }
@@ -43533,45 +44940,45 @@ var init_dev_server = __esm({
43533
44940
  }
43534
44941
  // ─── Phase 2: Auto-Implement Backend ───
43535
44942
  getLatestScriptVersionDir(scriptsDir) {
43536
- if (!fs14.existsSync(scriptsDir)) return null;
43537
- const versions = fs14.readdirSync(scriptsDir).filter((d) => {
44943
+ if (!fs15.existsSync(scriptsDir)) return null;
44944
+ const versions = fs15.readdirSync(scriptsDir).filter((d) => {
43538
44945
  try {
43539
- return fs14.statSync(path17.join(scriptsDir, d)).isDirectory();
44946
+ return fs15.statSync(path18.join(scriptsDir, d)).isDirectory();
43540
44947
  } catch {
43541
44948
  return false;
43542
44949
  }
43543
44950
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
43544
44951
  if (versions.length === 0) return null;
43545
- return path17.join(scriptsDir, versions[0]);
44952
+ return path18.join(scriptsDir, versions[0]);
43546
44953
  }
43547
44954
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
43548
- const canonicalUserDir = path17.resolve(this.providerLoader.getUserProviderDir(category, type));
43549
- const desiredDir = requestedDir ? path17.resolve(requestedDir) : canonicalUserDir;
43550
- const upstreamRoot = path17.resolve(this.providerLoader.getUpstreamDir());
43551
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path17.sep}`)) {
44955
+ const canonicalUserDir = path18.resolve(this.providerLoader.getUserProviderDir(category, type));
44956
+ const desiredDir = requestedDir ? path18.resolve(requestedDir) : canonicalUserDir;
44957
+ const upstreamRoot = path18.resolve(this.providerLoader.getUpstreamDir());
44958
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path18.sep}`)) {
43552
44959
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
43553
44960
  }
43554
- if (path17.basename(desiredDir) !== type) {
44961
+ if (path18.basename(desiredDir) !== type) {
43555
44962
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
43556
44963
  }
43557
44964
  const sourceDir = this.findProviderDir(type);
43558
44965
  if (!sourceDir) {
43559
44966
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
43560
44967
  }
43561
- if (!fs14.existsSync(desiredDir)) {
43562
- fs14.mkdirSync(path17.dirname(desiredDir), { recursive: true });
43563
- fs14.cpSync(sourceDir, desiredDir, { recursive: true });
44968
+ if (!fs15.existsSync(desiredDir)) {
44969
+ fs15.mkdirSync(path18.dirname(desiredDir), { recursive: true });
44970
+ fs15.cpSync(sourceDir, desiredDir, { recursive: true });
43564
44971
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
43565
44972
  }
43566
- const providerJson = path17.join(desiredDir, "provider.json");
43567
- if (!fs14.existsSync(providerJson)) {
44973
+ const providerJson = path18.join(desiredDir, "provider.json");
44974
+ if (!fs15.existsSync(providerJson)) {
43568
44975
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
43569
44976
  }
43570
44977
  try {
43571
- const providerData = JSON.parse(fs14.readFileSync(providerJson, "utf-8"));
44978
+ const providerData = JSON.parse(fs15.readFileSync(providerJson, "utf-8"));
43572
44979
  if (providerData.disableUpstream !== true) {
43573
44980
  providerData.disableUpstream = true;
43574
- fs14.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
44981
+ fs15.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
43575
44982
  }
43576
44983
  } catch (error48) {
43577
44984
  return {
@@ -43611,7 +45018,7 @@ var init_dev_server = __esm({
43611
45018
  setMode: "set_mode.js"
43612
45019
  };
43613
45020
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
43614
- const scriptsDir = path17.join(providerDir, "scripts");
45021
+ const scriptsDir = path18.join(providerDir, "scripts");
43615
45022
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
43616
45023
  if (latestScriptsDir) {
43617
45024
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -43619,10 +45026,10 @@ var init_dev_server = __esm({
43619
45026
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
43620
45027
  lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
43621
45028
  lines.push("");
43622
- for (const file2 of fs14.readdirSync(latestScriptsDir)) {
45029
+ for (const file2 of fs15.readdirSync(latestScriptsDir)) {
43623
45030
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
43624
45031
  try {
43625
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45032
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43626
45033
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
43627
45034
  lines.push("```javascript");
43628
45035
  lines.push(content);
@@ -43632,14 +45039,14 @@ var init_dev_server = __esm({
43632
45039
  }
43633
45040
  }
43634
45041
  }
43635
- const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
45042
+ const refFiles = fs15.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43636
45043
  if (refFiles.length > 0) {
43637
45044
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
43638
45045
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
43639
45046
  lines.push("");
43640
45047
  for (const file2 of refFiles) {
43641
45048
  try {
43642
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45049
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43643
45050
  lines.push(`### \`${file2}\` \u{1F512}`);
43644
45051
  lines.push("```javascript");
43645
45052
  lines.push(content);
@@ -43680,11 +45087,11 @@ var init_dev_server = __esm({
43680
45087
  lines.push("");
43681
45088
  }
43682
45089
  }
43683
- const docsDir = path17.join(providerDir, "../../docs");
45090
+ const docsDir = path18.join(providerDir, "../../docs");
43684
45091
  const loadGuide = (name) => {
43685
45092
  try {
43686
- const p = path17.join(docsDir, name);
43687
- if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
45093
+ const p = path18.join(docsDir, name);
45094
+ if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
43688
45095
  } catch {
43689
45096
  }
43690
45097
  return null;
@@ -43857,7 +45264,7 @@ var init_dev_server = __esm({
43857
45264
  parseApproval: "parse_approval.js"
43858
45265
  };
43859
45266
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
43860
- const scriptsDir = path17.join(providerDir, "scripts");
45267
+ const scriptsDir = path18.join(providerDir, "scripts");
43861
45268
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
43862
45269
  if (latestScriptsDir) {
43863
45270
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -43865,11 +45272,11 @@ var init_dev_server = __esm({
43865
45272
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
43866
45273
  lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
43867
45274
  lines.push("");
43868
- for (const file2 of fs14.readdirSync(latestScriptsDir)) {
45275
+ for (const file2 of fs15.readdirSync(latestScriptsDir)) {
43869
45276
  if (!file2.endsWith(".js")) continue;
43870
45277
  if (!targetFileNames.has(file2)) continue;
43871
45278
  try {
43872
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45279
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43873
45280
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
43874
45281
  lines.push("```javascript");
43875
45282
  lines.push(content);
@@ -43878,14 +45285,14 @@ var init_dev_server = __esm({
43878
45285
  } catch {
43879
45286
  }
43880
45287
  }
43881
- const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
45288
+ const refFiles = fs15.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43882
45289
  if (refFiles.length > 0) {
43883
45290
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
43884
45291
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
43885
45292
  lines.push("");
43886
45293
  for (const file2 of refFiles) {
43887
45294
  try {
43888
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45295
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43889
45296
  lines.push(`### \`${file2}\` \u{1F512}`);
43890
45297
  lines.push("```javascript");
43891
45298
  lines.push(content);
@@ -43918,11 +45325,11 @@ var init_dev_server = __esm({
43918
45325
  lines.push("");
43919
45326
  }
43920
45327
  }
43921
- const docsDir = path17.join(providerDir, "../../docs");
45328
+ const docsDir = path18.join(providerDir, "../../docs");
43922
45329
  const loadGuide = (name) => {
43923
45330
  try {
43924
- const p = path17.join(docsDir, name);
43925
- if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
45331
+ const p = path18.join(docsDir, name);
45332
+ if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
43926
45333
  } catch {
43927
45334
  }
43928
45335
  return null;
@@ -43987,6 +45394,7 @@ var init_dev_server = __esm({
43987
45394
  lines.push("### 2. Inspect parsed + raw adapter state");
43988
45395
  lines.push("```bash");
43989
45396
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
45397
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
43990
45398
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
43991
45399
  lines.push("```");
43992
45400
  lines.push("");
@@ -44121,6 +45529,16 @@ data: ${JSON.stringify(msg.data)}
44121
45529
  async handleCliSend(req, res) {
44122
45530
  return handleCliSend(this, req, res);
44123
45531
  }
45532
+ /** POST /api/cli/exercise — launch/send/approve/wait helper for provider-fix loops */
45533
+ async handleCliExercise(req, res) {
45534
+ return handleCliExercise(this, req, res);
45535
+ }
45536
+ async handleCliFixtureCapture(req, res) {
45537
+ return handleCliFixtureCapture(this, req, res);
45538
+ }
45539
+ async handleCliFixtureReplay(req, res) {
45540
+ return handleCliFixtureReplay(this, req, res);
45541
+ }
44124
45542
  /** POST /api/cli/stop — stop a running CLI { type } */
44125
45543
  async handleCliStop(req, res) {
44126
45544
  return handleCliStop(this, req, res);
@@ -44144,6 +45562,13 @@ data: ${JSON.stringify(msg.data)}
44144
45562
  async handleCliDebug(type, _req, res) {
44145
45563
  return handleCliDebug(this, type, _req, res);
44146
45564
  }
45565
+ /** GET /api/cli/trace/:type — recent CLI trace timeline plus current debug snapshot */
45566
+ async handleCliTrace(type, _req, res) {
45567
+ return handleCliTrace(this, type, _req, res);
45568
+ }
45569
+ async handleCliFixtureList(type, _req, res) {
45570
+ return handleCliFixtureList(this, type, _req, res);
45571
+ }
44147
45572
  /** POST /api/cli/resolve — resolve an approval modal { type, buttonIndex } */
44148
45573
  async handleCliResolve(req, res) {
44149
45574
  return handleCliResolve(this, req, res);
@@ -44451,7 +45876,18 @@ var init_session_host_transport = __esm({
44451
45876
  });
44452
45877
  }
44453
45878
  async boot() {
44454
- await this.client.connect();
45879
+ if (typeof this.options.ensureReady === "function") {
45880
+ await this.options.ensureReady();
45881
+ }
45882
+ try {
45883
+ await this.client.connect();
45884
+ } catch (error48) {
45885
+ if (typeof this.options.ensureReady !== "function") {
45886
+ throw error48;
45887
+ }
45888
+ await this.options.ensureReady();
45889
+ await this.client.connect();
45890
+ }
44455
45891
  this.unsubscribe = this.client.onEvent((event) => this.handleEvent(event));
44456
45892
  let record2 = null;
44457
45893
  if (this.options.attachExisting) {
@@ -44764,8 +46200,8 @@ async function installExtension(ide, extension) {
44764
46200
  const res = await fetch(extension.vsixUrl);
44765
46201
  if (res.ok) {
44766
46202
  const buffer = Buffer.from(await res.arrayBuffer());
44767
- const fs18 = await import("fs");
44768
- fs18.writeFileSync(vsixPath, buffer);
46203
+ const fs19 = await import("fs");
46204
+ fs19.writeFileSync(vsixPath, buffer);
44769
46205
  return new Promise((resolve13) => {
44770
46206
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
44771
46207
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
@@ -45604,17 +47040,17 @@ function canPeerUsePrivilegedShareCommand(commandType, permission) {
45604
47040
  return false;
45605
47041
  }
45606
47042
  }
45607
- var fs15, path18, os20, import_node_module2, esmRequire, logFile, log, logDebug, DaemonP2PSender;
47043
+ var fs16, path19, os20, import_node_module2, esmRequire, logFile, log, logDebug, DaemonP2PSender;
45608
47044
  var init_daemon_p2p = __esm({
45609
47045
  "src/daemon-p2p.ts"() {
45610
47046
  "use strict";
45611
- fs15 = __toESM(require("fs"));
47047
+ fs16 = __toESM(require("fs"));
45612
47048
  init_src();
45613
- path18 = __toESM(require("path"));
47049
+ path19 = __toESM(require("path"));
45614
47050
  os20 = __toESM(require("os"));
45615
47051
  import_node_module2 = require("module");
45616
47052
  esmRequire = (0, import_node_module2.createRequire)(__filename);
45617
- logFile = path18.join(os20.tmpdir(), "adhdev_daemon_p2p.log");
47053
+ logFile = path19.join(os20.tmpdir(), "adhdev_daemon_p2p.log");
45618
47054
  log = (msg) => {
45619
47055
  LOG.info("P2P", `[${(/* @__PURE__ */ new Date()).toISOString()}] [P2P] ${msg}`);
45620
47056
  };
@@ -45682,17 +47118,17 @@ ${e?.stack || ""}`);
45682
47118
  const prebuildKey = `${platform11}-${arch3}`;
45683
47119
  try {
45684
47120
  const candidates = [
45685
- path18.join(__dirname, "node_modules", "node-datachannel"),
45686
- path18.join(__dirname, "..", "node_modules", "node-datachannel"),
45687
- path18.join(__dirname, "..", "..", "node_modules", "node-datachannel")
47121
+ path19.join(__dirname, "node_modules", "node-datachannel"),
47122
+ path19.join(__dirname, "..", "node_modules", "node-datachannel"),
47123
+ path19.join(__dirname, "..", "..", "node_modules", "node-datachannel")
45688
47124
  ];
45689
47125
  for (const candidate of candidates) {
45690
- const prebuildPath = path18.join(candidate, "prebuilds", prebuildKey, "node_datachannel.node");
45691
- if (fs15.existsSync(prebuildPath)) {
45692
- const targetDir = path18.join(candidate, "build", "Release");
45693
- const targetPath = path18.join(targetDir, "node_datachannel.node");
45694
- fs15.mkdirSync(targetDir, { recursive: true });
45695
- fs15.copyFileSync(prebuildPath, targetPath);
47126
+ const prebuildPath = path19.join(candidate, "prebuilds", prebuildKey, "node_datachannel.node");
47127
+ if (fs16.existsSync(prebuildPath)) {
47128
+ const targetDir = path19.join(candidate, "build", "Release");
47129
+ const targetPath = path19.join(targetDir, "node_datachannel.node");
47130
+ fs16.mkdirSync(targetDir, { recursive: true });
47131
+ fs16.copyFileSync(prebuildPath, targetPath);
45696
47132
  try {
45697
47133
  delete esmRequire.cache[esmRequire.resolve("node-datachannel")];
45698
47134
  } catch {
@@ -46592,20 +48028,34 @@ __export(session_host_exports, {
46592
48028
  listHostedCliRuntimes: () => listHostedCliRuntimes2,
46593
48029
  stopSessionHost: () => stopSessionHost
46594
48030
  });
48031
+ function buildSessionHostEnv(baseEnv) {
48032
+ const env = {};
48033
+ for (const [key, value] of Object.entries(baseEnv)) {
48034
+ if (typeof value !== "string") continue;
48035
+ env[key] = value;
48036
+ }
48037
+ for (const key of Object.keys(env)) {
48038
+ if (key === "INIT_CWD" || key === "NO_COLOR" || key === "FORCE_COLOR" || key === "npm_command" || key === "npm_execpath" || key === "npm_node_execpath" || key.startsWith("npm_") || key.startsWith("npm_config_") || key.startsWith("npm_package_") || key.startsWith("npm_lifecycle_") || key.startsWith("PNPM_") || key.startsWith("YARN_") || key.startsWith("BUN_")) {
48039
+ delete env[key];
48040
+ }
48041
+ }
48042
+ env.ADHDEV_SESSION_HOST_NAME = SESSION_HOST_APP_NAME;
48043
+ return env;
48044
+ }
46595
48045
  function resolveSessionHostEntry() {
46596
48046
  const packagedCandidates = [
46597
- path19.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
46598
- path19.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
48047
+ path20.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
48048
+ path20.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
46599
48049
  ];
46600
48050
  for (const candidate of packagedCandidates) {
46601
- if (fs16.existsSync(candidate)) {
48051
+ if (fs17.existsSync(candidate)) {
46602
48052
  return candidate;
46603
48053
  }
46604
48054
  }
46605
48055
  return require.resolve("@adhdev/session-host-daemon");
46606
48056
  }
46607
48057
  function getSessionHostPidFile() {
46608
- return path19.join(os21.homedir(), ".adhdev", `${SESSION_HOST_APP_NAME}-session-host.pid`);
48058
+ return path20.join(os21.homedir(), ".adhdev", `${SESSION_HOST_APP_NAME}-session-host.pid`);
46609
48059
  }
46610
48060
  function killPid2(pid) {
46611
48061
  try {
@@ -46623,8 +48073,8 @@ function stopSessionHost() {
46623
48073
  let stopped = false;
46624
48074
  const pidFile = getSessionHostPidFile();
46625
48075
  try {
46626
- if (fs16.existsSync(pidFile)) {
46627
- const pid = Number.parseInt(fs16.readFileSync(pidFile, "utf8").trim(), 10);
48076
+ if (fs17.existsSync(pidFile)) {
48077
+ const pid = Number.parseInt(fs17.readFileSync(pidFile, "utf8").trim(), 10);
46628
48078
  if (Number.isFinite(pid)) {
46629
48079
  stopped = killPid2(pid) || stopped;
46630
48080
  }
@@ -46632,7 +48082,7 @@ function stopSessionHost() {
46632
48082
  } catch {
46633
48083
  } finally {
46634
48084
  try {
46635
- fs16.unlinkSync(pidFile);
48085
+ fs17.unlinkSync(pidFile);
46636
48086
  } catch {
46637
48087
  }
46638
48088
  }
@@ -46651,36 +48101,49 @@ function stopSessionHost() {
46651
48101
  return stopped;
46652
48102
  }
46653
48103
  async function ensureSessionHostReady2() {
46654
- return ensureSessionHostReady({
46655
- appName: SESSION_HOST_APP_NAME,
46656
- spawnHost: () => {
46657
- const entry = resolveSessionHostEntry();
46658
- const child = (0, import_child_process11.spawn)(process.execPath, [entry], {
46659
- detached: true,
46660
- stdio: "ignore",
46661
- windowsHide: true,
46662
- env: {
46663
- ...process.env,
46664
- ADHDEV_SESSION_HOST_NAME: SESSION_HOST_APP_NAME
46665
- }
46666
- });
46667
- child.unref();
46668
- }
46669
- });
48104
+ const spawnHost = () => {
48105
+ const entry = resolveSessionHostEntry();
48106
+ const child = (0, import_child_process11.spawn)(process.execPath, [entry], {
48107
+ detached: true,
48108
+ stdio: "ignore",
48109
+ windowsHide: true,
48110
+ env: buildSessionHostEnv(process.env)
48111
+ });
48112
+ child.unref();
48113
+ };
48114
+ try {
48115
+ return await ensureSessionHostReady({
48116
+ appName: SESSION_HOST_APP_NAME,
48117
+ spawnHost,
48118
+ timeoutMs: SESSION_HOST_START_TIMEOUT_MS
48119
+ });
48120
+ } catch (error48) {
48121
+ stopSessionHost();
48122
+ return ensureSessionHostReady({
48123
+ appName: SESSION_HOST_APP_NAME,
48124
+ spawnHost,
48125
+ timeoutMs: SESSION_HOST_START_TIMEOUT_MS
48126
+ }).catch((retryError) => {
48127
+ const initialMessage = error48 instanceof Error ? error48.message : String(error48);
48128
+ const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);
48129
+ throw new Error(`Session host failed to start after retry (${initialMessage}; retry: ${retryMessage})`);
48130
+ });
48131
+ }
46670
48132
  }
46671
48133
  async function listHostedCliRuntimes2(endpoint) {
46672
48134
  return listHostedCliRuntimes(endpoint);
46673
48135
  }
46674
- var import_child_process11, fs16, os21, path19, SESSION_HOST_APP_NAME;
48136
+ var import_child_process11, fs17, os21, path20, SESSION_HOST_APP_NAME, SESSION_HOST_START_TIMEOUT_MS;
46675
48137
  var init_session_host = __esm({
46676
48138
  "src/session-host.ts"() {
46677
48139
  "use strict";
46678
48140
  import_child_process11 = require("child_process");
46679
- fs16 = __toESM(require("fs"));
48141
+ fs17 = __toESM(require("fs"));
46680
48142
  os21 = __toESM(require("os"));
46681
- path19 = __toESM(require("path"));
48143
+ path20 = __toESM(require("path"));
46682
48144
  init_src();
46683
48145
  SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
48146
+ SESSION_HOST_START_TIMEOUT_MS = 15e3;
46684
48147
  }
46685
48148
  });
46686
48149
 
@@ -46692,24 +48155,24 @@ __export(adhdev_daemon_exports, {
46692
48155
  stopDaemon: () => stopDaemon
46693
48156
  });
46694
48157
  function getDaemonPidFile() {
46695
- const dir = path20.join(os22.homedir(), ".adhdev");
46696
- if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
46697
- return path20.join(dir, "daemon.pid");
48158
+ const dir = path21.join(os22.homedir(), ".adhdev");
48159
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
48160
+ return path21.join(dir, "daemon.pid");
46698
48161
  }
46699
48162
  function writeDaemonPid(pid) {
46700
- fs17.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
48163
+ fs18.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
46701
48164
  }
46702
48165
  function removeDaemonPid() {
46703
48166
  try {
46704
- fs17.unlinkSync(getDaemonPidFile());
48167
+ fs18.unlinkSync(getDaemonPidFile());
46705
48168
  } catch (e) {
46706
48169
  }
46707
48170
  }
46708
48171
  function isDaemonRunning() {
46709
48172
  const pidFile = getDaemonPidFile();
46710
48173
  try {
46711
- if (!fs17.existsSync(pidFile)) return false;
46712
- const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim());
48174
+ if (!fs18.existsSync(pidFile)) return false;
48175
+ const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim());
46713
48176
  process.kill(pid, 0);
46714
48177
  return true;
46715
48178
  } catch {
@@ -46720,8 +48183,8 @@ function isDaemonRunning() {
46720
48183
  function stopDaemon() {
46721
48184
  const pidFile = getDaemonPidFile();
46722
48185
  try {
46723
- if (!fs17.existsSync(pidFile)) return false;
46724
- const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim());
48186
+ if (!fs18.existsSync(pidFile)) return false;
48187
+ const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim());
46725
48188
  process.kill(pid, "SIGTERM");
46726
48189
  removeDaemonPid();
46727
48190
  return true;
@@ -46730,7 +48193,7 @@ function stopDaemon() {
46730
48193
  return false;
46731
48194
  }
46732
48195
  }
46733
- var os22, fs17, path20, import_chalk2, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
48196
+ var os22, fs18, path21, import_chalk2, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
46734
48197
  var init_adhdev_daemon = __esm({
46735
48198
  "src/adhdev-daemon.ts"() {
46736
48199
  "use strict";
@@ -46741,19 +48204,19 @@ var init_adhdev_daemon = __esm({
46741
48204
  init_session_host();
46742
48205
  init_dist();
46743
48206
  os22 = __toESM(require("os"));
46744
- fs17 = __toESM(require("fs"));
46745
- path20 = __toESM(require("path"));
48207
+ fs18 = __toESM(require("fs"));
48208
+ path21 = __toESM(require("path"));
46746
48209
  import_chalk2 = __toESM(require("chalk"));
46747
- pkgVersion = "0.7.46";
48210
+ pkgVersion = "0.8.0";
46748
48211
  if (pkgVersion === "unknown") {
46749
48212
  try {
46750
48213
  const possiblePaths = [
46751
- path20.join(__dirname, "..", "package.json"),
46752
- path20.join(__dirname, "package.json")
48214
+ path21.join(__dirname, "..", "package.json"),
48215
+ path21.join(__dirname, "package.json")
46753
48216
  ];
46754
48217
  for (const p of possiblePaths) {
46755
48218
  try {
46756
- const data = JSON.parse(fs17.readFileSync(p, "utf-8"));
48219
+ const data = JSON.parse(fs18.readFileSync(p, "utf-8"));
46757
48220
  if (data.version) {
46758
48221
  pkgVersion = data.version;
46759
48222
  break;
@@ -46851,6 +48314,10 @@ ${err?.stack || ""}`);
46851
48314
  removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
46852
48315
  createPtyTransportFactory: ({ runtimeId, providerType, workspace, cliArgs, providerSessionId, attachExisting }) => new SessionHostPtyTransportFactory({
46853
48316
  endpoint: sessionHostEndpoint,
48317
+ ensureReady: async () => {
48318
+ const activeEndpoint = await ensureSessionHostReady2();
48319
+ this.sessionHostEndpoint = activeEndpoint;
48320
+ },
46854
48321
  clientId: `daemon_${config2.machineId}`,
46855
48322
  runtimeId,
46856
48323
  providerType,
@@ -47446,8 +48913,8 @@ async function startDaemonFlow() {
47446
48913
  const daemon = new AdhdevDaemon2();
47447
48914
  const { execSync: execSync7 } = await import("child_process");
47448
48915
  const os23 = await import("os");
47449
- const path21 = await import("path");
47450
- const logPath = path21.join(os23.homedir(), ".adhdev", "daemon.log");
48916
+ const path23 = await import("path");
48917
+ const logPath = path23.join(os23.homedir(), ".adhdev", "daemon.log");
47451
48918
  const platform11 = os23.platform();
47452
48919
  try {
47453
48920
  if (platform11 === "win32") {
@@ -48437,35 +49904,35 @@ function registerProviderCommands(program2) {
48437
49904
  let osPaths = {};
48438
49905
  let processNames = {};
48439
49906
  if (category === "ide") {
48440
- const fs18 = await import("fs");
48441
- const path21 = await import("path");
49907
+ const fs19 = await import("fs");
49908
+ const path23 = await import("path");
48442
49909
  const os23 = await import("os");
48443
49910
  if (os23.platform() === "darwin") {
48444
49911
  while (true) {
48445
49912
  const p = (await rl.question(`macOS Application Path (e.g. /Applications/${defaultName}.app): `)).trim() || `/Applications/${defaultName}.app`;
48446
49913
  if (p === "skip") break;
48447
- if (!fs18.existsSync(p)) {
49914
+ if (!fs19.existsSync(p)) {
48448
49915
  console.log(import_chalk6.default.red(` \u2717 Path not found: ${p}`));
48449
49916
  console.log(import_chalk6.default.gray(` (Please provide the exact absolute path to the .app or binary, or type 'skip')`));
48450
49917
  continue;
48451
49918
  }
48452
49919
  console.log(import_chalk6.default.green(` \u2713 Path verified: ${p}`));
48453
49920
  osPaths["darwin"] = [p];
48454
- processNames["darwin"] = path21.basename(p, ".app");
49921
+ processNames["darwin"] = path23.basename(p, ".app");
48455
49922
  break;
48456
49923
  }
48457
49924
  } else if (os23.platform() === "win32") {
48458
49925
  while (true) {
48459
49926
  const p = (await rl.question(`Windows Executable Path (e.g. C:\\Program Files\\${defaultName}\\${defaultName}.exe): `)).trim();
48460
49927
  if (!p || p === "skip") break;
48461
- if (!fs18.existsSync(p)) {
49928
+ if (!fs19.existsSync(p)) {
48462
49929
  console.log(import_chalk6.default.red(` \u2717 Path not found: ${p}`));
48463
49930
  console.log(import_chalk6.default.gray(` (Please provide the exact absolute path, or type 'skip')`));
48464
49931
  continue;
48465
49932
  }
48466
49933
  console.log(import_chalk6.default.green(` \u2713 Path verified: ${p}`));
48467
49934
  osPaths["win32"] = [p];
48468
- processNames["win32"] = path21.basename(p, ".exe");
49935
+ processNames["win32"] = path23.basename(p, ".exe");
48469
49936
  break;
48470
49937
  }
48471
49938
  }
@@ -49141,8 +50608,8 @@ function registerCdpCommands(program2) {
49141
50608
  }
49142
50609
  const output = typeof result === "string" ? result : JSON.stringify(result, null, 2);
49143
50610
  if (options.output) {
49144
- const fs18 = await import("fs");
49145
- fs18.writeFileSync(options.output, output, "utf-8");
50611
+ const fs19 = await import("fs");
50612
+ fs19.writeFileSync(options.output, output, "utf-8");
49146
50613
  console.log(import_chalk6.default.green(`
49147
50614
  \u2713 Saved to ${options.output} (${output.length} chars)
49148
50615
  `));
@@ -49245,8 +50712,8 @@ function registerCdpCommands(program2) {
49245
50712
  ws2.on("message", async (data) => {
49246
50713
  const msg = JSON.parse(data.toString());
49247
50714
  if (msg.id === 1 && msg.result?.data) {
49248
- const fs18 = await import("fs");
49249
- fs18.writeFileSync(options.output, Buffer.from(msg.result.data, "base64"));
50715
+ const fs19 = await import("fs");
50716
+ fs19.writeFileSync(options.output, Buffer.from(msg.result.data, "base64"));
49250
50717
  console.log(import_chalk6.default.green(`
49251
50718
  \u2713 Screenshot saved to ${options.output}
49252
50719
  `));