@adhdev/daemon-core 1.0.18-rc.12 → 1.0.18-rc.14

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 CHANGED
@@ -442,10 +442,10 @@ function readInjected(value) {
442
442
  }
443
443
  function getDaemonBuildInfo() {
444
444
  if (cached) return cached;
445
- const commit = readInjected(true ? "8cce29137e6b62781be7645411736bd8d1a9e7a8" : void 0) ?? "unknown";
446
- const commitShort = readInjected(true ? "8cce2913" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
447
- const version = readInjected(true ? "1.0.18-rc.12" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
448
- const builtAt = readInjected(true ? "2026-07-22T12:25:26.100Z" : void 0);
445
+ const commit = readInjected(true ? "a44f4a2814c4db171a9ebb0f6fcfb0798203aebb" : void 0) ?? "unknown";
446
+ const commitShort = readInjected(true ? "a44f4a28" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
447
+ const version = readInjected(true ? "1.0.18-rc.14" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
448
+ const builtAt = readInjected(true ? "2026-07-22T17:37:52.683Z" : void 0);
449
449
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
450
450
  return cached;
451
451
  }
@@ -22227,34 +22227,37 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
22227
22227
  if (!dispatchMeshCommand) return;
22228
22228
  const meshId = mesh.id;
22229
22229
  const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
22230
- await Promise.allSettled(mesh.nodes.map(async (node) => {
22231
- const nodeDaemonId = readNonEmptyString(node.daemonId);
22232
- if (!nodeDaemonId) return;
22233
- if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
22234
- if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
22235
- const getPeerStatus = components.getMeshPeerConnectionStatus;
22236
- if (getPeerStatus) {
22237
- const peerSnapshot = getPeerStatus(nodeDaemonId);
22238
- if (!peerSnapshot || String(peerSnapshot.state) !== "connected") return;
22239
- }
22240
- for (const pendingEventArgs of pulls) {
22241
- let events;
22230
+ await Promise.allSettled(mesh.nodes.map((node) => pullPendingEventsFromNode(components, meshId, node, localDaemonId, candidateDaemonIds, pulls)));
22231
+ }
22232
+ async function pullPendingEventsFromNode(components, meshId, node, localDaemonId, candidateDaemonIds, pulls) {
22233
+ const dispatchMeshCommand = components.dispatchMeshCommand;
22234
+ if (!dispatchMeshCommand) return;
22235
+ const nodeDaemonId = readNonEmptyString(node.daemonId);
22236
+ if (!nodeDaemonId) return;
22237
+ if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
22238
+ if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
22239
+ const getPeerStatus = components.getMeshPeerConnectionStatus;
22240
+ if (getPeerStatus) {
22241
+ const peerSnapshot = getPeerStatus(nodeDaemonId);
22242
+ if (!peerSnapshot || String(peerSnapshot.state) !== "connected") return;
22243
+ }
22244
+ for (const pendingEventArgs of pulls) {
22245
+ let events;
22246
+ try {
22247
+ events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
22248
+ } catch {
22249
+ break;
22250
+ }
22251
+ const list = extractPendingEvents(events).filter((e) => readNonEmptyString(e?.meshId) === meshId);
22252
+ for (const event of list) {
22253
+ const payload = buildForwardPayloadFromPending(event);
22254
+ if (!payload.event || !payload.meshId) continue;
22242
22255
  try {
22243
- events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
22256
+ handleMeshForwardEvent(components, payload);
22244
22257
  } catch {
22245
- break;
22246
- }
22247
- const list = extractPendingEvents(events).filter((e) => readNonEmptyString(e?.meshId) === meshId);
22248
- for (const event of list) {
22249
- const payload = buildForwardPayloadFromPending(event);
22250
- if (!payload.event || !payload.meshId) continue;
22251
- try {
22252
- handleMeshForwardEvent(components, payload);
22253
- } catch {
22254
- }
22255
22258
  }
22256
22259
  }
22257
- }));
22260
+ }
22258
22261
  }
22259
22262
  function unwrapReadChatPayload(raw) {
22260
22263
  let cursor = raw;
@@ -23156,7 +23159,7 @@ function assignedRowLiveStatusIsAwaitingApproval(mesh, nodeId, sessionId) {
23156
23159
  return false;
23157
23160
  }
23158
23161
  }
23159
- async function recoverStrandedAssignedDispatches(components, mesh, store) {
23162
+ async function recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds = []) {
23160
23163
  const meshId = mesh.id;
23161
23164
  const assigned = getQueue(meshId, { status: ["assigned"] });
23162
23165
  if (!assigned.length) return;
@@ -23180,6 +23183,24 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
23180
23183
  updateTaskStatus(meshId, row.id, status);
23181
23184
  continue;
23182
23185
  }
23186
+ const assignedNode = row.assignedNodeId ? mesh.nodes?.find((n) => meshNodeIdMatches(n, row.assignedNodeId)) : void 0;
23187
+ if (assignedNode?.daemonId) {
23188
+ try {
23189
+ await pullPendingEventsFromNode(
23190
+ components,
23191
+ meshId,
23192
+ assignedNode,
23193
+ localDaemonId,
23194
+ selfIds,
23195
+ selfIds.length > 0 ? selfIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }]
23196
+ );
23197
+ } catch {
23198
+ }
23199
+ if (store.taskDeliveryConsumed(meshId, row.id)) {
23200
+ deliveredUnconsumedUnknownStreak.delete(`${meshId}::${row.id}`);
23201
+ continue;
23202
+ }
23203
+ }
23183
23204
  const shortStreakKey = `${meshId}::${row.id}`;
23184
23205
  const verdict = row.assignedSessionId ? resolveSessionBusyVerdict(components, row.assignedSessionId) : "IDLE_CONFIRMED";
23185
23206
  if (verdict === "GENERATING") {
@@ -23438,7 +23459,7 @@ async function runMeshReconcileTick(components) {
23438
23459
  const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
23439
23460
  if (!daemonHostsMesh(mesh, selfIds)) continue;
23440
23461
  try {
23441
- await recoverStrandedAssignedDispatches(components, mesh, store);
23462
+ await recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds);
23442
23463
  } catch (e) {
23443
23464
  LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
23444
23465
  }
@@ -49540,6 +49561,18 @@ var CliProviderInstance = class _CliProviderInstance {
49540
49561
  // MESH_WORKER_STALL_REFIRE_COOLDOWN_MS between successive emissions across
49541
49562
  // anchor re-arms (the per-anchor guard only covers a single continuous stall).
49542
49563
  meshStallLastFiredAt = -1;
49564
+ // KIMI-MESH-COMPLETION-EMIT (axis 1): the native-source transcript progress
49565
+ // fingerprint (record count + source mtime) observed the LAST time the stall
49566
+ // watchdog checked a native-source provider (transcriptAuthority=provider — e.g.
49567
+ // kimi wire.jsonl). A pure-PTY native-source worker running a long, screen-quiet
49568
+ // tool (no viewport bytes for minutes) looks stalled by the lastOutputAt clock
49569
+ // even though its transcript file is still growing. Before firing the stall, we
49570
+ // compare the current transcript fingerprint against this snapshot; if the
49571
+ // transcript advanced, the "stall" is a false positive of PTY-render stasis, so
49572
+ // we re-arm the anchor instead of paging the coordinator (whose no_progress
49573
+ // handling can lead to the worker being stopped mid-work → completion never
49574
+ // emitted). null = not yet sampled for this session/anchor.
49575
+ meshStallNativeTranscriptSample = null;
49543
49576
  // FALSE-IDLE continuity epoch: monotonically bumped on EVERY entry into a busy
49544
49577
  // phase (→generating or →waiting_approval). The completedDebouncePending snapshots
49545
49578
  // this value at arm time (busyEpochAtArm); the flush guard requires it UNCHANGED
@@ -50349,6 +50382,14 @@ var CliProviderInstance = class _CliProviderInstance {
50349
50382
  * once at completion). Reset on the next turn's start.
50350
50383
  */
50351
50384
  lastCompletionSummary = null;
50385
+ // KIMI-MESH-COMPLETION-EMIT (axis 2, double-emit guard): the (taskId, wall-clock)
50386
+ // of the most recent agent:generating_completed this instance emitted, stamped by
50387
+ // emitGeneratingCompleted. The pre-cleanup completion flush
50388
+ // (flushMeshCompletionBeforeCleanup, driven by cli-manager's exit monitor) reads
50389
+ // this to refuse a SECOND completion for a turn whose completion already fired —
50390
+ // so a worker that finished cleanly and is simply being auto-cleaned never emits a
50391
+ // duplicate. taskId '' covers an ad-hoc (no-task) turn. null = none emitted yet.
50392
+ lastEmittedCompletion = null;
50352
50393
  async enforceFreshSessionLaunchIfNeeded() {
50353
50394
  const scriptName = getForcedNewSessionScriptName(this.provider, this.launchMode);
50354
50395
  if (!scriptName) return;
@@ -50974,6 +51015,24 @@ var CliProviderInstance = class _CliProviderInstance {
50974
51015
  const threshold = turnActive ? _CliProviderInstance.MESH_WORKER_STALL_TURN_THRESHOLD_MS : _CliProviderInstance.MESH_WORKER_STALL_IDLE_THRESHOLD_MS;
50975
51016
  const stalledMs = now - this.meshStallAnchorAt;
50976
51017
  if (stalledMs < threshold) return;
51018
+ const nativeSample = this.sampleNativeTranscriptProgress();
51019
+ if (nativeSample) {
51020
+ const prev = this.meshStallNativeTranscriptSample;
51021
+ const advanced = !prev || nativeSample.msgCount > prev.msgCount || nativeSample.sourceMtimeMs > prev.sourceMtimeMs;
51022
+ this.meshStallNativeTranscriptSample = nativeSample;
51023
+ if (advanced) {
51024
+ if (this.isMeshWorkerSession()) {
51025
+ traceMeshEventDrop(
51026
+ "mesh_worker_stall_transcript_advancing",
51027
+ this.meshTraceCtx("monitor:no_progress"),
51028
+ `msgCount=${nativeSample.msgCount} sourceMtime=${nativeSample.sourceMtimeMs} (PTY quiet ${Math.round(stalledMs / 1e3)}s but transcript advancing)`
51029
+ );
51030
+ }
51031
+ this.meshStallAnchorAt = now;
51032
+ this.meshStallEmittedForAnchor = false;
51033
+ return;
51034
+ }
51035
+ }
50977
51036
  this.meshStallEmittedForAnchor = true;
50978
51037
  if (this.meshStallLastFiredAt >= 0 && now - this.meshStallLastFiredAt < _CliProviderInstance.MESH_WORKER_STALL_REFIRE_COOLDOWN_MS) {
50979
51038
  return;
@@ -51010,6 +51069,99 @@ var CliProviderInstance = class _CliProviderInstance {
51010
51069
  this.meshStallEmittedForAnchor = false;
51011
51070
  this.meshStallTurnActiveLast = void 0;
51012
51071
  this.meshStallLastFiredAt = -1;
51072
+ this.meshStallNativeTranscriptSample = null;
51073
+ }
51074
+ /**
51075
+ * KIMI-MESH-COMPLETION-EMIT (axis 1). For a native-source provider
51076
+ * (transcriptAuthority=provider — its authoritative history is an on-disk
51077
+ * transcript file, e.g. kimi's wire.jsonl), sample the transcript's current
51078
+ * progress fingerprint (record count + source-file mtime) WITHOUT parsing the
51079
+ * PTY. Used by the stall watchdog to distinguish "PTY render is quiet but the
51080
+ * worker is still doing long tool work (transcript growing)" from a genuine
51081
+ * wedge. Returns null for a pure-PTY provider (no native source) or when the
51082
+ * source cannot be resolved this tick — the caller then falls back to the
51083
+ * unchanged lastOutputAt-only judgment.
51084
+ *
51085
+ * Generalized on the provider's native-source flag, NOT a hardcoded provider
51086
+ * type, so every current and future pure-PTY long-tool native-source provider
51087
+ * benefits. Cheap enough for the stall path: it runs only at the stall threshold
51088
+ * (≥180s of PTY stasis), never on the routine 5s tick.
51089
+ */
51090
+ sampleNativeTranscriptProgress() {
51091
+ if (!isNativeSourceCanonicalHistory(this.provider?.nativeHistory)) return null;
51092
+ let messages = null;
51093
+ try {
51094
+ messages = this.readExternalCompletionMessages();
51095
+ } catch {
51096
+ return null;
51097
+ }
51098
+ const probe = this.lastExternalCompletionProbe;
51099
+ if (!probe) return null;
51100
+ return {
51101
+ msgCount: typeof probe.msgCount === "number" ? probe.msgCount : Array.isArray(messages) ? messages.length : 0,
51102
+ sourceMtimeMs: typeof probe.sourceMtimeMs === "number" ? probe.sourceMtimeMs : 0
51103
+ };
51104
+ }
51105
+ /**
51106
+ * KIMI-MESH-COMPLETION-EMIT (axis 2). Last-chance completion emit for a mesh
51107
+ * DELEGATED worker whose PTY has already exited (e.g. killed by a false stall)
51108
+ * and is about to be auto-cleaned (cli-manager.startCliExitMonitor →
51109
+ * removeInstance closes the event-emit window forever). If the worker actually
51110
+ * FINISHED its assigned turn — its authoritative native transcript holds a final
51111
+ * assistant message for the injected task — but the completion event never fired
51112
+ * (the stall-kill happened before the FSM's idle transition), emit it now so the
51113
+ * coordinator learns the task completed instead of waiting ~180s for the reconcile
51114
+ * transcript-poll to reclaim it.
51115
+ *
51116
+ * Scope & guards (must all hold to emit):
51117
+ * • mesh worker session only — a normal standalone session's ordinary exit is
51118
+ * never synthesized (isMeshWorkerSession()).
51119
+ * • DOUBLE-EMIT guard — refuse if this turn's completion already fired
51120
+ * (lastEmittedCompletion matches the current taskId). A worker that completed
51121
+ * cleanly and is merely being cleaned up never double-emits.
51122
+ * • evidence gate — reuse the same final-assistant/turn-scoped summary machinery
51123
+ * as the normal completion path (completionFinalSummary over the native
51124
+ * transcript). No in-turn assistant summary ⇒ no proof of completion ⇒ leave
51125
+ * the reclaim path to handle a genuinely-unfinished worker.
51126
+ *
51127
+ * Returns true when a synthetic completion was emitted, false otherwise. Safe to
51128
+ * call unconditionally from the cleanup path.
51129
+ */
51130
+ flushMeshCompletionBeforeCleanup() {
51131
+ if (!this.isMeshWorkerSession()) return false;
51132
+ const taskId = this.completingTurnTaskId();
51133
+ if (this.lastEmittedCompletion && this.lastEmittedCompletion.taskId === (taskId ?? "")) {
51134
+ return false;
51135
+ }
51136
+ if (!this.injectedTaskHasStartedGenerating()) return false;
51137
+ const turnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : this.meshTaskInjectedAt || void 0;
51138
+ let parsedMessages;
51139
+ try {
51140
+ parsedMessages = this.adapter?.getScriptParsedStatus?.()?.messages;
51141
+ } catch {
51142
+ parsedMessages = void 0;
51143
+ }
51144
+ let finalSummary;
51145
+ try {
51146
+ finalSummary = this.completionFinalSummary(parsedMessages, turnStartedAt);
51147
+ } catch {
51148
+ finalSummary = void 0;
51149
+ }
51150
+ if (!finalSummary) return false;
51151
+ LOG.warn("CLI", `[${this.type}] emitting pre-cleanup mesh completion for session ${this.instanceId} task=${taskId ?? "(none)"} \u2014 PTY exited before the completion event fired but the native transcript shows a finished turn; synthesizing completion so the coordinator is not left waiting for reclaim.`);
51152
+ if (this.isMeshWorkerSession()) {
51153
+ traceMeshEventStage("fired", this.meshTraceCtx(), "pre_cleanup_transcript_completion");
51154
+ }
51155
+ this.emitGeneratingCompleted({
51156
+ chatTitle: "",
51157
+ duration: void 0,
51158
+ timestamp: Date.now(),
51159
+ taskId,
51160
+ finalSummary,
51161
+ evidenceLevel: "transcript",
51162
+ completionDiagnostic: { source: "pre_cleanup_transcript_completion" }
51163
+ });
51164
+ return true;
51013
51165
  }
51014
51166
  /**
51015
51167
  * AUTOAPPROVE-FLAP-RECUR (Fix A+B): how long a busy blip / modal scroll-out may
@@ -51411,6 +51563,7 @@ var CliProviderInstance = class _CliProviderInstance {
51411
51563
  if (summary) {
51412
51564
  this.lastCompletionSummary = { content: summary, receivedAt: opts.timestamp };
51413
51565
  }
51566
+ this.lastEmittedCompletion = { taskId: typeof opts.taskId === "string" ? opts.taskId : "", at: Date.now() };
51414
51567
  this.pushEvent({
51415
51568
  event: "agent:generating_completed",
51416
51569
  chatTitle: opts.chatTitle,
@@ -54202,6 +54355,15 @@ var DaemonCliManager = class {
54202
54355
  clearInterval(checkStopped);
54203
54356
  setTimeout(() => {
54204
54357
  if (this.adapters.has(key2)) {
54358
+ try {
54359
+ const inst = instanceManager?.getInstance(key2);
54360
+ if (typeof inst?.flushMeshCompletionBeforeCleanup === "function") {
54361
+ const emitted = inst.flushMeshCompletionBeforeCleanup();
54362
+ if (emitted) LOG.info("CLI", `Emitted pre-cleanup mesh completion for ${cliType} session ${key2} before auto-clean`);
54363
+ }
54364
+ } catch (e) {
54365
+ LOG.warn("CLI", `pre-cleanup mesh completion flush failed for ${key2}: ${e?.message || e}`);
54366
+ }
54205
54367
  this.adapters.delete(key2);
54206
54368
  this.deps.removeAgentTracking(key2);
54207
54369
  sessionRegistry?.unregisterByInstanceKey(key2);