harnery 0.42.0 → 0.44.0
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/README.md +3 -3
- package/dist/commander.d.ts +16 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +18 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +95 -52
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +38 -11
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +10 -0
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +22 -7
- package/dist/commands/governor.js +22 -10
- package/dist/commands/inbox.d.ts +1 -1
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +55 -2
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +28 -4
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +16 -1
- package/dist/commands/supervisor.d.ts.map +1 -1
- package/dist/commands/supervisor.js +7 -2
- package/dist/commands/toc.d.ts +14 -0
- package/dist/commands/toc.d.ts.map +1 -1
- package/dist/commands/toc.js +7 -4
- package/dist/commands/tunnel.d.ts +65 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +290 -101
- package/dist/commands/web-fetch.d.ts +3 -2
- package/dist/commands/web-fetch.d.ts.map +1 -1
- package/dist/commands/web-fetch.js +25 -19
- package/dist/commands/web.d.ts +7 -1
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +9 -3
- package/dist/commands/workflow.js +24 -30
- package/dist/core/agents/live-authority-v3.d.ts +1 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +11 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts +4 -2
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/live-lifecycle-v3.js +28 -7
- package/dist/core/agents/mailbox.d.ts +9 -8
- package/dist/core/agents/mailbox.d.ts.map +1 -1
- package/dist/core/agents/mailbox.js +24 -17
- package/dist/core/agents/render/prompt-context.d.ts +2 -0
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +19 -17
- package/dist/core/agents/render/session-context.d.ts +2 -8
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +64 -43
- package/dist/core/agents/rules/stop-hook.js +3 -3
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +25 -14
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-writer.js +5 -0
- package/dist/core/agents/state/names.d.ts +43 -3
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +87 -3
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +5 -0
- package/dist/core/agents/state/proc-start.d.ts +19 -0
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +41 -0
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +180 -70
- package/dist/core/agents/state/unchanged-file.d.ts +44 -0
- package/dist/core/agents/state/unchanged-file.d.ts.map +1 -0
- package/dist/core/agents/state/unchanged-file.js +390 -0
- package/dist/core/context/index.d.ts +22 -10
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +381 -119
- package/dist/core/context/observation.d.ts +26 -0
- package/dist/core/context/observation.d.ts.map +1 -0
- package/dist/core/context/observation.js +11 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +25 -14
- package/dist/core/diagnostics/path-identity.d.ts +3 -0
- package/dist/core/diagnostics/path-identity.d.ts.map +1 -0
- package/dist/core/diagnostics/path-identity.js +12 -0
- package/dist/core/diagnostics/sanitize.d.ts.map +1 -1
- package/dist/core/diagnostics/sanitize.js +4 -3
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +29 -0
- package/dist/core/events/v3/generation-custody.d.ts +5 -0
- package/dist/core/events/v3/generation-custody.d.ts.map +1 -0
- package/dist/core/events/v3/generation-custody.js +50 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +1 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +7 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +77 -64
- package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
- package/dist/core/events/v3/support-storage/pack-reader.js +42 -16
- package/dist/core/governor/planning.d.ts.map +1 -1
- package/dist/core/governor/planning.js +14 -1
- package/dist/core/governor/service-read.d.ts +10 -2
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +105 -22
- package/dist/core/governor/service.d.ts +20 -2
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +72 -47
- package/dist/core/hooks/cli.js +120 -23
- package/dist/core/hooks/fork-lineage.d.ts +40 -0
- package/dist/core/hooks/fork-lineage.d.ts.map +1 -0
- package/dist/core/hooks/fork-lineage.js +62 -0
- package/dist/core/hooks/resolve/transcript.d.ts +16 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +84 -0
- package/dist/core/hooks/shell-rm.d.ts +2 -0
- package/dist/core/hooks/shell-rm.d.ts.map +1 -0
- package/dist/core/hooks/shell-rm.js +105 -0
- package/dist/core/hooks/shell-tokens.d.ts +12 -0
- package/dist/core/hooks/shell-tokens.d.ts.map +1 -0
- package/dist/core/hooks/shell-tokens.js +97 -0
- package/dist/core/hooks/shell-waiter.d.ts.map +1 -1
- package/dist/core/hooks/shell-waiter.js +3 -93
- package/dist/core/inbox/contract.d.ts +2 -1
- package/dist/core/inbox/contract.d.ts.map +1 -1
- package/dist/core/inbox/index.d.ts +2 -0
- package/dist/core/inbox/index.d.ts.map +1 -1
- package/dist/core/inbox/index.js +2 -0
- package/dist/core/inbox/peer-messages.d.ts +37 -0
- package/dist/core/inbox/peer-messages.d.ts.map +1 -0
- package/dist/core/inbox/peer-messages.js +72 -0
- package/dist/core/inbox/service.d.ts +8 -1
- package/dist/core/inbox/service.d.ts.map +1 -1
- package/dist/core/inbox/service.js +67 -21
- package/dist/core/inbox/targets.d.ts +22 -0
- package/dist/core/inbox/targets.d.ts.map +1 -0
- package/dist/core/inbox/targets.js +108 -0
- package/dist/core/inbox/watcher.js +7 -3
- package/dist/core/journal/index.d.ts.map +1 -1
- package/dist/core/journal/index.js +17 -2
- package/dist/core/resources/contract.d.ts +3 -0
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/service-status.d.ts +14 -1
- package/dist/core/resources/service-status.d.ts.map +1 -1
- package/dist/core/resources/service-status.js +23 -13
- package/dist/core/resources/service.d.ts +9 -1
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +47 -27
- package/dist/core/resources/status.d.ts +2 -5
- package/dist/core/resources/status.d.ts.map +1 -1
- package/dist/core/resources/status.js +36 -7
- package/dist/core/semantic/contract.d.ts +5 -5
- package/dist/core/servers/index.d.ts +24 -13
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +132 -92
- 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 +3 -9
- package/dist/core/storage/process-log.d.ts +12 -0
- package/dist/core/storage/process-log.d.ts.map +1 -1
- package/dist/core/storage/process-log.js +10 -2
- package/dist/core/supervisor/contract.d.ts +12 -0
- package/dist/core/supervisor/contract.d.ts.map +1 -1
- package/dist/core/supervisor/explanations.d.ts.map +1 -1
- package/dist/core/supervisor/explanations.js +2 -1
- package/dist/core/supervisor/findings.d.ts.map +1 -1
- package/dist/core/supervisor/findings.js +54 -9
- package/dist/core/supervisor/service.d.ts +9 -1
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +59 -29
- package/dist/core/supervisor/services.d.ts.map +1 -1
- package/dist/core/supervisor/services.js +22 -1
- package/dist/core/supervisor/status.d.ts +17 -2
- package/dist/core/supervisor/status.d.ts.map +1 -1
- package/dist/core/supervisor/status.js +70 -12
- package/dist/core/supervisor/timeline.d.ts.map +1 -1
- package/dist/core/supervisor/timeline.js +2 -1
- package/dist/core/work/state.js +7 -7
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +105 -32
- package/dist/core/workflow/failure-evidence.d.ts +16 -0
- package/dist/core/workflow/failure-evidence.d.ts.map +1 -0
- package/dist/core/workflow/failure-evidence.js +114 -0
- package/dist/core/workflow/index.d.ts +1 -1
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +1 -1
- package/dist/core/workflow/live-session-v3.d.ts +6 -0
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +126 -5
- package/dist/core/workflow/proof.d.ts +5 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +115 -20
- package/dist/core/workflow/run-state.d.ts +3 -1
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +31 -27
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +19 -0
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +13 -0
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +19 -0
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
- package/dist/core/workflow/spawn-opencode.js +14 -0
- package/dist/core/workflow/types.d.ts +64 -17
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/index.d.ts +0 -1
- package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/index.js +0 -1
- package/dist/core/workflow/workspaces/leases.d.ts +3 -1
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +30 -16
- package/dist/core/workflow/workspaces/local-git.d.ts +6 -2
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +270 -6
- package/dist/core/workflow/workspaces/ownership.d.ts +11 -0
- package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/ownership.js +194 -0
- package/dist/core/workflow/workspaces/reclaim.d.ts +35 -0
- package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/reclaim.js +14 -0
- package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/recovery.js +21 -13
- package/dist/core/workflow/workspaces/state.d.ts +1 -0
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +21 -1
- package/dist/lib/browser/windows-chrome.d.ts +100 -12
- package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
- package/dist/lib/browser/windows-chrome.js +262 -73
- package/dist/lib/docs-links.d.ts.map +1 -1
- package/dist/lib/docs-links.js +45 -2
- package/dist/lib/guarded-remove.d.ts +7 -0
- package/dist/lib/guarded-remove.d.ts.map +1 -1
- package/dist/lib/guarded-remove.js +106 -12
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +4 -0
- package/dist/lib/tunnel/allowlist.d.ts +44 -0
- package/dist/lib/tunnel/allowlist.d.ts.map +1 -0
- package/dist/lib/tunnel/allowlist.js +204 -0
- package/dist/lib/tunnel/current-address.d.ts +41 -0
- package/dist/lib/tunnel/current-address.d.ts.map +1 -0
- package/dist/lib/tunnel/current-address.js +123 -0
- package/dist/lib/tunnel/gate.js +13 -6
- package/dist/lib/tunnel/processes.d.ts +39 -0
- package/dist/lib/tunnel/processes.d.ts.map +1 -0
- package/dist/lib/tunnel/processes.js +121 -0
- package/dist/lib/tunnel/state.d.ts +28 -3
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +98 -27
- package/dist/lib/zip/index.d.ts +41 -0
- package/dist/lib/zip/index.d.ts.map +1 -0
- package/dist/lib/zip/index.js +398 -0
- package/package.json +8 -1
- package/src/commander.ts +32 -0
- package/src/commands/agents.ts +151 -74
- package/src/commands/browse.ts +50 -14
- package/src/commands/diagnostics.ts +10 -0
- package/src/commands/doctor.ts +26 -7
- package/src/commands/governor.ts +23 -10
- package/src/commands/inbox.ts +52 -2
- package/src/commands/rm.ts +43 -4
- package/src/commands/servers.ts +16 -4
- package/src/commands/supervisor.ts +7 -2
- package/src/commands/toc.ts +14 -6
- package/src/commands/tunnel.ts +394 -116
- package/src/commands/web-fetch.ts +30 -19
- package/src/commands/web.ts +9 -3
- package/src/commands/workflow.ts +30 -30
- package/src/core/agents/live-authority-v3.ts +17 -0
- package/src/core/agents/live-lifecycle-v3.ts +52 -14
- package/src/core/agents/mailbox.ts +26 -17
- package/src/core/agents/render/prompt-context.ts +35 -20
- package/src/core/agents/render/session-context.ts +92 -48
- package/src/core/agents/rules/stop-hook.ts +3 -3
- package/src/core/agents/state/heartbeat-writer.ts +29 -12
- package/src/core/agents/state/live-coordination-writer.ts +29 -0
- package/src/core/agents/state/names.ts +117 -6
- package/src/core/agents/state/pidmap.ts +13 -0
- package/src/core/agents/state/proc-start.ts +57 -0
- package/src/core/agents/state/stale-sweep.ts +247 -82
- package/src/core/agents/state/unchanged-file.ts +456 -0
- package/src/core/context/index.ts +446 -136
- package/src/core/context/observation.ts +29 -0
- package/src/core/diagnostics/bundle.ts +23 -18
- package/src/core/diagnostics/path-identity.ts +15 -0
- package/src/core/diagnostics/sanitize.ts +4 -3
- package/src/core/events/v3/authority-outbox.ts +56 -0
- package/src/core/events/v3/generation-custody.ts +59 -0
- package/src/core/events/v3/producers/coordination-recorder.ts +15 -0
- package/src/core/events/v3/producers/recorder.ts +94 -68
- package/src/core/events/v3/support-storage/pack-reader.ts +45 -19
- package/src/core/governor/planning.ts +20 -8
- package/src/core/governor/service-read.ts +128 -20
- package/src/core/governor/service.ts +119 -42
- package/src/core/hooks/cli.ts +139 -22
- package/src/core/hooks/fork-lineage.ts +82 -0
- package/src/core/hooks/resolve/transcript.ts +88 -0
- package/src/core/hooks/shell-rm.ts +103 -0
- package/src/core/hooks/shell-tokens.ts +96 -0
- package/src/core/hooks/shell-waiter.ts +4 -91
- package/src/core/inbox/contract.ts +2 -1
- package/src/core/inbox/index.ts +2 -0
- package/src/core/inbox/peer-messages.ts +94 -0
- package/src/core/inbox/service.ts +88 -22
- package/src/core/inbox/targets.ts +148 -0
- package/src/core/inbox/watcher.ts +8 -9
- package/src/core/journal/index.ts +19 -2
- package/src/core/resources/contract.ts +4 -0
- package/src/core/resources/service-status.ts +35 -12
- package/src/core/resources/service.ts +71 -24
- package/src/core/resources/status.ts +57 -8
- package/src/core/servers/index.ts +177 -91
- package/src/core/servers/tunnels.ts +3 -11
- package/src/core/storage/process-log.ts +17 -2
- package/src/core/supervisor/contract.ts +13 -0
- package/src/core/supervisor/explanations.ts +4 -1
- package/src/core/supervisor/findings.ts +68 -10
- package/src/core/supervisor/service.ts +88 -26
- package/src/core/supervisor/services.ts +26 -8
- package/src/core/supervisor/status.ts +89 -12
- package/src/core/supervisor/timeline.ts +2 -1
- package/src/core/work/state.ts +7 -7
- package/src/core/workflow/engine.ts +131 -49
- package/src/core/workflow/failure-evidence.ts +141 -0
- package/src/core/workflow/index.ts +0 -1
- package/src/core/workflow/live-session-v3.ts +146 -5
- package/src/core/workflow/proof.ts +134 -26
- package/src/core/workflow/run-state.ts +31 -29
- package/src/core/workflow/spawn-claude.ts +18 -0
- package/src/core/workflow/spawn-codex.ts +13 -0
- package/src/core/workflow/spawn-cursor.ts +18 -0
- package/src/core/workflow/spawn-opencode.ts +14 -0
- package/src/core/workflow/types.ts +51 -17
- package/src/core/workflow/workspaces/index.ts +0 -1
- package/src/core/workflow/workspaces/leases.ts +48 -17
- package/src/core/workflow/workspaces/local-git.ts +315 -5
- package/src/core/workflow/workspaces/ownership.ts +232 -0
- package/src/core/workflow/workspaces/reclaim.ts +58 -0
- package/src/core/workflow/workspaces/recovery.ts +25 -13
- package/src/core/workflow/workspaces/state.ts +20 -0
- package/src/lib/browser/windows-chrome.ts +346 -86
- package/src/lib/docs-links.ts +49 -2
- package/src/lib/guarded-remove.ts +132 -14
- package/src/lib/identities/assume.ts +4 -0
- package/src/lib/tunnel/allowlist.ts +208 -0
- package/src/lib/tunnel/current-address.ts +158 -0
- package/src/lib/tunnel/gate.ts +16 -8
- package/src/lib/tunnel/processes.ts +149 -0
- package/src/lib/tunnel/state.ts +123 -27
- package/src/lib/zip/index.ts +483 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { constants
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
3
|
import { lstat, mkdir, open, realpath, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { finished } from "node:stream/promises";
|
|
5
7
|
import { StringDecoder } from "node:string_decoder";
|
|
6
8
|
import { createGunzip, createInflateRaw } from "node:zlib";
|
|
7
9
|
import { stateDirMode, stateFileMode } from "../../../storage/modes.js";
|
|
@@ -44,18 +46,12 @@ async function* streamEventV3SupportPackRecordsForManifest(manifestPath, manifes
|
|
|
44
46
|
throw new Error("event_v3_support_payload_length_mismatch");
|
|
45
47
|
if (payloadStat.size > bounded.max_payload_bytes)
|
|
46
48
|
throw new Error("event_v3_support_payload_too_large");
|
|
47
|
-
if ((await hashHandle(
|
|
49
|
+
if ((await hashHandle(payloadHandle)) !== manifest.payload.digest) {
|
|
48
50
|
throw new Error("event_v3_support_payload_digest_mismatch");
|
|
49
51
|
}
|
|
50
52
|
limits.fault?.("after_payload_digest", payloadPath);
|
|
51
|
-
await assertCanonicalSingleGzipMember(
|
|
53
|
+
await assertCanonicalSingleGzipMember(payloadHandle, payloadStat.size, bounded.max_decompressed_bytes);
|
|
52
54
|
const gunzip = createGunzip();
|
|
53
|
-
const source = createReadStream(payloadPath, {
|
|
54
|
-
fd: payloadHandle.fd,
|
|
55
|
-
autoClose: false,
|
|
56
|
-
start: 0,
|
|
57
|
-
});
|
|
58
|
-
source.pipe(gunzip);
|
|
59
55
|
const decoder = new StringDecoder("utf8");
|
|
60
56
|
let pending = "";
|
|
61
57
|
let decompressedBytes = 0;
|
|
@@ -64,7 +60,7 @@ async function* streamEventV3SupportPackRecordsForManifest(manifestPath, manifes
|
|
|
64
60
|
let priorPath;
|
|
65
61
|
const entries = [];
|
|
66
62
|
const seen = new Set();
|
|
67
|
-
for await (const current of gunzip) {
|
|
63
|
+
for await (const current of decompressHandle(payloadHandle, 0, gunzip)) {
|
|
68
64
|
const chunk = current;
|
|
69
65
|
decompressedBytes += chunk.length;
|
|
70
66
|
if (decompressedBytes > bounded.max_decompressed_bytes) {
|
|
@@ -176,20 +172,51 @@ export async function unpackEventV3SupportPack(manifestPath, destination, limits
|
|
|
176
172
|
throw error;
|
|
177
173
|
}
|
|
178
174
|
}
|
|
179
|
-
async function hashHandle(
|
|
175
|
+
async function hashHandle(handle) {
|
|
180
176
|
const hash = createHash("sha256");
|
|
181
|
-
|
|
182
|
-
for await (const current of stream)
|
|
177
|
+
for await (const current of handleChunks(handle, 0))
|
|
183
178
|
hash.update(current);
|
|
184
179
|
return `sha256:${hash.digest("hex")}`;
|
|
185
180
|
}
|
|
181
|
+
async function* handleChunks(handle, position) {
|
|
182
|
+
while (true) {
|
|
183
|
+
const buffer = Buffer.alloc(64 * 1024);
|
|
184
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);
|
|
185
|
+
if (bytesRead === 0)
|
|
186
|
+
return;
|
|
187
|
+
position += bytesRead;
|
|
188
|
+
yield buffer.subarray(0, bytesRead);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function* decompressHandle(handle, start, decoder) {
|
|
192
|
+
const source = Readable.from(handleChunks(handle, start));
|
|
193
|
+
// Observe failures immediately, then settle source reads before the caller
|
|
194
|
+
// can close and reuse the verified handle, including on early rejection.
|
|
195
|
+
const completed = finished(source, { cleanup: true }).then(() => undefined, (error) => error);
|
|
196
|
+
source.once("error", (error) => decoder.destroy(error));
|
|
197
|
+
source.pipe(decoder);
|
|
198
|
+
try {
|
|
199
|
+
for await (const chunk of decoder)
|
|
200
|
+
yield chunk;
|
|
201
|
+
source.unpipe(decoder);
|
|
202
|
+
source.resume();
|
|
203
|
+
const error = await completed;
|
|
204
|
+
if (error)
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
source.destroy();
|
|
209
|
+
decoder.destroy();
|
|
210
|
+
await completed;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
186
213
|
async function realDirectory(path) {
|
|
187
214
|
const stat = await lstat(path);
|
|
188
215
|
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
189
216
|
throw new Error("event_v3_support_pack_root_invalid");
|
|
190
217
|
return realpath(path);
|
|
191
218
|
}
|
|
192
|
-
async function assertCanonicalSingleGzipMember(
|
|
219
|
+
async function assertCanonicalSingleGzipMember(handle, payloadBytes, maximumDecompressedBytes) {
|
|
193
220
|
if (payloadBytes < 18)
|
|
194
221
|
throw new Error("event_v3_support_gzip_truncated");
|
|
195
222
|
const header = Buffer.alloc(10);
|
|
@@ -203,9 +230,8 @@ async function assertCanonicalSingleGzipMember(path, handle, payloadBytes, maxim
|
|
|
203
230
|
throw new Error("event_v3_support_gzip_header_noncanonical");
|
|
204
231
|
}
|
|
205
232
|
const inflate = createInflateRaw();
|
|
206
|
-
createReadStream(path, { fd: handle.fd, autoClose: false, start: 10 }).pipe(inflate);
|
|
207
233
|
let decompressed = 0;
|
|
208
|
-
for await (const current of inflate) {
|
|
234
|
+
for await (const current of decompressHandle(handle, 10, inflate)) {
|
|
209
235
|
decompressed += current.length;
|
|
210
236
|
if (decompressed > maximumDecompressedBytes) {
|
|
211
237
|
inflate.destroy();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../../src/core/governor/planning.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,UAAU,EAQhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,mBAAmB,EAUzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../../src/core/governor/planning.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,UAAU,EAQhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,mBAAmB,EAUzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAkN9B;AAkMD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,mBAAmB,CAkHtB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAYtB;AAED;;;;;;;;gEAQgE;AAChE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAoBtB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA4CtB"}
|
|
@@ -65,6 +65,7 @@ export async function runGovernorPlanner(input) {
|
|
|
65
65
|
return recovered;
|
|
66
66
|
}
|
|
67
67
|
let proposalWritten = false;
|
|
68
|
+
let invalidProposal = false;
|
|
68
69
|
try {
|
|
69
70
|
const reviewRunId = reviewWorkflowRunId(request.id);
|
|
70
71
|
const resumingReview = Boolean(resumable &&
|
|
@@ -87,7 +88,16 @@ export async function runGovernorPlanner(input) {
|
|
|
87
88
|
concurrency: 1,
|
|
88
89
|
onLog: input.onLog,
|
|
89
90
|
})).result;
|
|
90
|
-
|
|
91
|
+
let proposal;
|
|
92
|
+
try {
|
|
93
|
+
proposal = normalizeProposal(request.id, rawProposal, input.record, history.materialized_work_ids.length, request.trigger ?? "recovery", reviewInput ? persistedProposalTimestamp(reviewInput.candidate) : undefined);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
// A fresh invalid proposal can consume a replan without aborting the run.
|
|
97
|
+
// Corrupt persisted review input still requires investigation.
|
|
98
|
+
invalidProposal = !reviewInput;
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
91
101
|
if (policy.review) {
|
|
92
102
|
if (proposal.decision === "attention") {
|
|
93
103
|
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
@@ -181,6 +191,9 @@ export async function runGovernorPlanner(input) {
|
|
|
181
191
|
reason: bounded(error.message, "plan failure", MAX_REASON),
|
|
182
192
|
...(failureClass ? { class: failureClass } : {}),
|
|
183
193
|
});
|
|
194
|
+
if (invalidProposal) {
|
|
195
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
|
|
196
|
+
}
|
|
184
197
|
throw error;
|
|
185
198
|
}
|
|
186
199
|
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type ProcessGenerationVerdict } from "../agents/state/proc-start.js";
|
|
2
|
+
import type { GovernorServiceBuild, GovernorServiceConfig, GovernorServiceProcessDependencies, GovernorServiceRuntime, GovernorServiceStatus, GovernorServiceStatusRecord } from "./service.js";
|
|
3
|
+
export declare function currentGovernorServiceBuild(): GovernorServiceBuild;
|
|
4
|
+
export declare function governorServiceBuildStatus(record: GovernorServiceStatusRecord | undefined): Pick<GovernorServiceStatus, "running_build" | "installed_build" | "restart_needed" | "build_status">;
|
|
5
|
+
/** An unknown token or process probe cannot establish a running or stopped owner. */
|
|
6
|
+
export declare function observeGovernorServiceProcess(record: Pick<GovernorServiceStatusRecord, "pid" | "host" | "state" | "start_token"> | undefined, dependencies?: GovernorServiceProcessDependencies): {
|
|
7
|
+
generation: ProcessGenerationVerdict;
|
|
8
|
+
liveness: GovernorServiceStatus["liveness"];
|
|
9
|
+
};
|
|
2
10
|
export declare function readGovernorServiceConfig(coordRootRaw: string): GovernorServiceConfig;
|
|
3
11
|
export declare function readGovernorServiceRuntime(coordRootRaw: string): GovernorServiceRuntime | undefined;
|
|
4
|
-
export declare function readGovernorServiceStatus(coordRootRaw: string): GovernorServiceStatus;
|
|
12
|
+
export declare function readGovernorServiceStatus(coordRootRaw: string, dependencies?: GovernorServiceProcessDependencies): GovernorServiceStatus;
|
|
5
13
|
export declare function governorServiceLogPath(coordRoot: string): string;
|
|
6
14
|
export interface GovernorServiceLogReadOptions {
|
|
7
15
|
max_bytes?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-read.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service-read.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service-read.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service-read.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AAMvC,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,kCAAkC,EAClC,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC5B,MAAM,cAAc,CAAC;AAMtB,wBAAgB,2BAA2B,IAAI,oBAAoB,CAqBlE;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,2BAA2B,GAAG,SAAS,GAC9C,IAAI,CACL,qBAAqB,EACrB,eAAe,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,cAAc,CACxE,CAgCA;AAED,qFAAqF;AACrF,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,IAAI,CAAC,2BAA2B,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC,GAAG,SAAS,EAC/F,YAAY,GAAE,kCAAuC,GACpD;IAAE,UAAU,EAAE,wBAAwB,CAAC;IAAC,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAA;CAAE,CA2BvF;AAOD,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CA0BrF;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,sBAAsB,GAAG,SAAS,CAgBpC;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,kCAAuC,GACpD,qBAAqB,CA4BvB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAahE;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAeD,wFAAwF;AACxF,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,6BAAkC,GAC1C,4BAA4B,CA6D9B"}
|
|
@@ -3,13 +3,99 @@ import { hostname } from "node:os";
|
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { gunzipSync } from "node:zlib";
|
|
5
5
|
import { coordEnv } from "../../lib/env.js";
|
|
6
|
+
import { verifyProcessGeneration, } from "../agents/state/proc-start.js";
|
|
7
|
+
import { currentHarneryRuntimeBuild } from "../events/v3/runtime-build.js";
|
|
6
8
|
import { createStorageCatalog } from "../storage/catalog.js";
|
|
7
9
|
import { parseLogRecord } from "../storage/jsonl.js";
|
|
8
10
|
import { familyLogDirectory, readSegmentManifest } from "../storage/segments.js";
|
|
9
11
|
const MAX_FILE_BYTES = 512 * 1024;
|
|
10
12
|
const MAX_LOG_RECORDS = 10_000;
|
|
11
13
|
const MAX_GOALS = 100;
|
|
12
|
-
|
|
14
|
+
export function currentGovernorServiceBuild() {
|
|
15
|
+
let version = "unknown";
|
|
16
|
+
let revision = "unknown";
|
|
17
|
+
try {
|
|
18
|
+
const manifest = JSON.parse(readFileSync(new URL("../../../package.json", import.meta.url), "utf8"));
|
|
19
|
+
if (typeof manifest.version === "string" && manifest.version.length <= 100) {
|
|
20
|
+
version = manifest.version;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Missing package metadata cannot establish that the running build is current.
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
revision = currentHarneryRuntimeBuild();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Status still reports the unavailable build instead of guessing a match.
|
|
31
|
+
}
|
|
32
|
+
return { version, revision };
|
|
33
|
+
}
|
|
34
|
+
export function governorServiceBuildStatus(record) {
|
|
35
|
+
const installed_build = currentGovernorServiceBuild();
|
|
36
|
+
const candidate = record?.running_build;
|
|
37
|
+
const running_build = candidate &&
|
|
38
|
+
typeof candidate.version === "string" &&
|
|
39
|
+
candidate.version.length > 0 &&
|
|
40
|
+
candidate.version.length <= 100 &&
|
|
41
|
+
typeof candidate.revision === "string" &&
|
|
42
|
+
candidate.revision.length > 0 &&
|
|
43
|
+
candidate.revision.length <= 100 &&
|
|
44
|
+
candidate.version !== "unknown" &&
|
|
45
|
+
candidate.revision !== "unknown"
|
|
46
|
+
? candidate
|
|
47
|
+
: null;
|
|
48
|
+
const restart_needed = running_build === null ||
|
|
49
|
+
installed_build.version === "unknown" ||
|
|
50
|
+
installed_build.revision === "unknown" ||
|
|
51
|
+
running_build.version !== installed_build.version ||
|
|
52
|
+
running_build.revision !== installed_build.revision;
|
|
53
|
+
return {
|
|
54
|
+
running_build,
|
|
55
|
+
installed_build,
|
|
56
|
+
restart_needed,
|
|
57
|
+
build_status: running_build === null
|
|
58
|
+
? "running build unknown; restart needed"
|
|
59
|
+
: restart_needed
|
|
60
|
+
? "restart needed"
|
|
61
|
+
: "current",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** An unknown token or process probe cannot establish a running or stopped owner. */
|
|
65
|
+
export function observeGovernorServiceProcess(record, dependencies = {}) {
|
|
66
|
+
if (!record)
|
|
67
|
+
return { generation: "unknown", liveness: "stopped" };
|
|
68
|
+
const generation = record.host === hostname()
|
|
69
|
+
? verifyProcessGeneration(record.pid, record.start_token, dependencies.readToken)
|
|
70
|
+
: "unknown";
|
|
71
|
+
if (record.host !== hostname())
|
|
72
|
+
return { generation, liveness: "unknown" };
|
|
73
|
+
try {
|
|
74
|
+
const present = (dependencies.probePid ?? probePid)(record.pid);
|
|
75
|
+
if (!present)
|
|
76
|
+
return { generation, liveness: "stopped" };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
generation,
|
|
81
|
+
liveness: error.code === "ESRCH" ? "stopped" : "unknown",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
generation,
|
|
86
|
+
liveness: generation === "same"
|
|
87
|
+
? record.state === "stopped"
|
|
88
|
+
? "stopped"
|
|
89
|
+
: "running"
|
|
90
|
+
: generation === "different"
|
|
91
|
+
? "stopped"
|
|
92
|
+
: "unknown",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function probePid(pid) {
|
|
96
|
+
process.kill(pid, 0);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
13
99
|
export function readGovernorServiceConfig(coordRootRaw) {
|
|
14
100
|
const coordRoot = resolve(coordRootRaw);
|
|
15
101
|
const config = readBoundedJson(join(serviceDir(coordRoot), "config.json"), "governor service configuration");
|
|
@@ -48,7 +134,7 @@ export function readGovernorServiceRuntime(coordRootRaw) {
|
|
|
48
134
|
}
|
|
49
135
|
return runtime;
|
|
50
136
|
}
|
|
51
|
-
export function readGovernorServiceStatus(coordRootRaw) {
|
|
137
|
+
export function readGovernorServiceStatus(coordRootRaw, dependencies = {}) {
|
|
52
138
|
const coordRoot = resolve(coordRootRaw);
|
|
53
139
|
const record = readStatusRecord(coordRoot);
|
|
54
140
|
let config;
|
|
@@ -65,10 +151,19 @@ export function readGovernorServiceStatus(coordRootRaw) {
|
|
|
65
151
|
catch {
|
|
66
152
|
// Runtime is recoverable and must not make the dashboard unreadable.
|
|
67
153
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
154
|
+
const observation = observeGovernorServiceProcess(record, dependencies);
|
|
155
|
+
if (!record && existsSync(join(serviceDir(coordRoot), "status.json"))) {
|
|
156
|
+
observation.liveness = "unknown";
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
running: observation.liveness === "running" && record?.state !== "stopped",
|
|
160
|
+
stale: observation.liveness === "stopped" && record !== undefined && record.state !== "stopped",
|
|
161
|
+
...observation,
|
|
162
|
+
...governorServiceBuildStatus(record),
|
|
163
|
+
record,
|
|
164
|
+
config,
|
|
165
|
+
runtime,
|
|
166
|
+
};
|
|
72
167
|
}
|
|
73
168
|
export function governorServiceLogPath(coordRoot) {
|
|
74
169
|
const root = resolve(coordRoot);
|
|
@@ -346,27 +441,15 @@ function readStatusRecord(coordRoot) {
|
|
|
346
441
|
!validTimestamp(value.heartbeat_at)) {
|
|
347
442
|
return undefined;
|
|
348
443
|
}
|
|
349
|
-
return
|
|
444
|
+
return {
|
|
445
|
+
...value,
|
|
446
|
+
start_token: typeof value.start_token === "string" ? value.start_token : undefined,
|
|
447
|
+
};
|
|
350
448
|
}
|
|
351
449
|
catch {
|
|
352
450
|
return undefined;
|
|
353
451
|
}
|
|
354
452
|
}
|
|
355
|
-
function statusOwnerIsLive(record) {
|
|
356
|
-
if (record.state === "stopped")
|
|
357
|
-
return false;
|
|
358
|
-
if (record.host === hostname()) {
|
|
359
|
-
try {
|
|
360
|
-
process.kill(record.pid, 0);
|
|
361
|
-
return true;
|
|
362
|
-
}
|
|
363
|
-
catch (error) {
|
|
364
|
-
return error.code === "EPERM";
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
const age = Date.now() - Date.parse(record.heartbeat_at);
|
|
368
|
-
return Number.isFinite(age) && age < FOREIGN_STATUS_STALE_MS;
|
|
369
|
-
}
|
|
370
453
|
function readBoundedJson(path, label) {
|
|
371
454
|
if (!existsSync(path))
|
|
372
455
|
throw new Error(`${label} does not exist`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ProcessGenerationSignalDependencies, type ProcessGenerationVerdict } from "../agents/state/proc-start.js";
|
|
1
2
|
import { type NormalizedPolicy, type PolicyIsolation } from "../policy/index.js";
|
|
2
3
|
import type { RunWorkItemInput } from "../work/index.js";
|
|
3
4
|
import { type GovernorRunReport, type GovernorStopReason } from "./runner.js";
|
|
@@ -50,9 +51,18 @@ export interface GovernorServiceRuntime {
|
|
|
50
51
|
goals: Record<string, GovernorServiceGoalRuntime>;
|
|
51
52
|
}
|
|
52
53
|
export type GovernorServiceProcessState = "starting" | "running" | "stopping" | "stopped";
|
|
54
|
+
export interface GovernorServiceBuild {
|
|
55
|
+
version: string;
|
|
56
|
+
revision: string;
|
|
57
|
+
}
|
|
58
|
+
export interface GovernorServiceProcessDependencies extends ProcessGenerationSignalDependencies {
|
|
59
|
+
probePid?: (pid: number) => boolean;
|
|
60
|
+
}
|
|
53
61
|
export interface GovernorServiceStatusRecord {
|
|
54
62
|
schema_version: typeof GOVERNOR_SERVICE_STATUS_SCHEMA_VERSION;
|
|
55
63
|
pid: number;
|
|
64
|
+
start_token?: string;
|
|
65
|
+
running_build?: GovernorServiceBuild;
|
|
56
66
|
host: string;
|
|
57
67
|
nonce: string;
|
|
58
68
|
state: GovernorServiceProcessState;
|
|
@@ -69,6 +79,14 @@ export interface GovernorServiceStatusRecord {
|
|
|
69
79
|
export interface GovernorServiceStatus {
|
|
70
80
|
running: boolean;
|
|
71
81
|
stale: boolean;
|
|
82
|
+
generation: ProcessGenerationVerdict;
|
|
83
|
+
liveness: "running" | "stopped" | "unknown";
|
|
84
|
+
running_build: GovernorServiceBuild | null;
|
|
85
|
+
installed_build: GovernorServiceBuild;
|
|
86
|
+
restart_needed: boolean;
|
|
87
|
+
build_status: string;
|
|
88
|
+
signal_sent?: boolean;
|
|
89
|
+
signal_verdict?: ProcessGenerationVerdict;
|
|
72
90
|
record?: GovernorServiceStatusRecord;
|
|
73
91
|
config?: GovernorServiceConfig;
|
|
74
92
|
runtime?: GovernorServiceRuntime;
|
|
@@ -105,9 +123,9 @@ export interface RunGovernorServiceDaemonInput {
|
|
|
105
123
|
export declare function configureGovernorService(input: ConfigureGovernorServiceInput): GovernorServiceConfig;
|
|
106
124
|
export declare function readGovernorServiceConfig(coordRootRaw: string): GovernorServiceConfig;
|
|
107
125
|
export declare function readGovernorServiceRuntime(coordRootRaw: string): GovernorServiceRuntime | undefined;
|
|
108
|
-
export declare function readGovernorServiceStatus(coordRootRaw: string): GovernorServiceStatus;
|
|
126
|
+
export declare function readGovernorServiceStatus(coordRootRaw: string, dependencies?: GovernorServiceProcessDependencies): GovernorServiceStatus;
|
|
109
127
|
export declare function spawnGovernorService(coordRootRaw: string): Promise<GovernorServiceStatus>;
|
|
110
|
-
export declare function requestGovernorServiceStop(coordRootRaw: string): GovernorServiceStatus;
|
|
128
|
+
export declare function requestGovernorServiceStop(coordRootRaw: string, dependencies?: GovernorServiceProcessDependencies): GovernorServiceStatus;
|
|
111
129
|
export declare function runGovernorServiceSweep(input: RunGovernorServiceSweepInput): Promise<GovernorServiceSweepReport>;
|
|
112
130
|
export declare function runGovernorServiceDaemon(input: RunGovernorServiceDaemonInput): Promise<GovernorServiceStatusRecord>;
|
|
113
131
|
export declare function governorServiceLogPath(coordRoot: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,gBAAgB,EAAmB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAIlG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAe,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,KAAK,mCAAmC,EACxC,KAAK,wBAAwB,EAG9B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,KAAK,gBAAgB,EAAmB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAIlG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAe,MAAM,aAAa,CAAC;AAM3F,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,YAAY,CAAC;AAE/D,eAAO,MAAM,sCAAsC,EAAG,CAAU,CAAC;AACjE,eAAO,MAAM,uCAAuC,EAAG,CAAU,CAAC;AAClE,eAAO,MAAM,sCAAsC,EAAG,CAAU,CAAC;AAMjE,MAAM,WAAW,2BAA2B;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,OAAO,sCAAsC,CAAC;IAC9D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,2BAA2B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;CAC/C;AAED,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAAC;AAE9E,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,wBAAwB,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,OAAO,uCAAuC,CAAC;IAC/D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;CACnD;AAED,MAAM,MAAM,2BAA2B,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAE1F,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kCAAmC,SAAQ,mCAAmC;IAC7F,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,2BAA2B;IAC1C,cAAc,EAAE,OAAO,sCAAsC,CAAC;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,2BAA2B,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,wBAAwB,CAAC;IACrC,QAAQ,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,aAAa,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC3C,eAAe,EAAE,oBAAoB,CAAC;IACtC,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,MAAM,CAAC,EAAE,2BAA2B,CAAC;IACrC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,OAAO,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,2BAA2B,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACvF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,cAAc,CAAC;IACjE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzD,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAWD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,6BAA6B,GACnC,qBAAqB,CAqDvB;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CAQrF;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,sBAAsB,GAAG,SAAS,CAkBpC;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,kCAAuC,GACpD,qBAAqB,CA0BvB;AAED,wBAAsB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAyC/F;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,kCAAuC,GACpD,qBAAqB,CAwBvB;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CAwIrC;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,2BAA2B,CAAC,CAyHtC;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKhE;AAwPD,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,QAAQ,GAAG,QAAQ,CAgBrB"}
|
|
@@ -4,11 +4,14 @@ import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, re
|
|
|
4
4
|
import { hostname } from "node:os";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { coordEnv } from "../../lib/env.js";
|
|
7
|
+
import { processStartToken, signalIfSameGeneration, } from "../agents/state/proc-start.js";
|
|
8
|
+
import { resolveBinName } from "../config.js";
|
|
7
9
|
import { normalizePolicy } from "../policy/index.js";
|
|
8
10
|
import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.js";
|
|
9
11
|
import { stateDirMode, stateFileMode } from "../storage/modes.js";
|
|
10
12
|
import { RotatingTextSink } from "../storage/process-log.js";
|
|
11
13
|
import { runGovernor } from "./runner.js";
|
|
14
|
+
import { currentGovernorServiceBuild, governorServiceBuildStatus, observeGovernorServiceProcess, } from "./service-read.js";
|
|
12
15
|
import { readGovernor } from "./state.js";
|
|
13
16
|
export const GOVERNOR_SERVICE_CONFIG_SCHEMA_VERSION = 1;
|
|
14
17
|
export const GOVERNOR_SERVICE_RUNTIME_SCHEMA_VERSION = 1;
|
|
@@ -16,12 +19,16 @@ export const GOVERNOR_SERVICE_STATUS_SCHEMA_VERSION = 1;
|
|
|
16
19
|
const MAX_FILE_BYTES = 512 * 1024;
|
|
17
20
|
const MAX_GOALS = 100;
|
|
18
21
|
const MAX_ERROR = 2_000;
|
|
19
|
-
const FOREIGN_STATUS_STALE_MS = 30_000;
|
|
20
22
|
export function configureGovernorService(input) {
|
|
21
23
|
const coordRoot = resolve(input.coordRoot);
|
|
22
24
|
const active = readStatusRecord(coordRoot);
|
|
23
|
-
if (active &&
|
|
24
|
-
throw
|
|
25
|
+
if (!active && existsSync(serviceStatusPath(coordRoot))) {
|
|
26
|
+
throw serviceStartRefusal(coordRoot, undefined, "unknown");
|
|
27
|
+
}
|
|
28
|
+
if (active) {
|
|
29
|
+
const liveness = statusOwnerIsLive(active);
|
|
30
|
+
if (liveness !== "stopped")
|
|
31
|
+
throw serviceStartRefusal(coordRoot, active.pid, liveness);
|
|
25
32
|
}
|
|
26
33
|
const goalIds = unique(input.goalIds.map((value) => value.trim()).filter(Boolean));
|
|
27
34
|
if (goalIds.length < 1 || goalIds.length > MAX_GOALS) {
|
|
@@ -73,7 +80,7 @@ export function readGovernorServiceRuntime(coordRootRaw) {
|
|
|
73
80
|
}
|
|
74
81
|
return runtime;
|
|
75
82
|
}
|
|
76
|
-
export function readGovernorServiceStatus(coordRootRaw) {
|
|
83
|
+
export function readGovernorServiceStatus(coordRootRaw, dependencies = {}) {
|
|
77
84
|
const coordRoot = resolve(coordRootRaw);
|
|
78
85
|
const record = readStatusRecord(coordRoot);
|
|
79
86
|
let config;
|
|
@@ -90,17 +97,25 @@ export function readGovernorServiceStatus(coordRootRaw) {
|
|
|
90
97
|
catch {
|
|
91
98
|
// Status remains readable when recoverable runtime state is corrupt.
|
|
92
99
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return {
|
|
100
|
+
const observation = observeGovernorServiceProcess(record, dependencies);
|
|
101
|
+
if (!record && existsSync(serviceStatusPath(coordRoot)))
|
|
102
|
+
observation.liveness = "unknown";
|
|
103
|
+
return {
|
|
104
|
+
running: observation.liveness === "running" && record?.state !== "stopped",
|
|
105
|
+
stale: observation.liveness === "stopped" && record !== undefined && record.state !== "stopped",
|
|
106
|
+
...observation,
|
|
107
|
+
...governorServiceBuildStatus(record),
|
|
108
|
+
record,
|
|
109
|
+
config,
|
|
110
|
+
runtime,
|
|
111
|
+
};
|
|
97
112
|
}
|
|
98
113
|
export async function spawnGovernorService(coordRootRaw) {
|
|
99
114
|
const coordRoot = resolve(coordRootRaw);
|
|
100
115
|
readGovernorServiceConfig(coordRoot);
|
|
101
116
|
const current = readGovernorServiceStatus(coordRoot);
|
|
102
|
-
if (current.
|
|
103
|
-
throw
|
|
117
|
+
if (current.liveness !== "stopped") {
|
|
118
|
+
throw serviceStartRefusal(coordRoot, current.record?.pid, current.liveness);
|
|
104
119
|
}
|
|
105
120
|
mkdirSync(serviceDir(coordRoot), { recursive: true, mode: stateDirMode() });
|
|
106
121
|
const sharedLogs = coordEnv("SHARED_LOGS") !== "0";
|
|
@@ -143,24 +158,24 @@ export async function spawnGovernorService(coordRootRaw) {
|
|
|
143
158
|
}
|
|
144
159
|
throw new Error(`governor service failed to start; inspect ${governorServiceLogPath(coordRoot)}`);
|
|
145
160
|
}
|
|
146
|
-
export function requestGovernorServiceStop(coordRootRaw) {
|
|
161
|
+
export function requestGovernorServiceStop(coordRootRaw, dependencies = {}) {
|
|
147
162
|
const coordRoot = resolve(coordRootRaw);
|
|
148
|
-
const status = readGovernorServiceStatus(coordRoot);
|
|
149
|
-
if (
|
|
150
|
-
return status;
|
|
163
|
+
const status = readGovernorServiceStatus(coordRoot, dependencies);
|
|
164
|
+
if ((status.record?.state === "stopped" || !status.record) && status.liveness === "stopped") {
|
|
165
|
+
return { ...status, signal_sent: false, signal_verdict: status.generation };
|
|
166
|
+
}
|
|
151
167
|
writePrivateJsonAtomic(serviceStopPath(coordRoot), {
|
|
152
168
|
requested_at: new Date().toISOString(),
|
|
153
169
|
requested_by_pid: process.pid,
|
|
154
170
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
return readGovernorServiceStatus(coordRoot);
|
|
171
|
+
const signal = status.record?.host === hostname() && status.record.state !== "stopped"
|
|
172
|
+
? signalIfSameGeneration(status.record.pid, status.record.start_token, "SIGTERM", dependencies)
|
|
173
|
+
: { sent: false, verdict: status.generation };
|
|
174
|
+
return {
|
|
175
|
+
...readGovernorServiceStatus(coordRoot, dependencies),
|
|
176
|
+
signal_sent: signal.sent,
|
|
177
|
+
signal_verdict: signal.verdict,
|
|
178
|
+
};
|
|
164
179
|
}
|
|
165
180
|
export async function runGovernorServiceSweep(input) {
|
|
166
181
|
const coordRoot = resolve(input.coordRoot);
|
|
@@ -298,12 +313,23 @@ export async function runGovernorServiceSweep(input) {
|
|
|
298
313
|
export async function runGovernorServiceDaemon(input) {
|
|
299
314
|
const coordRoot = resolve(input.coordRoot);
|
|
300
315
|
const config = readGovernorServiceConfig(coordRoot);
|
|
316
|
+
const existing = readStatusRecord(coordRoot);
|
|
317
|
+
if (!existing && existsSync(serviceStatusPath(coordRoot))) {
|
|
318
|
+
throw serviceStartRefusal(coordRoot, undefined, "unknown");
|
|
319
|
+
}
|
|
320
|
+
if (existing) {
|
|
321
|
+
const liveness = statusOwnerIsLive(existing);
|
|
322
|
+
if (liveness !== "stopped")
|
|
323
|
+
throw serviceStartRefusal(coordRoot, existing.pid, liveness);
|
|
324
|
+
}
|
|
301
325
|
const release = acquireServiceLease(coordRoot);
|
|
302
326
|
rmSync(serviceStopPath(coordRoot), { force: true });
|
|
303
327
|
const now = new Date().toISOString();
|
|
304
328
|
const status = {
|
|
305
329
|
schema_version: GOVERNOR_SERVICE_STATUS_SCHEMA_VERSION,
|
|
306
330
|
pid: process.pid,
|
|
331
|
+
start_token: processStartToken(process.pid) ?? undefined,
|
|
332
|
+
running_build: currentGovernorServiceBuild(),
|
|
307
333
|
host: hostname(),
|
|
308
334
|
nonce: randomUUID(),
|
|
309
335
|
state: "starting",
|
|
@@ -330,6 +356,8 @@ export async function runGovernorServiceDaemon(input) {
|
|
|
330
356
|
appendGovernorServiceDiagnostic(coordRoot, {
|
|
331
357
|
event: "service.started",
|
|
332
358
|
pid: process.pid,
|
|
359
|
+
start_token: status.start_token,
|
|
360
|
+
running_build: status.running_build,
|
|
333
361
|
goals: config.goal_ids,
|
|
334
362
|
config_created_at: config.created_at,
|
|
335
363
|
});
|
|
@@ -514,6 +542,8 @@ function acquireServiceLease(coordRoot) {
|
|
|
514
542
|
mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
|
|
515
543
|
const owner = {
|
|
516
544
|
pid: process.pid,
|
|
545
|
+
start_token: processStartToken(process.pid) ?? undefined,
|
|
546
|
+
running_build: currentGovernorServiceBuild(),
|
|
517
547
|
host: hostname(),
|
|
518
548
|
nonce: randomUUID(),
|
|
519
549
|
created_at: new Date().toISOString(),
|
|
@@ -537,8 +567,9 @@ function acquireServiceLease(coordRoot) {
|
|
|
537
567
|
};
|
|
538
568
|
if (!acquire()) {
|
|
539
569
|
const existing = readLease(path);
|
|
540
|
-
|
|
541
|
-
|
|
570
|
+
const liveness = existing ? leaseOwnerIsLive(existing) : "unknown";
|
|
571
|
+
if (liveness !== "stopped") {
|
|
572
|
+
throw serviceStartRefusal(coordRoot, existing?.pid, liveness);
|
|
542
573
|
}
|
|
543
574
|
unlinkSync(path);
|
|
544
575
|
if (!acquire())
|
|
@@ -563,7 +594,10 @@ function readLease(path) {
|
|
|
563
594
|
typeof value.host === "string" &&
|
|
564
595
|
typeof value.nonce === "string" &&
|
|
565
596
|
typeof value.created_at === "string"
|
|
566
|
-
?
|
|
597
|
+
? {
|
|
598
|
+
...value,
|
|
599
|
+
start_token: typeof value.start_token === "string" ? value.start_token : undefined,
|
|
600
|
+
}
|
|
567
601
|
: null;
|
|
568
602
|
}
|
|
569
603
|
catch {
|
|
@@ -571,11 +605,7 @@ function readLease(path) {
|
|
|
571
605
|
}
|
|
572
606
|
}
|
|
573
607
|
function leaseOwnerIsLive(lease) {
|
|
574
|
-
|
|
575
|
-
const age = Date.now() - Date.parse(lease.created_at);
|
|
576
|
-
return Number.isFinite(age) && age < FOREIGN_STATUS_STALE_MS;
|
|
577
|
-
}
|
|
578
|
-
return pidAlive(lease.pid);
|
|
608
|
+
return observeGovernorServiceProcess({ ...lease, state: "running" }).liveness;
|
|
579
609
|
}
|
|
580
610
|
function readStatusRecord(coordRoot) {
|
|
581
611
|
if (!existsSync(serviceStatusPath(coordRoot)))
|
|
@@ -591,28 +621,23 @@ function readStatusRecord(coordRoot) {
|
|
|
591
621
|
!validTimestamp(value.heartbeat_at)) {
|
|
592
622
|
return undefined;
|
|
593
623
|
}
|
|
594
|
-
return
|
|
624
|
+
return {
|
|
625
|
+
...value,
|
|
626
|
+
start_token: typeof value.start_token === "string" ? value.start_token : undefined,
|
|
627
|
+
};
|
|
595
628
|
}
|
|
596
629
|
catch {
|
|
597
630
|
return undefined;
|
|
598
631
|
}
|
|
599
632
|
}
|
|
600
633
|
function statusOwnerIsLive(record) {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
function pidAlive(pid) {
|
|
609
|
-
try {
|
|
610
|
-
process.kill(pid, 0);
|
|
611
|
-
return true;
|
|
612
|
-
}
|
|
613
|
-
catch (error) {
|
|
614
|
-
return error.code === "EPERM";
|
|
615
|
-
}
|
|
634
|
+
return observeGovernorServiceProcess(record).liveness;
|
|
635
|
+
}
|
|
636
|
+
function serviceStartRefusal(coordRoot, pid, liveness) {
|
|
637
|
+
const reason = liveness === "unknown"
|
|
638
|
+
? `governor service process generation is unknown${pid ? ` for pid ${pid}` : ""}`
|
|
639
|
+
: `governor service process is still running under pid ${pid}`;
|
|
640
|
+
return new Error(`${reason}; run \`${resolveBinName(coordRoot)} governor service stop\` to write a durable stop request before starting or reconfiguring it`);
|
|
616
641
|
}
|
|
617
642
|
export function appendGovernorServiceDiagnostic(coordRoot, data) {
|
|
618
643
|
if (coordEnv("SHARED_LOGS") !== "0") {
|