@adhdev/daemon-core 0.9.82-rc.395 → 0.9.82-rc.397

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.
@@ -39,6 +39,7 @@ export declare class ProviderCliAdapter implements CliAdapter {
39
39
  private providerSessionId;
40
40
  private responseTimeout;
41
41
  private ready;
42
+ private firstTurnSent;
42
43
  private startupBuffer;
43
44
  private startupParseGate;
44
45
  private startupSettleTimer;
@@ -178,6 +179,7 @@ export declare class ProviderCliAdapter implements CliAdapter {
178
179
  private commitSendUserTurn;
179
180
  private armResponseTimeout;
180
181
  private writeSubmitKeyForRetry;
182
+ private writeStuckRetry;
181
183
  private retrySubmitIfStuck;
182
184
  private retryImmediateSubmitIfStuck;
183
185
  private submitSendKey;
package/dist/index.js CHANGED
@@ -383,10 +383,10 @@ function readInjected(value) {
383
383
  }
384
384
  function getDaemonBuildInfo() {
385
385
  if (cached) return cached;
386
- const commit = readInjected(true ? "dea560a6fcafcb5579e0a62e3a2461d6af9aa289" : void 0) ?? "unknown";
387
- const commitShort = readInjected(true ? "dea560a6" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
388
- const version = readInjected(true ? "0.9.82-rc.395" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
389
- const builtAt = readInjected(true ? "2026-06-27T06:46:26.696Z" : void 0);
386
+ const commit = readInjected(true ? "5e6a6bcc5ba51a08f3941445f431cb0411217547" : void 0) ?? "unknown";
387
+ const commitShort = readInjected(true ? "5e6a6bcc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
388
+ const version = readInjected(true ? "0.9.82-rc.397" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
389
+ const builtAt = readInjected(true ? "2026-06-27T08:32:58.380Z" : void 0);
390
390
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
391
391
  return cached;
392
392
  }
@@ -5197,6 +5197,7 @@ var init_mesh_runtime_store = __esm({
5197
5197
  init_load_better_sqlite3();
5198
5198
  init_mesh_ledger();
5199
5199
  init_mesh_work_queue();
5200
+ init_dist();
5200
5201
  loggedMigrationFailure = false;
5201
5202
  MeshRuntimeStore = class _MeshRuntimeStore {
5202
5203
  static instance;
@@ -5729,6 +5730,8 @@ var init_mesh_runtime_store = __esm({
5729
5730
  if (providerType && typeof providerMaxParallel === "number" && Number.isFinite(providerMaxParallel) && providerMaxParallel >= 0 && this.activeProviderAssignmentCount(meshId, nodeId, providerType) >= providerMaxParallel) {
5730
5731
  return null;
5731
5732
  }
5733
+ const nodeIdForms = expandDaemonIdForms(nodeId);
5734
+ const nodePinnedPlaceholders = nodeIdForms.map(() => "?").join(", ");
5732
5735
  const rows = [
5733
5736
  ...this.db.prepare(`
5734
5737
  SELECT payload FROM mesh_queue
@@ -5737,9 +5740,9 @@ var init_mesh_runtime_store = __esm({
5737
5740
  `).all(meshId, sessionId),
5738
5741
  ...this.db.prepare(`
5739
5742
  SELECT payload FROM mesh_queue
5740
- WHERE mesh_id = ? AND status = 'pending' AND target_node_id = ? AND target_session_id IS NULL
5743
+ WHERE mesh_id = ? AND status = 'pending' AND target_node_id IN (${nodePinnedPlaceholders}) AND target_session_id IS NULL
5741
5744
  ORDER BY created_at ASC
5742
- `).all(meshId, nodeId),
5745
+ `).all(meshId, ...nodeIdForms),
5743
5746
  ...this.db.prepare(`
5744
5747
  SELECT payload FROM mesh_queue
5745
5748
  WHERE mesh_id = ? AND status = 'pending' AND target_node_id IS NULL AND target_session_id IS NULL
@@ -5769,7 +5772,9 @@ var init_mesh_runtime_store = __esm({
5769
5772
  const convergenceAllows = (candidate) => candidate.taskMode !== "convergence" || !nodeIsWorktree;
5770
5773
  const targetMatches = (candidate) => {
5771
5774
  if (candidate.targetSessionId && candidate.targetSessionId !== sessionId) return false;
5772
- if (candidate.targetNodeId && candidate.targetNodeId !== nodeId) return false;
5775
+ if (candidate.targetNodeId && !daemonIdsEquivalent(candidate.targetNodeId, nodeId) && !meshNodeIdMatches({ id: candidate.targetNodeId }, nodeId)) {
5776
+ return false;
5777
+ }
5773
5778
  return true;
5774
5779
  };
5775
5780
  const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
@@ -9866,27 +9871,32 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
9866
9871
  updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
9867
9872
  markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
9868
9873
  setImmediate(() => cleanupTerminalDirectDispatches());
9874
+ const eventName = kind === "task_completed" ? "agent:generating_completed" : "agent:stopped";
9875
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : "Remote agent";
9876
+ const metadataEvent = {
9877
+ targetSessionId: args.sessionId,
9878
+ providerType: providerType || void 0,
9879
+ providerSessionId: readNonEmptyString2(args.providerSessionId),
9880
+ finalSummary,
9881
+ taskId: args.taskId,
9882
+ workerResult,
9883
+ completionDiagnostic: {
9884
+ reason: "direct_task_transcript_reconciliation",
9885
+ terminalLedgerKind: kind,
9886
+ terminalLedgerId: entry.id
9887
+ }
9888
+ };
9889
+ const targetCoordinatorSessionId = readNonEmptyString2(args.targetCoordinatorSessionId) || readNonEmptyString2(dispatch?.payload?.coordinatorSessionId);
9869
9890
  queuePendingMeshCoordinatorEvent({
9870
- event: kind === "task_completed" ? "agent:generating_completed" : "agent:stopped",
9891
+ event: eventName,
9871
9892
  meshId: args.meshId,
9872
- nodeLabel: nodeId ? `Node '${nodeId}'` : "Remote agent",
9893
+ nodeLabel,
9873
9894
  nodeId: nodeId || void 0,
9874
- metadataEvent: {
9875
- targetSessionId: args.sessionId,
9876
- providerType: providerType || void 0,
9877
- providerSessionId: readNonEmptyString2(args.providerSessionId),
9878
- finalSummary,
9879
- taskId: args.taskId,
9880
- workerResult,
9881
- completionDiagnostic: {
9882
- reason: "direct_task_transcript_reconciliation",
9883
- terminalLedgerKind: kind,
9884
- terminalLedgerId: entry.id
9885
- }
9886
- },
9887
- coordinatorMessage: void 0,
9895
+ metadataEvent,
9896
+ coordinatorMessage: buildMeshSystemMessage({ event: eventName, nodeLabel, metadataEvent }),
9888
9897
  queuedAt: Date.now(),
9889
- ...readNonEmptyString2(args.targetCoordinatorDaemonId) ? { targetCoordinatorDaemonId: readNonEmptyString2(args.targetCoordinatorDaemonId) } : {}
9898
+ ...readNonEmptyString2(args.targetCoordinatorDaemonId) ? { targetCoordinatorDaemonId: readNonEmptyString2(args.targetCoordinatorDaemonId) } : {},
9899
+ ...targetCoordinatorSessionId ? { targetCoordinatorSessionId } : {}
9890
9900
  });
9891
9901
  return { reconciled: true, kind, workerResult, ledgerEntryId: entry.id };
9892
9902
  }
@@ -10778,7 +10788,7 @@ function deliverTaskToSession(dispatchThunk, ctx, warmup) {
10778
10788
  }
10779
10789
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
10780
10790
  const mesh = getMeshWithCache(components, meshId);
10781
- const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
10791
+ const node = mesh?.nodes.find((n) => meshNodeIdMatches(n, nodeId));
10782
10792
  const gateNode = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
10783
10793
  if (gateNode?.worktreeBootstrap?.status === "running") {
10784
10794
  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)`);
@@ -11387,7 +11397,7 @@ async function triggerMeshQueue(components, meshId) {
11387
11397
  const providerType = state.type || readNonEmptyString2(settings.providerType);
11388
11398
  if (providerType) {
11389
11399
  localIdleSessionsChecked += 1;
11390
- localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => readMeshNodeId(n) === nodeId) });
11400
+ localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => meshNodeIdMatches(n, nodeId)) });
11391
11401
  } else {
11392
11402
  skippedSessions.push({
11393
11403
  nodeId,
@@ -15222,7 +15232,19 @@ function shouldHoldPendingDrainForBusyLocalCoordinator(components, meshId, reque
15222
15232
  return localIds.some((id) => daemonIdsEquivalent(id, requested));
15223
15233
  }
15224
15234
  function injectPendingIntoCoordinator(coordinator, pending) {
15225
- if (!coordinator || !pending.coordinatorMessage) return;
15235
+ if (!coordinator) return;
15236
+ let coordinatorMessage = pending.coordinatorMessage;
15237
+ if (!coordinatorMessage) {
15238
+ if (!shouldForceInjectMeshEvent(pending.event)) return;
15239
+ const metadataEvent = pending.metadataEvent && typeof pending.metadataEvent === "object" ? pending.metadataEvent : {};
15240
+ coordinatorMessage = buildMeshSystemMessage({
15241
+ event: pending.event,
15242
+ nodeLabel: pending.nodeLabel,
15243
+ metadataEvent
15244
+ });
15245
+ if (!coordinatorMessage) return;
15246
+ LOG.warn("MeshReconcile", `Lazily synthesized missing coordinatorMessage for ${pending.event} (mesh ${pending.meshId}) at inject time \u2014 a queued terminal event arrived message-less`);
15247
+ }
15226
15248
  const force = shouldForceInjectMeshEvent(pending.event);
15227
15249
  traceMeshEventStage("surfaced", {
15228
15250
  taskId: pending.metadataEvent?.taskId,
@@ -15232,7 +15254,7 @@ function injectPendingIntoCoordinator(coordinator, pending) {
15232
15254
  event: pending.event
15233
15255
  }, force ? "force-inject" : "inject");
15234
15256
  coordinator.onEvent("send_message", {
15235
- input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
15257
+ input: { text: coordinatorMessage, textFallback: coordinatorMessage },
15236
15258
  ...force ? { force: true } : {}
15237
15259
  });
15238
15260
  }
@@ -19579,6 +19601,16 @@ var init_provider_cli_adapter = __esm({
19579
19601
  providerSessionId = null;
19580
19602
  responseTimeout = null;
19581
19603
  ready = false;
19604
+ // WIN32-READY-HOLD: the ready barrier can release on screen/spec-FSM grace
19605
+ // before win32 ConPTY's input layer is live. The first split write (text, then a
19606
+ // separate trailing CR via waitForEchoAndSubmit) then has its submit CR swallowed,
19607
+ // and every CR-only retry re-sends a bare CR the input layer keeps dropping — the
19608
+ // first message is typed-but-never-submitted and lost. Routing only the FIRST turn
19609
+ // through the atomic content+sendKey single write (submitImmediatePrompt) keeps the
19610
+ // Enter in the same PTY write unit as the text, the invariant win32 ConPTY needs to
19611
+ // recognize a submit, so the swallow is bypassed. Subsequent turns (input layer now
19612
+ // proven live) keep the normal echo-gated path. Flips true on first committed turn.
19613
+ firstTurnSent = false;
19582
19614
  startupBuffer = "";
19583
19615
  startupParseGate = false;
19584
19616
  startupSettleTimer = null;
@@ -19865,6 +19897,7 @@ ${lastSnapshot}`;
19865
19897
  this.resetTerminalScreen(import_session_host_core5.DEFAULT_SESSION_HOST_ROWS, import_session_host_core5.DEFAULT_SESSION_HOST_COLS);
19866
19898
  this.pendingTerminalQueryTail = "";
19867
19899
  this.ready = false;
19900
+ this.firstTurnSent = false;
19868
19901
  await this.ptyProcess.ready;
19869
19902
  this.engine.onSpawnReady();
19870
19903
  this.scheduleStartupSettleCheck();
@@ -20329,6 +20362,7 @@ ${lastSnapshot}`;
20329
20362
  commitSendUserTurn(state) {
20330
20363
  if (state.didCommitUserTurn) return;
20331
20364
  state.didCommitUserTurn = true;
20365
+ this.firstTurnSent = true;
20332
20366
  }
20333
20367
  armResponseTimeout() {
20334
20368
  if (this.responseTimeout) clearTimeout(this.responseTimeout);
@@ -20351,12 +20385,30 @@ ${lastSnapshot}`;
20351
20385
  LOG.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error?.message || error}`);
20352
20386
  });
20353
20387
  }
20388
+ // WIN32-READY-HOLD: choose the retry write for a stuck prompt. When the FIRST turn
20389
+ // is stuck on win32 — the premature-ready swallow window — the prompt text itself
20390
+ // may have been partially eaten by a not-yet-live ConPTY input layer, so re-sending
20391
+ // a bare CR keeps hitting nothing. Re-type the whole `text + sendKey` atomically
20392
+ // once so the input layer (now live) receives a self-contained, submit-coupled
20393
+ // write. All other cases keep the cheap bare-CR retry (the prompt is fully echoed
20394
+ // and only the Enter is missing).
20395
+ writeStuckRetry(state, mode) {
20396
+ const retypeFirstTurn = process.platform === "win32" && state.isFirstTurn;
20397
+ if (retypeFirstTurn) {
20398
+ LOG.info("CLI", `[${this.cliType}] ${mode}: re-typing full prompt atomically (win32 first-turn swallow recovery)`);
20399
+ void this.writeToPty(state.text + this.sendKey).catch((error) => {
20400
+ LOG.warn("CLI", `[${this.cliType}] ${mode} re-type write failed: ${error?.message || error}`);
20401
+ });
20402
+ return;
20403
+ }
20404
+ this.writeSubmitKeyForRetry(mode);
20405
+ }
20354
20406
  retrySubmitIfStuck(state, attempt) {
20355
20407
  this.submitRetryTimer = null;
20356
20408
  if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
20357
20409
  this.engine.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
20358
20410
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
20359
- this.writeSubmitKeyForRetry("submit_retry");
20411
+ this.writeStuckRetry(state, "submit_retry");
20360
20412
  if (attempt >= 3) {
20361
20413
  this.engine.submitRetryUsed = true;
20362
20414
  return;
@@ -20368,7 +20420,7 @@ ${lastSnapshot}`;
20368
20420
  if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
20369
20421
  this.engine.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
20370
20422
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
20371
- this.writeSubmitKeyForRetry("immediate_retry");
20423
+ this.writeStuckRetry(state, "immediate_retry");
20372
20424
  this.engine.submitRetryUsed = true;
20373
20425
  }
20374
20426
  submitSendKey(state, completion) {
@@ -20621,7 +20673,9 @@ ${lastSnapshot}`;
20621
20673
  submitDelayMs,
20622
20674
  maxEchoWaitMs,
20623
20675
  retryDelayMs,
20624
- didCommitUserTurn: false
20676
+ didCommitUserTurn: false,
20677
+ // Capture BEFORE the send commits — commitSendUserTurn flips firstTurnSent.
20678
+ isFirstTurn: !this.firstTurnSent
20625
20679
  };
20626
20680
  this.engine.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
20627
20681
  await new Promise((resolve24, reject) => {
@@ -20639,7 +20693,8 @@ ${lastSnapshot}`;
20639
20693
  reject(error);
20640
20694
  }
20641
20695
  };
20642
- if (this.submitStrategy === "immediate") {
20696
+ const useAtomicFirstTurn = this.submitStrategy === "immediate" || process.platform === "win32" && sendState.isFirstTurn;
20697
+ if (useAtomicFirstTurn) {
20643
20698
  this.submitImmediatePrompt(sendState, completion);
20644
20699
  return;
20645
20700
  }
@@ -54389,7 +54444,14 @@ ${hintLines.join("\n")}` : "",
54389
54444
  nodeId,
54390
54445
  sessionCleanupMode: refineSessionCleanupMode,
54391
54446
  ...refineSessionIds && refineSessionIds.length > 0 ? { sessionIds: refineSessionIds } : {},
54392
- inlineMesh: args?.inlineMesh
54447
+ inlineMesh: args?.inlineMesh,
54448
+ // REFINE-CLEANUP: refine reaches cleanup only AFTER a verified merge
54449
+ // convergence, so any residual worktree dirtiness here is incidental
54450
+ // (e.g. a bootstrap lockfile rewrite) — never unmerged work. `force`
54451
+ // sets requireClean=false so a plain-dirty worktree no longer aborts
54452
+ // removal with merged_cleanup_failed. Branch-ref deletion still keys off
54453
+ // mergeConvergence (NOT the force flag), so no merged work can be lost.
54454
+ force: true
54393
54455
  });
54394
54456
  recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
54395
54457
  removed: removeResult?.removed,