@adhdev/daemon-core 0.9.82-rc.461 → 0.9.82-rc.463
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/commands/router-aggregate-status.d.ts +24 -0
- package/dist/commands/router-mesh-session-owner.d.ts +59 -0
- package/dist/commands/router.d.ts +7 -47
- package/dist/index.js +388 -222
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +388 -222
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events-pending.d.ts +34 -2
- package/dist/mesh/mesh-events.d.ts +2 -2
- package/dist/mesh/mesh-reconcile-loop.d.ts +12 -0
- package/dist/providers/approval-utils.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +9 -0
- package/dist/providers/spec/types.d.ts +22 -0
- package/dist/repo-mesh-types.d.ts +31 -0
- package/package.json +3 -3
- package/src/commands/high-family/mesh-events.ts +14 -1
- package/src/commands/high-family/mesh-status.ts +19 -2
- package/src/commands/router-aggregate-status.ts +209 -0
- package/src/commands/router-mesh-session-owner.ts +114 -0
- package/src/commands/router.ts +27 -255
- package/src/mesh/mesh-events-pending.ts +99 -5
- package/src/mesh/mesh-events.ts +3 -0
- package/src/mesh/mesh-reconcile-loop.ts +66 -0
- package/src/providers/approval-utils.ts +1 -1
- package/src/providers/cli-provider-instance.ts +41 -12
- package/src/providers/native-history/hermes-cli-transcript.ts +54 -2
- package/src/providers/spec/native-history-executor.ts +73 -6
- package/src/providers/spec/types.ts +22 -0
- package/src/repo-mesh-types.ts +32 -0
package/dist/index.js
CHANGED
|
@@ -409,10 +409,10 @@ function readInjected(value) {
|
|
|
409
409
|
}
|
|
410
410
|
function getDaemonBuildInfo() {
|
|
411
411
|
if (cached) return cached;
|
|
412
|
-
const commit = readInjected(true ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
412
|
+
const commit = readInjected(true ? "3441855fe9c04e158a4dc94eed196b7bcba1647e" : void 0) ?? "unknown";
|
|
413
|
+
const commitShort = readInjected(true ? "3441855f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
414
|
+
const version = readInjected(true ? "0.9.82-rc.463" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
415
|
+
const builtAt = readInjected(true ? "2026-07-05T02:56:26.902Z" : void 0);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -11479,6 +11479,37 @@ var init_mesh_events_utils = __esm({
|
|
|
11479
11479
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
11480
11480
|
return expandDaemonIdForms(coordinatorDaemonId);
|
|
11481
11481
|
}
|
|
11482
|
+
function isMeshProtocolV2EnforceEnabled() {
|
|
11483
|
+
const raw = readNonEmptyString2(process.env.MESH_PROTOCOL_V2_ENFORCE);
|
|
11484
|
+
if (!raw) return false;
|
|
11485
|
+
const v = raw.trim().toLowerCase();
|
|
11486
|
+
return v === "1" || v === "true" || v === "on" || v === "yes";
|
|
11487
|
+
}
|
|
11488
|
+
function ledgerRecordQuarantinedEvent(event, reason) {
|
|
11489
|
+
try {
|
|
11490
|
+
const finalSummary = readMeshCompletionSummary(event.metadataEvent || {});
|
|
11491
|
+
appendLedgerEntry(event.meshId, {
|
|
11492
|
+
kind: "event_held",
|
|
11493
|
+
...event.nodeId ? { nodeId: event.nodeId } : {},
|
|
11494
|
+
payload: {
|
|
11495
|
+
event: event.event,
|
|
11496
|
+
reason,
|
|
11497
|
+
recoverable: true,
|
|
11498
|
+
nodeLabel: event.nodeLabel,
|
|
11499
|
+
...event.workspace ? { workspace: event.workspace } : {},
|
|
11500
|
+
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
11501
|
+
...readNonEmptyString2(event.eventId) ? { eventId: event.eventId } : {},
|
|
11502
|
+
queuedAt: event.queuedAt,
|
|
11503
|
+
...finalSummary ? { finalSummary } : {}
|
|
11504
|
+
}
|
|
11505
|
+
});
|
|
11506
|
+
} catch (e) {
|
|
11507
|
+
LOG.warn("MeshEventsV2", `Failed to ledger-record v2-quarantined ${event.event} for mesh ${event.meshId}: ${e?.message || e}`);
|
|
11508
|
+
}
|
|
11509
|
+
}
|
|
11510
|
+
function getMeshV2DrainCounters() {
|
|
11511
|
+
return { ...meshV2DrainCounters };
|
|
11512
|
+
}
|
|
11482
11513
|
function warnV2Once(key2, message) {
|
|
11483
11514
|
if (warnedV2Violations.has(key2)) return;
|
|
11484
11515
|
warnedV2Violations.add(key2);
|
|
@@ -11510,12 +11541,22 @@ function identityDeliversTo(intendedFor, drainer) {
|
|
|
11510
11541
|
}
|
|
11511
11542
|
function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
11512
11543
|
if (!drainer) return events;
|
|
11544
|
+
const enforce = isMeshProtocolV2EnforceEnabled();
|
|
11513
11545
|
const bump = (k) => {
|
|
11514
11546
|
if (ctx.countMetrics) meshV2DrainCounters[k]++;
|
|
11515
11547
|
};
|
|
11516
11548
|
const kept = [];
|
|
11517
11549
|
for (const event of events) {
|
|
11518
11550
|
if (!isV2Event(event)) {
|
|
11551
|
+
if (enforce) {
|
|
11552
|
+
bump("v1UnversionedQuarantined");
|
|
11553
|
+
if (ctx.countMetrics) ledgerRecordQuarantinedEvent(event, "v2_enforce_unversioned_quarantined");
|
|
11554
|
+
warnV2Once(
|
|
11555
|
+
`${event.meshId}::${event.eventId ?? event.event}::v1-quarantined`,
|
|
11556
|
+
`v2 ENFORCE: unversioned ${event.event} on mesh ${event.meshId} QUARANTINED (no v2 envelope \u2014 held back, not delivered; ledger-recorded recoverable). A producer path still emits v1.`
|
|
11557
|
+
);
|
|
11558
|
+
continue;
|
|
11559
|
+
}
|
|
11519
11560
|
bump("v1BroadcastAccepted");
|
|
11520
11561
|
kept.push(event);
|
|
11521
11562
|
continue;
|
|
@@ -11524,6 +11565,15 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
|
11524
11565
|
try {
|
|
11525
11566
|
validated = assertPendingMeshCoordinatorEventV2(event);
|
|
11526
11567
|
} catch (e) {
|
|
11568
|
+
if (enforce) {
|
|
11569
|
+
bump("v2ValidationFailedQuarantined");
|
|
11570
|
+
if (ctx.countMetrics) ledgerRecordQuarantinedEvent(event, "v2_enforce_validation_failed_quarantined");
|
|
11571
|
+
warnV2Once(
|
|
11572
|
+
`${event.meshId}::${event.eventId ?? event.event}::invalid-quarantined`,
|
|
11573
|
+
`v2 ENFORCE: envelope validation failed for ${event.event} on mesh ${event.meshId} \u2014 QUARANTINED (held back, not delivered; ledger-recorded recoverable): ${e?.message || e}`
|
|
11574
|
+
);
|
|
11575
|
+
continue;
|
|
11576
|
+
}
|
|
11527
11577
|
bump("v2ValidationFailedAccepted");
|
|
11528
11578
|
warnV2Once(
|
|
11529
11579
|
`${event.meshId}::${event.eventId ?? event.event}::invalid`,
|
|
@@ -12108,7 +12158,15 @@ var init_mesh_events_pending = __esm({
|
|
|
12108
12158
|
* coordinatorRunId change orphaned them). */
|
|
12109
12159
|
v2ReattributedToDrainer: 0,
|
|
12110
12160
|
/** v1 (unversioned) events passed through as broadcast (rollout baseline). */
|
|
12111
|
-
v1BroadcastAccepted: 0
|
|
12161
|
+
v1BroadcastAccepted: 0,
|
|
12162
|
+
/** T6 enforce: v2 events that FAILED validation and were QUARANTINED (held back
|
|
12163
|
+
* from delivery, not dropped). Non-zero here means a producer is still emitting a
|
|
12164
|
+
* malformed envelope after enforce was turned on. */
|
|
12165
|
+
v2ValidationFailedQuarantined: 0,
|
|
12166
|
+
/** T6 enforce: v1 (unversioned) events QUARANTINED because no v2 envelope could be
|
|
12167
|
+
* derived at emit time. Non-zero here means a producer path still emits v1 after
|
|
12168
|
+
* enforce — it should reach 0 once every node is on a v2-stamping build. */
|
|
12169
|
+
v1UnversionedQuarantined: 0
|
|
12112
12170
|
};
|
|
12113
12171
|
warnedV2Violations = /* @__PURE__ */ new Set();
|
|
12114
12172
|
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
@@ -18312,6 +18370,21 @@ function resolveAckedDeathDeadlineMs() {
|
|
|
18312
18370
|
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
18313
18371
|
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
18314
18372
|
}
|
|
18373
|
+
function getMeshV2BackstopCounters() {
|
|
18374
|
+
return { ...meshV2BackstopCounters };
|
|
18375
|
+
}
|
|
18376
|
+
function meshProtocolV2EnforceOn() {
|
|
18377
|
+
const raw = process.env.MESH_PROTOCOL_V2_ENFORCE;
|
|
18378
|
+
if (typeof raw !== "string") return false;
|
|
18379
|
+
const v = raw.trim().toLowerCase();
|
|
18380
|
+
return v === "1" || v === "true" || v === "on" || v === "yes";
|
|
18381
|
+
}
|
|
18382
|
+
function recordBackstopFire(kind, detail) {
|
|
18383
|
+
meshV2BackstopCounters[kind]++;
|
|
18384
|
+
if (meshProtocolV2EnforceOn()) {
|
|
18385
|
+
LOG.warn("MeshReconcileV2", `v2 ENFORCE last-resort backstop fired (${kind}): ${detail}. Under a healthy v2 completion contract this should be 0 \u2014 a worker's real terminal emit was lost/late.`);
|
|
18386
|
+
}
|
|
18387
|
+
}
|
|
18315
18388
|
function inFlightSynthKey(meshId, taskId) {
|
|
18316
18389
|
return `${meshId}::${taskId}`;
|
|
18317
18390
|
}
|
|
@@ -19226,6 +19299,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
19226
19299
|
};
|
|
19227
19300
|
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
19228
19301
|
const isAcked = dispatch.status === "acked";
|
|
19302
|
+
let backstopKind;
|
|
19229
19303
|
let payload = null;
|
|
19230
19304
|
let readFailed = false;
|
|
19231
19305
|
try {
|
|
@@ -19290,6 +19364,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
19290
19364
|
const idleHeldMs = nowMs - idleSinceMs;
|
|
19291
19365
|
if (idleHeldMs >= fastTrackGraceMs) {
|
|
19292
19366
|
fastTrackReady = true;
|
|
19367
|
+
backstopKind = "ackedHoldFastTrackFired";
|
|
19293
19368
|
LOG.info("MeshReconcile", `Acked-hold transcript fast-track: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle WITH a final assistant message for ${Math.round(idleHeldMs / 1e3)}s continuous (grace ${Math.round(fastTrackGraceMs / 1e3)}s) \u2014 promoting the synth ahead of the ${Math.round(deathDeadlineMs / 1e3)}s death backstop; the worker's real emit was lost/late and a later one no-ops idempotently.`);
|
|
19294
19369
|
}
|
|
19295
19370
|
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
@@ -19300,6 +19375,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
19300
19375
|
continue;
|
|
19301
19376
|
}
|
|
19302
19377
|
if (!fastTrackReady) {
|
|
19378
|
+
backstopKind = "ackedHoldDeathDeadlineFired";
|
|
19303
19379
|
LOG.warn("MeshReconcile", `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1e3)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1e3)}s) \u2014 synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
|
|
19304
19380
|
}
|
|
19305
19381
|
}
|
|
@@ -19344,6 +19420,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
19344
19420
|
source: "daemon_reconcile_transcript_completion"
|
|
19345
19421
|
});
|
|
19346
19422
|
if (result.reconciled) {
|
|
19423
|
+
recordBackstopFire(backstopKind ?? "phase4SynthesisFired", `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
|
|
19347
19424
|
LOG.info("MeshReconcile", `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
|
|
19348
19425
|
}
|
|
19349
19426
|
} catch (e) {
|
|
@@ -19473,7 +19550,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
19473
19550
|
}
|
|
19474
19551
|
};
|
|
19475
19552
|
}
|
|
19476
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, rehydratedHoldMeshes, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
19553
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, rehydratedHoldMeshes, meshV2BackstopCounters, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
19477
19554
|
var init_mesh_reconcile_loop = __esm({
|
|
19478
19555
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
19479
19556
|
"use strict";
|
|
@@ -19501,6 +19578,14 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
19501
19578
|
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
19502
19579
|
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
19503
19580
|
rehydratedHoldMeshes = /* @__PURE__ */ new Set();
|
|
19581
|
+
meshV2BackstopCounters = {
|
|
19582
|
+
/** PHASE-4 transcript synthesis actually reconciled a missing completion. */
|
|
19583
|
+
phase4SynthesisFired: 0,
|
|
19584
|
+
/** Acked-hold transcript fast-track promoted a synth ahead of the death deadline. */
|
|
19585
|
+
ackedHoldFastTrackFired: 0,
|
|
19586
|
+
/** Acked-hold death-deadline backstop released a held synth (the 8-min net). */
|
|
19587
|
+
ackedHoldDeathDeadlineFired: 0
|
|
19588
|
+
};
|
|
19504
19589
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
19505
19590
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
19506
19591
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
@@ -19520,9 +19605,12 @@ __export(mesh_events_exports, {
|
|
|
19520
19605
|
__resetMeshWorkspaceCacheForTests: () => __resetMeshWorkspaceCacheForTests,
|
|
19521
19606
|
clearPendingMeshCoordinatorEvents: () => clearPendingMeshCoordinatorEvents,
|
|
19522
19607
|
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
19608
|
+
getMeshV2BackstopCounters: () => getMeshV2BackstopCounters,
|
|
19609
|
+
getMeshV2DrainCounters: () => getMeshV2DrainCounters,
|
|
19523
19610
|
getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
|
|
19524
19611
|
handleMeshForwardEvent: () => handleMeshForwardEvent,
|
|
19525
19612
|
isMeshCoordinatorEvent: () => isMeshCoordinatorEvent,
|
|
19613
|
+
isMeshProtocolV2EnforceEnabled: () => isMeshProtocolV2EnforceEnabled,
|
|
19526
19614
|
isSessionActivelyGenerating: () => isSessionActivelyGenerating,
|
|
19527
19615
|
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
19528
19616
|
readV2EnvelopeFromWire: () => readV2EnvelopeFromWire,
|
|
@@ -40601,15 +40689,37 @@ function executeSqlite(src, input) {
|
|
|
40601
40689
|
}
|
|
40602
40690
|
try {
|
|
40603
40691
|
const requested = input.providerSessionId || "";
|
|
40604
|
-
const
|
|
40605
|
-
|
|
40606
|
-
|
|
40607
|
-
|
|
40608
|
-
|
|
40609
|
-
|
|
40610
|
-
|
|
40692
|
+
const resolveClusterIds = (anchorId) => {
|
|
40693
|
+
const ids = /* @__PURE__ */ new Set();
|
|
40694
|
+
if (anchorId) ids.add(anchorId);
|
|
40695
|
+
if (src.session_cluster_query && anchorId) {
|
|
40696
|
+
try {
|
|
40697
|
+
const rows = db.prepare(src.session_cluster_query).all(anchorId);
|
|
40698
|
+
for (const row of rows) {
|
|
40699
|
+
const idRaw = Object.values(row)[0];
|
|
40700
|
+
if (idRaw != null && String(idRaw)) ids.add(String(idRaw));
|
|
40701
|
+
}
|
|
40702
|
+
} catch {
|
|
40703
|
+
}
|
|
40611
40704
|
}
|
|
40612
|
-
return
|
|
40705
|
+
return Array.from(ids);
|
|
40706
|
+
};
|
|
40707
|
+
const resolveMessagesFor = (anchorId) => {
|
|
40708
|
+
if (!anchorId) return null;
|
|
40709
|
+
const clusterIds = resolveClusterIds(anchorId);
|
|
40710
|
+
const merged = [];
|
|
40711
|
+
for (const id of clusterIds) {
|
|
40712
|
+
let rows;
|
|
40713
|
+
try {
|
|
40714
|
+
rows = db.prepare(src.message_query).all(id);
|
|
40715
|
+
} catch {
|
|
40716
|
+
continue;
|
|
40717
|
+
}
|
|
40718
|
+
if (rows && rows.length > 0) merged.push(...rows);
|
|
40719
|
+
}
|
|
40720
|
+
if (merged.length === 0) return null;
|
|
40721
|
+
if (clusterIds.length > 1) sortRowsByMappedTimestamp(merged, src.message_map);
|
|
40722
|
+
return merged;
|
|
40613
40723
|
};
|
|
40614
40724
|
const resolveNewestSessionId = () => {
|
|
40615
40725
|
let sessionRow;
|
|
@@ -40666,6 +40776,20 @@ function executeSqlite(src, input) {
|
|
|
40666
40776
|
}
|
|
40667
40777
|
}
|
|
40668
40778
|
}
|
|
40779
|
+
function sortRowsByMappedTimestamp(rows, map) {
|
|
40780
|
+
if (!map.timestamp_ms) return;
|
|
40781
|
+
const keyed = rows.map((row, index) => {
|
|
40782
|
+
const parsed = parseTimestamp(jsonPathGet(row, map.timestamp_ms));
|
|
40783
|
+
return { row, index, ts: parsed == null ? Number.NaN : parsed };
|
|
40784
|
+
});
|
|
40785
|
+
keyed.sort((a, b) => {
|
|
40786
|
+
const aHas = !Number.isNaN(a.ts);
|
|
40787
|
+
const bHas = !Number.isNaN(b.ts);
|
|
40788
|
+
if (aHas && bHas && a.ts !== b.ts) return a.ts - b.ts;
|
|
40789
|
+
return a.index - b.index;
|
|
40790
|
+
});
|
|
40791
|
+
for (let i = 0; i < keyed.length; i += 1) rows[i] = keyed[i].row;
|
|
40792
|
+
}
|
|
40669
40793
|
function expandPath2(template, input, opts) {
|
|
40670
40794
|
if (!template) return null;
|
|
40671
40795
|
let out = template;
|
|
@@ -43290,6 +43414,19 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43290
43414
|
}
|
|
43291
43415
|
return probe;
|
|
43292
43416
|
}
|
|
43417
|
+
/**
|
|
43418
|
+
* The spawned CLI's env overrides (e.g. the mesh coordinator points hermes
|
|
43419
|
+
* at a per-coordinator HERMES_HOME so its state.db lives in a tmpdir instead
|
|
43420
|
+
* of ~/.hermes). The native-history executor expands `${HERMES_HOME:-~/.hermes}`
|
|
43421
|
+
* from this map, so the completion gate MUST pass it through — otherwise the
|
|
43422
|
+
* gate reads ~/.hermes, finds no coordinator-session transcript, and
|
|
43423
|
+
* false-fires missing_final_assistant on every coordinator turn.
|
|
43424
|
+
*/
|
|
43425
|
+
spawnedEnvOverrides() {
|
|
43426
|
+
const meta = typeof this.adapter?.getRuntimeMetadata === "function" ? this.adapter.getRuntimeMetadata() : void 0;
|
|
43427
|
+
const env = meta && typeof meta === "object" ? meta.spawnedEnv : void 0;
|
|
43428
|
+
return env && typeof env === "object" ? env : void 0;
|
|
43429
|
+
}
|
|
43293
43430
|
readExternalCompletionMessages() {
|
|
43294
43431
|
const adapterOwnsMessagesElsewhere = this.adapter?.chatMessagesOwnedExternally === true;
|
|
43295
43432
|
if (!adapterOwnsMessagesElsewhere) return null;
|
|
@@ -43310,6 +43447,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43310
43447
|
historyBehavior: this.provider.historyBehavior,
|
|
43311
43448
|
scripts: this.provider.scripts,
|
|
43312
43449
|
sessionStartedAtMs: this.startedAt,
|
|
43450
|
+
envOverrides: this.spawnedEnvOverrides(),
|
|
43313
43451
|
forceRefresh: true
|
|
43314
43452
|
});
|
|
43315
43453
|
if (restoredHistory.source !== "provider-native") {
|
|
@@ -43835,10 +43973,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43835
43973
|
if (buttonIndex < 0 || !hasReliableConsentAnchor) {
|
|
43836
43974
|
return autoApproveActive;
|
|
43837
43975
|
}
|
|
43976
|
+
const affirmativeAnchor = normalizeApprovalLabel(buttonLabel);
|
|
43838
43977
|
const modalSignature = [
|
|
43839
43978
|
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
43840
|
-
|
|
43841
|
-
buttonIndex
|
|
43979
|
+
affirmativeAnchor
|
|
43842
43980
|
].join("::");
|
|
43843
43981
|
const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
|
|
43844
43982
|
const busySignature = `${approvalEntrySeq}::${modalSignature}`;
|
|
@@ -48882,14 +49020,44 @@ function openDb() {
|
|
|
48882
49020
|
return null;
|
|
48883
49021
|
}
|
|
48884
49022
|
}
|
|
49023
|
+
function resolveClusterSessionIds(db, anchorId) {
|
|
49024
|
+
if (!anchorId) return [];
|
|
49025
|
+
try {
|
|
49026
|
+
const rows = db.prepare(
|
|
49027
|
+
`WITH RECURSIVE
|
|
49028
|
+
up(id) AS (
|
|
49029
|
+
SELECT id FROM sessions WHERE id = ?
|
|
49030
|
+
UNION
|
|
49031
|
+
SELECT s.parent_session_id FROM sessions s JOIN up ON s.id = up.id
|
|
49032
|
+
WHERE s.parent_session_id IS NOT NULL
|
|
49033
|
+
),
|
|
49034
|
+
cluster(id) AS (
|
|
49035
|
+
SELECT id FROM up
|
|
49036
|
+
UNION
|
|
49037
|
+
SELECT s.id FROM sessions s JOIN cluster ON s.parent_session_id = cluster.id
|
|
49038
|
+
)
|
|
49039
|
+
SELECT id FROM cluster`
|
|
49040
|
+
).all(anchorId);
|
|
49041
|
+
const ids = /* @__PURE__ */ new Set([anchorId]);
|
|
49042
|
+
for (const r of rows) {
|
|
49043
|
+
if (r && r.id != null && String(r.id)) ids.add(String(r.id));
|
|
49044
|
+
}
|
|
49045
|
+
return Array.from(ids);
|
|
49046
|
+
} catch {
|
|
49047
|
+
return [anchorId];
|
|
49048
|
+
}
|
|
49049
|
+
}
|
|
48885
49050
|
function loadMessagesForSession(db, sessionId) {
|
|
49051
|
+
const clusterIds = resolveClusterSessionIds(db, sessionId);
|
|
49052
|
+
if (clusterIds.length === 0) return [];
|
|
49053
|
+
const placeholders = clusterIds.map(() => "?").join(", ");
|
|
48886
49054
|
const rows = db.prepare(
|
|
48887
49055
|
`SELECT id, role, COALESCE(NULLIF(content, ''), tool_calls) AS content, timestamp
|
|
48888
49056
|
FROM messages
|
|
48889
|
-
WHERE session_id
|
|
49057
|
+
WHERE session_id IN (${placeholders})
|
|
48890
49058
|
AND ((content IS NOT NULL AND content != '') OR (tool_calls IS NOT NULL AND tool_calls != ''))
|
|
48891
49059
|
ORDER BY timestamp ASC, id ASC`
|
|
48892
|
-
).all(
|
|
49060
|
+
).all(...clusterIds);
|
|
48893
49061
|
const out = [];
|
|
48894
49062
|
for (const r of rows) {
|
|
48895
49063
|
const role = normalizeHermesRole(r.role);
|
|
@@ -53445,7 +53613,12 @@ var meshEventsHandlers = {
|
|
|
53445
53613
|
return { success: true, events: [], heldForBusyLocalCoordinator: true, hasLiveCliCoordinator };
|
|
53446
53614
|
}
|
|
53447
53615
|
const events = drainPendingMeshCoordinatorEvents(meshId || void 0, coordinatorDaemonId);
|
|
53448
|
-
|
|
53616
|
+
const meshProtocolV2Counters = {
|
|
53617
|
+
enforce: isMeshProtocolV2EnforceEnabled(),
|
|
53618
|
+
drain: { ...getMeshV2DrainCounters() },
|
|
53619
|
+
backstop: { ...getMeshV2BackstopCounters() }
|
|
53620
|
+
};
|
|
53621
|
+
return { success: true, events, hasLiveCliCoordinator, meshProtocolV2Counters, ...selfCoordinatorInboxRead ? { surfacedForSelfCoordinator: true } : {} };
|
|
53449
53622
|
},
|
|
53450
53623
|
interactive_prompt_response: async (ctx, args) => {
|
|
53451
53624
|
const sessionId = typeof args?.targetSessionId === "string" && args.targetSessionId.trim() ? args.targetSessionId.trim() : typeof args?.sessionId === "string" && args.sessionId.trim() ? args.sessionId.trim() : "";
|
|
@@ -54471,6 +54644,11 @@ var meshStatusHandlers = {
|
|
|
54471
54644
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : ctx.deps.statusInstanceId || void 0;
|
|
54472
54645
|
const pendingCoordinatorEvents = getPendingMeshCoordinatorEvents(meshId, callerCoordinatorDaemonId);
|
|
54473
54646
|
const unroutableDeliveries = getRecentUnroutableDeliveries();
|
|
54647
|
+
const meshProtocolV2Counters = {
|
|
54648
|
+
enforce: isMeshProtocolV2EnforceEnabled(),
|
|
54649
|
+
drain: { ...getMeshV2DrainCounters() },
|
|
54650
|
+
backstop: { ...getMeshV2BackstopCounters() }
|
|
54651
|
+
};
|
|
54474
54652
|
const previewFreshness = (() => {
|
|
54475
54653
|
const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate && fs27.existsSync(candidate));
|
|
54476
54654
|
return localRepoRoot ? buildPreviewFreshness(localRepoRoot) : void 0;
|
|
@@ -54560,6 +54738,7 @@ var meshStatusHandlers = {
|
|
|
54560
54738
|
...historicalSessions ? { historicalSessions } : {},
|
|
54561
54739
|
...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
|
|
54562
54740
|
...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {},
|
|
54741
|
+
meshProtocolV2Counters,
|
|
54563
54742
|
activeRefineJobs: Array.from(ctx.runningRefineJobs.values()).filter((job) => job.meshId === meshId).map((job) => ({
|
|
54564
54743
|
jobId: job.jobId,
|
|
54565
54744
|
nodeId: job.targetNodeId,
|
|
@@ -54569,12 +54748,13 @@ var meshStatusHandlers = {
|
|
|
54569
54748
|
targetCoordinatorDaemonId: job.targetCoordinatorDaemonId
|
|
54570
54749
|
}))
|
|
54571
54750
|
};
|
|
54572
|
-
const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, ...cacheableStatusResult } = statusResult;
|
|
54751
|
+
const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, meshProtocolV2Counters: _meshProtocolV2Counters, ...cacheableStatusResult } = statusResult;
|
|
54573
54752
|
const rememberedStatus = verboseMissions ? cacheableStatusResult : ctx.rememberAggregateMeshStatus(meshId, cacheableStatusResult, refreshReason);
|
|
54574
54753
|
const returnedStatus = {
|
|
54575
54754
|
...rememberedStatus,
|
|
54576
54755
|
...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
|
|
54577
|
-
...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {}
|
|
54756
|
+
...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {},
|
|
54757
|
+
meshProtocolV2Counters
|
|
54578
54758
|
};
|
|
54579
54759
|
logRepoMeshStatusDebug("return_live", {
|
|
54580
54760
|
meshId,
|
|
@@ -54817,7 +54997,6 @@ cleanOldFiles();
|
|
|
54817
54997
|
// src/commands/router.ts
|
|
54818
54998
|
init_debug_trace();
|
|
54819
54999
|
init_mesh_host_ownership();
|
|
54820
|
-
init_mesh_work_queue();
|
|
54821
55000
|
var fs33 = __toESM(require("fs"));
|
|
54822
55001
|
|
|
54823
55002
|
// src/mesh/mesh-node-identity.ts
|
|
@@ -59211,6 +59390,177 @@ async function cleanupMeshSessions(self, args) {
|
|
|
59211
59390
|
};
|
|
59212
59391
|
}
|
|
59213
59392
|
|
|
59393
|
+
// src/commands/router-aggregate-status.ts
|
|
59394
|
+
init_dist();
|
|
59395
|
+
init_mesh_work_queue();
|
|
59396
|
+
function cloneJsonValue(value) {
|
|
59397
|
+
if (typeof structuredClone === "function") return structuredClone(value);
|
|
59398
|
+
return JSON.parse(JSON.stringify(value));
|
|
59399
|
+
}
|
|
59400
|
+
function hydrateCachedAggregateMeshStatusFromInline(self, snapshot, mesh, options) {
|
|
59401
|
+
if (!mesh || typeof mesh !== "object" || !Array.isArray(mesh.nodes) || !Array.isArray(snapshot?.nodes)) return snapshot;
|
|
59402
|
+
const inlineNodesById = /* @__PURE__ */ new Map();
|
|
59403
|
+
for (const node of mesh.nodes) {
|
|
59404
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
59405
|
+
if (nodeId) inlineNodesById.set(nodeId, node);
|
|
59406
|
+
}
|
|
59407
|
+
if (!inlineNodesById.size) return snapshot;
|
|
59408
|
+
let changed = false;
|
|
59409
|
+
const unavailableNodeIds = /* @__PURE__ */ new Set();
|
|
59410
|
+
const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
|
|
59411
|
+
const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
|
|
59412
|
+
const deadNodeIds = /* @__PURE__ */ new Set();
|
|
59413
|
+
for (const node of mesh.nodes) {
|
|
59414
|
+
if (!isDeadLocalWorktreeNode(node)) continue;
|
|
59415
|
+
const deadId = readInlineMeshNodeId(node);
|
|
59416
|
+
if (deadId) deadNodeIds.add(deadId);
|
|
59417
|
+
}
|
|
59418
|
+
let droppedDeadUnavailable = false;
|
|
59419
|
+
for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
|
|
59420
|
+
const nodeId = readStringValue(entry);
|
|
59421
|
+
if (!nodeId) continue;
|
|
59422
|
+
if (deadNodeIds.has(nodeId)) {
|
|
59423
|
+
droppedDeadUnavailable = true;
|
|
59424
|
+
continue;
|
|
59425
|
+
}
|
|
59426
|
+
unavailableNodeIds.add(nodeId);
|
|
59427
|
+
}
|
|
59428
|
+
if (droppedDeadUnavailable) changed = true;
|
|
59429
|
+
const nodes = snapshot.nodes.map((statusNode) => {
|
|
59430
|
+
const nodeId = normalizeMeshNodeId(statusNode);
|
|
59431
|
+
const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
|
|
59432
|
+
if (!inlineNode) return statusNode;
|
|
59433
|
+
const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
|
|
59434
|
+
if (!liveGit) return statusNode;
|
|
59435
|
+
const nextStatus = { ...statusNode };
|
|
59436
|
+
nextStatus.git = liveGit;
|
|
59437
|
+
nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
|
|
59438
|
+
applyInlineMeshBranchConvergence(mesh, inlineNode, nextStatus);
|
|
59439
|
+
nextStatus.launchReady = readBooleanValue(nextStatus.launchReady) ?? true;
|
|
59440
|
+
const connection = readObjectRecord(nextStatus.connection);
|
|
59441
|
+
const connectionState = readStringValue(connection.state);
|
|
59442
|
+
const connectionReported = readBooleanValue(connection.reported) ?? false;
|
|
59443
|
+
if (!connectionReported || connectionState === "unknown") {
|
|
59444
|
+
nextStatus.connection = buildLivePeerGitConnection(connection);
|
|
59445
|
+
}
|
|
59446
|
+
delete nextStatus.gitProbePending;
|
|
59447
|
+
const error = readStringValue(nextStatus.error);
|
|
59448
|
+
if (error && /pending_git|git probe|live peer git snapshot|no peer git snapshot/i.test(error)) delete nextStatus.error;
|
|
59449
|
+
if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = "online";
|
|
59450
|
+
if (nodeId) unavailableNodeIds.delete(nodeId);
|
|
59451
|
+
changed = true;
|
|
59452
|
+
return nextStatus;
|
|
59453
|
+
});
|
|
59454
|
+
const aggregateDirectTruthSatisfied = sourceOfTruth.coordinatorOwnsLiveTruth === true || directPeerTruth.satisfied === true;
|
|
59455
|
+
if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied)) return snapshot;
|
|
59456
|
+
const nextSourceOfTruth = {
|
|
59457
|
+
...sourceOfTruth,
|
|
59458
|
+
...Object.keys(directPeerTruth).length ? {
|
|
59459
|
+
directPeerTruth: {
|
|
59460
|
+
...directPeerTruth,
|
|
59461
|
+
satisfied: options?.requireDirectPeerTruth === true ? aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
|
|
59462
|
+
unavailableNodeIds: [...unavailableNodeIds]
|
|
59463
|
+
},
|
|
59464
|
+
...options?.requireDirectPeerTruth === true ? {
|
|
59465
|
+
coordinatorOwnsLiveTruth: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0,
|
|
59466
|
+
currentStatus: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 ? "live_git_and_session_probes" : "direct_peer_truth_unavailable"
|
|
59467
|
+
} : {}
|
|
59468
|
+
} : {}
|
|
59469
|
+
};
|
|
59470
|
+
return {
|
|
59471
|
+
...snapshot,
|
|
59472
|
+
...options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied ? {
|
|
59473
|
+
success: false,
|
|
59474
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
59475
|
+
error: "Selected coordinator could not confirm direct mesh truth for every remote node yet."
|
|
59476
|
+
} : {},
|
|
59477
|
+
sourceOfTruth: nextSourceOfTruth,
|
|
59478
|
+
branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodes),
|
|
59479
|
+
nodes
|
|
59480
|
+
};
|
|
59481
|
+
}
|
|
59482
|
+
function getCachedAggregateMeshStatus(self, meshId, mesh, options) {
|
|
59483
|
+
const cached3 = self.aggregateMeshStatusCache.get(meshId);
|
|
59484
|
+
if (!cached3?.snapshot || cached3.snapshot.success !== true || !Array.isArray(cached3.snapshot.nodes)) return null;
|
|
59485
|
+
if (cached3.queueRevision !== getMeshQueueRevision(meshId)) return null;
|
|
59486
|
+
let snapshot = cloneJsonValue(cached3.snapshot);
|
|
59487
|
+
snapshot = hydrateCachedAggregateMeshStatusFromInline(self, snapshot, mesh, options);
|
|
59488
|
+
if (!options?.allowStalePending && shouldRefreshStalePendingAggregate(snapshot, options)) return null;
|
|
59489
|
+
const ageMs = Math.max(0, Date.now() - cached3.builtAt);
|
|
59490
|
+
const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
|
|
59491
|
+
snapshot.sourceOfTruth = {
|
|
59492
|
+
...sourceOfTruth,
|
|
59493
|
+
aggregateSnapshot: {
|
|
59494
|
+
...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
|
|
59495
|
+
owner: "coordinator_daemon_memory",
|
|
59496
|
+
cached: true,
|
|
59497
|
+
source: "memory",
|
|
59498
|
+
refreshReason: "memory_cache_hit",
|
|
59499
|
+
ageMs,
|
|
59500
|
+
cachedAt: new Date(cached3.builtAt).toISOString(),
|
|
59501
|
+
returnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
59502
|
+
}
|
|
59503
|
+
};
|
|
59504
|
+
return snapshot;
|
|
59505
|
+
}
|
|
59506
|
+
function rememberAggregateMeshStatus(self, meshId, snapshot, refreshReason) {
|
|
59507
|
+
if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
|
|
59508
|
+
const builtAt = Date.now();
|
|
59509
|
+
const next = cloneJsonValue(snapshot);
|
|
59510
|
+
const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
|
|
59511
|
+
next.sourceOfTruth = {
|
|
59512
|
+
...sourceOfTruth,
|
|
59513
|
+
aggregateSnapshot: {
|
|
59514
|
+
owner: "coordinator_daemon_memory",
|
|
59515
|
+
cached: false,
|
|
59516
|
+
source: "live_refresh",
|
|
59517
|
+
refreshReason,
|
|
59518
|
+
ageMs: 0,
|
|
59519
|
+
cachedAt: new Date(builtAt).toISOString(),
|
|
59520
|
+
returnedAt: new Date(builtAt).toISOString()
|
|
59521
|
+
}
|
|
59522
|
+
};
|
|
59523
|
+
self.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: cloneJsonValue(next), queueRevision: getMeshQueueRevision(meshId) });
|
|
59524
|
+
return next;
|
|
59525
|
+
}
|
|
59526
|
+
|
|
59527
|
+
// src/commands/router-mesh-session-owner.ts
|
|
59528
|
+
init_dist();
|
|
59529
|
+
function resolveRemoteMeshSessionOwnerDaemonId(self, sessionId, ownerNodeIdHint) {
|
|
59530
|
+
const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
|
|
59531
|
+
const nodeHint = typeof ownerNodeIdHint === "string" ? ownerNodeIdHint.trim() : "";
|
|
59532
|
+
if (!trimmed && !nodeHint) return void 0;
|
|
59533
|
+
const selfDaemonId = self.deps.statusInstanceId;
|
|
59534
|
+
const candidates = collectMeshSessionOwnerCandidateNodes(self);
|
|
59535
|
+
if (trimmed) {
|
|
59536
|
+
for (const node of candidates) {
|
|
59537
|
+
if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
|
|
59538
|
+
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
59539
|
+
if (!nodeDaemonId) continue;
|
|
59540
|
+
if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
|
|
59541
|
+
return nodeDaemonId;
|
|
59542
|
+
}
|
|
59543
|
+
}
|
|
59544
|
+
if (nodeHint) {
|
|
59545
|
+
for (const node of candidates) {
|
|
59546
|
+
if (!meshNodeIdMatches(node, nodeHint)) continue;
|
|
59547
|
+
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
59548
|
+
if (!nodeDaemonId) continue;
|
|
59549
|
+
if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
|
|
59550
|
+
return nodeDaemonId;
|
|
59551
|
+
}
|
|
59552
|
+
}
|
|
59553
|
+
return void 0;
|
|
59554
|
+
}
|
|
59555
|
+
function collectMeshSessionOwnerCandidateNodes(self) {
|
|
59556
|
+
const nodes = self.getCachedInlineMeshNodes();
|
|
59557
|
+
for (const cached3 of self.aggregateMeshStatusCache.values()) {
|
|
59558
|
+
const snapshotNodes = cached3?.snapshot?.nodes;
|
|
59559
|
+
if (Array.isArray(snapshotNodes)) nodes.push(...snapshotNodes);
|
|
59560
|
+
}
|
|
59561
|
+
return nodes;
|
|
59562
|
+
}
|
|
59563
|
+
|
|
59214
59564
|
// src/mesh/mesh-coordinator-config.ts
|
|
59215
59565
|
init_logger();
|
|
59216
59566
|
var yaml5 = __toESM(require("js-yaml"));
|
|
@@ -59379,7 +59729,8 @@ var DaemonCommandRouter = class {
|
|
|
59379
59729
|
* on disk) clears the tombstone and merges normally, preserving clone
|
|
59380
59730
|
* worktree visibility and legitimate node re-creation. */
|
|
59381
59731
|
removedInlineMeshNodeIds = /* @__PURE__ */ new Map();
|
|
59382
|
-
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default.
|
|
59732
|
+
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default.
|
|
59733
|
+
* Public (not private) so the extracted ./router-aggregate-status.ts orchestration can reach it via `self`. */
|
|
59383
59734
|
aggregateMeshStatusCache = /* @__PURE__ */ new Map();
|
|
59384
59735
|
/** Shared per-peer git_status probe dedup + recently-probed reuse gate.
|
|
59385
59736
|
* Spans separate mesh_status/get_mesh calls so the dashboard auto-retry
|
|
@@ -59401,135 +59752,19 @@ var DaemonCommandRouter = class {
|
|
|
59401
59752
|
constructor(deps) {
|
|
59402
59753
|
this.deps = deps;
|
|
59403
59754
|
}
|
|
59404
|
-
|
|
59405
|
-
|
|
59406
|
-
|
|
59407
|
-
|
|
59755
|
+
// ─── Aggregate mesh-status cache ────────────────────────────────────
|
|
59756
|
+
// Implementation lives in ./router-aggregate-status.ts (behavior-preserving
|
|
59757
|
+
// code move). Kept here as thin delegators: getCachedAggregateMeshStatus /
|
|
59758
|
+
// rememberAggregateMeshStatus are bound into HighFamilyContext, so callers
|
|
59759
|
+
// reach these via `self.` for correct instance dispatch.
|
|
59408
59760
|
hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options) {
|
|
59409
|
-
|
|
59410
|
-
const inlineNodesById = /* @__PURE__ */ new Map();
|
|
59411
|
-
for (const node of mesh.nodes) {
|
|
59412
|
-
const nodeId = readInlineMeshNodeId(node);
|
|
59413
|
-
if (nodeId) inlineNodesById.set(nodeId, node);
|
|
59414
|
-
}
|
|
59415
|
-
if (!inlineNodesById.size) return snapshot;
|
|
59416
|
-
let changed = false;
|
|
59417
|
-
const unavailableNodeIds = /* @__PURE__ */ new Set();
|
|
59418
|
-
const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
|
|
59419
|
-
const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
|
|
59420
|
-
const deadNodeIds = /* @__PURE__ */ new Set();
|
|
59421
|
-
for (const node of mesh.nodes) {
|
|
59422
|
-
if (!isDeadLocalWorktreeNode(node)) continue;
|
|
59423
|
-
const deadId = readInlineMeshNodeId(node);
|
|
59424
|
-
if (deadId) deadNodeIds.add(deadId);
|
|
59425
|
-
}
|
|
59426
|
-
let droppedDeadUnavailable = false;
|
|
59427
|
-
for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
|
|
59428
|
-
const nodeId = readStringValue(entry);
|
|
59429
|
-
if (!nodeId) continue;
|
|
59430
|
-
if (deadNodeIds.has(nodeId)) {
|
|
59431
|
-
droppedDeadUnavailable = true;
|
|
59432
|
-
continue;
|
|
59433
|
-
}
|
|
59434
|
-
unavailableNodeIds.add(nodeId);
|
|
59435
|
-
}
|
|
59436
|
-
if (droppedDeadUnavailable) changed = true;
|
|
59437
|
-
const nodes = snapshot.nodes.map((statusNode) => {
|
|
59438
|
-
const nodeId = normalizeMeshNodeId(statusNode);
|
|
59439
|
-
const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
|
|
59440
|
-
if (!inlineNode) return statusNode;
|
|
59441
|
-
const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
|
|
59442
|
-
if (!liveGit) return statusNode;
|
|
59443
|
-
const nextStatus = { ...statusNode };
|
|
59444
|
-
nextStatus.git = liveGit;
|
|
59445
|
-
nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
|
|
59446
|
-
applyInlineMeshBranchConvergence(mesh, inlineNode, nextStatus);
|
|
59447
|
-
nextStatus.launchReady = readBooleanValue(nextStatus.launchReady) ?? true;
|
|
59448
|
-
const connection = readObjectRecord(nextStatus.connection);
|
|
59449
|
-
const connectionState = readStringValue(connection.state);
|
|
59450
|
-
const connectionReported = readBooleanValue(connection.reported) ?? false;
|
|
59451
|
-
if (!connectionReported || connectionState === "unknown") {
|
|
59452
|
-
nextStatus.connection = buildLivePeerGitConnection(connection);
|
|
59453
|
-
}
|
|
59454
|
-
delete nextStatus.gitProbePending;
|
|
59455
|
-
const error = readStringValue(nextStatus.error);
|
|
59456
|
-
if (error && /pending_git|git probe|live peer git snapshot|no peer git snapshot/i.test(error)) delete nextStatus.error;
|
|
59457
|
-
if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = "online";
|
|
59458
|
-
if (nodeId) unavailableNodeIds.delete(nodeId);
|
|
59459
|
-
changed = true;
|
|
59460
|
-
return nextStatus;
|
|
59461
|
-
});
|
|
59462
|
-
const aggregateDirectTruthSatisfied = sourceOfTruth.coordinatorOwnsLiveTruth === true || directPeerTruth.satisfied === true;
|
|
59463
|
-
if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied)) return snapshot;
|
|
59464
|
-
const nextSourceOfTruth = {
|
|
59465
|
-
...sourceOfTruth,
|
|
59466
|
-
...Object.keys(directPeerTruth).length ? {
|
|
59467
|
-
directPeerTruth: {
|
|
59468
|
-
...directPeerTruth,
|
|
59469
|
-
satisfied: options?.requireDirectPeerTruth === true ? aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
|
|
59470
|
-
unavailableNodeIds: [...unavailableNodeIds]
|
|
59471
|
-
},
|
|
59472
|
-
...options?.requireDirectPeerTruth === true ? {
|
|
59473
|
-
coordinatorOwnsLiveTruth: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0,
|
|
59474
|
-
currentStatus: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 ? "live_git_and_session_probes" : "direct_peer_truth_unavailable"
|
|
59475
|
-
} : {}
|
|
59476
|
-
} : {}
|
|
59477
|
-
};
|
|
59478
|
-
return {
|
|
59479
|
-
...snapshot,
|
|
59480
|
-
...options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied ? {
|
|
59481
|
-
success: false,
|
|
59482
|
-
code: "mesh_direct_peer_truth_unavailable",
|
|
59483
|
-
error: "Selected coordinator could not confirm direct mesh truth for every remote node yet."
|
|
59484
|
-
} : {},
|
|
59485
|
-
sourceOfTruth: nextSourceOfTruth,
|
|
59486
|
-
branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodes),
|
|
59487
|
-
nodes
|
|
59488
|
-
};
|
|
59761
|
+
return hydrateCachedAggregateMeshStatusFromInline(this, snapshot, mesh, options);
|
|
59489
59762
|
}
|
|
59490
59763
|
getCachedAggregateMeshStatus(meshId, mesh, options) {
|
|
59491
|
-
|
|
59492
|
-
if (!cached3?.snapshot || cached3.snapshot.success !== true || !Array.isArray(cached3.snapshot.nodes)) return null;
|
|
59493
|
-
if (cached3.queueRevision !== getMeshQueueRevision(meshId)) return null;
|
|
59494
|
-
let snapshot = this.cloneJsonValue(cached3.snapshot);
|
|
59495
|
-
snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
|
|
59496
|
-
if (!options?.allowStalePending && shouldRefreshStalePendingAggregate(snapshot, options)) return null;
|
|
59497
|
-
const ageMs = Math.max(0, Date.now() - cached3.builtAt);
|
|
59498
|
-
const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
|
|
59499
|
-
snapshot.sourceOfTruth = {
|
|
59500
|
-
...sourceOfTruth,
|
|
59501
|
-
aggregateSnapshot: {
|
|
59502
|
-
...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
|
|
59503
|
-
owner: "coordinator_daemon_memory",
|
|
59504
|
-
cached: true,
|
|
59505
|
-
source: "memory",
|
|
59506
|
-
refreshReason: "memory_cache_hit",
|
|
59507
|
-
ageMs,
|
|
59508
|
-
cachedAt: new Date(cached3.builtAt).toISOString(),
|
|
59509
|
-
returnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
59510
|
-
}
|
|
59511
|
-
};
|
|
59512
|
-
return snapshot;
|
|
59764
|
+
return getCachedAggregateMeshStatus(this, meshId, mesh, options);
|
|
59513
59765
|
}
|
|
59514
59766
|
rememberAggregateMeshStatus(meshId, snapshot, refreshReason) {
|
|
59515
|
-
|
|
59516
|
-
const builtAt = Date.now();
|
|
59517
|
-
const next = this.cloneJsonValue(snapshot);
|
|
59518
|
-
const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
|
|
59519
|
-
next.sourceOfTruth = {
|
|
59520
|
-
...sourceOfTruth,
|
|
59521
|
-
aggregateSnapshot: {
|
|
59522
|
-
owner: "coordinator_daemon_memory",
|
|
59523
|
-
cached: false,
|
|
59524
|
-
source: "live_refresh",
|
|
59525
|
-
refreshReason,
|
|
59526
|
-
ageMs: 0,
|
|
59527
|
-
cachedAt: new Date(builtAt).toISOString(),
|
|
59528
|
-
returnedAt: new Date(builtAt).toISOString()
|
|
59529
|
-
}
|
|
59530
|
-
};
|
|
59531
|
-
this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next), queueRevision: getMeshQueueRevision(meshId) });
|
|
59532
|
-
return next;
|
|
59767
|
+
return rememberAggregateMeshStatus(this, meshId, snapshot, refreshReason);
|
|
59533
59768
|
}
|
|
59534
59769
|
getCachedInlineMeshNodes() {
|
|
59535
59770
|
const nodes = [];
|
|
@@ -59540,82 +59775,13 @@ var DaemonCommandRouter = class {
|
|
|
59540
59775
|
}
|
|
59541
59776
|
return nodes;
|
|
59542
59777
|
}
|
|
59543
|
-
|
|
59544
|
-
|
|
59545
|
-
|
|
59546
|
-
|
|
59547
|
-
|
|
59548
|
-
* instanceManager/sessionRegistry — only their cached mesh-node metadata. A
|
|
59549
|
-
* dashboard-issued session-scoped command (invoke_provider_script / resolve_action /
|
|
59550
|
-
* set_mode / …) lands on the coordinator with a targetSessionId the coordinator can't
|
|
59551
|
-
* find locally, and without forwarding it dies as "Live session not found". send_chat
|
|
59552
|
-
* happens to survive (its target resolves to the worker by another route), but the
|
|
59553
|
-
* controlbar commands do not — so the controlbar buttons appear to do nothing.
|
|
59554
|
-
*
|
|
59555
|
-
* Mirror the existing node-level remote-forward pattern (fast_forward_mesh_node etc.):
|
|
59556
|
-
* scan the candidate mesh nodes for the one hosting the targetSessionId, and return its
|
|
59557
|
-
* daemonId when that daemonId is a remote daemon (i.e. not this coordinator's own
|
|
59558
|
-
* statusInstanceId). Returns undefined for a locally-hosted session (no forward — execute
|
|
59559
|
-
* locally as before) or when ownership can't be resolved.
|
|
59560
|
-
*
|
|
59561
|
-
* The candidate set spans BOTH the cached inline-mesh nodes and the live aggregate
|
|
59562
|
-
* mesh-status snapshots. The inline cache reliably carries only each node's single primary
|
|
59563
|
-
* session (cachedStatus.activeSession), so a worker hosting more than one session exposes its
|
|
59564
|
-
* non-primary sessions only on the aggregate snapshot nodes (status.activeSessions /
|
|
59565
|
-
* activeSessionDetails, built from live session records). collectMeshNodeHostedSessionIds does
|
|
59566
|
-
* the wider plural-shape scan so a controlbar/modal command targeting a non-primary remote
|
|
59567
|
-
* session still resolves its owner — the singular readCachedInlineMeshActiveSessions semantics
|
|
59568
|
-
* other consumers depend on stay untouched.
|
|
59569
|
-
*
|
|
59570
|
-
* CANCEL-STOP-RELAY: the session-id cache scan above only matches when the coordinator's
|
|
59571
|
-
* cached status snapshot already lists the worker's session id in a recognized active-sessions
|
|
59572
|
-
* shape. A worktree-clone worker session whose id form/timing differs from the cached snapshot
|
|
59573
|
-
* (or is simply not yet reflected) misses the scan, so a stop that carries the authoritative
|
|
59574
|
-
* owning nodeId (mesh_queue_cancel knows assignedNodeId) used to silently fail to forward.
|
|
59575
|
-
* `ownerNodeIdHint` adds a deterministic fallback: when the session-id scan misses, resolve the
|
|
59576
|
-
* owner daemonId by matching the node by id (meshNodeIdMatches — same form-tolerant compare the
|
|
59577
|
-
* rest of the router uses, no new raw compare). The same self-loopback guard applies to both
|
|
59578
|
-
* paths, so a coordinator-hosted node is still never force-forwarded to a remote form of itself.
|
|
59579
|
-
*/
|
|
59778
|
+
// ─── Remote mesh-session owner resolution ───────────────────────────
|
|
59779
|
+
// Implementation lives in ./router-mesh-session-owner.ts (behavior-preserving
|
|
59780
|
+
// code move). resolveRemoteMeshSessionOwnerDaemonId stays public (the [Z]
|
|
59781
|
+
// session-scoped forward in executeDaemonCommand and a unit test call it), so
|
|
59782
|
+
// it's kept here as a thin delegator.
|
|
59580
59783
|
resolveRemoteMeshSessionOwnerDaemonId(sessionId, ownerNodeIdHint) {
|
|
59581
|
-
|
|
59582
|
-
const nodeHint = typeof ownerNodeIdHint === "string" ? ownerNodeIdHint.trim() : "";
|
|
59583
|
-
if (!trimmed && !nodeHint) return void 0;
|
|
59584
|
-
const selfDaemonId = this.deps.statusInstanceId;
|
|
59585
|
-
const candidates = this.collectMeshSessionOwnerCandidateNodes();
|
|
59586
|
-
if (trimmed) {
|
|
59587
|
-
for (const node of candidates) {
|
|
59588
|
-
if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
|
|
59589
|
-
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
59590
|
-
if (!nodeDaemonId) continue;
|
|
59591
|
-
if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
|
|
59592
|
-
return nodeDaemonId;
|
|
59593
|
-
}
|
|
59594
|
-
}
|
|
59595
|
-
if (nodeHint) {
|
|
59596
|
-
for (const node of candidates) {
|
|
59597
|
-
if (!meshNodeIdMatches(node, nodeHint)) continue;
|
|
59598
|
-
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
59599
|
-
if (!nodeDaemonId) continue;
|
|
59600
|
-
if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
|
|
59601
|
-
return nodeDaemonId;
|
|
59602
|
-
}
|
|
59603
|
-
}
|
|
59604
|
-
return void 0;
|
|
59605
|
-
}
|
|
59606
|
-
/**
|
|
59607
|
-
* Candidate nodes for remote-session owner resolution: the cached inline-mesh nodes (which
|
|
59608
|
-
* carry each node's primary session) plus the nodes from every cached aggregate mesh-status
|
|
59609
|
-
* snapshot (which carry each node's full live session list). getCachedInlineMeshNodes()
|
|
59610
|
-
* returns a fresh array, so appending the aggregate nodes never mutates cached state.
|
|
59611
|
-
*/
|
|
59612
|
-
collectMeshSessionOwnerCandidateNodes() {
|
|
59613
|
-
const nodes = this.getCachedInlineMeshNodes();
|
|
59614
|
-
for (const cached3 of this.aggregateMeshStatusCache.values()) {
|
|
59615
|
-
const snapshotNodes = cached3?.snapshot?.nodes;
|
|
59616
|
-
if (Array.isArray(snapshotNodes)) nodes.push(...snapshotNodes);
|
|
59617
|
-
}
|
|
59618
|
-
return nodes;
|
|
59784
|
+
return resolveRemoteMeshSessionOwnerDaemonId(this, sessionId, ownerNodeIdHint);
|
|
59619
59785
|
}
|
|
59620
59786
|
getCachedInlineMesh(meshId, inlineMesh) {
|
|
59621
59787
|
if (inlineMesh && typeof inlineMesh === "object") {
|