@adhdev/daemon-core 0.9.82-rc.376 → 0.9.82-rc.378

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.
Files changed (48) hide show
  1. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  2. package/dist/commands/chat-commands-read.d.ts +7 -0
  3. package/dist/commands/chat-commands-scope.d.ts +39 -0
  4. package/dist/commands/chat-commands-shared.d.ts +33 -0
  5. package/dist/commands/chat-commands-write.d.ts +14 -0
  6. package/dist/commands/chat-commands.d.ts +9 -49
  7. package/dist/commands/router.d.ts +3 -470
  8. package/dist/index.js +3166 -3115
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +3561 -3510
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  13. package/dist/mesh/mesh-event-classify.d.ts +5 -0
  14. package/dist/mesh/mesh-event-forwarding.d.ts +18 -0
  15. package/dist/mesh/mesh-events-coordinator.d.ts +4 -92
  16. package/dist/mesh/mesh-events-utils.d.ts +3 -0
  17. package/dist/mesh/mesh-ledger-reconciliation.d.ts +0 -1
  18. package/dist/mesh/mesh-node-identity.d.ts +289 -0
  19. package/dist/mesh/mesh-queue-assignment.d.ts +86 -0
  20. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  21. package/dist/mesh/mesh-runtime-store.d.ts +0 -3
  22. package/dist/providers/native-history/constants.d.ts +12 -0
  23. package/dist/runtime-defaults.d.ts +2 -0
  24. package/package.json +2 -2
  25. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  26. package/src/commands/chat-commands-read.ts +2327 -0
  27. package/src/commands/chat-commands-scope.ts +54 -0
  28. package/src/commands/chat-commands-shared.ts +114 -0
  29. package/src/commands/chat-commands-write.ts +880 -0
  30. package/src/commands/chat-commands.ts +20 -3697
  31. package/src/commands/router.ts +59 -3631
  32. package/src/mesh/mesh-coordinator-config.ts +97 -0
  33. package/src/mesh/mesh-event-classify.ts +51 -0
  34. package/src/mesh/mesh-event-forwarding.ts +1502 -0
  35. package/src/mesh/mesh-events-coordinator.ts +30 -2993
  36. package/src/mesh/mesh-events-pending.ts +1 -10
  37. package/src/mesh/mesh-events-stale.ts +3 -14
  38. package/src/mesh/mesh-events-utils.ts +52 -14
  39. package/src/mesh/mesh-ledger-reconciliation.ts +0 -2
  40. package/src/mesh/mesh-node-identity.ts +1887 -0
  41. package/src/mesh/mesh-queue-assignment.ts +1457 -0
  42. package/src/mesh/mesh-refine-gates.ts +1652 -0
  43. package/src/mesh/mesh-runtime-store.ts +0 -37
  44. package/src/providers/cli-provider-instance.ts +40 -1
  45. package/src/providers/native-history/constants.ts +19 -0
  46. package/src/providers/native-history/dispatcher.ts +2 -3
  47. package/src/providers/spec/native-history-executor.ts +1 -9
  48. package/src/runtime-defaults.ts +39 -0
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Hermes / MCP coordinator config helpers
3
+ *
4
+ * Extracted from commands/router.ts (behavior-preserving move). Contains the
5
+ * MCP-server config parse/serialize helpers and the Hermes coordinator base
6
+ * config loading / temp-override stripping / credential-copy helpers.
7
+ *
8
+ * router.ts re-exports every public symbol from here so existing import paths
9
+ * keep working.
10
+ */
11
+ import type { MeshCoordinatorConfigFormat } from './mesh-refine-gates.js';
12
+ export declare function getMcpServersKey(format: MeshCoordinatorConfigFormat): 'mcpServers' | 'mcp_servers';
13
+ export declare function parseMeshCoordinatorMcpConfig(text: string, format: MeshCoordinatorConfigFormat): Record<string, any>;
14
+ export declare function serializeMeshCoordinatorMcpConfig(config: Record<string, any>, format: MeshCoordinatorConfigFormat): string;
15
+ export declare function loadHermesCoordinatorBaseConfig(targetConfigPath: string): {
16
+ config: Record<string, any>;
17
+ sourceHome: string;
18
+ sourceConfigPath: string;
19
+ };
20
+ export declare function stripHermesCoordinatorTempModelProviderOverrides(config: Record<string, any>): Record<string, any>;
21
+ export declare function copyHermesCoordinatorCredentialFiles(sourceHome: string, targetHome: string): void;
@@ -0,0 +1,5 @@
1
+ import type { MeshLedgerKind } from './mesh-ledger.js';
2
+ export declare const EVENT_TO_LEDGER_KIND: Record<string, MeshLedgerKind>;
3
+ export declare function isMeshCoordinatorEvent(eventName: unknown): eventName is string;
4
+ export declare const MESH_FORCE_INJECT_EVENTS: ReadonlySet<string>;
5
+ export declare function shouldForceInjectMeshEvent(eventName: unknown): boolean;
@@ -0,0 +1,18 @@
1
+ import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
2
+ export declare function resolveForwardEventMeshId(components: DaemonComponents, payload: Record<string, unknown>): string;
3
+ export declare function __resetMeshWorkspaceCacheForTests(): void;
4
+ export declare function buildRelayMetadataEvent(payload: Record<string, unknown>): Record<string, unknown>;
5
+ export declare function handleMeshForwardEvent(components: DaemonComponents, payload: Record<string, unknown>): {
6
+ [extra: string]: unknown;
7
+ success: true;
8
+ forwarded: 0;
9
+ suppressed: true;
10
+ } | {
11
+ success: boolean;
12
+ forwarded: number;
13
+ error?: undefined;
14
+ } | {
15
+ success: boolean;
16
+ error: string;
17
+ };
18
+ export declare function setupMeshEventForwarding(components: DaemonComponents): void;
@@ -1,92 +1,4 @@
1
- import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
2
- import type { RepoMeshSchedulingStrategy } from '../repo-mesh-types.js';
3
- export declare function resolveForwardEventMeshId(components: DaemonComponents, payload: Record<string, unknown>): string;
4
- export declare function __resetIdleAutoFastForwardForTests(): void;
5
- export declare function __resetMeshWorkspaceCacheForTests(): void;
6
- export declare function tryAssignQueueTask(components: DaemonComponents, meshId: string, nodeId: string, sessionId: string, providerType: string): boolean;
7
- /** Active assignments that hold the one-active-per-node / global-parallel invariant
8
- * (everything except read-only diagnoses, which run unbounded by the write cap). */
9
- export declare function activeWriteAssignedCount(meshId: string): number;
10
- /** Active read-only (live_debug_readonly) assignments, for the read-only safety cap. */
11
- export declare function activeReadonlyAssignedCount(meshId: string): number;
12
- /**
13
- * Order eligible nodes for assignment per the mesh scheduling pipeline:
14
- * PRIORITY (schedulingPriority desc) → TIE-BREAK (strategy).
15
- *
16
- * The caller has already applied the TAG hard-filter and is responsible for the
17
- * MAX-ALLOC capacity gate (the per-node launch/claim checks). This function only
18
- * decides the *preference order* among nodes that are otherwise eligible.
19
- *
20
- * - 'first_eligible' (default): returns the input order verbatim and does NOT touch
21
- * the round-robin cursor — byte-for-byte the pre-feature behavior.
22
- * - 'priority_only': schedulingPriority desc, then input order (load ignored).
23
- * - 'least_loaded': schedulingPriority desc, then active load asc, then input order.
24
- * - 'round_robin': same as least_loaded, but among nodes tied at (priority, load)
25
- * the input order is rotated by a per-mesh cursor that advances once per pass.
26
- *
27
- * `nodes` carries the original config/array index so the tie-break can fall back to
28
- * deterministic input order. `bumpCursor` advances the round-robin cursor exactly
29
- * once per scheduling pass (only consulted for 'round_robin').
30
- */
31
- interface RankableNode {
32
- nodeId: string;
33
- node: any;
34
- index: number;
35
- }
36
- /** Test-only: the pure node-ordering stage (PRIORITY → TIE-BREAK). Exposed so the
37
- * scheduling pipeline can be unit-tested without standing up live CLI sessions. */
38
- export declare function __orderEligibleNodesForTests(meshId: string, strategy: RepoMeshSchedulingStrategy, nodes: RankableNode[], opts?: {
39
- bumpCursor?: boolean;
40
- }): RankableNode[];
41
- export interface MeshQueueTriggerResult {
42
- success: true;
43
- meshId: string;
44
- pendingBefore: number;
45
- assignedBefore: number;
46
- pendingAfter: number;
47
- assignedAfter: number;
48
- claimed: boolean;
49
- newlyAssignedTasks: Array<{
50
- id: string;
51
- nodeId?: string;
52
- sessionId?: string;
53
- }>;
54
- localIdleSessionsChecked: number;
55
- remoteIdleSessionsChecked: number;
56
- skippedSessions: Array<{
57
- nodeId?: string;
58
- sessionId?: string;
59
- reason: string;
60
- status?: string;
61
- }>;
62
- autoLaunchStarted: boolean;
63
- /**
64
- * True when a worker session is already on its way to claim a still-pending task —
65
- * either launched this tick (autoLaunchStarted) or launched on a prior tick and still
66
- * booting/awaiting-claim. Callers MUST treat this as "wait, do not launch another
67
- * session": a second launch double-edits the worktree. Mutually informative with
68
- * `noIdleMeshSessionAvailable`, which is suppressed whenever this is true.
69
- */
70
- autoLaunchPending?: boolean;
71
- noIdleMeshSessionAvailable?: boolean;
72
- }
73
- export declare function triggerMeshQueue(components: DaemonComponents, meshId: string): Promise<MeshQueueTriggerResult>;
74
- export declare function isMeshCoordinatorEvent(eventName: unknown): eventName is string;
75
- export declare const MESH_FORCE_INJECT_EVENTS: ReadonlySet<string>;
76
- export declare function shouldForceInjectMeshEvent(eventName: unknown): boolean;
77
- export declare function buildRelayMetadataEvent(payload: Record<string, unknown>): Record<string, unknown>;
78
- export declare function handleMeshForwardEvent(components: DaemonComponents, payload: Record<string, unknown>): {
79
- [extra: string]: unknown;
80
- success: true;
81
- forwarded: 0;
82
- suppressed: true;
83
- } | {
84
- success: boolean;
85
- forwarded: number;
86
- error?: undefined;
87
- } | {
88
- success: boolean;
89
- error: string;
90
- };
91
- export declare function setupMeshEventForwarding(components: DaemonComponents): void;
92
- export {};
1
+ export { isMeshCoordinatorEvent, MESH_FORCE_INJECT_EVENTS, shouldForceInjectMeshEvent, } from './mesh-event-classify.js';
2
+ export { __orderEligibleNodesForTests, __resetIdleAutoFastForwardForTests, activeReadonlyAssignedCount, activeWriteAssignedCount, triggerMeshQueue, tryAssignQueueTask, } from './mesh-queue-assignment.js';
3
+ export type { MeshQueueTriggerResult } from './mesh-queue-assignment.js';
4
+ export { __resetMeshWorkspaceCacheForTests, buildRelayMetadataEvent, handleMeshForwardEvent, resolveForwardEventMeshId, setupMeshEventForwarding, } from './mesh-event-forwarding.js';
@@ -52,6 +52,9 @@ export declare function resolveMeshSurfacedSessionPreview(metadataEvent: Record<
52
52
  role: 'assistant';
53
53
  receivedAt: number;
54
54
  } | undefined;
