@adhdev/daemon-core 0.9.82-rc.460 → 0.9.82-rc.461

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
@@ -404,10 +404,10 @@ function readInjected(value) {
404
404
  }
405
405
  function getDaemonBuildInfo() {
406
406
  if (cached) return cached;
407
- const commit = readInjected(true ? "f8ce1329d3bdef9564c4130a1e7f0b607738f3cd" : void 0) ?? "unknown";
408
- const commitShort = readInjected(true ? "f8ce1329" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
- const version = readInjected(true ? "0.9.82-rc.460" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
- const builtAt = readInjected(true ? "2026-07-04T14:24:11.778Z" : void 0);
407
+ const commit = readInjected(true ? "ed8842e811aa362a2b4cc530498bc1fc7e1a7e4a" : void 0) ?? "unknown";
408
+ const commitShort = readInjected(true ? "ed8842e8" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
+ const version = readInjected(true ? "0.9.82-rc.461" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
+ const builtAt = readInjected(true ? "2026-07-04T15:00:03.344Z" : void 0);
411
411
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
412
412
  return cached;
413
413
  }
@@ -3258,6 +3258,12 @@ function updateNode(meshId, nodeId, opts) {
3258
3258
  if (opts.reportedPlatform && opts.reportedPlatform.trim()) node.reportedPlatform = opts.reportedPlatform.trim();
3259
3259
  if (opts.reportedArch && opts.reportedArch.trim()) node.reportedArch = opts.reportedArch.trim();
3260
3260
  if (opts.reportedMachineNickname && opts.reportedMachineNickname.trim()) node.machineNickname = opts.reportedMachineNickname.trim();
3261
+ if (opts.reportedProviderVersions && Object.keys(opts.reportedProviderVersions).length > 0) {
3262
+ node.reportedProviderVersions = { ...opts.reportedProviderVersions };
3263
+ }
3264
+ if (opts.reportedDaemonBuildVersion && opts.reportedDaemonBuildVersion.trim()) {
3265
+ node.reportedDaemonBuildVersion = opts.reportedDaemonBuildVersion.trim();
3266
+ }
3261
3267
  if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
3262
3268
  if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
3263
3269
  if (Object.prototype.hasOwnProperty.call(opts, "systemPrompt")) {
@@ -3601,9 +3607,16 @@ function buildNodeStatusSection(nodes) {
3601
3607
  const healthIcon = n.health === "online" ? "\u{1F7E2}" : n.health === "dirty" ? "\u{1F7E1}" : n.health === "offline" ? "\u26AB" : "\u{1F534}";
3602
3608
  const sessions = n.activeSessions.length > 0 ? `sessions: ${n.activeSessions.join(", ")}` : "no active sessions";
3603
3609
  const branch = n.git?.branch ? `branch: \`${n.git.branch}\`` : "";
3610
+ const providerVersions = n.providerVersions && typeof n.providerVersions === "object" ? n.providerVersions : void 0;
3611
+ const providersRendered = n.providers?.length ? n.providers.map((p) => {
3612
+ const version = providerVersions?.[p];
3613
+ return version ? `${p}@${version}` : p;
3614
+ }).join(", ") : "";
3615
+ const buildVersion = typeof n.daemonBuildVersion === "string" && n.daemonBuildVersion ? `build: ${n.daemonBuildVersion}` : "";
3604
3616
  const context = [
3605
3617
  n.daemonId ? `daemon: \`${n.daemonId}\`` : "",
3606
- n.providers?.length ? `providers: ${n.providers.join(", ")}` : ""
3618
+ providersRendered ? `providers: ${providersRendered}` : "",
3619
+ buildVersion
3607
3620
  ].filter(Boolean).join(" | ");
3608
3621
  lines.push(`- ${healthIcon} **${n.machineLabel}** (nodeId: \`${n.nodeId}\`)`);
3609
3622
  lines.push(` workspace: \`${n.workspace}\`${context ? ` | ${context}` : ""} | ${branch} | ${sessions}`);
@@ -4167,6 +4180,98 @@ var init_load_better_sqlite3 = __esm({
4167
4180
  });
4168
4181
 
4169
4182
  // src/mesh/contracts.ts
4183
+ function isSupportedMeshProtocolVersion(value) {
4184
+ return typeof value === "string" && SUPPORTED_MESH_PROTOCOL_VERSIONS.includes(value);
4185
+ }
4186
+ function coordinatorIdentityEquals(a, b) {
4187
+ return daemonIdsEquivalent(a.daemonId, b.daemonId) && a.coordinatorRunId === b.coordinatorRunId && (a.sessionId ?? "") === (b.sessionId ?? "");
4188
+ }
4189
+ function coordinatorIdentityKey(identity) {
4190
+ const daemonCore = machineCoreFromDaemonId(identity.daemonId) ?? identity.daemonId;
4191
+ return `${daemonCore}|${identity.coordinatorRunId}|${identity.sessionId ?? ""}`;
4192
+ }
4193
+ function isMeshEventScope(value) {
4194
+ return typeof value === "string" && MESH_EVENT_SCOPES.includes(value);
4195
+ }
4196
+ function isNonEmptyString(value) {
4197
+ return typeof value === "string" && value.length > 0;
4198
+ }
4199
+ function assertCoordinatorIdentity(raw, path44) {
4200
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
4201
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, path44, "must be an object");
4202
+ }
4203
+ const obj = raw;
4204
+ if (!isNonEmptyString(obj.daemonId)) {
4205
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.daemonId`, "must be a non-empty string");
4206
+ }
4207
+ if (!isNonEmptyString(obj.coordinatorRunId)) {
4208
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.coordinatorRunId`, "must be a non-empty string");
4209
+ }
4210
+ const sessionId = obj.sessionId;
4211
+ if (sessionId !== void 0 && !isNonEmptyString(sessionId)) {
4212
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.sessionId`, "must be a non-empty string when provided");
4213
+ }
4214
+ return sessionId !== void 0 ? { daemonId: obj.daemonId, coordinatorRunId: obj.coordinatorRunId, sessionId } : { daemonId: obj.daemonId, coordinatorRunId: obj.coordinatorRunId };
4215
+ }
4216
+ function assertPendingMeshCoordinatorEventV2(raw, path44 = "$") {
4217
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
4218
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, path44, "must be an object");
4219
+ }
4220
+ const obj = raw;
4221
+ if (!isSupportedMeshProtocolVersion(obj.protocolVersion)) {
4222
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.protocolVersion`, `must be one of ${SUPPORTED_MESH_PROTOCOL_VERSIONS.join(", ")}`);
4223
+ }
4224
+ if (!isNonEmptyString(obj.eventId)) {
4225
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.eventId`, "must be a non-empty string");
4226
+ }
4227
+ if (!isMeshEventScope(obj.scope)) {
4228
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.scope`, `must be one of ${MESH_EVENT_SCOPES.join(", ")}`);
4229
+ }
4230
+ if (!isNonEmptyString(obj.event)) {
4231
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.event`, "must be a non-empty string");
4232
+ }
4233
+ if (!isNonEmptyString(obj.meshId)) {
4234
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.meshId`, "must be a non-empty string");
4235
+ }
4236
+ const dispatchedBy = assertCoordinatorIdentity(obj.dispatchedBy, `${path44}.dispatchedBy`);
4237
+ if (obj.scope === "unicast") {
4238
+ if (!obj.intendedFor) {
4239
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.intendedFor`, "unicast scope requires intendedFor");
4240
+ }
4241
+ } else if (obj.intendedFor !== void 0) {
4242
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.intendedFor`, "only unicast scope may set intendedFor");
4243
+ }
4244
+ const intendedFor = obj.intendedFor ? assertCoordinatorIdentity(obj.intendedFor, `${path44}.intendedFor`) : void 0;
4245
+ const metadata = obj.metadataEvent && typeof obj.metadataEvent === "object" && !Array.isArray(obj.metadataEvent) ? obj.metadataEvent : null;
4246
+ if (!metadata) {
4247
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.metadataEvent`, "must be an object");
4248
+ }
4249
+ const queuedAt = typeof obj.queuedAt === "number" && Number.isFinite(obj.queuedAt) ? obj.queuedAt : null;
4250
+ if (queuedAt === null) {
4251
+ throw new MeshContractViolationError(MESH_PROTOCOL_VERSION_V2, `${path44}.queuedAt`, "must be a finite number");
4252
+ }
4253
+ return {
4254
+ event: obj.event,
4255
+ meshId: obj.meshId,
4256
+ nodeLabel: isNonEmptyString(obj.nodeLabel) ? obj.nodeLabel : "",
4257
+ nodeId: typeof obj.nodeId === "string" ? obj.nodeId : void 0,
4258
+ workspace: typeof obj.workspace === "string" ? obj.workspace : void 0,
4259
+ metadataEvent: metadata,
4260
+ coordinatorMessage: typeof obj.coordinatorMessage === "string" ? obj.coordinatorMessage : void 0,
4261
+ queuedAt,
4262
+ protocolVersion: obj.protocolVersion,
4263
+ eventId: obj.eventId,
4264
+ scope: obj.scope,
4265
+ dispatchedBy,
4266
+ ...intendedFor ? { intendedFor } : {}
4267
+ };
4268
+ }
4269
+ function shouldDeliverPendingEventToCoordinator(event, drainer) {
4270
+ if (event.scope === "system") return false;
4271
+ if (event.scope === "broadcast") return true;
4272
+ if (!event.intendedFor) return false;
4273
+ return coordinatorIdentityEquals(event.intendedFor, drainer);
4274
+ }
4170
4275
  function defaultScopeForEvent(eventName) {
4171
4276
  if (SYSTEM_EVENTS.has(eventName)) return "system";
4172
4277
  if (TERMINAL_TASK_EVENTS.has(eventName)) return "unicast";
@@ -4195,12 +4300,28 @@ function buildPendingEventEmitStamp(opts) {
4195
4300
  ...intendedFor ? { intendedFor } : {}
4196
4301
  };
4197
4302
  }
4198
- var MESH_PROTOCOL_VERSION_V2, TERMINAL_TASK_EVENTS, SYSTEM_EVENTS;
4303
+ var MESH_PROTOCOL_VERSION_V1, MESH_PROTOCOL_VERSION_V2, SUPPORTED_MESH_PROTOCOL_VERSIONS, MESH_EVENT_SCOPES, MeshContractViolationError, TERMINAL_TASK_EVENTS, SYSTEM_EVENTS;
4199
4304
  var init_contracts = __esm({
4200
4305
  "src/mesh/contracts.ts"() {
4201
4306
  "use strict";
4202
4307
  init_dist();
4308
+ MESH_PROTOCOL_VERSION_V1 = "1.0";
4203
4309
  MESH_PROTOCOL_VERSION_V2 = "2.0";
4310
+ SUPPORTED_MESH_PROTOCOL_VERSIONS = [
4311
+ MESH_PROTOCOL_VERSION_V1,
4312
+ MESH_PROTOCOL_VERSION_V2
4313
+ ];
4314
+ MESH_EVENT_SCOPES = ["unicast", "broadcast", "system"];
4315
+ MeshContractViolationError = class extends Error {
4316
+ violationPath;
4317
+ protocolVersion;
4318
+ constructor(protocolVersion, violationPath, detail) {
4319
+ super(`mesh contract ${protocolVersion} violation at ${violationPath}: ${detail}`);
4320
+ this.name = "MeshContractViolationError";
4321
+ this.violationPath = violationPath;
4322
+ this.protocolVersion = protocolVersion;
4323
+ }
4324
+ };
4204
4325
  TERMINAL_TASK_EVENTS = /* @__PURE__ */ new Set([
4205
4326
  "agent:generating_completed",
4206
4327
  "agent:stopped",
@@ -7529,6 +7650,34 @@ var init_mesh_runtime_store = __esm({
7529
7650
  ).get(meshId, fingerprint);
7530
7651
  return row !== void 0;
7531
7652
  }
7653
+ /**
7654
+ * B3a — v2 eventId idempotency. Returns true when a row with this event_id has
7655
+ * ALREADY been drained (drained = 1) for the mesh. Drained rows are retained
7656
+ * (soft-marked, not deleted until mesh deletion), so this is a durable, restart-
7657
+ * surviving dedup: a v2 event whose eventId was already consumed is skipped on
7658
+ * re-delivery even when its content fingerprint differs. Scoped by mesh_id +
7659
+ * the partial event_id index (idx_mesh_pending_events_event_id).
7660
+ */
7661
+ hasDrainedEventId(meshId, eventId) {
7662
+ if (!eventId) return false;
7663
+ const row = this.db.prepare(
7664
+ "SELECT 1 FROM mesh_pending_events WHERE mesh_id = ? AND event_id = ? AND drained = 1 LIMIT 1"
7665
+ ).get(meshId, eventId);
7666
+ return row !== void 0;
7667
+ }
7668
+ /**
7669
+ * B3a — snapshot of the v2 event_ids ALREADY drained (drained = 1) for the mesh.
7670
+ * Taken BEFORE a drain call marks the current batch drained=1, so the resulting
7671
+ * set names only PRIOR drains — the re-delivery dedup baseline. (Reading it after
7672
+ * the drain would self-match the batch's own freshly-drained rows.) Non-v2 rows
7673
+ * have a NULL event_id and are excluded by the index/WHERE.
7674
+ */
7675
+ drainedEventIdsForMesh(meshId) {
7676
+ const rows = this.db.prepare(
7677
+ "SELECT DISTINCT event_id FROM mesh_pending_events WHERE mesh_id = ? AND drained = 1 AND event_id IS NOT NULL"
7678
+ ).all(meshId);
7679
+ return new Set(rows.map((r) => r.event_id));
7680
+ }
7532
7681
  // ── M3: Mission Records ─────────────────────────────────────────────────
7533
7682
  upsertMission(mission) {
7534
7683
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -11326,6 +11475,95 @@ import { randomUUID as randomUUID8 } from "crypto";
11326
11475
  function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
11327
11476
  return expandDaemonIdForms(coordinatorDaemonId);
11328
11477
  }
11478
+ function warnV2Once(key2, message) {
11479
+ if (warnedV2Violations.has(key2)) return;
11480
+ warnedV2Violations.add(key2);
11481
+ if (warnedV2Violations.size > 2e3) {
11482
+ const first = warnedV2Violations.values().next().value;
11483
+ if (first !== void 0) warnedV2Violations.delete(first);
11484
+ }
11485
+ LOG.warn("MeshEventsV2", message);
11486
+ }
11487
+ function resolveDrainerIdentity(daemonIds, explicit) {
11488
+ if (explicit) return explicit;
11489
+ return coordinatorIdentityFromEmitFields({ daemonId: daemonIds[0] });
11490
+ }
11491
+ function isV2Event(event) {
11492
+ return event.protocolVersion === MESH_PROTOCOL_VERSION_V2;
11493
+ }
11494
+ function runIdIsDaemonFormFallback(identity) {
11495
+ return daemonIdsEquivalent(identity.coordinatorRunId, identity.daemonId);
11496
+ }
11497
+ function identityDeliversTo(intendedFor, drainer) {
11498
+ if (runIdIsDaemonFormFallback(intendedFor) && runIdIsDaemonFormFallback(drainer)) {
11499
+ if (!daemonIdsEquivalent(intendedFor.daemonId, drainer.daemonId)) return false;
11500
+ if (intendedFor.sessionId && drainer.sessionId) {
11501
+ return intendedFor.sessionId === drainer.sessionId;
11502
+ }
11503
+ return true;
11504
+ }
11505
+ return coordinatorIdentityEquals(intendedFor, drainer);
11506
+ }
11507
+ function routeV2EventsForDrainer(events, drainer, ctx) {
11508
+ if (!drainer) return events;
11509
+ const bump = (k) => {
11510
+ if (ctx.countMetrics) meshV2DrainCounters[k]++;
11511
+ };
11512
+ const kept = [];
11513
+ for (const event of events) {
11514
+ if (!isV2Event(event)) {
11515
+ bump("v1BroadcastAccepted");
11516
+ kept.push(event);
11517
+ continue;
11518
+ }
11519
+ let validated;
11520
+ try {
11521
+ validated = assertPendingMeshCoordinatorEventV2(event);
11522
+ } catch (e) {
11523
+ bump("v2ValidationFailedAccepted");
11524
+ warnV2Once(
11525
+ `${event.meshId}::${event.eventId ?? event.event}::invalid`,
11526
+ `v2 envelope validation failed for ${event.event} on mesh ${event.meshId} \u2014 PASSED THROUGH (accept mode): ${e?.message || e}`
11527
+ );
11528
+ kept.push(event);
11529
+ continue;
11530
+ }
11531
+ const eventId = validated.eventId;
11532
+ if (ctx.batchSeen.has(eventId) || ctx.alreadyDrained(eventId)) {
11533
+ bump("v2DedupSkipped");
11534
+ continue;
11535
+ }
11536
+ if (validated.scope !== "unicast") {
11537
+ if (shouldDeliverPendingEventToCoordinator(validated, drainer)) {
11538
+ ctx.batchSeen.add(eventId);
11539
+ bump("v2Delivered");
11540
+ kept.push(event);
11541
+ } else {
11542
+ bump("v2RoutedAway");
11543
+ }
11544
+ continue;
11545
+ }
11546
+ if (validated.intendedFor && identityDeliversTo(validated.intendedFor, drainer)) {
11547
+ ctx.batchSeen.add(eventId);
11548
+ bump("v2Delivered");
11549
+ kept.push(event);
11550
+ continue;
11551
+ }
11552
+ const realRunIdMismatch = !runIdIsDaemonFormFallback(validated.intendedFor) || !runIdIsDaemonFormFallback(drainer);
11553
+ if (validated.intendedFor && realRunIdMismatch && daemonIdsEquivalent(validated.intendedFor.daemonId, drainer.daemonId)) {
11554
+ ctx.batchSeen.add(eventId);
11555
+ bump("v2ReattributedToDrainer");
11556
+ warnV2Once(
11557
+ `${event.meshId}::${eventId}::reattributed`,
11558
+ `v2 unicast ${event.event} on mesh ${event.meshId} re-attributed to current coordinator ${coordinatorIdentityKey(drainer)} (originating coordinatorRunId no longer live)`
11559
+ );
11560
+ kept.push(event);
11561
+ continue;
11562
+ }
11563
+ bump("v2RoutedAway");
11564
+ }
11565
+ return kept;
11566
+ }
11329
11567
  function readRefineJobId2(event) {
11330
11568
  const metadata = readRecord5(event.metadataEvent) || event;
11331
11569
  const result = readRecord5(metadata.result);
@@ -11544,6 +11782,36 @@ function stampPendingEventV2(event, hint) {
11544
11782
  ...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {}
11545
11783
  };
11546
11784
  }
11785
+ function readCoordinatorIdentityFromWire(raw) {
11786
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
11787
+ const obj = raw;
11788
+ const daemonId = readNonEmptyString2(obj.daemonId);
11789
+ const coordinatorRunId = readNonEmptyString2(obj.coordinatorRunId);
11790
+ if (!daemonId || !coordinatorRunId) return void 0;
11791
+ const sessionId = readNonEmptyString2(obj.sessionId);
11792
+ return { daemonId, coordinatorRunId, ...sessionId ? { sessionId } : {} };
11793
+ }
11794
+ function serializeV2EnvelopeToWire(event) {
11795
+ const out = {};
11796
+ if (event.protocolVersion) out.protocolVersion = event.protocolVersion;
11797
+ if (readNonEmptyString2(event.eventId)) out.eventId = event.eventId;
11798
+ if (event.scope) out.scope = event.scope;
11799
+ if (event.dispatchedBy) out.dispatchedBy = event.dispatchedBy;
11800
+ if (event.intendedFor) out.intendedFor = event.intendedFor;
11801
+ return out;
11802
+ }
11803
+ function readV2EnvelopeFromWire(payload) {
11804
+ const out = {};
11805
+ if (payload.protocolVersion === MESH_PROTOCOL_VERSION_V2) out.protocolVersion = MESH_PROTOCOL_VERSION_V2;
11806
+ const eventId = readNonEmptyString2(payload.eventId);
11807
+ if (eventId) out.eventId = eventId;
11808
+ if (isMeshEventScope(payload.scope)) out.scope = payload.scope;
11809
+ const dispatchedBy = readCoordinatorIdentityFromWire(payload.dispatchedBy);
11810
+ if (dispatchedBy) out.dispatchedBy = dispatchedBy;
11811
+ const intendedFor = readCoordinatorIdentityFromWire(payload.intendedFor);
11812
+ if (intendedFor) out.intendedFor = intendedFor;
11813
+ return out;
11814
+ }
11547
11815
  function queuePendingMeshCoordinatorEvent(rawEvent, hint) {
11548
11816
  const event = stampPendingEventV2(rawEvent, hint);
11549
11817
  try {
@@ -11666,6 +11934,12 @@ function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId, opts) {
11666
11934
  if (!meshId) return [];
11667
11935
  const daemonIds = normalizeCoordinatorDaemonIds(coordinatorDaemonId);
11668
11936
  const primaryDaemonId = daemonIds[0];
11937
+ const drainer = resolveDrainerIdentity(daemonIds, opts?.drainerIdentity);
11938
+ let priorDrainedEventIds = /* @__PURE__ */ new Set();
11939
+ try {
11940
+ priorDrainedEventIds = MeshRuntimeStore.getInstance().drainedEventIdsForMesh(meshId);
11941
+ } catch {
11942
+ }
11669
11943
  const onlyEvents = opts?.onlyEvents;
11670
11944
  const matchesFilter = (eventName) => !onlyEvents || onlyEvents.has(eventName);
11671
11945
  const merged = [];
@@ -11712,7 +11986,12 @@ function drainPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId, opts) {
11712
11986
  for (const event of filtered) pushUnique(event);
11713
11987
  }
11714
11988
  if (merged.length === 0) return [];
11715
- return reconcilePendingMeshCoordinatorEvents(meshId, merged);
11989
+ const routed = routeV2EventsForDrainer(merged, drainer, {
11990
+ alreadyDrained: (eventId) => priorDrainedEventIds.has(eventId),
11991
+ batchSeen: /* @__PURE__ */ new Set(),
11992
+ countMetrics: true
11993
+ });
11994
+ return reconcilePendingMeshCoordinatorEvents(meshId, routed);
11716
11995
  }
11717
11996
  function retractPendingDispatchBlockedEvent(meshId, taskId, coordinatorDaemonId) {
11718
11997
  if (!meshId || !taskId) return 0;
@@ -11743,9 +12022,15 @@ function retractPendingDispatchBlockedEvent(meshId, taskId, coordinatorDaemonId)
11743
12022
  }
11744
12023
  return removed;
11745
12024
  }
11746
- function getPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
12025
+ function getPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId, opts) {
11747
12026
  if (!meshId) return [];
11748
12027
  const daemonIds = normalizeCoordinatorDaemonIds(coordinatorDaemonId);
12028
+ const drainer = resolveDrainerIdentity(daemonIds, opts?.drainerIdentity);
12029
+ let priorDrainedEventIds = /* @__PURE__ */ new Set();
12030
+ try {
12031
+ priorDrainedEventIds = MeshRuntimeStore.getInstance().drainedEventIdsForMesh(meshId);
12032
+ } catch {
12033
+ }
11749
12034
  const merged = [];
11750
12035
  const seenFingerprints = /* @__PURE__ */ new Set();
11751
12036
  const pushUnique = (event) => {
@@ -11769,7 +12054,12 @@ function getPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
11769
12054
  for (const event of readPendingMeshCoordinatorEventsFromDisk(meshId, daemonIds)) {
11770
12055
  pushUnique(event);
11771
12056
  }
11772
- return reconcilePendingMeshCoordinatorEvents(meshId, merged);
12057
+ const routed = routeV2EventsForDrainer(merged, drainer, {
12058
+ alreadyDrained: (eventId) => priorDrainedEventIds.has(eventId),
12059
+ batchSeen: /* @__PURE__ */ new Set(),
12060
+ countMetrics: false
12061
+ });
12062
+ return reconcilePendingMeshCoordinatorEvents(meshId, routed);
11773
12063
  }
11774
12064
  function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
11775
12065
  if (!meshId) return;
@@ -11785,7 +12075,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
11785
12075
  }
11786
12076
  }
11787
12077
  }
11788
- var REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
12078
+ var REFINE_TERMINAL_EVENTS, meshV2DrainCounters, warnedV2Violations, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
11789
12079
  var init_mesh_events_pending = __esm({
11790
12080
  "src/mesh/mesh-events-pending.ts"() {
11791
12081
  "use strict";
@@ -11796,6 +12086,24 @@ var init_mesh_events_pending = __esm({
11796
12086
  init_dist();
11797
12087
  init_contracts();
11798
12088
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
12089
+ meshV2DrainCounters = {
12090
+ /** v2 events that passed validation and unicast/broadcast routing → delivered. */
12091
+ v2Delivered: 0,
12092
+ /** v2 unicast events skipped because intendedFor addressed another coordinator. */
12093
+ v2RoutedAway: 0,
12094
+ /** v2 events skipped because their eventId was already drained (idempotency). */
12095
+ v2DedupSkipped: 0,
12096
+ /** v2 events that failed assertPendingMeshCoordinatorEventV2 but were PASSED
12097
+ * THROUGH (accept mode). Non-zero here is the rollout signal that a producer
12098
+ * emits a malformed envelope. */
12099
+ v2ValidationFailedAccepted: 0,
12100
+ /** unicast events re-attributed to the drainer via daemon-core match (a
12101
+ * coordinatorRunId change orphaned them). */
12102
+ v2ReattributedToDrainer: 0,
12103
+ /** v1 (unversioned) events passed through as broadcast (rollout baseline). */
12104
+ v1BroadcastAccepted: 0
12105
+ };
12106
+ warnedV2Violations = /* @__PURE__ */ new Set();
11799
12107
  TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
11800
12108
  MAX_PENDING_EVENTS_BYTES = 100 * 1024;
11801
12109
  MAX_PENDING_EVENTS_KEEP = 50;
@@ -12853,10 +13161,46 @@ async function detectCLI(cliId, providerLoader, options) {
12853
13161
  const all = await detectCLIs(providerLoader, options);
12854
13162
  return all.find((c) => c.id === resolvedId && c.installed) || null;
12855
13163
  }
13164
+ function buildProviderVersions(detected) {
13165
+ const out = {};
13166
+ for (const cli of detected) {
13167
+ if (!cli.installed) continue;
13168
+ const version = typeof cli.version === "string" ? cli.version.trim() : "";
13169
+ if (!version) continue;
13170
+ out[cli.id] = version;
13171
+ }
13172
+ return out;
13173
+ }
13174
+ function refreshProviderVersionsSnapshot(providerLoader) {
13175
+ if (providerVersionsRefreshInFlight) return providerVersionsRefreshInFlight;
13176
+ providerVersionsRefreshInFlight = (async () => {
13177
+ try {
13178
+ const detected = await detectCLIs(providerLoader, { includeVersion: true });
13179
+ cachedProviderVersions = buildProviderVersions(detected);
13180
+ cachedProviderVersionsAt = Date.now();
13181
+ } catch {
13182
+ } finally {
13183
+ providerVersionsRefreshInFlight = null;
13184
+ }
13185
+ })();
13186
+ return providerVersionsRefreshInFlight;
13187
+ }
13188
+ function getCachedProviderVersions(providerLoader) {
13189
+ const stale = Date.now() - cachedProviderVersionsAt > PROVIDER_VERSIONS_TTL_MS;
13190
+ if (stale) {
13191
+ void refreshProviderVersionsSnapshot(providerLoader);
13192
+ }
13193
+ return { ...cachedProviderVersions };
13194
+ }
13195
+ var PROVIDER_VERSIONS_TTL_MS, cachedProviderVersions, cachedProviderVersionsAt, providerVersionsRefreshInFlight;
12856
13196
  var init_cli_detector = __esm({
12857
13197
  "src/detection/cli-detector.ts"() {
12858
13198
  "use strict";
12859
13199
  init_provider_cli_shared();
13200
+ PROVIDER_VERSIONS_TTL_MS = 5 * 60 * 1e3;
13201
+ cachedProviderVersions = {};
13202
+ cachedProviderVersionsAt = 0;
13203
+ providerVersionsRefreshInFlight = null;
12860
13204
  }
12861
13205
  });
12862
13206
 
@@ -17545,7 +17889,13 @@ function injectMeshSystemMessage(components, args) {
17545
17889
  ...workerCoordinatorDaemonId ? { targetCoordinatorDaemonId: workerCoordinatorDaemonId } : {},
17546
17890
  // Top-level session anchor for the local PHASE 2 strict-match on the coordinator
17547
17891
  // daemon. Absent → daemon-level broadcast (legacy / single-coordinator path).
17548
- ...workerCoordinatorSessionId ? { targetCoordinatorSessionId: workerCoordinatorSessionId } : {}
17892
+ ...workerCoordinatorSessionId ? { targetCoordinatorSessionId: workerCoordinatorSessionId } : {},
17893
+ // T4 (B3b): restore the v2 envelope from the remote relay so the re-queue keeps the
17894
+ // ORIGINAL eventId. Spread LAST so its authoritative eventId/scope/identity win over
17895
+ // any default. queuePendingMeshCoordinatorEvent → stampPendingEventV2 then no-ops
17896
+ // (already-stamped short-circuit) instead of minting a fresh eventId. Empty object
17897
+ // for a v1 relay → unchanged v1 emit-stamp path (version-skew safe).
17898
+ ...args.v2Envelope ?? {}
17549
17899
  };
17550
17900
  if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
17551
17901
  LOG.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
@@ -17658,7 +18008,12 @@ function handleMeshForwardEvent(components, payload) {
17658
18008
  nodeId,
17659
18009
  nodeLabel,
17660
18010
  event: eventName,
17661
- metadataEvent: buildRelayMetadataEvent(payload)
18011
+ metadataEvent: buildRelayMetadataEvent(payload),
18012
+ // T4 (B3b): restore the v2 envelope carried at the top level of the relayed flat
18013
+ // payload (buildForwardPayloadFromPending → serializeV2EnvelopeToWire) so the
18014
+ // re-queue preserves the original eventId (idempotency) and unicast routing rather
18015
+ // than re-stamping a fresh v1/broadcast event. Empty for a v1 relay (version-skew safe).
18016
+ v2Envelope: readV2EnvelopeFromWire(payload)
17662
18017
  });
17663
18018
  }
17664
18019
  function enqueueCoordinatorForwardPush(coordinatorDaemonId, run) {
@@ -19085,7 +19440,14 @@ function buildForwardPayloadFromPending(event) {
19085
19440
  ...(() => {
19086
19441
  const tid = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(metadata.meshActiveTaskId);
19087
19442
  return tid ? { taskId: tid } : {};
19088
- })()
19443
+ })(),
19444
+ // T4 (B3b): carry the v2 envelope (protocolVersion/eventId/scope/dispatchedBy/
19445
+ // intendedFor) across the P2P relay boundary at the TOP LEVEL. These live on the
19446
+ // pending event itself, not inside metadataEvent, so without this the remote pull
19447
+ // re-queue would re-stamp a fresh eventId — breaking cross-machine idempotency and
19448
+ // downgrading the relayed completion to v1 broadcast routing. Spread LAST so the
19449
+ // authoritative envelope always wins over any stale key the metadata spread carried.
19450
+ ...serializeV2EnvelopeToWire(event)
19089
19451
  };
19090
19452
  }
19091
19453
  function setupMeshReconcileLoop(components) {
@@ -19159,9 +19521,11 @@ __export(mesh_events_exports, {
19159
19521
  isMeshCoordinatorEvent: () => isMeshCoordinatorEvent,
19160
19522
  isSessionActivelyGenerating: () => isSessionActivelyGenerating,
19161
19523
  queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
19524
+ readV2EnvelopeFromWire: () => readV2EnvelopeFromWire,
19162
19525
  reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
19163
19526
  resolveCoordinatorDrainDeliverability: () => resolveCoordinatorDrainDeliverability,
19164
19527
  runMeshReconcileTick: () => runMeshReconcileTick,
19528
+ serializeV2EnvelopeToWire: () => serializeV2EnvelopeToWire,
19165
19529
  setupMeshEventForwarding: () => setupMeshEventForwarding,
19166
19530
  setupMeshReconcileLoop: () => setupMeshReconcileLoop,
19167
19531
  shouldHoldPendingDrainForBusyLocalCoordinator: () => shouldHoldPendingDrainForBusyLocalCoordinator,
@@ -25501,7 +25865,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
25501
25865
  getStatus: (workspace) => getGitRepoStatus(workspace),
25502
25866
  getDiffSummary: (workspace) => getGitDiffSummary(workspace)
25503
25867
  });
25504
- function createDefaultGitCommandServices() {
25868
+ function createDefaultGitCommandServices(overrides) {
25505
25869
  return {
25506
25870
  getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
25507
25871
  getDiffSummary: ({ workspace, base }) => getGitDiffSummary(workspace, base ? { baseRef: base } : {}),
@@ -25519,7 +25883,8 @@ function createDefaultGitCommandServices() {
25519
25883
  stashPop: async ({ workspace, stashRef }) => gitStashPop(workspace, stashRef),
25520
25884
  checkoutFiles: async ({ workspace, paths }) => gitCheckoutFiles(workspace, paths),
25521
25885
  getRemoteUrl: async ({ workspace, remote = "origin" }) => gitGetRemoteUrl(workspace, remote),
25522
- push: async ({ workspace, remote = "origin", branch, setUpstream = false }) => gitPush(workspace, remote, branch, setUpstream)
25886
+ push: async ({ workspace, remote = "origin", branch, setUpstream = false }) => gitPush(workspace, remote, branch, setUpstream),
25887
+ ...overrides?.getReporterProviderVersions ? { getReporterProviderVersions: overrides.getReporterProviderVersions } : {}
25523
25888
  };
25524
25889
  }
25525
25890
  var defaultGitCommandServices = createDefaultGitCommandServices();
@@ -25606,12 +25971,23 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
25606
25971
  return void 0;
25607
25972
  }
25608
25973
  })();
25974
+ const reporterVersions = (() => {
25975
+ try {
25976
+ return services.getReporterProviderVersions?.() ?? {};
25977
+ } catch {
25978
+ return {};
25979
+ }
25980
+ })();
25981
+ const reporterProviderVersions = reporterVersions.providerVersions && Object.keys(reporterVersions.providerVersions).length > 0 ? reporterVersions.providerVersions : void 0;
25982
+ const reporterDaemonBuildVersion = typeof reporterVersions.daemonBuildVersion === "string" && reporterVersions.daemonBuildVersion.trim() ? reporterVersions.daemonBuildVersion.trim() : void 0;
25609
25983
  return {
25610
25984
  success: true,
25611
25985
  status,
25612
25986
  reporterPlatform: process.platform,
25613
25987
  reporterArch: process.arch,
25614
- ...reporterMachineNickname ? { reporterMachineNickname } : {}
25988
+ ...reporterMachineNickname ? { reporterMachineNickname } : {},
25989
+ ...reporterProviderVersions ? { reporterProviderVersions } : {},
25990
+ ...reporterDaemonBuildVersion ? { reporterDaemonBuildVersion } : {}
25615
25991
  };
25616
25992
  }
25617
25993
  case "git_diff_summary": {
@@ -53496,6 +53872,12 @@ var meshStatusHandlers = {
53496
53872
  machineStatus: node.machineStatus,
53497
53873
  health: "unknown",
53498
53874
  providers: node.providers || [],
53875
+ // T7: surface self-healed provider versions + build version (from the
53876
+ // git_status envelope, persisted on the node) so the coordinator/UI can
53877
+ // spot a provider-version skew across nodes. Additive; omitted when a
53878
+ // node has never reported them.
53879
+ ...node.reportedProviderVersions && typeof node.reportedProviderVersions === "object" ? { providerVersions: node.reportedProviderVersions } : {},
53880
+ ...typeof node.reportedDaemonBuildVersion === "string" && node.reportedDaemonBuildVersion ? { daemonBuildVersion: node.reportedDaemonBuildVersion } : {},
53499
53881
  providerPriority,
53500
53882
  activeSessions: [],
53501
53883
  activeSessionDetails: [],
@@ -54269,7 +54651,13 @@ function buildLivePeerGitConnection(connection, timestamp = (/* @__PURE__ */ new
54269
54651
  }
54270
54652
  function recordInlineMeshDirectGitTruth(node, git, source) {
54271
54653
  if (!node || typeof node !== "object" || Array.isArray(node)) {
54272
- return { reporterPlatform: null, reporterArch: null, reporterMachineNickname: null };
54654
+ return {
54655
+ reporterPlatform: null,
54656
+ reporterArch: null,
54657
+ reporterMachineNickname: null,
54658
+ reporterProviderVersions: null,
54659
+ reporterDaemonBuildVersion: null
54660
+ };
54273
54661
  }
54274
54662
  const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
54275
54663
  const updatedAt = new Date(checkedAt).toISOString();
@@ -54296,7 +54684,28 @@ function recordInlineMeshDirectGitTruth(node, git, source) {
54296
54684
  if (reporterArch) node.reportedArch = reporterArch;
54297
54685
  const reporterMachineNickname = readStringValue(git.reporterMachineNickname) ?? null;
54298
54686
  if (reporterMachineNickname) node.machineNickname = reporterMachineNickname;
54299
- return { reporterPlatform, reporterArch, reporterMachineNickname };
54687
+ const reporterProviderVersions = readProviderVersionsRecord(git.reporterProviderVersions);
54688
+ if (reporterProviderVersions) node.reportedProviderVersions = reporterProviderVersions;
54689
+ const reporterDaemonBuildVersion = readStringValue(git.reporterDaemonBuildVersion) ?? null;
54690
+ if (reporterDaemonBuildVersion) node.reportedDaemonBuildVersion = reporterDaemonBuildVersion;
54691
+ return {
54692
+ reporterPlatform,
54693
+ reporterArch,
54694
+ reporterMachineNickname,
54695
+ reporterProviderVersions,
54696
+ reporterDaemonBuildVersion
54697
+ };
54698
+ }
54699
+ function readProviderVersionsRecord(value) {
54700
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
54701
+ const out = {};
54702
+ for (const [key2, raw] of Object.entries(value)) {
54703
+ if (typeof key2 !== "string" || !key2.trim()) continue;
54704
+ const version = typeof raw === "string" ? raw.trim() : "";
54705
+ if (!version) continue;
54706
+ out[key2] = version;
54707
+ }
54708
+ return Object.keys(out).length > 0 ? out : null;
54300
54709
  }
54301
54710
  function stampNodeReporterPlatform(node, platform10, arch2) {
54302
54711
  if (!node || typeof node !== "object" || Array.isArray(node)) return;
@@ -54320,8 +54729,18 @@ function persistNodeReporterPlatform(meshSource, mesh, nodeId, reporter) {
54320
54729
  const reportedPlatform = reporter.reporterPlatform ?? void 0;
54321
54730
  const reportedArch = reporter.reporterArch ?? void 0;
54322
54731
  const reportedMachineNickname = reporter.reporterMachineNickname ?? void 0;
54323
- if (!reportedPlatform && !reportedArch && !reportedMachineNickname) return;
54324
- void Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports)).then(({ updateNode: updateNode2 }) => updateNode2(meshId, nodeId, { reportedPlatform, reportedArch, reportedMachineNickname })).catch(() => {
54732
+ const reportedProviderVersions = reporter.reporterProviderVersions ?? void 0;
54733
+ const reportedDaemonBuildVersion = reporter.reporterDaemonBuildVersion ?? void 0;
54734
+ if (!reportedPlatform && !reportedArch && !reportedMachineNickname && !reportedProviderVersions && !reportedDaemonBuildVersion) {
54735
+ return;
54736
+ }
54737
+ void Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports)).then(({ updateNode: updateNode2 }) => updateNode2(meshId, nodeId, {
54738
+ reportedPlatform,
54739
+ reportedArch,
54740
+ reportedMachineNickname,
54741
+ reportedProviderVersions,
54742
+ reportedDaemonBuildVersion
54743
+ })).catch(() => {
54325
54744
  });
54326
54745
  }
54327
54746
  function buildCachedInlineMeshGitStatus(node) {
@@ -54978,6 +55397,10 @@ async function probeRemoteMeshGitStatus(args) {
54978
55397
  if (reporterPlatform) git.reporterPlatform = reporterPlatform;
54979
55398
  if (reporterArch) git.reporterArch = reporterArch;
54980
55399
  if (reporterMachineNickname) git.reporterMachineNickname = reporterMachineNickname;
55400
+ const reporterProviderVersions = readProviderVersionsRecord(remoteResult?.reporterProviderVersions);
55401
+ if (reporterProviderVersions) git.reporterProviderVersions = reporterProviderVersions;
55402
+ const reporterDaemonBuildVersion = readStringValue(remoteResult?.reporterDaemonBuildVersion);
55403
+ if (reporterDaemonBuildVersion) git.reporterDaemonBuildVersion = reporterDaemonBuildVersion;
54981
55404
  return git;
54982
55405
  }
54983
55406
  var MESH_DIRECT_PROBE_MAX_RETRIES = 2;
@@ -66919,6 +67342,7 @@ function launchIDE(ide, workspacePath) {
66919
67342
 
66920
67343
  // src/boot/daemon-lifecycle.ts
66921
67344
  init_cli_detector();
67345
+ init_build_info();
66922
67346
 
66923
67347
  // src/sessions/registry.ts
66924
67348
  var SessionRegistry = class {
@@ -67120,7 +67544,19 @@ async function initDaemonComponents(config) {
67120
67544
  providerLoader,
67121
67545
  instanceManager,
67122
67546
  sessionRegistry,
67123
- gitCommandServices: createDefaultGitCommandServices(),
67547
+ gitCommandServices: createDefaultGitCommandServices({
67548
+ // T7: fold this daemon's cached provider versions + build version onto the
67549
+ // git_status envelope so the mesh coordinator self-heals each node's
67550
+ // providerVersions. Non-blocking: reads a TTL cache, lazily refreshed.
67551
+ getReporterProviderVersions: () => {
67552
+ const providerVersions = getCachedProviderVersions(providerLoader);
67553
+ const daemonBuildVersion = getDaemonBuildInfo().version;
67554
+ return {
67555
+ ...Object.keys(providerVersions).length > 0 ? { providerVersions } : {},
67556
+ ...daemonBuildVersion && daemonBuildVersion !== "unknown" ? { daemonBuildVersion } : {}
67557
+ };
67558
+ }
67559
+ }),
67124
67560
  onProviderSettingChanged: async (providerType) => {
67125
67561
  await refreshProviderAvailability(providerType);
67126
67562
  config.onStatusChange?.();
@@ -67842,6 +68278,7 @@ export {
67842
68278
  readLedgerSliceFromStore,
67843
68279
  readMeshCompletionSummary,
67844
68280
  readOperatingNotes,
68281
+ readV2EnvelopeFromWire,
67845
68282
  reconcileDirectDispatchCompletionFromTranscript,
67846
68283
  recordCompletionConflict,
67847
68284
  recordDebugTrace,
@@ -67882,6 +68319,7 @@ export {
67882
68319
  runMeshWorktreeBootstrap,
67883
68320
  saveConfig,
67884
68321
  saveState,
68322
+ serializeV2EnvelopeToWire,
67885
68323
  setDebugRuntimeConfig,
67886
68324
  setLogLevel,
67887
68325
  setMagiKindPanel,