@adhdev/daemon-standalone 1.0.28-rc.20 → 1.0.28-rc.21

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
@@ -33311,10 +33311,10 @@ var require_dist3 = __commonJS({
33311
33311
  }
33312
33312
  function getDaemonBuildInfo() {
33313
33313
  if (cached2) return cached2;
33314
- const commit = readInjected(true ? "284a88d08b7bb93b250385f4da9c523fb4d8fd68" : void 0) ?? "unknown";
33315
- const commitShort = readInjected(true ? "284a88d0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
33316
- const version2 = readInjected(true ? "1.0.28-rc.20" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
33317
- const builtAt = readInjected(true ? "2026-07-28T17:20:58.778Z" : void 0);
33314
+ const commit = readInjected(true ? "878b909b3fa35ebc45f25ed51623f9a5dad45f3a" : void 0) ?? "unknown";
33315
+ const commitShort = readInjected(true ? "878b909b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
33316
+ const version2 = readInjected(true ? "1.0.28-rc.21" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
33317
+ const builtAt = readInjected(true ? "2026-07-29T00:15:43.541Z" : void 0);
33318
33318
  cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
33319
33319
  return cached2;
33320
33320
  }
@@ -37343,6 +37343,12 @@ ${error48.message || ""}`;
37343
37343
  function noteDroppedSuspension(reason) {
37344
37344
  metrics.suspensionsDropped[reason] = (metrics.suspensionsDropped[reason] ?? 0) + 1;
37345
37345
  }
37346
+ function noteRedriveBlocked(reason) {
37347
+ metrics.redriveBlockedByReason[reason] = (metrics.redriveBlockedByReason[reason] ?? 0) + 1;
37348
+ }
37349
+ function noteTargetPinCleared(reason) {
37350
+ metrics.targetPinClearedByReason[reason] = (metrics.targetPinClearedByReason[reason] ?? 0) + 1;
37351
+ }
37346
37352
  function logSuspensionOnce(level, key2, message) {
37347
37353
  if (suspensionLogKeys.has(key2)) return;
37348
37354
  if (suspensionLogKeys.size < MAX_SUSPENSION_LOG_KEYS) suspensionLogKeys.add(key2);
@@ -38070,7 +38076,9 @@ ${error48.message || ""}`;
38070
38076
  suspensionsDropped: {},
38071
38077
  reorderedGeneratingSuppressed: 0,
38072
38078
  redriveBlockedBySuspension: 0,
38073
- suspensionConsumedRecovered: 0
38079
+ suspensionConsumedRecovered: 0,
38080
+ redriveBlockedByReason: {},
38081
+ targetPinClearedByReason: {}
38074
38082
  };
38075
38083
  MAX_SUSPENSION_LOG_KEYS = 200;
38076
38084
  suspensionLogKeys = /* @__PURE__ */ new Set();
@@ -40204,6 +40212,7 @@ Next step: ${nextStep}`;
40204
40212
  deleteDirectDispatchesByTaskId: () => deleteDirectDispatchesByTaskId,
40205
40213
  describeTaskDependencyState: () => describeTaskDependencyState,
40206
40214
  enqueueTask: () => enqueueTask,
40215
+ expireTaskTargetPin: () => expireTaskTargetPin,
40207
40216
  getActiveDirectDispatches: () => getActiveDirectDispatches,
40208
40217
  getMeshQueueRevision: () => getMeshQueueRevision,
40209
40218
  getMeshQueueStats: () => getMeshQueueStats,
@@ -40906,6 +40915,24 @@ Next step: ${nextStep}`;
40906
40915
  if (result?.missionAffected) scheduleMissionCloseCandidateCheck(meshId, [result.entry, ...result.cascaded]);
40907
40916
  return result ? result.entry : null;
40908
40917
  }
40918
+ function expireTaskTargetPin(meshId, taskId, opts) {
40919
+ requireMeshHostQueueOwner(opts);
40920
+ return withQueueLock(meshId, () => {
40921
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
40922
+ if (!entry) return null;
40923
+ if (entry.status !== "pending") return null;
40924
+ if (!entry.targetSessionId && !entry.targetNodeId) return null;
40925
+ const clearedSession = entry.targetSessionId;
40926
+ const clearedNode = opts?.clearTargetNode ? entry.targetNodeId : void 0;
40927
+ delete entry.targetSessionId;
40928
+ if (opts?.clearTargetNode) delete entry.targetNodeId;
40929
+ entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
40930
+ if (opts?.reason) entry.requeueReason = opts.reason;
40931
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
40932
+ LOG2.warn("MeshQueue", `Expired stale target pin on task ${taskId} (mesh ${meshId}): cleared${clearedSession ? ` targetSessionId=${clearedSession}` : ""}${clearedNode ? ` targetNodeId=${clearedNode}` : ""} (${opts?.reason ?? "target_pin_expired"}) \u2014 the task is now claimable by any compatible session`);
40933
+ return entry;
40934
+ });
40935
+ }
40909
40936
  function reclaimStrandedAssignedTask(meshId, taskId, opts) {
40910
40937
  requireMeshHostQueueOwner(opts);
40911
40938
  const result = withQueueLock(meshId, () => {
@@ -54072,6 +54099,10 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
54072
54099
  }
54073
54100
  return isWithinCloneBootstrapGrace(targetNodeId);
54074
54101
  }
54102
+ function targetPinAgeMs(task, nowMs = Date.now()) {
54103
+ const anchorMs = Date.parse(task.requeuedAt || task.createdAt || "");
54104
+ return Number.isFinite(anchorMs) ? nowMs - anchorMs : null;
54105
+ }
54075
54106
  function resolveDeadTargetVerdict(components, meshId, mesh, task) {
54076
54107
  const NOT_DEAD = { dead: false, nodeDead: false, reason: "" };
54077
54108
  const targetSessionId = readNonEmptyString(task.targetSessionId);
@@ -54643,11 +54674,29 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
54643
54674
  clearTargetNode: deadTarget.nodeDead
54644
54675
  });
54645
54676
  if (requeued) {
54677
+ noteTargetPinCleared(deadTarget.reason);
54646
54678
  LOG2.warn("MeshQueue", `DEAD-TARGET-SELFHEAL: task ${task.id} (mesh ${meshId}) was pinned to a dead target (${deadTarget.reason}); requeued${deadTarget.nodeDead ? " and unpinned node" : ""} (requeueCount=${requeued.requeueCount ?? "?"}, status=${requeued.status}).`);
54647
54679
  }
54648
54680
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_dead_requeued" });
54649
54681
  continue;
54650
54682
  }
54683
+ const pinAgeMs = targetPinAgeMs(task);
54684
+ if (pinAgeMs !== null && pinAgeMs >= TARGET_SESSION_PIN_TTL_MS) {
54685
+ const expired = expireTaskTargetPin(meshId, task.id, { reason: "target_session_pin_expired_unclaimed" });
54686
+ if (expired) {
54687
+ noteTargetPinCleared("target_session_pin_expired_unclaimed");
54688
+ traceMeshEventDrop("target_session_pin_expired", {
54689
+ taskId: task.id,
54690
+ sessionId: readNonEmptyString(task.targetSessionId),
54691
+ nodeId: readNonEmptyString(task.targetNodeId),
54692
+ meshId,
54693
+ event: "agent:ready"
54694
+ }, `unclaimed ${Math.round(pinAgeMs / 1e3)}s \u2265 ttl ${Math.round(TARGET_SESSION_PIN_TTL_MS / 1e3)}s \u2192 pin cleared, claimable`);
54695
+ LOG2.warn("MeshQueue", `TARGET-PIN-TTL: task ${task.id} (mesh ${meshId}) stayed pinned-but-unclaimed for ${Math.round(pinAgeMs / 1e3)}s (ttl ${Math.round(TARGET_SESSION_PIN_TTL_MS / 1e3)}s); expired the stale target pin so a compatible session can claim it.`);
54696
+ }
54697
+ markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_pin_expired" });
54698
+ continue;
54699
+ }
54651
54700
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_constraint" });
54652
54701
  continue;
54653
54702
  }
@@ -55278,6 +55327,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
55278
55327
  var TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON;
55279
55328
  var lastActionableSkipNotified;
55280
55329
  var DEAD_TARGET_GRACE_MS;
55330
+ var TARGET_SESSION_PIN_TTL_MS;
55281
55331
  var init_mesh_queue_assignment = __esm2({
55282
55332
  "src/mesh/mesh-queue-assignment.ts"() {
55283
55333
  "use strict";
@@ -55343,6 +55393,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
55343
55393
  TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
55344
55394
  lastActionableSkipNotified = /* @__PURE__ */ new Map();
55345
55395
  DEAD_TARGET_GRACE_MS = 6e4;
55396
+ TARGET_SESSION_PIN_TTL_MS = 15 * 6e4;
55346
55397
  }
55347
55398
  });
55348
55399
  function readSettings(state) {
@@ -59573,21 +59624,28 @@ ${cleanBody}`;
59573
59624
  }
59574
59625
  }
59575
59626
  async function pollAssignedTaskInTurnProgress(components, mesh, row) {
59627
+ return (await pollAssignedTaskActivity(components, mesh, row)).inTurnProgress;
59628
+ }
59629
+ async function pollAssignedTaskActivity(components, mesh, row) {
59630
+ const NONE = { inTurnProgress: false, lastAgentActivityMs: null };
59576
59631
  const sessionId = readNonEmptyString(row.assignedSessionId);
59577
59632
  const nodeId = readNonEmptyString(row.assignedNodeId);
59578
- if (!sessionId || !nodeId) return false;
59633
+ if (!sessionId || !nodeId) return NONE;
59579
59634
  const dispatchedAtMs = Date.parse(readNonEmptyString(row.dispatchTimestamp));
59580
- if (!Number.isFinite(dispatchedAtMs)) return false;
59635
+ if (!Number.isFinite(dispatchedAtMs)) return NONE;
59581
59636
  const payload = await runSessionEvidenceCollection(sessionId, () => fetchAssignedTaskChatTail(components, mesh, row));
59582
- if (!payload) return false;
59637
+ if (!payload) return NONE;
59583
59638
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
59584
- return messages.some((msg) => {
59585
- if (!msg) return false;
59586
- if (msg.role === "user" || msg.role === "system") return false;
59639
+ let lastAgentActivityMs = null;
59640
+ for (const msg of messages) {
59641
+ if (!msg) continue;
59642
+ if (msg.role === "user" || msg.role === "system") continue;
59587
59643
  const ts2 = readChatMessageTimestampMs(msg);
59588
- if (typeof ts2 !== "number" || !Number.isFinite(ts2)) return false;
59589
- return ts2 >= dispatchedAtMs;
59590
- });
59644
+ if (typeof ts2 !== "number" || !Number.isFinite(ts2)) continue;
59645
+ if (ts2 < dispatchedAtMs) continue;
59646
+ if (lastAgentActivityMs === null || ts2 > lastAgentActivityMs) lastAgentActivityMs = ts2;
59647
+ }
59648
+ return { inTurnProgress: lastAgentActivityMs !== null, lastAgentActivityMs };
59591
59649
  }
59592
59650
  async function pollAssignedTaskTerminalEvidence(components, mesh, row, opts) {
59593
59651
  const sessionId = readNonEmptyString(row.assignedSessionId);
@@ -60053,6 +60111,7 @@ ${cleanBody}`;
60053
60111
  if (attempt.terminalOutcome) return false;
60054
60112
  const attemptSessionId = readNonEmptyString(attempt.sessionId);
60055
60113
  if (attemptSessionId && !sessionIdsEquivalent(attemptSessionId, sessionId)) return false;
60114
+ if (typeof row.dispatchNonce === "number" && typeof attempt.dispatchNonce === "number" && row.dispatchNonce !== attempt.dispatchNonce) return false;
60056
60115
  }
60057
60116
  const nodeId = readNonEmptyString(row.assignedNodeId);
60058
60117
  const coordinatorDaemonId = readNonEmptyString(attempt?.coordinatorDaemonId);
@@ -60205,6 +60264,26 @@ ${cleanBody}`;
60205
60264
  const redriveProfile = row.assignedSessionId ? resolveAssignedTranscriptProfile(components, row) : void 0;
60206
60265
  if (redriveProfile?.emitsPtyTurnEvents === false && await pollAssignedTaskInTurnProgress(components, { id: meshId, nodes: mesh.nodes }, row)) {
60207
60266
  deliveredUnconsumedUnknownStreak.delete(shortStreakKey);
60267
+ try {
60268
+ recordTurnAck({
60269
+ meshId,
60270
+ taskId: row.id,
60271
+ kind: "consumed",
60272
+ sessionId: row.assignedSessionId,
60273
+ legacy: {
60274
+ ...typeof row.dispatchNonce === "number" ? { dispatchNonce: row.dispatchNonce } : {},
60275
+ ...row.assignedNodeId ? { nodeId: row.assignedNodeId } : {},
60276
+ ...row.assignedProviderType ? { providerType: row.assignedProviderType } : {}
60277
+ },
60278
+ evidence: {
60279
+ source: "native_source_activity",
60280
+ profileClass: redriveProfile.class,
60281
+ profileTiming: redriveProfile.timing
60282
+ }
60283
+ });
60284
+ } catch {
60285
+ }
60286
+ noteRedriveBlocked("native_source_activity");
60208
60287
  traceMeshEventDrop("short_redrive_deferred_native_source_progress", {
60209
60288
  taskId: row.id,
60210
60289
  sessionId: row.assignedSessionId,
@@ -60440,6 +60519,70 @@ ${cleanBody}`;
60440
60519
  }, `${reclaimReason} \u2192 transcript ${terminalEvidence.outcome}${propagated ? " propagated" : ""}`);
