pi-daddy 0.22.0 → 0.23.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/CHANGELOG.md +30 -0
- package/contracts/daily-view/v1/README.md +114 -0
- package/contracts/daily-view/v1/fixtures/view.json +525 -0
- package/contracts/daily-view/v1/fixtures/view.txt +75 -0
- package/contracts/daily-view/v1/fixtures/work.jsonl +17 -0
- package/contracts/daily-view/v1/p03/README.md +26 -0
- package/contracts/daily-view/v1/p03/fixtures/retained-executions.json +241 -0
- package/contracts/daily-view/v1/p03/projection.schema.json +194 -0
- package/contracts/daily-view/v1/p03/provenance.json +21 -0
- package/contracts/dashboard-host/v1/README.md +176 -0
- package/contracts/debrief/v1/README.md +146 -0
- package/contracts/debrief/v1/intervention/README.md +32 -0
- package/contracts/debrief/v1/intervention/fixtures/artifact-3ee11136beb864f518252e5024dae9197421fbf97b6e981d3243c782b5c44bd0.txt +1 -0
- package/contracts/debrief/v1/intervention/fixtures/artifact-58905d872dd3c54a9705f67b05fa82edbad7af6476ae8993faf1a7b9fadfb905.txt +1 -0
- package/contracts/debrief/v1/intervention/fixtures/assessment.json +29 -0
- package/contracts/debrief/v1/intervention/fixtures/blind-view.json +20 -0
- package/contracts/debrief/v1/intervention/fixtures/choice.json +7 -0
- package/contracts/debrief/v1/intervention/fixtures/manifest.json +57 -0
- package/contracts/debrief/v1/intervention/fixtures/reveal.json +39 -0
- package/contracts/debrief/v1/provenance.json +89 -0
- package/contracts/debrief/v1/work-capture/README.md +38 -0
- package/contracts/debrief/v1/work-capture/fixtures/batch.json +17 -0
- package/contracts/debrief/v1/work-capture/fixtures/cases.json +184 -0
- package/contracts/debrief/v1/work-capture/fixtures/review.json +184 -0
- package/contracts/debrief/v1/work-capture/review-request.schema.json +41 -0
- package/contracts/debrief/v1/work-capture/work-case.schema.json +190 -0
- package/contracts/debrief/v2/README.md +71 -0
- package/contracts/debrief/v2/input-pin.json +66 -0
- package/contracts/debrief/v2/intervention-upstream.md +40 -0
- package/contracts/debrief/v2/work-signals-upstream.md +22 -0
- package/contracts/dispatch-control/v1/README.md +109 -0
- package/contracts/dispatch-control/v1/request.schema.json +19 -0
- package/contracts/effect-profile/v1/README.md +124 -0
- package/contracts/execution-retention/v1/README.md +109 -0
- package/contracts/execution-retention/v2/README.md +148 -0
- package/contracts/execution-retention/v2/fixtures/interrupted-native-bytes.json +91 -0
- package/contracts/execution-retention/v2/fixtures/missing-native-session.json +91 -0
- package/contracts/execution-retention/v2/fixtures/native-file-unknown-branch.json +91 -0
- package/contracts/execution-retention/v2/fixtures/native-id-without-bytes.json +91 -0
- package/contracts/execution-retention/v2/fixtures/native-live-branch.json +90 -0
- package/contracts/execution-retention/v2/fixtures/replaced-native-session.json +92 -0
- package/contracts/execution-retention/v2/fixtures/result-82c620cdfeb8ca6b858cf653d7f5e2eedca5315d6244216d60e8b36f03223d6a.bin +1 -0
- package/contracts/execution-retention/v2/fixtures/session-2ec1f134bc739984434f7fca689e1c3d1c39fce2dcadae709e9b6faedfcc4ac7.bin +3 -0
- package/contracts/execution-retention/v2/fixtures/session-9bdb4bd16a901da31580acf056bda525225259e15ec409e0410480109011772f.bin +3 -0
- package/contracts/execution-retention/v2/manifest.schema.json +858 -0
- package/contracts/experiment/v1/README.md +164 -0
- package/contracts/factory-order/v1/README.md +151 -0
- package/contracts/factory-order/v1/adoption-pin.json +8 -0
- package/contracts/intent-control/v1/README.md +135 -0
- package/contracts/intent-control/v1/request.schema.json +1096 -0
- package/contracts/intent-control/v2/README.md +34 -0
- package/contracts/intent-control/v2/request.schema.json +1070 -0
- package/contracts/ledger/v4/README.md +241 -0
- package/contracts/ledger/v4/fixtures/layout-options.json +428 -0
- package/contracts/ledger/v4/fixtures/work-acceptance.json +57 -0
- package/contracts/ledger/v4/fixtures/work-occurrence.json +44 -0
- package/contracts/ledger/v4/fixtures/work-revision.json +26 -0
- package/contracts/ledger/v4/fixtures/work-snapshot.json +73 -0
- package/contracts/ledger/v4/ledger-event.schema.json +162 -0
- package/contracts/ordinary-control/v1/README.md +59 -0
- package/contracts/producer-ipc/v1/README.md +137 -0
- package/dist/check-runner.d.ts +5 -0
- package/dist/check-runner.d.ts.map +1 -1
- package/dist/check-runner.js +16 -2
- package/dist/check-runner.js.map +1 -1
- package/dist/control-journal.d.ts +20 -0
- package/dist/control-journal.d.ts.map +1 -0
- package/dist/control-journal.js +73 -0
- package/dist/control-journal.js.map +1 -0
- package/dist/daily-view-input.d.ts +44 -0
- package/dist/daily-view-input.d.ts.map +1 -0
- package/dist/daily-view-input.js +68 -0
- package/dist/daily-view-input.js.map +1 -0
- package/dist/daily-view-render.d.ts +4 -0
- package/dist/daily-view-render.d.ts.map +1 -0
- package/dist/daily-view-render.js +41 -0
- package/dist/daily-view-render.js.map +1 -0
- package/dist/daily-view.d.ts +74 -0
- package/dist/daily-view.d.ts.map +1 -0
- package/dist/daily-view.js +170 -0
- package/dist/daily-view.js.map +1 -0
- package/dist/dashboard-cli.d.ts +26 -1
- package/dist/dashboard-cli.d.ts.map +1 -1
- package/dist/dashboard-cli.js +121 -3
- package/dist/dashboard-cli.js.map +1 -1
- package/dist/dashboard-harness.d.ts +19 -0
- package/dist/dashboard-harness.d.ts.map +1 -0
- package/dist/dashboard-harness.js +75 -0
- package/dist/dashboard-harness.js.map +1 -0
- package/dist/dashboard-herdr.d.ts.map +1 -1
- package/dist/dashboard-herdr.js +7 -2
- package/dist/dashboard-herdr.js.map +1 -1
- package/dist/dashboard-host-contract.d.ts +111 -0
- package/dist/dashboard-host-contract.d.ts.map +1 -0
- package/dist/dashboard-host-contract.js +14 -0
- package/dist/dashboard-host-contract.js.map +1 -0
- package/dist/dashboard-host-transport.d.ts +15 -0
- package/dist/dashboard-host-transport.d.ts.map +1 -0
- package/dist/dashboard-host-transport.js +122 -0
- package/dist/dashboard-host-transport.js.map +1 -0
- package/dist/dashboard-host.d.ts +149 -0
- package/dist/dashboard-host.d.ts.map +1 -0
- package/dist/dashboard-host.js +329 -0
- package/dist/dashboard-host.js.map +1 -0
- package/dist/dashboard-observation.d.ts +28 -0
- package/dist/dashboard-observation.d.ts.map +1 -0
- package/dist/dashboard-observation.js +86 -0
- package/dist/dashboard-observation.js.map +1 -0
- package/dist/debrief-contract.d.ts +65 -0
- package/dist/debrief-contract.d.ts.map +1 -0
- package/dist/debrief-contract.js +151 -0
- package/dist/debrief-contract.js.map +1 -0
- package/dist/debrief-fixture.d.ts +16 -0
- package/dist/debrief-fixture.d.ts.map +1 -0
- package/dist/debrief-fixture.js +41 -0
- package/dist/debrief-fixture.js.map +1 -0
- package/dist/debrief-host.d.ts +59 -0
- package/dist/debrief-host.d.ts.map +1 -0
- package/dist/debrief-host.js +49 -0
- package/dist/debrief-host.js.map +1 -0
- package/dist/debrief-render.d.ts +5 -0
- package/dist/debrief-render.d.ts.map +1 -0
- package/dist/debrief-render.js +65 -0
- package/dist/debrief-render.js.map +1 -0
- package/dist/debrief.d.ts +90 -0
- package/dist/debrief.d.ts.map +1 -0
- package/dist/debrief.js +263 -0
- package/dist/debrief.js.map +1 -0
- package/dist/delegate-types.d.ts +2 -0
- package/dist/delegate-types.d.ts.map +1 -1
- package/dist/delegate-types.js.map +1 -1
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +1 -0
- package/dist/delegate.js.map +1 -1
- package/dist/dispatch-control.d.ts +45 -0
- package/dist/dispatch-control.d.ts.map +1 -0
- package/dist/dispatch-control.js +76 -0
- package/dist/dispatch-control.js.map +1 -0
- package/dist/effect-profile-runtime.d.ts +40 -0
- package/dist/effect-profile-runtime.d.ts.map +1 -0
- package/dist/effect-profile-runtime.js +51 -0
- package/dist/effect-profile-runtime.js.map +1 -0
- package/dist/effect-profile.d.ts +40 -0
- package/dist/effect-profile.d.ts.map +1 -0
- package/dist/effect-profile.js +152 -0
- package/dist/effect-profile.js.map +1 -0
- package/dist/execution-retention.d.ts +90 -0
- package/dist/execution-retention.d.ts.map +1 -0
- package/dist/execution-retention.js +247 -0
- package/dist/execution-retention.js.map +1 -0
- package/dist/experiment-contract.d.ts +56 -0
- package/dist/experiment-contract.d.ts.map +1 -0
- package/dist/experiment-contract.js +80 -0
- package/dist/experiment-contract.js.map +1 -0
- package/dist/experiment-state.d.ts +22 -0
- package/dist/experiment-state.d.ts.map +1 -0
- package/dist/experiment-state.js +79 -0
- package/dist/experiment-state.js.map +1 -0
- package/dist/experiment-store.d.ts +28 -0
- package/dist/experiment-store.d.ts.map +1 -0
- package/dist/experiment-store.js +130 -0
- package/dist/experiment-store.js.map +1 -0
- package/dist/experiment.d.ts +65 -0
- package/dist/experiment.d.ts.map +1 -0
- package/dist/experiment.js +357 -0
- package/dist/experiment.js.map +1 -0
- package/dist/factory-contract.d.ts +79 -0
- package/dist/factory-contract.d.ts.map +1 -0
- package/dist/factory-contract.js +89 -0
- package/dist/factory-contract.js.map +1 -0
- package/dist/factory-migration.d.ts +20 -0
- package/dist/factory-migration.d.ts.map +1 -0
- package/dist/factory-migration.js +55 -0
- package/dist/factory-migration.js.map +1 -0
- package/dist/factory-order.d.ts +848 -0
- package/dist/factory-order.d.ts.map +1 -0
- package/dist/factory-order.js +83 -0
- package/dist/factory-order.js.map +1 -0
- package/dist/factory-registry.d.ts +121 -0
- package/dist/factory-registry.d.ts.map +1 -0
- package/dist/factory-registry.js +133 -0
- package/dist/factory-registry.js.map +1 -0
- package/dist/file-lock.d.ts +8 -2
- package/dist/file-lock.d.ts.map +1 -1
- package/dist/file-lock.js +78 -19
- package/dist/file-lock.js.map +1 -1
- package/dist/herdr-poll.d.ts +8 -0
- package/dist/herdr-poll.d.ts.map +1 -1
- package/dist/herdr-poll.js +23 -0
- package/dist/herdr-poll.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/intent-application.d.ts +17 -0
- package/dist/intent-application.d.ts.map +1 -0
- package/dist/intent-application.js +113 -0
- package/dist/intent-application.js.map +1 -0
- package/dist/intent-control.d.ts +201 -0
- package/dist/intent-control.d.ts.map +1 -0
- package/dist/intent-control.js +110 -0
- package/dist/intent-control.js.map +1 -0
- package/dist/intent-scheduling.d.ts +9 -0
- package/dist/intent-scheduling.d.ts.map +1 -0
- package/dist/intent-scheduling.js +15 -0
- package/dist/intent-scheduling.js.map +1 -0
- package/dist/ledger-append.d.ts +15 -0
- package/dist/ledger-append.d.ts.map +1 -0
- package/dist/ledger-append.js +94 -0
- package/dist/ledger-append.js.map +1 -0
- package/dist/ledger.d.ts +11 -0
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +3 -7
- package/dist/ledger.js.map +1 -1
- package/dist/native-session-target.d.ts +9 -0
- package/dist/native-session-target.d.ts.map +1 -0
- package/dist/native-session-target.js +29 -0
- package/dist/native-session-target.js.map +1 -0
- package/dist/native-session.d.ts +59 -0
- package/dist/native-session.d.ts.map +1 -0
- package/dist/native-session.js +154 -0
- package/dist/native-session.js.map +1 -0
- package/dist/order-schedule.d.ts +37 -0
- package/dist/order-schedule.d.ts.map +1 -0
- package/dist/order-schedule.js +81 -0
- package/dist/order-schedule.js.map +1 -0
- package/dist/ordinary-children.d.ts +52 -0
- package/dist/ordinary-children.d.ts.map +1 -0
- package/dist/ordinary-children.js +93 -0
- package/dist/ordinary-children.js.map +1 -0
- package/dist/producer-ipc-contract.d.ts +29 -0
- package/dist/producer-ipc-contract.d.ts.map +1 -0
- package/dist/producer-ipc-contract.js +29 -0
- package/dist/producer-ipc-contract.js.map +1 -0
- package/dist/producer-ipc.d.ts +55 -0
- package/dist/producer-ipc.d.ts.map +1 -0
- package/dist/producer-ipc.js +143 -0
- package/dist/producer-ipc.js.map +1 -0
- package/dist/resource-budget.d.ts +334 -0
- package/dist/resource-budget.d.ts.map +1 -0
- package/dist/resource-budget.js +415 -0
- package/dist/resource-budget.js.map +1 -0
- package/dist/retention-contract.d.ts +73 -0
- package/dist/retention-contract.d.ts.map +1 -0
- package/dist/retention-contract.js +104 -0
- package/dist/retention-contract.js.map +1 -0
- package/dist/retention-json.d.ts +3 -0
- package/dist/retention-json.d.ts.map +1 -0
- package/dist/retention-json.js +32 -0
- package/dist/retention-json.js.map +1 -0
- package/dist/run-child.d.ts +4 -0
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +16 -2
- package/dist/run-child.js.map +1 -1
- package/dist/run-herdr.d.ts +6 -0
- package/dist/run-herdr.d.ts.map +1 -1
- package/dist/run-herdr.js +19 -6
- package/dist/run-herdr.js.map +1 -1
- package/dist/vendor/adoption.d.ts +129 -0
- package/dist/vendor/adoption.d.ts.map +1 -0
- package/dist/vendor/adoption.js +102 -0
- package/dist/vendor/adoption.js.map +1 -0
- package/dist/work-ledger-destination.d.ts +20 -0
- package/dist/work-ledger-destination.d.ts.map +1 -0
- package/dist/work-ledger-destination.js +131 -0
- package/dist/work-ledger-destination.js.map +1 -0
- package/dist/work-ledger-json.d.ts +25 -0
- package/dist/work-ledger-json.d.ts.map +1 -0
- package/dist/work-ledger-json.js +267 -0
- package/dist/work-ledger-json.js.map +1 -0
- package/dist/work-ledger-occurrences.d.ts +227 -0
- package/dist/work-ledger-occurrences.d.ts.map +1 -0
- package/dist/work-ledger-occurrences.js +115 -0
- package/dist/work-ledger-occurrences.js.map +1 -0
- package/dist/work-ledger-projection.d.ts +295 -0
- package/dist/work-ledger-projection.d.ts.map +1 -0
- package/dist/work-ledger-projection.js +237 -0
- package/dist/work-ledger-projection.js.map +1 -0
- package/dist/work-ledger-snapshot.d.ts +29 -0
- package/dist/work-ledger-snapshot.d.ts.map +1 -0
- package/dist/work-ledger-snapshot.js +267 -0
- package/dist/work-ledger-snapshot.js.map +1 -0
- package/dist/work-ledger-types.d.ts +261 -0
- package/dist/work-ledger-types.d.ts.map +1 -0
- package/dist/work-ledger-types.js +13 -0
- package/dist/work-ledger-types.js.map +1 -0
- package/dist/work-ledger-validation.d.ts +14 -0
- package/dist/work-ledger-validation.d.ts.map +1 -0
- package/dist/work-ledger-validation.js +226 -0
- package/dist/work-ledger-validation.js.map +1 -0
- package/dist/work-ledger.d.ts +43 -0
- package/dist/work-ledger.d.ts.map +1 -0
- package/dist/work-ledger.js +225 -0
- package/dist/work-ledger.js.map +1 -0
- package/extensions/delegate-chain.ts +1 -0
- package/extensions/delegation-native.ts +12 -0
- package/extensions/delegation.ts +4 -3
- package/extensions/execute-child.ts +34 -4
- package/extensions/grants.ts +2 -0
- package/extensions/ordinary-runtime.ts +14 -0
- package/extensions/run-delegation.ts +7 -7
- package/extensions/session.ts +3 -1
- package/package.json +78 -4
- package/src/check-runner.ts +20 -2
- package/src/control-journal.ts +26 -0
- package/src/daily-view-input.ts +59 -0
- package/src/daily-view-render.ts +44 -0
- package/src/daily-view.ts +152 -0
- package/src/dashboard-cli.ts +103 -4
- package/src/dashboard-harness.ts +28 -0
- package/src/dashboard-herdr.ts +7 -2
- package/src/dashboard-host-contract.ts +42 -0
- package/src/dashboard-host-transport.ts +38 -0
- package/src/dashboard-host.ts +168 -0
- package/src/dashboard-observation.ts +44 -0
- package/src/debrief-contract.ts +127 -0
- package/src/debrief-fixture.ts +29 -0
- package/src/debrief-host.ts +53 -0
- package/src/debrief-render.ts +49 -0
- package/src/debrief.ts +198 -0
- package/src/delegate-types.ts +2 -0
- package/src/delegate.ts +1 -0
- package/src/dispatch-control.ts +81 -0
- package/src/effect-profile-runtime.ts +46 -0
- package/src/effect-profile.ts +129 -0
- package/src/execution-retention.ts +230 -0
- package/src/experiment-contract.ts +66 -0
- package/src/experiment-state.ts +44 -0
- package/src/experiment-store.ts +90 -0
- package/src/experiment.ts +231 -0
- package/src/factory-contract.ts +47 -0
- package/src/factory-migration.ts +29 -0
- package/src/factory-order.ts +56 -0
- package/src/factory-registry.ts +60 -0
- package/src/file-lock.ts +47 -11
- package/src/herdr-poll.ts +18 -0
- package/src/index.ts +32 -0
- package/src/intent-application.ts +90 -0
- package/src/intent-control.ts +107 -0
- package/src/intent-scheduling.ts +14 -0
- package/src/ledger-append.ts +72 -0
- package/src/ledger.ts +3 -9
- package/src/native-session-target.ts +23 -0
- package/src/native-session.ts +139 -0
- package/src/order-schedule.ts +42 -0
- package/src/ordinary-children.ts +59 -0
- package/src/producer-ipc-contract.ts +26 -0
- package/src/producer-ipc.ts +107 -0
- package/src/resource-budget.ts +349 -0
- package/src/retention-contract.ts +84 -0
- package/src/retention-json.ts +20 -0
- package/src/run-child.ts +13 -2
- package/src/run-herdr.ts +11 -7
- package/src/vendor/adoption.ts +109 -0
- package/src/work-ledger-destination.ts +113 -0
- package/src/work-ledger-json.ts +228 -0
- package/src/work-ledger-occurrences.ts +99 -0
- package/src/work-ledger-projection.ts +262 -0
- package/src/work-ledger-snapshot.ts +246 -0
- package/src/work-ledger-types.ts +229 -0
- package/src/work-ledger-validation.ts +174 -0
- package/src/work-ledger.ts +186 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
3
|
+
export const DIGEST_PROFILE = "linux-bwrap-digest-v1";
|
|
4
|
+
export const DIGEST_WORKER = `const b=Buffer.from(process.argv[1],'base64');if(b.length>16384)process.exit(90);process.stdout.write(JSON.stringify({bytes:b.length,sha256:require('node:crypto').createHash('sha256').update(b).digest('hex')})+'\\n');`;
|
|
5
|
+
function executableDetails(path, st) {
|
|
6
|
+
return { path, regular: st.isFile(), mode: (st.mode & 0o7777).toString(8), size: st.size,
|
|
7
|
+
predicates: { notRegular: !st.isFile(), writable: (st.mode & 0o022) !== 0, oversize: st.size > 256 * 1024 * 1024 } };
|
|
8
|
+
}
|
|
9
|
+
/** Read-only independent observations; no installation, admission or namespace qualification. */
|
|
10
|
+
export async function inspectDigestPrerequisites() {
|
|
11
|
+
const observations = [];
|
|
12
|
+
for (const requested of [process.execPath, "/usr/bin/bwrap", "/usr/bin/prlimit"]) {
|
|
13
|
+
try {
|
|
14
|
+
const path = requested === process.execPath ? await realpath(requested) : requested;
|
|
15
|
+
const details = executableDetails(path, await lstat(path));
|
|
16
|
+
observations.push({ requested, ...details, conforms: !Object.values(details.predicates).some(Boolean) });
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
observations.push({ requested, conforms: false, error: { code: error.code ?? null, message: String(error) } });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { version: "digest-prerequisites-v1", platform: process.platform, nodeVersion: process.version, execPath: process.execPath,
|
|
23
|
+
conforms: process.platform === "linux" && observations.every(o => o.conforms), observations, qualification: "not-assessed" };
|
|
24
|
+
}
|
|
25
|
+
export async function digestRuntime() {
|
|
26
|
+
if (process.platform !== "linux")
|
|
27
|
+
throw new Error("Linux user/mount/PID/network namespaces required");
|
|
28
|
+
const node = await realpath(process.execPath), fingerprints = {};
|
|
29
|
+
for (const path of [node, "/usr/bin/bwrap", "/usr/bin/prlimit"]) {
|
|
30
|
+
const st = await lstat(path);
|
|
31
|
+
if (!st.isFile() || (st.mode & 0o022) !== 0 || st.size > 256 * 1024 * 1024) {
|
|
32
|
+
const details = executableDetails(path, st), code = details.predicates.notRegular ? "RUNTIME_NOT_REGULAR" : details.predicates.writable ? "RUNTIME_WRITABLE" : "RUNTIME_TOO_LARGE";
|
|
33
|
+
throw Object.assign(new Error("unsupported mutable runtime executable"), { code, path, details });
|
|
34
|
+
}
|
|
35
|
+
fingerprints[path] = createHash("sha256").update(await readFile(path)).digest("hex");
|
|
36
|
+
}
|
|
37
|
+
return Object.freeze({ node, fingerprints: Object.freeze(fingerprints) });
|
|
38
|
+
}
|
|
39
|
+
/** Internal fixed boundary builder. No user command/environment/workspace/destination interface. */
|
|
40
|
+
export function digestNamespaceArgs(runtime, code, args, fixture) {
|
|
41
|
+
return ["--unshare-all", "--die-with-parent", "--new-session", "--cap-drop", "ALL",
|
|
42
|
+
"--ro-bind", "/usr", "/usr", "--ro-bind", "/lib", "/lib", "--ro-bind", "/lib64", "/lib64",
|
|
43
|
+
"--dir", "/runtime", "--ro-bind", runtime.node, "/runtime/node",
|
|
44
|
+
...(fixture ? ["--ro-bind", fixture, "/input"] : []),
|
|
45
|
+
"--proc", "/proc", "--dev", "/dev", "--clearenv", "--chdir", "/", "--",
|
|
46
|
+
"/usr/bin/prlimit", "--cpu=2:2", "--nofile=64:64", "--", "/runtime/node",
|
|
47
|
+
// No arbitrary code enters the production worker. Permission flags are additional tripwires,
|
|
48
|
+
// not a claim that Node's permission model is a hostile-JavaScript sandbox.
|
|
49
|
+
...(fixture ? [] : ["--permission"]), "--max-old-space-size=32", "-e", code, ...args];
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=effect-profile-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-profile-runtime.js","sourceRoot":"","sources":["../src/effect-profile-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type ChildRunResult } from "./run-child.ts";
|
|
2
|
+
import { type AttemptDemand, type GovernedBudgetBinding } from "./resource-budget.ts";
|
|
3
|
+
import { type IntentAdmission } from "./intent-control.ts";
|
|
4
|
+
import { DIGEST_PROFILE } from "./effect-profile-runtime.ts";
|
|
5
|
+
export { DIGEST_PROFILE } from "./effect-profile-runtime.ts";
|
|
6
|
+
export interface DigestProfile {
|
|
7
|
+
readonly profile: typeof DIGEST_PROFILE;
|
|
8
|
+
readonly bindingDigest: string;
|
|
9
|
+
readonly runtimeDigest: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class EffectProfileUnavailableError extends Error {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
export declare const isDigestProfile: (value: unknown) => value is DigestProfile;
|
|
15
|
+
/** Actual bounded native probes, not an executable-presence flag. Trusted fixture code only. */
|
|
16
|
+
export declare function prepareDigestProfile(binding: GovernedBudgetBinding): Promise<Readonly<DigestProfile>>;
|
|
17
|
+
export interface DigestAttempt {
|
|
18
|
+
attempt: Omit<AttemptDemand, "inputBytes" | "inputDigest">;
|
|
19
|
+
bytes: Uint8Array;
|
|
20
|
+
intent?: IntentAdmission;
|
|
21
|
+
}
|
|
22
|
+
/** A fixed, useful non-shell operation: hash at most 16 KiB. No writable destinations or provider calls.
|
|
23
|
+
* The opaque profile is bound to one budget. A claimed profile name/receipt cannot authorize a launch. */
|
|
24
|
+
export declare function runDigestProfile(profile: DigestProfile, request: DigestAttempt, signal?: AbortSignal): Promise<Readonly<{
|
|
25
|
+
attemptId: string;
|
|
26
|
+
output: ChildRunResult;
|
|
27
|
+
digest: string | null;
|
|
28
|
+
}>>;
|
|
29
|
+
export type FixedDigestOperation = "digest" | "hold";
|
|
30
|
+
export interface ReservedDigestRun {
|
|
31
|
+
readonly started: Promise<"spawned" | "settled-without-spawn">;
|
|
32
|
+
run(signal?: AbortSignal): ReturnType<typeof runDigestProfile>;
|
|
33
|
+
}
|
|
34
|
+
/** Atomic all-attempt admission; only minted closures hold the original permits. No caller-supplied permit. */
|
|
35
|
+
export declare function reserveDigestProfileBatch(profile: DigestProfile, requests: readonly {
|
|
36
|
+
attempt: DigestAttempt["attempt"];
|
|
37
|
+
bytes: Uint8Array;
|
|
38
|
+
operation: FixedDigestOperation;
|
|
39
|
+
}[]): Promise<readonly ReservedDigestRun[]>;
|
|
40
|
+
//# sourceMappingURL=effect-profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-profile.d.ts","sourceRoot":"","sources":["../src/effect-profile.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,EAA6C,KAAK,aAAa,EAAuB,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACtJ,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAyE,MAAM,6BAA6B,CAAC;AACpI,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,WAAW,aAAa;IAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,cAAc,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE;AAC1I,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,OAAO,EAAE,MAAM;CAC5B;AAED,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,aAAoG,CAAC;AAU/J,gGAAgG;AAChG,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAqB3G;AAED,MAAM,WAAW,aAAa;IAAG,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,GAAG,aAAa,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE;AAC1I;0GAC0G;AAC1G,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC7H,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAClE,CAAC,CAAC,CAiBF;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,MAAM,CAAC;AACrD,MAAM,WAAW,iBAAiB;IAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,GAAG,uBAAuB,CAAC,CAAC;IAAC,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;CAAE;AACrK,+GAA+G;AAC/G,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS;IAAE,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,oBAAoB,CAAA;CAAE,EAAE,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAoB7N"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdtemp, mkdir, readlink, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { runChild } from "./run-child.js";
|
|
5
|
+
import { runWithFinalizers } from "./finalization.js";
|
|
6
|
+
import { beginExecutionRetention, retentionConfigurationDigest } from "./execution-retention.js";
|
|
7
|
+
import { openResourceBudget, resourceBindingDigest } from "./resource-budget.js";
|
|
8
|
+
import { intentKey } from "./intent-control.js";
|
|
9
|
+
import { DIGEST_PROFILE, DIGEST_WORKER, digestNamespaceArgs, digestRuntime } from "./effect-profile-runtime.js";
|
|
10
|
+
export { DIGEST_PROFILE } from "./effect-profile-runtime.js";
|
|
11
|
+
export class EffectProfileUnavailableError extends Error {
|
|
12
|
+
constructor(message) { super(message); this.name = "EffectProfileUnavailableError"; }
|
|
13
|
+
}
|
|
14
|
+
const profiles = new WeakMap();
|
|
15
|
+
export const isDigestProfile = (value) => typeof value === "object" && value !== null && profiles.has(value);
|
|
16
|
+
const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
17
|
+
function requireClean(result) {
|
|
18
|
+
if (result.code !== 0 || result.spawnError || result.aborted || result.timedOut || result.truncated)
|
|
19
|
+
throw new EffectProfileUnavailableError(`fixed native profile failed: ${result.spawnError ?? result.text ?? result.code}`);
|
|
20
|
+
}
|
|
21
|
+
const child = (runtime, code, args, fixture, signal) => runChild({
|
|
22
|
+
command: "/usr/bin/bwrap", args: digestNamespaceArgs(runtime, code, args, fixture), cwd: "/", env: {},
|
|
23
|
+
timeoutMs: 3000, killGraceMs: 50, hardDeadlineAt: Date.now() + 3500, maxOutputBytes: 4096, signal,
|
|
24
|
+
});
|
|
25
|
+
/** Actual bounded native probes, not an executable-presence flag. Trusted fixture code only. */
|
|
26
|
+
export async function prepareDigestProfile(binding) {
|
|
27
|
+
const budget = openResourceBudget(binding);
|
|
28
|
+
await budget.inspect(); // Required admission state failures remain failures, not an unavailable fallback.
|
|
29
|
+
const runtime = await digestRuntime();
|
|
30
|
+
const root = await mkdtemp(join(budget.binding.directory, "profile-probe-")), input = join(root, "input");
|
|
31
|
+
return runWithFinalizers(async () => {
|
|
32
|
+
await mkdir(input, { mode: 0o700 });
|
|
33
|
+
await writeFile(join(input, "allowed"), "owned-readable", { mode: 0o600 });
|
|
34
|
+
await writeFile(join(root, "outside"), "owned-outside", { mode: 0o600 });
|
|
35
|
+
const net = await readlink("/proc/self/ns/net");
|
|
36
|
+
const code = `const fs=require('node:fs');let failures=0;for(const fn of [()=>fs.readFileSync(${JSON.stringify(join(root, "outside"))}),()=>fs.writeFileSync('/input/denied','bad')]){try{fn()}catch(e){if(['ENOENT','EROFS'].includes(e.code))failures++}}if(failures!==2||fs.readFileSync('/input/allowed','utf8')!=='owned-readable'||fs.readlinkSync('/proc/self/ns/net')===${JSON.stringify(net)})process.exit(91);console.log('boundary-ok');`;
|
|
37
|
+
const boundary = await child(runtime, code, [], input);
|
|
38
|
+
requireClean(boundary);
|
|
39
|
+
if (boundary.text.trim() !== "boundary-ok")
|
|
40
|
+
throw new EffectProfileUnavailableError("native boundary probe did not establish its expected observations");
|
|
41
|
+
const permission = await child(runtime, `try{require('node:child_process').spawnSync('/runtime/node',['-e','process.exit(92)']);process.exit(93)}catch(e){if(e.code!=='ERR_ACCESS_DENIED')process.exit(94);console.log('descendant-denied')}`, []);
|
|
42
|
+
requireClean(permission);
|
|
43
|
+
if (permission.text.trim() !== "descendant-denied")
|
|
44
|
+
throw new EffectProfileUnavailableError("descendant tripwire unavailable");
|
|
45
|
+
const sample = await child(runtime, DIGEST_WORKER, [Buffer.from("fixture").toString("base64")]);
|
|
46
|
+
requireClean(sample);
|
|
47
|
+
if (sample.text !== JSON.stringify({ bytes: 7, sha256: hash("fixture") }) + "\n")
|
|
48
|
+
throw new EffectProfileUnavailableError("fixed worker probe mismatch");
|
|
49
|
+
const result = Object.freeze({ profile: DIGEST_PROFILE, bindingDigest: resourceBindingDigest(budget.binding), runtimeDigest: retentionConfigurationDigest(runtime) });
|
|
50
|
+
profiles.set(result, { runtime, budget });
|
|
51
|
+
return result;
|
|
52
|
+
}, [{ label: "profile probe cleanup failed", run: () => rm(root, { recursive: true, force: true }) }]);
|
|
53
|
+
}
|
|
54
|
+
/** A fixed, useful non-shell operation: hash at most 16 KiB. No writable destinations or provider calls.
|
|
55
|
+
* The opaque profile is bound to one budget. A claimed profile name/receipt cannot authorize a launch. */
|
|
56
|
+
export async function runDigestProfile(profile, request, signal) {
|
|
57
|
+
const prepared = profiles.get(profile);
|
|
58
|
+
if (!prepared || profile.profile !== DIGEST_PROFILE)
|
|
59
|
+
throw new EffectProfileUnavailableError("unsupported or unprobed effect profile; no launch");
|
|
60
|
+
const requestKeys = ["attempt", "bytes", ...(request && Object.hasOwn(request, "intent") ? ["intent"] : [])];
|
|
61
|
+
if (!request || typeof request !== "object" || Reflect.ownKeys(request).length !== requestKeys.length ||
|
|
62
|
+
!requestKeys.every(k => { const d = Object.getOwnPropertyDescriptor(request, k); return d && d.enumerable && Object.hasOwn(d, "value"); }) ||
|
|
63
|
+
!(request.bytes instanceof Uint8Array) || request.bytes.byteLength > 16384)
|
|
64
|
+
throw new TypeError("bounded byte-only request required; no destination, code, money or workspace override");
|
|
65
|
+
const bytes = Buffer.from(request.bytes), inputDigest = hash(bytes);
|
|
66
|
+
const selectedIntent = Object.hasOwn(request, "intent") ? JSON.parse(intentKey(request.intent)) : undefined;
|
|
67
|
+
const descriptors = Object.getOwnPropertyDescriptors(request.attempt);
|
|
68
|
+
const keys = ["attemptId", "orderId", "experimentId", "kind", "parentAttemptId"];
|
|
69
|
+
if (Reflect.ownKeys(request.attempt).length !== keys.length || keys.some(k => !descriptors[k]?.enumerable || !Object.hasOwn(descriptors[k], "value")))
|
|
70
|
+
throw new TypeError("closed attempt identity required");
|
|
71
|
+
const attempt = Object.fromEntries(keys.map(k => [k, descriptors[k].value]));
|
|
72
|
+
if (signal?.aborted)
|
|
73
|
+
throw new EffectProfileUnavailableError("cancelled before reservation/launch");
|
|
74
|
+
if (retentionConfigurationDigest(await digestRuntime()) !== profile.runtimeDigest)
|
|
75
|
+
throw new EffectProfileUnavailableError("runtime changed since the native profile probe");
|
|
76
|
+
const permit = await prepared.budget.reserve({ ...attempt, inputBytes: bytes.length, inputDigest }, selectedIntent);
|
|
77
|
+
return executeReserved(profile, prepared.runtime, attempt, bytes, permit, "digest", signal);
|
|
78
|
+
}
|
|
79
|
+
/** Atomic all-attempt admission; only minted closures hold the original permits. No caller-supplied permit. */
|
|
80
|
+
export async function reserveDigestProfileBatch(profile, requests) {
|
|
81
|
+
const prepared = profiles.get(profile);
|
|
82
|
+
if (!prepared || !Array.isArray(requests) || !requests.length || requests.length > 32 || Reflect.ownKeys(requests).length !== requests.length + 1 || Array.from({ length: requests.length }, (_, i) => Object.getOwnPropertyDescriptor(requests, String(i))).some(d => !d?.enumerable || !Object.hasOwn(d, "value")))
|
|
83
|
+
throw new EffectProfileUnavailableError("probed profile and bounded batch required");
|
|
84
|
+
const detached = requests.map(r => {
|
|
85
|
+
const descriptors = r && Object.getOwnPropertyDescriptors(r);
|
|
86
|
+
if (!descriptors || Reflect.ownKeys(r).length !== 3 || ["attempt", "bytes", "operation"].some(k => !descriptors[k]?.enumerable || !Object.hasOwn(descriptors[k], "value")))
|
|
87
|
+
throw new TypeError("closed data variant required");
|
|
88
|
+
if (!r || !["digest", "hold"].includes(r.operation) || !(r.bytes instanceof Uint8Array) || r.bytes.length > 16384 || Object.keys(r).sort().join() !== "attempt,bytes,operation")
|
|
89
|
+
throw new TypeError("fixed byte-only variant required");
|
|
90
|
+
return { attempt: JSON.parse(intentKey(r.attempt)), bytes: Buffer.from(r.bytes), operation: r.operation };
|
|
91
|
+
});
|
|
92
|
+
if (retentionConfigurationDigest(await digestRuntime()) !== profile.runtimeDigest)
|
|
93
|
+
throw new EffectProfileUnavailableError("runtime changed before batch");
|
|
94
|
+
const permits = await prepared.budget.reserveBatch(detached.map(r => ({ ...r.attempt, inputBytes: r.bytes.length, inputDigest: hash(r.bytes) })));
|
|
95
|
+
return Object.freeze(detached.map((r, i) => {
|
|
96
|
+
let used = false, resolveStarted;
|
|
97
|
+
const started = { promise: new Promise(resolve => { resolveStarted = resolve; }), resolve: (value) => resolveStarted(value) };
|
|
98
|
+
return Object.freeze({ started: started.promise, async run(signal) {
|
|
99
|
+
if (used)
|
|
100
|
+
throw new Error("reserved execution already consumed; no replay");
|
|
101
|
+
used = true;
|
|
102
|
+
try {
|
|
103
|
+
return await executeReserved(profile, prepared.runtime, r.attempt, r.bytes, permits[i], r.operation, signal, () => started.resolve("spawned"));
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
started.resolve("settled-without-spawn");
|
|
107
|
+
} // Settled-without-spawn also unblocks waiters; never a spawn/identity claim.
|
|
108
|
+
} });
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
async function executeReserved(profile, runtime, attempt, bytes, permit, operation, signal, started) {
|
|
112
|
+
const inputDigest = hash(bytes), code = operation === "digest" ? DIGEST_WORKER : "setInterval(()=>{},1000);";
|
|
113
|
+
// From this point every outcome costs the full reservation. No posthoc result refunds resources.
|
|
114
|
+
const retention = beginExecutionRetention({ executionId: attempt.attemptId, parentExecutionId: attempt.parentAttemptId,
|
|
115
|
+
childId: "digest", toolCallId: null, executor: "process", taskDigest: inputDigest, definitionDigest: hash(code),
|
|
116
|
+
configurationDigest: retentionConfigurationDigest({ profile: profile.profile, binding: profile.bindingDigest, runtime: profile.runtimeDigest }), workspaceId: null });
|
|
117
|
+
let output;
|
|
118
|
+
let outcome = "failed";
|
|
119
|
+
let accountingFailed = false, spawned = false, exitObserved = false;
|
|
120
|
+
return runWithFinalizers(async () => {
|
|
121
|
+
if (!signal?.aborted && retentionConfigurationDigest(await digestRuntime()) !== profile.runtimeDigest)
|
|
122
|
+
throw new EffectProfileUnavailableError("runtime changed after admission");
|
|
123
|
+
output = await runChild({ command: "/usr/bin/bwrap", args: digestNamespaceArgs(runtime, code, [bytes.toString("base64")]),
|
|
124
|
+
cwd: "/", env: {}, signal, timeoutMs: 3000, killGraceMs: 50, hardDeadlineAt: Date.now() + 3500, maxOutputBytes: 4096,
|
|
125
|
+
onSpawn: pid => { spawned = true; retention.native({ pid }); started?.(); }, onObservation: (stream, data) => retention.capture(stream, data) });
|
|
126
|
+
exitObserved = output.code !== null || Boolean(output.signal);
|
|
127
|
+
if (spawned && !exitObserved)
|
|
128
|
+
throw new Error("owned executor exit unknown; reservation retained");
|
|
129
|
+
const completed = output.code === 0 && !output.aborted && !output.spawnError && !output.timedOut && !output.truncated;
|
|
130
|
+
if (completed && output.text !== JSON.stringify({ bytes: bytes.length, sha256: inputDigest }) + "\n")
|
|
131
|
+
throw new Error("fixed worker result mismatch");
|
|
132
|
+
outcome = output.aborted && (!spawned || Boolean(output.signal)) ? "cancelled" : completed ? "completed" : "failed";
|
|
133
|
+
retention.capture("result", Buffer.from(output.text), true);
|
|
134
|
+
return Object.freeze({ attemptId: attempt.attemptId, output, digest: completed ? inputDigest : null });
|
|
135
|
+
}, [{ label: "required resource settlement failed", run: async () => {
|
|
136
|
+
// Only this live controller, after executor settlement, releases a slot. Cleanup failure still rejects.
|
|
137
|
+
// Crashes/lost controllers keep their slots; reopening has no expiry, receipt-credit or reclaim API.
|
|
138
|
+
try {
|
|
139
|
+
if (spawned && !exitObserved)
|
|
140
|
+
throw new Error("owned executor exit unknown; no settlement credit");
|
|
141
|
+
await permit.settle(outcome);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
accountingFailed = true;
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
} }, { label: "retention observation failed", run: () => {
|
|
148
|
+
retention.finish({ code: output?.code ?? null, signal: output?.signal ?? null, timedOut: output?.timedOut ?? false,
|
|
149
|
+
aborted: output?.aborted ?? Boolean(signal?.aborted), truncated: output?.truncated ?? false, failed: outcome !== "completed" || accountingFailed });
|
|
150
|
+
} }]);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=effect-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-profile.js","sourceRoot":"","sources":["../src/effect-profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type NativeSessionObservation, type NativeSessionManager } from "./native-session.ts";
|
|
2
|
+
export { buildExecutionRetentionManifest, parseExecutionRetentionManifest, RETENTION_SCHEMA } from "./retention-contract.ts";
|
|
3
|
+
export { ENV_NATIVE_SESSION_ROOT, readNativeSession, parseNativeSessionBytes, type NativeSessionObservation, type NativeSessionManager } from "./native-session.ts";
|
|
4
|
+
/** Operator-owned archive boundary; never a model-facing parameter or an authority source. */
|
|
5
|
+
export declare const ENV_EXECUTION_ARCHIVE = "PI_GRANTS_EXECUTION_ARCHIVE";
|
|
6
|
+
export declare const RETENTION_VERSION = "2.0";
|
|
7
|
+
export interface RetentionIdentity {
|
|
8
|
+
executionId: string;
|
|
9
|
+
parentExecutionId: string | null;
|
|
10
|
+
childId: string;
|
|
11
|
+
toolCallId: string | null;
|
|
12
|
+
executor: "process" | "herdr" | "check";
|
|
13
|
+
taskDigest: string | null;
|
|
14
|
+
definitionDigest: string | null;
|
|
15
|
+
configurationDigest: string;
|
|
16
|
+
workspaceId: string | null;
|
|
17
|
+
}
|
|
18
|
+
export interface RetainedContent {
|
|
19
|
+
status: "retained" | "missing";
|
|
20
|
+
path: string | null;
|
|
21
|
+
sha256: string | null;
|
|
22
|
+
bytes: number | null;
|
|
23
|
+
}
|
|
24
|
+
export interface ExecutionRetentionManifest {
|
|
25
|
+
version: "2.0";
|
|
26
|
+
archiveId: string;
|
|
27
|
+
identity: RetentionIdentity;
|
|
28
|
+
native: {
|
|
29
|
+
pid: number | null;
|
|
30
|
+
paneId: string | null;
|
|
31
|
+
agentName: string | null;
|
|
32
|
+
tabId: string | null;
|
|
33
|
+
sessionId: string | null;
|
|
34
|
+
sessionPath: string | null;
|
|
35
|
+
branchLeafId: string | null;
|
|
36
|
+
};
|
|
37
|
+
nativeSession: NativeSessionObservation;
|
|
38
|
+
state: "running" | "terminal";
|
|
39
|
+
outcome: {
|
|
40
|
+
code: number | null;
|
|
41
|
+
signal: string | null;
|
|
42
|
+
timedOut: boolean;
|
|
43
|
+
aborted: boolean;
|
|
44
|
+
truncated: boolean;
|
|
45
|
+
failed: boolean;
|
|
46
|
+
} | null;
|
|
47
|
+
content: Record<"stdout" | "stderr" | "paneSnapshot" | "checkReceipt" | "result" | "session", RetainedContent>;
|
|
48
|
+
coverage: {
|
|
49
|
+
complete: false;
|
|
50
|
+
losses: string[];
|
|
51
|
+
};
|
|
52
|
+
/** Retention is observation, never a work-v4 acceptance decision. */
|
|
53
|
+
acceptance: "not-assessed";
|
|
54
|
+
}
|
|
55
|
+
export interface RetentionStatus {
|
|
56
|
+
manifestPath: string | null;
|
|
57
|
+
status: "disabled" | "pending" | "retained" | "lost";
|
|
58
|
+
}
|
|
59
|
+
/** Original live status only; drains admitted observations, not producer completeness or fsync. */
|
|
60
|
+
export declare function drainExecutionRetention(status: RetentionStatus): Promise<RetentionStatus>;
|
|
61
|
+
/** Hash only an explicitly selected configuration. Callers must not pass environment/auth objects. */
|
|
62
|
+
export declare const retentionConfigurationDigest: (configuration: unknown) => string;
|
|
63
|
+
/**
|
|
64
|
+
* A bounded, coalescing observation queue. No worker-control path awaits publication. A failed or stalled
|
|
65
|
+
* archive never changes required ledger/lease semantics. `flush` is exclusively for external archival at
|
|
66
|
+
* quiescence; it is NOT called by the spawner. Missing terminal publication means incomplete observation.
|
|
67
|
+
*/
|
|
68
|
+
export declare function beginExecutionRetention(identity: RetentionIdentity, directory?: string | undefined): {
|
|
69
|
+
/** Read-only native API reference; never derive IDs from the locator or a displayed name. */
|
|
70
|
+
observeSession: (reference: NonNullable<{
|
|
71
|
+
source: "herdr-id" | "herdr-path" | "pi-session-file" | "pi-session-manager";
|
|
72
|
+
value: string;
|
|
73
|
+
manager?: NativeSessionManager;
|
|
74
|
+
} | undefined>) => void;
|
|
75
|
+
observeSessionManager(manager: NativeSessionManager): void;
|
|
76
|
+
status: () => RetentionStatus;
|
|
77
|
+
native(value: Partial<Pick<ExecutionRetentionManifest["native"], "pid" | "paneId" | "agentName" | "tabId">>): void;
|
|
78
|
+
capture(kind: "stdout" | "stderr" | "paneSnapshot" | "checkReceipt" | "result", bytes: Uint8Array, replace?: boolean): void;
|
|
79
|
+
finish(outcome: NonNullable<ExecutionRetentionManifest["outcome"]>): void;
|
|
80
|
+
/** Observation-only diagnostic; never establishes successful execution or accepted work. */
|
|
81
|
+
coverage: () => {
|
|
82
|
+
complete: false;
|
|
83
|
+
losses: string[];
|
|
84
|
+
};
|
|
85
|
+
flush: () => Promise<RetentionStatus>;
|
|
86
|
+
};
|
|
87
|
+
export type ExecutionRetention = ReturnType<typeof beginExecutionRetention>;
|
|
88
|
+
/** Public consumer check: neither a reference nor a wire status supplies the missing bytes. */
|
|
89
|
+
export declare function verifyRetainedBytes(reference: RetainedContent, bytes?: Uint8Array): "retained" | "missing" | "mismatch";
|
|
90
|
+
//# sourceMappingURL=execution-retention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-retention.d.ts","sourceRoot":"","sources":["../src/execution-retention.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, writeFile, rename } from "node:fs/promises";
|
|
3
|
+
import { isAbsolute, join } from "node:path";
|
|
4
|
+
import { buildExecutionRetentionManifest } from "./retention-contract.js";
|
|
5
|
+
import { missingNativeSession, readNativeSession } from "./native-session.js";
|
|
6
|
+
export { buildExecutionRetentionManifest, parseExecutionRetentionManifest, RETENTION_SCHEMA } from "./retention-contract.js";
|
|
7
|
+
export { ENV_NATIVE_SESSION_ROOT, readNativeSession, parseNativeSessionBytes } from "./native-session.js";
|
|
8
|
+
/** Operator-owned archive boundary; never a model-facing parameter or an authority source. */
|
|
9
|
+
export const ENV_EXECUTION_ARCHIVE = "PI_GRANTS_EXECUTION_ARCHIVE";
|
|
10
|
+
export const RETENTION_VERSION = "2.0";
|
|
11
|
+
const LIMIT = 1024 * 1024;
|
|
12
|
+
const MAX_ACTIVE = 32;
|
|
13
|
+
let active = 0;
|
|
14
|
+
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
15
|
+
const drains = new WeakMap();
|
|
16
|
+
/** Original live status only; drains admitted observations, not producer completeness or fsync. */
|
|
17
|
+
export function drainExecutionRetention(status) {
|
|
18
|
+
const drain = drains.get(status);
|
|
19
|
+
if (!drain)
|
|
20
|
+
return Promise.reject(new TypeError("original live retention status required"));
|
|
21
|
+
return drain();
|
|
22
|
+
}
|
|
23
|
+
const missing = () => ({ status: "missing", path: null, sha256: null, bytes: null });
|
|
24
|
+
/** Hash only an explicitly selected configuration. Callers must not pass environment/auth objects. */
|
|
25
|
+
export const retentionConfigurationDigest = (configuration) => digest(JSON.stringify(configuration));
|
|
26
|
+
/**
|
|
27
|
+
* A bounded, coalescing observation queue. No worker-control path awaits publication. A failed or stalled
|
|
28
|
+
* archive never changes required ledger/lease semantics. `flush` is exclusively for external archival at
|
|
29
|
+
* quiescence; it is NOT called by the spawner. Missing terminal publication means incomplete observation.
|
|
30
|
+
*/
|
|
31
|
+
export function beginExecutionRetention(identity, directory = process.env[ENV_EXECUTION_ARCHIVE]) {
|
|
32
|
+
const archiveId = randomUUID();
|
|
33
|
+
const valid = Boolean(directory && isAbsolute(directory) && !directory.split(/[\\/]/).includes(".pi"));
|
|
34
|
+
const admitted = valid && active < MAX_ACTIVE;
|
|
35
|
+
const root = admitted ? join(directory, archiveId) : null;
|
|
36
|
+
const manifestPath = root ? join(root, "manifest.json") : null;
|
|
37
|
+
let status = !directory ? "disabled" : admitted ? "pending" : "lost";
|
|
38
|
+
const manifest = {
|
|
39
|
+
version: RETENTION_VERSION, archiveId, identity: {
|
|
40
|
+
executionId: identity.executionId, parentExecutionId: identity.parentExecutionId, childId: identity.childId,
|
|
41
|
+
toolCallId: identity.toolCallId, executor: identity.executor, taskDigest: identity.taskDigest,
|
|
42
|
+
definitionDigest: identity.definitionDigest, configurationDigest: identity.configurationDigest, workspaceId: identity.workspaceId,
|
|
43
|
+
},
|
|
44
|
+
native: { pid: null, paneId: null, agentName: null, tabId: null, sessionId: null, sessionPath: null, branchLeafId: null },
|
|
45
|
+
nativeSession: missingNativeSession(),
|
|
46
|
+
state: "running", outcome: null,
|
|
47
|
+
content: { stdout: missing(), stderr: missing(), paneSnapshot: missing(), checkReceipt: missing(), result: missing(), session: missing() },
|
|
48
|
+
coverage: { complete: false, losses: ["native-session-content-unavailable", "active-branch-unknown"] },
|
|
49
|
+
acceptance: "not-assessed",
|
|
50
|
+
};
|
|
51
|
+
const buffers = new Map();
|
|
52
|
+
const written = new Set();
|
|
53
|
+
let total = 0;
|
|
54
|
+
let dirty = false;
|
|
55
|
+
let running;
|
|
56
|
+
let finished = false;
|
|
57
|
+
let released = false;
|
|
58
|
+
let nativeTask;
|
|
59
|
+
let nextNative;
|
|
60
|
+
let pinnedSessionId;
|
|
61
|
+
let pinnedFile;
|
|
62
|
+
const loss = (reason) => { if (!manifest.coverage.losses.includes(reason))
|
|
63
|
+
manifest.coverage.losses.push(reason); };
|
|
64
|
+
const release = () => { if (admitted && !released) {
|
|
65
|
+
active--;
|
|
66
|
+
released = true;
|
|
67
|
+
} };
|
|
68
|
+
if (admitted)
|
|
69
|
+
active++;
|
|
70
|
+
else if (directory)
|
|
71
|
+
loss("archive-unavailable-or-capacity-exceeded");
|
|
72
|
+
const publish = async () => {
|
|
73
|
+
try {
|
|
74
|
+
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
75
|
+
while (dirty) {
|
|
76
|
+
dirty = false;
|
|
77
|
+
// Detached checkpoint: asynchronous I/O cannot mix later outcome/content into this generation.
|
|
78
|
+
const checkpoint = JSON.parse(JSON.stringify(manifest));
|
|
79
|
+
const contents = [...buffers];
|
|
80
|
+
for (const [kind, bytes] of contents) {
|
|
81
|
+
const sha256 = digest(bytes);
|
|
82
|
+
const name = `${kind}-${sha256}.bin`;
|
|
83
|
+
if (!written.has(name)) {
|
|
84
|
+
await writeFile(join(root, name), bytes, { flag: "wx", mode: 0o600 });
|
|
85
|
+
written.add(name);
|
|
86
|
+
}
|
|
87
|
+
checkpoint.content[kind] = { status: "retained", path: name, sha256, bytes: bytes.length };
|
|
88
|
+
}
|
|
89
|
+
await writeFile(join(root, "manifest.pending"), JSON.stringify(buildExecutionRetentionManifest(checkpoint)) + "\n", { mode: 0o600 });
|
|
90
|
+
await rename(join(root, "manifest.pending"), manifestPath);
|
|
91
|
+
status = "retained";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
status = "lost";
|
|
96
|
+
loss("archive-write-failed");
|
|
97
|
+
buffers.clear();
|
|
98
|
+
release();
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
running = undefined;
|
|
102
|
+
if (finished && !nativeTask) {
|
|
103
|
+
buffers.clear();
|
|
104
|
+
release();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const schedule = () => {
|
|
109
|
+
if (!admitted || status === "lost" || released)
|
|
110
|
+
return;
|
|
111
|
+
dirty = true;
|
|
112
|
+
status = "pending";
|
|
113
|
+
if (!running)
|
|
114
|
+
running = Promise.resolve().then(publish);
|
|
115
|
+
};
|
|
116
|
+
const observeSession = (reference) => {
|
|
117
|
+
if (finished || !admitted || released || status === "lost")
|
|
118
|
+
return;
|
|
119
|
+
if (nextNative && (nextNative.source !== reference.source || nextNative.value !== reference.value))
|
|
120
|
+
loss("native-session-reference-coalesced");
|
|
121
|
+
nextNative = { source: reference.source, value: reference.value, ...(reference.manager ? { manager: reference.manager } : {}) };
|
|
122
|
+
if (nativeTask)
|
|
123
|
+
return;
|
|
124
|
+
nativeTask = Promise.resolve().then(async () => {
|
|
125
|
+
while (nextNative) {
|
|
126
|
+
const current = nextNative;
|
|
127
|
+
nextNative = undefined;
|
|
128
|
+
const captured = current.source === "herdr-id"
|
|
129
|
+
? { observation: { ...missingNativeSession(), source: current.source, status: "missing",
|
|
130
|
+
sessionId: current.value, reason: "native-session-path-unavailable" } }
|
|
131
|
+
: await readNativeSession({ path: current.value, source: current.source, manager: current.manager, expectedSessionId: pinnedSessionId, expectedFile: pinnedFile });
|
|
132
|
+
if (captured.observation.sessionId && captured.fileIdentity)
|
|
133
|
+
pinnedFile ??= captured.fileIdentity;
|
|
134
|
+
let observation = captured.observation;
|
|
135
|
+
if (pinnedSessionId && observation.sessionId && pinnedSessionId !== observation.sessionId) {
|
|
136
|
+
observation = { ...missingNativeSession(), source: current.source, status: "changed", reason: "native-session-id-changed" };
|
|
137
|
+
}
|
|
138
|
+
if (observation.sessionId)
|
|
139
|
+
pinnedSessionId ??= observation.sessionId;
|
|
140
|
+
manifest.nativeSession = { ...observation };
|
|
141
|
+
manifest.native.sessionId = observation.sessionId;
|
|
142
|
+
manifest.native.sessionPath = observation.sessionPath;
|
|
143
|
+
manifest.native.branchLeafId = observation.branchLeafId;
|
|
144
|
+
buffers.delete("session");
|
|
145
|
+
if (captured.bytes && observation === captured.observation)
|
|
146
|
+
buffers.set("session", captured.bytes);
|
|
147
|
+
if (observation.reason)
|
|
148
|
+
loss(observation.reason);
|
|
149
|
+
schedule();
|
|
150
|
+
}
|
|
151
|
+
}).catch(() => { loss("native-session-observation-failed"); }).finally(() => { nativeTask = undefined; schedule(); });
|
|
152
|
+
};
|
|
153
|
+
const drain = async () => {
|
|
154
|
+
while (nativeTask || running) {
|
|
155
|
+
if (nativeTask)
|
|
156
|
+
await nativeTask;
|
|
157
|
+
if (running)
|
|
158
|
+
await running;
|
|
159
|
+
}
|
|
160
|
+
return { manifestPath, status };
|
|
161
|
+
};
|
|
162
|
+
schedule();
|
|
163
|
+
return {
|
|
164
|
+
/** Read-only native API reference; never derive IDs from the locator or a displayed name. */
|
|
165
|
+
observeSession,
|
|
166
|
+
observeSessionManager(manager) {
|
|
167
|
+
try {
|
|
168
|
+
const value = manager.getSessionFile();
|
|
169
|
+
if (value)
|
|
170
|
+
observeSession({ source: "pi-session-manager", value, manager });
|
|
171
|
+
else {
|
|
172
|
+
loss("native-session-not-persisted");
|
|
173
|
+
schedule();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
loss("native-session-manager-unavailable");
|
|
178
|
+
schedule();
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
status: () => { const value = { manifestPath, status }; drains.set(value, drain); return value; },
|
|
182
|
+
native(value) {
|
|
183
|
+
if (finished)
|
|
184
|
+
return;
|
|
185
|
+
for (const key of ["pid", "paneId", "agentName", "tabId"]) {
|
|
186
|
+
const item = value[key];
|
|
187
|
+
if (key === "pid") {
|
|
188
|
+
if (typeof item === "number" && Number.isSafeInteger(item) && item > 0)
|
|
189
|
+
manifest.native.pid = item;
|
|
190
|
+
}
|
|
191
|
+
else if (typeof item === "string" && item.length <= 4096)
|
|
192
|
+
manifest.native[key] = item;
|
|
193
|
+
}
|
|
194
|
+
schedule();
|
|
195
|
+
},
|
|
196
|
+
capture(kind, bytes, replace = false) {
|
|
197
|
+
if (finished || !admitted || status === "lost")
|
|
198
|
+
return;
|
|
199
|
+
const indivisible = kind === "checkReceipt" || kind === "result";
|
|
200
|
+
if (indivisible)
|
|
201
|
+
replace = true;
|
|
202
|
+
const old = buffers.get(kind) ?? Buffer.alloc(0);
|
|
203
|
+
const available = indivisible ? LIMIT : LIMIT - total + (replace ? old.length : 0);
|
|
204
|
+
// Receipts and assembled results each have reserved capacity and are never partially published.
|
|
205
|
+
if (indivisible && bytes.length > available) {
|
|
206
|
+
loss(`${kind === "checkReceipt" ? "check-receipt" : kind}-not-retained-capacity`);
|
|
207
|
+
schedule();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const kept = Buffer.from(bytes.subarray(0, Math.max(0, available)));
|
|
211
|
+
if (kept.length !== bytes.length)
|
|
212
|
+
loss(`${kind}-observation-dropped`);
|
|
213
|
+
if (kind === "paneSnapshot")
|
|
214
|
+
loss("pane-snapshot-not-full-transcript");
|
|
215
|
+
const next = replace ? kept : Buffer.concat([old, kept]);
|
|
216
|
+
if (!indivisible)
|
|
217
|
+
total += next.length - old.length;
|
|
218
|
+
buffers.set(kind, next);
|
|
219
|
+
schedule();
|
|
220
|
+
},
|
|
221
|
+
finish(outcome) {
|
|
222
|
+
if (finished)
|
|
223
|
+
return;
|
|
224
|
+
manifest.outcome = { code: outcome.code, signal: outcome.signal, timedOut: outcome.timedOut,
|
|
225
|
+
aborted: outcome.aborted, truncated: outcome.truncated, failed: outcome.failed };
|
|
226
|
+
manifest.state = "terminal";
|
|
227
|
+
if (outcome.truncated)
|
|
228
|
+
loss("executor-output-truncated");
|
|
229
|
+
if (outcome.aborted || outcome.timedOut)
|
|
230
|
+
loss("execution-interrupted");
|
|
231
|
+
finished = true;
|
|
232
|
+
schedule();
|
|
233
|
+
},
|
|
234
|
+
/** Observation-only diagnostic; never establishes successful execution or accepted work. */
|
|
235
|
+
coverage: () => ({ complete: false, losses: [...manifest.coverage.losses] }),
|
|
236
|
+
flush: drain,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/** Public consumer check: neither a reference nor a wire status supplies the missing bytes. */
|
|
240
|
+
export function verifyRetainedBytes(reference, bytes) {
|
|
241
|
+
if (reference.status !== "retained" || bytes === undefined)
|
|
242
|
+
return "missing";
|
|
243
|
+
if (reference.bytes !== bytes.byteLength || reference.sha256 !== digest(bytes))
|
|
244
|
+
return "mismatch";
|
|
245
|
+
return "retained";
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=execution-retention.js.map
|