adhdev 0.7.46 → 0.8.1

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];
@@ -39587,6 +40039,15 @@ var init_poller = __esm({
39587
40039
  cdpManagerKey: ideType,
39588
40040
  instanceKey: `ide:${ideType}`
39589
40041
  });
40042
+ const activeSessionId2 = agentStreamManager.getActiveSessionId(parentSessionId);
40043
+ if (!activeSessionId2 || enabledExtTypes.size === 1) {
40044
+ await agentStreamManager.setActiveSession(
40045
+ cdp,
40046
+ parentSessionId,
40047
+ extInstance.getInstanceId()
40048
+ );
40049
+ LOG.info("AgentStream", `Auto-activated enabled extension: ${extType} (${ideType})`);
40050
+ }
39590
40051
  }
39591
40052
  LOG.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
39592
40053
  }
@@ -41422,6 +41883,160 @@ var init_dev_cdp_handlers = __esm({
41422
41883
  });
41423
41884
 
41424
41885
  // ../../oss/packages/daemon-core/src/daemon/dev-cli-debug.ts
41886
+ function slugifyFixtureName(value) {
41887
+ const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
41888
+ return normalized || `fixture-${Date.now()}`;
41889
+ }
41890
+ function getCliFixtureDir(ctx, type) {
41891
+ const providerDir = ctx.providerLoader.findProviderDir(type);
41892
+ if (!providerDir) {
41893
+ throw new Error(`Provider directory not found for '${type}'`);
41894
+ }
41895
+ return path16.join(providerDir, "fixtures");
41896
+ }
41897
+ function readCliFixture(ctx, type, name) {
41898
+ const fixtureDir = getCliFixtureDir(ctx, type);
41899
+ const filePath = path16.join(fixtureDir, `${name}.json`);
41900
+ if (!fs13.existsSync(filePath)) {
41901
+ throw new Error(`Fixture not found: ${filePath}`);
41902
+ }
41903
+ return JSON.parse(fs13.readFileSync(filePath, "utf-8"));
41904
+ }
41905
+ function getExerciseTranscriptText(result) {
41906
+ const parts = [];
41907
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41908
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41909
+ for (const message of [...debugMessages, ...traceMessages]) {
41910
+ if (!message || typeof message.content !== "string") continue;
41911
+ parts.push(message.content);
41912
+ }
41913
+ if (typeof result?.debug?.partialResponse === "string") parts.push(result.debug.partialResponse);
41914
+ if (typeof result?.trace?.responseBuffer === "string") parts.push(result.trace.responseBuffer);
41915
+ return parts.join("\n");
41916
+ }
41917
+ function getExerciseLastAssistant(result) {
41918
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41919
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41920
+ for (const messages of [debugMessages, traceMessages]) {
41921
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
41922
+ const message = messages[i];
41923
+ if (message?.role === "assistant" && typeof message.content === "string" && message.content.trim()) {
41924
+ return message.content;
41925
+ }
41926
+ }
41927
+ }
41928
+ return "";
41929
+ }
41930
+ function getExerciseMessageCount(result) {
41931
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41932
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41933
+ return Math.max(debugMessages.length, traceMessages.length);
41934
+ }
41935
+ function compileFixtureRegex(source) {
41936
+ const value = String(source || "").trim();
41937
+ if (!value) return null;
41938
+ const delimited = value.match(/^\/([\s\S]+)\/([dgimsuvy]*)$/);
41939
+ try {
41940
+ if (delimited) {
41941
+ return new RegExp(delimited[1], delimited[2]);
41942
+ }
41943
+ return new RegExp(value, "m");
41944
+ } catch {
41945
+ return null;
41946
+ }
41947
+ }
41948
+ function statusesContainSequence(actual, expected) {
41949
+ if (!expected.length) return true;
41950
+ let index = 0;
41951
+ for (const status of actual) {
41952
+ if (status === expected[index]) index += 1;
41953
+ if (index >= expected.length) return true;
41954
+ }
41955
+ return false;
41956
+ }
41957
+ function validateCliFixtureResult(result, assertions) {
41958
+ const failures = [];
41959
+ const transcriptText = getExerciseTranscriptText(result);
41960
+ const lastAssistant = getExerciseLastAssistant(result);
41961
+ const mustContainAny = assertions.mustContainAny || [];
41962
+ const mustNotContainAny = assertions.mustNotContainAny || [];
41963
+ const mustMatchAny = assertions.mustMatchAny || [];
41964
+ const mustNotMatchAny = assertions.mustNotMatchAny || [];
41965
+ const lastAssistantMustContainAny = assertions.lastAssistantMustContainAny || [];
41966
+ const lastAssistantMustNotContainAny = assertions.lastAssistantMustNotContainAny || [];
41967
+ const lastAssistantMustMatchAny = assertions.lastAssistantMustMatchAny || [];
41968
+ const lastAssistantMustNotMatchAny = assertions.lastAssistantMustNotMatchAny || [];
41969
+ const statusesSeen = Array.isArray(result?.statusesSeen) ? result.statusesSeen.map((value) => String(value)) : [];
41970
+ if (assertions.requireNotTimedOut !== false && result?.timedOut) {
41971
+ failures.push("Exercise timed out");
41972
+ }
41973
+ const missingRequired = mustContainAny.filter((value) => !transcriptText.includes(value));
41974
+ if (missingRequired.length > 0) {
41975
+ failures.push(`Missing required substrings: ${missingRequired.join(", ")}`);
41976
+ }
41977
+ const presentBanned = mustNotContainAny.filter((value) => transcriptText.includes(value));
41978
+ if (presentBanned.length > 0) {
41979
+ failures.push(`Found banned substrings: ${presentBanned.join(", ")}`);
41980
+ }
41981
+ const missingRegex = mustMatchAny.filter((value) => {
41982
+ const regex = compileFixtureRegex(value);
41983
+ return !regex || !regex.test(transcriptText);
41984
+ });
41985
+ if (missingRegex.length > 0) {
41986
+ failures.push(`Missing required regex matches: ${missingRegex.join(", ")}`);
41987
+ }
41988
+ const presentBannedRegex = mustNotMatchAny.filter((value) => {
41989
+ const regex = compileFixtureRegex(value);
41990
+ return !!regex && regex.test(transcriptText);
41991
+ });
41992
+ if (presentBannedRegex.length > 0) {
41993
+ failures.push(`Found banned regex matches: ${presentBannedRegex.join(", ")}`);
41994
+ }
41995
+ const missingLastAssistant = lastAssistantMustContainAny.filter((value) => !lastAssistant.includes(value));
41996
+ if (missingLastAssistant.length > 0) {
41997
+ failures.push(`Missing required lastAssistant substrings: ${missingLastAssistant.join(", ")}`);
41998
+ }
41999
+ const presentBannedLastAssistant = lastAssistantMustNotContainAny.filter((value) => lastAssistant.includes(value));
42000
+ if (presentBannedLastAssistant.length > 0) {
42001
+ failures.push(`Found banned lastAssistant substrings: ${presentBannedLastAssistant.join(", ")}`);
42002
+ }
42003
+ const missingLastAssistantRegex = lastAssistantMustMatchAny.filter((value) => {
42004
+ const regex = compileFixtureRegex(value);
42005
+ return !regex || !regex.test(lastAssistant);
42006
+ });
42007
+ if (missingLastAssistantRegex.length > 0) {
42008
+ failures.push(`Missing required lastAssistant regex matches: ${missingLastAssistantRegex.join(", ")}`);
42009
+ }
42010
+ const presentBannedLastAssistantRegex = lastAssistantMustNotMatchAny.filter((value) => {
42011
+ const regex = compileFixtureRegex(value);
42012
+ return !!regex && regex.test(lastAssistant);
42013
+ });
42014
+ if (presentBannedLastAssistantRegex.length > 0) {
42015
+ failures.push(`Found banned lastAssistant regex matches: ${presentBannedLastAssistantRegex.join(", ")}`);
42016
+ }
42017
+ if (assertions.statusesSeen?.length && !statusesContainSequence(statusesSeen, assertions.statusesSeen)) {
42018
+ failures.push(`Expected statuses sequence not observed: ${assertions.statusesSeen.join(" -> ")}`);
42019
+ }
42020
+ if (result && typeof result === "object") {
42021
+ result.lastAssistant = lastAssistant;
42022
+ }
42023
+ return failures;
42024
+ }
42025
+ function getCliProviderResolutionMeta(ctx, type, adapter) {
42026
+ const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
42027
+ const resolvedProvider = ctx.providerLoader.resolve(type);
42028
+ if (!adapterMeta && !resolvedProvider) return null;
42029
+ return {
42030
+ type,
42031
+ providerDir: adapterMeta?.providerDir || resolvedProvider?._resolvedProviderDir || ctx.providerLoader.findProviderDir(type),
42032
+ scriptDir: adapterMeta?.scriptDir || resolvedProvider?._resolvedScriptDir || null,
42033
+ scriptsPath: adapterMeta?.scriptsPath || resolvedProvider?._resolvedScriptsPath || null,
42034
+ scriptsSource: adapterMeta?.scriptsSource || resolvedProvider?._resolvedScriptsSource || null,
42035
+ resolvedVersion: adapterMeta?.resolvedVersion || resolvedProvider?._resolvedVersion || null,
42036
+ resolvedOs: adapterMeta?.resolvedOs || resolvedProvider?._resolvedOs || null,
42037
+ versionWarning: adapterMeta?.versionWarning || resolvedProvider?._versionWarning || null
42038
+ };
42039
+ }
41425
42040
  function findCliTarget(ctx, type, instanceId) {
41426
42041
  if (!ctx.instanceManager) return null;
41427
42042
  const cliStates = ctx.instanceManager.collectAllStates().filter((s15) => s15.category === "cli" || s15.category === "acp");
@@ -41430,6 +42045,331 @@ function findCliTarget(ctx, type, instanceId) {
41430
42045
  const matches = cliStates.filter((s15) => s15.type === type);
41431
42046
  return matches[matches.length - 1] || null;
41432
42047
  }
42048
+ function getCliTargetBundle(ctx, type, instanceId) {
42049
+ if (!ctx.instanceManager) return null;
42050
+ const target = findCliTarget(ctx, type, instanceId);
42051
+ if (!target) return null;
42052
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
42053
+ if (!instance) return null;
42054
+ const adapter = instance.getAdapter?.() || instance.adapter;
42055
+ if (!adapter) return null;
42056
+ return { target, instance, adapter };
42057
+ }
42058
+ function sleep(ms2) {
42059
+ return new Promise((resolve13) => setTimeout(resolve13, ms2));
42060
+ }
42061
+ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
42062
+ const startedAt = Date.now();
42063
+ while (Date.now() - startedAt < timeoutMs) {
42064
+ const bundle = getCliTargetBundle(ctx, type, instanceId);
42065
+ if (bundle) {
42066
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42067
+ const startupParseGate = !!debug?.startupParseGate;
42068
+ const adapterReady = !!debug?.ready;
42069
+ const visibleStatusReady = bundle.target.status === "generating" || bundle.target.status === "waiting_approval";
42070
+ const idleReady = bundle.target.status === "idle" && !startupParseGate;
42071
+ if (adapterReady || visibleStatusReady || idleReady) {
42072
+ return bundle;
42073
+ }
42074
+ }
42075
+ await sleep(100);
42076
+ }
42077
+ return getCliTargetBundle(ctx, type, instanceId);
42078
+ }
42079
+ async function runCliExerciseInternal(ctx, body) {
42080
+ if (!ctx.cliManager) {
42081
+ throw new Error("CliManager not available");
42082
+ }
42083
+ if (!ctx.instanceManager) {
42084
+ throw new Error("InstanceManager not available");
42085
+ }
42086
+ const {
42087
+ type,
42088
+ text,
42089
+ instanceId: requestedInstanceId,
42090
+ workingDir,
42091
+ args,
42092
+ autoLaunch = true,
42093
+ freshSession = true,
42094
+ autoResolveApprovals = true,
42095
+ approvalButtonIndex = 0,
42096
+ timeoutMs = 45e3,
42097
+ readyTimeoutMs = 15e3,
42098
+ idleSettledMs = 1200,
42099
+ traceLimit = 160,
42100
+ stopWhenDone = false
42101
+ } = body || {};
42102
+ if (!type) {
42103
+ throw new Error("type required (e.g. claude-cli, codex-cli)");
42104
+ }
42105
+ if (!text || typeof text !== "string") {
42106
+ throw new Error("text required (prompt to send to the CLI)");
42107
+ }
42108
+ let resolvedInstanceId = requestedInstanceId;
42109
+ if (freshSession) {
42110
+ const staleTargets = ctx.instanceManager.collectAllStates().filter((state) => (state.category === "cli" || state.category === "acp") && state.type === type).map((state) => state.instanceId);
42111
+ for (const staleId of staleTargets) {
42112
+ ctx.instanceManager.removeInstance(staleId);
42113
+ }
42114
+ resolvedInstanceId = void 0;
42115
+ }
42116
+ let bundle = getCliTargetBundle(ctx, type, resolvedInstanceId);
42117
+ if (!bundle && autoLaunch) {
42118
+ const launchArgs = [type, workingDir || process.cwd(), Array.isArray(args) ? args : []];
42119
+ let launched = null;
42120
+ let lastLaunchError = null;
42121
+ for (let attempt = 1; attempt <= 2; attempt += 1) {
42122
+ try {
42123
+ launched = await ctx.cliManager.startSession(...launchArgs);
42124
+ lastLaunchError = null;
42125
+ break;
42126
+ } catch (error48) {
42127
+ lastLaunchError = error48 instanceof Error ? error48 : new Error(String(error48?.message || error48));
42128
+ const message = String(lastLaunchError.message || "");
42129
+ const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
42130
+ if (!retryable || attempt === 2) break;
42131
+ await sleep(1e3);
42132
+ }
42133
+ }
42134
+ if (!launched) {
42135
+ throw lastLaunchError || new Error(`Failed to start ${type}`);
42136
+ }
42137
+ resolvedInstanceId = launched.runtimeSessionId;
42138
+ bundle = await waitForCliReady(ctx, type, resolvedInstanceId, Math.max(1e3, readyTimeoutMs));
42139
+ }
42140
+ if (!bundle) {
42141
+ throw new Error(`No running instance found for: ${resolvedInstanceId || type}`);
42142
+ }
42143
+ const initialDebug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42144
+ const initialTrace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
42145
+ const providerResolution = getCliProviderResolutionMeta(ctx, bundle.target.type, bundle.adapter);
42146
+ const preTraceCount = Number(initialTrace?.entryCount || 0);
42147
+ const startAt = Date.now();
42148
+ const statusesSeen = [];
42149
+ const approvalsResolved = [];
42150
+ let lastStatus = "";
42151
+ let lastModalKey = "";
42152
+ let idleSince = 0;
42153
+ let sawBusy = false;
42154
+ ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
42155
+ while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
42156
+ await sleep(150);
42157
+ bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
42158
+ if (!bundle) {
42159
+ throw new Error("CLI instance disappeared during exercise");
42160
+ }
42161
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42162
+ const trace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
42163
+ const status = String(debug?.status || bundle.target.status || "unknown");
42164
+ const traceEntries = Array.isArray(trace?.entries) ? trace.entries : [];
42165
+ const sawSendMessage = traceEntries.some((entry) => entry?.type === "send_message");
42166
+ const sawSubmitWrite = traceEntries.some((entry) => entry?.type === "submit_write");
42167
+ const hasTurnStarted = sawSendMessage || sawSubmitWrite || !!debug?.currentTurnScope;
42168
+ if (status !== lastStatus) {
42169
+ statusesSeen.push(status);
42170
+ lastStatus = status;
42171
+ }
42172
+ if (status === "generating" || status === "waiting_approval") {
42173
+ sawBusy = true;
42174
+ idleSince = 0;
42175
+ }
42176
+ const modal = debug?.activeModal || trace?.activeModal || null;
42177
+ if (autoResolveApprovals && status === "waiting_approval" && modal && Array.isArray(modal.buttons) && modal.buttons.length > 0) {
42178
+ const clampedIndex = Math.max(0, Math.min(Number(approvalButtonIndex) || 0, modal.buttons.length - 1));
42179
+ const modalKey = JSON.stringify({
42180
+ message: modal.message || "",
42181
+ buttons: modal.buttons,
42182
+ index: clampedIndex
42183
+ });
42184
+ if (modalKey !== lastModalKey && typeof bundle.adapter.resolveModal === "function") {
42185
+ lastModalKey = modalKey;
42186
+ approvalsResolved.push({
42187
+ at: Date.now(),
42188
+ buttonIndex: clampedIndex,
42189
+ label: modal.buttons[clampedIndex] || null
42190
+ });
42191
+ bundle.adapter.resolveModal(clampedIndex);
42192
+ continue;
42193
+ }
42194
+ }
42195
+ const traceCount = Number(trace?.entryCount || 0);
42196
+ const hasProgress = hasTurnStarted && (traceCount > preTraceCount || statusesSeen.length > 1 || approvalsResolved.length > 0);
42197
+ if (status === "idle" && hasProgress && sawBusy) {
42198
+ if (!idleSince) idleSince = Date.now();
42199
+ if (Date.now() - idleSince >= Math.max(200, idleSettledMs)) {
42200
+ const payload2 = {
42201
+ exercised: true,
42202
+ instanceId: bundle.target.instanceId,
42203
+ providerState: {
42204
+ type: bundle.target.type,
42205
+ name: bundle.target.name,
42206
+ status: bundle.target.status,
42207
+ mode: "mode" in bundle.target ? bundle.target.mode : void 0
42208
+ },
42209
+ providerResolution,
42210
+ initialDebug,
42211
+ initialTrace,
42212
+ debug,
42213
+ trace,
42214
+ statusesSeen,
42215
+ approvalsResolved,
42216
+ elapsedMs: Date.now() - startAt,
42217
+ timedOut: false
42218
+ };
42219
+ payload2.lastAssistant = getExerciseLastAssistant(payload2);
42220
+ payload2.messageCount = getExerciseMessageCount(payload2);
42221
+ if (stopWhenDone) {
42222
+ ctx.instanceManager.removeInstance(bundle.target.instanceId);
42223
+ }
42224
+ return payload2;
42225
+ }
42226
+ } else if (status === "idle" && hasProgress) {
42227
+ if (!idleSince) idleSince = Date.now();
42228
+ if (Date.now() - idleSince >= Math.max(500, idleSettledMs) && Date.now() - startAt >= 750) {
42229
+ const payload2 = {
42230
+ exercised: true,
42231
+ instanceId: bundle.target.instanceId,
42232
+ providerState: {
42233
+ type: bundle.target.type,
42234
+ name: bundle.target.name,
42235
+ status: bundle.target.status,
42236
+ mode: "mode" in bundle.target ? bundle.target.mode : void 0
42237
+ },
42238
+ providerResolution,
42239
+ initialDebug,
42240
+ initialTrace,
42241
+ debug,
42242
+ trace,
42243
+ statusesSeen,
42244
+ approvalsResolved,
42245
+ elapsedMs: Date.now() - startAt,
42246
+ timedOut: false
42247
+ };
42248
+ payload2.lastAssistant = getExerciseLastAssistant(payload2);
42249
+ payload2.messageCount = getExerciseMessageCount(payload2);
42250
+ if (stopWhenDone) {
42251
+ ctx.instanceManager.removeInstance(bundle.target.instanceId);
42252
+ }
42253
+ return payload2;
42254
+ }
42255
+ } else {
42256
+ idleSince = 0;
42257
+ }
42258
+ }
42259
+ const finalBundle = getCliTargetBundle(ctx, type, bundle.target.instanceId) || bundle;
42260
+ const finalDebug = typeof finalBundle.adapter.getDebugState === "function" ? finalBundle.adapter.getDebugState() : null;
42261
+ const finalTrace = typeof finalBundle.adapter.getTraceState === "function" ? finalBundle.adapter.getTraceState(traceLimit) : null;
42262
+ if (stopWhenDone) {
42263
+ ctx.instanceManager.removeInstance(finalBundle.target.instanceId);
42264
+ }
42265
+ const payload = {
42266
+ exercised: true,
42267
+ instanceId: finalBundle.target.instanceId,
42268
+ providerState: {
42269
+ type: finalBundle.target.type,
42270
+ name: finalBundle.target.name,
42271
+ status: finalBundle.target.status,
42272
+ mode: "mode" in finalBundle.target ? finalBundle.target.mode : void 0
42273
+ },
42274
+ providerResolution: getCliProviderResolutionMeta(ctx, finalBundle.target.type, finalBundle.adapter),
42275
+ initialDebug,
42276
+ initialTrace,
42277
+ debug: finalDebug,
42278
+ trace: finalTrace,
42279
+ statusesSeen,
42280
+ approvalsResolved,
42281
+ elapsedMs: Date.now() - startAt,
42282
+ timedOut: true
42283
+ };
42284
+ payload.lastAssistant = getExerciseLastAssistant(payload);
42285
+ payload.messageCount = getExerciseMessageCount(payload);
42286
+ return payload;
42287
+ }
42288
+ async function runCliAutoImplVerification(ctx, type, verification) {
42289
+ const assertions = {
42290
+ mustContainAny: verification?.mustContainAny || [],
42291
+ mustNotContainAny: verification?.mustNotContainAny || [],
42292
+ mustMatchAny: verification?.mustMatchAny || [],
42293
+ mustNotMatchAny: verification?.mustNotMatchAny || [],
42294
+ lastAssistantMustContainAny: verification?.lastAssistantMustContainAny || [],
42295
+ lastAssistantMustNotContainAny: verification?.lastAssistantMustNotContainAny || [],
42296
+ lastAssistantMustMatchAny: verification?.lastAssistantMustMatchAny || [],
42297
+ lastAssistantMustNotMatchAny: verification?.lastAssistantMustNotMatchAny || [],
42298
+ requireNotTimedOut: true
42299
+ };
42300
+ const rawFixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
42301
+ if (rawFixtureNames.length > 0) {
42302
+ const results = [];
42303
+ for (const rawFixtureName2 of rawFixtureNames) {
42304
+ const name = slugifyFixtureName(rawFixtureName2);
42305
+ const fixture = readCliFixture(ctx, type, name);
42306
+ const mergedAssertions = {
42307
+ ...fixture.assertions,
42308
+ ...assertions
42309
+ };
42310
+ const result2 = await runCliExerciseInternal(ctx, {
42311
+ ...fixture.request,
42312
+ type
42313
+ });
42314
+ const failures2 = validateCliFixtureResult(result2, mergedAssertions);
42315
+ results.push({
42316
+ fixtureName: name,
42317
+ pass: failures2.length === 0,
42318
+ failures: failures2,
42319
+ result: result2,
42320
+ assertions: mergedAssertions,
42321
+ fixture
42322
+ });
42323
+ }
42324
+ const firstFailure = results.find((item) => !item.pass) || results[results.length - 1];
42325
+ return {
42326
+ mode: "fixture_replay_suite",
42327
+ pass: results.every((item) => item.pass),
42328
+ failures: results.flatMap((item) => item.failures.map((failure) => `${item.fixtureName}: ${failure}`)),
42329
+ result: firstFailure.result,
42330
+ assertions: firstFailure.assertions,
42331
+ fixture: firstFailure.fixture,
42332
+ results
42333
+ };
42334
+ }
42335
+ const rawFixtureName = String(verification?.fixtureName || "").trim();
42336
+ if (rawFixtureName) {
42337
+ const name = slugifyFixtureName(rawFixtureName);
42338
+ try {
42339
+ const fixture = readCliFixture(ctx, type, name);
42340
+ const mergedAssertions = {
42341
+ ...fixture.assertions,
42342
+ ...assertions
42343
+ };
42344
+ const result2 = await runCliExerciseInternal(ctx, {
42345
+ ...fixture.request,
42346
+ type
42347
+ });
42348
+ const failures2 = validateCliFixtureResult(result2, mergedAssertions);
42349
+ return {
42350
+ mode: "fixture_replay",
42351
+ pass: failures2.length === 0,
42352
+ failures: failures2,
42353
+ result: result2,
42354
+ assertions: mergedAssertions,
42355
+ fixture
42356
+ };
42357
+ } catch {
42358
+ }
42359
+ }
42360
+ const result = await runCliExerciseInternal(ctx, {
42361
+ ...verification?.request || {},
42362
+ type
42363
+ });
42364
+ const failures = validateCliFixtureResult(result, assertions);
42365
+ return {
42366
+ mode: "exercise",
42367
+ pass: failures.length === 0,
42368
+ failures,
42369
+ result,
42370
+ assertions
42371
+ };
42372
+ }
41433
42373
  async function handleCliStatus(ctx, _req, res) {
41434
42374
  if (!ctx.instanceManager) {
41435
42375
  ctx.json(res, 503, { error: "InstanceManager not available (daemon not fully initialized)" });
@@ -41568,12 +42508,14 @@ async function handleCliDebug(ctx, type, _req, res) {
41568
42508
  status: target.status,
41569
42509
  mode: "mode" in target ? target.mode : void 0
41570
42510
  },
42511
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
41571
42512
  debug: debugState
41572
42513
  });