60441
60520
  continue;
60442
60521
  }
60522
+ const currentAttempt = (() => {
60523
+ try {
60524
+ return store.getCurrentTurnAttempt(meshId, row.id);
60525
+ } catch {
60526
+ return null;
60527
+ }
60528
+ })();
60529
+ const attemptStage = readNonEmptyString(currentAttempt?.stage);
60530
+ if (currentAttempt && !currentAttempt.terminalOutcome && (attemptStage === "generating" || attemptStage === "waiting_approval" || attemptStage === "waiting_choice" || attemptStage === "finalizing")) {
60531
+ deliveredNoTurnUnknownStreak.delete(streakKey);
60532
+ noteRedriveBlocked("active_attempt_stage");
60533
+ traceMeshEventDrop("redrive_blocked_active_attempt", {
60534
+ taskId: row.id,
60535
+ sessionId: row.assignedSessionId,
60536
+ nodeId: row.assignedNodeId,
60537
+ meshId,
60538
+ event: "agent:generating_completed"
60539
+ }, `attempt stage ${attemptStage} \u2014 live turn, ${reclaimReason} suppressed`);
60540
+ continue;
60541
+ }
60542
+ const noTurnProfile = row.assignedSessionId ? resolveAssignedTranscriptProfile(components, row) : void 0;
60543
+ if (noTurnProfile?.emitsPtyTurnEvents === false) {
60544
+ const activity = await pollAssignedTaskActivity(components, { id: meshId, nodes: mesh.nodes }, row);
60545
+ if (activity.inTurnProgress && activity.lastAgentActivityMs !== null && nowMs - activity.lastAgentActivityMs <= NATIVE_SOURCE_ACTIVITY_STALE_MS) {
60546
+ deliveredNoTurnUnknownStreak.delete(streakKey);
60547
+ try {
60548
+ recordTurnAck({
60549
+ meshId,
60550
+ taskId: row.id,
60551
+ kind: "consumed",
60552
+ sessionId: row.assignedSessionId,
60553
+ legacy: {
60554
+ ...typeof row.dispatchNonce === "number" ? { dispatchNonce: row.dispatchNonce } : {},
60555
+ ...row.assignedNodeId ? { nodeId: row.assignedNodeId } : {},
60556
+ ...row.assignedProviderType ? { providerType: row.assignedProviderType } : {}
60557
+ },
60558
+ evidence: {
60559
+ source: "native_source_activity",
60560
+ profileClass: noTurnProfile.class,
60561
+ profileTiming: noTurnProfile.timing
60562
+ }
60563
+ });
60564
+ } catch {
60565
+ }
60566
+ noteRedriveBlocked("native_source_activity");
60567
+ traceMeshEventDrop("redrive_blocked_native_source_activity", {
60568
+ taskId: row.id,
60569
+ sessionId: row.assignedSessionId,
60570
+ nodeId: row.assignedNodeId,
60571
+ meshId,
60572
+ event: "agent:generating_completed"
60573
+ }, `${noTurnProfile.class}_fresh_activity \u2014 consumed promoted, ${reclaimReason} suppressed`);
60574
+ continue;
60575
+ }
60576
+ if (activity.inTurnProgress) {
60577
+ traceMeshEventStage("native_source_activity_stale", {
60578
+ taskId: row.id,
60579
+ sessionId: row.assignedSessionId,
60580
+ nodeId: row.assignedNodeId,
60581
+ meshId,
60582
+ event: "agent:generating_completed"
60583
+ }, `${noTurnProfile.class} quiet >${Math.round(NATIVE_SOURCE_ACTIVITY_STALE_MS / 1e3)}s \u2192 ${reclaimReason} proceeds`);
60584
+ }
60585
+ }
60443
60586
  const reclaimedLost = reclaimStrandedAssignedTask(meshId, row.id, {
60444
60587
  reason: reclaimReason,
60445
60588
  ageMs: nowMs - dispatchedAtMs
@@ -61005,6 +61148,7 @@ ${cleanBody}`;
61005
61148
  var heldEventLedgerRecorded;
61006
61149
  var ASSIGNED_STRANDED_DEADLINE_MS;
61007
61150
  var DELIVERED_NO_TURN_DEADLINE_MS;
61151
+ var NATIVE_SOURCE_ACTIVITY_STALE_MS;
61008
61152
  var ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS;
61009
61153
  var RECLAIM_UNKNOWN_GRACE_TICKS;
61010
61154
  var deliveredNoTurnUnknownStreak;
@@ -61055,6 +61199,7 @@ ${cleanBody}`;
61055
61199
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
61056
61200
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
61057
61201
  DELIVERED_NO_TURN_DEADLINE_MS = 15 * 6e4;
61202
+ NATIVE_SOURCE_ACTIVITY_STALE_MS = 10 * 6e4;
61058
61203
  ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS = 25e3;
61059
61204
  RECLAIM_UNKNOWN_GRACE_TICKS = 3;
61060
61205
  deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
@@ -67899,6 +68044,7 @@ ${lastSnapshot}`;
67899
68044
  isOperatingNoteTombstoned: () => isOperatingNoteTombstoned,
67900
68045
  isP2pRelayTransportFailure: () => isP2pRelayTransportFailure,
67901
68046
  isPathInside: () => isPathInside,
68047
+ isPreviewReleaseChannel: () => isPreviewReleaseChannel,
67902
68048
  isRestartBlockingPresentation: () => isRestartBlockingPresentation,
67903
68049
  isSessionHostLiveRuntime: () => import_session_host_core4.isSessionHostLiveRuntime,
67904
68050
  isSessionHostRecoverySnapshot: () => import_session_host_core4.isSessionHostRecoverySnapshot,
@@ -68209,6 +68355,28 @@ ${lastSnapshot}`;
68209
68355
  });
