@adhdev/daemon-standalone 0.9.82-rc.536 → 0.9.82-rc.538
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +345 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/vendor/mcp-server/index.js +29 -2
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -30208,10 +30208,10 @@ var require_dist3 = __commonJS({
|
|
|
30208
30208
|
}
|
|
30209
30209
|
function getDaemonBuildInfo() {
|
|
30210
30210
|
if (cached2) return cached2;
|
|
30211
|
-
const commit = readInjected(true ? "
|
|
30212
|
-
const commitShort = readInjected(true ? "
|
|
30213
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30214
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
30211
|
+
const commit = readInjected(true ? "35ac849eca76162066561b27633e11827fa19a73" : void 0) ?? "unknown";
|
|
30212
|
+
const commitShort = readInjected(true ? "35ac849e" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30213
|
+
const version2 = readInjected(true ? "0.9.82-rc.538" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30214
|
+
const builtAt = readInjected(true ? "2026-07-15T15:52:37.408Z" : void 0);
|
|
30215
30215
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30216
30216
|
return cached2;
|
|
30217
30217
|
}
|
|
@@ -35565,6 +35565,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35565
35565
|
MESH_TASK_MODES: () => MESH_TASK_MODES,
|
|
35566
35566
|
MESH_TASK_PRIORITIES: () => MESH_TASK_PRIORITIES,
|
|
35567
35567
|
NOT_BEFORE_RELATIVE_THRESHOLD_MS: () => NOT_BEFORE_RELATIVE_THRESHOLD_MS,
|
|
35568
|
+
REDRIVE_RECLAIM_REASONS: () => REDRIVE_RECLAIM_REASONS,
|
|
35569
|
+
REDRIVE_SUPERSEDE_WINDOW_MS: () => REDRIVE_SUPERSEDE_WINDOW_MS,
|
|
35568
35570
|
__clearDirectDispatchesForTests: () => __clearDirectDispatchesForTests,
|
|
35569
35571
|
__clearMeshQueueForTests: () => __clearMeshQueueForTests,
|
|
35570
35572
|
__replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
|
|
@@ -35860,10 +35862,21 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35860
35862
|
return true;
|
|
35861
35863
|
});
|
|
35862
35864
|
}
|
|
35863
|
-
function
|
|
35864
|
-
const
|
|
35865
|
-
|
|
35866
|
-
|
|
35865
|
+
function readNodeProviderTypes(policy) {
|
|
35866
|
+
const record2 = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
35867
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35868
|
+
const out = [];
|
|
35869
|
+
const push = (type) => {
|
|
35870
|
+
const trimmed = typeof type === "string" ? type.trim() : "";
|
|
35871
|
+
if (!trimmed || seen.has(trimmed)) return;
|
|
35872
|
+
seen.add(trimmed);
|
|
35873
|
+
out.push(trimmed);
|
|
35874
|
+
};
|
|
35875
|
+
for (const slot of normalizeNodeCapabilitySlots(record2.slots)) push(slot.provider);
|
|
35876
|
+
if (Array.isArray(record2.providerPriority)) {
|
|
35877
|
+
for (const type of record2.providerPriority) push(type);
|
|
35878
|
+
}
|
|
35879
|
+
return out;
|
|
35867
35880
|
}
|
|
35868
35881
|
function readNodeOverride(node, key2) {
|
|
35869
35882
|
const overrides = node?.userOverrides;
|
|
@@ -35876,7 +35889,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35876
35889
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
35877
35890
|
}
|
|
35878
35891
|
function buildMeshNodeCapabilityTags(node, providerType) {
|
|
35879
|
-
const
|
|
35892
|
+
const pinnedProvider = typeof providerType === "string" && providerType.trim() ? providerType.trim() : void 0;
|
|
35893
|
+
const providerTags = pinnedProvider ? [pinnedProvider] : readNodeProviderTypes(node?.policy);
|
|
35880
35894
|
const worktreeBranch = typeof node?.worktreeBranch === "string" && node.worktreeBranch.trim() ? node.worktreeBranch.trim() : null;
|
|
35881
35895
|
const os322 = readNodeOverride(node, "platform") ?? readNodeReporter(node, "platform") ?? process.platform;
|
|
35882
35896
|
const arch2 = readNodeOverride(node, "arch") ?? readNodeReporter(node, "arch") ?? process.arch;
|
|
@@ -35884,7 +35898,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35884
35898
|
...Array.isArray(node?.capabilities) ? node.capabilities : [],
|
|
35885
35899
|
`os=${os322}`,
|
|
35886
35900
|
`arch=${arch2}`,
|
|
35887
|
-
...
|
|
35901
|
+
...providerTags.map((p) => `provider=${p}`),
|
|
35888
35902
|
// Worktree nodes automatically expose a "worktree=<branch>" tag so that
|
|
35889
35903
|
// mesh_enqueue_task with required_tags: ["worktree=<branch>"] routes
|
|
35890
35904
|
// only to the matching worktree node.
|
|
@@ -36400,6 +36414,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
36400
36414
|
var GIT_STASH_READONLY_SUBCOMMANDS;
|
|
36401
36415
|
var DEPENDENCY_FAILURE_TERMINALS;
|
|
36402
36416
|
var MAX_STRANDED_RECLAIMS;
|
|
36417
|
+
var REDRIVE_RECLAIM_REASONS;
|
|
36418
|
+
var REDRIVE_SUPERSEDE_WINDOW_MS;
|
|
36403
36419
|
var init_mesh_work_queue = __esm2({
|
|
36404
36420
|
"src/mesh/mesh-work-queue.ts"() {
|
|
36405
36421
|
"use strict";
|
|
@@ -36468,6 +36484,12 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
36468
36484
|
GIT_STASH_READONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "show"]);
|
|
36469
36485
|
DEPENDENCY_FAILURE_TERMINALS = /* @__PURE__ */ new Set(["failed", "cancelled"]);
|
|
36470
36486
|
MAX_STRANDED_RECLAIMS = 3;
|
|
36487
|
+
REDRIVE_RECLAIM_REASONS = /* @__PURE__ */ new Set([
|
|
36488
|
+
"delivered_no_turn_deadline",
|
|
36489
|
+
"reclaim_after_unknown_grace",
|
|
36490
|
+
"delivered_not_consumed_redrive"
|
|
36491
|
+
]);
|
|
36492
|
+
REDRIVE_SUPERSEDE_WINDOW_MS = 5 * 6e4;
|
|
36471
36493
|
}
|
|
36472
36494
|
});
|
|
36473
36495
|
function loadDatabaseCtor() {
|
|
@@ -46753,7 +46775,8 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
46753
46775
|
if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
|
|
46754
46776
|
if (task.taskMode === "convergence" && node?.isLocalWorktree === true) return false;
|
|
46755
46777
|
if (task.requiredTags?.length) {
|
|
46756
|
-
const
|
|
46778
|
+
const slotProviders = resolveNodeCapabilitySlots(node).map((s2) => s2.provider).filter(Boolean);
|
|
46779
|
+
const priorities = slotProviders.length ? slotProviders : normalizeProviderPriority2(node?.policy);
|
|
46757
46780
|
const providerCandidates = priorities.length ? priorities : [void 0];
|
|
46758
46781
|
return providerCandidates.some(
|
|
46759
46782
|
(p) => nodeSatisfiesRequiredTags(task.requiredTags, buildMeshNodeCapabilityTags(node, p))
|
|
@@ -50373,6 +50396,52 @@ ${cleanBody}`;
|
|
|
50373
50396
|
LOG2.warn("MeshQueue", `stopStaleMeshWorker error for ${sessionId}: ${e?.message || e}`);
|
|
50374
50397
|
}
|
|
50375
50398
|
}
|
|
50399
|
+
function supersedeRedriveReclaimForLateCompletion(components, meshId, row, completingSessionId, outcome, args) {
|
|
50400
|
+
if (!row.requeueReason || !REDRIVE_RECLAIM_REASONS.has(row.requeueReason)) return false;
|
|
50401
|
+
if (row.status === "completed" || row.status === "failed" || row.status === "cancelled") return false;
|
|
50402
|
+
const requeuedAtMs = Date.parse(row.requeuedAt ?? "");
|
|
50403
|
+
if (!Number.isFinite(requeuedAtMs)) return false;
|
|
50404
|
+
if (Date.now() - requeuedAtMs > REDRIVE_SUPERSEDE_WINDOW_MS) return false;
|
|
50405
|
+
const reDispatchedSessionId = row.assignedSessionId;
|
|
50406
|
+
if (row.status === "assigned" && reDispatchedSessionId && !sessionIdsEquivalent(reDispatchedSessionId, completingSessionId)) {
|
|
50407
|
+
stopStaleMeshWorker(components, {
|
|
50408
|
+
meshId,
|
|
50409
|
+
sessionId: reDispatchedSessionId,
|
|
50410
|
+
nodeId: row.assignedNodeId,
|
|
50411
|
+
providerType: row.assignedProviderType
|
|
50412
|
+
});
|
|
50413
|
+
}
|
|
50414
|
+
endTaskDispatchInFlight(meshId, row.id);
|
|
50415
|
+
updateTaskStatus(meshId, row.id, outcome === "completed" ? "completed" : "failed");
|
|
50416
|
+
if (!findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
|
|
50417
|
+
try {
|
|
50418
|
+
appendLedgerEntry(meshId, {
|
|
50419
|
+
kind: outcome === "completed" ? "task_completed" : "task_failed",
|
|
50420
|
+
sessionId: completingSessionId,
|
|
50421
|
+
nodeId: readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId) || void 0,
|
|
50422
|
+
providerType: readNonEmptyString2(args.metadataEvent.providerType) || void 0,
|
|
50423
|
+
payload: {
|
|
50424
|
+
taskId: row.id,
|
|
50425
|
+
event: args.event,
|
|
50426
|
+
source: "redrive_late_completion_supersede",
|
|
50427
|
+
reclaimReason: row.requeueReason,
|
|
50428
|
+
reclaimAgeMs: Date.now() - requeuedAtMs,
|
|
50429
|
+
finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0
|
|
50430
|
+
}
|
|
50431
|
+
});
|
|
50432
|
+
} catch {
|
|
50433
|
+
}
|
|
50434
|
+
}
|
|
50435
|
+
LOG2.warn("MeshQueue", `Late completion superseded re-drive for task ${row.id} on mesh ${meshId} (reclaimed '${row.requeueReason}' ${Math.round((Date.now() - requeuedAtMs) / 1e3)}s ago; completing session ${completingSessionId}) \u2192 flipped ${outcome}${row.status === "assigned" && reDispatchedSessionId && !sessionIdsEquivalent(reDispatchedSessionId, completingSessionId) ? `, stopped duplicate re-dispatch on ${reDispatchedSessionId}` : ""}`);
|
|
50436
|
+
traceMeshEventDrop("redrive_late_completion_supersede", {
|
|
50437
|
+
taskId: row.id,
|
|
50438
|
+
sessionId: completingSessionId,
|
|
50439
|
+
nodeId: row.assignedNodeId ?? args.nodeId,
|
|
50440
|
+
meshId,
|
|
50441
|
+
event: args.event
|
|
50442
|
+
}, `${row.requeueReason} ${Math.round((Date.now() - requeuedAtMs) / 1e3)}s \u2192 ${outcome}`);
|
|
50443
|
+
return true;
|
|
50444
|
+
}
|
|
50376
50445
|
function injectMeshSystemMessage(components, args) {
|
|
50377
50446
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
50378
50447
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
@@ -50484,6 +50553,7 @@ ${cleanBody}`;
|
|
|
50484
50553
|
}
|
|
50485
50554
|
});
|
|
50486
50555
|
}
|
|
50556
|
+
} else if (strandedRow && supersedeRedriveReclaimForLateCompletion(components, args.meshId, strandedRow, sessionId, outcome, args)) {
|
|
50487
50557
|
}
|
|
50488
50558
|
} catch {
|
|
50489
50559
|
}
|
|
@@ -51807,6 +51877,50 @@ ${cleanBody}`;
|
|
|
51807
51877
|
LOG2.info("MeshReconcile", `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
51808
51878
|
}
|
|
51809
51879
|
}
|
|
51880
|
+
async function pollAssignedTaskTerminalEvidence(components, mesh, row) {
|
|
51881
|
+
const sessionId = readNonEmptyString2(row.assignedSessionId);
|
|
51882
|
+
const nodeId = readNonEmptyString2(row.assignedNodeId);
|
|
51883
|
+
if (!sessionId || !nodeId) return null;
|
|
51884
|
+
const node = (mesh.nodes ?? []).find((n) => n.id === nodeId);
|
|
51885
|
+
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
51886
|
+
const localDaemonId = readNonEmptyString2(components.statusInstanceId);
|
|
51887
|
+
const isLocalNode = !nodeDaemonId || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
51888
|
+
const providerType = readNonEmptyString2(row.assignedProviderType);
|
|
51889
|
+
const readArgs = {
|
|
51890
|
+
sessionId,
|
|
51891
|
+
targetSessionId: sessionId,
|
|
51892
|
+
tailLimit: 10,
|
|
51893
|
+
...node?.workspace ? { workspace: node.workspace } : {},
|
|
51894
|
+
...providerType ? { agentType: providerType, providerType } : {}
|
|
51895
|
+
};
|
|
51896
|
+
let payload = null;
|
|
51897
|
+
try {
|
|
51898
|
+
if (isLocalNode) {
|
|
51899
|
+
const result = await components.commandHandler?.handle("read_chat", readArgs);
|
|
51900
|
+
if (result && result.success === false) return null;
|
|
51901
|
+
payload = unwrapReadChatPayload(result);
|
|
51902
|
+
} else if (components.dispatchMeshCommand) {
|
|
51903
|
+
const result = await components.dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
51904
|
+
payload = unwrapReadChatPayload(result);
|
|
51905
|
+
if (payload && payload.success === false) return null;
|
|
51906
|
+
} else {
|
|
51907
|
+
return null;
|
|
51908
|
+
}
|
|
51909
|
+
} catch {
|
|
51910
|
+
return null;
|
|
51911
|
+
}
|
|
51912
|
+
if (!payload) return null;
|
|
51913
|
+
if (readChatPayloadStatus(payload) !== "idle") return null;
|
|
51914
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
51915
|
+
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
51916
|
+
if (!evidence.finalSummary) return null;
|
|
51917
|
+
const dispatchedAtMs = Date.parse(readNonEmptyString2(row.dispatchTimestamp));
|
|
51918
|
+
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
51919
|
+
if (!(Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs >= dispatchedAtMs)) {
|
|
51920
|
+
return null;
|
|
51921
|
+
}
|
|
51922
|
+
return "completed";
|
|
51923
|
+
}
|
|
51810
51924
|
var init_mesh_completion_synthesis = __esm2({
|
|
51811
51925
|
"src/mesh/mesh-completion-synthesis.ts"() {
|
|
51812
51926
|
"use strict";
|
|
@@ -52081,7 +52195,8 @@ ${cleanBody}`;
|
|
|
52081
52195
|
}
|
|
52082
52196
|
return delivered;
|
|
52083
52197
|
}
|
|
52084
|
-
function recoverStrandedAssignedDispatches(components,
|
|
52198
|
+
async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
52199
|
+
const meshId = mesh.id;
|
|
52085
52200
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
52086
52201
|
if (!assigned.length) return;
|
|
52087
52202
|
const nowMs = Date.now();
|
|
@@ -52188,6 +52303,36 @@ ${cleanBody}`;
|
|
|
52188
52303
|
}
|
|
52189
52304
|
reclaimReason = "reclaim_after_unknown_grace";
|
|
52190
52305
|
}
|
|
52306
|
+
const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row);
|
|
52307
|
+
if (terminalEvidence) {
|
|
52308
|
+
deliveredNoTurnUnknownStreak.delete(streakKey);
|
|
52309
|
+
updateTaskStatus(meshId, row.id, terminalEvidence);
|
|
52310
|
+
if (!findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
|
|
52311
|
+
try {
|
|
52312
|
+
appendLedgerEntry(meshId, {
|
|
52313
|
+
kind: terminalEvidence === "completed" ? "task_completed" : "task_failed",
|
|
52314
|
+
nodeId: row.assignedNodeId,
|
|
52315
|
+
sessionId: row.assignedSessionId,
|
|
52316
|
+
providerType: row.assignedProviderType,
|
|
52317
|
+
payload: {
|
|
52318
|
+
taskId: row.id,
|
|
52319
|
+
event: "agent:generating_completed",
|
|
52320
|
+
source: "redrive_deadline_transcript_evidence"
|
|
52321
|
+
}
|
|
52322
|
+
});
|
|
52323
|
+
} catch {
|
|
52324
|
+
}
|
|
52325
|
+
}
|
|
52326
|
+
LOG2.warn("MeshReconcile", `Skipped delivered-no-turn re-drive for task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}): worker transcript is idle with a final assistant message after dispatch \u2014 the completion event was lost/late, task is ${terminalEvidence}, NOT re-driving`);
|
|
52327
|
+
traceMeshEventDrop("redrive_deadline_transcript_completed", {
|
|
52328
|
+
taskId: row.id,
|
|
52329
|
+
sessionId: row.assignedSessionId,
|
|
52330
|
+
nodeId: row.assignedNodeId,
|
|
52331
|
+
meshId,
|
|
52332
|
+
event: "agent:generating_completed"
|
|
52333
|
+
}, `${reclaimReason} \u2192 transcript ${terminalEvidence}`);
|
|
52334
|
+
continue;
|
|
52335
|
+
}
|
|
52191
52336
|
const reclaimedLost = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
52192
52337
|
reason: reclaimReason,
|
|
52193
52338
|
ageMs: nowMs - dispatchedAtMs
|
|
@@ -52314,7 +52459,7 @@ ${cleanBody}`;
|
|
|
52314
52459
|
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
52315
52460
|
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
52316
52461
|
try {
|
|
52317
|
-
recoverStrandedAssignedDispatches(components, mesh
|
|
52462
|
+
await recoverStrandedAssignedDispatches(components, mesh, store);
|
|
52318
52463
|
} catch (e) {
|
|
52319
52464
|
LOG2.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
52320
52465
|
}
|
|
@@ -54488,6 +54633,70 @@ ${cleanBody}`;
|
|
|
54488
54633
|
if (buttonBlockApprovalCue(spec, text)) return true;
|
|
54489
54634
|
return false;
|
|
54490
54635
|
}
|
|
54636
|
+
function lastModalCueLine(spec, screenText) {
|
|
54637
|
+
if (!screenText) return -1;
|
|
54638
|
+
const lines = screenText.split("\n");
|
|
54639
|
+
const question = compile2(spec.questionPattern, spec.questionFlags ?? "i");
|
|
54640
|
+
const variants = (spec.questionVariants ?? []).map((v) => compile2(v.regex, v.flags ?? "i"));
|
|
54641
|
+
const buttonFlags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
|
|
54642
|
+
const buttonRe = compile2(spec.buttonPattern, buttonFlags);
|
|
54643
|
+
let last = -1;
|
|
54644
|
+
for (let i = 0; i < lines.length; i++) {
|
|
54645
|
+
const line = lines[i];
|
|
54646
|
+
question.lastIndex = 0;
|
|
54647
|
+
if (question.test(line)) {
|
|
54648
|
+
last = i;
|
|
54649
|
+
continue;
|
|
54650
|
+
}
|
|
54651
|
+
if (variants.some((re) => {
|
|
54652
|
+
re.lastIndex = 0;
|
|
54653
|
+
return re.test(line);
|
|
54654
|
+
})) {
|
|
54655
|
+
last = i;
|
|
54656
|
+
continue;
|
|
54657
|
+
}
|
|
54658
|
+
buttonRe.lastIndex = 0;
|
|
54659
|
+
if (buttonRe.test(line)) {
|
|
54660
|
+
last = i;
|
|
54661
|
+
continue;
|
|
54662
|
+
}
|
|
54663
|
+
}
|
|
54664
|
+
return last;
|
|
54665
|
+
}
|
|
54666
|
+
function modalSupersededBySettledPrompt(modalSpec, settledSpec, settled, input) {
|
|
54667
|
+
if (!settled || !settledSpec) return false;
|
|
54668
|
+
if (settledSpec.scope === "whole-screen") return false;
|
|
54669
|
+
const screenText = input.screenText ?? "";
|
|
54670
|
+
if (!screenText) return false;
|
|
54671
|
+
const modalLine = lastModalCueLine(modalSpec, screenText);
|
|
54672
|
+
if (modalLine < 0) return false;
|
|
54673
|
+
const lines = screenText.split("\n");
|
|
54674
|
+
const below = lines.slice(modalLine + 1);
|
|
54675
|
+
if (below.length === 0) return false;
|
|
54676
|
+
const belowText = below.join("\n");
|
|
54677
|
+
if (!settled.prompt.test(belowText)) return false;
|
|
54678
|
+
if (settled.footers.length > 0 && !settled.footers.every((f) => f.test(belowText))) return false;
|
|
54679
|
+
const question = compile2(modalSpec.questionPattern, modalSpec.questionFlags ?? "i");
|
|
54680
|
+
const variants = (modalSpec.questionVariants ?? []).map((v) => compile2(v.regex, v.flags ?? "i"));
|
|
54681
|
+
const buttonFlags = modalSpec.buttonFlags && modalSpec.buttonFlags.includes("m") ? modalSpec.buttonFlags : `${modalSpec.buttonFlags ?? ""}m`;
|
|
54682
|
+
const buttonRe = compile2(modalSpec.buttonPattern, buttonFlags);
|
|
54683
|
+
const isModalCueLine = (line) => {
|
|
54684
|
+
question.lastIndex = 0;
|
|
54685
|
+
if (question.test(line)) return true;
|
|
54686
|
+
if (variants.some((re) => {
|
|
54687
|
+
re.lastIndex = 0;
|
|
54688
|
+
return re.test(line);
|
|
54689
|
+
})) return true;
|
|
54690
|
+
buttonRe.lastIndex = 0;
|
|
54691
|
+
return buttonRe.test(line);
|
|
54692
|
+
};
|
|
54693
|
+
const settledPromptLineRe = compile2(settledSpec.regex, (settledSpec.flags ?? "m").includes("m") ? settledSpec.flags ?? "m" : `${settledSpec.flags ?? ""}m`);
|
|
54694
|
+
const isSettledLine = (line) => {
|
|
54695
|
+
settledPromptLineRe.lastIndex = 0;
|
|
54696
|
+
return settledPromptLineRe.test(line);
|
|
54697
|
+
};
|
|
54698
|
+
return below.some((line) => line.trim() !== "" && !isModalCueLine(line) && !isSettledLine(line));
|
|
54699
|
+
}
|
|
54491
54700
|
function evaluateGroup(group, spec, input, compiled) {
|
|
54492
54701
|
switch (group) {
|
|
54493
54702
|
case "spinner": {
|
|
@@ -54497,7 +54706,9 @@ ${cleanBody}`;
|
|
|
54497
54706
|
}
|
|
54498
54707
|
case "modal": {
|
|
54499
54708
|
if (!spec.modal) return null;
|
|
54500
|
-
|
|
54709
|
+
if (!modalMatches(spec.modal, input)) return null;
|
|
54710
|
+
if (modalSupersededBySettledPrompt(spec.modal, spec.settledPrompt, compiled.settled, input)) return null;
|
|
54711
|
+
return "waiting_approval";
|
|
54501
54712
|
}
|
|
54502
54713
|
case "settled-prompt": {
|
|
54503
54714
|
if (!spec.settledPrompt || !compiled.settled) return null;
|
|
@@ -54553,6 +54764,21 @@ ${cleanBody}`;
|
|
|
54553
54764
|
}
|
|
54554
54765
|
function findQuestionLineIndex(spec, lines) {
|
|
54555
54766
|
const primary = compile3(spec.questionPattern, spec.questionFlags ?? "i");
|
|
54767
|
+
const buttonFlags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
|
|
54768
|
+
const buttonRe = compile3(spec.buttonPattern, buttonFlags);
|
|
54769
|
+
const isButtonLine = (line) => {
|
|
54770
|
+
buttonRe.lastIndex = 0;
|
|
54771
|
+
return buttonRe.test(line);
|
|
54772
|
+
};
|
|
54773
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
54774
|
+
if (primary.test(lines[i]) && !isButtonLine(lines[i])) return { index: i, matchedSource: "primary" };
|
|
54775
|
+
}
|
|
54776
|
+
for (const variant of spec.questionVariants ?? []) {
|
|
54777
|
+
const re = compile3(variant.regex, variant.flags ?? "i");
|
|
54778
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
54779
|
+
if (re.test(lines[i]) && !isButtonLine(lines[i])) return { index: i, matchedSource: variant.label ?? "variant" };
|
|
54780
|
+
}
|
|
54781
|
+
}
|
|
54556
54782
|
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
54557
54783
|
if (primary.test(lines[i])) return { index: i, matchedSource: "primary" };
|
|
54558
54784
|
}
|
|
@@ -55286,6 +55512,7 @@ ${cont}` : cont;
|
|
|
55286
55512
|
* paint and made the engine type "1" repeatedly into the prompt.
|
|
55287
55513
|
*/
|
|
55288
55514
|
modalLostAt = 0;
|
|
55515
|
+
modalLostRecheckTimer = null;
|
|
55289
55516
|
approvalExitTimeout = null;
|
|
55290
55517
|
// ── Response tracking ────────────────────────────
|
|
55291
55518
|
responseEpoch = 0;
|
|
@@ -55337,6 +55564,10 @@ ${cont}` : cont;
|
|
|
55337
55564
|
setStatus(status, trigger) {
|
|
55338
55565
|
const prev = this.currentStatus;
|
|
55339
55566
|
if (prev === status) return;
|
|
55567
|
+
if (prev === "waiting_approval" && this.modalLostRecheckTimer) {
|
|
55568
|
+
clearTimeout(this.modalLostRecheckTimer);
|
|
55569
|
+
this.modalLostRecheckTimer = null;
|
|
55570
|
+
}
|
|
55340
55571
|
this.currentStatus = status;
|
|
55341
55572
|
this.statusHistory.push({ status, at: Date.now(), trigger });
|
|
55342
55573
|
if (this.statusHistory.length > 50) this.statusHistory.shift();
|
|
@@ -55497,6 +55728,10 @@ ${cont}` : cont;
|
|
|
55497
55728
|
clearTimeout(this.approvalExitTimeout);
|
|
55498
55729
|
this.approvalExitTimeout = null;
|
|
55499
55730
|
}
|
|
55731
|
+
if (this.modalLostRecheckTimer) {
|
|
55732
|
+
clearTimeout(this.modalLostRecheckTimer);
|
|
55733
|
+
this.modalLostRecheckTimer = null;
|
|
55734
|
+
}
|
|
55500
55735
|
if (this.finishRetryTimer) {
|
|
55501
55736
|
clearTimeout(this.finishRetryTimer);
|
|
55502
55737
|
this.finishRetryTimer = null;
|
|
@@ -55808,7 +56043,7 @@ ${cont}` : cont;
|
|
|
55808
56043
|
if (!inCooldown || modal) {
|
|
55809
56044
|
if (!modal) {
|
|
55810
56045
|
LOG2.warn("CLI", `[${this.provider.type}] detectStatus=waiting_approval but parseApproval returned null; ignoring`);
|
|
55811
|
-
if (this.currentStatus === "waiting_approval"
|
|
56046
|
+
if (this.currentStatus === "waiting_approval") {
|
|
55812
56047
|
const lostAt = this.modalLostAt || Date.now();
|
|
55813
56048
|
if (!this.modalLostAt) this.modalLostAt = lostAt;
|
|
55814
56049
|
if (Date.now() - lostAt >= this.timeouts.approvalCooldown) {
|
|
@@ -55816,6 +56051,8 @@ ${cont}` : cont;
|
|
|
55816
56051
|
this.modalLostAt = 0;
|
|
55817
56052
|
this.setStatus("generating", "approval_lost_modal");
|
|
55818
56053
|
this.callbacks.onStatusChange();
|
|
56054
|
+
} else {
|
|
56055
|
+
this.armModalLostRecheck();
|
|
55819
56056
|
}
|
|
55820
56057
|
}
|
|
55821
56058
|
return;
|
|
@@ -56077,6 +56314,25 @@ ${cont}` : cont;
|
|
|
56077
56314
|
this.recordTrace("idle_finish_cancelled", { trigger: reason });
|
|
56078
56315
|
}
|
|
56079
56316
|
// ─── Helpers ────────────────────────────────────────────────────────────
|
|
56317
|
+
/**
|
|
56318
|
+
* Schedule one more settled evaluation while pinned to `waiting_approval`
|
|
56319
|
+
* with no actionable modal. The settled FSM normally only re-runs on new
|
|
56320
|
+
* PTY output; a provider whose modal cue lingers in a form detectStatus
|
|
56321
|
+
* still matches (e.g. kimi's questionPattern hitting the user echo) but
|
|
56322
|
+
* whose PTY has gone quiet would never get another evaluation, latching
|
|
56323
|
+
* `waiting_approval` forever. This timer guarantees the modal-lost recovery
|
|
56324
|
+
* in `applyWaitingApproval` is reached even against a silent PTY. It is a
|
|
56325
|
+
* no-op once the FSM leaves `waiting_approval` (the re-evaluation itself
|
|
56326
|
+
* takes the recovery branch and clears the state).
|
|
56327
|
+
*/
|
|
56328
|
+
armModalLostRecheck() {
|
|
56329
|
+
if (this.modalLostRecheckTimer) return;
|
|
56330
|
+
this.modalLostRecheckTimer = setTimeout(() => {
|
|
56331
|
+
this.modalLostRecheckTimer = null;
|
|
56332
|
+
if (this.currentStatus !== "waiting_approval") return;
|
|
56333
|
+
this.evaluateSettled(this.transport.getSnapshot());
|
|
56334
|
+
}, this.timeouts.approvalCooldown);
|
|
56335
|
+
}
|
|
56080
56336
|
armApprovalExitTimeout() {
|
|
56081
56337
|
if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
|
|
56082
56338
|
this.approvalExitTimeout = setTimeout(() => {
|
|
@@ -56669,6 +56925,7 @@ ${cont}` : cont;
|
|
|
56669
56925
|
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
56670
56926
|
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
56671
56927
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
56928
|
+
if (this.runDetectStatus(screenText) === "idle") return screenText;
|
|
56672
56929
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
56673
56930
|
return `${screenText}
|
|
56674
56931
|
${lastSnapshot}`;
|
|
@@ -65824,6 +66081,33 @@ ${effect.notification.body || ""}`.trim();
|
|
|
65824
66081
|
getState(key2) {
|
|
65825
66082
|
return this.records.get(key2)?.state ?? INITIAL_CHAT_SOURCE_STATE;
|
|
65826
66083
|
}
|
|
66084
|
+
/**
|
|
66085
|
+
* Opaque snapshot of a session's FULL record (state + lock + transitions),
|
|
66086
|
+
* for callers that need to speculatively `observe()` and then roll back if
|
|
66087
|
+
* the resulting decision is undesirable (STICKY-NATIVE hold: a trusted
|
|
66088
|
+
* exact-identity session must not flip to PTY on a transient native gap).
|
|
66089
|
+
* Returns undefined when the session has no record yet. The snapshot is a
|
|
66090
|
+
* shallow copy — transitions array is copied so a later append does not
|
|
66091
|
+
* mutate it.
|
|
66092
|
+
*/
|
|
66093
|
+
snapshotRecord(key2) {
|
|
66094
|
+
const rec = this.records.get(key2);
|
|
66095
|
+
if (!rec) return void 0;
|
|
66096
|
+
return { state: rec.state, lockedSince: rec.lockedSince, transitions: [...rec.transitions] };
|
|
66097
|
+
}
|
|
66098
|
+
/** Restore a previously snapshotted record, undoing a speculative observe.
|
|
66099
|
+
* Passing undefined clears the key (it had no record when snapshotted). */
|
|
66100
|
+
restoreRecord(key2, snapshot) {
|
|
66101
|
+
if (!snapshot) {
|
|
66102
|
+
this.records.delete(key2);
|
|
66103
|
+
return;
|
|
66104
|
+
}
|
|
66105
|
+
this.records.set(key2, {
|
|
66106
|
+
state: snapshot.state,
|
|
66107
|
+
lockedSince: snapshot.lockedSince,
|
|
66108
|
+
transitions: [...snapshot.transitions]
|
|
66109
|
+
});
|
|
66110
|
+
}
|
|
65827
66111
|
/** Recent transitions, newest last. Empty array when nothing has happened. */
|
|
65828
66112
|
getTransitions(key2) {
|
|
65829
66113
|
return this.records.get(key2)?.transitions ?? [];
|
|
@@ -66245,7 +66529,52 @@ ${effect.notification.body || ""}`.trim();
|
|
|
66245
66529
|
const supportsNative = supportsCliNativeTranscript(args.providerType, args.provider);
|
|
66246
66530
|
const observation = buildObservationForCli(args, supportsNative);
|
|
66247
66531
|
const sessionKey = chatSourceSessionKey(args.providerType, args.sessionId);
|
|
66532
|
+
const priorSnapshot = CHAT_SOURCE_REGISTRY.snapshotRecord(sessionKey);
|
|
66533
|
+
const priorState = priorSnapshot?.state ?? CHAT_SOURCE_REGISTRY.getState(sessionKey);
|
|
66534
|
+
const eligibleForStickyHold = args.trustedExactNativeIdentity === true && (priorState.name === "NativeLocked" || priorState.name === "Recovering");
|
|
66248
66535
|
let decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
66536
|
+
if (eligibleForStickyHold && decision.selected === "pty-parser") {
|
|
66537
|
+
CHAT_SOURCE_REGISTRY.restoreRecord(sessionKey, priorSnapshot);
|
|
66538
|
+
const heldNativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
66539
|
+
const messageSource2 = buildCliMessageSourceProvenance({
|
|
66540
|
+
selected: "native-history",
|
|
66541
|
+
provider: args.providerType,
|
|
66542
|
+
nativeHandle: typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0,
|
|
66543
|
+
sessionWorkspace: args.sessionWorkspace,
|
|
66544
|
+
intendedWorkspace: args.intendedWorkspace,
|
|
66545
|
+
transcriptWorkspace: void 0,
|
|
66546
|
+
fallbackReason: "native_history_transient_gap_held",
|
|
66547
|
+
nativeSource: "provider-native",
|
|
66548
|
+
sourcePath: typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0,
|
|
66549
|
+
sourceMtimeMs: typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0,
|
|
66550
|
+
nativeHistoryCoverage: void 0,
|
|
66551
|
+
partialReason: void 0,
|
|
66552
|
+
unavailableReason: observation.kind === "native_unavailable" ? observation.reason : void 0,
|
|
66553
|
+
nativeMessages: heldNativeMessages,
|
|
66554
|
+
ptyMessages: args.ptyMessages,
|
|
66555
|
+
returnedMessages: heldNativeMessages,
|
|
66556
|
+
safeMapping: args.safeMapping,
|
|
66557
|
+
freshEnough: true,
|
|
66558
|
+
ptyStatusApprovalOnly: true
|
|
66559
|
+
});
|
|
66560
|
+
return {
|
|
66561
|
+
decision: {
|
|
66562
|
+
selected: "native-history",
|
|
66563
|
+
nextState: priorState,
|
|
66564
|
+
transition: {
|
|
66565
|
+
fromState: priorState.name,
|
|
66566
|
+
toState: priorState.name,
|
|
66567
|
+
event: "NoOp",
|
|
66568
|
+
cause: decision.transition.cause,
|
|
66569
|
+
at: Date.now()
|
|
66570
|
+
},
|
|
66571
|
+
lockState: { locked: priorState.name === "NativeLocked" }
|
|
66572
|
+
},
|
|
66573
|
+
messageSource: messageSource2,
|
|
66574
|
+
nativeMessages: heldNativeMessages,
|
|
66575
|
+
nativeSelected: true
|
|
66576
|
+
};
|
|
66577
|
+
}
|
|
66249
66578
|
if (decision.selected === "pty-parser" && args.trustedExactNativeIdentity === true && args.safeMapping && args.ptyMessages.length === 0 && observation.kind === "native_present" && observation.coverage !== "partial" && observation.messages.length > 0) {
|
|
66250
66579
|
CHAT_SOURCE_REGISTRY.clear(sessionKey);
|
|
66251
66580
|
decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
@@ -66565,7 +66894,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
66565
66894
|
function readCliProviderNativeHistory(agentStr, args) {
|
|
66566
66895
|
const canBindFromLiveSession = !args.historySessionId && typeof args.sessionStartedAtMs === "number" && args.sessionStartedAtMs > 0 && typeof args.workspace === "string" && args.workspace.trim().length > 0;
|
|
66567
66896
|
const pinnedProviderSessionId = typeof args.pinnedProviderSessionId === "string" ? args.pinnedProviderSessionId.trim() : "";
|
|
66568
|
-
const effectiveHistorySessionId = args.historySessionId ||
|
|
66897
|
+
const effectiveHistorySessionId = args.historySessionId || pinnedProviderSessionId || "";
|
|
66569
66898
|
const workspaceLatestFallback = !effectiveHistorySessionId && !canBindFromLiveSession && !pinnedProviderSessionId && args.allowWorkspaceLatestFallback === true && typeof args.workspace === "string" && args.workspace.trim().length > 0;
|
|
66570
66899
|
if (!effectiveHistorySessionId && !canBindFromLiveSession && !workspaceLatestFallback) {
|
|
66571
66900
|
return {
|