harnery 0.45.0 → 0.45.1
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/commander.js +0 -1
- package/dist/commands/files.d.ts +2 -2
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +4 -7
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +17 -11
- package/dist/commands/tunnel.d.ts +0 -15
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +153 -453
- package/dist/core/agents/live-authority-v3.d.ts +0 -1
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +0 -11
- package/dist/core/agents/live-lifecycle-v3.d.ts +2 -4
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/live-lifecycle-v3.js +7 -28
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +14 -25
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-writer.js +0 -5
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +0 -5
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +70 -180
- package/dist/core/artifacts/activity.d.ts +4 -1
- package/dist/core/artifacts/activity.d.ts.map +1 -1
- package/dist/core/artifacts/activity.js +8 -2
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
- package/dist/core/artifacts/delivery-card.js +1 -2
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +38 -12
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +0 -29
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +0 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +0 -7
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +64 -77
- package/dist/core/hooks/cli.js +78 -48
- package/dist/core/servers/index.d.ts +13 -10
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +97 -192
- package/dist/core/servers/tunnels.d.ts +3 -5
- package/dist/core/servers/tunnels.d.ts.map +1 -1
- package/dist/core/servers/tunnels.js +2 -45
- package/dist/core/storage/durable-history.js +56 -22
- package/dist/core/storage/segments.d.ts.map +1 -1
- package/dist/core/storage/segments.js +73 -17
- package/dist/core/work/state.js +7 -7
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +21 -65
- package/dist/core/workflow/live-session-v3.d.ts +0 -6
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +5 -126
- package/dist/core/workflow/proof.d.ts +4 -4
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +4 -12
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +0 -19
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +0 -13
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +0 -19
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
- package/dist/core/workflow/spawn-opencode.js +0 -14
- package/dist/core/workflow/types.d.ts +11 -54
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +0 -4
- package/dist/lib/tunnel/state.d.ts +6 -13
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +12 -58
- package/package.json +1 -6
- package/src/commander.ts +0 -10
- package/src/commands/files.ts +5 -13
- package/src/commands/servers.ts +23 -12
- package/src/commands/tunnel.ts +166 -533
- package/src/core/agents/live-authority-v3.ts +0 -17
- package/src/core/agents/live-lifecycle-v3.ts +14 -52
- package/src/core/agents/state/heartbeat-writer.ts +12 -29
- package/src/core/agents/state/live-coordination-writer.ts +0 -29
- package/src/core/agents/state/pidmap.ts +0 -13
- package/src/core/agents/state/stale-sweep.ts +82 -247
- package/src/core/artifacts/activity.ts +9 -2
- package/src/core/artifacts/delivery-card.ts +1 -7
- package/src/core/artifacts/index.ts +45 -12
- package/src/core/events/v3/authority-outbox.ts +0 -56
- package/src/core/events/v3/producers/coordination-recorder.ts +0 -15
- package/src/core/events/v3/producers/recorder.ts +68 -94
- package/src/core/hooks/cli.ts +85 -47
- package/src/core/servers/index.ts +106 -228
- package/src/core/servers/tunnels.ts +3 -55
- package/src/core/storage/durable-history.ts +52 -20
- package/src/core/storage/segments.ts +79 -17
- package/src/core/work/state.ts +7 -7
- package/src/core/workflow/engine.ts +21 -73
- package/src/core/workflow/live-session-v3.ts +5 -146
- package/src/core/workflow/proof.ts +5 -21
- package/src/core/workflow/spawn-claude.ts +0 -18
- package/src/core/workflow/spawn-codex.ts +0 -13
- package/src/core/workflow/spawn-cursor.ts +0 -18
- package/src/core/workflow/spawn-opencode.ts +0 -14
- package/src/core/workflow/types.ts +11 -41
- package/src/lib/identities/assume.ts +0 -4
- package/src/lib/tunnel/state.ts +15 -70
- package/dist/commands/turn-rollback.d.ts +0 -5
- package/dist/commands/turn-rollback.d.ts.map +0 -1
- package/dist/commands/turn-rollback.js +0 -76
- package/dist/core/agents/state/unchanged-file.d.ts +0 -44
- package/dist/core/agents/state/unchanged-file.d.ts.map +0 -1
- package/dist/core/agents/state/unchanged-file.js +0 -390
- package/dist/core/events/v3/generation-custody.d.ts +0 -5
- package/dist/core/events/v3/generation-custody.d.ts.map +0 -1
- package/dist/core/events/v3/generation-custody.js +0 -50
- package/dist/core/turn-rollback/content.d.ts +0 -53
- package/dist/core/turn-rollback/content.d.ts.map +0 -1
- package/dist/core/turn-rollback/content.js +0 -396
- package/dist/core/turn-rollback/index.d.ts +0 -72
- package/dist/core/turn-rollback/index.d.ts.map +0 -1
- package/dist/core/turn-rollback/index.js +0 -443
- package/dist/core/workflow/failure-evidence.d.ts +0 -16
- package/dist/core/workflow/failure-evidence.d.ts.map +0 -1
- package/dist/core/workflow/failure-evidence.js +0 -114
- package/src/commands/turn-rollback.ts +0 -111
- package/src/core/agents/state/unchanged-file.ts +0 -456
- package/src/core/events/v3/generation-custody.ts +0 -59
- package/src/core/turn-rollback/content.ts +0 -499
- package/src/core/turn-rollback/index.ts +0 -580
- package/src/core/workflow/failure-evidence.ts +0 -141
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-authority-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-authority-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAI7C,OAAO,EAAE,KAAK,gBAAgB,EAA2B,MAAM,yBAAyB,CAAC;AAgBzF,OAAO,EACL,KAAK,mCAAmC,EAEzC,MAAM,iDAAiD,CAAC;AASzD,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,6BAA6B,CAAC;AAQrC,eAAO,MAAM,gCAAgC,EAAG,iBAA0B,CAAC;AAE3E,qBAAa,gCAAiC,SAAQ,KAAK;aAC7B,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAI3C;AAED,MAAM,MAAM,iCAAiC,GACzC;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,mCAAmC,CAAA;CAAE,CAAC;AAEvE,MAAM,WAAW,oCAAoC;IACnD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,OAAO,MAAM,EAAE,CAAC;IACrC,aAAa,EAAE,OAAO,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,uCAAuC;IACtD,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,+BAA+B;IAC9C,KAAK,EAAE,WAAW,GAAG,UAAU,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"live-authority-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-authority-v3.ts"],"names":[],"mappings":"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"}
|
|
@@ -419,10 +419,6 @@ function recordLiveAuthority(input, signal, observation, expected, desired, appl
|
|
|
419
419
|
platform: livePlatformV3(),
|
|
420
420
|
expected_prior_state_digest: coordinationAuthorityStateDigestV3(expected),
|
|
421
421
|
desired_state_digest: coordinationAuthorityStateDigestV3(desired),
|
|
422
|
-
expected_generation_id: input.expectedGenerationId ??
|
|
423
|
-
(subject === input.owner
|
|
424
|
-
? expected.v3_generation_id
|
|
425
|
-
: readLiveCoordinationRow(input.coordRoot, input.owner)?.v3_generation_id),
|
|
426
422
|
reconciler: {
|
|
427
423
|
readStateDigest: () => {
|
|
428
424
|
const heartbeat = readHeartbeat(input.coordRoot, subject);
|
|
@@ -452,16 +448,9 @@ export function liveCoordinationWriteModeV3(coordRoot) {
|
|
|
452
448
|
return route.mode;
|
|
453
449
|
}
|
|
454
450
|
function requireHeartbeat(input, owner) {
|
|
455
|
-
if (input.expectedGenerationId &&
|
|
456
|
-
readLiveCoordinationRow(input.coordRoot, owner)?.v3_generation_id !== input.expectedGenerationId) {
|
|
457
|
-
throw new LiveCoordinationAuthorityV3Error("expected_generation_changed");
|
|
458
|
-
}
|
|
459
451
|
const heartbeat = ensureLiveCoordinationHeartbeat(input.coordRoot, owner, owner === input.owner ? input.nativeSessionId : owner, input.adapter);
|
|
460
452
|
if (!heartbeat)
|
|
461
453
|
throw new LiveCoordinationAuthorityV3Error(`heartbeat_missing:${owner}`);
|
|
462
|
-
if (input.expectedGenerationId && heartbeat.v3_generation_id !== input.expectedGenerationId) {
|
|
463
|
-
throw new LiveCoordinationAuthorityV3Error("expected_generation_changed");
|
|
464
|
-
}
|
|
465
454
|
return heartbeat;
|
|
466
455
|
}
|
|
467
456
|
export function coordinationAuthorityStateDigestV3(heartbeat) {
|
|
@@ -11,12 +11,10 @@ interface LiveLifecycleObservationBaseV3 {
|
|
|
11
11
|
adapter: EventAdapterIdV3;
|
|
12
12
|
observedAt?: string;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
expectedGenerationId: `gen_${string}` | null;
|
|
14
|
+
export declare function recordLiveSweepObservationV3(input: LiveLifecycleObservationBaseV3 & {
|
|
16
15
|
observation: "stale_heartbeat" | "killed" | "unparseable_heartbeat" | "missing_timestamp";
|
|
17
16
|
ageMs: number;
|
|
18
|
-
}
|
|
19
|
-
export declare function recordLiveSweepObservationV3(input: LiveSweepObservationV3Input): LiveLifecycleObservationV3Result;
|
|
17
|
+
}): LiveLifecycleObservationV3Result;
|
|
20
18
|
export declare function recordLiveResumeObservationV3(input: LiveLifecycleObservationBaseV3): LiveLifecycleObservationV3Result;
|
|
21
19
|
export {};
|
|
22
20
|
//# sourceMappingURL=live-lifecycle-v3.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-lifecycle-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-lifecycle-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"live-lifecycle-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-lifecycle-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAaxD,MAAM,MAAM,gCAAgC,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAErF,UAAU,8BAA8B;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,8BAA8B,GAAG;IACtC,WAAW,EAAE,iBAAiB,GAAG,QAAQ,GAAG,uBAAuB,GAAG,mBAAmB,CAAC;IAC1F,KAAK,EAAE,MAAM,CAAC;CACf,GACA,gCAAgC,CAOlC;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,8BAA8B,GACpC,gCAAgC,CAQlC"}
|
|
@@ -3,27 +3,17 @@ import { buildEventV3 } from "../events/v3/builder.js";
|
|
|
3
3
|
import { normalizeNativeIdV3 } from "../events/v3/canonical.js";
|
|
4
4
|
import { readEventV3ControlState } from "../events/v3/control.js";
|
|
5
5
|
import { fingerprintContextV3 } from "../events/v3/fingerprint-keys.js";
|
|
6
|
-
import { withGenerationCustodyV3 } from "../events/v3/generation-custody.js";
|
|
7
6
|
import { liveInstanceIdV3, livePlatformV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
8
7
|
import { readJoinableHookProducerStateV3 } from "../events/v3/producers/recorder.js";
|
|
9
8
|
import { writeEventV3 } from "../events/v3/writer.js";
|
|
10
9
|
import { LiveCoordinationAuthorityV3Error } from "./live-authority-v3.js";
|
|
11
10
|
import { liveCoordinationAdapterV3 } from "./state/live-coordination-view.js";
|
|
12
11
|
export function recordLiveSweepObservationV3(input) {
|
|
13
|
-
input
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
requireSweepHookState(input);
|
|
19
|
-
return recordObservation(input, "lifecycle.sweep_observed", {
|
|
20
|
-
subject_instance_id: liveInstanceIdV3(input.owner),
|
|
21
|
-
observation: input.observation,
|
|
22
|
-
provisional: true,
|
|
23
|
-
age_ms: Math.max(0, Math.floor(input.ageMs)),
|
|
24
|
-
}, () => {
|
|
25
|
-
requireSweepHookState(input);
|
|
26
|
-
});
|
|
12
|
+
return recordObservation(input, "lifecycle.sweep_observed", {
|
|
13
|
+
subject_instance_id: liveInstanceIdV3(input.owner),
|
|
14
|
+
observation: input.observation,
|
|
15
|
+
provisional: true,
|
|
16
|
+
age_ms: Math.max(0, Math.floor(input.ageMs)),
|
|
27
17
|
});
|
|
28
18
|
}
|
|
29
19
|
export function recordLiveResumeObservationV3(input) {
|
|
@@ -33,9 +23,9 @@ export function recordLiveResumeObservationV3(input) {
|
|
|
33
23
|
prior_generation_id: hook.generation_id,
|
|
34
24
|
continuity: "native",
|
|
35
25
|
evidence_reference: "heartbeat_recreated",
|
|
36
|
-
}
|
|
26
|
+
});
|
|
37
27
|
}
|
|
38
|
-
function recordObservation(input, eventType, payload
|
|
28
|
+
function recordObservation(input, eventType, payload) {
|
|
39
29
|
const route = resolveLiveEventLedgerRouteV3(input.coordRoot);
|
|
40
30
|
if (route.state === "blocked")
|
|
41
31
|
throw new LiveCoordinationAuthorityV3Error(route.reason);
|
|
@@ -83,7 +73,6 @@ function recordObservation(input, eventType, payload, beforeWrite) {
|
|
|
83
73
|
monotonic_ns: process.hrtime.bigint().toString(),
|
|
84
74
|
};
|
|
85
75
|
const event = buildEventV3(eventType, { ...common, payload });
|
|
86
|
-
beforeWrite();
|
|
87
76
|
const durability = writeEventV3(input.coordRoot, event, {
|
|
88
77
|
expectedGenesisId: control.genesis.event.payload.genesis_id,
|
|
89
78
|
});
|
|
@@ -92,16 +81,6 @@ function recordObservation(input, eventType, payload, beforeWrite) {
|
|
|
92
81
|
}
|
|
93
82
|
return { state: "recorded", event };
|
|
94
83
|
}
|
|
95
|
-
function requireSweepHookState(input) {
|
|
96
|
-
if (typeof input.expectedGenerationId !== "string" ||
|
|
97
|
-
!/^gen_[a-zA-Z0-9._-]+$/.test(input.expectedGenerationId)) {
|
|
98
|
-
throw new LiveCoordinationAuthorityV3Error("hook_generation_not_joinable");
|
|
99
|
-
}
|
|
100
|
-
const hook = requireHookState(withAttestedAdapter(input));
|
|
101
|
-
if (hook.generation_id !== input.expectedGenerationId) {
|
|
102
|
-
throw new LiveCoordinationAuthorityV3Error("expected_generation_changed");
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
84
|
function withAttestedAdapter(input) {
|
|
106
85
|
const adapter = liveCoordinationAdapterV3(input.coordRoot, input.owner);
|
|
107
86
|
if (!adapter)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/heartbeat-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"heartbeat-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/heartbeat-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,8 +15,6 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
17
17
|
import { dirname, join } from "node:path";
|
|
18
|
-
import { assertCurrentGenerationV3, withGenerationCustodyV3, } from "../../events/v3/generation-custody.js";
|
|
19
|
-
import { liveInstanceIdV3 } from "../../events/v3/live-routing.js";
|
|
20
18
|
import { canonicalClaimPath } from "../claim-path.js";
|
|
21
19
|
import { heartbeatPath, readHeartbeat } from "./heartbeat-reader.js";
|
|
22
20
|
export { readHeartbeat } from "./heartbeat-reader.js";
|
|
@@ -40,16 +38,13 @@ export function setLifecycleCache(coordRoot, instanceId, state, reason, suggeste
|
|
|
40
38
|
}));
|
|
41
39
|
}
|
|
42
40
|
function mutate(coordRoot, instanceId, fn) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
atomicWrite(heartbeatPath(coordRoot, instanceId), JSON.stringify(next, null, 2));
|
|
51
|
-
return next;
|
|
52
|
-
});
|
|
41
|
+
const hb = readHeartbeat(coordRoot, instanceId);
|
|
42
|
+
if (!hb)
|
|
43
|
+
return null;
|
|
44
|
+
const next = fn(hb);
|
|
45
|
+
next.last_heartbeat = nowIsoSeconds();
|
|
46
|
+
atomicWrite(heartbeatPath(coordRoot, instanceId), JSON.stringify(next, null, 2));
|
|
47
|
+
return next;
|
|
53
48
|
}
|
|
54
49
|
export function setTask(coordRoot, instanceId, task) {
|
|
55
50
|
return mutate(coordRoot, instanceId, (hb) => {
|
|
@@ -73,16 +68,13 @@ export function setTask(coordRoot, instanceId, task) {
|
|
|
73
68
|
}
|
|
74
69
|
/** Update the disposable identity cache after a canonical V3 attestation. */
|
|
75
70
|
export function setIdentityCache(coordRoot, instanceId, name, agentId) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
atomicWrite(heartbeatPath(coordRoot, instanceId), JSON.stringify(heartbeat, null, 2));
|
|
84
|
-
return heartbeat;
|
|
85
|
-
});
|
|
71
|
+
const heartbeat = readHeartbeat(coordRoot, instanceId);
|
|
72
|
+
if (!heartbeat)
|
|
73
|
+
return null;
|
|
74
|
+
heartbeat.name = name;
|
|
75
|
+
heartbeat.agent_id = agentId;
|
|
76
|
+
atomicWrite(heartbeatPath(coordRoot, instanceId), JSON.stringify(heartbeat, null, 2));
|
|
77
|
+
return heartbeat;
|
|
86
78
|
}
|
|
87
79
|
/** Restore the pool-assigned display name on a generation that was
|
|
88
80
|
* materialized before the adapter's normal SessionStart naming path ran.
|
|
@@ -256,9 +248,6 @@ export function clearCoordinationCache(coordRoot, instanceId) {
|
|
|
256
248
|
}
|
|
257
249
|
}
|
|
258
250
|
export function healPidmap(coordRoot, instanceId, pid) {
|
|
259
|
-
withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(instanceId)], () => healPidmapUnderCustody(coordRoot, instanceId, pid));
|
|
260
|
-
}
|
|
261
|
-
function healPidmapUnderCustody(coordRoot, instanceId, pid) {
|
|
262
251
|
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
263
252
|
mkdirSync(dir, { recursive: true });
|
|
264
253
|
const hb = readHeartbeat(coordRoot, instanceId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-coordination-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/live-coordination-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"live-coordination-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/live-coordination-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAMhD,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,uBAAuB,CAAC;AAUtE;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,OAAO,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,SAAS,GAAG,IAAI,CASlB;AAED,wFAAwF;AACxF,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,OAAO,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,SAAS,GAAG,IAAI,CASlB"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { readCoordinationViewV3, requireAuthoritySafeCoordinationViewV3, } from "../../events/v3/coordination-view.js";
|
|
4
|
-
import { assertCurrentGenerationV3, withGenerationCustodyV3, } from "../../events/v3/generation-custody.js";
|
|
5
4
|
import { liveInstanceIdV3, resolveLiveEventLedgerRouteV3 } from "../../events/v3/live-routing.js";
|
|
6
5
|
import { readHeartbeat } from "./heartbeat-reader.js";
|
|
7
6
|
import { isAdapterV3, isCurrentV3HeartbeatCache, observedAdapterV3, projectHeartbeatV3, } from "./live-coordination-view.js";
|
|
@@ -20,9 +19,6 @@ export function repairLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nat
|
|
|
20
19
|
return materializeLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nativeSessionId, adapter, model, true);
|
|
21
20
|
}
|
|
22
21
|
function materializeLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nativeSessionId, _adapter, model, force) {
|
|
23
|
-
return withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(nativeInstanceId)], () => materializeHeartbeatUnderCustody(coordRoot, nativeInstanceId, nativeSessionId, _adapter, model, force));
|
|
24
|
-
}
|
|
25
|
-
function materializeHeartbeatUnderCustody(coordRoot, nativeInstanceId, nativeSessionId, _adapter, model, force) {
|
|
26
22
|
const route = resolveLiveEventLedgerRouteV3(coordRoot);
|
|
27
23
|
if (route.state === "blocked")
|
|
28
24
|
throw new Error(`event_v3_coordination_view:${route.reason}`);
|
|
@@ -89,7 +85,6 @@ function materializeHeartbeatUnderCustody(coordRoot, nativeInstanceId, nativeSes
|
|
|
89
85
|
v3_projection_event_id: generation.last_event_id,
|
|
90
86
|
v3_task_state: generation.task_state === "set" ? "set" : "cleared",
|
|
91
87
|
};
|
|
92
|
-
assertCurrentGenerationV3(coordRoot, liveInstanceIdV3(nativeInstanceId), generation.generation_id);
|
|
93
88
|
writeHeartbeatCache(coordRoot, nativeInstanceId, materialized);
|
|
94
89
|
return materialized;
|
|
95
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pidmap.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/pidmap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"pidmap.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/pidmap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAyBH,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAGA;AAwCD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA8B7D;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,IAAI,CA6BN;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAmBjF;AAED,yFAAyF;AACzF,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAoBzF"}
|
|
@@ -15,8 +15,6 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
17
17
|
import { dirname, join } from "node:path";
|
|
18
|
-
import { withGenerationCustodyV3 } from "../../events/v3/generation-custody.js";
|
|
19
|
-
import { liveInstanceIdV3 } from "../../events/v3/live-routing.js";
|
|
20
18
|
import { checkPidToken, processStartToken } from "./proc-start.js";
|
|
21
19
|
/**
|
|
22
20
|
* Row count that triggers a dead-row sweep on the next write.
|
|
@@ -112,9 +110,6 @@ export function prunePidmapDeadRows(coordRoot) {
|
|
|
112
110
|
return removed;
|
|
113
111
|
}
|
|
114
112
|
export function writePidmapRow(coordRoot, pid, instanceId, platform) {
|
|
115
|
-
withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(instanceId)], () => writePidmapRowUnderCustody(coordRoot, pid, instanceId, platform));
|
|
116
|
-
}
|
|
117
|
-
function writePidmapRowUnderCustody(coordRoot, pid, instanceId, platform) {
|
|
118
113
|
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
119
114
|
const path = join(dir, String(pid));
|
|
120
115
|
// Stamped at write time, when the pid provably belongs to the process we
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stale-sweep.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/stale-sweep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"stale-sweep.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/stale-sweep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkEH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG;IAC7C,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAyJA"}
|
|
@@ -9,15 +9,12 @@
|
|
|
9
9
|
* HARNERY_AGENT_COORD_FRESHNESS env var or `.harnery/config.jsonc`
|
|
10
10
|
* `coord.freshness_seconds` (see `coordFreshnessSeconds`).
|
|
11
11
|
*/
|
|
12
|
-
import { existsSync,
|
|
13
|
-
import {
|
|
12
|
+
import { existsSync, readdirSync, readFileSync, statSync, unlinkSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
14
|
import { coordFreshnessSeconds } from "../../config.js";
|
|
15
15
|
import { eventAdapterIdV3FromPlatform } from "../../events/v3/adapter-id.js";
|
|
16
|
-
import { withGenerationCustodyV3 } from "../../events/v3/generation-custody.js";
|
|
17
|
-
import { liveInstanceIdV3 } from "../../events/v3/live-routing.js";
|
|
18
16
|
import { writeProducerDiagnosticV3 } from "../../events/v3/producers/intake.js";
|
|
19
17
|
import { recordLiveSweepObservationV3 } from "../live-lifecycle-v3.js";
|
|
20
|
-
import { captureFileRevision, deleteFileIfUnchanged, recoverInterruptedFileDeletions, } from "./unchanged-file.js";
|
|
21
18
|
/** platform → adapter, for the swept-event envelope (mirrors heartbeat-writer's adapterOf). */
|
|
22
19
|
/**
|
|
23
20
|
* Record the sweep before deleting disposable cache state.
|
|
@@ -28,14 +25,13 @@ import { captureFileRevision, deleteFileIfUnchanged, recoverInterruptedFileDelet
|
|
|
28
25
|
* diagnostics spool instead. If neither durable record can be written, fail
|
|
29
26
|
* closed and keep the file.
|
|
30
27
|
*/
|
|
31
|
-
function emitSwept(coordRoot, instanceId, adapter, sessionId,
|
|
28
|
+
function emitSwept(coordRoot, instanceId, adapter, sessionId, reason, ageSecs) {
|
|
32
29
|
try {
|
|
33
30
|
recordLiveSweepObservationV3({
|
|
34
31
|
coordRoot,
|
|
35
32
|
owner: instanceId,
|
|
36
33
|
nativeSessionId: sessionId,
|
|
37
34
|
adapter,
|
|
38
|
-
expectedGenerationId,
|
|
39
35
|
observation: reason === "stale"
|
|
40
36
|
? "stale_heartbeat"
|
|
41
37
|
: reason === "unparseable"
|
|
@@ -57,58 +53,14 @@ function emitSwept(coordRoot, instanceId, adapter, sessionId, expectedGeneration
|
|
|
57
53
|
}));
|
|
58
54
|
}
|
|
59
55
|
}
|
|
60
|
-
/**
|
|
61
|
-
function
|
|
62
|
-
if (uncertainOwners.has("*") || uncertainOwners.has(owner))
|
|
63
|
-
return true;
|
|
64
|
-
if (!/^[A-Za-z0-9_-]{1,128}$/.test(owner))
|
|
65
|
-
return true;
|
|
66
|
-
const heartbeat = join(activeDir, `${owner}.json`);
|
|
56
|
+
/** File mtime in epoch-seconds, or +Infinity if it can't be read (treat as fresh → don't reap). */
|
|
57
|
+
function mtimeSecs(path) {
|
|
67
58
|
try {
|
|
68
|
-
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
if (error.code !== "ENOENT")
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
try {
|
|
76
|
-
if (!lstatSync(activeDir).isDirectory())
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
return error.code !== "ENOENT";
|
|
81
|
-
}
|
|
82
|
-
// Callers hold this owner's custody. A sweeper that died after the initial
|
|
83
|
-
// directory scan may have left its heartbeat hidden under a private pin.
|
|
84
|
-
for (const recovery of recoverInterruptedFileDeletions(activeDir, (source) => source === heartbeat)) {
|
|
85
|
-
if (recovery.sourcePath && recovery.sourcePath !== heartbeat)
|
|
86
|
-
continue;
|
|
87
|
-
if (recovery.state !== "restored") {
|
|
88
|
-
uncertainOwners.add(recovery.sourcePath ? owner : "*");
|
|
89
|
-
recordCleanupFailure(coordRoot, recovery.sourcePath ?? activeDir, recovery);
|
|
90
|
-
}
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
function recordCleanupFailure(coordRoot, sourcePath, result) {
|
|
96
|
-
if (result.state !== "error" &&
|
|
97
|
-
result.state !== "recovery-required" &&
|
|
98
|
-
result.state !== "retained") {
|
|
99
|
-
return;
|
|
59
|
+
return Math.floor(statSync(path).mtimeMs / 1000);
|
|
100
60
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
state: "cache_cleanup_pending",
|
|
104
|
-
reason: `${result.state}:${result.error ?? "file_cleanup_pending"}; source=${sourcePath}; recovery=${result.recoveryPath ?? "unavailable"}`,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
function recordHeartbeatCleanupResult(coordRoot, sourcePath, owner, result, uncertainOwners) {
|
|
108
|
-
if (result.state === "recovery-required" || result.state === "error") {
|
|
109
|
-
uncertainOwners.add(owner);
|
|
61
|
+
catch {
|
|
62
|
+
return Number.POSITIVE_INFINITY;
|
|
110
63
|
}
|
|
111
|
-
recordCleanupFailure(coordRoot, sourcePath, result);
|
|
112
64
|
}
|
|
113
65
|
export function staleSweep(coordRoot) {
|
|
114
66
|
const heartbeatsRemoved = [];
|
|
@@ -134,129 +86,81 @@ export function staleSweep(coordRoot) {
|
|
|
134
86
|
// lifecycle.sweep_observed; a terminal or unavailable generation gets a
|
|
135
87
|
// heartbeat_sweep_unrecorded producer diagnostic without being resurrected.
|
|
136
88
|
const liveInstanceIds = new Set();
|
|
137
|
-
const
|
|
138
|
-
const d = resolve(coordRoot, ".harnery", "active");
|
|
139
|
-
for (const recovery of existsSync(d)
|
|
140
|
-
? recoverInterruptedFileDeletions(d, (source) => dirname(source) === d && /^[A-Za-z0-9_-]{1,128}\.json$/.test(basename(source)))
|
|
141
|
-
: []) {
|
|
142
|
-
if (recovery.state !== "restored") {
|
|
143
|
-
uncertainOwners.add(recovery.sourcePath ? basename(recovery.sourcePath, ".json") : "*");
|
|
144
|
-
recordCleanupFailure(coordRoot, recovery.sourcePath ?? d, recovery);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
89
|
+
const d = join(coordRoot, ".harnery", "active");
|
|
147
90
|
if (existsSync(d)) {
|
|
148
91
|
for (const f of readdirSync(d)) {
|
|
149
92
|
if (!f.endsWith(".json"))
|
|
150
93
|
continue;
|
|
151
94
|
const path = join(d, f);
|
|
152
95
|
const idFromFile = f.replace(/\.json$/, "");
|
|
153
|
-
|
|
154
|
-
continue;
|
|
96
|
+
let parsed = null;
|
|
155
97
|
try {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
98
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
parsed = null;
|
|
102
|
+
}
|
|
103
|
+
if (parsed === null) {
|
|
104
|
+
// Unparseable: only reap if the file itself is mtime-old.
|
|
105
|
+
if (mtimeSecs(path) < cutoff) {
|
|
162
106
|
try {
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
parsed = null;
|
|
169
|
-
}
|
|
170
|
-
if (parsed === null) {
|
|
171
|
-
// Unparseable: only reap if the file itself is mtime-old.
|
|
172
|
-
if (mtimeSecs < cutoff) {
|
|
173
|
-
const result = deleteFileIfUnchanged(path, revision, () => emitSwept(coordRoot, idFromFile, "claude-code", idFromFile, null, "unparseable", nowSec - mtimeSecs));
|
|
174
|
-
recordHeartbeatCleanupResult(coordRoot, path, idFromFile, result, uncertainOwners);
|
|
175
|
-
if (result.state === "deleted") {
|
|
176
|
-
heartbeatsRemoved.push(f);
|
|
177
|
-
}
|
|
107
|
+
const ageSecs = nowSec - mtimeSecs(path);
|
|
108
|
+
if (!emitSwept(coordRoot, idFromFile, "claude-code", idFromFile, "unparseable", ageSecs)) {
|
|
109
|
+
continue;
|
|
178
110
|
}
|
|
179
|
-
|
|
111
|
+
unlinkSync(path);
|
|
112
|
+
heartbeatsRemoved.push(f);
|
|
180
113
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (parsed.instance_id !== undefined && parsed.instance_id !== idFromFile)
|
|
184
|
-
return;
|
|
185
|
-
const instanceId = parsed.instance_id ?? idFromFile;
|
|
186
|
-
const adapter = eventAdapterIdV3FromPlatform(parsed.platform, { context: "stale-sweep" });
|
|
187
|
-
const sessionId = parsed.session_id ?? instanceId;
|
|
188
|
-
const generationId = typeof parsed.v3_generation_id === "string" &&
|
|
189
|
-
/^gen_[A-Za-z0-9._-]+$/.test(parsed.v3_generation_id)
|
|
190
|
-
? parsed.v3_generation_id
|
|
191
|
-
: null;
|
|
192
|
-
const ts = parsed.last_heartbeat
|
|
193
|
-
? Math.floor(Date.parse(parsed.last_heartbeat) / 1000)
|
|
194
|
-
: Number.NaN;
|
|
195
|
-
if (!parsed.last_heartbeat || !Number.isFinite(ts)) {
|
|
196
|
-
// No / NaN last_heartbeat: can't trust content; gate on mtime.
|
|
197
|
-
if (mtimeSecs < cutoff) {
|
|
198
|
-
const result = deleteFileIfUnchanged(path, revision, () => emitSwept(coordRoot, instanceId, adapter, sessionId, generationId, "missing_ts", nowSec - mtimeSecs));
|
|
199
|
-
recordHeartbeatCleanupResult(coordRoot, path, idFromFile, result, uncertainOwners);
|
|
200
|
-
if (result.state === "deleted") {
|
|
201
|
-
heartbeatsRemoved.push(f);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
else if (parsed.instance_id) {
|
|
205
|
-
liveInstanceIds.add(parsed.instance_id);
|
|
206
|
-
}
|
|
207
|
-
return;
|
|
114
|
+
catch {
|
|
115
|
+
/* swallow */
|
|
208
116
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
117
|
+
}
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const instanceId = parsed.instance_id ?? idFromFile;
|
|
121
|
+
const adapter = eventAdapterIdV3FromPlatform(parsed.platform, { context: "stale-sweep" });
|
|
122
|
+
const sessionId = parsed.session_id ?? instanceId;
|
|
123
|
+
const ts = parsed.last_heartbeat
|
|
124
|
+
? Math.floor(Date.parse(parsed.last_heartbeat) / 1000)
|
|
125
|
+
: Number.NaN;
|
|
126
|
+
if (!parsed.last_heartbeat || !Number.isFinite(ts)) {
|
|
127
|
+
// No / NaN last_heartbeat: can't trust content; gate on mtime.
|
|
128
|
+
if (mtimeSecs(path) < cutoff) {
|
|
129
|
+
if (!emitSwept(coordRoot, instanceId, adapter, sessionId, "missing_ts", nowSec - mtimeSecs(path))) {
|
|
130
|
+
continue;
|
|
217
131
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
132
|
+
unlinkSync(path);
|
|
133
|
+
heartbeatsRemoved.push(f);
|
|
134
|
+
}
|
|
135
|
+
else if (parsed.instance_id) {
|
|
136
|
+
liveInstanceIds.add(parsed.instance_id);
|
|
137
|
+
}
|
|
138
|
+
continue;
|
|
221
139
|
}
|
|
222
|
-
|
|
223
|
-
//
|
|
224
|
-
|
|
140
|
+
if (ts < cutoff) {
|
|
141
|
+
// Legitimate stale prune (valid timestamp, past the freshness cutoff).
|
|
142
|
+
if (!emitSwept(coordRoot, instanceId, adapter, sessionId, "stale", nowSec - ts)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
unlinkSync(path);
|
|
146
|
+
heartbeatsRemoved.push(f);
|
|
147
|
+
continue;
|
|
225
148
|
}
|
|
149
|
+
if (parsed.instance_id)
|
|
150
|
+
liveInstanceIds.add(parsed.instance_id);
|
|
226
151
|
}
|
|
227
152
|
}
|
|
228
153
|
// 2. Prune pid-map entries whose instance has no live heartbeat.
|
|
229
|
-
const pidmapDir =
|
|
230
|
-
for (const recovery of existsSync(pidmapDir)
|
|
231
|
-
? recoverInterruptedFileDeletions(pidmapDir, (source) => dirname(source) === pidmapDir && /^\d+$/.test(basename(source)))
|
|
232
|
-
: [])
|
|
233
|
-
recordCleanupFailure(coordRoot, recovery.sourcePath ?? pidmapDir, recovery);
|
|
154
|
+
const pidmapDir = join(coordRoot, ".harnery", "pid-map");
|
|
234
155
|
if (existsSync(pidmapDir)) {
|
|
235
156
|
for (const f of readdirSync(pidmapDir)) {
|
|
236
|
-
if (f.startsWith(".harnery-delete-"))
|
|
237
|
-
continue;
|
|
238
157
|
const path = join(pidmapDir, f);
|
|
239
158
|
try {
|
|
240
|
-
const
|
|
241
|
-
if (!revision)
|
|
242
|
-
continue;
|
|
243
|
-
const row = revision.bytes.toString("utf8").trim();
|
|
159
|
+
const row = readFileSync(path, "utf8").trim();
|
|
244
160
|
const ownerId = row.split("\t")[0]?.trim() ?? "";
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
!retainsHeartbeat(coordRoot, d, ownerId, uncertainOwners))) {
|
|
249
|
-
const result = deleteFileIfUnchanged(path, revision, () => !ownerId || !retainsHeartbeat(coordRoot, d, ownerId, uncertainOwners));
|
|
250
|
-
recordCleanupFailure(coordRoot, path, result);
|
|
251
|
-
if (result.state === "deleted")
|
|
252
|
-
pidmapsRemoved += 1;
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
if (/^[A-Za-z0-9_-]{1,128}$/.test(ownerId)) {
|
|
256
|
-
withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(ownerId)], prune);
|
|
257
|
-
}
|
|
258
|
-
else if (!ownerId) {
|
|
259
|
-
prune();
|
|
161
|
+
if (!ownerId || !liveInstanceIds.has(ownerId)) {
|
|
162
|
+
unlinkSync(path);
|
|
163
|
+
pidmapsRemoved += 1;
|
|
260
164
|
}
|
|
261
165
|
}
|
|
262
166
|
catch {
|
|
@@ -266,12 +170,7 @@ export function staleSweep(coordRoot) {
|
|
|
266
170
|
}
|
|
267
171
|
// 3. Prune prompt hashes for dead owners. Resource hashes retain their own
|
|
268
172
|
// count so existing peer-hash telemetry keeps its original meaning.
|
|
269
|
-
const agentsDir =
|
|
270
|
-
for (const recovery of existsSync(agentsDir)
|
|
271
|
-
? recoverInterruptedFileDeletions(agentsDir, (source) => dirname(source) === agentsDir &&
|
|
272
|
-
/^\.last-(?:resource|peer)-hash\.[A-Za-z0-9_-]{1,128}$/.test(basename(source)))
|
|
273
|
-
: [])
|
|
274
|
-
recordCleanupFailure(coordRoot, recovery.sourcePath ?? agentsDir, recovery);
|
|
173
|
+
const agentsDir = join(coordRoot, ".harnery");
|
|
275
174
|
if (existsSync(agentsDir)) {
|
|
276
175
|
for (const f of readdirSync(agentsDir)) {
|
|
277
176
|
const resourceHash = f.startsWith(".last-resource-hash.");
|
|
@@ -284,25 +183,16 @@ export function staleSweep(coordRoot) {
|
|
|
284
183
|
// retained heartbeat's liveness could not be determined safely.
|
|
285
184
|
if (!/^[A-Za-z0-9_-]{1,128}$/.test(owner))
|
|
286
185
|
continue;
|
|
186
|
+
if (existsSync(join(d, `${owner}.json`)))
|
|
187
|
+
continue;
|
|
287
188
|
}
|
|
288
|
-
if (!liveInstanceIds.has(owner)
|
|
189
|
+
if (!liveInstanceIds.has(owner)) {
|
|
289
190
|
try {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (!revision)
|
|
296
|
-
return;
|
|
297
|
-
const result = deleteFileIfUnchanged(path, revision, () => !retainsHeartbeat(coordRoot, d, owner, uncertainOwners));
|
|
298
|
-
recordCleanupFailure(coordRoot, path, result);
|
|
299
|
-
if (result.state === "deleted") {
|
|
300
|
-
if (resourceHash)
|
|
301
|
-
resourceHashesRemoved += 1;
|
|
302
|
-
else
|
|
303
|
-
peerHashesRemoved += 1;
|
|
304
|
-
}
|
|
305
|
-
});
|
|
191
|
+
unlinkSync(join(agentsDir, f));
|
|
192
|
+
if (resourceHash)
|
|
193
|
+
resourceHashesRemoved += 1;
|
|
194
|
+
else
|
|
195
|
+
peerHashesRemoved += 1;
|
|
306
196
|
}
|
|
307
197
|
catch {
|
|
308
198
|
/* swallow */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Stats } from "node:fs";
|
|
1
2
|
/** A checkpoint taken before an internal manifest write, never an expiry override. */
|
|
2
3
|
export interface ArtifactActivity {
|
|
3
4
|
last_changed_at: string;
|
|
@@ -9,6 +10,8 @@ export declare function artifactRootEntries(path: string): string;
|
|
|
9
10
|
* Keep the prior root activity while its payload entries match the checkpoint.
|
|
10
11
|
* A root deletion or rename changes that fingerprint; nested changes retain
|
|
11
12
|
* their ordinary filesystem timestamps. Symlinks are inspected, never followed.
|
|
13
|
+
* `visit` sees every entry's lstat exactly once, including a root manifest the
|
|
14
|
+
* activity rules skip, so a caller can size the tree in the same walk.
|
|
12
15
|
*/
|
|
13
|
-
export declare function readArtifactActivity(path: string, now: Date, previous?: ArtifactActivity): ArtifactActivity;
|
|
16
|
+
export declare function readArtifactActivity(path: string, now: Date, previous?: ArtifactActivity, visit?: (entry: string, stat: Stats) => void): ArtifactActivity;
|
|
14
17
|
//# sourceMappingURL=activity.d.ts.map
|