@adhdev/daemon-core 1.0.28-rc.16 → 1.0.28-rc.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -143,7 +143,7 @@ export type { ProviderModule, AutoApproveMode, AutoApproveModesConfig, AutoAppro
143
143
  export type { ProviderSourceConfigSnapshot, ProviderSourceConfigUpdate } from './config/provider-source-config.js';
144
144
  export { parseProviderSourceConfigUpdate } from './config/provider-source-config.js';
145
145
  export { normalizeInputEnvelope, normalizeMessageParts, flattenMessageParts } from './providers/io-contracts.js';
146
- export { BUILTIN_CHAT_MESSAGE_KINDS, isBuiltinChatMessageKind, normalizeChatMessageKind, resolveChatMessageKind, buildChatMessage, buildSystemChatMessage, buildRuntimeSystemChatMessage, buildAssistantChatMessage, buildThoughtChatMessage, buildToolChatMessage, buildTerminalChatMessage, buildUserChatMessage, normalizeChatMessage, normalizeChatMessages, CHAT_MESSAGE_VISIBILITIES, CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES, CHAT_MESSAGE_AUDIENCES, CHAT_MESSAGE_SOURCES, CHAT_MESSAGE_ACTIVITY_SOURCES, CHAT_MESSAGE_INTERNAL_SOURCES, classifyChatMessageVisibility, isUserFacingChatMessage, isActivityChatMessage, isInternalChatMessage, filterUserFacingChatMessages, filterActivityChatMessages, filterInternalChatMessages, filterChatMessagesByVisibility, } from './providers/chat-message-normalization.js';
146
+ export { BUILTIN_CHAT_MESSAGE_KINDS, isBuiltinChatMessageKind, normalizeChatMessageKind, resolveChatMessageKind, buildChatMessage, buildSystemChatMessage, buildRuntimeSystemChatMessage, buildAssistantChatMessage, buildThoughtChatMessage, buildToolChatMessage, buildTerminalChatMessage, buildUserChatMessage, normalizeChatMessage, normalizeChatMessages, CHAT_MESSAGE_VISIBILITIES, CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES, CHAT_MESSAGE_AUDIENCES, CHAT_MESSAGE_SOURCES, CHAT_MESSAGE_ACTIVITY_SOURCES, CHAT_MESSAGE_INTERNAL_SOURCES, classifyChatMessageVisibility, hasTrailingToolActivityAfterFinalAssistant, isUserFacingChatMessage, isActivityChatMessage, isInternalChatMessage, filterUserFacingChatMessages, filterActivityChatMessages, filterInternalChatMessages, filterChatMessagesByVisibility, } from './providers/chat-message-normalization.js';
147
147
  export type { BuiltinChatMessageKind, ChatMessageKind, ChatMessageVisibility, ChatMessageTranscriptVisibility, ChatMessageAudience, ChatMessageSource, ChatMessageTranscriptSurface, ChatMessageVisibilityClassification } from './providers/chat-message-normalization.js';
148
148
  export { VersionArchive, detectAllVersions } from './providers/version-archive.js';
149
149
  export type { ProviderVersionInfo, VersionHistory } from './providers/version-archive.js';
package/dist/index.js CHANGED
@@ -791,10 +791,10 @@ function readInjected(value) {
791
791
  }
792
792
  function getDaemonBuildInfo() {
793
793
  if (cached) return cached;
794
- const commit = readInjected(true ? "3a48f660f00c3bf2e42ba36df7789edbc654b99c" : void 0) ?? "unknown";
795
- const commitShort = readInjected(true ? "3a48f660" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
796
- const version = readInjected(true ? "1.0.28-rc.16" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
797
- const builtAt = readInjected(true ? "2026-07-26T16:40:47.778Z" : void 0);
794
+ const commit = readInjected(true ? "2ab22815548d9465b9f6a28a058049ba230dfb61" : void 0) ?? "unknown";
795
+ const commitShort = readInjected(true ? "2ab22815" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
796
+ const version = readInjected(true ? "1.0.28-rc.18" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
797
+ const builtAt = readInjected(true ? "2026-07-27T05:51:47.959Z" : void 0);
798
798
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
799
799
  return cached;
800
800
  }
@@ -16437,6 +16437,31 @@ var init_debug_trace = __esm({
16437
16437
  function recordSynthCompletionGateTrace(stage, payload) {
16438
16438
  recordDebugTrace({ category: "completion-gate", stage, level: "debug", payload });
16439
16439
  }
16440
+ function evaluateTranscriptSynthAdmission(admission) {
16441
+ if (!admission) return { admitted: true };
16442
+ if (admission.trailingToolActivityAfterFinalAssistant === true) {
16443
+ return { admitted: false, reason: "trailing_tool_activity_after_final_assistant" };
16444
+ }
16445
+ if (!admission.boundedBackstop && typeof admission.liveTurnPendingEvidence === "function") {
16446
+ let pending = false;
16447
+ try {
16448
+ pending = admission.liveTurnPendingEvidence() === true;
16449
+ } catch {
16450
+ }
16451
+ if (pending) return { admitted: false, reason: "live_turn_pending_evidence" };
16452
+ }
16453
+ return { admitted: true };
16454
+ }
16455
+ function resolveLiveTurnPendingEvidence(components, sessionId) {
16456
+ try {
16457
+ const instance = components?.instanceManager?.getInstance?.(sessionId);
16458
+ if (typeof instance?.hasLiveTurnPendingEvidence !== "function") return void 0;
16459
+ const probe = instance.hasLiveTurnPendingEvidence.bind(instance);
16460
+ return () => probe();
16461
+ } catch {
16462
+ return void 0;
16463
+ }
16464
+ }
16440
16465
  function findRecentTerminalLedgerEvidence(args) {
16441
16466
  if (!args.sessionId && !args.nodeId) return null;
16442
16467
  const entries = readLedgerEntries(args.meshId, { tail: 200 });
@@ -16557,6 +16582,17 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
16557
16582
  })) {
16558
16583
  return { reconciled: false, alreadyTerminal: true, reason: "terminal_ledger_entry_exists" };
16559
16584
  }
16585
+ const admission = evaluateTranscriptSynthAdmission(args.causalAdmission);
16586
+ if (!admission.admitted) {
16587
+ LOG.info("MeshEvents", `Transcript synth vetoed for task ${args.taskId} session ${args.sessionId} (source ${args.source || "direct_task_transcript_reconciliation"}): ${admission.reason} \u2014 holding the completion; it re-evaluates on the next reconcile pass`);
16588
+ recordSynthCompletionGateTrace("synth-veto", {
16589
+ producer: "transcript_reconcile",
16590
+ source: args.source || "direct_task_transcript_reconciliation",
16591
+ taskId: args.taskId,
16592
+ reason: admission.reason
16593
+ });
16594
+ return { reconciled: false, reason: admission.reason };
16595
+ }
16560
16596
  const nodeId = readNonEmptyString(args.nodeId) || dispatch?.nodeId;
16561
16597
  const providerType = readNonEmptyString(args.providerType) || dispatch?.providerType || readNonEmptyString(dispatch?.payload.providerType);
16562
16598
  const completedAt = args.completedAt || (/* @__PURE__ */ new Date()).toISOString();
@@ -16718,6 +16754,7 @@ var init_mesh_events_stale = __esm({
16718
16754
  init_mesh_events_pending();
16719
16755
  init_mesh_events_utils();
16720
16756
  init_debug_trace();
16757
+ init_logger();
16721
16758
  init_dist();
16722
16759
  DIRECT_DISPATCH_RECONCILE_GRACE_MS = 6e4;
16723
16760
  DIRECT_DISPATCH_IDLE_SESSION_RECONCILE_GRACE_MS = 12e4;
@@ -23091,6 +23128,14 @@ function evaluateMeshEventSuppression(args, ctx) {
23091
23128
  };
23092
23129
  }
23093
23130
  }
23131
+ if (!readNonEmptyString(args.metadataEvent.taskId) && !sessionHasActiveAssignment(args.meshId, eventSessionId) && !findRecentTerminalLedgerEvidence({ meshId: args.meshId, sessionId: eventSessionId, nodeId: eventNodeId || void 0 }) && isWeakCompletionEvidence(args.metadataEvent)) {
23132
+ LOG.info("MeshEvents", `Suppressed agent:generating_completed for session ${eventSessionId} (mesh ${args.meshId}): no taskId, no active assignment, and no prior terminal ledger evidence \u2014 a pre-dispatch startup/greeting artifact, not a real task completion`);
23133
+ traceMeshEventDrop("no_dispatch_native_completion", traceCtx);
23134
+ return {
23135
+ kind: "suppress",
23136
+ result: { success: true, forwarded: 0, suppressed: true, noDispatchNativeCompletion: true }
23137
+ };
23138
+ }
23094
23139
  const inWindowTask = findInWindowUnclaimedAutoLaunchTask(args.meshId, eventSessionId, Date.now());
23095
23140
  if (inWindowTask) {
23096
23141
  const causalEvidence = MeshRuntimeStore.getInstance().taskDeliveryConsumed(args.meshId, inWindowTask.id) || hasMatchingTaskDispatchedLedgerEntry(args.meshId, inWindowTask.id, eventSessionId);
@@ -24841,6 +24886,18 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
24841
24886
  }
24842
24887
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
24843
24888
  const evidence = extractFinalAssistantSummaryEvidence(messages);
24889
+ if (hasTrailingToolActivityAfterFinalAssistant(messages)) {
24890
+ setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
24891
+ LOG.info("MeshReconcile", `Mid-turn causal admission: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) \u2014 the latest final-looking assistant bubble is followed by trailing tool/terminal activity (interim narration; the turn is still executing); holding the transcript synth`);
24892
+ traceMeshEventDrop("reconcile_synth_veto_trailing_tool_activity", {
24893
+ taskId,
24894
+ sessionId,
24895
+ nodeId,
24896
+ meshId: mesh.id,
24897
+ event: "agent:generating_completed"
24898
+ });
24899
+ continue;
24900
+ }
24844
24901
  if (isAcked) {
24845
24902
  const ackedAtMs = Date.parse(readNonEmptyString(dispatch.updatedAt));
24846
24903
  const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
@@ -24915,6 +24972,17 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
24915
24972
  // The ledger-recovered dispatching-coordinator daemon (inside the reconcile fn)
24916
24973
  // takes PRIORITY over this arg; this remains the best-available fallback.
24917
24974
  ...coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {},
24975
+ // MID-TURN-CAUSAL-ADMISSION (rc.16): pass the LOCAL live adapter's synchronous
24976
+ // turn-state probe into the unified choke point — a pending verdict vetoes this
24977
+ // eager synth (never-acked first-idle / acked fast-track). The death-deadline
24978
+ // backstop is the bounded max-wait net and overrides the veto (genuine-final
24979
+ // fail-open preserved); a remote/missing live source resolves to undefined and
24980
+ // fails open onto the bounded transcript evidence above. The trailing-tool veto
24981
+ // already ran at the top of this tick.
24982
+ causalAdmission: {
24983
+ liveTurnPendingEvidence: resolveLiveTurnPendingEvidence(components, sessionId),
24984
+ boundedBackstop: backstopKind === "ackedHoldDeathDeadlineFired"
24985
+ },
24918
24986
  source: "daemon_reconcile_transcript_completion"
24919
24987
  });
24920
24988
  if (result.reconciled) {
@@ -25360,10 +25428,10 @@ async function evaluateEarlyIdleTranscriptArm(components, mesh, store, row, loca
25360
25428
  if (profile) return profile.emitsPtyTurnEvents === false;
25361
25429
  return verdict === "UNKNOWN";
25362
25430
  }
25363
- function propagateWatchdogTranscriptCompletion(meshId, row, evidence, source) {
25431
+ function propagateWatchdogTranscriptCompletion(components, meshId, row, evidence, source, opts) {
25364
25432
  const sessionId = readNonEmptyString(row.assignedSessionId) || evidence.sessionId;
25365
25433
  if (!sessionId || !readNonEmptyString(evidence.finalSummary)) {
25366
- return false;
25434
+ return "unavailable";
25367
25435
  }
25368
25436
  try {
25369
25437
  const result = reconcileDirectDispatchCompletionFromTranscript({
@@ -25379,11 +25447,26 @@ function propagateWatchdogTranscriptCompletion(meshId, row, evidence, source) {
25379
25447
  // The watchdog poll already enforced idle + post-dispatch + no-trailing-tool + streak;
25380
25448
  // skip the reconcile's own grace/transcript_not_proven gates (dedup backstops remain).
25381
25449
  preValidatedTranscriptEvidence: true,
25450
+ // MID-TURN-CAUSAL-ADMISSION (rc.16): the transcript poll's structural evidence can
25451
+ // still straddle a genuinely mid-turn LOCAL worker (the incident shape: transcript
25452
+ // reads idle-with-final-assistant while the raw PTY is mid-tool). Route the live
25453
+ // adapter's synchronous probe through the unified choke point. The EARLY-IDLE
25454
+ // caller is an eager path (no opts) → a pending verdict defers; the redrive-deadline
25455
+ // caller passes boundedBackstop (the max-wait net) → the veto yields, preserving the
25456
+ // genuine-final fail-open semantics.
25457
+ causalAdmission: {
25458
+ liveTurnPendingEvidence: resolveLiveTurnPendingEvidence(components, sessionId),
25459
+ boundedBackstop: opts?.boundedBackstop === true
25460
+ },
25382
25461
  source
25383
25462
  });
25384
- return result.reconciled || result.alreadyTerminal === true;
25463
+ if (result.reconciled || result.alreadyTerminal === true) return "propagated";
25464
+ if (result.reason === "live_turn_pending_evidence" || result.reason === "trailing_tool_activity_after_final_assistant") {
25465
+ return "deferred";
25466
+ }
25467
+ return "unavailable";
25385
25468
  } catch {
25386
- return false;
25469
+ return "unavailable";
25387
25470
  }
25388
25471
  }
25389
25472
  async function recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds = []) {
@@ -25417,14 +25500,28 @@ async function recoverStrandedAssignedDispatches(components, mesh, store, localD
25417
25500
  minFinalAssistantAgeMs: ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS
25418
25501
  });
25419
25502
  if (terminalEvidence) {
25420
- assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
25421
- updateTaskStatus(meshId, row.id, terminalEvidence.outcome);
25422
- const propagated = propagateWatchdogTranscriptCompletion(
25503
+ const propagation = propagateWatchdogTranscriptCompletion(
25504
+ components,
25423
25505
  meshId,
25424
25506
  row,
25425
25507
  terminalEvidence,
25426
25508
  "early_idle_transcript_evidence"
25427
25509
  );
25510
+ if (propagation === "deferred") {
25511
+ assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
25512
+ LOG.info("MeshReconcile", `Deferred early transcript completion for task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}): the live adapter still reports the turn pending (mid-tool / streaming / modal) \u2014 holding; the completion re-evaluates next tick`);
25513
+ traceMeshEventDrop("early_idle_completion_deferred_live_pending", {
25514
+ taskId: row.id,
25515
+ sessionId: row.assignedSessionId,
25516
+ nodeId: row.assignedNodeId,
25517
+ meshId,
25518
+ event: "agent:generating_completed"
25519
+ });
25520
+ continue;
25521
+ }
25522
+ assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
25523
+ updateTaskStatus(meshId, row.id, terminalEvidence.outcome);
25524
+ const propagated = propagation === "propagated";
25428
25525
  if (!propagated && !findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
25429
25526
  try {
25430
25527
  appendLedgerEntry(meshId, {
@@ -25599,12 +25696,15 @@ async function recoverStrandedAssignedDispatches(components, mesh, store, localD
25599
25696
  if (terminalEvidence) {
25600
25697
  deliveredNoTurnUnknownStreak.delete(streakKey);
25601
25698
  updateTaskStatus(meshId, row.id, terminalEvidence.outcome);
25602
- const propagated = propagateWatchdogTranscriptCompletion(
25699
+ const propagation = propagateWatchdogTranscriptCompletion(
25700
+ components,
25603
25701
  meshId,
25604
25702
  row,
25605
25703
  terminalEvidence,
25606
- "redrive_deadline_transcript_evidence"
25704
+ "redrive_deadline_transcript_evidence",
25705
+ { boundedBackstop: true }
25607
25706
  );
25707
+ const propagated = propagation === "propagated";
25608
25708
  if (!propagated && !findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
25609
25709
  try {
25610
25710
  appendLedgerEntry(meshId, {
@@ -29448,7 +29548,10 @@ var init_cli_state_engine = __esm({
29448
29548
  const session = this.runParseSession(snap);
29449
29549
  if (!session) return;
29450
29550
  const { status, messages } = session;
29451
- const modal = session.activeModal ?? session.modal ?? null;
29551
+ const rawModal = session.activeModal ?? session.modal ?? null;
29552
+ const modal = rawModal && Array.isArray(rawModal.buttons) && rawModal.buttons.some(
29553
+ (button) => typeof button === "string" && button.trim().length > 0
29554
+ ) ? rawModal : null;
29452
29555
  const parsedStatus = session.parsedStatus ?? null;
29453
29556
  const parsedMessages = normalizeCliParsedMessages(messages, {
29454
29557
  scope: null,
@@ -33001,6 +33104,7 @@ __export(index_exports, {
33001
33104
  handleGitCommand: () => handleGitCommand,
33002
33105
  hasCdpManager: () => hasCdpManager,
33003
33106
  hasPendingDependents: () => hasPendingDependents,
33107
+ hasTrailingToolActivityAfterFinalAssistant: () => hasTrailingToolActivityAfterFinalAssistant,
33004
33108
  hashSignatureParts: () => hashSignatureParts,
33005
33109
  initDaemonComponents: () => initDaemonComponents,
33006
33110
  insertDirectDispatch: () => insertDirectDispatch,
@@ -40107,7 +40211,7 @@ async function handleReadChat(h, args) {
40107
40211
  });
40108
40212
  }
40109
40213
  }
40110
- if (isGeneratingLikeStatus(selectedStatus) && selectedTranscriptAuthority === "provider" && !hasNonEmptyModalButtons(activeModal) && hasFinalVisibleAssistantMessage(selectedMessages)) {
40214
+ if (isGeneratingLikeStatus(selectedStatus) && selectedTranscriptAuthority === "provider" && !hasNonEmptyModalButtons(activeModal) && hasFinalVisibleAssistantMessage(selectedMessages) && !hasTrailingToolActivityAfterFinalAssistant(selectedMessages) && !hasTrailingToolActivityAfterFinalAssistant(returnedMessages)) {
40111
40215
  selectedStatus = "idle";
40112
40216
  selectedMessages = finalizeStreamingMessagesWhenIdle(selectedMessages, selectedStatus);
40113
40217
  messageSource = {
@@ -51629,9 +51733,36 @@ var CliProviderInstance = class _CliProviderInstance {
51629
51733
  * OR isModalParked() (a live approval/choice modal) — so a session this method reports
51630
51734
  * pending is, by construction, one the local finalization gate would also refuse to
51631
51735
  * finalize right now.
51736
+ *
51737
+ * NATIVE-TRAILING-TOOL-GATE (rc.16 follow-up): the three adapter-state discriminators
51738
+ * above are blind to a background shell tool that keeps a turn alive without the adapter
51739
+ * reporting a pending response — e.g. a backgrounded `sleep 40 &` between narration
51740
+ * bubbles on a write-lag native-source provider (claude-cli), which is deliberately
51741
+ * un-floored (noExternalTranscriptSource omitted, mission f2f6da1b owner decision) so its
51742
+ * transcript write-lag emits promptly. That un-flooring is correct for the ordinary
51743
+ * fraction-of-a-second trail, but it also means the growth-hold / busy-lease protections
51744
+ * in getCompletedFinalizationBlock never engage for claude-cli, so an interim final-
51745
+ * LOOKING bubble followed by continuing tool calls can still finalize as a completion
51746
+ * while the transcript demonstrably shows the turn still executing. Close that gap here,
51747
+ * narrowly: for a native-source provider only, reuse the SAME bounded transcript read the
51748
+ * class's own completion judgment already performs (probeNativeTranscriptSignals) and
51749
+ * apply the SAME trailing-tool-activity veto the transcript-synth admission choke point
51750
+ * uses (hasTrailingToolActivityAfterFinalAssistant) — the latest final-looking assistant
51751
+ * bubble followed by tool/terminal activity is interim narration, not a turn end. Fail-open
51752
+ * by construction: a non-native-source class (probe returns null), an unresolved
51753
+ * transcript, or a read error never reaches the veto, so a missing/unavailable transcript
51754
+ * can never wedge a session as "pending" forever.
51632
51755
  */
51633
51756
  hasLiveTurnPendingEvidence() {
51634
- return this.hasAdapterPendingResponse() || this.isModalParked();
51757
+ if (this.hasAdapterPendingResponse() || this.isModalParked()) return true;
51758
+ try {
51759
+ const probe = this.probeNativeTranscriptSignals();
51760
+ if (probe?.snapshot?.available === true && Array.isArray(probe.messages)) {
51761
+ if (hasTrailingToolActivityAfterFinalAssistant(probe.messages)) return true;
51762
+ }
51763
+ } catch {
51764
+ }
51765
+ return false;
51635
51766
  }
51636
51767
  /**
51637
51768
  * PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
@@ -78841,6 +78972,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
78841
78972
  handleGitCommand,
78842
78973
  hasCdpManager,
78843
78974
  hasPendingDependents,
78975
+ hasTrailingToolActivityAfterFinalAssistant,
78844
78976
  hashSignatureParts,
78845
78977
  initDaemonComponents,
78846
78978
  insertDirectDispatch,