@adhdev/daemon-standalone 0.9.82-rc.362 → 0.9.82-rc.364
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 +139 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30036,10 +30036,10 @@ var require_dist3 = __commonJS({
|
|
|
30036
30036
|
}
|
|
30037
30037
|
function getDaemonBuildInfo() {
|
|
30038
30038
|
if (cached2) return cached2;
|
|
30039
|
-
const commit = readInjected(true ? "
|
|
30040
|
-
const commitShort = readInjected(true ? "
|
|
30041
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30042
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
30039
|
+
const commit = readInjected(true ? "1428e9d027beefe860a77f34dea34d202db80f00" : void 0) ?? "unknown";
|
|
30040
|
+
const commitShort = readInjected(true ? "1428e9d0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30041
|
+
const version2 = readInjected(true ? "0.9.82-rc.364" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30042
|
+
const builtAt = readInjected(true ? "2026-06-24T00:06:20.085Z" : void 0);
|
|
30043
30043
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30044
30044
|
return cached2;
|
|
30045
30045
|
}
|
|
@@ -38374,6 +38374,13 @@ ${rendered}`, "utf-8");
|
|
|
38374
38374
|
}
|
|
38375
38375
|
return 0;
|
|
38376
38376
|
}
|
|
38377
|
+
function isWeakCompletionMetadata(metadataEvent) {
|
|
38378
|
+
const evidenceLevel = readNonEmptyString2(metadataEvent.evidenceLevel);
|
|
38379
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
38380
|
+
if (metadataEvent.reviewRecommended === true) return true;
|
|
38381
|
+
const diag = readRecord4(metadataEvent.completionDiagnostic);
|
|
38382
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
38383
|
+
}
|
|
38377
38384
|
function formatCompletionMetadata(event) {
|
|
38378
38385
|
const completionDiagnostic = event.completionDiagnostic && typeof event.completionDiagnostic === "object" ? event.completionDiagnostic : null;
|
|
38379
38386
|
const diagnosticReason = completionDiagnostic ? readNonEmptyString2(completionDiagnostic.blockReason) || "present" : "";
|
|
@@ -38396,17 +38403,19 @@ ${rendered}`, "utf-8");
|
|
|
38396
38403
|
return `[System] ${args.nodeLabel} already has completion evidence${metadata}. The no-progress monitor reconciled the terminal handoff and marked the session complete; wait for the queued completion event/status refresh before doing any manual transcript check.`;
|
|
38397
38404
|
}
|
|
38398
38405
|
const reviewRecommended = args.metadataEvent.reviewRecommended === true;
|
|
38406
|
+
const weakCompletion = isWeakCompletionMetadata(args.metadataEvent);
|
|
38407
|
+
const verifyTextNote = " Completion evidence is weak \u2014 verify via mesh_read_chat or git status before declaring the task done; the worker may still be parked on an approval/modal.";
|
|
38399
38408
|
const completionSummary = readMeshCompletionSummary(args.metadataEvent);
|
|
38400
38409
|
if (completionSummary) {
|
|
38401
38410
|
const truncationSuffix = "\n\u2026[truncated \u2014 call mesh_read_chat once for the full transcript]";
|
|
38402
38411
|
const surfaced = completionSummary.length > MESH_COMPLETION_SURFACE_MAX_CHARS ? `${completionSummary.slice(0, MESH_COMPLETION_SURFACE_MAX_CHARS - truncationSuffix.length)}${truncationSuffix}` : completionSummary;
|
|
38403
|
-
const verifyNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done." : "";
|
|
38412
|
+
const verifyNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done." : weakCompletion ? verifyTextNote : "";
|
|
38404
38413
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. Its final summary is included below \u2014 read it directly and only call mesh_read_chat if you need the full transcript.${verifyNote}
|
|
38405
38414
|
|
|
38406
38415
|
--- ${args.nodeLabel} final summary ---
|
|
38407
38416
|
${surfaced}`;
|
|
38408
38417
|
}
|
|
38409
|
-
const reviewNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done. Use mesh_read_chat once if needed, but do not poll repeatedly." : " Use mesh_read_chat once to review its final progress, but do not poll repeatedly.";
|
|
38418
|
+
const reviewNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done. Use mesh_read_chat once if needed, but do not poll repeatedly." : weakCompletion ? `${verifyTextNote} Use mesh_read_chat once if needed, but do not poll repeatedly.` : " Use mesh_read_chat once to review its final progress, but do not poll repeatedly.";
|
|
38410
38419
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path;${reviewNote}`;
|
|
38411
38420
|
}
|
|
38412
38421
|
if (args.event === "agent:waiting_approval") {
|
|
@@ -38540,7 +38549,7 @@ Next step: ${nextStep}`;
|
|
|
38540
38549
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
38541
38550
|
);
|
|
38542
38551
|
}
|
|
38543
|
-
function
|
|
38552
|
+
function isWeakCompletionMetadata2(metadata) {
|
|
38544
38553
|
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
38545
38554
|
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
38546
38555
|
if (metadata.reviewRecommended === true) return true;
|
|
@@ -38559,7 +38568,7 @@ Next step: ${nextStep}`;
|
|
|
38559
38568
|
event.meshId,
|
|
38560
38569
|
event.event,
|
|
38561
38570
|
terminalTaskId,
|
|
38562
|
-
|
|
38571
|
+
isWeakCompletionMetadata2(metadata) ? "weak" : "genuine"
|
|
38563
38572
|
].join("::");
|
|
38564
38573
|
}
|
|
38565
38574
|
}
|
|
@@ -42652,9 +42661,22 @@ ${cleanBody}`;
|
|
|
42652
42661
|
}
|
|
42653
42662
|
});
|
|
42654
42663
|
}
|
|
42664
|
+
function normalizeMeshWorkspaceForCompare(dir) {
|
|
42665
|
+
if (typeof dir !== "string") return "";
|
|
42666
|
+
return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
42667
|
+
}
|
|
42655
42668
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
42656
42669
|
const mesh = getMeshWithCache(components, meshId);
|
|
42657
42670
|
const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
|
|
42671
|
+
const localClaimAdapter = components.cliManager?.adapters?.get(sessionId);
|
|
42672
|
+
if (localClaimAdapter) {
|
|
42673
|
+
const sessionWorkspace = normalizeMeshWorkspaceForCompare(localClaimAdapter.workingDir);
|
|
42674
|
+
const nodeWorkspace = normalizeMeshWorkspaceForCompare(readNonEmptyString2(node?.workspace));
|
|
42675
|
+
if (sessionWorkspace && nodeWorkspace && sessionWorkspace !== nodeWorkspace) {
|
|
42676
|
+
LOG2.info("MeshQueue", `WTCLAIM: refusing claim for node ${nodeId} (${sessionId}) \u2014 session workspace "${sessionWorkspace}" \u2260 node workspace "${nodeWorkspace}" (cross-workspace dispatch blocked)`);
|
|
42677
|
+
return false;
|
|
42678
|
+
}
|
|
42679
|
+
}
|
|
42658
42680
|
const capabilityTags = buildMeshNodeCapabilityTags(node, providerType);
|
|
42659
42681
|
const providerMaxParallel = resolveProviderMaxParallel(node?.policy, providerType);
|
|
42660
42682
|
const task = claimNextTask(meshId, nodeId, sessionId, capabilityTags, {
|
|
@@ -47174,6 +47196,12 @@ ${cont}` : cont;
|
|
|
47174
47196
|
* seq) is always a real, distinct approval and must be written.
|
|
47175
47197
|
*/
|
|
47176
47198
|
approvalEntrySeq = 0;
|
|
47199
|
+
// Records which approval entry the last resolveModal() handled. Set unconditionally on
|
|
47200
|
+
// every resolveModal (auto-approve fire, dashboard/mesh_approve, dev-cli-debug), so
|
|
47201
|
+
// `lastResolvedEntrySeq >= approvalEntrySeq` is positive, ADHDev-side proof that the
|
|
47202
|
+
// current/latest approval entry was actually resolved. Exposed via getStatus so the
|
|
47203
|
+
// completion finalization gate (FALSEIDLE-a) can require resolution evidence before
|
|
47204
|
+
// confirming a waiting_approval→idle transition. Public (read-only by convention).
|
|
47177
47205
|
lastResolvedEntrySeq = -1;
|
|
47178
47206
|
/**
|
|
47179
47207
|
* When the engine previously held a modal but the latest parse failed
|
|
@@ -48890,6 +48918,7 @@ ${lastSnapshot}`;
|
|
|
48890
48918
|
workingDir: this.workingDir,
|
|
48891
48919
|
activeModal: effectiveModal,
|
|
48892
48920
|
approvalEntrySeq: this.engine.approvalEntrySeq,
|
|
48921
|
+
lastResolvedEntrySeq: this.engine.lastResolvedEntrySeq,
|
|
48893
48922
|
pendingOutboundCount: this.pendingOutboundQueue.length,
|
|
48894
48923
|
pendingOutboundMessages: this.pendingOutboundQueue.map((message) => ({
|
|
48895
48924
|
id: message.id,
|
|
@@ -64700,6 +64729,11 @@ ${body}
|
|
|
64700
64729
|
lastWin32WriteAt = 0;
|
|
64701
64730
|
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
64702
64731
|
win32WriteTimer = null;
|
|
64732
|
+
/** Timer driving the win32 verification-based modal-confirm CR resend loop (see
|
|
64733
|
+
* scheduleWin32ModalConfirm). A lone CR that confirms an approval/picker choice
|
|
64734
|
+
* is absorbed by ConPTY the same way a send_message submit CR is, so the confirm
|
|
64735
|
+
* must be resent until the modal actually resolves (status leaves 'approval'). */
|
|
64736
|
+
win32ModalConfirmTimer = null;
|
|
64703
64737
|
currentEval = null;
|
|
64704
64738
|
stateHistory = [];
|
|
64705
64739
|
prevStateAt = 0;
|
|
@@ -64824,6 +64858,10 @@ ${body}
|
|
|
64824
64858
|
clearTimeout(this.win32WriteTimer);
|
|
64825
64859
|
this.win32WriteTimer = null;
|
|
64826
64860
|
}
|
|
64861
|
+
if (this.win32ModalConfirmTimer) {
|
|
64862
|
+
clearTimeout(this.win32ModalConfirmTimer);
|
|
64863
|
+
this.win32ModalConfirmTimer = null;
|
|
64864
|
+
}
|
|
64827
64865
|
this.specWatcher?.close();
|
|
64828
64866
|
this.adapter.kill();
|
|
64829
64867
|
}
|
|
@@ -65419,10 +65457,61 @@ ${body}
|
|
|
65419
65457
|
const nav = step.repeat(Math.abs(delta));
|
|
65420
65458
|
const confirm = (rule.key_for_index || "\r").replace(/\{index\}/g, "") || "\r";
|
|
65421
65459
|
if (nav) this.adapter.send_keys(nav);
|
|
65422
|
-
this.
|
|
65460
|
+
this.submitModalConfirm(confirm);
|
|
65423
65461
|
return;
|
|
65424
65462
|
}
|
|
65425
|
-
this.
|
|
65463
|
+
this.submitModalConfirm(btn.key);
|
|
65464
|
+
}
|
|
65465
|
+
/**
|
|
65466
|
+
* Submit a modal-confirm key sequence (the choice key + its trailing CR).
|
|
65467
|
+
*
|
|
65468
|
+
* On win32 the trailing CR is the SAME lone-CR-swallow case as a send_message
|
|
65469
|
+
* submit: ConPTY can absorb a single CR as a literal newline instead of a
|
|
65470
|
+
* confirm, so the approval/picker modal never resolves and the FSM flaps
|
|
65471
|
+
* approval↔busy while auto-approve keeps firing into the void (APPROVESTUCK).
|
|
65472
|
+
* So we split any non-CR prefix (e.g. the "1" of "1\r") off, write it once, and
|
|
65473
|
+
* resend the CR on a fixed cadence until the modal actually resolves (status
|
|
65474
|
+
* leaves 'approval'). Non-win32 keeps the single direct write — its CR submits
|
|
65475
|
+
* on the first try.
|
|
65476
|
+
*/
|
|
65477
|
+
submitModalConfirm(keys) {
|
|
65478
|
+
if (process.platform !== "win32") {
|
|
65479
|
+
this.adapter.send_keys(keys);
|
|
65480
|
+
return;
|
|
65481
|
+
}
|
|
65482
|
+
const m = /^([\s\S]*?)([\r\n]+)$/.exec(keys);
|
|
65483
|
+
const prefix = m ? m[1] : keys;
|
|
65484
|
+
const cr = m ? m[2] : "";
|
|
65485
|
+
if (prefix) this.adapter.send_keys(prefix);
|
|
65486
|
+
if (!cr) return;
|
|
65487
|
+
this.scheduleWin32ModalConfirm(cr);
|
|
65488
|
+
}
|
|
65489
|
+
/**
|
|
65490
|
+
* win32 modal-confirm CR resend loop. Mirrors scheduleWin32Submit's phase-2
|
|
65491
|
+
* verified resend, but gated on still being IN a modal (status 'approval')
|
|
65492
|
+
* rather than still idle: the first CR fires immediately, then resends every
|
|
65493
|
+
* WIN32_SUBMIT_RESEND_GAP_MS while the FSM is still showing the modal, up to
|
|
65494
|
+
* WIN32_SUBMIT_MAX_RESENDS. The instant the modal resolves (status flips to
|
|
65495
|
+
* generating/idle) we stop, so no stray CR leaks into the next turn's composer.
|
|
65496
|
+
*/
|
|
65497
|
+
scheduleWin32ModalConfirm(submitKey) {
|
|
65498
|
+
if (this.win32ModalConfirmTimer) {
|
|
65499
|
+
clearTimeout(this.win32ModalConfirmTimer);
|
|
65500
|
+
this.win32ModalConfirmTimer = null;
|
|
65501
|
+
}
|
|
65502
|
+
const fire = (attempt) => {
|
|
65503
|
+
this.win32ModalConfirmTimer = null;
|
|
65504
|
+
this.adapter.send_keys(submitKey);
|
|
65505
|
+
if (attempt + 1 >= WIN32_SUBMIT_MAX_RESENDS) return;
|
|
65506
|
+
this.win32ModalConfirmTimer = setTimeout(() => {
|
|
65507
|
+
if (this.currentStatus() !== "approval") {
|
|
65508
|
+
this.win32ModalConfirmTimer = null;
|
|
65509
|
+
return;
|
|
65510
|
+
}
|
|
65511
|
+
fire(attempt + 1);
|
|
65512
|
+
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
65513
|
+
};
|
|
65514
|
+
fire(0);
|
|
65426
65515
|
}
|
|
65427
65516
|
handleAttachImage(blob, mime) {
|
|
65428
65517
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.action.type === "attach_image");
|
|
@@ -68272,6 +68361,8 @@ ${body}
|
|
|
68272
68361
|
};
|
|
68273
68362
|
}
|
|
68274
68363
|
}
|
|
68364
|
+
const approvalResolutionBlock = this.approvalResolutionFinalizationBlock(pending);
|
|
68365
|
+
if (approvalResolutionBlock) return approvalResolutionBlock;
|
|
68275
68366
|
try {
|
|
68276
68367
|
const screenText = typeof this.adapter.getScreenText === "function" ? String(this.adapter.getScreenText() || "") : "";
|
|
68277
68368
|
if (screenText) {
|
|
@@ -68284,6 +68375,44 @@ ${body}
|
|
|
68284
68375
|
}
|
|
68285
68376
|
return null;
|
|
68286
68377
|
}
|
|
68378
|
+
// (FALSEIDLE-a) Positive, structural proof that the latest approval entry was resolved
|
|
68379
|
+
// through ADHDev. resolveModal() — driven by auto-approve, dashboard/mesh_approve, and
|
|
68380
|
+
// dev-cli-debug alike — advances the engine's lastResolvedEntrySeq to the current
|
|
68381
|
+
// approvalEntrySeq. So `lastResolvedEntrySeq >= approvalEntrySeq` (with a real entry,
|
|
68382
|
+
// approvalEntrySeq > 0) means the modal we last saw was actually answered. Absence of this
|
|
68383
|
+
// evidence after a waiting_approval→idle transition means the idle is suspect: the spec's
|
|
68384
|
+
// text-based approval→idle rule false-tripped while the modal is still unresolved.
|
|
68385
|
+
// Fails OPEN (returns true) when the seq fields are unavailable, so the gate can never wedge
|
|
68386
|
+
// a session on a provider/adapter that does not surface the counters.
|
|
68387
|
+
hasApprovalResolutionEvidence() {
|
|
68388
|
+
try {
|
|
68389
|
+
const status = this.adapter.getStatus({ allowParse: false });
|
|
68390
|
+
const entrySeq = typeof status?.approvalEntrySeq === "number" ? status.approvalEntrySeq : 0;
|
|
68391
|
+
if (entrySeq <= 0) return true;
|
|
68392
|
+
const resolvedSeq = typeof status?.lastResolvedEntrySeq === "number" ? status.lastResolvedEntrySeq : void 0;
|
|
68393
|
+
if (resolvedSeq === void 0) return true;
|
|
68394
|
+
return resolvedSeq >= entrySeq;
|
|
68395
|
+
} catch {
|
|
68396
|
+
return true;
|
|
68397
|
+
}
|
|
68398
|
+
}
|
|
68399
|
+
// (FALSEIDLE-a) Hold a completion that is the anomalous DIRECT waiting_approval→idle
|
|
68400
|
+
// transition with no positive resolution evidence. A genuinely resolved approval routes
|
|
68401
|
+
// through resolveModal → setStatus('generating'), so its completion's previousStatus is
|
|
68402
|
+
// 'generating' (not 'waiting_approval') and this gate never fires for it. Scoped to
|
|
68403
|
+
// delegated mesh/coordinator sessions — whose only modal-resolution path is auto-approve /
|
|
68404
|
+
// mesh_approve (both advance lastResolvedEntrySeq) — so an interactive local session, where
|
|
68405
|
+
// a human may answer the PTY prompt directly and leave no resolveModal record, is untouched.
|
|
68406
|
+
// Non-terminal: the hold is bounded by COMPLETED_FINALIZATION_MAX_WAIT_MS (30s), giving a
|
|
68407
|
+
// settling auto-approve time to fire and advance the seq, and guaranteeing no permanent wedge
|
|
68408
|
+
// if resolution ever happens via a path that does not record evidence.
|
|
68409
|
+
approvalResolutionFinalizationBlock(pending) {
|
|
68410
|
+
if (pending.previousStatus !== "waiting_approval") return null;
|
|
68411
|
+
const meshContext = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
|
|
68412
|
+
if (!meshContext) return null;
|
|
68413
|
+
if (this.hasApprovalResolutionEvidence()) return null;
|
|
68414
|
+
return { reason: "approval_resolution_unconfirmed", terminal: false };
|
|
68415
|
+
}
|
|
68287
68416
|
scheduleCompletedDebounceFlush(delayMs) {
|
|
68288
68417
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
68289
68418
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|