68210
68356
  return { promptId, answers };
68211
68357
  }
68358
+ function interactivePromptContentFingerprint(questions) {
68359
+ let hash2 = 2166136261;
68360
+ const mix = (text) => {
68361
+ for (let i = 0; i < text.length; i += 1) {
68362
+ hash2 ^= text.charCodeAt(i);
68363
+ hash2 = Math.imul(hash2, 16777619) >>> 0;
68364
+ }
68365
+ };
68366
+ for (const question of questions) {
68367
+ mix(question.question);
68368
+ mix(question.multiSelect ? "multi" : "single");
68369
+ for (const option of question.options) {
68370
+ mix("");
68371
+ mix(option.label);
68372
+ }
68373
+ mix("");
68374
+ }
68375
+ return hash2.toString(16).padStart(8, "0");
68376
+ }
68377
+ function stableClaudeTuiPromptId(questions) {
68378
+ return `ask-user-tui-${interactivePromptContentFingerprint(questions)}`;
68379
+ }
68212
68380
  function buildClaudeInteractiveToolResult(response) {
68213
68381
  return JSON.stringify({
68214
68382
  type: "user",
@@ -85059,10 +85227,15 @@ ${body}
85059
85227
  if (!screenText.includes("Enter to select")) return;
85060
85228
  if (headers.length === 0) {
85061
85229
  const prompt = detectClaudeAskUserQuestionPromptFromTuiPages([{ screenText }], {
85062
- promptId: `ask-user-${this.providerSessionId || "claude"}-${Date.now()}`,
85230
+ // REBIND OPTION FIDELITY (rc.20): provisional id — replaced with the
85231
+ // content-addressed stable id below, so the SAME picker re-captured
85232
+ // after a daemon restart keeps the SAME promptId and pre-restart
85233
+ // answers still bind to the options they were issued against.
85234
+ promptId: "ask-user-tui-pending",
85063
85235
  providerType: this.cliType
85064
85236
  });
85065
85237
  if (!prompt) return;
85238
+ prompt.promptId = stableClaudeTuiPromptId(prompt.questions);
85066
85239
  this.activeInteractivePrompt = prompt;
85067
85240
  this.interactivePromptTransport = "tui";
85068
85241
  this.interactivePromptLostAt = null;
@@ -85170,10 +85343,14 @@ ${body}
85170
85343
  }
85171
85344
  }
85172
85345
  const prompt = detectClaudeAskUserQuestionPromptFromTuiPages(pages, {
85173
- promptId: `ask-user-${this.providerSessionId || "claude"}-${Date.now()}`,
85346
+ // REBIND OPTION FIDELITY (rc.20): provisional id — replaced with the
85347
+ // content-addressed stable id below (same rationale as the
85348
+ // headerless capture in maybeCaptureClaudeTuiPrompt).
85349
+ promptId: "ask-user-tui-pending",
85174
85350
  providerType: this.cliType
85175
85351
  });
85176
85352
  if (!prompt) return;
85353
+ prompt.promptId = stableClaudeTuiPromptId(prompt.questions);
85177
85354
  this.activeInteractivePrompt = prompt;
85178
85355
  this.interactivePromptTransport = "tui";
85179
85356
  this.interactivePromptLostAt = null;
@@ -86662,6 +86839,12 @@ ${body}
86662
86839
  }
86663
86840
  } else if (event === "interactive_prompt_response" && data) {
86664
86841
  try {
86842
+ const heldPromptId = typeof this.activeInteractivePrompt?.promptId === "string" && this.activeInteractivePrompt.promptId ? this.activeInteractivePrompt.promptId : "";
86843
+ const incomingPromptId = typeof data?.promptId === "string" ? data.promptId.trim() : "";
86844
+ if (heldPromptId && incomingPromptId && incomingPromptId !== heldPromptId) {
86845
+ LOG2.warn("CLI", `[${this.type}] interactive_prompt_response REJECTED: stale promptId "${incomingPromptId}" does not match active prompt "${heldPromptId}" \u2014 answer not applied (no index/default fallback); re-answer against the active promptId`);
86846
+ return;
86847
+ }
86665
86848
  const response = this.activeInteractivePrompt && this.activeInteractivePrompt.promptId === data?.promptId && Array.isArray(data?.answers) ? resolveInteractivePromptResponse(this.activeInteractivePrompt, data) : normalizeInteractivePromptResponse2(data);
86666
86849
  if (this.activeInteractivePrompt?.promptId === response.promptId) {
86667
86850
  this.activeInteractivePrompt = null;
@@ -91615,6 +91798,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
91615
91798
  if (coordinatorEntry?.meshId) {
91616
91799
  restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
91617
91800
  }
91801
+ const recordMeshNodeFor = typeof record2.meshNodeFor === "string" && record2.meshNodeFor.trim() ? record2.meshNodeFor.trim() : "";
91802
+ const recordMeshNodeId = typeof record2.meshNodeId === "string" && record2.meshNodeId.trim() ? record2.meshNodeId.trim() : "";
91803
+ if (recordMeshNodeFor) restoredSettings.meshNodeFor = recordMeshNodeFor;
91804
+ if (recordMeshNodeId) {
91805
+ restoredSettings.meshNodeId = recordMeshNodeId;
91806
+ restoredSettings.meshLastNodeId = recordMeshNodeId;
91807
+ }
91808
+ if (record2.launchedByCoordinator === true) restoredSettings.launchedByCoordinator = true;
91618
91809
  try {
91619
91810
  await this.registerCliInstance(
91620
91811
  record2.runtimeId,
@@ -94291,9 +94482,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
94291
94482
  this.providerType = providerType;
94292
94483
  }
94293
94484
  };
94294
- function resolveProviderChannel(configured, env2 = process.env) {
94485
+ function isPreviewReleaseChannel(releaseChannel) {
94486
+ const normalized = typeof releaseChannel === "string" ? releaseChannel.trim().toLowerCase() : "";
94487
+ return normalized === "preview" || normalized === "next";
94488
+ }
94489
+ function resolveProviderChannel(configured, env2 = process.env, releaseChannel) {
94295
94490
  const raw = configured && configured.trim() || (env2[PROVIDER_CHANNEL_ENV_VAR] ?? "").trim();
94296
- return raw === "preview" ? "preview" : "stable";
94491
+ if (raw) return raw === "preview" ? "preview" : "stable";
94492
+ return isPreviewReleaseChannel(releaseChannel) ? "preview" : DEFAULT_PROVIDER_CHANNEL;
94297
94493
  }
94298
94494
  function partitionChannelEntries(entries) {
94299
94495
  const activatable = [];
@@ -95086,10 +95282,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
95086
95282
  * the resolved provider channel is 'stable' (production mode).
95087
95283
  */
95088
95284
  static UNVERIFIED_TARBALL_ENV_VAR = "ADHDEV_PROVIDER_ALLOW_UNVERIFIED_TARBALL";
95089
- /** Resolved explicit provider channel (absent/ambiguous → 'stable'). */
95285
+ /** Resolved provider channel (explicit config/env wins; otherwise derived from the daemon release channel; absent/ambiguous → 'stable'). */
95090
95286
  channel;
95091
95287
  allowUnverifiedTarball;
95092
95288
  channelStore;
95289
+ channelSyncIO;
95093
95290
  probeStarts = [];
95094
95291
  siblingLogged = false;
95095
95292
  siblingRefusalLogged = false;
@@ -95171,9 +95368,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
95171
95368
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
95172
95369
  this.registryBaseUrl = resolveRegistryBaseUrl(options?.registryUrl);
95173
95370
  this.providerTarballUrl = resolveProviderTarballUrl(options?.providerTarballUrl);
95174
- this.channel = resolveProviderChannel(options?.channel);
95371
+ this.channel = resolveProviderChannel(options?.channel, process.env, options?.updateChannel);
95175
95372
  this.allowUnverifiedTarball = options?.allowUnverifiedTarball === true || process.env[_ProviderLoader.UNVERIFIED_TARBALL_ENV_VAR] === "1";
95176
95373
  this.channelStore = options?.channelStore === null ? null : options?.channelStore ?? new ProviderChannelStore(ProviderChannelStore.defaultRoot(), this.logFn);
95374
+ this.channelSyncIO = options?.channelSyncIO;
95177
95375
  this.defaultProvidersDir = path41.join(getConfigDir2(), "providers");
95178
95376
  const detected = this.detectDefaultUserDir();
95179
95377
  this.userDir = detected.path;
@@ -95437,7 +95635,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
95437
95635
  store: this.channelStore,
95438
95636
  registryBaseUrl: this.registryBaseUrl,
95439
95637
  providerTarballUrl: this.providerTarballUrl,
95440
- logFn: this.logFn
95638
+ logFn: this.logFn,
95639
+ ...this.channelSyncIO
95441
95640
  });
95442
95641
  const targetTypes = collectSyncTargetTypes(this.upstreamDir, this.channelStore, this.channel);
95443
95642
  const report = await runtime.sync({ channel: this.channel, targetTypes });
@@ -95452,6 +95651,39 @@ Run 'adhdev doctor' for detailed diagnostics.`
95452
95651
  }
95453
95652
  return report;
95454
95653
  }
95654
+ /**
95655
+ * Number of valid active pointers on the resolved channel (0 = empty or
95656
+ * disabled store). Corrupt pointer files are excluded by the store.
95657
+ */
95658
+ countVerifiedChannelPointers() {
95659
+ if (!this.channelStore) return 0;
95660
+ try {
95661
+ return this.channelStore.listPointers(this.channel).pointers.size;
95662
+ } catch {
95663
+ return 0;
95664
+ }
95665
+ }
95666
+ /**
95667
+ * Bounded one-shot first sync for an empty verified channel store.
95668
+ *
95669
+ * Closes the rc.20 preview activation gap: a daemon whose provider channel
95670
+ * newly derives to a channel with an EMPTY store (e.g. updateChannel=preview
95671
+ * while providerChannel defaulted to stable) would otherwise sit at 0 active
95672
+ * providers until a manual check_provider_updates. Runs at most one
95673
+ * verified sync per call, only when the resolved channel has no pointers
95674
+ * AND there are installed (.upstream) providers to sync. Fail-closed: any
95675
+ * registry/transport failure activates nothing (last-known-good preserved)
95676
+ * and is retried on the next boot or via check_provider_updates. Never
95677
+ * invoked from any status path.
95678
+ *
95679
+ * Returns the sync report, or null when the first-sync gate did not apply.
95680
+ */
95681
+ async maybeFirstSyncVerifiedChannel() {
95682
+ if (!this.channelStore) return null;
95683
+ if (this.countVerifiedChannelPointers() > 0) return null;
95684
+ if (!this.hasUpstream()) return null;
95685
+ return this.syncVerifiedChannel();
95686
+ }
95455
95687
  /**
95456
95688
  * Roll a provider back to its previously activated verified object. Pure
95457
95689
  * local pointer flip — no network. Returns the new active digest, or null
@@ -97061,6 +97293,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
97061
97293
  return 0;
97062
97294
  }
97063
97295
  };
97296
+ init_config();
97064
97297
  function normalizeMacAppPath(appPath) {
97065
97298
  const trimmed = String(appPath || "").trim();
97066
97299
  if (!trimmed) return null;
@@ -97102,8 +97335,14 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
97102
97335
  var _providerLoader = null;
97103
97336
  function getProviderLoader() {
97104
97337
  if (!_providerLoader) {
97105
- _providerLoader = new ProviderLoader({ logFn: () => {
97106
- } });
97338
+ const appConfig = loadConfig2();
97339
+ _providerLoader = new ProviderLoader({
97340
+ logFn: () => {
97341
+ },
97342
+ // Suppress logs during launch
97343
+ channel: appConfig.providerChannel,
97344
+ updateChannel: appConfig.updateChannel
97345
+ });
97107
97346
  _providerLoader.loadAll();
97108
97347
  _providerLoader.registerToDetector();
97109
97348
  }
@@ -99667,6 +99906,25 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
99667
99906
  if (!instance) return { success: false, error: `No running instance for session ${sessionId}` };
99668
99907
  const isFriendlyArrayForm = rawResponse && typeof rawResponse === "object" && Array.isArray(rawResponse.answers);
99669
99908
  const payload = isFriendlyArrayForm ? rawResponse : normalizeInteractivePromptResponse2(rawResponse);
99909
+ const heldPrompt = (() => {
99910
+ try {
99911
+ const state = instance.getState?.();
99912
+ return state?.activeChat?.activeInteractivePrompt ?? state?.activeInteractivePrompt ?? null;
99913
+ } catch {
99914
+ return null;
99915
+ }
99916
+ })();
99917
+ const heldPromptId = typeof heldPrompt?.promptId === "string" && heldPrompt.promptId.trim() ? heldPrompt.promptId.trim() : "";
99918
+ const incomingPromptId = typeof payload?.promptId === "string" ? payload.promptId.trim() : "";
99919
+ if (heldPromptId && incomingPromptId && incomingPromptId !== heldPromptId) {
99920
+ return {
99921
+ success: false,
99922
+ error: `Stale promptId "${incomingPromptId}" \u2014 the session's active question is "${heldPromptId}". The answer was NOT applied; re-answer with mesh_answer_question against the active promptId.`,
99923
+ waitingChoice: true,
99924
+ promptId: heldPromptId,
99925
+ stalePromptId: incomingPromptId
99926
+ };
99927
+ }
99670
99928
  ctx.deps.instanceManager.sendEvent(sessionId, "interactive_prompt_response", payload);
99671
99929
  return { success: true };
99672
99930
  }
