@adhdev/daemon-standalone 0.9.82-rc.537 → 0.9.82-rc.539
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 +277 -15
- 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.539" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30214
|
+
const builtAt = readInjected(true ? "2026-07-15T15:55:46.990Z" : 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
|
}
|
|
@@ -54619,6 +54764,21 @@ ${cleanBody}`;
|
|
|
54619
54764
|
}
|
|
54620
54765
|
function findQuestionLineIndex(spec, lines) {
|
|
54621
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
|
+
}
|
|
54622
54782
|
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
54623
54783
|
if (primary.test(lines[i])) return { index: i, matchedSource: "primary" };
|
|
54624
54784
|
}
|
|
@@ -55352,6 +55512,7 @@ ${cont}` : cont;
|
|
|
55352
55512
|
* paint and made the engine type "1" repeatedly into the prompt.
|
|
55353
55513
|
*/
|
|
55354
55514
|
modalLostAt = 0;
|
|
55515
|
+
modalLostRecheckTimer = null;
|
|
55355
55516
|
approvalExitTimeout = null;
|
|
55356
55517
|
// ── Response tracking ────────────────────────────
|
|
55357
55518
|
responseEpoch = 0;
|
|
@@ -55403,6 +55564,10 @@ ${cont}` : cont;
|
|
|
55403
55564
|
setStatus(status, trigger) {
|
|
55404
55565
|
const prev = this.currentStatus;
|
|
55405
55566
|
if (prev === status) return;
|
|
55567
|
+
if (prev === "waiting_approval" && this.modalLostRecheckTimer) {
|
|
55568
|
+
clearTimeout(this.modalLostRecheckTimer);
|
|
55569
|
+
this.modalLostRecheckTimer = null;
|
|
55570
|
+
}
|
|
55406
55571
|
this.currentStatus = status;
|
|
55407
55572
|
this.statusHistory.push({ status, at: Date.now(), trigger });
|
|
55408
55573
|
if (this.statusHistory.length > 50) this.statusHistory.shift();
|
|
@@ -55563,6 +55728,10 @@ ${cont}` : cont;
|
|
|
55563
55728
|
clearTimeout(this.approvalExitTimeout);
|
|
55564
55729
|
this.approvalExitTimeout = null;
|
|
55565
55730
|
}
|
|
55731
|
+
if (this.modalLostRecheckTimer) {
|
|
55732
|
+
clearTimeout(this.modalLostRecheckTimer);
|
|
55733
|
+
this.modalLostRecheckTimer = null;
|
|
55734
|
+
}
|
|
55566
55735
|
if (this.finishRetryTimer) {
|
|
55567
55736
|
clearTimeout(this.finishRetryTimer);
|
|
55568
55737
|
this.finishRetryTimer = null;
|
|
@@ -55874,7 +56043,7 @@ ${cont}` : cont;
|
|
|
55874
56043
|
if (!inCooldown || modal) {
|
|
55875
56044
|
if (!modal) {
|
|
55876
56045
|
LOG2.warn("CLI", `[${this.provider.type}] detectStatus=waiting_approval but parseApproval returned null; ignoring`);
|
|
55877
|
-
if (this.currentStatus === "waiting_approval"
|
|
56046
|
+
if (this.currentStatus === "waiting_approval") {
|
|
55878
56047
|
const lostAt = this.modalLostAt || Date.now();
|
|
55879
56048
|
if (!this.modalLostAt) this.modalLostAt = lostAt;
|
|
55880
56049
|
if (Date.now() - lostAt >= this.timeouts.approvalCooldown) {
|
|
@@ -55882,6 +56051,8 @@ ${cont}` : cont;
|
|
|
55882
56051
|
this.modalLostAt = 0;
|
|
55883
56052
|
this.setStatus("generating", "approval_lost_modal");
|
|
55884
56053
|
this.callbacks.onStatusChange();
|
|
56054
|
+
} else {
|
|
56055
|
+
this.armModalLostRecheck();
|
|
55885
56056
|
}
|
|
55886
56057
|
}
|
|
55887
56058
|
return;
|
|
@@ -56143,6 +56314,25 @@ ${cont}` : cont;
|
|
|
56143
56314
|
this.recordTrace("idle_finish_cancelled", { trigger: reason });
|
|
56144
56315
|
}
|
|
56145
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
|
+
}
|
|
56146
56336
|
armApprovalExitTimeout() {
|
|
56147
56337
|
if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
|
|
56148
56338
|
this.approvalExitTimeout = setTimeout(() => {
|
|
@@ -65891,6 +66081,33 @@ ${effect.notification.body || ""}`.trim();
|
|
|
65891
66081
|
getState(key2) {
|
|
65892
66082
|
return this.records.get(key2)?.state ?? INITIAL_CHAT_SOURCE_STATE;
|
|
65893
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
|
+
}
|
|
65894
66111
|
/** Recent transitions, newest last. Empty array when nothing has happened. */
|
|
65895
66112
|
getTransitions(key2) {
|
|
65896
66113
|
return this.records.get(key2)?.transitions ?? [];
|
|
@@ -66312,7 +66529,52 @@ ${effect.notification.body || ""}`.trim();
|
|
|
66312
66529
|
const supportsNative = supportsCliNativeTranscript(args.providerType, args.provider);
|
|
66313
66530
|
const observation = buildObservationForCli(args, supportsNative);
|
|
66314
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");
|
|
66315
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
|
+
}
|
|
66316
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) {
|
|
66317
66579
|
CHAT_SOURCE_REGISTRY.clear(sessionKey);
|
|
66318
66580
|
decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
@@ -66632,7 +66894,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
66632
66894
|
function readCliProviderNativeHistory(agentStr, args) {
|
|
66633
66895
|
const canBindFromLiveSession = !args.historySessionId && typeof args.sessionStartedAtMs === "number" && args.sessionStartedAtMs > 0 && typeof args.workspace === "string" && args.workspace.trim().length > 0;
|
|
66634
66896
|
const pinnedProviderSessionId = typeof args.pinnedProviderSessionId === "string" ? args.pinnedProviderSessionId.trim() : "";
|
|
66635
|
-
const effectiveHistorySessionId = args.historySessionId ||
|
|
66897
|
+
const effectiveHistorySessionId = args.historySessionId || pinnedProviderSessionId || "";
|
|
66636
66898
|
const workspaceLatestFallback = !effectiveHistorySessionId && !canBindFromLiveSession && !pinnedProviderSessionId && args.allowWorkspaceLatestFallback === true && typeof args.workspace === "string" && args.workspace.trim().length > 0;
|
|
66637
66899
|
if (!effectiveHistorySessionId && !canBindFromLiveSession && !workspaceLatestFallback) {
|
|
66638
66900
|
return {
|