adhdev 0.7.46 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -569,18 +569,18 @@ function checkPathExists(paths) {
569
569
  return null;
570
570
  }
571
571
  async function detectIDEs() {
572
- const os21 = (0, import_os2.platform)();
572
+ const os22 = (0, import_os2.platform)();
573
573
  const results = [];
574
574
  for (const def of getMergedDefinitions()) {
575
575
  const cliPath = findCliCommand(def.cli);
576
- const appPath = checkPathExists(def.paths[os21] || []);
576
+ const appPath = checkPathExists(def.paths[os22] || []);
577
577
  const installed = !!(cliPath || appPath);
578
578
  let resolvedCli = cliPath;
579
- if (!resolvedCli && appPath && os21 === "darwin") {
579
+ if (!resolvedCli && appPath && os22 === "darwin") {
580
580
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
581
581
  if ((0, import_fs2.existsSync)(bundledCli)) resolvedCli = bundledCli;
582
582
  }
583
- if (!resolvedCli && appPath && os21 === "win32") {
583
+ if (!resolvedCli && appPath && os22 === "win32") {
584
584
  const { dirname: dirname9 } = await import("path");
585
585
  const appDir = dirname9(appPath);
586
586
  const candidates = [
@@ -2687,6 +2687,7 @@ var init_chat_history = __esm({
2687
2687
  role: msg.role,
2688
2688
  content: msg.content || "",
2689
2689
  kind: typeof msg.kind === "string" ? msg.kind : void 0,
2690
+ senderName: typeof msg.senderName === "string" ? msg.senderName : void 0,
2690
2691
  agent: agentType,
2691
2692
  instanceId,
2692
2693
  historySessionId: effectiveHistoryKey,
@@ -2725,6 +2726,7 @@ var init_chat_history = __esm({
2725
2726
  kind: "system",
2726
2727
  content,
2727
2728
  receivedAt: options.receivedAt,
2729
+ senderName: options.senderName,
2728
2730
  historyDedupKey: options.dedupKey
2729
2731
  }],
2730
2732
  options.sessionTitle,
@@ -3847,6 +3849,12 @@ function getCurrentManagerKey(h) {
3847
3849
  function getTargetedCliAdapter(h, args, providerType) {
3848
3850
  return h.getCliAdapter(args?.targetSessionId || providerType || h.currentSession?.providerType || h.currentManagerKey);
3849
3851
  }
3852
+ function getTargetInstance(h, args) {
3853
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
3854
+ const sessionId = targetSessionId || h.currentSession?.sessionId || "";
3855
+ if (!sessionId) return null;
3856
+ return h.ctx.instanceManager?.getInstance(sessionId);
3857
+ }
3850
3858
  function getTargetTransport(h, provider) {
3851
3859
  if (h.currentSession?.transport) return h.currentSession.transport;
3852
3860
  switch (provider?.category) {
@@ -4589,6 +4597,7 @@ async function handleResolveAction(h, args) {
4589
4597
  adapter.writeRaw?.(keys);
4590
4598
  }
4591
4599
  LOG.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
4600
+ getTargetInstance(h, args)?.recordApprovalSelection?.(buttons[buttonIndex] ?? button);
4592
4601
  return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
4593
4602
  }
4594
4603
  if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
@@ -15163,10 +15172,10 @@ __export(provider_cli_adapter_exports, {
15163
15172
  normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
15164
15173
  });
15165
15174
  function stripAnsi(str) {
15166
- 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, " ");
15175
+ 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, " ");
15167
15176
  }
15168
15177
  function stripTerminalNoise(str) {
15169
- 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, " ");
15178
+ 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, " ");
15170
15179
  }
15171
15180
  function sanitizeTerminalText(str) {
15172
15181
  return stripTerminalNoise(stripAnsi(str));
@@ -15209,12 +15218,12 @@ function findBinary(name) {
15209
15218
  function isScriptBinary(binaryPath) {
15210
15219
  if (!path7.isAbsolute(binaryPath)) return false;
15211
15220
  try {
15212
- const fs17 = require("fs");
15213
- const resolved = fs17.realpathSync(binaryPath);
15221
+ const fs18 = require("fs");
15222
+ const resolved = fs18.realpathSync(binaryPath);
15214
15223
  const head = Buffer.alloc(8);
15215
- const fd = fs17.openSync(resolved, "r");
15216
- fs17.readSync(fd, head, 0, 8, 0);
15217
- fs17.closeSync(fd);
15224
+ const fd = fs18.openSync(resolved, "r");
15225
+ fs18.readSync(fd, head, 0, 8, 0);
15226
+ fs18.closeSync(fd);
15218
15227
  let i = 0;
15219
15228
  if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
15220
15229
  return head[i] === 35 && head[i + 1] === 33;
@@ -15225,12 +15234,12 @@ function isScriptBinary(binaryPath) {
15225
15234
  function looksLikeMachOOrElf(filePath) {
15226
15235
  if (!path7.isAbsolute(filePath)) return false;
15227
15236
  try {
15228
- const fs17 = require("fs");
15229
- const resolved = fs17.realpathSync(filePath);
15237
+ const fs18 = require("fs");
15238
+ const resolved = fs18.realpathSync(filePath);
15230
15239
  const buf = Buffer.alloc(8);
15231
- const fd = fs17.openSync(resolved, "r");
15232
- fs17.readSync(fd, buf, 0, 8, 0);
15233
- fs17.closeSync(fd);
15240
+ const fd = fs18.openSync(resolved, "r");
15241
+ fs18.readSync(fd, buf, 0, 8, 0);
15242
+ fs18.closeSync(fd);
15234
15243
  let i = 0;
15235
15244
  if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
15236
15245
  const b2 = buf.subarray(i);
@@ -15283,6 +15292,9 @@ function promptLikelyVisible(screenText, promptSnippet) {
15283
15292
  ).length;
15284
15293
  return matched >= required2;
15285
15294
  }
15295
+ function normalizeScreenSnapshot(text) {
15296
+ return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
15297
+ }
15286
15298
  function parsePatternEntry(x) {
15287
15299
  if (x instanceof RegExp) return x;
15288
15300
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -15321,14 +15333,14 @@ var init_provider_cli_adapter = __esm({
15321
15333
  pty2 = require("node-pty");
15322
15334
  if (os9.platform() !== "win32") {
15323
15335
  try {
15324
- const fs17 = require("fs");
15336
+ const fs18 = require("fs");
15325
15337
  const ptyDir = path7.resolve(path7.dirname(require.resolve("node-pty")), "..");
15326
15338
  const platformArch = `${os9.platform()}-${os9.arch()}`;
15327
15339
  const helper = path7.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
15328
- if (fs17.existsSync(helper)) {
15329
- const stat4 = fs17.statSync(helper);
15340
+ if (fs18.existsSync(helper)) {
15341
+ const stat4 = fs18.statSync(helper);
15330
15342
  if (!(stat4.mode & 73)) {
15331
- fs17.chmodSync(helper, stat4.mode | 493);
15343
+ fs18.chmodSync(helper, stat4.mode | 493);
15332
15344
  LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
15333
15345
  }
15334
15346
  }
@@ -15362,10 +15374,25 @@ var init_provider_cli_adapter = __esm({
15362
15374
  this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
15363
15375
  this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
15364
15376
  this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
15377
+ this.providerResolutionMeta = {
15378
+ type: provider.type,
15379
+ name: provider.name,
15380
+ resolvedVersion: provider._resolvedVersion || null,
15381
+ resolvedOs: provider._resolvedOs || null,
15382
+ providerDir: provider._resolvedProviderDir || null,
15383
+ scriptDir: provider._resolvedScriptDir || null,
15384
+ scriptsPath: provider._resolvedScriptsPath || null,
15385
+ scriptsSource: provider._resolvedScriptsSource || null,
15386
+ versionWarning: provider._versionWarning || null
15387
+ };
15365
15388
  this.cliScripts = provider.scripts || {};
15366
15389
  const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
15367
15390
  if (scriptNames.length > 0) {
15368
15391
  LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
15392
+ LOG.info(
15393
+ "CLI",
15394
+ `[${this.cliType}] Provider resolution: providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"} source=${this.providerResolutionMeta.scriptsSource || "-"} version=${this.providerResolutionMeta.resolvedVersion || "-"}`
15395
+ );
15369
15396
  } else {
15370
15397
  LOG.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js`);
15371
15398
  }
@@ -15398,6 +15425,10 @@ var init_provider_cli_adapter = __esm({
15398
15425
  ptyOutputBuffer = "";
15399
15426
  ptyOutputFlushTimer = null;
15400
15427
  pendingTerminalQueryTail = "";
15428
+ lastOutputAt = 0;
15429
+ lastNonEmptyOutputAt = 0;
15430
+ lastScreenChangeAt = 0;
15431
+ lastScreenSnapshot = "";
15401
15432
  // Server log forwarding
15402
15433
  serverConn = null;
15403
15434
  logBuffer = [];
@@ -15418,6 +15449,7 @@ var init_provider_cli_adapter = __esm({
15418
15449
  submitRetryTimer = null;
15419
15450
  submitRetryUsed = false;
15420
15451
  submitRetryPromptSnippet = "";
15452
+ idleFinishCandidate = null;
15421
15453
  // Resize redraw suppression
15422
15454
  resizeSuppressUntil = 0;
15423
15455
  // Debug: status transition history
@@ -15433,6 +15465,12 @@ var init_provider_cli_adapter = __esm({
15433
15465
  /** Max accumulated buffer size (last 50KB) */
15434
15466
  static MAX_ACCUMULATED_BUFFER = 5e4;
15435
15467
  currentTurnScope = null;
15468
+ traceEntries = [];
15469
+ traceSeq = 0;
15470
+ traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
15471
+ static MAX_TRACE_ENTRIES = 250;
15472
+ providerResolutionMeta;
15473
+ static IDLE_FINISH_CONFIRM_MS = 900;
15436
15474
  syncMessageViews() {
15437
15475
  this.messages = [...this.committedMessages];
15438
15476
  this.structuredMessages = [...this.committedMessages];
@@ -15468,8 +15506,89 @@ var init_provider_cli_adapter = __esm({
15468
15506
  this.currentStatus = status;
15469
15507
  this.statusHistory.push({ status, at: Date.now(), trigger });
15470
15508
  if (this.statusHistory.length > 50) this.statusHistory.shift();
15509
+ this.recordTrace("status", {
15510
+ previousStatus: prev,
15511
+ trigger: trigger || null
15512
+ });
15471
15513
  LOG.info("CLI", `[${this.cliType}] status: ${prev} \u2192 ${status}${trigger ? ` (${trigger})` : ""}`);
15472
15514
  }
15515
+ clearIdleFinishCandidate(reason) {
15516
+ if (!this.idleFinishCandidate) return;
15517
+ this.recordTrace("idle_candidate_reset", {
15518
+ reason,
15519
+ candidate: this.idleFinishCandidate
15520
+ });
15521
+ this.idleFinishCandidate = null;
15522
+ }
15523
+ armIdleFinishCandidate(assistantLength) {
15524
+ const now = Date.now();
15525
+ this.idleFinishCandidate = {
15526
+ armedAt: now,
15527
+ lastOutputAt: this.lastOutputAt,
15528
+ lastScreenChangeAt: this.lastScreenChangeAt,
15529
+ responseEpoch: this.responseEpoch,
15530
+ assistantLength
15531
+ };
15532
+ this.recordTrace("idle_candidate_armed", {
15533
+ confirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
15534
+ candidate: this.idleFinishCandidate,
15535
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
15536
+ });
15537
+ if (this.settleTimer) clearTimeout(this.settleTimer);
15538
+ this.settleTimer = setTimeout(() => {
15539
+ this.settleTimer = null;
15540
+ this.settledBuffer = this.recentOutputBuffer;
15541
+ this.evaluateSettled();
15542
+ }, _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS);
15543
+ }
15544
+ summarizeTraceText(text, max = 800) {
15545
+ const value = sanitizeTerminalText(String(text || ""));
15546
+ if (value.length <= max) return value;
15547
+ return `\u2026${value.slice(-max)}`;
15548
+ }
15549
+ summarizeTraceMessages(messages, limit = 3) {
15550
+ return messages.slice(-limit).map((message) => ({
15551
+ role: message.role,
15552
+ content: this.summarizeTraceText(message.content, 240),
15553
+ timestamp: message.timestamp
15554
+ }));
15555
+ }
15556
+ buildTraceParseSnapshot(scope, partialResponse = "") {
15557
+ const scopedBuffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
15558
+ const scopedRawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
15559
+ return {
15560
+ currentTurnScope: scope || null,
15561
+ responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
15562
+ partialResponse: this.summarizeTraceText(partialResponse || this.responseBuffer, 1200),
15563
+ turnBuffer: this.summarizeTraceText(scopedBuffer, 1600),
15564
+ turnRawPreview: this.summarizeTraceText(scopedRawBuffer, 1600),
15565
+ turnSanitizedRawPreview: this.summarizeTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
15566
+ };
15567
+ }
15568
+ recordTrace(type, payload = {}) {
15569
+ const entry = {
15570
+ id: ++this.traceSeq,
15571
+ at: Date.now(),
15572
+ type,
15573
+ status: this.currentStatus,
15574
+ isWaitingForResponse: this.isWaitingForResponse,
15575
+ activeModal: this.activeModal ? { message: this.activeModal.message, buttons: [...this.activeModal.buttons] } : null,
15576
+ payload
15577
+ };
15578
+ this.traceEntries.push(entry);
15579
+ if (this.traceEntries.length > _ProviderCliAdapter.MAX_TRACE_ENTRIES) {
15580
+ this.traceEntries.splice(0, this.traceEntries.length - _ProviderCliAdapter.MAX_TRACE_ENTRIES);
15581
+ }
15582
+ }
15583
+ resetTraceSession() {
15584
+ this.traceEntries = [];
15585
+ this.traceSeq = 0;
15586
+ this.traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
15587
+ this.recordTrace("session_start", {
15588
+ providerType: this.cliType,
15589
+ workingDir: this.workingDir
15590
+ });
15591
+ }
15473
15592
  // Resolved timeouts
15474
15593
  timeouts;
15475
15594
  // Provider approval key mapping
@@ -15515,6 +15634,7 @@ var init_provider_cli_adapter = __esm({
15515
15634
  const isWin = os9.platform() === "win32";
15516
15635
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
15517
15636
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
15637
+ this.resetTraceSession();
15518
15638
  let shellCmd;
15519
15639
  let shellArgs;
15520
15640
  const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
@@ -15540,6 +15660,14 @@ var init_provider_cli_adapter = __esm({
15540
15660
  cwd: this.workingDir,
15541
15661
  env: buildCliSpawnEnv(process.env, spawnConfig.env)
15542
15662
  };
15663
+ this.recordTrace("spawn", {
15664
+ shellCommand: shellCmd,
15665
+ shellArgs,
15666
+ cwd: ptyOpts.cwd,
15667
+ cols: ptyOpts.cols,
15668
+ rows: ptyOpts.rows,
15669
+ providerResolution: this.providerResolutionMeta
15670
+ });
15543
15671
  try {
15544
15672
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
15545
15673
  } catch (err) {
@@ -15582,6 +15710,7 @@ var init_provider_cli_adapter = __esm({
15582
15710
  this.ptyProcess.onExit(({ exitCode }) => {
15583
15711
  LOG.info("CLI", `[${this.cliType}] Exit code ${exitCode}`);
15584
15712
  this.flushPendingOutputParse();
15713
+ this.recordTrace("exit", { exitCode });
15585
15714
  this.ptyProcess = null;
15586
15715
  this.setStatus("stopped", "pty_exit");
15587
15716
  this.ready = false;
@@ -15597,6 +15726,9 @@ var init_provider_cli_adapter = __esm({
15597
15726
  this.currentTurnScope = null;
15598
15727
  this.ready = false;
15599
15728
  await this.ptyProcess.ready;
15729
+ this.recordTrace("ready", {
15730
+ runtimeMeta: this.getRuntimeMetadata()
15731
+ });
15600
15732
  this.setStatus("idle", "pty_ready");
15601
15733
  this.onStatusChange?.();
15602
15734
  }
@@ -15604,6 +15736,24 @@ var init_provider_cli_adapter = __esm({
15604
15736
  handleOutput(rawData) {
15605
15737
  this.terminalScreen.write(rawData);
15606
15738
  const cleanData = sanitizeTerminalText(rawData);
15739
+ const now = Date.now();
15740
+ const normalizedScreenSnapshot = normalizeScreenSnapshot(this.terminalScreen.getText());
15741
+ this.lastOutputAt = now;
15742
+ if (cleanData.trim()) this.lastNonEmptyOutputAt = now;
15743
+ if (normalizedScreenSnapshot !== this.lastScreenSnapshot) {
15744
+ this.lastScreenSnapshot = normalizedScreenSnapshot;
15745
+ this.lastScreenChangeAt = now;
15746
+ }
15747
+ if (this.idleFinishCandidate && (rawData.length > 0 || cleanData.length > 0)) {
15748
+ this.clearIdleFinishCandidate("new_output");
15749
+ }
15750
+ this.recordTrace("output", {
15751
+ rawLength: rawData.length,
15752
+ cleanLength: cleanData.length,
15753
+ rawPreview: this.summarizeTraceText(rawData, 300),
15754
+ cleanPreview: this.summarizeTraceText(cleanData, 300),
15755
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
15756
+ });
15607
15757
  if (this.isWaitingForResponse && cleanData) {
15608
15758
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
15609
15759
  }
@@ -15621,11 +15771,17 @@ var init_provider_cli_adapter = __esm({
15621
15771
  this.startupBuffer += cleanData;
15622
15772
  const elapsed = Date.now() - this.spawnAt;
15623
15773
  const scriptStatus = this.runDetectStatus(this.startupBuffer);
15624
- const isReady = scriptStatus === "idle" || scriptStatus === "waiting_approval" || elapsed > 8e3 || this.startupBuffer.length > 12e3;
15774
+ const screenText = this.terminalScreen.getText() || "";
15775
+ const hasInteractivePrompt = this.looksLikeVisibleIdlePrompt(screenText);
15776
+ const startupStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
15777
+ const isReady = (scriptStatus === "idle" || scriptStatus === "waiting_approval") && hasInteractivePrompt && startupStableMs >= 700 || elapsed > 8e3 || this.startupBuffer.length > 12e3;
15625
15778
  if (isReady) {
15626
15779
  this.startupParseGate = false;
15627
15780
  this.ready = true;
15628
- LOG.info("CLI", `[${this.cliType}] Startup ready (${elapsed}ms, scriptStatus=${scriptStatus})`);
15781
+ LOG.info(
15782
+ "CLI",
15783
+ `[${this.cliType}] Startup ready (${elapsed}ms, scriptStatus=${scriptStatus}, prompt=${hasInteractivePrompt}, stableMs=${startupStableMs}) providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
15784
+ );
15629
15785
  this.onStatusChange?.();
15630
15786
  }
15631
15787
  }
@@ -15670,6 +15826,41 @@ var init_provider_cli_adapter = __esm({
15670
15826
  if (!text.trim()) return false;
15671
15827
  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);
15672
15828
  }
15829
+ async waitForInteractivePrompt(maxWaitMs = 5e3) {
15830
+ const startedAt = Date.now();
15831
+ let loggedWait = false;
15832
+ while (Date.now() - startedAt < maxWaitMs) {
15833
+ const screenText = this.terminalScreen.getText() || "";
15834
+ const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
15835
+ const stableMs = this.lastScreenChangeAt ? Date.now() - this.lastScreenChangeAt : 0;
15836
+ const recentlyOutput = this.lastNonEmptyOutputAt ? Date.now() - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
15837
+ const status = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
15838
+ const startupLikelyActive = /Welcome back|Tips for getting|Recent activity|Claude Code v\d/i.test(screenText);
15839
+ const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "starting" && status !== "generating";
15840
+ if (interactiveReady) {
15841
+ if (loggedWait) {
15842
+ LOG.info(
15843
+ "CLI",
15844
+ `[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput}, startup=${startupLikelyActive})`
15845
+ );
15846
+ }
15847
+ return;
15848
+ }
15849
+ if (!loggedWait && Date.now() - startedAt >= 400) {
15850
+ loggedWait = true;
15851
+ LOG.info(
15852
+ "CLI",
15853
+ `[${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)}`
15854
+ );
15855
+ }
15856
+ await new Promise((resolve13) => setTimeout(resolve13, 50));
15857
+ }
15858
+ const finalScreenText = this.terminalScreen.getText() || "";
15859
+ LOG.warn(
15860
+ "CLI",
15861
+ `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(this.summarizeTraceText(finalScreenText, 240)).slice(0, 280)}`
15862
+ );
15863
+ }
15673
15864
  evaluateSettled() {
15674
15865
  const now = Date.now();
15675
15866
  if (this.submitPendingUntil > now || this.responseSettleIgnoreUntil > now) {
@@ -15687,6 +15878,30 @@ var init_provider_cli_adapter = __esm({
15687
15878
  const modal = this.runParseApproval(tail);
15688
15879
  const rawScriptStatus = this.runDetectStatus(tail);
15689
15880
  const scriptStatus = rawScriptStatus;
15881
+ const parsedTranscript = this.parseCurrentTranscript(
15882
+ this.committedMessages,
15883
+ this.responseBuffer,
15884
+ this.currentTurnScope
15885
+ );
15886
+ const parsedMessages = Array.isArray(parsedTranscript?.messages) ? this.normalizeParsedMessages(parsedTranscript.messages) : [];
15887
+ const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
15888
+ this.recordTrace("settled", {
15889
+ tail: this.summarizeTraceText(tail, 500),
15890
+ screenText: this.summarizeTraceText(screenText, 1200),
15891
+ detectStatus: scriptStatus,
15892
+ parsedStatus: parsedTranscript?.status || null,
15893
+ parsedMessageCount: parsedMessages.length,
15894
+ parsedLastAssistant: lastParsedAssistant ? this.summarizeTraceText(lastParsedAssistant.content, 280) : "",
15895
+ parsedActiveModal: parsedTranscript?.activeModal ?? null,
15896
+ approval: modal,
15897
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
15898
+ });
15899
+ if (this.currentTurnScope && !lastParsedAssistant) {
15900
+ LOG.info(
15901
+ "CLI",
15902
+ `[${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 || "-"}`
15903
+ );
15904
+ }
15690
15905
  if (!scriptStatus) return;
15691
15906
  const prevStatus = this.currentStatus;
15692
15907
  const clearPendingScriptStatus = () => {
@@ -15722,6 +15937,7 @@ var init_provider_cli_adapter = __esm({
15722
15937
  clearPendingScriptStatus();
15723
15938
  }
15724
15939
  if (scriptStatus === "waiting_approval") {
15940
+ this.clearIdleFinishCandidate("waiting_approval");
15725
15941
  const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
15726
15942
  const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
15727
15943
  if ((inCooldown || visibleIdlePrompt) && !modal) {
@@ -15755,6 +15971,7 @@ var init_provider_cli_adapter = __esm({
15755
15971
  }
15756
15972
  }
15757
15973
  if (scriptStatus === "generating") {
15974
+ this.clearIdleFinishCandidate("generating");
15758
15975
  const effectiveScreenText = screenText || this.accumulatedBuffer;
15759
15976
  const noActiveTurn = !this.currentTurnScope;
15760
15977
  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));
@@ -15791,13 +16008,58 @@ var init_provider_cli_adapter = __esm({
15791
16008
  this.lastApprovalResolvedAt = Date.now();
15792
16009
  }
15793
16010
  if (this.isWaitingForResponse) {
16011
+ const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
16012
+ const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
16013
+ const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
16014
+ const hasAssistantTurn = !!lastParsedAssistant;
16015
+ const assistantLength = lastParsedAssistant?.content?.length || 0;
16016
+ const idleQuietThresholdMs = Math.max(220, this.timeouts.outputSettle);
16017
+ const idleStableThresholdMs = Math.max(120, Math.min(220, this.timeouts.outputSettle));
16018
+ const idleReady = visibleIdlePrompt && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
16019
+ const candidate = this.idleFinishCandidate;
16020
+ 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;
16021
+ const canFinishImmediately = idleReady && candidateQuiet;
16022
+ this.recordTrace("idle_decision", {
16023
+ visibleIdlePrompt,
16024
+ quietForMs,
16025
+ screenStableMs,
16026
+ hasAssistantTurn,
16027
+ assistantLength,
16028
+ hasModal: !!modal,
16029
+ idleQuietThresholdMs,
16030
+ idleStableThresholdMs,
16031
+ idleReady,
16032
+ idleFinishConfirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
16033
+ idleFinishCandidate: candidate,
16034
+ candidateQuiet,
16035
+ canFinishImmediately,
16036
+ submitPendingUntil: this.submitPendingUntil,
16037
+ responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
16038
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16039
+ });
16040
+ if (canFinishImmediately) {
16041
+ this.clearIdleFinishCandidate("finish_response");
16042
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
16043
+ this.finishResponse();
16044
+ return;
16045
+ }
16046
+ if (idleReady) {
16047
+ if (!candidate) {
16048
+ this.armIdleFinishCandidate(assistantLength);
16049
+ return;
16050
+ }
16051
+ } else {
16052
+ this.clearIdleFinishCandidate("idle_not_ready");
16053
+ }
15794
16054
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
15795
16055
  this.idleTimeout = setTimeout(() => {
15796
16056
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
16057
+ this.clearIdleFinishCandidate("idle_timeout_finish");
15797
16058
  this.finishResponse();
15798
16059
  }
15799
16060
  }, this.timeouts.idleFinish);
15800
16061
  } else if (prevStatus !== "idle") {
16062
+ this.clearIdleFinishCandidate("idle_without_response");
15801
16063
  this.setStatus("idle", "script_detect");
15802
16064
  this.onStatusChange?.();
15803
16065
  }
@@ -15806,6 +16068,10 @@ var init_provider_cli_adapter = __esm({
15806
16068
  finishResponse() {
15807
16069
  if (this.submitPendingUntil > Date.now()) return;
15808
16070
  if (this.responseSettleIgnoreUntil > Date.now()) return;
16071
+ this.clearIdleFinishCandidate("finish_response_enter");
16072
+ this.recordTrace("finish_response", {
16073
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16074
+ });
15809
16075
  this.commitCurrentTranscript();
15810
16076
  if (this.responseTimeout) {
15811
16077
  clearTimeout(this.responseTimeout);
@@ -15842,6 +16108,20 @@ var init_provider_cli_adapter = __esm({
15842
16108
  if (parsed && Array.isArray(parsed.messages)) {
15843
16109
  this.committedMessages = this.normalizeParsedMessages(parsed.messages);
15844
16110
  this.syncMessageViews();
16111
+ const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
16112
+ this.recordTrace("commit_transcript", {
16113
+ parsedStatus: parsed.status || null,
16114
+ messageCount: this.committedMessages.length,
16115
+ lastAssistant: lastAssistant ? this.summarizeTraceText(lastAssistant.content, 320) : "",
16116
+ messages: this.summarizeTraceMessages(this.committedMessages),
16117
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
16118
+ });
16119
+ if (!lastAssistant && this.currentTurnScope) {
16120
+ LOG.warn(
16121
+ "CLI",
16122
+ `[${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 || "-"}`
16123
+ );
16124
+ }
15845
16125
  }
15846
16126
  }
15847
16127
  // ─── Script Execution ──────────────────────────
@@ -15965,16 +16245,23 @@ ${data.message || ""}`.trim();
15965
16245
  }
15966
16246
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
15967
16247
  if (this.isWaitingForResponse) return;
16248
+ await this.waitForInteractivePrompt();
15968
16249
  this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
15969
16250
  this.syncMessageViews();
15970
16251
  this.isWaitingForResponse = true;
15971
16252
  this.responseBuffer = "";
16253
+ this.clearIdleFinishCandidate("send_message");
15972
16254
  this.currentTurnScope = {
15973
16255
  prompt: text,
15974
16256
  startedAt: Date.now(),
15975
16257
  bufferStart: this.accumulatedBuffer.length,
15976
16258
  rawBufferStart: this.accumulatedRawBuffer.length
15977
16259
  };
16260
+ this.recordTrace("send_message", {
16261
+ text: this.summarizeTraceText(text, 500),
16262
+ estimatedLines: estimatePromptDisplayLines(text),
16263
+ turnScope: this.currentTurnScope
16264
+ });
15978
16265
  LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
15979
16266
  this.submitRetryUsed = false;
15980
16267
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
@@ -16004,6 +16291,11 @@ ${data.message || ""}`.trim();
16004
16291
  const submit = () => {
16005
16292
  if (!this.ptyProcess) return;
16006
16293
  this.submitPendingUntil = 0;
16294
+ this.recordTrace("submit_write", {
16295
+ mode: "submit_key",
16296
+ sendKey: this.sendKey,
16297
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
16298
+ });
16007
16299
  this.ptyProcess.write(this.sendKey);
16008
16300
  const retrySubmitIfStuck = (attempt) => {
16009
16301
  this.submitRetryTimer = null;
@@ -16015,6 +16307,12 @@ ${data.message || ""}`.trim();
16015
16307
  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;
16016
16308
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
16017
16309
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
16310
+ this.recordTrace("submit_write", {
16311
+ mode: "submit_retry",
16312
+ attempt,
16313
+ sendKey: this.sendKey,
16314
+ screenText: this.summarizeTraceText(screenText, 500)
16315
+ });
16018
16316
  this.ptyProcess.write(this.sendKey);
16019
16317
  if (attempt >= 3) {
16020
16318
  this.submitRetryUsed = true;
@@ -16027,6 +16325,12 @@ ${data.message || ""}`.trim();
16027
16325
  };
16028
16326
  if (this.submitStrategy === "immediate") {
16029
16327
  this.submitPendingUntil = 0;
16328
+ this.recordTrace("submit_write", {
16329
+ mode: "immediate",
16330
+ text: this.summarizeTraceText(text, 500),
16331
+ sendKey: this.sendKey,
16332
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
16333
+ });
16030
16334
  this.ptyProcess.write(text + this.sendKey);
16031
16335
  this.submitRetryTimer = setTimeout(() => {
16032
16336
  this.submitRetryTimer = null;
@@ -16037,6 +16341,12 @@ ${data.message || ""}`.trim();
16037
16341
  if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
16038
16342
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
16039
16343
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
16344
+ this.recordTrace("submit_write", {
16345
+ mode: "immediate_retry",
16346
+ attempt: 1,
16347
+ sendKey: this.sendKey,
16348
+ screenText: this.summarizeTraceText(screenText, 500)
16349
+ });
16040
16350
  this.ptyProcess.write(this.sendKey);
16041
16351
  this.submitRetryUsed = true;
16042
16352
  }, retryDelayMs);
@@ -16047,6 +16357,12 @@ ${data.message || ""}`.trim();
16047
16357
  this.submitPendingUntil = Date.now() + submitDelayMs;
16048
16358
  }
16049
16359
  this.ptyProcess.write(text);
16360
+ this.recordTrace("submit_write", {
16361
+ mode: "type_then_submit",
16362
+ text: this.summarizeTraceText(text, 500),
16363
+ sendKey: this.sendKey,
16364
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
16365
+ });
16050
16366
  const submitStartedAt = Date.now();
16051
16367
  let lastNormalizedScreen = "";
16052
16368
  let lastScreenChangeAt = submitStartedAt;
@@ -16147,6 +16463,7 @@ ${data.message || ""}`.trim();
16147
16463
  });
16148
16464
  }
16149
16465
  shutdown() {
16466
+ this.clearIdleFinishCandidate("shutdown");
16150
16467
  if (this.settleTimer) {
16151
16468
  clearTimeout(this.settleTimer);
16152
16469
  this.settleTimer = null;
@@ -16187,6 +16504,7 @@ ${data.message || ""}`.trim();
16187
16504
  }
16188
16505
  }
16189
16506
  detach() {
16507
+ this.clearIdleFinishCandidate("detach");
16190
16508
  if (this.settleTimer) {
16191
16509
  clearTimeout(this.settleTimer);
16192
16510
  this.settleTimer = null;
@@ -16227,6 +16545,7 @@ ${data.message || ""}`.trim();
16227
16545
  this.onStatusChange?.();
16228
16546
  }
16229
16547
  clearHistory() {
16548
+ this.clearIdleFinishCandidate("clear_history");
16230
16549
  this.committedMessages = [];
16231
16550
  this.syncMessageViews();
16232
16551
  this.accumulatedBuffer = "";
@@ -16256,10 +16575,19 @@ ${data.message || ""}`.trim();
16256
16575
  return this.ready;
16257
16576
  }
16258
16577
  writeRaw(data) {
16578
+ this.recordTrace("write_raw", {
16579
+ keys: JSON.stringify(data),
16580
+ length: data.length
16581
+ });
16259
16582
  this.ptyProcess?.write(data);
16260
16583
  }
16261
16584
  resolveModal(buttonIndex) {
16262
16585
  if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
16586
+ this.clearIdleFinishCandidate("resolve_modal");
16587
+ this.recordTrace("resolve_modal", {
16588
+ buttonIndex,
16589
+ activeModal: this.activeModal
16590
+ });
16263
16591
  this.activeModal = null;
16264
16592
  this.lastApprovalResolvedAt = Date.now();
16265
16593
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
@@ -16291,6 +16619,7 @@ ${data.message || ""}`.trim();
16291
16619
  return {
16292
16620
  type: this.cliType,
16293
16621
  name: this.cliName,
16622
+ providerResolution: this.providerResolutionMeta,
16294
16623
  status: this.currentStatus,
16295
16624
  ready: this.ready,
16296
16625
  startupParseGate: this.startupParseGate,
@@ -16310,6 +16639,10 @@ ${data.message || ""}`.trim();
16310
16639
  rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
16311
16640
  sanitizedRawPreview: sanitizeTerminalText(this.accumulatedRawBuffer).slice(-1e3),
16312
16641
  responseBuffer: this.responseBuffer.slice(-1e3),
16642
+ lastOutputAt: this.lastOutputAt,
16643
+ lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
16644
+ lastScreenChangeAt: this.lastScreenChangeAt,
16645
+ lastScreenSnapshot: this.lastScreenSnapshot.slice(-500),
16313
16646
  isWaitingForResponse: this.isWaitingForResponse,
16314
16647
  activeModal: this.activeModal,
16315
16648
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
@@ -16321,6 +16654,8 @@ ${data.message || ""}`.trim();
16321
16654
  resizeSuppressUntil: this.resizeSuppressUntil,
16322
16655
  hasCliScripts: this.hasCliScripts(),
16323
16656
  scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
16657
+ traceSessionId: this.traceSessionId,
16658
+ traceEntryCount: this.traceEntries.length,
16324
16659
  statusHistory: this.statusHistory.slice(-30),
16325
16660
  timeouts: this.timeouts,
16326
16661
  pendingOutputParseBufferLength: this.pendingOutputParseBuffer.length,
@@ -16328,6 +16663,25 @@ ${data.message || ""}`.trim();
16328
16663
  ptyAlive: !!this.ptyProcess
16329
16664
  };
16330
16665
  }
16666
+ getTraceState(limit = 120) {
16667
+ const cappedLimit = Math.max(1, Math.min(500, Number.isFinite(limit) ? Math.floor(limit) : 120));
16668
+ return {
16669
+ sessionId: this.traceSessionId,
16670
+ providerResolution: this.providerResolutionMeta,
16671
+ entryCount: this.traceEntries.length,
16672
+ entries: this.traceEntries.slice(-cappedLimit),
16673
+ screenText: this.summarizeTraceText(this.terminalScreen.getText(), 4e3),
16674
+ recentOutputBuffer: this.summarizeTraceText(this.recentOutputBuffer, 1e3),
16675
+ responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
16676
+ status: this.currentStatus,
16677
+ activeModal: this.activeModal,
16678
+ currentTurnScope: this.currentTurnScope,
16679
+ messages: this.summarizeTraceMessages(this.committedMessages, 5)
16680
+ };
16681
+ }
16682
+ getProviderResolutionMeta() {
16683
+ return { ...this.providerResolutionMeta };
16684
+ }
16331
16685
  respondToTerminalQueries(data) {
16332
16686
  if (!this.ptyProcess || !data) return;
16333
16687
  const combined = this.pendingTerminalQueryTail + data;
@@ -16399,6 +16753,7 @@ var init_cli_provider_instance = __esm({
16399
16753
  generatingDebouncePending = null;
16400
16754
  lastApprovalEventAt = 0;
16401
16755
  historyWriter;
16756
+ runtimeMessages = [];
16402
16757
  instanceId;
16403
16758
  presentationMode;
16404
16759
  providerSessionId;
@@ -16461,6 +16816,7 @@ var init_cli_provider_instance = __esm({
16461
16816
  }
16462
16817
  const runtime = this.adapter.getRuntimeMetadata();
16463
16818
  const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
16819
+ const mergedMessages = this.mergeConversationMessages(parsedMessages);
16464
16820
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
16465
16821
  if (parsedMessages.length > 0) {
16466
16822
  let messagesToSave = parsedMessages;
@@ -16490,7 +16846,7 @@ var init_cli_provider_instance = __esm({
16490
16846
  id: `${this.type}_${this.workingDir}`,
16491
16847
  title: parsedStatus?.title || dirName,
16492
16848
  status: parsedStatus?.status || adapterStatus.status,
16493
- messages: parsedMessages,
16849
+ messages: mergedMessages,
16494
16850
  activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
16495
16851
  inputContent: ""
16496
16852
  },
@@ -16589,6 +16945,11 @@ var init_cli_provider_instance = __esm({
16589
16945
  const approvalCooldown = 5e3;
16590
16946
  if (this.lastStatus !== "waiting_approval" && (!this.lastApprovalEventAt || now - this.lastApprovalEventAt > approvalCooldown)) {
16591
16947
  this.lastApprovalEventAt = now;
16948
+ this.appendRuntimeSystemMessage(
16949
+ this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
16950
+ `approval_request:${now}`,
16951
+ now
16952
+ );
16592
16953
  this.pushEvent({
16593
16954
  event: "agent:waiting_approval",
16594
16955
  chatTitle,
@@ -16660,11 +17021,71 @@ var init_cli_provider_instance = __esm({
16660
17021
  get cliName() {
16661
17022
  return this.provider.name;
16662
17023
  }
17024
+ recordApprovalSelection(buttonText) {
17025
+ const cleanButton = String(buttonText || "").trim();
17026
+ if (!cleanButton) return;
17027
+ const now = Date.now();
17028
+ this.appendRuntimeSystemMessage(
17029
+ `Approval selected: ${cleanButton}`,
17030
+ `approval_selection:${now}:${cleanButton}`,
17031
+ now
17032
+ );
17033
+ }
16663
17034
  formatMarkerTimestamp(timestamp) {
16664
17035
  const date5 = new Date(timestamp);
16665
17036
  const pad = (value) => String(value).padStart(2, "0");
16666
17037
  return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
16667
17038
  }
17039
+ appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
17040
+ const normalizedContent = String(content || "").trim();
17041
+ if (!normalizedContent) return;
17042
+ if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
17043
+ this.runtimeMessages.push({
17044
+ key: dedupKey,
17045
+ message: {
17046
+ role: "system",
17047
+ senderName: "System",
17048
+ content: normalizedContent,
17049
+ receivedAt,
17050
+ timestamp: receivedAt
17051
+ }
17052
+ });
17053
+ if (this.runtimeMessages.length > 50) {
17054
+ this.runtimeMessages = this.runtimeMessages.slice(-50);
17055
+ }
17056
+ this.historyWriter.appendNewMessages(
17057
+ this.type,
17058
+ [{
17059
+ role: "system",
17060
+ senderName: "System",
17061
+ content: normalizedContent,
17062
+ receivedAt,
17063
+ historyDedupKey: dedupKey
17064
+ }],
17065
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
17066
+ this.instanceId,
17067
+ this.providerSessionId
17068
+ );
17069
+ }
17070
+ mergeConversationMessages(parsedMessages) {
17071
+ if (this.runtimeMessages.length === 0) return parsedMessages;
17072
+ return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b2) => {
17073
+ const aTime = a.message.receivedAt || a.message.timestamp || 0;
17074
+ const bTime = b2.message.receivedAt || b2.message.timestamp || 0;
17075
+ if (aTime !== bTime) return aTime - bTime;
17076
+ return a.index - b2.index;
17077
+ }).map((entry) => entry.message);
17078
+ }
17079
+ formatApprovalRequestMessage(modalMessage, buttons) {
17080
+ const lines = ["Approval requested"];
17081
+ const cleanMessage = String(modalMessage || "").trim();
17082
+ if (cleanMessage) lines.push(cleanMessage);
17083
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
17084
+ if (labels.length > 0) {
17085
+ lines.push(labels.map((label) => `[${label}]`).join(" "));
17086
+ }
17087
+ return lines.join("\n");
17088
+ }
16668
17089
  promoteProviderSessionId(sessionId) {
16669
17090
  const nextSessionId = String(sessionId || "").trim();
16670
17091
  if (!nextSessionId || nextSessionId === this.providerSessionId) return;
@@ -17001,10 +17422,10 @@ function mergeDefs(...defs) {
17001
17422
  function cloneDef(schema) {
17002
17423
  return mergeDefs(schema._zod.def);
17003
17424
  }
17004
- function getElementAtPath(obj, path20) {
17005
- if (!path20)
17425
+ function getElementAtPath(obj, path21) {
17426
+ if (!path21)
17006
17427
  return obj;
17007
- return path20.reduce((acc, key) => acc?.[key], obj);
17428
+ return path21.reduce((acc, key) => acc?.[key], obj);
17008
17429
  }
17009
17430
  function promiseAllObject(promisesObj) {
17010
17431
  const keys = Object.keys(promisesObj);
@@ -17316,11 +17737,11 @@ function aborted(x, startIndex = 0) {
17316
17737
  }
17317
17738
  return false;
17318
17739
  }
17319
- function prefixIssues(path20, issues) {
17740
+ function prefixIssues(path21, issues) {
17320
17741
  return issues.map((iss) => {
17321
17742
  var _a2;
17322
17743
  (_a2 = iss).path ?? (_a2.path = []);
17323
- iss.path.unshift(path20);
17744
+ iss.path.unshift(path21);
17324
17745
  return iss;
17325
17746
  });
17326
17747
  }
@@ -17563,7 +17984,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
17563
17984
  }
17564
17985
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
17565
17986
  const result = { errors: [] };
17566
- const processError = (error49, path20 = []) => {
17987
+ const processError = (error49, path21 = []) => {
17567
17988
  var _a2, _b;
17568
17989
  for (const issue2 of error49.issues) {
17569
17990
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -17573,7 +17994,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
17573
17994
  } else if (issue2.code === "invalid_element") {
17574
17995
  processError({ issues: issue2.issues }, issue2.path);
17575
17996
  } else {
17576
- const fullpath = [...path20, ...issue2.path];
17997
+ const fullpath = [...path21, ...issue2.path];
17577
17998
  if (fullpath.length === 0) {
17578
17999
  result.errors.push(mapper(issue2));
17579
18000
  continue;
@@ -17605,8 +18026,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
17605
18026
  }
17606
18027
  function toDotPath(_path) {
17607
18028
  const segs = [];
17608
- const path20 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
17609
- for (const seg of path20) {
18029
+ const path21 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
18030
+ for (const seg of path21) {
17610
18031
  if (typeof seg === "number")
17611
18032
  segs.push(`[${seg}]`);
17612
18033
  else if (typeof seg === "symbol")
@@ -30370,13 +30791,13 @@ function resolveRef(ref, ctx) {
30370
30791
  if (!ref.startsWith("#")) {
30371
30792
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
30372
30793
  }
30373
- const path20 = ref.slice(1).split("/").filter(Boolean);
30374
- if (path20.length === 0) {
30794
+ const path21 = ref.slice(1).split("/").filter(Boolean);
30795
+ if (path21.length === 0) {
30375
30796
  return ctx.rootSchema;
30376
30797
  }
30377
30798
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
30378
- if (path20[0] === defsKey) {
30379
- const key = path20[1];
30799
+ if (path21[0] === defsKey) {
30800
+ const key = path21[1];
30380
30801
  if (!key || !ctx.defs[key]) {
30381
30802
  throw new Error(`Reference not found: ${ref}`);
30382
30803
  }
@@ -34764,7 +35185,7 @@ var init_readdirp = __esm({
34764
35185
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
34765
35186
  const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
34766
35187
  if (wantBigintFsStats) {
34767
- this._stat = (path20) => statMethod(path20, { bigint: true });
35188
+ this._stat = (path21) => statMethod(path21, { bigint: true });
34768
35189
  } else {
34769
35190
  this._stat = statMethod;
34770
35191
  }
@@ -34789,8 +35210,8 @@ var init_readdirp = __esm({
34789
35210
  const par = this.parent;
34790
35211
  const fil = par && par.files;
34791
35212
  if (fil && fil.length > 0) {
34792
- const { path: path20, depth } = par;
34793
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path20));
35213
+ const { path: path21, depth } = par;
35214
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path21));
34794
35215
  const awaited = await Promise.all(slice);
34795
35216
  for (const entry of awaited) {
34796
35217
  if (!entry)
@@ -34830,20 +35251,20 @@ var init_readdirp = __esm({
34830
35251
  this.reading = false;
34831
35252
  }
34832
35253
  }
34833
- async _exploreDir(path20, depth) {
35254
+ async _exploreDir(path21, depth) {
34834
35255
  let files;
34835
35256
  try {
34836
- files = await (0, import_promises.readdir)(path20, this._rdOptions);
35257
+ files = await (0, import_promises.readdir)(path21, this._rdOptions);
34837
35258
  } catch (error48) {
34838
35259
  this._onError(error48);
34839
35260
  }
34840
- return { files, depth, path: path20 };
35261
+ return { files, depth, path: path21 };
34841
35262
  }
34842
- async _formatEntry(dirent, path20) {
35263
+ async _formatEntry(dirent, path21) {
34843
35264
  let entry;
34844
35265
  const basename7 = this._isDirent ? dirent.name : dirent;
34845
35266
  try {
34846
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path20, basename7));
35267
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path21, basename7));
34847
35268
  entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename7 };
34848
35269
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
34849
35270
  } catch (err) {
@@ -34900,16 +35321,16 @@ var init_readdirp = __esm({
34900
35321
  });
34901
35322
 
34902
35323
  // ../../oss/packages/daemon-core/node_modules/chokidar/handler.js
34903
- function createFsWatchInstance(path20, options, listener, errHandler, emitRaw) {
35324
+ function createFsWatchInstance(path21, options, listener, errHandler, emitRaw) {
34904
35325
  const handleEvent = (rawEvent, evPath) => {
34905
- listener(path20);
34906
- emitRaw(rawEvent, evPath, { watchedPath: path20 });
34907
- if (evPath && path20 !== evPath) {
34908
- fsWatchBroadcast(sp.resolve(path20, evPath), KEY_LISTENERS, sp.join(path20, evPath));
35326
+ listener(path21);
35327
+ emitRaw(rawEvent, evPath, { watchedPath: path21 });
35328
+ if (evPath && path21 !== evPath) {
35329
+ fsWatchBroadcast(sp.resolve(path21, evPath), KEY_LISTENERS, sp.join(path21, evPath));
34909
35330
  }
34910
35331
  };
34911
35332
  try {
34912
- return (0, import_node_fs.watch)(path20, {
35333
+ return (0, import_node_fs.watch)(path21, {
34913
35334
  persistent: options.persistent
34914
35335
  }, handleEvent);
34915
35336
  } catch (error48) {
@@ -35258,12 +35679,12 @@ var init_handler2 = __esm({
35258
35679
  listener(val1, val2, val3);
35259
35680
  });
35260
35681
  };
35261
- setFsWatchListener = (path20, fullPath, options, handlers) => {
35682
+ setFsWatchListener = (path21, fullPath, options, handlers) => {
35262
35683
  const { listener, errHandler, rawEmitter } = handlers;
35263
35684
  let cont = FsWatchInstances.get(fullPath);
35264
35685
  let watcher;
35265
35686
  if (!options.persistent) {
35266
- watcher = createFsWatchInstance(path20, options, listener, errHandler, rawEmitter);
35687
+ watcher = createFsWatchInstance(path21, options, listener, errHandler, rawEmitter);
35267
35688
  if (!watcher)
35268
35689
  return;
35269
35690
  return watcher.close.bind(watcher);
@@ -35274,7 +35695,7 @@ var init_handler2 = __esm({
35274
35695
  addAndConvert(cont, KEY_RAW, rawEmitter);
35275
35696
  } else {
35276
35697
  watcher = createFsWatchInstance(
35277
- path20,
35698
+ path21,
35278
35699
  options,
35279
35700
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
35280
35701
  errHandler,
@@ -35289,7 +35710,7 @@ var init_handler2 = __esm({
35289
35710
  cont.watcherUnusable = true;
35290
35711
  if (isWindows && error48.code === "EPERM") {
35291
35712
  try {
35292
- const fd = await (0, import_promises2.open)(path20, "r");
35713
+ const fd = await (0, import_promises2.open)(path21, "r");
35293
35714
  await fd.close();
35294
35715
  broadcastErr(error48);
35295
35716
  } catch (err) {
@@ -35320,7 +35741,7 @@ var init_handler2 = __esm({
35320
35741
  };
35321
35742
  };
35322
35743
  FsWatchFileInstances = /* @__PURE__ */ new Map();
35323
- setFsWatchFileListener = (path20, fullPath, options, handlers) => {
35744
+ setFsWatchFileListener = (path21, fullPath, options, handlers) => {
35324
35745
  const { listener, rawEmitter } = handlers;
35325
35746
  let cont = FsWatchFileInstances.get(fullPath);
35326
35747
  const copts = cont && cont.options;
@@ -35342,7 +35763,7 @@ var init_handler2 = __esm({
35342
35763
  });
35343
35764
  const currmtime = curr.mtimeMs;
35344
35765
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
35345
- foreach(cont.listeners, (listener2) => listener2(path20, curr));
35766
+ foreach(cont.listeners, (listener2) => listener2(path21, curr));
35346
35767
  }
35347
35768
  })
35348
35769
  };
@@ -35372,13 +35793,13 @@ var init_handler2 = __esm({
35372
35793
  * @param listener on fs change
35373
35794
  * @returns closer for the watcher instance
35374
35795
  */
35375
- _watchWithNodeFs(path20, listener) {
35796
+ _watchWithNodeFs(path21, listener) {
35376
35797
  const opts = this.fsw.options;
35377
- const directory = sp.dirname(path20);
35378
- const basename7 = sp.basename(path20);
35798
+ const directory = sp.dirname(path21);
35799
+ const basename7 = sp.basename(path21);
35379
35800
  const parent = this.fsw._getWatchedDir(directory);
35380
35801
  parent.add(basename7);
35381
- const absolutePath = sp.resolve(path20);
35802
+ const absolutePath = sp.resolve(path21);
35382
35803
  const options = {
35383
35804
  persistent: opts.persistent
35384
35805
  };
@@ -35388,12 +35809,12 @@ var init_handler2 = __esm({
35388
35809
  if (opts.usePolling) {
35389
35810
  const enableBin = opts.interval !== opts.binaryInterval;
35390
35811
  options.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
35391
- closer = setFsWatchFileListener(path20, absolutePath, options, {
35812
+ closer = setFsWatchFileListener(path21, absolutePath, options, {
35392
35813
  listener,
35393
35814
  rawEmitter: this.fsw._emitRaw
35394
35815
  });
35395
35816
  } else {
35396
- closer = setFsWatchListener(path20, absolutePath, options, {
35817
+ closer = setFsWatchListener(path21, absolutePath, options, {
35397
35818
  listener,
35398
35819
  errHandler: this._boundHandleError,
35399
35820
  rawEmitter: this.fsw._emitRaw
@@ -35415,7 +35836,7 @@ var init_handler2 = __esm({
35415
35836
  let prevStats = stats;
35416
35837
  if (parent.has(basename7))
35417
35838
  return;
35418
- const listener = async (path20, newStats) => {
35839
+ const listener = async (path21, newStats) => {
35419
35840
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
35420
35841
  return;
35421
35842
  if (!newStats || newStats.mtimeMs === 0) {
@@ -35429,11 +35850,11 @@ var init_handler2 = __esm({
35429
35850
  this.fsw._emit(EV.CHANGE, file2, newStats2);
35430
35851
  }
35431
35852
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
35432
- this.fsw._closeFile(path20);
35853
+ this.fsw._closeFile(path21);
35433
35854
  prevStats = newStats2;
35434
35855
  const closer2 = this._watchWithNodeFs(file2, listener);
35435
35856
  if (closer2)
35436
- this.fsw._addPathCloser(path20, closer2);
35857
+ this.fsw._addPathCloser(path21, closer2);
35437
35858
  } else {
35438
35859
  prevStats = newStats2;
35439
35860
  }
@@ -35465,7 +35886,7 @@ var init_handler2 = __esm({
35465
35886
  * @param item basename of this item
35466
35887
  * @returns true if no more processing is needed for this entry.
35467
35888
  */
35468
- async _handleSymlink(entry, directory, path20, item) {
35889
+ async _handleSymlink(entry, directory, path21, item) {
35469
35890
  if (this.fsw.closed) {
35470
35891
  return;
35471
35892
  }
@@ -35475,7 +35896,7 @@ var init_handler2 = __esm({
35475
35896
  this.fsw._incrReadyCount();
35476
35897
  let linkPath;
35477
35898
  try {
35478
- linkPath = await (0, import_promises2.realpath)(path20);
35899
+ linkPath = await (0, import_promises2.realpath)(path21);
35479
35900
  } catch (e) {
35480
35901
  this.fsw._emitReady();
35481
35902
  return true;
@@ -35485,12 +35906,12 @@ var init_handler2 = __esm({
35485
35906
  if (dir.has(item)) {
35486
35907
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
35487
35908
  this.fsw._symlinkPaths.set(full, linkPath);
35488
- this.fsw._emit(EV.CHANGE, path20, entry.stats);
35909
+ this.fsw._emit(EV.CHANGE, path21, entry.stats);
35489
35910
  }
35490
35911
  } else {
35491
35912
  dir.add(item);
35492
35913
  this.fsw._symlinkPaths.set(full, linkPath);
35493
- this.fsw._emit(EV.ADD, path20, entry.stats);
35914
+ this.fsw._emit(EV.ADD, path21, entry.stats);
35494
35915
  }
35495
35916
  this.fsw._emitReady();
35496
35917
  return true;
@@ -35520,9 +35941,9 @@ var init_handler2 = __esm({
35520
35941
  return;
35521
35942
  }
35522
35943
  const item = entry.path;
35523
- let path20 = sp.join(directory, item);
35944
+ let path21 = sp.join(directory, item);
35524
35945
  current.add(item);
35525
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path20, item)) {
35946
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path21, item)) {
35526
35947
  return;
35527
35948
  }
35528
35949
  if (this.fsw.closed) {
@@ -35531,8 +35952,8 @@ var init_handler2 = __esm({
35531
35952
  }
35532
35953
  if (item === target || !target && !previous.has(item)) {
35533
35954
  this.fsw._incrReadyCount();
35534
- path20 = sp.join(dir, sp.relative(dir, path20));
35535
- this._addToNodeFs(path20, initialAdd, wh, depth + 1);
35955
+ path21 = sp.join(dir, sp.relative(dir, path21));
35956
+ this._addToNodeFs(path21, initialAdd, wh, depth + 1);
35536
35957
  }
35537
35958
  }).on(EV.ERROR, this._boundHandleError);
35538
35959
  return new Promise((resolve13, reject) => {
@@ -35601,13 +36022,13 @@ var init_handler2 = __esm({
35601
36022
  * @param depth Child path actually targeted for watch
35602
36023
  * @param target Child path actually targeted for watch
35603
36024
  */
35604
- async _addToNodeFs(path20, initialAdd, priorWh, depth, target) {
36025
+ async _addToNodeFs(path21, initialAdd, priorWh, depth, target) {
35605
36026
  const ready = this.fsw._emitReady;
35606
- if (this.fsw._isIgnored(path20) || this.fsw.closed) {
36027
+ if (this.fsw._isIgnored(path21) || this.fsw.closed) {
35607
36028
  ready();
35608
36029
  return false;
35609
36030
  }
35610
- const wh = this.fsw._getWatchHelpers(path20);
36031
+ const wh = this.fsw._getWatchHelpers(path21);
35611
36032
  if (priorWh) {
35612
36033
  wh.filterPath = (entry) => priorWh.filterPath(entry);
35613
36034
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -35623,8 +36044,8 @@ var init_handler2 = __esm({
35623
36044
  const follow = this.fsw.options.followSymlinks;
35624
36045
  let closer;
35625
36046
  if (stats.isDirectory()) {
35626
- const absPath = sp.resolve(path20);
35627
- const targetPath = follow ? await (0, import_promises2.realpath)(path20) : path20;
36047
+ const absPath = sp.resolve(path21);
36048
+ const targetPath = follow ? await (0, import_promises2.realpath)(path21) : path21;
35628
36049
  if (this.fsw.closed)
35629
36050
  return;
35630
36051
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -35634,29 +36055,29 @@ var init_handler2 = __esm({
35634
36055
  this.fsw._symlinkPaths.set(absPath, targetPath);
35635
36056
  }
35636
36057
  } else if (stats.isSymbolicLink()) {
35637
- const targetPath = follow ? await (0, import_promises2.realpath)(path20) : path20;
36058
+ const targetPath = follow ? await (0, import_promises2.realpath)(path21) : path21;
35638
36059
  if (this.fsw.closed)
35639
36060
  return;
35640
36061
  const parent = sp.dirname(wh.watchPath);
35641
36062
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
35642
36063
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
35643
- closer = await this._handleDir(parent, stats, initialAdd, depth, path20, wh, targetPath);
36064
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path21, wh, targetPath);
35644
36065
  if (this.fsw.closed)
35645
36066
  return;
35646
36067
  if (targetPath !== void 0) {
35647
- this.fsw._symlinkPaths.set(sp.resolve(path20), targetPath);
36068
+ this.fsw._symlinkPaths.set(sp.resolve(path21), targetPath);
35648
36069
  }
35649
36070
  } else {
35650
36071
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
35651
36072
  }
35652
36073
  ready();
35653
36074
  if (closer)
35654
- this.fsw._addPathCloser(path20, closer);
36075
+ this.fsw._addPathCloser(path21, closer);
35655
36076
  return false;
35656
36077
  } catch (error48) {
35657
36078
  if (this.fsw._handleError(error48)) {
35658
36079
  ready();
35659
- return path20;
36080
+ return path21;
35660
36081
  }
35661
36082
  }
35662
36083
  }
@@ -35691,24 +36112,24 @@ function createPattern(matcher) {
35691
36112
  }
35692
36113
  return () => false;
35693
36114
  }
35694
- function normalizePath(path20) {
35695
- if (typeof path20 !== "string")
36115
+ function normalizePath(path21) {
36116
+ if (typeof path21 !== "string")
35696
36117
  throw new Error("string expected");
35697
- path20 = sp2.normalize(path20);
35698
- path20 = path20.replace(/\\/g, "/");
36118
+ path21 = sp2.normalize(path21);
36119
+ path21 = path21.replace(/\\/g, "/");
35699
36120
  let prepend = false;
35700
- if (path20.startsWith("//"))
36121
+ if (path21.startsWith("//"))
35701
36122
  prepend = true;
35702
- path20 = path20.replace(DOUBLE_SLASH_RE, "/");
36123
+ path21 = path21.replace(DOUBLE_SLASH_RE, "/");
35703
36124
  if (prepend)
35704
- path20 = "/" + path20;
35705
- return path20;
36125
+ path21 = "/" + path21;
36126
+ return path21;
35706
36127
  }
35707
36128
  function matchPatterns(patterns, testString, stats) {
35708
- const path20 = normalizePath(testString);
36129
+ const path21 = normalizePath(testString);
35709
36130
  for (let index = 0; index < patterns.length; index++) {
35710
36131
  const pattern = patterns[index];
35711
- if (pattern(path20, stats)) {
36132
+ if (pattern(path21, stats)) {
35712
36133
  return true;
35713
36134
  }
35714
36135
  }
@@ -35771,19 +36192,19 @@ var init_chokidar = __esm({
35771
36192
  }
35772
36193
  return str;
35773
36194
  };
35774
- normalizePathToUnix = (path20) => toUnix(sp2.normalize(toUnix(path20)));
35775
- normalizeIgnored = (cwd = "") => (path20) => {
35776
- if (typeof path20 === "string") {
35777
- return normalizePathToUnix(sp2.isAbsolute(path20) ? path20 : sp2.join(cwd, path20));
36195
+ normalizePathToUnix = (path21) => toUnix(sp2.normalize(toUnix(path21)));
36196
+ normalizeIgnored = (cwd = "") => (path21) => {
36197
+ if (typeof path21 === "string") {
36198
+ return normalizePathToUnix(sp2.isAbsolute(path21) ? path21 : sp2.join(cwd, path21));
35778
36199
  } else {
35779
- return path20;
36200
+ return path21;
35780
36201
  }
35781
36202
  };
35782
- getAbsolutePath = (path20, cwd) => {
35783
- if (sp2.isAbsolute(path20)) {
35784
- return path20;
36203
+ getAbsolutePath = (path21, cwd) => {
36204
+ if (sp2.isAbsolute(path21)) {
36205
+ return path21;
35785
36206
  }
35786
- return sp2.join(cwd, path20);
36207
+ return sp2.join(cwd, path21);
35787
36208
  };
35788
36209
  EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
35789
36210
  DirEntry = class {
@@ -35848,10 +36269,10 @@ var init_chokidar = __esm({
35848
36269
  dirParts;
35849
36270
  followSymlinks;
35850
36271
  statMethod;
35851
- constructor(path20, follow, fsw) {
36272
+ constructor(path21, follow, fsw) {
35852
36273
  this.fsw = fsw;
35853
- const watchPath = path20;
35854
- this.path = path20 = path20.replace(REPLACER_RE, "");
36274
+ const watchPath = path21;
36275
+ this.path = path21 = path21.replace(REPLACER_RE, "");
35855
36276
  this.watchPath = watchPath;
35856
36277
  this.fullWatchPath = sp2.resolve(watchPath);
35857
36278
  this.dirParts = [];
@@ -35991,20 +36412,20 @@ var init_chokidar = __esm({
35991
36412
  this._closePromise = void 0;
35992
36413
  let paths = unifyPaths(paths_);
35993
36414
  if (cwd) {
35994
- paths = paths.map((path20) => {
35995
- const absPath = getAbsolutePath(path20, cwd);
36415
+ paths = paths.map((path21) => {
36416
+ const absPath = getAbsolutePath(path21, cwd);
35996
36417
  return absPath;
35997
36418
  });
35998
36419
  }
35999
- paths.forEach((path20) => {
36000
- this._removeIgnoredPath(path20);
36420
+ paths.forEach((path21) => {
36421
+ this._removeIgnoredPath(path21);
36001
36422
  });
36002
36423
  this._userIgnored = void 0;
36003
36424
  if (!this._readyCount)
36004
36425
  this._readyCount = 0;
36005
36426
  this._readyCount += paths.length;
36006
- Promise.all(paths.map(async (path20) => {
36007
- const res = await this._nodeFsHandler._addToNodeFs(path20, !_internal, void 0, 0, _origAdd);
36427
+ Promise.all(paths.map(async (path21) => {
36428
+ const res = await this._nodeFsHandler._addToNodeFs(path21, !_internal, void 0, 0, _origAdd);
36008
36429
  if (res)
36009
36430
  this._emitReady();
36010
36431
  return res;
@@ -36026,17 +36447,17 @@ var init_chokidar = __esm({
36026
36447
  return this;
36027
36448
  const paths = unifyPaths(paths_);
36028
36449
  const { cwd } = this.options;
36029
- paths.forEach((path20) => {
36030
- if (!sp2.isAbsolute(path20) && !this._closers.has(path20)) {
36450
+ paths.forEach((path21) => {
36451
+ if (!sp2.isAbsolute(path21) && !this._closers.has(path21)) {
36031
36452
  if (cwd)
36032
- path20 = sp2.join(cwd, path20);
36033
- path20 = sp2.resolve(path20);
36453
+ path21 = sp2.join(cwd, path21);
36454
+ path21 = sp2.resolve(path21);
36034
36455
  }
36035
- this._closePath(path20);
36036
- this._addIgnoredPath(path20);
36037
- if (this._watched.has(path20)) {
36456
+ this._closePath(path21);
36457
+ this._addIgnoredPath(path21);
36458
+ if (this._watched.has(path21)) {
36038
36459
  this._addIgnoredPath({
36039
- path: path20,
36460
+ path: path21,
36040
36461
  recursive: true
36041
36462
  });
36042
36463
  }
@@ -36100,38 +36521,38 @@ var init_chokidar = __esm({
36100
36521
  * @param stats arguments to be passed with event
36101
36522
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
36102
36523
  */
36103
- async _emit(event, path20, stats) {
36524
+ async _emit(event, path21, stats) {
36104
36525
  if (this.closed)
36105
36526
  return;
36106
36527
  const opts = this.options;
36107
36528
  if (isWindows)
36108
- path20 = sp2.normalize(path20);
36529
+ path21 = sp2.normalize(path21);
36109
36530
  if (opts.cwd)
36110
- path20 = sp2.relative(opts.cwd, path20);
36111
- const args = [path20];
36531
+ path21 = sp2.relative(opts.cwd, path21);
36532
+ const args = [path21];
36112
36533
  if (stats != null)
36113
36534
  args.push(stats);
36114
36535
  const awf = opts.awaitWriteFinish;
36115
36536
  let pw;
36116
- if (awf && (pw = this._pendingWrites.get(path20))) {
36537
+ if (awf && (pw = this._pendingWrites.get(path21))) {
36117
36538
  pw.lastChange = /* @__PURE__ */ new Date();
36118
36539
  return this;
36119
36540
  }
36120
36541
  if (opts.atomic) {
36121
36542
  if (event === EVENTS.UNLINK) {
36122
- this._pendingUnlinks.set(path20, [event, ...args]);
36543
+ this._pendingUnlinks.set(path21, [event, ...args]);
36123
36544
  setTimeout(() => {
36124
- this._pendingUnlinks.forEach((entry, path21) => {
36545
+ this._pendingUnlinks.forEach((entry, path23) => {
36125
36546
  this.emit(...entry);
36126
36547
  this.emit(EVENTS.ALL, ...entry);
36127
- this._pendingUnlinks.delete(path21);
36548
+ this._pendingUnlinks.delete(path23);
36128
36549
  });
36129
36550
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
36130
36551
  return this;
36131
36552
  }
36132
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path20)) {
36553
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path21)) {
36133
36554
  event = EVENTS.CHANGE;
36134
- this._pendingUnlinks.delete(path20);
36555
+ this._pendingUnlinks.delete(path21);
36135
36556
  }
36136
36557
  }
36137
36558
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -36149,16 +36570,16 @@ var init_chokidar = __esm({
36149
36570
  this.emitWithAll(event, args);
36150
36571
  }
36151
36572
  };
36152
- this._awaitWriteFinish(path20, awf.stabilityThreshold, event, awfEmit);
36573
+ this._awaitWriteFinish(path21, awf.stabilityThreshold, event, awfEmit);
36153
36574
  return this;
36154
36575
  }
36155
36576
  if (event === EVENTS.CHANGE) {
36156
- const isThrottled = !this._throttle(EVENTS.CHANGE, path20, 50);
36577
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path21, 50);
36157
36578
  if (isThrottled)
36158
36579
  return this;
36159
36580
  }
36160
36581
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
36161
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path20) : path20;
36582
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path21) : path21;
36162
36583
  let stats2;
36163
36584
  try {
36164
36585
  stats2 = await (0, import_promises3.stat)(fullPath);
@@ -36189,23 +36610,23 @@ var init_chokidar = __esm({
36189
36610
  * @param timeout duration of time to suppress duplicate actions
36190
36611
  * @returns tracking object or false if action should be suppressed
36191
36612
  */
36192
- _throttle(actionType, path20, timeout) {
36613
+ _throttle(actionType, path21, timeout) {
36193
36614
  if (!this._throttled.has(actionType)) {
36194
36615
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
36195
36616
  }
36196
36617
  const action = this._throttled.get(actionType);
36197
36618
  if (!action)
36198
36619
  throw new Error("invalid throttle");
36199
- const actionPath = action.get(path20);
36620
+ const actionPath = action.get(path21);
36200
36621
  if (actionPath) {
36201
36622
  actionPath.count++;
36202
36623
  return false;
36203
36624
  }
36204
36625
  let timeoutObject;
36205
36626
  const clear = () => {
36206
- const item = action.get(path20);
36627
+ const item = action.get(path21);
36207
36628
  const count = item ? item.count : 0;
36208
- action.delete(path20);
36629
+ action.delete(path21);
36209
36630
  clearTimeout(timeoutObject);
36210
36631
  if (item)
36211
36632
  clearTimeout(item.timeoutObject);
@@ -36213,7 +36634,7 @@ var init_chokidar = __esm({
36213
36634
  };
36214
36635
  timeoutObject = setTimeout(clear, timeout);
36215
36636
  const thr = { timeoutObject, clear, count: 0 };
36216
- action.set(path20, thr);
36637
+ action.set(path21, thr);
36217
36638
  return thr;
36218
36639
  }
36219
36640
  _incrReadyCount() {
@@ -36227,44 +36648,44 @@ var init_chokidar = __esm({
36227
36648
  * @param event
36228
36649
  * @param awfEmit Callback to be called when ready for event to be emitted.
36229
36650
  */
36230
- _awaitWriteFinish(path20, threshold, event, awfEmit) {
36651
+ _awaitWriteFinish(path21, threshold, event, awfEmit) {
36231
36652
  const awf = this.options.awaitWriteFinish;
36232
36653
  if (typeof awf !== "object")
36233
36654
  return;
36234
36655
  const pollInterval = awf.pollInterval;
36235
36656
  let timeoutHandler;
36236
- let fullPath = path20;
36237
- if (this.options.cwd && !sp2.isAbsolute(path20)) {
36238
- fullPath = sp2.join(this.options.cwd, path20);
36657
+ let fullPath = path21;
36658
+ if (this.options.cwd && !sp2.isAbsolute(path21)) {
36659
+ fullPath = sp2.join(this.options.cwd, path21);
36239
36660
  }
36240
36661
  const now = /* @__PURE__ */ new Date();
36241
36662
  const writes = this._pendingWrites;
36242
36663
  function awaitWriteFinishFn(prevStat) {
36243
36664
  (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
36244
- if (err || !writes.has(path20)) {
36665
+ if (err || !writes.has(path21)) {
36245
36666
  if (err && err.code !== "ENOENT")
36246
36667
  awfEmit(err);
36247
36668
  return;
36248
36669
  }
36249
36670
  const now2 = Number(/* @__PURE__ */ new Date());
36250
36671
  if (prevStat && curStat.size !== prevStat.size) {
36251
- writes.get(path20).lastChange = now2;
36672
+ writes.get(path21).lastChange = now2;
36252
36673
  }
36253
- const pw = writes.get(path20);
36674
+ const pw = writes.get(path21);
36254
36675
  const df = now2 - pw.lastChange;
36255
36676
  if (df >= threshold) {
36256
- writes.delete(path20);
36677
+ writes.delete(path21);
36257
36678
  awfEmit(void 0, curStat);
36258
36679
  } else {
36259
36680
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
36260
36681
  }
36261
36682
  });
36262
36683
  }
36263
- if (!writes.has(path20)) {
36264
- writes.set(path20, {
36684
+ if (!writes.has(path21)) {
36685
+ writes.set(path21, {
36265
36686
  lastChange: now,
36266
36687
  cancelWait: () => {
36267
- writes.delete(path20);
36688
+ writes.delete(path21);
36268
36689
  clearTimeout(timeoutHandler);
36269
36690
  return event;
36270
36691
  }
@@ -36275,8 +36696,8 @@ var init_chokidar = __esm({
36275
36696
  /**
36276
36697
  * Determines whether user has asked to ignore this path.
36277
36698
  */
36278
- _isIgnored(path20, stats) {
36279
- if (this.options.atomic && DOT_RE.test(path20))
36699
+ _isIgnored(path21, stats) {
36700
+ if (this.options.atomic && DOT_RE.test(path21))
36280
36701
  return true;
36281
36702
  if (!this._userIgnored) {
36282
36703
  const { cwd } = this.options;
@@ -36286,17 +36707,17 @@ var init_chokidar = __esm({
36286
36707
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
36287
36708
  this._userIgnored = anymatch(list, void 0);
36288
36709
  }
36289
- return this._userIgnored(path20, stats);
36710
+ return this._userIgnored(path21, stats);
36290
36711
  }
36291
- _isntIgnored(path20, stat4) {
36292
- return !this._isIgnored(path20, stat4);
36712
+ _isntIgnored(path21, stat4) {
36713
+ return !this._isIgnored(path21, stat4);
36293
36714
  }
36294
36715
  /**
36295
36716
  * Provides a set of common helpers and properties relating to symlink handling.
36296
36717
  * @param path file or directory pattern being watched
36297
36718
  */
36298
- _getWatchHelpers(path20) {
36299
- return new WatchHelper(path20, this.options.followSymlinks, this);
36719
+ _getWatchHelpers(path21) {
36720
+ return new WatchHelper(path21, this.options.followSymlinks, this);
36300
36721
  }
36301
36722
  // Directory helpers
36302
36723
  // -----------------
@@ -36328,63 +36749,63 @@ var init_chokidar = __esm({
36328
36749
  * @param item base path of item/directory
36329
36750
  */
36330
36751
  _remove(directory, item, isDirectory) {
36331
- const path20 = sp2.join(directory, item);
36332
- const fullPath = sp2.resolve(path20);
36333
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path20) || this._watched.has(fullPath);
36334
- if (!this._throttle("remove", path20, 100))
36752
+ const path21 = sp2.join(directory, item);
36753
+ const fullPath = sp2.resolve(path21);
36754
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path21) || this._watched.has(fullPath);
36755
+ if (!this._throttle("remove", path21, 100))
36335
36756
  return;
36336
36757
  if (!isDirectory && this._watched.size === 1) {
36337
36758
  this.add(directory, item, true);
36338
36759
  }
36339
- const wp = this._getWatchedDir(path20);
36760
+ const wp = this._getWatchedDir(path21);
36340
36761
  const nestedDirectoryChildren = wp.getChildren();
36341
- nestedDirectoryChildren.forEach((nested) => this._remove(path20, nested));
36762
+ nestedDirectoryChildren.forEach((nested) => this._remove(path21, nested));
36342
36763
  const parent = this._getWatchedDir(directory);
36343
36764
  const wasTracked = parent.has(item);
36344
36765
  parent.remove(item);
36345
36766
  if (this._symlinkPaths.has(fullPath)) {
36346
36767
  this._symlinkPaths.delete(fullPath);
36347
36768
  }
36348
- let relPath = path20;
36769
+ let relPath = path21;
36349
36770
  if (this.options.cwd)
36350
- relPath = sp2.relative(this.options.cwd, path20);
36771
+ relPath = sp2.relative(this.options.cwd, path21);
36351
36772
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
36352
36773
  const event = this._pendingWrites.get(relPath).cancelWait();
36353
36774
  if (event === EVENTS.ADD)
36354
36775
  return;
36355
36776
  }
36356
- this._watched.delete(path20);
36777
+ this._watched.delete(path21);
36357
36778
  this._watched.delete(fullPath);
36358
36779
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
36359
- if (wasTracked && !this._isIgnored(path20))
36360
- this._emit(eventName, path20);
36361
- this._closePath(path20);
36780
+ if (wasTracked && !this._isIgnored(path21))
36781
+ this._emit(eventName, path21);
36782
+ this._closePath(path21);
36362
36783
  }
36363
36784
  /**
36364
36785
  * Closes all watchers for a path
36365
36786
  */
36366
- _closePath(path20) {
36367
- this._closeFile(path20);
36368
- const dir = sp2.dirname(path20);
36369
- this._getWatchedDir(dir).remove(sp2.basename(path20));
36787
+ _closePath(path21) {
36788
+ this._closeFile(path21);
36789
+ const dir = sp2.dirname(path21);
36790
+ this._getWatchedDir(dir).remove(sp2.basename(path21));
36370
36791
  }
36371
36792
  /**
36372
36793
  * Closes only file-specific watchers
36373
36794
  */
36374
- _closeFile(path20) {
36375
- const closers = this._closers.get(path20);
36795
+ _closeFile(path21) {
36796
+ const closers = this._closers.get(path21);
36376
36797
  if (!closers)
36377
36798
  return;
36378
36799
  closers.forEach((closer) => closer());
36379
- this._closers.delete(path20);
36800
+ this._closers.delete(path21);
36380
36801
  }
36381
- _addPathCloser(path20, closer) {
36802
+ _addPathCloser(path21, closer) {
36382
36803
  if (!closer)
36383
36804
  return;
36384
- let list = this._closers.get(path20);
36805
+ let list = this._closers.get(path21);
36385
36806
  if (!list) {
36386
36807
  list = [];
36387
- this._closers.set(path20, list);
36808
+ this._closers.set(path21, list);
36388
36809
  }
36389
36810
  list.push(closer);
36390
36811
  }
@@ -36760,6 +37181,7 @@ var init_provider_loader = __esm({
36760
37181
  resolve(type, context) {
36761
37182
  const base = this.providers.get(type);
36762
37183
  if (!base) return void 0;
37184
+ const providerDir = this.findProviderDirInternal(type) || void 0;
36763
37185
  const currentOs = context?.os || process.platform;
36764
37186
  const currentVersion = context?.version ?? this.versionArchive?.getLatest(type) ?? void 0;
36765
37187
  const resolved = JSON.parse(JSON.stringify(base));
@@ -36769,6 +37191,9 @@ var init_provider_loader = __esm({
36769
37191
  if (base.scripts) {
36770
37192
  resolved.scripts = { ...base.scripts };
36771
37193
  }
37194
+ if (providerDir) {
37195
+ resolved._resolvedProviderDir = providerDir;
37196
+ }
36772
37197
  if (base.os?.[currentOs]) {
36773
37198
  const osOverride = base.os[currentOs];
36774
37199
  if (osOverride.scripts) {
@@ -36789,6 +37214,12 @@ var init_provider_loader = __esm({
36789
37214
  if (loaded) {
36790
37215
  resolved.scripts = loaded;
36791
37216
  this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
37217
+ resolved._resolvedScriptDir = entry.scriptDir;
37218
+ resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
37219
+ if (providerDir) {
37220
+ const fullDir = path10.join(providerDir, entry.scriptDir);
37221
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37222
+ }
36792
37223
  matched = true;
36793
37224
  }
36794
37225
  break;
@@ -36799,6 +37230,12 @@ var init_provider_loader = __esm({
36799
37230
  if (loaded) {
36800
37231
  resolved.scripts = loaded;
36801
37232
  this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
37233
+ resolved._resolvedScriptDir = base.defaultScriptDir;
37234
+ resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
37235
+ if (providerDir) {
37236
+ const fullDir = path10.join(providerDir, base.defaultScriptDir);
37237
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37238
+ }
36802
37239
  }
36803
37240
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
36804
37241
  }
@@ -36811,6 +37248,12 @@ var init_provider_loader = __esm({
36811
37248
  if (loaded) {
36812
37249
  resolved.scripts = loaded;
36813
37250
  this.log(` [version override] ${type} ${range} \u2192 ${dirOverride}`);
37251
+ resolved._resolvedScriptDir = dirOverride;
37252
+ resolved._resolvedScriptsSource = `versions:${range}`;
37253
+ if (providerDir) {
37254
+ const fullDir = path10.join(providerDir, dirOverride);
37255
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37256
+ }
36814
37257
  }
36815
37258
  } else if (override.scripts) {
36816
37259
  resolved.scripts = { ...resolved.scripts, ...override.scripts };
@@ -36822,6 +37265,12 @@ var init_provider_loader = __esm({
36822
37265
  if (loaded) {
36823
37266
  resolved.scripts = loaded;
36824
37267
  this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
37268
+ resolved._resolvedScriptDir = base.defaultScriptDir;
37269
+ resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
37270
+ if (providerDir) {
37271
+ const fullDir = path10.join(providerDir, base.defaultScriptDir);
37272
+ resolved._resolvedScriptsPath = fs7.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
37273
+ }
36825
37274
  }
36826
37275
  }
36827
37276
  if (base.overrides) {
@@ -36890,6 +37339,9 @@ var init_provider_loader = __esm({
36890
37339
  awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
36891
37340
  });
36892
37341
  const handleChange = (filePath) => {
37342
+ if (/[\/\\]fixtures[\/\\]/.test(filePath)) {
37343
+ return;
37344
+ }
36893
37345
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
36894
37346
  this.log(`File changed: ${path10.basename(filePath)}, reloading...`);
36895
37347
  this.reload();
@@ -37583,7 +38035,7 @@ function detectCurrentWorkspace(ideId) {
37583
38035
  }
37584
38036
  } else if (plat === "win32") {
37585
38037
  try {
37586
- const fs17 = require("fs");
38038
+ const fs18 = require("fs");
37587
38039
  const appNameMap = getMacAppIdentifiers();
37588
38040
  const appName = appNameMap[ideId];
37589
38041
  if (appName) {
@@ -37592,8 +38044,8 @@ function detectCurrentWorkspace(ideId) {
37592
38044
  appName,
37593
38045
  "storage.json"
37594
38046
  );
37595
- if (fs17.existsSync(storagePath)) {
37596
- const data = JSON.parse(fs17.readFileSync(storagePath, "utf-8"));
38047
+ if (fs18.existsSync(storagePath)) {
38048
+ const data = JSON.parse(fs18.readFileSync(storagePath, "utf-8"));
37597
38049
  const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
37598
38050
  if (workspaces.length > 0) {
37599
38051
  const recent = workspaces[0];
@@ -41051,6 +41503,160 @@ var init_dev_cdp_handlers = __esm({
41051
41503
  });
41052
41504
 
41053
41505
  // ../../oss/packages/daemon-core/src/daemon/dev-cli-debug.ts
41506
+ function slugifyFixtureName(value) {
41507
+ const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
41508
+ return normalized || `fixture-${Date.now()}`;
41509
+ }
41510
+ function getCliFixtureDir(ctx, type) {
41511
+ const providerDir = ctx.providerLoader.findProviderDir(type);
41512
+ if (!providerDir) {
41513
+ throw new Error(`Provider directory not found for '${type}'`);
41514
+ }
41515
+ return path15.join(providerDir, "fixtures");
41516
+ }
41517
+ function readCliFixture(ctx, type, name) {
41518
+ const fixtureDir = getCliFixtureDir(ctx, type);
41519
+ const filePath = path15.join(fixtureDir, `${name}.json`);
41520
+ if (!fs12.existsSync(filePath)) {
41521
+ throw new Error(`Fixture not found: ${filePath}`);
41522
+ }
41523
+ return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
41524
+ }
41525
+ function getExerciseTranscriptText(result) {
41526
+ const parts = [];
41527
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41528
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41529
+ for (const message of [...debugMessages, ...traceMessages]) {
41530
+ if (!message || typeof message.content !== "string") continue;
41531
+ parts.push(message.content);
41532
+ }
41533
+ if (typeof result?.debug?.partialResponse === "string") parts.push(result.debug.partialResponse);
41534
+ if (typeof result?.trace?.responseBuffer === "string") parts.push(result.trace.responseBuffer);
41535
+ return parts.join("\n");
41536
+ }
41537
+ function getExerciseLastAssistant(result) {
41538
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41539
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41540
+ for (const messages of [debugMessages, traceMessages]) {
41541
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
41542
+ const message = messages[i];
41543
+ if (message?.role === "assistant" && typeof message.content === "string" && message.content.trim()) {
41544
+ return message.content;
41545
+ }
41546
+ }
41547
+ }
41548
+ return "";
41549
+ }
41550
+ function getExerciseMessageCount(result) {
41551
+ const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
41552
+ const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
41553
+ return Math.max(debugMessages.length, traceMessages.length);
41554
+ }
41555
+ function compileFixtureRegex(source) {
41556
+ const value = String(source || "").trim();
41557
+ if (!value) return null;
41558
+ const delimited = value.match(/^\/([\s\S]+)\/([dgimsuvy]*)$/);
41559
+ try {
41560
+ if (delimited) {
41561
+ return new RegExp(delimited[1], delimited[2]);
41562
+ }
41563
+ return new RegExp(value, "m");
41564
+ } catch {
41565
+ return null;
41566
+ }
41567
+ }
41568
+ function statusesContainSequence(actual, expected) {
41569
+ if (!expected.length) return true;
41570
+ let index = 0;
41571
+ for (const status of actual) {
41572
+ if (status === expected[index]) index += 1;
41573
+ if (index >= expected.length) return true;
41574
+ }
41575
+ return false;
41576
+ }
41577
+ function validateCliFixtureResult(result, assertions) {
41578
+ const failures = [];
41579
+ const transcriptText = getExerciseTranscriptText(result);
41580
+ const lastAssistant = getExerciseLastAssistant(result);
41581
+ const mustContainAny = assertions.mustContainAny || [];
41582
+ const mustNotContainAny = assertions.mustNotContainAny || [];
41583
+ const mustMatchAny = assertions.mustMatchAny || [];
41584
+ const mustNotMatchAny = assertions.mustNotMatchAny || [];
41585
+ const lastAssistantMustContainAny = assertions.lastAssistantMustContainAny || [];
41586
+ const lastAssistantMustNotContainAny = assertions.lastAssistantMustNotContainAny || [];
41587
+ const lastAssistantMustMatchAny = assertions.lastAssistantMustMatchAny || [];
41588
+ const lastAssistantMustNotMatchAny = assertions.lastAssistantMustNotMatchAny || [];
41589
+ const statusesSeen = Array.isArray(result?.statusesSeen) ? result.statusesSeen.map((value) => String(value)) : [];
41590
+ if (assertions.requireNotTimedOut !== false && result?.timedOut) {
41591
+ failures.push("Exercise timed out");
41592
+ }
41593
+ const missingRequired = mustContainAny.filter((value) => !transcriptText.includes(value));
41594
+ if (missingRequired.length > 0) {
41595
+ failures.push(`Missing required substrings: ${missingRequired.join(", ")}`);
41596
+ }
41597
+ const presentBanned = mustNotContainAny.filter((value) => transcriptText.includes(value));
41598
+ if (presentBanned.length > 0) {
41599
+ failures.push(`Found banned substrings: ${presentBanned.join(", ")}`);
41600
+ }
41601
+ const missingRegex = mustMatchAny.filter((value) => {
41602
+ const regex = compileFixtureRegex(value);
41603
+ return !regex || !regex.test(transcriptText);
41604
+ });
41605
+ if (missingRegex.length > 0) {
41606
+ failures.push(`Missing required regex matches: ${missingRegex.join(", ")}`);
41607
+ }
41608
+ const presentBannedRegex = mustNotMatchAny.filter((value) => {
41609
+ const regex = compileFixtureRegex(value);
41610
+ return !!regex && regex.test(transcriptText);
41611
+ });
41612
+ if (presentBannedRegex.length > 0) {
41613
+ failures.push(`Found banned regex matches: ${presentBannedRegex.join(", ")}`);
41614
+ }
41615
+ const missingLastAssistant = lastAssistantMustContainAny.filter((value) => !lastAssistant.includes(value));
41616
+ if (missingLastAssistant.length > 0) {
41617
+ failures.push(`Missing required lastAssistant substrings: ${missingLastAssistant.join(", ")}`);
41618
+ }
41619
+ const presentBannedLastAssistant = lastAssistantMustNotContainAny.filter((value) => lastAssistant.includes(value));
41620
+ if (presentBannedLastAssistant.length > 0) {
41621
+ failures.push(`Found banned lastAssistant substrings: ${presentBannedLastAssistant.join(", ")}`);
41622
+ }
41623
+ const missingLastAssistantRegex = lastAssistantMustMatchAny.filter((value) => {
41624
+ const regex = compileFixtureRegex(value);
41625
+ return !regex || !regex.test(lastAssistant);
41626
+ });
41627
+ if (missingLastAssistantRegex.length > 0) {
41628
+ failures.push(`Missing required lastAssistant regex matches: ${missingLastAssistantRegex.join(", ")}`);
41629
+ }
41630
+ const presentBannedLastAssistantRegex = lastAssistantMustNotMatchAny.filter((value) => {
41631
+ const regex = compileFixtureRegex(value);
41632
+ return !!regex && regex.test(lastAssistant);
41633
+ });
41634
+ if (presentBannedLastAssistantRegex.length > 0) {
41635
+ failures.push(`Found banned lastAssistant regex matches: ${presentBannedLastAssistantRegex.join(", ")}`);
41636
+ }
41637
+ if (assertions.statusesSeen?.length && !statusesContainSequence(statusesSeen, assertions.statusesSeen)) {
41638
+ failures.push(`Expected statuses sequence not observed: ${assertions.statusesSeen.join(" -> ")}`);
41639
+ }
41640
+ if (result && typeof result === "object") {
41641
+ result.lastAssistant = lastAssistant;
41642
+ }
41643
+ return failures;
41644
+ }
41645
+ function getCliProviderResolutionMeta(ctx, type, adapter) {
41646
+ const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
41647
+ const resolvedProvider = ctx.providerLoader.resolve(type);
41648
+ if (!adapterMeta && !resolvedProvider) return null;
41649
+ return {
41650
+ type,
41651
+ providerDir: adapterMeta?.providerDir || resolvedProvider?._resolvedProviderDir || ctx.providerLoader.findProviderDir(type),
41652
+ scriptDir: adapterMeta?.scriptDir || resolvedProvider?._resolvedScriptDir || null,
41653
+ scriptsPath: adapterMeta?.scriptsPath || resolvedProvider?._resolvedScriptsPath || null,
41654
+ scriptsSource: adapterMeta?.scriptsSource || resolvedProvider?._resolvedScriptsSource || null,
41655
+ resolvedVersion: adapterMeta?.resolvedVersion || resolvedProvider?._resolvedVersion || null,
41656
+ resolvedOs: adapterMeta?.resolvedOs || resolvedProvider?._resolvedOs || null,
41657
+ versionWarning: adapterMeta?.versionWarning || resolvedProvider?._versionWarning || null
41658
+ };
41659
+ }
41054
41660
  function findCliTarget(ctx, type, instanceId) {
41055
41661
  if (!ctx.instanceManager) return null;
41056
41662
  const cliStates = ctx.instanceManager.collectAllStates().filter((s15) => s15.category === "cli" || s15.category === "acp");
@@ -41059,6 +41665,331 @@ function findCliTarget(ctx, type, instanceId) {
41059
41665
  const matches = cliStates.filter((s15) => s15.type === type);
41060
41666
  return matches[matches.length - 1] || null;
41061
41667
  }
41668
+ function getCliTargetBundle(ctx, type, instanceId) {
41669
+ if (!ctx.instanceManager) return null;
41670
+ const target = findCliTarget(ctx, type, instanceId);
41671
+ if (!target) return null;
41672
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
41673
+ if (!instance) return null;
41674
+ const adapter = instance.getAdapter?.() || instance.adapter;
41675
+ if (!adapter) return null;
41676
+ return { target, instance, adapter };
41677
+ }
41678
+ function sleep(ms2) {
41679
+ return new Promise((resolve13) => setTimeout(resolve13, ms2));
41680
+ }
41681
+ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
41682
+ const startedAt = Date.now();
41683
+ while (Date.now() - startedAt < timeoutMs) {
41684
+ const bundle = getCliTargetBundle(ctx, type, instanceId);
41685
+ if (bundle) {
41686
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
41687
+ const startupParseGate = !!debug?.startupParseGate;
41688
+ const adapterReady = !!debug?.ready;
41689
+ const visibleStatusReady = bundle.target.status === "generating" || bundle.target.status === "waiting_approval";
41690
+ const idleReady = bundle.target.status === "idle" && !startupParseGate;
41691
+ if (adapterReady || visibleStatusReady || idleReady) {
41692
+ return bundle;
41693
+ }
41694
+ }
41695
+ await sleep(100);
41696
+ }
41697
+ return getCliTargetBundle(ctx, type, instanceId);
41698
+ }
41699
+ async function runCliExerciseInternal(ctx, body) {
41700
+ if (!ctx.cliManager) {
41701
+ throw new Error("CliManager not available");
41702
+ }
41703
+ if (!ctx.instanceManager) {
41704
+ throw new Error("InstanceManager not available");
41705
+ }
41706
+ const {
41707
+ type,
41708
+ text,
41709
+ instanceId: requestedInstanceId,
41710
+ workingDir,
41711
+ args,
41712
+ autoLaunch = true,
41713
+ freshSession = true,
41714
+ autoResolveApprovals = true,
41715
+ approvalButtonIndex = 0,
41716
+ timeoutMs = 45e3,
41717
+ readyTimeoutMs = 15e3,
41718
+ idleSettledMs = 1200,
41719
+ traceLimit = 160,
41720
+ stopWhenDone = false
41721
+ } = body || {};
41722
+ if (!type) {
41723
+ throw new Error("type required (e.g. claude-cli, codex-cli)");
41724
+ }
41725
+ if (!text || typeof text !== "string") {
41726
+ throw new Error("text required (prompt to send to the CLI)");
41727
+ }
41728
+ let resolvedInstanceId = requestedInstanceId;
41729
+ if (freshSession) {
41730
+ const staleTargets = ctx.instanceManager.collectAllStates().filter((state) => (state.category === "cli" || state.category === "acp") && state.type === type).map((state) => state.instanceId);
41731
+ for (const staleId of staleTargets) {
41732
+ ctx.instanceManager.removeInstance(staleId);
41733
+ }
41734
+ resolvedInstanceId = void 0;
41735
+ }
41736
+ let bundle = getCliTargetBundle(ctx, type, resolvedInstanceId);
41737
+ if (!bundle && autoLaunch) {
41738
+ const launchArgs = [type, workingDir || process.cwd(), Array.isArray(args) ? args : []];
41739
+ let launched = null;
41740
+ let lastLaunchError = null;
41741
+ for (let attempt = 1; attempt <= 2; attempt += 1) {
41742
+ try {
41743
+ launched = await ctx.cliManager.startSession(...launchArgs);
41744
+ lastLaunchError = null;
41745
+ break;
41746
+ } catch (error48) {
41747
+ lastLaunchError = error48 instanceof Error ? error48 : new Error(String(error48?.message || error48));
41748
+ const message = String(lastLaunchError.message || "");
41749
+ const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
41750
+ if (!retryable || attempt === 2) break;
41751
+ await sleep(1e3);
41752
+ }
41753
+ }
41754
+ if (!launched) {
41755
+ throw lastLaunchError || new Error(`Failed to start ${type}`);
41756
+ }
41757
+ resolvedInstanceId = launched.runtimeSessionId;
41758
+ bundle = await waitForCliReady(ctx, type, resolvedInstanceId, Math.max(1e3, readyTimeoutMs));
41759
+ }
41760
+ if (!bundle) {
41761
+ throw new Error(`No running instance found for: ${resolvedInstanceId || type}`);
41762
+ }
41763
+ const initialDebug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
41764
+ const initialTrace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
41765
+ const providerResolution = getCliProviderResolutionMeta(ctx, bundle.target.type, bundle.adapter);
41766
+ const preTraceCount = Number(initialTrace?.entryCount || 0);
41767
+ const startAt = Date.now();
41768
+ const statusesSeen = [];
41769
+ const approvalsResolved = [];
41770
+ let lastStatus = "";
41771
+ let lastModalKey = "";
41772
+ let idleSince = 0;
41773
+ let sawBusy = false;
41774
+ ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
41775
+ while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
41776
+ await sleep(150);
41777
+ bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
41778
+ if (!bundle) {
41779
+ throw new Error("CLI instance disappeared during exercise");
41780
+ }
41781
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
41782
+ const trace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
41783
+ const status = String(debug?.status || bundle.target.status || "unknown");
41784
+ const traceEntries = Array.isArray(trace?.entries) ? trace.entries : [];
41785
+ const sawSendMessage = traceEntries.some((entry) => entry?.type === "send_message");
41786
+ const sawSubmitWrite = traceEntries.some((entry) => entry?.type === "submit_write");
41787
+ const hasTurnStarted = sawSendMessage || sawSubmitWrite || !!debug?.currentTurnScope;
41788
+ if (status !== lastStatus) {
41789
+ statusesSeen.push(status);
41790
+ lastStatus = status;
41791
+ }
41792
+ if (status === "generating" || status === "waiting_approval") {
41793
+ sawBusy = true;
41794
+ idleSince = 0;
41795
+ }
41796
+ const modal = debug?.activeModal || trace?.activeModal || null;
41797
+ if (autoResolveApprovals && status === "waiting_approval" && modal && Array.isArray(modal.buttons) && modal.buttons.length > 0) {
41798
+ const clampedIndex = Math.max(0, Math.min(Number(approvalButtonIndex) || 0, modal.buttons.length - 1));
41799
+ const modalKey = JSON.stringify({
41800
+ message: modal.message || "",
41801
+ buttons: modal.buttons,
41802
+ index: clampedIndex
41803
+ });
41804
+ if (modalKey !== lastModalKey && typeof bundle.adapter.resolveModal === "function") {
41805
+ lastModalKey = modalKey;
41806
+ approvalsResolved.push({
41807
+ at: Date.now(),
41808
+ buttonIndex: clampedIndex,
41809
+ label: modal.buttons[clampedIndex] || null
41810
+ });
41811
+ bundle.adapter.resolveModal(clampedIndex);
41812
+ continue;
41813
+ }
41814
+ }
41815
+ const traceCount = Number(trace?.entryCount || 0);
41816
+ const hasProgress = hasTurnStarted && (traceCount > preTraceCount || statusesSeen.length > 1 || approvalsResolved.length > 0);
41817
+ if (status === "idle" && hasProgress && sawBusy) {
41818
+ if (!idleSince) idleSince = Date.now();
41819
+ if (Date.now() - idleSince >= Math.max(200, idleSettledMs)) {
41820
+ const payload2 = {
41821
+ exercised: true,
41822
+ instanceId: bundle.target.instanceId,
41823
+ providerState: {
41824
+ type: bundle.target.type,
41825
+ name: bundle.target.name,
41826
+ status: bundle.target.status,
41827
+ mode: "mode" in bundle.target ? bundle.target.mode : void 0
41828
+ },
41829
+ providerResolution,
41830
+ initialDebug,
41831
+ initialTrace,
41832
+ debug,
41833
+ trace,
41834
+ statusesSeen,
41835
+ approvalsResolved,
41836
+ elapsedMs: Date.now() - startAt,
41837
+ timedOut: false
41838
+ };
41839
+ payload2.lastAssistant = getExerciseLastAssistant(payload2);
41840
+ payload2.messageCount = getExerciseMessageCount(payload2);
41841
+ if (stopWhenDone) {
41842
+ ctx.instanceManager.removeInstance(bundle.target.instanceId);
41843
+ }
41844
+ return payload2;
41845
+ }
41846
+ } else if (status === "idle" && hasProgress) {
41847
+ if (!idleSince) idleSince = Date.now();
41848
+ if (Date.now() - idleSince >= Math.max(500, idleSettledMs) && Date.now() - startAt >= 750) {
41849
+ const payload2 = {
41850
+ exercised: true,
41851
+ instanceId: bundle.target.instanceId,
41852
+ providerState: {
41853
+ type: bundle.target.type,
41854
+ name: bundle.target.name,
41855
+ status: bundle.target.status,
41856
+ mode: "mode" in bundle.target ? bundle.target.mode : void 0
41857
+ },
41858
+ providerResolution,
41859
+ initialDebug,
41860
+ initialTrace,
41861
+ debug,
41862
+ trace,
41863
+ statusesSeen,
41864
+ approvalsResolved,
41865
+ elapsedMs: Date.now() - startAt,
41866
+ timedOut: false
41867
+ };
41868
+ payload2.lastAssistant = getExerciseLastAssistant(payload2);
41869
+ payload2.messageCount = getExerciseMessageCount(payload2);
41870
+ if (stopWhenDone) {
41871
+ ctx.instanceManager.removeInstance(bundle.target.instanceId);
41872
+ }
41873
+ return payload2;
41874
+ }
41875
+ } else {
41876
+ idleSince = 0;
41877
+ }
41878
+ }
41879
+ const finalBundle = getCliTargetBundle(ctx, type, bundle.target.instanceId) || bundle;
41880
+ const finalDebug = typeof finalBundle.adapter.getDebugState === "function" ? finalBundle.adapter.getDebugState() : null;
41881
+ const finalTrace = typeof finalBundle.adapter.getTraceState === "function" ? finalBundle.adapter.getTraceState(traceLimit) : null;
41882
+ if (stopWhenDone) {
41883
+ ctx.instanceManager.removeInstance(finalBundle.target.instanceId);
41884
+ }
41885
+ const payload = {
41886
+ exercised: true,
41887
+ instanceId: finalBundle.target.instanceId,
41888
+ providerState: {
41889
+ type: finalBundle.target.type,
41890
+ name: finalBundle.target.name,
41891
+ status: finalBundle.target.status,
41892
+ mode: "mode" in finalBundle.target ? finalBundle.target.mode : void 0
41893
+ },
41894
+ providerResolution: getCliProviderResolutionMeta(ctx, finalBundle.target.type, finalBundle.adapter),
41895
+ initialDebug,
41896
+ initialTrace,
41897
+ debug: finalDebug,
41898
+ trace: finalTrace,
41899
+ statusesSeen,
41900
+ approvalsResolved,
41901
+ elapsedMs: Date.now() - startAt,
41902
+ timedOut: true
41903
+ };
41904
+ payload.lastAssistant = getExerciseLastAssistant(payload);
41905
+ payload.messageCount = getExerciseMessageCount(payload);
41906
+ return payload;
41907
+ }
41908
+ async function runCliAutoImplVerification(ctx, type, verification) {
41909
+ const assertions = {
41910
+ mustContainAny: verification?.mustContainAny || [],
41911
+ mustNotContainAny: verification?.mustNotContainAny || [],
41912
+ mustMatchAny: verification?.mustMatchAny || [],
41913
+ mustNotMatchAny: verification?.mustNotMatchAny || [],
41914
+ lastAssistantMustContainAny: verification?.lastAssistantMustContainAny || [],
41915
+ lastAssistantMustNotContainAny: verification?.lastAssistantMustNotContainAny || [],
41916
+ lastAssistantMustMatchAny: verification?.lastAssistantMustMatchAny || [],
41917
+ lastAssistantMustNotMatchAny: verification?.lastAssistantMustNotMatchAny || [],
41918
+ requireNotTimedOut: true
41919
+ };
41920
+ const rawFixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
41921
+ if (rawFixtureNames.length > 0) {
41922
+ const results = [];
41923
+ for (const rawFixtureName2 of rawFixtureNames) {
41924
+ const name = slugifyFixtureName(rawFixtureName2);
41925
+ const fixture = readCliFixture(ctx, type, name);
41926
+ const mergedAssertions = {
41927
+ ...fixture.assertions,
41928
+ ...assertions
41929
+ };
41930
+ const result2 = await runCliExerciseInternal(ctx, {
41931
+ ...fixture.request,
41932
+ type
41933
+ });
41934
+ const failures2 = validateCliFixtureResult(result2, mergedAssertions);
41935
+ results.push({
41936
+ fixtureName: name,
41937
+ pass: failures2.length === 0,
41938
+ failures: failures2,
41939
+ result: result2,
41940
+ assertions: mergedAssertions,
41941
+ fixture
41942
+ });
41943
+ }
41944
+ const firstFailure = results.find((item) => !item.pass) || results[results.length - 1];
41945
+ return {
41946
+ mode: "fixture_replay_suite",
41947
+ pass: results.every((item) => item.pass),
41948
+ failures: results.flatMap((item) => item.failures.map((failure) => `${item.fixtureName}: ${failure}`)),
41949
+ result: firstFailure.result,
41950
+ assertions: firstFailure.assertions,
41951
+ fixture: firstFailure.fixture,
41952
+ results
41953
+ };
41954
+ }
41955
+ const rawFixtureName = String(verification?.fixtureName || "").trim();
41956
+ if (rawFixtureName) {
41957
+ const name = slugifyFixtureName(rawFixtureName);
41958
+ try {
41959
+ const fixture = readCliFixture(ctx, type, name);
41960
+ const mergedAssertions = {
41961
+ ...fixture.assertions,
41962
+ ...assertions
41963
+ };
41964
+ const result2 = await runCliExerciseInternal(ctx, {
41965
+ ...fixture.request,
41966
+ type
41967
+ });
41968
+ const failures2 = validateCliFixtureResult(result2, mergedAssertions);
41969
+ return {
41970
+ mode: "fixture_replay",
41971
+ pass: failures2.length === 0,
41972
+ failures: failures2,
41973
+ result: result2,
41974
+ assertions: mergedAssertions,
41975
+ fixture
41976
+ };
41977
+ } catch {
41978
+ }
41979
+ }
41980
+ const result = await runCliExerciseInternal(ctx, {
41981
+ ...verification?.request || {},
41982
+ type
41983
+ });
41984
+ const failures = validateCliFixtureResult(result, assertions);
41985
+ return {
41986
+ mode: "exercise",
41987
+ pass: failures.length === 0,
41988
+ failures,
41989
+ result,
41990
+ assertions
41991
+ };
41992
+ }
41062
41993
  async function handleCliStatus(ctx, _req, res) {
41063
41994
  if (!ctx.instanceManager) {
41064
41995
  ctx.json(res, 503, { error: "InstanceManager not available (daemon not fully initialized)" });
@@ -41197,12 +42128,14 @@ async function handleCliDebug(ctx, type, _req, res) {
41197
42128
  status: target.status,
41198
42129
  mode: "mode" in target ? target.mode : void 0
41199
42130
  },
42131
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
41200
42132
  debug: debugState
41201
42133
  });
41202
42134
  } else {
41203
42135
  ctx.json(res, 200, {
41204
42136
  instanceId: target.instanceId,
41205
42137
  providerState: target,
42138
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
41206
42139
  debug: null,
41207
42140
  message: "No debug state available (adapter.getDebugState not found)"
41208
42141
  });
@@ -41211,6 +42144,191 @@ async function handleCliDebug(ctx, type, _req, res) {
41211
42144
  ctx.json(res, 500, { error: `Debug state failed: ${e.message}` });
41212
42145
  }
41213
42146
  }
42147
+ async function handleCliTrace(ctx, type, req, res) {
42148
+ if (!ctx.instanceManager) {
42149
+ ctx.json(res, 503, { error: "InstanceManager not available" });
42150
+ return;
42151
+ }
42152
+ const target = findCliTarget(ctx, type);
42153
+ if (!target) {
42154
+ const allStates = ctx.instanceManager.collectAllStates();
42155
+ ctx.json(res, 404, {
42156
+ error: `No running instance for: ${type}`,
42157
+ available: allStates.filter((s15) => s15.category === "cli" || s15.category === "acp").map((s15) => s15.type)
42158
+ });
42159
+ return;
42160
+ }
42161
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
42162
+ if (!instance) {
42163
+ ctx.json(res, 404, { error: `Instance not found: ${target.instanceId}` });
42164
+ return;
42165
+ }
42166
+ try {
42167
+ const adapter = instance.getAdapter?.() || instance.adapter;
42168
+ const url2 = new URL(req.url || "/", "http://127.0.0.1");
42169
+ const limit = parseInt(url2.searchParams.get("limit") || "120", 10);
42170
+ if (adapter && typeof adapter.getTraceState === "function") {
42171
+ const trace = adapter.getTraceState(limit);
42172
+ const debug = typeof adapter.getDebugState === "function" ? adapter.getDebugState() : null;
42173
+ ctx.json(res, 200, {
42174
+ instanceId: target.instanceId,
42175
+ providerState: {
42176
+ type: target.type,
42177
+ name: target.name,
42178
+ status: target.status,
42179
+ mode: "mode" in target ? target.mode : void 0
42180
+ },
42181
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
42182
+ debug,
42183
+ trace
42184
+ });
42185
+ } else {
42186
+ ctx.json(res, 200, {
42187
+ instanceId: target.instanceId,
42188
+ providerState: target,
42189
+ providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
42190
+ debug: typeof adapter?.getDebugState === "function" ? adapter.getDebugState() : null,
42191
+ trace: null,
42192
+ message: "No trace state available (adapter.getTraceState not found)"
42193
+ });
42194
+ }
42195
+ } catch (e) {
42196
+ ctx.json(res, 500, { error: `Trace state failed: ${e.message}` });
42197
+ }
42198
+ }
42199
+ async function handleCliExercise(ctx, req, res) {
42200
+ try {
42201
+ const body = await ctx.readBody(req);
42202
+ const result = await runCliExerciseInternal(ctx, body || {});
42203
+ ctx.json(res, 200, result);
42204
+ } catch (e) {
42205
+ ctx.json(res, 500, { error: `Exercise failed: ${e.message}` });
42206
+ }
42207
+ }
42208
+ async function handleCliFixtureCapture(ctx, req, res) {
42209
+ try {
42210
+ const body = await ctx.readBody(req);
42211
+ const type = String(body?.type || "");
42212
+ const request = body?.request || {};
42213
+ if (!type) {
42214
+ ctx.json(res, 400, { error: "type required" });
42215
+ return;
42216
+ }
42217
+ if (!request?.text) {
42218
+ ctx.json(res, 400, { error: "request.text required" });
42219
+ return;
42220
+ }
42221
+ const fixtureDir = getCliFixtureDir(ctx, type);
42222
+ fs12.mkdirSync(fixtureDir, { recursive: true });
42223
+ const name = slugifyFixtureName(String(body?.name || `${type}-${Date.now()}`));
42224
+ const result = await runCliExerciseInternal(ctx, { ...request, type });
42225
+ const fixture = {
42226
+ version: 1,
42227
+ kind: "cli-exercise-fixture",
42228
+ name,
42229
+ type,
42230
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
42231
+ providerDir: ctx.providerLoader.findProviderDir(type),
42232
+ providerResolution: result?.providerResolution || null,
42233
+ request: { ...request, type },
42234
+ result,
42235
+ assertions: {
42236
+ mustContainAny: Array.isArray(body?.assertions?.mustContainAny) ? body.assertions.mustContainAny : [],
42237
+ mustNotContainAny: Array.isArray(body?.assertions?.mustNotContainAny) ? body.assertions.mustNotContainAny : [],
42238
+ mustMatchAny: Array.isArray(body?.assertions?.mustMatchAny) ? body.assertions.mustMatchAny : [],
42239
+ mustNotMatchAny: Array.isArray(body?.assertions?.mustNotMatchAny) ? body.assertions.mustNotMatchAny : [],
42240
+ lastAssistantMustContainAny: Array.isArray(body?.assertions?.lastAssistantMustContainAny) ? body.assertions.lastAssistantMustContainAny : [],
42241
+ lastAssistantMustNotContainAny: Array.isArray(body?.assertions?.lastAssistantMustNotContainAny) ? body.assertions.lastAssistantMustNotContainAny : [],
42242
+ lastAssistantMustMatchAny: Array.isArray(body?.assertions?.lastAssistantMustMatchAny) ? body.assertions.lastAssistantMustMatchAny : [],
42243
+ lastAssistantMustNotMatchAny: Array.isArray(body?.assertions?.lastAssistantMustNotMatchAny) ? body.assertions.lastAssistantMustNotMatchAny : [],
42244
+ statusesSeen: Array.isArray(body?.assertions?.statusesSeen) ? body.assertions.statusesSeen : void 0,
42245
+ requireNotTimedOut: body?.assertions?.requireNotTimedOut !== false
42246
+ },
42247
+ notes: typeof body?.notes === "string" ? body.notes : void 0
42248
+ };
42249
+ const filePath = path15.join(fixtureDir, `${name}.json`);
42250
+ fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
42251
+ ctx.json(res, 200, {
42252
+ saved: true,
42253
+ name,
42254
+ path: filePath,
42255
+ fixture,
42256
+ verification: {
42257
+ pass: validateCliFixtureResult(result, fixture.assertions).length === 0,
42258
+ failures: validateCliFixtureResult(result, fixture.assertions)
42259
+ }
42260
+ });
42261
+ } catch (e) {
42262
+ ctx.json(res, 500, { error: `Fixture capture failed: ${e.message}` });
42263
+ }
42264
+ }
42265
+ async function handleCliFixtureList(ctx, type, _req, res) {
42266
+ try {
42267
+ const fixtureDir = getCliFixtureDir(ctx, type);
42268
+ if (!fs12.existsSync(fixtureDir)) {
42269
+ ctx.json(res, 200, { fixtures: [], count: 0 });
42270
+ return;
42271
+ }
42272
+ const fixtures = fs12.readdirSync(fixtureDir).filter((file2) => file2.endsWith(".json")).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file2) => {
42273
+ const fullPath = path15.join(fixtureDir, file2);
42274
+ try {
42275
+ const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
42276
+ return {
42277
+ name: raw.name || file2.replace(/\.json$/i, ""),
42278
+ path: fullPath,
42279
+ createdAt: raw.createdAt || null,
42280
+ notes: raw.notes || null,
42281
+ requestText: raw.request?.text || "",
42282
+ assertions: raw.assertions || {}
42283
+ };
42284
+ } catch {
42285
+ return {
42286
+ name: file2.replace(/\.json$/i, ""),
42287
+ path: fullPath,
42288
+ createdAt: null,
42289
+ notes: "Unreadable fixture",
42290
+ requestText: "",
42291
+ assertions: {}
42292
+ };
42293
+ }
42294
+ });
42295
+ ctx.json(res, 200, { fixtures, count: fixtures.length });
42296
+ } catch (e) {
42297
+ ctx.json(res, 500, { error: `Fixture list failed: ${e.message}` });
42298
+ }
42299
+ }
42300
+ async function handleCliFixtureReplay(ctx, req, res) {
42301
+ try {
42302
+ const body = await ctx.readBody(req);
42303
+ const type = String(body?.type || "");
42304
+ const rawName = String(body?.name || "").trim();
42305
+ if (!type || !rawName) {
42306
+ ctx.json(res, 400, { error: "type and name required" });
42307
+ return;
42308
+ }
42309
+ const name = slugifyFixtureName(rawName);
42310
+ const fixture = readCliFixture(ctx, type, name);
42311
+ const result = await runCliExerciseInternal(ctx, {
42312
+ ...fixture.request,
42313
+ type
42314
+ });
42315
+ const assertions = {
42316
+ ...fixture.assertions,
42317
+ ...body?.assertions || {}
42318
+ };
42319
+ const failures = validateCliFixtureResult(result, assertions);
42320
+ ctx.json(res, 200, {
42321
+ replayed: true,
42322
+ pass: failures.length === 0,
42323
+ failures,
42324
+ fixture,
42325
+ result,
42326
+ assertions
42327
+ });
42328
+ } catch (e) {
42329
+ ctx.json(res, 500, { error: `Fixture replay failed: ${e.message}` });
42330
+ }
42331
+ }
41214
42332
  async function handleCliResolve(ctx, req, res) {
41215
42333
  const body = await ctx.readBody(req);
41216
42334
  const { type, buttonIndex, instanceId } = body;
@@ -41285,13 +42403,36 @@ async function handleCliRaw(ctx, req, res) {
41285
42403
  ctx.json(res, 500, { error: `Raw send failed: ${e.message}` });
41286
42404
  }
41287
42405
  }
42406
+ var fs12, path15;
41288
42407
  var init_dev_cli_debug = __esm({
41289
42408
  "../../oss/packages/daemon-core/src/daemon/dev-cli-debug.ts"() {
41290
42409
  "use strict";
42410
+ fs12 = __toESM(require("fs"));
42411
+ path15 = __toESM(require("path"));
41291
42412
  }
41292
42413
  });
41293
42414
 
41294
42415
  // ../../oss/packages/daemon-core/src/daemon/dev-auto-implement.ts
42416
+ function getAutoImplPid(ctx) {
42417
+ const proc = ctx.autoImplProcess;
42418
+ return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
42419
+ }
42420
+ function isPidAlive(pid) {
42421
+ try {
42422
+ process.kill(pid, 0);
42423
+ return true;
42424
+ } catch (error48) {
42425
+ return error48?.code === "EPERM";
42426
+ }
42427
+ }
42428
+ function clearStaleAutoImplState(ctx, reason) {
42429
+ if (!ctx.autoImplStatus.running && !ctx.autoImplProcess) return;
42430
+ const pid = getAutoImplPid(ctx);
42431
+ if (pid && isPidAlive(pid)) return;
42432
+ ctx.log(`Clearing stale auto-implement state: ${reason}${pid ? ` (pid ${pid})` : ""}`);
42433
+ ctx.autoImplProcess = null;
42434
+ ctx.autoImplStatus.running = false;
42435
+ }
41295
42436
  function getDefaultAutoImplReference(ctx, category, type) {
41296
42437
  if (category === "cli") {
41297
42438
  return type === "codex-cli" ? "claude-cli" : "codex-cli";
@@ -41307,45 +42448,45 @@ function resolveAutoImplReference(ctx, category, requestedReference, targetType)
41307
42448
  return fallback?.type || null;
41308
42449
  }
41309
42450
  function getLatestScriptVersionDir(scriptsDir) {
41310
- if (!fs12.existsSync(scriptsDir)) return null;
41311
- const versions = fs12.readdirSync(scriptsDir).filter((d) => {
42451
+ if (!fs13.existsSync(scriptsDir)) return null;
42452
+ const versions = fs13.readdirSync(scriptsDir).filter((d) => {
41312
42453
  try {
41313
- return fs12.statSync(path15.join(scriptsDir, d)).isDirectory();
42454
+ return fs13.statSync(path16.join(scriptsDir, d)).isDirectory();
41314
42455
  } catch {
41315
42456
  return false;
41316
42457
  }
41317
42458
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
41318
42459
  if (versions.length === 0) return null;
41319
- return path15.join(scriptsDir, versions[0]);
42460
+ return path16.join(scriptsDir, versions[0]);
41320
42461
  }
41321
42462
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
41322
- const canonicalUserDir = path15.resolve(ctx.providerLoader.getUserProviderDir(category, type));
41323
- const desiredDir = requestedDir ? path15.resolve(requestedDir) : canonicalUserDir;
41324
- const upstreamRoot = path15.resolve(ctx.providerLoader.getUpstreamDir());
41325
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path15.sep}`)) {
42463
+ const canonicalUserDir = path16.resolve(ctx.providerLoader.getUserProviderDir(category, type));
42464
+ const desiredDir = requestedDir ? path16.resolve(requestedDir) : canonicalUserDir;
42465
+ const upstreamRoot = path16.resolve(ctx.providerLoader.getUpstreamDir());
42466
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path16.sep}`)) {
41326
42467
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
41327
42468
  }
41328
- if (path15.basename(desiredDir) !== type) {
42469
+ if (path16.basename(desiredDir) !== type) {
41329
42470
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
41330
42471
  }
41331
42472
  const sourceDir = ctx.findProviderDir(type);
41332
42473
  if (!sourceDir) {
41333
42474
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
41334
42475
  }
41335
- if (!fs12.existsSync(desiredDir)) {
41336
- fs12.mkdirSync(path15.dirname(desiredDir), { recursive: true });
41337
- fs12.cpSync(sourceDir, desiredDir, { recursive: true });
42476
+ if (!fs13.existsSync(desiredDir)) {
42477
+ fs13.mkdirSync(path16.dirname(desiredDir), { recursive: true });
42478
+ fs13.cpSync(sourceDir, desiredDir, { recursive: true });
41338
42479
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
41339
42480
  }
41340
- const providerJson = path15.join(desiredDir, "provider.json");
41341
- if (!fs12.existsSync(providerJson)) {
42481
+ const providerJson = path16.join(desiredDir, "provider.json");
42482
+ if (!fs13.existsSync(providerJson)) {
41342
42483
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
41343
42484
  }
41344
42485
  try {
41345
- const providerData = JSON.parse(fs12.readFileSync(providerJson, "utf-8"));
42486
+ const providerData = JSON.parse(fs13.readFileSync(providerJson, "utf-8"));
41346
42487
  if (providerData.disableUpstream !== true) {
41347
42488
  providerData.disableUpstream = true;
41348
- fs12.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
42489
+ fs13.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
41349
42490
  }
41350
42491
  } catch (error48) {
41351
42492
  return {
@@ -41358,15 +42499,15 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
41358
42499
  function loadAutoImplReferenceScripts(ctx, referenceType) {
41359
42500
  if (!referenceType) return {};
41360
42501
  const refDir = ctx.findProviderDir(referenceType);
41361
- if (!refDir || !fs12.existsSync(refDir)) return {};
42502
+ if (!refDir || !fs13.existsSync(refDir)) return {};
41362
42503
  const referenceScripts = {};
41363
- const scriptsDir = path15.join(refDir, "scripts");
42504
+ const scriptsDir = path16.join(refDir, "scripts");
41364
42505
  const latestDir = getLatestScriptVersionDir(scriptsDir);
41365
42506
  if (!latestDir) return referenceScripts;
41366
- for (const file2 of fs12.readdirSync(latestDir)) {
42507
+ for (const file2 of fs13.readdirSync(latestDir)) {
41367
42508
  if (!file2.endsWith(".js")) continue;
41368
42509
  try {
41369
- referenceScripts[file2] = fs12.readFileSync(path15.join(latestDir, file2), "utf-8");
42510
+ referenceScripts[file2] = fs13.readFileSync(path16.join(latestDir, file2), "utf-8");
41370
42511
  } catch {
41371
42512
  }
41372
42513
  }
@@ -41374,11 +42515,20 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
41374
42515
  }
41375
42516
  async function handleAutoImplement(ctx, type, req, res) {
41376
42517
  const body = await ctx.readBody(req);
41377
- const { agent = "claude-cli", functions, reference, model, comment, providerDir: requestedProviderDir } = body;
42518
+ const {
42519
+ agent = "claude-cli",
42520
+ functions,
42521
+ reference,
42522
+ model,
42523
+ comment,
42524
+ providerDir: requestedProviderDir,
42525
+ verification
42526
+ } = body;
41378
42527
  if (!functions || !Array.isArray(functions) || functions.length === 0) {
41379
42528
  ctx.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
41380
42529
  return;
41381
42530
  }
42531
+ clearStaleAutoImplState(ctx, "new auto-implement request");
41382
42532
  if (ctx.autoImplStatus.running) {
41383
42533
  ctx.json(res, 409, { error: "Auto-implement already in progress", type: ctx.autoImplStatus.type });
41384
42534
  return;
@@ -41396,7 +42546,55 @@ async function handleAutoImplement(ctx, type, req, res) {
41396
42546
  return;
41397
42547
  }
41398
42548
  const providerDir = writableProvider.dir;
42549
+ ctx.autoImplStatus = { running: false, type, progress: [] };
42550
+ if (provider.category === "cli" && verification && (verification.fixtureName || verification.fixtureNames && verification.fixtureNames.length > 0)) {
42551
+ sendAutoImplSSE(ctx, {
42552
+ event: "progress",
42553
+ data: {
42554
+ function: "_preflight",
42555
+ status: "verifying",
42556
+ message: "Running preflight verification before spawning agent..."
42557
+ }
42558
+ });
42559
+ try {
42560
+ const preflight = await runCliAutoImplVerification(ctx, type, verification);
42561
+ sendAutoImplSSE(ctx, { event: "verification", data: preflight });
42562
+ if (preflight.pass) {
42563
+ sendAutoImplSSE(ctx, {
42564
+ event: "complete",
42565
+ data: {
42566
+ success: true,
42567
+ exitCode: 0,
42568
+ functions,
42569
+ message: `\u2705 No-op: exact ${preflight.mode} already passes`,
42570
+ verification: preflight,
42571
+ skipped: true
42572
+ }
42573
+ });
42574
+ ctx.json(res, 200, {
42575
+ started: false,
42576
+ skipped: true,
42577
+ type,
42578
+ functions,
42579
+ providerDir,
42580
+ verification: preflight,
42581
+ message: "Preflight verification already passes. No auto-implement run needed."
42582
+ });
42583
+ return;
42584
+ }
42585
+ } catch (error48) {
42586
+ sendAutoImplSSE(ctx, {
42587
+ event: "progress",
42588
+ data: {
42589
+ function: "_preflight",
42590
+ status: "verify_failed",
42591
+ message: `Preflight verification errored, continuing to agent run: ${error48?.message || error48}`
42592
+ }
42593
+ });
42594
+ }
42595
+ }
41399
42596
  try {
42597
+ ctx.autoImplStatus = { running: true, type, progress: ctx.autoImplStatus.progress };
41400
42598
  const resolvedReference = resolveAutoImplReference(ctx, provider.category, reference, type);
41401
42599
  sendAutoImplSSE(ctx, {
41402
42600
  event: "progress",
@@ -41416,17 +42614,17 @@ async function handleAutoImplement(ctx, type, req, res) {
41416
42614
  }
41417
42615
  });
41418
42616
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
41419
- const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
41420
- const tmpDir = path15.join(os17.tmpdir(), "adhdev-autoimpl");
41421
- if (!fs12.existsSync(tmpDir)) fs12.mkdirSync(tmpDir, { recursive: true });
41422
- const promptFile = path15.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
41423
- fs12.writeFileSync(promptFile, prompt, "utf-8");
42617
+ const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
42618
+ const tmpDir = path16.join(os17.tmpdir(), "adhdev-autoimpl");
42619
+ if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
42620
+ const promptFile = path16.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
42621
+ fs13.writeFileSync(promptFile, prompt, "utf-8");
41424
42622
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
41425
42623
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
41426
42624
  const spawn5 = agentProvider?.spawn;
41427
42625
  if (!spawn5?.command) {
41428
42626
  try {
41429
- fs12.unlinkSync(promptFile);
42627
+ fs13.unlinkSync(promptFile);
41430
42628
  } catch {
41431
42629
  }
41432
42630
  ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
@@ -41435,7 +42633,8 @@ async function handleAutoImplement(ctx, type, req, res) {
41435
42633
  const agentCategory = agentProvider?.category;
41436
42634
  if (agentCategory === "acp") {
41437
42635
  sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${spawn5.command} ${(spawn5.args || []).join(" ")}` } });
41438
- ctx.autoImplStatus = { running: true, type, progress: [] };
42636
+ ctx.autoImplStatus.running = true;
42637
+ ctx.autoImplStatus.type = type;
41439
42638
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
41440
42639
  const { Readable: Readable3, Writable: Writable2 } = await import("stream");
41441
42640
  const { spawn: spawnFn2 } = await import("child_process");
@@ -41527,7 +42726,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41527
42726
  } catch {
41528
42727
  }
41529
42728
  try {
41530
- fs12.unlinkSync(promptFile);
42729
+ fs13.unlinkSync(promptFile);
41531
42730
  } catch {
41532
42731
  }
41533
42732
  ctx.log(`Auto-implement (ACP) ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
@@ -41605,7 +42804,8 @@ async function handleAutoImplement(ctx, type, req, res) {
41605
42804
  }
41606
42805
  }
41607
42806
  sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning agent: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
41608
- ctx.autoImplStatus = { running: true, type, progress: [] };
42807
+ ctx.autoImplStatus.running = true;
42808
+ ctx.autoImplStatus.type = type;
41609
42809
  const spawnedAt = Date.now();
41610
42810
  let child;
41611
42811
  let isPty = false;
@@ -41648,6 +42848,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41648
42848
  let approvalKeys = { 0: "y\r" };
41649
42849
  let approvalBuffer = "";
41650
42850
  let lastApprovalTime = 0;
42851
+ let completionSignalSeen = false;
41651
42852
  try {
41652
42853
  const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
41653
42854
  const normalized = normalizeCliProviderForRuntime2(agentProvider);
@@ -41661,6 +42862,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41661
42862
  approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
41662
42863
  const elapsed = Date.now() - spawnedAt;
41663
42864
  if (elapsed > 15e3 && cleanData.includes("_PIPELINE_COMPLETE_SIGNAL_")) {
42865
+ completionSignalSeen = true;
41664
42866
  ctx.log(`Agent finished task after ${Math.round(elapsed / 1e3)}s. Terminating interactive CLI session to unblock pipeline.`);
41665
42867
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: `
41666
42868
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
@@ -41684,6 +42886,55 @@ async function handleAutoImplement(ctx, type, req, res) {
41684
42886
  lastApprovalTime = Date.now();
41685
42887
  }
41686
42888
  };
42889
+ const finalizeCliAutoImpl = async (code) => {
42890
+ ctx.autoImplProcess = null;
42891
+ let success2 = completionSignalSeen || code === 0;
42892
+ let message = success2 ? completionSignalSeen && code !== 0 ? "\u2705 Auto-implement complete (completion signal)" : "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`;
42893
+ let verificationSummary = null;
42894
+ try {
42895
+ ctx.providerLoader.reload();
42896
+ } catch {
42897
+ }
42898
+ if (provider.category === "cli" && verification) {
42899
+ sendAutoImplSSE(ctx, {
42900
+ event: "progress",
42901
+ data: {
42902
+ function: "_verify",
42903
+ status: "running",
42904
+ message: "Running exact post-patch verification..."
42905
+ }
42906
+ });
42907
+ try {
42908
+ verificationSummary = await runCliAutoImplVerification(ctx, type, verification);
42909
+ sendAutoImplSSE(ctx, { event: "verification", data: verificationSummary });
42910
+ success2 = verificationSummary.pass;
42911
+ message = verificationSummary.pass ? `\u2705 Auto-implement complete (${verificationSummary.mode})` : `\u274C Post-patch verification failed (${verificationSummary.mode}): ${verificationSummary.failures.join("; ") || "unknown failure"}`;
42912
+ } catch (error48) {
42913
+ success2 = false;
42914
+ message = `\u274C Post-patch verification error: ${error48?.message || error48}`;
42915
+ sendAutoImplSSE(ctx, {
42916
+ event: "verification",
42917
+ data: { pass: false, error: error48?.message || String(error48) }
42918
+ });
42919
+ }
42920
+ }
42921
+ ctx.autoImplStatus.running = false;
42922
+ sendAutoImplSSE(ctx, {
42923
+ event: "complete",
42924
+ data: {
42925
+ success: success2,
42926
+ exitCode: code,
42927
+ functions,
42928
+ message,
42929
+ verification: verificationSummary
42930
+ }
42931
+ });
42932
+ try {
42933
+ fs13.unlinkSync(promptFile);
42934
+ } catch {
42935
+ }
42936
+ ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})${verificationSummary ? ` verify=${verificationSummary.pass ? "pass" : "fail"}` : ""}`);
42937
+ };
41687
42938
  if (isPty) {
41688
42939
  child.onData((data) => {
41689
42940
  stdout += data;
@@ -41695,21 +42946,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41695
42946
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
41696
42947
  });
41697
42948
  child.onExit(({ exitCode: code }) => {
41698
- ctx.autoImplProcess = null;
41699
- ctx.autoImplStatus.running = false;
41700
- const success2 = code === 0;
41701
- sendAutoImplSSE(ctx, {
41702
- event: "complete",
41703
- data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})` }
41704
- });
41705
- try {
41706
- ctx.providerLoader.reload();
41707
- } catch {
41708
- }
41709
- try {
41710
- fs12.unlinkSync(promptFile);
41711
- } catch {
41712
- }
42949
+ void finalizeCliAutoImpl(code);
41713
42950
  });
41714
42951
  } else {
41715
42952
  child.stdout?.on("data", (d) => {
@@ -41726,27 +42963,7 @@ async function handleAutoImplement(ctx, type, req, res) {
41726
42963
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
41727
42964
  });
41728
42965
  child.on("exit", (code) => {
41729
- ctx.autoImplProcess = null;
41730
- ctx.autoImplStatus.running = false;
41731
- const success2 = code === 0;
41732
- sendAutoImplSSE(ctx, {
41733
- event: "complete",
41734
- data: {
41735
- success: success2,
41736
- exitCode: code,
41737
- functions,
41738
- message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`
41739
- }
41740
- });
41741
- try {
41742
- ctx.providerLoader.reload();
41743
- } catch {
41744
- }
41745
- try {
41746
- fs12.unlinkSync(promptFile);
41747
- } catch {
41748
- }
41749
- ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
42966
+ void finalizeCliAutoImpl(code);
41750
42967
  });
41751
42968
  }
41752
42969
  ctx.json(res, 202, {
@@ -41763,9 +42980,9 @@ async function handleAutoImplement(ctx, type, req, res) {
41763
42980
  ctx.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
41764
42981
  }
41765
42982
  }
41766
- function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType) {
42983
+ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType, verification) {
41767
42984
  if (provider.category === "cli") {
41768
- return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
42985
+ return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification);
41769
42986
  }
41770
42987
  const lines = [];
41771
42988
  lines.push("You are implementing browser automation scripts for an IDE provider.");
@@ -41790,7 +43007,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
41790
43007
  setMode: "set_mode.js"
41791
43008
  };
41792
43009
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
41793
- const scriptsDir = path15.join(providerDir, "scripts");
43010
+ const scriptsDir = path16.join(providerDir, "scripts");
41794
43011
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
41795
43012
  if (latestScriptsDir) {
41796
43013
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -41798,10 +43015,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
41798
43015
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
41799
43016
  lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
41800
43017
  lines.push("");
41801
- for (const file2 of fs12.readdirSync(latestScriptsDir)) {
43018
+ for (const file2 of fs13.readdirSync(latestScriptsDir)) {
41802
43019
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
41803
43020
  try {
41804
- const content = fs12.readFileSync(path15.join(latestScriptsDir, file2), "utf-8");
43021
+ const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
41805
43022
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
41806
43023
  lines.push("```javascript");
41807
43024
  lines.push(content);
@@ -41811,14 +43028,14 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
41811
43028
  }
41812
43029
  }
41813
43030
  }
41814
- const refFiles = fs12.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43031
+ const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
41815
43032
  if (refFiles.length > 0) {
41816
43033
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
41817
43034
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
41818
43035
  lines.push("");
41819
43036
  for (const file2 of refFiles) {
41820
43037
  try {
41821
- const content = fs12.readFileSync(path15.join(latestScriptsDir, file2), "utf-8");
43038
+ const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
41822
43039
  lines.push(`### \`${file2}\` \u{1F512}`);
41823
43040
  lines.push("```javascript");
41824
43041
  lines.push(content);
@@ -41859,11 +43076,11 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
41859
43076
  lines.push("");
41860
43077
  }
41861
43078
  }
41862
- const docsDir = path15.join(providerDir, "../../docs");
43079
+ const docsDir = path16.join(providerDir, "../../docs");
41863
43080
  const loadGuide = (name) => {
41864
43081
  try {
41865
- const p = path15.join(docsDir, name);
41866
- if (fs12.existsSync(p)) return fs12.readFileSync(p, "utf-8");
43082
+ const p = path16.join(docsDir, name);
43083
+ if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
41867
43084
  } catch {
41868
43085
  }
41869
43086
  return null;
@@ -42021,8 +43238,69 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
42021
43238
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
42022
43239
  return lines.join("\n");
42023
43240
  }
42024
- function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType) {
43241
+ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification) {
42025
43242
  const lines = [];
43243
+ const defaultExercisePayload = {
43244
+ type,
43245
+ workingDir: providerDir,
43246
+ freshSession: true,
43247
+ autoLaunch: true,
43248
+ autoResolveApprovals: true,
43249
+ approvalButtonIndex: 0,
43250
+ timeoutMs: 45e3,
43251
+ traceLimit: 200,
43252
+ 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."
43253
+ };
43254
+ const exercisePayload = {
43255
+ ...defaultExercisePayload,
43256
+ ...verification?.request || {},
43257
+ type,
43258
+ workingDir: providerDir
43259
+ };
43260
+ const exerciseJson = JSON.stringify(exercisePayload).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43261
+ const verificationInspectFields = verification?.inspectFields?.length ? verification.inspectFields : [
43262
+ "debug.messages",
43263
+ "trace.entries[].payload.parsedLastAssistant",
43264
+ "trace.entries[].payload.lastAssistant"
43265
+ ];
43266
+ const verificationMustContainAny = verification?.mustContainAny || [];
43267
+ const verificationMustNotContainAny = verification?.mustNotContainAny || [];
43268
+ const verificationMustMatchAny = verification?.mustMatchAny || [];
43269
+ const verificationMustNotMatchAny = verification?.mustNotMatchAny || [];
43270
+ const verificationLastAssistantMustContainAny = verification?.lastAssistantMustContainAny || [];
43271
+ const verificationLastAssistantMustNotContainAny = verification?.lastAssistantMustNotContainAny || [];
43272
+ const verificationLastAssistantMustMatchAny = verification?.lastAssistantMustMatchAny || [];
43273
+ const verificationLastAssistantMustNotMatchAny = verification?.lastAssistantMustNotMatchAny || [];
43274
+ const quotedMustContain = verificationMustContainAny.map((value) => JSON.stringify(value)).join(", ");
43275
+ const quotedMustNotContain = verificationMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
43276
+ const quotedMustMatch = verificationMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
43277
+ const quotedMustNotMatch = verificationMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
43278
+ const quotedLastAssistantMustContain = verificationLastAssistantMustContainAny.map((value) => JSON.stringify(value)).join(", ");
43279
+ const quotedLastAssistantMustNotContain = verificationLastAssistantMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
43280
+ const quotedLastAssistantMustMatch = verificationLastAssistantMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
43281
+ const quotedLastAssistantMustNotMatch = verificationLastAssistantMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
43282
+ const fixtureName = verification?.fixtureName || `${type}-provider-fix`;
43283
+ const fixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
43284
+ const fixtureCaptureJson = JSON.stringify({
43285
+ type,
43286
+ name: fixtureName,
43287
+ request: exercisePayload,
43288
+ assertions: {
43289
+ mustContainAny: verificationMustContainAny,
43290
+ mustNotContainAny: verificationMustNotContainAny,
43291
+ mustMatchAny: verificationMustMatchAny,
43292
+ mustNotMatchAny: verificationMustNotMatchAny,
43293
+ lastAssistantMustContainAny: verificationLastAssistantMustContainAny,
43294
+ lastAssistantMustNotContainAny: verificationLastAssistantMustNotContainAny,
43295
+ lastAssistantMustMatchAny: verificationLastAssistantMustMatchAny,
43296
+ lastAssistantMustNotMatchAny: verificationLastAssistantMustNotMatchAny,
43297
+ requireNotTimedOut: true
43298
+ }
43299
+ }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43300
+ const fixtureReplayJson = JSON.stringify({
43301
+ type,
43302
+ name: fixtureName
43303
+ }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
42026
43304
  lines.push("You are implementing PTY parsing scripts for a CLI provider.");
42027
43305
  lines.push("Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.");
42028
43306
  lines.push("");
@@ -42036,7 +43314,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42036
43314
  parseApproval: "parse_approval.js"
42037
43315
  };
42038
43316
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
42039
- const scriptsDir = path15.join(providerDir, "scripts");
43317
+ const scriptsDir = path16.join(providerDir, "scripts");
42040
43318
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
42041
43319
  if (latestScriptsDir) {
42042
43320
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -42044,11 +43322,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42044
43322
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
42045
43323
  lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
42046
43324
  lines.push("");
42047
- for (const file2 of fs12.readdirSync(latestScriptsDir)) {
43325
+ for (const file2 of fs13.readdirSync(latestScriptsDir)) {
42048
43326
  if (!file2.endsWith(".js")) continue;
42049
43327
  if (!targetFileNames.has(file2)) continue;
42050
43328
  try {
42051
- const content = fs12.readFileSync(path15.join(latestScriptsDir, file2), "utf-8");
43329
+ const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
42052
43330
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
42053
43331
  lines.push("```javascript");
42054
43332
  lines.push(content);
@@ -42057,14 +43335,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42057
43335
  } catch {
42058
43336
  }
42059
43337
  }
42060
- const refFiles = fs12.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43338
+ const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
42061
43339
  if (refFiles.length > 0) {
42062
43340
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
42063
43341
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
42064
43342
  lines.push("");
42065
43343
  for (const file2 of refFiles) {
42066
43344
  try {
42067
- const content = fs12.readFileSync(path15.join(latestScriptsDir, file2), "utf-8");
43345
+ const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
42068
43346
  lines.push(`### \`${file2}\` \u{1F512}`);
42069
43347
  lines.push("```javascript");
42070
43348
  lines.push(content);
@@ -42097,17 +43375,17 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42097
43375
  lines.push("");
42098
43376
  }
42099
43377
  }
42100
- const docsDir = path15.join(providerDir, "../../docs");
43378
+ const docsDir = path16.join(providerDir, "../../docs");
42101
43379
  const loadGuide = (name) => {
42102
43380
  try {
42103
- const p = path15.join(docsDir, name);
42104
- if (fs12.existsSync(p)) return fs12.readFileSync(p, "utf-8");
43381
+ const p = path16.join(docsDir, name);
43382
+ if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
42105
43383
  } catch {
42106
43384
  }
42107
43385
  return null;
42108
43386
  };
42109
43387
  const providerGuide = loadGuide("PROVIDER_GUIDE.md");
42110
- if (providerGuide) {
43388
+ if (providerGuide && provider.category !== "cli") {
42111
43389
  lines.push("## Documentation: PROVIDER_GUIDE.md");
42112
43390
  lines.push("```markdown");
42113
43391
  lines.push(providerGuide);
@@ -42149,6 +43427,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42149
43427
  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.");
42150
43428
  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.");
42151
43429
  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.");
43430
+ 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.');
43431
+ 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.");
43432
+ 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.');
43433
+ 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.");
43434
+ 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.");
42152
43435
  lines.push("");
42153
43436
  lines.push("## Task");
42154
43437
  lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
@@ -42156,35 +43439,145 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42156
43439
  lines.push("## Verification API");
42157
43440
  lines.push("Use the DevServer CLI debug endpoints, not DOM/CDP routes.");
42158
43441
  lines.push("");
42159
- lines.push("### 1. Launch the target CLI");
43442
+ lines.push("### 1. Preferred: run a full autonomous repro");
43443
+ 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.");
42160
43444
  lines.push("```bash");
42161
- lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
43445
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
42162
43446
  lines.push(' -H "Content-Type: application/json" \\');
42163
- lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
43447
+ lines.push(` -d '${exerciseJson}'`);
42164
43448
  lines.push("```");
42165
43449
  lines.push("");
43450
+ if (verification?.description) {
43451
+ lines.push("Verification intent:");
43452
+ lines.push(verification.description);
43453
+ lines.push("");
43454
+ }
43455
+ lines.push("Read the JSON response carefully. It already includes:");
43456
+ lines.push("1. `instanceId`");
43457
+ lines.push("2. `statusesSeen` and `approvalsResolved`");
43458
+ lines.push("3. `debug` for the final settled state");
43459
+ lines.push("4. `trace.entries` for the repro turn");
43460
+ lines.push("");
43461
+ lines.push("Save the response to a temp file and inspect the exact parsed transcript fields before editing:");
43462
+ lines.push("```bash");
43463
+ lines.push(`EXERCISE_JSON=$(mktemp)`);
43464
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
43465
+ lines.push(' -H "Content-Type: application/json" \\');
43466
+ lines.push(` -d '${exerciseJson}' > "$EXERCISE_JSON"`);
43467
+ lines.push(`jq '{timedOut,statusesSeen,approvalsResolved,inspect:{${verificationInspectFields.map((field, index) => `f${index + 1}: .${field}`).join(", ")}}}' "$EXERCISE_JSON"`);
43468
+ lines.push("```");
43469
+ lines.push("");
43470
+ 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) {
43471
+ 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.");
43472
+ lines.push("```bash");
43473
+ if (verificationMustContainAny.length > 0) {
43474
+ 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"`);
43475
+ }
43476
+ if (verificationMustNotContainAny.length > 0) {
43477
+ 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"`);
43478
+ }
43479
+ if (verificationMustMatchAny.length > 0) {
43480
+ 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"`);
43481
+ }
43482
+ if (verificationMustNotMatchAny.length > 0) {
43483
+ 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"`);
43484
+ }
43485
+ if (verificationLastAssistantMustContainAny.length > 0) {
43486
+ 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"`);
43487
+ }
43488
+ if (verificationLastAssistantMustNotContainAny.length > 0) {
43489
+ 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"`);
43490
+ }
43491
+ if (verificationLastAssistantMustMatchAny.length > 0) {
43492
+ 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"`);
43493
+ }
43494
+ if (verificationLastAssistantMustNotMatchAny.length > 0) {
43495
+ 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"`);
43496
+ }
43497
+ lines.push("```");
43498
+ lines.push("");
43499
+ }
43500
+ 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.");
43501
+ lines.push("");
43502
+ lines.push("### 1b. Persist or replay the exact repro as a reusable fixture");
43503
+ if (fixtureNames.length > 0) {
43504
+ 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(", ")}.`);
43505
+ for (const name of fixtureNames) {
43506
+ const replayJson = JSON.stringify({ type, name }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
43507
+ lines.push("```bash");
43508
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43509
+ lines.push(' -H "Content-Type: application/json" \\');
43510
+ lines.push(` -d '${replayJson}'`);
43511
+ lines.push("```");
43512
+ lines.push("");
43513
+ }
43514
+ lines.push("Do not create new fixtures unless one of the listed fixtures is missing or stale.");
43515
+ } else if (verification?.fixtureName) {
43516
+ 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.`);
43517
+ lines.push("```bash");
43518
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43519
+ lines.push(' -H "Content-Type: application/json" \\');
43520
+ lines.push(` -d '${fixtureReplayJson}'`);
43521
+ lines.push("```");
43522
+ lines.push("");
43523
+ 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.");
43524
+ lines.push("```bash");
43525
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
43526
+ lines.push(' -H "Content-Type: application/json" \\');
43527
+ lines.push(` -d '${fixtureCaptureJson}'`);
43528
+ lines.push("```");
43529
+ } else {
43530
+ lines.push("Capture the exact exercise once before editing. After patching, replay THIS fixture and do not declare success unless replay passes.");
43531
+ lines.push("```bash");
43532
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
43533
+ lines.push(' -H "Content-Type: application/json" \\');
43534
+ lines.push(` -d '${fixtureCaptureJson}'`);
43535
+ lines.push("");
43536
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
43537
+ lines.push(' -H "Content-Type: application/json" \\');
43538
+ lines.push(` -d '${fixtureReplayJson}'`);
43539
+ lines.push("```");
43540
+ }
43541
+ lines.push("");
43542
+ 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.");
43543
+ lines.push("");
42166
43544
  lines.push("### 2. Inspect parsed + raw adapter state");
42167
43545
  lines.push("```bash");
43546
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
43547
+ lines.push(' -H "Content-Type: application/json" \\');
43548
+ lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
42168
43549
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
43550
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
42169
43551
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
42170
43552
  lines.push("```");
42171
43553
  lines.push("");
43554
+ lines.push("The CLI trace endpoint is the primary debugging source. Read it BEFORE editing any parser code.");
43555
+ lines.push("Use the trace timeline to find the latest `settled` or `commit_transcript` frame for the repro turn and inspect these fields first:");
43556
+ lines.push("1. `payload.screenText`");
43557
+ lines.push("2. `payload.detectStatus` and `payload.parsedStatus`");
43558
+ lines.push("3. `payload.parsedLastAssistant`");
43559
+ lines.push("4. `payload.approval` / `payload.parsedActiveModal`");
43560
+ lines.push("5. `payload.rawPreview` only when control-sequence residue matters");
43561
+ lines.push("");
42172
43562
  lines.push("The debug payload should be read in this priority order:");
42173
43563
  lines.push("1. `screenText` / current visible state");
42174
43564
  lines.push("2. parsed `status`, `messages`, `activeModal`");
42175
43565
  lines.push("3. `rawBuffer` only for style/control-sequence cues");
42176
43566
  lines.push("4. `buffer` only when the current screen is insufficient");
42177
43567
  lines.push("");
42178
- lines.push("Extract the current `instanceId` from the launch or status response and keep using it below.");
43568
+ 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.");
43569
+ lines.push("Do NOT guess based only on the final chat bubble or a truncated UI preview.");
43570
+ lines.push("");
43571
+ lines.push("Extract the current `instanceId` from the exercise, launch, or status response and keep using it below.");
42179
43572
  lines.push("");
42180
- lines.push("### 3. Send a realistic approval-triggering prompt");
43573
+ lines.push("### 3. Manual fallback only: send a realistic approval-triggering prompt");
42181
43574
  lines.push("```bash");
42182
43575
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
42183
43576
  lines.push(' -H "Content-Type: application/json" \\');
42184
43577
  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."}'`);
42185
43578
  lines.push("```");
42186
43579
  lines.push("");
42187
- lines.push("### 4. If approval appears, resolve it until the CLI reaches idle");
43580
+ lines.push("### 4. Manual fallback only: if approval appears, resolve it until the CLI reaches idle");
42188
43581
  lines.push("```bash");
42189
43582
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
42190
43583
  lines.push(' -H "Content-Type: application/json" \\');
@@ -42194,10 +43587,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42194
43587
  lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
42195
43588
  lines.push("```");
42196
43589
  lines.push("");
42197
- 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.");
43590
+ 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.");
42198
43591
  lines.push("");
42199
43592
  lines.push("### Patch Discipline");
42200
43593
  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.");
43594
+ 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.");
43595
+ 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.");
43596
+ 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.");
43597
+ 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.');
42201
43598
  lines.push("");
42202
43599
  lines.push("### 5. Verify the side effects outside the CLI");
42203
43600
  lines.push("```bash");
@@ -42222,6 +43619,8 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42222
43619
  lines.push("7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
42223
43620
  lines.push("8. Confirm the parser still works after a redraw or scroll change without duplicating transcript history.");
42224
43621
  lines.push("9. Confirm the implementation prefers current-screen signals over stale history when both are present.");
43622
+ 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.");
43623
+ 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.");
42225
43624
  lines.push("");
42226
43625
  if (userComment) {
42227
43626
  lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
@@ -42230,10 +43629,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
42230
43629
  lines.push(userComment);
42231
43630
  lines.push("");
42232
43631
  }
42233
- lines.push("Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.");
43632
+ lines.push("Start NOW. Launch the CLI, inspect the trace and PTY state, edit the scripts, and verify via the CLI debug + trace endpoints.");
42234
43633
  return lines.join("\n");
42235
43634
  }
42236
43635
  function handleAutoImplSSE(ctx, type, req, res) {
43636
+ clearStaleAutoImplState(ctx, "SSE connection opened");
42237
43637
  res.writeHead(200, {
42238
43638
  "Content-Type": "text/event-stream",
42239
43639
  "Cache-Control": "no-cache",
@@ -42255,6 +43655,7 @@ data: ${JSON.stringify(p.data)}
42255
43655
  });
42256
43656
  }
42257
43657
  function handleAutoImplCancel(ctx, _type, _req, res) {
43658
+ clearStaleAutoImplState(ctx, "cancel request");
42258
43659
  if (ctx.autoImplProcess) {
42259
43660
  ctx.autoImplProcess.kill("SIGTERM");
42260
43661
  setTimeout(() => {
@@ -42282,25 +43683,26 @@ data: ${JSON.stringify(msg.data)}
42282
43683
  }
42283
43684
  }
42284
43685
  }
42285
- var fs12, path15, os17;
43686
+ var fs13, path16, os17;
42286
43687
  var init_dev_auto_implement = __esm({
42287
43688
  "../../oss/packages/daemon-core/src/daemon/dev-auto-implement.ts"() {
42288
43689
  "use strict";
42289
- fs12 = __toESM(require("fs"));
42290
- path15 = __toESM(require("path"));
43690
+ fs13 = __toESM(require("fs"));
43691
+ path16 = __toESM(require("path"));
42291
43692
  os17 = __toESM(require("os"));
42292
43693
  init_dev_server();
43694
+ init_dev_cli_debug();
42293
43695
  }
42294
43696
  });
42295
43697
 
42296
43698
  // ../../oss/packages/daemon-core/src/daemon/dev-server.ts
42297
- var http2, fs13, path16, DEV_SERVER_PORT, DevServer;
43699
+ var http2, fs14, path17, DEV_SERVER_PORT, DevServer;
42298
43700
  var init_dev_server = __esm({
42299
43701
  "../../oss/packages/daemon-core/src/daemon/dev-server.ts"() {
42300
43702
  "use strict";
42301
43703
  http2 = __toESM(require("http"));
42302
- fs13 = __toESM(require("fs"));
42303
- path16 = __toESM(require("path"));
43704
+ fs14 = __toESM(require("fs"));
43705
+ path17 = __toESM(require("path"));
42304
43706
  init_scaffold_template();
42305
43707
  init_version_archive();
42306
43708
  init_logger();
@@ -42361,11 +43763,16 @@ var init_dev_server = __esm({
42361
43763
  { method: "GET", pattern: "/api/cli/status", handler: (q2, s15) => this.handleCliStatus(q2, s15) },
42362
43764
  { method: "POST", pattern: "/api/cli/launch", handler: (q2, s15) => this.handleCliLaunch(q2, s15) },
42363
43765
  { method: "POST", pattern: "/api/cli/send", handler: (q2, s15) => this.handleCliSend(q2, s15) },
43766
+ { method: "POST", pattern: "/api/cli/exercise", handler: (q2, s15) => this.handleCliExercise(q2, s15) },
43767
+ { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q2, s15) => this.handleCliFixtureCapture(q2, s15) },
43768
+ { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q2, s15) => this.handleCliFixtureReplay(q2, s15) },
42364
43769
  { method: "POST", pattern: "/api/cli/resolve", handler: (q2, s15) => this.handleCliResolve(q2, s15) },
42365
43770
  { method: "POST", pattern: "/api/cli/raw", handler: (q2, s15) => this.handleCliRaw(q2, s15) },
42366
43771
  { method: "POST", pattern: "/api/cli/stop", handler: (q2, s15) => this.handleCliStop(q2, s15) },
42367
43772
  { method: "GET", pattern: "/api/cli/events", handler: (q2, s15) => this.handleCliSSE(q2, s15) },
42368
43773
  { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliDebug(p[0], q2, s15) },
43774
+ { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliTrace(p[0], q2, s15) },
43775
+ { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliFixtureList(p[0], q2, s15) },
42369
43776
  // Dynamic routes (provider :type param)
42370
43777
  { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q2, s15, p) => this.handleRunScript(p[0], q2, s15) },
42371
43778
  { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q2, s15, p) => this.handleListFiles(p[0], q2, s15) },
@@ -42399,8 +43806,8 @@ var init_dev_server = __esm({
42399
43806
  }
42400
43807
  getEndpointList() {
42401
43808
  return this.routes.map((r) => {
42402
- const path20 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
42403
- return `${r.method.padEnd(5)} ${path20}`;
43809
+ const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
43810
+ return `${r.method.padEnd(5)} ${path21}`;
42404
43811
  });
42405
43812
  }
42406
43813
  async start(port = DEV_SERVER_PORT) {
@@ -42682,12 +44089,12 @@ var init_dev_server = __esm({
42682
44089
  // ─── DevConsole SPA ───
42683
44090
  getConsoleDistDir() {
42684
44091
  const candidates = [
42685
- path16.resolve(__dirname, "../../web-devconsole/dist"),
42686
- path16.resolve(__dirname, "../../../web-devconsole/dist"),
42687
- path16.join(process.cwd(), "packages/web-devconsole/dist")
44092
+ path17.resolve(__dirname, "../../web-devconsole/dist"),
44093
+ path17.resolve(__dirname, "../../../web-devconsole/dist"),
44094
+ path17.join(process.cwd(), "packages/web-devconsole/dist")
42688
44095
  ];
42689
44096
  for (const dir of candidates) {
42690
- if (fs13.existsSync(path16.join(dir, "index.html"))) return dir;
44097
+ if (fs14.existsSync(path17.join(dir, "index.html"))) return dir;
42691
44098
  }
42692
44099
  return null;
42693
44100
  }
@@ -42697,9 +44104,9 @@ var init_dev_server = __esm({
42697
44104
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
42698
44105
  return;
42699
44106
  }
42700
- const htmlPath = path16.join(distDir, "index.html");
44107
+ const htmlPath = path17.join(distDir, "index.html");
42701
44108
  try {
42702
- const html = fs13.readFileSync(htmlPath, "utf-8");
44109
+ const html = fs14.readFileSync(htmlPath, "utf-8");
42703
44110
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
42704
44111
  res.end(html);
42705
44112
  } catch (e) {
@@ -42722,15 +44129,15 @@ var init_dev_server = __esm({
42722
44129
  this.json(res, 404, { error: "Not found" });
42723
44130
  return;
42724
44131
  }
42725
- const safePath = path16.normalize(pathname).replace(/^\.\.\//, "");
42726
- const filePath = path16.join(distDir, safePath);
44132
+ const safePath = path17.normalize(pathname).replace(/^\.\.\//, "");
44133
+ const filePath = path17.join(distDir, safePath);
42727
44134
  if (!filePath.startsWith(distDir)) {
42728
44135
  this.json(res, 403, { error: "Forbidden" });
42729
44136
  return;
42730
44137
  }
42731
44138
  try {
42732
- const content = fs13.readFileSync(filePath);
42733
- const ext = path16.extname(filePath);
44139
+ const content = fs14.readFileSync(filePath);
44140
+ const ext = path17.extname(filePath);
42734
44141
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
42735
44142
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
42736
44143
  res.end(content);
@@ -42838,14 +44245,14 @@ var init_dev_server = __esm({
42838
44245
  const files = [];
42839
44246
  const scan = (d, prefix) => {
42840
44247
  try {
42841
- for (const entry of fs13.readdirSync(d, { withFileTypes: true })) {
44248
+ for (const entry of fs14.readdirSync(d, { withFileTypes: true })) {
42842
44249
  if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
42843
44250
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
42844
44251
  if (entry.isDirectory()) {
42845
44252
  files.push({ path: rel, size: 0, type: "dir" });
42846
- scan(path16.join(d, entry.name), rel);
44253
+ scan(path17.join(d, entry.name), rel);
42847
44254
  } else {
42848
- const stat4 = fs13.statSync(path16.join(d, entry.name));
44255
+ const stat4 = fs14.statSync(path17.join(d, entry.name));
42849
44256
  files.push({ path: rel, size: stat4.size, type: "file" });
42850
44257
  }
42851
44258
  }
@@ -42868,16 +44275,16 @@ var init_dev_server = __esm({
42868
44275
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
42869
44276
  return;
42870
44277
  }
42871
- const fullPath = path16.resolve(dir, path16.normalize(filePath));
44278
+ const fullPath = path17.resolve(dir, path17.normalize(filePath));
42872
44279
  if (!fullPath.startsWith(dir)) {
42873
44280
  this.json(res, 403, { error: "Forbidden" });
42874
44281
  return;
42875
44282
  }
42876
- if (!fs13.existsSync(fullPath) || fs13.statSync(fullPath).isDirectory()) {
44283
+ if (!fs14.existsSync(fullPath) || fs14.statSync(fullPath).isDirectory()) {
42877
44284
  this.json(res, 404, { error: `File not found: ${filePath}` });
42878
44285
  return;
42879
44286
  }
42880
- const content = fs13.readFileSync(fullPath, "utf-8");
44287
+ const content = fs14.readFileSync(fullPath, "utf-8");
42881
44288
  this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
42882
44289
  }
42883
44290
  /** POST /api/providers/:type/file — write a file { path, content } */
@@ -42893,15 +44300,15 @@ var init_dev_server = __esm({
42893
44300
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
42894
44301
  return;
42895
44302
  }
42896
- const fullPath = path16.resolve(dir, path16.normalize(filePath));
44303
+ const fullPath = path17.resolve(dir, path17.normalize(filePath));
42897
44304
  if (!fullPath.startsWith(dir)) {
42898
44305
  this.json(res, 403, { error: "Forbidden" });
42899
44306
  return;
42900
44307
  }
42901
44308
  try {
42902
- if (fs13.existsSync(fullPath)) fs13.copyFileSync(fullPath, fullPath + ".bak");
42903
- fs13.mkdirSync(path16.dirname(fullPath), { recursive: true });
42904
- fs13.writeFileSync(fullPath, content, "utf-8");
44309
+ if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
44310
+ fs14.mkdirSync(path17.dirname(fullPath), { recursive: true });
44311
+ fs14.writeFileSync(fullPath, content, "utf-8");
42905
44312
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
42906
44313
  this.providerLoader.reload();
42907
44314
  this.json(res, 200, { saved: true, path: filePath, chars: content.length });
@@ -42917,9 +44324,9 @@ var init_dev_server = __esm({
42917
44324
  return;
42918
44325
  }
42919
44326
  for (const name of ["scripts.js", "provider.json"]) {
42920
- const p = path16.join(dir, name);
42921
- if (fs13.existsSync(p)) {
42922
- const source = fs13.readFileSync(p, "utf-8");
44327
+ const p = path17.join(dir, name);
44328
+ if (fs14.existsSync(p)) {
44329
+ const source = fs14.readFileSync(p, "utf-8");
42923
44330
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
42924
44331
  return;
42925
44332
  }
@@ -42938,11 +44345,11 @@ var init_dev_server = __esm({
42938
44345
  this.json(res, 404, { error: `Provider not found: ${type}` });
42939
44346
  return;
42940
44347
  }
42941
- const target = fs13.existsSync(path16.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
42942
- const targetPath = path16.join(dir, target);
44348
+ const target = fs14.existsSync(path17.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
44349
+ const targetPath = path17.join(dir, target);
42943
44350
  try {
42944
- if (fs13.existsSync(targetPath)) fs13.copyFileSync(targetPath, targetPath + ".bak");
42945
- fs13.writeFileSync(targetPath, source, "utf-8");
44351
+ if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
44352
+ fs14.writeFileSync(targetPath, source, "utf-8");
42946
44353
  this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
42947
44354
  this.providerLoader.reload();
42948
44355
  this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
@@ -43099,21 +44506,21 @@ var init_dev_server = __esm({
43099
44506
  }
43100
44507
  let targetDir;
43101
44508
  targetDir = this.providerLoader.getUserProviderDir(category, type);
43102
- const jsonPath = path16.join(targetDir, "provider.json");
43103
- if (fs13.existsSync(jsonPath)) {
44509
+ const jsonPath = path17.join(targetDir, "provider.json");
44510
+ if (fs14.existsSync(jsonPath)) {
43104
44511
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
43105
44512
  return;
43106
44513
  }
43107
44514
  try {
43108
44515
  const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2, osPaths, processNames });
43109
- fs13.mkdirSync(targetDir, { recursive: true });
43110
- fs13.writeFileSync(jsonPath, result["provider.json"], "utf-8");
44516
+ fs14.mkdirSync(targetDir, { recursive: true });
44517
+ fs14.writeFileSync(jsonPath, result["provider.json"], "utf-8");
43111
44518
  const createdFiles = ["provider.json"];
43112
44519
  if (result.files) {
43113
44520
  for (const [relPath, content] of Object.entries(result.files)) {
43114
- const fullPath = path16.join(targetDir, relPath);
43115
- fs13.mkdirSync(path16.dirname(fullPath), { recursive: true });
43116
- fs13.writeFileSync(fullPath, content, "utf-8");
44521
+ const fullPath = path17.join(targetDir, relPath);
44522
+ fs14.mkdirSync(path17.dirname(fullPath), { recursive: true });
44523
+ fs14.writeFileSync(fullPath, content, "utf-8");
43117
44524
  createdFiles.push(relPath);
43118
44525
  }
43119
44526
  }
@@ -43162,45 +44569,45 @@ var init_dev_server = __esm({
43162
44569
  }
43163
44570
  // ─── Phase 2: Auto-Implement Backend ───
43164
44571
  getLatestScriptVersionDir(scriptsDir) {
43165
- if (!fs13.existsSync(scriptsDir)) return null;
43166
- const versions = fs13.readdirSync(scriptsDir).filter((d) => {
44572
+ if (!fs14.existsSync(scriptsDir)) return null;
44573
+ const versions = fs14.readdirSync(scriptsDir).filter((d) => {
43167
44574
  try {
43168
- return fs13.statSync(path16.join(scriptsDir, d)).isDirectory();
44575
+ return fs14.statSync(path17.join(scriptsDir, d)).isDirectory();
43169
44576
  } catch {
43170
44577
  return false;
43171
44578
  }
43172
44579
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
43173
44580
  if (versions.length === 0) return null;
43174
- return path16.join(scriptsDir, versions[0]);
44581
+ return path17.join(scriptsDir, versions[0]);
43175
44582
  }
43176
44583
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
43177
- const canonicalUserDir = path16.resolve(this.providerLoader.getUserProviderDir(category, type));
43178
- const desiredDir = requestedDir ? path16.resolve(requestedDir) : canonicalUserDir;
43179
- const upstreamRoot = path16.resolve(this.providerLoader.getUpstreamDir());
43180
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path16.sep}`)) {
44584
+ const canonicalUserDir = path17.resolve(this.providerLoader.getUserProviderDir(category, type));
44585
+ const desiredDir = requestedDir ? path17.resolve(requestedDir) : canonicalUserDir;
44586
+ const upstreamRoot = path17.resolve(this.providerLoader.getUpstreamDir());
44587
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path17.sep}`)) {
43181
44588
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
43182
44589
  }
43183
- if (path16.basename(desiredDir) !== type) {
44590
+ if (path17.basename(desiredDir) !== type) {
43184
44591
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
43185
44592
  }
43186
44593
  const sourceDir = this.findProviderDir(type);
43187
44594
  if (!sourceDir) {
43188
44595
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
43189
44596
  }
43190
- if (!fs13.existsSync(desiredDir)) {
43191
- fs13.mkdirSync(path16.dirname(desiredDir), { recursive: true });
43192
- fs13.cpSync(sourceDir, desiredDir, { recursive: true });
44597
+ if (!fs14.existsSync(desiredDir)) {
44598
+ fs14.mkdirSync(path17.dirname(desiredDir), { recursive: true });
44599
+ fs14.cpSync(sourceDir, desiredDir, { recursive: true });
43193
44600
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
43194
44601
  }
43195
- const providerJson = path16.join(desiredDir, "provider.json");
43196
- if (!fs13.existsSync(providerJson)) {
44602
+ const providerJson = path17.join(desiredDir, "provider.json");
44603
+ if (!fs14.existsSync(providerJson)) {
43197
44604
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
43198
44605
  }
43199
44606
  try {
43200
- const providerData = JSON.parse(fs13.readFileSync(providerJson, "utf-8"));
44607
+ const providerData = JSON.parse(fs14.readFileSync(providerJson, "utf-8"));
43201
44608
  if (providerData.disableUpstream !== true) {
43202
44609
  providerData.disableUpstream = true;
43203
- fs13.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
44610
+ fs14.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
43204
44611
  }
43205
44612
  } catch (error48) {
43206
44613
  return {
@@ -43240,7 +44647,7 @@ var init_dev_server = __esm({
43240
44647
  setMode: "set_mode.js"
43241
44648
  };
43242
44649
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
43243
- const scriptsDir = path16.join(providerDir, "scripts");
44650
+ const scriptsDir = path17.join(providerDir, "scripts");
43244
44651
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
43245
44652
  if (latestScriptsDir) {
43246
44653
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -43248,10 +44655,10 @@ var init_dev_server = __esm({
43248
44655
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
43249
44656
  lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
43250
44657
  lines.push("");
43251
- for (const file2 of fs13.readdirSync(latestScriptsDir)) {
44658
+ for (const file2 of fs14.readdirSync(latestScriptsDir)) {
43252
44659
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
43253
44660
  try {
43254
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
44661
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
43255
44662
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
43256
44663
  lines.push("```javascript");
43257
44664
  lines.push(content);
@@ -43261,14 +44668,14 @@ var init_dev_server = __esm({
43261
44668
  }
43262
44669
  }
43263
44670
  }
43264
- const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
44671
+ const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43265
44672
  if (refFiles.length > 0) {
43266
44673
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
43267
44674
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
43268
44675
  lines.push("");
43269
44676
  for (const file2 of refFiles) {
43270
44677
  try {
43271
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
44678
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
43272
44679
  lines.push(`### \`${file2}\` \u{1F512}`);
43273
44680
  lines.push("```javascript");
43274
44681
  lines.push(content);
@@ -43309,11 +44716,11 @@ var init_dev_server = __esm({
43309
44716
  lines.push("");
43310
44717
  }
43311
44718
  }
43312
- const docsDir = path16.join(providerDir, "../../docs");
44719
+ const docsDir = path17.join(providerDir, "../../docs");
43313
44720
  const loadGuide = (name) => {
43314
44721
  try {
43315
- const p = path16.join(docsDir, name);
43316
- if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
44722
+ const p = path17.join(docsDir, name);
44723
+ if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
43317
44724
  } catch {
43318
44725
  }
43319
44726
  return null;
@@ -43486,7 +44893,7 @@ var init_dev_server = __esm({
43486
44893
  parseApproval: "parse_approval.js"
43487
44894
  };
43488
44895
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
43489
- const scriptsDir = path16.join(providerDir, "scripts");
44896
+ const scriptsDir = path17.join(providerDir, "scripts");
43490
44897
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
43491
44898
  if (latestScriptsDir) {
43492
44899
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -43494,11 +44901,11 @@ var init_dev_server = __esm({
43494
44901
  lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
43495
44902
  lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
43496
44903
  lines.push("");
43497
- for (const file2 of fs13.readdirSync(latestScriptsDir)) {
44904
+ for (const file2 of fs14.readdirSync(latestScriptsDir)) {
43498
44905
  if (!file2.endsWith(".js")) continue;
43499
44906
  if (!targetFileNames.has(file2)) continue;
43500
44907
  try {
43501
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
44908
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
43502
44909
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
43503
44910
  lines.push("```javascript");
43504
44911
  lines.push(content);
@@ -43507,14 +44914,14 @@ var init_dev_server = __esm({
43507
44914
  } catch {
43508
44915
  }
43509
44916
  }
43510
- const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
44917
+ const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
43511
44918
  if (refFiles.length > 0) {
43512
44919
  lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
43513
44920
  lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
43514
44921
  lines.push("");
43515
44922
  for (const file2 of refFiles) {
43516
44923
  try {
43517
- const content = fs13.readFileSync(path16.join(latestScriptsDir, file2), "utf-8");
44924
+ const content = fs14.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
43518
44925
  lines.push(`### \`${file2}\` \u{1F512}`);
43519
44926
  lines.push("```javascript");
43520
44927
  lines.push(content);
@@ -43547,11 +44954,11 @@ var init_dev_server = __esm({
43547
44954
  lines.push("");
43548
44955
  }
43549
44956
  }
43550
- const docsDir = path16.join(providerDir, "../../docs");
44957
+ const docsDir = path17.join(providerDir, "../../docs");
43551
44958
  const loadGuide = (name) => {
43552
44959
  try {
43553
- const p = path16.join(docsDir, name);
43554
- if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
44960
+ const p = path17.join(docsDir, name);
44961
+ if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
43555
44962
  } catch {
43556
44963
  }
43557
44964
  return null;
@@ -43616,6 +45023,7 @@ var init_dev_server = __esm({
43616
45023
  lines.push("### 2. Inspect parsed + raw adapter state");
43617
45024
  lines.push("```bash");
43618
45025
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
45026
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
43619
45027
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
43620
45028
  lines.push("```");
43621
45029
  lines.push("");
@@ -43750,6 +45158,16 @@ data: ${JSON.stringify(msg.data)}
43750
45158
  async handleCliSend(req, res) {
43751
45159
  return handleCliSend(this, req, res);
43752
45160
  }
45161
+ /** POST /api/cli/exercise — launch/send/approve/wait helper for provider-fix loops */
45162
+ async handleCliExercise(req, res) {
45163
+ return handleCliExercise(this, req, res);
45164
+ }
45165
+ async handleCliFixtureCapture(req, res) {
45166
+ return handleCliFixtureCapture(this, req, res);
45167
+ }
45168
+ async handleCliFixtureReplay(req, res) {
45169
+ return handleCliFixtureReplay(this, req, res);
45170
+ }
43753
45171
  /** POST /api/cli/stop — stop a running CLI { type } */
43754
45172
  async handleCliStop(req, res) {
43755
45173
  return handleCliStop(this, req, res);
@@ -43773,6 +45191,13 @@ data: ${JSON.stringify(msg.data)}
43773
45191
  async handleCliDebug(type, _req, res) {
43774
45192
  return handleCliDebug(this, type, _req, res);
43775
45193
  }
45194
+ /** GET /api/cli/trace/:type — recent CLI trace timeline plus current debug snapshot */
45195
+ async handleCliTrace(type, _req, res) {
45196
+ return handleCliTrace(this, type, _req, res);
45197
+ }
45198
+ async handleCliFixtureList(type, _req, res) {
45199
+ return handleCliFixtureList(this, type, _req, res);
45200
+ }
43776
45201
  /** POST /api/cli/resolve — resolve an approval modal { type, buttonIndex } */
43777
45202
  async handleCliResolve(req, res) {
43778
45203
  return handleCliResolve(this, req, res);
@@ -44080,7 +45505,18 @@ var init_session_host_transport = __esm({
44080
45505
  });
44081
45506
  }
44082
45507
  async boot() {
44083
- await this.client.connect();
45508
+ if (typeof this.options.ensureReady === "function") {
45509
+ await this.options.ensureReady();
45510
+ }
45511
+ try {
45512
+ await this.client.connect();
45513
+ } catch (error48) {
45514
+ if (typeof this.options.ensureReady !== "function") {
45515
+ throw error48;
45516
+ }
45517
+ await this.options.ensureReady();
45518
+ await this.client.connect();
45519
+ }
44084
45520
  this.unsubscribe = this.client.onEvent((event) => this.handleEvent(event));
44085
45521
  let record2 = null;
44086
45522
  if (this.options.attachExisting) {
@@ -44967,17 +46403,17 @@ function canPeerUsePrivilegedShareCommand(commandType, permission) {
44967
46403
  return false;
44968
46404
  }
44969
46405
  }
44970
- var fs14, path17, os19, import_node_module2, esmRequire, logFile, log, logDebug, DaemonP2PSender;
46406
+ var fs15, path18, os19, import_node_module2, esmRequire, logFile, log, logDebug, DaemonP2PSender;
44971
46407
  var init_daemon_p2p = __esm({
44972
46408
  "src/daemon-p2p.ts"() {
44973
46409
  "use strict";
44974
- fs14 = __toESM(require("fs"));
46410
+ fs15 = __toESM(require("fs"));
44975
46411
  init_src();
44976
- path17 = __toESM(require("path"));
46412
+ path18 = __toESM(require("path"));
44977
46413
  os19 = __toESM(require("os"));
44978
46414
  import_node_module2 = require("module");
44979
46415
  esmRequire = (0, import_node_module2.createRequire)(__filename);
44980
- logFile = path17.join(os19.tmpdir(), "adhdev_daemon_p2p.log");
46416
+ logFile = path18.join(os19.tmpdir(), "adhdev_daemon_p2p.log");
44981
46417
  log = (msg) => {
44982
46418
  LOG.info("P2P", `[${(/* @__PURE__ */ new Date()).toISOString()}] [P2P] ${msg}`);
44983
46419
  };
@@ -45045,17 +46481,17 @@ ${e?.stack || ""}`);
45045
46481
  const prebuildKey = `${platform11}-${arch3}`;
45046
46482
  try {
45047
46483
  const candidates = [
45048
- path17.join(__dirname, "node_modules", "node-datachannel"),
45049
- path17.join(__dirname, "..", "node_modules", "node-datachannel"),
45050
- path17.join(__dirname, "..", "..", "node_modules", "node-datachannel")
46484
+ path18.join(__dirname, "node_modules", "node-datachannel"),
46485
+ path18.join(__dirname, "..", "node_modules", "node-datachannel"),
46486
+ path18.join(__dirname, "..", "..", "node_modules", "node-datachannel")
45051
46487
  ];
45052
46488
  for (const candidate of candidates) {
45053
- const prebuildPath = path17.join(candidate, "prebuilds", prebuildKey, "node_datachannel.node");
45054
- if (fs14.existsSync(prebuildPath)) {
45055
- const targetDir = path17.join(candidate, "build", "Release");
45056
- const targetPath = path17.join(targetDir, "node_datachannel.node");
45057
- fs14.mkdirSync(targetDir, { recursive: true });
45058
- fs14.copyFileSync(prebuildPath, targetPath);
46489
+ const prebuildPath = path18.join(candidate, "prebuilds", prebuildKey, "node_datachannel.node");
46490
+ if (fs15.existsSync(prebuildPath)) {
46491
+ const targetDir = path18.join(candidate, "build", "Release");
46492
+ const targetPath = path18.join(targetDir, "node_datachannel.node");
46493
+ fs15.mkdirSync(targetDir, { recursive: true });
46494
+ fs15.copyFileSync(prebuildPath, targetPath);
45059
46495
  try {
45060
46496
  delete esmRequire.cache[esmRequire.resolve("node-datachannel")];
45061
46497
  } catch {
@@ -45949,48 +47385,122 @@ var init_screenshot_controller = __esm({
45949
47385
  });
45950
47386
 
45951
47387
  // src/session-host.ts
47388
+ function buildSessionHostEnv(baseEnv) {
47389
+ const env = {};
47390
+ for (const [key, value] of Object.entries(baseEnv)) {
47391
+ if (typeof value !== "string") continue;
47392
+ env[key] = value;
47393
+ }
47394
+ for (const key of Object.keys(env)) {
47395
+ 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_")) {
47396
+ delete env[key];
47397
+ }
47398
+ }
47399
+ env.ADHDEV_SESSION_HOST_NAME = SESSION_HOST_APP_NAME;
47400
+ return env;
47401
+ }
45952
47402
  function resolveSessionHostEntry() {
45953
47403
  const packagedCandidates = [
45954
- path18.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
45955
- path18.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
47404
+ path19.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
47405
+ path19.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
45956
47406
  ];
45957
47407
  for (const candidate of packagedCandidates) {
45958
- if (fs15.existsSync(candidate)) {
47408
+ if (fs16.existsSync(candidate)) {
45959
47409
  return candidate;
45960
47410
  }
45961
47411
  }
45962
47412
  return require.resolve("@adhdev/session-host-daemon");
45963
47413
  }
45964
- async function ensureSessionHostReady2() {
45965
- return ensureSessionHostReady({
45966
- appName: SESSION_HOST_APP_NAME,
45967
- spawnHost: () => {
45968
- const entry = resolveSessionHostEntry();
45969
- const child = (0, import_child_process9.spawn)(process.execPath, [entry], {
45970
- detached: true,
45971
- stdio: "ignore",
45972
- windowsHide: true,
45973
- env: {
45974
- ...process.env,
45975
- ADHDEV_SESSION_HOST_NAME: SESSION_HOST_APP_NAME
47414
+ function getSessionHostPidFile() {
47415
+ return path19.join(os20.homedir(), ".adhdev", `${SESSION_HOST_APP_NAME}-session-host.pid`);
47416
+ }
47417
+ function killPid(pid) {
47418
+ try {
47419
+ if (process.platform === "win32") {
47420
+ (0, import_child_process9.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
47421
+ } else {
47422
+ process.kill(pid, "SIGTERM");
47423
+ }
47424
+ return true;
47425
+ } catch {
47426
+ return false;
47427
+ }
47428
+ }
47429
+ function stopSessionHost() {
47430
+ let stopped = false;
47431
+ const pidFile = getSessionHostPidFile();
47432
+ try {
47433
+ if (fs16.existsSync(pidFile)) {
47434
+ const pid = Number.parseInt(fs16.readFileSync(pidFile, "utf8").trim(), 10);
47435
+ if (Number.isFinite(pid)) {
47436
+ stopped = killPid(pid) || stopped;
47437
+ }
47438
+ }
47439
+ } catch {
47440
+ } finally {
47441
+ try {
47442
+ fs16.unlinkSync(pidFile);
47443
+ } catch {
47444
+ }
47445
+ }
47446
+ if (process.platform !== "win32") {
47447
+ try {
47448
+ const raw = (0, import_child_process9.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
47449
+ for (const line of raw.split("\n")) {
47450
+ const pid = Number.parseInt(line.trim(), 10);
47451
+ if (Number.isFinite(pid)) {
47452
+ stopped = killPid(pid) || stopped;
45976
47453
  }
45977
- });
45978
- child.unref();
47454
+ }
47455
+ } catch {
45979
47456
  }
45980
- });
47457
+ }
47458
+ return stopped;
47459
+ }
47460
+ async function ensureSessionHostReady2() {
47461
+ const spawnHost = () => {
47462
+ const entry = resolveSessionHostEntry();
47463
+ const child = (0, import_child_process9.spawn)(process.execPath, [entry], {
47464
+ detached: true,
47465
+ stdio: "ignore",
47466
+ windowsHide: true,
47467
+ env: buildSessionHostEnv(process.env)
47468
+ });
47469
+ child.unref();
47470
+ };
47471
+ try {
47472
+ return await ensureSessionHostReady({
47473
+ appName: SESSION_HOST_APP_NAME,
47474
+ spawnHost,
47475
+ timeoutMs: SESSION_HOST_START_TIMEOUT_MS
47476
+ });
47477
+ } catch (error48) {
47478
+ stopSessionHost();
47479
+ return ensureSessionHostReady({
47480
+ appName: SESSION_HOST_APP_NAME,
47481
+ spawnHost,
47482
+ timeoutMs: SESSION_HOST_START_TIMEOUT_MS
47483
+ }).catch((retryError) => {
47484
+ const initialMessage = error48 instanceof Error ? error48.message : String(error48);
47485
+ const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);
47486
+ throw new Error(`Session host failed to start after retry (${initialMessage}; retry: ${retryMessage})`);
47487
+ });
47488
+ }
45981
47489
  }
45982
47490
  async function listHostedCliRuntimes2(endpoint) {
45983
47491
  return listHostedCliRuntimes(endpoint);
45984
47492
  }
45985
- var import_child_process9, fs15, path18, SESSION_HOST_APP_NAME;
47493
+ var import_child_process9, fs16, os20, path19, SESSION_HOST_APP_NAME, SESSION_HOST_START_TIMEOUT_MS;
45986
47494
  var init_session_host = __esm({
45987
47495
  "src/session-host.ts"() {
45988
47496
  "use strict";
45989
47497
  import_child_process9 = require("child_process");
45990
- fs15 = __toESM(require("fs"));
45991
- path18 = __toESM(require("path"));
47498
+ fs16 = __toESM(require("fs"));
47499
+ os20 = __toESM(require("os"));
47500
+ path19 = __toESM(require("path"));
45992
47501
  init_src();
45993
47502
  SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
47503
+ SESSION_HOST_START_TIMEOUT_MS = 15e3;
45994
47504
  }
45995
47505
  });
45996
47506
 
@@ -46002,24 +47512,24 @@ __export(adhdev_daemon_exports, {
46002
47512
  stopDaemon: () => stopDaemon
46003
47513
  });
46004
47514
  function getDaemonPidFile() {
46005
- const dir = path19.join(os20.homedir(), ".adhdev");
46006
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
46007
- return path19.join(dir, "daemon.pid");
47515
+ const dir = path20.join(os21.homedir(), ".adhdev");
47516
+ if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
47517
+ return path20.join(dir, "daemon.pid");
46008
47518
  }
46009
47519
  function writeDaemonPid(pid) {
46010
- fs16.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
47520
+ fs17.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
46011
47521
  }
46012
47522
  function removeDaemonPid() {
46013
47523
  try {
46014
- fs16.unlinkSync(getDaemonPidFile());
47524
+ fs17.unlinkSync(getDaemonPidFile());
46015
47525
  } catch (e) {
46016
47526
  }
46017
47527
  }
46018
47528
  function isDaemonRunning() {
46019
47529
  const pidFile = getDaemonPidFile();
46020
47530
  try {
46021
- if (!fs16.existsSync(pidFile)) return false;
46022
- const pid = parseInt(fs16.readFileSync(pidFile, "utf-8").trim());
47531
+ if (!fs17.existsSync(pidFile)) return false;
47532
+ const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim());
46023
47533
  process.kill(pid, 0);
46024
47534
  return true;
46025
47535
  } catch {
@@ -46030,8 +47540,8 @@ function isDaemonRunning() {
46030
47540
  function stopDaemon() {
46031
47541
  const pidFile = getDaemonPidFile();
46032
47542
  try {
46033
- if (!fs16.existsSync(pidFile)) return false;
46034
- const pid = parseInt(fs16.readFileSync(pidFile, "utf-8").trim());
47543
+ if (!fs17.existsSync(pidFile)) return false;
47544
+ const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim());
46035
47545
  process.kill(pid, "SIGTERM");
46036
47546
  removeDaemonPid();
46037
47547
  return true;
@@ -46040,7 +47550,7 @@ function stopDaemon() {
46040
47550
  return false;
46041
47551
  }
46042
47552
  }
46043
- var os20, fs16, path19, import_chalk2, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
47553
+ var os21, fs17, path20, import_chalk2, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
46044
47554
  var init_adhdev_daemon = __esm({
46045
47555
  "src/adhdev-daemon.ts"() {
46046
47556
  "use strict";
@@ -46050,20 +47560,20 @@ var init_adhdev_daemon = __esm({
46050
47560
  init_screenshot_controller();
46051
47561
  init_session_host();
46052
47562
  init_dist();
46053
- os20 = __toESM(require("os"));
46054
- fs16 = __toESM(require("fs"));
46055
- path19 = __toESM(require("path"));
47563
+ os21 = __toESM(require("os"));
47564
+ fs17 = __toESM(require("fs"));
47565
+ path20 = __toESM(require("path"));
46056
47566
  import_chalk2 = __toESM(require("chalk"));
46057
- pkgVersion = "0.7.46";
47567
+ pkgVersion = "0.8.0";
46058
47568
  if (pkgVersion === "unknown") {
46059
47569
  try {
46060
47570
  const possiblePaths = [
46061
- path19.join(__dirname, "..", "package.json"),
46062
- path19.join(__dirname, "package.json")
47571
+ path20.join(__dirname, "..", "package.json"),
47572
+ path20.join(__dirname, "package.json")
46063
47573
  ];
46064
47574
  for (const p of possiblePaths) {
46065
47575
  try {
46066
- const data = JSON.parse(fs16.readFileSync(p, "utf-8"));
47576
+ const data = JSON.parse(fs17.readFileSync(p, "utf-8"));
46067
47577
  if (data.version) {
46068
47578
  pkgVersion = data.version;
46069
47579
  break;
@@ -46161,6 +47671,10 @@ ${err?.stack || ""}`);
46161
47671
  removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
46162
47672
  createPtyTransportFactory: ({ runtimeId, providerType, workspace, cliArgs, providerSessionId, attachExisting }) => new SessionHostPtyTransportFactory({
46163
47673
  endpoint: sessionHostEndpoint,
47674
+ ensureReady: async () => {
47675
+ const activeEndpoint = await ensureSessionHostReady2();
47676
+ this.sessionHostEndpoint = activeEndpoint;
47677
+ },
46164
47678
  clientId: `daemon_${config2.machineId}`,
46165
47679
  runtimeId,
46166
47680
  providerType,
@@ -46206,8 +47720,8 @@ ${err?.stack || ""}`);
46206
47720
  cliInfo: {
46207
47721
  type: "adhdev-daemon",
46208
47722
  version: pkgVersion,
46209
- platform: os20.platform(),
46210
- hostname: os20.hostname(),
47723
+ platform: os21.platform(),
47724
+ hostname: os21.hostname(),
46211
47725
  machineId: config2.machineId,
46212
47726
  instanceId
46213
47727
  }
@@ -46672,16 +48186,16 @@ async function loginFlow() {
46672
48186
  let verificationUrl;
46673
48187
  try {
46674
48188
  const config2 = loadConfig();
46675
- const os21 = await import("os");
48189
+ const os22 = await import("os");
46676
48190
  const res = await fetch(`${SERVER_URL}/auth/cli/init`, {
46677
48191
  method: "POST",
46678
48192
  headers: { "Content-Type": "application/json" },
46679
48193
  body: JSON.stringify({
46680
48194
  clientMachineId: config2.machineId,
46681
48195
  registeredMachineId: config2.registeredMachineId,
46682
- hostname: os21.hostname(),
46683
- platform: os21.platform(),
46684
- arch: os21.arch()
48196
+ hostname: os22.hostname(),
48197
+ platform: os22.platform(),
48198
+ arch: os22.arch()
46685
48199
  })
46686
48200
  });
46687
48201
  if (!res.ok) {
@@ -46780,10 +48294,10 @@ async function startDaemonFlow() {
46780
48294
  const { AdhdevDaemon: AdhdevDaemon2 } = await Promise.resolve().then(() => (init_adhdev_daemon(), adhdev_daemon_exports));
46781
48295
  const daemon = new AdhdevDaemon2();
46782
48296
  const { execSync: execSync6 } = await import("child_process");
46783
- const os21 = await import("os");
46784
- const path20 = await import("path");
46785
- const logPath = path20.join(os21.homedir(), ".adhdev", "daemon.log");
46786
- const platform11 = os21.platform();
48297
+ const os22 = await import("os");
48298
+ const path21 = await import("path");
48299
+ const logPath = path21.join(os22.homedir(), ".adhdev", "daemon.log");
48300
+ const platform11 = os22.platform();
46787
48301
  try {
46788
48302
  if (platform11 === "win32") {
46789
48303
  execSync6(`start /B adhdev daemon > "${logPath}" 2>&1`, {