@@ -113259,7 +113517,13 @@ data: ${JSON.stringify(msg.data)}
113259
113517
  workspace: record2.workspace,
113260
113518
  cliArgs: Array.isArray(record2.meta?.cliArgs) ? record2.meta.cliArgs : [],
113261
113519
  providerSessionId: typeof record2.meta?.providerSessionId === "string" ? String(record2.meta.providerSessionId) : void 0,
113262
- managedBy: typeof record2.meta?.managedBy === "string" ? String(record2.meta.managedBy) : void 0
113520
+ managedBy: typeof record2.meta?.managedBy === "string" ? String(record2.meta.managedBy) : void 0,
113521
+ // Session-level mesh membership (rc.20 rebound relay envelope) —
113522
+ // surfaced so restoreHostedSessions can re-apply it to the rebuilt
113523
+ // instance settings. Task-level markers stay out (see the descriptor).
113524
+ meshNodeFor: typeof record2.meta?.meshNodeFor === "string" && record2.meta.meshNodeFor.trim() ? String(record2.meta.meshNodeFor).trim() : void 0,
113525
+ meshNodeId: typeof record2.meta?.meshNodeId === "string" && record2.meta.meshNodeId.trim() ? String(record2.meta.meshNodeId).trim() : void 0,
113526
+ launchedByCoordinator: record2.meta?.launchedByCoordinator === true ? true : void 0
113263
113527
  }));
