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

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.
@@ -270,6 +270,39 @@ export interface CliProviderModule {
270
270
  _resolvedScriptsSource?: string | null;
271
271
  _versionWarning?: string | null;
272
272
  }
273
+ /**
274
+ * PURE-PTY TRANSCRIPT CLASS predicate (kimi and kin).
275
+ *
276
+ * A provider is "pure-PTY full-buffer" when it reconstructs its ENTIRE transcript
277
+ * from the rendered PTY buffer on every read and has NO alternate transcript
278
+ * source:
279
+ * - transcriptAuthority !== 'provider' (the daemon PTY parser owns the transcript,
280
+ * not a provider-side canonical source)
281
+ * - NO nativeHistory (no on-disk / native-source history to fall back to)
282
+ * - tui.transcriptPty.scope === 'buffer' (the parser walks the full rendered buffer)
283
+ *
284
+ * This class is invisible to two provider-authority-keyed code paths that other
285
+ * providers rely on for mesh completion semantics:
286
+ * 1. CliStateEngine.onTurnStarted only promotes to 'generating' for
287
+ * transcriptAuthority==='provider' providers — so a pure-PTY session that
288
+ * submits a prompt while already idle collapses idle→idle, the
289
+ * generating→idle edge never occurs, and agent:generating_completed is never
290
+ * emitted (the coordinator ledger leaves the task 'assigned' forever).
291
+ * 2. checkMeshWorkerStall's native-transcript completion reconcile is gated on
292
+ * the native-source shape, so a finished pure-PTY worker's static idle is
293
+ * misread as monitor:no_progress (a false task_stalled).
294
+ *
295
+ * The runtime capability, NOT any single spec field value, is authoritative: a
296
+ * given kimi manifest checkout may declare nativeHistory/transcriptAuthority, but
297
+ * the live-loaded pure-PTY session has none. Callers that only hold a
298
+ * CliProviderModule (the engine) share this exact predicate with the adapter
299
+ * (parsesFullPtyTranscriptFromBuffer) so the two never drift.
300
+ */
301
+ export declare function isPurePtyTranscriptProvider(provider: {
302
+ transcriptAuthority?: 'provider' | 'daemon';
303
+ nativeHistory?: unknown;
304
+ tui?: Record<string, unknown>;
305
+ }): boolean;
273
306
  /**
274
307
  * Stateful, transcript-oriented terminal cell accumulator.
275
308
  *
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 ? "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);
445
+ const commit = readInjected(true ? "64f056340da99d3b28464efcf5c05fe643e5db63" : void 0) ?? "unknown";
446
+ const commitShort = readInjected(true ? "64f05634" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
447
+ const version = readInjected(true ? "1.0.18-rc.15" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
448
+ const builtAt = readInjected(true ? "2026-07-23T00:51:36.808Z" : void 0);
449
449
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
450
450
  return cached;
451
451
  }
@@ -12931,6 +12931,12 @@ var init_spawn_env = __esm({
12931
12931
  });
12932
12932
 
12933
12933
  // src/cli-adapters/provider-cli-shared.ts
12934
+ function isPurePtyTranscriptProvider(provider) {
12935
+ if (provider.transcriptAuthority === "provider") return false;
12936
+ if (provider.nativeHistory) return false;
12937
+ const transcriptPty = provider.tui?.transcriptPty;
12938
+ return transcriptPty?.scope === "buffer";
12939
+ }
12934
12940
  function stripAnsi(str) {
12935
12941
  return str.replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
12936
12942
  }
@@ -23172,10 +23178,54 @@ async function recoverStrandedAssignedDispatches(components, mesh, store, localD
23172
23178
  for (const key2 of [...deliveredUnconsumedUnknownStreak.keys()]) {
23173
23179
  if (key2.startsWith(meshKeyPrefix) && !assignedKeys.has(key2)) deliveredUnconsumedUnknownStreak.delete(key2);
23174
23180
  }
23181
+ for (const key2 of [...assignedIdleFinalAssistantSince.keys()]) {
23182
+ if (key2.startsWith(meshKeyPrefix) && !assignedKeys.has(key2)) assignedIdleFinalAssistantSince.delete(key2);
23183
+ }
23175
23184
  for (const row of assigned) {
23176
23185
  const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
23177
23186
  if (!Number.isFinite(dispatchedAtMs)) continue;
23178
23187
  const ageMs = nowMs - dispatchedAtMs;
23188
+ const idleTranscriptStreakKey = `${meshId}::${row.id}`;
23189
+ if (store.taskHasConfirmedDelivery(meshId, row.id) && !findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id }) && readNonEmptyString(row.assignedSessionId) && resolveSessionBusyVerdict(components, row.assignedSessionId) !== "GENERATING") {
23190
+ const since = assignedIdleFinalAssistantSince.get(idleTranscriptStreakKey);
23191
+ if (since === void 0) {
23192
+ assignedIdleFinalAssistantSince.set(idleTranscriptStreakKey, nowMs);
23193
+ } else if (nowMs - since >= ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS) {
23194
+ const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row);
23195
+ if (terminalEvidence) {
23196
+ assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
23197
+ updateTaskStatus(meshId, row.id, terminalEvidence);
23198
+ if (!findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
23199
+ try {
23200
+ appendLedgerEntry(meshId, {
23201
+ kind: terminalEvidence === "completed" ? "task_completed" : "task_failed",
23202
+ nodeId: row.assignedNodeId,
23203
+ sessionId: row.assignedSessionId,
23204
+ providerType: row.assignedProviderType,
23205
+ payload: {
23206
+ taskId: row.id,
23207
+ event: "agent:generating_completed",
23208
+ source: "early_idle_transcript_evidence"
23209
+ }
23210
+ });
23211
+ } catch {
23212
+ }
23213
+ }
23214
+ LOG.warn("MeshReconcile", `Early-completed assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}): worker idle with a final assistant message after dispatch for \u2265${Math.round(ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS / 1e3)}s \u2014 the completion event was lost/late (pure-PTY provider), task is ${terminalEvidence} without waiting the 15-min deadline`);
23215
+ traceMeshEventDrop("assigned_early_transcript_completed", {
23216
+ taskId: row.id,
23217
+ sessionId: row.assignedSessionId,
23218
+ nodeId: row.assignedNodeId,
23219
+ meshId,
23220
+ event: "agent:generating_completed"
23221
+ }, terminalEvidence);
23222
+ continue;
23223
+ }
23224
+ assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
23225
+ }
23226
+ } else {
23227
+ assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
23228
+ }
23179
23229
  if (ageMs >= ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS && ageMs < ASSIGNED_STRANDED_DEADLINE_MS && store.taskHasConfirmedDelivery(meshId, row.id) && !store.taskDeliveryConsumed(meshId, row.id)) {
23180
23230
  const terminal2 = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
23181
23231
  if (terminal2) {
@@ -23851,7 +23901,7 @@ function setupMeshReconcileLoop(components) {
23851
23901
  }
23852
23902
  };
23853
23903
  }
23854
- var coordinatorModalParkState, DISK_RETENTION_INTERVAL_MS, lastDiskRetentionRunAt, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, deliveredUnconsumedUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
23904
+ var coordinatorModalParkState, DISK_RETENTION_INTERVAL_MS, lastDiskRetentionRunAt, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, deliveredUnconsumedUnknownStreak, ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS, assignedIdleFinalAssistantSince, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
23855
23905
  var init_mesh_reconcile_loop = __esm({
23856
23906
  "src/mesh/mesh-reconcile-loop.ts"() {
23857
23907
  "use strict";
@@ -23889,6 +23939,8 @@ var init_mesh_reconcile_loop = __esm({
23889
23939
  RECLAIM_UNKNOWN_GRACE_TICKS = 3;
23890
23940
  deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
23891
23941
  deliveredUnconsumedUnknownStreak = /* @__PURE__ */ new Map();
