@adhdev/daemon-core 0.6.56 → 0.6.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -0
- package/dist/index.js +175 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +191 -21
package/dist/index.d.ts
CHANGED
|
@@ -2664,6 +2664,11 @@ declare class ProviderCliAdapter implements CliAdapter {
|
|
|
2664
2664
|
private settleTimer;
|
|
2665
2665
|
private settledBuffer;
|
|
2666
2666
|
private submitPendingUntil;
|
|
2667
|
+
private responseSettleIgnoreUntil;
|
|
2668
|
+
private responseEpoch;
|
|
2669
|
+
private submitRetryTimer;
|
|
2670
|
+
private submitRetryUsed;
|
|
2671
|
+
private submitRetryPromptSnippet;
|
|
2667
2672
|
private resizeSuppressUntil;
|
|
2668
2673
|
private statusHistory;
|
|
2669
2674
|
private cliScripts;
|
|
@@ -2689,6 +2694,7 @@ declare class ProviderCliAdapter implements CliAdapter {
|
|
|
2689
2694
|
spawn(): Promise<void>;
|
|
2690
2695
|
private handleOutput;
|
|
2691
2696
|
private scheduleSettle;
|
|
2697
|
+
private armApprovalExitTimeout;
|
|
2692
2698
|
private evaluateSettled;
|
|
2693
2699
|
private finishResponse;
|
|
2694
2700
|
private runDetectStatus;
|
package/dist/index.js
CHANGED
|
@@ -718,6 +718,38 @@ function shSingleQuote(arg) {
|
|
|
718
718
|
if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
|
|
719
719
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
720
720
|
}
|
|
721
|
+
function estimatePromptDisplayLines(text, cols = 100) {
|
|
722
|
+
const normalized = String(text || "").replace(/\r/g, "");
|
|
723
|
+
if (!normalized) return 1;
|
|
724
|
+
return normalized.split("\n").reduce((sum, line) => sum + Math.max(1, Math.ceil(Math.max(1, line.length) / cols)), 0);
|
|
725
|
+
}
|
|
726
|
+
function extractPromptRetrySnippet(text) {
|
|
727
|
+
const lines = String(text || "").replace(/\r/g, "").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
728
|
+
const candidate = lines[lines.length - 1] || lines[0] || "";
|
|
729
|
+
return candidate.slice(-120);
|
|
730
|
+
}
|
|
731
|
+
function normalizePromptText(text) {
|
|
732
|
+
return String(text || "").replace(/\s+/g, " ").trim();
|
|
733
|
+
}
|
|
734
|
+
function compactPromptText(text) {
|
|
735
|
+
return String(text || "").replace(/\s+/g, "").trim();
|
|
736
|
+
}
|
|
737
|
+
function promptLikelyVisible(screenText, promptSnippet) {
|
|
738
|
+
const snippet = normalizePromptText(promptSnippet);
|
|
739
|
+
if (!snippet) return false;
|
|
740
|
+
const normalizedScreen = normalizePromptText(screenText);
|
|
741
|
+
if (normalizedScreen.includes(snippet)) return true;
|
|
742
|
+
const compactScreen = compactPromptText(screenText);
|
|
743
|
+
const compactSnippet = compactPromptText(promptSnippet);
|
|
744
|
+
if (compactSnippet && compactScreen.includes(compactSnippet)) return true;
|
|
745
|
+
const tokens = snippet.split(/[^A-Za-z0-9_.:/-]+/).map((token) => token.trim()).filter((token) => token.length >= 4);
|
|
746
|
+
if (tokens.length === 0) return false;
|
|
747
|
+
const required = Math.min(tokens.length, 3);
|
|
748
|
+
const matched = tokens.filter(
|
|
749
|
+
(token) => normalizedScreen.includes(token) || compactScreen.includes(compactPromptText(token))
|
|
750
|
+
).length;
|
|
751
|
+
return matched >= required;
|
|
752
|
+
}
|
|
721
753
|
function parsePatternEntry(x) {
|
|
722
754
|
if (x instanceof RegExp) return x;
|
|
723
755
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
@@ -837,6 +869,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
837
869
|
settleTimer = null;
|
|
838
870
|
settledBuffer = "";
|
|
839
871
|
submitPendingUntil = 0;
|
|
872
|
+
responseSettleIgnoreUntil = 0;
|
|
873
|
+
responseEpoch = 0;
|
|
874
|
+
submitRetryTimer = null;
|
|
875
|
+
submitRetryUsed = false;
|
|
876
|
+
submitRetryPromptSnippet = "";
|
|
840
877
|
// Resize redraw suppression
|
|
841
878
|
resizeSuppressUntil = 0;
|
|
842
879
|
// Debug: status transition history
|
|
@@ -960,7 +997,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
960
997
|
this.startupParseGate = true;
|
|
961
998
|
this.startupBuffer = "";
|
|
962
999
|
this.terminalScreen.reset(40, 120);
|
|
963
|
-
this.ready =
|
|
1000
|
+
this.ready = false;
|
|
964
1001
|
this.setStatus("idle", "pty_ready");
|
|
965
1002
|
this.onStatusChange?.();
|
|
966
1003
|
}
|
|
@@ -1005,7 +1042,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1005
1042
|
const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
|
|
1006
1043
|
if (isReady) {
|
|
1007
1044
|
this.startupParseGate = false;
|
|
1045
|
+
this.ready = true;
|
|
1008
1046
|
LOG.info("CLI", `[${this.cliType}] Startup gate end (${elapsed}ms, scriptStatus=${scriptStatus})`);
|
|
1047
|
+
this.onStatusChange?.();
|
|
1009
1048
|
} else {
|
|
1010
1049
|
return;
|
|
1011
1050
|
}
|
|
@@ -1014,19 +1053,45 @@ var init_provider_cli_adapter = __esm({
|
|
|
1014
1053
|
}
|
|
1015
1054
|
scheduleSettle() {
|
|
1016
1055
|
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
1056
|
+
const settleEpoch = this.responseEpoch;
|
|
1017
1057
|
const delay = Math.max(
|
|
1018
1058
|
this.timeouts.outputSettle,
|
|
1019
1059
|
this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
|
|
1020
1060
|
);
|
|
1021
1061
|
this.settleTimer = setTimeout(() => {
|
|
1022
1062
|
this.settleTimer = null;
|
|
1063
|
+
if (settleEpoch !== this.responseEpoch) return;
|
|
1023
1064
|
this.settledBuffer = this.recentOutputBuffer;
|
|
1024
1065
|
this.evaluateSettled();
|
|
1025
1066
|
}, delay);
|
|
1026
1067
|
}
|
|
1068
|
+
armApprovalExitTimeout() {
|
|
1069
|
+
if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
|
|
1070
|
+
this.approvalExitTimeout = setTimeout(() => {
|
|
1071
|
+
if (this.currentStatus !== "waiting_approval") return;
|
|
1072
|
+
const tail = this.recentOutputBuffer;
|
|
1073
|
+
const modal = this.runParseApproval(tail);
|
|
1074
|
+
const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
|
|
1075
|
+
if (stillWaiting) {
|
|
1076
|
+
this.activeModal = modal || this.activeModal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
1077
|
+
this.onStatusChange?.();
|
|
1078
|
+
this.armApprovalExitTimeout();
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1082
|
+
this.activeModal = null;
|
|
1083
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
1084
|
+
this.setStatus("idle", "approval_timeout");
|
|
1085
|
+
this.onStatusChange?.();
|
|
1086
|
+
}, 6e4);
|
|
1087
|
+
}
|
|
1027
1088
|
evaluateSettled() {
|
|
1089
|
+
if (this.submitPendingUntil > Date.now()) return;
|
|
1090
|
+
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1028
1091
|
const tail = this.settledBuffer;
|
|
1029
|
-
const
|
|
1092
|
+
const modal = this.runParseApproval(tail);
|
|
1093
|
+
const rawScriptStatus = this.runDetectStatus(tail);
|
|
1094
|
+
const scriptStatus = rawScriptStatus === "waiting_approval" || modal ? "waiting_approval" : rawScriptStatus;
|
|
1030
1095
|
if (!scriptStatus) return;
|
|
1031
1096
|
const prevStatus = this.currentStatus;
|
|
1032
1097
|
if (scriptStatus === "waiting_approval") {
|
|
@@ -1034,19 +1099,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1034
1099
|
if (!inCooldown) {
|
|
1035
1100
|
this.isWaitingForResponse = true;
|
|
1036
1101
|
this.setStatus("waiting_approval", "script_detect");
|
|
1037
|
-
const modal = this.runParseApproval(tail);
|
|
1038
1102
|
this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
1039
1103
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1040
|
-
|
|
1041
|
-
this.approvalExitTimeout = setTimeout(() => {
|
|
1042
|
-
if (this.currentStatus === "waiting_approval") {
|
|
1043
|
-
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1044
|
-
this.activeModal = null;
|
|
1045
|
-
this.lastApprovalResolvedAt = Date.now();
|
|
1046
|
-
this.setStatus("idle", "approval_timeout");
|
|
1047
|
-
this.onStatusChange?.();
|
|
1048
|
-
}
|
|
1049
|
-
}, 6e4);
|
|
1104
|
+
this.armApprovalExitTimeout();
|
|
1050
1105
|
this.onStatusChange?.();
|
|
1051
1106
|
return;
|
|
1052
1107
|
}
|
|
@@ -1082,7 +1137,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1082
1137
|
this.lastApprovalResolvedAt = Date.now();
|
|
1083
1138
|
}
|
|
1084
1139
|
if (this.isWaitingForResponse) {
|
|
1085
|
-
this.
|
|
1140
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1141
|
+
this.idleTimeout = setTimeout(() => {
|
|
1142
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
1143
|
+
this.finishResponse();
|
|
1144
|
+
}
|
|
1145
|
+
}, this.timeouts.idleFinish);
|
|
1086
1146
|
} else if (prevStatus !== "idle") {
|
|
1087
1147
|
this.setStatus("idle", "script_detect");
|
|
1088
1148
|
this.onStatusChange?.();
|
|
@@ -1090,6 +1150,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
1090
1150
|
}
|
|
1091
1151
|
}
|
|
1092
1152
|
finishResponse() {
|
|
1153
|
+
if (this.submitPendingUntil > Date.now()) return;
|
|
1154
|
+
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1093
1155
|
if (this.responseTimeout) {
|
|
1094
1156
|
clearTimeout(this.responseTimeout);
|
|
1095
1157
|
this.responseTimeout = null;
|
|
@@ -1102,8 +1164,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
1102
1164
|
clearTimeout(this.approvalExitTimeout);
|
|
1103
1165
|
this.approvalExitTimeout = null;
|
|
1104
1166
|
}
|
|
1167
|
+
if (this.submitRetryTimer) {
|
|
1168
|
+
clearTimeout(this.submitRetryTimer);
|
|
1169
|
+
this.submitRetryTimer = null;
|
|
1170
|
+
}
|
|
1105
1171
|
this.responseBuffer = "";
|
|
1106
1172
|
this.isWaitingForResponse = false;
|
|
1173
|
+
this.responseSettleIgnoreUntil = 0;
|
|
1174
|
+
this.submitRetryUsed = false;
|
|
1175
|
+
this.submitRetryPromptSnippet = "";
|
|
1107
1176
|
this.activeModal = null;
|
|
1108
1177
|
this.setStatus("idle", "response_finished");
|
|
1109
1178
|
this.onStatusChange?.();
|
|
@@ -1218,29 +1287,95 @@ ${data.message || ""}`.trim();
|
|
|
1218
1287
|
}
|
|
1219
1288
|
async sendMessage(text) {
|
|
1220
1289
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
1290
|
+
if (this.startupParseGate) {
|
|
1291
|
+
const deadline = Date.now() + 1e4;
|
|
1292
|
+
while (this.startupParseGate && Date.now() < deadline) {
|
|
1293
|
+
await new Promise((resolve8) => setTimeout(resolve8, 50));
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1221
1296
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
1222
1297
|
if (this.isWaitingForResponse) return;
|
|
1223
1298
|
this.messages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
1224
1299
|
this.structuredMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
1225
1300
|
this.isWaitingForResponse = true;
|
|
1226
1301
|
this.responseBuffer = "";
|
|
1302
|
+
this.submitRetryUsed = false;
|
|
1303
|
+
this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
|
|
1304
|
+
const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
|
|
1305
|
+
if (this.submitRetryTimer) {
|
|
1306
|
+
clearTimeout(this.submitRetryTimer);
|
|
1307
|
+
this.submitRetryTimer = null;
|
|
1308
|
+
}
|
|
1309
|
+
const estimatedLines = estimatePromptDisplayLines(text);
|
|
1310
|
+
const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
|
|
1311
|
+
const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
|
|
1312
|
+
const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
|
|
1313
|
+
if (this.settleTimer) {
|
|
1314
|
+
clearTimeout(this.settleTimer);
|
|
1315
|
+
this.settleTimer = null;
|
|
1316
|
+
}
|
|
1317
|
+
this.responseEpoch += 1;
|
|
1318
|
+
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
1227
1319
|
this.setStatus("generating", "sendMessage");
|
|
1228
1320
|
this.onStatusChange?.();
|
|
1321
|
+
if (submitDelayMs > 0) {
|
|
1322
|
+
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
1323
|
+
}
|
|
1229
1324
|
this.ptyProcess.write(text);
|
|
1230
1325
|
const submit = () => {
|
|
1231
1326
|
if (!this.ptyProcess) return;
|
|
1232
1327
|
this.submitPendingUntil = 0;
|
|
1233
1328
|
this.ptyProcess.write(this.sendKey);
|
|
1329
|
+
const retrySubmitIfStuck = (attempt) => {
|
|
1330
|
+
this.submitRetryTimer = null;
|
|
1331
|
+
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
1332
|
+
if (this.currentStatus !== "generating") return;
|
|
1333
|
+
if ((this.responseBuffer || "").trim()) return;
|
|
1334
|
+
const screenText = this.terminalScreen.getText();
|
|
1335
|
+
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
1336
|
+
if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
|
|
1337
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1338
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
1339
|
+
this.ptyProcess.write(this.sendKey);
|
|
1340
|
+
if (attempt >= 3) {
|
|
1341
|
+
this.submitRetryUsed = true;
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
|
|
1345
|
+
};
|
|
1346
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
|
|
1234
1347
|
this.responseTimeout = setTimeout(() => {
|
|
1235
1348
|
if (this.isWaitingForResponse) this.finishResponse();
|
|
1236
1349
|
}, this.timeouts.maxResponse);
|
|
1237
1350
|
};
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1351
|
+
const submitStartedAt = Date.now();
|
|
1352
|
+
let lastNormalizedScreen = "";
|
|
1353
|
+
let lastScreenChangeAt = submitStartedAt;
|
|
1354
|
+
const waitForEchoAndSubmit = () => {
|
|
1355
|
+
if (!this.ptyProcess) return;
|
|
1356
|
+
const now = Date.now();
|
|
1357
|
+
const elapsed = now - submitStartedAt;
|
|
1358
|
+
const screenText = this.terminalScreen.getText();
|
|
1359
|
+
const normalizedScreen = normalizePromptText(screenText);
|
|
1360
|
+
if (normalizedScreen !== lastNormalizedScreen) {
|
|
1361
|
+
lastNormalizedScreen = normalizedScreen;
|
|
1362
|
+
lastScreenChangeAt = now;
|
|
1363
|
+
}
|
|
1364
|
+
const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
|
|
1365
|
+
if (echoVisible) {
|
|
1366
|
+
const screenSettled = now - lastScreenChangeAt >= 500;
|
|
1367
|
+
if (elapsed >= submitDelayMs && screenSettled) {
|
|
1368
|
+
submit();
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (elapsed >= maxEchoWaitMs) {
|
|
1373
|
+
submit();
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
setTimeout(waitForEchoAndSubmit, 50);
|
|
1377
|
+
};
|
|
1378
|
+
waitForEchoAndSubmit();
|
|
1244
1379
|
}
|
|
1245
1380
|
getPartialResponse() {
|
|
1246
1381
|
if (!this.isWaitingForResponse) return "";
|
|
@@ -1258,6 +1393,10 @@ ${data.message || ""}`.trim();
|
|
|
1258
1393
|
clearTimeout(this.approvalExitTimeout);
|
|
1259
1394
|
this.approvalExitTimeout = null;
|
|
1260
1395
|
}
|
|
1396
|
+
if (this.submitRetryTimer) {
|
|
1397
|
+
clearTimeout(this.submitRetryTimer);
|
|
1398
|
+
this.submitRetryTimer = null;
|
|
1399
|
+
}
|
|
1261
1400
|
if (this.ptyProcess) {
|
|
1262
1401
|
this.ptyProcess.write("");
|
|
1263
1402
|
setTimeout(() => {
|
|
@@ -1279,6 +1418,8 @@ ${data.message || ""}`.trim();
|
|
|
1279
1418
|
this.structuredMessages = [];
|
|
1280
1419
|
this.accumulatedBuffer = "";
|
|
1281
1420
|
this.accumulatedRawBuffer = "";
|
|
1421
|
+
this.submitRetryUsed = false;
|
|
1422
|
+
this.submitRetryPromptSnippet = "";
|
|
1282
1423
|
this.terminalScreen.reset();
|
|
1283
1424
|
this.onStatusChange?.();
|
|
1284
1425
|
}
|
|
@@ -1292,7 +1433,16 @@ ${data.message || ""}`.trim();
|
|
|
1292
1433
|
this.ptyProcess?.write(data);
|
|
1293
1434
|
}
|
|
1294
1435
|
resolveModal(buttonIndex) {
|
|
1295
|
-
if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
|
|
1436
|
+
if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
|
|
1437
|
+
this.activeModal = null;
|
|
1438
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
1439
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1440
|
+
if (this.approvalExitTimeout) {
|
|
1441
|
+
clearTimeout(this.approvalExitTimeout);
|
|
1442
|
+
this.approvalExitTimeout = null;
|
|
1443
|
+
}
|
|
1444
|
+
this.setStatus("generating", "approval_resolved");
|
|
1445
|
+
this.onStatusChange?.();
|
|
1296
1446
|
if (buttonIndex in this.approvalKeys) {
|
|
1297
1447
|
this.ptyProcess.write(this.approvalKeys[buttonIndex]);
|
|
1298
1448
|
} else {
|
|
@@ -1334,6 +1484,10 @@ ${data.message || ""}`.trim();
|
|
|
1334
1484
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
1335
1485
|
activeModal: this.activeModal,
|
|
1336
1486
|
lastApprovalResolvedAt: this.lastApprovalResolvedAt,
|
|
1487
|
+
sendDelayMs: this.sendDelayMs,
|
|
1488
|
+
sendKey: this.sendKey,
|
|
1489
|
+
submitPendingUntil: this.submitPendingUntil,
|
|
1490
|
+
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
1337
1491
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
1338
1492
|
hasCliScripts: this.hasCliScripts(),
|
|
1339
1493
|
scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
|