@adhdev/daemon-core 0.9.82-rc.274 → 0.9.82-rc.275

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
@@ -275,10 +275,10 @@ function readInjected(value) {
275
275
  }
276
276
  function getDaemonBuildInfo() {
277
277
  if (cached) return cached;
278
- const commit = readInjected(true ? "89d1ac61612c1dfe7fac53be61ec5dbfa67d00b2" : void 0) ?? "unknown";
279
- const commitShort = readInjected(true ? "89d1ac61" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
280
- const version = readInjected(true ? "0.9.82-rc.274" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
281
- const builtAt = readInjected(true ? "2026-06-15T07:04:52.710Z" : void 0);
278
+ const commit = readInjected(true ? "080b607ef221e44126942d9d52eaf547b4e92550" : void 0) ?? "unknown";
279
+ const commitShort = readInjected(true ? "080b607e" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
280
+ const version = readInjected(true ? "0.9.82-rc.275" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
281
+ const builtAt = readInjected(true ? "2026-06-15T08:24:26.468Z" : void 0);
282
282
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
283
283
  return cached;
284
284
  }
@@ -4264,12 +4264,33 @@ var init_mesh_runtime_store = __esm({
4264
4264
  this.maybeCheckpointWal();
4265
4265
  return result.changes > 0;
4266
4266
  }
4267
- drainPendingEvents(meshId, coordinatorDaemonId) {
4267
+ /**
4268
+ * Drain undrained pending events for a mesh, atomically marking them drained.
4269
+ * When `opts.onlyEvents` is supplied, ONLY rows whose `event` is in that set are
4270
+ * drained — the rest stay queued (drained=0) for a later drain. This is how the
4271
+ * reconcile loop force-drains terminal/force-inject events into a *generating*
4272
+ * coordinator while leaving non-force progress events for the coordinator's next
4273
+ * idle transition. Filtering happens inside the same transaction as the
4274
+ * drained=1 marking, so force-drain + a concurrent full drain can never both
4275
+ * consume the same row.
4276
+ */
4277
+ drainPendingEvents(meshId, coordinatorDaemonId, opts) {
4268
4278
  return this.transaction(() => {
4269
- const whereClause = coordinatorDaemonId ? `WHERE mesh_id = ? AND drained = 0 AND (coordinator_daemon_id IS NULL OR coordinator_daemon_id = ?)` : `WHERE mesh_id = ? AND drained = 0`;
4270
- const params = coordinatorDaemonId ? [meshId, coordinatorDaemonId] : [meshId];
4279
+ const onlyEvents = opts?.onlyEvents;
4280
+ if (onlyEvents && onlyEvents.size === 0) return [];
4281
+ const eventList = onlyEvents ? [...onlyEvents] : [];
4282
+ const clauses = ["mesh_id = ?", "drained = 0"];
4283
+ const params = [meshId];
4284
+ if (coordinatorDaemonId) {
4285
+ clauses.push("(coordinator_daemon_id IS NULL OR coordinator_daemon_id = ?)");
4286
+ params.push(coordinatorDaemonId);
4287
+ }
4288
+ if (eventList.length > 0) {
4289
+ clauses.push(`event IN (${eventList.map(() => "?").join(",")})`);
4290
+ params.push(...eventList);
4291
+ }
4271
4292
  const rows = this.db.prepare(
4272
- `SELECT id, event, payload FROM mesh_pending_events ${whereClause} ORDER BY queued_at ASC LIMIT 100`
4293
+ `SELECT id, event, payload FROM mesh_pending_events WHERE ${clauses.join(" AND ")} ORDER BY queued_at ASC LIMIT 100`
4273
4294
  ).all(...params);
4274
4295
  if (rows.length === 0) return [];
4275
4296
  const ids = rows.map((r) => r.id);
@@ -6529,8 +6550,57 @@ function atomicDrainFile(path39) {
6529
6550
  return null;
6530
6551
  }
6531
6552
  }
6532
- function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
6553
+ function selectiveDrainFile(path39, predicate) {
6554
+ const tmpPath = `${path39}.draining`;
6555
+ try {
6556
+ (0, import_fs8.renameSync)(path39, tmpPath);
6557
+ } catch {
6558
+ return [];
6559
+ }
6560
+ let content;
6561
+ try {
6562
+ content = (0, import_fs8.readFileSync)(tmpPath, "utf-8");
6563
+ } catch {
6564
+ try {
6565
+ (0, import_fs8.unlinkSync)(tmpPath);
6566
+ } catch {
6567
+ }
6568
+ return [];
6569
+ }
6570
+ const consumed = [];
6571
+ const keptLines = [];
6572
+ for (const line of content.split("\n")) {
6573
+ if (!line) continue;
6574
+ let parsed;
6575
+ try {
6576
+ parsed = JSON.parse(line);
6577
+ } catch {
6578
+ parsed = void 0;
6579
+ }
6580
+ if (parsed && predicate(parsed)) {
6581
+ consumed.push(parsed);
6582
+ } else {
6583
+ keptLines.push(line);
6584
+ }
6585
+ }
6586
+ try {
6587
+ if (keptLines.length > 0) {
6588
+ (0, import_fs8.writeFileSync)(path39, keptLines.join("\n") + "\n", "utf-8");
6589
+ }
6590
+ (0, import_fs8.unlinkSync)(tmpPath);
6591
+ } catch {
6592
+ try {
6593
+ if ((0, import_fs8.existsSync)(tmpPath) && !(0, import_fs8.existsSync)(path39)) (0, import_fs8.renameSync)(tmpPath, path39);
6594
+ } catch {
6595
+ }
6596
+ return [];
6597
+ }
6598
+ return consumed;
6599
+ }
6600
+ function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId, opts) {
6533
6601
  if (!meshId) return [];
6602
+ const onlyEvents = opts?.onlyEvents;
6603
+ const matchesFilter = (eventName) => !onlyEvents || onlyEvents.has(eventName);
6534
6604
  const merged = [];
6535
6605
  const seenFingerprints = /* @__PURE__ */ new Set();
6536
6606
  const pushUnique = (event) => {
@@ -6544,7 +6614,7 @@ function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
6544
6614
  try {
6545
6615
  const store = MeshRuntimeStore.getInstance();
6546
6616
  if (store.pendingEventCount(meshId) > 0) {
6547
- for (const row of store.drainPendingEvents(meshId, coordinatorDaemonId)) {
6617
+ for (const row of store.drainPendingEvents(meshId, coordinatorDaemonId, onlyEvents ? { onlyEvents } : void 0)) {
6548
6618
  const event = row.payload;
6549
6619
  if (event) pushUnique(event);
6550
6620
  }
@@ -6553,6 +6623,14 @@ function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
6553
6623
  }
6554
6624
  const paths = coordinatorDaemonId ? [getPendingEventsPath(meshId, coordinatorDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
6555
6625
  for (const path39 of paths) {
6626
+ const isSharedFile = coordinatorDaemonId && path39 === getPendingEventsPath(meshId);
6627
+ const targets = (e) => !isSharedFile || !e.targetCoordinatorDaemonId || e.targetCoordinatorDaemonId === coordinatorDaemonId;
6628
+ if (onlyEvents) {
6629
+ for (const event of selectiveDrainFile(path39, (e) => targets(e) && matchesFilter(e.event))) {
6630
+ pushUnique(event);
6631
+ }
6632
+ continue;
6633
+ }
6556
6634
  const content = atomicDrainFile(path39);
6557
6635
  if (!content) continue;
6558
6636
  const parsed = content.split("\n").filter(Boolean).flatMap((line) => {
@@ -6562,7 +6640,7 @@ function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
6562
6640
  return [];
6563
6641
  }
6564
6642
  });
6565
- const filtered = coordinatorDaemonId && path39 === getPendingEventsPath(meshId) ? parsed.filter((e) => !e.targetCoordinatorDaemonId || e.targetCoordinatorDaemonId === coordinatorDaemonId) : parsed;
6643
+ const filtered = isSharedFile ? parsed.filter(targets) : parsed;
6566
6644
  for (const event of filtered) pushUnique(event);
6567
6645
  }
6568
6646
  if (merged.length === 0) return [];
@@ -8582,7 +8660,9 @@ async function runMeshReconcileTick(components) {
8582
8660
  }
8583
8661
  }
8584
8662
  const idleCoordinators = meshCoordinators.filter((c) => c.idle);
8585
- if (idleCoordinators.length === 0) continue;
8663
+ const generatingCoordinators = meshCoordinators.filter((c) => !c.idle);
8664
+ const targetCoordinators = idleCoordinators.length > 0 ? idleCoordinators : generatingCoordinators;
8665
+ const forceOnly = idleCoordinators.length === 0;
8586
8666
  if (store) {
8587
8667
  try {
8588
8668
  if (store.pendingEventCount(meshId) === 0) continue;
@@ -8591,15 +8671,20 @@ async function runMeshReconcileTick(components) {
8591
8671
  }
8592
8672
  let pendingEvents = [];
8593
8673
  try {
8594
- pendingEvents = drainPendingMeshCoordinatorEvents(meshId, localDaemonId);
8674
+ pendingEvents = drainPendingMeshCoordinatorEvents(
8675
+ meshId,
8676
+ localDaemonId,
8677
+ forceOnly ? { onlyEvents: MESH_FORCE_INJECT_EVENTS } : void 0
8678
+ );
8595
8679
  } catch (e) {
8596
8680
  LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
8597
8681
  continue;
8598
8682
  }
8599
8683
  if (pendingEvents.length === 0) continue;
8600
- LOG.info("MeshReconcile", `Reconcile inject: ${pendingEvents.length} pending event(s) \u2192 ${idleCoordinators.length} idle coordinator(s) for mesh ${meshId}`);
8684
+ const mode = forceOnly ? "force-drain \u2192 generating" : "inject \u2192 idle";
8685
+ LOG.info("MeshReconcile", `Reconcile ${mode}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
8601
8686
  for (const pending of pendingEvents) {
8602
- for (const c of idleCoordinators) {
8687
+ for (const c of targetCoordinators) {
8603
8688
  injectPendingIntoCoordinator(c.instance, pending);
8604
8689
  }
8605
8690
  }