@adhdev/daemon-core 0.9.82-rc.362 → 0.9.82-rc.363
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-adapters/cli-state-engine.d.ts +1 -1
- package/dist/cli-adapters/provider-cli-shared.d.ts +10 -0
- package/dist/index.js +77 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +77 -8
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events-utils.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -0
- package/package.json +2 -2
- package/src/cli-adapters/cli-state-engine.ts +7 -1
- package/src/cli-adapters/provider-cli-adapter.ts +1 -0
- package/src/cli-adapters/provider-cli-shared.ts +10 -0
- package/src/mesh/mesh-events-coordinator.ts +37 -0
- package/src/mesh/mesh-events-utils.ts +28 -2
- package/src/providers/cli-provider-instance.ts +46 -0
package/dist/index.mjs
CHANGED
|
@@ -311,10 +311,10 @@ function readInjected(value) {
|
|
|
311
311
|
}
|
|
312
312
|
function getDaemonBuildInfo() {
|
|
313
313
|
if (cached) return cached;
|
|
314
|
-
const commit = readInjected(true ? "
|
|
315
|
-
const commitShort = readInjected(true ? "
|
|
316
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
317
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
314
|
+
const commit = readInjected(true ? "4c5b30b1b0527ec5234c037893ba4fc24b88a8a0" : void 0) ?? "unknown";
|
|
315
|
+
const commitShort = readInjected(true ? "4c5b30b1" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
316
|
+
const version = readInjected(true ? "0.9.82-rc.363" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
317
|
+
const builtAt = readInjected(true ? "2026-06-23T16:13:33.075Z" : void 0);
|
|
318
318
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
319
319
|
return cached;
|
|
320
320
|
}
|
|
@@ -8588,6 +8588,13 @@ function readEventTimestampValue(value) {
|
|
|
8588
8588
|
}
|
|
8589
8589
|
return 0;
|
|
8590
8590
|
}
|
|
8591
|
+
function isWeakCompletionMetadata(metadataEvent) {
|
|
8592
|
+
const evidenceLevel = readNonEmptyString2(metadataEvent.evidenceLevel);
|
|
8593
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
8594
|
+
if (metadataEvent.reviewRecommended === true) return true;
|
|
8595
|
+
const diag = readRecord4(metadataEvent.completionDiagnostic);
|
|
8596
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
8597
|
+
}
|
|
8591
8598
|
function formatCompletionMetadata(event) {
|
|
8592
8599
|
const completionDiagnostic = event.completionDiagnostic && typeof event.completionDiagnostic === "object" ? event.completionDiagnostic : null;
|
|
8593
8600
|
const diagnosticReason = completionDiagnostic ? readNonEmptyString2(completionDiagnostic.blockReason) || "present" : "";
|
|
@@ -8610,17 +8617,19 @@ function buildMeshSystemMessage(args) {
|
|
|
8610
8617
|
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.`;
|
|
8611
8618
|
}
|
|
8612
8619
|
const reviewRecommended = args.metadataEvent.reviewRecommended === true;
|
|
8620
|
+
const weakCompletion = isWeakCompletionMetadata(args.metadataEvent);
|
|
8621
|
+
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.";
|
|
8613
8622
|
const completionSummary = readMeshCompletionSummary(args.metadataEvent);
|
|
8614
8623
|
if (completionSummary) {
|
|
8615
8624
|
const truncationSuffix = "\n\u2026[truncated \u2014 call mesh_read_chat once for the full transcript]";
|
|
8616
8625
|
const surfaced = completionSummary.length > MESH_COMPLETION_SURFACE_MAX_CHARS ? `${completionSummary.slice(0, MESH_COMPLETION_SURFACE_MAX_CHARS - truncationSuffix.length)}${truncationSuffix}` : completionSummary;
|
|
8617
|
-
const verifyNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done." : "";
|
|
8626
|
+
const verifyNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done." : weakCompletion ? verifyTextNote : "";
|
|
8618
8627
|
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}
|
|
8619
8628
|
|
|
8620
8629
|
--- ${args.nodeLabel} final summary ---
|
|
8621
8630
|
${surfaced}`;
|
|
8622
8631
|
}
|
|
8623
|
-
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.";
|
|
8632
|
+
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.";
|
|
8624
8633
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path;${reviewNote}`;
|
|
8625
8634
|
}
|
|
8626
8635
|
if (args.event === "agent:waiting_approval") {
|
|
@@ -8758,7 +8767,7 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
8758
8767
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
8759
8768
|
);
|
|
8760
8769
|
}
|
|
8761
|
-
function
|
|
8770
|
+
function isWeakCompletionMetadata2(metadata) {
|
|
8762
8771
|
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
8763
8772
|
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
8764
8773
|
if (metadata.reviewRecommended === true) return true;
|
|
@@ -8777,7 +8786,7 @@ function buildPendingEventFingerprint(event) {
|
|
|
8777
8786
|
event.meshId,
|
|
8778
8787
|
event.event,
|
|
8779
8788
|
terminalTaskId,
|
|
8780
|
-
|
|
8789
|
+
isWeakCompletionMetadata2(metadata) ? "weak" : "genuine"
|
|
8781
8790
|
].join("::");
|
|
8782
8791
|
}
|
|
8783
8792
|
}
|
|
@@ -12860,9 +12869,22 @@ function deliverTaskToSession(dispatchThunk, ctx) {
|
|
|
12860
12869
|
}
|
|
12861
12870
|
});
|
|
12862
12871
|
}
|
|
12872
|
+
function normalizeMeshWorkspaceForCompare(dir) {
|
|
12873
|
+
if (typeof dir !== "string") return "";
|
|
12874
|
+
return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
12875
|
+
}
|
|
12863
12876
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
12864
12877
|
const mesh = getMeshWithCache(components, meshId);
|
|
12865
12878
|
const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
|
|
12879
|
+
const localClaimAdapter = components.cliManager?.adapters?.get(sessionId);
|
|
12880
|
+
if (localClaimAdapter) {
|
|
12881
|
+
const sessionWorkspace = normalizeMeshWorkspaceForCompare(localClaimAdapter.workingDir);
|
|
12882
|
+
const nodeWorkspace = normalizeMeshWorkspaceForCompare(readNonEmptyString2(node?.workspace));
|
|
12883
|
+
if (sessionWorkspace && nodeWorkspace && sessionWorkspace !== nodeWorkspace) {
|
|
12884
|
+
LOG.info("MeshQueue", `WTCLAIM: refusing claim for node ${nodeId} (${sessionId}) \u2014 session workspace "${sessionWorkspace}" \u2260 node workspace "${nodeWorkspace}" (cross-workspace dispatch blocked)`);
|
|
12885
|
+
return false;
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12866
12888
|
const capabilityTags = buildMeshNodeCapabilityTags(node, providerType);
|
|
12867
12889
|
const providerMaxParallel = resolveProviderMaxParallel(node?.policy, providerType);
|
|
12868
12890
|
const task = claimNextTask(meshId, nodeId, sessionId, capabilityTags, {
|
|
@@ -17373,6 +17395,12 @@ var init_cli_state_engine = __esm({
|
|
|
17373
17395
|
* seq) is always a real, distinct approval and must be written.
|
|
17374
17396
|
*/
|
|
17375
17397
|
approvalEntrySeq = 0;
|
|
17398
|
+
// Records which approval entry the last resolveModal() handled. Set unconditionally on
|
|
17399
|
+
// every resolveModal (auto-approve fire, dashboard/mesh_approve, dev-cli-debug), so
|
|
17400
|
+
// `lastResolvedEntrySeq >= approvalEntrySeq` is positive, ADHDev-side proof that the
|
|
17401
|
+
// current/latest approval entry was actually resolved. Exposed via getStatus so the
|
|
17402
|
+
// completion finalization gate (FALSEIDLE-a) can require resolution evidence before
|
|
17403
|
+
// confirming a waiting_approval→idle transition. Public (read-only by convention).
|
|
17376
17404
|
lastResolvedEntrySeq = -1;
|
|
17377
17405
|
/**
|
|
17378
17406
|
* When the engine previously held a modal but the latest parse failed
|
|
@@ -19089,6 +19117,7 @@ ${lastSnapshot}`;
|
|
|
19089
19117
|
workingDir: this.workingDir,
|
|
19090
19118
|
activeModal: effectiveModal,
|
|
19091
19119
|
approvalEntrySeq: this.engine.approvalEntrySeq,
|
|
19120
|
+
lastResolvedEntrySeq: this.engine.lastResolvedEntrySeq,
|
|
19092
19121
|
pendingOutboundCount: this.pendingOutboundQueue.length,
|
|
19093
19122
|
pendingOutboundMessages: this.pendingOutboundQueue.map((message) => ({
|
|
19094
19123
|
id: message.id,
|
|
@@ -38284,6 +38313,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38284
38313
|
};
|
|
38285
38314
|
}
|
|
38286
38315
|
}
|
|
38316
|
+
const approvalResolutionBlock = this.approvalResolutionFinalizationBlock(pending);
|
|
38317
|
+
if (approvalResolutionBlock) return approvalResolutionBlock;
|
|
38287
38318
|
try {
|
|
38288
38319
|
const screenText = typeof this.adapter.getScreenText === "function" ? String(this.adapter.getScreenText() || "") : "";
|
|
38289
38320
|
if (screenText) {
|
|
@@ -38296,6 +38327,44 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38296
38327
|
}
|
|
38297
38328
|
return null;
|
|
38298
38329
|
}
|
|
38330
|
+
// (FALSEIDLE-a) Positive, structural proof that the latest approval entry was resolved
|
|
38331
|
+
// through ADHDev. resolveModal() — driven by auto-approve, dashboard/mesh_approve, and
|
|
38332
|
+
// dev-cli-debug alike — advances the engine's lastResolvedEntrySeq to the current
|
|
38333
|
+
// approvalEntrySeq. So `lastResolvedEntrySeq >= approvalEntrySeq` (with a real entry,
|
|
38334
|
+
// approvalEntrySeq > 0) means the modal we last saw was actually answered. Absence of this
|
|
38335
|
+
// evidence after a waiting_approval→idle transition means the idle is suspect: the spec's
|
|
38336
|
+
// text-based approval→idle rule false-tripped while the modal is still unresolved.
|
|
38337
|
+
// Fails OPEN (returns true) when the seq fields are unavailable, so the gate can never wedge
|
|
38338
|
+
// a session on a provider/adapter that does not surface the counters.
|
|
38339
|
+
hasApprovalResolutionEvidence() {
|
|
38340
|
+
try {
|
|
38341
|
+
const status = this.adapter.getStatus({ allowParse: false });
|
|
38342
|
+
const entrySeq = typeof status?.approvalEntrySeq === "number" ? status.approvalEntrySeq : 0;
|
|
38343
|
+
if (entrySeq <= 0) return true;
|
|
38344
|
+
const resolvedSeq = typeof status?.lastResolvedEntrySeq === "number" ? status.lastResolvedEntrySeq : void 0;
|
|
38345
|
+
if (resolvedSeq === void 0) return true;
|
|
38346
|
+
return resolvedSeq >= entrySeq;
|
|
38347
|
+
} catch {
|
|
38348
|
+
return true;
|
|
38349
|
+
}
|
|
38350
|
+
}
|
|
38351
|
+
// (FALSEIDLE-a) Hold a completion that is the anomalous DIRECT waiting_approval→idle
|
|
38352
|
+
// transition with no positive resolution evidence. A genuinely resolved approval routes
|
|
38353
|
+
// through resolveModal → setStatus('generating'), so its completion's previousStatus is
|
|
38354
|
+
// 'generating' (not 'waiting_approval') and this gate never fires for it. Scoped to
|
|
38355
|
+
// delegated mesh/coordinator sessions — whose only modal-resolution path is auto-approve /
|
|
38356
|
+
// mesh_approve (both advance lastResolvedEntrySeq) — so an interactive local session, where
|
|
38357
|
+
// a human may answer the PTY prompt directly and leave no resolveModal record, is untouched.
|
|
38358
|
+
// Non-terminal: the hold is bounded by COMPLETED_FINALIZATION_MAX_WAIT_MS (30s), giving a
|
|
38359
|
+
// settling auto-approve time to fire and advance the seq, and guaranteeing no permanent wedge
|
|
38360
|
+
// if resolution ever happens via a path that does not record evidence.
|
|
38361
|
+
approvalResolutionFinalizationBlock(pending) {
|
|
38362
|
+
if (pending.previousStatus !== "waiting_approval") return null;
|
|
38363
|
+
const meshContext = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
|
|
38364
|
+
if (!meshContext) return null;
|
|
38365
|
+
if (this.hasApprovalResolutionEvidence()) return null;
|
|
38366
|
+
return { reason: "approval_resolution_unconfirmed", terminal: false };
|
|
38367
|
+
}
|
|
38299
38368
|
scheduleCompletedDebounceFlush(delayMs) {
|
|
38300
38369
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
38301
38370
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|