41573
42514
  } else {
41574
42515
  ctx.json(res, 200, {
41575
42516
  instanceId: target.instanceId,
41576
42517
  providerState: target,
42518
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
41577
42519
  debug: null,
41578
42520
  message: "No debug state available (adapter.getDebugState not found)"
41579
42521
  });
@@ -41582,6 +42524,191 @@ async function handleCliDebug(ctx, type, _req, res) {
41582
42524
  ctx.json(res, 500, { error: `Debug state failed: ${e.message}` });
41583
42525
  }
41584
42526
  }
42527
+ async function handleCliTrace(ctx, type, req, res) {
42528
+ if (!ctx.instanceManager) {
42529
+ ctx.json(res, 503, { error: "InstanceManager not available" });
42530
+ return;
42531
+ }
42532
+ const target = findCliTarget(ctx, type);
42533
+ if (!target) {
42534
+ const allStates = ctx.instanceManager.collectAllStates();
42535
+ ctx.json(res, 404, {
42536
+ error: `No running instance for: ${type}`,
42537
+ available: allStates.filter((s15) => s15.category === "cli" || s15.category === "acp").map((s15) => s15.type)
42538
+ });
42539
+ return;
42540
+ }
42541
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
42542
+ if (!instance) {
42543
+ ctx.json(res, 404, { error: `Instance not found: ${target.instanceId}` });
42544
+ return;
42545
+ }
42546
+ try {
42547
+ const adapter = instance.getAdapter?.() || instance.adapter;
42548
+ const url2 = new URL(req.url || "/", "http://127.0.0.1");
42549
+ const limit = parseInt(url2.searchParams.get("limit") || "120", 10);
42550
+ if (adapter && typeof adapter.getTraceState === "function") {
42551
+ const trace = adapter.getTraceState(limit);
42552
+ const debug = typeof adapter.getDebugState === "function" ? adapter.getDebugState() : null;
42553
+ ctx.json(res, 200, {
42554
+ instanceId: target.instanceId,
42555
+ providerState: {
42556
+ type: target.type,
42557
+ name: target.name,
42558
+ status: target.status,
42559
+ mode: "mode" in target ? target.mode : void 0
42560
+ },
42561
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
42562
+ debug,
42563
+ trace
42564
+ });
42565
+ } else {
42566
+ ctx.json(res, 200, {
42567
+ instanceId: target.instanceId,
42568
+ providerState: target,
42569
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
42570
+ debug: typeof adapter?.getDebugState === "function" ? adapter.getDebugState() : null,
42571
+ trace: null,
42572
+ message: "No trace state available (adapter.getTraceState not found)"
42573
+ });
42574
+ }
42575
+ } catch (e) {
42576
+ ctx.json(res, 500, { error: `Trace state failed: ${e.message}` });
42577
+ }
42578
+ }
42579
+ async function handleCliExercise(ctx, req, res) {
42580
+ try {
42581
+ const body = await ctx.readBody(req);
42582
+ const result = await runCliExerciseInternal(ctx, body || {});
42583
+ ctx.json(res, 200, result);
42584
+ } catch (e) {
42585
+ ctx.json(res, 500, { error: `Exercise failed: ${e.message}` });
42586
+ }
42587
+ }
42588
+ async function handleCliFixtureCapture(ctx, req, res) {
42589
+ try {
42590
+ const body = await ctx.readBody(req);
42591
+ const type = String(body?.type || "");
42592
+ const request = body?.request || {};
42593
+ if (!type) {
42594
+ ctx.json(res, 400, { error: "type required" });
42595
+ return;
42596
+ }
42597
+ if (!request?.text) {
42598
+ ctx.json(res, 400, { error: "request.text required" });
42599
+ return;
42600
+ }
42601
+ const fixtureDir = getCliFixtureDir(ctx, type);
42602
+ fs13.mkdirSync(fixtureDir, { recursive: true });
42603
+ const name = slugifyFixtureName(String(body?.name || `${type}-${Date.now()}`));
42604
+ const result = await runCliExerciseInternal(ctx, { ...request, type });
42605
+ const fixture = {
42606
+ version: 1,
42607
+ kind: "cli-exercise-fixture",
42608
+ name,
42609
+ type,
42610
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
42611
+ providerDir: ctx.providerLoader.findProviderDir(type),
42612
+ providerResolution: result?.providerResolution || null,
42613
+ request: { ...request, type },
42614
+ result,
42615
+ assertions: {
42616
+ mustContainAny: Array.isArray(body?.assertions?.mustContainAny) ? body.assertions.mustContainAny : [],
42617
+ mustNotContainAny: Array.isArray(body?.assertions?.mustNotContainAny) ? body.assertions.mustNotContainAny : [],
42618
+ mustMatchAny: Array.isArray(body?.assertions?.mustMatchAny) ? body.assertions.mustMatchAny : [],
42619
+ mustNotMatchAny: Array.isArray(body?.assertions?.mustNotMatchAny) ? body.assertions.mustNotMatchAny : [],
42620
+ lastAssistantMustContainAny: Array.isArray(body?.assertions?.lastAssistantMustContainAny) ? body.assertions.lastAssistantMustContainAny : [],
42621
+ lastAssistantMustNotContainAny: Array.isArray(body?.assertions?.lastAssistantMustNotContainAny) ? body.assertions.lastAssistantMustNotContainAny : [],
42622
+ lastAssistantMustMatchAny: Array.isArray(body?.assertions?.lastAssistantMustMatchAny) ? body.assertions.lastAssistantMustMatchAny : [],
42623
+ lastAssistantMustNotMatchAny: Array.isArray(body?.assertions?.lastAssistantMustNotMatchAny) ? body.assertions.lastAssistantMustNotMatchAny : [],
42624
+ statusesSeen: Array.isArray(body?.assertions?.statusesSeen) ? body.assertions.statusesSeen : void 0,
42625
+ requireNotTimedOut: body?.assertions?.requireNotTimedOut !== false
42626
+ },
42627
+ notes: typeof body?.notes === "string" ? body.notes : void 0
42628
+ };
42629
+ const filePath = path16.join(fixtureDir, `${name}.json`);
42630
+ fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
42631
+ ctx.json(res, 200, {
42632
+ saved: true,
42633
+ name,
42634
+ path: filePath,
42635
+ fixture,
42636
+ verification: {
42637
+ pass: validateCliFixtureResult(result, fixture.assertions).length === 0,
42638
+ failures: validateCliFixtureResult(result, fixture.assertions)
42639
+ }
42640
+ });
42641
+ } catch (e) {
42642
+ ctx.json(res, 500, { error: `Fixture capture failed: ${e.message}` });
42643
+ }
42644
+ }
42645
+ async function handleCliFixtureList(ctx, type, _req, res) {
42646
+ try {
42647
+ const fixtureDir = getCliFixtureDir(ctx, type);
42648
+ if (!fs13.existsSync(fixtureDir)) {
42649
+ ctx.json(res, 200, { fixtures: [], count: 0 });
42650
+ return;
42651
+ }
42652
+ const fixtures = fs13.readdirSync(fixtureDir).filter((file2) => file2.endsWith(".json")).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file2) => {
42653
+ const fullPath = path16.join(fixtureDir, file2);
42654
+ try {
42655
+ const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
42656
+ return {
42657
+ name: raw.name || file2.replace(/\.json$/i, ""),
42658
+ path: fullPath,
42659
+ createdAt: raw.createdAt || null,
42660
+ notes: raw.notes || null,
42661
+ requestText: raw.request?.text || "",
42662
+ assertions: raw.assertions || {}
42663
+ };
42664
+ } catch {
42665
+ return {
42666
+ name: file2.replace(/\.json$/i, ""),
42667
+ path: fullPath,
42668
+ createdAt: null,
42669
+ notes: "Unreadable fixture",
42670
+ requestText: "",
42671
+ assertions: {}
42672
+ };
42673
+ }
42674
+ });
42675
+ ctx.json(res, 200, { fixtures, count: fixtures.length });
42676
+ } catch (e) {
42677
+ ctx.json(res, 500, { error: `Fixture list failed: ${e.message}` });
42678
+ }
42679
+ }
42680
+ async function handleCliFixtureReplay(ctx, req, res) {
42681
+ try {
42682
+ const body = await ctx.readBody(req);
42683
+ const type = String(body?.type || "");
42684
+ const rawName = String(body?.name || "").trim();
42685
+ if (!type || !rawName) {
42686
+ ctx.json(res, 400, { error: "type and name required" });
42687
+ return;
42688
+ }
42689
+ const name = slugifyFixtureName(rawName);
42690
+ const fixture = readCliFixture(ctx, type, name);
42691
+ const result = await runCliExerciseInternal(ctx, {
42692
+ ...fixture.request,
42693
+ type
42694
+ });
42695
+ const assertions = {
42696
+ ...fixture.assertions,
42697
+ ...body?.assertions || {}
42698
+ };
42699
+ const failures = validateCliFixtureResult(result, assertions);
42700
+ ctx.json(res, 200, {
42701
+ replayed: true,
42702
+ pass: failures.length === 0,
42703
+ failures,
42704
+ fixture,
42705
+ result,
42706
+ assertions
42707
+ });
42708
+ } catch (e) {
42709
+ ctx.json(res, 500, { error: `Fixture replay failed: ${e.message}` });
42710
+ }
42711
+ }
41585
42712
  async function handleCliResolve(ctx, req, res) {
41586
42713
  const body = await ctx.readBody(req);
41587
42714
  const { type, buttonIndex, instanceId } = body;
@@ -41656,13 +42783,36 @@ async function handleCliRaw(ctx, req, res) {
41656
42783
  ctx.json(res, 500, { error: `Raw send failed: ${e.message}` });
41657
42784
  }
41658
42785
  }
