adhdev 0.9.6 → 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 +380 -487
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +380 -487
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 (
|
|
8828
|
+
if (!effectiveModal) {
|
|
8829
8829
|
return { success: false, error: "Not in approval state" };
|
|
8830
8830
|
}
|
|
8831
|
-
const buttons = effectiveModal
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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}
|
|
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:
|
|
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
|
-
|
|
13122
|
-
|
|
13123
|
-
const
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
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
|
|
13218
|
+
const modal = this.runParseApproval(tail) || parsedModal;
|
|
13199
13219
|
const rawScriptStatus = this.runDetectStatus(tail);
|
|
13200
|
-
const scriptStatus =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
13272
|
-
|
|
13273
|
-
|
|
13274
|
-
|
|
13275
|
-
|
|
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
|
|
13298
|
-
if (
|
|
13299
|
-
|
|
13300
|
-
|
|
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
|
-
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
this.
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
|
|
13342
|
-
|
|
13343
|
-
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
this.
|
|
13348
|
-
|
|
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
|
-
|
|
13351
|
-
|
|
13352
|
-
this.setStatus("
|
|
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.
|
|
13356
|
-
|
|
13357
|
-
|
|
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 (
|
|
13361
|
-
|
|
13362
|
-
|
|
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
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
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.
|
|
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 (
|
|
13392
|
-
if (
|
|
13393
|
-
|
|
13394
|
-
|
|
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
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
|
|
13418
|
-
|
|
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;
|
|
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");
|
|
13464
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
|
-
|
|
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
|
|
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
|
-
|
|
13555
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
13702
|
+
status: resolvedStatus,
|
|
13724
13703
|
activeModal: null
|
|
13725
13704
|
};
|
|
13726
13705
|
}
|
|
13727
13706
|
// ─── Public API (CliAdapter) ───────────────────
|
|
13728
13707
|
getStatus() {
|
|
13729
|
-
const
|
|
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
|
|
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
|
-
|
|
13947
|
-
|
|
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
|
|
13980
|
-
|
|
13981
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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 {
|
|
@@ -87180,7 +87073,7 @@ var init_adhdev_daemon = __esm({
|
|
|
87180
87073
|
init_version();
|
|
87181
87074
|
init_src();
|
|
87182
87075
|
init_runtime_defaults();
|
|
87183
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
87076
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.8" });
|
|
87184
87077
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
87185
87078
|
localHttpServer = null;
|
|
87186
87079
|
localWss = null;
|