harnery 0.45.1 → 0.46.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/dist/commander.d.ts +13 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commands/admission.d.ts.map +1 -1
- package/dist/commands/admission.js +214 -27
- package/dist/commands/agents.d.ts +4 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +102 -25
- package/dist/commands/browse.d.ts +3 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +172 -8
- package/dist/commands/fetch.js +1 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +8 -2
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +40 -0
- package/dist/commands/qa-run.d.ts.map +1 -1
- package/dist/commands/qa-run.js +4 -3
- package/dist/commands/review-pack.d.ts.map +1 -1
- package/dist/commands/review-pack.js +33 -6
- 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/index.d.ts +1 -0
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +1 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +11 -4
- package/dist/core/agents/render/session-context.d.ts +0 -6
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +1 -6
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +12 -4
- package/dist/core/agents/state/heartbeat-reader.d.ts +3 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.d.ts +3 -1
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +6 -2
- package/dist/core/agents/state/parent-reference-contract.d.ts +16 -0
- package/dist/core/agents/state/parent-reference-contract.d.ts.map +1 -0
- package/dist/core/agents/state/parent-reference-contract.js +1 -0
- package/dist/core/agents/state/parent-reference.d.ts +18 -0
- package/dist/core/agents/state/parent-reference.d.ts.map +1 -0
- package/dist/core/agents/state/parent-reference.js +119 -0
- package/dist/core/agents/state/pidmap.js +2 -2
- 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/config.d.ts +39 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +63 -0
- 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/diagnostics/path-identity.d.ts +1 -1
- package/dist/core/diagnostics/path-identity.d.ts.map +1 -1
- package/dist/core/diagnostics/path-identity.js +51 -6
- package/dist/core/events/v3/canonical.js +43 -14
- package/dist/core/events/v3/index.d.ts +1 -1
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +1 -1
- package/dist/core/events/v3/producers/recorder.d.ts +34 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +117 -13
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +53 -13
- 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/events/v3/validate.d.ts.map +1 -1
- package/dist/core/events/v3/validate.js +36 -1
- 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/adapter/native-parent.d.ts +23 -0
- package/dist/core/hooks/adapter/native-parent.d.ts.map +1 -0
- package/dist/core/hooks/adapter/native-parent.js +91 -0
- package/dist/core/hooks/cli.js +79 -4
- package/dist/core/hooks/resolve/owner.d.ts +0 -11
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +2 -25
- package/dist/core/hooks/shell-admission.d.ts +84 -0
- package/dist/core/hooks/shell-admission.d.ts.map +1 -0
- package/dist/core/hooks/shell-admission.js +622 -0
- package/dist/core/hooks/shell-commit-tree.d.ts +2 -0
- package/dist/core/hooks/shell-commit-tree.d.ts.map +1 -0
- package/dist/core/hooks/shell-commit-tree.js +104 -0
- package/dist/core/inbox/contract.d.ts +12 -0
- package/dist/core/inbox/contract.d.ts.map +1 -1
- package/dist/core/inbox/contract.js +16 -0
- package/dist/core/inbox/peer-messages.d.ts +41 -16
- package/dist/core/inbox/peer-messages.d.ts.map +1 -1
- package/dist/core/inbox/peer-messages.js +372 -15
- 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 +83 -3
- package/dist/core/inbox/targets.d.ts +17 -3
- package/dist/core/inbox/targets.d.ts.map +1 -1
- package/dist/core/inbox/targets.js +77 -2
- package/dist/core/presence/git.d.ts +18 -12
- package/dist/core/presence/git.d.ts.map +1 -1
- package/dist/core/presence/git.js +32 -38
- package/dist/core/presence/index.d.ts +2 -2
- package/dist/core/presence/index.d.ts.map +1 -1
- package/dist/core/presence/index.js +8 -6
- package/dist/core/presence/mail.d.ts +133 -0
- package/dist/core/presence/mail.d.ts.map +1 -0
- package/dist/core/presence/mail.js +464 -0
- 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/contract.d.ts +5 -5
- 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 +0 -2
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +3 -18
- package/dist/core/storage/modes.d.ts +4 -0
- package/dist/core/storage/modes.d.ts.map +1 -1
- package/dist/core/storage/modes.js +4 -0
- package/dist/core/storage/segments.d.ts.map +1 -1
- package/dist/core/storage/segments.js +5 -4
- 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/workflow/engine.js +2 -1
- 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/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +30 -74
- 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/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/admission-history.d.ts +96 -0
- package/dist/lib/admission-history.d.ts.map +1 -0
- package/dist/lib/admission-history.js +196 -0
- package/dist/lib/admission.d.ts +56 -7
- package/dist/lib/admission.d.ts.map +1 -1
- package/dist/lib/admission.js +161 -19
- package/dist/lib/browser/client.d.ts +18 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +100 -12
- package/dist/lib/browser/content-checks.d.ts +3 -1
- package/dist/lib/browser/content-checks.d.ts.map +1 -1
- package/dist/lib/browser/content-checks.js +10 -2
- package/dist/lib/browser/critique.d.ts +32 -0
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +72 -3
- package/dist/lib/browser/geometry.d.ts +2 -0
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +61 -15
- package/dist/lib/browser/index.d.ts +1 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +1 -1
- package/dist/lib/browser/page-review-contracts.d.ts +6 -1
- package/dist/lib/browser/page-review-contracts.d.ts.map +1 -1
- package/dist/lib/browser/page-review-contracts.js +6 -1
- package/dist/lib/browser/page-review-judge.d.ts +3 -1
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.js +41 -11
- package/dist/lib/browser/page-review-pack.d.ts +3 -0
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
- package/dist/lib/browser/page-review-pack.js +5 -2
- package/dist/lib/browser/qa-run-contracts.d.ts +11 -0
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run-contracts.js +11 -4
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +73 -16
- package/dist/lib/browser/runts.d.ts +4 -2
- package/dist/lib/browser/runts.d.ts.map +1 -1
- package/dist/lib/browser/runts.js +84 -33
- package/dist/lib/browser/windows-chrome.d.ts +14 -0
- package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
- package/dist/lib/browser/windows-chrome.js +42 -0
- package/dist/lib/browser/windows-login-sync.d.ts +110 -0
- package/dist/lib/browser/windows-login-sync.d.ts.map +1 -0
- package/dist/lib/browser/windows-login-sync.js +171 -0
- package/dist/lib/cookies/client.d.ts +30 -5
- package/dist/lib/cookies/client.d.ts.map +1 -1
- package/dist/lib/cookies/client.js +55 -10
- package/dist/lib/cookies/index.d.ts +1 -1
- package/dist/lib/cookies/index.d.ts.map +1 -1
- package/dist/lib/cookies/index.js +1 -1
- package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
- package/dist/lib/docs-metadata-sync.js +41 -2
- package/dist/lib/durable-job.d.ts +8 -0
- package/dist/lib/durable-job.d.ts.map +1 -1
- package/dist/lib/durable-job.js +10 -0
- package/dist/lib/http/client.d.ts +9 -8
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +44 -2
- package/dist/lib/instructions/templates.js +4 -4
- package/package.json +2 -2
- package/src/commander.ts +13 -0
- package/src/commands/admission.ts +272 -29
- package/src/commands/agents.ts +132 -27
- package/src/commands/browse.ts +208 -6
- package/src/commands/fetch.ts +1 -0
- package/src/commands/ledger-v3.ts +8 -2
- package/src/commands/presence.ts +49 -0
- package/src/commands/qa-run.ts +4 -3
- package/src/commands/review-pack.ts +41 -5
- package/src/commands/workflow.ts +8 -58
- package/src/core/agents/coord-client.ts +0 -20
- package/src/core/agents/index.ts +6 -0
- package/src/core/agents/live-authority-v3.ts +11 -4
- package/src/core/agents/render/session-context.ts +1 -7
- package/src/core/agents/session-events.ts +18 -3
- package/src/core/agents/state/heartbeat-reader.ts +3 -0
- package/src/core/agents/state/live-coordination-view.ts +13 -6
- package/src/core/agents/state/parent-reference-contract.ts +14 -0
- package/src/core/agents/state/parent-reference.ts +179 -0
- package/src/core/agents/state/pidmap.ts +2 -2
- package/src/core/agents/state/proc-start.ts +41 -69
- package/src/core/agents/state/service-process.ts +217 -0
- package/src/core/config.ts +85 -0
- package/src/core/context/index.ts +207 -272
- package/src/core/context/observation.ts +40 -9
- package/src/core/diagnostics/path-identity.ts +52 -6
- package/src/core/events/v3/canonical.ts +46 -13
- package/src/core/events/v3/index.ts +3 -0
- package/src/core/events/v3/producers/recorder.ts +151 -13
- package/src/core/events/v3/reader.ts +55 -11
- package/src/core/events/v3/runtime-build.ts +62 -0
- package/src/core/events/v3/validate.ts +42 -1
- 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/adapter/native-parent.ts +109 -0
- package/src/core/hooks/cli.ts +83 -4
- package/src/core/hooks/resolve/owner.ts +2 -25
- package/src/core/hooks/shell-admission.ts +634 -0
- package/src/core/hooks/shell-commit-tree.ts +102 -0
- package/src/core/inbox/contract.ts +18 -0
- package/src/core/inbox/peer-messages.ts +501 -15
- package/src/core/inbox/service.ts +108 -3
- package/src/core/inbox/targets.ts +94 -3
- package/src/core/presence/git.ts +45 -37
- package/src/core/presence/index.ts +16 -8
- package/src/core/presence/mail.ts +620 -0
- 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 +3 -23
- package/src/core/storage/modes.ts +6 -0
- package/src/core/storage/segments.ts +5 -4
- 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/workflow/engine.ts +1 -1
- package/src/core/workflow/index.ts +2 -13
- package/src/core/workflow/proof.ts +35 -83
- package/src/core/workflow/resume-lock.ts +179 -0
- package/src/core/workflow/run-state.ts +3 -207
- 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/admission-history.ts +267 -0
- package/src/lib/admission.ts +217 -19
- package/src/lib/browser/client.ts +147 -35
- package/src/lib/browser/content-checks.ts +14 -3
- package/src/lib/browser/critique.ts +113 -3
- package/src/lib/browser/geometry.ts +63 -14
- package/src/lib/browser/index.ts +5 -0
- package/src/lib/browser/page-review-contracts.ts +6 -1
- package/src/lib/browser/page-review-judge.ts +58 -13
- package/src/lib/browser/page-review-pack.ts +13 -2
- package/src/lib/browser/qa-run-contracts.ts +30 -4
- package/src/lib/browser/qa-run.ts +78 -17
- package/src/lib/browser/runts.ts +85 -37
- package/src/lib/browser/windows-chrome.ts +50 -0
- package/src/lib/browser/windows-login-sync.ts +275 -0
- package/src/lib/cookies/client.ts +62 -10
- package/src/lib/cookies/index.ts +3 -0
- package/src/lib/docs-metadata-sync.ts +44 -2
- package/src/lib/durable-job.ts +15 -0
- package/src/lib/http/client.ts +63 -1
- package/src/lib/instructions/templates.ts +4 -4
- 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/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/core/agents/state/process-handle.ts +0 -165
- package/src/core/workflow/recovery-audit.ts +0 -181
|
@@ -15,9 +15,9 @@ import {
|
|
|
15
15
|
cleanEventV3Archives,
|
|
16
16
|
initializeEventLedgerV3,
|
|
17
17
|
inventoryEventV3Archives,
|
|
18
|
-
listHookProducerStateRecordsV3,
|
|
19
18
|
readEventV3ControlState,
|
|
20
19
|
recoverInvalidEventLedgerV3,
|
|
20
|
+
scanHookProducerStateRecordsV3,
|
|
21
21
|
sha256V3,
|
|
22
22
|
} from "../core/events/v3/index.ts";
|
|
23
23
|
import type { EventV3SupportClassificationEvidence } from "../core/events/v3/support-storage/index.ts";
|
|
@@ -61,7 +61,8 @@ export function registerLedgerV3Command(
|
|
|
61
61
|
try {
|
|
62
62
|
const root = resolve(options.root ?? coordRoot(context));
|
|
63
63
|
const control = readEventV3ControlState(root);
|
|
64
|
-
const
|
|
64
|
+
const scan = scanHookProducerStateRecordsV3(root, { includeTerminal: true });
|
|
65
|
+
const producers = scan.records;
|
|
65
66
|
const counts = producers.reduce<Record<string, number>>((summary, record) => {
|
|
66
67
|
summary[record.state.adapter] = (summary[record.state.adapter] ?? 0) + 1;
|
|
67
68
|
return summary;
|
|
@@ -72,6 +73,11 @@ export function registerLedgerV3Command(
|
|
|
72
73
|
adapters: Object.keys(counts).sort(),
|
|
73
74
|
producer_states: producers.length,
|
|
74
75
|
producer_states_by_adapter: counts,
|
|
76
|
+
invalid_producer_states: scan.invalid.map((file) => ({
|
|
77
|
+
adapter: file.adapter,
|
|
78
|
+
session_hash: file.session_hash,
|
|
79
|
+
reason: file.reason,
|
|
80
|
+
})),
|
|
75
81
|
},
|
|
76
82
|
});
|
|
77
83
|
} catch (error) {
|
package/src/commands/presence.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
resolveOwner,
|
|
9
9
|
} from "../core/agents/index.ts";
|
|
10
10
|
import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-view.ts";
|
|
11
|
+
import { peerInbox } from "../core/inbox/peer-messages.ts";
|
|
11
12
|
import {
|
|
12
13
|
fetchPresence,
|
|
13
14
|
publishPresence,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
relayDaemonStatus,
|
|
16
17
|
runRelayDaemon,
|
|
17
18
|
} from "../core/presence/index.ts";
|
|
19
|
+
import { importMail, mailStatus, publishMail } from "../core/presence/mail.ts";
|
|
18
20
|
import {
|
|
19
21
|
ageSeconds,
|
|
20
22
|
applyDetection,
|
|
@@ -134,6 +136,53 @@ export function registerPresenceCommand(program: Command, emit: EmitContext): vo
|
|
|
134
136
|
emit.data(r);
|
|
135
137
|
});
|
|
136
138
|
|
|
139
|
+
cmd
|
|
140
|
+
.command("mail")
|
|
141
|
+
.description(
|
|
142
|
+
"Show cross-machine peer messages (ADR 0222): this machine's unacknowledged outbox, " +
|
|
143
|
+
"acknowledgements it is publishing, and delivered/expired counts. --sync fetches, " +
|
|
144
|
+
"imports, and publishes first (synchronous; errors report).",
|
|
145
|
+
)
|
|
146
|
+
.option(
|
|
147
|
+
"--sync",
|
|
148
|
+
"Fetch peers' refs, import mail addressed here, and publish this machine's ref",
|
|
149
|
+
)
|
|
150
|
+
.option("--json", "JSON output")
|
|
151
|
+
.action((opts: { sync?: boolean; json?: boolean }) => {
|
|
152
|
+
const root = requireRoot(emit);
|
|
153
|
+
let sync: Record<string, unknown> | undefined;
|
|
154
|
+
if (opts.sync) {
|
|
155
|
+
const fetched = fetchPresence(root, { force: true, sync: true });
|
|
156
|
+
if (fetched.status === "error") {
|
|
157
|
+
emit.error({ code: "fetch_failed", message: fetched.error });
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
const imported = importMail(root, peerInbox(root), { publish: false });
|
|
161
|
+
const published = publishMail(root, { sync: true });
|
|
162
|
+
if (published.status === "error") {
|
|
163
|
+
emit.error({ code: "publish_failed", message: published.error });
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
sync = { imported, published };
|
|
167
|
+
}
|
|
168
|
+
const status = mailStatus(root);
|
|
169
|
+
if (opts.json) emit.config({ format: "json" });
|
|
170
|
+
if (opts.json || !process.stdout.isTTY) {
|
|
171
|
+
emit.data({ ...status, ...(sync ? { sync } : {}) });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
emit.text(
|
|
175
|
+
`${status.machine}: ${status.outbox.length} waiting for acknowledgement, ` +
|
|
176
|
+
`${status.acks} acknowledgements published, ${status.delivered} delivered, ` +
|
|
177
|
+
`${status.expired} expired\n`,
|
|
178
|
+
);
|
|
179
|
+
for (const m of status.outbox) {
|
|
180
|
+
emit.text(
|
|
181
|
+
` ${m.message_id} to agent-${m.recipient} on ${m.to_machine} (queued ${m.queued_at})\n`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
137
186
|
cmd
|
|
138
187
|
.command("relay-daemon")
|
|
139
188
|
.description(
|
package/src/commands/qa-run.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
resolveQaRepoRoot,
|
|
18
18
|
} from "../core/qa-artifacts.ts";
|
|
19
19
|
import { acquireAdmission, admissionBaseDir, admissionStatus } from "../lib/admission.ts";
|
|
20
|
+
import { PAGE_REVIEW_MAX_TILE_BUDGET } from "../lib/browser/page-review-contracts.ts";
|
|
20
21
|
import {
|
|
21
22
|
deleteExpiredPacks,
|
|
22
23
|
PAGE_REVIEW_DEFAULT_RETENTION_MINUTES,
|
|
@@ -99,7 +100,7 @@ export function registerQaRunCommand(
|
|
|
99
100
|
)
|
|
100
101
|
.option(
|
|
101
102
|
"--tile-budget <n>",
|
|
102
|
-
|
|
103
|
+
`Maximum native tiles across the complete review pack (8-${PAGE_REVIEW_MAX_TILE_BUDGET}; default 96).`,
|
|
103
104
|
)
|
|
104
105
|
.option(
|
|
105
106
|
"--accept-dispositions",
|
|
@@ -224,10 +225,10 @@ export function registerQaRunCommand(
|
|
|
224
225
|
const policy = { ...validation.job.policy };
|
|
225
226
|
if (opts.tileBudget !== undefined) {
|
|
226
227
|
const n = Number(opts.tileBudget);
|
|
227
|
-
if (!Number.isInteger(n) || n < 8 || n >
|
|
228
|
+
if (!Number.isInteger(n) || n < 8 || n > PAGE_REVIEW_MAX_TILE_BUDGET) {
|
|
228
229
|
emit.error({
|
|
229
230
|
code: "qa_run_invalid_tile_budget",
|
|
230
|
-
message:
|
|
231
|
+
message: `--tile-budget must be an integer between 8 and ${PAGE_REVIEW_MAX_TILE_BUDGET}`,
|
|
231
232
|
});
|
|
232
233
|
process.exitCode = 1;
|
|
233
234
|
return;
|
|
@@ -14,7 +14,8 @@ import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-
|
|
|
14
14
|
import { artifactsRoot } from "../core/artifacts/index.ts";
|
|
15
15
|
import { resolveBinName, reviewPackAutoCleanEnabled } from "../core/config.ts";
|
|
16
16
|
import { createManagedQaOutParent, resolveQaRepoRoot } from "../core/qa-artifacts.ts";
|
|
17
|
-
import { DEFAULT_CRITIQUE_RUBRIC } from "../lib/browser/critique.ts";
|
|
17
|
+
import { DEFAULT_CRITIQUE_RUBRIC, formatCritiqueUsage } from "../lib/browser/critique.ts";
|
|
18
|
+
import { PAGE_REVIEW_MAX_TILE_BUDGET } from "../lib/browser/page-review-contracts.ts";
|
|
18
19
|
import { persistPackReviewDecisions } from "../lib/browser/page-review-evidence.ts";
|
|
19
20
|
import { judgePageReviewPack, toCritiqueRecords } from "../lib/browser/page-review-judge.ts";
|
|
20
21
|
import {
|
|
@@ -382,7 +383,9 @@ export function registerReviewPackCommand(
|
|
|
382
383
|
)
|
|
383
384
|
.option(
|
|
384
385
|
"--max-tiles <n>",
|
|
385
|
-
"Native tile cap per context, including required top and bottom bands."
|
|
386
|
+
"Native tile cap per context, including required top and bottom bands (default 24). " +
|
|
387
|
+
`The whole pack never exceeds ${PAGE_REVIEW_MAX_TILE_BUDGET} tiles, so the cap is ` +
|
|
388
|
+
"lowered when the contexts would need more.",
|
|
386
389
|
)
|
|
387
390
|
.option("--concurrency <n>", "Concurrent capture browsers (1-8; default 2).", "2")
|
|
388
391
|
.option("--timeout <ms>", "Per-capture timeout in milliseconds (default 120000).", "120000")
|
|
@@ -411,6 +414,31 @@ export function registerReviewPackCommand(
|
|
|
411
414
|
process.exitCode = 1;
|
|
412
415
|
return;
|
|
413
416
|
}
|
|
417
|
+
const requestedMaxTiles = Number(opts.maxTiles ?? "24");
|
|
418
|
+
if (
|
|
419
|
+
!Number.isInteger(requestedMaxTiles) ||
|
|
420
|
+
requestedMaxTiles < 1 ||
|
|
421
|
+
requestedMaxTiles > PAGE_REVIEW_MAX_TILE_BUDGET
|
|
422
|
+
) {
|
|
423
|
+
emit.error({
|
|
424
|
+
code: "review_pack_invalid_max_tiles",
|
|
425
|
+
message: `--max-tiles must be an integer between 1 and ${PAGE_REVIEW_MAX_TILE_BUDGET}`,
|
|
426
|
+
});
|
|
427
|
+
process.exitCode = 1;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
// The judge refuses a pack above the ceiling, so share it across contexts here.
|
|
431
|
+
const perContextMaxTiles = Math.max(
|
|
432
|
+
2,
|
|
433
|
+
Math.min(requestedMaxTiles, Math.floor(PAGE_REVIEW_MAX_TILE_BUDGET / contexts.length)),
|
|
434
|
+
);
|
|
435
|
+
if (perContextMaxTiles < requestedMaxTiles) {
|
|
436
|
+
emit.log(
|
|
437
|
+
`review-pack: ${contexts.length} contexts share the ${PAGE_REVIEW_MAX_TILE_BUDGET}-tile ceiling; ` +
|
|
438
|
+
`capping each at ${perContextMaxTiles} tiles`,
|
|
439
|
+
"warn",
|
|
440
|
+
);
|
|
441
|
+
}
|
|
414
442
|
const concurrency = Math.max(
|
|
415
443
|
1,
|
|
416
444
|
Math.min(8, Number.parseInt(opts.concurrency ?? "2", 10) || 2),
|
|
@@ -472,7 +500,8 @@ export function registerReviewPackCommand(
|
|
|
472
500
|
"--qa-state",
|
|
473
501
|
ctx.state,
|
|
474
502
|
...(opts.scope ?? []).flatMap((selector) => ["--review-pack-scope", selector]),
|
|
475
|
-
|
|
503
|
+
"--check-critique-max-tiles",
|
|
504
|
+
String(perContextMaxTiles),
|
|
476
505
|
];
|
|
477
506
|
emit.log(`capture ${ctx.id}`, "info");
|
|
478
507
|
const res = await defaultQaRunExec(argv, { timeoutMs, env });
|
|
@@ -641,7 +670,12 @@ export function registerReviewPackCommand(
|
|
|
641
670
|
else process.env[QA_RUN_HEADLESS_ONLY_ENV] = prior;
|
|
642
671
|
|
|
643
672
|
const merged = new Map((manifest.critique ?? []).map((row) => [row.context_id, row]));
|
|
644
|
-
for (const row of toCritiqueRecords(result))
|
|
673
|
+
for (const row of toCritiqueRecords(result)) {
|
|
674
|
+
// Re-judging never changes the captured coverage, so a signoff's
|
|
675
|
+
// sampled acceptance (ADR 0224) still applies.
|
|
676
|
+
const prior = merged.get(row.context_id)?.coverage_mode;
|
|
677
|
+
merged.set(row.context_id, prior ? { ...row, coverage_mode: prior } : row);
|
|
678
|
+
}
|
|
645
679
|
const judgedRecords = new Map(result.contexts.map((row) => [row.context_id, row.record]));
|
|
646
680
|
finalizePageReviewPack({
|
|
647
681
|
packDir,
|
|
@@ -671,7 +705,9 @@ export function registerReviewPackCommand(
|
|
|
671
705
|
);
|
|
672
706
|
}
|
|
673
707
|
emit.log(
|
|
674
|
-
`judge: ${result.outcome} · pool ${result.pool.concurrency} · ${result.tiles_reviewed} tile(s) in ${result.pool.wall_time_ms}ms
|
|
708
|
+
`judge: ${result.outcome} · pool ${result.pool.concurrency} · ${result.tiles_reviewed} tile(s) in ${result.pool.wall_time_ms}ms` +
|
|
709
|
+
(result.usage ? ` · ${formatCritiqueUsage(result.usage)}` : "") +
|
|
710
|
+
` · ${packPaths(packDir).review}`,
|
|
675
711
|
result.outcome === "pass" ? "info" : "warn",
|
|
676
712
|
);
|
|
677
713
|
if (opts.json) emit.data(result as unknown as Record<string, unknown>);
|
package/src/commands/workflow.ts
CHANGED
|
@@ -73,15 +73,7 @@ interface WorkflowConfirmedMutationOpts {
|
|
|
73
73
|
|
|
74
74
|
interface WorkflowReclaimOpts extends WorkflowConfirmedMutationOpts {
|
|
75
75
|
discard?: boolean;
|
|
76
|
-
|
|
77
|
-
actor?: string;
|
|
78
|
-
reason?: string;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
interface WorkflowUnlockOpts extends WorkflowConfirmedMutationOpts {
|
|
82
|
-
lockSha256?: string;
|
|
83
|
-
actor?: string;
|
|
84
|
-
reason?: string;
|
|
76
|
+
force?: boolean;
|
|
85
77
|
}
|
|
86
78
|
|
|
87
79
|
export function registerWorkflowCommand(program: Command, emit: EmitContext): void {
|
|
@@ -632,11 +624,9 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
632
624
|
.option("--yes", "Confirm that this commits or discards uncommitted work, then releases")
|
|
633
625
|
.option("--discard", "Throw the uncommitted work away instead of salvaging it")
|
|
634
626
|
.option(
|
|
635
|
-
"--
|
|
636
|
-
"
|
|
627
|
+
"--force",
|
|
628
|
+
"With --yes, admit missing or corrupt liveness evidence (active evidence still refuses) and record it",
|
|
637
629
|
)
|
|
638
|
-
.option("--actor <id>", "Actor responsible for an audited recovery")
|
|
639
|
-
.option("--reason <text>", "Reason for an audited recovery")
|
|
640
630
|
.option("--json", "Emit the reclaim preview or confirmed result as JSON")
|
|
641
631
|
.action(async (runId: string, opts: WorkflowReclaimOpts) => {
|
|
642
632
|
const coordRoot = resolveCoordRoot();
|
|
@@ -663,13 +653,7 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
663
653
|
const result = await provider.reclaim(binding, {
|
|
664
654
|
mode: opts.discard ? "discard" : "salvage",
|
|
665
655
|
yes: opts.yes,
|
|
666
|
-
|
|
667
|
-
? {
|
|
668
|
-
evidenceSha256: opts.unknownLiveness,
|
|
669
|
-
actor: opts.actor!,
|
|
670
|
-
reason: opts.reason!,
|
|
671
|
-
}
|
|
672
|
-
: undefined,
|
|
656
|
+
force: opts.force,
|
|
673
657
|
});
|
|
674
658
|
if (opts.json) {
|
|
675
659
|
emit.config({ format: "json" });
|
|
@@ -684,11 +668,13 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
684
668
|
emit.text(
|
|
685
669
|
`reclaim preview: ${result.run_id}\n` +
|
|
686
670
|
`mode: ${result.mode}\nliveness: ${result.liveness}\nownership: ${result.ownership}\n` +
|
|
687
|
-
`evidence sha256: ${result.evidence_sha256}\n` +
|
|
688
671
|
`lease holder: ${holders.length > 0 ? holders.join(", ") : "none observed"}\n` +
|
|
689
672
|
`dirty paths: ${result.dirty_paths === null ? "unknown" : result.dirty_paths.length > 0 ? result.dirty_paths.join(", ") : "none"}\n` +
|
|
690
673
|
(result.ownership_detail ? `ownership detail: ${result.ownership_detail}\n` : "") +
|
|
691
|
-
`Pass --yes to confirm ${result.mode} and release after all checks pass.\n
|
|
674
|
+
`Pass --yes to confirm ${result.mode} and release after all checks pass.\n` +
|
|
675
|
+
(result.liveness === "unknown"
|
|
676
|
+
? "Liveness is unknown; add --force with --yes only if the run is known to be stopped.\n"
|
|
677
|
+
: ""),
|
|
692
678
|
);
|
|
693
679
|
return;
|
|
694
680
|
}
|
|
@@ -708,42 +694,6 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
708
694
|
}
|
|
709
695
|
});
|
|
710
696
|
|
|
711
|
-
workflow
|
|
712
|
-
.command("unlock <run-id>")
|
|
713
|
-
.description(
|
|
714
|
-
"Preview or explicitly retire one exact resume lock whose local owner is proven dead.",
|
|
715
|
-
)
|
|
716
|
-
.option("--lock-sha256 <sha256>", "Exact lock identity digest returned by the preview")
|
|
717
|
-
.option("--actor <id>", "Actor responsible for the recovery")
|
|
718
|
-
.option("--reason <text>", "Reason for the recovery")
|
|
719
|
-
.option("--yes", "Confirm removal after dead-owner and exact-lock checks")
|
|
720
|
-
.option("--json", "Emit the recovery preview or result as JSON")
|
|
721
|
-
.action(async (runId: string, opts: WorkflowUnlockOpts) => {
|
|
722
|
-
try {
|
|
723
|
-
const coordRoot = resolveCoordRoot();
|
|
724
|
-
if (!coordRoot) throw new Error("no .harnery/ coordination root found");
|
|
725
|
-
const { recoverWorkflowResumeLease } = await import("../core/workflow/index.ts");
|
|
726
|
-
const result = recoverWorkflowResumeLease(coordRoot, runId, opts);
|
|
727
|
-
if (opts.json) {
|
|
728
|
-
emit.config({ format: "json" });
|
|
729
|
-
emit.data(result);
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
emit.text(
|
|
733
|
-
`resume lock ${result.action}: ${runId}\nowner: ${result.owner_state}\nlock sha256: ${result.lock_sha256 ?? "absent"}\n` +
|
|
734
|
-
(result.action === "preview"
|
|
735
|
-
? "Pass --lock-sha256, --actor, --reason and --yes to confirm exact dead-owner recovery.\n"
|
|
736
|
-
: `recovery: ${result.recovery_id}\n`),
|
|
737
|
-
);
|
|
738
|
-
} catch (error) {
|
|
739
|
-
emit.error({
|
|
740
|
-
code: "workflow_resume_unlock_failed",
|
|
741
|
-
message: error instanceof Error ? error.message : String(error),
|
|
742
|
-
});
|
|
743
|
-
process.exit(1);
|
|
744
|
-
}
|
|
745
|
-
});
|
|
746
|
-
|
|
747
697
|
const approvals = program
|
|
748
698
|
.command("approval")
|
|
749
699
|
.description("Inspect and resolve durable run-policy approvals.");
|
|
@@ -265,27 +265,7 @@ export function parsePidmapRowStartToken(row: string): string | undefined {
|
|
|
265
265
|
* a test can hold this one against `processStartToken` and fail on drift.
|
|
266
266
|
*/
|
|
267
267
|
export function pidStartToken(pid: number): string | null {
|
|
268
|
-
if (!Number.isInteger(pid) || pid <= 0) return null;
|
|
269
268
|
const forced = process.env.HARNERY_PID_PROBE;
|
|
270
|
-
if (process.platform === "win32" && forced !== "procfs" && forced !== "ps") {
|
|
271
|
-
try {
|
|
272
|
-
const out = spawnSync(
|
|
273
|
-
"powershell.exe",
|
|
274
|
-
[
|
|
275
|
-
"-NoLogo",
|
|
276
|
-
"-NoProfile",
|
|
277
|
-
"-NonInteractive",
|
|
278
|
-
"-Command",
|
|
279
|
-
`$process = [Diagnostics.Process]::GetProcessById(${pid}); try { 'w' + $process.StartTime.ToFileTimeUtc().ToString([Globalization.CultureInfo]::InvariantCulture) } finally { $process.Dispose() }`,
|
|
280
|
-
],
|
|
281
|
-
{ encoding: "utf8", timeout: 10_000, windowsHide: true },
|
|
282
|
-
);
|
|
283
|
-
const token = String(out.stdout ?? "").trim();
|
|
284
|
-
return out.status === 0 && /^w\d+$/.test(token) ? token : null;
|
|
285
|
-
} catch {
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
269
|
const useProcfs = forced === "procfs" || (forced !== "ps" && existsSync("/proc/self/stat"));
|
|
290
270
|
// One machine, one probe. Falling back to the other on a read failure would
|
|
291
271
|
// answer in the wrong dialect and read as a recycled pid.
|
package/src/core/agents/index.ts
CHANGED
|
@@ -11,4 +11,10 @@ export * from "./canonical-emit.js";
|
|
|
11
11
|
export * from "./coord-client.js";
|
|
12
12
|
export * from "./live-observation-v3.js";
|
|
13
13
|
export * from "./session-events.js";
|
|
14
|
+
export {
|
|
15
|
+
type AgentParentReference,
|
|
16
|
+
type AgentParentReferenceOptions,
|
|
17
|
+
type AgentParentSubject,
|
|
18
|
+
resolveAgentParentReference,
|
|
19
|
+
} from "./state/parent-reference.js";
|
|
14
20
|
export * from "./state/session-state.js";
|
|
@@ -25,10 +25,10 @@ import {
|
|
|
25
25
|
} from "../events/v3/producers/coordination-recorder.ts";
|
|
26
26
|
import {
|
|
27
27
|
type HookProducerStateV3,
|
|
28
|
-
listHookProducerStateRecordsV3,
|
|
29
28
|
readHookProducerStateV3,
|
|
30
29
|
readTerminalHookProducerStateV3,
|
|
31
30
|
recordHookSignalV3,
|
|
31
|
+
scanHookProducerStateRecordsV3,
|
|
32
32
|
} from "../events/v3/producers/recorder.ts";
|
|
33
33
|
import { canonicalClaimPath } from "./claim-path.ts";
|
|
34
34
|
import {
|
|
@@ -259,13 +259,20 @@ function readInstanceProducerStatesForBootstrap(
|
|
|
259
259
|
coordRoot: string,
|
|
260
260
|
instanceId: `inst_${string}`,
|
|
261
261
|
): HookProducerStateV3[] {
|
|
262
|
+
let scan: ReturnType<typeof scanHookProducerStateRecordsV3>;
|
|
262
263
|
try {
|
|
263
|
-
|
|
264
|
-
.map((record) => record.state)
|
|
265
|
-
.filter((state) => state.instance_id === instanceId);
|
|
264
|
+
scan = scanHookProducerStateRecordsV3(coordRoot, { includeTerminal: true });
|
|
266
265
|
} catch {
|
|
267
266
|
throw new LiveCoordinationAuthorityV3Error("producer_state_unsafe");
|
|
268
267
|
}
|
|
268
|
+
// Another session's invalid file does not block this one; this instance's
|
|
269
|
+
// own invalid file still fails closed.
|
|
270
|
+
if (scan.invalid.some((file) => file.instance_id === instanceId)) {
|
|
271
|
+
throw new LiveCoordinationAuthorityV3Error("producer_state_unsafe");
|
|
272
|
+
}
|
|
273
|
+
return scan.records
|
|
274
|
+
.map((record) => record.state)
|
|
275
|
+
.filter((state) => state.instance_id === instanceId);
|
|
269
276
|
}
|
|
270
277
|
|
|
271
278
|
function terminalGenerationForSession(
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
|
-
import { existsSync, readdirSync, readFileSync
|
|
11
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { resolveBinName, resolveHooksSetupHint } from "../../config.ts";
|
|
14
14
|
import { harneryVersion, loadAdapterWiring } from "../../hooks/adapter/wiring.ts";
|
|
@@ -482,9 +482,3 @@ export function formatPendingCouncils(coordRoot: string, agentName: string): str
|
|
|
482
482
|
}
|
|
483
483
|
return `Councils waiting on your input (${pending.length} open): ${list}. Run \`${bin} agents council list --mine\` to see all of them, then \`${bin} agents council show <id>\` for any brief.`;
|
|
484
484
|
}
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Suppress unused import warning when statSync isn't used in this file
|
|
488
|
-
* (kept exported for future renderers, e.g. heartbeat-freshness coloring).
|
|
489
|
-
*/
|
|
490
|
-
export const _ensureStatSyncImported = statSync;
|
|
@@ -89,9 +89,20 @@ function commandKey(fields: Record<string, unknown>): string | undefined {
|
|
|
89
89
|
: undefined;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
/**
|
|
93
|
+
* `deferDrain` stages each summary durably in the spool without appending it,
|
|
94
|
+
* for a caller that writes the completion next: that write drains every staged
|
|
95
|
+
* row under one lease and one witness advance instead of one per row.
|
|
96
|
+
*/
|
|
97
|
+
function flushCommandOutput(command: PendingCommand, deferDrain = false): void {
|
|
93
98
|
for (const summary of command.streams.values()) {
|
|
94
|
-
recordCommandObservation(
|
|
99
|
+
recordCommandObservation(
|
|
100
|
+
"command.output_observed",
|
|
101
|
+
command.fields,
|
|
102
|
+
command.coordRoot,
|
|
103
|
+
summary,
|
|
104
|
+
deferDrain,
|
|
105
|
+
);
|
|
95
106
|
}
|
|
96
107
|
command.streams.clear();
|
|
97
108
|
}
|
|
@@ -104,6 +115,7 @@ function recordCommandObservation(
|
|
|
104
115
|
fields: Record<string, unknown>,
|
|
105
116
|
coordRoot: string,
|
|
106
117
|
summary?: OutputSummary,
|
|
118
|
+
deferDrain = false,
|
|
107
119
|
): boolean {
|
|
108
120
|
const instanceId = typeof fields.instance_id === "string" ? fields.instance_id : undefined;
|
|
109
121
|
if (!instanceId) return false;
|
|
@@ -134,6 +146,7 @@ function recordCommandObservation(
|
|
|
134
146
|
platform: livePlatformV3(),
|
|
135
147
|
...(fields.bridge === "codex-wsl" ? { bridge: "codex-wsl" as const } : {}),
|
|
136
148
|
monotonic_ns: process.hrtime.bigint().toString(),
|
|
149
|
+
...(deferDrain ? { writerOptions: { deferDrain: true } } : {}),
|
|
137
150
|
});
|
|
138
151
|
if (result.state === "generation_unavailable") {
|
|
139
152
|
const expectedLifecycleReopenGap =
|
|
@@ -276,7 +289,9 @@ export function writeSessionEvent(
|
|
|
276
289
|
const coordRoot = command?.coordRoot ?? coordinationRootPath();
|
|
277
290
|
if (type === "command.completed") {
|
|
278
291
|
pendingCommands.delete(key);
|
|
279
|
-
|
|
292
|
+
// The completion below drains the staged summaries with itself. If it
|
|
293
|
+
// never writes, the rows stay durable in the spool for the next drain.
|
|
294
|
+
if (command) flushCommandOutput(command, true);
|
|
280
295
|
recordCommandObservation(type, fields, coordRoot);
|
|
281
296
|
} else if (recordCommandObservation(type, fields, coordRoot) && !command) {
|
|
282
297
|
pendingCommands.set(key, {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { dirname, resolve, sep } from "node:path";
|
|
5
|
+
import type { AgentParentReference } from "./parent-reference-contract.ts";
|
|
5
6
|
import type { AgentActivity, TaskState } from "./session-state.ts";
|
|
6
7
|
|
|
7
8
|
export interface Heartbeat {
|
|
@@ -50,6 +51,8 @@ export interface Heartbeat {
|
|
|
50
51
|
last_status_at?: string;
|
|
51
52
|
current_turn_id?: string;
|
|
52
53
|
parent_instance_id?: string;
|
|
54
|
+
/** Read-only display/recipient evidence; never a claim or lifecycle authority input. */
|
|
55
|
+
parent_reference?: AgentParentReference;
|
|
53
56
|
workflow_run_id?: string;
|
|
54
57
|
workflow_agent_id?: string;
|
|
55
58
|
/** Disposable-cache bindings that prove a row belongs to the current V3 generation. */
|
|
@@ -27,6 +27,17 @@ export interface V3HeartbeatMaterialization extends Heartbeat {
|
|
|
27
27
|
v3_task_state: "set" | "cleared";
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/** Index exact generations; a current replacement never erases its terminal predecessor. */
|
|
31
|
+
export function indexCoordinationGenerationsV3(
|
|
32
|
+
view: CoordinationViewV3,
|
|
33
|
+
): ReadonlyMap<string, CoordinationGenerationViewV3> {
|
|
34
|
+
return new Map(
|
|
35
|
+
[...Object.values(view.terminal_generations), ...Object.values(view.instances)].map(
|
|
36
|
+
(generation) => [generation.generation_id, generation],
|
|
37
|
+
),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
/** Read the live coordination rows through the hard-cut ledger route. */
|
|
31
42
|
export function readLiveCoordinationRows(coordRoot: string): V3HeartbeatMaterialization[] {
|
|
32
43
|
const route = observeLiveEventLedgerRouteV3(coordRoot);
|
|
@@ -38,9 +49,7 @@ export function readLiveCoordinationRows(coordRoot: string): V3HeartbeatMaterial
|
|
|
38
49
|
return [];
|
|
39
50
|
}
|
|
40
51
|
const caches = readV3Caches(coordRoot);
|
|
41
|
-
const byGeneration =
|
|
42
|
-
Object.values(view.instances).map((generation) => [generation.generation_id, generation]),
|
|
43
|
-
);
|
|
52
|
+
const byGeneration = indexCoordinationGenerationsV3(view);
|
|
44
53
|
return Object.values(view.instances)
|
|
45
54
|
.filter((generation) => generation.authority_eligible)
|
|
46
55
|
.map((generation) => {
|
|
@@ -70,9 +79,7 @@ export function readLiveCoordinationRow(
|
|
|
70
79
|
if (!generation?.authority_eligible) return null;
|
|
71
80
|
const cache = readHeartbeat(coordRoot, nativeInstanceId);
|
|
72
81
|
const parent = generation.parent_generation_id
|
|
73
|
-
?
|
|
74
|
-
(candidate) => candidate.generation_id === generation.parent_generation_id,
|
|
75
|
-
)
|
|
82
|
+
? indexCoordinationGenerationsV3(view).get(generation.parent_generation_id)
|
|
76
83
|
: undefined;
|
|
77
84
|
return projectHeartbeatV3(
|
|
78
85
|
coordRoot,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type AgentParentReference =
|
|
2
|
+
| {
|
|
3
|
+
state: "verified";
|
|
4
|
+
relationship: "delegated-child" | "native-child";
|
|
5
|
+
parent_instance_id: string;
|
|
6
|
+
parent_v3_instance_id: string;
|
|
7
|
+
parent_generation_id: string | null;
|
|
8
|
+
parent_session_id: string | null;
|
|
9
|
+
parent_name: string | null;
|
|
10
|
+
source: "v3-session-link" | "native-session-metadata";
|
|
11
|
+
source_witness?: string;
|
|
12
|
+
addressable: boolean;
|
|
13
|
+
}
|
|
14
|
+
| { state: "none" | "unknown" | "conflict"; reason: string };
|