@adhdev/daemon-core 0.9.82-rc.421 → 0.9.82-rc.422

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
@@ -384,10 +384,10 @@ function readInjected(value) {
384
384
  }
385
385
  function getDaemonBuildInfo() {
386
386
  if (cached) return cached;
387
- const commit = readInjected(true ? "ae90493419784d563faac61e6caab2a6f05e0719" : void 0) ?? "unknown";
388
- const commitShort = readInjected(true ? "ae904934" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
389
- const version = readInjected(true ? "0.9.82-rc.421" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
390
- const builtAt = readInjected(true ? "2026-06-29T03:34:21.633Z" : void 0);
387
+ const commit = readInjected(true ? "308e099c65d2de2491f3db46913f9ced6aa3992c" : void 0) ?? "unknown";
388
+ const commitShort = readInjected(true ? "308e099c" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
389
+ const version = readInjected(true ? "0.9.82-rc.422" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
390
+ const builtAt = readInjected(true ? "2026-06-29T05:26:31.350Z" : void 0);
391
391
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
392
392
  return cached;
393
393
  }
@@ -3680,21 +3680,6 @@ var init_async_batch_writer = __esm({
3680
3680
  });
3681
3681
 
3682
3682
  // src/logging/logger.ts
3683
- var logger_exports = {};
3684
- __export(logger_exports, {
3685
- LOG: () => LOG,
3686
- LOG_DIR_PATH: () => LOG_DIR_PATH,
3687
- LOG_PATH: () => LOG_PATH,
3688
- daemonLog: () => daemonLog,
3689
- getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
3690
- getDaemonLogDir: () => getDaemonLogDir,
3691
- getLogBufferSize: () => getLogBufferSize,
3692
- getLogLevel: () => getLogLevel,
3693
- getLogPath: () => getLogPath,
3694
- getRecentLogs: () => getRecentLogs,
3695
- installGlobalInterceptor: () => installGlobalInterceptor,
3696
- setLogLevel: () => setLogLevel
3697
- });
3698
3683
  import * as fs4 from "fs";
3699
3684
  import * as path9 from "path";
3700
3685
  import * as os3 from "os";
@@ -3769,9 +3754,6 @@ function getRecentLogs(count = 50, minLevel = "info") {
3769
3754
  const filtered = ringBuffer.filter((e) => LEVEL_NUM[e.level] >= minNum);
3770
3755
  return filtered.slice(-count);
3771
3756
  }
3772
- function getLogBufferSize() {
3773
- return ringBuffer.length;
3774
- }
3775
3757
  function ts() {
3776
3758
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
3777
3759
  }
@@ -3851,10 +3833,7 @@ function installGlobalInterceptor() {
3851
3833
  writeToFile(`Log file: ${currentLogFile}`);
3852
3834
  writeToFile(`Log level: ${currentLevel}`);
3853
3835
  }
3854
- function getLogPath() {
3855
- return currentLogFile;
3856
- }
3857
- var LEVEL_NUM, LEVEL_LABEL, currentLevel, ADHDEV_HOME, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
3836
+ var LEVEL_NUM, LEVEL_LABEL, currentLevel, ADHDEV_HOME, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
3858
3837
  var init_logger = __esm({
3859
3838
  "src/logging/logger.ts"() {
3860
3839
  "use strict";
@@ -3913,7 +3892,6 @@ var init_logger = __esm({
3913
3892
  };
3914
3893
  interceptorInstalled = false;
3915
3894
  LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
3916
- LOG_DIR_PATH = LOG_DIR;
3917
3895
  }
3918
3896
  });
3919
3897
 
@@ -12524,6 +12502,23 @@ function liveSessionCountForNode(components, meshId, nodeId) {
12524
12502
  return !isTerminalSessionStatus(status);
12525
12503
  }).length;
12526
12504
  }
12505
+ function nodeHasLiveSessionPendingClaim(components, meshId, nodeId) {
12506
+ const busySessionIds = new Set(
12507
+ getQueue(meshId, { status: ["assigned"] }).filter((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId)).map((task) => readNonEmptyString2(task.assignedSessionId)).filter(Boolean)
12508
+ );
12509
+ return components.instanceManager.getByCategory("cli").some((inst) => {
12510
+ const state = inst.getState();
12511
+ const settings = state.settings || {};
12512
+ if (readNonEmptyString2(settings.meshNodeFor) !== meshId) return false;
12513
+ const instNodeId = readNonEmptyString2(settings.meshNodeId) || readNonEmptyString2(settings.nodeId);
12514
+ if (!daemonIdsEquivalent(instNodeId, nodeId)) return false;
12515
+ const status = readNonEmptyString2(state.status).toLowerCase();
12516
+ if (isTerminalSessionStatus(status)) return false;
12517
+ const sessionId = readNonEmptyString2(state.instanceId);
12518
+ if (sessionId && busySessionIds.has(sessionId)) return false;
12519
+ return true;
12520
+ });
12521
+ }
12527
12522
  function recordAutoLaunchEvent(meshId, args) {
12528
12523
  const dedupKey = `${meshId}:${args.taskId}`;
12529
12524
  const currentSig = `${args.phase}|${args.reason || ""}`;
@@ -12709,6 +12704,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12709
12704
  sweepExpiredCooldowns();
12710
12705
  continue;
12711
12706
  }
12707
+ if (nodeHasLiveSessionPendingClaim(components, meshId, nodeId)) {
12708
+ markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_live_session_pending_claim", nodeId });
12709
+ continue;
12710
+ }
12712
12711
  if (!isTaskReadonly(task) && nodeHasActiveAssignment(meshId, nodeId)) {
12713
12712
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_active_assignment", nodeId });
12714
12713
  continue;
@@ -44595,8 +44594,9 @@ Run 'adhdev doctor' for detailed diagnostics.`
44595
44594
  const meshContext = args?.meshContext;
44596
44595
  if (meshContext && typeof meshContext === "object" && typeof meshContext.meshId === "string" && meshContext.meshId) {
44597
44596
  const targetInstanceId = key2;
44597
+ let stampResult;
44598
44598
  try {
44599
- this.deps.getInstanceManager()?.attachMeshAssignmentToInstance(targetInstanceId, {
44599
+ stampResult = this.deps.getInstanceManager()?.attachMeshAssignmentToInstance(targetInstanceId, {
44600
44600
  meshId: meshContext.meshId,
44601
44601
  ...typeof meshContext.nodeId === "string" && meshContext.nodeId ? { nodeId: meshContext.nodeId } : {},
44602
44602
  ...typeof meshContext.taskId === "string" && meshContext.taskId ? { taskId: meshContext.taskId } : {},
@@ -44604,6 +44604,9 @@ Run 'adhdev doctor' for detailed diagnostics.`
44604
44604
  });
44605
44605
  } catch {
44606
44606
  }
44607
+ if (stampResult && stampResult.stamped === false && stampResult.reason === "task_already_stamped_on_live_instance") {
44608
+ throw new Error(`Refusing duplicate mesh dispatch: task ${meshContext.taskId} is already being worked by a live session on this daemon`);
44609
+ }
44607
44610
  }