113264
113528
  } finally {
113265
113529
  await client.close().catch(() => {
@@ -113780,10 +114044,19 @@ data: ${JSON.stringify(msg.data)}
113780
114044
  registryUrl: appConfig.registryUrl,
113781
114045
  providerTarballUrl: appConfig.providerTarballUrl,
113782
114046
  channel: appConfig.providerChannel,
114047
+ updateChannel: appConfig.updateChannel,
113783
114048
  allowUnverifiedTarball: appConfig.providerAllowUnverifiedTarball
113784
114049
  });
113785
114050
  providerLoader.loadAll();
113786
114051
  providerLoader.registerToDetector();
114052
+ void providerLoader.maybeFirstSyncVerifiedChannel().then((report) => {
114053
+ if (!report) return;
114054
+ if (report.status === "error") {
114055
+ LOG2.warn("Init", `Verified channel first-sync failed (last-known-good preserved): ${report.errors.map((e) => e.code).join(", ") || "unknown"}`);
114056
+ } else if (report.activated.length > 0) {
114057
+ LOG2.info("Init", `Verified channel first-sync activated ${report.activated.length} providers (${providerLoader.channel})`);
114058
+ }
114059
+ }).catch((e) => LOG2.warn("Init", `Verified channel first-sync error: ${e?.message || e}`));
113787
114060
  setDefaultProviderLoader(providerLoader);
113788
114061
  const versionArchive = new VersionArchive();
113789
114062
  providerLoader.setVersionArchive(versionArchive);