harnery 0.45.0 → 0.45.2
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/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +6 -45
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +0 -18
- 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 +2 -7
- package/dist/core/agents/state/proc-start.d.ts +20 -31
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +37 -70
- package/dist/core/agents/state/service-process.d.ts +61 -0
- package/dist/core/agents/state/service-process.d.ts.map +1 -0
- package/dist/core/agents/state/service-process.js +143 -0
- 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/context/index.d.ts +6 -4
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +194 -256
- package/dist/core/context/observation.d.ts +9 -9
- package/dist/core/context/observation.d.ts.map +1 -1
- package/dist/core/context/observation.js +37 -6
- 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/events/v3/runtime-build.d.ts +14 -0
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +44 -0
- package/dist/core/governor/index.d.ts +2 -1
- package/dist/core/governor/index.d.ts.map +1 -1
- package/dist/core/governor/index.js +2 -1
- package/dist/core/governor/service-read.d.ts +3 -10
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +10 -94
- package/dist/core/governor/service.d.ts +3 -7
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +17 -182
- package/dist/core/hooks/cli.js +78 -48
- package/dist/core/hooks/resolve/owner.js +2 -2
- package/dist/core/resources/sampler.js +2 -2
- package/dist/core/resources/service-status.d.ts +2 -14
- package/dist/core/resources/service-status.d.ts.map +1 -1
- package/dist/core/resources/service-status.js +3 -23
- package/dist/core/resources/service.d.ts +3 -7
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +12 -101
- package/dist/core/resources/status.d.ts.map +1 -1
- package/dist/core/resources/status.js +3 -2
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +9 -2
- package/dist/core/servers/index.d.ts +11 -10
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +82 -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/supervisor/service.d.ts +4 -7
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +23 -122
- package/dist/core/supervisor/services.js +2 -2
- package/dist/core/supervisor/status.d.ts +3 -17
- package/dist/core/supervisor/status.d.ts.map +1 -1
- package/dist/core/supervisor/status.js +7 -70
- package/dist/core/work/state.js +7 -7
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +23 -66
- package/dist/core/workflow/index.d.ts +3 -4
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -2
- 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 +34 -86
- package/dist/core/workflow/resume-lock.d.ts +17 -0
- package/dist/core/workflow/resume-lock.d.ts.map +1 -0
- package/dist/core/workflow/resume-lock.js +158 -0
- package/dist/core/workflow/run-state.d.ts +0 -21
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +3 -174
- 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/core/workflow/workspaces/leases.d.ts +4 -0
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +1 -1
- package/dist/core/workflow/workspaces/local-git.js +91 -210
- package/dist/core/workflow/workspaces/ownership.d.ts +0 -7
- package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/ownership.js +3 -130
- package/dist/core/workflow/workspaces/reclaim.d.ts +4 -7
- package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/reclaim.js +0 -4
- package/dist/core/workflow/workspaces/recovery.d.ts +1 -1
- package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/recovery.js +1 -1
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +1 -4
- 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/commands/workflow.ts +8 -58
- package/src/core/agents/coord-client.ts +0 -20
- 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 +2 -15
- package/src/core/agents/state/proc-start.ts +41 -69
- package/src/core/agents/state/service-process.ts +217 -0
- 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/context/index.ts +207 -272
- package/src/core/context/observation.ts +40 -9
- 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/events/v3/runtime-build.ts +62 -0
- package/src/core/governor/index.ts +1 -2
- package/src/core/governor/service-read.ts +15 -114
- package/src/core/governor/service.ts +36 -220
- package/src/core/hooks/cli.ts +85 -47
- package/src/core/hooks/resolve/owner.ts +2 -2
- package/src/core/resources/sampler.ts +3 -2
- package/src/core/resources/service-status.ts +6 -35
- package/src/core/resources/service.ts +23 -133
- package/src/core/resources/status.ts +3 -2
- package/src/core/semantic/service.ts +8 -2
- package/src/core/servers/index.ts +86 -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/supervisor/service.ts +33 -155
- package/src/core/supervisor/services.ts +2 -2
- package/src/core/supervisor/status.ts +10 -85
- package/src/core/work/state.ts +7 -7
- package/src/core/workflow/engine.ts +22 -74
- package/src/core/workflow/index.ts +2 -13
- package/src/core/workflow/live-session-v3.ts +5 -146
- package/src/core/workflow/proof.ts +40 -104
- package/src/core/workflow/resume-lock.ts +179 -0
- package/src/core/workflow/run-state.ts +3 -207
- 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/core/workflow/workspaces/leases.ts +1 -1
- package/src/core/workflow/workspaces/local-git.ts +120 -239
- package/src/core/workflow/workspaces/ownership.ts +3 -158
- package/src/core/workflow/workspaces/reclaim.ts +3 -9
- package/src/core/workflow/workspaces/recovery.ts +1 -1
- package/src/core/workflow/workspaces/state.ts +1 -5
- 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/process-handle.d.ts +0 -26
- package/dist/core/agents/state/process-handle.d.ts.map +0 -1
- package/dist/core/agents/state/process-handle.js +0 -121
- 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/dist/core/workflow/recovery-audit.d.ts +0 -30
- package/dist/core/workflow/recovery-audit.d.ts.map +0 -1
- package/dist/core/workflow/recovery-audit.js +0 -116
- package/src/commands/turn-rollback.ts +0 -111
- package/src/core/agents/state/process-handle.ts +0 -165
- 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
- package/src/core/workflow/recovery-audit.ts +0 -181
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Repository observation contract shared by context recovery and workflow proof.
|
|
3
3
|
*
|
|
4
|
-
* This module
|
|
5
|
-
* dashboard, proof readers) can use it without reaching the
|
|
6
|
-
* snapshot code in ./index.ts.
|
|
4
|
+
* This module runs no Git and touches no files, so read-only consumers (the
|
|
5
|
+
* Codec dashboard, proof readers) can use it without reaching the
|
|
6
|
+
* Git-running snapshot code in ./index.ts.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { isAbsolute } from "node:path";
|
|
10
|
+
|
|
9
11
|
export type RepoObservation = "ok" | "unavailable" | "partial";
|
|
10
12
|
|
|
11
13
|
export interface RepoSnapshot {
|
|
@@ -20,10 +22,39 @@ export interface RepoSnapshot {
|
|
|
20
22
|
dirty_paths_truncated?: boolean;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Every reason two snapshots cannot establish repository drift. Only an empty
|
|
27
|
+
* list lets a caller compare branch, HEAD and dirty paths; anything else
|
|
28
|
+
* leaves the whole comparison unknown.
|
|
29
|
+
*/
|
|
30
|
+
export function repoComparisonProblems(
|
|
31
|
+
a: RepoSnapshot,
|
|
32
|
+
b: RepoSnapshot,
|
|
33
|
+
labels: readonly [string, string],
|
|
34
|
+
): string[] {
|
|
35
|
+
const sides = [
|
|
36
|
+
[labels[0], a],
|
|
37
|
+
[labels[1], b],
|
|
38
|
+
] as const;
|
|
39
|
+
const failed = sides.flatMap(([label, repo]) =>
|
|
40
|
+
repo.observation === "ok"
|
|
41
|
+
? []
|
|
42
|
+
: [
|
|
43
|
+
// Snapshots recorded before observations existed carry none.
|
|
44
|
+
`${label} snapshot is ${repo.observation ?? "unavailable"}${repo.observation_detail ? ` (${repo.observation_detail})` : ""}`,
|
|
45
|
+
],
|
|
46
|
+
);
|
|
47
|
+
if (failed.length > 0) return failed;
|
|
48
|
+
const problems: string[] = [];
|
|
49
|
+
if (a.dirty_paths_truncated || b.dirty_paths_truncated) {
|
|
50
|
+
problems.push("dirty path list is truncated");
|
|
51
|
+
}
|
|
52
|
+
if (!a.root || !b.root || !isAbsolute(a.root) || !isAbsolute(b.root)) {
|
|
53
|
+
problems.push("repository root is unknown");
|
|
54
|
+
} else if (a.root !== b.root) {
|
|
55
|
+
problems.push("repository roots differ");
|
|
56
|
+
}
|
|
57
|
+
if (!a.branch?.trim() || !b.branch?.trim()) problems.push("branch is unknown");
|
|
58
|
+
if (!a.head?.trim() || !b.head?.trim()) problems.push("HEAD is unknown");
|
|
59
|
+
return problems;
|
|
29
60
|
}
|
|
@@ -16,7 +16,6 @@ import { fsyncParentDirectory } from "../../workflow/durable-record.ts";
|
|
|
16
16
|
import { canonicalJsonV3, sha256V3 } from "./canonical.ts";
|
|
17
17
|
import type { EventV3 } from "./contract.ts";
|
|
18
18
|
import { liveGenesisIdV3 } from "./control.ts";
|
|
19
|
-
import { assertCurrentGenerationV3, withGenerationCustodyV3 } from "./generation-custody.ts";
|
|
20
19
|
import { assertEventV3 } from "./validate.ts";
|
|
21
20
|
import { ensureEventV3Layout, eventV3Paths, writeEventV3 } from "./writer.ts";
|
|
22
21
|
|
|
@@ -155,32 +154,9 @@ export function publishAuthorityTransactionV3(
|
|
|
155
154
|
coordRoot: string,
|
|
156
155
|
transaction: AuthorityTransactionV3,
|
|
157
156
|
fence: AuthorityEpochFenceV3 = {},
|
|
158
|
-
): AuthorityTransactionV3 {
|
|
159
|
-
return withGenerationCustodyV3(
|
|
160
|
-
coordRoot,
|
|
161
|
-
[transaction.actor_instance_id, transaction.subject_instance_id],
|
|
162
|
-
() => publishAuthorityTransactionWithCustodyV3(coordRoot, transaction, fence),
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function publishAuthorityTransactionWithCustodyV3(
|
|
167
|
-
coordRoot: string,
|
|
168
|
-
transaction: AuthorityTransactionV3,
|
|
169
|
-
fence: AuthorityEpochFenceV3,
|
|
170
157
|
): AuthorityTransactionV3 {
|
|
171
158
|
validateTransaction(transaction);
|
|
172
159
|
const paths = ensureEventV3Layout(coordRoot);
|
|
173
|
-
const committedPath = authorityCommittedPath(paths.authorityOutbox, transaction.transaction_id);
|
|
174
|
-
if (existsSync(committedPath)) {
|
|
175
|
-
if (
|
|
176
|
-
readAuthorityReceiptV3(committedPath).transaction_digest !==
|
|
177
|
-
sha256V3(`${canonicalJsonV3(transaction)}\n`)
|
|
178
|
-
) {
|
|
179
|
-
throw new Error("authority committed transaction conflicts with this transaction");
|
|
180
|
-
}
|
|
181
|
-
return transaction;
|
|
182
|
-
}
|
|
183
|
-
assertTransactionGeneration(coordRoot, transaction);
|
|
184
160
|
if (fence.expectedGenesisId && liveGenesisIdV3(coordRoot) !== fence.expectedGenesisId) {
|
|
185
161
|
throw new Error("authority transaction epoch was replaced before publication");
|
|
186
162
|
}
|
|
@@ -209,26 +185,6 @@ export function reconcileAuthorityTransactionV3(
|
|
|
209
185
|
transactionId: string,
|
|
210
186
|
reconciler: AuthorityReconcilerV3,
|
|
211
187
|
fence: AuthorityEpochFenceV3 = {},
|
|
212
|
-
): AuthorityReceiptV3 {
|
|
213
|
-
assertTransactionId(transactionId);
|
|
214
|
-
const paths = ensureEventV3Layout(coordRoot);
|
|
215
|
-
const committedPath = authorityCommittedPath(paths.authorityOutbox, transactionId);
|
|
216
|
-
if (existsSync(committedPath)) return readAuthorityReceiptV3(committedPath);
|
|
217
|
-
const transaction = readAuthorityTransactionV3(
|
|
218
|
-
authorityReadyPath(paths.authorityOutbox, transactionId),
|
|
219
|
-
);
|
|
220
|
-
return withGenerationCustodyV3(
|
|
221
|
-
coordRoot,
|
|
222
|
-
[transaction.actor_instance_id, transaction.subject_instance_id],
|
|
223
|
-
() => reconcileAuthorityTransactionWithCustodyV3(coordRoot, transactionId, reconciler, fence),
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function reconcileAuthorityTransactionWithCustodyV3(
|
|
228
|
-
coordRoot: string,
|
|
229
|
-
transactionId: string,
|
|
230
|
-
reconciler: AuthorityReconcilerV3,
|
|
231
|
-
fence: AuthorityEpochFenceV3,
|
|
232
188
|
): AuthorityReceiptV3 {
|
|
233
189
|
assertTransactionId(transactionId);
|
|
234
190
|
const paths = ensureEventV3Layout(coordRoot);
|
|
@@ -236,10 +192,8 @@ function reconcileAuthorityTransactionWithCustodyV3(
|
|
|
236
192
|
if (existsSync(committedPath)) return readAuthorityReceiptV3(committedPath);
|
|
237
193
|
const readyPath = authorityReadyPath(paths.authorityOutbox, transactionId);
|
|
238
194
|
const transaction = readAuthorityTransactionV3(readyPath);
|
|
239
|
-
assertTransactionGeneration(coordRoot, transaction);
|
|
240
195
|
const current = reconciler.readStateDigest();
|
|
241
196
|
if (current === transaction.expected_prior_state_digest) {
|
|
242
|
-
assertTransactionGeneration(coordRoot, transaction);
|
|
243
197
|
reconciler.apply(transaction.mutation, transaction.transaction_id);
|
|
244
198
|
} else if (current !== transaction.desired_state_digest) {
|
|
245
199
|
throw new Error("authority transaction prior state conflicts with current state");
|
|
@@ -247,7 +201,6 @@ function reconcileAuthorityTransactionWithCustodyV3(
|
|
|
247
201
|
if (reconciler.readStateDigest() !== transaction.desired_state_digest) {
|
|
248
202
|
throw new Error("authority transaction did not reach its declared desired state");
|
|
249
203
|
}
|
|
250
|
-
assertTransactionGeneration(coordRoot, transaction);
|
|
251
204
|
const event = JSON.parse(transaction.event_row) as unknown;
|
|
252
205
|
assertEventV3(event);
|
|
253
206
|
const durability = writeEventV3(coordRoot, event, {
|
|
@@ -277,15 +230,6 @@ function reconcileAuthorityTransactionWithCustodyV3(
|
|
|
277
230
|
return receipt;
|
|
278
231
|
}
|
|
279
232
|
|
|
280
|
-
function assertTransactionGeneration(coordRoot: string, transaction: AuthorityTransactionV3): void {
|
|
281
|
-
const event = JSON.parse(transaction.event_row) as EventV3;
|
|
282
|
-
assertCurrentGenerationV3(
|
|
283
|
-
coordRoot,
|
|
284
|
-
transaction.actor_instance_id,
|
|
285
|
-
"generation_id" in event.scope ? event.scope.generation_id : undefined,
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
233
|
export function listPendingAuthorityTransactionsV3(coordRoot: string): AuthorityTransactionV3[] {
|
|
290
234
|
const outbox = eventV3Paths(coordRoot).authorityOutbox;
|
|
291
235
|
if (!existsSync(outbox)) return [];
|
|
@@ -33,7 +33,6 @@ import { markObservedClockRegressionV3 } from "../clock-order.ts";
|
|
|
33
33
|
import type { EventV3 } from "../contract.ts";
|
|
34
34
|
import { type EventV3WriteMode, readEventV3ControlState } from "../control.ts";
|
|
35
35
|
import { fingerprintContextV3 } from "../fingerprint-keys.ts";
|
|
36
|
-
import { assertCurrentGenerationV3, withGenerationCustodyV3 } from "../generation-custody.ts";
|
|
37
36
|
import { clockIdV3, spanIdV3 } from "../ids.ts";
|
|
38
37
|
import { closeSpanStateV3, type OpenSpanStateV3, openSpanStateV3 } from "../span-state.ts";
|
|
39
38
|
import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../writer.ts";
|
|
@@ -104,7 +103,6 @@ export interface RecordCoordinationAuthorityV3Input<
|
|
|
104
103
|
bridge?: "codex-wsl";
|
|
105
104
|
expected_prior_state_digest: `sha256:${string}`;
|
|
106
105
|
desired_state_digest: `sha256:${string}`;
|
|
107
|
-
expected_generation_id?: `gen_${string}`;
|
|
108
106
|
monotonic_ns?: string;
|
|
109
107
|
observed_at?: string;
|
|
110
108
|
reconciler: AuthorityReconcilerV3;
|
|
@@ -131,16 +129,6 @@ export type RecordCoordinationAuthorityV3Result =
|
|
|
131
129
|
*/
|
|
132
130
|
export function recordCoordinationAuthorityV3<S extends CoordinationAuthoritySignalV3>(
|
|
133
131
|
input: RecordCoordinationAuthorityV3Input<S>,
|
|
134
|
-
): RecordCoordinationAuthorityV3Result {
|
|
135
|
-
return withGenerationCustodyV3(
|
|
136
|
-
input.coordRoot,
|
|
137
|
-
[input.actor_instance_id, input.subject_instance_id],
|
|
138
|
-
() => recordCoordinationAuthorityWithCustodyV3(input),
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function recordCoordinationAuthorityWithCustodyV3<S extends CoordinationAuthoritySignalV3>(
|
|
143
|
-
input: RecordCoordinationAuthorityV3Input<S>,
|
|
144
132
|
): RecordCoordinationAuthorityV3Result {
|
|
145
133
|
const control = readEventV3ControlState(input.coordRoot);
|
|
146
134
|
if (control.state !== input.mode) return { state: "gate_closed", reason: control.state };
|
|
@@ -153,8 +141,6 @@ function recordCoordinationAuthorityWithCustodyV3<S extends CoordinationAuthorit
|
|
|
153
141
|
if (
|
|
154
142
|
!hook ||
|
|
155
143
|
hook.terminal ||
|
|
156
|
-
(input.expected_generation_id !== undefined &&
|
|
157
|
-
hook.generation_id !== input.expected_generation_id) ||
|
|
158
144
|
hook.instance_id !== input.actor_instance_id ||
|
|
159
145
|
!hook.last_event_id
|
|
160
146
|
) {
|
|
@@ -342,7 +328,6 @@ function recordCoordinationAuthorityWithCustodyV3<S extends CoordinationAuthorit
|
|
|
342
328
|
mutation: normalized.mutation,
|
|
343
329
|
event: normalized.event,
|
|
344
330
|
});
|
|
345
|
-
assertCurrentGenerationV3(input.coordRoot, state.actor_instance_id, state.generation_id);
|
|
346
331
|
if (input.signal === "wait-ended" && waitId) delete state.open_waits[waitId];
|
|
347
332
|
state.pending = { source_id: sourceId, transaction };
|
|
348
333
|
publishCoordinationState(path, state);
|
|
@@ -43,7 +43,6 @@ import { markObservedClockRegressionV3 } from "../clock-order.ts";
|
|
|
43
43
|
import type { EventV3 } from "../contract.ts";
|
|
44
44
|
import { type EventV3WriteMode, readEventV3ControlState } from "../control.ts";
|
|
45
45
|
import { fingerprintContextV3 } from "../fingerprint-keys.ts";
|
|
46
|
-
import { withGenerationCustodyV3 } from "../generation-custody.ts";
|
|
47
46
|
import {
|
|
48
47
|
attestationIdV3,
|
|
49
48
|
clockIdV3,
|
|
@@ -659,17 +658,6 @@ function processHookSignalLocked(
|
|
|
659
658
|
input: RecordHookSignalV3Input,
|
|
660
659
|
sessionHash: `hid_${string}`,
|
|
661
660
|
path: string,
|
|
662
|
-
): RecordHookSignalV3Result {
|
|
663
|
-
return withGenerationCustodyV3(input.coordRoot, [input.instance_id], () =>
|
|
664
|
-
processHookSignalWithCustodyLocked(control, input, sessionHash, path),
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
function processHookSignalWithCustodyLocked(
|
|
669
|
-
control: OpenHookControlStateV3,
|
|
670
|
-
input: RecordHookSignalV3Input,
|
|
671
|
-
sessionHash: `hid_${string}`,
|
|
672
|
-
path: string,
|
|
673
661
|
): RecordHookSignalV3Result {
|
|
674
662
|
const behavior = adapterBehavior(input.adapter);
|
|
675
663
|
const rootId = control.genesis.event.scope.root_id as `root_${string}`;
|
|
@@ -3221,14 +3209,6 @@ function suppressClosedSpanSignal(
|
|
|
3221
3209
|
*/
|
|
3222
3210
|
export function recordApprovedSessionEndV3(
|
|
3223
3211
|
input: RecordApprovedSessionEndV3Input,
|
|
3224
|
-
): RecordApprovedSessionEndV3Result {
|
|
3225
|
-
return withGenerationCustodyV3(input.coordRoot, [input.instance_id], () =>
|
|
3226
|
-
recordApprovedSessionEndWithCustodyV3(input),
|
|
3227
|
-
);
|
|
3228
|
-
}
|
|
3229
|
-
|
|
3230
|
-
function recordApprovedSessionEndWithCustodyV3(
|
|
3231
|
-
input: RecordApprovedSessionEndV3Input,
|
|
3232
3212
|
): RecordApprovedSessionEndV3Result {
|
|
3233
3213
|
const control = readEventV3ControlState(input.coordRoot);
|
|
3234
3214
|
if (control.state !== input.mode) {
|
|
@@ -3576,81 +3556,77 @@ export function reanchorArchivedHookProducersV3(
|
|
|
3576
3556
|
for (const archived of listArchivedHookProducerStatesV3(input.archivedEpoch)) {
|
|
3577
3557
|
const previous = archived.state;
|
|
3578
3558
|
if (previous.terminal || !previous.started_event_id) continue;
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3559
|
+
const path = producerStatePath(input.coordRoot, previous.adapter, archived.sessionHash);
|
|
3560
|
+
const lease = acquireStateLeaseWithRetry(input.coordRoot, path, 40);
|
|
3561
|
+
if (!lease) {
|
|
3562
|
+
throw new Error(`event_v3_rotation_reanchor_busy:${previous.instance_id}`);
|
|
3563
|
+
}
|
|
3564
|
+
try {
|
|
3565
|
+
if (existsSync(path)) {
|
|
3566
|
+
const current = readProducerState(path);
|
|
3567
|
+
if (current.epoch_genesis_id === genesisId) continue;
|
|
3584
3568
|
}
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3569
|
+
const sourceEvent = `${previous.adapter}.epoch-rotation-reanchor`;
|
|
3570
|
+
const rotationInput: RecordHookSignalV3Input = {
|
|
3571
|
+
coordRoot: input.coordRoot,
|
|
3572
|
+
mode: input.mode,
|
|
3573
|
+
signal: "session-start",
|
|
3574
|
+
payload: {
|
|
3575
|
+
raw: {},
|
|
3576
|
+
...(previous.current_native_turn_id ? { turn_id: previous.current_native_turn_id } : {}),
|
|
3577
|
+
...(adapterBehavior(previous.adapter).tracksExecutionMode && previous.cursor_mode
|
|
3578
|
+
? { cursor_mode: previous.cursor_mode }
|
|
3579
|
+
: {}),
|
|
3580
|
+
},
|
|
3581
|
+
adapter: previous.adapter,
|
|
3582
|
+
instance_id: previous.instance_id,
|
|
3583
|
+
producer_id: "prd_agent-hook",
|
|
3584
|
+
build_id: input.build_id,
|
|
3585
|
+
platform: input.platform,
|
|
3586
|
+
observed_at: observedAt,
|
|
3587
|
+
writerOptions: { expectedGenesisId: genesisId },
|
|
3588
|
+
};
|
|
3589
|
+
const state = newProducerState(
|
|
3590
|
+
rotationInput,
|
|
3591
|
+
previous.session_id,
|
|
3592
|
+
epochId,
|
|
3593
|
+
boundaryEventId as `evt_${string}`,
|
|
3594
|
+
genesisId,
|
|
3595
|
+
);
|
|
3596
|
+
const sessionStart = buildMidFlightSessionStart(rotationInput, state, rootId);
|
|
3597
|
+
if (sessionStart.event_type !== "session.started") {
|
|
3598
|
+
throw new Error("rotation re-anchor session start could not be normalized");
|
|
3599
|
+
}
|
|
3600
|
+
sessionStart.provenance = {
|
|
3601
|
+
...sessionStart.provenance,
|
|
3602
|
+
source_event: sourceEvent,
|
|
3603
|
+
attestation: "derived",
|
|
3604
|
+
confidence: "high",
|
|
3605
|
+
attribution: {
|
|
3606
|
+
method: "session_env",
|
|
3607
|
+
state: "verified",
|
|
3608
|
+
subject_instance_id: state.instance_id,
|
|
3609
|
+
},
|
|
3610
|
+
};
|
|
3611
|
+
sessionStart.payload.resume = {
|
|
3612
|
+
state: "unknown",
|
|
3613
|
+
reason: "epoch_rotation_reanchor",
|
|
3614
|
+
};
|
|
3615
|
+
assertEventV3(sessionStart);
|
|
3616
|
+
commitEventLocked(rotationInput, state, path, sessionStart);
|
|
3617
|
+
sessions += 1;
|
|
3618
|
+
|
|
3619
|
+
if (previous.current_turn_id && previous.current_turn_span) {
|
|
3620
|
+
commitMidFlightTurnStart(rotationInput, state, path, rootId, {
|
|
3625
3621
|
source_event: sourceEvent,
|
|
3626
|
-
attestation: "derived",
|
|
3627
3622
|
confidence: "high",
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
subject_instance_id: state.instance_id,
|
|
3632
|
-
},
|
|
3633
|
-
};
|
|
3634
|
-
sessionStart.payload.resume = {
|
|
3635
|
-
state: "unknown",
|
|
3636
|
-
reason: "epoch_rotation_reanchor",
|
|
3637
|
-
};
|
|
3638
|
-
assertEventV3(sessionStart);
|
|
3639
|
-
commitEventLocked(rotationInput, state, path, sessionStart);
|
|
3640
|
-
sessions += 1;
|
|
3641
|
-
|
|
3642
|
-
if (previous.current_turn_id && previous.current_turn_span) {
|
|
3643
|
-
commitMidFlightTurnStart(rotationInput, state, path, rootId, {
|
|
3644
|
-
source_event: sourceEvent,
|
|
3645
|
-
confidence: "high",
|
|
3646
|
-
attribution_method: "session_env",
|
|
3647
|
-
});
|
|
3648
|
-
turns += 1;
|
|
3649
|
-
}
|
|
3650
|
-
} finally {
|
|
3651
|
-
lease.release();
|
|
3623
|
+
attribution_method: "session_env",
|
|
3624
|
+
});
|
|
3625
|
+
turns += 1;
|
|
3652
3626
|
}
|
|
3653
|
-
}
|
|
3627
|
+
} finally {
|
|
3628
|
+
lease.release();
|
|
3629
|
+
}
|
|
3654
3630
|
}
|
|
3655
3631
|
return { sessions, turns };
|
|
3656
3632
|
}
|
|
@@ -3888,9 +3864,7 @@ export function readJoinableHookProducerStateV3(
|
|
|
3888
3864
|
instanceId: `inst_${string}`,
|
|
3889
3865
|
): HookProducerStateV3 | undefined {
|
|
3890
3866
|
const direct = readHookProducerStateV3(coordRoot, adapter, nativeSessionId);
|
|
3891
|
-
|
|
3892
|
-
// not permission to adopt a replacement published under the same instance.
|
|
3893
|
-
if (direct?.instance_id === instanceId) return direct.terminal ? undefined : direct;
|
|
3867
|
+
if (direct?.instance_id === instanceId && !direct.terminal) return direct;
|
|
3894
3868
|
const byInstance = readHookProducerStateByInstanceV3(coordRoot, instanceId);
|
|
3895
3869
|
return byInstance?.adapter === adapter && !byInstance.terminal ? byInstance : undefined;
|
|
3896
3870
|
}
|
|
@@ -40,3 +40,65 @@ export function currentHarneryRuntimeBuild(): string {
|
|
|
40
40
|
export function harneryPackageRoot(): string {
|
|
41
41
|
return resolve(dirname(fileURLToPath(import.meta.url)), "../../../..");
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
export interface HarneryBuild {
|
|
45
|
+
version: string;
|
|
46
|
+
revision: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The installed package version and runtime revision; "unknown" when unreadable. */
|
|
50
|
+
export function installedHarneryBuild(): HarneryBuild {
|
|
51
|
+
let version = "unknown";
|
|
52
|
+
let revision = "unknown";
|
|
53
|
+
try {
|
|
54
|
+
const manifest = JSON.parse(
|
|
55
|
+
readFileSync(resolve(harneryPackageRoot(), "package.json"), "utf8"),
|
|
56
|
+
) as { version?: unknown };
|
|
57
|
+
if (typeof manifest.version === "string" && manifest.version.length <= 100)
|
|
58
|
+
version = manifest.version;
|
|
59
|
+
} catch {
|
|
60
|
+
// Missing package metadata cannot establish that a running build is current.
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
revision = currentHarneryRuntimeBuild();
|
|
64
|
+
} catch {
|
|
65
|
+
// Status still reports the unavailable build instead of guessing a match.
|
|
66
|
+
}
|
|
67
|
+
return { version, revision };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ServiceBuildStatus {
|
|
71
|
+
running_build: HarneryBuild | null;
|
|
72
|
+
installed_build: HarneryBuild;
|
|
73
|
+
restart_needed: boolean;
|
|
74
|
+
build_status: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** A missing or unknown running build, or any difference, means restart. */
|
|
78
|
+
export function serviceBuildStatus(recorded: unknown): ServiceBuildStatus {
|
|
79
|
+
const installed_build = installedHarneryBuild();
|
|
80
|
+
const candidate = recorded as Partial<HarneryBuild> | undefined;
|
|
81
|
+
const known = (value: unknown): value is string =>
|
|
82
|
+
typeof value === "string" && value.length > 0 && value.length <= 100 && value !== "unknown";
|
|
83
|
+
const running_build =
|
|
84
|
+
candidate && known(candidate.version) && known(candidate.revision)
|
|
85
|
+
? { version: candidate.version, revision: candidate.revision }
|
|
86
|
+
: null;
|
|
87
|
+
const restart_needed =
|
|
88
|
+
running_build === null ||
|
|
89
|
+
installed_build.version === "unknown" ||
|
|
90
|
+
installed_build.revision === "unknown" ||
|
|
91
|
+
running_build.version !== installed_build.version ||
|
|
92
|
+
running_build.revision !== installed_build.revision;
|
|
93
|
+
return {
|
|
94
|
+
running_build,
|
|
95
|
+
installed_build,
|
|
96
|
+
restart_needed,
|
|
97
|
+
build_status:
|
|
98
|
+
running_build === null
|
|
99
|
+
? "running build unknown; restart needed"
|
|
100
|
+
: restart_needed
|
|
101
|
+
? "restart needed"
|
|
102
|
+
: "current",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -63,13 +63,12 @@ export {
|
|
|
63
63
|
type RunGovernorServiceDaemonInput,
|
|
64
64
|
type RunGovernorServiceSweepInput,
|
|
65
65
|
readGovernorServiceConfig,
|
|
66
|
-
readGovernorServiceRuntime,
|
|
67
|
-
readGovernorServiceStatus,
|
|
68
66
|
requestGovernorServiceStop,
|
|
69
67
|
runGovernorServiceDaemon,
|
|
70
68
|
runGovernorServiceSweep,
|
|
71
69
|
spawnGovernorService,
|
|
72
70
|
} from "./service.ts";
|
|
71
|
+
export { readGovernorServiceRuntime, readGovernorServiceStatus } from "./service-read.ts";
|
|
73
72
|
export {
|
|
74
73
|
assertGovernorId,
|
|
75
74
|
type CreateGovernorInput,
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { closeSync, existsSync, openSync, readFileSync, readSync, statSync } from "node:fs";
|
|
2
|
-
import { hostname } from "node:os";
|
|
3
2
|
import { join, resolve } from "node:path";
|
|
4
3
|
import { gunzipSync } from "node:zlib";
|
|
5
4
|
import { coordEnv } from "../../lib/env.ts";
|
|
5
|
+
import type { ProcessGenerationVerdict } from "../agents/state/proc-start.ts";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
observeServiceProcess,
|
|
8
|
+
type ServiceLiveness,
|
|
9
|
+
type ServiceProcessDependencies,
|
|
10
|
+
} from "../agents/state/service-process.ts";
|
|
11
|
+
import { serviceBuildStatus } from "../events/v3/runtime-build.ts";
|
|
11
12
|
import { createStorageCatalog } from "../storage/catalog.ts";
|
|
12
13
|
import type { HarneryLogRecordV1 } from "../storage/jsonl.ts";
|
|
13
14
|
import { parseLogRecord } from "../storage/jsonl.ts";
|
|
14
15
|
import { familyLogDirectory, readSegmentManifest } from "../storage/segments.ts";
|
|
15
16
|
import type {
|
|
16
|
-
GovernorServiceBuild,
|
|
17
17
|
GovernorServiceConfig,
|
|
18
|
-
GovernorServiceProcessDependencies,
|
|
19
18
|
GovernorServiceRuntime,
|
|
20
19
|
GovernorServiceStatus,
|
|
21
20
|
GovernorServiceStatusRecord,
|
|
@@ -25,106 +24,6 @@ const MAX_FILE_BYTES = 512 * 1024;
|
|
|
25
24
|
const MAX_LOG_RECORDS = 10_000;
|
|
26
25
|
const MAX_GOALS = 100;
|
|
27
26
|
|
|
28
|
-
export function currentGovernorServiceBuild(): GovernorServiceBuild {
|
|
29
|
-
let version = "unknown";
|
|
30
|
-
let revision = "unknown";
|
|
31
|
-
try {
|
|
32
|
-
const manifest = JSON.parse(
|
|
33
|
-
readFileSync(new URL("../../../package.json", import.meta.url), "utf8"),
|
|
34
|
-
) as {
|
|
35
|
-
version?: unknown;
|
|
36
|
-
};
|
|
37
|
-
if (typeof manifest.version === "string" && manifest.version.length <= 100) {
|
|
38
|
-
version = manifest.version;
|
|
39
|
-
}
|
|
40
|
-
} catch {
|
|
41
|
-
// Missing package metadata cannot establish that the running build is current.
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
revision = currentHarneryRuntimeBuild();
|
|
45
|
-
} catch {
|
|
46
|
-
// Status still reports the unavailable build instead of guessing a match.
|
|
47
|
-
}
|
|
48
|
-
return { version, revision };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function governorServiceBuildStatus(
|
|
52
|
-
record: GovernorServiceStatusRecord | undefined,
|
|
53
|
-
): Pick<
|
|
54
|
-
GovernorServiceStatus,
|
|
55
|
-
"running_build" | "installed_build" | "restart_needed" | "build_status"
|
|
56
|
-
> {
|
|
57
|
-
const installed_build = currentGovernorServiceBuild();
|
|
58
|
-
const candidate = record?.running_build;
|
|
59
|
-
const running_build =
|
|
60
|
-
candidate &&
|
|
61
|
-
typeof candidate.version === "string" &&
|
|
62
|
-
candidate.version.length > 0 &&
|
|
63
|
-
candidate.version.length <= 100 &&
|
|
64
|
-
typeof candidate.revision === "string" &&
|
|
65
|
-
candidate.revision.length > 0 &&
|
|
66
|
-
candidate.revision.length <= 100 &&
|
|
67
|
-
candidate.version !== "unknown" &&
|
|
68
|
-
candidate.revision !== "unknown"
|
|
69
|
-
? candidate
|
|
70
|
-
: null;
|
|
71
|
-
const restart_needed =
|
|
72
|
-
running_build === null ||
|
|
73
|
-
installed_build.version === "unknown" ||
|
|
74
|
-
installed_build.revision === "unknown" ||
|
|
75
|
-
running_build.version !== installed_build.version ||
|
|
76
|
-
running_build.revision !== installed_build.revision;
|
|
77
|
-
return {
|
|
78
|
-
running_build,
|
|
79
|
-
installed_build,
|
|
80
|
-
restart_needed,
|
|
81
|
-
build_status:
|
|
82
|
-
running_build === null
|
|
83
|
-
? "running build unknown; restart needed"
|
|
84
|
-
: restart_needed
|
|
85
|
-
? "restart needed"
|
|
86
|
-
: "current",
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** An unknown token or process probe cannot establish a running or stopped owner. */
|
|
91
|
-
export function observeGovernorServiceProcess(
|
|
92
|
-
record: Pick<GovernorServiceStatusRecord, "pid" | "host" | "state" | "start_token"> | undefined,
|
|
93
|
-
dependencies: GovernorServiceProcessDependencies = {},
|
|
94
|
-
): { generation: ProcessGenerationVerdict; liveness: GovernorServiceStatus["liveness"] } {
|
|
95
|
-
if (!record) return { generation: "unknown", liveness: "stopped" };
|
|
96
|
-
const generation =
|
|
97
|
-
record.host === hostname()
|
|
98
|
-
? verifyProcessGeneration(record.pid, record.start_token, dependencies.readToken)
|
|
99
|
-
: "unknown";
|
|
100
|
-
if (record.host !== hostname()) return { generation, liveness: "unknown" };
|
|
101
|
-
try {
|
|
102
|
-
const present = (dependencies.probePid ?? probePid)(record.pid);
|
|
103
|
-
if (!present) return { generation, liveness: "stopped" };
|
|
104
|
-
} catch (error) {
|
|
105
|
-
return {
|
|
106
|
-
generation,
|
|
107
|
-
liveness: (error as NodeJS.ErrnoException).code === "ESRCH" ? "stopped" : "unknown",
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
return {
|
|
111
|
-
generation,
|
|
112
|
-
liveness:
|
|
113
|
-
generation === "same"
|
|
114
|
-
? record.state === "stopped"
|
|
115
|
-
? "stopped"
|
|
116
|
-
: "running"
|
|
117
|
-
: generation === "different"
|
|
118
|
-
? "stopped"
|
|
119
|
-
: "unknown",
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function probePid(pid: number): boolean {
|
|
124
|
-
process.kill(pid, 0);
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
27
|
export function readGovernorServiceConfig(coordRootRaw: string): GovernorServiceConfig {
|
|
129
28
|
const coordRoot = resolve(coordRootRaw);
|
|
130
29
|
const config = readBoundedJson<GovernorServiceConfig>(
|
|
@@ -175,7 +74,7 @@ export function readGovernorServiceRuntime(
|
|
|
175
74
|
|
|
176
75
|
export function readGovernorServiceStatus(
|
|
177
76
|
coordRootRaw: string,
|
|
178
|
-
dependencies:
|
|
77
|
+
dependencies: ServiceProcessDependencies = {},
|
|
179
78
|
): GovernorServiceStatus {
|
|
180
79
|
const coordRoot = resolve(coordRootRaw);
|
|
181
80
|
const record = readStatusRecord(coordRoot);
|
|
@@ -191,15 +90,17 @@ export function readGovernorServiceStatus(
|
|
|
191
90
|
} catch {
|
|
192
91
|
// Runtime is recoverable and must not make the dashboard unreadable.
|
|
193
92
|
}
|
|
194
|
-
const observation =
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
93
|
+
const observation: { generation: ProcessGenerationVerdict; liveness: ServiceLiveness } = record
|
|
94
|
+
? observeServiceProcess(record, dependencies)
|
|
95
|
+
: {
|
|
96
|
+
generation: "unknown",
|
|
97
|
+
liveness: existsSync(join(serviceDir(coordRoot), "status.json")) ? "unknown" : "stopped",
|
|
98
|
+
};
|
|
198
99
|
return {
|
|
199
|
-
running: observation.liveness === "running"
|
|
100
|
+
running: observation.liveness === "running",
|
|
200
101
|
stale: observation.liveness === "stopped" && record !== undefined && record.state !== "stopped",
|
|
201
102
|
...observation,
|
|
202
|
-
...
|
|
103
|
+
...serviceBuildStatus(record?.running_build),
|
|
203
104
|
record,
|
|
204
105
|
config,
|
|
205
106
|
runtime,
|