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
|
@@ -191,25 +191,19 @@ export async function withFamilyLease(directory, policy, operation) {
|
|
|
191
191
|
let owner;
|
|
192
192
|
while (true) {
|
|
193
193
|
try {
|
|
194
|
-
|
|
195
|
-
const leaseIdentity = captureDirectoryIdentity(lease);
|
|
196
|
-
owner = {
|
|
197
|
-
owner_id: randomUUID(),
|
|
198
|
-
pid: process.pid,
|
|
199
|
-
acquired_at: new Date().toISOString(),
|
|
200
|
-
};
|
|
201
|
-
writeNewFile(join(lease, "owner.json"), Buffer.from(`${JSON.stringify(owner)}\n`));
|
|
202
|
-
assertDirectoryIdentity(leaseIdentity);
|
|
194
|
+
owner = claimLease(lease);
|
|
203
195
|
break;
|
|
204
196
|
}
|
|
205
197
|
catch (error) {
|
|
206
|
-
if (
|
|
198
|
+
if (leaseHasWrongType(lease)) {
|
|
207
199
|
throw new HarneryLogLeaseError("wrong_type", `log lease is not a directory: ${lease}`);
|
|
208
200
|
}
|
|
209
201
|
if (recoverStaleLease(lease, policy.lease_stale_ms))
|
|
210
202
|
continue;
|
|
211
203
|
if (Date.now() - started >= policy.lease_timeout_ms) {
|
|
212
|
-
throw new HarneryLogLeaseError("timeout",
|
|
204
|
+
throw new HarneryLogLeaseError("timeout", leaseHasValidOwner(lease)
|
|
205
|
+
? `timed out acquiring log lease: ${lease}`
|
|
206
|
+
: `timed out acquiring log lease with no valid owner; an interrupted writer left it, and it is never recovered automatically: ${lease}`);
|
|
213
207
|
}
|
|
214
208
|
await new Promise((resolve) => setTimeout(resolve, policy.lease_retry_ms));
|
|
215
209
|
void error;
|
|
@@ -223,6 +217,42 @@ export async function withFamilyLease(directory, policy, operation) {
|
|
|
223
217
|
releaseOwnedLease(lease, owner);
|
|
224
218
|
}
|
|
225
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Publish a complete lease in one rename. The owner record is written and synced
|
|
222
|
+
* in a private claim directory first, so a writer stopped at any point leaves
|
|
223
|
+
* either no lease or one with an owner. A held lease always has an owner record,
|
|
224
|
+
* here and in the earlier create-then-write protocol, so a rename that replaces
|
|
225
|
+
* an empty lease directory never takes a held lease. A lease with any entry makes
|
|
226
|
+
* the rename fail, and the caller waits or recovers as before.
|
|
227
|
+
*/
|
|
228
|
+
function claimLease(lease) {
|
|
229
|
+
const owner = {
|
|
230
|
+
owner_id: randomUUID(),
|
|
231
|
+
pid: process.pid,
|
|
232
|
+
acquired_at: new Date().toISOString(),
|
|
233
|
+
};
|
|
234
|
+
const content = `${JSON.stringify(owner)}\n`;
|
|
235
|
+
const claim = `${lease}.claim-${process.pid}-${owner.owner_id}`;
|
|
236
|
+
try {
|
|
237
|
+
mkdirSync(claim, { mode: stateDirMode() });
|
|
238
|
+
writeNewFile(join(claim, "owner.json"), Buffer.from(content));
|
|
239
|
+
renameSync(claim, lease);
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
rmSync(claim, { recursive: true, force: true });
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
captureDirectoryIdentity(lease);
|
|
246
|
+
if (readRegularFile(join(lease, "owner.json"), 4_096).toString("utf8") !== content) {
|
|
247
|
+
throw new Error(`log lease owner changed during claim: ${lease}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
releaseOwnedLease(lease, owner);
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
return owner;
|
|
255
|
+
}
|
|
226
256
|
function shouldRotate(active, incoming, options, now) {
|
|
227
257
|
const stat = regularFileStat(active);
|
|
228
258
|
const incomingBytes = incoming.reduce((sum, record) => sum + record.byteLength, 0);
|
|
@@ -315,6 +345,18 @@ function atomicJson(path, value) {
|
|
|
315
345
|
renameSync(temporary, path);
|
|
316
346
|
assertRegularPath(path, captureDirectoryIdentity(dirname(path)));
|
|
317
347
|
}
|
|
348
|
+
function leaseHasValidOwner(lease) {
|
|
349
|
+
try {
|
|
350
|
+
const owner = JSON.parse(readRegularFile(join(lease, "owner.json"), 4_096).toString("utf8"));
|
|
351
|
+
return (typeof owner?.owner_id === "string" &&
|
|
352
|
+
owner.owner_id.length > 0 &&
|
|
353
|
+
Number.isSafeInteger(owner.pid) &&
|
|
354
|
+
Number.isFinite(Date.parse(owner.acquired_at)));
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
318
360
|
function recoverStaleLease(lease, maximumAgeMs) {
|
|
319
361
|
let identity;
|
|
320
362
|
let raw;
|
|
@@ -344,7 +386,7 @@ function recoverStaleLease(lease, maximumAgeMs) {
|
|
|
344
386
|
assertDirectoryIdentity(identity);
|
|
345
387
|
if (readRegularFile(join(lease, "owner.json"), 4_096).toString("utf8") !== raw)
|
|
346
388
|
return false;
|
|
347
|
-
|
|
389
|
+
retireLease(lease, randomUUID());
|
|
348
390
|
return true;
|
|
349
391
|
}
|
|
350
392
|
catch {
|
|
@@ -356,12 +398,22 @@ function releaseOwnedLease(lease, owner) {
|
|
|
356
398
|
const current = JSON.parse(readRegularFile(join(lease, "owner.json"), 4_096).toString("utf8"));
|
|
357
399
|
if (current.owner_id !== owner.owner_id)
|
|
358
400
|
return;
|
|
359
|
-
|
|
401
|
+
retireLease(lease, owner.owner_id);
|
|
360
402
|
}
|
|
361
403
|
catch {
|
|
362
404
|
// A missing or replaced lease does not belong to this operation.
|
|
363
405
|
}
|
|
364
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* Move a lease aside before deleting it. Its path goes from held to absent in
|
|
409
|
+
* one rename and is never an empty directory that a concurrent claim could
|
|
410
|
+
* replace while a recursive removal is still running.
|
|
411
|
+
*/
|
|
412
|
+
function retireLease(lease, tag) {
|
|
413
|
+
const retired = `${lease}.retired-${process.pid}-${tag}`;
|
|
414
|
+
renameSync(lease, retired);
|
|
415
|
+
rmSync(retired, { recursive: true, force: true });
|
|
416
|
+
}
|
|
365
417
|
function processIsAlive(pid) {
|
|
366
418
|
try {
|
|
367
419
|
process.kill(pid, 0);
|
|
@@ -519,12 +571,16 @@ function writeAllSync(fd, buffer, writer) {
|
|
|
519
571
|
function nativeWriteSync(fd, buffer, offset, length) {
|
|
520
572
|
return writeSync(fd, buffer, offset, length);
|
|
521
573
|
}
|
|
522
|
-
|
|
574
|
+
/** One lstat, so a lease released between checks reads as absent, not as a wrong type. */
|
|
575
|
+
function leaseHasWrongType(path) {
|
|
523
576
|
try {
|
|
524
|
-
|
|
577
|
+
const stat = lstatSync(path);
|
|
578
|
+
return stat.isSymbolicLink() || !stat.isDirectory();
|
|
525
579
|
}
|
|
526
|
-
catch {
|
|
527
|
-
|
|
580
|
+
catch (error) {
|
|
581
|
+
if (error.code === "ENOENT")
|
|
582
|
+
return false;
|
|
583
|
+
throw error;
|
|
528
584
|
}
|
|
529
585
|
}
|
|
530
586
|
function pathExists(path) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ServiceProcessDependencies, type ServiceStopFields } from "../agents/state/service-process.js";
|
|
2
2
|
import { type SupervisorServiceStatusRecord, type SupervisorStatus } from "./contract.js";
|
|
3
|
-
import { type SupervisorProcessDependencies } from "./status.js";
|
|
4
3
|
export declare const SUPERVISOR_DEFAULT_INTERVAL_MS = 2000;
|
|
5
4
|
export declare const SUPERVISOR_DEFAULT_IDLE_EXIT_MS: number;
|
|
6
5
|
export interface RunSupervisorInput {
|
|
@@ -26,10 +25,8 @@ export declare function spawnSupervisor(coordRootRaw: string, options?: {
|
|
|
26
25
|
keepAlive?: boolean;
|
|
27
26
|
}): Promise<SupervisorStatus>;
|
|
28
27
|
export declare function ensureSupervisorRunning(coordRoot: string): Promise<EnsureSupervisorResult>;
|
|
29
|
-
export
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
export declare function requestSupervisorStop(coordRootRaw: string, dependencies?: SupervisorProcessDependencies & ProcessGenerationSignalDependencies): SupervisorStopResult;
|
|
28
|
+
export type SupervisorStopResult = SupervisorStatus & ServiceStopFields;
|
|
29
|
+
/** Windows has no graceful SIGTERM, so the durable request alone stops it there. */
|
|
30
|
+
export declare function requestSupervisorStop(coordRootRaw: string, dependencies?: ServiceProcessDependencies): SupervisorStopResult;
|
|
34
31
|
export declare function runSupervisor(input: RunSupervisorInput): Promise<SupervisorServiceStatusRecord>;
|
|
35
32
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/service.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,0BAA0B,EAC/B,KAAK,iBAAiB,EAGvB,MAAM,oCAAoC,CAAC;AAgB5C,OAAO,EAML,KAAK,6BAA6B,EAElC,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAsBvB,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AACpD,eAAO,MAAM,+BAA+B,QAAa,CAAC;AAO1D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9E,OAAO,CAAC,gBAAgB,CAAC,CAuD3B;AAED,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAahG;AAED,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAExE,oFAAoF;AACpF,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,0BAA+B,GAC5C,oBAAoB,CAStB;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,6BAA6B,CAAC,CA4QxC"}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
import { closeSync, existsSync, mkdirSync, openSync, readdirSync, readFileSync, rmSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
|
|
4
3
|
import { hostname } from "node:os";
|
|
5
4
|
import { resolve } from "node:path";
|
|
6
5
|
import { performance } from "node:perf_hooks";
|
|
7
6
|
import { fileURLToPath } from "node:url";
|
|
8
7
|
import { collectCoordinationHealthSnapshot } from "../agents/health.js";
|
|
9
|
-
import { processStartToken
|
|
8
|
+
import { processStartToken } from "../agents/state/proc-start.js";
|
|
9
|
+
import { acquireServiceLease, requestServiceStop, serviceLeaseOwner, serviceStartRefusal, } from "../agents/state/service-process.js";
|
|
10
10
|
import { resolveBinName } from "../config.js";
|
|
11
11
|
import { pressureHistoryFromSupervisor } from "../diagnostics/advice.js";
|
|
12
12
|
import { assessPressure } from "../diagnostics/pressure.js";
|
|
13
13
|
import { readEventV3ControlState } from "../events/v3/control.js";
|
|
14
14
|
import { janitorLiveDisplayV3 } from "../events/v3/live-feed.js";
|
|
15
|
+
import { installedHarneryBuild } from "../events/v3/runtime-build.js";
|
|
15
16
|
import { sampleResources } from "../resources/sampler.js";
|
|
16
17
|
import { requestResourceServiceStop } from "../resources/service.js";
|
|
17
18
|
import { readResourceServiceStatus } from "../resources/service-status.js";
|
|
18
19
|
import { resourcePaths } from "../resources/storage.js";
|
|
19
20
|
import { writePrivateJsonAtomic } from "../storage/atomic-json.js";
|
|
20
21
|
import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.js";
|
|
21
|
-
import { stateDirMode
|
|
22
|
+
import { stateDirMode } from "../storage/modes.js";
|
|
22
23
|
import { collectSupervisorActivitySnapshot } from "./activity.js";
|
|
23
24
|
import { SUPERVISOR_PRESSURE_SCHEMA_VERSION, SUPERVISOR_SNAPSHOT_SCHEMA_VERSION, SUPERVISOR_STATUS_SCHEMA_VERSION, } from "./contract.js";
|
|
24
25
|
import { explainSupervisorFinding } from "./explanations.js";
|
|
@@ -29,7 +30,7 @@ import { writeSupervisorHookHealth } from "./hook-health-storage.js";
|
|
|
29
30
|
import { collectHookHealth } from "./hooks.js";
|
|
30
31
|
import { SupervisorLogCollector } from "./log-feed.js";
|
|
31
32
|
import { collectServiceHealth } from "./services.js";
|
|
32
|
-
import {
|
|
33
|
+
import { readSupervisorStatus } from "./status.js";
|
|
33
34
|
import { readSupervisorFindings, readSupervisorHistory, readSupervisorPressure, supervisorPaths, } from "./storage.js";
|
|
34
35
|
import { buildSupervisorTimeline } from "./timeline.js";
|
|
35
36
|
export const SUPERVISOR_DEFAULT_INTERVAL_MS = 2_000;
|
|
@@ -42,13 +43,12 @@ const LIVE_DISPLAY_SWEEP_INTERVAL_MS = 5 * 60_000;
|
|
|
42
43
|
export async function spawnSupervisor(coordRootRaw, options = {}) {
|
|
43
44
|
const coordRoot = resolve(coordRootRaw);
|
|
44
45
|
const current = readSupervisorStatus(coordRoot);
|
|
45
|
-
if (current.liveness
|
|
46
|
-
throw
|
|
47
|
-
if (current.liveness === "running") {
|
|
48
|
-
throw new Error(`local supervisor is already running under pid ${current.record?.pid}`);
|
|
49
|
-
}
|
|
46
|
+
if (current.liveness !== "stopped")
|
|
47
|
+
throw startRefusal(current.record?.pid, current.liveness);
|
|
50
48
|
const paths = supervisorPaths(coordRoot);
|
|
51
|
-
|
|
49
|
+
const lease = serviceLeaseOwner(paths.lease);
|
|
50
|
+
if (lease.liveness !== "stopped")
|
|
51
|
+
throw startRefusal(lease.lease?.pid, lease.liveness);
|
|
52
52
|
await stopLegacyResourceObserver(coordRoot);
|
|
53
53
|
const intervalMs = normalizeInterval(options.intervalMs);
|
|
54
54
|
const idleExitMs = normalizeIdleExit(options.idleExitMs);
|
|
@@ -112,45 +112,29 @@ export async function ensureSupervisorRunning(coordRoot) {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
/** Windows has no graceful SIGTERM, so the durable request alone stops it there. */
|
|
115
116
|
export function requestSupervisorStop(coordRootRaw, dependencies = {}) {
|
|
116
117
|
const coordRoot = resolve(coordRootRaw);
|
|
117
|
-
const paths = supervisorPaths(coordRoot);
|
|
118
|
-
const status = readSupervisorStatus(coordRoot, Date.now(), dependencies);
|
|
119
|
-
mkdirSync(paths.root, { recursive: true, mode: stateDirMode() });
|
|
120
|
-
writePrivateJsonAtomic(paths.stop, {
|
|
121
|
-
requested_at: new Date().toISOString(),
|
|
122
|
-
requested_by_pid: process.pid,
|
|
123
|
-
});
|
|
124
118
|
const legacyPaths = resourcePaths(coordRoot);
|
|
125
119
|
if (existsSync(legacyPaths.service) || existsSync(legacyPaths.lease))
|
|
126
120
|
requestResourceServiceStop(coordRoot, dependencies);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
signal = signalIfSameGeneration(status.record.pid, status.record.start_token, "SIGTERM", dependencies);
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
...readSupervisorStatus(coordRoot, Date.now(), dependencies),
|
|
135
|
-
signal_sent: signal.sent,
|
|
136
|
-
signal_verdict: signal.verdict,
|
|
137
|
-
};
|
|
121
|
+
const read = () => readSupervisorStatus(coordRoot, Date.now(), dependencies);
|
|
122
|
+
return requestServiceStop(read(), read, supervisorPaths(coordRoot).stop, dependencies, {
|
|
123
|
+
signal: process.platform !== "win32",
|
|
124
|
+
});
|
|
138
125
|
}
|
|
139
126
|
export async function runSupervisor(input) {
|
|
140
127
|
const coordRoot = resolve(input.coordRoot);
|
|
141
128
|
const current = readSupervisorStatus(coordRoot);
|
|
142
|
-
if (current.liveness
|
|
143
|
-
throw
|
|
144
|
-
if (current.liveness === "running") {
|
|
145
|
-
throw new Error(`local supervisor is already running under pid ${current.record?.pid}`);
|
|
146
|
-
}
|
|
129
|
+
if (current.liveness !== "stopped")
|
|
130
|
+
throw startRefusal(current.record?.pid, current.liveness);
|
|
147
131
|
const paths = supervisorPaths(coordRoot);
|
|
148
132
|
const intervalMs = normalizeInterval(input.intervalMs);
|
|
149
133
|
const idleExitMs = normalizeIdleExit(input.idleExitMs);
|
|
150
134
|
const keepAlive = input.keepAlive ?? false;
|
|
151
135
|
const now = input.now ?? (() => new Date());
|
|
152
136
|
const wait = input.wait ?? delay;
|
|
153
|
-
const lease =
|
|
137
|
+
const lease = acquireServiceLease(paths.lease, startRefusal);
|
|
154
138
|
rmSync(paths.stop, { force: true });
|
|
155
139
|
const startedAt = now().toISOString();
|
|
156
140
|
const startToken = processStartToken(process.pid);
|
|
@@ -158,7 +142,7 @@ export async function runSupervisor(input) {
|
|
|
158
142
|
schema_version: SUPERVISOR_STATUS_SCHEMA_VERSION,
|
|
159
143
|
pid: process.pid,
|
|
160
144
|
...(startToken ? { start_token: startToken } : {}),
|
|
161
|
-
running_build:
|
|
145
|
+
running_build: installedHarneryBuild(),
|
|
162
146
|
host: hostname(),
|
|
163
147
|
nonce: lease.nonce,
|
|
164
148
|
state: "starting",
|
|
@@ -400,7 +384,7 @@ export async function runSupervisor(input) {
|
|
|
400
384
|
await closeProcessLoggers();
|
|
401
385
|
}
|
|
402
386
|
finally {
|
|
403
|
-
|
|
387
|
+
lease.release();
|
|
404
388
|
}
|
|
405
389
|
}
|
|
406
390
|
return status;
|
|
@@ -440,48 +424,6 @@ function observeLedgerControlState(coordRoot, now) {
|
|
|
440
424
|
};
|
|
441
425
|
}
|
|
442
426
|
}
|
|
443
|
-
function acquireLease(coordRoot, now) {
|
|
444
|
-
const paths = supervisorPaths(coordRoot);
|
|
445
|
-
mkdirSync(paths.root, { recursive: true, mode: stateDirMode() });
|
|
446
|
-
for (let attempt = 0; attempt < 2; attempt++) {
|
|
447
|
-
const startToken = processStartToken(process.pid);
|
|
448
|
-
const lease = {
|
|
449
|
-
pid: process.pid,
|
|
450
|
-
...(startToken ? { start_token: startToken } : {}),
|
|
451
|
-
host: hostname(),
|
|
452
|
-
nonce: randomUUID(),
|
|
453
|
-
created_at: now.toISOString(),
|
|
454
|
-
};
|
|
455
|
-
try {
|
|
456
|
-
const fd = openSync(paths.lease, "wx", stateFileMode());
|
|
457
|
-
try {
|
|
458
|
-
writeFileSync(fd, `${JSON.stringify(lease)}\n`, "utf8");
|
|
459
|
-
}
|
|
460
|
-
finally {
|
|
461
|
-
closeSync(fd);
|
|
462
|
-
}
|
|
463
|
-
return lease;
|
|
464
|
-
}
|
|
465
|
-
catch (error) {
|
|
466
|
-
if (error.code !== "EEXIST")
|
|
467
|
-
throw error;
|
|
468
|
-
const existing = readLease(paths.lease);
|
|
469
|
-
const liveness = existing ? leaseIsLive(existing) : "unknown";
|
|
470
|
-
if (liveness === "unknown")
|
|
471
|
-
throw unknownOwnerError();
|
|
472
|
-
if (existing && liveness === "running") {
|
|
473
|
-
throw new Error(`local supervisor lease is held by pid ${existing.pid}`);
|
|
474
|
-
}
|
|
475
|
-
try {
|
|
476
|
-
unlinkSync(paths.lease);
|
|
477
|
-
}
|
|
478
|
-
catch {
|
|
479
|
-
// A concurrent starter may have replaced or removed the stale lease.
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
throw new Error("local supervisor could not acquire its singleton lease");
|
|
484
|
-
}
|
|
485
427
|
function pruneProjectionDirectory(directory, retainedFindingIds) {
|
|
486
428
|
for (const file of readdirSync(directory)) {
|
|
487
429
|
if (!file.endsWith(".json"))
|
|
@@ -491,49 +433,8 @@ function pruneProjectionDirectory(directory, retainedFindingIds) {
|
|
|
491
433
|
rmSync(resolve(directory, file), { force: true });
|
|
492
434
|
}
|
|
493
435
|
}
|
|
494
|
-
function
|
|
495
|
-
|
|
496
|
-
if (current?.nonce !== nonce)
|
|
497
|
-
return;
|
|
498
|
-
try {
|
|
499
|
-
unlinkSync(path);
|
|
500
|
-
}
|
|
501
|
-
catch {
|
|
502
|
-
// A missing lease is already released.
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
function readLease(path) {
|
|
506
|
-
try {
|
|
507
|
-
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
508
|
-
return value &&
|
|
509
|
-
Number.isSafeInteger(value.pid) &&
|
|
510
|
-
value.pid > 0 &&
|
|
511
|
-
typeof value.host === "string" &&
|
|
512
|
-
value.host.length > 0 &&
|
|
513
|
-
typeof value.nonce === "string" &&
|
|
514
|
-
value.nonce.length > 0
|
|
515
|
-
? value
|
|
516
|
-
: undefined;
|
|
517
|
-
}
|
|
518
|
-
catch {
|
|
519
|
-
return undefined;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
function leaseIsLive(lease) {
|
|
523
|
-
return supervisorProcessLiveness(lease).liveness;
|
|
524
|
-
}
|
|
525
|
-
function assertLeaseAvailable(path) {
|
|
526
|
-
if (!existsSync(path))
|
|
527
|
-
return;
|
|
528
|
-
const lease = readLease(path);
|
|
529
|
-
const liveness = lease ? leaseIsLive(lease) : "unknown";
|
|
530
|
-
if (liveness === "unknown")
|
|
531
|
-
throw unknownOwnerError();
|
|
532
|
-
if (liveness === "running")
|
|
533
|
-
throw new Error(`local supervisor lease is held by pid ${lease?.pid}`);
|
|
534
|
-
}
|
|
535
|
-
function unknownOwnerError() {
|
|
536
|
-
return new Error(`local supervisor process identity is unknown; run ${resolveBinName()} supervisor stop to write the durable stop request before starting again`);
|
|
436
|
+
function startRefusal(pid, liveness) {
|
|
437
|
+
return serviceStartRefusal("local supervisor", `${resolveBinName()} supervisor stop`, pid, liveness);
|
|
537
438
|
}
|
|
538
439
|
async function stopLegacyResourceObserver(coordRoot) {
|
|
539
440
|
const legacy = readResourceServiceStatus(coordRoot);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
|
|
2
2
|
import { hostname } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { processStartToken, verifyProcessGeneration } from "../agents/state/proc-start.js";
|
|
5
5
|
import { readGovernorServiceStatus } from "../governor/service-read.js";
|
|
6
6
|
import { writePrivateJsonAtomic } from "../storage/atomic-json.js";
|
|
7
7
|
import { SUPERVISOR_CONSUMER_SCHEMA_VERSION, } from "./contract.js";
|
|
@@ -87,7 +87,7 @@ function consumerAlive(record) {
|
|
|
87
87
|
if (error.code !== "EPERM")
|
|
88
88
|
return false;
|
|
89
89
|
}
|
|
90
|
-
return
|
|
90
|
+
return verifyProcessGeneration(record.pid, record.start_token) !== "different";
|
|
91
91
|
}
|
|
92
92
|
function readDetachedService(path, id) {
|
|
93
93
|
const record = readBoundedJson(path);
|
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type
|
|
3
|
-
export
|
|
4
|
-
readToken?: (pid: number) => string | null;
|
|
5
|
-
probePid?: (pid: number) => unknown;
|
|
6
|
-
}
|
|
7
|
-
export declare function installedSupervisorBuild(): SupervisorBuild;
|
|
8
|
-
export declare function readSupervisorStatus(coordRoot: string, nowMs?: number, dependencies?: SupervisorProcessDependencies): SupervisorStatus;
|
|
9
|
-
/** A stale heartbeat does not prove that a process has exited. */
|
|
10
|
-
export declare function supervisorProcessLiveness(owner: {
|
|
11
|
-
pid: number;
|
|
12
|
-
host: string;
|
|
13
|
-
start_token?: string;
|
|
14
|
-
}, dependencies?: SupervisorProcessDependencies): {
|
|
15
|
-
liveness: SupervisorStatus["liveness"];
|
|
16
|
-
generation: ProcessGenerationVerdict;
|
|
17
|
-
};
|
|
1
|
+
import { type ServiceProcessDependencies } from "../agents/state/service-process.js";
|
|
2
|
+
import { type SupervisorStatus } from "./contract.js";
|
|
3
|
+
export declare function readSupervisorStatus(coordRoot: string, nowMs?: number, dependencies?: ServiceProcessDependencies): SupervisorStatus;
|
|
18
4
|
//# sourceMappingURL=status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/status.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/status.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAKvB,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,SAAa,EAClB,YAAY,GAAE,0BAA+B,GAC5C,gBAAgB,CA4BlB"}
|
|
@@ -1,45 +1,13 @@
|
|
|
1
|
-
import { existsSync
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { verifyProcessGeneration, } from "../agents/state/proc-start.js";
|
|
5
|
-
import { currentHarneryRuntimeBuild, harneryPackageRoot } from "../events/v3/runtime-build.js";
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { observeServiceProcess, } from "../agents/state/service-process.js";
|
|
3
|
+
import { serviceBuildStatus } from "../events/v3/runtime-build.js";
|
|
6
4
|
import { SUPERVISOR_STATUS_SCHEMA_VERSION, } from "./contract.js";
|
|
7
5
|
import { readSupervisorServiceRecord, supervisorPaths } from "./storage.js";
|
|
8
6
|
const STALE_HEARTBEAT_MS = 15_000;
|
|
9
|
-
export function installedSupervisorBuild() {
|
|
10
|
-
let version = "unknown";
|
|
11
|
-
let revision = "unknown";
|
|
12
|
-
try {
|
|
13
|
-
const pkg = JSON.parse(readFileSync(join(harneryPackageRoot(), "package.json"), "utf8"));
|
|
14
|
-
if (typeof pkg.version === "string")
|
|
15
|
-
version = pkg.version;
|
|
16
|
-
revision = currentHarneryRuntimeBuild();
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
// Missing build evidence must still produce an inspectable status.
|
|
20
|
-
}
|
|
21
|
-
return { version, revision };
|
|
22
|
-
}
|
|
23
7
|
export function readSupervisorStatus(coordRoot, nowMs = Date.now(), dependencies = {}) {
|
|
24
8
|
const paths = supervisorPaths(coordRoot);
|
|
25
9
|
const record = readSupervisorServiceRecord(coordRoot);
|
|
26
|
-
const
|
|
27
|
-
const runningBuild = validBuild(record?.running_build) ? record.running_build : null;
|
|
28
|
-
const restartNeeded = !runningBuild ||
|
|
29
|
-
installedBuild.version === "unknown" ||
|
|
30
|
-
installedBuild.revision === "unknown" ||
|
|
31
|
-
runningBuild.version !== installedBuild.version ||
|
|
32
|
-
runningBuild.revision !== installedBuild.revision;
|
|
33
|
-
const build = {
|
|
34
|
-
running_build: runningBuild,
|
|
35
|
-
installed_build: installedBuild,
|
|
36
|
-
restart_needed: restartNeeded,
|
|
37
|
-
build_status: !runningBuild
|
|
38
|
-
? "running build unknown; restart needed"
|
|
39
|
-
: restartNeeded
|
|
40
|
-
? "restart needed"
|
|
41
|
-
: "current",
|
|
42
|
-
};
|
|
10
|
+
const build = serviceBuildStatus(record?.running_build);
|
|
43
11
|
if (!validRecord(record)) {
|
|
44
12
|
return {
|
|
45
13
|
running: false,
|
|
@@ -53,12 +21,11 @@ export function readSupervisorStatus(coordRoot, nowMs = Date.now(), dependencies
|
|
|
53
21
|
}
|
|
54
22
|
const heartbeatAt = Date.parse(record.heartbeat_at);
|
|
55
23
|
const stale = !Number.isFinite(heartbeatAt) || nowMs - heartbeatAt > STALE_HEARTBEAT_MS;
|
|
56
|
-
const
|
|
57
|
-
const liveness = owner.generation === "same" && record.state === "stopped" ? "stopped" : owner.liveness;
|
|
24
|
+
const { generation, liveness } = observeServiceProcess(record, dependencies);
|
|
58
25
|
return {
|
|
59
|
-
running: liveness === "running" && !stale
|
|
26
|
+
running: liveness === "running" && !stale,
|
|
60
27
|
stale,
|
|
61
|
-
generation
|
|
28
|
+
generation,
|
|
62
29
|
liveness,
|
|
63
30
|
...build,
|
|
64
31
|
record,
|
|
@@ -74,33 +41,3 @@ function validRecord(value) {
|
|
|
74
41
|
typeof value.heartbeat_at === "string" &&
|
|
75
42
|
typeof value.keep_alive === "boolean");
|
|
76
43
|
}
|
|
77
|
-
/** A stale heartbeat does not prove that a process has exited. */
|
|
78
|
-
export function supervisorProcessLiveness(owner, dependencies = {}) {
|
|
79
|
-
if (owner.host !== hostname())
|
|
80
|
-
return { liveness: "unknown", generation: "unknown" };
|
|
81
|
-
try {
|
|
82
|
-
(dependencies.probePid ?? ((pid) => process.kill(pid, 0)))(owner.pid);
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
return {
|
|
86
|
-
liveness: error.code === "ESRCH" ? "stopped" : "unknown",
|
|
87
|
-
generation: "unknown",
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
const generation = verifyProcessGeneration(owner.pid, owner.start_token, dependencies.readToken);
|
|
91
|
-
return {
|
|
92
|
-
generation,
|
|
93
|
-
liveness: generation === "same" ? "running" : generation === "different" ? "stopped" : "unknown",
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
function validBuild(value) {
|
|
97
|
-
if (!value || typeof value !== "object")
|
|
98
|
-
return false;
|
|
99
|
-
const build = value;
|
|
100
|
-
return (typeof build.version === "string" &&
|
|
101
|
-
!!build.version &&
|
|
102
|
-
build.version !== "unknown" &&
|
|
103
|
-
typeof build.revision === "string" &&
|
|
104
|
-
!!build.revision &&
|
|
105
|
-
build.revision !== "unknown");
|
|
106
|
-
}
|
package/dist/core/work/state.js
CHANGED
|
@@ -6,7 +6,7 @@ import { appendSegmentedJsonlFile, readSegmentedJsonlFileSync, } from "../storag
|
|
|
6
6
|
import { stateDirMode, stateFileMode } from "../storage/modes.js";
|
|
7
7
|
import { readWorkflowApproval } from "../workflow/approvals.js";
|
|
8
8
|
import { stableDigest } from "../workflow/durable-record.js";
|
|
9
|
-
import {
|
|
9
|
+
import { readWorkflowProof } from "../workflow/proof.js";
|
|
10
10
|
import { readWorkflowRunManifest, workflowScriptDigest } from "../workflow/run-state.js";
|
|
11
11
|
import { WORKFLOW_TRANSCRIPT_EVENT_BYTES, workflowTranscriptPath } from "../workflow/transcript.js";
|
|
12
12
|
import { isWorkspaceBoundExecutionEvidence } from "../workflow/workspaces/validate.js";
|
|
@@ -464,13 +464,13 @@ function inspectAttempt(coordRoot, event, intent, priorRunId) {
|
|
|
464
464
|
proof.acceptance.summary.unknown === 0
|
|
465
465
|
? "succeeded"
|
|
466
466
|
: "failed";
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
//
|
|
467
|
+
// A failed attempt the run classified as uninformative about the work is
|
|
468
|
+
// uncharged (ADR 0046). Absent class ⇒ charged, as before. Read only for a
|
|
469
|
+
// failed attempt: a succeeded run never carries a class.
|
|
470
470
|
if (attempt.status === "failed" &&
|
|
471
|
-
(proof.run.class === "
|
|
472
|
-
|
|
473
|
-
|
|
471
|
+
(proof.run.class === "environment" ||
|
|
472
|
+
proof.run.class === "upstream" ||
|
|
473
|
+
proof.run.class === "decision")) {
|
|
474
474
|
attempt.uncharged = proof.run.class;
|
|
475
475
|
if (proof.run.class === "decision" && typeof proof.run.decision_id === "string") {
|
|
476
476
|
attempt.blocked_on = proof.run.decision_id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAiDH,OAAO,KAAK,EAIV,UAAU,EAGV,SAAS,EAeV,MAAM,YAAY,CAAC;AAuDpB,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM/E;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEpB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;CAOvF;AAED;;;;6EAI6E;AAC7E,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAEjB,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAUhD;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CA6E1F"}
|