55
+ export declare function isMissingFinalAssistantDiagnostic(record: Record<string, unknown> | undefined): boolean;
56
+ export declare function isFalseIdleCompletion(record: Record<string, unknown>): boolean;
57
+ export declare function isWeakCompletionEvidence(record: Record<string, unknown> | undefined): boolean;
55
58
  export declare function isWeakCompletionMetadata(metadataEvent: Record<string, unknown>): boolean;
56
59
  export declare function buildMeshSystemMessage(args: {
57
60
  event: string;
@@ -44,7 +44,6 @@ export interface MeshLedgerReconciliationEvidence {
44
44
  sourceOfTruth: {
45
45
  kind: 'coordinator_local_sqlite';
46
46
  p2pOnly: true;
47
- cloudD1LedgerSync: false;
48
47
  notes: string;
49
48
  };
50
49
  replicas: MeshLedgerReplicaEvidence[];
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Mesh node-identity & git-freshness helpers
3
+ *
4
+ * Extracted from commands/router.ts (behavior-preserving move). Contains:
5
+ * - daemon-id / machine-id / hostname normalization + canonicalization
6
+ * - inline-mesh node identity reconciliation and transient-state handling
7
+ * - git-status normalization, branch-convergence, and freshness/staleness derivation
8
+ * - the direct git-probe cache and remote git-status probe machinery
9
+ *
10
+ * router.ts re-exports every public symbol from here so existing import paths
11
+ * (e.g. `from '.../commands/router.js'`) keep working.
12
+ */
13
+ import type { ProviderLoader } from '../providers/provider-loader.js';
14
+ import { awaitWithWarmupDeadline } from '../mesh/mesh-warmup-deadline.js';
15
+ export declare function readProviderPriorityFromPolicy(policy: unknown): string[];
16
+ /**
17
+ * Normalize a providerRoles array (RepoMeshNodePolicy.providerRoles) from raw
18
+ * tool args. Each entry binds a providerType to an optional `maxParallel` cap.
19
+ * Entries without a usable providerType are dropped; the last entry wins on
20
+ * duplicate providerType. Returns [] when no valid entries — callers then omit
21
+ * the field entirely (full backward compat). Routing is governed by required_tags;
22
+ * any legacy `role` field on the input is ignored.
23
+ */
24
+ export declare function normalizeProviderRoles(value: unknown): Array<{
25
+ providerType: string;
26
+ maxParallel?: number;
27
+ }>;
28
+ export declare function readObjectRecord(value: unknown): Record<string, any>;
29
+ export declare function readStringValue(...values: unknown[]): string | undefined;
30
+ export declare function readBooleanValue(...values: unknown[]): boolean | undefined;
31
+ export declare function summarizeRepoMeshStatusDebug(status: any): Record<string, unknown>;
32
+ export declare function logRepoMeshStatusDebug(event: string, fields: Record<string, unknown>): void;
33
+ export declare function buildMeshNodeDisplayLabel(node: Record<string, unknown>, nodeId: string, providerPriority: string[]): string;
34
+ export declare function readMeshNodeMachineId(node: Record<string, unknown>): string | undefined;
35
+ export declare function readMeshNodeDaemonId(node: Record<string, unknown>): string | undefined;
36
+ export declare function readMeshNodeHostname(node: Record<string, unknown>): string | undefined;
37
+ export declare function buildMeshNodeMachineIdentity(node: Record<string, unknown>, opts: {
38
+ localMachineId?: string;
39
+ localDaemonId?: string;
40
+ coordinatorHostname?: string;
41
+ isSelfNode?: boolean;
42
+ }): Record<string, unknown>;
43
+ export declare function buildInlineMeshTransitGitStatus(node: any): Record<string, unknown> | undefined;
44
+ export declare function shouldRefreshStalePendingAggregate(snapshot: any, options?: {
45
+ requireDirectPeerTruth?: boolean;
46
+ }): boolean;
47
+ export declare function buildLivePeerGitConnection(connection: Record<string, unknown>, timestamp?: string): Record<string, unknown>;
48
+ export declare function recordInlineMeshDirectGitTruth(node: any, git: Record<string, unknown>, source: 'selected_coordinator_local_git' | 'selected_coordinator_mesh_p2p_git'): {
49
+ reporterPlatform: string | null;
50
+ reporterArch: string | null;
51
+ };
52
+ /**
53
+ * Persist the live self-reported platform/arch onto the local meshes.json node
54
+ * record so capability-tag os=/arch= self-heals across coordinator restarts.
55
+ *
56
+ * The in-memory stamp done by recordInlineMeshDirectGitTruth lives on the
57
+ * mesh_status assembly object and is discarded after the response; only a
58
+ * `local_config` mesh has a backing meshes.json node to write through to. Inline
59
+ * cache/bootstrap meshes have no local node to update, so we no-op for them.
60
+ * Fire-and-forget (same pattern as the worktreeBootstrap writer) — a persistence
61
+ * failure must never block the status response.
62
+ */
63
+ export declare function persistNodeReporterPlatform(meshSource: 'inline_cache' | 'inline_bootstrap' | 'local_config', mesh: any, nodeId: string | undefined, reporter: {
64
+ reporterPlatform: string | null;
65
+ reporterArch: string | null;
66
+ }): void;
67
+ export declare function inlineMeshCarriesTransientNodeTruth(inlineMesh: any): boolean;
68
+ export declare function readInlineMeshNodeId(node: any): string;
69
+ export declare function isDeadLocalWorktreeNode(node: any): boolean;
70
+ export declare function foldMeshNodeIdentityToCanonical(node: any): any;
71
+ export declare function normalizeInlineMeshNodeIdentity(inlineMesh: any): any;
72
+ export declare function sanitizeInlineMesh(inlineMesh: any): any;
73
+ export declare function reconcileInlineMeshCache(cached: any, incoming: any): any;
74
+ export declare function deriveMeshNodeHealthFromGit(git: Record<string, unknown> | null | undefined): 'online' | 'dirty' | 'degraded';
75
+ export declare function applyInlineMeshBranchConvergence(mesh: any, node: any, status: Record<string, unknown>): void;
76
+ export declare function summarizeInlineMeshBranchConvergence(nodes: Array<Record<string, unknown>>): Record<string, unknown>;
77
+ export declare function readCachedInlineMeshActiveSessions(node: any): string[];
78
+ /**
79
+ * Wider session-ownership scan used ONLY by resolveRemoteMeshSessionOwnerDaemonId: collect
80
+ * EVERY session id a mesh node currently hosts. readCachedInlineMeshActiveSessions above only
81
+ * surfaces the node's single primary session (cachedStatus.activeSession) — other consumers
82
+ * depend on that one-session semantics, so it is left untouched. A worker hosting more than one
83
+ * session exposes its non-primary sessions only through the plural live-session arrays the
84
+ * coordinator carries: status.activeSessions / activeSessionDetails (built from live records on
85
+ * the aggregate snapshot, see get_mesh_status), or a worker's merged session report. A
86
+ * controlbar/modal command (invoke_provider_script / resolve_action / set_mode / …) targeting a
87
+ * non-primary remote session resolves its owner daemon only when those plural shapes are scanned
88
+ * too. Mirrors sessionStatusFromNodes' shape tolerance (mesh-active-work.ts): plural arrays of
89
+ * string ids OR objects keyed by id/sessionId/session_id/runtimeSessionId/instanceId, on both
90
+ * camelCase and snake_case, at the node root and under cachedStatus / lastProbe.
91
+ */
92
+ export declare function collectMeshNodeHostedSessionIds(node: any): Set<string>;
93
+ /**
94
+ * Resolve the owning-node attribution for a mesh node record so a coordinator can
95
+ * stamp the TRUE owner onto a synthetic session entry instead of letting the
96
+ * dashboard fall back to the coordinator's own daemonId. Returns whichever of the
97
+ * owning node's `daemonId` / display machine name could be read from the node's
98
+ * (possibly multi-serialization-path) shape; both may be undefined for a node that
99
+ * never carried machine identity.
100
+ */
101
+ export declare function resolveMeshNodeAttribution(node: unknown): {
102
+ daemonId?: string;
103
+ machineName?: string;
104
+ };
105
+ export declare function readCachedInlineMeshActiveSessionDetails(node: any): Array<Record<string, unknown>>;
106
+ /**
107
+ * Transient per-node marker the mesh_status render loop stamps onto a node
108
+ * `status` at the two sites that obtain git truth from a FRESH probe this call
109
+ * (a successful local `getGitRepoStatus`, or a successful P2P `git_status`
110
+ * round-trip). finalizeMeshNodeStatus consumes and deletes it. Held/standing
111
+ * truth (node.lastGit / cachedStatus / inline transit) is deliberately NOT
112
+ * stamped — its absence is exactly how the freshness marker tells "live" apart
113
+ * from "cached". Internal only; never serialized in the response.
114
+ */
115
+ export declare const MESH_NODE_LIVE_TRUTH_MARKER = "__liveTruthProbed";
116
+ /**
117
+ * Build the additive per-node `dataFreshness` marker. This NEVER mutates any
118
+ * existing field — it only adds an explicit, machine-readable answer to the
119
+ * question the legacy fields blurred: is this node's data live (just probed),
120
+ * cached (held truth, maybe old), or absent because the peer was unreachable?
121
+ *
122
+ * The crucial separation: an UNREACHABLE peer (P2P probe failed / not connected)
123
+ * is no longer indistinguishable from an idle/EMPTY node. Both used to render as
124
+ * `health:'unknown'` with no sessions; now `dataFreshness.dataSource` and
125
+ * `reachable` tell them apart so a coordinator never reads a dead peer as "online
126
+ * but doing nothing".
127
+ */
128
+ export declare function buildMeshNodeDataFreshness(args: {
129
+ status: Record<string, unknown>;
130
+ node?: any;
131
+ isSelfNode: boolean;
132
+ daemonId?: string;
133
+ /** True when this node was stamped with a fresh live git probe this call. */
134
+ liveTruthProbed: boolean;
135
+ /** True when direct-peer-truth accounting classified this node unavailable. */
136
+ directTruthUnavailable?: boolean;
137
+ now?: () => number;
138
+ }): Record<string, unknown>;
139
+ /**
140
+ * Canonical live-probe → freshness adapter. The coordinator-facing mesh_status
141
+ * (mcp-server `meshStatus`) builds each node entry from a SINGLE fresh git_status
142
+ * probe that either returns (live truth) or throws (peer unreachable). It used to
143
+ * hand-reconstruct the freshness INPUT inline — a synthetic `{ git, connection }`
144
+ * status plus the directTruthUnavailable/liveTruthProbed wiring — which is exactly
145
+ * how a field added to `buildMeshNodeDataFreshness`'s input contract ends up "wired
146
+ * on the daemon surface, null on the coordinator surface" (the rc.371
147
+ * null-everywhere regression). Routing every live-probe surface through this one
148
+ * adapter keeps the marker derivation canonical: there is a SINGLE place that turns
149
+ * a probe outcome into freshness args, so the two mesh_status surfaces cannot drift.
150
+ *
151
+ * `liveTruthProbed` true → the probe returned (live/self truth); false → it threw,
152
+ * so a configured peer is unreachable while an unconfigured node (no daemonId) falls
153
+ * through to the classifier's `unconfigured` branch.
154
+ */
155
+ export declare function buildMeshNodeProbeFreshness(args: {
156
+ /** The git snapshot this probe stamped on the node entry (entry.git). */
157
+ git: unknown;
158
+ /** True when the fresh git_status probe RETURNED (live truth); false when it threw. */
159
+ liveTruthProbed: boolean;
160
+ isSelfNode: boolean;
161
+ /** The node's resolved daemonId; absent → unconfigured node. */
162
+ daemonId?: string;
163
+ /** The mesh node record, for held-git fallback when the probe did not return live. */
164
+ node?: any;
165
+ now?: () => number;
166
+ }): Record<string, unknown>;
167
+ export declare function finalizeMeshNodeStatus(args: {
168
+ status: Record<string, unknown>;
169
+ node: any;
170
+ daemonId?: string;
171
+ isSelfNode: boolean;
172
+ /** True when direct-peer-truth accounting classified this node unavailable. */
173
+ directTruthUnavailable?: boolean;
174
+ }): void;
175
+ export declare const MESH_DIRECT_PROBE_TIMEOUT_MS: number;
176
+ export declare const MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS: number;
177
+ export declare const MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS: number;
178
+ export declare const MESH_DIRECT_PROBE_REUSE_MS: number;
179
+ /**
180
+ * De-duplicates and rate-limits per-peer git_status probes so a single mesh
181
+ * refresh — or a burst of refreshes from the dashboard auto-retry loop — cannot
182
+ * launch a storm of concurrent/back-to-back `refreshUpstream:true` commands to
183
+ * the same slow peer.
184
+ *
185
+ * Two gates, both keyed by `daemonId::workspace`:
186
+ * - In-flight dedup: a second probe for a key with a probe already running
187
+ * shares (awaits) the in-flight promise instead of issuing a second command.
188
+ * - Recently-probed reuse: a successful probe younger than `reuseMs` is reused
189
+ * verbatim instead of issuing a fresh probe. Failures are NOT cached (so a
190
+ * transient timeout doesn't pin a peer to "no truth" for the whole window).
191
+ *
192
+ * Lives on the router instance so the gate spans separate mesh_status calls,
193
+ * which is exactly where the refresh storm happens.
194
+ */
195
+ export declare class MeshGitProbeCache {
196
+ private readonly reuseMs;
197
+ private readonly now;
198
+ private inflight;
199
+ private recent;
200
+ constructor(reuseMs: number, now?: () => number);
201
+ private key;
202
+ /**
203
+ * Run `probe` for this peer, but reuse a fresh recent result or an in-flight
204
+ * probe for the same key when one is available. `probe` is only invoked when
205
+ * neither gate is satisfied.
206
+ */
207
+ probe(daemonId: string, workspace: string, probe: () => Promise<Record<string, unknown> | null>): Promise<Record<string, unknown> | null>;
208
+ }
209
+ export { awaitWithWarmupDeadline };
210
+ /**
211
+ * Probe a remote peer's git_status with a bounded retry budget, but only while
212
+ * the peer is reported `connected`. A single slow (often TURN-relayed) peer can
213
+ * exceed one probe window; retrying — with the connection re-checked before each
214
+ * attempt so we abandon a peer that dropped — recovers it without blocking the
215
+ * mesh forever. Shared by the bootstrap hydrate path and the per-node render
216
+ * path so both treat a connected-but-slow peer identically.
217
+ *
218
+ * Returns the git status on success, or null if every attempt failed/timed out
219
+ * (caller decides how to classify). `getConnection` is consulted before each
220
+ * attempt; a non-`connected` state short-circuits the retry loop (the very first
221
+ * attempt always runs so a missing connection getter still gets one try).
222
+ */
223
+ export declare function probeRemoteMeshGitStatusWithRetry(args: {
224
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
225
+ daemonId: string;
226
+ workspace: string;
227
+ timeoutMs: number;
228
+ /** Per-attempt timeout for retries (attempts > 0); defaults to timeoutMs. */
229
+ retryTimeoutMs?: number;
230
+ /** Cold-open warmup budget per attempt; defaults to MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS. */
231
+ connectTimeoutMs?: number;
232
+ getConnection?: (daemonId: string) => Record<string, unknown> | null;
233
+ onConnection?: (connection: Record<string, unknown>) => void;
234
+ }): Promise<Record<string, unknown> | null>;
235
+ export declare function hydrateInlineMeshDirectTruth(args: {
236
+ mesh: any;
237
+ meshSource: 'inline_cache' | 'inline_bootstrap' | 'local_config';
238
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
239
+ getMeshPeerConnectionStatus?: (daemonId: string) => Record<string, unknown> | null;
240
+ statusInstanceId?: string;
241
+ localMachineId?: string;
242
+ probeRemotePeers: boolean;
243
+ probeCache?: MeshGitProbeCache;
244
+ }): Promise<{
245
+ directEvidenceCount: number;
246
+ localConfirmedCount: number;
247
+ peerAttemptedCount: number;
248
+ peerConfirmedCount: number;
249
+ standingEvidenceCount: number;
250
+ unavailableNodeIds: string[];
251
+ deadNodeIds: string[];
252
+ }>;
253
+ export declare function summarizeMeshSessionRecord(record: any): Record<string, unknown>;
254
+ export declare function readLiveMeshNodeWorkspace(args: {
255
+ meshId: string;
256
+ nodeId: string;
257
+ liveSessionRecords: any[];
258
+ allowCoordinatorSession?: boolean;
259
+ }): string;
260
+ export declare function collectLiveMeshSessionRecords(args: {
261
+ meshId: string;
262
+ node: any;
263
+ nodeId: string;
264
+ liveSessionRecords: any[];
265
+ allowCoordinatorSession?: boolean;
266
+ }): any[];
267
+ export declare function buildHistoricalMeshSessions(args: {
268
+ meshId: string;
269
+ nodes: any[];
270
+ liveSessionRecords: any[];
271
+ }): {
272
+ count: number;
273
+ sessions: Record<string, unknown>[];
274
+ instruction: string;
275
+ } | undefined;
276
+ export declare function applyCachedInlineMeshNodeStatus(status: Record<string, unknown>, node: any, options?: {
277
+ skipGit?: boolean;
278
+ skipError?: boolean;
279
+ skipHealth?: boolean;
280
+ }): boolean;
281
+ export declare function resolveProviderTypeFromPriority(args: {
282
+ nodeId: string;
283
+ providerPriority: string[];
284
+ providerLoader: ProviderLoader;
285
+ onStatusChange?: () => void;
286
+ }): Promise<{
287
+ providerType?: string;
288
+ error?: string;
289
+ }>;
@@ -0,0 +1,86 @@
1
+ import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
2
+ import type { RepoMeshSchedulingStrategy } from '../repo-mesh-types.js';
3
+ export declare function __resetIdleAutoFastForwardForTests(): void;
4
+ export declare function getMeshWithCache(components: DaemonComponents, meshId: string): any | undefined;
5
+ export declare function tryAssignQueueTask(components: DaemonComponents, meshId: string, nodeId: string, sessionId: string, providerType: string): boolean;
6
+ /** Active assignments that hold the one-active-per-node / global-parallel invariant
7
+ * (everything except read-only diagnoses, which run unbounded by the write cap). */
8
+ export declare function activeWriteAssignedCount(meshId: string): number;
9
+ /** Active read-only (live_debug_readonly) assignments, for the read-only safety cap. */
10
+ export declare function activeReadonlyAssignedCount(meshId: string): number;
11
+ /**
12
+ * Order eligible nodes for assignment per the mesh scheduling pipeline:
13
+ * PRIORITY (schedulingPriority desc) → TIE-BREAK (strategy).
14
+ *
15
+ * The caller has already applied the TAG hard-filter and is responsible for the
16
+ * MAX-ALLOC capacity gate (the per-node launch/claim checks). This function only
17
+ * decides the *preference order* among nodes that are otherwise eligible.
18
+ *
19
+ * - 'first_eligible' (default): returns the input order verbatim and does NOT touch
20
+ * the round-robin cursor — byte-for-byte the pre-feature behavior.
21
+ * - 'priority_only': schedulingPriority desc, then input order (load ignored).
22
+ * - 'least_loaded': schedulingPriority desc, then active load asc, then input order.
23
+ * - 'round_robin': same as least_loaded, but among nodes tied at (priority, load)
24
+ * the input order is rotated by a per-mesh cursor that advances once per pass.
25
+ *
26
+ * `nodes` carries the original config/array index so the tie-break can fall back to
27
+ * deterministic input order. `bumpCursor` advances the round-robin cursor exactly
28
+ * once per scheduling pass (only consulted for 'round_robin').
29
+ */
30
+ interface RankableNode {
31
+ nodeId: string;
32
+ node: any;
33
+ index: number;
34
+ }
35
+ /** Test-only: the pure node-ordering stage (PRIORITY → TIE-BREAK). Exposed so the
36
+ * scheduling pipeline can be unit-tested without standing up live CLI sessions. */
37
+ export declare function __orderEligibleNodesForTests(meshId: string, strategy: RepoMeshSchedulingStrategy, nodes: RankableNode[], opts?: {
38
+ bumpCursor?: boolean;
39
+ }): RankableNode[];
40
+ export declare function sessionHasActiveAssignment(meshId: string, sessionId: string): boolean;
41
+ export interface MeshQueueTriggerResult {
42
+ success: true;
43
+ meshId: string;
44
+ pendingBefore: number;
45
+ assignedBefore: number;
46
+ pendingAfter: number;
47
+ assignedAfter: number;
48
+ claimed: boolean;
49
+ newlyAssignedTasks: Array<{
50
+ id: string;
51
+ nodeId?: string;
52
+ sessionId?: string;
53
+ }>;
54
+ localIdleSessionsChecked: number;
55
+ remoteIdleSessionsChecked: number;
56
+ skippedSessions: Array<{
57
+ nodeId?: string;
58
+ sessionId?: string;
59
+ reason: string;
60
+ status?: string;
61
+ }>;
62
+ autoLaunchStarted: boolean;
63
+ /**
64
+ * True when a worker session is already on its way to claim a still-pending task —
65
+ * either launched this tick (autoLaunchStarted) or launched on a prior tick and still
66
+ * booting/awaiting-claim. Callers MUST treat this as "wait, do not launch another
67
+ * session": a second launch double-edits the worktree. Mutually informative with
68
+ * `noIdleMeshSessionAvailable`, which is suppressed whenever this is true.
69
+ */
70
+ autoLaunchPending?: boolean;
71
+ noIdleMeshSessionAvailable?: boolean;
72
+ }
73
+ export declare function triggerMeshQueue(components: DaemonComponents, meshId: string): Promise<MeshQueueTriggerResult>;
74
+ export declare function maybeAutoFastForwardIdleNode(components: DaemonComponents, args: {
75
+ meshId: string;
76
+ nodeId: string;
77
+ sessionId?: string;
78
+ providerType?: string;
79
+ }): Promise<void>;
80
+ export declare function runIdleMaintenanceThenAssignQueue(components: DaemonComponents, args: {
81
+ meshId: string;
82
+ nodeId: string;
83
+ sessionId: string;
84
+ providerType: string;
85
+ }): void;
86
+ export {};