@piagent/platform 1.6.1 → 1.7.1
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 +55 -0
- package/README.md +8 -2
- package/README.vi.md +11 -2
- package/adapters/common/assurance-producers.json +109 -0
- package/adapters/common/structured-assurance-facts.mjs +153 -0
- package/adapters/node-typescript/contract-families.json +2811 -0
- package/adapters/node-typescript/contract-families.md +90 -0
- package/benchmarks/production-v1/grade.mjs +20 -0
- package/benchmarks/production-v1/spend-control.v1.json +3 -3
- package/benchmarks/production-v2/grade.mjs +892 -0
- package/benchmarks/production-v2/project/README.md +7 -0
- package/benchmarks/production-v2/project/config/service.json +4 -0
- package/benchmarks/production-v2/project/data/audit-ledger.jsonl +1 -0
- package/benchmarks/production-v2/project/docs/ops.md +3 -0
- package/benchmarks/production-v2/project/logs/incident.log +2 -0
- package/benchmarks/production-v2/project/package.json +11 -0
- package/benchmarks/production-v2/project/scripts/check.mjs +21 -0
- package/benchmarks/production-v2/project/src/backend/auth.js +3 -0
- package/benchmarks/production-v2/project/src/backend/billing-window.js +4 -0
- package/benchmarks/production-v2/project/src/backend/cache.js +15 -0
- package/benchmarks/production-v2/project/src/backend/invoice.js +4 -0
- package/benchmarks/production-v2/project/src/backend/revocation-cache.js +3 -0
- package/benchmarks/production-v2/project/src/data/csv.js +3 -0
- package/benchmarks/production-v2/project/src/data/dedup.js +5 -0
- package/benchmarks/production-v2/project/src/data/migration.js +9 -0
- package/benchmarks/production-v2/project/src/data/ndjson-stream.js +5 -0
- package/benchmarks/production-v2/project/src/data/versioned-replay.js +8 -0
- package/benchmarks/production-v2/project/src/frontend/chat-events.js +7 -0
- package/benchmarks/production-v2/project/src/frontend/pagination.js +8 -0
- package/benchmarks/production-v2/project/src/frontend/request-lifecycle.js +15 -0
- package/benchmarks/production-v2/project/src/frontend/search-state.js +8 -0
- package/benchmarks/production-v2/project/src/frontend/unicode-search.js +7 -0
- package/benchmarks/production-v2/project/src/fullstack/contract-sync.js +10 -0
- package/benchmarks/production-v2/project/src/platform/args.js +10 -0
- package/benchmarks/production-v2/project/src/platform/config.js +7 -0
- package/benchmarks/production-v2/project/src/platform/workflow-session.js +9 -0
- package/benchmarks/production-v2/project/src/platform/workspace.js +13 -0
- package/benchmarks/production-v2/project/src/reliability/checkpoint.js +5 -0
- package/benchmarks/production-v2/project/src/reliability/expiry.js +5 -0
- package/benchmarks/production-v2/project/src/reliability/retry.js +15 -0
- package/benchmarks/production-v2/project/test/smoke.test.js +21 -0
- package/benchmarks/production-v2/project/vendor/README.md +1 -0
- package/benchmarks/production-v2/prompts/abort-reconnect-supersession.md +11 -0
- package/benchmarks/production-v2/prompts/backend-frontend-contract-sync.md +12 -0
- package/benchmarks/production-v2/prompts/billing-cutoff-clock-skew.md +11 -0
- package/benchmarks/production-v2/prompts/bounded-retry.md +7 -0
- package/benchmarks/production-v2/prompts/chunked-record-boundary.md +9 -0
- package/benchmarks/production-v2/prompts/cli-double-dash.md +7 -0
- package/benchmarks/production-v2/prompts/config-precedence.md +6 -0
- package/benchmarks/production-v2/prompts/destructive-history-refusal.md +3 -0
- package/benchmarks/production-v2/prompts/expiry-boundary.md +7 -0
- package/benchmarks/production-v2/prompts/idempotent-replay-conflict.md +11 -0
- package/benchmarks/production-v2/prompts/incident-diagnosis.md +4 -0
- package/benchmarks/production-v2/prompts/invoice-rounding.md +9 -0
- package/benchmarks/production-v2/prompts/journeys/config-precedence-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/expiry-boundary-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/quoted-csv-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/recover-after-uncertain-send.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/repository-prompt-injection-scout.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/resumable-checkpoint-partial-failure-scout.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/stable-dedup-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/stale-search-response-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/tenant-cache-isolation-scout.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/verify-current-contract.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/workflow-switch-same-session-scout.md +4 -0
- package/benchmarks/production-v2/prompts/pagination-boundary.md +7 -0
- package/benchmarks/production-v2/prompts/protected-env-refusal.md +2 -0
- package/benchmarks/production-v2/prompts/quoted-csv.md +6 -0
- package/benchmarks/production-v2/prompts/reconnect-chat-event-order.md +19 -0
- package/benchmarks/production-v2/prompts/repository-prompt-injection.md +5 -0
- package/benchmarks/production-v2/prompts/resumable-checkpoint-partial-failure.md +11 -0
- package/benchmarks/production-v2/prompts/revoked-session-cache.md +10 -0
- package/benchmarks/production-v2/prompts/schema-migration.md +6 -0
- package/benchmarks/production-v2/prompts/stable-dedup.md +6 -0
- package/benchmarks/production-v2/prompts/stale-search-response.md +6 -0
- package/benchmarks/production-v2/prompts/tenant-cache-isolation.md +6 -0
- package/benchmarks/production-v2/prompts/tenant-role-authorization.md +6 -0
- package/benchmarks/production-v2/prompts/unicode-search.md +6 -0
- package/benchmarks/production-v2/prompts/workflow-switch-same-session.md +30 -0
- package/benchmarks/production-v2/prompts/workspace-order.md +7 -0
- package/benchmarks/production-v2/spend-control.v1.json +115 -0
- package/benchmarks/production-v2/suite.json +1009 -0
- package/benchmarks/production-v2/variant.mjs +169 -0
- package/benchmarks/production-v3/CONTRACT-REVISION-20260922.md +31 -0
- package/benchmarks/production-v3/calibration/corpus.v1.json +63 -0
- package/benchmarks/production-v3/calibration/human-review-rubric.v1.json +36 -0
- package/benchmarks/production-v3/grade.mjs +1017 -0
- package/benchmarks/production-v3/project/README.md +7 -0
- package/benchmarks/production-v3/project/config/service.json +4 -0
- package/benchmarks/production-v3/project/data/audit-ledger.jsonl +1 -0
- package/benchmarks/production-v3/project/docs/ops.md +3 -0
- package/benchmarks/production-v3/project/logs/incident.log +2 -0
- package/benchmarks/production-v3/project/package.json +11 -0
- package/benchmarks/production-v3/project/scripts/check.mjs +21 -0
- package/benchmarks/production-v3/project/src/backend/auth.js +3 -0
- package/benchmarks/production-v3/project/src/backend/billing-window.js +4 -0
- package/benchmarks/production-v3/project/src/backend/cache.js +15 -0
- package/benchmarks/production-v3/project/src/backend/invoice.js +4 -0
- package/benchmarks/production-v3/project/src/backend/revocation-cache.js +12 -0
- package/benchmarks/production-v3/project/src/data/csv.js +3 -0
- package/benchmarks/production-v3/project/src/data/dedup.js +5 -0
- package/benchmarks/production-v3/project/src/data/migration.js +9 -0
- package/benchmarks/production-v3/project/src/data/ndjson-stream.js +5 -0
- package/benchmarks/production-v3/project/src/data/versioned-replay.js +8 -0
- package/benchmarks/production-v3/project/src/frontend/chat-events.js +7 -0
- package/benchmarks/production-v3/project/src/frontend/pagination.js +8 -0
- package/benchmarks/production-v3/project/src/frontend/request-lifecycle.js +23 -0
- package/benchmarks/production-v3/project/src/frontend/search-state.js +8 -0
- package/benchmarks/production-v3/project/src/frontend/unicode-search.js +7 -0
- package/benchmarks/production-v3/project/src/fullstack/contract-sync.js +10 -0
- package/benchmarks/production-v3/project/src/platform/args.js +10 -0
- package/benchmarks/production-v3/project/src/platform/config.js +7 -0
- package/benchmarks/production-v3/project/src/platform/workflow-session.js +9 -0
- package/benchmarks/production-v3/project/src/platform/workspace.js +13 -0
- package/benchmarks/production-v3/project/src/reliability/checkpoint.js +5 -0
- package/benchmarks/production-v3/project/src/reliability/expiry.js +14 -0
- package/benchmarks/production-v3/project/src/reliability/retry.js +15 -0
- package/benchmarks/production-v3/project/test/smoke.test.js +21 -0
- package/benchmarks/production-v3/project/vendor/README.md +1 -0
- package/benchmarks/production-v3/prompts/abort-reconnect-supersession.md +11 -0
- package/benchmarks/production-v3/prompts/backend-frontend-contract-sync.md +20 -0
- package/benchmarks/production-v3/prompts/billing-cutoff-clock-skew.md +11 -0
- package/benchmarks/production-v3/prompts/bounded-retry.md +7 -0
- package/benchmarks/production-v3/prompts/chunked-record-boundary.md +11 -0
- package/benchmarks/production-v3/prompts/cli-double-dash.md +7 -0
- package/benchmarks/production-v3/prompts/config-precedence.md +6 -0
- package/benchmarks/production-v3/prompts/destructive-history-refusal.md +9 -0
- package/benchmarks/production-v3/prompts/expiry-boundary.md +14 -0
- package/benchmarks/production-v3/prompts/idempotent-replay-conflict.md +13 -0
- package/benchmarks/production-v3/prompts/incident-diagnosis.md +4 -0
- package/benchmarks/production-v3/prompts/invoice-rounding.md +9 -0
- package/benchmarks/production-v3/prompts/journeys/config-precedence-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/expiry-boundary-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/quoted-csv-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/recover-after-uncertain-send.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/repository-prompt-injection-scout.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/resumable-checkpoint-partial-failure-scout.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/stable-dedup-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/stale-search-response-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/tenant-cache-isolation-scout.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/verify-current-contract.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/workflow-switch-same-session-scout.md +4 -0
- package/benchmarks/production-v3/prompts/pagination-boundary.md +9 -0
- package/benchmarks/production-v3/prompts/protected-env-refusal.md +8 -0
- package/benchmarks/production-v3/prompts/quoted-csv.md +6 -0
- package/benchmarks/production-v3/prompts/reconnect-chat-event-order.md +20 -0
- package/benchmarks/production-v3/prompts/repository-prompt-injection.md +5 -0
- package/benchmarks/production-v3/prompts/resumable-checkpoint-partial-failure.md +15 -0
- package/benchmarks/production-v3/prompts/revoked-session-cache.md +10 -0
- package/benchmarks/production-v3/prompts/schema-migration.md +6 -0
- package/benchmarks/production-v3/prompts/stable-dedup.md +6 -0
- package/benchmarks/production-v3/prompts/stale-search-response.md +6 -0
- package/benchmarks/production-v3/prompts/tenant-cache-isolation.md +6 -0
- package/benchmarks/production-v3/prompts/tenant-role-authorization.md +6 -0
- package/benchmarks/production-v3/prompts/unicode-search.md +6 -0
- package/benchmarks/production-v3/prompts/workflow-switch-same-session.md +30 -0
- package/benchmarks/production-v3/prompts/workspace-order.md +7 -0
- package/benchmarks/production-v3/public-checks/abort-reconnect-supersession.js +34 -0
- package/benchmarks/production-v3/public-checks/expiry-boundary.js +29 -0
- package/benchmarks/production-v3/public-checks/revoked-session-cache.js +20 -0
- package/benchmarks/production-v3/spend-control.v1.json +121 -0
- package/benchmarks/production-v3/suite.json +1010 -0
- package/benchmarks/production-v3/variant.mjs +178 -0
- package/catalog/capabilities.json +2 -2
- package/docs/benchmark-codex-mcp-metadata-contract-v1.md +159 -0
- package/docs/benchmark-codex-mcp-metadata-contract-v2.md +182 -0
- package/docs/benchmark-codex-mcp-metadata-contract-v3.md +194 -0
- package/docs/benchmark-public-contract-addendum-v2.md +85 -0
- package/docs/benchmark-public-contract-addendum-v3.md +116 -0
- package/docs/command-reference-vietnamese.md +10 -7
- package/docs/context-window-policy.md +3 -3
- package/docs/distribution-standard.md +9 -9
- package/docs/languages.json +2 -2
- package/docs/operator-manual-vietnamese.md +12 -12
- package/docs/piagent-codex-benchmark-recovery-plan.md +1817 -0
- package/docs/piagent-core-evaluation-specs-2026-09-06.json +706 -0
- package/docs/piagent-core-improvement-plan.md +528 -0
- package/docs/piagent-core-offline-implementation-2026-09-06.md +219 -0
- package/docs/piagent-core-plan-checkpoint-2026-09-06.json +69 -0
- package/docs/piagent-core-reasoning-research-2026-09-06.md +225 -0
- package/docs/piagent-core-research-sources-2026-09-06.json +416 -0
- package/docs/piagent-open-session-wait.md +19 -0
- package/docs/piagent-runtime-benchmark-execution-plan.md +685 -0
- package/docs/publishing-for-teams.md +2 -0
- package/docs/quality-benchmark.md +128 -8
- package/docs/quickstart-vietnamese.md +2 -2
- package/docs/release-install-policy.md +32 -9
- package/docs/research/harness-next-evidence-review.md +113 -0
- package/docs/team-onboarding.md +7 -7
- package/docs/third-party-neutrality.md +7 -0
- package/docs/usage-observability.md +1 -1
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/content/en/runtime.html +1 -1
- package/docs-site/content/en/whats-new.html +11 -0
- package/docs-site/content/runtime.html +2 -2
- package/docs-site/content/whats-new.html +11 -0
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +1 -1
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +2 -2
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +12 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +1 -1
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +3 -3
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +12 -1
- package/docs-site/workflows.html +1 -1
- package/evals/architecture-conformance-v1/lane.json +18 -0
- package/evals/architecture-conformance-v1/runner.mjs +77 -0
- package/evals/fixtures/approved-host-contracts.invalid.json +43 -0
- package/evals/fixtures/approved-host-contracts.valid.json +43 -0
- package/evals/fixtures/benchmark-attempt-outcome.invalid.json +42 -0
- package/evals/fixtures/benchmark-attempt-outcome.valid.json +42 -0
- package/evals/fixtures/benchmark-independent-verification-plan.invalid.json +7 -0
- package/evals/fixtures/benchmark-independent-verification-plan.valid.json +21 -0
- package/evals/fixtures/composite-criterion.invalid.json +10 -0
- package/evals/fixtures/composite-criterion.valid.json +33 -0
- package/evals/fixtures/contract-family-library.invalid.json +42 -0
- package/evals/fixtures/contract-family-library.valid.json +41 -0
- package/evals/fixtures/contract-selection-recipe.invalid.json +29 -0
- package/evals/fixtures/contract-selection-recipe.valid.json +29 -0
- package/evals/fixtures/host-contract-plan.invalid.json +42 -0
- package/evals/fixtures/host-contract-plan.valid.json +41 -0
- package/evals/fixtures/scoped-project-verification-receipt-v2.invalid.json +42 -0
- package/evals/fixtures/scoped-project-verification-receipt-v2.valid.json +42 -0
- package/evals/fixtures/scoped-project-verification-receipt-v3.invalid.json +57 -0
- package/evals/fixtures/scoped-project-verification-receipt-v3.valid.json +57 -0
- package/evals/fixtures/scoped-verification-receipt-v1.invalid.json +40 -0
- package/evals/fixtures/scoped-verification-receipt-v1.valid.json +40 -0
- package/evals/fs5-artifact-archive/README.md +32 -0
- package/evals/fs5-artifact-archive/manifest.json +148 -0
- package/evals/fs5-artifact-archive/sha256/1f073f6d42c093a3182685e0e096144c8b3befd87594aeea1af05ce17653860c.txt +380 -0
- package/evals/fs5-artifact-archive/sha256/1ff46984c5ff668647dfad94248cd9dcfb72384a8aa529279345582f90d7486a.txt +331 -0
- package/evals/fs5-artifact-archive/sha256/20a5e1ef1cab3234a888b876b3cec52e702a05bc5ac000b691f94c651beed9ca.txt +800 -0
- package/evals/fs5-artifact-archive/sha256/29bb79e96b047d79056626d747baa0b3a6ca9d4da7ad80b9668c0085e5581706.txt +116 -0
- package/evals/fs5-artifact-archive/sha256/2bcc0cf6c18eee0c080c30e727610b0f10a278f5862855d920ba5797f07a2f2d.txt +252 -0
- package/evals/fs5-artifact-archive/sha256/37ecc65febe2c5947ac9288ad958bc149e0f08c6beda137edb1c660908853832.txt +324 -0
- package/evals/fs5-artifact-archive/sha256/5d937632d2cfff34dbbb781dd367bb78feb64c36d571c36ca15f2cc40c576af8.txt +142 -0
- package/evals/fs5-artifact-archive/sha256/6057c7bf2f40f8e3db7e293f08d745133c05293b75e9f363fb4e2e53bd09a76a.txt +244 -0
- package/evals/fs5-artifact-archive/sha256/62ea354afb6816b148ae9bd95ffb1ee5e29580eb4a22473e1ae19dbb471ec36b.txt +930 -0
- package/evals/fs5-artifact-archive/sha256/8987775b742f3b3650d75cce84e6d58fcdd3dfb835d03dac4c2bfe6d9eea3a2e.txt +903 -0
- package/evals/fs5-artifact-archive/sha256/902e886d0920b66811f54d0d1d933d70f8fab8704813b46d578bee6af1f21eef.txt +942 -0
- package/evals/fs5-artifact-archive/sha256/976a9908adfd765ee7be0655616f39a44fff64824f5e8535d726082e550b02eb.txt +910 -0
- package/evals/fs5-artifact-archive/sha256/9c07bda5bfe7bb7b0959844ccea6790735cc9f154d8d5972e18785148cea6d9a.txt +101 -0
- package/evals/fs5-artifact-archive/sha256/b936a604db87a697bf69581c33d753e26d9e5e2ccce40bf9c9b2070948f49919.txt +931 -0
- package/evals/fs5-artifact-archive/sha256/bf91f69473f48fc3de7c7c55e7ce893ba0511074c4ec930d9f3bcb9615d8e9d5.txt +950 -0
- package/evals/fs5-artifact-archive/sha256/ce4ed1b4a033f2a8cb4632d1336b0867edb3454ce1380f0642c4055149e6ac59.txt +784 -0
- package/evals/fs5-artifact-archive/sha256/db97f444db8ba604512daf0aa26b3fe1e2a120ace2b21d4730db5b18aa0c528f.txt +950 -0
- package/evals/fs5-causal-arm.v1.json +9 -5
- package/evals/fs5-pilot-protocol.v1.json +1 -1
- package/evals/fs5-pilot-protocol.v4.json +4 -4
- package/evals/fs5-pilot-protocol.v5.json +6 -5
- package/evals/harness-next/development-corpus.mjs +106 -0
- package/evals/harness-next/resource-budget-probe.mjs +38 -0
- package/evals/harness-next/run-calibration.mjs +83 -0
- package/evals/harness-next/run-resource-probe.mjs +55 -0
- package/evals/harness-next/selected-development-corpus.mjs +27 -0
- package/evals/harness-next.v1.json +51 -0
- package/evals/long-horizon-v1/README.md +19 -0
- package/evals/long-horizon-v1/runner.mjs +116 -48
- package/evals/long-horizon-v1/worker.mjs +77 -30
- package/evals/private-holdout-v1/CURRENT_BOUNDARY.md +53 -0
- package/evals/private-holdout-v1/README.md +5 -2
- package/evals/private-holdout-v1/public-exposure.v2.json +273 -0
- package/package.json +9 -4
- package/packages/piagent-core/README.md +2 -2
- package/packages/piagent-core/benchmark/benchmark-all-attempt-efficiency.js +55 -0
- package/packages/piagent-core/benchmark/benchmark-artifact-binding.js +49 -0
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +265 -14
- package/packages/piagent-core/benchmark/benchmark-budget-governor.js +271 -0
- package/packages/piagent-core/benchmark/benchmark-campaign.js +592 -0
- package/packages/piagent-core/benchmark/benchmark-candidate.js +8 -3
- package/packages/piagent-core/benchmark/benchmark-checkpoint.js +67 -0
- package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +269 -2
- package/packages/piagent-core/benchmark/benchmark-cli.js +120 -3
- package/packages/piagent-core/benchmark/benchmark-codex-events.js +235 -0
- package/packages/piagent-core/benchmark/benchmark-codex-outcome.js +20 -0
- package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +2 -1
- package/packages/piagent-core/benchmark/benchmark-codex-rollout.js +521 -0
- package/packages/piagent-core/benchmark/benchmark-codex.js +104 -8
- package/packages/piagent-core/benchmark/benchmark-comparison.js +284 -1
- package/packages/piagent-core/benchmark/benchmark-core.js +107 -107
- package/packages/piagent-core/benchmark/benchmark-diagnostic-source-evidence.js +40 -0
- package/packages/piagent-core/benchmark/benchmark-diagnostic-treatment.js +104 -0
- package/packages/piagent-core/benchmark/benchmark-evaluator-v3.js +226 -0
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +23 -1
- package/packages/piagent-core/benchmark/benchmark-forensics.js +63 -50
- package/packages/piagent-core/benchmark/benchmark-goal-assessment.js +193 -0
- package/packages/piagent-core/benchmark/benchmark-goal-report.js +87 -0
- package/packages/piagent-core/benchmark/benchmark-independent-verification-observation.js +64 -0
- package/packages/piagent-core/benchmark/benchmark-matrix-summary.js +141 -0
- package/packages/piagent-core/benchmark/benchmark-matrix.js +1 -0
- package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +62 -0
- package/packages/piagent-core/benchmark/benchmark-pi-home.js +1 -0
- package/packages/piagent-core/benchmark/benchmark-preflight.js +69 -8
- package/packages/piagent-core/benchmark/benchmark-process.js +23 -9
- package/packages/piagent-core/benchmark/benchmark-production-completion.js +84 -0
- package/packages/piagent-core/benchmark/benchmark-production-stage-validation.js +209 -0
- package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +162 -45
- package/packages/piagent-core/benchmark/benchmark-provider-free-owner.js +24 -0
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +378 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.d.ts +2 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +269 -3
- package/packages/piagent-core/benchmark/benchmark-release-claim-controls.js +132 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +79 -4
- package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +280 -10
- package/packages/piagent-core/benchmark/benchmark-runner-policy.js +88 -1
- package/packages/piagent-core/benchmark/benchmark-runtime-identity.js +50 -1
- package/packages/piagent-core/benchmark/benchmark-runtime.js +102 -10
- package/packages/piagent-core/benchmark/benchmark-safety-evidence.js +74 -0
- package/packages/piagent-core/benchmark/benchmark-service-tier.js +189 -0
- package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +144 -128
- package/packages/piagent-core/benchmark/benchmark-suite-identity.js +264 -1
- package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +4 -0
- package/packages/piagent-core/benchmark/benchmark-suite.js +211 -4
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +30 -2
- package/packages/piagent-core/benchmark/benchmark-timing-contract.js +189 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +110 -139
- package/packages/piagent-core/benchmark/benchmark-transport-evidence.js +203 -0
- package/packages/piagent-core/benchmark/benchmark-transport-observation.js +147 -0
- package/packages/piagent-core/benchmark/benchmark-tree-identity.js +2 -1
- package/packages/piagent-core/benchmark/benchmark-usage.js +395 -33
- package/packages/piagent-core/benchmark/benchmark-workflow.js +136 -38
- package/packages/piagent-core/benchmark/fs5-pilot-protocol.js +21 -2
- package/packages/piagent-core/capabilities/runtime-integrity.js +3 -0
- package/packages/piagent-core/extensions/acceptance-api-baseline.js +24 -0
- package/packages/piagent-core/extensions/acceptance-assessment.js +153 -0
- package/packages/piagent-core/extensions/acceptance-authenticated-admission.d.ts +41 -0
- package/packages/piagent-core/extensions/acceptance-authenticated-admission.js +120 -0
- package/packages/piagent-core/extensions/acceptance-behavior-proof.js +264 -70
- package/packages/piagent-core/extensions/acceptance-boundary-binding.js +31 -0
- package/packages/piagent-core/extensions/acceptance-boundary-guidance.js +214 -0
- package/packages/piagent-core/extensions/acceptance-callable-scanner.js +244 -0
- package/packages/piagent-core/extensions/acceptance-clause-group.js +45 -0
- package/packages/piagent-core/extensions/acceptance-composite-contract.js +334 -0
- package/packages/piagent-core/extensions/acceptance-contract-conjunction.js +78 -0
- package/packages/piagent-core/extensions/acceptance-contract-selection.js +161 -0
- package/packages/piagent-core/extensions/acceptance-contract-semantics.js +211 -211
- package/packages/piagent-core/extensions/acceptance-declared-api.js +126 -0
- package/packages/piagent-core/extensions/acceptance-diagnostic-policy.ts +14 -0
- package/packages/piagent-core/extensions/acceptance-document-content.js +73 -0
- package/packages/piagent-core/extensions/acceptance-durable-execution.d.ts +59 -0
- package/packages/piagent-core/extensions/acceptance-durable-execution.js +139 -0
- package/packages/piagent-core/extensions/acceptance-error-classes.js +1 -1
- package/packages/piagent-core/extensions/acceptance-evidence-store.js +223 -0
- package/packages/piagent-core/extensions/acceptance-executable-evidence.js +490 -88
- package/packages/piagent-core/extensions/acceptance-execution-diagnostics.js +34 -0
- package/packages/piagent-core/extensions/acceptance-execution-snapshot.js +174 -0
- package/packages/piagent-core/extensions/acceptance-executor/.dockerignore +21 -0
- package/packages/piagent-core/extensions/acceptance-executor/Dockerfile +5 -0
- package/packages/piagent-core/extensions/acceptance-executor/README.md +103 -0
- package/packages/piagent-core/extensions/acceptance-executor/budget.mjs +54 -0
- package/packages/piagent-core/extensions/acceptance-executor/callback-intrinsics.mjs +126 -0
- package/packages/piagent-core/extensions/acceptance-executor/capabilities.mjs +127 -0
- package/packages/piagent-core/extensions/acceptance-executor/guest.mjs +285 -0
- package/packages/piagent-core/extensions/acceptance-executor/intrinsics.mjs +133 -0
- package/packages/piagent-core/extensions/acceptance-executor/invocation.mjs +39 -0
- package/packages/piagent-core/extensions/acceptance-executor/jobs.mjs +29 -0
- package/packages/piagent-core/extensions/acceptance-executor/module-graph.mjs +70 -0
- package/packages/piagent-core/extensions/acceptance-executor/node-profile.mjs +398 -0
- package/packages/piagent-core/extensions/acceptance-executor/package-lock.json +40 -0
- package/packages/piagent-core/extensions/acceptance-executor/package.json +10 -0
- package/packages/piagent-core/extensions/acceptance-executor/protocol.mjs +248 -0
- package/packages/piagent-core/extensions/acceptance-executor/reference-identity.mjs +61 -0
- package/packages/piagent-core/extensions/acceptance-executor/references.mjs +14 -0
- package/packages/piagent-core/extensions/acceptance-executor/structured-clone.mjs +53 -0
- package/packages/piagent-core/extensions/acceptance-executor/values.mjs +97 -0
- package/packages/piagent-core/extensions/acceptance-executor/worker.mjs +75 -0
- package/packages/piagent-core/extensions/acceptance-expiry-calendar-proof.js +162 -0
- package/packages/piagent-core/extensions/acceptance-expression-parser.js +155 -0
- package/packages/piagent-core/extensions/acceptance-focused-verification.js +40 -0
- package/packages/piagent-core/extensions/acceptance-host-configuration.js +337 -0
- package/packages/piagent-core/extensions/acceptance-identifier-criteria.js +25 -0
- package/packages/piagent-core/extensions/acceptance-independent-contract.js +209 -0
- package/packages/piagent-core/extensions/acceptance-independent-registry.js +106 -0
- package/packages/piagent-core/extensions/acceptance-input-provenance.js +40 -0
- package/packages/piagent-core/extensions/acceptance-integer-domains.js +322 -0
- package/packages/piagent-core/extensions/acceptance-invalid-input-receipt.js +20 -0
- package/packages/piagent-core/extensions/acceptance-invalid-partitions.js +26 -0
- package/packages/piagent-core/extensions/acceptance-invalid-sentinel-proof.js +477 -0
- package/packages/piagent-core/extensions/acceptance-isolated-executor.js +254 -0
- package/packages/piagent-core/extensions/acceptance-lexical-sentinels.js +130 -0
- package/packages/piagent-core/extensions/acceptance-literal-dataflow.js +735 -0
- package/packages/piagent-core/extensions/acceptance-local-binding.js +106 -0
- package/packages/piagent-core/extensions/acceptance-normalizer-evidence.js +719 -0
- package/packages/piagent-core/extensions/acceptance-obligations.js +75 -0
- package/packages/piagent-core/extensions/acceptance-parameter-contract.js +756 -0
- package/packages/piagent-core/extensions/acceptance-precedence-contract.js +572 -0
- package/packages/piagent-core/extensions/acceptance-proof-capability.js +26 -0
- package/packages/piagent-core/extensions/acceptance-receipt.js +139 -152
- package/packages/piagent-core/extensions/acceptance-result-contract-evidence.js +159 -0
- package/packages/piagent-core/extensions/acceptance-source-origin.js +214 -0
- package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +64 -8
- package/packages/piagent-core/extensions/acceptance-tagged-event-evidence.js +685 -0
- package/packages/piagent-core/extensions/acceptance-temporal-contract.js +756 -0
- package/packages/piagent-core/extensions/acceptance-temporal-dataflow-proof.js +618 -0
- package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +20 -2
- package/packages/piagent-core/extensions/acceptance-test-bindings.js +86 -0
- package/packages/piagent-core/extensions/acceptance-tuple-shapes.js +12 -0
- package/packages/piagent-core/extensions/context-engine.js +11 -6
- package/packages/piagent-core/extensions/criterion-context-pack.js +96 -4
- package/packages/piagent-core/extensions/failure-types.ts +2 -2
- package/packages/piagent-core/extensions/guard-types.ts +5 -1
- package/packages/piagent-core/extensions/piagent-guard.ts +197 -155
- package/packages/piagent-core/extensions/readonly-inline-inspection.ts +378 -0
- package/packages/piagent-core/extensions/recovery-decision-validation.ts +92 -0
- package/packages/piagent-core/extensions/shell-write-targets.js +15 -14
- package/packages/piagent-core/extensions/task-contract-view.js +4 -4
- package/packages/piagent-core/extensions/task-digest-migration.js +2 -2
- package/packages/piagent-core/extensions/task-journal.js +48 -3
- package/packages/piagent-core/extensions/task-runtime-audit.js +8 -2
- package/packages/piagent-core/extensions/task-state.js +74 -38
- package/packages/piagent-core/extensions/task-terminal-disposition.js +10 -0
- package/packages/piagent-core/extensions/trajectory-contract.ts +5 -0
- package/packages/piagent-core/extensions/verification-intelligence.js +60 -8
- package/packages/piagent-core/extensions/workflow-catalog.ts +98 -0
- package/packages/piagent-core/extensions/workspace-revision.js +48 -0
- package/packages/piagent-core/extensions/workspace-verification-snapshot.js +13 -0
- package/packages/piagent-core/package.json +3 -3
- package/packages/piagent-core/policies/base-policy.json +1 -0
- package/packages/piagent-core/runtime/context/adaptive-planner.ts +7 -3
- package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +60 -59
- package/packages/piagent-core/runtime/hooks/agent-start-types.ts +48 -0
- package/packages/piagent-core/runtime/hooks/completion-hook.ts +76 -83
- package/packages/piagent-core/runtime/hooks/input-hook.ts +92 -7
- package/packages/piagent-core/runtime/hooks/protected-refusal-completion.ts +86 -0
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +5 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +50 -18
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +53 -20
- package/packages/piagent-core/runtime/hooks/tool-result-metadata.ts +9 -0
- package/packages/piagent-core/runtime/hooks/tool-result-navigation.ts +36 -0
- package/packages/piagent-core/runtime/hooks/tool-result-retrieval.ts +42 -0
- package/packages/piagent-core/runtime/input/chat-images.ts +1 -1
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +1 -1
- package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +2 -2
- package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +49 -8
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +61 -15
- package/packages/piagent-core/runtime/inspection/workspace-file-reader.ts +2 -132
- package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +20 -0
- package/packages/piagent-core/runtime/model/service-tier-runtime.ts +242 -0
- package/packages/piagent-core/runtime/policy/source-worktree-transaction.ts +75 -14
- package/packages/piagent-core/runtime/product/activity-inspector.ts +6 -3
- package/packages/piagent-core/runtime/product/edit-verifier-timing.ts +26 -0
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +12 -7
- package/packages/piagent-core/runtime/product/operator-projections.ts +8 -3
- package/packages/piagent-core/runtime/product/task-usage-hooks.ts +78 -0
- package/packages/piagent-core/runtime/product/task-usage.ts +104 -0
- package/packages/piagent-core/runtime/quality/protected-refusal-handoff.ts +35 -0
- package/packages/piagent-core/runtime/recovery/acceptance-recovery-guidance.ts +21 -0
- package/packages/piagent-core/runtime/recovery/continuation-budget.ts +11 -2
- package/packages/piagent-core/runtime/recovery/diagnostic-delivery.ts +61 -0
- package/packages/piagent-core/runtime/recovery/handoff-projection.ts +192 -57
- package/packages/piagent-core/runtime/recovery/handoff-verifier-binding.ts +24 -0
- package/packages/piagent-core/runtime/recovery/independent-verification-recovery.ts +79 -0
- package/packages/piagent-core/runtime/recovery/recovery-policy.ts +27 -39
- package/packages/piagent-core/runtime/recovery/resume-state.ts +8 -5
- package/packages/piagent-core/runtime/registration/activity-inspector-command.ts +2 -1
- package/packages/piagent-core/runtime/registration/context-commands.ts +12 -8
- package/packages/piagent-core/runtime/registration/operator-catalogs.ts +4 -9
- package/packages/piagent-core/runtime/registration/policy-tools.ts +5 -3
- package/packages/piagent-core/runtime/registration/session-commands.ts +9 -7
- package/packages/piagent-core/runtime/registration/session-wait-tool.ts +54 -0
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +27 -11
- package/packages/piagent-core/runtime/registration/task-start-conditional-mutation.ts +45 -0
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +5 -2
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +23 -23
- package/packages/piagent-core/runtime/registration/workflow-commands.ts +64 -93
- package/packages/piagent-core/runtime/session/completion-signals.ts +23 -0
- package/packages/piagent-core/runtime/session/message-signals.ts +6 -22
- package/packages/piagent-core/runtime/session/retrieval-evidence-runtime.ts +188 -0
- package/packages/piagent-core/runtime/session/runtime-state.ts +29 -35
- package/packages/piagent-core/runtime/session/system-prompt.ts +3 -3
- package/packages/piagent-core/runtime/session/uncertain-send-continuation.ts +231 -0
- package/packages/piagent-core/runtime/session/usage.ts +4 -3
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +6 -6
- package/packages/piagent-core/runtime/tools/phase-tool-runtime.ts +1 -1
- package/packages/piagent-core/runtime/tools/phase-tools.ts +3 -2
- package/packages/piagent-core/runtime/tools/session-wait.ts +42 -0
- package/packages/piagent-core/runtime/tools/tool-groups.ts +10 -3
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +192 -5
- package/packages/piagent-core/runtime/trajectory/trajectory-types.ts +3 -2
- package/packages/piagent-core/runtime/verification/acceptance-api-baseline.js +488 -0
- package/packages/piagent-core/runtime/verification/completion-preparation.ts +22 -0
- package/packages/piagent-core/runtime/verification/composite-completion-finalizer.ts +105 -0
- package/packages/piagent-core/runtime/verification/composite-journal-anchor.ts +181 -0
- package/packages/piagent-core/runtime/verification/composite-runtime-binding.ts +76 -0
- package/packages/piagent-core/runtime/verification/composite-scoped-mediation.ts +318 -0
- package/packages/piagent-core/runtime/verification/composite-session-persistence.ts +175 -0
- package/packages/piagent-core/runtime/verification/composite-task-publication.ts +273 -0
- package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +11 -11
- package/packages/piagent-core/runtime/verification/host-project-verification.ts +71 -0
- package/packages/piagent-core/runtime/verification/independent-acceptance-runtime.ts +500 -0
- package/packages/piagent-core/runtime/verification/runtime-assurance-facts.ts +500 -0
- package/packages/piagent-core/runtime/verification/runtime-contract-runner.ts +107 -0
- package/packages/piagent-core/runtime/verification/shell-verification-snapshots.ts +56 -0
- package/packages/piagent-core/runtime/workflows/change-clarification.ts +61 -0
- package/packages/piagent-core/runtime/workflows/input-routing.ts +21 -14
- package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +44 -7
- package/packages/piagent-core/runtime/workflows/task-followup-policy.ts +163 -0
- package/packages/piagent-core/runtime/workflows/task-intake.ts +221 -242
- package/packages/piagent-core/runtime/workflows/task-repair-intent.ts +67 -0
- package/packages/piagent-core/runtime/workflows/task-scope-resolution.ts +83 -0
- package/packages/piagent-core/runtime/workflows/webui-runtime-command.ts +5 -2
- package/packages/piagent-core/runtime/workflows/webui-workflow.ts +39 -32
- package/packages/piagent-core/runtime/workflows/workflow-follow-up.ts +33 -0
- package/packages/piagent-core/security/workspace-file-reader.ts +132 -0
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-B4XehTCU.js → MarkdownMessage-DGk34zJT.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{index-BV-_03yl.css → index-DVahUVWy.css} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-DiKRmCEP.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +2 -2
- package/packages/piagent-webui/extension/dispatch-user-entry.ts +13 -0
- package/packages/piagent-webui/extension/piagent-webui.ts +10 -2
- package/packages/piagent-webui/extension/review-controller.ts +29 -6
- package/packages/piagent-webui/extension/same-session-bridge.ts +6 -7
- package/packages/piagent-webui/extension/session-stream-adapter.ts +60 -11
- package/packages/piagent-webui/extension/source-mutation-controller.ts +29 -3
- package/packages/piagent-webui/extension/source-open-controller.ts +29 -7
- package/packages/piagent-webui/extension/source-revert-controller.ts +26 -3
- package/packages/piagent-webui/gateway/gateway-events.ts +22 -5
- package/packages/piagent-webui/gateway/gateway-service.ts +7 -2
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +141 -19
- package/packages/piagent-webui/gateway/rpc-ui-context.ts +34 -9
- package/packages/piagent-webui/gateway/runtime-command-controller.ts +46 -6
- package/packages/piagent-webui/gateway/runtime-session-controls.ts +17 -2
- package/packages/piagent-webui/gateway/session-catalog.ts +9 -3
- package/packages/piagent-webui/gateway/session-command-controller.ts +29 -9
- package/packages/piagent-webui/gateway/session-effective-options.ts +2 -9
- package/packages/piagent-webui/gateway/session-inspection-registry.ts +11 -2
- package/packages/piagent-webui/gateway/session-operation-settlement.ts +28 -0
- package/packages/piagent-webui/gateway/session-prompt-dispatch.ts +37 -0
- package/packages/piagent-webui/gateway/session-runtime-close.ts +36 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +183 -6
- package/packages/piagent-webui/gateway/session-runtime-ownership.ts +48 -0
- package/packages/piagent-webui/gateway/session-runtime-state.ts +24 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +114 -114
- package/packages/piagent-webui/server/core-inspection-provider.ts +73 -14
- package/packages/piagent-webui/server/loopback-server.ts +9 -7
- package/packages/piagent-webui/server/terminal-delivery-receipt.ts +144 -0
- package/packages/piagent-webui/server/transcript-projection.ts +65 -12
- package/packages/piagent-webui/shared/message-correlation.ts +25 -0
- package/schemas/approved-host-contracts.schema.json +973 -0
- package/schemas/benchmark-attempt-outcome.schema.json +303 -0
- package/schemas/benchmark-independent-verification-plan.schema.json +34 -0
- package/schemas/composite-criterion.schema.json +788 -0
- package/schemas/contract-family-library.schema.json +28 -0
- package/schemas/contract-selection-recipe.schema.json +31 -0
- package/schemas/failure-evidence.schema.json +2 -2
- package/schemas/helper-request.schema.json +16 -4
- package/schemas/host-contract-plan.schema.json +25 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +16 -2
- package/schemas/piagent-webui/runtime-command-v1.schema.json +26 -3
- package/schemas/piagent-webui/runtime-event-v2.schema.json +32 -1
- package/schemas/piagent-webui/session-live-state-v1.schema.json +2 -0
- package/schemas/piagent-webui/snapshot-v1.schema.json +3 -0
- package/schemas/piagent-webui/source-change-v1.schema.json +12 -0
- package/schemas/piagent-webui/transcript-v1.schema.json +2 -1
- package/schemas/public-contracts/codex-mcp-metadata-v1.schema.json +206 -0
- package/schemas/public-contracts/codex-mcp-metadata-v2.schema.json +228 -0
- package/schemas/public-contracts/codex-mcp-metadata-v3.schema.json +233 -0
- package/schemas/public-contracts/revocation-v1.schema.json +87 -0
- package/schemas/public-contracts/subscription-contract-v1.schema.json +76 -0
- package/schemas/scoped-project-verification-receipt-v2.schema.json +83 -0
- package/schemas/scoped-project-verification-receipt-v3.schema.json +295 -0
- package/schemas/scoped-verification-receipt-v1.schema.json +76 -0
- package/schemas/task-contract.schema.json +30 -0
- package/scripts/approve-independent-verification.mjs +57 -0
- package/scripts/benchmark-arm-observer.mjs +320 -0
- package/scripts/benchmark-budget-ipc.mjs +34 -0
- package/scripts/benchmark-budget-launcher.mjs +91 -0
- package/scripts/benchmark-budget-processes.mjs +133 -0
- package/scripts/benchmark-budget-publication.mjs +228 -0
- package/scripts/benchmark-budget-runtime.mjs +136 -0
- package/scripts/benchmark-candidate-ablation.mjs +265 -0
- package/scripts/benchmark-codex-journey.mjs +406 -0
- package/scripts/benchmark-independent-verification.mjs +628 -0
- package/scripts/benchmark-journey-outcome.mjs +92 -0
- package/scripts/benchmark-production-v3-human-review.mjs +192 -0
- package/scripts/benchmark-public-input-catalog.mjs +158 -0
- package/scripts/benchmark-registered-plan-author.mjs +355 -0
- package/scripts/benchmark-registered-plan-recipe-support.mjs +85 -0
- package/scripts/benchmark-registered-plan-recipes-backend.mjs +165 -0
- package/scripts/benchmark-registered-plan-recipes-data.mjs +164 -0
- package/scripts/benchmark-registered-plan-recipes-platform.mjs +165 -0
- package/scripts/benchmark-runner-completion.mjs +133 -0
- package/scripts/benchmark-runner-configuration.mjs +159 -0
- package/scripts/benchmark-runner-core.mjs +217 -388
- package/scripts/benchmark-runner-finalization.mjs +140 -27
- package/scripts/benchmark-runner-provider-boundary.mjs +44 -0
- package/scripts/benchmark-runner-schedule.mjs +256 -0
- package/scripts/benchmark-runner-support.mjs +136 -4
- package/scripts/benchmark-runner.mjs +95 -18
- package/scripts/benchmark-scoped-broker-custody.mjs +483 -0
- package/scripts/benchmark-scoped-docs-verifier.mjs +203 -0
- package/scripts/benchmark-scoped-frozen-qualification.mjs +676 -0
- package/scripts/benchmark-scoped-pi-router.mjs +196 -0
- package/scripts/benchmark-scoped-project-verification-receipt.mjs +49 -0
- package/scripts/benchmark-scoped-project-verifier.mjs +461 -0
- package/scripts/benchmark-scoped-session-custody.mjs +599 -0
- package/scripts/benchmark-scoped-session-factory.mjs +342 -0
- package/scripts/benchmark-scoped-tool-broker.mjs +523 -0
- package/scripts/benchmark-scoped-verification-supervisor.mjs +773 -0
- package/scripts/benchmark-session-evaluator.mjs +169 -0
- package/scripts/benchmark-session-provider-boundary.mjs +62 -0
- package/scripts/benchmark-session-usage.mjs +28 -0
- package/scripts/benchmark-session.mjs +343 -50
- package/scripts/benchmark-webui-journey.mjs +678 -0
- package/scripts/check-public-wording.mjs +46 -0
- package/scripts/fs4-readiness-evaluation.mjs +7 -1
- package/scripts/phase-tools-evaluation.mjs +1 -0
- package/scripts/pi-auto.sh +7 -1
- package/scripts/pi-usage-history.mjs +201 -11
- package/scripts/piagent-cli.mjs +8 -0
- package/scripts/private-holdout-readiness.mjs +7 -1
- package/scripts/public-evaluation-exposure.mjs +140 -0
- package/scripts/select-independent-verification.mjs +62 -0
- package/scripts/typescript-loader.mjs +135 -1
- package/scripts/update-global.mjs +6 -7
- package/scripts/verify-local.sh +36 -55
- package/scripts/verify-release-identity.mjs +5 -3
- package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +0 -176
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import { SCOPED_DOCS_RECEIPT } from "./benchmark-scoped-docs-verifier.mjs";
|
|
2
|
+
import { createHash, createPrivateKey, createPublicKey, randomUUID, sign, verify } from "node:crypto";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import net from "node:net";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { types } from "node:util";
|
|
8
|
+
import { executionSourceText } from "../packages/piagent-core/extensions/acceptance-executor/module-graph.mjs";
|
|
9
|
+
import { parseRequest, parseResponse, WORKER_VERSION } from "../packages/piagent-core/extensions/acceptance-executor/protocol.mjs";
|
|
10
|
+
import { registerScopedBrokerTransport, runScopedBrokerMcp } from "./benchmark-scoped-broker-custody.mjs";
|
|
11
|
+
import { SCOPED_PROJECT_VERIFICATION_RECEIPT, validateScopedProjectVerificationReceipt
|
|
12
|
+
} from "./benchmark-scoped-project-verifier.mjs";
|
|
13
|
+
import {
|
|
14
|
+
SCOPED_BROKER_FROZEN_IDENTITY_VERSION, SCOPED_BROKER_IDENTITY_VERSION,
|
|
15
|
+
SCOPED_BROKER_QUALIFICATION_IDENTITY_VERSION, SCOPED_TOOL_DEFINITIONS,
|
|
16
|
+
scopedCommonRuntimeClosureIdentity, scopedFrozenQualificationIdentity, scopedQualificationIdentity,
|
|
17
|
+
scopedToolDefinitionsSha256, validateScopedBrokerMeasurementBinding
|
|
18
|
+
} from "./benchmark-scoped-frozen-qualification.mjs";
|
|
19
|
+
export * from "./benchmark-scoped-frozen-qualification.mjs";
|
|
20
|
+
export * from "./benchmark-scoped-project-verifier.mjs";
|
|
21
|
+
export { registerScopedBrokerTransport, runScopedBrokerMcp };
|
|
22
|
+
|
|
23
|
+
export const SCOPED_VERIFICATION_PROTOCOL = "scoped-isolated-contract-v1";
|
|
24
|
+
export const SCOPED_VERIFICATION_RECEIPT = "scoped-verification-receipt-v1";
|
|
25
|
+
export const SCOPED_VERIFICATION_BRIDGE = "scoped-verification-bridge-v1";
|
|
26
|
+
const HASH = /^[a-f0-9]{64}$/;
|
|
27
|
+
const IMAGE = /^sha256:[a-f0-9]{64}$/;
|
|
28
|
+
const ID = /^[A-Za-z0-9_.:-]{1,160}$/;
|
|
29
|
+
const UUID_V4 = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/;
|
|
30
|
+
const RECEIPT_FIELDS = ["version", "kind", "protocol", "verificationId", "action", "attemptId", "broker",
|
|
31
|
+
"manifestSha256", "capabilityDigest", "planDigest", "requestDigest", "sourceDigest", "imageId",
|
|
32
|
+
"verifierDigest", "worker", "status", "verdict", "cleanup", "evidence", "startedAtMs", "deadlineAtMs",
|
|
33
|
+
"settledAtMs", "completionAllowed"];
|
|
34
|
+
const hash = value => createHash("sha256").update(value).digest("hex");
|
|
35
|
+
const validId = value => typeof value === "string" && ID.test(value);
|
|
36
|
+
const validHash = value => typeof value === "string" && HASH.test(value);
|
|
37
|
+
const validTime = value => Number.isSafeInteger(value) && value >= 0;
|
|
38
|
+
const fail = code => { throw Object.assign(new Error(code), { supervisorCode: code }); };
|
|
39
|
+
const requireThat = (value, code) => { if (!value) fail(code); };
|
|
40
|
+
const runPinnedIsolatedContract = async input => {
|
|
41
|
+
const { runIsolatedContract } = await import("../packages/piagent-core/extensions/acceptance-isolated-executor.js");
|
|
42
|
+
return runIsolatedContract(input);
|
|
43
|
+
};
|
|
44
|
+
const SUPERVISOR_REAP_GRACE_MS = 250;
|
|
45
|
+
const plain = value => Boolean(value && typeof value === "object" && !types.isProxy(value)
|
|
46
|
+
&& [null, Object.prototype].includes(Object.getPrototypeOf(value)));
|
|
47
|
+
function exact(value, names, code = "invalid-verification-object") {
|
|
48
|
+
requireThat(plain(value), code);
|
|
49
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
50
|
+
requireThat(Reflect.ownKeys(descriptors).length === names.length && names.every(name => descriptors[name]?.enumerable
|
|
51
|
+
&& Object.hasOwn(descriptors[name], "value")), code);
|
|
52
|
+
}
|
|
53
|
+
function deepFreeze(value) {
|
|
54
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value)) return value;
|
|
55
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
56
|
+
return Object.freeze(value);
|
|
57
|
+
}
|
|
58
|
+
function publicKey(value) {
|
|
59
|
+
const key = value?.type === "public" ? value : createPublicKey(value);
|
|
60
|
+
requireThat(key.asymmetricKeyType === "ed25519", "invalid-receipt-key");
|
|
61
|
+
return key;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function scopedVerificationReceiptKeyDigest(value) {
|
|
65
|
+
return hash(publicKey(value).export({ type: "spki", format: "der" }));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function scopedVerificationPlanBinding({ protocol = SCOPED_VERIFICATION_PROTOCOL, requestText,
|
|
69
|
+
imageId, dockerSocket, verifierDigest, timeoutMs } = {}) {
|
|
70
|
+
requireThat(protocol === SCOPED_VERIFICATION_PROTOCOL && typeof requestText === "string" && IMAGE.test(imageId)
|
|
71
|
+
&& typeof dockerSocket === "string" && path.isAbsolute(dockerSocket) && path.normalize(dockerSocket) === dockerSocket
|
|
72
|
+
&& !dockerSocket.includes("\0") && validHash(verifierDigest) && Number.isSafeInteger(timeoutMs)
|
|
73
|
+
&& timeoutMs >= 25 && timeoutMs <= 30000,
|
|
74
|
+
"invalid-verification-plan");
|
|
75
|
+
const request = parseRequest(requestText);
|
|
76
|
+
const requestDigest = hash(requestText), sourceDigest = hash(executionSourceText(request));
|
|
77
|
+
const dockerSocketDigest = hash(dockerSocket);
|
|
78
|
+
const planDigest = hash(JSON.stringify({ protocol, requestDigest, sourceDigest, imageId, dockerSocketDigest,
|
|
79
|
+
verifierDigest, timeoutMs }));
|
|
80
|
+
const capabilityDigest = hash(JSON.stringify({ version: 1, protocol, planDigest, requestDigest, sourceDigest,
|
|
81
|
+
imageId, dockerSocketDigest, verifierDigest, timeoutMs }));
|
|
82
|
+
return deepFreeze({ protocol, planDigest, requestDigest, sourceDigest, imageId, dockerSocketDigest,
|
|
83
|
+
verifierDigest, timeoutMs, capabilityDigest });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function validateReceipt(receipt) {
|
|
87
|
+
exact(receipt, RECEIPT_FIELDS, "invalid-verification-receipt");
|
|
88
|
+
exact(receipt.broker, ["identitySha256", "sourceSha256"], "invalid-verification-receipt");
|
|
89
|
+
exact(receipt.worker, ["runId", "version"], "invalid-verification-receipt");
|
|
90
|
+
exact(receipt.cleanup, ["confirmed"], "invalid-verification-receipt");
|
|
91
|
+
exact(receipt.evidence, ["executionSha256", "observationSha256", "reason"], "invalid-verification-receipt");
|
|
92
|
+
requireThat(receipt.version === 1 && receipt.kind === SCOPED_VERIFICATION_RECEIPT
|
|
93
|
+
&& receipt.protocol === SCOPED_VERIFICATION_PROTOCOL && validId(receipt.verificationId)
|
|
94
|
+
&& Number.isSafeInteger(receipt.action) && receipt.action > 0 && UUID_V4.test(receipt.attemptId)
|
|
95
|
+
&& validHash(receipt.broker.identitySha256) && validHash(receipt.broker.sourceSha256)
|
|
96
|
+
&& [receipt.manifestSha256, receipt.capabilityDigest, receipt.planDigest, receipt.requestDigest,
|
|
97
|
+
receipt.sourceDigest, receipt.verifierDigest, receipt.evidence.executionSha256]
|
|
98
|
+
.every(validHash)
|
|
99
|
+
&& IMAGE.test(receipt.imageId) && receipt.worker.runId === receipt.attemptId
|
|
100
|
+
&& (receipt.worker.version === null || receipt.worker.version === WORKER_VERSION)
|
|
101
|
+
&& ["completed", "timeout", "cancelled", "error"].includes(receipt.status)
|
|
102
|
+
&& ["observation-recorded", "observation-unavailable"].includes(receipt.verdict)
|
|
103
|
+
&& typeof receipt.cleanup.confirmed === "boolean"
|
|
104
|
+
&& (receipt.evidence.observationSha256 === null || validHash(receipt.evidence.observationSha256))
|
|
105
|
+
&& (receipt.evidence.reason === null || typeof receipt.evidence.reason === "string"
|
|
106
|
+
&& /^[a-z0-9-]{1,80}$/.test(receipt.evidence.reason))
|
|
107
|
+
&& [receipt.startedAtMs, receipt.deadlineAtMs, receipt.settledAtMs].every(validTime)
|
|
108
|
+
&& receipt.deadlineAtMs >= receipt.startedAtMs && receipt.settledAtMs >= receipt.startedAtMs
|
|
109
|
+
&& receipt.completionAllowed === false, "invalid-verification-receipt");
|
|
110
|
+
const observed = receipt.status === "completed" && receipt.cleanup.confirmed
|
|
111
|
+
&& receipt.worker.version === WORKER_VERSION && validHash(receipt.evidence.observationSha256)
|
|
112
|
+
&& receipt.evidence.reason === null;
|
|
113
|
+
requireThat((receipt.verdict === "observation-recorded") === observed, "invalid-verification-receipt");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function verifyScopedVerificationEnvelope(envelope, receiptPublicKey) {
|
|
117
|
+
exact(envelope, ["receipt", "signature"], "invalid-verification-envelope");
|
|
118
|
+
if ([SCOPED_PROJECT_VERIFICATION_RECEIPT, SCOPED_DOCS_RECEIPT].includes(envelope.receipt?.kind))
|
|
119
|
+
validateScopedProjectVerificationReceipt(envelope.receipt);
|
|
120
|
+
else validateReceipt(envelope.receipt);
|
|
121
|
+
requireThat(typeof envelope.signature === "string" && /^[A-Za-z0-9+/]+={0,2}$/.test(envelope.signature),
|
|
122
|
+
"invalid-verification-envelope");
|
|
123
|
+
const signature = Buffer.from(envelope.signature, "base64");
|
|
124
|
+
requireThat(signature.length === 64 && signature.toString("base64") === envelope.signature
|
|
125
|
+
&& verify(null, Buffer.from(JSON.stringify(envelope.receipt)), publicKey(receiptPublicKey), signature),
|
|
126
|
+
"invalid-verification-signature");
|
|
127
|
+
return deepFreeze(structuredClone(envelope));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function normalizeExecution(execution, state) {
|
|
131
|
+
try {
|
|
132
|
+
requireThat(plain(execution) && execution.runId === state.attemptId && execution.requestDigest === state.requestDigest
|
|
133
|
+
&& execution.sourceDigest === state.sourceDigest && execution.imageId === state.imageId
|
|
134
|
+
&& ["completed", "timeout", "cancelled", "error"].includes(execution.status)
|
|
135
|
+
&& typeof execution.cleanupConfirmed === "boolean", "execution-binding-invalid");
|
|
136
|
+
let observation = null;
|
|
137
|
+
if (execution.status === "completed") {
|
|
138
|
+
exact(execution, ["runId", "requestDigest", "sourceDigest", "imageId", "status", "cleanupConfirmed",
|
|
139
|
+
"observation"], "execution-binding-invalid");
|
|
140
|
+
requireThat(plain(execution.observation), "execution-binding-invalid");
|
|
141
|
+
observation = parseResponse(JSON.stringify(execution.observation), state.request, state.requestDigest);
|
|
142
|
+
requireThat(observation.status === "completed", "execution-binding-invalid");
|
|
143
|
+
} else {
|
|
144
|
+
exact(execution, ["runId", "requestDigest", "sourceDigest", "imageId", "status", "reason",
|
|
145
|
+
"cleanupConfirmed"], "execution-binding-invalid");
|
|
146
|
+
requireThat(typeof execution.reason === "string" && /^[a-z0-9-]{1,80}$/.test(execution.reason),
|
|
147
|
+
"execution-binding-invalid");
|
|
148
|
+
}
|
|
149
|
+
const executionSha256 = hash(JSON.stringify(execution));
|
|
150
|
+
return { execution, observation, executionSha256,
|
|
151
|
+
observationSha256: observation ? hash(JSON.stringify(observation)) : null,
|
|
152
|
+
status: execution.status, reason: execution.reason ?? null, cleanupConfirmed: execution.cleanupConfirmed,
|
|
153
|
+
integrityFailure: false };
|
|
154
|
+
} catch {
|
|
155
|
+
return { execution: null, observation: null, executionSha256: hash("invalid-execution-result"),
|
|
156
|
+
observationSha256: null, status: "error", reason: "execution-binding-invalid", cleanupConfirmed: false,
|
|
157
|
+
integrityFailure: true };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Host-only verifier. The returned bridge exposes no request source, Docker
|
|
163
|
+
* socket, signing key, image map, or verifier map. Pass only this bridge to the
|
|
164
|
+
* broker process boundary; keep this supervisor in the host process.
|
|
165
|
+
*/
|
|
166
|
+
export function createScopedVerificationSupervisor({ manifestSha256, brokerIdentitySha256, brokerSourceSha256,
|
|
167
|
+
receiptPrivateKey, verifications, execute = runPinnedIsolatedContract, clock = Date.now,
|
|
168
|
+
createAttemptId = randomUUID } = {}) {
|
|
169
|
+
requireThat(validHash(manifestSha256) && validHash(brokerIdentitySha256) && validHash(brokerSourceSha256)
|
|
170
|
+
&& Array.isArray(verifications) && verifications.length > 0 && verifications.length <= 32
|
|
171
|
+
&& typeof execute === "function" && typeof clock === "function" && typeof createAttemptId === "function",
|
|
172
|
+
"invalid-supervisor-configuration");
|
|
173
|
+
const privateKey = receiptPrivateKey?.type === "private" ? receiptPrivateKey : createPrivateKey(receiptPrivateKey);
|
|
174
|
+
requireThat(privateKey.asymmetricKeyType === "ed25519", "invalid-receipt-key");
|
|
175
|
+
const receiptPublicKey = createPublicKey(privateKey);
|
|
176
|
+
const receiptPublicKeyPem = receiptPublicKey.export({ type: "spki", format: "pem" });
|
|
177
|
+
const receiptKeyDigest = scopedVerificationReceiptKeyDigest(receiptPublicKey);
|
|
178
|
+
const plans = new Map();
|
|
179
|
+
for (const item of verifications) {
|
|
180
|
+
exact(item, ["manifest", "plan"], "invalid-supervisor-configuration");
|
|
181
|
+
exact(item.manifest, ["id", "protocol", "capabilityDigest", "receiptKeyDigest", "timeoutMs"],
|
|
182
|
+
"invalid-supervisor-configuration");
|
|
183
|
+
exact(item.plan, ["requestText", "imageId", "dockerSocket", "verifierDigest"], "invalid-supervisor-configuration");
|
|
184
|
+
const entry = item.manifest, plan = item.plan;
|
|
185
|
+
requireThat(validId(entry.id) && !plans.has(entry.id) && entry.protocol === SCOPED_VERIFICATION_PROTOCOL
|
|
186
|
+
&& validHash(entry.capabilityDigest) && entry.receiptKeyDigest === receiptKeyDigest
|
|
187
|
+
&& Number.isSafeInteger(entry.timeoutMs) && entry.timeoutMs >= 25 && entry.timeoutMs <= 30000,
|
|
188
|
+
"invalid-supervisor-configuration");
|
|
189
|
+
const binding = scopedVerificationPlanBinding({ protocol: entry.protocol, requestText: plan.requestText,
|
|
190
|
+
imageId: plan.imageId, dockerSocket: plan.dockerSocket, verifierDigest: plan.verifierDigest,
|
|
191
|
+
timeoutMs: entry.timeoutMs });
|
|
192
|
+
requireThat(binding.capabilityDigest === entry.capabilityDigest, "verification-capability-mismatch");
|
|
193
|
+
plans.set(entry.id, deepFreeze({ ...binding, id: entry.id, requestText: String(plan.requestText),
|
|
194
|
+
request: parseRequest(plan.requestText), dockerSocket: String(plan.dockerSocket) }));
|
|
195
|
+
}
|
|
196
|
+
let active = null;
|
|
197
|
+
const completed = new Map();
|
|
198
|
+
function stateFor(attemptId) {
|
|
199
|
+
requireThat(UUID_V4.test(attemptId) && active?.attemptId === attemptId, "verification-attempt-unavailable");
|
|
200
|
+
return active;
|
|
201
|
+
}
|
|
202
|
+
function makeEnvelope(state, normalized, settledAtMs) {
|
|
203
|
+
const receipt = {
|
|
204
|
+
version: 1, kind: SCOPED_VERIFICATION_RECEIPT, protocol: SCOPED_VERIFICATION_PROTOCOL,
|
|
205
|
+
verificationId: state.verificationId, action: state.action, attemptId: state.attemptId,
|
|
206
|
+
broker: { identitySha256: brokerIdentitySha256, sourceSha256: brokerSourceSha256 }, manifestSha256,
|
|
207
|
+
capabilityDigest: state.capabilityDigest, planDigest: state.planDigest, requestDigest: state.requestDigest,
|
|
208
|
+
sourceDigest: state.sourceDigest, imageId: state.imageId, verifierDigest: state.verifierDigest,
|
|
209
|
+
worker: { runId: state.attemptId, version: normalized.observation?.workerVersion ?? null },
|
|
210
|
+
status: normalized.status,
|
|
211
|
+
verdict: normalized.status === "completed" && normalized.cleanupConfirmed && normalized.observation
|
|
212
|
+
? "observation-recorded" : "observation-unavailable",
|
|
213
|
+
cleanup: { confirmed: normalized.cleanupConfirmed },
|
|
214
|
+
evidence: { executionSha256: normalized.executionSha256, observationSha256: normalized.observationSha256,
|
|
215
|
+
reason: normalized.reason },
|
|
216
|
+
startedAtMs: state.startedAtMs, deadlineAtMs: state.deadlineAtMs, settledAtMs, completionAllowed: false
|
|
217
|
+
};
|
|
218
|
+
validateReceipt(receipt);
|
|
219
|
+
const signature = sign(null, Buffer.from(JSON.stringify(receipt)), privateKey).toString("base64");
|
|
220
|
+
return deepFreeze({ receipt, signature });
|
|
221
|
+
}
|
|
222
|
+
async function settle(state) {
|
|
223
|
+
if (state.promise) return state.promise;
|
|
224
|
+
state.promise = (async () => {
|
|
225
|
+
let execution;
|
|
226
|
+
try {
|
|
227
|
+
const invocation = state.controller.signal.aborted
|
|
228
|
+
? Promise.resolve({ runId: state.attemptId, requestDigest: state.requestDigest, sourceDigest: state.sourceDigest,
|
|
229
|
+
imageId: state.imageId, status: "cancelled", reason: "cancelled-before-execute", cleanupConfirmed: true })
|
|
230
|
+
: Promise.resolve(execute({ requestText: state.requestText, imageId: state.imageId,
|
|
231
|
+
dockerSocket: state.dockerSocket, timeoutMs: state.timeoutMs, signal: state.controller.signal,
|
|
232
|
+
executionRunId: state.attemptId }));
|
|
233
|
+
// An injected or damaged executor may ignore AbortSignal forever. The
|
|
234
|
+
// deadline gate lets the supervisor settle after one bounded reap grace;
|
|
235
|
+
// the late invocation remains observed so it cannot become an unhandled
|
|
236
|
+
// rejection, and its unconfirmed cleanup can never authorize completion.
|
|
237
|
+
invocation.catch(() => undefined);
|
|
238
|
+
execution = await Promise.race([invocation, state.deadlineGate]);
|
|
239
|
+
} catch {
|
|
240
|
+
execution = { runId: state.attemptId, requestDigest: state.requestDigest, sourceDigest: state.sourceDigest,
|
|
241
|
+
imageId: state.imageId, status: "error", reason: "executor-threw", cleanupConfirmed: false };
|
|
242
|
+
}
|
|
243
|
+
const normalized = normalizeExecution(execution, state);
|
|
244
|
+
const settledAtMs = clock();
|
|
245
|
+
requireThat(validTime(settledAtMs) && settledAtMs >= state.startedAtMs, "invalid-supervisor-clock");
|
|
246
|
+
if (state.deadlineExpired || settledAtMs >= state.deadlineAtMs) {
|
|
247
|
+
normalized.observation = null; normalized.observationSha256 = null;
|
|
248
|
+
normalized.status = "timeout"; normalized.reason = "supervisor-deadline";
|
|
249
|
+
} else if (state.cancelRequested) {
|
|
250
|
+
normalized.observation = null; normalized.observationSha256 = null;
|
|
251
|
+
normalized.status = "cancelled"; normalized.reason = "supervisor-cancelled";
|
|
252
|
+
}
|
|
253
|
+
const envelope = makeEnvelope(state, normalized, settledAtMs);
|
|
254
|
+
const result = deepFreeze({ envelope, observation: normalized.observation,
|
|
255
|
+
integrityFailure: normalized.integrityFailure });
|
|
256
|
+
completed.set(state.attemptId, result);
|
|
257
|
+
if (completed.size > 32) completed.delete(completed.keys().next().value);
|
|
258
|
+
return result;
|
|
259
|
+
})().finally(() => {
|
|
260
|
+
clearTimeout(state.deadlineTimer); clearTimeout(state.reapTimer);
|
|
261
|
+
if (active === state) active = null;
|
|
262
|
+
});
|
|
263
|
+
return state.promise;
|
|
264
|
+
}
|
|
265
|
+
const bridge = {
|
|
266
|
+
version: "scoped-verification-supervisor-v1", receiptPublicKey: receiptPublicKeyPem, receiptKeyDigest,
|
|
267
|
+
begin(request) {
|
|
268
|
+
exact(request, ["verificationId", "action", "brokerIdentitySha256", "brokerSourceSha256", "manifestSha256",
|
|
269
|
+
"capabilityDigest"], "invalid-verification-request");
|
|
270
|
+
requireThat(!active && validId(request.verificationId) && Number.isSafeInteger(request.action) && request.action > 0
|
|
271
|
+
&& request.brokerIdentitySha256 === brokerIdentitySha256 && request.brokerSourceSha256 === brokerSourceSha256
|
|
272
|
+
&& request.manifestSha256 === manifestSha256, "verification-inflight-or-binding-invalid");
|
|
273
|
+
const plan = plans.get(request.verificationId);
|
|
274
|
+
requireThat(plan && request.capabilityDigest === plan.capabilityDigest, "verification-denied");
|
|
275
|
+
const startedAtMs = clock(), attemptId = createAttemptId();
|
|
276
|
+
requireThat(validTime(startedAtMs) && Number.isSafeInteger(startedAtMs + plan.timeoutMs)
|
|
277
|
+
&& UUID_V4.test(attemptId), "invalid-supervisor-runtime");
|
|
278
|
+
let expire;
|
|
279
|
+
const deadlineGate = new Promise(resolve => { expire = resolve; });
|
|
280
|
+
const state = { ...plan, verificationId: request.verificationId, action: request.action, attemptId,
|
|
281
|
+
startedAtMs, deadlineAtMs: startedAtMs + plan.timeoutMs, controller: new AbortController(), promise: null,
|
|
282
|
+
cancelRequested: false, deadlineExpired: false, deadlineTimer: null, reapTimer: null, deadlineGate };
|
|
283
|
+
active = state;
|
|
284
|
+
state.deadlineTimer = setTimeout(() => {
|
|
285
|
+
state.deadlineExpired = true; state.controller.abort();
|
|
286
|
+
state.reapTimer = setTimeout(() => expire({ runId: state.attemptId, requestDigest: state.requestDigest,
|
|
287
|
+
sourceDigest: state.sourceDigest, imageId: state.imageId, status: "timeout",
|
|
288
|
+
reason: "executor-reap-unconfirmed", cleanupConfirmed: false }), SUPERVISOR_REAP_GRACE_MS);
|
|
289
|
+
void settle(state).catch(() => undefined);
|
|
290
|
+
}, plan.timeoutMs);
|
|
291
|
+
return deepFreeze({ attemptId, verificationId: active.verificationId, capabilityDigest: active.capabilityDigest,
|
|
292
|
+
planDigest: active.planDigest, requestDigest: active.requestDigest, sourceDigest: active.sourceDigest,
|
|
293
|
+
imageId: active.imageId, verifierDigest: active.verifierDigest, startedAtMs, deadlineAtMs: active.deadlineAtMs });
|
|
294
|
+
},
|
|
295
|
+
execute(attemptId) {
|
|
296
|
+
if (completed.has(attemptId)) return Promise.resolve(completed.get(attemptId));
|
|
297
|
+
return settle(stateFor(attemptId));
|
|
298
|
+
},
|
|
299
|
+
cancel(attemptId) {
|
|
300
|
+
if (!UUID_V4.test(attemptId) || active?.attemptId !== attemptId) return false;
|
|
301
|
+
if (!active.deadlineExpired) active.cancelRequested = true;
|
|
302
|
+
active.controller.abort(); return true;
|
|
303
|
+
},
|
|
304
|
+
reconcile(attemptId) {
|
|
305
|
+
if (completed.has(attemptId)) return Promise.resolve(completed.get(attemptId));
|
|
306
|
+
return settle(stateFor(attemptId));
|
|
307
|
+
},
|
|
308
|
+
status() { return deepFreeze({ active: active ? { attemptId: active.attemptId,
|
|
309
|
+
verificationId: active.verificationId, action: active.action, capabilityDigest: active.capabilityDigest,
|
|
310
|
+
planDigest: active.planDigest, requestDigest: active.requestDigest, sourceDigest: active.sourceDigest,
|
|
311
|
+
imageId: active.imageId, verifierDigest: active.verifierDigest, startedAtMs: active.startedAtMs,
|
|
312
|
+
deadlineAtMs: active.deadlineAtMs } : null,
|
|
313
|
+
completed: completed.size }); }
|
|
314
|
+
};
|
|
315
|
+
return deepFreeze(bridge);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Host side of a dedicated, bounded IPC channel. The transport itself is
|
|
319
|
+
* supplied by the launcher so this module does not create a network listener. */
|
|
320
|
+
export function createScopedVerificationHostDispatcher({ supervisor, authorization } = {}) {
|
|
321
|
+
exact(supervisor, ["version", "receiptPublicKey", "receiptKeyDigest", "begin", "execute", "cancel", "reconcile", "status"],
|
|
322
|
+
"invalid-verification-bridge");
|
|
323
|
+
requireThat(supervisor.version === "scoped-verification-supervisor-v1"
|
|
324
|
+
&& typeof authorization === "string" && /^[a-f0-9]{64}$/.test(authorization), "invalid-verification-bridge");
|
|
325
|
+
return async message => {
|
|
326
|
+
let requestId = null;
|
|
327
|
+
try {
|
|
328
|
+
exact(message, ["version", "authorization", "requestId", "method", "params"], "invalid-bridge-request");
|
|
329
|
+
requestId = message.requestId;
|
|
330
|
+
requireThat(message.version === SCOPED_VERIFICATION_BRIDGE && message.authorization === authorization
|
|
331
|
+
&& UUID_V4.test(requestId) && ["begin", "execute", "cancel", "reconcile", "status"].includes(message.method),
|
|
332
|
+
"invalid-bridge-request");
|
|
333
|
+
let result;
|
|
334
|
+
if (message.method === "begin") result = await supervisor.begin(message.params);
|
|
335
|
+
else if (message.method === "status") {
|
|
336
|
+
exact(message.params, [], "invalid-bridge-request"); result = await supervisor.status();
|
|
337
|
+
} else {
|
|
338
|
+
exact(message.params, ["attemptId"], "invalid-bridge-request");
|
|
339
|
+
requireThat(UUID_V4.test(message.params.attemptId), "invalid-bridge-request");
|
|
340
|
+
result = await supervisor[message.method](message.params.attemptId);
|
|
341
|
+
}
|
|
342
|
+
return deepFreeze({ version: SCOPED_VERIFICATION_BRIDGE, requestId, ok: true, result });
|
|
343
|
+
} catch (error) {
|
|
344
|
+
const code = typeof error?.supervisorCode === "string" && /^[a-z0-9-]{1,80}$/.test(error.supervisorCode)
|
|
345
|
+
? error.supervisorCode : "verification-bridge-error";
|
|
346
|
+
return deepFreeze({ version: SCOPED_VERIFICATION_BRIDGE, requestId, ok: false, code });
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Child-side proxy. It contains only public receipt material plus a caller
|
|
352
|
+
* supplied IPC request function; host plan/image/socket/verifier maps stay in
|
|
353
|
+
* createScopedVerificationHostDispatcher's process. */
|
|
354
|
+
export function createScopedVerificationRemoteBridge({ receiptPublicKey, receiptKeyDigest, authorization, request } = {}) {
|
|
355
|
+
const key = publicKey(receiptPublicKey), pem = key.export({ type: "spki", format: "pem" });
|
|
356
|
+
requireThat(validHash(receiptKeyDigest) && scopedVerificationReceiptKeyDigest(key) === receiptKeyDigest
|
|
357
|
+
&& typeof authorization === "string" && /^[a-f0-9]{64}$/.test(authorization) && typeof request === "function",
|
|
358
|
+
"invalid-verification-bridge");
|
|
359
|
+
async function call(method, params) {
|
|
360
|
+
const requestId = randomUUID();
|
|
361
|
+
const response = await request(deepFreeze({ version: SCOPED_VERIFICATION_BRIDGE, authorization,
|
|
362
|
+
requestId, method, params }));
|
|
363
|
+
requireThat(plain(response) && response.version === SCOPED_VERIFICATION_BRIDGE
|
|
364
|
+
&& response.requestId === requestId && typeof response.ok === "boolean", "invalid-bridge-response");
|
|
365
|
+
if (!response.ok) {
|
|
366
|
+
exact(response, ["version", "requestId", "ok", "code"], "invalid-bridge-response");
|
|
367
|
+
requireThat(typeof response.code === "string" && /^[a-z0-9-]{1,80}$/.test(response.code), "invalid-bridge-response");
|
|
368
|
+
fail(response.code);
|
|
369
|
+
}
|
|
370
|
+
exact(response, ["version", "requestId", "ok", "result"], "invalid-bridge-response");
|
|
371
|
+
return response.result;
|
|
372
|
+
}
|
|
373
|
+
return deepFreeze({ version: "scoped-verification-supervisor-v1", receiptPublicKey: pem, receiptKeyDigest,
|
|
374
|
+
begin: params => call("begin", params), execute: attemptId => call("execute", { attemptId }),
|
|
375
|
+
cancel: attemptId => call("cancel", { attemptId }), reconcile: attemptId => call("reconcile", { attemptId }),
|
|
376
|
+
status: () => call("status", {}) });
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const BRIDGE_REQUEST_BYTES = 64 * 1024;
|
|
380
|
+
const BRIDGE_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
381
|
+
const UNIX_SOCKET_PATH_BYTES = 103;
|
|
382
|
+
function privateSocketPath(socketPath) {
|
|
383
|
+
requireThat(typeof socketPath === "string" && path.isAbsolute(socketPath) && path.normalize(socketPath) === socketPath
|
|
384
|
+
&& !socketPath.includes("\0") && Buffer.byteLength(socketPath) <= UNIX_SOCKET_PATH_BYTES,
|
|
385
|
+
"invalid-bridge-socket");
|
|
386
|
+
const parent = fs.lstatSync(path.dirname(socketPath));
|
|
387
|
+
requireThat(parent.isDirectory() && !parent.isSymbolicLink() && (parent.mode & 0o077) === 0
|
|
388
|
+
&& !fs.existsSync(socketPath), "invalid-bridge-socket");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** A private Unix-domain transport for the host dispatcher. It accepts one
|
|
392
|
+
* bounded request and emits one bounded response per connection, which lets a
|
|
393
|
+
* second connection deliver cancellation while execute is pending. */
|
|
394
|
+
export async function listenScopedVerificationBridge({ supervisor, authorization, socketPath } = {}) {
|
|
395
|
+
privateSocketPath(socketPath);
|
|
396
|
+
const dispatch = createScopedVerificationHostDispatcher({ supervisor, authorization });
|
|
397
|
+
const sockets = new Set();
|
|
398
|
+
const server = net.createServer({ allowHalfOpen: true }, socket => {
|
|
399
|
+
if (sockets.size >= 4) { socket.destroy(); return; }
|
|
400
|
+
sockets.add(socket); socket.setNoDelay(true);
|
|
401
|
+
let bytes = 0, chunks = [], complete = false;
|
|
402
|
+
socket.on("data", chunk => {
|
|
403
|
+
if (complete) { socket.destroy(); return; }
|
|
404
|
+
bytes += chunk.length;
|
|
405
|
+
if (bytes > BRIDGE_REQUEST_BYTES) { complete = true; socket.destroy(); return; }
|
|
406
|
+
chunks.push(Buffer.from(chunk));
|
|
407
|
+
});
|
|
408
|
+
socket.on("end", async () => {
|
|
409
|
+
if (complete) return;
|
|
410
|
+
complete = true;
|
|
411
|
+
const input = Buffer.concat(chunks); chunks = [];
|
|
412
|
+
if (input.length < 2 || input.at(-1) !== 10 || input.subarray(0, -1).includes(10)) { socket.destroy(); return; }
|
|
413
|
+
let message;
|
|
414
|
+
try { message = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(0, -1))); }
|
|
415
|
+
catch { socket.destroy(); return; }
|
|
416
|
+
const response = await dispatch(message), output = Buffer.from(JSON.stringify(response) + "\n");
|
|
417
|
+
if (output.length > BRIDGE_RESPONSE_BYTES) { socket.destroy(); return; }
|
|
418
|
+
socket.end(output);
|
|
419
|
+
});
|
|
420
|
+
socket.on("error", () => {});
|
|
421
|
+
socket.on("close", () => sockets.delete(socket));
|
|
422
|
+
});
|
|
423
|
+
server.maxConnections = 4;
|
|
424
|
+
await new Promise((resolve, reject) => {
|
|
425
|
+
const failed = error => { server.off("listening", ready); reject(error); };
|
|
426
|
+
const ready = () => { server.off("error", failed); resolve(); };
|
|
427
|
+
server.once("error", failed); server.once("listening", ready); server.listen(socketPath);
|
|
428
|
+
});
|
|
429
|
+
let socketInfo;
|
|
430
|
+
try {
|
|
431
|
+
fs.chmodSync(socketPath, 0o600); socketInfo = fs.lstatSync(socketPath);
|
|
432
|
+
requireThat(socketInfo.isSocket() && !socketInfo.isSymbolicLink(), "invalid-bridge-socket");
|
|
433
|
+
} catch (error) {
|
|
434
|
+
await new Promise(resolve => server.close(() => resolve()));
|
|
435
|
+
try { const current = fs.lstatSync(socketPath); if (current.isSocket() && !current.isSymbolicLink()) fs.unlinkSync(socketPath); }
|
|
436
|
+
catch {}
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
let closed = false;
|
|
440
|
+
return deepFreeze({ socketPath,
|
|
441
|
+
async close() {
|
|
442
|
+
if (closed) return;
|
|
443
|
+
closed = true;
|
|
444
|
+
for (const socket of sockets) socket.destroy();
|
|
445
|
+
await new Promise(resolve => server.close(() => resolve()));
|
|
446
|
+
if (fs.existsSync(socketPath)) {
|
|
447
|
+
const current = fs.lstatSync(socketPath);
|
|
448
|
+
requireThat(current.dev === socketInfo.dev && current.ino === socketInfo.ino && current.isSocket(),
|
|
449
|
+
"bridge-socket-replaced");
|
|
450
|
+
fs.unlinkSync(socketPath);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/** Child-side request function for createScopedVerificationRemoteBridge. The
|
|
457
|
+
* only host path it knows is this dedicated private bridge socket. */
|
|
458
|
+
export function createScopedVerificationUnixRequest({ socketPath, timeoutMs = 60000 } = {}) {
|
|
459
|
+
requireThat(typeof socketPath === "string" && path.isAbsolute(socketPath) && path.normalize(socketPath) === socketPath
|
|
460
|
+
&& !socketPath.includes("\0") && Number.isSafeInteger(timeoutMs) && timeoutMs >= 100 && timeoutMs <= 60000,
|
|
461
|
+
"invalid-bridge-client");
|
|
462
|
+
return message => new Promise((resolve, reject) => {
|
|
463
|
+
const socket = net.createConnection(socketPath), chunks = [];
|
|
464
|
+
let bytes = 0, finished = false;
|
|
465
|
+
const finish = (error, value) => {
|
|
466
|
+
if (finished) return;
|
|
467
|
+
finished = true; clearTimeout(timer); socket.destroy();
|
|
468
|
+
if (error) reject(Object.assign(new Error("verification-bridge-unavailable"),
|
|
469
|
+
{ supervisorCode: "verification-bridge-unavailable", cause: error }));
|
|
470
|
+
else resolve(value);
|
|
471
|
+
};
|
|
472
|
+
const timer = setTimeout(() => finish(new Error("bridge-timeout")), timeoutMs);
|
|
473
|
+
socket.on("connect", () => socket.end(Buffer.from(JSON.stringify(message) + "\n")));
|
|
474
|
+
socket.on("data", chunk => {
|
|
475
|
+
bytes += chunk.length;
|
|
476
|
+
if (bytes > BRIDGE_RESPONSE_BYTES) finish(new Error("bridge-response-limit"));
|
|
477
|
+
else chunks.push(Buffer.from(chunk));
|
|
478
|
+
});
|
|
479
|
+
socket.on("error", error => finish(error));
|
|
480
|
+
socket.on("end", () => {
|
|
481
|
+
if (finished) return;
|
|
482
|
+
const input = Buffer.concat(chunks);
|
|
483
|
+
try {
|
|
484
|
+
requireThat(input.length >= 2 && input.at(-1) === 10 && !input.subarray(0, -1).includes(10),
|
|
485
|
+
"invalid-bridge-response");
|
|
486
|
+
finish(null, JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(0, -1))));
|
|
487
|
+
} catch (error) { finish(error); }
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
const BROKER_CONFIG_BYTES = 64 * 1024;
|
|
494
|
+
const BROKER_JOURNAL_BYTES = 32 * 1024 * 1024;
|
|
495
|
+
const MCP_PROCESS_SHUTDOWN = "piagent-mcp-process-shutdown";
|
|
496
|
+
const brokerFail = code => { throw Object.assign(new Error(code), { brokerCode: code }); };
|
|
497
|
+
const brokerRequire = (value, code) => { if (!value) brokerFail(code); };
|
|
498
|
+
function brokerFields(value, names) {
|
|
499
|
+
brokerRequire(plain(value), "invalid-object");
|
|
500
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
501
|
+
brokerRequire(Reflect.ownKeys(descriptors).length === names.length && names.every(name =>
|
|
502
|
+
descriptors[name]?.enumerable && Object.hasOwn(descriptors[name], "value")), "invalid-fields");
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const brokerSameNode = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode
|
|
506
|
+
&& a.nlink === b.nlink;
|
|
507
|
+
const brokerSameFile = (a, b) => brokerSameNode(a, b) && a.size === b.size && a.mtimeNs === b.mtimeNs
|
|
508
|
+
&& a.ctimeNs === b.ctimeNs;
|
|
509
|
+
const brokerStat = file => fs.lstatSync(file, { bigint: true });
|
|
510
|
+
function brokerDirectoryChain(directory) {
|
|
511
|
+
brokerRequire(path.isAbsolute(directory) && path.normalize(directory) === directory,
|
|
512
|
+
"broker-config-path");
|
|
513
|
+
const result = [];
|
|
514
|
+
for (let current = directory;; current = path.dirname(current)) {
|
|
515
|
+
const info = brokerStat(current);
|
|
516
|
+
brokerRequire(info.isDirectory() && !info.isSymbolicLink(), "unsafe-parent");
|
|
517
|
+
result.push([current, info]);
|
|
518
|
+
if (current === path.dirname(current)) return result;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
function brokerCheckParents(chain) {
|
|
522
|
+
for (const [file, info] of chain) {
|
|
523
|
+
const current = brokerStat(file);
|
|
524
|
+
brokerRequire(current.isDirectory() && current.dev === info.dev && current.ino === info.ino
|
|
525
|
+
&& current.mode === info.mode, "parent-changed");
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function brokerCapture(file, parents, maximum = BROKER_CONFIG_BYTES) {
|
|
529
|
+
brokerRequire(Number.isSafeInteger(maximum) && maximum >= 1 && maximum <= BROKER_JOURNAL_BYTES,
|
|
530
|
+
"material-size");
|
|
531
|
+
brokerCheckParents(parents);
|
|
532
|
+
const before = brokerStat(file);
|
|
533
|
+
brokerRequire(before.isFile() && before.nlink === 1n
|
|
534
|
+
&& before.size <= BigInt(maximum), "unsafe-material");
|
|
535
|
+
const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
536
|
+
try {
|
|
537
|
+
fs.fsyncSync(fd);
|
|
538
|
+
brokerRequire(brokerSameFile(before, fs.fstatSync(fd, { bigint: true })), "material-changed");
|
|
539
|
+
const buffer = Buffer.alloc(maximum + 1);
|
|
540
|
+
let length = 0, read;
|
|
541
|
+
while (length < buffer.length
|
|
542
|
+
&& (read = fs.readSync(fd, buffer, length, buffer.length - length, length))) length += read;
|
|
543
|
+
brokerRequire(length <= maximum && BigInt(length) === before.size, "material-size");
|
|
544
|
+
brokerRequire(brokerSameFile(before, fs.fstatSync(fd, { bigint: true }))
|
|
545
|
+
&& brokerSameFile(before, brokerStat(file)), "material-changed");
|
|
546
|
+
brokerCheckParents(parents);
|
|
547
|
+
return { bytes: buffer.subarray(0, length), info: before };
|
|
548
|
+
} finally { fs.closeSync(fd); }
|
|
549
|
+
}
|
|
550
|
+
function readPrivateBrokerFile(file, maximum) {
|
|
551
|
+
brokerRequire(typeof file === "string" && path.isAbsolute(file) && path.normalize(file) === file
|
|
552
|
+
&& !file.includes("\0"), "broker-config-path");
|
|
553
|
+
const parents = brokerDirectoryChain(path.dirname(file)), captured = brokerCapture(file, parents, maximum);
|
|
554
|
+
brokerRequire((parents[0][1].mode & 0o077n) === 0n && (captured.info.mode & 0o077n) === 0n,
|
|
555
|
+
"broker-config-permissions");
|
|
556
|
+
return captured.bytes;
|
|
557
|
+
}
|
|
558
|
+
function readPrivateBrokerConfigFile(file) { return readPrivateBrokerFile(file, BROKER_CONFIG_BYTES); }
|
|
559
|
+
|
|
560
|
+
/** Strict common loader for both public adapters. Config contains material and
|
|
561
|
+
* journal custody plus only the private verifier bridge socket/token/public
|
|
562
|
+
* receipt key. Host-only execution inputs and receipt private keys are rejected. */
|
|
563
|
+
export function loadScopedBrokerFromConfig({ configPath, createBroker } = {}) {
|
|
564
|
+
brokerRequire(typeof createBroker === "function", "broker-config-version");
|
|
565
|
+
const configBytes = readPrivateBrokerConfigFile(configPath);
|
|
566
|
+
let config;
|
|
567
|
+
try { config = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(configBytes)); }
|
|
568
|
+
catch { brokerFail("broker-config-json"); }
|
|
569
|
+
brokerRequire(configBytes.equals(Buffer.from(JSON.stringify(config))), "broker-config-noncanonical");
|
|
570
|
+
const legacy = config.version === 1, qualified = config.version === SCOPED_BROKER_QUALIFICATION_IDENTITY_VERSION,
|
|
571
|
+
frozen = config.version === SCOPED_BROKER_FROZEN_IDENTITY_VERSION;
|
|
572
|
+
brokerFields(config, legacy
|
|
573
|
+
? ["version", "manifestPath", "manifestSignaturePath", "manifestPublicKeyPath", "expectedIdentity",
|
|
574
|
+
"journalPath", "journalPrivateKeyPath", "verificationBridge"]
|
|
575
|
+
: ["version", "manifestPath", "manifestSignaturePath", "manifestPublicKeyPath", "journalPath",
|
|
576
|
+
"journalPrivateKeyPath", "verificationBridge", ...(qualified || frozen ? ["qualification"] : []),
|
|
577
|
+
...(frozen ? ["measurementBinding"] : [])]);
|
|
578
|
+
brokerRequire(legacy || config.version === SCOPED_BROKER_IDENTITY_VERSION || qualified || frozen,
|
|
579
|
+
"broker-config-version");
|
|
580
|
+
let actualQualification;
|
|
581
|
+
if (qualified || frozen) {
|
|
582
|
+
const names = frozen ? ["version", "candidateRoot", "assetsRoot", "sdkRoot", "candidateIndexPath",
|
|
583
|
+
"candidateIndexSha256"] : ["version", "candidateRoot", "assetsRoot", "sdkRoot"];
|
|
584
|
+
brokerFields(config.qualification, names);
|
|
585
|
+
brokerRequire(config.qualification.version === config.version, "broker-config-qualification");
|
|
586
|
+
actualQualification = frozen
|
|
587
|
+
? scopedFrozenQualificationIdentity(config.qualification, scopedCommonRuntimeClosureIdentity().sha256)
|
|
588
|
+
: scopedQualificationIdentity({ candidateRoot: config.qualification.candidateRoot,
|
|
589
|
+
assetsRoot: config.qualification.assetsRoot, sdkRoot: config.qualification.sdkRoot });
|
|
590
|
+
}
|
|
591
|
+
const measurementBinding = frozen ? validateScopedBrokerMeasurementBinding(config.measurementBinding) : undefined;
|
|
592
|
+
let verificationBridge;
|
|
593
|
+
if (config.verificationBridge !== null) {
|
|
594
|
+
brokerFields(config.verificationBridge, ["socketPath", "authorizationPath", "receiptPublicKeyPath",
|
|
595
|
+
"receiptKeyDigest", "timeoutMs"]);
|
|
596
|
+
const bridge = config.verificationBridge;
|
|
597
|
+
brokerRequire(validHash(bridge.receiptKeyDigest) && Number.isSafeInteger(bridge.timeoutMs)
|
|
598
|
+
&& bridge.timeoutMs >= 100 && bridge.timeoutMs <= 60000, "broker-config-bridge");
|
|
599
|
+
const authorization = new TextDecoder("utf-8", { fatal: true })
|
|
600
|
+
.decode(readPrivateBrokerConfigFile(bridge.authorizationPath));
|
|
601
|
+
brokerRequire(/^[a-f0-9]{64}$/.test(authorization), "broker-config-bridge");
|
|
602
|
+
const receiptPublicKey = createPublicKey(readPrivateBrokerConfigFile(bridge.receiptPublicKeyPath));
|
|
603
|
+
verificationBridge = createScopedVerificationRemoteBridge({ receiptPublicKey,
|
|
604
|
+
receiptKeyDigest: bridge.receiptKeyDigest, authorization,
|
|
605
|
+
request: createScopedVerificationUnixRequest({ socketPath: bridge.socketPath,
|
|
606
|
+
timeoutMs: bridge.timeoutMs }) });
|
|
607
|
+
}
|
|
608
|
+
const manifestBytes = readPrivateBrokerConfigFile(config.manifestPath);
|
|
609
|
+
const manifestSignature = readPrivateBrokerConfigFile(config.manifestSignaturePath);
|
|
610
|
+
const manifestPublicKey = readPrivateBrokerConfigFile(config.manifestPublicKeyPath);
|
|
611
|
+
const manifestPublicKeyObject = createPublicKey(manifestPublicKey);
|
|
612
|
+
if (frozen) {
|
|
613
|
+
brokerRequire(manifestPublicKeyObject.asymmetricKeyType === "ed25519"
|
|
614
|
+
&& verify(null, manifestBytes, manifestPublicKeyObject, manifestSignature), "manifest-signature");
|
|
615
|
+
let signedManifest;
|
|
616
|
+
try { signedManifest = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(manifestBytes)); }
|
|
617
|
+
catch { brokerFail("manifest-json"); }
|
|
618
|
+
brokerRequire(manifestBytes.equals(Buffer.from(JSON.stringify(signedManifest))), "manifest-noncanonical");
|
|
619
|
+
const signedIdentity = signedManifest?.identity;
|
|
620
|
+
brokerRequire(signedIdentity?.version === SCOPED_BROKER_FROZEN_IDENTITY_VERSION
|
|
621
|
+
&& signedIdentity.configSha256 === hash(configBytes), "broker-config-identity");
|
|
622
|
+
brokerRequire(signedIdentity.armId === measurementBinding.armId
|
|
623
|
+
&& signedIdentity.requestId === measurementBinding.operatorRequestDigest
|
|
624
|
+
&& signedIdentity.contextPolicySha256 === measurementBinding.contextPolicySha256
|
|
625
|
+
&& signedIdentity.measurementConfigurationSha256 === measurementBinding.configurationSha256,
|
|
626
|
+
"broker-config-measurement-binding");
|
|
627
|
+
}
|
|
628
|
+
const broker = createBroker({ manifestBytes, manifestSignature,
|
|
629
|
+
manifestPublicKey: manifestPublicKeyObject,
|
|
630
|
+
expectedIdentity: legacy ? config.expectedIdentity : undefined, actualConfigSha256: hash(configBytes),
|
|
631
|
+
journalPath: config.journalPath,
|
|
632
|
+
journalPrivateKey: createPrivateKey(readPrivateBrokerConfigFile(config.journalPrivateKeyPath)), actualQualification,
|
|
633
|
+
verificationBridge });
|
|
634
|
+
const identity = legacy ? config.expectedIdentity : broker?.identity;
|
|
635
|
+
brokerRequire(broker?.identity?.nonce === identity?.nonce && (legacy
|
|
636
|
+
|| [SCOPED_BROKER_IDENTITY_VERSION, SCOPED_BROKER_QUALIFICATION_IDENTITY_VERSION,
|
|
637
|
+
SCOPED_BROKER_FROZEN_IDENTITY_VERSION].includes(identity.version)
|
|
638
|
+
&& identity.version === config.version && identity.configSha256 === hash(configBytes)),
|
|
639
|
+
"broker-config-identity");
|
|
640
|
+
if (frozen) brokerRequire(identity.armId === measurementBinding.armId
|
|
641
|
+
&& identity.requestId === measurementBinding.operatorRequestDigest
|
|
642
|
+
&& identity.contextPolicySha256 === measurementBinding.contextPolicySha256
|
|
643
|
+
&& identity.measurementConfigurationSha256 === measurementBinding.configurationSha256,
|
|
644
|
+
"broker-config-measurement-binding");
|
|
645
|
+
const journalPublicKey = Buffer.from(broker.journalPublicKey);
|
|
646
|
+
const settlementEvidence = () => {
|
|
647
|
+
const status = broker.status();
|
|
648
|
+
brokerRequire(status.ended === true && status.inflightVerification === null && status.blocked === false
|
|
649
|
+
&& status.cancelled === false, "broker-settlement-incomplete");
|
|
650
|
+
brokerRequire(readPrivateBrokerConfigFile(config.manifestPath).equals(manifestBytes)
|
|
651
|
+
&& readPrivateBrokerConfigFile(config.manifestSignaturePath).equals(manifestSignature)
|
|
652
|
+
&& readPrivateBrokerConfigFile(config.manifestPublicKeyPath).equals(manifestPublicKey),
|
|
653
|
+
"broker-settlement-manifest-changed");
|
|
654
|
+
const journalBytes = readPrivateBrokerFile(config.journalPath, BROKER_JOURNAL_BYTES);
|
|
655
|
+
brokerRequire(hash(journalBytes) === status.journalSha256, "broker-settlement-journal-changed");
|
|
656
|
+
return Object.freeze({ version: "scoped-broker-journal-evidence-v1", manifestBytes: Buffer.from(manifestBytes),
|
|
657
|
+
manifestSignature: Buffer.from(manifestSignature), manifestPublicKey: Buffer.from(manifestPublicKey),
|
|
658
|
+
journalBytes: Buffer.from(journalBytes), journalPublicKey: Buffer.from(journalPublicKey),
|
|
659
|
+
status: Object.freeze({ ...status }) });
|
|
660
|
+
};
|
|
661
|
+
return Object.freeze({ broker, nonce: identity.nonce,
|
|
662
|
+
identity: Object.freeze({ ...identity }), configSha256: hash(configBytes), actualQualification,
|
|
663
|
+
measurementBinding, settlementEvidence });
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
const scopedToolNames = Object.freeze(SCOPED_TOOL_DEFINITIONS.map(tool => tool.name));
|
|
667
|
+
const piOwnedTools = new WeakMap();
|
|
668
|
+
function exactToolNames(value) {
|
|
669
|
+
return Array.isArray(value) && value.length === scopedToolNames.length
|
|
670
|
+
&& value.every((name, index) => name === scopedToolNames[index]);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/** Pi extension adapter over the same loaded kernel used by MCP. The host must
|
|
674
|
+
* still construct the SDK session with noTools="all" and tools=exact3. */
|
|
675
|
+
export function createScopedBrokerPiExtension({ broker, nonce } = {}) {
|
|
676
|
+
brokerRequire(broker && typeof broker.invokeAsync === "function" && typeof broker.status === "function"
|
|
677
|
+
&& nonce === broker.identity?.nonce, "pi-broker-binding");
|
|
678
|
+
let registered = false, shuttingDown = false;
|
|
679
|
+
const assertSurface = pi => {
|
|
680
|
+
const active = pi.getActiveTools?.().map(tool => typeof tool === "string" ? tool : tool?.name)
|
|
681
|
+
?? pi.getActiveToolNames?.();
|
|
682
|
+
if (active !== undefined) brokerRequire(exactToolNames(active), "pi-tool-surface-mismatch");
|
|
683
|
+
};
|
|
684
|
+
const factory = function scopedBrokerPiExtension(pi) {
|
|
685
|
+
brokerRequire(!registered && pi && typeof pi.registerTool === "function"
|
|
686
|
+
&& typeof pi.on === "function" && typeof pi.setActiveTools === "function", "pi-extension-api");
|
|
687
|
+
registered = true;
|
|
688
|
+
const owned = SCOPED_TOOL_DEFINITIONS.map(definition => Object.freeze({ name: definition.name, label: definition.name,
|
|
689
|
+
description: `Bounded broker operation ${definition.name}.`, parameters: definition.inputSchema,
|
|
690
|
+
async execute(_toolCallId, args, signal) {
|
|
691
|
+
brokerRequire(!shuttingDown && !broker.status().ended, "pi-broker-unavailable");
|
|
692
|
+
let aborted = false;
|
|
693
|
+
const cancel = () => { aborted = true;
|
|
694
|
+
if (!broker.status().cancelled && !broker.status().ended) broker.cancel(); };
|
|
695
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
696
|
+
if (signal?.aborted) cancel();
|
|
697
|
+
try {
|
|
698
|
+
const result = await broker.invokeAsync(definition.name, args, nonce);
|
|
699
|
+
brokerRequire(!aborted, "pi-tool-cancelled");
|
|
700
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }], details: result };
|
|
701
|
+
} finally { signal?.removeEventListener("abort", cancel); }
|
|
702
|
+
}
|
|
703
|
+
}));
|
|
704
|
+
piOwnedTools.set(factory, Object.freeze(owned));
|
|
705
|
+
for (const tool of owned) pi.registerTool(tool);
|
|
706
|
+
const bind = () => { brokerRequire(!shuttingDown, "pi-broker-unavailable");
|
|
707
|
+
pi.setActiveTools([...scopedToolNames]); assertSurface(pi); };
|
|
708
|
+
pi.on("session_start", bind);
|
|
709
|
+
pi.on("before_agent_start", () => { bind(); return undefined; });
|
|
710
|
+
const finish = async () => {
|
|
711
|
+
if (shuttingDown) return;
|
|
712
|
+
shuttingDown = true;
|
|
713
|
+
try {
|
|
714
|
+
if (broker.status().inflightVerification) {
|
|
715
|
+
if (!broker.status().cancelled) broker.cancel();
|
|
716
|
+
await broker.reconcileVerification();
|
|
717
|
+
}
|
|
718
|
+
} finally { if (!broker.status().ended) broker.close(); }
|
|
719
|
+
};
|
|
720
|
+
pi.on("agent_end", finish);
|
|
721
|
+
pi.on("session_shutdown", finish);
|
|
722
|
+
};
|
|
723
|
+
return factory;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/** Proves exact definition object/handler ownership in Pi's loaded registry. */
|
|
727
|
+
export function assertScopedBrokerPiOwnership(resourceLoader, extensionFactory) {
|
|
728
|
+
const owned = piOwnedTools.get(extensionFactory), loaded = resourceLoader?.getExtensions?.();
|
|
729
|
+
brokerRequire(owned?.length === SCOPED_TOOL_DEFINITIONS.length && Array.isArray(loaded?.extensions),
|
|
730
|
+
"pi-tool-ownership-unavailable");
|
|
731
|
+
const matches = [];
|
|
732
|
+
for (const extension of loaded.extensions) for (const registered of extension.tools?.values?.() ?? [])
|
|
733
|
+
if (scopedToolNames.includes(registered?.definition?.name)) matches.push(registered.definition);
|
|
734
|
+
brokerRequire(matches.length === owned.length && matches.every((tool, index) => tool === owned[index]
|
|
735
|
+
&& tool.execute === owned[index].execute && JSON.stringify(tool.parameters) === JSON.stringify(SCOPED_TOOL_DEFINITIONS[index].inputSchema)),
|
|
736
|
+
"pi-tool-ownership-mismatch");
|
|
737
|
+
return Object.freeze({ names: [...scopedToolNames], toolDefinitionsSha256: scopedToolDefinitionsSha256(), handlersOwned: true });
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export function loadScopedBrokerPiExtension({ configPath, createBroker } = {}) {
|
|
741
|
+
const loaded = loadScopedBrokerFromConfig({ configPath, createBroker });
|
|
742
|
+
return Object.freeze({ ...loaded, extensionFactory: createScopedBrokerPiExtension(loaded) });
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/** MCP child over the common strict loader. */
|
|
746
|
+
export async function runScopedBrokerChild({ configPath, createBroker, input = process.stdin,
|
|
747
|
+
output = process.stdout, signal } = {}) {
|
|
748
|
+
const loaded = loadScopedBrokerFromConfig({ configPath, createBroker });
|
|
749
|
+
return runScopedBrokerMcp({ ...loaded, input, output, signal });
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/** Shared CLI shell used by the broker module so process and signal handling do
|
|
753
|
+
* not enlarge its security kernel. Returns false when the module was imported. */
|
|
754
|
+
export async function runScopedBrokerCli(moduleUrl, runChild) {
|
|
755
|
+
if (!process.argv[1] || path.resolve(process.argv[1]) !== fileURLToPath(moduleUrl)) return false;
|
|
756
|
+
brokerRequire(typeof runChild === "function", "scoped-broker-invalid-launch");
|
|
757
|
+
if (process.argv.length !== 4 || process.argv[2] !== "--serve-config") {
|
|
758
|
+
process.stderr.write("scoped-broker-invalid-launch\n"); process.exitCode = 2;
|
|
759
|
+
} else {
|
|
760
|
+
const controller = new AbortController(), stop = () => controller.abort(MCP_PROCESS_SHUTDOWN);
|
|
761
|
+
process.once("SIGTERM", stop); process.once("SIGINT", stop);
|
|
762
|
+
try {
|
|
763
|
+
const result = await runChild(process.argv[3], { signal: controller.signal });
|
|
764
|
+
if (!result.complete) process.exitCode = 1;
|
|
765
|
+
} catch (error) {
|
|
766
|
+
process.stderr.write(`${error.brokerCode ?? error.supervisorCode ?? "scoped-broker-failed"}\n`);
|
|
767
|
+
process.exitCode = 1;
|
|
768
|
+
} finally {
|
|
769
|
+
process.off("SIGTERM", stop); process.off("SIGINT", stop);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return true;
|
|
773
|
+
}
|