44608
44611
  const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
44609
44612
  const provider = this.providerLoader.resolve(agentType) || this.providerLoader.getMeta(agentType);
@@ -58211,25 +58214,54 @@ var ProviderInstanceManager = class {
58211
58214
  }
58212
58215
  /** Stamp a mesh assignment on a single instance (used by mesh_send_task
58213
58216
  * --direct so the worker's completion event has a coordinator routing
58214
- * marker in state.settings). Returns true if the instance existed and
58215
- * the stamp was applied. */
58217
+ * marker in state.settings). Returns `{ stamped: true }` when the stamp was
58218
+ * applied, or `{ stamped: false, reason }` when it was refused — the instance
58219
+ * was missing / has no attach method, or the DOUBLE-DISPATCH idempotence guard
58220
+ * fired (the same task is already running on another live session here). */
58216
58221
  attachMeshAssignmentToInstance(instanceId, assignment) {
58217
58222
  const inst = this.instances.get(instanceId);
58218
58223
  if (!inst || typeof inst.attachMeshAssignment !== "function") {
58219
- try {
58220
- const { LOG: LOG2 } = (init_logger(), __toCommonJS(logger_exports));
58221
- LOG2.warn?.("MeshDispatch", `attachMeshAssignment skipped: instance ${instanceId} ${inst ? "has no attach method" : "not found"}`);
58222
- } catch {
58224
+ LOG.warn("MeshDispatch", `attachMeshAssignment skipped: instance ${instanceId} ${inst ? "has no attach method" : "not found"}`);
58225
+ return { stamped: false, reason: inst ? "instance_has_no_attach_method" : "instance_not_found" };
58226
+ }
58227
+ if (assignment.taskId) {
58228
+ const conflict = this.findLiveWorkingTaskHolder(assignment.meshId, assignment.taskId, instanceId);
58229
+ if (conflict) {
58230
+ LOG.warn("MeshDispatch", `attachMeshAssignment refused: task ${assignment.taskId} (mesh ${assignment.meshId}) is already being worked by live session ${conflict} \u2014 skipping duplicate stamp on ${instanceId}`);
58231
+ return { stamped: false, reason: "task_already_stamped_on_live_instance" };
58223
58232
  }
58224
- return false;
58225
58233
  }
58226
58234
  inst.attachMeshAssignment(assignment);
58227
- try {
58228
- const { LOG: LOG2 } = (init_logger(), __toCommonJS(logger_exports));
58229
- LOG2.info?.("MeshDispatch", `stamped mesh assignment on ${instanceId}: mesh=${assignment.meshId} node=${assignment.nodeId || ""} task=${assignment.taskId || ""} coordinator=${assignment.coordinatorDaemonId || ""}`);
58230
- } catch {
58235
+ LOG.info("MeshDispatch", `stamped mesh assignment on ${instanceId}: mesh=${assignment.meshId} node=${assignment.nodeId || ""} task=${assignment.taskId || ""} coordinator=${assignment.coordinatorDaemonId || ""}`);
58236
+ return { stamped: true };
58237
+ }
58238
+ /**
58239
+ * DOUBLE-DISPATCH support: the id of another LIVE, actively-working instance that already
58240
+ * holds (meshId, taskId), or null. "Live working" = stamped with this exact mesh+task AND
58241
+ * currently mid-turn / booting toward it (generating / waiting on approval-or-choice /
58242
+ * starting) — NOT idle, stopped, or errored. A stale/dead/idle holder is deliberately
58243
+ * ignored so a legitimate re-dispatch (e.g. after a dispatch failure) is never blocked.
58244
+ * The instance being stamped (excludeInstanceId) is skipped so re-stamping the same
58245
+ * session stays idempotent. O(n) over instances — the count is small.
58246
+ */
58247
+ findLiveWorkingTaskHolder(meshId, taskId, excludeInstanceId) {
58248
+ const working = /* @__PURE__ */ new Set(["generating", "waiting_approval", "waiting_choice", "starting", "streaming", "working", "no_progress", "long_generating"]);
58249
+ for (const [id, inst] of this.instances) {
58250
+ if (id === excludeInstanceId) continue;
58251
+ let state;
58252
+ try {
58253
+ state = inst.getState();
58254
+ } catch {
58255
+ continue;
58256
+ }
58257
+ const settings = state.settings || {};
58258
+ if (settings.meshNodeFor !== meshId) continue;
58259
+ if (settings.meshActiveTaskId !== taskId) continue;
58260
+ const status = (typeof state.status === "string" ? state.status : "").toLowerCase();
58261
+ const chatStatus = (typeof state.activeChat?.status === "string" ? state.activeChat.status : "").toLowerCase();
58262
+ if (working.has(status) || working.has(chatStatus)) return id;
58231
58263
  }
58232
- return true;
58264
+ return null;
58233
58265
  }
58234
58266
  /** Clear a mesh assignment after the dispatched task reaches a terminal
58235
58267
  * state (generating_completed / stopped / failed). */