@piagent/platform 1.3.1 → 1.4.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 +132 -0
- package/README.md +10 -4
- package/README.vi.md +27 -0
- package/architecture/layers.json +96 -1
- package/docs/README.md +1 -0
- package/docs/architecture.md +1 -0
- package/docs/authority-manifest.md +1 -0
- package/docs/auto-delegation-policy.md +1 -0
- package/docs/capability-packs.md +1 -0
- package/docs/command-reference-vietnamese.md +5 -4
- package/docs/context-engine.md +1 -0
- package/docs/context-window-policy.md +1 -0
- package/docs/distribution-standard.md +8 -7
- package/docs/en/architecture.md +13 -0
- package/docs/herdr-workflow.md +1 -0
- package/docs/languages.json +20 -4
- package/docs/mcp-and-tools.md +125 -9
- package/docs/memory-policy.md +1 -0
- package/docs/model-options.md +1 -0
- package/docs/oauth-providers.md +1 -0
- package/docs/operator-manual-vietnamese.md +15 -12
- package/docs/package-architecture-notes.md +1 -0
- package/docs/project-adapters.md +1 -0
- package/docs/project-onboarding.md +1 -0
- package/docs/publishing-for-teams.md +37 -0
- package/docs/quality-benchmark.md +1 -0
- package/docs/quickstart-vietnamese.md +3 -2
- package/docs/release-install-policy.md +22 -8
- package/docs/runtime-harness-standard.md +2 -1
- package/docs/runtime-policy-design.md +1 -0
- package/docs/runtime-quality-baseline.md +1 -0
- package/docs/security-redaction-benchmark.md +1 -0
- package/docs/security-threat-model.md +2 -1
- package/docs/subagent-orchestration-capabilities.md +1 -0
- package/docs/subagents-and-multiagent.md +1 -0
- package/docs/task-implementation-contract.md +12 -4
- package/docs/task-lifecycle-vietnamese.md +1 -0
- package/docs/team-onboarding.md +3 -2
- package/docs/third-party-neutrality.md +26 -0
- package/docs/usage-observability.md +71 -0
- package/docs/vercel-docs-site.md +1 -0
- package/docs/vi/architecture.md +13 -0
- package/docs/workflow-recipes.md +1 -0
- package/docs-site/architecture.html +5 -1
- package/docs-site/benchmark.html +5 -1
- package/docs-site/commands.html +5 -1
- package/docs-site/content/en/index.html +49 -0
- package/docs-site/content/en/runtime.html +13 -0
- package/docs-site/content/index.html +49 -0
- package/docs-site/content/runtime.html +28 -0
- package/docs-site/context-engine.html +5 -1
- package/docs-site/en/architecture.html +5 -1
- package/docs-site/en/benchmark.html +5 -1
- package/docs-site/en/commands.html +5 -1
- package/docs-site/en/context-engine.html +5 -1
- package/docs-site/en/index.html +54 -1
- package/docs-site/en/mcp-approval.html +5 -1
- package/docs-site/en/mcp-auth.html +5 -1
- package/docs-site/en/mcp-servers.html +5 -1
- package/docs-site/en/mcp.html +5 -1
- package/docs-site/en/permissions.html +5 -1
- package/docs-site/en/profiles.html +5 -1
- package/docs-site/en/quickstart.html +5 -1
- package/docs-site/en/runtime.html +18 -1
- package/docs-site/en/scope.html +5 -1
- package/docs-site/en/security.html +5 -1
- package/docs-site/en/team.html +5 -1
- package/docs-site/en/whats-new.html +5 -1
- package/docs-site/en/workflows.html +5 -1
- package/docs-site/index.html +54 -1
- package/docs-site/mcp-approval.html +5 -1
- package/docs-site/mcp-auth.html +5 -1
- package/docs-site/mcp-servers.html +5 -1
- package/docs-site/mcp.html +5 -1
- package/docs-site/permissions.html +5 -1
- package/docs-site/profiles.html +5 -1
- package/docs-site/quickstart.html +5 -1
- package/docs-site/runtime.html +33 -1
- package/docs-site/scope.html +5 -1
- package/docs-site/security.html +5 -1
- package/docs-site/team.html +5 -1
- package/docs-site/whats-new.html +5 -1
- package/docs-site/workflows.html +5 -1
- package/evals/fixtures/mutation-provenance-record.invalid.json +17 -0
- package/evals/fixtures/mutation-provenance-record.valid.json +27 -0
- package/evals/fixtures/piagent-webui/approval-v1.invalid.json +54 -0
- package/evals/fixtures/piagent-webui/approval-v1.valid.json +58 -0
- package/evals/fixtures/piagent-webui/attachment-v1.invalid.json +25 -0
- package/evals/fixtures/piagent-webui/attachment-v1.valid.json +25 -0
- package/evals/fixtures/piagent-webui/capabilities-v1.invalid.json +51 -0
- package/evals/fixtures/piagent-webui/capabilities-v1.valid.json +122 -0
- package/evals/fixtures/piagent-webui/commit-summary-v1.invalid.json +10 -0
- package/evals/fixtures/piagent-webui/commit-summary-v1.valid.json +25 -0
- package/evals/fixtures/piagent-webui/control-command-v1.invalid.json +37 -0
- package/evals/fixtures/piagent-webui/control-command-v1.valid.json +35 -0
- package/evals/fixtures/piagent-webui/diff-v1.invalid.json +13 -0
- package/evals/fixtures/piagent-webui/diff-v1.valid.json +141 -0
- package/evals/fixtures/piagent-webui/gateway-capabilities-v1.invalid.json +35 -0
- package/evals/fixtures/piagent-webui/gateway-capabilities-v1.valid.json +35 -0
- package/evals/fixtures/piagent-webui/gateway-protocol-v1.invalid.json +14 -0
- package/evals/fixtures/piagent-webui/gateway-protocol-v1.valid.json +14 -0
- package/evals/fixtures/piagent-webui/handoff-history-v1.invalid.json +16 -0
- package/evals/fixtures/piagent-webui/handoff-history-v1.valid.json +16 -0
- package/evals/fixtures/piagent-webui/model-catalog-v1.invalid.json +31 -0
- package/evals/fixtures/piagent-webui/model-catalog-v1.valid.json +43 -0
- package/evals/fixtures/piagent-webui/queue-v1.invalid.json +29 -0
- package/evals/fixtures/piagent-webui/queue-v1.valid.json +44 -0
- package/evals/fixtures/piagent-webui/recovery-history-v1.invalid.json +17 -0
- package/evals/fixtures/piagent-webui/recovery-history-v1.valid.json +20 -0
- package/evals/fixtures/piagent-webui/release-monitor-v1.invalid.json +12 -0
- package/evals/fixtures/piagent-webui/release-monitor-v1.valid.json +29 -0
- package/evals/fixtures/piagent-webui/review-state-v1.invalid.json +25 -0
- package/evals/fixtures/piagent-webui/review-state-v1.valid.json +38 -0
- package/evals/fixtures/piagent-webui/runtime-event-v2.invalid.json +49 -0
- package/evals/fixtures/piagent-webui/runtime-event-v2.valid.json +49 -0
- package/evals/fixtures/piagent-webui/session-catalog-v1.invalid.json +17 -0
- package/evals/fixtures/piagent-webui/session-catalog-v1.valid.json +58 -0
- package/evals/fixtures/piagent-webui/session-command-v1.invalid.json +19 -0
- package/evals/fixtures/piagent-webui/session-command-v1.valid.json +19 -0
- package/evals/fixtures/piagent-webui/snapshot-v1.invalid.json +5 -0
- package/evals/fixtures/piagent-webui/snapshot-v1.valid.json +191 -0
- package/evals/fixtures/piagent-webui/source-change-v1.invalid.json +57 -0
- package/evals/fixtures/piagent-webui/source-change-v1.valid.json +98 -0
- package/evals/fixtures/piagent-webui/source-mutation-v1.invalid.json +19 -0
- package/evals/fixtures/piagent-webui/source-mutation-v1.valid.json +38 -0
- package/evals/fixtures/piagent-webui/source-revert-v1.invalid.json +20 -0
- package/evals/fixtures/piagent-webui/source-revert-v1.valid.json +62 -0
- package/evals/fixtures/piagent-webui/subagent-tree-v1.invalid.json +26 -0
- package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +39 -0
- package/evals/fixtures/piagent-webui/task-index-v1.invalid.json +15 -0
- package/evals/fixtures/piagent-webui/task-index-v1.valid.json +15 -0
- package/evals/fixtures/piagent-webui/task-timeline-v1.invalid.json +14 -0
- package/evals/fixtures/piagent-webui/task-timeline-v1.valid.json +16 -0
- package/evals/fixtures/piagent-webui/transcript-v1.invalid.json +35 -0
- package/evals/fixtures/piagent-webui/transcript-v1.valid.json +55 -0
- package/evals/fixtures/task-baseline-manifest.invalid.json +16 -0
- package/evals/fixtures/task-baseline-manifest.valid.json +41 -0
- package/evals/fixtures/verifier-file-snapshot.invalid.json +21 -0
- package/evals/fixtures/verifier-file-snapshot.valid.json +21 -0
- package/package.json +43 -4
- package/packages/piagent-core/README.md +3 -2
- package/packages/piagent-core/benchmark/benchmark-candidate.d.ts +1 -0
- package/packages/piagent-core/benchmark/benchmark-forensics.d.ts +1 -0
- package/packages/piagent-core/benchmark/benchmark-ledger.d.ts +4 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.d.ts +1 -0
- package/packages/piagent-core/benchmark/benchmark-runtime.d.ts +1 -0
- package/packages/piagent-core/capabilities/capability-core.js +2 -2
- package/packages/piagent-core/capabilities/capability-verification-cache.js +17 -7
- package/packages/piagent-core/capabilities/runtime-integrity.js +190 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +80 -272
- package/packages/piagent-core/extensions/redaction-core.d.ts +2 -0
- package/packages/piagent-core/extensions/runtime-evidence.js +12 -1
- package/packages/piagent-core/extensions/shell-reach.ts +250 -0
- package/packages/piagent-core/extensions/task-journal.js +30 -1
- package/packages/piagent-core/extensions/task-state.js +33 -36
- package/packages/piagent-core/mcp/mcp-command-actions.js +1 -1
- package/packages/piagent-core/mcp/mcp-server-catalog.js +139 -9
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +2 -2
- package/packages/piagent-core/runtime/hooks/tool-call-hook.ts +12 -2
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +20 -19
- package/packages/piagent-core/runtime/hooks/tool-result-metadata.ts +13 -0
- package/packages/piagent-core/runtime/input/chat-images.ts +2 -2
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +94 -0
- package/packages/piagent-core/runtime/inspection/approval-broker.ts +318 -0
- package/packages/piagent-core/runtime/inspection/commit-summary-projection.ts +59 -0
- package/packages/piagent-core/runtime/inspection/context-telemetry-inspection.ts +37 -0
- package/packages/piagent-core/runtime/inspection/criteria-links.ts +295 -0
- package/packages/piagent-core/runtime/inspection/diff-projection.ts +499 -0
- package/packages/piagent-core/runtime/inspection/git-filter-safety.ts +38 -0
- package/packages/piagent-core/runtime/inspection/git-numstat-adapter.ts +71 -0
- package/packages/piagent-core/runtime/inspection/git-status-adapter.ts +493 -0
- package/packages/piagent-core/runtime/inspection/git-tree-adapter.ts +108 -0
- package/packages/piagent-core/runtime/inspection/mcp-control.ts +10 -0
- package/packages/piagent-core/runtime/inspection/mutation-provenance-contract.ts +131 -0
- package/packages/piagent-core/runtime/inspection/mutation-provenance-recorder.ts +48 -0
- package/packages/piagent-core/runtime/inspection/mutation-provenance-store.ts +161 -0
- package/packages/piagent-core/runtime/inspection/project-runtime-inspection.ts +36 -0
- package/packages/piagent-core/runtime/inspection/review-state-contract.ts +108 -0
- package/packages/piagent-core/runtime/inspection/review-state-projection.ts +93 -0
- package/packages/piagent-core/runtime/inspection/review-state-store.ts +112 -0
- package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +262 -0
- package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +103 -0
- package/packages/piagent-core/runtime/inspection/source-change-projection.ts +471 -0
- package/packages/piagent-core/runtime/inspection/source-evidence-contract.ts +139 -0
- package/packages/piagent-core/runtime/inspection/source-evidence-store.ts +315 -0
- package/packages/piagent-core/runtime/inspection/source-handoff-store.ts +70 -0
- package/packages/piagent-core/runtime/inspection/source-inspection-plan.ts +34 -0
- package/packages/piagent-core/runtime/inspection/source-mutation-projection.ts +164 -0
- package/packages/piagent-core/runtime/inspection/source-mutation-store.ts +168 -0
- package/packages/piagent-core/runtime/inspection/source-open-target.ts +38 -0
- package/packages/piagent-core/runtime/inspection/source-revert-projection.ts +147 -0
- package/packages/piagent-core/runtime/inspection/task-baseline-start-capture.ts +22 -0
- package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +160 -0
- package/packages/piagent-core/runtime/inspection/task-control-journal.ts +131 -0
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +95 -0
- package/packages/piagent-core/runtime/inspection/task-provenance-projection.ts +60 -0
- package/packages/piagent-core/runtime/inspection/task-recovery-timeline.ts +88 -0
- package/packages/piagent-core/runtime/inspection/task-run-index.ts +87 -0
- package/packages/piagent-core/runtime/inspection/task-source-projection.ts +401 -0
- package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +101 -0
- package/packages/piagent-core/runtime/inspection/text-diff.ts +60 -0
- package/packages/piagent-core/runtime/inspection/verifier-snapshot-contract.ts +114 -0
- package/packages/piagent-core/runtime/inspection/verifier-snapshot-store.ts +189 -0
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +320 -0
- package/packages/piagent-core/runtime/inspection/workspace-file-reader.ts +132 -0
- package/packages/piagent-core/runtime/inspection/workspace-source-projection.ts +96 -0
- package/packages/piagent-core/runtime/inspection/zero-turn-conformance.ts +175 -0
- package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +93 -6
- package/packages/piagent-core/runtime/policy/block-remedy.ts +139 -0
- package/packages/piagent-core/runtime/policy/source-index-transaction.ts +173 -0
- package/packages/piagent-core/runtime/policy/source-mutation-guard-binding.ts +42 -0
- package/packages/piagent-core/runtime/policy/source-mutation-guard.ts +184 -0
- package/packages/piagent-core/runtime/policy/source-worktree-transaction.ts +105 -0
- package/packages/piagent-core/runtime/product/activity-inspector-footer.ts +5 -3
- package/packages/piagent-core/runtime/product/activity-inspector.ts +85 -343
- package/packages/piagent-core/runtime/recovery/resume-state.ts +38 -1
- package/packages/piagent-core/runtime/registration/activity-inspector-command.ts +68 -14
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +22 -27
- package/packages/piagent-core/runtime/session/model-authorship-state.ts +31 -3
- package/packages/piagent-core/runtime/session/runtime-state.ts +11 -1
- package/packages/piagent-core/runtime/session/token-economics.js +34 -0
- package/packages/piagent-core/runtime/tools/phase-tool-runtime.ts +2 -1
- package/packages/piagent-core/runtime/workflows/task-intake.ts +5 -0
- package/packages/piagent-core/security/sensitive-data.js +7 -0
- package/packages/piagent-webui/dist/client/assets/index-DwKCWbwd.css +1 -0
- package/packages/piagent-webui/dist/client/assets/index-bu7XpD9Q.js +172 -0
- package/packages/piagent-webui/dist/client/index.html +16 -0
- package/packages/piagent-webui/extension/attachment-store.ts +323 -0
- package/packages/piagent-webui/extension/held-message-queue.ts +311 -0
- package/packages/piagent-webui/extension/lifecycle-controller.ts +423 -0
- package/packages/piagent-webui/extension/lifecycle-event-adapter.ts +23 -0
- package/packages/piagent-webui/extension/piagent-webui.ts +470 -0
- package/packages/piagent-webui/extension/review-controller.ts +160 -0
- package/packages/piagent-webui/extension/same-session-bridge.ts +500 -0
- package/packages/piagent-webui/extension/session-options-controller.ts +281 -0
- package/packages/piagent-webui/extension/session-stream-adapter.ts +249 -0
- package/packages/piagent-webui/extension/source-mutation-controller.ts +215 -0
- package/packages/piagent-webui/extension/source-open-controller.ts +136 -0
- package/packages/piagent-webui/extension/source-revert-controller.ts +189 -0
- package/packages/piagent-webui/extension/terminal-session-adapter.ts +73 -0
- package/packages/piagent-webui/extension/vscode-handoff.ts +51 -0
- package/packages/piagent-webui/gateway/control-socket.ts +92 -0
- package/packages/piagent-webui/gateway/extension-authority.ts +47 -0
- package/packages/piagent-webui/gateway/gateway-events.ts +60 -0
- package/packages/piagent-webui/gateway/gateway-protocol-service.ts +64 -0
- package/packages/piagent-webui/gateway/gateway-service.ts +215 -0
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +110 -0
- package/packages/piagent-webui/gateway/mcp-auth-broker.ts +158 -0
- package/packages/piagent-webui/gateway/native-project-picker.ts +29 -0
- package/packages/piagent-webui/gateway/pi-host.ts +41 -0
- package/packages/piagent-webui/gateway/profile-state.ts +1 -0
- package/packages/piagent-webui/gateway/project-registry.ts +108 -0
- package/packages/piagent-webui/gateway/provider-auth-broker.ts +172 -0
- package/packages/piagent-webui/gateway/session-catalog.ts +128 -0
- package/packages/piagent-webui/gateway/session-command-controller.ts +237 -0
- package/packages/piagent-webui/gateway/session-command-store.ts +224 -0
- package/packages/piagent-webui/gateway/session-inspection-registry.ts +239 -0
- package/packages/piagent-webui/gateway/session-lease-store.ts +1 -0
- package/packages/piagent-webui/gateway/session-metadata-store.ts +152 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +489 -0
- package/packages/piagent-webui/ownership/gateway-runtime-context.ts +8 -0
- package/packages/piagent-webui/ownership/profile-state.ts +117 -0
- package/packages/piagent-webui/ownership/session-lease-store.ts +329 -0
- package/packages/piagent-webui/ownership/session-refs.ts +8 -0
- package/packages/piagent-webui/package.json +33 -0
- package/packages/piagent-webui/server/README.md +4 -0
- package/packages/piagent-webui/server/benchmark-release-monitor.ts +230 -0
- package/packages/piagent-webui/server/core-inspection-provider.ts +403 -0
- package/packages/piagent-webui/server/gateway-websocket.ts +143 -0
- package/packages/piagent-webui/server/http-security.ts +27 -0
- package/packages/piagent-webui/server/ipc-read-model-client.ts +89 -0
- package/packages/piagent-webui/server/loopback-server.ts +368 -0
- package/packages/piagent-webui/server/read-model-provider.ts +37 -0
- package/packages/piagent-webui/server/read-only-router.ts +105 -0
- package/packages/piagent-webui/server/session-auth.ts +88 -0
- package/packages/piagent-webui/server/sidecar-main.ts +86 -0
- package/packages/piagent-webui/server/sse-hub.ts +76 -0
- package/packages/piagent-webui/server/static-bundle.ts +40 -0
- package/packages/piagent-webui/server/transcript-projection.ts +125 -0
- package/schemas/mutation-provenance-record.schema.json +100 -0
- package/schemas/piagent-webui/approval-v1.schema.json +654 -0
- package/schemas/piagent-webui/attachment-v1.schema.json +267 -0
- package/schemas/piagent-webui/capabilities-v1.schema.json +729 -0
- package/schemas/piagent-webui/catalog-v1.json +240 -0
- package/schemas/piagent-webui/commit-summary-v1.schema.json +63 -0
- package/schemas/piagent-webui/common-v1.schema.json +479 -0
- package/schemas/piagent-webui/control-command-v1.schema.json +1780 -0
- package/schemas/piagent-webui/diff-v1.schema.json +826 -0
- package/schemas/piagent-webui/gateway-capabilities-v1.schema.json +136 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +456 -0
- package/schemas/piagent-webui/handoff-history-v1.schema.json +92 -0
- package/schemas/piagent-webui/model-catalog-v1.schema.json +95 -0
- package/schemas/piagent-webui/queue-v1.schema.json +99 -0
- package/schemas/piagent-webui/recovery-history-v1.schema.json +144 -0
- package/schemas/piagent-webui/release-monitor-v1.schema.json +173 -0
- package/schemas/piagent-webui/review-state-v1.schema.json +206 -0
- package/schemas/piagent-webui/runtime-event-v2.schema.json +5206 -0
- package/schemas/piagent-webui/session-catalog-v1.schema.json +222 -0
- package/schemas/piagent-webui/session-command-v1.schema.json +390 -0
- package/schemas/piagent-webui/snapshot-v1.schema.json +2622 -0
- package/schemas/piagent-webui/source-change-v1.schema.json +763 -0
- package/schemas/piagent-webui/source-mutation-v1.schema.json +96 -0
- package/schemas/piagent-webui/source-revert-v1.schema.json +130 -0
- package/schemas/piagent-webui/subagent-tree-v1.schema.json +88 -0
- package/schemas/piagent-webui/task-index-v1.schema.json +74 -0
- package/schemas/piagent-webui/task-timeline-v1.schema.json +49 -0
- package/schemas/piagent-webui/transcript-v1.schema.json +243 -0
- package/schemas/task-baseline-manifest.schema.json +122 -0
- package/schemas/verifier-file-snapshot.schema.json +81 -0
- package/scripts/build-docs-site.mjs +21 -1
- package/scripts/check-architecture.mjs +1 -0
- package/scripts/check-doc-languages.mjs +19 -2
- package/scripts/check-third-party-neutrality.mjs +43 -0
- package/scripts/explain-command.mjs +240 -0
- package/scripts/install-global.sh +105 -4
- package/scripts/mcp-manage.mjs +17 -4
- package/scripts/pi-session-stats.sh +10 -2
- package/scripts/piagent-cli.mjs +30 -3
- package/scripts/piagent-dashboard.mjs +261 -0
- package/scripts/piagent-webui-launcher.mjs +121 -0
- package/scripts/setup.sh +69 -33
- package/scripts/traffic-snapshot.mjs +214 -0
- package/scripts/typescript-loader.mjs +42 -1
- package/scripts/uninstall-global.sh +53 -2
- package/scripts/update-global.mjs +33 -1
- package/scripts/verify-local.sh +257 -0
- package/scripts/verify-release-identity.mjs +4 -1
- package/scripts/verify-translation-pairing.mjs +121 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Answers the one question the guard never answers: why.
|
|
3
|
+
//
|
|
4
|
+
// A blocked command is the only interface most operators ever have with this
|
|
5
|
+
// policy, and a denial that says "no" without saying "what now" leaves them
|
|
6
|
+
// guessing. This runs the guard's static shell preflight, in the same order,
|
|
7
|
+
// over the same resolved protected paths, and prints what each step saw.
|
|
8
|
+
//
|
|
9
|
+
// It reuses `shell-reach.js` rather than re-deriving anything. A second opinion
|
|
10
|
+
// about what a command reaches would be worse than no opinion: the operator
|
|
11
|
+
// would tune a command until this said allow and still be blocked at run time.
|
|
12
|
+
// The final decision also depends on live session/task facts this standalone
|
|
13
|
+
// process does not own, so passing static preflight is deliberately reported as
|
|
14
|
+
// indeterminate rather than as permission to execute.
|
|
15
|
+
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
|
|
18
|
+
import { evaluateExecPolicyCore, findProtectedPathInCommand, unresolvedPathExpansions } from "../packages/piagent-core/extensions/policy-core.js";
|
|
19
|
+
import {
|
|
20
|
+
findResolvedProtectedPathInCommand,
|
|
21
|
+
shellGlobTargetsProtectedPath,
|
|
22
|
+
unresolvedExpansionReason
|
|
23
|
+
// `.ts` rather than the `.js` specifier the TypeScript sources use: this file is
|
|
24
|
+
// plain ESM, so the loader resolves what is actually on disk.
|
|
25
|
+
} from "../packages/piagent-core/extensions/shell-reach.ts";
|
|
26
|
+
import { effectiveProtectedPaths, loadProjectContextIndexPolicy } from "../packages/piagent-core/extensions/context-index-policy.js";
|
|
27
|
+
|
|
28
|
+
const platformRoot = path.resolve(import.meta.dirname, "..");
|
|
29
|
+
|
|
30
|
+
function usage() {
|
|
31
|
+
return [
|
|
32
|
+
"Usage: piagent explain <command> [--project <path>] [--json]",
|
|
33
|
+
" piagent explain --scope [--project <path>] [--json]",
|
|
34
|
+
"",
|
|
35
|
+
"Prints a fail-closed static preflight for a shell command and what to do",
|
|
36
|
+
"next. A static pass is indeterminate until the live Pi runtime evaluates",
|
|
37
|
+
"Task Contract, scope, permission, lifecycle, approval, and budget state.",
|
|
38
|
+
"Nothing is executed.",
|
|
39
|
+
"",
|
|
40
|
+
" --scope List the boundary in effect instead of judging a command",
|
|
41
|
+
" --project <path> Evaluate against this project's profile (default: cwd)",
|
|
42
|
+
" --json Machine-readable output",
|
|
43
|
+
" -h, --help Show this help"
|
|
44
|
+
].join("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseArgs(argv) {
|
|
48
|
+
let project = process.cwd(), json = false, scope = false;
|
|
49
|
+
const words = [];
|
|
50
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
51
|
+
const value = argv[index];
|
|
52
|
+
if (value === "-h" || value === "--help") return { help: true };
|
|
53
|
+
if (value === "--json") { json = true; continue; }
|
|
54
|
+
if (value === "--scope") { scope = true; continue; }
|
|
55
|
+
if (value === "--project") {
|
|
56
|
+
const next = argv[index += 1];
|
|
57
|
+
if (!next || next.startsWith("--")) throw new Error("--project needs a path");
|
|
58
|
+
project = path.resolve(next);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (value.startsWith("--")) throw new Error(`Unknown option: ${value}`);
|
|
62
|
+
words.push(value);
|
|
63
|
+
}
|
|
64
|
+
return { help: false, project, json, scope, command: words.join(" ").trim() };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// What the operator should do next. The guard states 74 refusals and only three
|
|
68
|
+
// of them say this, which is why a denial so often ends the conversation.
|
|
69
|
+
const REMEDY = {
|
|
70
|
+
"protected-path": "Use an approved context projection if one is available. Direct access requires the operator to change the protected-path policy; task scope alone does not override it.",
|
|
71
|
+
"protected-glob": "Name the file you mean instead of a pattern; a pattern is refused when any name it can match is protected.",
|
|
72
|
+
"resolved-protected": "The path resolves to a protected file through a link or a parent directory. Use the real path you intend.",
|
|
73
|
+
"unresolved": "Write the path out, or put the expansion in its own argument, so the guard can see what is being opened.",
|
|
74
|
+
"exec-policy": "This is refused by an exec-policy rule, not by a path. Change the command, or ask the operator to run it.",
|
|
75
|
+
"runtime-required": "Run the command through the current Pi session. Only that runtime owns the Task Contract, scope, permission, lifecycle, approval, and budget facts needed for a final decision."
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const RUNTIME_GATES = [
|
|
79
|
+
"task-contract",
|
|
80
|
+
"task-scope",
|
|
81
|
+
"permission-profile",
|
|
82
|
+
"lifecycle-control",
|
|
83
|
+
"approval-state",
|
|
84
|
+
"context-budget"
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
function explain(command, protectedPaths, policy, cwd) {
|
|
88
|
+
const steps = [];
|
|
89
|
+
const record = (name, hit, detail) => { steps.push({ step: name, matched: Boolean(hit), detail }); return hit; };
|
|
90
|
+
|
|
91
|
+
const exec = evaluateExecPolicyCore(command, { policy, mode: "enforce" });
|
|
92
|
+
record("exec-policy", exec.decision === "forbid", exec.reasons.length ? exec.reasons.join("; ") : "no rule matched");
|
|
93
|
+
if (exec.decision === "forbid") {
|
|
94
|
+
return { decision: "deny", kind: "exec-policy", confidence: "exact", reason: exec.reasons.join("; "), steps, exec };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const literal = findProtectedPathInCommand(command, protectedPaths);
|
|
98
|
+
record("literal-path", literal, literal ? `${literal.candidate} matches ${literal.pattern}` : "no word names a protected path");
|
|
99
|
+
if (literal) {
|
|
100
|
+
return {
|
|
101
|
+
decision: "deny", kind: "protected-path", confidence: "exact",
|
|
102
|
+
reason: `Command touches protected path: ${literal.candidate} matches ${literal.pattern}`, steps, exec
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const glob = shellGlobTargetsProtectedPath(command, protectedPaths);
|
|
107
|
+
record("glob", glob, glob ? `${glob.glob} can match ${glob.example} via ${glob.pattern}` : "no pattern can reach a protected name");
|
|
108
|
+
if (glob) {
|
|
109
|
+
return {
|
|
110
|
+
decision: "deny", kind: "protected-glob",
|
|
111
|
+
// A pattern is matched against generated examples of each protected
|
|
112
|
+
// pattern, not against the filesystem, so this answers for names that may
|
|
113
|
+
// not exist. That is deliberate, and worth saying out loud.
|
|
114
|
+
confidence: "over-approximate",
|
|
115
|
+
reason: `Command glob can target protected path: ${glob.glob} can match ${glob.example} via ${glob.pattern}`, steps, exec
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const resolved = findResolvedProtectedPathInCommand(cwd, command, protectedPaths);
|
|
120
|
+
record("resolved-path", resolved, resolved ? `${resolved.candidate} resolves to ${resolved.resolved}` : "no candidate resolves onto a protected path");
|
|
121
|
+
if (resolved) {
|
|
122
|
+
return {
|
|
123
|
+
decision: "deny", kind: "resolved-protected", confidence: "exact",
|
|
124
|
+
reason: `Command resolves to protected path: ${resolved.candidate} resolves to ${resolved.resolved} matching ${resolved.pattern}`, steps, exec
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const unresolved = protectedPaths.length > 0 ? unresolvedPathExpansions(command) : [];
|
|
129
|
+
record("unresolved-expansion", unresolved.length > 0, unresolved.length ? unresolved.join(", ") : "every path is resolvable");
|
|
130
|
+
if (unresolved.length > 0) {
|
|
131
|
+
return {
|
|
132
|
+
decision: "deny", kind: "unresolved",
|
|
133
|
+
// Nothing was proven to be protected here. The command is refused because
|
|
134
|
+
// its target is unknowable before it runs, which is a different statement
|
|
135
|
+
// and leads the operator to a different fix.
|
|
136
|
+
confidence: "unknown-target",
|
|
137
|
+
reason: unresolvedExpansionReason("Command", unresolved), steps, exec
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const staticDecision = exec.decision === "prompt" ? "confirm" : "allow";
|
|
142
|
+
return {
|
|
143
|
+
decision: "indeterminate", kind: "runtime-required", confidence: "runtime-required",
|
|
144
|
+
staticDecision,
|
|
145
|
+
reason: staticDecision === "confirm"
|
|
146
|
+
? `Static preflight requires confirmation (${exec.reasons.join("; ")}), but the live runtime may still block it.`
|
|
147
|
+
: "Static preflight found no refusal. A final decision requires live session and task state.",
|
|
148
|
+
remainingGates: RUNTIME_GATES,
|
|
149
|
+
steps, exec
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function render(result, context) {
|
|
154
|
+
const lines = [`decision: ${result.decision}`, ""];
|
|
155
|
+
lines.push(` reason ${result.reason}`);
|
|
156
|
+
lines.push(` confidence ${result.confidence}`);
|
|
157
|
+
if (result.staticDecision) lines.push(` static ${result.staticDecision}`);
|
|
158
|
+
lines.push(` remedy ${REMEDY[result.kind] ?? REMEDY["runtime-required"]}`);
|
|
159
|
+
if (result.remainingGates?.length) lines.push(` still needs ${result.remainingGates.join(", ")}`);
|
|
160
|
+
lines.push("", " static chain (the order the guard asks these):");
|
|
161
|
+
for (const step of result.steps) {
|
|
162
|
+
lines.push(` ${step.matched ? "HIT " : " "} ${step.step.padEnd(20)} ${step.detail}`);
|
|
163
|
+
}
|
|
164
|
+
lines.push("", ` profile ${context.profileSource} (${context.profilePath})`);
|
|
165
|
+
lines.push(` protected ${context.protectedPaths.length} patterns in effect`);
|
|
166
|
+
return lines.join("\n");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function renderScope(loaded, effective) {
|
|
170
|
+
const lines = ["boundary in effect", ""];
|
|
171
|
+
lines.push(` profile ${loaded.profileSource} (${loaded.profilePath})`);
|
|
172
|
+
lines.push(` mode ${loaded.profile.mode ?? "unset"}`);
|
|
173
|
+
if (typeof loaded.profile.displayName === "string") lines.push(` project ${loaded.profile.displayName}`);
|
|
174
|
+
// Packs are `{name, version}` records, not names, so joining them raw printed
|
|
175
|
+
// `[object Object]` where the operator expected to read what is loaded.
|
|
176
|
+
const packs = (Array.isArray(loaded.profile.capabilityPacks) ? loaded.profile.capabilityPacks : [])
|
|
177
|
+
.map((pack) => (pack && typeof pack === "object" ? `${pack.name}@${pack.version}` : String(pack)));
|
|
178
|
+
lines.push(` packs ${packs.length > 0 ? packs.join(", ") : "none"}`);
|
|
179
|
+
for (const [label, key] of [
|
|
180
|
+
["shell", "shellProtectedPaths"],
|
|
181
|
+
["read", "readProtectedPaths"],
|
|
182
|
+
["write", "writeProtectedPaths"],
|
|
183
|
+
["read-only", "readOnlyPaths"]
|
|
184
|
+
]) {
|
|
185
|
+
const values = effective[key];
|
|
186
|
+
lines.push("", ` ${label} (${values.length})`);
|
|
187
|
+
for (const value of values) lines.push(` ${value}`);
|
|
188
|
+
if (values.length === 0) lines.push(" (none)");
|
|
189
|
+
}
|
|
190
|
+
return lines.join("\n");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let parsed;
|
|
194
|
+
try {
|
|
195
|
+
parsed = parseArgs(process.argv.slice(2));
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error(`FAIL: ${error.message}\n\n${usage()}`);
|
|
198
|
+
process.exit(2);
|
|
199
|
+
}
|
|
200
|
+
if (parsed.help) { process.stdout.write(`${usage()}\n`); process.exit(0); }
|
|
201
|
+
if (!parsed.command && !parsed.scope) { console.error(`FAIL: nothing to explain\n\n${usage()}`); process.exit(2); }
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const loaded = loadProjectContextIndexPolicy(platformRoot, parsed.project, { profilePath: process.env.PIAGENT_PROFILE });
|
|
205
|
+
const effective = effectiveProtectedPaths(loaded.policy, loaded.profile);
|
|
206
|
+
const protectedPaths = effective.shellProtectedPaths;
|
|
207
|
+
if (parsed.scope) {
|
|
208
|
+
// The boundary is otherwise only visible by running into it.
|
|
209
|
+
if (parsed.json) {
|
|
210
|
+
process.stdout.write(`${JSON.stringify({
|
|
211
|
+
profileSource: loaded.profileSource, profilePath: loaded.profilePath,
|
|
212
|
+
mode: loaded.profile.mode ?? null, capabilityPacks: loaded.profile.capabilityPacks ?? [], ...effective
|
|
213
|
+
}, null, 2)}\n`);
|
|
214
|
+
} else {
|
|
215
|
+
process.stdout.write(`${renderScope(loaded, effective)}\n`);
|
|
216
|
+
}
|
|
217
|
+
process.exit(0);
|
|
218
|
+
}
|
|
219
|
+
const result = explain(parsed.command, protectedPaths, loaded.policy, parsed.project);
|
|
220
|
+
const context = { profileSource: loaded.profileSource, profilePath: loaded.profilePath, protectedPaths };
|
|
221
|
+
if (parsed.json) {
|
|
222
|
+
process.stdout.write(`${JSON.stringify({
|
|
223
|
+
command: parsed.command, decision: result.decision, kind: result.kind, confidence: result.confidence,
|
|
224
|
+
reason: result.reason, remedy: REMEDY[result.kind] ?? REMEDY["runtime-required"],
|
|
225
|
+
staticDecision: result.staticDecision ?? null,
|
|
226
|
+
remainingGates: result.remainingGates ?? [], steps: result.steps,
|
|
227
|
+
protectedPatternCount: protectedPaths.length, profileSource: loaded.profileSource
|
|
228
|
+
}, null, 2)}\n`);
|
|
229
|
+
} else {
|
|
230
|
+
process.stdout.write(`${render(result, context)}\n`);
|
|
231
|
+
}
|
|
232
|
+
// Exit status is a permission signal for existing shell callers: 0 is reserved
|
|
233
|
+
// for commands that are conclusively allowed. This standalone process can no
|
|
234
|
+
// longer make that claim; 1 is a conclusive static denial and 2 means the live
|
|
235
|
+
// runtime still has to decide.
|
|
236
|
+
process.exit(result.decision === "deny" ? 1 : 2);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error(`FAIL: ${error instanceof Error ? error.message : String(error)}`);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
@@ -4,7 +4,32 @@ set -euo pipefail
|
|
|
4
4
|
usage() {
|
|
5
5
|
cat <<'USAGE'
|
|
6
6
|
Usage:
|
|
7
|
-
scripts/install-global.sh [--stable|--dev|--local|--channel <stable|dev|local>] [--version <tag>] [--resolve-tag] [--package-source <source>] [--dry-run] [--with-mcp|--no-mcp] [--mcp-preset <preset>] [--with-subagents|--no-subagents] [--subagents-preset <preset>] [--with-web-access|--no-web-access] [--with-herdr] [--model-scope <preset>|--no-model-scope]
|
|
7
|
+
scripts/install-global.sh [--stable|--dev|--local|--channel <stable|dev|local>] [--version <tag>] [--resolve-tag] [--package-source <source>] [--dry-run] [--with-mcp|--no-mcp] [--mcp-preset <preset>] [--with-subagents|--no-subagents] [--subagents-preset <preset>] [--subagents-model-scope <scope>] [--with-web-access|--no-web-access] [--with-herdr] [--model-scope <preset>|--no-model-scope] [--default-model <model>] [-h|--help]
|
|
8
|
+
|
|
9
|
+
Options:
|
|
10
|
+
--channel <stable|dev|local> Package channel; --stable/--dev/--local are shorthands.
|
|
11
|
+
--version, --tag <tag> Pin a release tag (pair with --resolve-tag for a SHA).
|
|
12
|
+
--resolve-tag Resolve the tag to a commit SHA before installing.
|
|
13
|
+
--package-source <source> Explicit package source; overrides the channel.
|
|
14
|
+
--dry-run Print the planned steps without changing user config.
|
|
15
|
+
--with-mcp | --no-mcp Install the MCP adapter (default: install).
|
|
16
|
+
--mcp-preset <preset> MCP server set (default: core).
|
|
17
|
+
--with-subagents | --no-subagents
|
|
18
|
+
Install pi-subagents (default: only if already present).
|
|
19
|
+
--subagents-preset <minimal|safe|async|parallel>
|
|
20
|
+
Subagent runtime preset (default: safe).
|
|
21
|
+
--subagents-model-scope <none|piagent|codex|claude>
|
|
22
|
+
Model family the subagents run on (default: none).
|
|
23
|
+
--with-web-access | --no-web-access
|
|
24
|
+
Install pi-web-access for the researcher subagent (default: install).
|
|
25
|
+
--with-herdr Also configure Herdr integration.
|
|
26
|
+
--model-scope <full|codex|claude>
|
|
27
|
+
Model families to enable in Pi (default: full).
|
|
28
|
+
--no-model-scope Leave the user's enabledModels untouched.
|
|
29
|
+
--default-model <provider/model[:thinking]>
|
|
30
|
+
Default model written to Pi settings
|
|
31
|
+
(default: openai-codex/gpt-5.5:high).
|
|
32
|
+
-h, --help Print this help and exit.
|
|
8
33
|
|
|
9
34
|
Purpose:
|
|
10
35
|
Install the piagent Pi package into the current user's global Pi settings.
|
|
@@ -74,6 +99,7 @@ RESOLVE_TAG=false
|
|
|
74
99
|
RESOLVED_PACKAGE_TAG=""
|
|
75
100
|
RESOLVED_PACKAGE_COMMIT=""
|
|
76
101
|
CLI_PACKAGE_SELECTOR=""
|
|
102
|
+
LOCAL_HELPER_PREFIX="${PIAGENT_LOCAL_HELPER_PREFIX:-}"
|
|
77
103
|
PI_MCP_ADAPTER_SOURCE="npm:pi-mcp-adapter@2.15.0"
|
|
78
104
|
PI_SUBAGENTS_SOURCE="npm:pi-subagents@0.38.0"
|
|
79
105
|
PI_WEB_ACCESS_SOURCE="npm:pi-web-access@0.17.0"
|
|
@@ -181,6 +207,61 @@ run_cmd() {
|
|
|
181
207
|
fi
|
|
182
208
|
}
|
|
183
209
|
|
|
210
|
+
active_piagent_helper_prefix() {
|
|
211
|
+
if [[ -n "$LOCAL_HELPER_PREFIX" ]]; then
|
|
212
|
+
printf '%s\n' "$LOCAL_HELPER_PREFIX"
|
|
213
|
+
return 0
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
local helper_command
|
|
217
|
+
helper_command="$(command -v piagent 2>/dev/null || true)"
|
|
218
|
+
[[ -n "$helper_command" ]] || return 1
|
|
219
|
+
|
|
220
|
+
node --input-type=module - "$helper_command" <<'NODE'
|
|
221
|
+
import fs from "node:fs";
|
|
222
|
+
import path from "node:path";
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const command = path.resolve(process.argv[2]);
|
|
226
|
+
if (path.basename(path.dirname(command)) === "bin") {
|
|
227
|
+
process.stdout.write(`${path.dirname(path.dirname(command))}\n`);
|
|
228
|
+
process.exit(0);
|
|
229
|
+
}
|
|
230
|
+
const target = fs.realpathSync(command);
|
|
231
|
+
const marker = `${path.sep}lib${path.sep}node_modules${path.sep}@piagent${path.sep}platform${path.sep}`;
|
|
232
|
+
const index = target.indexOf(marker);
|
|
233
|
+
if (index <= 0) process.exit(1);
|
|
234
|
+
process.stdout.write(`${target.slice(0, index)}\n`);
|
|
235
|
+
} catch {
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
NODE
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
sync_local_helper() {
|
|
242
|
+
[[ "$RESOLVED_CHANNEL_LABEL" == "local" ]] || return 0
|
|
243
|
+
|
|
244
|
+
if ! command -v npm >/dev/null 2>&1; then
|
|
245
|
+
echo "FAIL: npm is required to synchronize the local Piagent helper and Gateway runtime." >&2
|
|
246
|
+
exit 1
|
|
247
|
+
fi
|
|
248
|
+
|
|
249
|
+
local prefix="" used_fallback=false
|
|
250
|
+
prefix="$(active_piagent_helper_prefix 2>/dev/null || true)"
|
|
251
|
+
if [[ -z "$prefix" ]]; then
|
|
252
|
+
prefix="${HOME}/.pi/npm-global"
|
|
253
|
+
used_fallback=true
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
echo "Synchronizing local terminal helper and Gateway runtime:"
|
|
257
|
+
run_cmd npm install -g --ignore-scripts --prefix "$prefix" "$PLATFORM_ROOT"
|
|
258
|
+
|
|
259
|
+
if [[ "$used_fallback" == true ]]; then
|
|
260
|
+
echo "NOTE: no existing Piagent helper was found; the local helper was installed under $prefix." >&2
|
|
261
|
+
echo "NOTE: add $prefix/bin to PATH if piagent is not found after this run." >&2
|
|
262
|
+
fi
|
|
263
|
+
}
|
|
264
|
+
|
|
184
265
|
resolve_user_package_path() {
|
|
185
266
|
local source="$1"
|
|
186
267
|
local pi_agent_dir="${PI_CODING_AGENT_DIR:-"${HOME}/.pi/agent"}"
|
|
@@ -285,10 +366,29 @@ verify_npm_integrity() {
|
|
|
285
366
|
echo "FAIL: npm is required to verify package integrity for $package_spec." >&2
|
|
286
367
|
exit 1
|
|
287
368
|
fi
|
|
288
|
-
local actual
|
|
289
|
-
|
|
369
|
+
# The status is captured rather than left to `set -e`. Declaring `local actual`
|
|
370
|
+
# and assigning on the next line makes the command substitution's own status the
|
|
371
|
+
# status of the assignment, so under `pipefail` an unreachable registry -- no
|
|
372
|
+
# network, a proxy, a private registry, an npm outage -- killed the script on
|
|
373
|
+
# this line. The `FAIL:` below was never reached and npm's stderr was already
|
|
374
|
+
# discarded, so the run ended with an empty screen and exit 1, after `pi install`
|
|
375
|
+
# had already succeeded. The operator was left half-installed with no reason
|
|
376
|
+
# given. (Writing `local actual="$(...)"` also avoids the exit, but by hiding the
|
|
377
|
+
# failure inside the empty-value branch, which then reports a digest mismatch --
|
|
378
|
+
# a security message for what is usually a network problem.)
|
|
379
|
+
local actual="" status=0
|
|
380
|
+
actual="$(npm view "$package_spec" dist.integrity 2>/dev/null | tr -d '\r\n')" || status=$?
|
|
381
|
+
if [[ "$status" -ne 0 ]]; then
|
|
382
|
+
echo "FAIL: could not reach the npm registry to verify $package_spec (npm exited $status)." >&2
|
|
383
|
+
echo " Nothing further was installed. Check network, proxy, or registry auth," >&2
|
|
384
|
+
echo " then re-run. To see npm's own message: npm view $package_spec dist.integrity" >&2
|
|
385
|
+
exit 1
|
|
386
|
+
fi
|
|
290
387
|
if [[ -z "$actual" || "$actual" != "$expected" ]]; then
|
|
291
388
|
echo "FAIL: registry integrity does not match the approved digest for $package_spec." >&2
|
|
389
|
+
echo " approved: $expected" >&2
|
|
390
|
+
echo " registry: ${actual:-<empty>}" >&2
|
|
391
|
+
echo " Do not proceed. The published package differs from the reviewed release." >&2
|
|
292
392
|
exit 1
|
|
293
393
|
fi
|
|
294
394
|
}
|
|
@@ -609,6 +709,7 @@ if [[ -n "$RESOLVED_PACKAGE_COMMIT" ]]; then
|
|
|
609
709
|
echo " resolvedCommit: $RESOLVED_PACKAGE_COMMIT"
|
|
610
710
|
fi
|
|
611
711
|
echo " source: $PACKAGE_SOURCE"
|
|
712
|
+
sync_local_helper
|
|
612
713
|
echo "Removing previous Pi Agent Platform package registrations:"
|
|
613
714
|
remove_existing_piagent_platform_sources
|
|
614
715
|
run_cmd pi install "$PACKAGE_SOURCE"
|
|
@@ -677,7 +778,7 @@ echo " /login"
|
|
|
677
778
|
echo " /model # or Ctrl+L: select provider/model from Pi selector"
|
|
678
779
|
echo " /scoped-models # optional: edit Ctrl+P model cycle scope"
|
|
679
780
|
if [[ "$WITH_MCP" == true ]]; then
|
|
680
|
-
echo " /mcp # inspect MCP servers; authenticate
|
|
781
|
+
echo " /mcp # inspect MCP servers; authenticate approved remote servers only when needed"
|
|
681
782
|
fi
|
|
682
783
|
echo " /subagents-doctor"
|
|
683
784
|
echo " /workflow task Implement <task> # parent may auto-delegate scout/planner/reviewer"
|
package/scripts/mcp-manage.mjs
CHANGED
|
@@ -536,7 +536,7 @@ function commandPreset(args) {
|
|
|
536
536
|
presets: CATALOG_PRESETS,
|
|
537
537
|
servers: Object.fromEntries(Object.entries(CATALOG_SERVERS).map(([name, server]) => [
|
|
538
538
|
name,
|
|
539
|
-
{ description: server.description, requires: CATALOG_PREREQUISITES[name] ?? [] }
|
|
539
|
+
{ description: server.description, maturity: server.maturity ?? "stable", requires: CATALOG_PREREQUISITES[name] ?? [] }
|
|
540
540
|
]))
|
|
541
541
|
}, null, 2)}\n`);
|
|
542
542
|
return 0;
|
|
@@ -563,7 +563,9 @@ function commandPreset(args) {
|
|
|
563
563
|
const added = [];
|
|
564
564
|
const kept = [];
|
|
565
565
|
const replaced = [];
|
|
566
|
-
|
|
566
|
+
const resolvedPreset = resolvePreset(presetName);
|
|
567
|
+
const experimental = resolvedPreset.filter((server) => server.maturity === "experimental").map((server) => server.name);
|
|
568
|
+
for (const server of resolvedPreset) {
|
|
567
569
|
if (Object.hasOwn(config.mcpServers, server.name)) {
|
|
568
570
|
if (!replace) {
|
|
569
571
|
kept.push(server.name);
|
|
@@ -585,6 +587,7 @@ function commandPreset(args) {
|
|
|
585
587
|
added,
|
|
586
588
|
kept,
|
|
587
589
|
replaced,
|
|
590
|
+
experimental,
|
|
588
591
|
serverCount: Object.keys(config.mcpServers).length
|
|
589
592
|
};
|
|
590
593
|
|
|
@@ -594,11 +597,21 @@ function commandPreset(args) {
|
|
|
594
597
|
return 0;
|
|
595
598
|
}
|
|
596
599
|
|
|
600
|
+
// Warn before the write. Naming a Google preset is explicit, but it is not
|
|
601
|
+
// evidence that the operator knows the endpoint is pre-GA or that Pi OAuth
|
|
602
|
+
// has not passed a credentialed release gate yet.
|
|
603
|
+
if (experimental.length > 0) {
|
|
604
|
+
process.stderr.write(
|
|
605
|
+
`\nEXPERIMENTAL: ${experimental.join(", ")} use Google Workspace Developer Preview endpoints. `
|
|
606
|
+
+ "They are not part of the default presets and have no Pi OAuth end-to-end release proof yet.\n"
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
|
|
597
610
|
writeMcpConfig(file, config);
|
|
598
611
|
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
599
612
|
|
|
600
|
-
// stdout stays machine-readable;
|
|
601
|
-
const lines =
|
|
613
|
+
// stdout stays machine-readable; operator notes go to stderr.
|
|
614
|
+
const lines = resolvedPreset.flatMap((server) => server.requires.map((item) => ` ${server.name}: ${item}`));
|
|
602
615
|
if (lines.length > 0) {
|
|
603
616
|
process.stderr.write("\nServer definitions are written. Each still needs this before it can connect:\n");
|
|
604
617
|
for (const line of lines) process.stderr.write(`${line}\n`);
|
|
@@ -108,8 +108,13 @@ RPC_OUTPUT="$(
|
|
|
108
108
|
| pi -ne --mode rpc --session "$SESSION_FILE" --offline --approve
|
|
109
109
|
)"
|
|
110
110
|
|
|
111
|
-
node --input-type=module - "$RPC_OUTPUT" <<'NODE'
|
|
111
|
+
node --input-type=module - "$RPC_OUTPUT" "$SCRIPT_DIR/../packages/piagent-core/runtime/session/token-economics.js" <<'NODE'
|
|
112
|
+
import { pathToFileURL } from "node:url";
|
|
113
|
+
|
|
112
114
|
const input = process.argv[2] ?? "";
|
|
115
|
+
// The token arithmetic lives in a module both this command and its test can
|
|
116
|
+
// read, so the terminal cannot drift from the definition the benchmark uses.
|
|
117
|
+
const { sessionTokenEconomics, formatTokenEconomics } = await import(pathToFileURL(process.argv[3]).href);
|
|
113
118
|
|
|
114
119
|
const line = input
|
|
115
120
|
.split(/\n+/)
|
|
@@ -126,6 +131,7 @@ const input = process.argv[2] ?? "";
|
|
|
126
131
|
const data = response.data;
|
|
127
132
|
const tokens = data.tokens ?? {};
|
|
128
133
|
const context = data.contextUsage ?? {};
|
|
134
|
+
const economics = sessionTokenEconomics(tokens);
|
|
129
135
|
const number = (value) => value === null || value === undefined ? "unknown" : Math.round(Number(value)).toLocaleString("en-US");
|
|
130
136
|
const money = (value) => value === null || value === undefined ? "unknown" : `$${Number(value).toFixed(6)}`;
|
|
131
137
|
const percent = (value) => value === null || value === undefined ? "unknown" : `${Number(value).toFixed(1)}%`;
|
|
@@ -144,7 +150,8 @@ const input = process.argv[2] ?? "";
|
|
|
144
150
|
output: tokens.output ?? null,
|
|
145
151
|
cacheRead: tokens.cacheRead ?? null,
|
|
146
152
|
cacheWrite: tokens.cacheWrite ?? null,
|
|
147
|
-
total: tokens.total ?? null
|
|
153
|
+
total: tokens.total ?? null,
|
|
154
|
+
...economics
|
|
148
155
|
},
|
|
149
156
|
cost: data.cost ?? null,
|
|
150
157
|
contextUsage: context.tokens === undefined ? null : {
|
|
@@ -154,6 +161,7 @@ const input = process.argv[2] ?? "";
|
|
|
154
161
|
},
|
|
155
162
|
summary: {
|
|
156
163
|
tokens: `${number(tokens.total)} total (${number(tokens.input)} input, ${number(tokens.output)} output, ${number(tokens.cacheRead)} cache read, ${number(tokens.cacheWrite)} cache write)`,
|
|
164
|
+
...formatTokenEconomics(economics, number, percent),
|
|
157
165
|
cost: money(data.cost),
|
|
158
166
|
context: context.tokens === undefined ? "unknown" : `${number(context.tokens)} / ${number(context.contextWindow)} (${percent(context.percent)})`
|
|
159
167
|
}
|
package/scripts/piagent-cli.mjs
CHANGED
|
@@ -23,12 +23,39 @@ const scriptByCommand = {
|
|
|
23
23
|
"piagent-migrate": "scripts/migrate-project-state.mjs",
|
|
24
24
|
"piagent-import-instructions": "scripts/import-agent-instructions.mjs",
|
|
25
25
|
"piagent-auto": "scripts/pi-auto.sh",
|
|
26
|
-
"piagent-context": "scripts/context-engine.mjs"
|
|
26
|
+
"piagent-context": "scripts/context-engine.mjs",
|
|
27
|
+
"piagent-explain": "scripts/explain-command.mjs",
|
|
28
|
+
"piagent-webui": "scripts/piagent-webui-launcher.mjs",
|
|
29
|
+
"piagent-dashboard": "scripts/piagent-dashboard.mjs"
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
30
33
|
const invokedAs = path.basename(process.argv[1] ?? "");
|
|
31
|
-
|
|
34
|
+
let forwardedArgs = process.argv.slice(2);
|
|
35
|
+
let script = scriptByCommand[invokedAs];
|
|
36
|
+
|
|
37
|
+
if (invokedAs === "piagent") {
|
|
38
|
+
const subcommand = forwardedArgs[0];
|
|
39
|
+
if (subcommand === "dashboard") {
|
|
40
|
+
script = "scripts/piagent-dashboard.mjs";
|
|
41
|
+
forwardedArgs = forwardedArgs.slice(1);
|
|
42
|
+
} else if (subcommand === "explain") {
|
|
43
|
+
script = "scripts/explain-command.mjs";
|
|
44
|
+
forwardedArgs = forwardedArgs.slice(1);
|
|
45
|
+
} else if ([undefined, "help", "--help", "-h"].includes(subcommand)) {
|
|
46
|
+
// Subcommands are listed, their flags are not. Restating them here meant a
|
|
47
|
+
// second copy that drifts: this line still advertised the dashboard without
|
|
48
|
+
// `--repair` after that flag shipped. Each command states its own surface.
|
|
49
|
+
console.log("Usage: piagent <command> [options]");
|
|
50
|
+
console.log("");
|
|
51
|
+
console.log("Commands:");
|
|
52
|
+
console.log(" dashboard Open and manage the local session hub");
|
|
53
|
+
console.log(" explain Say why the guard would allow or block a shell command");
|
|
54
|
+
console.log("");
|
|
55
|
+
console.log("Run `piagent <command> --help` for that command's options.");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
32
59
|
|
|
33
60
|
if (!script) {
|
|
34
61
|
console.error(`Unknown Pi Agent command: ${invokedAs || "(unknown)"}`);
|
|
@@ -58,7 +85,7 @@ const runner = target.endsWith(".mjs") ? process.execPath : "bash";
|
|
|
58
85
|
const runnerArgs = target.endsWith(".mjs")
|
|
59
86
|
? ["--disable-warning=ExperimentalWarning", "--import", path.join(sourceRoot, "scripts", "register-typescript-loader.mjs"), target]
|
|
60
87
|
: [target];
|
|
61
|
-
const child = spawn(runner, [...runnerArgs, ...
|
|
88
|
+
const child = spawn(runner, [...runnerArgs, ...forwardedArgs], {
|
|
62
89
|
cwd: process.cwd(),
|
|
63
90
|
env: process.env,
|
|
64
91
|
stdio: "inherit"
|