@adhdev/daemon-core 0.9.82-rc.368 → 0.9.82-rc.369
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/boot/daemon-lifecycle.d.ts +1 -0
- package/dist/commands/router.d.ts +37 -32
- package/dist/index.js +245 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +245 -89
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
- package/package.json +2 -2
- package/src/boot/daemon-lifecycle.ts +8 -0
- package/src/commands/cli-manager.ts +57 -10
- package/src/commands/high-family/mesh-status.ts +6 -3
- package/src/commands/router.ts +188 -94
- package/src/mesh/mesh-events-coordinator.ts +70 -12
- package/src/mesh/mesh-warmup-deadline.ts +152 -0
|
@@ -81,6 +81,7 @@ export interface DaemonComponents {
|
|
|
81
81
|
};
|
|
82
82
|
refreshProviderAvailability: (providerType?: string) => Promise<void>;
|
|
83
83
|
dispatchMeshCommand?: (daemonId: string, command: string, args: Record<string, unknown>) => Promise<any>;
|
|
84
|
+
getMeshPeerConnectionStatus?: (daemonId: string) => Record<string, unknown> | null;
|
|
84
85
|
onMeshCoordinatorEventForwarded?: (payload: Record<string, unknown>) => void;
|
|
85
86
|
meshReconcileLoop?: {
|
|
86
87
|
stop(): void;
|
|
@@ -14,6 +14,7 @@ import { DaemonCliManager } from './cli-manager.js';
|
|
|
14
14
|
import type { ProviderLoader } from '../providers/provider-loader.js';
|
|
15
15
|
import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
|
|
16
16
|
import { SessionRegistry } from '../sessions/registry.js';
|
|
17
|
+
import { awaitWithWarmupDeadline } from '../mesh/mesh-warmup-deadline.js';
|
|
17
18
|
export declare function readProviderPriorityFromPolicy(policy: unknown): string[];
|
|
18
19
|
/**
|
|
19
20
|
* Normalize a providerRoles array (RepoMeshNodePolicy.providerRoles) from raw
|
|
@@ -78,11 +79,46 @@ export declare function resolveMeshNodeAttribution(node: unknown): {
|
|
|
78
79
|
machineName?: string;
|
|
79
80
|
};
|
|
80
81
|
export declare function readCachedInlineMeshActiveSessionDetails(node: any): Array<Record<string, unknown>>;
|
|
82
|
+
/**
|
|
83
|
+
* Transient per-node marker the mesh_status render loop stamps onto a node
|
|
84
|
+
* `status` at the two sites that obtain git truth from a FRESH probe this call
|
|
85
|
+
* (a successful local `getGitRepoStatus`, or a successful P2P `git_status`
|
|
86
|
+
* round-trip). finalizeMeshNodeStatus consumes and deletes it. Held/standing
|
|
87
|
+
* truth (node.lastGit / cachedStatus / inline transit) is deliberately NOT
|
|
88
|
+
* stamped — its absence is exactly how the freshness marker tells "live" apart
|
|
89
|
+
* from "cached". Internal only; never serialized in the response.
|
|
90
|
+
*/
|
|
91
|
+
export declare const MESH_NODE_LIVE_TRUTH_MARKER = "__liveTruthProbed";
|
|
92
|
+
/**
|
|
93
|
+
* Build the additive per-node `dataFreshness` marker. This NEVER mutates any
|
|
94
|
+
* existing field — it only adds an explicit, machine-readable answer to the
|
|
95
|
+
* question the legacy fields blurred: is this node's data live (just probed),
|
|
96
|
+
* cached (held truth, maybe old), or absent because the peer was unreachable?
|
|
97
|
+
*
|
|
98
|
+
* The crucial separation: an UNREACHABLE peer (P2P probe failed / not connected)
|
|
99
|
+
* is no longer indistinguishable from an idle/EMPTY node. Both used to render as
|
|
100
|
+
* `health:'unknown'` with no sessions; now `dataFreshness.dataSource` and
|
|
101
|
+
* `reachable` tell them apart so a coordinator never reads a dead peer as "online
|
|
102
|
+
* but doing nothing".
|
|
103
|
+
*/
|
|
104
|
+
export declare function buildMeshNodeDataFreshness(args: {
|
|
105
|
+
status: Record<string, unknown>;
|
|
106
|
+
node?: any;
|
|
107
|
+
isSelfNode: boolean;
|
|
108
|
+
daemonId?: string;
|
|
109
|
+
/** True when this node was stamped with a fresh live git probe this call. */
|
|
110
|
+
liveTruthProbed: boolean;
|
|
111
|
+
/** True when direct-peer-truth accounting classified this node unavailable. */
|
|
112
|
+
directTruthUnavailable?: boolean;
|
|
113
|
+
now?: () => number;
|
|
114
|
+
}): Record<string, unknown>;
|
|
81
115
|
export declare function finalizeMeshNodeStatus(args: {
|
|
82
116
|
status: Record<string, unknown>;
|
|
83
117
|
node: any;
|
|
84
118
|
daemonId?: string;
|
|
85
119
|
isSelfNode: boolean;
|
|
120
|
+
/** True when direct-peer-truth accounting classified this node unavailable. */
|
|
121
|
+
directTruthUnavailable?: boolean;
|
|
86
122
|
}): void;
|
|
87
123
|
export declare const MESH_DIRECT_PROBE_TIMEOUT_MS: number;
|
|
88
124
|
export declare const MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS: number;
|
|
@@ -117,37 +153,7 @@ export declare class MeshGitProbeCache {
|
|
|
117
153
|
*/
|
|
118
154
|
probe(daemonId: string, workspace: string, probe: () => Promise<Record<string, unknown> | null>): Promise<Record<string, unknown> | null>;
|
|
119
155
|
}
|
|
120
|
-
|
|
121
|
-
* Await `work` under a warmup-aware deadline so a cold-open DataChannel handshake
|
|
122
|
-
* is NOT charged against the command response budget — the root cause of the
|
|
123
|
-
* "first mesh probe to a cold peer false-times-out, the warm retry succeeds"
|
|
124
|
-
* signature. Two budgets, switched by the live peer connection state:
|
|
125
|
-
*
|
|
126
|
-
* - While `isConnected()` returns false the peer's channel is still opening; the
|
|
127
|
-
* cold-open `connectTimeoutMs` budget applies. This phase is deliberately
|
|
128
|
-
* generous because a TURN-relayed cross-machine handshake legitimately needs
|
|
129
|
-
* many seconds — but a genuine connect *failure* is surfaced by `work`
|
|
130
|
-
* rejecting on its own (the mesh manager fails the peer the instant its
|
|
131
|
-
* PeerConnection state goes terminal), so a real failure is never masked for
|
|
132
|
-
* the whole window.
|
|
133
|
-
* - The first time `isConnected()` returns true the channel is warm; from that
|
|
134
|
-
* instant the tight `responseTimeoutMs` governs how long the handler may take.
|
|
135
|
-
* Warm-channel callers therefore see behavior identical to the old single
|
|
136
|
-
* `Promise.race(work, responseTimeoutMs)`.
|
|
137
|
-
*
|
|
138
|
-
* Rejects with `Error('timeout')` when either budget is exhausted, mirroring the
|
|
139
|
-
* previous single-race contract. Pure except for timers + the injected
|
|
140
|
-
* `isConnected` probe, so it is unit-testable under fake timers without any real
|
|
141
|
-
* WebRTC. When no connection getter is wired `isConnected` should be `() => true`
|
|
142
|
-
* (the caller's choice) so the response deadline governs from t0 — the legacy
|
|
143
|
-
* single-budget behavior, never a combined connect+response window.
|
|
144
|
-
*/
|
|
145
|
-
export declare function awaitWithWarmupDeadline<T>(work: Promise<T>, opts: {
|
|
146
|
-
isConnected: () => boolean;
|
|
147
|
-
connectTimeoutMs: number;
|
|
148
|
-
responseTimeoutMs: number;
|
|
149
|
-
pollIntervalMs?: number;
|
|
150
|
-
}): Promise<T>;
|
|
156
|
+
export { awaitWithWarmupDeadline };
|
|
151
157
|
/**
|
|
152
158
|
* Probe a remote peer's git_status with a bounded retry budget, but only while
|
|
153
159
|
* the peer is reported `connected`. A single slow (often TURN-relayed) peer can
|
|
@@ -781,4 +787,3 @@ export declare class DaemonCommandRouter {
|
|
|
781
787
|
*/
|
|
782
788
|
private stopIde;
|
|
783
789
|
}
|
|
784
|
-
export {};
|
package/dist/index.js
CHANGED
|
@@ -316,10 +316,10 @@ function readInjected(value) {
|
|
|
316
316
|
}
|
|
317
317
|
function getDaemonBuildInfo() {
|
|
318
318
|
if (cached) return cached;
|
|
319
|
-
const commit = readInjected(true ? "
|
|
320
|
-
const commitShort = readInjected(true ? "
|
|
321
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
322
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
319
|
+
const commit = readInjected(true ? "4464cd9f1effac841aa1fbef3b1691d2f06d64e4" : void 0) ?? "unknown";
|
|
320
|
+
const commitShort = readInjected(true ? "4464cd9f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
321
|
+
const version = readInjected(true ? "0.9.82-rc.369" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
322
|
+
const builtAt = readInjected(true ? "2026-06-24T08:22:14.501Z" : void 0);
|
|
323
323
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
324
324
|
return cached;
|
|
325
325
|
}
|
|
@@ -10382,6 +10382,90 @@ var init_mesh_event_trace = __esm({
|
|
|
10382
10382
|
}
|
|
10383
10383
|
});
|
|
10384
10384
|
|
|
10385
|
+
// src/mesh/mesh-warmup-deadline.ts
|
|
10386
|
+
function awaitWithWarmupDeadline(work, opts) {
|
|
10387
|
+
const pollMs = Math.max(1, Math.min(opts.pollIntervalMs ?? 200, opts.connectTimeoutMs));
|
|
10388
|
+
return new Promise((resolve24, reject) => {
|
|
10389
|
+
let done = false;
|
|
10390
|
+
let poll;
|
|
10391
|
+
let responseTimer;
|
|
10392
|
+
const startedAt = Date.now();
|
|
10393
|
+
const cleanup = () => {
|
|
10394
|
+
if (poll) {
|
|
10395
|
+
clearInterval(poll);
|
|
10396
|
+
poll = void 0;
|
|
10397
|
+
}
|
|
10398
|
+
if (responseTimer) {
|
|
10399
|
+
clearTimeout(responseTimer);
|
|
10400
|
+
responseTimer = void 0;
|
|
10401
|
+
}
|
|
10402
|
+
};
|
|
10403
|
+
const settle = (fn) => {
|
|
10404
|
+
if (done) return;
|
|
10405
|
+
done = true;
|
|
10406
|
+
cleanup();
|
|
10407
|
+
fn();
|
|
10408
|
+
};
|
|
10409
|
+
const armResponse = () => {
|
|
10410
|
+
if (responseTimer || done) return;
|
|
10411
|
+
responseTimer = setTimeout(
|
|
10412
|
+
() => settle(() => reject(new Error("timeout"))),
|
|
10413
|
+
opts.responseTimeoutMs
|
|
10414
|
+
);
|
|
10415
|
+
if (typeof responseTimer.unref === "function") responseTimer.unref();
|
|
10416
|
+
};
|
|
10417
|
+
const onPoll = () => {
|
|
10418
|
+
if (done) return;
|
|
10419
|
+
if (opts.isConnected()) {
|
|
10420
|
+
if (poll) {
|
|
10421
|
+
clearInterval(poll);
|
|
10422
|
+
poll = void 0;
|
|
10423
|
+
}
|
|
10424
|
+
armResponse();
|
|
10425
|
+
return;
|
|
10426
|
+
}
|
|
10427
|
+
if (Date.now() - startedAt >= opts.connectTimeoutMs) {
|
|
10428
|
+
settle(() => reject(new Error("timeout")));
|
|
10429
|
+
}
|
|
10430
|
+
};
|
|
10431
|
+
if (opts.isConnected()) {
|
|
10432
|
+
armResponse();
|
|
10433
|
+
} else {
|
|
10434
|
+
poll = setInterval(onPoll, pollMs);
|
|
10435
|
+
if (typeof poll.unref === "function") poll.unref();
|
|
10436
|
+
}
|
|
10437
|
+
work.then(
|
|
10438
|
+
(val) => settle(() => resolve24(val)),
|
|
10439
|
+
(err) => settle(() => reject(err))
|
|
10440
|
+
);
|
|
10441
|
+
});
|
|
10442
|
+
}
|
|
10443
|
+
function readWarmupConnectionState(connection) {
|
|
10444
|
+
const state = connection?.state;
|
|
10445
|
+
return typeof state === "string" && state.length > 0 ? state : void 0;
|
|
10446
|
+
}
|
|
10447
|
+
function resolveWarmupDeadlineOpts(opts) {
|
|
10448
|
+
const { getConnection, daemonId, connectTimeoutMs, responseTimeoutMs } = opts;
|
|
10449
|
+
if (getConnection) {
|
|
10450
|
+
return {
|
|
10451
|
+
isConnected: () => readWarmupConnectionState(getConnection(daemonId)) === "connected",
|
|
10452
|
+
connectTimeoutMs,
|
|
10453
|
+
responseTimeoutMs
|
|
10454
|
+
};
|
|
10455
|
+
}
|
|
10456
|
+
opts.onMissingGetter?.(daemonId);
|
|
10457
|
+
return {
|
|
10458
|
+
isConnected: () => false,
|
|
10459
|
+
connectTimeoutMs: connectTimeoutMs + responseTimeoutMs,
|
|
10460
|
+
responseTimeoutMs
|
|
10461
|
+
};
|
|
10462
|
+
}
|
|
10463
|
+
var init_mesh_warmup_deadline = __esm({
|
|
10464
|
+
"src/mesh/mesh-warmup-deadline.ts"() {
|
|
10465
|
+
"use strict";
|
|
10466
|
+
}
|
|
10467
|
+
});
|
|
10468
|
+
|
|
10385
10469
|
// src/config/state-store.ts
|
|
10386
10470
|
function isPlainObject2(value) {
|
|
10387
10471
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -12817,7 +12901,12 @@ function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
|
|
|
12817
12901
|
return void 0;
|
|
12818
12902
|
}
|
|
12819
12903
|
}
|
|
12820
|
-
function
|
|
12904
|
+
function warnDispatchWarmupGetterMissingOnce(daemonId) {
|
|
12905
|
+
if (dispatchWarmupGetterMissingWarned.has(daemonId)) return;
|
|
12906
|
+
dispatchWarmupGetterMissingWarned.add(daemonId);
|
|
12907
|
+
LOG.warn("MeshQueue", `Mesh peer connection getter unavailable for ${String(daemonId).slice(0, 12)}; remote task-dispatch warmup deadline degraded to the combined connect+response window. Avoids a cold-open false-timeout but loses warm/cold precision \u2014 wire getMeshPeerConnectionStatus on this daemon.`);
|
|
12908
|
+
}
|
|
12909
|
+
function deliverTaskToSession(dispatchThunk, ctx, warmup) {
|
|
12821
12910
|
const delivery = createSessionDelivery({
|
|
12822
12911
|
meshId: ctx.meshId,
|
|
12823
12912
|
nodeId: ctx.nodeId,
|
|
@@ -12837,16 +12926,27 @@ function deliverTaskToSession(dispatchThunk, ctx) {
|
|
|
12837
12926
|
dispatchPromise = Promise.reject(e);
|
|
12838
12927
|
}
|
|
12839
12928
|
let timer;
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
|
|
12843
|
-
|
|
12844
|
-
|
|
12845
|
-
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
})
|
|
12849
|
-
|
|
12929
|
+
let guarded;
|
|
12930
|
+
if (warmup) {
|
|
12931
|
+
guarded = awaitWithWarmupDeadline(dispatchPromise, resolveWarmupDeadlineOpts({
|
|
12932
|
+
getConnection: warmup.getConnection,
|
|
12933
|
+
daemonId: warmup.daemonId,
|
|
12934
|
+
connectTimeoutMs: DISPATCH_CONNECT_TIMEOUT_MS,
|
|
12935
|
+
responseTimeoutMs: DISPATCH_CONFIRM_TIMEOUT_MS,
|
|
12936
|
+
onMissingGetter: warnDispatchWarmupGetterMissingOnce
|
|
12937
|
+
}));
|
|
12938
|
+
} else {
|
|
12939
|
+
guarded = Promise.race([
|
|
12940
|
+
dispatchPromise,
|
|
12941
|
+
new Promise((_, reject) => {
|
|
12942
|
+
timer = setTimeout(
|
|
12943
|
+
() => reject(new Error(`dispatch_confirm_timeout after ${DISPATCH_CONFIRM_TIMEOUT_MS}ms`)),
|
|
12944
|
+
DISPATCH_CONFIRM_TIMEOUT_MS
|
|
12945
|
+
);
|
|
12946
|
+
if (typeof timer?.unref === "function") timer.unref();
|
|
12947
|
+
})
|
|
12948
|
+
]);
|
|
12949
|
+
}
|
|
12850
12950
|
guarded.then(() => {
|
|
12851
12951
|
if (timer) clearTimeout(timer);
|
|
12852
12952
|
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
@@ -12930,7 +13030,11 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
12930
13030
|
transport: "remote",
|
|
12931
13031
|
...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
|
|
12932
13032
|
...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
|
|
12933
|
-
}
|
|
13033
|
+
},
|
|
13034
|
+
// Warmup-aware deadline: this dispatch can be the FIRST command to a
|
|
13035
|
+
// peer whose mesh DataChannel is still opening — charge the cold-open
|
|
13036
|
+
// handshake to the connect budget, not the response budget.
|
|
13037
|
+
{ daemonId: remoteDaemonId, getConnection: components.getMeshPeerConnectionStatus }
|
|
12934
13038
|
);
|
|
12935
13039
|
return true;
|
|
12936
13040
|
}
|
|
@@ -14309,7 +14413,7 @@ function setupMeshEventForwarding(components) {
|
|
|
14309
14413
|
});
|
|
14310
14414
|
});
|
|
14311
14415
|
}
|
|
14312
|
-
var import_fs13, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, DISPATCH_CONFIRM_TIMEOUT_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS, coordinatorForwardLanes;
|
|
14416
|
+
var import_fs13, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS, coordinatorForwardLanes;
|
|
14313
14417
|
var init_mesh_events_coordinator = __esm({
|
|
14314
14418
|
"src/mesh/mesh-events-coordinator.ts"() {
|
|
14315
14419
|
"use strict";
|
|
@@ -14327,6 +14431,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
14327
14431
|
init_mesh_routing();
|
|
14328
14432
|
init_mesh_unresolved_forward_outbox();
|
|
14329
14433
|
init_mesh_event_trace();
|
|
14434
|
+
init_mesh_warmup_deadline();
|
|
14330
14435
|
init_snapshot();
|
|
14331
14436
|
init_repo_mesh_types();
|
|
14332
14437
|
init_dist();
|
|
@@ -14340,6 +14445,8 @@ var init_mesh_events_coordinator = __esm({
|
|
|
14340
14445
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
14341
14446
|
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
14342
14447
|
DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
|
|
14448
|
+
DISPATCH_CONNECT_TIMEOUT_MS = 45e3;
|
|
14449
|
+
dispatchWarmupGetterMissingWarned = /* @__PURE__ */ new Set();
|
|
14343
14450
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
14344
14451
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
14345
14452
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -41849,6 +41956,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
41849
41956
|
let restored = 0;
|
|
41850
41957
|
const restoredBindings = /* @__PURE__ */ new Set();
|
|
41851
41958
|
const managerTag = this.deps.hostedRuntimeManagerTag;
|
|
41959
|
+
const restoredRuntimeIds = /* @__PURE__ */ new Set();
|
|
41960
|
+
const workspaceTypeCounts = /* @__PURE__ */ new Map();
|
|
41961
|
+
for (const r of sessions) {
|
|
41962
|
+
if (!r?.runtimeId || !r?.cliType || !r?.workspace) continue;
|
|
41963
|
+
restoredRuntimeIds.add(r.runtimeId);
|
|
41964
|
+
const key = `${r.workspace}::${r.cliType}`;
|
|
41965
|
+
workspaceTypeCounts.set(key, (workspaceTypeCounts.get(key) || 0) + 1);
|
|
41966
|
+
}
|
|
41852
41967
|
for (const record of sessions) {
|
|
41853
41968
|
if (!record?.runtimeId || !record?.cliType || !record?.workspace) continue;
|
|
41854
41969
|
if (!shouldRestoreHostedRuntime(record, managerTag)) {
|
|
@@ -41886,11 +42001,21 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
41886
42001
|
if (!coordinatorEntry?.meshId && record.workspace) {
|
|
41887
42002
|
const workspaceCoordinators = listCoordinatorsForWorkspace(record.workspace).filter((e) => e.meshId && (!e.cliType || e.cliType === record.cliType));
|
|
41888
42003
|
if (workspaceCoordinators.length === 1) {
|
|
41889
|
-
|
|
41890
|
-
|
|
41891
|
-
|
|
41892
|
-
|
|
41893
|
-
|
|
42004
|
+
const candidate = workspaceCoordinators[0];
|
|
42005
|
+
const coordinatorPresentById = !!candidate.sessionId && restoredRuntimeIds.has(candidate.sessionId);
|
|
42006
|
+
const siblingCount = workspaceTypeCounts.get(`${record.workspace}::${record.cliType}`) || 1;
|
|
42007
|
+
if (!coordinatorPresentById && siblingCount === 1) {
|
|
42008
|
+
coordinatorEntry = candidate;
|
|
42009
|
+
LOG.info(
|
|
42010
|
+
"CLI",
|
|
42011
|
+
`\u21BB Rebound coordinator mark by workspace for ${record.runtimeKey || record.runtimeId} (mesh ${candidate.meshId} @ ${record.workspace}); registry key did not match runtimeId`
|
|
42012
|
+
);
|
|
42013
|
+
} else {
|
|
42014
|
+
LOG.info(
|
|
42015
|
+
"CLI",
|
|
42016
|
+
`\u21B7 Skipping workspace coordinator rebind for ${record.runtimeKey || record.runtimeId} (${record.cliType} @ ${record.workspace}): ${coordinatorPresentById ? "registered coordinator is restoring under its own id \u2014 this is a delegated worker" : `ambiguous (${siblingCount} sessions share this workspace+cliType)`}`
|
|
42017
|
+
);
|
|
42018
|
+
}
|
|
41894
42019
|
}
|
|
41895
42020
|
}
|
|
41896
42021
|
if (coordinatorEntry?.meshId) {
|
|
@@ -48372,6 +48497,7 @@ var meshStatusHandlers = {
|
|
|
48372
48497
|
const remoteGit = await meshGitProbeCache.probe(daemonId, workspace, runNodeProbe);
|
|
48373
48498
|
if (remoteGit) {
|
|
48374
48499
|
status.git = remoteGit;
|
|
48500
|
+
status[MESH_NODE_LIVE_TRUTH_MARKER] = true;
|
|
48375
48501
|
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
48376
48502
|
const connection = readObjectRecord(status.connection);
|
|
48377
48503
|
const connectionState = readStringValue(connection.state);
|
|
@@ -48397,13 +48523,13 @@ var meshStatusHandlers = {
|
|
|
48397
48523
|
pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : void 0
|
|
48398
48524
|
)) {
|
|
48399
48525
|
applyInlineMeshBranchConvergence(mesh, node, status);
|
|
48400
|
-
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
48526
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode, directTruthUnavailable: directTruthUnavailableNodeIds.has(nodeId) });
|
|
48401
48527
|
nodeStatuses.push(status);
|
|
48402
48528
|
continue;
|
|
48403
48529
|
}
|
|
48404
48530
|
if (meshRecord?.source === "inline_cache" && !isSelfNode) {
|
|
48405
48531
|
applyInlineMeshBranchConvergence(mesh, node, status);
|
|
48406
|
-
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
48532
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode, directTruthUnavailable: directTruthUnavailableNodeIds.has(nodeId) });
|
|
48407
48533
|
nodeStatuses.push(status);
|
|
48408
48534
|
continue;
|
|
48409
48535
|
}
|
|
@@ -48412,6 +48538,7 @@ var meshStatusHandlers = {
|
|
|
48412
48538
|
try {
|
|
48413
48539
|
const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
48414
48540
|
status.git = gitStatus;
|
|
48541
|
+
status[MESH_NODE_LIVE_TRUTH_MARKER] = true;
|
|
48415
48542
|
const reporter = recordInlineMeshDirectGitTruth(node, gitStatus, "selected_coordinator_local_git");
|
|
48416
48543
|
persistNodeReporterPlatform(meshRecord.source, mesh, nodeId, reporter);
|
|
48417
48544
|
if (gitStatus.isGitRepo) {
|
|
@@ -48430,7 +48557,7 @@ var meshStatusHandlers = {
|
|
|
48430
48557
|
applyCachedInlineMeshNodeStatus(status, node);
|
|
48431
48558
|
}
|
|
48432
48559
|
applyInlineMeshBranchConvergence(mesh, node, status);
|
|
48433
|
-
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
48560
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode, directTruthUnavailable: directTruthUnavailableNodeIds.has(nodeId) });
|
|
48434
48561
|
nodeStatuses.push(status);
|
|
48435
48562
|
}
|
|
48436
48563
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : ctx.deps.statusInstanceId || void 0;
|
|
@@ -48844,6 +48971,7 @@ function orderMeshRefineBatchNodes(changeAreas) {
|
|
|
48844
48971
|
|
|
48845
48972
|
// src/commands/router.ts
|
|
48846
48973
|
init_mesh_work_queue();
|
|
48974
|
+
init_mesh_warmup_deadline();
|
|
48847
48975
|
init_repo_mesh_types();
|
|
48848
48976
|
var import_os4 = require("os");
|
|
48849
48977
|
var import_path13 = require("path");
|
|
@@ -49585,14 +49713,92 @@ function synthesizeMeshNodeFreshnessFromConnection(status) {
|
|
|
49585
49713
|
status.updatedAt = gitCheckedAt ?? connectionFreshAt;
|
|
49586
49714
|
}
|
|
49587
49715
|
}
|
|
49716
|
+
var MESH_NODE_LIVE_TRUTH_MARKER = "__liveTruthProbed";
|
|
49717
|
+
var MESH_FRESHNESS_FRESH_MS = 3e4;
|
|
49718
|
+
var MESH_FRESHNESS_RECENT_MS = 3e5;
|
|
49719
|
+
function classifyMeshNodeStaleness(dataSource, ageMs) {
|
|
49720
|
+
if (dataSource === "self" || dataSource === "live") return "fresh";
|
|
49721
|
+
if (ageMs === null) return "unknown";
|
|
49722
|
+
if (ageMs < MESH_FRESHNESS_FRESH_MS) return "fresh";
|
|
49723
|
+
if (ageMs < MESH_FRESHNESS_RECENT_MS) return "recent";
|
|
49724
|
+
return "stale";
|
|
49725
|
+
}
|
|
49726
|
+
function buildMeshNodeDataFreshness(args) {
|
|
49727
|
+
const { status, node, isSelfNode, daemonId, liveTruthProbed, directTruthUnavailable } = args;
|
|
49728
|
+
const now = args.now ?? Date.now;
|
|
49729
|
+
const connection = readObjectRecord(status.connection);
|
|
49730
|
+
const connectionState = readStringValue(connection.state);
|
|
49731
|
+
const git = readObjectRecord(status.git);
|
|
49732
|
+
const hasGit = readBooleanValue(git.isGitRepo) === true || !!readStringValue(git.branch, git.headCommit, git.head, git.upstream);
|
|
49733
|
+
const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
|
|
49734
|
+
const liveGitCheckedAt = liveTruthProbed ? toIsoTimestamp(git.lastCheckedAt) : null;
|
|
49735
|
+
const heldGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
49736
|
+
const heldCheckedAt = toIsoTimestamp(heldGit.checkedAt ?? heldGit.checked_at);
|
|
49737
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
49738
|
+
const cachedGitCheckedAt = toIsoTimestamp(readObjectRecord(cachedStatus.git).lastCheckedAt);
|
|
49739
|
+
const lastProbeAt = liveGitCheckedAt ?? heldCheckedAt ?? cachedGitCheckedAt ?? toIsoTimestamp(git.lastCheckedAt) ?? connectionFreshAt ?? toIsoTimestamp(status.updatedAt) ?? toIsoTimestamp(status.lastSeenAt);
|
|
49740
|
+
const connectionReachable = connectionState === "connected" ? true : !connectionState || connectionState === "unknown" || connectionState === "connecting" ? connectionState === "connecting" ? true : null : false;
|
|
49741
|
+
let dataSource;
|
|
49742
|
+
let reachable;
|
|
49743
|
+
if (isSelfNode) {
|
|
49744
|
+
dataSource = "self";
|
|
49745
|
+
reachable = true;
|
|
49746
|
+
} else if (liveTruthProbed) {
|
|
49747
|
+
dataSource = "live";
|
|
49748
|
+
reachable = true;
|
|
49749
|
+
} else if (readBooleanValue(status.gitProbePending) === true) {
|
|
49750
|
+
dataSource = "pending";
|
|
49751
|
+
reachable = connectionReachable;
|
|
49752
|
+
} else if (directTruthUnavailable) {
|
|
49753
|
+
dataSource = "unreachable";
|
|
49754
|
+
reachable = false;
|
|
49755
|
+
} else if (hasGit) {
|
|
49756
|
+
dataSource = "cached";
|
|
49757
|
+
reachable = connectionReachable;
|
|
49758
|
+
} else if (!daemonId) {
|
|
49759
|
+
dataSource = "unconfigured";
|
|
49760
|
+
reachable = null;
|
|
49761
|
+
} else if (connectionState === "connected") {
|
|
49762
|
+
dataSource = "empty";
|
|
49763
|
+
reachable = true;
|
|
49764
|
+
} else {
|
|
49765
|
+
dataSource = "unreachable";
|
|
49766
|
+
reachable = false;
|
|
49767
|
+
}
|
|
49768
|
+
const probeOk = dataSource === "live" || dataSource === "self";
|
|
49769
|
+
let ageMs = null;
|
|
49770
|
+
if (lastProbeAt) {
|
|
49771
|
+
const parsed = Date.parse(lastProbeAt);
|
|
49772
|
+
if (Number.isFinite(parsed)) ageMs = Math.max(0, now() - parsed);
|
|
49773
|
+
}
|
|
49774
|
+
const staleness = classifyMeshNodeStaleness(dataSource, ageMs);
|
|
49775
|
+
return {
|
|
49776
|
+
dataSource,
|
|
49777
|
+
probeOk,
|
|
49778
|
+
reachable,
|
|
49779
|
+
lastProbeAt: lastProbeAt ?? null,
|
|
49780
|
+
ageMs,
|
|
49781
|
+
staleness
|
|
49782
|
+
};
|
|
49783
|
+
}
|
|
49588
49784
|
function finalizeMeshNodeStatus(args) {
|
|
49589
|
-
const { status, node, daemonId, isSelfNode } = args;
|
|
49785
|
+
const { status, node, daemonId, isSelfNode, directTruthUnavailable } = args;
|
|
49590
49786
|
if (!readStringValue(status.machineStatus)) {
|
|
49591
49787
|
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
49592
49788
|
const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
|
|
49593
49789
|
if (machineStatus) status.machineStatus = machineStatus;
|
|
49594
49790
|
}
|
|
49595
49791
|
synthesizeMeshNodeFreshnessFromConnection(status);
|
|
49792
|
+
const liveTruthProbed = readBooleanValue(status[MESH_NODE_LIVE_TRUTH_MARKER]) === true;
|
|
49793
|
+
delete status[MESH_NODE_LIVE_TRUTH_MARKER];
|
|
49794
|
+
status.dataFreshness = buildMeshNodeDataFreshness({
|
|
49795
|
+
status,
|
|
49796
|
+
node,
|
|
49797
|
+
isSelfNode,
|
|
49798
|
+
daemonId,
|
|
49799
|
+
liveTruthProbed,
|
|
49800
|
+
directTruthUnavailable
|
|
49801
|
+
});
|
|
49596
49802
|
const bootstrap = readObjectRecord(node?.worktreeBootstrap);
|
|
49597
49803
|
if (node?.isLocalWorktree && readStringValue(bootstrap.status)) {
|
|
49598
49804
|
status.worktreeBootstrap = bootstrap;
|
|
@@ -49660,73 +49866,16 @@ var MeshGitProbeCache = class {
|
|
|
49660
49866
|
}
|
|
49661
49867
|
}
|
|
49662
49868
|
};
|
|
49663
|
-
function awaitWithWarmupDeadline(work, opts) {
|
|
49664
|
-
const pollMs = Math.max(1, Math.min(opts.pollIntervalMs ?? 200, opts.connectTimeoutMs));
|
|
49665
|
-
return new Promise((resolve24, reject) => {
|
|
49666
|
-
let done = false;
|
|
49667
|
-
let poll;
|
|
49668
|
-
let responseTimer;
|
|
49669
|
-
const startedAt = Date.now();
|
|
49670
|
-
const cleanup = () => {
|
|
49671
|
-
if (poll) {
|
|
49672
|
-
clearInterval(poll);
|
|
49673
|
-
poll = void 0;
|
|
49674
|
-
}
|
|
49675
|
-
if (responseTimer) {
|
|
49676
|
-
clearTimeout(responseTimer);
|
|
49677
|
-
responseTimer = void 0;
|
|
49678
|
-
}
|
|
49679
|
-
};
|
|
49680
|
-
const settle = (fn) => {
|
|
49681
|
-
if (done) return;
|
|
49682
|
-
done = true;
|
|
49683
|
-
cleanup();
|
|
49684
|
-
fn();
|
|
49685
|
-
};
|
|
49686
|
-
const armResponse = () => {
|
|
49687
|
-
if (responseTimer || done) return;
|
|
49688
|
-
responseTimer = setTimeout(
|
|
49689
|
-
() => settle(() => reject(new Error("timeout"))),
|
|
49690
|
-
opts.responseTimeoutMs
|
|
49691
|
-
);
|
|
49692
|
-
if (typeof responseTimer.unref === "function") responseTimer.unref();
|
|
49693
|
-
};
|
|
49694
|
-
const onPoll = () => {
|
|
49695
|
-
if (done) return;
|
|
49696
|
-
if (opts.isConnected()) {
|
|
49697
|
-
if (poll) {
|
|
49698
|
-
clearInterval(poll);
|
|
49699
|
-
poll = void 0;
|
|
49700
|
-
}
|
|
49701
|
-
armResponse();
|
|
49702
|
-
return;
|
|
49703
|
-
}
|
|
49704
|
-
if (Date.now() - startedAt >= opts.connectTimeoutMs) {
|
|
49705
|
-
settle(() => reject(new Error("timeout")));
|
|
49706
|
-
}
|
|
49707
|
-
};
|
|
49708
|
-
if (opts.isConnected()) {
|
|
49709
|
-
armResponse();
|
|
49710
|
-
} else {
|
|
49711
|
-
poll = setInterval(onPoll, pollMs);
|
|
49712
|
-
if (typeof poll.unref === "function") poll.unref();
|
|
49713
|
-
}
|
|
49714
|
-
work.then(
|
|
49715
|
-
(val) => settle(() => resolve24(val)),
|
|
49716
|
-
(err) => settle(() => reject(err))
|
|
49717
|
-
);
|
|
49718
|
-
});
|
|
49719
|
-
}
|
|
49720
49869
|
async function probeRemoteMeshGitStatus(args) {
|
|
49721
49870
|
if (!args.dispatchMeshCommand) return null;
|
|
49722
49871
|
const dispatch = args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace, refreshUpstream: true });
|
|
49723
|
-
const
|
|
49724
|
-
|
|
49725
|
-
|
|
49726
|
-
isConnected,
|
|
49872
|
+
const remoteResult = await awaitWithWarmupDeadline(dispatch, resolveWarmupDeadlineOpts({
|
|
49873
|
+
getConnection: args.getConnection,
|
|
49874
|
+
daemonId: args.daemonId,
|
|
49727
49875
|
connectTimeoutMs: args.connectTimeoutMs,
|
|
49728
|
-
responseTimeoutMs: args.responseTimeoutMs
|
|
49729
|
-
|
|
49876
|
+
responseTimeoutMs: args.responseTimeoutMs,
|
|
49877
|
+
onMissingGetter: warnMeshWarmupGetterMissingOnce
|
|
49878
|
+
}));
|
|
49730
49879
|
const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
|
|
49731
49880
|
if (!remoteGit || typeof remoteGit !== "object" || typeof remoteGit.isGitRepo !== "boolean") return null;
|
|
49732
49881
|
const reporterPlatform = readStringValue(remoteResult?.reporterPlatform);
|
|
@@ -49740,6 +49889,12 @@ var MESH_DIRECT_PROBE_MAX_RETRIES = 2;
|
|
|
49740
49889
|
function readMeshConnectionState(connection) {
|
|
49741
49890
|
return readStringValue(connection?.state);
|
|
49742
49891
|
}
|
|
49892
|
+
var meshWarmupGetterMissingWarned = /* @__PURE__ */ new Set();
|
|
49893
|
+
function warnMeshWarmupGetterMissingOnce(daemonId) {
|
|
49894
|
+
if (meshWarmupGetterMissingWarned.has(daemonId)) return;
|
|
49895
|
+
meshWarmupGetterMissingWarned.add(daemonId);
|
|
49896
|
+
LOG.warn("Mesh", `Mesh peer connection getter unavailable for ${String(daemonId).slice(0, 12)}; warmup deadline degraded to the combined connect+response window (cannot observe DataChannel open). This avoids a cold-open false-timeout but loses warm/cold precision \u2014 wire getMeshPeerConnectionStatus on this daemon.`);
|
|
49897
|
+
}
|
|
49743
49898
|
function isMeshConnectionDefinitivelyDown(connection) {
|
|
49744
49899
|
if (!connection) return true;
|
|
49745
49900
|
const state = readMeshConnectionState(connection);
|
|
@@ -61816,6 +61971,7 @@ async function initDaemonComponents(config) {
|
|
|
61816
61971
|
detectedIdes: detectedIdesRef,
|
|
61817
61972
|
refreshProviderAvailability,
|
|
61818
61973
|
dispatchMeshCommand: config.dispatchMeshCommand,
|
|
61974
|
+
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
61819
61975
|
onMeshCoordinatorEventForwarded: config.onMeshCoordinatorEventForwarded,
|
|
61820
61976
|
statusInstanceId: config.statusInstanceId
|
|
61821
61977
|
};
|