42786
+ var fs13, path16;
41659
42787
  var init_dev_cli_debug = __esm({
41660
42788
  "../../oss/packages/daemon-core/src/daemon/dev-cli-debug.ts"() {
41661
42789
  "use strict";
42790
+ fs13 = __toESM(require("fs"));
42791
+ path16 = __toESM(require("path"));
41662
42792
  }
41663
42793
  });
41664
42794
 
41665
42795
  // ../../oss/packages/daemon-core/src/daemon/dev-auto-implement.ts
42796
+ function getAutoImplPid(ctx) {
42797
+ const proc = ctx.autoImplProcess;
42798
+ return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
42799
+ }
42800
+ function isPidAlive(pid) {
42801
+ try {
42802
+ process.kill(pid, 0);
42803
+ return true;
42804
+ } catch (error48) {
42805
+ return error48?.code === "EPERM";
42806
+ }
42807
+ }
42808
+ function clearStaleAutoImplState(ctx, reason) {
42809
+ if (!ctx.autoImplStatus.running && !ctx.autoImplProcess) return;
42810
+ const pid = getAutoImplPid(ctx);
42811
+ if (pid && isPidAlive(pid)) return;
42812
+ ctx.log(`Clearing stale auto-implement state: ${reason}${pid ? ` (pid ${pid})` : ""}`);
42813
+ ctx.autoImplProcess = null;
42814
+ ctx.autoImplStatus.running = false;
42815
+ }
41666
42816
  function getDefaultAutoImplReference(ctx, category, type) {
41667
42817
  if (category === "cli") {
41668
42818
  return type === "codex-cli" ? "claude-cli" : "codex-cli";
@@ -41678,45 +42828,45 @@ function resolveAutoImplReference(ctx, category, requestedReference, targetType)
41678
42828
  return fallback?.type || null;
41679
42829
  }
41680
42830
  function getLatestScriptVersionDir(scriptsDir) {
41681
- if (!fs13.existsSync(scriptsDir)) return null;
41682
- const versions = fs13.readdirSync(scriptsDir).filter((d) => {
42831
+ if (!fs14.existsSync(scriptsDir)) return null;
42832
+ const versions = fs14.readdirSync(scriptsDir).filter((d) => {
41683
42833
  try {
41684
- return fs13.statSync(path16.join(scriptsDir, d)).isDirectory();
42834
+ return fs14.statSync(path17.join(scriptsDir, d)).isDirectory();
41685
42835
  } catch {
41686
42836
  return false;
41687
42837
  }
41688
42838
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
41689
42839
  if (versions.length === 0) return null;
41690
- return path16.join(scriptsDir, versions[0]);
42840
+ return path17.join(scriptsDir, versions[0]);
41691
42841
  }
41692
42842
  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}`)) {
42843
+ const canonicalUserDir = path17.resolve(ctx.providerLoader.getUserProviderDir(category, type));
42844
+ const desiredDir = requestedDir ? path17.resolve(requestedDir) : canonicalUserDir;
42845
+ const upstreamRoot = path17.resolve(ctx.providerLoader.getUpstreamDir());
42846
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path17.sep}`)) {
41697
42847
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
41698
42848
  }
41699
- if (path16.basename(desiredDir) !== type) {
42849
+ if (path17.basename(desiredDir) !== type) {
41700
42850
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
41701
42851
  }
41702
42852
  const sourceDir = ctx.findProviderDir(type);
41703
42853
  if (!sourceDir) {
41704
42854
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
41705
42855
  }
41706
- if (!fs13.existsSync(desiredDir)) {
41707
- fs13.mkdirSync(path16.dirname(desiredDir), { recursive: true });
41708
- fs13.cpSync(sourceDir, desiredDir, { recursive: true });
42856
+ if (!fs14.existsSync(desiredDir)) {
42857
+ fs14.mkdirSync(path17.dirname(desiredDir), { recursive: true });
42858
+ fs14.cpSync(sourceDir, desiredDir, { recursive: true });
41709
42859
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
41710
42860
  }
41711
- const providerJson = path16.join(desiredDir, "provider.json");
41712
- if (!fs13.existsSync(providerJson)) {
42861
+ const providerJson = path17.join(desiredDir, "provider.json");
42862
+ if (!fs14.existsSync(providerJson)) {
41713
42863
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
41714
42864
  }
41715
42865
  try {
41716
- const providerData = JSON.parse(fs13.readFileSync(providerJson, "utf-8"));
42866
+ const providerData = JSON.parse(fs14.readFileSync(providerJson, "utf-8"));
41717
42867
  if (providerData.disableUpstream !== true) {
41718
42868
  providerData.disableUpstream = true;
41719
- fs13.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
42869
+ fs14.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
41720
42870
  }
41721
42871
  } catch (error48) {
41722
42872
  return {
@@ -41729,15 +42879,15 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
41729
42879
  function loadAutoImplReferenceScripts(ctx, referenceType) {
41730
42880
  if (!referenceType) return {};
41731
42881
  const refDir = ctx.findProviderDir(referenceType);
41732
- if (!refDir || !fs13.existsSync(refDir)) return {};
42882
+ if (!refDir || !fs14.existsSync(refDir)) return {};
41733
42883
  const referenceScripts = {};
41734
- const scriptsDir = path16.join(refDir, "scripts");
42884
+ const scriptsDir = path17.join(refDir, "scripts");
41735
42885
  const latestDir = getLatestScriptVersionDir(scriptsDir);
41736
42886
  if (!latestDir) return referenceScripts;
41737
- for (const file2 of fs13.readdirSync(latestDir)) {
42887
+ for (const file2 of fs14.readdirSync(latestDir)) {
41738
42888
  if (!file2.endsWith(".js")) continue;
41739
42889
  try {
41740
- referenceScripts[file2] = fs13.readFileSync(path16.join(latestDir, file2), "utf-8");
42890
+ referenceScripts[file2] = fs14.readFileSync(path17.join(latestDir, file2), "utf-8");
41741
42891
  } catch {
41742
42892
  }
41743
42893
  }
@@ -41745,11 +42895,20 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
41745
42895
  }
41746
42896
  async function handleAutoImplement(ctx, type, req, res) {
41747
42897
  const body = await ctx.readBody(req);
41748
- const { agent = "claude-cli", functions, reference, model, comment, providerDir: requestedProviderDir } = body;
42898
+ const {
42899
+ agent = "claude-cli",
42900
+ functions,
42901
+ reference,
42902
+ model,
42903
+ comment,
42904
+ providerDir: requestedProviderDir,
42905
+ verification
42906
+ } = body;
41749
42907
  if (!functions || !Array.isArray(functions) || functions.length === 0) {
41750
42908
  ctx.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
41751
42909
  return;
41752
42910
  }
42911
+ clearStaleAutoImplState(ctx, "new auto-implement request");
41753
42912
  if (ctx.autoImplStatus.running) {
41754
42913
  ctx.json(res, 409, { error: "Auto-implement already in progress", type: ctx.autoImplStatus.type });
41755
42914
  return;
@@ -41767,7 +42926,55 @@ async function handleAutoImplement(ctx, type, req, res) {
41767
42926
  return;
41768
42927
  }
41769
42928
  const providerDir = writableProvider.dir;
42929
+ ctx.autoImplStatus = { running: false, type, progress: [] };
42930
+ if (provider.category === "cli" && verification && (verification.fixtureName || verification.fixtureNames && verification.fixtureNames.length > 0)) {
42931
+ sendAutoImplSSE(ctx, {
42932
+ event: "progress",
42933
+ data: {
42934
+ function: "_preflight",
42935
+ status: "verifying",
42936
+ message: "Running preflight verification before spawning agent..."
42937
+ }
42938
+ });
42939
+ try {
42940
+ const preflight = await runCliAutoImplVerification(ctx, type, verification);
42941
+ sendAutoImplSSE(ctx, { event: "verification", data: preflight });
42942
+ if (preflight.pass) {
42943
+ sendAutoImplSSE(ctx, {
42944
+ event: "complete",
42945
+ data: {
42946
+ success: true,
42947
+ exitCode: 0,
42948
+ functions,
42949
+ message: `\u2705 No-op: exact ${preflight.mode} already passes`,
42950
+ verification: preflight,
42951
+ skipped: true
42952
+ }
42953
+ });
42954
+ ctx.json(res, 200, {
42955
+ started: false,
42956
+ skipped: true,
42957
+ type,
42958
+ functions,
42959
+ providerDir,
42960
+ verification: preflight,
42961
+ message: "Preflight verification already passes. No auto-implement run needed."
42962
+ });
42963
+ return;
42964
+ }
42965
+ } catch (error48) {
42966
+ sendAutoImplSSE(ctx, {
42967
+ event: "progress",
42968
+ data: {
42969
+ function: "_preflight",
42970
+ status: "verify_failed",
42971
+ message: `Preflight verification errored, continuing to agent run: ${error48?.message || error48}`
42972
+ }
42973
+ });
42974
+ }
42975
+ }
41770
42976
  try {
42977
+ ctx.autoImplStatus = { running: true, type, progress: ctx.autoImplStatus.progress };
41771
42978
  const resolvedReference = resolveAutoImplReference(ctx, provider.category, reference, type);
41772
42979
  sendAutoImplSSE(ctx, {
41773
42980
  event: "progress",
@@ -41787,17 +42994,17 @@ async function handleAutoImplement(ctx, type, req, res) {
41787
42994
  }
41788
42995
  });
41789
42996
  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");
42997
+ const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
42998
+ const tmpDir = path17.join(os18.tmpdir(), "adhdev-autoimpl");
42999
+ if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
43000
+ const promptFile = path17.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
43001
+ fs14.writeFileSync(promptFile, prompt, "utf-8");
41795
43002
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
41796
43003
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
41797
43004
  const spawn5 = agentProvider?.spawn;
41798
43005
  if (!spawn5?.command) {
41799
43006
  try {
41800
- fs13.unlinkSync(promptFile);
43007
+ fs14.unlinkSync(promptFile);
41801
43008
  } catch {
41802
43009
  }
41803
43010
  ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
@@ -41806,7 +43013,8 @@ async function handleAutoImplement(ctx, type, req, res) {
41806
43013
  const agentCategory = agentProvider?.category;
41807
43014
  if (agentCategory === "acp") {
41808
43015
  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: [] };
43016
+ ctx.autoImplStatus.running = true;
43017
+ ctx.autoImplStatus.type = type;
41810
43018
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
41811
43019
  const { Readable: Readable3, Writable: Writable2 } = await import("stream");
41812
43020
  const { spawn: spawnFn2 } = await import("child_process");
@@ -41898,7 +43106,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41898
43106
  } catch {
41899
43107
  }
41900
43108
  try {
41901
- fs13.unlinkSync(promptFile);
43109
+ fs14.unlinkSync(promptFile);
41902
43110
  } catch {
41903
43111
  }
41904
43112
  ctx.log(`Auto-implement (ACP) ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -41976,7 +43184,8 @@ async function handleAutoImplement(ctx, type, req, res) {
41976
43184
  }
41977
43185
  }
41978
43186
  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: [] };
43187
+ ctx.autoImplStatus.running = true;
43188
+ ctx.autoImplStatus.type = type;
41980
43189
  const spawnedAt = Date.now();
41981
43190
  let child;
41982
43191
  let isPty = false;
@@ -42019,6 +43228,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42019
43228
  let approvalKeys = { 0: "y\r" };
42020
43229
  let approvalBuffer = "";
42021
43230
  let lastApprovalTime = 0;
43231
+ let completionSignalSeen = false;
42022
43232
  try {
42023
43233
  const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
42024
43234
  const normalized = normalizeCliProviderForRuntime2(agentProvider);
@@ -42032,6 +43242,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42032
43242
  approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
42033
43243
  const elapsed = Date.now() - spawnedAt;
42034
43244
  if (elapsed > 15e3 && cleanData.includes("_PIPELINE_COMPLETE_SIGNAL_")) {
43245
+ completionSignalSeen = true;
42035
43246
  ctx.log(`Agent finished task after ${Math.round(elapsed / 1e3)}s. Terminating interactive CLI session to unblock pipeline.`);
42036
43247
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: `
42037
43248
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
@@ -42055,6 +43266,55 @@ async function handleAutoImplement(ctx, type, req, res) {
42055
43266
  lastApprovalTime = Date.now();
42056
43267
  }
42057
43268
  };
43269
+ const finalizeCliAutoImpl = async (code) => {
43270
+ ctx.autoImplProcess = null;
43271
+ let success2 = completionSignalSeen || code === 0;
43272
+ let message = success2 ? completionSignalSeen && code !== 0 ? "\u2705 Auto-implement complete (completion signal)" : "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`;
43273
+ let verificationSummary = null;
43274
+ try {
43275
+ ctx.providerLoader.reload();
43276
+ } catch {
43277
+ }
43278
+ if (provider.category === "cli" && verification) {
43279
+ sendAutoImplSSE(ctx, {
43280
+ event: "progress",
43281
+ data: {
43282
+ function: "_verify",
43283
+ status: "running",
43284
+ message: "Running exact post-patch verification..."
43285
+ }
43286
+ });
43287
+ try {
43288
+ verificationSummary = await runCliAutoImplVerification(ctx, type, verification);
43289
+ sendAutoImplSSE(ctx, { event: "verification", data: verificationSummary });
43290
+ success2 = verificationSummary.pass;
43291
+ message = verificationSummary.pass ? `\u2705 Auto-implement complete (${verificationSummary.mode})` : `\u274C Post-patch verification failed (${verificationSummary.mode}): ${verificationSummary.failures.join("; ") || "unknown failure"}`;
43292
+ } catch (error48) {
43293
+ success2 = false;
43294
+ message = `\u274C Post-patch verification error: ${error48?.message || error48}`;
43295
+ sendAutoImplSSE(ctx, {
43296
+ event: "verification",
43297
+ data: { pass: false, error: error48?.message || String(error48) }
43298
+ });
43299
+ }
43300
+ }
43301
+ ctx.autoImplStatus.running = false;
43302
+ sendAutoImplSSE(ctx, {
43303
+ event: "complete",
43304
+ data: {
43305
+ success: success2,
43306
+ exitCode: code,
43307
+ functions,
43308
+ message,
43309
+ verification: verificationSummary
43310
+ }
43311
+ });
43312
+ try {
43313
+ fs14.unlinkSync(promptFile);
43314
+ } catch {
43315
+ }
43316
+ ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})${verificationSummary ? ` verify=${verificationSummary.pass ? "pass" : "fail"}` : ""}`);
43317
+ };
42058
43318
  if (isPty) {
42059
43319
  child.onData((data) => {
42060
43320
  stdout += data;
@@ -42066,21 +43326,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42066
43326
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
42067
43327
  });
42068
43328
  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
- }
43329
+ void finalizeCliAutoImpl(code);
42084
43330
  });
42085
43331
  } else {
42086
43332
  child.stdout?.on("data", (d) => {
@@ -42097,27 +43343,7 @@ async function handleAutoImplement(ctx, type, req, res) {
42097
43343
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
42098
43344
  });
42099
43345
  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})`);
43346
+ void finalizeCliAutoImpl(code);
42121
43347
  });
42122
43348
  }
42123
43349
  ctx.json(res, 202, {
@@ -42134,9 +43360,9 @@ async function handleAutoImplement(ctx, type, req, res) {
42134
43360
  ctx.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
42135
43361
  }
42136
43362
  }
42137
- function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType) {
43363
+ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType, verification) {
42138
43364
  if (provider.category === "cli") {
42139
- return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
43365
+ return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification);
42140
43366
  }
42141
43367
  const lines = [];
42142
43368
  lines.push("You are implementing browser automation scripts for an IDE provider.");
@@ -42161,7 +43387,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42161
43387
  setMode: "set_mode.js"
42162
43388
  };
42163
43389
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
42164
- const scriptsDir = path16.join(providerDir, "scripts");
43390
+ const scriptsDir = path17.join(providerDir, "scripts");
42165
43391
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
42166
43392
  if (latestScriptsDir) {
42167
43393
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -42169,10 +43395,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42169
43395
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
42170
43396
  lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
42171
43397
  lines.push("");
42172
- for (const file2 of fs13.readdirSync(latestScriptsDir)) {
43398
+ for (const file2 of fs14.readdirSync(latestScriptsDir)) {
42173
43399
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
42174
43400
  try {
42175
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43401
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42176
43402
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
42177
43403
  lines.push("```javascript");
42178
43404
  lines.push(content);
@@ -42182,14 +43408,14 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42182
43408
  }
42183
43409
  }
42184
43410
  }
42185
- const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43411
+ const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
42186
43412
  if (refFiles.length > 0) {
42187
43413
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
42188
43414
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
42189
43415
  lines.push("");
42190
43416
  for (const file2 of refFiles) {
42191
43417
  try {
42192
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43418
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42193
43419
  lines.push(`### \`${file2}\` \u{1F512}`);
42194
43420
  lines.push("```javascript");
42195
43421
  lines.push(content);
@@ -42230,11 +43456,11 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42230
43456
  lines.push("");
42231
43457
  }
42232
43458
  }
42233
- const docsDir = path16.join(providerDir, "../../docs");
43459
+ const docsDir = path17.join(providerDir, "../../docs");
42234
43460
  const loadGuide = (name) => {
42235
43461
  try {
42236
- const p = path16.join(docsDir, name);
42237
- if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
43462
+ const p = path17.join(docsDir, name);
43463
+ if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
42238
43464
  } catch {
42239
43465
  }
42240
43466
  return null;
@@ -42392,8 +43618,69 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42392
43618
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
42393
43619
  return lines.join("\n");
42394
43620
  }
42395
- function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType) {
43621
+ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification) {
42396
43622
  const lines = [];
43623
+ const defaultExercisePayload = {
43624
+ type,
43625
+ workingDir: providerDir,
43626
+ freshSession: true,
43627
+ autoLaunch: true,
43628
+ autoResolveApprovals: true,
43629
+ approvalButtonIndex: 0,
43630
+ timeoutMs: 45e3,
43631
+ traceLimit: 200,
43632
+ 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."
43633
+ };
43634
+ const exercisePayload = {
43635
+ ...defaultExercisePayload,
43636
+ ...verification?.request || {},
43637
+ type,
43638
+ workingDir: providerDir
43639
+ };
43640
+ const exerciseJson = JSON.stringify(exercisePayload).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43641
+ const verificationInspectFields = verification?.inspectFields?.length ? verification.inspectFields : [
43642
+ "debug.messages",
43643
+ "trace.entries[].payload.parsedLastAssistant",
43644
+ "trace.entries[].payload.lastAssistant"
43645
+ ];
43646
+ const verificationMustContainAny = verification?.mustContainAny || [];
43647
+ const verificationMustNotContainAny = verification?.mustNotContainAny || [];
43648
+ const verificationMustMatchAny = verification?.mustMatchAny || [];
43649
+ const verificationMustNotMatchAny = verification?.mustNotMatchAny || [];
43650
+ const verificationLastAssistantMustContainAny = verification?.lastAssistantMustContainAny || [];
43651
+ const verificationLastAssistantMustNotContainAny = verification?.lastAssistantMustNotContainAny || [];
43652
+ const verificationLastAssistantMustMatchAny = verification?.lastAssistantMustMatchAny || [];
43653
+ const verificationLastAssistantMustNotMatchAny = verification?.lastAssistantMustNotMatchAny || [];
43654
+ const quotedMustContain = verificationMustContainAny.map((value) => JSON.stringify(value)).join(", ");
43655
+ const quotedMustNotContain = verificationMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
43656
+ const quotedMustMatch = verificationMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
43657
+ const quotedMustNotMatch = verificationMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
43658
+ const quotedLastAssistantMustContain = verificationLastAssistantMustContainAny.map((value) => JSON.stringify(value)).join(", ");
43659
+ const quotedLastAssistantMustNotContain = verificationLastAssistantMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
43660
+ const quotedLastAssistantMustMatch = verificationLastAssistantMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
43661
+ const quotedLastAssistantMustNotMatch = verificationLastAssistantMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
43662
+ const fixtureName = verification?.fixtureName || `${type}-provider-fix`;
43663
+ const fixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
43664
+ const fixtureCaptureJson = JSON.stringify({
43665
+ type,
43666
+ name: fixtureName,
43667
+ request: exercisePayload,
43668
+ assertions: {
43669
+ mustContainAny: verificationMustContainAny,
43670
+ mustNotContainAny: verificationMustNotContainAny,
43671
+ mustMatchAny: verificationMustMatchAny,
43672
+ mustNotMatchAny: verificationMustNotMatchAny,
43673
+ lastAssistantMustContainAny: verificationLastAssistantMustContainAny,
43674
+ lastAssistantMustNotContainAny: verificationLastAssistantMustNotContainAny,
43675
+ lastAssistantMustMatchAny: verificationLastAssistantMustMatchAny,
43676
+ lastAssistantMustNotMatchAny: verificationLastAssistantMustNotMatchAny,
43677
+ requireNotTimedOut: true
43678
+ }
43679
+ }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43680
+ const fixtureReplayJson = JSON.stringify({
43681
+ type,
43682
+ name: fixtureName
43683
+ }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
42397
43684
  lines.push("You are implementing PTY parsing scripts for a CLI provider.");
42398
43685
  lines.push("Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.");
42399
43686
  lines.push("");
@@ -42407,7 +43694,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42407
43694
  parseApproval: "parse_approval.js"
42408
43695
  };
42409
43696
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
42410
- const scriptsDir = path16.join(providerDir, "scripts");
43697
+ const scriptsDir = path17.join(providerDir, "scripts");
42411
43698
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
42412
43699
  if (latestScriptsDir) {
42413
43700
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -42415,11 +43702,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42415
43702
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
42416
43703
  lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
42417
43704
  lines.push("");
42418
- for (const file2 of fs13.readdirSync(latestScriptsDir)) {
43705
+ for (const file2 of fs14.readdirSync(latestScriptsDir)) {
42419
43706
  if (!file2.endsWith(".js")) continue;
42420
43707
  if (!targetFileNames.has(file2)) continue;
42421
43708
  try {
42422
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43709
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42423
43710
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
42424
43711
  lines.push("```javascript");
42425
43712
  lines.push(content);
@@ -42428,14 +43715,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42428
43715
  } catch {
42429
43716
  }
42430
43717
  }
42431
- const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43718
+ const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
42432
43719
  if (refFiles.length > 0) {
42433
43720
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
42434
43721
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
42435
43722
  lines.push("");
42436
43723
  for (const file2 of refFiles) {
42437
43724
  try {
42438
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
43725
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
42439
43726
  lines.push(`### \`${file2}\` \u{1F512}`);
42440
43727
  lines.push("```javascript");
42441
43728
  lines.push(content);
@@ -42468,17 +43755,17 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42468
43755
  lines.push("");
42469
43756
  }
42470
43757
  }
42471
- const docsDir = path16.join(providerDir, "../../docs");
43758
+ const docsDir = path17.join(providerDir, "../../docs");
42472
43759
  const loadGuide = (name) => {
42473
43760
  try {
42474
- const p = path16.join(docsDir, name);
42475
- if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
43761
+ const p = path17.join(docsDir, name);
43762
+ if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
42476
43763
  } catch {
42477
43764
  }
42478
43765
  return null;
42479
43766
  };
42480
43767
  const providerGuide = loadGuide("PROVIDER_GUIDE.md");
42481
- if (providerGuide) {
43768
+ if (providerGuide && provider.category !== "cli") {
42482
43769
  lines.push("## Documentation: PROVIDER_GUIDE.md");
42483
43770
  lines.push("```markdown");
42484
43771
  lines.push(providerGuide);
@@ -42520,6 +43807,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42520
43807
  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
43808
  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
43809
  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.");
43810
+ 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.');
43811
+ 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.");
43812
+ 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.');
43813
+ 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.");
43814
+ 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
43815
  lines.push("");
42524
43816
  lines.push("## Task");
42525
43817
  lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
@@ -42527,35 +43819,145 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42527
43819
  lines.push("## Verification API");
42528
43820
  lines.push("Use the DevServer CLI debug endpoints, not DOM/CDP routes.");
42529
43821
  lines.push("");
42530
- lines.push("### 1. Launch the target CLI");
43822
+ lines.push("### 1. Preferred: run a full autonomous repro");
43823
+ 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
43824
  lines.push("```bash");
42532
- lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
43825
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
42533
43826
  lines.push(' -H "Content-Type: application/json" \\');
42534
- lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
43827
+ lines.push(` -d '${exerciseJson}'`);
43828
+ lines.push("```");
43829
+ lines.push("");
43830
+ if (verification?.description) {
43831
+ lines.push("Verification intent:");
43832
+ lines.push(verification.description);
43833
+ lines.push("");
43834
+ }
43835
+ lines.push("Read the JSON response carefully. It already includes:");
43836
+ lines.push("1. `instanceId`");
43837
+ lines.push("2. `statusesSeen` and `approvalsResolved`");
43838
+ lines.push("3. `debug` for the final settled state");
43839
+ lines.push("4. `trace.entries` for the repro turn");
43840
+ lines.push("");
43841
+ lines.push("Save the response to a temp file and inspect the exact parsed transcript fields before editing:");
43842
+ lines.push("```bash");
43843
+ lines.push(`EXERCISE_JSON=$(mktemp)`);
43844
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
43845
+ lines.push(' -H "Content-Type: application/json" \\');
43846
+ lines.push(` -d '${exerciseJson}' > "$EXERCISE_JSON"`);
43847
+ lines.push(`jq '{timedOut,statusesSeen,approvalsResolved,inspect:{${verificationInspectFields.map((field, index) => `f${index + 1}: .${field}`).join(", ")}}}' "$EXERCISE_JSON"`);
42535
43848
  lines.push("```");
42536
43849
  lines.push("");
43850
+ 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) {
43851
+ 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.");
43852
+ lines.push("```bash");
43853
+ if (verificationMustContainAny.length > 0) {
43854
+ 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"`);
43855
+ }
43856
+ if (verificationMustNotContainAny.length > 0) {
43857
+ 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"`);
43858
+ }
43859
+ if (verificationMustMatchAny.length > 0) {
43860
+ 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"`);
43861
+ }
43862
+ if (verificationMustNotMatchAny.length > 0) {
43863
+ 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"`);
43864
+ }
43865
+ if (verificationLastAssistantMustContainAny.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 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"`);
43867
+ }
43868
+ if (verificationLastAssistantMustNotContainAny.length > 0) {
43869
+ 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"`);
43870
+ }
43871
+ if (verificationLastAssistantMustMatchAny.length > 0) {
43872
+ 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"`);
43873
+ }
43874
+ if (verificationLastAssistantMustNotMatchAny.length > 0) {
43875
+ 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"`);
43876
+ }
43877
+ lines.push("```");
43878
+ lines.push("");
43879
+ }
43880
+ 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.");
43881
+ lines.push("");
43882
+ lines.push("### 1b. Persist or replay the exact repro as a reusable fixture");
43883
+ if (fixtureNames.length > 0) {
43884
+ 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(", ")}.`);
43885
+ for (const name of fixtureNames) {
43886
+ const replayJson = JSON.stringify({ type, name }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43887
+ lines.push("```bash");
43888
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43889
+ lines.push(' -H "Content-Type: application/json" \\');
43890
+ lines.push(` -d '${replayJson}'`);
43891
+ lines.push("```");
43892
+ lines.push("");
43893
+ }
43894
+ lines.push("Do not create new fixtures unless one of the listed fixtures is missing or stale.");
43895
+ } else if (verification?.fixtureName) {
43896
+ 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.`);
43897
+ lines.push("```bash");
43898
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43899
+ lines.push(' -H "Content-Type: application/json" \\');
43900
+ lines.push(` -d '${fixtureReplayJson}'`);
43901
+ lines.push("```");
43902
+ lines.push("");
43903
+ 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.");
43904
+ lines.push("```bash");
43905
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
43906
+ lines.push(' -H "Content-Type: application/json" \\');
43907
+ lines.push(` -d '${fixtureCaptureJson}'`);
43908
+ lines.push("```");
43909
+ } else {
43910
+ lines.push("Capture the exact exercise once before editing. After patching, replay THIS fixture and do not declare success unless replay passes.");
43911
+ lines.push("```bash");
43912
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
43913
+ lines.push(' -H "Content-Type: application/json" \\');
43914
+ lines.push(` -d '${fixtureCaptureJson}'`);
43915
+ lines.push("");
43916
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43917
+ lines.push(' -H "Content-Type: application/json" \\');
43918
+ lines.push(` -d '${fixtureReplayJson}'`);
43919
+ lines.push("```");
43920
+ }
43921
+ lines.push("");
43922
+ 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.");
43923
+ lines.push("");
42537
43924
  lines.push("### 2. Inspect parsed + raw adapter state");
42538
43925
  lines.push("```bash");
43926
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
43927
+ lines.push(' -H "Content-Type: application/json" \\');
43928
+ lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
42539
43929
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
43930
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
42540
43931
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
42541
43932
  lines.push("```");
42542
43933
  lines.push("");
43934
+ lines.push("The CLI trace endpoint is the primary debugging source. Read it BEFORE editing any parser code.");
43935
+ lines.push("Use the trace timeline to find the latest `settled` or `commit_transcript` frame for the repro turn and inspect these fields first:");
43936
+ lines.push("1. `payload.screenText`");
43937
+ lines.push("2. `payload.detectStatus` and `payload.parsedStatus`");
43938
+ lines.push("3. `payload.parsedLastAssistant`");
43939
+ lines.push("4. `payload.approval` / `payload.parsedActiveModal`");
43940
+ lines.push("5. `payload.rawPreview` only when control-sequence residue matters");
43941
+ lines.push("");
42543
43942
  lines.push("The debug payload should be read in this priority order:");
42544
43943
  lines.push("1. `screenText` / current visible state");
42545
43944
  lines.push("2. parsed `status`, `messages`, `activeModal`");
42546
43945
  lines.push("3. `rawBuffer` only for style/control-sequence cues");
42547
43946
  lines.push("4. `buffer` only when the current screen is insufficient");
42548
43947
  lines.push("");
42549
- lines.push("Extract the current `instanceId` from the launch or status response and keep using it below.");
43948
+ 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.");
43949
+ lines.push("Do NOT guess based only on the final chat bubble or a truncated UI preview.");
43950
+ lines.push("");
43951
+ lines.push("Extract the current `instanceId` from the exercise, launch, or status response and keep using it below.");
42550
43952
  lines.push("");
42551
- lines.push("### 3. Send a realistic approval-triggering prompt");
43953
+ lines.push("### 3. Manual fallback only: send a realistic approval-triggering prompt");
42552
43954
  lines.push("```bash");
42553
43955
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
42554
43956
  lines.push(' -H "Content-Type: application/json" \\');
42555
43957
  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
43958
  lines.push("```");
42557
43959
  lines.push("");
42558
- lines.push("### 4. If approval appears, resolve it until the CLI reaches idle");
43960
+ lines.push("### 4. Manual fallback only: if approval appears, resolve it until the CLI reaches idle");
42559
43961
  lines.push("```bash");
42560
43962
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
42561
43963
  lines.push(' -H "Content-Type: application/json" \\');
@@ -42565,10 +43967,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42565
43967
  lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
42566
43968
  lines.push("```");
42567
43969
  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.");
43970
+ 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
43971
  lines.push("");
42570
43972
  lines.push("### Patch Discipline");
42571
43973
  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.");
43974
+ 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.");
43975
+ 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.");
43976
+ 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.");
43977
+ 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
43978
  lines.push("");
42573
43979
  lines.push("### 5. Verify the side effects outside the CLI");
42574
43980
  lines.push("```bash");
@@ -42593,6 +43999,8 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42593
43999
  lines.push("7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
42594
44000
  lines.push("8. Confirm the parser still works after a redraw or scroll change without duplicating transcript history.");
42595
44001
  lines.push("9. Confirm the implementation prefers current-screen signals over stale history when both are present.");
44002
+ 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.");
44003
+ 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
44004
  lines.push("");
42597
44005
  if (userComment) {
42598
44006
  lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
@@ -42601,10 +44009,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42601
44009
  lines.push(userComment);
42602
44010
  lines.push("");
42603
44011
  }
42604
- lines.push("Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.");
44012
+ 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
44013
  return lines.join("\n");
42606
44014
  }
42607
44015
  function handleAutoImplSSE(ctx, type, req, res) {
44016
+ clearStaleAutoImplState(ctx, "SSE connection opened");
42608
44017
  res.writeHead(200, {
42609
44018
  "Content-Type": "text/event-stream",
42610
44019
  "Cache-Control": "no-cache",
@@ -42626,6 +44035,7 @@ data: ${JSON.stringify(p.data)}
42626
44035
  });
42627
44036
  }
42628
44037
  function handleAutoImplCancel(ctx, _type, _req, res) {
44038
+ clearStaleAutoImplState(ctx, "cancel request");
42629
44039
  if (ctx.autoImplProcess) {
42630
44040
  ctx.autoImplProcess.kill("SIGTERM");
42631
44041
  setTimeout(() => {
@@ -42653,25 +44063,26 @@ data: ${JSON.stringify(msg.data)}
42653
44063
  }
42654
44064
  }
42655
44065
  }
42656
- var fs13, path16, os18;
44066
+ var fs14, path17, os18;
42657
44067
  var init_dev_auto_implement = __esm({
42658
44068
  "../../oss/packages/daemon-core/src/daemon/dev-auto-implement.ts"() {
42659
44069
  "use strict";
42660
- fs13 = __toESM(require("fs"));
42661
- path16 = __toESM(require("path"));
44070
+ fs14 = __toESM(require("fs"));
44071
+ path17 = __toESM(require("path"));
42662
44072
  os18 = __toESM(require("os"));
42663
44073
  init_dev_server();
44074
+ init_dev_cli_debug();
42664
44075
  }
42665
44076
  });
42666
44077
 
42667
44078
  // ../../oss/packages/daemon-core/src/daemon/dev-server.ts
42668
- var http2, fs14, path17, DEV_SERVER_PORT, DevServer;
44079
+ var http2, fs15, path18, DEV_SERVER_PORT, DevServer;
42669
44080
  var init_dev_server = __esm({
42670
44081
  "../../oss/packages/daemon-core/src/daemon/dev-server.ts"() {
42671
44082
  "use strict";
42672
44083
  http2 = __toESM(require("http"));
42673
- fs14 = __toESM(require("fs"));
42674
- path17 = __toESM(require("path"));
44084
+ fs15 = __toESM(require("fs"));
44085
+ path18 = __toESM(require("path"));
42675
44086
  init_scaffold_template();
42676
44087
  init_version_archive();
42677
44088
  init_logger();
@@ -42732,11 +44143,16 @@ var init_dev_server = __esm({
42732
44143
  { method: "GET", pattern: "/api/cli/status", handler: (q2, s15) => this.handleCliStatus(q2, s15) },
42733
44144
  { method: "POST", pattern: "/api/cli/launch", handler: (q2, s15) => this.handleCliLaunch(q2, s15) },
42734
44145
  { method: "POST", pattern: "/api/cli/send", handler: (q2, s15) => this.handleCliSend(q2, s15) },
44146
+ { method: "POST", pattern: "/api/cli/exercise", handler: (q2, s15) => this.handleCliExercise(q2, s15) },
44147
+ { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q2, s15) => this.handleCliFixtureCapture(q2, s15) },
44148
+ { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q2, s15) => this.handleCliFixtureReplay(q2, s15) },
42735
44149
  { method: "POST", pattern: "/api/cli/resolve", handler: (q2, s15) => this.handleCliResolve(q2, s15) },
42736
44150
  { method: "POST", pattern: "/api/cli/raw", handler: (q2, s15) => this.handleCliRaw(q2, s15) },
42737
44151
  { method: "POST", pattern: "/api/cli/stop", handler: (q2, s15) => this.handleCliStop(q2, s15) },
42738
44152
  { method: "GET", pattern: "/api/cli/events", handler: (q2, s15) => this.handleCliSSE(q2, s15) },
42739
44153
  { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliDebug(p[0], q2, s15) },
44154
+ { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliTrace(p[0], q2, s15) },
44155
+ { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliFixtureList(p[0], q2, s15) },
42740
44156
  // Dynamic routes (provider :type param)
42741
44157
  { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q2, s15, p) => this.handleRunScript(p[0], q2, s15) },
42742
44158
  { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q2, s15, p) => this.handleListFiles(p[0], q2, s15) },
@@ -42770,8 +44186,8 @@ var init_dev_server = __esm({
42770
44186
  }
42771
44187
  getEndpointList() {
42772
44188
  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}`;
44189
+ const path23 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
44190
+ return `${r.method.padEnd(5)} ${path23}`;
42775
44191
  });
42776
44192
  }
42777
44193
  async start(port = DEV_SERVER_PORT) {
@@ -43053,12 +44469,12 @@ var init_dev_server = __esm({
43053
44469
  // ─── DevConsole SPA ───
43054
44470
  getConsoleDistDir() {
43055
44471
  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")
44472
+ path18.resolve(__dirname, "../../web-devconsole/dist"),
44473
+ path18.resolve(__dirname, "../../../web-devconsole/dist"),
44474
+ path18.join(process.cwd(), "packages/web-devconsole/dist")
43059
44475
  ];
43060
44476
  for (const dir of candidates) {
43061
- if (fs14.existsSync(path17.join(dir, "index.html"))) return dir;
44477
+ if (fs15.existsSync(path18.join(dir, "index.html"))) return dir;
43062
44478
  }
43063
44479
  return null;
43064
44480
  }
@@ -43068,9 +44484,9 @@ var init_dev_server = __esm({
43068
44484
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
43069
44485
  return;
43070
44486
  }
43071
- const htmlPath = path17.join(distDir, "index.html");
44487
+ const htmlPath = path18.join(distDir, "index.html");
43072
44488
  try {
43073
- const html = fs14.readFileSync(htmlPath, "utf-8");
44489
+ const html = fs15.readFileSync(htmlPath, "utf-8");
43074
44490
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
43075
44491
  res.end(html);
43076
44492
  } catch (e) {
@@ -43093,15 +44509,15 @@ var init_dev_server = __esm({
43093
44509
  this.json(res, 404, { error: "Not found" });
43094
44510
  return;
43095
44511
  }
43096
- const safePath = path17.normalize(pathname).replace(/^\.\.\//, "");
43097
- const filePath = path17.join(distDir, safePath);
44512
+ const safePath = path18.normalize(pathname).replace(/^\.\.\//, "");
44513
+ const filePath = path18.join(distDir, safePath);
43098
44514
  if (!filePath.startsWith(distDir)) {
43099
44515
  this.json(res, 403, { error: "Forbidden" });
43100
44516
  return;
43101
44517
  }
43102
44518
  try {
43103
- const content = fs14.readFileSync(filePath);
43104
- const ext = path17.extname(filePath);
44519
+ const content = fs15.readFileSync(filePath);
44520
+ const ext = path18.extname(filePath);
43105
44521
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
43106
44522
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
43107
44523
  res.end(content);
@@ -43209,14 +44625,14 @@ var init_dev_server = __esm({
43209
44625
  const files = [];
43210
44626
  const scan = (d, prefix) => {
43211
44627
  try {
43212
- for (const entry of fs14.readdirSync(d, { withFileTypes: true })) {
44628
+ for (const entry of fs15.readdirSync(d, { withFileTypes: true })) {
43213
44629
  if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
43214
44630
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
43215
44631
  if (entry.isDirectory()) {
43216
44632
  files.push({ path: rel, size: 0, type: "dir" });
43217
- scan(path17.join(d, entry.name), rel);
44633
+ scan(path18.join(d, entry.name), rel);
43218
44634
  } else {
43219
- const stat4 = fs14.statSync(path17.join(d, entry.name));
44635
+ const stat4 = fs15.statSync(path18.join(d, entry.name));
43220
44636
  files.push({ path: rel, size: stat4.size, type: "file" });
43221
44637
  }
43222
44638
  }
@@ -43239,16 +44655,16 @@ var init_dev_server = __esm({
43239
44655
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
43240
44656
  return;
43241
44657
  }
43242
- const fullPath = path17.resolve(dir, path17.normalize(filePath));
44658
+ const fullPath = path18.resolve(dir, path18.normalize(filePath));
43243
44659
  if (!fullPath.startsWith(dir)) {
43244
44660
  this.json(res, 403, { error: "Forbidden" });
43245
44661
  return;
43246
44662
  }
43247
- if (!fs14.existsSync(fullPath) || fs14.statSync(fullPath).isDirectory()) {
44663
+ if (!fs15.existsSync(fullPath) || fs15.statSync(fullPath).isDirectory()) {
43248
44664
  this.json(res, 404, { error: `File not found: ${filePath}` });
43249
44665
  return;
43250
44666
  }
43251
- const content = fs14.readFileSync(fullPath, "utf-8");
44667
+ const content = fs15.readFileSync(fullPath, "utf-8");
43252
44668
  this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
43253
44669
  }
43254
44670
  /** POST /api/providers/:type/file — write a file { path, content } */
@@ -43264,15 +44680,15 @@ var init_dev_server = __esm({
43264
44680
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
43265
44681
  return;
43266
44682
  }
43267
- const fullPath = path17.resolve(dir, path17.normalize(filePath));
44683
+ const fullPath = path18.resolve(dir, path18.normalize(filePath));
43268
44684
  if (!fullPath.startsWith(dir)) {
43269
44685
  this.json(res, 403, { error: "Forbidden" });
43270
44686
  return;
43271
44687
  }
43272
44688
  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");
44689
+ if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
44690
+ fs15.mkdirSync(path18.dirname(fullPath), { recursive: true });
44691
+ fs15.writeFileSync(fullPath, content, "utf-8");
43276
44692
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
43277
44693
  this.providerLoader.reload();
43278
44694
  this.json(res, 200, { saved: true, path: filePath, chars: content.length });
@@ -43288,9 +44704,9 @@ var init_dev_server = __esm({
43288
44704
  return;
43289
44705
  }
43290
44706
  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");
44707
+ const p = path18.join(dir, name);
44708
+ if (fs15.existsSync(p)) {
44709
+ const source = fs15.readFileSync(p, "utf-8");
43294
44710
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
43295
44711
  return;
43296
44712
  }
@@ -43309,11 +44725,11 @@ var init_dev_server = __esm({
43309
44725
  this.json(res, 404, { error: `Provider not found: ${type}` });
43310
44726
  return;
43311
44727
  }
43312
- const target = fs14.existsSync(path17.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
43313
- const targetPath = path17.join(dir, target);
44728
+ const target = fs15.existsSync(path18.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
44729
+ const targetPath = path18.join(dir, target);
43314
44730
  try {
43315
- if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
43316
- fs14.writeFileSync(targetPath, source, "utf-8");
44731
+ if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
44732
+ fs15.writeFileSync(targetPath, source, "utf-8");
43317
44733
  this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
43318
44734
  this.providerLoader.reload();
43319
44735
  this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
@@ -43470,21 +44886,21 @@ var init_dev_server = __esm({
43470
44886
  }
43471
44887
  let targetDir;
43472
44888
  targetDir = this.providerLoader.getUserProviderDir(category, type);
43473
- const jsonPath = path17.join(targetDir, "provider.json");
43474
- if (fs14.existsSync(jsonPath)) {
44889
+ const jsonPath = path18.join(targetDir, "provider.json");
44890
+ if (fs15.existsSync(jsonPath)) {
43475
44891
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
43476
44892
  return;
43477
44893
  }
43478
44894
  try {
43479
44895
  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");
44896
+ fs15.mkdirSync(targetDir, { recursive: true });
44897
+ fs15.writeFileSync(jsonPath, result["provider.json"], "utf-8");
43482
44898
  const createdFiles = ["provider.json"];
43483
44899
  if (result.files) {
43484
44900
  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");
44901
+ const fullPath = path18.join(targetDir, relPath);
44902
+ fs15.mkdirSync(path18.dirname(fullPath), { recursive: true });
44903
+ fs15.writeFileSync(fullPath, content, "utf-8");
43488
44904
  createdFiles.push(relPath);
43489
44905
  }
43490
44906
  }
@@ -43533,45 +44949,45 @@ var init_dev_server = __esm({
43533
44949
  }
43534
44950
  // ─── Phase 2: Auto-Implement Backend ───
43535
44951
  getLatestScriptVersionDir(scriptsDir) {
43536
- if (!fs14.existsSync(scriptsDir)) return null;
43537
- const versions = fs14.readdirSync(scriptsDir).filter((d) => {
44952
+ if (!fs15.existsSync(scriptsDir)) return null;
44953
+ const versions = fs15.readdirSync(scriptsDir).filter((d) => {
43538
44954
  try {
43539
- return fs14.statSync(path17.join(scriptsDir, d)).isDirectory();
44955
+ return fs15.statSync(path18.join(scriptsDir, d)).isDirectory();
43540
44956
  } catch {
43541
44957
  return false;
43542
44958
  }
43543
44959
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
43544
44960
  if (versions.length === 0) return null;
43545
- return path17.join(scriptsDir, versions[0]);
44961
+ return path18.join(scriptsDir, versions[0]);
43546
44962
  }
43547
44963
  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}`)) {
44964
+ const canonicalUserDir = path18.resolve(this.providerLoader.getUserProviderDir(category, type));
44965
+ const desiredDir = requestedDir ? path18.resolve(requestedDir) : canonicalUserDir;
44966
+ const upstreamRoot = path18.resolve(this.providerLoader.getUpstreamDir());
44967
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path18.sep}`)) {
43552
44968
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
43553
44969
  }
43554
- if (path17.basename(desiredDir) !== type) {
44970
+ if (path18.basename(desiredDir) !== type) {
43555
44971
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
43556
44972
  }
43557
44973
  const sourceDir = this.findProviderDir(type);
43558
44974
  if (!sourceDir) {
43559
44975
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
43560
44976
  }
43561
- if (!fs14.existsSync(desiredDir)) {
43562
- fs14.mkdirSync(path17.dirname(desiredDir), { recursive: true });
43563
- fs14.cpSync(sourceDir, desiredDir, { recursive: true });
44977
+ if (!fs15.existsSync(desiredDir)) {
44978
+ fs15.mkdirSync(path18.dirname(desiredDir), { recursive: true });
44979
+ fs15.cpSync(sourceDir, desiredDir, { recursive: true });
43564
44980
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
43565
44981
  }
43566
- const providerJson = path17.join(desiredDir, "provider.json");
43567
- if (!fs14.existsSync(providerJson)) {
44982
+ const providerJson = path18.join(desiredDir, "provider.json");
44983
+ if (!fs15.existsSync(providerJson)) {
43568
44984
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
43569
44985
  }
43570
44986
  try {
43571
- const providerData = JSON.parse(fs14.readFileSync(providerJson, "utf-8"));
44987
+ const providerData = JSON.parse(fs15.readFileSync(providerJson, "utf-8"));
43572
44988
  if (providerData.disableUpstream !== true) {
43573
44989
  providerData.disableUpstream = true;
43574
- fs14.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
44990
+ fs15.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
43575
44991
  }
43576
44992
  } catch (error48) {
43577
44993
  return {
@@ -43611,7 +45027,7 @@ var init_dev_server = __esm({
43611
45027
  setMode: "set_mode.js"
43612
45028
  };
43613
45029
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
43614
- const scriptsDir = path17.join(providerDir, "scripts");
45030
+ const scriptsDir = path18.join(providerDir, "scripts");
43615
45031
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
43616
45032
  if (latestScriptsDir) {
43617
45033
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -43619,10 +45035,10 @@ var init_dev_server = __esm({
43619
45035
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
43620
45036
  lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
43621
45037
  lines.push("");
43622
- for (const file2 of fs14.readdirSync(latestScriptsDir)) {
45038
+ for (const file2 of fs15.readdirSync(latestScriptsDir)) {
43623
45039
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
43624
45040
  try {
43625
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45041
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43626
45042
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
43627
45043
  lines.push("```javascript");
43628
45044
  lines.push(content);
@@ -43632,14 +45048,14 @@ var init_dev_server = __esm({
43632
45048
  }
43633
45049
  }
43634
45050
  }
43635
- const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
45051
+ const refFiles = fs15.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43636
45052
  if (refFiles.length > 0) {
43637
45053
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
43638
45054
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
43639
45055
  lines.push("");
43640
45056
  for (const file2 of refFiles) {
43641
45057
  try {
43642
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45058
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43643
45059
  lines.push(`### \`${file2}\` \u{1F512}`);
43644
45060
  lines.push("```javascript");
43645
45061
  lines.push(content);
@@ -43680,11 +45096,11 @@ var init_dev_server = __esm({
43680
45096
  lines.push("");
43681
45097
  }
43682
45098
  }
43683
- const docsDir = path17.join(providerDir, "../../docs");
45099
+ const docsDir = path18.join(providerDir, "../../docs");
43684
45100
  const loadGuide = (name) => {
43685
45101
  try {
43686
- const p = path17.join(docsDir, name);
43687
- if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
45102
+ const p = path18.join(docsDir, name);
45103
+ if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
43688
45104
  } catch {
43689
45105
  }
43690
45106
  return null;
@@ -43857,7 +45273,7 @@ var init_dev_server = __esm({
43857
45273
  parseApproval: "parse_approval.js"
43858
45274
  };
43859
45275
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
43860
- const scriptsDir = path17.join(providerDir, "scripts");
45276
+ const scriptsDir = path18.join(providerDir, "scripts");
43861
45277
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
43862
45278
  if (latestScriptsDir) {
43863
45279
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -43865,11 +45281,11 @@ var init_dev_server = __esm({
43865
45281
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
43866
45282
  lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
43867
45283
  lines.push("");
43868
- for (const file2 of fs14.readdirSync(latestScriptsDir)) {
45284
+ for (const file2 of fs15.readdirSync(latestScriptsDir)) {
43869
45285
  if (!file2.endsWith(".js")) continue;
43870
45286
  if (!targetFileNames.has(file2)) continue;
43871
45287
  try {
43872
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45288
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43873
45289
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
43874
45290
  lines.push("```javascript");
43875
45291
  lines.push(content);
@@ -43878,14 +45294,14 @@ var init_dev_server = __esm({
43878
45294
  } catch {
43879
45295
  }
43880
45296
  }
43881
- const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
45297
+ const refFiles = fs15.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43882
45298
  if (refFiles.length > 0) {
43883
45299
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
43884
45300
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
43885
45301
  lines.push("");
43886
45302
  for (const file2 of refFiles) {
43887
45303
  try {
43888
- const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45304
+ const content = fs15.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
43889
45305
  lines.push(`### \`${file2}\` \u{1F512}`);
43890
45306
  lines.push("```javascript");
43891
45307
  lines.push(content);
@@ -43918,11 +45334,11 @@ var init_dev_server = __esm({
43918
45334
  lines.push("");
43919
45335
  }
43920
45336
  }
43921
- const docsDir = path17.join(providerDir, "../../docs");
45337
+ const docsDir = path18.join(providerDir, "../../docs");
43922
45338
  const loadGuide = (name) => {
43923
45339
  try {
43924
- const p = path17.join(docsDir, name);
43925
- if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
45340
+ const p = path18.join(docsDir, name);
45341
+ if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
43926
45342
  } catch {
43927
45343
  }
43928
45344
  return null;
@@ -43987,6 +45403,7 @@ var init_dev_server = __esm({
43987
45403
  lines.push("### 2. Inspect parsed + raw adapter state");
43988
45404
  lines.push("```bash");
43989
45405
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
45406
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
43990
45407
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
43991
45408
  lines.push("```");
43992
45409
  lines.push("");
@@ -44121,6 +45538,16 @@ data: ${JSON.stringify(msg.data)}
44121
45538
  async handleCliSend(req, res) {
44122
45539
  return handleCliSend(this, req, res);
44123
45540
  }
45541
+ /** POST /api/cli/exercise — launch/send/approve/wait helper for provider-fix loops */
45542
+ async handleCliExercise(req, res) {
45543
+ return handleCliExercise(this, req, res);
45544
+ }
45545
+ async handleCliFixtureCapture(req, res) {
45546
+ return handleCliFixtureCapture(this, req, res);
45547
+ }
45548
+ async handleCliFixtureReplay(req, res) {
45549
+ return handleCliFixtureReplay(this, req, res);
45550
+ }
44124
45551
  /** POST /api/cli/stop — stop a running CLI { type } */
44125
45552
  async handleCliStop(req, res) {
44126
45553
  return handleCliStop(this, req, res);
@@ -44144,6 +45571,13 @@ data: ${JSON.stringify(msg.data)}
44144
45571
  async handleCliDebug(type, _req, res) {
44145
45572
  return handleCliDebug(this, type, _req, res);
44146
45573
  }
45574
+ /** GET /api/cli/trace/:type — recent CLI trace timeline plus current debug snapshot */
45575
+ async handleCliTrace(type, _req, res) {
45576
+ return handleCliTrace(this, type, _req, res);
45577
+ }
45578
+ async handleCliFixtureList(type, _req, res) {
45579
+ return handleCliFixtureList(this, type, _req, res);
45580
+ }
44147
45581
  /** POST /api/cli/resolve — resolve an approval modal { type, buttonIndex } */
44148
45582
  async handleCliResolve(req, res) {
44149
45583
  return handleCliResolve(this, req, res);
@@ -44451,7 +45885,18 @@ var init_session_host_transport = __esm({
44451
45885
  });
44452
45886
  }
44453
45887
  async boot() {
44454
- await this.client.connect();
45888
+ if (typeof this.options.ensureReady === "function") {
45889
+ await this.options.ensureReady();
45890
+ }
45891
+ try {
45892
+ await this.client.connect();
45893
+ } catch (error48) {
45894
+ if (typeof this.options.ensureReady !== "function") {
45895
+ throw error48;
45896
+ }
45897
+ await this.options.ensureReady();
45898
+ await this.client.connect();
45899
+ }
44455
45900
  this.unsubscribe = this.client.onEvent((event) => this.handleEvent(event));
44456
45901
  let record2 = null;
44457
45902
  if (this.options.attachExisting) {
@@ -44764,8 +46209,8 @@ async function installExtension(ide, extension) {
44764
46209
  const res = await fetch(extension.vsixUrl);
44765
46210
  if (res.ok) {
44766
46211
  const buffer = Buffer.from(await res.arrayBuffer());
44767
- const fs18 = await import("fs");
44768
- fs18.writeFileSync(vsixPath, buffer);
46212
+ const fs19 = await import("fs");
46213
+ fs19.writeFileSync(vsixPath, buffer);
44769
46214
  return new Promise((resolve13) => {
44770
46215
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
44771
46216
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
@@ -45604,17 +47049,17 @@ function canPeerUsePrivilegedShareCommand(commandType, permission) {
45604
47049
  return false;
45605
47050
  }
45606
47051
  }
45607
- var fs15, path18, os20, import_node_module2, esmRequire, logFile, log, logDebug, DaemonP2PSender;
47052
+ var fs16, path19, os20, import_node_module2, esmRequire, logFile, log, logDebug, DaemonP2PSender;
45608
47053
  var init_daemon_p2p = __esm({
45609
47054
  "src/daemon-p2p.ts"() {
45610
47055
  "use strict";
45611
- fs15 = __toESM(require("fs"));
47056
+ fs16 = __toESM(require("fs"));
45612
47057
  init_src();
45613
- path18 = __toESM(require("path"));
47058
+ path19 = __toESM(require("path"));
45614
47059
  os20 = __toESM(require("os"));
45615
47060
  import_node_module2 = require("module");
45616
47061
  esmRequire = (0, import_node_module2.createRequire)(__filename);
45617
- logFile = path18.join(os20.tmpdir(), "adhdev_daemon_p2p.log");
47062
+ logFile = path19.join(os20.tmpdir(), "adhdev_daemon_p2p.log");
45618
47063
  log = (msg) => {
45619
47064
  LOG.info("P2P", `[${(/* @__PURE__ */ new Date()).toISOString()}] [P2P] ${msg}`);
45620
47065
  };
@@ -45682,17 +47127,17 @@ ${e?.stack || ""}`);
45682
47127
  const prebuildKey = `${platform11}-${arch3}`;
45683
47128
  try {
45684
47129
  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")
47130
+ path19.join(__dirname, "node_modules", "node-datachannel"),
47131
+ path19.join(__dirname, "..", "node_modules", "node-datachannel"),
47132
+ path19.join(__dirname, "..", "..", "node_modules", "node-datachannel")
45688
47133
  ];
45689
47134
  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);
47135
+ const prebuildPath = path19.join(candidate, "prebuilds", prebuildKey, "node_datachannel.node");
47136
+ if (fs16.existsSync(prebuildPath)) {
47137
+ const targetDir = path19.join(candidate, "build", "Release");
47138
+ const targetPath = path19.join(targetDir, "node_datachannel.node");
47139
+ fs16.mkdirSync(targetDir, { recursive: true });
47140
+ fs16.copyFileSync(prebuildPath, targetPath);
45696
47141
  try {
45697
47142
  delete esmRequire.cache[esmRequire.resolve("node-datachannel")];
45698
47143
  } catch {
@@ -46592,20 +48037,34 @@ __export(session_host_exports, {
46592
48037
  listHostedCliRuntimes: () => listHostedCliRuntimes2,
46593
48038
  stopSessionHost: () => stopSessionHost
46594
48039
  });
48040
+ function buildSessionHostEnv(baseEnv) {
48041
+ const env = {};
48042
+ for (const [key, value] of Object.entries(baseEnv)) {
48043
+ if (typeof value !== "string") continue;
48044
+ env[key] = value;
48045
+ }
48046
+ for (const key of Object.keys(env)) {
48047
+ 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_")) {
48048
+ delete env[key];
48049
+ }
48050
+ }
48051
+ env.ADHDEV_SESSION_HOST_NAME = SESSION_HOST_APP_NAME;
48052
+ return env;
48053
+ }
46595
48054
  function resolveSessionHostEntry() {
46596
48055
  const packagedCandidates = [
46597
- path19.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
46598
- path19.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
48056
+ path20.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
48057
+ path20.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
46599
48058
  ];
46600
48059
  for (const candidate of packagedCandidates) {
46601
- if (fs16.existsSync(candidate)) {
48060
+ if (fs17.existsSync(candidate)) {
46602
48061
  return candidate;
46603
48062
  }
46604
48063
  }
46605
48064
  return require.resolve("@adhdev/session-host-daemon");
46606
48065
  }
46607
48066
  function getSessionHostPidFile() {
46608
- return path19.join(os21.homedir(), ".adhdev", `${SESSION_HOST_APP_NAME}-session-host.pid`);
48067
+ return path20.join(os21.homedir(), ".adhdev", `${SESSION_HOST_APP_NAME}-session-host.pid`);
46609
48068
  }
46610
48069
  function killPid2(pid) {
46611
48070
  try {
@@ -46623,8 +48082,8 @@ function stopSessionHost() {
46623
48082
  let stopped = false;
46624
48083
  const pidFile = getSessionHostPidFile();
46625
48084
  try {
46626
- if (fs16.existsSync(pidFile)) {
46627
- const pid = Number.parseInt(fs16.readFileSync(pidFile, "utf8").trim(), 10);
48085
+ if (fs17.existsSync(pidFile)) {
48086
+ const pid = Number.parseInt(fs17.readFileSync(pidFile, "utf8").trim(), 10);
46628
48087
  if (Number.isFinite(pid)) {
46629
48088
  stopped = killPid2(pid) || stopped;
46630
48089
  }
@@ -46632,7 +48091,7 @@ function stopSessionHost() {
46632
48091
  } catch {
46633
48092
  } finally {
46634
48093
  try {
46635
- fs16.unlinkSync(pidFile);
48094
+ fs17.unlinkSync(pidFile);
46636
48095
  } catch {
46637
48096
  }
46638
48097
  }
@@ -46651,36 +48110,49 @@ function stopSessionHost() {
46651
48110
  return stopped;
46652
48111
  }
46653
48112
  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
- });
48113
+ const spawnHost = () => {
48114
+ const entry = resolveSessionHostEntry();
48115
+ const child = (0, import_child_process11.spawn)(process.execPath, [entry], {
48116
+ detached: true,
48117
+ stdio: "ignore",
48118
+ windowsHide: true,
48119
+ env: buildSessionHostEnv(process.env)
48120
+ });
48121
+ child.unref();
48122
+ };
48123
+ try {
48124
+ return await ensureSessionHostReady({
48125
+ appName: SESSION_HOST_APP_NAME,
48126
+ spawnHost,
48127
+ timeoutMs: SESSION_HOST_START_TIMEOUT_MS
48128
+ });
48129
+ } catch (error48) {
48130
+ stopSessionHost();
48131
+ return ensureSessionHostReady({
48132
+ appName: SESSION_HOST_APP_NAME,
48133
+ spawnHost,
48134
+ timeoutMs: SESSION_HOST_START_TIMEOUT_MS
48135
+ }).catch((retryError) => {
48136
+ const initialMessage = error48 instanceof Error ? error48.message : String(error48);
48137
+ const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);
48138
+ throw new Error(`Session host failed to start after retry (${initialMessage}; retry: ${retryMessage})`);
48139
+ });
48140
+ }
46670
48141
  }
46671
48142
  async function listHostedCliRuntimes2(endpoint) {
46672
48143
  return listHostedCliRuntimes(endpoint);
46673
48144
  }
46674
- var import_child_process11, fs16, os21, path19, SESSION_HOST_APP_NAME;
48145
+ var import_child_process11, fs17, os21, path20, SESSION_HOST_APP_NAME, SESSION_HOST_START_TIMEOUT_MS;
46675
48146
  var init_session_host = __esm({
46676
48147
  "src/session-host.ts"() {
46677
48148
  "use strict";
46678
48149
  import_child_process11 = require("child_process");
46679
- fs16 = __toESM(require("fs"));
48150
+ fs17 = __toESM(require("fs"));
46680
48151
  os21 = __toESM(require("os"));
46681
- path19 = __toESM(require("path"));
48152
+ path20 = __toESM(require("path"));
46682
48153
  init_src();
46683
48154
  SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
48155
+ SESSION_HOST_START_TIMEOUT_MS = 15e3;
46684
48156
  }
46685
48157
  });
46686
48158
 
@@ -46692,24 +48164,24 @@ __export(adhdev_daemon_exports, {
46692
48164
  stopDaemon: () => stopDaemon
46693
48165
  });
46694
48166
  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");
48167
+ const dir = path21.join(os22.homedir(), ".adhdev");
48168
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
48169
+ return path21.join(dir, "daemon.pid");
46698
48170
  }
46699
48171
  function writeDaemonPid(pid) {
46700
- fs17.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
48172
+ fs18.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
46701
48173
  }
46702
48174
  function removeDaemonPid() {
46703
48175
  try {
46704
- fs17.unlinkSync(getDaemonPidFile());
48176
+ fs18.unlinkSync(getDaemonPidFile());
46705
48177
  } catch (e) {
46706
48178
  }
46707
48179
  }
46708
48180
  function isDaemonRunning() {
46709
48181
  const pidFile = getDaemonPidFile();
46710
48182
  try {
46711
- if (!fs17.existsSync(pidFile)) return false;
46712
- const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim());
48183
+ if (!fs18.existsSync(pidFile)) return false;
48184
+ const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim());
46713
48185
  process.kill(pid, 0);
46714
48186
  return true;
46715
48187
  } catch {
@@ -46720,8 +48192,8 @@ function isDaemonRunning() {
46720
48192
  function stopDaemon() {
46721
48193
  const pidFile = getDaemonPidFile();
46722
48194
  try {
46723
- if (!fs17.existsSync(pidFile)) return false;
46724
- const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim());
48195
+ if (!fs18.existsSync(pidFile)) return false;
48196
+ const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim());
46725
48197
  process.kill(pid, "SIGTERM");
46726
48198
  removeDaemonPid();
46727
48199
  return true;
@@ -46730,7 +48202,7 @@ function stopDaemon() {
46730
48202
  return false;
46731
48203
  }
46732
48204
  }
46733
- var os22, fs17, path20, import_chalk2, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
48205
+ var os22, fs18, path21, import_chalk2, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
46734
48206
  var init_adhdev_daemon = __esm({
46735
48207
  "src/adhdev-daemon.ts"() {
46736
48208
  "use strict";
@@ -46741,19 +48213,19 @@ var init_adhdev_daemon = __esm({
46741
48213
  init_session_host();
46742
48214
  init_dist();
46743
48215
  os22 = __toESM(require("os"));
46744
- fs17 = __toESM(require("fs"));
46745
- path20 = __toESM(require("path"));
48216
+ fs18 = __toESM(require("fs"));
48217
+ path21 = __toESM(require("path"));
46746
48218
  import_chalk2 = __toESM(require("chalk"));
46747
- pkgVersion = "0.7.46";
48219
+ pkgVersion = "0.8.1";
46748
48220
  if (pkgVersion === "unknown") {
46749
48221
  try {
46750
48222
  const possiblePaths = [
46751
- path20.join(__dirname, "..", "package.json"),
46752
- path20.join(__dirname, "package.json")
48223
+ path21.join(__dirname, "..", "package.json"),
48224
+ path21.join(__dirname, "package.json")
46753
48225
  ];
46754
48226
  for (const p of possiblePaths) {
46755
48227
  try {
46756
- const data = JSON.parse(fs17.readFileSync(p, "utf-8"));
48228
+ const data = JSON.parse(fs18.readFileSync(p, "utf-8"));
46757
48229
  if (data.version) {
46758
48230
  pkgVersion = data.version;
46759
48231
  break;
@@ -46851,6 +48323,10 @@ ${err?.stack || ""}`);
46851
48323
  removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
46852
48324
  createPtyTransportFactory: ({ runtimeId, providerType, workspace, cliArgs, providerSessionId, attachExisting }) => new SessionHostPtyTransportFactory({
46853
48325
  endpoint: sessionHostEndpoint,
48326
+ ensureReady: async () => {
48327
+ const activeEndpoint = await ensureSessionHostReady2();
48328
+ this.sessionHostEndpoint = activeEndpoint;
48329
+ },
46854
48330
  clientId: `daemon_${config2.machineId}`,
46855
48331
  runtimeId,
46856
48332
  providerType,
@@ -47221,9 +48697,13 @@ var wizard_exports = {};
47221
48697
  __export(wizard_exports, {
47222
48698
  runWizard: () => runWizard
47223
48699
  });
48700
+ function hasCloudMachineAuth() {
48701
+ const config2 = loadConfig();
48702
+ return Boolean(config2.machineSecret && config2.machineSecret.trim());
48703
+ }
47224
48704
  async function runWizard(options = {}) {
47225
48705
  console.log(LOGO);
47226
- if (isSetupComplete() && !options.force) {
48706
+ if (isSetupComplete() && hasCloudMachineAuth() && !options.force) {
47227
48707
  const config2 = loadConfig();
47228
48708
  console.log(import_chalk3.default.green("\u2713") + " ADHDev is already configured.");
47229
48709
  console.log(import_chalk3.default.gray(` Account: ${config2.userEmail || "not logged in"}`));
@@ -47288,29 +48768,46 @@ async function checkForUpdate() {
47288
48768
  async function quickSetup() {
47289
48769
  console.log(import_chalk3.default.bold("\n\u{1F680} Quick Setup\n"));
47290
48770
  const loginResult = await loginFlow();
48771
+ const setupDate = (/* @__PURE__ */ new Date()).toISOString();
47291
48772
  if (!loginResult) {
47292
- console.log(import_chalk3.default.yellow("\u26A0 Setup completed without login. You can login later with `adhdev setup`."));
48773
+ updateConfig({
48774
+ selectedIde: "daemon",
48775
+ configuredIdes: ["daemon"],
48776
+ installedExtensions: ["adhdev"],
48777
+ setupCompleted: false,
48778
+ setupDate,
48779
+ userEmail: null,
48780
+ userName: null,
48781
+ machineSecret: null
48782
+ });
48783
+ console.log(import_chalk3.default.yellow("\u26A0 Setup is not complete without login. Run `adhdev setup` after signing in."));
47293
48784
  }
47294
- markSetupComplete(["daemon"], ["adhdev"]);
47295
48785
  if (loginResult) {
48786
+ markSetupComplete(["daemon"], ["adhdev"]);
47296
48787
  const configUpdate = {
47297
48788
  machineSecret: loginResult.machineSecret,
47298
48789
  userEmail: loginResult.email,
47299
48790
  userName: loginResult.name,
48791
+ setupDate,
47300
48792
  ...loginResult.registeredMachineId ? { registeredMachineId: loginResult.registeredMachineId } : {}
47301
48793
  };
47302
48794
  updateConfig(configUpdate);
47303
48795
  console.log(import_chalk3.default.green(` \u2713 Machine registered`));
47304
48796
  }
47305
48797
  await installCliOnly();
47306
- await startDaemonFlow();
48798
+ if (loginResult) {
48799
+ await startDaemonFlow();
48800
+ } else {
48801
+ console.log(import_chalk3.default.gray(" Start daemon after login: adhdev setup"));
48802
+ console.log();
48803
+ }
47307
48804
  console.log(DIVIDER);
47308
48805
  console.log(import_chalk3.default.bold("\n\u{1F389} Setup Complete!\n"));
47309
48806
  console.log(` ${import_chalk3.default.bold("User:")} ${loginResult?.email || "not logged in"}`);
47310
- console.log(` ${import_chalk3.default.bold("Status:")} ${import_chalk3.default.green("Ready to connect")}`);
48807
+ console.log(` ${import_chalk3.default.bold("Status:")} ${loginResult ? import_chalk3.default.green("Ready to connect") : import_chalk3.default.yellow("Login required")}`);
47311
48808
  console.log();
47312
48809
  console.log(import_chalk3.default.gray(" Next steps:"));
47313
- console.log(import_chalk3.default.gray(" adhdev daemon \u2014 Start the main daemon (required for all features)"));
48810
+ console.log(import_chalk3.default.gray(` ${loginResult ? "adhdev daemon \u2014 Start the main daemon (required for all features)" : "adhdev setup \u2014 Sign in to finish setup and enable the daemon"}`));
47314
48811
  console.log(import_chalk3.default.gray(" adhdev launch cursor \u2014 Launch Cursor IDE with remote control"));
47315
48812
  console.log(import_chalk3.default.gray(" adhdev launch windsurf \u2014 Launch Windsurf IDE with remote control"));
47316
48813
  console.log(import_chalk3.default.gray(" adhdev launch gemini \u2014 Start Gemini CLI agent via daemon"));
@@ -47446,8 +48943,8 @@ async function startDaemonFlow() {
47446
48943
  const daemon = new AdhdevDaemon2();
47447
48944
  const { execSync: execSync7 } = await import("child_process");
47448
48945
  const os23 = await import("os");
47449
- const path21 = await import("path");
47450
- const logPath = path21.join(os23.homedir(), ".adhdev", "daemon.log");
48946
+ const path23 = await import("path");
48947
+ const logPath = path23.join(os23.homedir(), ".adhdev", "daemon.log");
47451
48948
  const platform11 = os23.platform();
47452
48949
  try {
47453
48950
  if (platform11 === "win32") {
@@ -47926,12 +49423,19 @@ function registerSetupCommands(program2, providerLoader) {
47926
49423
  program2.command("status").description("Show current ADHDev setup status").action(async () => {
47927
49424
  const { loadConfig: loadConfig2, detectIDEs: detectIDEs2, detectCLIs: detectCLIs2 } = await Promise.resolve().then(() => (init_src(), src_exports));
47928
49425
  const config2 = loadConfig2();
49426
+ const hasMachineSecret = Boolean(config2.machineSecret && config2.machineSecret.trim());
47929
49427
  console.log(import_chalk4.default.bold("\n\u{1F9A6} ADHDev Status\n"));
47930
49428
  if (!config2.setupCompleted) {
47931
49429
  console.log(import_chalk4.default.yellow(" Status: Not configured"));
47932
49430
  console.log(import_chalk4.default.gray(" Run `adhdev setup` to get started.\n"));
47933
49431
  return;
47934
49432
  }
49433
+ if (!hasMachineSecret) {
49434
+ console.log(` ${import_chalk4.default.bold("Status:")} ${import_chalk4.default.yellow("Login required")}`);
49435
+ console.log(import_chalk4.default.gray(" Setup was started, but this machine is not linked to an ADHDev account yet."));
49436
+ console.log(import_chalk4.default.gray(" Run `adhdev setup` to finish authentication.\n"));
49437
+ return;
49438
+ }
47935
49439
  const ideList = config2.configuredIdes?.length ? config2.configuredIdes : config2.selectedIde ? [config2.selectedIde] : [];
47936
49440
  console.log(` ${import_chalk4.default.bold("Status:")} ${import_chalk4.default.green("\u2713 Configured")}`);
47937
49441
  if (ideList.length > 0) {
@@ -48437,35 +49941,35 @@ function registerProviderCommands(program2) {
48437
49941
  let osPaths = {};
48438
49942
  let processNames = {};
48439
49943
  if (category === "ide") {
48440
- const fs18 = await import("fs");
48441
- const path21 = await import("path");
49944
+ const fs19 = await import("fs");
49945
+ const path23 = await import("path");
48442
49946
  const os23 = await import("os");
48443
49947
  if (os23.platform() === "darwin") {
48444
49948
  while (true) {
48445
49949
  const p = (await rl.question(`macOS Application Path (e.g. /Applications/${defaultName}.app): `)).trim() || `/Applications/${defaultName}.app`;
48446
49950
  if (p === "skip") break;
48447
- if (!fs18.existsSync(p)) {
49951
+ if (!fs19.existsSync(p)) {
48448
49952
  console.log(import_chalk6.default.red(` \u2717 Path not found: ${p}`));
48449
49953
  console.log(import_chalk6.default.gray(` (Please provide the exact absolute path to the .app or binary, or type 'skip')`));
48450
49954
  continue;
48451
49955
  }
48452
49956
  console.log(import_chalk6.default.green(` \u2713 Path verified: ${p}`));
48453
49957
  osPaths["darwin"] = [p];
48454
- processNames["darwin"] = path21.basename(p, ".app");
49958
+ processNames["darwin"] = path23.basename(p, ".app");
48455
49959
  break;
48456
49960
  }
48457
49961
  } else if (os23.platform() === "win32") {
48458
49962
  while (true) {
48459
49963
  const p = (await rl.question(`Windows Executable Path (e.g. C:\\Program Files\\${defaultName}\\${defaultName}.exe): `)).trim();
48460
49964
  if (!p || p === "skip") break;
48461
- if (!fs18.existsSync(p)) {
49965
+ if (!fs19.existsSync(p)) {
48462
49966
  console.log(import_chalk6.default.red(` \u2717 Path not found: ${p}`));
48463
49967
  console.log(import_chalk6.default.gray(` (Please provide the exact absolute path, or type 'skip')`));
48464
49968
  continue;
48465
49969
  }
48466
49970
  console.log(import_chalk6.default.green(` \u2713 Path verified: ${p}`));
48467
49971
  osPaths["win32"] = [p];
48468
- processNames["win32"] = path21.basename(p, ".exe");
49972
+ processNames["win32"] = path23.basename(p, ".exe");
48469
49973
  break;
48470
49974
  }
48471
49975
  }
@@ -49141,8 +50645,8 @@ function registerCdpCommands(program2) {
49141
50645
  }
49142
50646
  const output = typeof result === "string" ? result : JSON.stringify(result, null, 2);
49143
50647
  if (options.output) {
49144
- const fs18 = await import("fs");
49145
- fs18.writeFileSync(options.output, output, "utf-8");
50648
+ const fs19 = await import("fs");
50649
+ fs19.writeFileSync(options.output, output, "utf-8");
49146
50650
  console.log(import_chalk6.default.green(`
49147
50651
  \u2713 Saved to ${options.output} (${output.length} chars)
49148
50652
  `));
@@ -49245,8 +50749,8 @@ function registerCdpCommands(program2) {
49245
50749
  ws2.on("message", async (data) => {
49246
50750
  const msg = JSON.parse(data.toString());
49247
50751
  if (msg.id === 1 && msg.result?.data) {
49248
- const fs18 = await import("fs");
49249
- fs18.writeFileSync(options.output, Buffer.from(msg.result.data, "base64"));
50752
+ const fs19 = await import("fs");
50753
+ fs19.writeFileSync(options.output, Buffer.from(msg.result.data, "base64"));
49250
50754
  console.log(import_chalk6.default.green(`
49251
50755
  \u2713 Screenshot saved to ${options.output}
49252
50756
  `));