gentle-pi 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -18
- package/assets/agents/gentle-ai-explore.md +11 -4
- package/assets/agents/gentle-ai-verify.md +23 -4
- package/assets/agents/gentle-ai-worker.md +6 -6
- package/assets/install-wizard/index.html +47 -0
- package/assets/install-wizard/wizard.css +1279 -0
- package/assets/install-wizard/wizard.js +951 -0
- package/assets/orchestrator-delegation.md +70 -163
- package/assets/orchestrator-memory.md +11 -4
- package/assets/orchestrator-prompts.md +48 -0
- package/assets/orchestrator-tracking.md +53 -0
- package/assets/orchestrator-verification.md +28 -0
- package/assets/orchestrator-writer.md +38 -0
- package/assets/orchestrator.md +29 -25
- package/assets/sounds/LICENSE.md +52 -0
- package/assets/sounds/attention.wav +0 -0
- package/assets/sounds/error.wav +0 -0
- package/assets/sounds/success.wav +0 -0
- package/bin/engram-guard +9 -0
- package/bin/gentle-shell-install.mjs +302 -0
- package/bin/gentle-shell.mjs +708 -22
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +7 -7
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/manifest.json +2 -2
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/orchestration/pi.md +16 -4
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-capabilities.baseline.json +2 -2
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-roles.baseline.json +1 -1
- package/docs/auto-permission-answers.md +25 -0
- package/docs/auto-permission-evidence.md +39 -0
- package/docs/bundled-install.md +399 -0
- package/docs/delegated-verification.md +3 -5
- package/docs/gentle-agents-activity.md +513 -0
- package/docs/gentle-shell-uninstall.md +136 -0
- package/docs/gentle-shell.md +90 -33
- package/docs/install-wizard.md +2040 -0
- package/docs/native-authority-architecture.md +1 -1
- package/docs/permission-modes.md +127 -0
- package/docs/prompt-history.md +1 -1
- package/docs/readme-reference.md +310 -47
- package/docs/render-cache-performance.md +28 -0
- package/docs/session-profile-format.md +39 -0
- package/docs/sound-notifications-proposal.md +191 -0
- package/docs/sound-notifications.md +114 -0
- package/docs/yolo-mode.md +11 -10
- package/extensions/ask-user-choice.ts +4 -0
- package/extensions/ask-user-question.ts +6 -1
- package/extensions/child-context.ts +11 -2
- package/extensions/child-safety.ts +4 -2
- package/extensions/codegraph-tools.ts +18 -5
- package/extensions/gentle-agents.ts +718 -87
- package/extensions/gentle-ai.ts +991 -263
- package/extensions/gentle-herdr-activity.ts +81 -0
- package/extensions/gentle-notifications.ts +104 -0
- package/extensions/gentle-shell.ts +271 -80
- package/extensions/gentle-todo.ts +123 -18
- package/extensions/history/index.ts +11 -6
- package/extensions/pi-pretty.ts +39 -3
- package/extensions/quiet-tools.ts +91 -21
- package/extensions/skill-registry.ts +175 -46
- package/extensions/startup-banner.ts +11 -2
- package/lib/agent-home.ts +10 -1
- package/lib/agent-model-resolution.ts +80 -0
- package/lib/agent-profiles.ts +13 -3
- package/lib/agents-completion-delivery.ts +11 -3
- package/lib/agents-messaging.ts +1 -1
- package/lib/agents-protocol.ts +40 -1
- package/lib/agents-runner.ts +90 -15
- package/lib/auto-permission-answers.ts +133 -0
- package/lib/auto-permission-classifier.ts +459 -0
- package/lib/auto-permission-evidence.ts +88 -0
- package/lib/auto-permission-memory.ts +69 -0
- package/lib/auto-permission-runtime.ts +484 -0
- package/lib/auto-permission-tool-context.ts +61 -0
- package/lib/background-jobs-tools.ts +202 -0
- package/lib/background-jobs.ts +253 -0
- package/lib/background-monitor.ts +154 -0
- package/lib/bounded-writer-admission.ts +83 -10
- package/lib/builtin-codemode-optout.ts +166 -0
- package/lib/card-content-policy.ts +85 -0
- package/lib/child-package-injection.ts +62 -0
- package/lib/codemode-renderer.ts +14 -4
- package/lib/command-palette-catalog.ts +3 -2
- package/lib/context-threshold.ts +26 -0
- package/lib/destructive-command-guard.ts +104 -28
- package/lib/gentle-ai-binary.ts +109 -4
- package/lib/gentle-shell-bundled.ts +535 -0
- package/lib/gentle-shell-launcher.ts +75 -24
- package/lib/gentle-shell-startup-flow.ts +54 -0
- package/lib/gentle-shell-startup-update.ts +92 -0
- package/lib/gentle-shell-uninstall.ts +840 -0
- package/lib/gentle-shell-update-panel.ts +231 -0
- package/lib/herdr-activity.ts +183 -0
- package/lib/inprocess-reviewer.ts +3 -0
- package/lib/jobs-sidebar-state.ts +20 -0
- package/lib/jobs-view.ts +161 -0
- package/lib/model-price-ratio.ts +83 -0
- package/lib/model-routing-authority.ts +6 -1
- package/lib/nan-provider.ts +33 -11
- package/lib/native-review-cli.ts +194 -73
- package/lib/notification-audio-native.ts +162 -0
- package/lib/notification-audio-windows.ts +399 -0
- package/lib/notification-audio.ts +332 -0
- package/lib/notification-customize.ts +241 -0
- package/lib/notification-events.ts +113 -0
- package/lib/notification-policy.ts +148 -0
- package/lib/notification-pulse-client.ts +367 -0
- package/lib/notification-pulse-protocol.ts +305 -0
- package/lib/notification-pulse-stream.ts +213 -0
- package/lib/notification-pulse-worker.ts +66 -0
- package/lib/notification-scheduler.ts +173 -0
- package/lib/notification-service.ts +202 -0
- package/lib/notification-ui.ts +87 -0
- package/lib/odd-phase.ts +1 -1
- package/lib/orchestrator-alias.ts +20 -0
- package/lib/orchestrator-catalog.ts +79 -0
- package/lib/orchestrator-consultation.ts +61 -0
- package/lib/orchestrator-discovery.ts +49 -0
- package/lib/orchestrator-helper-consent.ts +122 -0
- package/lib/orchestrator-helper.ts +167 -0
- package/lib/orchestrator-message-card.ts +105 -0
- package/lib/orchestrator-presence.ts +115 -14
- package/lib/orchestrator-scope.ts +80 -0
- package/lib/orchestrator-state.ts +107 -0
- package/lib/orchestrator-tool-card.ts +280 -0
- package/lib/orchestrator-work-search.ts +218 -0
- package/lib/orchestrator-work.ts +79 -0
- package/lib/permission-mode-policy.ts +59 -0
- package/lib/review-candidate-view-owner.ts +8 -6
- package/lib/review-candidate-view.ts +3 -2
- package/lib/review-compact-contract.ts +2 -2
- package/lib/review-host-relay.ts +7 -2
- package/lib/review-integration-v2.ts +100 -22
- package/lib/review-publication-gate.ts +1 -1
- package/lib/review-risk-assessment.ts +77 -51
- package/lib/review-sidebar-state.ts +2 -1
- package/lib/review-transaction.ts +72 -3
- package/lib/runtime-metrics-children.ts +1 -1
- package/lib/runtime-metrics-native.ts +3 -2
- package/lib/selection-engine.ts +22 -7
- package/lib/session-change-capture.ts +5 -4
- package/lib/session-changes.ts +27 -22
- package/lib/session-profile-binding.ts +83 -0
- package/lib/session-profile-freeze.ts +261 -0
- package/lib/session-profile-persistence.ts +187 -0
- package/lib/session-worktree-registry.ts +74 -8
- package/lib/shell-bar.ts +41 -11
- package/lib/shell-changes-view.ts +40 -13
- package/lib/shell-changes.ts +88 -71
- package/lib/shell-prompt.ts +6 -4
- package/lib/shell-sidebar-layout.ts +5 -1
- package/lib/shell-todo.ts +81 -26
- package/lib/shell-usage.ts +4 -3
- package/lib/status-timing-diagnostics.ts +201 -0
- package/lib/telemetry-trigger.ts +3 -1
- package/lib/vim-editor-adapter.ts +27 -5
- package/lib/visual-customization-policy.ts +20 -9
- package/lib/visual-customize-view.ts +171 -20
- package/lib/writer-surfaces.ts +162 -0
- package/lib/yolo-session-policy.ts +198 -121
- package/package.json +5 -5
- package/runtime/child-package-injection.mjs +63 -0
- package/runtime/gentle-ai-binary.mjs +109 -4
- package/runtime/gentle-shell-bundled.mjs +536 -0
- package/runtime/gentle-shell-launcher.mjs +74 -23
- package/runtime/gentle-shell-startup-flow.mjs +55 -0
- package/runtime/gentle-shell-startup-update.mjs +93 -0
- package/runtime/gentle-shell-uninstall.mjs +841 -0
- package/runtime/gentle-shell-update-panel.mjs +232 -0
- package/runtime/native-review-cli.mjs +191 -70
- package/runtime/review-integration-v2.mjs +100 -22
- package/runtime/review-risk-assessment.mjs +77 -51
- package/runtime/status-timing-diagnostics.mjs +202 -0
- package/runtime/telemetry-trigger.mjs +3 -1
- package/scripts/bootstrap.cmd +255 -0
- package/scripts/bootstrap.sh +168 -0
- package/scripts/build-distribution.mjs +157 -0
- package/scripts/build-installer-bundles.mjs +136 -0
- package/scripts/build-runtime-modules.mjs +7 -0
- package/scripts/bundled-install.mjs +1308 -0
- package/scripts/bundled-wizard.mjs +399 -0
- package/scripts/check-types.mjs +4 -6
- package/scripts/gentle-ai-installer.mjs +79 -32
- package/scripts/install-gentle-ai.mjs +48 -1
- package/scripts/install-tui-mode-setting.mjs +10 -1
- package/scripts/install-wizard-preview.mjs +154 -0
- package/scripts/installer-downloads.mjs +648 -0
- package/scripts/installer-preflight.mjs +387 -0
- package/scripts/installer-probes.mjs +564 -0
- package/scripts/installer-runner.mjs +1102 -0
- package/scripts/installer-server.mjs +881 -0
- package/scripts/installer-windows-artifacts.json +15 -0
- package/scripts/installer-windows.mjs +752 -0
- package/scripts/main-channel.mjs +452 -0
- package/scripts/npm-pack-result.mjs +31 -0
- package/scripts/pi-update.mjs +223 -0
- package/scripts/render-cache-performance-worker.mjs +205 -0
- package/scripts/render-cache-performance.mjs +115 -0
- package/scripts/run-test-suite.mjs +22 -8
- package/scripts/test-installer-acceptance.sh +161 -0
- package/scripts/test-packed-runner.mjs +23 -5
- package/scripts/types-baseline.json +2 -92
- package/scripts/verify-package-files.mjs +82 -18
- package/skills/gentle-ai/SKILL.md +12 -11
- package/tests/agent-home.test.ts +56 -3
- package/tests/agent-model-resolution.test.ts +113 -0
- package/tests/agent-profiles.test.ts +12 -0
- package/tests/agent-risk-escalation.test.ts +123 -0
- package/tests/agents-completion-delivery.test.ts +17 -0
- package/tests/agents-protocol.test.ts +57 -0
- package/tests/agents-queries.test.ts +9 -9
- package/tests/agents-runner-process.test.ts +31 -0
- package/tests/agents-runner.test.ts +89 -4
- package/tests/append-system-prompt-route.test.ts +18 -1
- package/tests/auto-mode-human-answers.test.ts +68 -0
- package/tests/auto-mode-invariants.test.ts +276 -0
- package/tests/auto-mode-sdk.test.ts +84 -0
- package/tests/auto-mode.test.ts +49 -0
- package/tests/auto-permission-answers.test.ts +170 -0
- package/tests/auto-permission-classifier.test.ts +634 -0
- package/tests/auto-permission-compound.test.ts +24 -0
- package/tests/auto-permission-evidence.test.ts +88 -0
- package/tests/auto-permission-memory.test.ts +46 -0
- package/tests/auto-permission-public-regressions.test.ts +111 -0
- package/tests/auto-permission-runtime.test.ts +454 -0
- package/tests/autonomous-guard.test.ts +86 -16
- package/tests/background-cache-warming.test.ts +2 -1
- package/tests/background-jobs.test.ts +227 -0
- package/tests/background-monitor.test.ts +195 -0
- package/tests/background-subagents-default-mode.test.ts +28 -5
- package/tests/bounded-stop-contract.test.ts +85 -0
- package/tests/bounded-writer-admission.test.ts +52 -1
- package/tests/bridge-wake-lifecycle.test.ts +129 -0
- package/tests/bridge-wake-rendering.test.ts +56 -0
- package/tests/build-distribution.test.ts +269 -0
- package/tests/builtin-codemode-optout.test.ts +242 -0
- package/tests/bundled-install.test.ts +1319 -0
- package/tests/bundled-wizard.test.ts +505 -0
- package/tests/card-content-policy.test.ts +68 -0
- package/tests/card-style-policy.test.ts +34 -2
- package/tests/child-codegraph-bootstrap.test.ts +74 -0
- package/tests/child-package-entrypoints.test.ts +65 -0
- package/tests/child-package-injection.test.ts +74 -0
- package/tests/child-safety.test.ts +12 -0
- package/tests/child-web-package.test.ts +224 -0
- package/tests/codegraph-tools.test.ts +35 -0
- package/tests/codemode-rendering.test.ts +107 -2
- package/tests/command-palette.test.ts +5 -5
- package/tests/context-threshold.test.ts +31 -0
- package/tests/delegate-for-reason-contract.test.ts +327 -0
- package/tests/delegated-key-learnings-contract.test.ts +3 -2
- package/tests/devbinary/native-review-parity.devtest.ts +1 -1
- package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
- package/tests/engram-safety.test.ts +316 -0
- package/tests/generic-agent-tools.test.ts +16 -1
- package/tests/gentle-agents.test.ts +1895 -76
- package/tests/gentle-ai-binary-isolation.test.ts +135 -0
- package/tests/gentle-ai-binary.test.ts +19 -2
- package/tests/gentle-ai-child-guards.test.ts +202 -0
- package/tests/gentle-ai-dev-binary-surfacing.test.ts +125 -15
- package/tests/gentle-ai-installer.test.ts +548 -58
- package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
- package/tests/gentle-ai-renderer.test.ts +6 -6
- package/tests/gentle-ai.test.ts +999 -31
- package/tests/gentle-herdr-activity.test.ts +100 -0
- package/tests/gentle-notifications.test.ts +427 -0
- package/tests/gentle-shell-bin.test.ts +263 -19
- package/tests/gentle-shell-bundled.test.ts +1036 -0
- package/tests/gentle-shell-launcher.test.ts +251 -25
- package/tests/gentle-shell-startup-flow.test.ts +75 -0
- package/tests/gentle-shell-startup-update.test.ts +85 -0
- package/tests/gentle-shell-uninstall.test.ts +978 -0
- package/tests/gentle-shell-update-panel.test.ts +158 -0
- package/tests/gentle-shell.test.ts +611 -100
- package/tests/gentle-todo.test.ts +317 -14
- package/tests/herdr-activity.test.ts +243 -0
- package/tests/history-agent-home.test.ts +81 -0
- package/tests/history-child-guard.test.ts +70 -0
- package/tests/inprocess-reviewer.test.ts +20 -0
- package/tests/install-gentle-ai-failure.test.ts +69 -0
- package/tests/install-tui-mode-setting.test.ts +15 -0
- package/tests/install-wizard.test.ts +1223 -0
- package/tests/installer-bundles.test.ts +122 -0
- package/tests/installer-posix-bootstrap.test.ts +1201 -0
- package/tests/installer-preflight.test.ts +750 -0
- package/tests/installer-probes.test.ts +1106 -0
- package/tests/installer-runner.test.ts +2159 -0
- package/tests/installer-server.test.ts +1567 -0
- package/tests/installer-windows-bootstrap.test.ts +2410 -0
- package/tests/jobs-view.test.ts +160 -0
- package/tests/main-channel-upgrade.test.ts +395 -0
- package/tests/main-channel.test.ts +344 -0
- package/tests/maintainer/provider-relay.maintest.ts +13 -12
- package/tests/model-price-ratio.test.ts +116 -0
- package/tests/model-profiles-preservation.test.ts +153 -0
- package/tests/model-routing-package.test.ts +10 -0
- package/tests/nan-provider-runtime.test.ts +156 -0
- package/tests/nan-provider.test.ts +28 -18
- package/tests/native-binary-gate.test.ts +2 -0
- package/tests/native-review-capability-contract.test.ts +7 -1
- package/tests/native-review-cli.test.ts +236 -1
- package/tests/native-review-consent.test.ts +2 -2
- package/tests/native-review-parity-runtime.test.ts +1 -1
- package/tests/native-review-parity.test.ts +12 -48
- package/tests/native-risk-evidence-parity.test.ts +21 -0
- package/tests/no-self-pause-contract.test.ts +87 -0
- package/tests/notification-audio-native.test.ts +281 -0
- package/tests/notification-audio-windows.test.ts +581 -0
- package/tests/notification-audio.test.ts +548 -0
- package/tests/notification-customize.test.ts +655 -0
- package/tests/notification-events.test.ts +115 -0
- package/tests/notification-policy.test.ts +201 -0
- package/tests/notification-pulse-client.test.ts +356 -0
- package/tests/notification-pulse-protocol.test.ts +213 -0
- package/tests/notification-pulse-stream.test.ts +320 -0
- package/tests/notification-scheduler.test.ts +258 -0
- package/tests/notification-ui.test.ts +157 -0
- package/tests/npm-pack-result.test.ts +41 -0
- package/tests/odd-integration.test.ts +14 -5
- package/tests/odd-routing-canonical-ratchet.test.ts +53 -12
- package/tests/odd-routing-contract.test.ts +80 -23
- package/tests/odd-runtime-delegation-gate.test.ts +4 -1
- package/tests/orchestrator-budget.test.ts +29 -6
- package/tests/orchestrator-catalog.test.ts +146 -0
- package/tests/orchestrator-consultation-sdk.test.ts +614 -0
- package/tests/orchestrator-consultation.test.ts +111 -0
- package/tests/orchestrator-discovery.test.ts +241 -0
- package/tests/orchestrator-helper-consent.test.ts +171 -0
- package/tests/orchestrator-helper.test.ts +297 -0
- package/tests/orchestrator-message-card.test.ts +190 -0
- package/tests/orchestrator-presence.test.ts +23 -0
- package/tests/orchestrator-rdd-ownership.test.ts +6 -5
- package/tests/orchestrator-scope.test.ts +107 -0
- package/tests/orchestrator-state.test.ts +114 -0
- package/tests/orchestrator-status-publication-contract.test.ts +34 -0
- package/tests/orchestrator-tool-card.test.ts +398 -0
- package/tests/orchestrator-work-search.test.ts +318 -0
- package/tests/orchestrator-work.test.ts +147 -0
- package/tests/package-manifest.test.ts +105 -21
- package/tests/packed-runner-owned-path.test.ts +35 -1
- package/tests/parallel-reason-contract.test.ts +21 -0
- package/tests/parallel-writer-admission.test.ts +210 -0
- package/tests/permission-mode-policy.test.ts +194 -0
- package/tests/persona-single-channel.test.ts +4 -12
- package/tests/pi-pretty.test.ts +56 -0
- package/tests/pi-update-launcher.test.ts +87 -0
- package/tests/pi-update.test.ts +186 -0
- package/tests/provider-defect-handoff.test.ts +4 -3
- package/tests/quiet-tool-rendering.test.ts +160 -3
- package/tests/rdd-aware-verification-contract.test.ts +29 -41
- package/tests/rdd-status-line.test.ts +52 -0
- package/tests/render-cache-performance.test.ts +48 -0
- package/tests/review-agent-end-preflight.test.ts +62 -10
- package/tests/review-candidate-view.test.ts +101 -12
- package/tests/review-contract-prompt.test.ts +33 -4
- package/tests/review-controller-native-recovery.test.ts +327 -17
- package/tests/review-controller-native-routing.test.ts +255 -1
- package/tests/review-controller-workspace-root.test.ts +43 -2
- package/tests/review-controller.test.ts +2 -2
- package/tests/review-correction-lifecycle.test.ts +2 -1
- package/tests/review-gate.test.ts +7 -4
- package/tests/review-graph-schema.test.ts +2 -2
- package/tests/review-host-relay-routing.test.ts +5 -3
- package/tests/review-host-relay.test.ts +49 -2
- package/tests/review-integration-v2-forward.test.ts +21 -1
- package/tests/review-json-arguments.test.ts +167 -0
- package/tests/review-last-event-closure.test.ts +157 -8
- package/tests/review-ledger-contract.test.ts +5 -4
- package/tests/review-policy-judgment-day.test.ts +1 -1
- package/tests/review-policy-ordinary.test.ts +2 -2
- package/tests/review-relay-transport-agent.test.ts +66 -1
- package/tests/review-risk-assessment.test.ts +109 -33
- package/tests/review-session-standing-permission-controller.test.ts +16 -17
- package/tests/review-session-standing-permission-ipc.test.ts +6 -5
- package/tests/review-test-fixtures.ts +7 -1
- package/tests/review-transaction.test.ts +18 -1
- package/tests/run-test-suite.test.ts +83 -5
- package/tests/runtime-harness.mjs +42 -15
- package/tests/runtime-metrics-extension.test.ts +1 -1
- package/tests/runtime-metrics-native.test.ts +31 -1
- package/tests/selection-engine.test.ts +65 -5
- package/tests/session-change-capture.test.ts +10 -10
- package/tests/session-changes-shell.test.ts +242 -48
- package/tests/session-changes.test.ts +17 -24
- package/tests/session-profile-binding.test.ts +163 -0
- package/tests/session-profile-freeze.test.ts +394 -0
- package/tests/session-profile-persistence.test.ts +334 -0
- package/tests/session-subject-routing-contract.test.ts +34 -0
- package/tests/session-worktree-registry.test.ts +57 -2
- package/tests/shell-bar.test.ts +40 -0
- package/tests/shell-changes-view.test.ts +85 -34
- package/tests/shell-changes.test.ts +79 -62
- package/tests/shell-render-cache-runtime.test.ts +69 -0
- package/tests/shell-render-cache.test.ts +129 -0
- package/tests/shell-sidebar-layout.test.ts +27 -2
- package/tests/shell-todo.test.ts +132 -11
- package/tests/shell-usage-view.test.ts +1 -1
- package/tests/shell-usage.test.ts +35 -0
- package/tests/short-check-routing-contract.test.ts +49 -0
- package/tests/skill-registry-watcher.test.ts +119 -0
- package/tests/skill-registry.test.ts +311 -5
- package/tests/startup-banner.test.ts +117 -3
- package/tests/startup-home-repo.test.ts +170 -0
- package/tests/status-timing-diagnostics.test.ts +283 -0
- package/tests/support/orchestrator-modules.ts +19 -0
- package/tests/task-size-routing-contract.test.ts +241 -0
- package/tests/telemetry-trigger.test.ts +27 -1
- package/tests/test-strength-contract.test.ts +124 -0
- package/tests/verify-agent-contract.test.ts +90 -0
- package/tests/verify-first-launch-contract.test.ts +139 -0
- package/tests/verify-package-files.test.ts +56 -0
- package/tests/vim-editor-adapter.test.ts +47 -21
- package/tests/visual-customization-policy.test.ts +32 -3
- package/tests/visual-customize-view.test.ts +288 -10
- package/tests/writer-edit-surface-scope.test.ts +59 -2
- package/tests/writer-surfaces.test.ts +199 -0
- package/tests/yolo-customize.test.ts +18 -3
- package/tests/yolo-mode-runtime.test.ts +37 -10
- package/tests/yolo-mode.test.ts +38 -5
- package/tests/yolo-session-policy.test.ts +1 -1
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/README.md +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/lens.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/refuter.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/targeted-validator.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/lens.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/refuter.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/targeted-validator.json +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Generated by scripts/build-runtime-modules.mjs. Do not edit.
|
|
2
|
-
import { execFile } from "node:child_process";
|
|
2
|
+
import { execFile, spawn } from "node:child_process";
|
|
3
3
|
import { chmod, mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { dirname, isAbsolute, join, posix, win32 } from "node:path";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
|
-
import { PackageLocalGentleAiBinaryMissingError, resolveGentleAiBinary } from "./gentle-ai-binary.mjs";
|
|
7
|
+
import { gentleAiIsolationEnv, PackageLocalGentleAiBinaryMissingError, resolveGentleAiBinary } from "./gentle-ai-binary.mjs";
|
|
8
8
|
import { GENTLE_PI_REVIEW_RELAY_CONTRACT, GENTLE_PI_REVIEW_RELAY_CONTRACT_ENV } from "./review-relay-contract.mjs";
|
|
9
9
|
import { decodeReviewAssessmentV1, } from "./review-risk-assessment.mjs";
|
|
10
10
|
import {
|
|
@@ -32,6 +32,8 @@ import {
|
|
|
32
32
|
|
|
33
33
|
} from "./review-integration-v2.mjs";
|
|
34
34
|
|
|
35
|
+
import { observeNativeStatus, measureStatusSync, measureStatusAsync } from "./status-timing-diagnostics.mjs";
|
|
36
|
+
|
|
35
37
|
const execFileAsync = promisify(execFile);
|
|
36
38
|
|
|
37
39
|
// Negotiated review/status responses can carry a complete authority inventory.
|
|
@@ -258,6 +260,8 @@ export const NATIVE_REVIEW_RECOVER_DISPOSITION = ["scope_changed", "invalidated"
|
|
|
258
260
|
|
|
259
261
|
|
|
260
262
|
|
|
263
|
+
|
|
264
|
+
|
|
261
265
|
|
|
262
266
|
|
|
263
267
|
|
|
@@ -276,6 +280,13 @@ export const NATIVE_REVIEW_LEGACY_ALIAS_REPAIR = {
|
|
|
276
280
|
} ;
|
|
277
281
|
|
|
278
282
|
|
|
283
|
+
export const NATIVE_REVIEW_ABANDON_REASONS = ["operator_disposition", "retired_schema"] ;
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
export function isNativeReviewAbandonReason(value ) {
|
|
287
|
+
return value === "operator_disposition" || value === "retired_schema";
|
|
288
|
+
}
|
|
289
|
+
|
|
279
290
|
|
|
280
291
|
|
|
281
292
|
|
|
@@ -472,6 +483,24 @@ export const NATIVE_REVIEW_UNACHIEVABLE_LENS_DETAIL_LIMIT = 512;
|
|
|
472
483
|
// gentle-pi#638 fail-open capability gate: `review capture-unachievable` is younger than every released binary pinned in NATIVE_CLI_CONTRACTS, so the verb is gated invocation-adjacent instead of by a capability row. An older binary renders Go's exact `unknown review command "capture-unachievable"` refusal (internal/cli/review_facade.go) on stderr with no stdout, so the invocation rejects before any decode and the captured diagnostics are the only place that text survives. Every other failure -- a typed binding-mismatch refusal, a timeout, a decode failure -- is a real outcome the caller must surface, never a capability signal. Duck-typed on purpose: the classifier must survive a duplicated module instance exactly like the error it inspects.
|
|
473
484
|
const NATIVE_REVIEW_UNKNOWN_UNACHIEVABLE_VERB_REFUSAL = /unknown review command "capture-unachievable"/;
|
|
474
485
|
|
|
486
|
+
// A provider older than START lens selection refuses the STATUS preflight
|
|
487
|
+
// flags with this exact typed preflight cause, before reading the repository.
|
|
488
|
+
const NATIVE_REVIEW_UNKNOWN_LENS_FLAG_CAUSE = /^flag provided but not defined: -lenses(?:-reason)?$/;
|
|
489
|
+
|
|
490
|
+
/** Reports a not-started STATUS refusal caused only by an unknown --lenses flag. */
|
|
491
|
+
export function isNativeReviewLensSelectionUnsupported(error ) {
|
|
492
|
+
if (!(error instanceof NativeReviewIntegrationError)) return false;
|
|
493
|
+
const failure = error.failureEnvelope;
|
|
494
|
+
return failure.code === "invalid_request" && failure.mutationOutcome === "not_started" &&
|
|
495
|
+
typeof failure.cause === "string" && NATIVE_REVIEW_UNKNOWN_LENS_FLAG_CAUSE.test(failure.cause);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function nativeLensSelectionArguments(request ) {
|
|
499
|
+
if (request.lenses === undefined && request.lensesReason === undefined) return [];
|
|
500
|
+
if (request.lenses === undefined || request.lenses.length === 0 || request.lensesReason === undefined) throw new TypeError("Native lens selection requires lenses and lensesReason together");
|
|
501
|
+
return ["--lenses", request.lenses.join(","), "--lenses-reason", request.lensesReason];
|
|
502
|
+
}
|
|
503
|
+
|
|
475
504
|
export function isNativeReviewUnachievableVerbRefused(error ) {
|
|
476
505
|
if (typeof error !== "object" || error === null) return false;
|
|
477
506
|
const stderr = (error ).diagnostics?.stderr;
|
|
@@ -498,6 +527,16 @@ export const NATIVE_UNTRACKED_SCOPE = {
|
|
|
498
527
|
|
|
499
528
|
|
|
500
529
|
|
|
530
|
+
/**
|
|
531
|
+
* The agent's own review lens choice (gentle-ai START --lenses): canonical
|
|
532
|
+
* lens names in 4R order and one reason. Providers that predate it refuse
|
|
533
|
+
* the flag, and START then falls back to the tier default.
|
|
534
|
+
*/
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
501
540
|
|
|
502
541
|
|
|
503
542
|
|
|
@@ -753,6 +792,8 @@ const REVIEW_RISK_SUBJECT_BY_CODE = Object.fre
|
|
|
753
792
|
shell_source: "shell scripting",
|
|
754
793
|
process_boundary: "code that starts other processes",
|
|
755
794
|
process_scan_limit: "code that starts other processes",
|
|
795
|
+
dangerous_sink: "a dangerous code pattern",
|
|
796
|
+
agent_escalation: "the agent that made this change flagged it as high risk",
|
|
756
797
|
executable_mode: "an executable permission change",
|
|
757
798
|
executable_change: "an executable change",
|
|
758
799
|
configuration_change: "a configuration change",
|
|
@@ -1035,6 +1076,13 @@ export const NATIVE_CLI_CONTRACTS = Object.freeze({
|
|
|
1035
1076
|
// to /v4 without a review-integration/v2 change. No new negotiated
|
|
1036
1077
|
// capability is asserted.
|
|
1037
1078
|
"4.0.0": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
1079
|
+
// v4.1.1 repeats 4.0.0: the published binary still advertises
|
|
1080
|
+
// capabilities/v2.6 under review-integration/v2. The provider contract moved
|
|
1081
|
+
// from 1.2.0 to 1.3.0 (additive agent lens selection, gentle-ai#5348), with
|
|
1082
|
+
// published tarball SHA-256
|
|
1083
|
+
// b04b6b75d1a446c942a816fbf92932d16f8c3d3001f93159dee2a92bbf2ebe44.
|
|
1084
|
+
// No new negotiated capability identity is asserted.
|
|
1085
|
+
"4.1.1": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
1038
1086
|
});
|
|
1039
1087
|
|
|
1040
1088
|
|
|
@@ -1076,21 +1124,98 @@ export class NativeReviewCliError extends Error {
|
|
|
1076
1124
|
// makes. It declares the Pi host relay handshake on each spawn: gentle-ai
|
|
1077
1125
|
// refuses pi admission pre-authority without it (gentle-pi#311 P4), and a
|
|
1078
1126
|
// single injection point keeps the declaration impossible to forget on any
|
|
1079
|
-
// individual operation.
|
|
1127
|
+
// individual operation. In a bundled install it also keeps Gentle AI's state
|
|
1128
|
+
// inside the prefix (gentleAiIsolationEnv, S9).
|
|
1080
1129
|
export function gentleAiProcessEnvironment(base = process.env) {
|
|
1081
|
-
return { ...base, [GENTLE_PI_REVIEW_RELAY_CONTRACT_ENV]: GENTLE_PI_REVIEW_RELAY_CONTRACT };
|
|
1130
|
+
return { ...gentleAiIsolationEnv(base), [GENTLE_PI_REVIEW_RELAY_CONTRACT_ENV]: GENTLE_PI_REVIEW_RELAY_CONTRACT };
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
// A bare "taskkill" resolves from the current directory before PATH on
|
|
1138
|
+
// Windows, so a repository shipping its own taskkill.exe would run on any
|
|
1139
|
+
// abort. Always use the System32 binary, from System32 itself.
|
|
1140
|
+
export function windowsTaskkillPath(env = process.env) {
|
|
1141
|
+
const systemRoot = env.SystemRoot || env.windir;
|
|
1142
|
+
return win32.join(systemRoot && win32.isAbsolute(systemRoot) ? systemRoot : "C:\\Windows", "System32", "taskkill.exe");
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// taskkill walks the tree from a live parent, so it must run before the
|
|
1146
|
+
// parent dies; Node's own abort/timeout kill would orphan the git children.
|
|
1147
|
+
export function createWindowsProcessTreeKiller(env = process.env, spawnProcess = spawn) {
|
|
1148
|
+
const taskkill = windowsTaskkillPath(env);
|
|
1149
|
+
return (pid) => {
|
|
1150
|
+
try {
|
|
1151
|
+
spawnProcess(taskkill, ["/pid", String(pid), "/T", "/F"], { cwd: win32.dirname(taskkill), stdio: "ignore", windowsHide: true }).on("error", () => {});
|
|
1152
|
+
} catch { /* Best effort: the call still settles through its own child. */ }
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
export const windowsProcessTreeKiller = (pid) => createWindowsProcessTreeKiller()(pid);
|
|
1157
|
+
|
|
1158
|
+
const WINDOWS_TREE_KILL_GRACE_MS = 1_000;
|
|
1159
|
+
|
|
1160
|
+
function abortError(signal ) {
|
|
1161
|
+
return Object.assign(new Error("The operation was aborted", { cause: signal.reason }), { name: "AbortError", code: "ABORT_ERR" });
|
|
1082
1162
|
}
|
|
1083
1163
|
|
|
1084
|
-
|
|
1164
|
+
function execFileResultFromError(error , timedOut ) {
|
|
1165
|
+
const detail = error ;
|
|
1166
|
+
if (detail.code === "ENOENT" || detail.code === "EACCES" || detail.name === "AbortError") throw error;
|
|
1167
|
+
const outputLimitExceeded = detail.code === "ENOBUFS" || detail.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER";
|
|
1168
|
+
return { stdout: detail.stdout ?? "", stderr: detail.stderr ?? "", exitCode: typeof detail.code === "number" ? detail.code : 1, signal: detail.signal ?? null, timedOut: !outputLimitExceeded && (timedOut || detail.killed === true), outputLimitExceeded };
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// Windows: abort and timeout kill the whole process tree instead of only
|
|
1172
|
+
// gentle-ai, with the same observable results as the POSIX path.
|
|
1173
|
+
function windowsExecFile(request , killProcessTree ) {
|
|
1174
|
+
const { signal } = request;
|
|
1175
|
+
if (signal?.aborted) return Promise.reject(abortError(signal));
|
|
1176
|
+
return new Promise((resolve, reject) => {
|
|
1177
|
+
let timedOut = false, aborted = false, pipesCut = false;
|
|
1178
|
+
let timer ;
|
|
1179
|
+
let fallback ;
|
|
1180
|
+
const child = execFile(request.file, [...request.arguments], { cwd: request.cwd, encoding: "utf8", shell: false, windowsHide: true, maxBuffer: request.maxBufferBytes, env: gentleAiProcessEnvironment() }, (error, stdout, stderr) => {
|
|
1181
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
1182
|
+
if (fallback !== undefined) clearTimeout(fallback);
|
|
1183
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1184
|
+
if (aborted && signal) { reject(abortError(signal)); return; }
|
|
1185
|
+
if (error === null) { resolve({ stdout, stderr, exitCode: 0, signal: null, timedOut: pipesCut, outputLimitExceeded: false }); return; }
|
|
1186
|
+
try { resolve(execFileResultFromError(Object.assign(error, { stdout, stderr }), timedOut)); } catch (failure) { reject(failure); }
|
|
1187
|
+
});
|
|
1188
|
+
// If taskkill cannot run (AppLocker, a broken PATH), still end gentle-ai
|
|
1189
|
+
// itself so the deadline holds; its children may then outlive it. A
|
|
1190
|
+
// surviving descendant can still hold the inherited stdout/stderr open,
|
|
1191
|
+
// which would keep execFile from calling back, so cut the pipes too.
|
|
1192
|
+
const killTree = () => {
|
|
1193
|
+
if (child.pid === undefined) { child.kill(); return; }
|
|
1194
|
+
killProcessTree(child.pid);
|
|
1195
|
+
fallback = setTimeout(() => {
|
|
1196
|
+
if (child.exitCode === null && child.signalCode === null) child.kill();
|
|
1197
|
+
pipesCut = true;
|
|
1198
|
+
child.stdout?.destroy();
|
|
1199
|
+
child.stderr?.destroy();
|
|
1200
|
+
}, WINDOWS_TREE_KILL_GRACE_MS);
|
|
1201
|
+
};
|
|
1202
|
+
function onAbort() { if (aborted || timedOut) return; aborted = true; killTree(); }
|
|
1203
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1204
|
+
if (request.timeoutMs !== undefined && request.timeoutMs > 0) timer = setTimeout(() => { if (aborted) return; timedOut = true; killTree(); }, request.timeoutMs);
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
export function createNodeExecFileAdapter(options = {}) {
|
|
1209
|
+
if ((options.platform ?? process.platform) === "win32") {
|
|
1210
|
+
const killProcessTree = options.killProcessTree ?? windowsProcessTreeKiller;
|
|
1211
|
+
return (request) => windowsExecFile(request, killProcessTree);
|
|
1212
|
+
}
|
|
1085
1213
|
return async (request) => {
|
|
1086
1214
|
try {
|
|
1087
1215
|
const output = await execFileAsync(request.file, [...request.arguments], { cwd: request.cwd, encoding: "utf8", shell: false, windowsHide: true, timeout: request.timeoutMs, maxBuffer: request.maxBufferBytes, signal: request.signal, env: gentleAiProcessEnvironment() });
|
|
1088
1216
|
return { stdout: output.stdout, stderr: output.stderr, exitCode: 0, signal: null, timedOut: false, outputLimitExceeded: false };
|
|
1089
1217
|
} catch (error) {
|
|
1090
|
-
|
|
1091
|
-
if (detail.code === "ENOENT" || detail.code === "EACCES" || detail.name === "AbortError") throw error;
|
|
1092
|
-
const outputLimitExceeded = detail.code === "ENOBUFS" || detail.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER";
|
|
1093
|
-
return { stdout: detail.stdout ?? "", stderr: detail.stderr ?? "", exitCode: typeof detail.code === "number" ? detail.code : 1, signal: detail.signal ?? null, timedOut: !outputLimitExceeded && detail.killed === true, outputLimitExceeded };
|
|
1218
|
+
return execFileResultFromError(error, false);
|
|
1094
1219
|
}
|
|
1095
1220
|
};
|
|
1096
1221
|
}
|
|
@@ -1187,8 +1312,10 @@ function nativeProcessDiagnostics(operation , code
|
|
|
1187
1312
|
}
|
|
1188
1313
|
|
|
1189
1314
|
function parseJson(stdout , operation , mutating , diagnostics ) {
|
|
1190
|
-
|
|
1191
|
-
|
|
1315
|
+
return measureStatusSync("decode", () => {
|
|
1316
|
+
if (stdout.length === 0) throw new NativeReviewCliError(NATIVE_REVIEW_ERROR_CODE.EMPTY_OUTPUT, operation, true, mutating, "native command returned empty output", { ...diagnostics, error_code: NATIVE_REVIEW_ERROR_CODE.EMPTY_OUTPUT });
|
|
1317
|
+
try { return object(JSON.parse(stdout)); } catch { throw new NativeReviewCliError(NATIVE_REVIEW_ERROR_CODE.MALFORMED_JSON, operation, true, mutating, "native command returned malformed JSON", { ...diagnostics, error_code: NATIVE_REVIEW_ERROR_CODE.MALFORMED_JSON }); }
|
|
1318
|
+
});
|
|
1192
1319
|
}
|
|
1193
1320
|
function decodeNativeMaintenanceResult(value , expectedOperation ) {
|
|
1194
1321
|
const body = exactObject(value, ["operation", "record"]);
|
|
@@ -1219,7 +1346,7 @@ function assertSupportedNextTransitionOperation(body )
|
|
|
1219
1346
|
}
|
|
1220
1347
|
}
|
|
1221
1348
|
function decode (operation , mutating , callback , diagnostics = nativeProcessDiagnostics(operation, NATIVE_REVIEW_ERROR_CODE.SCHEMA_INCOMPATIBLE)) {
|
|
1222
|
-
try { return callback
|
|
1349
|
+
try { return measureStatusSync("decode", callback); } catch (error) { if (error instanceof NativeReviewCliError) throw error; throw new NativeReviewCliError(NATIVE_REVIEW_ERROR_CODE.SCHEMA_INCOMPATIBLE, operation, true, mutating, "native response is schema incompatible", { ...diagnostics, error_code: NATIVE_REVIEW_ERROR_CODE.SCHEMA_INCOMPATIBLE }); }
|
|
1223
1350
|
}
|
|
1224
1351
|
function decodeReviewStartResponse(value ) {
|
|
1225
1352
|
const body = object(value);
|
|
@@ -1232,50 +1359,6 @@ function decodeReleaseEvidence(value ) {
|
|
|
1232
1359
|
for (const field of ["release_tree", "configuration_hash", "generated_artifact_hash", "provenance_hash", "publication_boundary_hash", "evidence_freshness_hash"]) requiredString(release[field]);
|
|
1233
1360
|
if (release.publication_state !== "sealed" || release.evidence_freshness_state !== "current") throw new Error("invalid release evidence");
|
|
1234
1361
|
}
|
|
1235
|
-
function decodeNonDecidingGateContext(value , expectedGate ) {
|
|
1236
|
-
const context = exactObject(value, ["gate"]);
|
|
1237
|
-
const gate = enumString(context.gate, NATIVE_GATE);
|
|
1238
|
-
if (gate !== expectedGate) throw new Error("native non-deciding gate context does not match the requested gate");
|
|
1239
|
-
return { lineageId: "", storeRevision: "", raw: context };
|
|
1240
|
-
}
|
|
1241
|
-
function decodeGateContext(value ) {
|
|
1242
|
-
const context = exactObject(
|
|
1243
|
-
value,
|
|
1244
|
-
["gate", "lineage_id", "generation", "base_tree", "candidate_tree", "paths_digest", "fix_delta_hash", "policy_hash", "ledger_hash", "evidence_hash", "base_relationship_valid"],
|
|
1245
|
-
["store_revision", "genesis_revision", "chain_identity", "bundle_digest", "external_evidence", "base_advanced_compatible", "release", "pre_pr_boundary", "denial"],
|
|
1246
|
-
);
|
|
1247
|
-
const gate = stringValue(context.gate);
|
|
1248
|
-
if (gate !== "" && !(NATIVE_GATE ).includes(gate)) throw new Error("invalid gate context gate");
|
|
1249
|
-
for (const field of ["lineage_id", "base_tree", "candidate_tree", "paths_digest", "fix_delta_hash", "policy_hash", "ledger_hash", "evidence_hash"]) stringValue(context[field]);
|
|
1250
|
-
for (const field of ["store_revision", "genesis_revision", "chain_identity", "bundle_digest"]) if (context[field] !== undefined) stringValue(context[field]);
|
|
1251
|
-
nonNegativeInteger(context.generation);
|
|
1252
|
-
booleanValue(context.base_relationship_valid);
|
|
1253
|
-
if (context.external_evidence !== undefined) enumString(context.external_evidence, ["invalidating", "escalating"]);
|
|
1254
|
-
let sanitizedContext = context;
|
|
1255
|
-
if (context.denial !== undefined) {
|
|
1256
|
-
const denial = exactObject(context.denial, ["stage", "code"]);
|
|
1257
|
-
const stage = sanitizeNativeDiagnosticText(requiredString(denial.stage), NATIVE_REVIEW_DENIAL_TEXT_LIMIT);
|
|
1258
|
-
const code = sanitizeNativeDiagnosticText(requiredString(denial.code), NATIVE_REVIEW_DENIAL_TEXT_LIMIT);
|
|
1259
|
-
if (!isCanonicalProcessString(stage) || !isCanonicalProcessString(code)) throw new Error("non-canonical denial evidence");
|
|
1260
|
-
sanitizedContext = { ...context, denial: { stage, code } };
|
|
1261
|
-
}
|
|
1262
|
-
if (context.pre_pr_boundary !== undefined) {
|
|
1263
|
-
const boundary = exactObject(context.pre_pr_boundary, ["source", "selector", "commit"], ["remote", "remote_ref", "remote_identity"]);
|
|
1264
|
-
enumString(boundary.source, ["explicit", "publication-default"]); requiredString(boundary.selector); stringValue(boundary.commit);
|
|
1265
|
-
for (const field of ["remote", "remote_ref", "remote_identity"]) if (boundary[field] !== undefined) requiredString(boundary[field]);
|
|
1266
|
-
}
|
|
1267
|
-
if (context.base_advanced_compatible !== undefined) {
|
|
1268
|
-
const proof = exactObject(context.base_advanced_compatible, ["status", "compatible", "old_base_tree", "new_base_tree", "original_patch_identity", "delivered_patch_identity", "delivered_paths_digest", "base_advance_paths_digest", "paths_disjoint", "merged_result_tree", "ci_attestation_artifact_hash", "ci_attestation_issuer", "ci_status"]);
|
|
1269
|
-
for (const field of ["status", "old_base_tree", "new_base_tree", "original_patch_identity", "delivered_patch_identity", "delivered_paths_digest", "base_advance_paths_digest", "merged_result_tree", "ci_attestation_artifact_hash", "ci_attestation_issuer", "ci_status"]) requiredString(proof[field]);
|
|
1270
|
-
booleanValue(proof.compatible); booleanValue(proof.paths_disjoint);
|
|
1271
|
-
}
|
|
1272
|
-
if (context.release !== undefined) decodeReleaseEvidence(context.release);
|
|
1273
|
-
return {
|
|
1274
|
-
lineageId: stringValue(context.lineage_id),
|
|
1275
|
-
storeRevision: context.store_revision === undefined ? "" : stringValue(context.store_revision),
|
|
1276
|
-
raw: sanitizedContext,
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
1362
|
function decodeNativeReviewRecovery(value ) {
|
|
1280
1363
|
const recovery = exactObject(value, ["predecessor_lineage_id", "predecessor_revision", "disposition", "reason", "actor", "recovered_at"], ["maintainer_authorization"]);
|
|
1281
1364
|
return {
|
|
@@ -1366,7 +1449,7 @@ function decodeNativeReviewStatus(value ) {
|
|
|
1366
1449
|
const complete = booleanValue(body.complete);
|
|
1367
1450
|
const authoritative = booleanValue(body.authoritative);
|
|
1368
1451
|
if (authoritative && !complete) throw new Error("incomplete inventory cannot be authoritative");
|
|
1369
|
-
if (!Array.isArray(body.entries) || !Array.isArray(body.locks)) throw new Error("invalid native status inventory");
|
|
1452
|
+
if (!Array.isArray(body.entries) || !Array.isArray(body.locks) || !Array.isArray(body.diagnostics)) throw new Error("invalid native status inventory");
|
|
1370
1453
|
return {
|
|
1371
1454
|
repository: requiredString(body.repository),
|
|
1372
1455
|
complete,
|
|
@@ -1538,7 +1621,10 @@ class NativeReviewPlainCli {
|
|
|
1538
1621
|
// membership in the frozen set.
|
|
1539
1622
|
async execute(operation , cwd , arguments_ , mutating , signal , toleratedStderr = []) {
|
|
1540
1623
|
let result ;
|
|
1541
|
-
try {
|
|
1624
|
+
try {
|
|
1625
|
+
const file = measureStatusSync("resolution", () => this.executablePath(operation, mutating));
|
|
1626
|
+
result = await measureStatusAsync("adapter", () => this.adapter({ file, arguments: arguments_, cwd, timeoutMs: mutating ? undefined : this.timeoutMs, maxBufferBytes: this.maxBufferBytes, signal }));
|
|
1627
|
+
}
|
|
1542
1628
|
catch (error) {
|
|
1543
1629
|
if (error instanceof NativeReviewCliError) throw nativeError(error.code, operation, mutating, error.message, undefined, error.launchAttempted);
|
|
1544
1630
|
if (error instanceof Error && error.name === "AbortError") throw nativeError(NATIVE_REVIEW_ERROR_CODE.CANCELLED, operation, mutating, "native process was cancelled");
|
|
@@ -1548,7 +1634,7 @@ class NativeReviewPlainCli {
|
|
|
1548
1634
|
if (result.outputLimitExceeded) throw nativeError(NATIVE_REVIEW_ERROR_CODE.OUTPUT_LIMIT, operation, mutating, "native process output exceeded limit", result, true, undefined, this.maxBufferBytes);
|
|
1549
1635
|
if (result.timedOut) throw nativeError(NATIVE_REVIEW_ERROR_CODE.TIMEOUT, operation, mutating, "native process timed out", result);
|
|
1550
1636
|
if (result.signal) throw nativeError(NATIVE_REVIEW_ERROR_CODE.SIGNAL, operation, mutating, "native process was signalled", result);
|
|
1551
|
-
const maintenancePartialFailure = [NATIVE_REVIEW_OPERATION.ABANDON, NATIVE_REVIEW_OPERATION.QUARANTINE_LEGACY, NATIVE_REVIEW_OPERATION.RECONCILE_AUTHORITY, NATIVE_REVIEW_OPERATION.REPAIR_LEGACY_ALIAS].
|
|
1637
|
+
const maintenancePartialFailure = new Set ([NATIVE_REVIEW_OPERATION.ABANDON, NATIVE_REVIEW_OPERATION.QUARANTINE_LEGACY, NATIVE_REVIEW_OPERATION.RECONCILE_AUTHORITY, NATIVE_REVIEW_OPERATION.REPAIR_LEGACY_ALIAS]).has(operation) && result.exitCode !== 0;
|
|
1552
1638
|
const toleratedNotice = stderrIsTolerated(result.stderr, toleratedStderr);
|
|
1553
1639
|
if (result.exitCode !== 0 && !maintenancePartialFailure) throw nativeError(NATIVE_REVIEW_ERROR_CODE.NON_ZERO, operation, mutating, "native process failed", result);
|
|
1554
1640
|
if (result.stderr.trim().length > 0 && !maintenancePartialFailure && !toleratedNotice) throw nativeError(NATIVE_REVIEW_ERROR_CODE.UNEXPECTED_STDERR, operation, mutating, "native process wrote stderr", result);
|
|
@@ -1556,6 +1642,10 @@ class NativeReviewPlainCli {
|
|
|
1556
1642
|
}
|
|
1557
1643
|
|
|
1558
1644
|
async reviewStatus(request ) {
|
|
1645
|
+
return observeNativeStatus(this.timeoutMs, () => this.observedReviewStatus(request));
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
async observedReviewStatus(request ) {
|
|
1559
1649
|
const { body: result } = await this.execute(NATIVE_REVIEW_OPERATION.STATUS, request.cwd, ["review", "status", "--cwd", request.cwd], false, request.signal);
|
|
1560
1650
|
const status = decode(NATIVE_REVIEW_OPERATION.STATUS, false, () => decodeNativeReviewStatus(result));
|
|
1561
1651
|
if (!await repositoriesMatch(request.cwd, status.repository)) throw nativeError(NATIVE_REVIEW_ERROR_CODE.IDENTITY_MISMATCH, NATIVE_REVIEW_OPERATION.STATUS, false, "native review status repository mismatch");
|
|
@@ -1603,9 +1693,13 @@ class NativeReviewPlainCli {
|
|
|
1603
1693
|
if (request.maintainerAuthorization !== undefined && (request.maintainerAuthorization.length === 0 || /[\u0000-\u0009\u000b-\u001f\u007f]/.test(request.maintainerAuthorization))) {
|
|
1604
1694
|
throw new TypeError("Native RECOVER maintainerAuthorization must be a non-empty LF-only binding");
|
|
1605
1695
|
}
|
|
1696
|
+
if (request.baseRef !== undefined && !isCanonicalProcessString(request.baseRef)) throw new TypeError("Native RECOVER baseRef must be a non-empty, trimmed, NUL-free string");
|
|
1697
|
+
if (request.baseRef !== undefined && request.committedOnly !== true) throw new TypeError("Native RECOVER baseRef requires explicit committedOnly acknowledgement");
|
|
1698
|
+
if (request.baseRef === undefined && request.committedOnly !== undefined) throw new TypeError("Native RECOVER committedOnly requires an explicit baseRef");
|
|
1606
1699
|
if (!(NATIVE_REVIEW_RECOVER_DISPOSITION ).includes(request.disposition)) throw new TypeError("Native RECOVER disposition must be scope_changed, invalidated, or escalated");
|
|
1607
1700
|
const { body } = await this.execute(NATIVE_REVIEW_OPERATION.RECOVER, request.cwd, [
|
|
1608
1701
|
"review", "recover", "--cwd", request.cwd,
|
|
1702
|
+
...(request.baseRef === undefined ? [] : ["--base-ref", request.baseRef, "--committed-only"]),
|
|
1609
1703
|
"--predecessor-lineage", request.predecessorLineage,
|
|
1610
1704
|
"--expected-predecessor-revision", request.expectedPredecessorRevision,
|
|
1611
1705
|
"--successor-lineage", request.successorLineage,
|
|
@@ -1618,6 +1712,7 @@ class NativeReviewPlainCli {
|
|
|
1618
1712
|
}
|
|
1619
1713
|
|
|
1620
1714
|
async abandon(request ) {
|
|
1715
|
+
if (!isNativeReviewAbandonReason(request.reason)) throw new TypeError('Native ABANDON reason must be "operator_disposition" or "retired_schema"');
|
|
1621
1716
|
for (const [name, value] of [["lineage", request.lineage], ["expectedRevision", request.expectedRevision], ["snapshotIdentity", request.snapshotIdentity], ["actor", request.actor], ["reason", request.reason]] ) {
|
|
1622
1717
|
if (!isCanonicalProcessString(value)) throw new TypeError(`Native ABANDON ${name} must be a non-empty, trimmed, NUL-free string`);
|
|
1623
1718
|
}
|
|
@@ -1716,6 +1811,10 @@ export function nativeReviewAbandonAuthorization(request
|
|
|
1716
1811
|
// so the native v2 gate verifies an exact eight-line binding (schema, lineage,
|
|
1717
1812
|
// revision, snapshot_identity, reason, captured_lens_results, findings_present,
|
|
1718
1813
|
// actor) — there is no evidence_records_present line to derive or relay.
|
|
1814
|
+
// capturedLensResults must arrive verbatim from the native authority
|
|
1815
|
+
// inventory projection (issue #1159): the gate recomputes this line from its
|
|
1816
|
+
// own ordered record, whose entries carry the ordinal prefix, so caller- or
|
|
1817
|
+
// facade-authored lens names cannot reproduce it.
|
|
1719
1818
|
return [
|
|
1720
1819
|
"gentle-ai.review-abandon-authorization/v2",
|
|
1721
1820
|
`lineage=${request.lineage}`,
|
|
@@ -1856,10 +1955,11 @@ function splitNativeConsentInvocation(invocation ) {
|
|
|
1856
1955
|
continue;
|
|
1857
1956
|
}
|
|
1858
1957
|
// Provider invocations are not shell commands. Keep every path backslash
|
|
1859
|
-
// verbatim, including quoted UNC and drive-root paths. Outside quotes,
|
|
1860
|
-
// only
|
|
1958
|
+
// verbatim, including quoted UNC and drive-root paths. Outside quotes, a
|
|
1959
|
+
// backslash escapes only whitespace or a quote, so a space-containing token
|
|
1960
|
+
// and a POSIX-quoted apostrophe (`'it'\''s'`) split exactly.
|
|
1861
1961
|
const next = source[index + 1];
|
|
1862
|
-
if (character === "\\" && quote === undefined && next !== undefined && /\s/.test(next)) {
|
|
1962
|
+
if (character === "\\" && quote === undefined && next !== undefined && (/\s/.test(next) || next === "'" || next === '"')) {
|
|
1863
1963
|
escaping = true;
|
|
1864
1964
|
started = true;
|
|
1865
1965
|
continue;
|
|
@@ -2102,7 +2202,7 @@ export class NativeReviewCliV216 {
|
|
|
2102
2202
|
) {
|
|
2103
2203
|
let result ;
|
|
2104
2204
|
try {
|
|
2105
|
-
result = await this.adapter({ file: path, arguments: arguments_, cwd, timeoutMs: mutating ? undefined : this.timeoutMs, maxBufferBytes: this.maxBufferBytes, signal });
|
|
2205
|
+
result = await measureStatusAsync("adapter", () => this.adapter({ file: path, arguments: arguments_, cwd, timeoutMs: mutating ? undefined : this.timeoutMs, maxBufferBytes: this.maxBufferBytes, signal }));
|
|
2106
2206
|
} catch (error) {
|
|
2107
2207
|
if (error instanceof Error && error.name === "AbortError") throw nativeError(NATIVE_REVIEW_ERROR_CODE.CANCELLED, operation, mutating, "native process was cancelled");
|
|
2108
2208
|
throw nativeError(NATIVE_REVIEW_ERROR_CODE.UNAVAILABLE, operation, mutating, "native process could not start");
|
|
@@ -2118,7 +2218,7 @@ export class NativeReviewCliV216 {
|
|
|
2118
2218
|
const body = parseJson(result.stdout, operation, mutating, diagnostics);
|
|
2119
2219
|
if (result.exitCode !== 0) {
|
|
2120
2220
|
try {
|
|
2121
|
-
throw new NativeReviewIntegrationError(decodeReviewFailureV2(body));
|
|
2221
|
+
throw new NativeReviewIntegrationError(measureStatusSync("decode", () => decodeReviewFailureV2(body)));
|
|
2122
2222
|
} catch (error) {
|
|
2123
2223
|
if (error instanceof NativeReviewIntegrationError) throw error;
|
|
2124
2224
|
throw nativeError(NATIVE_REVIEW_ERROR_CODE.NON_ZERO, operation, mutating, "native negotiated operation failed without a valid failure envelope", result);
|
|
@@ -2137,7 +2237,7 @@ export class NativeReviewCliV216 {
|
|
|
2137
2237
|
signal ,
|
|
2138
2238
|
toleratedStderr = [],
|
|
2139
2239
|
) {
|
|
2140
|
-
return this.invoke(operation, cwd, arguments_, mutating, signal, this.executablePath(operation, mutating), toleratedStderr);
|
|
2240
|
+
return this.invoke(operation, cwd, arguments_, mutating, signal, measureStatusSync("resolution", () => this.executablePath(operation, mutating)), toleratedStderr);
|
|
2141
2241
|
}
|
|
2142
2242
|
|
|
2143
2243
|
async start(request ) {
|
|
@@ -2150,7 +2250,7 @@ export class NativeReviewCliV216 {
|
|
|
2150
2250
|
// drift; Pi never rebuilds that vector from request fields.
|
|
2151
2251
|
const projection = request.projection ?? "workspace";
|
|
2152
2252
|
const selection = nativeUntrackedSelection(request);
|
|
2153
|
-
const
|
|
2253
|
+
const statusRequest = {
|
|
2154
2254
|
cwd: request.cwd,
|
|
2155
2255
|
projection,
|
|
2156
2256
|
...(request.baseRef === undefined ? {} : { baseRef: request.baseRef, committedOnly: true }),
|
|
@@ -2159,7 +2259,19 @@ export class NativeReviewCliV216 {
|
|
|
2159
2259
|
...(request.intendedUntrackedSelection === undefined ? {} : { intendedUntrackedSelection: request.intendedUntrackedSelection }),
|
|
2160
2260
|
agent: "pi",
|
|
2161
2261
|
...(request.signal === undefined ? {} : { signal: request.signal }),
|
|
2162
|
-
}
|
|
2262
|
+
};
|
|
2263
|
+
const lensSelection = request.lenses === undefined && request.lensesReason === undefined
|
|
2264
|
+
? {}
|
|
2265
|
+
: { lenses: request.lenses, lensesReason: request.lensesReason };
|
|
2266
|
+
let status ;
|
|
2267
|
+
try {
|
|
2268
|
+
status = await this.targetStatus({ ...statusRequest, ...lensSelection });
|
|
2269
|
+
} catch (error) {
|
|
2270
|
+
// Phase A: a provider that predates lens selection still reviews,
|
|
2271
|
+
// with the tier default, instead of refusing the candidate.
|
|
2272
|
+
if (Object.keys(lensSelection).length === 0 || !isNativeReviewLensSelectionUnsupported(error)) throw error;
|
|
2273
|
+
status = await this.targetStatus(statusRequest);
|
|
2274
|
+
}
|
|
2163
2275
|
const transition = status.nextTransition?.kind === "execute" && status.nextTransition.execute?.operation === "review.start"
|
|
2164
2276
|
? status.nextTransition.execute
|
|
2165
2277
|
: undefined;
|
|
@@ -2256,6 +2368,10 @@ export class NativeReviewCliV216 {
|
|
|
2256
2368
|
}
|
|
2257
2369
|
|
|
2258
2370
|
async targetStatus(request ) {
|
|
2371
|
+
return observeNativeStatus(this.timeoutMs, () => this.observedTargetStatus(request));
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
async observedTargetStatus(request ) {
|
|
2259
2375
|
if (request.baseRef !== undefined && !isCanonicalProcessString(request.baseRef)) throw new TypeError("Native STATUS baseRef must be a non-empty, trimmed, NUL-free string");
|
|
2260
2376
|
if (request.baseRef !== undefined && request.committedOnly !== true) throw new TypeError("Native STATUS baseRef requires explicit committedOnly acknowledgement");
|
|
2261
2377
|
if (request.baseRef === undefined && request.committedOnly !== undefined) throw new TypeError("Native STATUS committedOnly requires an explicit baseRef");
|
|
@@ -2294,10 +2410,11 @@ export class NativeReviewCliV216 {
|
|
|
2294
2410
|
...(request.baseRef === undefined ? [] : ["--base-ref", request.baseRef, "--committed-only"]),
|
|
2295
2411
|
...(request.lineageId === undefined ? [] : ["--lineage", request.lineageId]),
|
|
2296
2412
|
...(request.agent === undefined ? [] : ["--agent", request.agent]),
|
|
2413
|
+
...nativeLensSelectionArguments(request),
|
|
2297
2414
|
"--next-transition",
|
|
2298
|
-
] : ["review", "status", "--cwd", request.cwd, ...submittedTokens, ...forwardedBaseRef, ...forwardedLineage];
|
|
2415
|
+
] : ["review", "status", "--cwd", request.cwd, ...submittedTokens, ...forwardedBaseRef, ...forwardedLineage, ...nativeLensSelectionArguments(request)];
|
|
2299
2416
|
const execution = await this.negotiated(NATIVE_REVIEW_OPERATION.STATUS, request.cwd, statusArguments, false, request.signal);
|
|
2300
|
-
assertSupportedNextTransitionOperation(execution.body);
|
|
2417
|
+
measureStatusSync("decode", () => assertSupportedNextTransitionOperation(execution.body));
|
|
2301
2418
|
return decode(NATIVE_REVIEW_OPERATION.STATUS, false, () => decodeReviewStatusV3(execution.body));
|
|
2302
2419
|
}
|
|
2303
2420
|
|
|
@@ -2486,13 +2603,17 @@ export class NativeReviewCliV216 {
|
|
|
2486
2603
|
// mutually exclusive with a path.
|
|
2487
2604
|
|
|
2488
2605
|
async reviewStatus(request ) {
|
|
2606
|
+
return observeNativeStatus(this.timeoutMs, () => this.observedReviewStatus(request));
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
async observedReviewStatus(request ) {
|
|
2489
2610
|
const execution = await this.invoke(
|
|
2490
2611
|
NATIVE_REVIEW_OPERATION.STATUS,
|
|
2491
2612
|
request.cwd,
|
|
2492
2613
|
["review", "status", "--cwd", request.cwd],
|
|
2493
2614
|
false,
|
|
2494
2615
|
request.signal,
|
|
2495
|
-
this.executablePath(NATIVE_REVIEW_OPERATION.STATUS, false),
|
|
2616
|
+
measureStatusSync("resolution", () => this.executablePath(NATIVE_REVIEW_OPERATION.STATUS, false)),
|
|
2496
2617
|
);
|
|
2497
2618
|
const status = decode(NATIVE_REVIEW_OPERATION.STATUS, false, () => decodeNativeReviewStatus(execution.body));
|
|
2498
2619
|
if (!await repositoriesMatch(request.cwd, status.repository)) throw nativeError(NATIVE_REVIEW_ERROR_CODE.IDENTITY_MISMATCH, NATIVE_REVIEW_OPERATION.STATUS, false, "native review status repository mismatch");
|