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 +440 -497
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +439 -496
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8305,25 +8305,23 @@ async function handleResolveAction(h, args) {
|
|
|
8305
8305
|
const effectiveModal = statusModal || surfacedModal;
|
|
8306
8306
|
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
8307
8307
|
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"}`);
|
|
8308
|
-
if (
|
|
8308
|
+
if (!effectiveModal) {
|
|
8309
8309
|
return { success: false, error: "Not in approval state" };
|
|
8310
8310
|
}
|
|
8311
|
-
const buttons = effectiveModal
|
|
8311
|
+
const buttons = Array.isArray(effectiveModal.buttons) ? effectiveModal.buttons : [];
|
|
8312
8312
|
let buttonIndex = typeof args?.buttonIndex === "number" ? args.buttonIndex : -1;
|
|
8313
|
-
if (buttonIndex < 0) {
|
|
8313
|
+
if (buttonIndex < 0 && button) {
|
|
8314
8314
|
const btnLower = button.toLowerCase();
|
|
8315
8315
|
buttonIndex = buttons.findIndex((b) => b.toLowerCase().includes(btnLower));
|
|
8316
8316
|
}
|
|
8317
|
+
if (buttonIndex < 0 && (action === "reject" || action === "deny")) {
|
|
8318
|
+
buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
|
|
8319
|
+
}
|
|
8320
|
+
if (buttonIndex < 0 && (action === "always" || /always/i.test(button))) {
|
|
8321
|
+
buttonIndex = buttons.findIndex((b) => /always/i.test(b));
|
|
8322
|
+
}
|
|
8317
8323
|
if (buttonIndex < 0) {
|
|
8318
|
-
|
|
8319
|
-
buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
|
|
8320
|
-
if (buttonIndex < 0) buttonIndex = buttons.length - 1;
|
|
8321
|
-
} else if (action === "always" || /always/i.test(button)) {
|
|
8322
|
-
buttonIndex = buttons.findIndex((b) => /always/i.test(b));
|
|
8323
|
-
if (buttonIndex < 0) buttonIndex = 1;
|
|
8324
|
-
} else {
|
|
8325
|
-
buttonIndex = 0;
|
|
8326
|
-
}
|
|
8324
|
+
return { success: false, error: "Approval action did not match any visible button" };
|
|
8327
8325
|
}
|
|
8328
8326
|
if (typeof adapter.resolveModal === "function") {
|
|
8329
8327
|
adapter.resolveModal(buttonIndex);
|
|
@@ -11132,8 +11130,35 @@ function promptLikelyVisible(screenText, promptSnippet) {
|
|
|
11132
11130
|
function normalizeScreenSnapshot(text) {
|
|
11133
11131
|
return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
|
|
11134
11132
|
}
|
|
11133
|
+
function shouldReflowComparableMessageLines(lines) {
|
|
11134
|
+
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));
|
|
11135
|
+
}
|
|
11136
|
+
function joinComparableMessageLines(lines) {
|
|
11137
|
+
return lines.reduce((acc, line) => {
|
|
11138
|
+
const next = String(line || "").trim();
|
|
11139
|
+
if (!next) return acc;
|
|
11140
|
+
if (!acc) return next;
|
|
11141
|
+
if (/[,\d]$/.test(acc) && /^\d/.test(next)) {
|
|
11142
|
+
return `${acc}${next}`;
|
|
11143
|
+
}
|
|
11144
|
+
if (/[A-Za-z]$/.test(acc) && /^\d/.test(next)) {
|
|
11145
|
+
return `${acc}${next}`;
|
|
11146
|
+
}
|
|
11147
|
+
const fragmentMatch = acc.match(/([A-Za-z]{1,4})$/);
|
|
11148
|
+
const fragment = fragmentMatch ? fragmentMatch[1].toLowerCase() : "";
|
|
11149
|
+
if (/^[a-z]/.test(next) && fragment && !COMMON_COMPARABLE_WRAP_WORDS.has(fragment)) {
|
|
11150
|
+
return `${acc}${next}`;
|
|
11151
|
+
}
|
|
11152
|
+
return `${acc} ${next}`;
|
|
11153
|
+
}, "").replace(/\s+([,.;:!?])/g, "$1").replace(/(\d)\s+,/g, "$1,").replace(/\s+/g, " ").trim();
|
|
11154
|
+
}
|
|
11135
11155
|
function normalizeComparableMessageContent(text) {
|
|
11136
|
-
|
|
11156
|
+
const lines = String(text || "").split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
|
|
11157
|
+
if (lines.length === 0) return "";
|
|
11158
|
+
if (shouldReflowComparableMessageLines(lines)) {
|
|
11159
|
+
return joinComparableMessageLines(lines);
|
|
11160
|
+
}
|
|
11161
|
+
return lines.join(" ").replace(/\s+/g, " ").trim();
|
|
11137
11162
|
}
|
|
11138
11163
|
function trimPromptEchoPrefix(text, promptText) {
|
|
11139
11164
|
const prompt2 = normalizeComparableMessageContent(String(promptText || ""));
|
|
@@ -11166,9 +11191,6 @@ function getLastUserPromptText(messages) {
|
|
|
11166
11191
|
}
|
|
11167
11192
|
return "";
|
|
11168
11193
|
}
|
|
11169
|
-
function looksLikeConfirmOnlyLabel(label) {
|
|
11170
|
-
return /^(?:continue|confirm|ok|yes|trust|proceed|enter)$/i.test(String(label || "").trim());
|
|
11171
|
-
}
|
|
11172
11194
|
function parsePatternEntry(x) {
|
|
11173
11195
|
if (x instanceof RegExp) return x;
|
|
11174
11196
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
@@ -11195,7 +11217,7 @@ function normalizeCliProviderForRuntime(raw) {
|
|
|
11195
11217
|
}
|
|
11196
11218
|
};
|
|
11197
11219
|
}
|
|
11198
|
-
var os10, path9, import_child_process4, buildCliSpawnEnv;
|
|
11220
|
+
var os10, path9, import_child_process4, buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
|
|
11199
11221
|
var init_provider_cli_shared = __esm({
|
|
11200
11222
|
"../../oss/packages/daemon-core/src/cli-adapters/provider-cli-shared.ts"() {
|
|
11201
11223
|
"use strict";
|
|
@@ -11204,6 +11226,32 @@ var init_provider_cli_shared = __esm({
|
|
|
11204
11226
|
import_child_process4 = require("child_process");
|
|
11205
11227
|
init_spawn_env();
|
|
11206
11228
|
buildCliSpawnEnv = sanitizeSpawnEnv;
|
|
11229
|
+
COMMON_COMPARABLE_WRAP_WORDS = /* @__PURE__ */ new Set([
|
|
11230
|
+
"a",
|
|
11231
|
+
"an",
|
|
11232
|
+
"and",
|
|
11233
|
+
"as",
|
|
11234
|
+
"at",
|
|
11235
|
+
"but",
|
|
11236
|
+
"by",
|
|
11237
|
+
"for",
|
|
11238
|
+
"from",
|
|
11239
|
+
"in",
|
|
11240
|
+
"into",
|
|
11241
|
+
"is",
|
|
11242
|
+
"it",
|
|
11243
|
+
"of",
|
|
11244
|
+
"on",
|
|
11245
|
+
"or",
|
|
11246
|
+
"that",
|
|
11247
|
+
"the",
|
|
11248
|
+
"their",
|
|
11249
|
+
"then",
|
|
11250
|
+
"this",
|
|
11251
|
+
"to",
|
|
11252
|
+
"was",
|
|
11253
|
+
"with"
|
|
11254
|
+
]);
|
|
11207
11255
|
}
|
|
11208
11256
|
});
|
|
11209
11257
|
|
|
@@ -11259,8 +11307,44 @@ function hydrateCliParsedMessages(parsedMessages, options) {
|
|
|
11259
11307
|
};
|
|
11260
11308
|
});
|
|
11261
11309
|
}
|
|
11310
|
+
function chooseMoreComparableCliMessage(left2, right2) {
|
|
11311
|
+
const leftComparable = normalizeComparableMessageContent(left2.content || "");
|
|
11312
|
+
const rightComparable = normalizeComparableMessageContent(right2.content || "");
|
|
11313
|
+
if (leftComparable && leftComparable === rightComparable) {
|
|
11314
|
+
const leftNewlines = String(left2.content || "").split(/\r\n|\n|\r/g).length - 1;
|
|
11315
|
+
const rightNewlines = String(right2.content || "").split(/\r\n|\n|\r/g).length - 1;
|
|
11316
|
+
return rightNewlines < leftNewlines ? right2 : left2;
|
|
11317
|
+
}
|
|
11318
|
+
return rightComparable.length > leftComparable.length ? right2 : left2;
|
|
11319
|
+
}
|
|
11320
|
+
function dedupeConsecutiveComparableCliMessages(messages) {
|
|
11321
|
+
const deduped = [];
|
|
11322
|
+
for (const message of messages) {
|
|
11323
|
+
const current = {
|
|
11324
|
+
...message,
|
|
11325
|
+
content: typeof message.content === "string" ? message.content : String(message.content || "")
|
|
11326
|
+
};
|
|
11327
|
+
const previous = deduped[deduped.length - 1];
|
|
11328
|
+
if (!previous) {
|
|
11329
|
+
deduped.push(current);
|
|
11330
|
+
continue;
|
|
11331
|
+
}
|
|
11332
|
+
const previousComparable = normalizeComparableMessageContent(previous.content || "");
|
|
11333
|
+
const currentComparable = normalizeComparableMessageContent(current.content || "");
|
|
11334
|
+
const sameRole = previous.role === current.role;
|
|
11335
|
+
const sameKind = (previous.kind || "standard") === (current.kind || "standard");
|
|
11336
|
+
const sameSender = (previous.senderName || "") === (current.senderName || "");
|
|
11337
|
+
const comparableMatch = previousComparable && previousComparable === currentComparable;
|
|
11338
|
+
if (sameRole && sameKind && sameSender && comparableMatch) {
|
|
11339
|
+
deduped[deduped.length - 1] = chooseMoreComparableCliMessage(previous, current);
|
|
11340
|
+
continue;
|
|
11341
|
+
}
|
|
11342
|
+
deduped.push(current);
|
|
11343
|
+
}
|
|
11344
|
+
return deduped;
|
|
11345
|
+
}
|
|
11262
11346
|
function normalizeCliParsedMessages(parsedMessages, options) {
|
|
11263
|
-
return hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
|
|
11347
|
+
return dedupeConsecutiveComparableCliMessages(hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
|
|
11264
11348
|
role: message.role,
|
|
11265
11349
|
content: message.content,
|
|
11266
11350
|
timestamp: message.timestamp,
|
|
@@ -11270,7 +11354,7 @@ function normalizeCliParsedMessages(parsedMessages, options) {
|
|
|
11270
11354
|
index: message.index,
|
|
11271
11355
|
meta: message.meta,
|
|
11272
11356
|
senderName: message.senderName
|
|
11273
|
-
}));
|
|
11357
|
+
})));
|
|
11274
11358
|
}
|
|
11275
11359
|
function buildCliParseInput(options) {
|
|
11276
11360
|
const {
|
|
@@ -11933,7 +12017,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
11933
12017
|
if (!hasStartupOutput) return;
|
|
11934
12018
|
const stableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
11935
12019
|
if (stableMs < 2e3) return;
|
|
11936
|
-
const startupModal = this.
|
|
12020
|
+
const startupModal = this.runParseApproval(this.recentOutputBuffer);
|
|
11937
12021
|
this.startupParseGate = false;
|
|
11938
12022
|
if (this.startupSettleTimer) {
|
|
11939
12023
|
clearTimeout(this.startupSettleTimer);
|
|
@@ -11990,11 +12074,17 @@ var init_provider_cli_adapter = __esm({
|
|
|
11990
12074
|
if (this.currentStatus !== "waiting_approval") return;
|
|
11991
12075
|
const tail = this.recentOutputBuffer;
|
|
11992
12076
|
const screenText = this.terminalScreen.getText() || "";
|
|
11993
|
-
const
|
|
11994
|
-
const modal = this.runParseApproval(tail) || startupModal;
|
|
12077
|
+
const modal = this.runParseApproval(tail);
|
|
11995
12078
|
const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
|
|
11996
12079
|
if (stillWaiting) {
|
|
11997
|
-
|
|
12080
|
+
if (!modal) {
|
|
12081
|
+
LOG.warn("CLI", `[${this.cliType}] approval timeout check found no actionable modal; keeping approval state fail-closed`);
|
|
12082
|
+
this.activeModal = null;
|
|
12083
|
+
this.onStatusChange?.();
|
|
12084
|
+
this.armApprovalExitTimeout();
|
|
12085
|
+
return;
|
|
12086
|
+
}
|
|
12087
|
+
this.activeModal = modal;
|
|
11998
12088
|
this.onStatusChange?.();
|
|
11999
12089
|
this.armApprovalExitTimeout();
|
|
12000
12090
|
return;
|
|
@@ -12006,81 +12096,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
12006
12096
|
this.onStatusChange?.();
|
|
12007
12097
|
}, 6e4);
|
|
12008
12098
|
}
|
|
12009
|
-
looksLikeVisibleIdlePrompt(screenText) {
|
|
12010
|
-
const text = String(screenText || "");
|
|
12011
|
-
if (!text.trim()) return false;
|
|
12012
|
-
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)) {
|
|
12013
|
-
return true;
|
|
12014
|
-
}
|
|
12015
|
-
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);
|
|
12016
|
-
}
|
|
12017
|
-
findLastMatchingLineIndex(lines, predicate) {
|
|
12018
|
-
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
12019
|
-
if (predicate(lines[index])) return index;
|
|
12020
|
-
}
|
|
12021
|
-
return -1;
|
|
12022
|
-
}
|
|
12023
|
-
looksLikeClaudeGeneratingLine(line) {
|
|
12024
|
-
const trimmed = String(line || "").trim();
|
|
12025
|
-
if (!trimmed) return false;
|
|
12026
|
-
if (/^⏵⏵\s+accept edits on/i.test(trimmed)) return false;
|
|
12027
|
-
if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) return true;
|
|
12028
|
-
if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+\S+.*\b(?:thinking|thought for \d+s?)\b/i.test(trimmed)) return true;
|
|
12029
|
-
if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+[A-Z][A-Za-z-]{3,}ing\b.*(?:…|\.{3})/u.test(trimmed)) return true;
|
|
12030
|
-
if (/^[⏺•]\s+(?:Reading|Writing|Editing|Searching|Inspecting|Planning|Analyzing|Synthesizing|Drafting|Running|Listing|Scanning|Matching)\b.*(?:…|\.{3})/i.test(trimmed)) {
|
|
12031
|
-
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);
|
|
12032
|
-
}
|
|
12033
|
-
return false;
|
|
12034
|
-
}
|
|
12035
|
-
detectClaudeGeneratingOverride(screenText, tail) {
|
|
12036
|
-
if (this.cliType !== "claude-cli") return false;
|
|
12037
|
-
const source = sanitizeTerminalText(screenText || tail || "");
|
|
12038
|
-
if (!source.trim()) return false;
|
|
12039
|
-
const allLines = source.split(/\r\n|\n|\r/g).map((line) => line.trim()).filter(Boolean);
|
|
12040
|
-
if (allLines.length === 0) return false;
|
|
12041
|
-
const recentLines = allLines.slice(-12);
|
|
12042
|
-
const promptIndex = this.findLastMatchingLineIndex(recentLines, (line) => /^[❯›>]\s*$/.test(line));
|
|
12043
|
-
const activeRegion = promptIndex >= 0 ? recentLines.slice(Math.max(0, promptIndex - 2), promptIndex) : recentLines;
|
|
12044
|
-
if (activeRegion.length === 0) return false;
|
|
12045
|
-
return activeRegion.some((line) => this.looksLikeClaudeGeneratingLine(line));
|
|
12046
|
-
}
|
|
12047
|
-
refineDetectedStatus(status, tail, screenText) {
|
|
12048
|
-
if (this.startupParseGate) {
|
|
12049
|
-
return this.getStartupConfirmationModal(screenText || "") ? "waiting_approval" : "starting";
|
|
12050
|
-
}
|
|
12051
|
-
if (status === "waiting_approval") return status;
|
|
12052
|
-
if (this.detectClaudeGeneratingOverride(screenText || "", tail)) return "generating";
|
|
12053
|
-
return status;
|
|
12054
|
-
}
|
|
12055
|
-
looksLikeVisibleAssistantCandidate(screenText) {
|
|
12056
|
-
const lines = sanitizeTerminalText(String(screenText || "")).split(/\r\n|\n|\r/g);
|
|
12057
|
-
for (const line of lines) {
|
|
12058
|
-
const trimmed = String(line || "").trim();
|
|
12059
|
-
if (!trimmed) continue;
|
|
12060
|
-
if (/^➜\s+\S+/.test(trimmed)) continue;
|
|
12061
|
-
if (/^Update available!/i.test(trimmed)) continue;
|
|
12062
|
-
if (/Claude Code v\d/i.test(trimmed)) continue;
|
|
12063
|
-
if (/^⏵⏵\s+accept edits on/i.test(trimmed)) continue;
|
|
12064
|
-
if (/^[◐◑◒◓◴◵◶◷◸◹◺◿].*\/effort/i.test(trimmed)) continue;
|
|
12065
|
-
if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+$/.test(trimmed)) continue;
|
|
12066
|
-
if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) continue;
|
|
12067
|
-
const assistantMatch = trimmed.match(/^⏺\s+(.+)$/);
|
|
12068
|
-
if (!assistantMatch) continue;
|
|
12069
|
-
const content = assistantMatch[1].trim();
|
|
12070
|
-
if (!content) continue;
|
|
12071
|
-
if (/^(?:Bash|Read|Write|Edit|MultiEdit|Task|Glob|Grep|LS|NotebookEdit)\(/.test(content)) continue;
|
|
12072
|
-
if (/This command requires approval|Do you want to proceed|Allow once|Always allow/i.test(content)) continue;
|
|
12073
|
-
return true;
|
|
12074
|
-
}
|
|
12075
|
-
return false;
|
|
12076
|
-
}
|
|
12077
12099
|
shouldRetryFinishResponse(commitResult) {
|
|
12078
12100
|
if (!this.currentTurnScope) return false;
|
|
12079
12101
|
if (this.currentStatus === "waiting_approval" || this.activeModal) return false;
|
|
12080
12102
|
if (this.finishRetryCount >= _ProviderCliAdapter.MAX_FINISH_RETRIES) return false;
|
|
12081
12103
|
if (commitResult.hasAssistant && commitResult.assistantContent.trim()) return false;
|
|
12082
|
-
|
|
12083
|
-
if (!this.looksLikeVisibleAssistantCandidate(screenText)) return false;
|
|
12104
|
+
if (this.runDetectStatus(this.recentOutputBuffer) !== "idle") return false;
|
|
12084
12105
|
const now = Date.now();
|
|
12085
12106
|
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
12086
12107
|
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
@@ -12104,45 +12125,21 @@ var init_provider_cli_adapter = __esm({
|
|
|
12104
12125
|
}
|
|
12105
12126
|
return false;
|
|
12106
12127
|
}
|
|
12107
|
-
getStartupConfirmationModal(screenText) {
|
|
12108
|
-
const text = sanitizeTerminalText(String(screenText || ""));
|
|
12109
|
-
if (!text.trim()) return null;
|
|
12110
|
-
if (this.cliType === "claude-cli") {
|
|
12111
|
-
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);
|
|
12112
|
-
const hasConfirmFooter = /Press Enter to (?:continue|confirm)/i.test(text) || /Enter to confirm/i.test(text) || /Esc to (?:cancel|exit)/i.test(text);
|
|
12113
|
-
if (hasTrustPrompt || hasConfirmFooter && /trust/i.test(text)) {
|
|
12114
|
-
return {
|
|
12115
|
-
message: "Confirm Claude Code project trust",
|
|
12116
|
-
buttons: ["Continue"]
|
|
12117
|
-
};
|
|
12118
|
-
}
|
|
12119
|
-
}
|
|
12120
|
-
return null;
|
|
12121
|
-
}
|
|
12122
|
-
shouldResolveModalWithEnter(modal, buttonIndex) {
|
|
12123
|
-
if (!modal || buttonIndex !== 0) return false;
|
|
12124
|
-
const buttons = Array.isArray(modal.buttons) ? modal.buttons : [];
|
|
12125
|
-
if (buttons.length !== 1) return false;
|
|
12126
|
-
const buttonLabel = String(buttons[0] || "").trim();
|
|
12127
|
-
return looksLikeConfirmOnlyLabel(buttonLabel);
|
|
12128
|
-
}
|
|
12129
12128
|
async waitForInteractivePrompt(maxWaitMs = 5e3) {
|
|
12130
12129
|
const startedAt = Date.now();
|
|
12131
12130
|
let loggedWait = false;
|
|
12132
12131
|
while (Date.now() - startedAt < maxWaitMs) {
|
|
12133
12132
|
this.resolveStartupState("interactive_wait");
|
|
12134
12133
|
const screenText = this.terminalScreen.getText() || "";
|
|
12135
|
-
const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
12136
12134
|
const stableMs = this.lastScreenChangeAt ? Date.now() - this.lastScreenChangeAt : 0;
|
|
12137
12135
|
const recentlyOutput = this.lastNonEmptyOutputAt ? Date.now() - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
12138
12136
|
const status = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
|
|
12139
|
-
const
|
|
12140
|
-
const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "generating";
|
|
12137
|
+
const interactiveReady = status === "idle" && stableMs >= 700 && recentlyOutput >= 350;
|
|
12141
12138
|
if (interactiveReady) {
|
|
12142
12139
|
if (loggedWait) {
|
|
12143
12140
|
LOG.info(
|
|
12144
12141
|
"CLI",
|
|
12145
|
-
`[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput}
|
|
12142
|
+
`[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput})`
|
|
12146
12143
|
);
|
|
12147
12144
|
}
|
|
12148
12145
|
return;
|
|
@@ -12151,7 +12148,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12151
12148
|
loggedWait = true;
|
|
12152
12149
|
LOG.info(
|
|
12153
12150
|
"CLI",
|
|
12154
|
-
`[${this.cliType}] Waiting for interactive prompt:
|
|
12151
|
+
`[${this.cliType}] Waiting for interactive prompt: status=${status} stableMs=${stableMs} recentOutputMs=${recentlyOutput} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
|
|
12155
12152
|
);
|
|
12156
12153
|
}
|
|
12157
12154
|
await new Promise((resolve16) => setTimeout(resolve16, 50));
|
|
@@ -12162,13 +12159,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
12162
12159
|
`[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
|
|
12163
12160
|
);
|
|
12164
12161
|
}
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
const
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
}
|
|
12162
|
+
trimLastAssistantEcho(messages, prompt2) {
|
|
12163
|
+
if (!prompt2) return;
|
|
12164
|
+
const last = [...messages].reverse().find((m) => m.role === "assistant" && typeof m.content === "string");
|
|
12165
|
+
if (last) last.content = trimPromptEchoPrefix(last.content, prompt2);
|
|
12166
|
+
}
|
|
12167
|
+
clearAllTimers() {
|
|
12172
12168
|
if (this.responseTimeout) {
|
|
12173
12169
|
clearTimeout(this.responseTimeout);
|
|
12174
12170
|
this.responseTimeout = null;
|
|
@@ -12181,10 +12177,38 @@ var init_provider_cli_adapter = __esm({
|
|
|
12181
12177
|
clearTimeout(this.approvalExitTimeout);
|
|
12182
12178
|
this.approvalExitTimeout = null;
|
|
12183
12179
|
}
|
|
12180
|
+
if (this.submitRetryTimer) {
|
|
12181
|
+
clearTimeout(this.submitRetryTimer);
|
|
12182
|
+
this.submitRetryTimer = null;
|
|
12183
|
+
}
|
|
12184
12184
|
if (this.finishRetryTimer) {
|
|
12185
12185
|
clearTimeout(this.finishRetryTimer);
|
|
12186
12186
|
this.finishRetryTimer = null;
|
|
12187
12187
|
}
|
|
12188
|
+
if (this.settleTimer) {
|
|
12189
|
+
clearTimeout(this.settleTimer);
|
|
12190
|
+
this.settleTimer = null;
|
|
12191
|
+
}
|
|
12192
|
+
if (this.pendingScriptStatusTimer) {
|
|
12193
|
+
clearTimeout(this.pendingScriptStatusTimer);
|
|
12194
|
+
this.pendingScriptStatusTimer = null;
|
|
12195
|
+
}
|
|
12196
|
+
if (this.pendingOutputParseTimer) {
|
|
12197
|
+
clearTimeout(this.pendingOutputParseTimer);
|
|
12198
|
+
this.pendingOutputParseTimer = null;
|
|
12199
|
+
}
|
|
12200
|
+
if (this.ptyOutputFlushTimer) {
|
|
12201
|
+
clearTimeout(this.ptyOutputFlushTimer);
|
|
12202
|
+
this.ptyOutputFlushTimer = null;
|
|
12203
|
+
}
|
|
12204
|
+
}
|
|
12205
|
+
clearStaleIdleResponseGuard(reason) {
|
|
12206
|
+
const blockingModal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
|
|
12207
|
+
const isIdle = this.runDetectStatus(this.recentOutputBuffer) === "idle";
|
|
12208
|
+
if (!this.isWaitingForResponse || this.currentStatus !== "idle" || !isIdle || !!blockingModal) {
|
|
12209
|
+
return false;
|
|
12210
|
+
}
|
|
12211
|
+
this.clearAllTimers();
|
|
12188
12212
|
this.clearIdleFinishCandidate(reason);
|
|
12189
12213
|
this.responseBuffer = "";
|
|
12190
12214
|
this.isWaitingForResponse = false;
|
|
@@ -12194,10 +12218,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12194
12218
|
this.finishRetryCount = 0;
|
|
12195
12219
|
this.currentTurnScope = null;
|
|
12196
12220
|
this.activeModal = null;
|
|
12197
|
-
this.recordTrace("stale_idle_response_cleared", {
|
|
12198
|
-
reason,
|
|
12199
|
-
screenText: summarizeCliTraceText(screenText, 240)
|
|
12200
|
-
});
|
|
12221
|
+
this.recordTrace("stale_idle_response_cleared", { reason });
|
|
12201
12222
|
return true;
|
|
12202
12223
|
}
|
|
12203
12224
|
hasMeaningfulResponseBuffer(promptSnippet) {
|
|
@@ -12232,16 +12253,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
12232
12253
|
if (this.startupParseGate) {
|
|
12233
12254
|
return;
|
|
12234
12255
|
}
|
|
12235
|
-
const startupModal = this.getStartupConfirmationModal(screenText);
|
|
12236
12256
|
const parsedTranscript = this.parseCurrentTranscript(
|
|
12237
12257
|
this.committedMessages,
|
|
12238
12258
|
this.responseBuffer,
|
|
12239
12259
|
this.currentTurnScope
|
|
12240
12260
|
);
|
|
12241
12261
|
const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsedTranscript.activeModal : null;
|
|
12242
|
-
const modal = this.runParseApproval(tail) || parsedModal
|
|
12262
|
+
const modal = this.runParseApproval(tail) || parsedModal;
|
|
12243
12263
|
const rawScriptStatus = this.runDetectStatus(tail);
|
|
12244
|
-
const scriptStatus =
|
|
12264
|
+
const scriptStatus = parsedTranscript?.status === "waiting_approval" && modal ? "waiting_approval" : rawScriptStatus;
|
|
12245
12265
|
const parsedMessages = Array.isArray(parsedTranscript?.messages) ? normalizeCliParsedMessages(parsedTranscript.messages, {
|
|
12246
12266
|
committedMessages: this.committedMessages,
|
|
12247
12267
|
scope: this.currentTurnScope,
|
|
@@ -12296,15 +12316,44 @@ var init_provider_cli_adapter = __esm({
|
|
|
12296
12316
|
}
|
|
12297
12317
|
if (!scriptStatus) return;
|
|
12298
12318
|
const prevStatus = this.currentStatus;
|
|
12299
|
-
const
|
|
12319
|
+
const ctx = { now, screenText, modal, scriptStatus, parsedTranscript, parsedMessages, lastParsedAssistant, parsedShowsLiveAssistantProgress, prevStatus };
|
|
12320
|
+
if (!this.applyPendingScriptStatusDebounce(ctx)) return;
|
|
12321
|
+
const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
|
|
12322
|
+
LOG.info(
|
|
12323
|
+
"CLI",
|
|
12324
|
+
`[${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)}`
|
|
12325
|
+
);
|
|
12326
|
+
const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(parsedTranscript?.status === "idle" && !!lastParsedAssistant);
|
|
12327
|
+
if (shouldHoldGenerating) {
|
|
12328
|
+
this.applyHoldGenerating(ctx, recentInteractiveActivity);
|
|
12329
|
+
return;
|
|
12330
|
+
}
|
|
12331
|
+
if (scriptStatus === "waiting_approval") {
|
|
12332
|
+
this.applyWaitingApproval(ctx);
|
|
12333
|
+
return;
|
|
12334
|
+
}
|
|
12335
|
+
if (scriptStatus === "generating") {
|
|
12336
|
+
this.applyGenerating(ctx);
|
|
12337
|
+
return;
|
|
12338
|
+
}
|
|
12339
|
+
if (scriptStatus === "idle") {
|
|
12340
|
+
this.applyIdle(ctx, now);
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
12343
|
+
// Returns false if the caller should bail out (debounce pending).
|
|
12344
|
+
applyPendingScriptStatusDebounce(ctx) {
|
|
12345
|
+
const { now, scriptStatus, prevStatus } = ctx;
|
|
12346
|
+
const shouldDebounce = prevStatus === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && (scriptStatus === "generating" || scriptStatus === "waiting_approval");
|
|
12347
|
+
if (!shouldDebounce) {
|
|
12300
12348
|
this.pendingScriptStatus = null;
|
|
12301
12349
|
this.pendingScriptStatusSince = 0;
|
|
12302
12350
|
if (this.pendingScriptStatusTimer) {
|
|
12303
12351
|
clearTimeout(this.pendingScriptStatusTimer);
|
|
12304
12352
|
this.pendingScriptStatusTimer = null;
|
|
12305
12353
|
}
|
|
12306
|
-
|
|
12307
|
-
|
|
12354
|
+
return true;
|
|
12355
|
+
}
|
|
12356
|
+
const armPending = (delayMs) => {
|
|
12308
12357
|
if (this.pendingScriptStatusTimer) clearTimeout(this.pendingScriptStatusTimer);
|
|
12309
12358
|
this.pendingScriptStatusTimer = setTimeout(() => {
|
|
12310
12359
|
this.pendingScriptStatusTimer = null;
|
|
@@ -12312,200 +12361,187 @@ var init_provider_cli_adapter = __esm({
|
|
|
12312
12361
|
this.evaluateSettled();
|
|
12313
12362
|
}, delayMs);
|
|
12314
12363
|
};
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
armPendingScriptStatus(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS);
|
|
12321
|
-
return;
|
|
12322
|
-
}
|
|
12323
|
-
const elapsed = now - this.pendingScriptStatusSince;
|
|
12324
|
-
if (elapsed < _ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS) {
|
|
12325
|
-
armPendingScriptStatus(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS - elapsed);
|
|
12326
|
-
return;
|
|
12327
|
-
}
|
|
12328
|
-
} else {
|
|
12329
|
-
clearPendingScriptStatus();
|
|
12330
|
-
}
|
|
12331
|
-
const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
|
|
12332
|
-
const statusActivityHoldMs = this.getStatusActivityHoldMs();
|
|
12333
|
-
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
12334
|
-
const visibleAssistantCandidate = this.looksLikeVisibleAssistantCandidate(screenText);
|
|
12335
|
-
if (this.currentTurnScope && this.cliType === "claude-cli") {
|
|
12336
|
-
LOG.info(
|
|
12337
|
-
"CLI",
|
|
12338
|
-
`[${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)}`
|
|
12339
|
-
);
|
|
12364
|
+
if (this.pendingScriptStatus !== scriptStatus) {
|
|
12365
|
+
this.pendingScriptStatus = scriptStatus;
|
|
12366
|
+
this.pendingScriptStatusSince = now;
|
|
12367
|
+
armPending(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS);
|
|
12368
|
+
return false;
|
|
12340
12369
|
}
|
|
12341
|
-
const
|
|
12342
|
-
if (
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12346
|
-
this.idleTimeout = setTimeout(() => {
|
|
12347
|
-
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
12348
|
-
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12349
|
-
this.finishResponse();
|
|
12350
|
-
}
|
|
12351
|
-
}, this.timeouts.generatingIdle);
|
|
12352
|
-
this.recordTrace("hold_generating_recent_activity", {
|
|
12353
|
-
scriptStatus,
|
|
12354
|
-
recentInteractiveActivity,
|
|
12355
|
-
lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
|
|
12356
|
-
lastScreenChangeAt: this.lastScreenChangeAt,
|
|
12357
|
-
holdMs: statusActivityHoldMs,
|
|
12358
|
-
...buildCliTraceParseSnapshot({
|
|
12359
|
-
accumulatedBuffer: this.accumulatedBuffer,
|
|
12360
|
-
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
12361
|
-
responseBuffer: this.responseBuffer,
|
|
12362
|
-
partialResponse: this.responseBuffer,
|
|
12363
|
-
scope: this.currentTurnScope
|
|
12364
|
-
})
|
|
12365
|
-
});
|
|
12366
|
-
this.onStatusChange?.();
|
|
12367
|
-
return;
|
|
12370
|
+
const elapsed = now - this.pendingScriptStatusSince;
|
|
12371
|
+
if (elapsed < _ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS) {
|
|
12372
|
+
armPending(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS - elapsed);
|
|
12373
|
+
return false;
|
|
12368
12374
|
}
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
this.
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
this.
|
|
12392
|
-
|
|
12375
|
+
return true;
|
|
12376
|
+
}
|
|
12377
|
+
applyHoldGenerating(ctx, recentInteractiveActivity) {
|
|
12378
|
+
const { scriptStatus } = ctx;
|
|
12379
|
+
this.clearIdleFinishCandidate("hold_generating_recent_activity");
|
|
12380
|
+
this.setStatus("generating", "recent_activity_hold");
|
|
12381
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12382
|
+
this.idleTimeout = setTimeout(() => {
|
|
12383
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
12384
|
+
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12385
|
+
this.finishResponse();
|
|
12386
|
+
}
|
|
12387
|
+
}, this.timeouts.generatingIdle);
|
|
12388
|
+
this.recordTrace("hold_generating_recent_activity", {
|
|
12389
|
+
scriptStatus,
|
|
12390
|
+
recentInteractiveActivity,
|
|
12391
|
+
lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
|
|
12392
|
+
lastScreenChangeAt: this.lastScreenChangeAt,
|
|
12393
|
+
holdMs: this.getStatusActivityHoldMs(),
|
|
12394
|
+
...buildCliTraceParseSnapshot({
|
|
12395
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
12396
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
12397
|
+
responseBuffer: this.responseBuffer,
|
|
12398
|
+
partialResponse: this.responseBuffer,
|
|
12399
|
+
scope: this.currentTurnScope
|
|
12400
|
+
})
|
|
12401
|
+
});
|
|
12402
|
+
this.onStatusChange?.();
|
|
12403
|
+
}
|
|
12404
|
+
applyWaitingApproval(ctx) {
|
|
12405
|
+
const { modal } = ctx;
|
|
12406
|
+
this.clearIdleFinishCandidate("waiting_approval");
|
|
12407
|
+
const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
|
|
12408
|
+
if (inCooldown && !modal) {
|
|
12409
|
+
if (this.approvalExitTimeout) {
|
|
12410
|
+
clearTimeout(this.approvalExitTimeout);
|
|
12411
|
+
this.approvalExitTimeout = null;
|
|
12393
12412
|
}
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
this.setStatus("
|
|
12397
|
-
this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
12413
|
+
this.activeModal = null;
|
|
12414
|
+
if (this.isWaitingForResponse) {
|
|
12415
|
+
this.setStatus("generating", inCooldown ? "approval_cooldown_ignore" : "approval_prompt_gone");
|
|
12398
12416
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12399
|
-
this.
|
|
12400
|
-
|
|
12401
|
-
|
|
12417
|
+
this.idleTimeout = setTimeout(() => {
|
|
12418
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
12419
|
+
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12420
|
+
this.finishResponse();
|
|
12421
|
+
}
|
|
12422
|
+
}, this.timeouts.generatingIdle);
|
|
12423
|
+
} else {
|
|
12424
|
+
this.setStatus("idle", inCooldown ? "approval_cooldown_ignore" : "approval_prompt_gone");
|
|
12402
12425
|
}
|
|
12426
|
+
this.onStatusChange?.();
|
|
12427
|
+
return;
|
|
12403
12428
|
}
|
|
12404
|
-
if (
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
const noActiveTurn = !this.currentTurnScope;
|
|
12408
|
-
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));
|
|
12409
|
-
if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
|
|
12429
|
+
if (!inCooldown) {
|
|
12430
|
+
if (!modal) {
|
|
12431
|
+
LOG.warn("CLI", `[${this.cliType}] detectStatus reported waiting_approval without parseApproval modal; ignoring non-actionable approval state`);
|
|
12410
12432
|
return;
|
|
12411
12433
|
}
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
this.approvalExitTimeout = null;
|
|
12416
|
-
}
|
|
12417
|
-
this.activeModal = null;
|
|
12418
|
-
this.lastApprovalResolvedAt = Date.now();
|
|
12419
|
-
}
|
|
12420
|
-
if (!this.isWaitingForResponse) {
|
|
12421
|
-
this.isWaitingForResponse = true;
|
|
12422
|
-
this.responseBuffer = "";
|
|
12423
|
-
}
|
|
12424
|
-
this.setStatus("generating", "script_detect");
|
|
12434
|
+
this.isWaitingForResponse = true;
|
|
12435
|
+
this.setStatus("waiting_approval", "script_detect");
|
|
12436
|
+
this.activeModal = modal;
|
|
12425
12437
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12426
|
-
this.
|
|
12427
|
-
if (this.isWaitingForResponse) {
|
|
12428
|
-
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12429
|
-
this.finishResponse();
|
|
12430
|
-
}
|
|
12431
|
-
}, this.timeouts.generatingIdle);
|
|
12438
|
+
this.armApprovalExitTimeout();
|
|
12432
12439
|
this.onStatusChange?.();
|
|
12440
|
+
}
|
|
12441
|
+
}
|
|
12442
|
+
applyGenerating(ctx) {
|
|
12443
|
+
const { screenText, modal, parsedShowsLiveAssistantProgress, prevStatus } = ctx;
|
|
12444
|
+
this.clearIdleFinishCandidate("generating");
|
|
12445
|
+
const effectiveScreenText = screenText || this.accumulatedBuffer;
|
|
12446
|
+
const noActiveTurn = !this.currentTurnScope;
|
|
12447
|
+
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));
|
|
12448
|
+
if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
|
|
12433
12449
|
return;
|
|
12434
12450
|
}
|
|
12435
|
-
if (
|
|
12436
|
-
if (
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
this.approvalExitTimeout = null;
|
|
12440
|
-
}
|
|
12441
|
-
this.activeModal = null;
|
|
12442
|
-
this.lastApprovalResolvedAt = Date.now();
|
|
12451
|
+
if (prevStatus === "waiting_approval") {
|
|
12452
|
+
if (this.approvalExitTimeout) {
|
|
12453
|
+
clearTimeout(this.approvalExitTimeout);
|
|
12454
|
+
this.approvalExitTimeout = null;
|
|
12443
12455
|
}
|
|
12456
|
+
this.activeModal = null;
|
|
12457
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
12458
|
+
}
|
|
12459
|
+
if (!this.isWaitingForResponse) {
|
|
12460
|
+
this.isWaitingForResponse = true;
|
|
12461
|
+
this.responseBuffer = "";
|
|
12462
|
+
}
|
|
12463
|
+
this.setStatus("generating", "script_detect");
|
|
12464
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12465
|
+
this.idleTimeout = setTimeout(() => {
|
|
12444
12466
|
if (this.isWaitingForResponse) {
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
hasModal: !!modal,
|
|
12464
|
-
idleQuietThresholdMs,
|
|
12465
|
-
idleStableThresholdMs,
|
|
12466
|
-
idleReady,
|
|
12467
|
-
idleFinishConfirmMs,
|
|
12468
|
-
idleFinishCandidate: candidate,
|
|
12469
|
-
candidateQuiet,
|
|
12470
|
-
canFinishImmediately,
|
|
12471
|
-
submitPendingUntil: this.submitPendingUntil,
|
|
12472
|
-
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
12473
|
-
...buildCliTraceParseSnapshot({
|
|
12474
|
-
accumulatedBuffer: this.accumulatedBuffer,
|
|
12475
|
-
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
12476
|
-
responseBuffer: this.responseBuffer,
|
|
12477
|
-
partialResponse: this.responseBuffer,
|
|
12478
|
-
scope: this.currentTurnScope
|
|
12479
|
-
})
|
|
12480
|
-
});
|
|
12481
|
-
if (canFinishImmediately) {
|
|
12482
|
-
this.clearIdleFinishCandidate("finish_response");
|
|
12483
|
-
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12484
|
-
this.finishResponse();
|
|
12485
|
-
return;
|
|
12486
|
-
}
|
|
12487
|
-
if (idleReady) {
|
|
12488
|
-
if (!candidate) {
|
|
12489
|
-
this.armIdleFinishCandidate(assistantLength);
|
|
12490
|
-
return;
|
|
12491
|
-
}
|
|
12492
|
-
} else {
|
|
12493
|
-
this.clearIdleFinishCandidate("idle_not_ready");
|
|
12494
|
-
}
|
|
12495
|
-
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12496
|
-
this.idleTimeout = setTimeout(() => {
|
|
12497
|
-
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
12498
|
-
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12499
|
-
this.clearIdleFinishCandidate("idle_timeout_finish");
|
|
12500
|
-
this.finishResponse();
|
|
12501
|
-
}
|
|
12502
|
-
}, this.timeouts.idleFinish);
|
|
12503
|
-
} else if (prevStatus !== "idle") {
|
|
12467
|
+
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12468
|
+
this.finishResponse();
|
|
12469
|
+
}
|
|
12470
|
+
}, this.timeouts.generatingIdle);
|
|
12471
|
+
this.onStatusChange?.();
|
|
12472
|
+
}
|
|
12473
|
+
applyIdle(ctx, now) {
|
|
12474
|
+
const { screenText, modal, lastParsedAssistant, prevStatus } = ctx;
|
|
12475
|
+
if (prevStatus === "waiting_approval") {
|
|
12476
|
+
if (this.approvalExitTimeout) {
|
|
12477
|
+
clearTimeout(this.approvalExitTimeout);
|
|
12478
|
+
this.approvalExitTimeout = null;
|
|
12479
|
+
}
|
|
12480
|
+
this.activeModal = null;
|
|
12481
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
12482
|
+
}
|
|
12483
|
+
if (!this.isWaitingForResponse) {
|
|
12484
|
+
if (prevStatus !== "idle") {
|
|
12504
12485
|
this.clearIdleFinishCandidate("idle_without_response");
|
|
12505
12486
|
this.setStatus("idle", "script_detect");
|
|
12506
12487
|
this.onStatusChange?.();
|
|
12507
12488
|
}
|
|
12489
|
+
return;
|
|
12508
12490
|
}
|
|
12491
|
+
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
12492
|
+
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
12493
|
+
const hasAssistantTurn = !!lastParsedAssistant;
|
|
12494
|
+
const assistantLength = lastParsedAssistant?.content?.length || 0;
|
|
12495
|
+
const idleFinishConfirmMs = this.getIdleFinishConfirmMs();
|
|
12496
|
+
const idleQuietThresholdMs = Math.max(idleFinishConfirmMs, this.timeouts.outputSettle);
|
|
12497
|
+
const idleReady = !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleFinishConfirmMs;
|
|
12498
|
+
const candidate = this.idleFinishCandidate;
|
|
12499
|
+
const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= idleFinishConfirmMs;
|
|
12500
|
+
this.recordTrace("idle_decision", {
|
|
12501
|
+
quietForMs,
|
|
12502
|
+
screenStableMs,
|
|
12503
|
+
hasAssistantTurn,
|
|
12504
|
+
assistantLength,
|
|
12505
|
+
hasModal: !!modal,
|
|
12506
|
+
idleQuietThresholdMs,
|
|
12507
|
+
idleStableThresholdMs: idleFinishConfirmMs,
|
|
12508
|
+
idleReady,
|
|
12509
|
+
idleFinishConfirmMs,
|
|
12510
|
+
idleFinishCandidate: candidate,
|
|
12511
|
+
candidateQuiet,
|
|
12512
|
+
canFinishImmediately: idleReady && candidateQuiet,
|
|
12513
|
+
submitPendingUntil: this.submitPendingUntil,
|
|
12514
|
+
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
12515
|
+
...buildCliTraceParseSnapshot({
|
|
12516
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
12517
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
12518
|
+
responseBuffer: this.responseBuffer,
|
|
12519
|
+
partialResponse: this.responseBuffer,
|
|
12520
|
+
scope: this.currentTurnScope
|
|
12521
|
+
})
|
|
12522
|
+
});
|
|
12523
|
+
if (idleReady && candidateQuiet) {
|
|
12524
|
+
this.clearIdleFinishCandidate("finish_response");
|
|
12525
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12526
|
+
this.finishResponse();
|
|
12527
|
+
return;
|
|
12528
|
+
}
|
|
12529
|
+
if (idleReady) {
|
|
12530
|
+
if (!candidate) {
|
|
12531
|
+
this.armIdleFinishCandidate(assistantLength);
|
|
12532
|
+
return;
|
|
12533
|
+
}
|
|
12534
|
+
} else {
|
|
12535
|
+
this.clearIdleFinishCandidate("idle_not_ready");
|
|
12536
|
+
}
|
|
12537
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
12538
|
+
this.idleTimeout = setTimeout(() => {
|
|
12539
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
12540
|
+
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
12541
|
+
this.clearIdleFinishCandidate("idle_timeout_finish");
|
|
12542
|
+
this.finishResponse();
|
|
12543
|
+
}
|
|
12544
|
+
}, this.timeouts.idleFinish);
|
|
12509
12545
|
}
|
|
12510
12546
|
finishResponse() {
|
|
12511
12547
|
if (this.submitPendingUntil > Date.now()) return;
|
|
@@ -12544,26 +12580,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12544
12580
|
}, _ProviderCliAdapter.FINISH_RETRY_DELAY_MS);
|
|
12545
12581
|
return;
|
|
12546
12582
|
}
|
|
12547
|
-
|
|
12548
|
-
clearTimeout(this.responseTimeout);
|
|
12549
|
-
this.responseTimeout = null;
|
|
12550
|
-
}
|
|
12551
|
-
if (this.idleTimeout) {
|
|
12552
|
-
clearTimeout(this.idleTimeout);
|
|
12553
|
-
this.idleTimeout = null;
|
|
12554
|
-
}
|
|
12555
|
-
if (this.approvalExitTimeout) {
|
|
12556
|
-
clearTimeout(this.approvalExitTimeout);
|
|
12557
|
-
this.approvalExitTimeout = null;
|
|
12558
|
-
}
|
|
12559
|
-
if (this.submitRetryTimer) {
|
|
12560
|
-
clearTimeout(this.submitRetryTimer);
|
|
12561
|
-
this.submitRetryTimer = null;
|
|
12562
|
-
}
|
|
12563
|
-
if (this.finishRetryTimer) {
|
|
12564
|
-
clearTimeout(this.finishRetryTimer);
|
|
12565
|
-
this.finishRetryTimer = null;
|
|
12566
|
-
}
|
|
12583
|
+
this.clearAllTimers();
|
|
12567
12584
|
this.responseBuffer = "";
|
|
12568
12585
|
this.isWaitingForResponse = false;
|
|
12569
12586
|
this.responseSettleIgnoreUntil = 0;
|
|
@@ -12575,18 +12592,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
12575
12592
|
this.setStatus("idle", "response_finished");
|
|
12576
12593
|
this.onStatusChange?.();
|
|
12577
12594
|
}
|
|
12578
|
-
maybeCommitVisibleIdleTranscript(parsed
|
|
12595
|
+
maybeCommitVisibleIdleTranscript(parsed) {
|
|
12579
12596
|
const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
|
|
12580
12597
|
if (!allowImmediateScriptIdleCommit) return false;
|
|
12581
12598
|
if (!parsed || !Array.isArray(parsed.messages) || parsed.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || parsed.activeModal) {
|
|
12582
12599
|
return false;
|
|
12583
12600
|
}
|
|
12584
|
-
if (options?.requireVisibleAssistantCandidate) {
|
|
12585
|
-
const candidateText = options.screenText || this.terminalScreen.getText() || "";
|
|
12586
|
-
if (!this.looksLikeVisibleAssistantCandidate(candidateText)) {
|
|
12587
|
-
return false;
|
|
12588
|
-
}
|
|
12589
|
-
}
|
|
12590
12601
|
const hydratedForIdleCommit = normalizeCliParsedMessages(parsed.messages, {
|
|
12591
12602
|
committedMessages: this.committedMessages,
|
|
12592
12603
|
scope: this.currentTurnScope,
|
|
@@ -12595,33 +12606,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
12595
12606
|
const visibleAssistant = [...hydratedForIdleCommit].reverse().find((message) => message.role === "assistant" && message.content.trim());
|
|
12596
12607
|
if (!visibleAssistant) return false;
|
|
12597
12608
|
this.committedMessages = hydratedForIdleCommit;
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
12601
|
-
if (lastAssistantForTrim) {
|
|
12602
|
-
lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
|
|
12603
|
-
}
|
|
12604
|
-
}
|
|
12605
|
-
if (this.responseTimeout) {
|
|
12606
|
-
clearTimeout(this.responseTimeout);
|
|
12607
|
-
this.responseTimeout = null;
|
|
12608
|
-
}
|
|
12609
|
-
if (this.idleTimeout) {
|
|
12610
|
-
clearTimeout(this.idleTimeout);
|
|
12611
|
-
this.idleTimeout = null;
|
|
12612
|
-
}
|
|
12613
|
-
if (this.approvalExitTimeout) {
|
|
12614
|
-
clearTimeout(this.approvalExitTimeout);
|
|
12615
|
-
this.approvalExitTimeout = null;
|
|
12616
|
-
}
|
|
12617
|
-
if (this.submitRetryTimer) {
|
|
12618
|
-
clearTimeout(this.submitRetryTimer);
|
|
12619
|
-
this.submitRetryTimer = null;
|
|
12620
|
-
}
|
|
12621
|
-
if (this.finishRetryTimer) {
|
|
12622
|
-
clearTimeout(this.finishRetryTimer);
|
|
12623
|
-
this.finishRetryTimer = null;
|
|
12624
|
-
}
|
|
12609
|
+
this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
|
|
12610
|
+
this.clearAllTimers();
|
|
12625
12611
|
this.syncMessageViews();
|
|
12626
12612
|
this.responseBuffer = "";
|
|
12627
12613
|
this.isWaitingForResponse = false;
|
|
@@ -12651,13 +12637,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12651
12637
|
scope: this.currentTurnScope,
|
|
12652
12638
|
lastOutputAt: this.lastOutputAt
|
|
12653
12639
|
});
|
|
12654
|
-
|
|
12655
|
-
if (promptForTrim) {
|
|
12656
|
-
const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
12657
|
-
if (lastAssistantForTrim) {
|
|
12658
|
-
lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
|
|
12659
|
-
}
|
|
12660
|
-
}
|
|
12640
|
+
this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
|
|
12661
12641
|
this.syncMessageViews();
|
|
12662
12642
|
const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
12663
12643
|
if (this.currentTurnScope) {
|
|
@@ -12715,7 +12695,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12715
12695
|
screen: buildCliScreenSnapshot(screenText),
|
|
12716
12696
|
tailScreen: buildCliScreenSnapshot(text.slice(-500))
|
|
12717
12697
|
});
|
|
12718
|
-
return
|
|
12698
|
+
return status;
|
|
12719
12699
|
} catch (e) {
|
|
12720
12700
|
LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
|
|
12721
12701
|
return null;
|
|
@@ -12755,23 +12735,21 @@ var init_provider_cli_adapter = __esm({
|
|
|
12755
12735
|
if (!inApprovalCooldown) {
|
|
12756
12736
|
return parsed;
|
|
12757
12737
|
}
|
|
12758
|
-
const
|
|
12759
|
-
const visibleModal = this.runParseApproval(recentBuffer) || startupModal;
|
|
12738
|
+
const visibleModal = this.runParseApproval(recentBuffer);
|
|
12760
12739
|
if (visibleModal) {
|
|
12761
12740
|
return parsed;
|
|
12762
12741
|
}
|
|
12763
12742
|
const detectedStatus = this.runDetectStatus(recentBuffer);
|
|
12764
|
-
const
|
|
12743
|
+
const resolvedStatus = detectedStatus && detectedStatus !== "waiting_approval" ? detectedStatus : this.isWaitingForResponse || this.currentTurnScope ? "generating" : this.currentStatus === "waiting_approval" ? "idle" : this.currentStatus;
|
|
12765
12744
|
return {
|
|
12766
12745
|
...parsed,
|
|
12767
|
-
status:
|
|
12746
|
+
status: resolvedStatus,
|
|
12768
12747
|
activeModal: null
|
|
12769
12748
|
};
|
|
12770
12749
|
}
|
|
12771
12750
|
// ─── Public API (CliAdapter) ───────────────────
|
|
12772
12751
|
getStatus() {
|
|
12773
|
-
const
|
|
12774
|
-
const startupModal = this.startupParseGate ? this.getStartupConfirmationModal(screenText) : null;
|
|
12752
|
+
const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
12775
12753
|
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
12776
12754
|
let effectiveModal = startupModal || this.activeModal;
|
|
12777
12755
|
if (!startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
|
|
@@ -12852,8 +12830,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12852
12830
|
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
12853
12831
|
}));
|
|
12854
12832
|
const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === "assistant" && typeof message.content === "string" && message.content.trim());
|
|
12855
|
-
const
|
|
12856
|
-
const shouldAdoptParsedIdleReplay = !this.currentTurnScope && !this.activeModal && !!parsedLastAssistant && parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, committedHydratedMessages) && (this.currentStatus === "idle" || this.currentStatus === "generating" && this.isWaitingForResponse && parsed.status === "idle" && visibleIdlePrompt);
|
|
12833
|
+
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");
|
|
12857
12834
|
if (shouldAdoptParsedIdleReplay) {
|
|
12858
12835
|
this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
|
|
12859
12836
|
committedMessages: this.committedMessages,
|
|
@@ -12982,17 +12959,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
12982
12959
|
if (parsed && typeof parsed === "object") {
|
|
12983
12960
|
Object.assign(parsed, validateReadChatResultPayload(parsed, `${this.cliType} parseOutput`));
|
|
12984
12961
|
}
|
|
12985
|
-
const refinedStatus = this.refineDetectedStatus(typeof parsed?.status === "string" ? parsed.status : null, input.recentBuffer, input.screenText);
|
|
12986
|
-
if (parsed && refinedStatus && parsed.status !== refinedStatus) {
|
|
12987
|
-
parsed.status = refinedStatus;
|
|
12988
|
-
}
|
|
12989
12962
|
const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
const lastAssistant = [...normalizedParsed.messages].reverse().find((message) => message?.role === "assistant" && typeof message.content === "string");
|
|
12993
|
-
if (lastAssistant) {
|
|
12994
|
-
lastAssistant.content = trimPromptEchoPrefix(lastAssistant.content, promptForTrim);
|
|
12995
|
-
}
|
|
12963
|
+
if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
|
|
12964
|
+
this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
|
|
12996
12965
|
}
|
|
12997
12966
|
this.parseErrorMessage = null;
|
|
12998
12967
|
return normalizedParsed;
|
|
@@ -13020,16 +12989,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
13020
12989
|
LOG.warn("CLI", `[${this.cliType}] resolveAction error: ${e.message}`);
|
|
13021
12990
|
}
|
|
13022
12991
|
}
|
|
13023
|
-
if (!promptText
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
${data.explanation || ""}
|
|
13027
|
-
|
|
13028
|
-
${data.message || ""}`.trim();
|
|
13029
|
-
}
|
|
13030
|
-
if (promptText) {
|
|
13031
|
-
await this.sendMessage(promptText);
|
|
12992
|
+
if (!promptText) {
|
|
12993
|
+
LOG.warn("CLI", `[${this.cliType}] resolveAction skipped: provider script did not supply a prompt`);
|
|
12994
|
+
return;
|
|
13032
12995
|
}
|
|
12996
|
+
await this.sendMessage(promptText);
|
|
13033
12997
|
}
|
|
13034
12998
|
async sendMessage(text) {
|
|
13035
12999
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
@@ -13047,9 +13011,7 @@ ${data.message || ""}`.trim();
|
|
|
13047
13011
|
}
|
|
13048
13012
|
if (!this.ready) {
|
|
13049
13013
|
this.resolveStartupState("send_precheck");
|
|
13050
|
-
|
|
13051
|
-
const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
13052
|
-
if (hasPrompt && this.currentStatus === "idle") {
|
|
13014
|
+
if (this.runDetectStatus(this.recentOutputBuffer) === "idle" && this.currentStatus === "idle") {
|
|
13053
13015
|
this.ready = true;
|
|
13054
13016
|
this.startupParseGate = false;
|
|
13055
13017
|
LOG.info("CLI", `[${this.cliType}] sendMessage recovered idle prompt readiness`);
|
|
@@ -13155,7 +13117,10 @@ ${data.message || ""}`.trim();
|
|
|
13155
13117
|
if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
|
|
13156
13118
|
const screenText2 = this.terminalScreen.getText();
|
|
13157
13119
|
if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
|
|
13158
|
-
|
|
13120
|
+
const liveApproval = this.runParseApproval(screenText2) || this.runParseApproval(this.recentOutputBuffer);
|
|
13121
|
+
if (liveApproval) return;
|
|
13122
|
+
const liveStatus = this.runDetectStatus(screenText2) || this.runDetectStatus(this.recentOutputBuffer);
|
|
13123
|
+
if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
|
|
13159
13124
|
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
13160
13125
|
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
13161
13126
|
this.recordTrace("submit_write", {
|
|
@@ -13192,6 +13157,10 @@ ${data.message || ""}`.trim();
|
|
|
13192
13157
|
if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
|
|
13193
13158
|
const screenText = this.terminalScreen.getText();
|
|
13194
13159
|
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
13160
|
+
const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
|
|
13161
|
+
if (liveApproval) return;
|
|
13162
|
+
const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
|
|
13163
|
+
if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
|
|
13195
13164
|
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
13196
13165
|
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
13197
13166
|
this.recordTrace("submit_write", {
|
|
@@ -13323,44 +13292,9 @@ ${data.message || ""}`.trim();
|
|
|
13323
13292
|
}
|
|
13324
13293
|
shutdown() {
|
|
13325
13294
|
this.clearIdleFinishCandidate("shutdown");
|
|
13326
|
-
|
|
13327
|
-
clearTimeout(this.settleTimer);
|
|
13328
|
-
this.settleTimer = null;
|
|
13329
|
-
}
|
|
13330
|
-
if (this.approvalExitTimeout) {
|
|
13331
|
-
clearTimeout(this.approvalExitTimeout);
|
|
13332
|
-
this.approvalExitTimeout = null;
|
|
13333
|
-
}
|
|
13334
|
-
if (this.submitRetryTimer) {
|
|
13335
|
-
clearTimeout(this.submitRetryTimer);
|
|
13336
|
-
this.submitRetryTimer = null;
|
|
13337
|
-
}
|
|
13338
|
-
if (this.finishRetryTimer) {
|
|
13339
|
-
clearTimeout(this.finishRetryTimer);
|
|
13340
|
-
this.finishRetryTimer = null;
|
|
13341
|
-
}
|
|
13342
|
-
if (this.responseTimeout) {
|
|
13343
|
-
clearTimeout(this.responseTimeout);
|
|
13344
|
-
this.responseTimeout = null;
|
|
13345
|
-
}
|
|
13346
|
-
if (this.idleTimeout) {
|
|
13347
|
-
clearTimeout(this.idleTimeout);
|
|
13348
|
-
this.idleTimeout = null;
|
|
13349
|
-
}
|
|
13350
|
-
if (this.pendingScriptStatusTimer) {
|
|
13351
|
-
clearTimeout(this.pendingScriptStatusTimer);
|
|
13352
|
-
this.pendingScriptStatusTimer = null;
|
|
13353
|
-
}
|
|
13354
|
-
if (this.pendingOutputParseTimer) {
|
|
13355
|
-
clearTimeout(this.pendingOutputParseTimer);
|
|
13356
|
-
this.pendingOutputParseTimer = null;
|
|
13357
|
-
}
|
|
13295
|
+
this.clearAllTimers();
|
|
13358
13296
|
this.pendingOutputParseBuffer = "";
|
|
13359
13297
|
this.pendingTerminalQueryTail = "";
|
|
13360
|
-
if (this.ptyOutputFlushTimer) {
|
|
13361
|
-
clearTimeout(this.ptyOutputFlushTimer);
|
|
13362
|
-
this.ptyOutputFlushTimer = null;
|
|
13363
|
-
}
|
|
13364
13298
|
this.ptyOutputBuffer = "";
|
|
13365
13299
|
this.finishRetryCount = 0;
|
|
13366
13300
|
if (this.ptyProcess) {
|
|
@@ -13381,44 +13315,9 @@ ${data.message || ""}`.trim();
|
|
|
13381
13315
|
}
|
|
13382
13316
|
detach() {
|
|
13383
13317
|
this.clearIdleFinishCandidate("detach");
|
|
13384
|
-
|
|
13385
|
-
clearTimeout(this.settleTimer);
|
|
13386
|
-
this.settleTimer = null;
|
|
13387
|
-
}
|
|
13388
|
-
if (this.approvalExitTimeout) {
|
|
13389
|
-
clearTimeout(this.approvalExitTimeout);
|
|
13390
|
-
this.approvalExitTimeout = null;
|
|
13391
|
-
}
|
|
13392
|
-
if (this.submitRetryTimer) {
|
|
13393
|
-
clearTimeout(this.submitRetryTimer);
|
|
13394
|
-
this.submitRetryTimer = null;
|
|
13395
|
-
}
|
|
13396
|
-
if (this.finishRetryTimer) {
|
|
13397
|
-
clearTimeout(this.finishRetryTimer);
|
|
13398
|
-
this.finishRetryTimer = null;
|
|
13399
|
-
}
|
|
13400
|
-
if (this.responseTimeout) {
|
|
13401
|
-
clearTimeout(this.responseTimeout);
|
|
13402
|
-
this.responseTimeout = null;
|
|
13403
|
-
}
|
|
13404
|
-
if (this.idleTimeout) {
|
|
13405
|
-
clearTimeout(this.idleTimeout);
|
|
13406
|
-
this.idleTimeout = null;
|
|
13407
|
-
}
|
|
13408
|
-
if (this.pendingScriptStatusTimer) {
|
|
13409
|
-
clearTimeout(this.pendingScriptStatusTimer);
|
|
13410
|
-
this.pendingScriptStatusTimer = null;
|
|
13411
|
-
}
|
|
13412
|
-
if (this.pendingOutputParseTimer) {
|
|
13413
|
-
clearTimeout(this.pendingOutputParseTimer);
|
|
13414
|
-
this.pendingOutputParseTimer = null;
|
|
13415
|
-
}
|
|
13318
|
+
this.clearAllTimers();
|
|
13416
13319
|
this.pendingOutputParseBuffer = "";
|
|
13417
13320
|
this.pendingTerminalQueryTail = "";
|
|
13418
|
-
if (this.ptyOutputFlushTimer) {
|
|
13419
|
-
clearTimeout(this.ptyOutputFlushTimer);
|
|
13420
|
-
this.ptyOutputFlushTimer = null;
|
|
13421
|
-
}
|
|
13422
13321
|
this.ptyOutputBuffer = "";
|
|
13423
13322
|
this.finishRetryCount = 0;
|
|
13424
13323
|
if (this.ptyProcess) {
|
|
@@ -13480,8 +13379,7 @@ ${data.message || ""}`.trim();
|
|
|
13480
13379
|
this.ptyProcess?.write(data);
|
|
13481
13380
|
}
|
|
13482
13381
|
resolveModal(buttonIndex) {
|
|
13483
|
-
|
|
13484
|
-
let modal = this.activeModal || this.getStartupConfirmationModal(screenText);
|
|
13382
|
+
let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
|
|
13485
13383
|
if (!modal && typeof this.cliScripts?.parseOutput === "function") {
|
|
13486
13384
|
try {
|
|
13487
13385
|
const parsed = this.getScriptParsedStatus();
|
|
@@ -13512,12 +13410,7 @@ ${data.message || ""}`.trim();
|
|
|
13512
13410
|
}
|
|
13513
13411
|
this.setStatus("generating", "approval_resolved");
|
|
13514
13412
|
this.onStatusChange?.();
|
|
13515
|
-
|
|
13516
|
-
if (startupTrustModal && buttonIndex in this.approvalKeys) {
|
|
13517
|
-
this.ptyProcess.write(`${this.approvalKeys[buttonIndex]}\r`);
|
|
13518
|
-
} else if (this.shouldResolveModalWithEnter(modal, buttonIndex)) {
|
|
13519
|
-
this.ptyProcess.write("\r");
|
|
13520
|
-
} else if (buttonIndex in this.approvalKeys) {
|
|
13413
|
+
if (buttonIndex in this.approvalKeys) {
|
|
13521
13414
|
this.ptyProcess.write(this.approvalKeys[buttonIndex]);
|
|
13522
13415
|
} else {
|
|
13523
13416
|
const DOWN = "\x1B[B";
|
|
@@ -13537,7 +13430,7 @@ ${data.message || ""}`.trim();
|
|
|
13537
13430
|
}
|
|
13538
13431
|
getDebugState() {
|
|
13539
13432
|
const screenText = sanitizeTerminalText(this.terminalScreen.getText());
|
|
13540
|
-
const startupModal = this.startupParseGate ? this.
|
|
13433
|
+
const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
13541
13434
|
const effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
13542
13435
|
const effectiveReady = this.ready || !!startupModal;
|
|
13543
13436
|
return {
|
|
@@ -13759,6 +13652,13 @@ var init_cli_provider_instance = __esm({
|
|
|
13759
13652
|
runtimeMessages = [];
|
|
13760
13653
|
lastPersistedHistoryMessages = [];
|
|
13761
13654
|
lastCanonicalHermesSyncMtimeMs = 0;
|
|
13655
|
+
lastCanonicalHermesExistCheckAt = 0;
|
|
13656
|
+
lastCanonicalHermesWatchPath = void 0;
|
|
13657
|
+
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
13658
|
+
lastCanonicalClaudeCheckAt = 0;
|
|
13659
|
+
cachedSqliteDb = null;
|
|
13660
|
+
cachedSqliteDbPath = null;
|
|
13661
|
+
cachedSqliteDbMissingUntil = 0;
|
|
13762
13662
|
instanceId;
|
|
13763
13663
|
suppressIdleHistoryReplay = false;
|
|
13764
13664
|
errorMessage = void 0;
|
|
@@ -13823,7 +13723,12 @@ var init_cli_provider_instance = __esm({
|
|
|
13823
13723
|
*/
|
|
13824
13724
|
probeSessionIdFromConfig(probe) {
|
|
13825
13725
|
const resolvedDbPath = probe.dbPath.replace(/^~/, os13.homedir());
|
|
13826
|
-
|
|
13726
|
+
const now = Date.now();
|
|
13727
|
+
if (this.cachedSqliteDbMissingUntil > now) return null;
|
|
13728
|
+
if (!fs5.existsSync(resolvedDbPath)) {
|
|
13729
|
+
this.cachedSqliteDbMissingUntil = now + 1e4;
|
|
13730
|
+
return null;
|
|
13731
|
+
}
|
|
13827
13732
|
const directories = this.getProbeDirectories();
|
|
13828
13733
|
const minCreatedAt = Math.max(0, this.startedAt - 6e4);
|
|
13829
13734
|
const tsFormat = probe.timestampFormat || "unix_ms";
|
|
@@ -13994,6 +13899,12 @@ var init_cli_provider_instance = __esm({
|
|
|
13994
13899
|
this.adapter.shutdown();
|
|
13995
13900
|
this.monitor.reset();
|
|
13996
13901
|
this.appliedEffectKeys.clear();
|
|
13902
|
+
try {
|
|
13903
|
+
this.cachedSqliteDb?.close();
|
|
13904
|
+
} catch {
|
|
13905
|
+
}
|
|
13906
|
+
this.cachedSqliteDb = null;
|
|
13907
|
+
this.cachedSqliteDbPath = null;
|
|
13997
13908
|
}
|
|
13998
13909
|
completedDebounceTimer = null;
|
|
13999
13910
|
completedDebouncePending = null;
|
|
@@ -14398,13 +14309,35 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14398
14309
|
let rebuilt = false;
|
|
14399
14310
|
if (canonicalHistory.format === "hermes-json") {
|
|
14400
14311
|
const watchPath = canonicalHistory.watchPath.replace(/^~/, os13.homedir()).replace("{{sessionId}}", this.providerSessionId);
|
|
14401
|
-
|
|
14312
|
+
const now = Date.now();
|
|
14313
|
+
if (watchPath !== this.lastCanonicalHermesWatchPath || now - this.lastCanonicalHermesExistCheckAt >= 2e3) {
|
|
14314
|
+
this.lastCanonicalHermesWatchPath = watchPath;
|
|
14315
|
+
this.lastCanonicalHermesExistCheckAt = now;
|
|
14316
|
+
if (!fs5.existsSync(watchPath)) return false;
|
|
14317
|
+
} else if (this.lastCanonicalHermesSyncMtimeMs === 0) {
|
|
14318
|
+
if (!fs5.existsSync(watchPath)) return false;
|
|
14319
|
+
}
|
|
14402
14320
|
const stat4 = fs5.statSync(watchPath);
|
|
14403
14321
|
if (stat4.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
14404
14322
|
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
14405
14323
|
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat4.mtimeMs;
|
|
14406
14324
|
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
14325
|
+
const now = Date.now();
|
|
14326
|
+
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
14327
|
+
return true;
|
|
14328
|
+
}
|
|
14329
|
+
this.lastCanonicalClaudeCheckAt = now;
|
|
14330
|
+
const claudeProjectsDir = path11.join(os13.homedir(), ".claude", "projects");
|
|
14331
|
+
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
14332
|
+
const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
14333
|
+
let transcriptMtime = 0;
|
|
14334
|
+
try {
|
|
14335
|
+
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14336
|
+
} catch {
|
|
14337
|
+
}
|
|
14338
|
+
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14407
14339
|
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14340
|
+
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14408
14341
|
}
|
|
14409
14342
|
if (!rebuilt) return false;
|
|
14410
14343
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -14469,20 +14402,29 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14469
14402
|
return Array.from({ length: count }, () => "?").join(", ");
|
|
14470
14403
|
}
|
|
14471
14404
|
querySqliteText(dbPath, query, params) {
|
|
14472
|
-
let db = null;
|
|
14473
14405
|
try {
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14406
|
+
if (this.cachedSqliteDb === null || this.cachedSqliteDbPath !== dbPath) {
|
|
14407
|
+
try {
|
|
14408
|
+
this.cachedSqliteDb?.close();
|
|
14409
|
+
} catch {
|
|
14410
|
+
}
|
|
14411
|
+
this.cachedSqliteDb = null;
|
|
14412
|
+
this.cachedSqliteDbPath = null;
|
|
14413
|
+
const DatabaseSync = getDatabaseSync();
|
|
14414
|
+
this.cachedSqliteDb = new DatabaseSync(dbPath, { readOnly: true });
|
|
14415
|
+
this.cachedSqliteDbPath = dbPath;
|
|
14416
|
+
}
|
|
14417
|
+
const row = this.cachedSqliteDb.prepare(query).get(...params);
|
|
14477
14418
|
const sessionId = typeof row?.id === "string" ? row.id.trim() : "";
|
|
14478
14419
|
return sessionId || null;
|
|
14479
14420
|
} catch {
|
|
14480
|
-
return null;
|
|
14481
|
-
} finally {
|
|
14482
14421
|
try {
|
|
14483
|
-
|
|
14422
|
+
this.cachedSqliteDb?.close();
|
|
14484
14423
|
} catch {
|
|
14485
14424
|
}
|
|
14425
|
+
this.cachedSqliteDb = null;
|
|
14426
|
+
this.cachedSqliteDbPath = null;
|
|
14427
|
+
return null;
|
|
14486
14428
|
}
|
|
14487
14429
|
}
|
|
14488
14430
|
};
|
|
@@ -34649,6 +34591,7 @@ var init_provider_schema = __esm({
|
|
|
34649
34591
|
"canonicalHistory",
|
|
34650
34592
|
"autoFixProfile",
|
|
34651
34593
|
"ideLevelScripts",
|
|
34594
|
+
"allowInputDuringGeneration",
|
|
34652
34595
|
"scripts",
|
|
34653
34596
|
"vscodeCommands",
|
|
34654
34597
|
"inputMethod",
|
|
@@ -55410,7 +55353,7 @@ var init_adhdev_daemon = __esm({
|
|
|
55410
55353
|
init_version();
|
|
55411
55354
|
init_src();
|
|
55412
55355
|
init_runtime_defaults();
|
|
55413
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
55356
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.8" });
|
|
55414
55357
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
55415
55358
|
localHttpServer = null;
|
|
55416
55359
|
localWss = null;
|