23942
+ ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS = 8e3;
23943
+ assignedIdleFinalAssistantSince = /* @__PURE__ */ new Map();
23892
23944
  ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
23893
23945
  STRICT_SESSION_MATCH_TTL_MS = 6e4;
23894
23946
  unresolvedForwardRejectionCounts = /* @__PURE__ */ new Map();
@@ -26658,7 +26710,8 @@ var init_cli_state_engine = __esm({
26658
26710
  this.currentTurnStartedAt = Date.now();
26659
26711
  this.responseEpoch += 1;
26660
26712
  this.clearApprovalResolutionMemory();
26661
- if (this.provider.transcriptAuthority === "provider" && this.currentStatus !== "waiting_approval") {
26713
+ const promoteOnTurnStart = this.provider.transcriptAuthority === "provider" || isPurePtyTranscriptProvider(this.provider);
26714
+ if (promoteOnTurnStart && this.currentStatus !== "waiting_approval") {
26662
26715
  this.setStatus("generating", "turn_started");
26663
26716
  this.callbacks.onStatusChange();
26664
26717
  }
@@ -28189,10 +28242,7 @@ ${lastSnapshot}`;
28189
28242
  * provider-owned) so no other provider's turn-scoped parse changes.
28190
28243
  */
28191
28244
  parsesFullPtyTranscriptFromBuffer() {
28192
- if (this.providerOwnsTranscript()) return false;
28193
- if (this.provider.nativeHistory) return false;
28194
- const transcriptPty = this.provider.tui?.transcriptPty;
28195
- return transcriptPty?.scope === "buffer";
28245
+ return isPurePtyTranscriptProvider(this.provider);
28196
28246
  }
28197
28247
  /**
28198
28248
  * The turn scope to feed the transcript parser. Normally the live turn scope
@@ -45357,6 +45407,7 @@ var fs24 = __toESM(require("fs"));
45357
45407
  init_contracts2();
45358
45408
  init_provider_input_support();
45359
45409
  init_hash();
45410
+ init_provider_cli_shared();
45360
45411
 
45361
45412
  // src/providers/spec/route.ts
45362
45413
  var fs22 = __toESM(require("fs"));
@@ -51033,6 +51084,10 @@ var CliProviderInstance = class _CliProviderInstance {
51033
51084
  return;
51034
51085
  }
51035
51086
  }
51087
+ if (this.tryReconcilePurePtyCompletionForStall(observedStatus)) {
51088
+ this.meshStallEmittedForAnchor = true;
51089
+ return;
51090
+ }
51036
51091
  this.meshStallEmittedForAnchor = true;
51037
51092
  if (this.meshStallLastFiredAt >= 0 && now - this.meshStallLastFiredAt < _CliProviderInstance.MESH_WORKER_STALL_REFIRE_COOLDOWN_MS) {
51038
51093
  return;
@@ -51163,6 +51218,70 @@ var CliProviderInstance = class _CliProviderInstance {
51163
51218
  });
51164
51219
  return true;
51165
51220
  }
51221
+ /**
51222
+ * KIMI-PURE-PTY-COMPLETION-EMIT (Fix 3): stall-path completion reconcile for the
51223
+ * PURE-PTY transcript class (kimi and kin — no native transcript, no provider
51224
+ * authority; see isPurePtyTranscriptProvider). Such a worker whose
51225
+ * generating_completed never emitted (the onTurnStarted idle→idle collapse Fix 1
51226
+ * fixes at the source) sits at a STATIC idle prompt: its PTY output stops the
51227
+ * instant the answer is rendered, so the status-agnostic no-progress watchdog
51228
+ * (checkMeshWorkerStall) reads the finished-but-quiet session as a stall and would
51229
+ * false-fire monitor:no_progress. The native-transcript reconcile
51230
+ * (sampleNativeTranscriptProgress) does NOT cover this class (no native source →
51231
+ * null sample), so the stall path needs its own guard.
51232
+ *
51233
+ * Called from checkMeshWorkerStall just before the fire. Returns true when the
51234
+ * session is a finished pure-PTY turn — idle, no pending response, and a PTY-parsed
51235
+ * in-turn final assistant summary — in which case it emits the missing
51236
+ * generating_completed (idempotent: a real/late emit writes the terminal ledger and
51237
+ * the coordinator's reconcile makes any duplicate a no-op) and the caller SUPPRESSES
51238
+ * the stall. Returns false for every other class/state (native-source provider, a
51239
+ * genuinely mid-turn or wedged worker with no final assistant), so a real stall still
51240
+ * fires unchanged.
51241
+ *
51242
+ * Evidence bar is identical to flushMeshCompletionBeforeCleanup: injected task's turn
51243
+ * genuinely started + an in-turn final assistant summary. Conservative by
51244
+ * construction — no summary ⇒ no proof of completion ⇒ return false and let the real
51245
+ * stall fire.
51246
+ */
51247
+ tryReconcilePurePtyCompletionForStall(observedStatus) {
51248
+ if (!isPurePtyTranscriptProvider(this.provider)) return false;
51249
+ if (observedStatus !== "idle") return false;
51250
+ if (this.hasAdapterPendingResponse()) return false;
51251
+ const taskId = this.completingTurnTaskId();
51252
+ if (this.lastEmittedCompletion && this.lastEmittedCompletion.taskId === (taskId ?? "")) {
51253
+ return false;
51254
+ }
51255
+ if (!this.injectedTaskHasStartedGenerating()) return false;
51256
+ const turnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : this.meshTaskInjectedAt || void 0;
51257
+ let parsedMessages;
51258
+ try {
51259
+ parsedMessages = this.adapter?.getScriptParsedStatus?.()?.messages;
51260
+ } catch {
51261
+ parsedMessages = void 0;
51262
+ }
51263
+ let finalSummary;
51264
+ try {
51265
+ finalSummary = this.completionFinalSummary(parsedMessages, turnStartedAt);
51266
+ } catch {
51267
+ finalSummary = void 0;
51268
+ }
51269
+ if (!finalSummary) return false;
51270
+ LOG.warn("CLI", `[${this.type}] reconciling pure-PTY mesh completion from the stall path for session ${this.instanceId} task=${taskId ?? "(none)"} \u2014 PTY is idle-quiet with an in-turn final assistant message but the completion event never fired (pure-PTY provider); emitting it instead of a false monitor:no_progress.`);
51271
+ if (this.isMeshWorkerSession()) {
51272
+ traceMeshEventStage("fired", this.meshTraceCtx(), "stall_pure_pty_transcript_completion");
51273
+ }
51274
+ this.emitGeneratingCompleted({
51275
+ chatTitle: "",
51276
+ duration: void 0,
51277
+ timestamp: Date.now(),
51278
+ taskId,
51279
+ finalSummary,
51280
+ evidenceLevel: "transcript",
51281
+ completionDiagnostic: { source: "stall_pure_pty_transcript_completion" }
51282
+ });
51283
+ return true;
51284
+ }
51166
51285
  /**
51167
51286
  * AUTOAPPROVE-FLAP-RECUR (Fix A+B): how long a busy blip / modal scroll-out may
51168
51287
  * persist before the in-progress settle gate is torn down. For a delegated