adhdev 0.9.5 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -8825,25 +8825,23 @@ async function handleResolveAction(h, args) {
8825
8825
  const effectiveModal = statusModal || surfacedModal;
8826
8826
  const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" ? "waiting_approval" : status?.status;
8827
8827
  LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
8828
- if (effectiveStatus !== "waiting_approval" && !effectiveModal) {
8828
+ if (!effectiveModal) {
8829
8829
  return { success: false, error: "Not in approval state" };
8830
8830
  }
8831
- const buttons = effectiveModal?.buttons || ["Allow once", "Always allow", "Deny"];
8831
+ const buttons = Array.isArray(effectiveModal.buttons) ? effectiveModal.buttons : [];
8832
8832
  let buttonIndex = typeof args?.buttonIndex === "number" ? args.buttonIndex : -1;
8833
- if (buttonIndex < 0) {
8833
+ if (buttonIndex < 0 && button) {
8834
8834
  const btnLower = button.toLowerCase();
8835
8835
  buttonIndex = buttons.findIndex((b) => b.toLowerCase().includes(btnLower));
8836
8836
  }
8837
+ if (buttonIndex < 0 && (action === "reject" || action === "deny")) {
8838
+ buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
8839
+ }
8840
+ if (buttonIndex < 0 && (action === "always" || /always/i.test(button))) {
8841
+ buttonIndex = buttons.findIndex((b) => /always/i.test(b));
8842
+ }
8837
8843
  if (buttonIndex < 0) {
8838
- if (action === "reject" || action === "deny") {
8839
- buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
8840
- if (buttonIndex < 0) buttonIndex = buttons.length - 1;
8841
- } else if (action === "always" || /always/i.test(button)) {
8842
- buttonIndex = buttons.findIndex((b) => /always/i.test(b));
8843
- if (buttonIndex < 0) buttonIndex = 1;
8844
- } else {
8845
- buttonIndex = 0;
8846
- }
8844
+ return { success: false, error: "Approval action did not match any visible button" };
8847
8845
  }
8848
8846
  if (typeof adapter.resolveModal === "function") {
8849
8847
  adapter.resolveModal(buttonIndex);
@@ -12088,8 +12086,35 @@ function promptLikelyVisible(screenText, promptSnippet) {
12088
12086
  function normalizeScreenSnapshot(text) {
12089
12087
  return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
12090
12088
  }
12089
+ function shouldReflowComparableMessageLines(lines) {
12090
+ return Array.isArray(lines) && lines.length > 1 && lines.slice(0, -1).every((line) => String(line || "").trim().length >= 48) && !lines.some((line) => /^```/.test(line)) && !lines.some((line) => /^\|/.test(line)) && !lines.some((line) => /^\s*(?:[-*+] |\d+\.\s)/.test(line));
12091
+ }
12092
+ function joinComparableMessageLines(lines) {
12093
+ return lines.reduce((acc, line) => {
12094
+ const next = String(line || "").trim();
12095
+ if (!next) return acc;
12096
+ if (!acc) return next;
12097
+ if (/[,\d]$/.test(acc) && /^\d/.test(next)) {
12098
+ return `${acc}${next}`;
12099
+ }
12100
+ if (/[A-Za-z]$/.test(acc) && /^\d/.test(next)) {
12101
+ return `${acc}${next}`;
12102
+ }
12103
+ const fragmentMatch = acc.match(/([A-Za-z]{1,4})$/);
12104
+ const fragment = fragmentMatch ? fragmentMatch[1].toLowerCase() : "";
12105
+ if (/^[a-z]/.test(next) && fragment && !COMMON_COMPARABLE_WRAP_WORDS.has(fragment)) {
12106
+ return `${acc}${next}`;
12107
+ }
12108
+ return `${acc} ${next}`;
12109
+ }, "").replace(/\s+([,.;:!?])/g, "$1").replace(/(\d)\s+,/g, "$1,").replace(/\s+/g, " ").trim();
12110
+ }
12091
12111
  function normalizeComparableMessageContent(text) {
12092
- return String(text || "").replace(/\s+/g, " ").trim();
12112
+ const lines = String(text || "").split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
12113
+ if (lines.length === 0) return "";
12114
+ if (shouldReflowComparableMessageLines(lines)) {
12115
+ return joinComparableMessageLines(lines);
12116
+ }
12117
+ return lines.join(" ").replace(/\s+/g, " ").trim();
12093
12118
  }
12094
12119
  function trimPromptEchoPrefix(text, promptText) {
12095
12120
  const prompt2 = normalizeComparableMessageContent(String(promptText || ""));
@@ -12122,9 +12147,6 @@ function getLastUserPromptText(messages) {
12122
12147
  }
12123
12148
  return "";
12124
12149
  }
12125
- function looksLikeConfirmOnlyLabel(label) {
12126
- return /^(?:continue|confirm|ok|yes|trust|proceed|enter)$/i.test(String(label || "").trim());
12127
- }
12128
12150
  function parsePatternEntry(x) {
12129
12151
  if (x instanceof RegExp) return x;
12130
12152
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -12151,7 +12173,7 @@ function normalizeCliProviderForRuntime(raw) {
12151
12173
  }
12152
12174
  };
12153
12175
  }
12154
- var os11, path10, import_child_process4, buildCliSpawnEnv;
12176
+ var os11, path10, import_child_process4, buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
12155
12177
  var init_provider_cli_shared = __esm({
12156
12178
  "../../oss/packages/daemon-core/src/cli-adapters/provider-cli-shared.ts"() {
12157
12179
  "use strict";
@@ -12160,6 +12182,32 @@ var init_provider_cli_shared = __esm({
12160
12182
  import_child_process4 = require("child_process");
12161
12183
  init_spawn_env();
12162
12184
  buildCliSpawnEnv = sanitizeSpawnEnv;
12185
+ COMMON_COMPARABLE_WRAP_WORDS = /* @__PURE__ */ new Set([
12186
+ "a",
12187
+ "an",
12188
+ "and",
12189
+ "as",
12190
+ "at",
12191
+ "but",
12192
+ "by",
12193
+ "for",
12194
+ "from",
12195
+ "in",
12196
+ "into",
12197
+ "is",
12198
+ "it",
12199
+ "of",
12200
+ "on",
12201
+ "or",
12202
+ "that",
12203
+ "the",
12204
+ "their",
12205
+ "then",
12206
+ "this",
12207
+ "to",
12208
+ "was",
12209
+ "with"
12210
+ ]);
12163
12211
  }
12164
12212
  });
12165
12213
 
@@ -12215,8 +12263,44 @@ function hydrateCliParsedMessages(parsedMessages, options) {
12215
12263
  };
12216
12264
  });
12217
12265
  }
12266
+ function chooseMoreComparableCliMessage(left2, right2) {
12267
+ const leftComparable = normalizeComparableMessageContent(left2.content || "");
12268
+ const rightComparable = normalizeComparableMessageContent(right2.content || "");
12269
+ if (leftComparable && leftComparable === rightComparable) {
12270
+ const leftNewlines = String(left2.content || "").split(/\r\n|\n|\r/g).length - 1;
12271
+ const rightNewlines = String(right2.content || "").split(/\r\n|\n|\r/g).length - 1;
12272
+ return rightNewlines < leftNewlines ? right2 : left2;
12273
+ }
12274
+ return rightComparable.length > leftComparable.length ? right2 : left2;
12275
+ }
12276
+ function dedupeConsecutiveComparableCliMessages(messages) {
12277
+ const deduped = [];
12278
+ for (const message of messages) {
12279
+ const current = {
12280
+ ...message,
12281
+ content: typeof message.content === "string" ? message.content : String(message.content || "")
12282
+ };
12283
+ const previous = deduped[deduped.length - 1];
12284
+ if (!previous) {
12285
+ deduped.push(current);
12286
+ continue;
12287
+ }
12288
+ const previousComparable = normalizeComparableMessageContent(previous.content || "");
12289
+ const currentComparable = normalizeComparableMessageContent(current.content || "");
12290
+ const sameRole = previous.role === current.role;
12291
+ const sameKind = (previous.kind || "standard") === (current.kind || "standard");
12292
+ const sameSender = (previous.senderName || "") === (current.senderName || "");
12293
+ const comparableMatch = previousComparable && previousComparable === currentComparable;
12294
+ if (sameRole && sameKind && sameSender && comparableMatch) {
12295
+ deduped[deduped.length - 1] = chooseMoreComparableCliMessage(previous, current);
12296
+ continue;
12297
+ }
12298
+ deduped.push(current);
12299
+ }
12300
+ return deduped;
12301
+ }
12218
12302
  function normalizeCliParsedMessages(parsedMessages, options) {
12219
- return hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
12303
+ return dedupeConsecutiveComparableCliMessages(hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
12220
12304
  role: message.role,
12221
12305
  content: message.content,
12222
12306
  timestamp: message.timestamp,
@@ -12226,7 +12310,7 @@ function normalizeCliParsedMessages(parsedMessages, options) {
12226
12310
  index: message.index,
12227
12311
  meta: message.meta,
12228
12312
  senderName: message.senderName
12229
- }));
12313
+ })));
12230
12314
  }
12231
12315
  function buildCliParseInput(options) {
12232
12316
  const {
@@ -12889,7 +12973,7 @@ var init_provider_cli_adapter = __esm({
12889
12973
  if (!hasStartupOutput) return;
12890
12974
  const stableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
12891
12975
  if (stableMs < 2e3) return;
12892
- const startupModal = this.getStartupConfirmationModal(screenText);
12976
+ const startupModal = this.runParseApproval(this.recentOutputBuffer);
12893
12977
  this.startupParseGate = false;
12894
12978
  if (this.startupSettleTimer) {
12895
12979
  clearTimeout(this.startupSettleTimer);
@@ -12946,11 +13030,17 @@ var init_provider_cli_adapter = __esm({
12946
13030
  if (this.currentStatus !== "waiting_approval") return;
12947
13031
  const tail = this.recentOutputBuffer;
12948
13032
  const screenText = this.terminalScreen.getText() || "";
12949
- const startupModal = this.getStartupConfirmationModal(screenText);
12950
- const modal = this.runParseApproval(tail) || startupModal;
13033
+ const modal = this.runParseApproval(tail);
12951
13034
  const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
12952
13035
  if (stillWaiting) {
12953
- this.activeModal = modal || this.activeModal || { message: "Approval required", buttons: ["Allow", "Deny"] };
13036
+ if (!modal) {
13037
+ LOG.warn("CLI", `[${this.cliType}] approval timeout check found no actionable modal; keeping approval state fail-closed`);
13038
+ this.activeModal = null;
13039
+ this.onStatusChange?.();
13040
+ this.armApprovalExitTimeout();
13041
+ return;
13042
+ }
13043
+ this.activeModal = modal;
12954
13044
  this.onStatusChange?.();
12955
13045
  this.armApprovalExitTimeout();
12956
13046
  return;
@@ -12962,81 +13052,12 @@ var init_provider_cli_adapter = __esm({
12962
13052
  this.onStatusChange?.();
12963
13053
  }, 6e4);
12964
13054
  }
12965
- looksLikeVisibleIdlePrompt(screenText) {
12966
- const text = String(screenText || "");
12967
- if (!text.trim()) return false;
12968
- if (this.cliType === "codex-cli" && /(^|\n)\s*[❯›>]\s+(?:Find and fix a bug in @filename|Improve documentation in @filename|Use \/skills|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Run \/review on my current changes)(?:\n|$)/im.test(text)) {
12969
- return true;
12970
- }
12971
- 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);
12972
- }
12973
- findLastMatchingLineIndex(lines, predicate) {
12974
- for (let index = lines.length - 1; index >= 0; index -= 1) {
12975
- if (predicate(lines[index])) return index;
12976
- }
12977
- return -1;
12978
- }
12979
- looksLikeClaudeGeneratingLine(line) {
12980
- const trimmed = String(line || "").trim();
12981
- if (!trimmed) return false;
12982
- if (/^⏵⏵\s+accept edits on/i.test(trimmed)) return false;
12983
- if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) return true;
12984
- if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+\S+.*\b(?:thinking|thought for \d+s?)\b/i.test(trimmed)) return true;
12985
- if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+[A-Z][A-Za-z-]{3,}ing\b.*(?:…|\.{3})/u.test(trimmed)) return true;
12986
- if (/^[⏺•]\s+(?:Reading|Writing|Editing|Searching|Inspecting|Planning|Analyzing|Synthesizing|Drafting|Running|Listing|Scanning|Matching)\b.*(?:…|\.{3})/i.test(trimmed)) {
12987
- return /ctrl\+o to expand/i.test(trimmed) || /\b\d+\s+(?:file|files|pattern|patterns|director(?:y|ies)|match|matches|result|results)\b/i.test(trimmed);
12988
- }
12989
- return false;
12990
- }
12991
- detectClaudeGeneratingOverride(screenText, tail) {
12992
- if (this.cliType !== "claude-cli") return false;
12993
- const source = sanitizeTerminalText(screenText || tail || "");
12994
- if (!source.trim()) return false;
12995
- const allLines = source.split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
12996
- if (allLines.length === 0) return false;
12997
- const recentLines = allLines.slice(-12);
12998
- const promptIndex = this.findLastMatchingLineIndex(recentLines, (line) => /^[❯›>]\s*$/.test(line));
12999
- const activeRegion = promptIndex >= 0 ? recentLines.slice(Math.max(0, promptIndex - 2), promptIndex) : recentLines;
13000
- if (activeRegion.length === 0) return false;
13001
- return activeRegion.some((line) => this.looksLikeClaudeGeneratingLine(line));
13002
- }
13003
- refineDetectedStatus(status, tail, screenText) {
13004
- if (this.startupParseGate) {
13005
- return this.getStartupConfirmationModal(screenText || "") ? "waiting_approval" : "starting";
13006
- }
13007
- if (status === "waiting_approval") return status;
13008
- if (this.detectClaudeGeneratingOverride(screenText || "", tail)) return "generating";
13009
- return status;
13010
- }
13011
- looksLikeVisibleAssistantCandidate(screenText) {
13012
- const lines = sanitizeTerminalText(String(screenText || "")).split(/\r\n|\n|\r/g);
13013
- for (const line of lines) {
13014
- const trimmed = String(line || "").trim();
13015
- if (!trimmed) continue;
13016
- if (/^➜\s+\S+/.test(trimmed)) continue;
13017
- if (/^Update available!/i.test(trimmed)) continue;
13018
- if (/Claude Code v\d/i.test(trimmed)) continue;
13019
- if (/^⏵⏵\s+accept edits on/i.test(trimmed)) continue;
13020
- if (/^[◐◑◒◓◴◵◶◷◸◹◺◿].*\/effort/i.test(trimmed)) continue;
13021
- if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+$/.test(trimmed)) continue;
13022
- if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) continue;
13023
- const assistantMatch = trimmed.match(/^⏺\s+(.+)$/);
13024
- if (!assistantMatch) continue;
13025
- const content = assistantMatch[1].trim();
13026
- if (!content) continue;
13027
- if (/^(?:Bash|Read|Write|Edit|MultiEdit|Task|Glob|Grep|LS|NotebookEdit)\(/.test(content)) continue;
13028
- if (/This command requires approval|Do you want to proceed|Allow once|Always allow/i.test(content)) continue;
13029
- return true;
13030
- }
13031
- return false;
13032
- }
13033
13055
  shouldRetryFinishResponse(commitResult) {
13034
13056
  if (!this.currentTurnScope) return false;
13035
13057
  if (this.currentStatus === "waiting_approval" || this.activeModal) return false;
13036
13058
  if (this.finishRetryCount >= _ProviderCliAdapter.MAX_FINISH_RETRIES) return false;
13037
13059
  if (commitResult.hasAssistant && commitResult.assistantContent.trim()) return false;
13038
- const screenText = this.terminalScreen.getText() || "";
13039
- if (!this.looksLikeVisibleAssistantCandidate(screenText)) return false;
13060
+ if (this.runDetectStatus(this.recentOutputBuffer) !== "idle") return false;
13040
13061
  const now = Date.now();
13041
13062
  const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
13042
13063
  const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
@@ -13060,45 +13081,21 @@ var init_provider_cli_adapter = __esm({
13060
13081
  }
13061
13082
  return false;
13062
13083
  }
13063
- getStartupConfirmationModal(screenText) {
13064
- const text = sanitizeTerminalText(String(screenText || ""));
13065
- if (!text.trim()) return null;
13066
- if (this.cliType === "claude-cli") {
13067
- const hasTrustPrompt = /Quick safety check/i.test(text) || /Is this a project you trust/i.test(text) || /Do you trust (?:this project|the contents of this directory|the files in this folder)/i.test(text);
13068
- const hasConfirmFooter = /Press Enter to (?:continue|confirm)/i.test(text) || /Enter to confirm/i.test(text) || /Esc to (?:cancel|exit)/i.test(text);
13069
- if (hasTrustPrompt || hasConfirmFooter && /trust/i.test(text)) {
13070
- return {
13071
- message: "Confirm Claude Code project trust",
13072
- buttons: ["Continue"]
13073
- };
13074
- }
13075
- }
13076
- return null;
13077
- }
13078
- shouldResolveModalWithEnter(modal, buttonIndex) {
13079
- if (!modal || buttonIndex !== 0) return false;
13080
- const buttons = Array.isArray(modal.buttons) ? modal.buttons : [];
13081
- if (buttons.length !== 1) return false;
13082
- const buttonLabel = String(buttons[0] || "").trim();
13083
- return looksLikeConfirmOnlyLabel(buttonLabel);
13084
- }
13085
13084
  async waitForInteractivePrompt(maxWaitMs = 5e3) {
13086
13085
  const startedAt = Date.now();
13087
13086
  let loggedWait = false;
13088
13087
  while (Date.now() - startedAt < maxWaitMs) {
13089
13088
  this.resolveStartupState("interactive_wait");
13090
13089
  const screenText = this.terminalScreen.getText() || "";
13091
- const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
13092
13090
  const stableMs = this.lastScreenChangeAt ? Date.now() - this.lastScreenChangeAt : 0;
13093
13091
  const recentlyOutput = this.lastNonEmptyOutputAt ? Date.now() - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
13094
13092
  const status = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
13095
- const startupLikelyActive = /Welcome back|Tips for getting|Recent activity|Claude Code v\d/i.test(screenText);
13096
- const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "generating";
13093
+ const interactiveReady = status === "idle" && stableMs >= 700 && recentlyOutput >= 350;
13097
13094
  if (interactiveReady) {
13098
13095
  if (loggedWait) {
13099
13096
  LOG.info(
13100
13097
  "CLI",
13101
- `[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput}, startup=${startupLikelyActive})`
13098
+ `[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput})`
13102
13099
  );
13103
13100
  }
13104
13101
  return;
@@ -13107,7 +13104,7 @@ var init_provider_cli_adapter = __esm({
13107
13104
  loggedWait = true;
13108
13105
  LOG.info(
13109
13106
  "CLI",
13110
- `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
13107
+ `[${this.cliType}] Waiting for interactive prompt: status=${status} stableMs=${stableMs} recentOutputMs=${recentlyOutput} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
13111
13108
  );
13112
13109
  }
13113
13110
  await new Promise((resolve18) => setTimeout(resolve18, 50));
@@ -13118,13 +13115,12 @@ var init_provider_cli_adapter = __esm({
13118
13115
  `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
13119
13116
  );
13120
13117
  }
13121
- clearStaleIdleResponseGuard(reason) {
13122
- const screenText = this.terminalScreen.getText() || "";
13123
- const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
13124
- const blockingModal = this.activeModal || this.getStartupConfirmationModal(screenText);
13125
- if (!this.isWaitingForResponse || this.currentStatus !== "idle" || !visibleIdlePrompt || !!blockingModal) {
13126
- return false;
13127
- }
13118
+ trimLastAssistantEcho(messages, prompt2) {
13119
+ if (!prompt2) return;
13120
+ const last = [...messages].reverse().find((m) => m.role === "assistant" && typeof m.content === "string");
13121
+ if (last) last.content = trimPromptEchoPrefix(last.content, prompt2);
13122
+ }
13123
+ clearAllTimers() {
13128
13124
  if (this.responseTimeout) {
13129
13125
  clearTimeout(this.responseTimeout);
13130
13126
  this.responseTimeout = null;
@@ -13137,10 +13133,38 @@ var init_provider_cli_adapter = __esm({
13137
13133
  clearTimeout(this.approvalExitTimeout);
13138
13134
  this.approvalExitTimeout = null;
13139
13135
  }
13136
+ if (this.submitRetryTimer) {
13137
+ clearTimeout(this.submitRetryTimer);
13138
+ this.submitRetryTimer = null;
13139
+ }
13140
13140
  if (this.finishRetryTimer) {
13141
13141
  clearTimeout(this.finishRetryTimer);
13142
13142
  this.finishRetryTimer = null;
13143
13143
  }
13144
+ if (this.settleTimer) {
13145
+ clearTimeout(this.settleTimer);
13146
+ this.settleTimer = null;
13147
+ }
13148
+ if (this.pendingScriptStatusTimer) {
13149
+ clearTimeout(this.pendingScriptStatusTimer);
13150
+ this.pendingScriptStatusTimer = null;
13151
+ }
13152
+ if (this.pendingOutputParseTimer) {
13153
+ clearTimeout(this.pendingOutputParseTimer);
13154
+ this.pendingOutputParseTimer = null;
13155
+ }
13156
+ if (this.ptyOutputFlushTimer) {
13157
+ clearTimeout(this.ptyOutputFlushTimer);
13158
+ this.ptyOutputFlushTimer = null;
13159
+ }
13160
+ }
13161
+ clearStaleIdleResponseGuard(reason) {
13162
+ const blockingModal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
13163
+ const isIdle = this.runDetectStatus(this.recentOutputBuffer) === "idle";
13164
+ if (!this.isWaitingForResponse || this.currentStatus !== "idle" || !isIdle || !!blockingModal) {
13165
+ return false;
13166
+ }
13167
+ this.clearAllTimers();
13144
13168
  this.clearIdleFinishCandidate(reason);
13145
13169
  this.responseBuffer = "";
13146
13170
  this.isWaitingForResponse = false;
@@ -13150,10 +13174,7 @@ var init_provider_cli_adapter = __esm({
13150
13174
  this.finishRetryCount = 0;
13151
13175
  this.currentTurnScope = null;
13152
13176
  this.activeModal = null;
13153
- this.recordTrace("stale_idle_response_cleared", {
13154
- reason,
13155
- screenText: summarizeCliTraceText(screenText, 240)
13156
- });
13177
+ this.recordTrace("stale_idle_response_cleared", { reason });
13157
13178
  return true;
13158
13179
  }
13159
13180
  hasMeaningfulResponseBuffer(promptSnippet) {
@@ -13188,16 +13209,15 @@ var init_provider_cli_adapter = __esm({
13188
13209
  if (this.startupParseGate) {
13189
13210
  return;
13190
13211
  }
13191
- const startupModal = this.getStartupConfirmationModal(screenText);
13192
13212
  const parsedTranscript = this.parseCurrentTranscript(
13193
13213
  this.committedMessages,
13194
13214
  this.responseBuffer,
13195
13215
  this.currentTurnScope
13196
13216
  );
13197
13217
  const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsedTranscript.activeModal : null;
13198
- const modal = this.runParseApproval(tail) || parsedModal || startupModal;
13218
+ const modal = this.runParseApproval(tail) || parsedModal;
13199
13219
  const rawScriptStatus = this.runDetectStatus(tail);
13200
- const scriptStatus = startupModal ? "waiting_approval" : parsedModal && parsedTranscript?.status === "waiting_approval" ? "waiting_approval" : rawScriptStatus;
13220
+ const scriptStatus = parsedTranscript?.status === "waiting_approval" && modal ? "waiting_approval" : rawScriptStatus;
13201
13221
  const parsedMessages = Array.isArray(parsedTranscript?.messages) ? normalizeCliParsedMessages(parsedTranscript.messages, {
13202
13222
  committedMessages: this.committedMessages,
13203
13223
  scope: this.currentTurnScope,
@@ -13252,15 +13272,44 @@ var init_provider_cli_adapter = __esm({
13252
13272
  }
13253
13273
  if (!scriptStatus) return;
13254
13274
  const prevStatus = this.currentStatus;
13255
- const clearPendingScriptStatus = () => {
13275
+ const ctx = { now, screenText, modal, scriptStatus, parsedTranscript, parsedMessages, lastParsedAssistant, parsedShowsLiveAssistantProgress, prevStatus };
13276
+ if (!this.applyPendingScriptStatusDebounce(ctx)) return;
13277
+ const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
13278
+ LOG.info(
13279
+ "CLI",
13280
+ `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 140)} scriptStatus=${String(scriptStatus || "")} parsedStatus=${String(parsedTranscript?.status || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
13281
+ );
13282
+ const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(parsedTranscript?.status === "idle" && !!lastParsedAssistant);
13283
+ if (shouldHoldGenerating) {
13284
+ this.applyHoldGenerating(ctx, recentInteractiveActivity);
13285
+ return;
13286
+ }
13287
+ if (scriptStatus === "waiting_approval") {
13288
+ this.applyWaitingApproval(ctx);
13289
+ return;
13290
+ }
13291
+ if (scriptStatus === "generating") {
13292
+ this.applyGenerating(ctx);
13293
+ return;
13294
+ }
13295
+ if (scriptStatus === "idle") {
13296
+ this.applyIdle(ctx, now);
13297
+ }
13298
+ }
13299
+ // Returns false if the caller should bail out (debounce pending).
13300
+ applyPendingScriptStatusDebounce(ctx) {
13301
+ const { now, scriptStatus, prevStatus } = ctx;
13302
+ const shouldDebounce = prevStatus === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && (scriptStatus === "generating" || scriptStatus === "waiting_approval");
13303
+ if (!shouldDebounce) {
13256
13304
  this.pendingScriptStatus = null;
13257
13305
  this.pendingScriptStatusSince = 0;
13258
13306
  if (this.pendingScriptStatusTimer) {
13259
13307
  clearTimeout(this.pendingScriptStatusTimer);
13260
13308
  this.pendingScriptStatusTimer = null;
13261
13309
  }
13262
- };
13263
- const armPendingScriptStatus = (delayMs) => {
13310
+ return true;
13311
+ }
13312
+ const armPending = (delayMs) => {
13264
13313
  if (this.pendingScriptStatusTimer) clearTimeout(this.pendingScriptStatusTimer);
13265
13314
  this.pendingScriptStatusTimer = setTimeout(() => {
13266
13315
  this.pendingScriptStatusTimer = null;
@@ -13268,200 +13317,187 @@ var init_provider_cli_adapter = __esm({
13268
13317
  this.evaluateSettled();
13269
13318
  }, delayMs);
13270
13319
  };
13271
- const shouldDebouncePromotion = (status) => prevStatus === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && (status === "generating" || status === "waiting_approval");
13272
- if (shouldDebouncePromotion(scriptStatus)) {
13273
- if (this.pendingScriptStatus !== scriptStatus) {
13274
- this.pendingScriptStatus = scriptStatus;
13275
- this.pendingScriptStatusSince = now;
13276
- armPendingScriptStatus(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS);
13277
- return;
13278
- }
13279
- const elapsed = now - this.pendingScriptStatusSince;
13280
- if (elapsed < _ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS) {
13281
- armPendingScriptStatus(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS - elapsed);
13282
- return;
13283
- }
13284
- } else {
13285
- clearPendingScriptStatus();
13286
- }
13287
- const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
13288
- const statusActivityHoldMs = this.getStatusActivityHoldMs();
13289
- const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
13290
- const visibleAssistantCandidate = this.looksLikeVisibleAssistantCandidate(screenText);
13291
- if (this.currentTurnScope && this.cliType === "claude-cli") {
13292
- LOG.info(
13293
- "CLI",
13294
- `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} scriptStatus=${String(scriptStatus || "")} parsedStatus=${String(parsedTranscript?.status || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} visibleIdlePrompt=${String(visibleIdlePrompt)} visibleAssistantCandidate=${String(visibleAssistantCandidate)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
13295
- );
13320
+ if (this.pendingScriptStatus !== scriptStatus) {
13321
+ this.pendingScriptStatus = scriptStatus;
13322
+ this.pendingScriptStatusSince = now;
13323
+ armPending(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS);
13324
+ return false;
13296
13325
  }
13297
- const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(visibleIdlePrompt && visibleAssistantCandidate) && !(parsedTranscript?.status === "idle" && !!lastParsedAssistant);
13298
- if (shouldHoldGenerating) {
13299
- this.clearIdleFinishCandidate("hold_generating_recent_activity");
13300
- this.setStatus("generating", "recent_activity_hold");
13301
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
13302
- this.idleTimeout = setTimeout(() => {
13303
- if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
13304
- if (this.shouldDeferIdleTimeoutFinish()) return;
13305
- this.finishResponse();
13306
- }
13307
- }, this.timeouts.generatingIdle);
13308
- this.recordTrace("hold_generating_recent_activity", {
13309
- scriptStatus,
13310
- recentInteractiveActivity,
13311
- lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
13312
- lastScreenChangeAt: this.lastScreenChangeAt,
13313
- holdMs: statusActivityHoldMs,
13314
- ...buildCliTraceParseSnapshot({
13315
- accumulatedBuffer: this.accumulatedBuffer,
13316
- accumulatedRawBuffer: this.accumulatedRawBuffer,
13317
- responseBuffer: this.responseBuffer,
13318
- partialResponse: this.responseBuffer,
13319
- scope: this.currentTurnScope
13320
- })
13321
- });
13322
- this.onStatusChange?.();
13323
- return;
13326
+ const elapsed = now - this.pendingScriptStatusSince;
13327
+ if (elapsed < _ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS) {
13328
+ armPending(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS - elapsed);
13329
+ return false;
13324
13330
  }
13325
- if (scriptStatus === "waiting_approval") {
13326
- this.clearIdleFinishCandidate("waiting_approval");
13327
- const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
13328
- const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
13329
- if ((inCooldown || visibleIdlePrompt2) && !modal) {
13330
- if (this.approvalExitTimeout) {
13331
- clearTimeout(this.approvalExitTimeout);
13332
- this.approvalExitTimeout = null;
13333
- }
13334
- this.activeModal = null;
13335
- if (this.isWaitingForResponse) {
13336
- this.setStatus("generating", inCooldown ? "approval_cooldown_ignore" : "approval_prompt_gone");
13337
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
13338
- this.idleTimeout = setTimeout(() => {
13339
- if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
13340
- if (this.shouldDeferIdleTimeoutFinish()) return;
13341
- this.finishResponse();
13342
- }
13343
- }, this.timeouts.generatingIdle);
13344
- } else {
13345
- this.setStatus("idle", inCooldown ? "approval_cooldown_ignore" : "approval_prompt_gone");
13346
- }
13347
- this.onStatusChange?.();
13348
- return;
13331
+ return true;
13332
+ }
13333
+ applyHoldGenerating(ctx, recentInteractiveActivity) {
13334
+ const { scriptStatus } = ctx;
13335
+ this.clearIdleFinishCandidate("hold_generating_recent_activity");
13336
+ this.setStatus("generating", "recent_activity_hold");
13337
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
13338
+ this.idleTimeout = setTimeout(() => {
13339
+ if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
13340
+ if (this.shouldDeferIdleTimeoutFinish()) return;
13341
+ this.finishResponse();
13342
+ }
13343
+ }, this.timeouts.generatingIdle);
13344
+ this.recordTrace("hold_generating_recent_activity", {
13345
+ scriptStatus,
13346
+ recentInteractiveActivity,
13347
+ lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
13348
+ lastScreenChangeAt: this.lastScreenChangeAt,
13349
+ holdMs: this.getStatusActivityHoldMs(),
13350
+ ...buildCliTraceParseSnapshot({
13351
+ accumulatedBuffer: this.accumulatedBuffer,
13352
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
13353
+ responseBuffer: this.responseBuffer,
13354
+ partialResponse: this.responseBuffer,
13355
+ scope: this.currentTurnScope
13356
+ })
13357
+ });
13358
+ this.onStatusChange?.();
13359
+ }
13360
+ applyWaitingApproval(ctx) {
13361
+ const { modal } = ctx;
13362
+ this.clearIdleFinishCandidate("waiting_approval");
13363
+ const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
13364
+ if (inCooldown && !modal) {
13365
+ if (this.approvalExitTimeout) {
13366
+ clearTimeout(this.approvalExitTimeout);
13367
+ this.approvalExitTimeout = null;
13349
13368
  }
13350
- if (!inCooldown) {
13351
- this.isWaitingForResponse = true;
13352
- this.setStatus("waiting_approval", "script_detect");
13353
- this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
13369
+ this.activeModal = null;
13370
+ if (this.isWaitingForResponse) {
13371
+ this.setStatus("generating", inCooldown ? "approval_cooldown_ignore" : "approval_prompt_gone");
13354
13372
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
13355
- this.armApprovalExitTimeout();
13356
- this.onStatusChange?.();
13357
- return;
13373
+ this.idleTimeout = setTimeout(() => {
13374
+ if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
13375
+ if (this.shouldDeferIdleTimeoutFinish()) return;
13376
+ this.finishResponse();
13377
+ }
13378
+ }, this.timeouts.generatingIdle);
13379
+ } else {
13380
+ this.setStatus("idle", inCooldown ? "approval_cooldown_ignore" : "approval_prompt_gone");
13358
13381
  }
13382
+ this.onStatusChange?.();
13383
+ return;
13359
13384
  }
13360
- if (scriptStatus === "generating") {
13361
- this.clearIdleFinishCandidate("generating");
13362
- const effectiveScreenText = screenText || this.accumulatedBuffer;
13363
- const noActiveTurn = !this.currentTurnScope;
13364
- 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));
13365
- if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
13385
+ if (!inCooldown) {
13386
+ if (!modal) {
13387
+ LOG.warn("CLI", `[${this.cliType}] detectStatus reported waiting_approval without parseApproval modal; ignoring non-actionable approval state`);
13366
13388
  return;
13367
13389
  }
13368
- if (prevStatus === "waiting_approval") {
13369
- if (this.approvalExitTimeout) {
13370
- clearTimeout(this.approvalExitTimeout);
13371
- this.approvalExitTimeout = null;
13372
- }
13373
- this.activeModal = null;
13374
- this.lastApprovalResolvedAt = Date.now();
13375
- }
13376
- if (!this.isWaitingForResponse) {
13377
- this.isWaitingForResponse = true;
13378
- this.responseBuffer = "";
13379
- }
13380
- this.setStatus("generating", "script_detect");
13390
+ this.isWaitingForResponse = true;
13391
+ this.setStatus("waiting_approval", "script_detect");
13392
+ this.activeModal = modal;
13381
13393
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
13382
- this.idleTimeout = setTimeout(() => {
13383
- if (this.isWaitingForResponse) {
13384
- if (this.shouldDeferIdleTimeoutFinish()) return;
13385
- this.finishResponse();
13386
- }
13387
- }, this.timeouts.generatingIdle);
13394
+ this.armApprovalExitTimeout();
13388
13395
  this.onStatusChange?.();
13396
+ }
13397
+ }
13398
+ applyGenerating(ctx) {
13399
+ const { screenText, modal, parsedShowsLiveAssistantProgress, prevStatus } = ctx;
13400
+ this.clearIdleFinishCandidate("generating");
13401
+ const effectiveScreenText = screenText || this.accumulatedBuffer;
13402
+ const noActiveTurn = !this.currentTurnScope;
13403
+ 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));
13404
+ if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
13389
13405
  return;
13390
13406
  }
13391
- if (scriptStatus === "idle") {
13392
- if (prevStatus === "waiting_approval") {
13393
- if (this.approvalExitTimeout) {
13394
- clearTimeout(this.approvalExitTimeout);
13395
- this.approvalExitTimeout = null;
13396
- }
13397
- this.activeModal = null;
13398
- this.lastApprovalResolvedAt = Date.now();
13407
+ if (prevStatus === "waiting_approval") {
13408
+ if (this.approvalExitTimeout) {
13409
+ clearTimeout(this.approvalExitTimeout);
13410
+ this.approvalExitTimeout = null;
13399
13411
  }
13412
+ this.activeModal = null;
13413
+ this.lastApprovalResolvedAt = Date.now();
13414
+ }
13415
+ if (!this.isWaitingForResponse) {
13416
+ this.isWaitingForResponse = true;
13417
+ this.responseBuffer = "";
13418
+ }
13419
+ this.setStatus("generating", "script_detect");
13420
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
13421
+ this.idleTimeout = setTimeout(() => {
13400
13422
  if (this.isWaitingForResponse) {
13401
- const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
13402
- const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
13403
- const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
13404
- const hasAssistantTurn = !!lastParsedAssistant;
13405
- const assistantLength = lastParsedAssistant?.content?.length || 0;
13406
- const idleFinishConfirmMs = this.getIdleFinishConfirmMs();
13407
- const idleQuietThresholdMs = Math.max(idleFinishConfirmMs, this.timeouts.outputSettle);
13408
- const idleStableThresholdMs = idleFinishConfirmMs;
13409
- const idleReady = visibleIdlePrompt2 && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
13410
- const candidate = this.idleFinishCandidate;
13411
- const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= idleFinishConfirmMs;
13412
- const canFinishImmediately = idleReady && candidateQuiet;
13413
- this.recordTrace("idle_decision", {
13414
- visibleIdlePrompt: visibleIdlePrompt2,
13415
- quietForMs,
13416
- screenStableMs,
13417
- hasAssistantTurn,
13418
- assistantLength,
13419
- hasModal: !!modal,
13420
- idleQuietThresholdMs,
13421
- idleStableThresholdMs,
13422
- idleReady,
13423
- idleFinishConfirmMs,
13424
- idleFinishCandidate: candidate,
13425
- candidateQuiet,
13426
- canFinishImmediately,
13427
- submitPendingUntil: this.submitPendingUntil,
13428
- responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
13429
- ...buildCliTraceParseSnapshot({
13430
- accumulatedBuffer: this.accumulatedBuffer,
13431
- accumulatedRawBuffer: this.accumulatedRawBuffer,
13432
- responseBuffer: this.responseBuffer,
13433
- partialResponse: this.responseBuffer,
13434
- scope: this.currentTurnScope
13435
- })
13436
- });
13437
- if (canFinishImmediately) {
13438
- this.clearIdleFinishCandidate("finish_response");
13439
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
13440
- this.finishResponse();
13441
- return;
13442
- }
13443
- if (idleReady) {
13444
- if (!candidate) {
13445
- this.armIdleFinishCandidate(assistantLength);
13446
- return;
13447
- }
13448
- } else {
13449
- this.clearIdleFinishCandidate("idle_not_ready");
13450
- }
13451
- if (this.idleTimeout) clearTimeout(this.idleTimeout);
13452
- this.idleTimeout = setTimeout(() => {
13453
- if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
13454
- if (this.shouldDeferIdleTimeoutFinish()) return;
13455
- this.clearIdleFinishCandidate("idle_timeout_finish");
13456
- this.finishResponse();
13457
- }
13458
- }, this.timeouts.idleFinish);
13459
- } else if (prevStatus !== "idle") {
13423
+ if (this.shouldDeferIdleTimeoutFinish()) return;
13424
+ this.finishResponse();
13425
+ }
13426
+ }, this.timeouts.generatingIdle);
13427
+ this.onStatusChange?.();
13428
+ }
13429
+ applyIdle(ctx, now) {
13430
+ const { screenText, modal, lastParsedAssistant, prevStatus } = ctx;
13431
+ if (prevStatus === "waiting_approval") {
13432
+ if (this.approvalExitTimeout) {
13433
+ clearTimeout(this.approvalExitTimeout);
13434
+ this.approvalExitTimeout = null;
13435
+ }
13436
+ this.activeModal = null;
13437
+ this.lastApprovalResolvedAt = Date.now();
13438
+ }
13439
+ if (!this.isWaitingForResponse) {
13440
+ if (prevStatus !== "idle") {
13460
13441
  this.clearIdleFinishCandidate("idle_without_response");
13461
13442
  this.setStatus("idle", "script_detect");
13462
13443
  this.onStatusChange?.();
13463
13444
  }
13445
+ return;
13464
13446
  }
13447
+ const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
13448
+ const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
13449
+ const hasAssistantTurn = !!lastParsedAssistant;
13450
+ const assistantLength = lastParsedAssistant?.content?.length || 0;
13451
+ const idleFinishConfirmMs = this.getIdleFinishConfirmMs();
13452
+ const idleQuietThresholdMs = Math.max(idleFinishConfirmMs, this.timeouts.outputSettle);
13453
+ const idleReady = !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleFinishConfirmMs;
13454
+ const candidate = this.idleFinishCandidate;
13455
+ const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= idleFinishConfirmMs;
13456
+ this.recordTrace("idle_decision", {
13457
+ quietForMs,
13458
+ screenStableMs,
13459
+ hasAssistantTurn,
13460
+ assistantLength,
13461
+ hasModal: !!modal,
13462
+ idleQuietThresholdMs,
13463
+ idleStableThresholdMs: idleFinishConfirmMs,
13464
+ idleReady,
13465
+ idleFinishConfirmMs,
13466
+ idleFinishCandidate: candidate,
13467
+ candidateQuiet,
13468
+ canFinishImmediately: idleReady && candidateQuiet,
13469
+ submitPendingUntil: this.submitPendingUntil,
13470
+ responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
13471
+ ...buildCliTraceParseSnapshot({
13472
+ accumulatedBuffer: this.accumulatedBuffer,
13473
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
13474
+ responseBuffer: this.responseBuffer,
13475
+ partialResponse: this.responseBuffer,
13476
+ scope: this.currentTurnScope
13477
+ })
13478
+ });
13479
+ if (idleReady && candidateQuiet) {
13480
+ this.clearIdleFinishCandidate("finish_response");
13481
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
13482
+ this.finishResponse();
13483
+ return;
13484
+ }
13485
+ if (idleReady) {
13486
+ if (!candidate) {
13487
+ this.armIdleFinishCandidate(assistantLength);
13488
+ return;
13489
+ }
13490
+ } else {
13491
+ this.clearIdleFinishCandidate("idle_not_ready");
13492
+ }
13493
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
13494
+ this.idleTimeout = setTimeout(() => {
13495
+ if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
13496
+ if (this.shouldDeferIdleTimeoutFinish()) return;
13497
+ this.clearIdleFinishCandidate("idle_timeout_finish");
13498
+ this.finishResponse();
13499
+ }
13500
+ }, this.timeouts.idleFinish);
13465
13501
  }
13466
13502
  finishResponse() {
13467
13503
  if (this.submitPendingUntil > Date.now()) return;
@@ -13500,26 +13536,7 @@ var init_provider_cli_adapter = __esm({
13500
13536
  }, _ProviderCliAdapter.FINISH_RETRY_DELAY_MS);
13501
13537
  return;
13502
13538
  }
13503
- if (this.responseTimeout) {
13504
- clearTimeout(this.responseTimeout);
13505
- this.responseTimeout = null;
13506
- }
13507
- if (this.idleTimeout) {
13508
- clearTimeout(this.idleTimeout);
13509
- this.idleTimeout = null;
13510
- }
13511
- if (this.approvalExitTimeout) {
13512
- clearTimeout(this.approvalExitTimeout);
13513
- this.approvalExitTimeout = null;
13514
- }
13515
- if (this.submitRetryTimer) {
13516
- clearTimeout(this.submitRetryTimer);
13517
- this.submitRetryTimer = null;
13518
- }
13519
- if (this.finishRetryTimer) {
13520
- clearTimeout(this.finishRetryTimer);
13521
- this.finishRetryTimer = null;
13522
- }
13539
+ this.clearAllTimers();
13523
13540
  this.responseBuffer = "";
13524
13541
  this.isWaitingForResponse = false;
13525
13542
  this.responseSettleIgnoreUntil = 0;
@@ -13531,18 +13548,12 @@ var init_provider_cli_adapter = __esm({
13531
13548
  this.setStatus("idle", "response_finished");
13532
13549
  this.onStatusChange?.();
13533
13550
  }
13534
- maybeCommitVisibleIdleTranscript(parsed, options) {
13551
+ maybeCommitVisibleIdleTranscript(parsed) {
13535
13552
  const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
13536
13553
  if (!allowImmediateScriptIdleCommit) return false;
13537
13554
  if (!parsed || !Array.isArray(parsed.messages) || parsed.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || parsed.activeModal) {
13538
13555
  return false;
13539
13556
  }
13540
- if (options?.requireVisibleAssistantCandidate) {
13541
- const candidateText = options.screenText || this.terminalScreen.getText() || "";
13542
- if (!this.looksLikeVisibleAssistantCandidate(candidateText)) {
13543
- return false;
13544
- }
13545
- }
13546
13557
  const hydratedForIdleCommit = normalizeCliParsedMessages(parsed.messages, {
13547
13558
  committedMessages: this.committedMessages,
13548
13559
  scope: this.currentTurnScope,
@@ -13551,33 +13562,8 @@ var init_provider_cli_adapter = __esm({
13551
13562
  const visibleAssistant = [...hydratedForIdleCommit].reverse().find((message) => message.role === "assistant" && message.content.trim());
13552
13563
  if (!visibleAssistant) return false;
13553
13564
  this.committedMessages = hydratedForIdleCommit;
13554
- const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
13555
- if (promptForTrim) {
13556
- const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
13557
- if (lastAssistantForTrim) {
13558
- lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
13559
- }
13560
- }
13561
- if (this.responseTimeout) {
13562
- clearTimeout(this.responseTimeout);
13563
- this.responseTimeout = null;
13564
- }
13565
- if (this.idleTimeout) {
13566
- clearTimeout(this.idleTimeout);
13567
- this.idleTimeout = null;
13568
- }
13569
- if (this.approvalExitTimeout) {
13570
- clearTimeout(this.approvalExitTimeout);
13571
- this.approvalExitTimeout = null;
13572
- }
13573
- if (this.submitRetryTimer) {
13574
- clearTimeout(this.submitRetryTimer);
13575
- this.submitRetryTimer = null;
13576
- }
13577
- if (this.finishRetryTimer) {
13578
- clearTimeout(this.finishRetryTimer);
13579
- this.finishRetryTimer = null;
13580
- }
13565
+ this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
13566
+ this.clearAllTimers();
13581
13567
  this.syncMessageViews();
13582
13568
  this.responseBuffer = "";
13583
13569
  this.isWaitingForResponse = false;
@@ -13607,13 +13593,7 @@ var init_provider_cli_adapter = __esm({
13607
13593
  scope: this.currentTurnScope,
13608
13594
  lastOutputAt: this.lastOutputAt
13609
13595
  });
13610
- const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
13611
- if (promptForTrim) {
13612
- const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
13613
- if (lastAssistantForTrim) {
13614
- lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
13615
- }
13616
- }
13596
+ this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
13617
13597
  this.syncMessageViews();
13618
13598
  const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
13619
13599
  if (this.currentTurnScope) {
@@ -13671,7 +13651,7 @@ var init_provider_cli_adapter = __esm({
13671
13651
  screen: buildCliScreenSnapshot(screenText),
13672
13652
  tailScreen: buildCliScreenSnapshot(text.slice(-500))
13673
13653
  });
13674
- return this.refineDetectedStatus(status, text, screenText || "");
13654
+ return status;
13675
13655
  } catch (e) {
13676
13656
  LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
13677
13657
  return null;
@@ -13711,23 +13691,21 @@ var init_provider_cli_adapter = __esm({
13711
13691
  if (!inApprovalCooldown) {
13712
13692
  return parsed;
13713
13693
  }
13714
- const startupModal = this.getStartupConfirmationModal(screenText || "");
13715
- const visibleModal = this.runParseApproval(recentBuffer) || startupModal;
13694
+ const visibleModal = this.runParseApproval(recentBuffer);
13716
13695
  if (visibleModal) {
13717
13696
  return parsed;
13718
13697
  }
13719
13698
  const detectedStatus = this.runDetectStatus(recentBuffer);
13720
- const fallbackStatus = detectedStatus && detectedStatus !== "waiting_approval" ? detectedStatus : this.isWaitingForResponse || this.currentTurnScope ? "generating" : this.currentStatus === "waiting_approval" ? "idle" : this.currentStatus;
13699
+ const resolvedStatus = detectedStatus && detectedStatus !== "waiting_approval" ? detectedStatus : this.isWaitingForResponse || this.currentTurnScope ? "generating" : this.currentStatus === "waiting_approval" ? "idle" : this.currentStatus;
13721
13700
  return {
13722
13701
  ...parsed,
13723
- status: fallbackStatus,
13702
+ status: resolvedStatus,
13724
13703
  activeModal: null
13725
13704
  };
13726
13705
  }
13727
13706
  // ─── Public API (CliAdapter) ───────────────────
13728
13707
  getStatus() {
13729
- const screenText = this.terminalScreen.getText() || "";
13730
- const startupModal = this.startupParseGate ? this.getStartupConfirmationModal(screenText) : null;
13708
+ const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
13731
13709
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
13732
13710
  let effectiveModal = startupModal || this.activeModal;
13733
13711
  if (!startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
@@ -13808,8 +13786,7 @@ var init_provider_cli_adapter = __esm({
13808
13786
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
13809
13787
  }));
13810
13788
  const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === "assistant" && typeof message.content === "string" && message.content.trim());
13811
- const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
13812
- const shouldAdoptParsedIdleReplay = !this.currentTurnScope && !this.activeModal && !!parsedLastAssistant && parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, committedHydratedMessages) && (this.currentStatus === "idle" || this.currentStatus === "generating" && this.isWaitingForResponse && parsed.status === "idle" && visibleIdlePrompt);
13789
+ const shouldAdoptParsedIdleReplay = !this.currentTurnScope && !this.activeModal && !!parsedLastAssistant && parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, committedHydratedMessages) && (this.currentStatus === "idle" || this.currentStatus === "generating" && this.isWaitingForResponse && parsed.status === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle");
13813
13790
  if (shouldAdoptParsedIdleReplay) {
13814
13791
  this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
13815
13792
  committedMessages: this.committedMessages,
@@ -13938,17 +13915,9 @@ var init_provider_cli_adapter = __esm({
13938
13915
  if (parsed && typeof parsed === "object") {
13939
13916
  Object.assign(parsed, validateReadChatResultPayload(parsed, `${this.cliType} parseOutput`));
13940
13917
  }
13941
- const refinedStatus = this.refineDetectedStatus(typeof parsed?.status === "string" ? parsed.status : null, input.recentBuffer, input.screenText);
13942
- if (parsed && refinedStatus && parsed.status !== refinedStatus) {
13943
- parsed.status = refinedStatus;
13944
- }
13945
13918
  const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
13946
- const promptForTrim = scope?.prompt || getLastUserPromptText(baseMessages);
13947
- if (normalizedParsed && Array.isArray(normalizedParsed.messages) && promptForTrim) {
13948
- const lastAssistant = [...normalizedParsed.messages].reverse().find((message) => message?.role === "assistant" && typeof message.content === "string");
13949
- if (lastAssistant) {
13950
- lastAssistant.content = trimPromptEchoPrefix(lastAssistant.content, promptForTrim);
13951
- }
13919
+ if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
13920
+ this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
13952
13921
  }
13953
13922
  this.parseErrorMessage = null;
13954
13923
  return normalizedParsed;
@@ -13976,16 +13945,11 @@ var init_provider_cli_adapter = __esm({
13976
13945
  LOG.warn("CLI", `[${this.cliType}] resolveAction error: ${e.message}`);
13977
13946
  }
13978
13947
  }
13979
- if (!promptText && data) {
13980
- promptText = `Please fix the following issue:
13981
- ${data.title || ""}
13982
- ${data.explanation || ""}
13983
-
13984
- ${data.message || ""}`.trim();
13985
- }
13986
- if (promptText) {
13987
- await this.sendMessage(promptText);
13948
+ if (!promptText) {
13949
+ LOG.warn("CLI", `[${this.cliType}] resolveAction skipped: provider script did not supply a prompt`);
13950
+ return;
13988
13951
  }
13952
+ await this.sendMessage(promptText);
13989
13953
  }
13990
13954
  async sendMessage(text) {
13991
13955
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
@@ -14003,9 +13967,7 @@ ${data.message || ""}`.trim();
14003
13967
  }
14004
13968
  if (!this.ready) {
14005
13969
  this.resolveStartupState("send_precheck");
14006
- const screenText = this.terminalScreen.getText() || "";
14007
- const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
14008
- if (hasPrompt && this.currentStatus === "idle") {
13970
+ if (this.runDetectStatus(this.recentOutputBuffer) === "idle" && this.currentStatus === "idle") {
14009
13971
  this.ready = true;
14010
13972
  this.startupParseGate = false;
14011
13973
  LOG.info("CLI", `[${this.cliType}] sendMessage recovered idle prompt readiness`);
@@ -14111,7 +14073,10 @@ ${data.message || ""}`.trim();
14111
14073
  if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
14112
14074
  const screenText2 = this.terminalScreen.getText();
14113
14075
  if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
14114
- 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(screenText2)) return;
14076
+ const liveApproval = this.runParseApproval(screenText2) || this.runParseApproval(this.recentOutputBuffer);
14077
+ if (liveApproval) return;
14078
+ const liveStatus = this.runDetectStatus(screenText2) || this.runDetectStatus(this.recentOutputBuffer);
14079
+ if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
14115
14080
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
14116
14081
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
14117
14082
  this.recordTrace("submit_write", {
@@ -14148,6 +14113,10 @@ ${data.message || ""}`.trim();
14148
14113
  if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
14149
14114
  const screenText = this.terminalScreen.getText();
14150
14115
  if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
14116
+ const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
14117
+ if (liveApproval) return;
14118
+ const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
14119
+ if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
14151
14120
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
14152
14121
  this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
14153
14122
  this.recordTrace("submit_write", {
@@ -14279,44 +14248,9 @@ ${data.message || ""}`.trim();
14279
14248
  }
14280
14249
  shutdown() {
14281
14250
  this.clearIdleFinishCandidate("shutdown");
14282
- if (this.settleTimer) {
14283
- clearTimeout(this.settleTimer);
14284
- this.settleTimer = null;
14285
- }
14286
- if (this.approvalExitTimeout) {
14287
- clearTimeout(this.approvalExitTimeout);
14288
- this.approvalExitTimeout = null;
14289
- }
14290
- if (this.submitRetryTimer) {
14291
- clearTimeout(this.submitRetryTimer);
14292
- this.submitRetryTimer = null;
14293
- }
14294
- if (this.finishRetryTimer) {
14295
- clearTimeout(this.finishRetryTimer);
14296
- this.finishRetryTimer = null;
14297
- }
14298
- if (this.responseTimeout) {
14299
- clearTimeout(this.responseTimeout);
14300
- this.responseTimeout = null;
14301
- }
14302
- if (this.idleTimeout) {
14303
- clearTimeout(this.idleTimeout);
14304
- this.idleTimeout = null;
14305
- }
14306
- if (this.pendingScriptStatusTimer) {
14307
- clearTimeout(this.pendingScriptStatusTimer);
14308
- this.pendingScriptStatusTimer = null;
14309
- }
14310
- if (this.pendingOutputParseTimer) {
14311
- clearTimeout(this.pendingOutputParseTimer);
14312
- this.pendingOutputParseTimer = null;
14313
- }
14251
+ this.clearAllTimers();
14314
14252
  this.pendingOutputParseBuffer = "";
14315
14253
  this.pendingTerminalQueryTail = "";
14316
- if (this.ptyOutputFlushTimer) {
14317
- clearTimeout(this.ptyOutputFlushTimer);
14318
- this.ptyOutputFlushTimer = null;
14319
- }
14320
14254
  this.ptyOutputBuffer = "";
14321
14255
  this.finishRetryCount = 0;
14322
14256
  if (this.ptyProcess) {
@@ -14337,44 +14271,9 @@ ${data.message || ""}`.trim();
14337
14271
  }
14338
14272
  detach() {
14339
14273
  this.clearIdleFinishCandidate("detach");
14340
- if (this.settleTimer) {
14341
- clearTimeout(this.settleTimer);
14342
- this.settleTimer = null;
14343
- }
14344
- if (this.approvalExitTimeout) {
14345
- clearTimeout(this.approvalExitTimeout);
14346
- this.approvalExitTimeout = null;
14347
- }
14348
- if (this.submitRetryTimer) {
14349
- clearTimeout(this.submitRetryTimer);
14350
- this.submitRetryTimer = null;
14351
- }
14352
- if (this.finishRetryTimer) {
14353
- clearTimeout(this.finishRetryTimer);
14354
- this.finishRetryTimer = null;
14355
- }
14356
- if (this.responseTimeout) {
14357
- clearTimeout(this.responseTimeout);
14358
- this.responseTimeout = null;
14359
- }
14360
- if (this.idleTimeout) {
14361
- clearTimeout(this.idleTimeout);
14362
- this.idleTimeout = null;
14363
- }
14364
- if (this.pendingScriptStatusTimer) {
14365
- clearTimeout(this.pendingScriptStatusTimer);
14366
- this.pendingScriptStatusTimer = null;
14367
- }
14368
- if (this.pendingOutputParseTimer) {
14369
- clearTimeout(this.pendingOutputParseTimer);
14370
- this.pendingOutputParseTimer = null;
14371
- }
14274
+ this.clearAllTimers();
14372
14275
  this.pendingOutputParseBuffer = "";
14373
14276
  this.pendingTerminalQueryTail = "";
14374
- if (this.ptyOutputFlushTimer) {
14375
- clearTimeout(this.ptyOutputFlushTimer);
14376
- this.ptyOutputFlushTimer = null;
14377
- }
14378
14277
  this.ptyOutputBuffer = "";
14379
14278
  this.finishRetryCount = 0;
14380
14279
  if (this.ptyProcess) {
@@ -14436,8 +14335,7 @@ ${data.message || ""}`.trim();
14436
14335
  this.ptyProcess?.write(data);
14437
14336
  }
14438
14337
  resolveModal(buttonIndex) {
14439
- const screenText = this.terminalScreen.getText() || "";
14440
- let modal = this.activeModal || this.getStartupConfirmationModal(screenText);
14338
+ let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
14441
14339
  if (!modal && typeof this.cliScripts?.parseOutput === "function") {
14442
14340
  try {
14443
14341
  const parsed = this.getScriptParsedStatus();
@@ -14468,12 +14366,7 @@ ${data.message || ""}`.trim();
14468
14366
  }
14469
14367
  this.setStatus("generating", "approval_resolved");
14470
14368
  this.onStatusChange?.();
14471
- const startupTrustModal = /Quick safety check|project trust|Confirm Claude Code project trust|trust (?:this project|the contents of this directory|the files in this folder)/i.test(String(modal?.message || ""));
14472
- if (startupTrustModal && buttonIndex in this.approvalKeys) {
14473
- this.ptyProcess.write(`${this.approvalKeys[buttonIndex]}\r`);
14474
- } else if (this.shouldResolveModalWithEnter(modal, buttonIndex)) {
14475
- this.ptyProcess.write("\r");
14476
- } else if (buttonIndex in this.approvalKeys) {
14369
+ if (buttonIndex in this.approvalKeys) {
14477
14370
  this.ptyProcess.write(this.approvalKeys[buttonIndex]);
14478
14371
  } else {
14479
14372
  const DOWN = "\x1B[B";
@@ -14493,7 +14386,7 @@ ${data.message || ""}`.trim();
14493
14386
  }
14494
14387
  getDebugState() {
14495
14388
  const screenText = sanitizeTerminalText(this.terminalScreen.getText());
14496
- const startupModal = this.startupParseGate ? this.getStartupConfirmationModal(screenText) : null;
14389
+ const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
14497
14390
  const effectiveStatus = this.projectEffectiveStatus(startupModal);
14498
14391
  const effectiveReady = this.ready || !!startupModal;
14499
14392
  return {
@@ -14715,6 +14608,13 @@ var init_cli_provider_instance = __esm({
14715
14608
  runtimeMessages = [];
14716
14609
  lastPersistedHistoryMessages = [];
14717
14610
  lastCanonicalHermesSyncMtimeMs = 0;
14611
+ lastCanonicalHermesExistCheckAt = 0;
14612
+ lastCanonicalHermesWatchPath = void 0;
14613
+ lastCanonicalClaudeRebuildMtimeMs = 0;
14614
+ lastCanonicalClaudeCheckAt = 0;
14615
+ cachedSqliteDb = null;
14616
+ cachedSqliteDbPath = null;
14617
+ cachedSqliteDbMissingUntil = 0;
14718
14618
  instanceId;
14719
14619
  suppressIdleHistoryReplay = false;
14720
14620
  errorMessage = void 0;
@@ -14779,7 +14679,12 @@ var init_cli_provider_instance = __esm({
14779
14679
  */
14780
14680
  probeSessionIdFromConfig(probe) {
14781
14681
  const resolvedDbPath = probe.dbPath.replace(/^~/, os14.homedir());
14782
- if (!fs5.existsSync(resolvedDbPath)) return null;
14682
+ const now = Date.now();
14683
+ if (this.cachedSqliteDbMissingUntil > now) return null;
14684
+ if (!fs5.existsSync(resolvedDbPath)) {
14685
+ this.cachedSqliteDbMissingUntil = now + 1e4;
14686
+ return null;
14687
+ }
14783
14688
  const directories = this.getProbeDirectories();
14784
14689
  const minCreatedAt = Math.max(0, this.startedAt - 6e4);
14785
14690
  const tsFormat = probe.timestampFormat || "unix_ms";
@@ -14950,6 +14855,12 @@ var init_cli_provider_instance = __esm({
14950
14855
  this.adapter.shutdown();
14951
14856
  this.monitor.reset();
14952
14857
  this.appliedEffectKeys.clear();
14858
+ try {
14859
+ this.cachedSqliteDb?.close();
14860
+ } catch {
14861
+ }
14862
+ this.cachedSqliteDb = null;
14863
+ this.cachedSqliteDbPath = null;
14953
14864
  }
14954
14865
  completedDebounceTimer = null;
14955
14866
  completedDebouncePending = null;
@@ -15354,13 +15265,35 @@ ${effect.notification.body || ""}`.trim();
15354
15265
  let rebuilt = false;
15355
15266
  if (canonicalHistory.format === "hermes-json") {
15356
15267
  const watchPath = canonicalHistory.watchPath.replace(/^~/, os14.homedir()).replace("{{sessionId}}", this.providerSessionId);
15357
- if (!fs5.existsSync(watchPath)) return false;
15268
+ const now = Date.now();
15269
+ if (watchPath !== this.lastCanonicalHermesWatchPath || now - this.lastCanonicalHermesExistCheckAt >= 2e3) {
15270
+ this.lastCanonicalHermesWatchPath = watchPath;
15271
+ this.lastCanonicalHermesExistCheckAt = now;
15272
+ if (!fs5.existsSync(watchPath)) return false;
15273
+ } else if (this.lastCanonicalHermesSyncMtimeMs === 0) {
15274
+ if (!fs5.existsSync(watchPath)) return false;
15275
+ }
15358
15276
  const stat4 = fs5.statSync(watchPath);
15359
15277
  if (stat4.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
15360
15278
  rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
15361
15279
  if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat4.mtimeMs;
15362
15280
  } else if (canonicalHistory.format === "claude-jsonl") {
15281
+ const now = Date.now();
15282
+ if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
15283
+ return true;
15284
+ }
15285
+ this.lastCanonicalClaudeCheckAt = now;
15286
+ const claudeProjectsDir = path12.join(os14.homedir(), ".claude", "projects");
15287
+ const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
15288
+ const transcriptFile = path12.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
15289
+ let transcriptMtime = 0;
15290
+ try {
15291
+ transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
15292
+ } catch {
15293
+ }
15294
+ if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
15363
15295
  rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
15296
+ if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
15364
15297
  }
15365
15298
  if (!rebuilt) return false;
15366
15299
  const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
@@ -15425,20 +15358,29 @@ ${effect.notification.body || ""}`.trim();
15425
15358
  return Array.from({ length: count }, () => "?").join(", ");
15426
15359
  }
15427
15360
  querySqliteText(dbPath, query, params) {
15428
- let db = null;
15429
15361
  try {
15430
- const DatabaseSync = getDatabaseSync();
15431
- db = new DatabaseSync(dbPath, { readOnly: true });
15432
- const row = db.prepare(query).get(...params);
15362
+ if (this.cachedSqliteDb === null || this.cachedSqliteDbPath !== dbPath) {
15363
+ try {
15364
+ this.cachedSqliteDb?.close();
15365
+ } catch {
15366
+ }
15367
+ this.cachedSqliteDb = null;
15368
+ this.cachedSqliteDbPath = null;
15369
+ const DatabaseSync = getDatabaseSync();
15370
+ this.cachedSqliteDb = new DatabaseSync(dbPath, { readOnly: true });
15371
+ this.cachedSqliteDbPath = dbPath;
15372
+ }
15373
+ const row = this.cachedSqliteDb.prepare(query).get(...params);
15433
15374
  const sessionId = typeof row?.id === "string" ? row.id.trim() : "";
15434
15375
  return sessionId || null;
15435
15376
  } catch {
15436
- return null;
15437
- } finally {
15438
15377
  try {
15439
- db?.close();
15378
+ this.cachedSqliteDb?.close();
15440
15379
  } catch {
15441
15380
  }
15381
+ this.cachedSqliteDb = null;
15382
+ this.cachedSqliteDbPath = null;
15383
+ return null;
15442
15384
  }
15443
15385
  }
15444
15386
  };
@@ -35605,6 +35547,7 @@ var init_provider_schema = __esm({
35605
35547
  "canonicalHistory",
35606
35548
  "autoFixProfile",
35607
35549
  "ideLevelScripts",
35550
+ "allowInputDuringGeneration",
35608
35551
  "scripts",
35609
35552
  "vscodeCommands",
35610
35553
  "inputMethod",
@@ -87130,7 +87073,7 @@ var init_adhdev_daemon = __esm({
87130
87073
  init_version();
87131
87074
  init_src();
87132
87075
  init_runtime_defaults();
87133
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.5" });
87076
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.8" });
87134
87077
  AdhdevDaemon = class _AdhdevDaemon {
87135
87078
  localHttpServer = null;
87136
87079
  localWss = null;
@@ -92820,7 +92763,7 @@ function registerProviderCommands(program2) {
92820
92763
  process.exit(1);
92821
92764
  }
92822
92765
  });
92823
- provider.command("fix [type] [scripts...]").description("Auto-implement provider scripts using AI for IDE DOM or CLI PTY parsing").option("-a, --agent <agent>", "AI agent to use (e.g. claude-cli, gemini-cli, codex-cli, or any ACP provider like cline-acp)", "codex-cli").option("-m, --model <model>", "Model override (e.g. claude-sonnet-3.5, gemini-2.0-pro)").option("-r, --reference <ref>", "Reference provider to learn from").option("-c, --comment <text>", "Additional instructions for the AI agent").action(async (typeArg, scripts, options) => {
92766
+ provider.command("fix [type] [scripts...]").description("Auto-implement provider scripts using AI for IDE DOM or CLI PTY parsing").option("-a, --agent <agent>", "AI agent to use (e.g. claude-cli, gemini-cli, codex-cli, or any ACP provider like cline-acp)").option("-m, --model <model>", "Model override (e.g. claude-sonnet-3.5, gemini-2.0-pro)").option("-r, --reference <ref>", "Reference provider to learn from").option("-c, --comment <text>", "Additional instructions for the AI agent").action(async (typeArg, scripts, options) => {
92824
92767
  try {
92825
92768
  const http3 = await import("http");
92826
92769
  const inquirer2 = (await Promise.resolve().then(() => (init_lib(), lib_exports))).default;