@adhdev/daemon-core 0.9.82-rc.360 → 0.9.82-rc.361
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/cli-manager.d.ts +13 -0
- package/dist/commands/low-family/index.d.ts +3 -0
- package/dist/commands/low-family/refine-config.d.ts +2 -0
- package/dist/commands/low-family/session-host.d.ts +2 -0
- package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
- package/dist/commands/low-family/types.d.ts +16 -0
- package/dist/commands/router.d.ts +0 -1
- package/dist/index.js +2074 -2008
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2073 -2007
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events-utils.d.ts +0 -2
- package/package.json +2 -2
- package/src/commands/cli-manager.ts +69 -4
- package/src/commands/low-family/index.ts +23 -0
- package/src/commands/low-family/refine-config.ts +106 -0
- package/src/commands/low-family/session-host.ts +274 -0
- package/src/commands/low-family/spec-providerdev.ts +217 -0
- package/src/commands/low-family/types.ts +19 -0
- package/src/commands/router.ts +15 -555
- package/src/mesh/contracts.ts +12 -3
- package/src/mesh/mesh-events-coordinator.ts +1 -1
- package/src/mesh/mesh-events-utils.ts +0 -20
- package/src/providers/cli-provider-instance.ts +16 -3
package/src/mesh/contracts.ts
CHANGED
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
* types and leaves runtime behaviour unchanged.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
import { daemonIdsEquivalent, machineCoreFromDaemonId } from '@adhdev/mesh-shared';
|
|
32
|
+
|
|
31
33
|
/** Provider type identifier (e.g. 'claude-cli', 'codex-cli', 'roo-code').
|
|
32
34
|
* Free-form string; no shared enum exists in daemon-core yet. */
|
|
33
35
|
type ProviderType = string;
|
|
@@ -76,15 +78,22 @@ export interface CoordinatorIdentity {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
export function coordinatorIdentityEquals(a: CoordinatorIdentity, b: CoordinatorIdentity): boolean {
|
|
79
|
-
|
|
81
|
+
// daemonId compares by machine core: the same daemon answers to three
|
|
82
|
+
// interchangeable id forms (mach_X / daemon_mach_X / standalone_mach_X), so a
|
|
83
|
+
// raw `===` would treat one coordinator addressed under two forms as distinct.
|
|
84
|
+
return daemonIdsEquivalent(a.daemonId, b.daemonId)
|
|
80
85
|
&& a.coordinatorRunId === b.coordinatorRunId
|
|
81
86
|
&& (a.sessionId ?? '') === (b.sessionId ?? '');
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
export function coordinatorIdentityKey(identity: CoordinatorIdentity): string {
|
|
85
90
|
// Stable string form for map keys and ledger payloads. Avoids the
|
|
86
|
-
// {a:b, c:d} JSON.stringify ordering trap by enforcing field order.
|
|
87
|
-
|
|
91
|
+
// {a:b, c:d} JSON.stringify ordering trap by enforcing field order. The
|
|
92
|
+
// daemonId is normalized to its machine core so the key stays consistent with
|
|
93
|
+
// coordinatorIdentityEquals — two equal identities addressed under different
|
|
94
|
+
// daemon-id forms must produce the SAME key (else equal-but-distinct-key bug).
|
|
95
|
+
const daemonCore = machineCoreFromDaemonId(identity.daemonId) ?? identity.daemonId;
|
|
96
|
+
return `${daemonCore}|${identity.coordinatorRunId}|${identity.sessionId ?? ''}`;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
// ─── Session handle ──────────────────────────────────────────────────────
|
|
@@ -2444,7 +2444,7 @@ function ackUnresolvedDelegateForwardByFingerprint(
|
|
|
2444
2444
|
payload: Record<string, unknown>,
|
|
2445
2445
|
): void {
|
|
2446
2446
|
const match = peekUnresolvedDelegateForwards().find(entry =>
|
|
2447
|
-
entry.coordinatorDaemonId
|
|
2447
|
+
daemonIdsEquivalent(entry.coordinatorDaemonId, coordinatorDaemonId)
|
|
2448
2448
|
&& readNonEmptyString(entry.payload.event) === eventName
|
|
2449
2449
|
&& readNonEmptyString(entry.payload.targetSessionId || entry.payload.sessionId || entry.payload.instanceId)
|
|
2450
2450
|
=== readNonEmptyString(payload.targetSessionId || payload.sessionId || payload.instanceId)
|
|
@@ -10,26 +10,6 @@ export function readRecord(value: unknown): Record<string, unknown> | undefined
|
|
|
10
10
|
: undefined;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
// A single daemon is identified three ways across the system: the raw machineId
|
|
14
|
-
// (`mach_X`, what loadConfig().machineId returns and what the core forwarder uses as
|
|
15
|
-
// localDaemonId), the cloud daemon id (`daemon_mach_X`), and the standalone daemon id
|
|
16
|
-
// (`standalone_mach_X`, the runtime instanceId the MCP coordinator reports as
|
|
17
|
-
// ctx.localDaemonId). Worker envelope stamps (meshCoordinatorDaemonId) and coordinator
|
|
18
|
-
// drains use the prefixed forms, while the forwarder compares against the raw id — so a
|
|
19
|
-
// naive `===` treats the same daemon as remote and breaks both coordinator matching and
|
|
20
|
-
// the R3 direct-delivered dedup. Canonicalize to the raw id before comparing.
|
|
21
|
-
export function canonicalDaemonId(value: unknown): string {
|
|
22
|
-
const id = readNonEmptyString(value);
|
|
23
|
-
if (!id) return '';
|
|
24
|
-
return id.replace(/^(?:daemon|standalone)_/, '');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function sameDaemonId(a: unknown, b: unknown): boolean {
|
|
28
|
-
const ca = canonicalDaemonId(a);
|
|
29
|
-
const cb = canonicalDaemonId(b);
|
|
30
|
-
return ca !== '' && ca === cb;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
13
|
/**
|
|
34
14
|
* The relay-safety metadata a worker session must carry so that its completion /
|
|
35
15
|
* generating events route back to the coordinator proactively (without waiting for
|
|
@@ -910,7 +910,13 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
910
910
|
this.settings = {
|
|
911
911
|
...this.settings,
|
|
912
912
|
meshNodeFor: assignment.meshId,
|
|
913
|
-
|
|
913
|
+
// WTCLAIM (A): track the bound node id under BOTH the active marker
|
|
914
|
+
// (meshNodeId, cleared on detach) and a sticky marker (meshLastNodeId,
|
|
915
|
+
// preserved across detach). The sticky marker lets a detached but still
|
|
916
|
+
// coordinator-owned session be re-picked ONLY for the SAME node it served
|
|
917
|
+
// — never auto-adopted for a sibling node (e.g. a cloned worktree) that
|
|
918
|
+
// shares this daemon. See isMeshOwnedDelegateSession's post-detach gate.
|
|
919
|
+
...(assignment.nodeId ? { meshNodeId: assignment.nodeId, meshLastNodeId: assignment.nodeId } : {}),
|
|
914
920
|
...(assignment.taskId ? { meshActiveTaskId: assignment.taskId } : {}),
|
|
915
921
|
...(assignment.coordinatorDaemonId ? { meshCoordinatorDaemonId: assignment.coordinatorDaemonId } : {}),
|
|
916
922
|
// Session-level routing anchor: the originating coordinator session, so this
|
|
@@ -929,8 +935,15 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
929
935
|
detachMeshAssignment(): void {
|
|
930
936
|
if (!this.settings.meshNodeFor && !this.settings.meshActiveTaskId && !this.settings.meshNodeId) return;
|
|
931
937
|
const { meshNodeFor, meshNodeId, meshActiveTaskId, ...rest } = this.settings;
|
|
932
|
-
void meshNodeFor; void
|
|
933
|
-
|
|
938
|
+
void meshNodeFor; void meshActiveTaskId;
|
|
939
|
+
// WTCLAIM (A): clear the active binding but PRESERVE the last bound node id
|
|
940
|
+
// (meshLastNodeId) so a later sessionless dispatch can re-adopt this idle
|
|
941
|
+
// session ONLY for the node it last served. Carry the id being cleared, or
|
|
942
|
+
// keep an already-present sticky marker if meshNodeId was absent.
|
|
943
|
+
const lastNodeId = (typeof meshNodeId === 'string' && meshNodeId.trim())
|
|
944
|
+
? meshNodeId.trim()
|
|
945
|
+
: (typeof rest.meshLastNodeId === 'string' && rest.meshLastNodeId.trim() ? rest.meshLastNodeId.trim() : undefined);
|
|
946
|
+
this.settings = lastNodeId ? { ...rest, meshLastNodeId: lastNodeId } : rest;
|
|
934
947
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
935
948
|
}
|
|
936
949
|
|