@adhdev/daemon-core 0.9.82-rc.396 → 0.9.82-rc.398

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.mjs CHANGED
@@ -378,10 +378,10 @@ function readInjected(value) {
378
378
  }
379
379
  function getDaemonBuildInfo() {
380
380
  if (cached) return cached;
381
- const commit = readInjected(true ? "109c5230408ea2b33e9083395b42b1c3e894aed2" : void 0) ?? "unknown";
382
- const commitShort = readInjected(true ? "109c5230" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
383
- const version = readInjected(true ? "0.9.82-rc.396" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
384
- const builtAt = readInjected(true ? "2026-06-27T07:15:39.648Z" : void 0);
381
+ const commit = readInjected(true ? "a572a9e7fe0e92e33a309d89e35299ad42aa407d" : void 0) ?? "unknown";
382
+ const commitShort = readInjected(true ? "a572a9e7" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
383
+ const version = readInjected(true ? "0.9.82-rc.398" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
384
+ const builtAt = readInjected(true ? "2026-06-27T09:05:08.687Z" : void 0);
385
385
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
386
386
  return cached;
387
387
  }
@@ -5190,6 +5190,7 @@ var init_mesh_runtime_store = __esm({
5190
5190
  init_load_better_sqlite3();
5191
5191
  init_mesh_ledger();
5192
5192
  init_mesh_work_queue();
5193
+ init_dist();
5193
5194
  loggedMigrationFailure = false;
5194
5195
  MeshRuntimeStore = class _MeshRuntimeStore {
5195
5196
  static instance;
@@ -5722,6 +5723,8 @@ var init_mesh_runtime_store = __esm({
5722
5723
  if (providerType && typeof providerMaxParallel === "number" && Number.isFinite(providerMaxParallel) && providerMaxParallel >= 0 && this.activeProviderAssignmentCount(meshId, nodeId, providerType) >= providerMaxParallel) {
5723
5724
  return null;
5724
5725
  }
5726
+ const nodeIdForms = expandDaemonIdForms(nodeId);
5727
+ const nodePinnedPlaceholders = nodeIdForms.map(() => "?").join(", ");
5725
5728
  const rows = [
5726
5729
  ...this.db.prepare(`
5727
5730
  SELECT payload FROM mesh_queue
@@ -5730,9 +5733,9 @@ var init_mesh_runtime_store = __esm({
5730
5733
  `).all(meshId, sessionId),
5731
5734
  ...this.db.prepare(`
5732
5735
  SELECT payload FROM mesh_queue
5733
- WHERE mesh_id = ? AND status = 'pending' AND target_node_id = ? AND target_session_id IS NULL
5736
+ WHERE mesh_id = ? AND status = 'pending' AND target_node_id IN (${nodePinnedPlaceholders}) AND target_session_id IS NULL
5734
5737
  ORDER BY created_at ASC
5735
- `).all(meshId, nodeId),
5738
+ `).all(meshId, ...nodeIdForms),
5736
5739
  ...this.db.prepare(`
5737
5740
  SELECT payload FROM mesh_queue
5738
5741
  WHERE mesh_id = ? AND status = 'pending' AND target_node_id IS NULL AND target_session_id IS NULL
@@ -5762,7 +5765,9 @@ var init_mesh_runtime_store = __esm({
5762
5765
  const convergenceAllows = (candidate) => candidate.taskMode !== "convergence" || !nodeIsWorktree;
5763
5766
  const targetMatches = (candidate) => {
5764
5767
  if (candidate.targetSessionId && candidate.targetSessionId !== sessionId) return false;
5765
- if (candidate.targetNodeId && candidate.targetNodeId !== nodeId) return false;
5768
+ if (candidate.targetNodeId && !daemonIdsEquivalent(candidate.targetNodeId, nodeId) && !meshNodeIdMatches({ id: candidate.targetNodeId }, nodeId)) {
5769
+ return false;
5770
+ }
5766
5771
  return true;
5767
5772
  };
5768
5773
  const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
@@ -10779,7 +10784,7 @@ function deliverTaskToSession(dispatchThunk, ctx, warmup) {
10779
10784
  }
10780
10785
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
10781
10786
  const mesh = getMeshWithCache(components, meshId);
10782
- const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
10787
+ const node = mesh?.nodes.find((n) => meshNodeIdMatches(n, nodeId));
10783
10788
  const gateNode = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
10784
10789
  if (gateNode?.worktreeBootstrap?.status === "running") {
10785
10790
  LOG.info("MeshQueue", `Gating queue claim for worktree node ${nodeId} (${sessionId}): worktree bootstrap still running \u2014 task left pending; claim re-fires once bootstrap reaches a terminal state (guards against dispatching into a half-built worktree \u2192 empty session)`);
@@ -11388,7 +11393,7 @@ async function triggerMeshQueue(components, meshId) {
11388
11393
  const providerType = state.type || readNonEmptyString2(settings.providerType);
11389
11394
  if (providerType) {
11390
11395
  localIdleSessionsChecked += 1;
11391
- localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => readMeshNodeId(n) === nodeId) });
11396
+ localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => meshNodeIdMatches(n, nodeId)) });
11392
11397
  } else {
11393
11398
  skippedSessions.push({
11394
11399
  nodeId,
@@ -14662,6 +14667,18 @@ function injectMeshSystemMessage(components, args) {
14662
14667
  completedTaskForLedger = markSessionTerminal(sessionId, "failed");
14663
14668
  }
14664
14669
  } else if (args.event === "worktree_bootstrap_complete" || args.event === "worktree_bootstrap_failed") {
14670
+ const bootstrapNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
14671
+ if (bootstrapNodeId) {
14672
+ try {
14673
+ components.router?.markWorktreeBootstrapTerminalState?.(
14674
+ args.meshId,
14675
+ bootstrapNodeId,
14676
+ args.event === "worktree_bootstrap_failed" ? "failed" : "complete"
14677
+ );
14678
+ } catch (e) {
14679
+ LOG.warn("MeshQueue", `Failed to stamp terminal bootstrap state for ${bootstrapNodeId} (mesh ${args.meshId}): ${e?.message || e}`);
14680
+ }
14681
+ }
14665
14682
  setImmediate(() => {
14666
14683
  triggerMeshQueue(components, args.meshId).catch((e) => {
14667
14684
  LOG.warn("MeshQueue", `Queue re-fire after ${args.event} failed (mesh ${args.meshId}): ${e?.message || e}`);
@@ -19589,6 +19606,16 @@ var init_provider_cli_adapter = __esm({
19589
19606
  providerSessionId = null;
19590
19607
  responseTimeout = null;
19591
19608
  ready = false;
19609
+ // WIN32-READY-HOLD: the ready barrier can release on screen/spec-FSM grace
19610
+ // before win32 ConPTY's input layer is live. The first split write (text, then a
19611
+ // separate trailing CR via waitForEchoAndSubmit) then has its submit CR swallowed,
19612
+ // and every CR-only retry re-sends a bare CR the input layer keeps dropping — the
19613
+ // first message is typed-but-never-submitted and lost. Routing only the FIRST turn
19614
+ // through the atomic content+sendKey single write (submitImmediatePrompt) keeps the
19615
+ // Enter in the same PTY write unit as the text, the invariant win32 ConPTY needs to
19616
+ // recognize a submit, so the swallow is bypassed. Subsequent turns (input layer now
19617
+ // proven live) keep the normal echo-gated path. Flips true on first committed turn.
19618
+ firstTurnSent = false;
19592
19619
  startupBuffer = "";
19593
19620
  startupParseGate = false;
19594
19621
  startupSettleTimer = null;
@@ -19875,6 +19902,7 @@ ${lastSnapshot}`;
19875
19902
  this.resetTerminalScreen(DEFAULT_SESSION_HOST_ROWS4, DEFAULT_SESSION_HOST_COLS4);
19876
19903
  this.pendingTerminalQueryTail = "";
19877
19904
  this.ready = false;
19905
+ this.firstTurnSent = false;
19878
19906
  await this.ptyProcess.ready;
19879
19907
  this.engine.onSpawnReady();
19880
19908
  this.scheduleStartupSettleCheck();
@@ -20339,6 +20367,7 @@ ${lastSnapshot}`;
20339
20367
  commitSendUserTurn(state) {
20340
20368
  if (state.didCommitUserTurn) return;
20341
20369
  state.didCommitUserTurn = true;
20370
+ this.firstTurnSent = true;
20342
20371
  }
20343
20372
  armResponseTimeout() {
20344
20373
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
@@ -20361,12 +20390,30 @@ ${lastSnapshot}`;
20361
20390
  LOG.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error?.message || error}`);
20362
20391
  });
20363
20392
  }
20393
+ // WIN32-READY-HOLD: choose the retry write for a stuck prompt. When the FIRST turn
20394
+ // is stuck on win32 — the premature-ready swallow window — the prompt text itself
20395
+ // may have been partially eaten by a not-yet-live ConPTY input layer, so re-sending
20396
+ // a bare CR keeps hitting nothing. Re-type the whole `text + sendKey` atomically
20397
+ // once so the input layer (now live) receives a self-contained, submit-coupled
20398
+ // write. All other cases keep the cheap bare-CR retry (the prompt is fully echoed
20399
+ // and only the Enter is missing).
20400
+ writeStuckRetry(state, mode) {
20401
+ const retypeFirstTurn = process.platform === "win32" && state.isFirstTurn;
20402
+ if (retypeFirstTurn) {
20403
+ LOG.info("CLI", `[${this.cliType}] ${mode}: re-typing full prompt atomically (win32 first-turn swallow recovery)`);
20404
+ void this.writeToPty(state.text + this.sendKey).catch((error) => {
20405
+ LOG.warn("CLI", `[${this.cliType}] ${mode} re-type write failed: ${error?.message || error}`);
20406
+ });
20407
+ return;
20408
+ }
20409
+ this.writeSubmitKeyForRetry(mode);
20410
+ }
20364
20411
  retrySubmitIfStuck(state, attempt) {
20365
20412
  this.submitRetryTimer = null;
20366
20413
  if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
20367
20414
  this.engine.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
20368
20415
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
20369
- this.writeSubmitKeyForRetry("submit_retry");
20416
+ this.writeStuckRetry(state, "submit_retry");
20370
20417
  if (attempt >= 3) {
20371
20418
  this.engine.submitRetryUsed = true;
20372
20419
  return;
@@ -20378,7 +20425,7 @@ ${lastSnapshot}`;
20378
20425
  if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
20379
20426
  this.engine.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
20380
20427
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
20381
- this.writeSubmitKeyForRetry("immediate_retry");
20428
+ this.writeStuckRetry(state, "immediate_retry");
20382
20429
  this.engine.submitRetryUsed = true;
20383
20430
  }
20384
20431
  submitSendKey(state, completion) {
@@ -20631,7 +20678,9 @@ ${lastSnapshot}`;
20631
20678
  submitDelayMs,
20632
20679
  maxEchoWaitMs,
20633
20680
  retryDelayMs,
20634
- didCommitUserTurn: false
20681
+ didCommitUserTurn: false,
20682
+ // Capture BEFORE the send commits — commitSendUserTurn flips firstTurnSent.
20683
+ isFirstTurn: !this.firstTurnSent
20635
20684
  };
20636
20685
  this.engine.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
20637
20686
  await new Promise((resolve24, reject) => {
@@ -20649,7 +20698,8 @@ ${lastSnapshot}`;
20649
20698
  reject(error);
20650
20699
  }
20651
20700
  };
20652
- if (this.submitStrategy === "immediate") {
20701
+ const useAtomicFirstTurn = this.submitStrategy === "immediate" || process.platform === "win32" && sendState.isFirstTurn;
20702
+ if (useAtomicFirstTurn) {
20653
20703
  this.submitImmediatePrompt(sendState, completion);
20654
20704
  return;
20655
20705
  }
@@ -52647,6 +52697,64 @@ var DaemonCommandRouter = class {
52647
52697
  this.invalidateAggregateMeshStatus(meshId);
52648
52698
  return true;
52649
52699
  }
52700
+ /**
52701
+ * WORKTREE-BOOTSTRAP-COORD-STATE: mark a worktree node's bootstrap as reaching a
52702
+ * terminal state (complete / failed) in THIS daemon's mesh view.
52703
+ *
52704
+ * Root cause this fixes: clone_mesh_node forwards the clone+bootstrap to the
52705
+ * source node's daemon (the worktree's machine). persistWorktreeSetupState
52706
+ * therefore flips worktreeBootstrap.status to 'complete' on the WORKER daemon's
52707
+ * mesh object — never on the coordinator's. The coordinator only ever holds the
52708
+ * 'running' state it stamped from the forwarded clone reply. The claim path's
52709
+ * bootstrap gate (mesh-event-forwarding agent:ready / mesh-queue-assignment)
52710
+ * reads the coordinator's mesh via getMeshWithCache, sees status==='running'
52711
+ * forever, and DEFERS every claim — so the worktree_bootstrap_complete re-fire
52712
+ * (triggerMeshQueue) loops against a gate that never opens: claim never lands,
52713
+ * the idle session is re-registered each tick, and auto-launch keeps spawning
52714
+ * fresh sessions (runaway worktree-session multiplication).
52715
+ *
52716
+ * Called from the worktree_bootstrap_complete/_failed event handler BEFORE the
52717
+ * queue re-fire so the gate sees the terminal state and the deferred claim can
52718
+ * finally land. Updates the inline cache (clone worktree nodes are inline-only)
52719
+ * and, when the node also exists in local config, persists there too; both paths
52720
+ * invalidate the aggregate status cache. Best-effort and idempotent.
52721
+ */
52722
+ markWorktreeBootstrapTerminalState(meshId, nodeId, status) {
52723
+ if (!meshId || !nodeId) return;
52724
+ const stamp = (mesh) => {
52725
+ if (!mesh || !Array.isArray(mesh.nodes)) return false;
52726
+ const node = mesh.nodes.find((entry) => meshNodeIdMatches(entry, nodeId));
52727
+ if (!node) return false;
52728
+ const prev = node.worktreeBootstrap && typeof node.worktreeBootstrap === "object" ? node.worktreeBootstrap : {};
52729
+ if (prev.status === status) return false;
52730
+ node.worktreeBootstrap = {
52731
+ ...prev,
52732
+ status,
52733
+ completedAt: prev.completedAt ?? (/* @__PURE__ */ new Date()).toISOString()
52734
+ };
52735
+ return true;
52736
+ };
52737
+ let changed = false;
52738
+ try {
52739
+ const cached3 = this.getCachedInlineMesh(meshId);
52740
+ if (cached3 && stamp(cached3)) {
52741
+ cached3.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
52742
+ this.inlineMeshCache.set(meshId, cached3);
52743
+ changed = true;
52744
+ }
52745
+ } catch {
52746
+ }
52747
+ if (changed) this.invalidateAggregateMeshStatus(meshId);
52748
+ void Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports)).then(({ getMesh: getMesh2, updateNode: updateNode2 }) => {
52749
+ const local = getMesh2(meshId);
52750
+ if (local && stamp(local)) {
52751
+ const node = local.nodes.find((entry) => meshNodeIdMatches(entry, nodeId));
52752
+ if (node) updateNode2(meshId, node.id, { worktreeBootstrap: node.worktreeBootstrap });
52753
+ this.invalidateAggregateMeshStatus(meshId);
52754
+ }
52755
+ }).catch(() => {
52756
+ });
52757
+ }
52650
52758
  tombstoneRemovedInlineMeshNode(meshId, nodeId) {
52651
52759
  if (!nodeId) return;
52652
52760
  let set = this.removedInlineMeshNodeIds.get(meshId);
@@ -54030,7 +54138,14 @@ ${hintLines.join("\n")}` : "",
54030
54138
  nodeId,
54031
54139
  sessionCleanupMode: refineSessionCleanupMode,
54032
54140
  ...refineSessionIds && refineSessionIds.length > 0 ? { sessionIds: refineSessionIds } : {},
54033
- inlineMesh: args?.inlineMesh
54141
+ inlineMesh: args?.inlineMesh,
54142
+ // REFINE-CLEANUP: refine reaches cleanup only AFTER a verified merge
54143
+ // convergence, so any residual worktree dirtiness here is incidental
54144
+ // (e.g. a bootstrap lockfile rewrite) — never unmerged work. `force`
54145
+ // sets requireClean=false so a plain-dirty worktree no longer aborts
54146
+ // removal with merged_cleanup_failed. Branch-ref deletion still keys off
54147
+ // mergeConvergence (NOT the force flag), so no merged work can be lost.
54148
+ force: true
54034
54149
  });
54035
54150
  recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
54036
54151
  removed: removeResult?.removed,