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,14 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
3
6
|
import { initTheme, keyHint } from "@earendil-works/pi-coding-agent";
|
|
4
7
|
import { imageFallback, visibleWidth } from "@earendil-works/pi-tui";
|
|
5
8
|
import { cardBody, cardHint, cardTitle, cardTone } from "./gentle-card-text.ts";
|
|
6
9
|
import { CARD_STYLE, cardStyle, setCardStyle } from "../lib/shell-card.ts";
|
|
7
10
|
import { stripAnsi } from "../lib/terminal-theme.ts";
|
|
11
|
+
import { CARD_CONTENT, cardContent, setCardContent } from "../lib/card-content-policy.ts";
|
|
8
12
|
import piPretty from "../extensions/pi-pretty.ts";
|
|
9
13
|
import productionQuietTools, {
|
|
10
14
|
createQuietToolRenderer,
|
|
@@ -252,7 +256,7 @@ test("quiet tool rendering can be disabled by env", () => {
|
|
|
252
256
|
|
|
253
257
|
test("pi-pretty suppresses overlapping tools before quiet tools register", async () => {
|
|
254
258
|
await withEnvAsync(
|
|
255
|
-
{ GENTLE_PI_QUIET_TOOLS: undefined, PRETTY_DISABLE_TOOLS: "multi_grep" },
|
|
259
|
+
{ GENTLE_PI_AGENTS_CHILD: undefined, GENTLE_PI_QUIET_TOOLS: undefined, PRETTY_DISABLE_TOOLS: "multi_grep" },
|
|
256
260
|
async () => {
|
|
257
261
|
const { pi, tools } = createPi({ throwOnToolConflict: true });
|
|
258
262
|
|
|
@@ -270,7 +274,7 @@ test("pi-pretty suppresses overlapping tools before quiet tools register", async
|
|
|
270
274
|
|
|
271
275
|
test("pi-pretty preserves byte-exact model-visible read results when quiet tools suppress its renderer", async () => {
|
|
272
276
|
await withEnvAsync(
|
|
273
|
-
{ GENTLE_PI_QUIET_TOOLS: undefined, PRETTY_DISABLE_TOOLS: undefined },
|
|
277
|
+
{ GENTLE_PI_AGENTS_CHILD: undefined, GENTLE_PI_QUIET_TOOLS: undefined, PRETTY_DISABLE_TOOLS: undefined },
|
|
274
278
|
async () => {
|
|
275
279
|
const { pi, hooks } = createPi();
|
|
276
280
|
await piPretty(pi as any, fakePiPrettyDeps as any);
|
|
@@ -293,6 +297,7 @@ test("pi-pretty preserves byte-exact model-visible read results when quiet tools
|
|
|
293
297
|
test("pi-pretty suppression is skipped when quiet tools are disabled", async () => {
|
|
294
298
|
await withEnvAsync(
|
|
295
299
|
{
|
|
300
|
+
GENTLE_PI_AGENTS_CHILD: undefined,
|
|
296
301
|
GENTLE_PI_QUIET_TOOLS: "0",
|
|
297
302
|
PRETTY_DISABLE_TOOLS: undefined,
|
|
298
303
|
PRETTY_ENABLE_TOOLS: "ls",
|
|
@@ -424,7 +429,7 @@ test("quiet Bash errors preserve meaningful rows for both public output ordering
|
|
|
424
429
|
["probe stderr detail \x1b[31mwith terminal color\x1b[0m", ["", ""]],
|
|
425
430
|
["probe exit status: 7", []],
|
|
426
431
|
]],
|
|
427
|
-
]
|
|
432
|
+
] satisfies ReadonlyArray<readonly [string, ReadonlyArray<readonly [string, readonly string[]]>]>;
|
|
428
433
|
assert.equal(cases.length, 2);
|
|
429
434
|
const args = { command: "false" };
|
|
430
435
|
const renderResult = (result: any, expanded: boolean) => tool.renderResult(result, { expanded, isPartial: false, isError: true }, passthroughTheme, { args, isError: true });
|
|
@@ -989,6 +994,62 @@ test("quiet tool rendering keeps concise collapsed edit and write summaries", ()
|
|
|
989
994
|
assert.equal(formatToolResultOutput("write", textResult("Successfully wrote 12 bytes\n" + text) as any, { expanded: false }), "\n✓ wrote 12 bytes");
|
|
990
995
|
});
|
|
991
996
|
|
|
997
|
+
test("quiet write expansion shows the complete written content without changing the compact summary", () => {
|
|
998
|
+
const tool = registeredQuietTools().get("write");
|
|
999
|
+
const content = Array.from({ length: 12 }, (_, index) => `written line ${index + 1}`).join("\n");
|
|
1000
|
+
const result = textResult("Successfully wrote 182 bytes to file.ts");
|
|
1001
|
+
const context = { args: { path: "file.ts", content } };
|
|
1002
|
+
|
|
1003
|
+
assert.equal(renderToolResult(tool, result, { expanded: true, isPartial: false }, context), content);
|
|
1004
|
+
assert.equal(renderToolResult(tool, result, { expanded: false, isPartial: false }, context), "✓ wrote 182 bytes");
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
test("quiet write expansion renders content after a real built-in write", async () => {
|
|
1008
|
+
const cwd = await mkdtemp(join(tmpdir(), "gentle-write-expanded-"));
|
|
1009
|
+
try {
|
|
1010
|
+
const tool = registeredQuietTools().get("write");
|
|
1011
|
+
const args = { path: "example.ts", content: "export const answer = 42;\n" };
|
|
1012
|
+
const result = await tool.execute("write-expanded", args, undefined, undefined, { cwd });
|
|
1013
|
+
|
|
1014
|
+
assert.equal(await readFile(join(cwd, args.path), "utf8"), args.content);
|
|
1015
|
+
assert.match(extractTextContent(result), /Successfully wrote/);
|
|
1016
|
+
assert.doesNotMatch(extractTextContent(result), /export const answer/);
|
|
1017
|
+
assert.equal(renderToolResult(tool, result, { expanded: true, isPartial: false }, { args }), args.content);
|
|
1018
|
+
} finally {
|
|
1019
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
test("quiet write expansion sanitizes content and respects narrow card widths", () => {
|
|
1024
|
+
const tool = registeredQuietTools().get("write");
|
|
1025
|
+
const content = "first\n\nsafe\x1b]52;c;Y2xpcGJvYXJk\x07\x1b[2Jdone\n界e\u0301😀";
|
|
1026
|
+
const result = textResult("Successfully wrote to file.ts");
|
|
1027
|
+
const context = { args: { path: "file.ts", content } };
|
|
1028
|
+
const options = { expanded: true, isPartial: false };
|
|
1029
|
+
|
|
1030
|
+
assert.equal(renderToolResult(tool, result, options, context), "first\n\nsafedone\n界e\u0301😀");
|
|
1031
|
+
const lines = frameLines(tool.renderResult(result, options, passthroughTheme, context), 16);
|
|
1032
|
+
assert.ok(lines.every((line) => visibleWidth(line) <= 16));
|
|
1033
|
+
assert.doesNotMatch(lines.join("\n"), /\x1b/);
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
test("quiet write expansion preserves failures, partial results and fallback confirmations", () => {
|
|
1037
|
+
const tool = registeredQuietTools().get("write");
|
|
1038
|
+
const context = { args: { path: "file.ts", content: "not written" } };
|
|
1039
|
+
const options = { expanded: true, isPartial: false };
|
|
1040
|
+
for (const errorContext of [context, { ...context, isError: true }]) {
|
|
1041
|
+
const rendered = renderToolResult(tool, textResult("EACCES: permission denied"), { ...options, isError: true }, errorContext);
|
|
1042
|
+
assert.equal(rendered, "EACCES: permission denied");
|
|
1043
|
+
}
|
|
1044
|
+
const partial = renderToolResult(tool, textResult("writing…"), { expanded: true, isPartial: true }, context);
|
|
1045
|
+
assert.match(partial, /writing…/);
|
|
1046
|
+
assert.doesNotMatch(partial, /not written/);
|
|
1047
|
+
const confirmation = "Successfully wrote 0 bytes to file.ts";
|
|
1048
|
+
for (const fallbackContext of [{}, { args: {} }, { args: { content: 42 } }, { args: { content: "" } }]) {
|
|
1049
|
+
assert.equal(renderToolResult(tool, textResult(confirmation), options, fallbackContext), confirmation);
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
|
|
992
1053
|
test("quiet tool rendering sanitizes collapsed output and call rows", () => {
|
|
993
1054
|
const { pi, tools } = createPi();
|
|
994
1055
|
withEnv({ GENTLE_PI_QUIET_TOOLS: undefined }, () => quietTools(pi as any));
|
|
@@ -1586,3 +1647,99 @@ test("quiet cards stay outlined in the neon style with a background-capable them
|
|
|
1586
1647
|
assert.match(rows.at(-1)!, /^╰─+╯$/);
|
|
1587
1648
|
assert.doesNotMatch(rows.join("\n"), /▎/);
|
|
1588
1649
|
});
|
|
1650
|
+
|
|
1651
|
+
// The Card content slot is process-wide; each test that needs a level sets it
|
|
1652
|
+
// and restores the previous one.
|
|
1653
|
+
function useCardContent(t: { after(fn: () => void): void }, level: (typeof CARD_CONTENT)[keyof typeof CARD_CONTENT]): void {
|
|
1654
|
+
const previous = cardContent();
|
|
1655
|
+
t.after(() => setCardContent(previous));
|
|
1656
|
+
setCardContent(level);
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
test("the Card content preference defaults to the result previews", () => {
|
|
1660
|
+
assert.equal(cardContent(), CARD_CONTENT.DEFAULT);
|
|
1661
|
+
const rendered = renderToolResult(registeredQuietTools().get("read"), textResult("first line\nsecond line"), { expanded: false, isPartial: false }, {});
|
|
1662
|
+
assert.match(rendered, /first line/);
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
test("minimal command-only cards keep the bounded error tail of failed calls", (t) => {
|
|
1666
|
+
useCardContent(t, CARD_CONTENT.MINIMAL);
|
|
1667
|
+
const tools = registeredQuietTools();
|
|
1668
|
+
for (const toolName of ["read", "bash", "write", "grep", "find", "ls", "edit"] as const) {
|
|
1669
|
+
const rendered = renderToolResult(tools.get(toolName), textResult("error one\nerror two\nerror three\nerror four"), { expanded: false, isPartial: false, isError: true }, toolName === "bash" ? { args: { command: "false" } } : {});
|
|
1670
|
+
assert.match(rendered, /error two\nerror three\nerror four/, `${toolName}: a failed call says why while collapsed`);
|
|
1671
|
+
assert.doesNotMatch(rendered, /to expand/);
|
|
1672
|
+
}
|
|
1673
|
+
});
|
|
1674
|
+
|
|
1675
|
+
test("every quiet tool card shows only the command while collapsed and stays expandable", (t) => {
|
|
1676
|
+
useCardContent(t, CARD_CONTENT.MINIMAL);
|
|
1677
|
+
const tools = registeredQuietTools();
|
|
1678
|
+
const finished = { isPartial: false, executionStarted: true };
|
|
1679
|
+
const cases: Array<[string, Record<string, unknown>, string, string]> = [
|
|
1680
|
+
["read", { path: "a.ts" }, "first line\nsecond line", "first line"],
|
|
1681
|
+
["write", { path: "b.ts", content: "body" }, "Successfully wrote 4 bytes", "body"],
|
|
1682
|
+
["bash", { command: "printf hi" }, "hi\nthere", "there"],
|
|
1683
|
+
["grep", { pattern: "needle", path: "src" }, "src/a.ts:1:needle", "src/a.ts:1:needle"],
|
|
1684
|
+
["find", { pattern: "*.ts", path: "src" }, "src/a.ts\nsrc/b.ts", "src/b.ts"],
|
|
1685
|
+
["ls", { path: "src" }, "file-a.ts\nfile-b.ts", "file-b.ts"],
|
|
1686
|
+
["edit", { path: "file.ts", edits: [] }, "Applied edits", "Applied edits"],
|
|
1687
|
+
];
|
|
1688
|
+
for (const [name, args, output, visible] of cases) {
|
|
1689
|
+
const tool = tools.get(name);
|
|
1690
|
+
const context = routineRenderContext({ args, ...finished });
|
|
1691
|
+
const callRows = tool.renderCall(args, passthroughTheme, context).render(120).map(stripAnsi);
|
|
1692
|
+
assert.ok(callRows.some((row) => row.includes("to expand")), `${name}: the expand key stays`);
|
|
1693
|
+
const collapsed = renderToString(tool.renderResult(textResult(output), { expanded: false, isPartial: false }, passthroughTheme, context));
|
|
1694
|
+
assert.equal(collapsed.trim(), "", `${name}: no result rows while collapsed`);
|
|
1695
|
+
const expanded = renderToString(tool.renderResult(textResult(output), { expanded: true, isPartial: false }, passthroughTheme, context));
|
|
1696
|
+
assert.match(expanded, new RegExp(visible.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")), `${name}: expanding reveals the result`);
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
|
|
1700
|
+
test("the default Card content preference restores result previews and native bash drawing", () => {
|
|
1701
|
+
const tools = registeredQuietTools();
|
|
1702
|
+
const read = tools.get("read");
|
|
1703
|
+
setCardContent(CARD_CONTENT.DEFAULT);
|
|
1704
|
+
try {
|
|
1705
|
+
const context = routineRenderContext({ args: { path: "a.ts" }, executionStarted: true, isPartial: false });
|
|
1706
|
+
const collapsed = renderToString(read.renderResult(textResult("first line\nsecond line"), { expanded: false, isPartial: false }, passthroughTheme, context));
|
|
1707
|
+
assert.match(collapsed, /first line\nsecond line/, "default content keeps the read preview");
|
|
1708
|
+
const write = renderToString(tools.get("write").renderResult(textResult("Successfully wrote 4 bytes"), { expanded: false, isPartial: false }, passthroughTheme, routineRenderContext({ args: { path: "b.ts", content: "body" }, executionStarted: true, isPartial: false })));
|
|
1709
|
+
assert.match(write, /wrote 4 bytes/, "default content keeps the write summary");
|
|
1710
|
+
|
|
1711
|
+
const { pi } = createPi();
|
|
1712
|
+
const resolvers: Array<(toolName: string, next: () => unknown) => unknown> = [];
|
|
1713
|
+
(pi as any).registerToolRenderer = (resolver: (toolName: string, next: () => unknown) => unknown) => {
|
|
1714
|
+
resolvers.push(resolver);
|
|
1715
|
+
};
|
|
1716
|
+
withEnv({ GENTLE_PI_QUIET_TOOLS: undefined }, () => quietTools(pi as any));
|
|
1717
|
+
const native = { marker: "native" };
|
|
1718
|
+
assert.equal(resolvers.at(-1)!("bash", () => native), native, "default content defers bash drawing to the native renderer");
|
|
1719
|
+
assert.equal(resolvers.at(-1)!("read", () => native), native, "every other tool still defers");
|
|
1720
|
+
} finally {
|
|
1721
|
+
setCardContent(CARD_CONTENT.DEFAULT);
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
|
|
1725
|
+
test("the production factory takes over native bash drawing through a tool renderer resolver", (t) => {
|
|
1726
|
+
useCardContent(t, CARD_CONTENT.MINIMAL);
|
|
1727
|
+
const { pi } = createPi();
|
|
1728
|
+
const resolvers: Array<(toolName: string, next: () => unknown) => unknown> = [];
|
|
1729
|
+
(pi as any).registerToolRenderer = (resolver: (toolName: string, next: () => unknown) => unknown) => {
|
|
1730
|
+
resolvers.push(resolver);
|
|
1731
|
+
};
|
|
1732
|
+
withEnv({ GENTLE_PI_QUIET_TOOLS: undefined }, () => quietTools(pi as any));
|
|
1733
|
+
assert.ok(resolvers.length >= 1, "quiet tools registers a tool renderer resolver");
|
|
1734
|
+
const resolver = resolvers.at(-1)!;
|
|
1735
|
+
const native = { marker: "native" };
|
|
1736
|
+
assert.equal(resolver("read", () => native), native, "every other tool keeps the next renderer");
|
|
1737
|
+
const bash = resolver("bash", () => native) as any;
|
|
1738
|
+
assert.notEqual(bash, native);
|
|
1739
|
+
assert.equal(bash.renderShell, "self");
|
|
1740
|
+
assert.equal(typeof bash.renderCall, "function");
|
|
1741
|
+
assert.equal(typeof bash.renderResult, "function");
|
|
1742
|
+
const call = bash.renderCall({ command: "printf hi", timeout: 5 }, passthroughTheme, routineRenderContext({ args: { command: "printf hi", timeout: 5 }, executionStarted: true, isPartial: false }));
|
|
1743
|
+
assert.match(renderToString(call), /printf hi \(timeout 5s\)/);
|
|
1744
|
+
});
|
|
1745
|
+
|
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import test from "node:test";
|
|
5
5
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { createGentleAiExtension } from "../extensions/gentle-ai.ts";
|
|
7
|
+
import { readDelegationDetail } from "./support/orchestrator-modules.ts";
|
|
7
8
|
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
// gentle-pi#661/#662: RDD-aware verification rule for delegated work.
|
|
@@ -14,15 +15,14 @@ import { createGentleAiExtension } from "../extensions/gentle-ai.ts";
|
|
|
14
15
|
// rendered `Receipt-driven development:` line, stated normatively exactly
|
|
15
16
|
// once in trigger 5 (Verification rule) and referenced -- not restated --
|
|
16
17
|
// everywhere else in this asset:
|
|
17
|
-
// - `on`
|
|
18
|
-
//
|
|
19
|
-
// passive risk, which gets a structural readback.
|
|
20
|
-
// - `off`/`unknown` -> gentle-pi#662: the parent calls `gentle_review` with
|
|
18
|
+
// - every line (`on`, `off`, `unknown`) -> verify-always-rdd-high S1: the
|
|
19
|
+
// parent calls `gentle_review` with
|
|
21
20
|
// `{"operation":"assess"}` over the writer's diff and
|
|
22
21
|
// follows the returned plan by native risk tier
|
|
23
22
|
// (passive/medium/high/unassessable), instead of a
|
|
24
|
-
// blanket non-trivial judgment.
|
|
25
|
-
//
|
|
23
|
+
// blanket non-trivial judgment.
|
|
24
|
+
// - `on` -> the native review is an additional outside view; it
|
|
25
|
+
// never replaces or skips the tier's verification.
|
|
26
26
|
// These tests assert the exact distinctive sentences (not bare words like
|
|
27
27
|
// `off`/`unknown`/`partial`/`blocked`), that the tier table is stated exactly
|
|
28
28
|
// once, that the routing ladder paragraph references trigger 5 rather than
|
|
@@ -41,14 +41,14 @@ function countOccurrences(haystack: string, needle: string): number {
|
|
|
41
41
|
return haystack.split(needle).length - 1;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const delegation =
|
|
44
|
+
const delegation = readDelegationDetail();
|
|
45
45
|
const worker = read("assets/agents/gentle-ai-worker.md");
|
|
46
46
|
|
|
47
|
-
const
|
|
48
|
-
"
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const TIER_TABLE_HEADER = "| Native risk tier | Verification
|
|
47
|
+
const ROUTING_SENTENCE =
|
|
48
|
+
'After the writer returns, call `gentle_review` with `{"operation":"assess"}` over the writer\'s diff and follow the returned plan, whatever the `Receipt-driven development:` line reads (`on`, `off`, or `unknown`), instead of judging non-triviality from the task description: the operation resolves the native risk tier and states exactly who verifies next.';
|
|
49
|
+
const RDD_ON_SENTENCE =
|
|
50
|
+
"When the line reads `on`, the native review is an additional outside view of the change; it never replaces or skips the tier's verification, and the tier's verifier runs before review.";
|
|
51
|
+
const TIER_TABLE_HEADER = "| Native risk tier | Verification (any RDD state) |";
|
|
52
52
|
const PASSIVE_TIER_ROW = "| passive | structural readback by the parent; no separate verifier, no tests |";
|
|
53
53
|
const MEDIUM_TIER_ROW = "| medium | writer self-verification stands; a separate `gentle-ai-verify` run is added only when the writer profile is a small model (mini or low effort) |";
|
|
54
54
|
const HIGH_TIER_ROW = "| high | writer self-verification plus a separate `gentle-ai-verify` run, always |";
|
|
@@ -57,19 +57,15 @@ const SMALL_MODEL_BIAS_SENTENCE =
|
|
|
57
57
|
"The small-model bias raises the tier by one for verification purposes (medium becomes high); an unknown `Receipt-driven development:` line never lowers a tier below `off`.";
|
|
58
58
|
const SPOT_CHECK_SENTENCE =
|
|
59
59
|
"The parent spot check (re-running one reported command before delivery) stays required in every tier.";
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// a clone-local disable, or a refused START/STATUS all fall back to the exact
|
|
63
|
-
// same risk-gated path as `off`.
|
|
64
|
-
const ON_BRANCH_FALLBACK_SENTENCE =
|
|
65
|
-
'That `on` branch holds only while the native review actually reaches a terminal outcome for this candidate (gentle-pi#668): a human decline of the consent envelope for this candidate (candidate-scoped, never the RDD kill switch), a clone-local RDD disable discovered mid-flow, or a refused START/STATUS all fall back to the risk-gated path exactly as `off` -- call `gentle_review` with `{"operation":"assess"}` (pass `nativeReviewOutcome` when the parent already knows it; the tool derives it from what it itself observed for the candidate otherwise, failing closed to `unknown` when it cannot) and follow the returned plan.';
|
|
66
|
-
|
|
67
|
-
test("trigger 5 (Verification rule) states the exact on-line routing: writer report is the verification of record", () => {
|
|
68
|
-
assert.ok(delegation.includes(ON_SENTENCE), "trigger 5 is missing the exact on-line sentence");
|
|
60
|
+
test("trigger 5 (Verification rule) routes every RDD line through assess and the risk tier", () => {
|
|
61
|
+
assert.ok(delegation.includes(ROUTING_SENTENCE), "trigger 5 is missing the exact routing sentence");
|
|
69
62
|
});
|
|
70
63
|
|
|
71
|
-
test("trigger 5 states
|
|
72
|
-
assert.ok(delegation.includes(
|
|
64
|
+
test("trigger 5 states that with RDD on the native review adds an outside view and never replaces verification", () => {
|
|
65
|
+
assert.ok(delegation.includes(RDD_ON_SENTENCE), "trigger 5 is missing the RDD-on sentence");
|
|
66
|
+
for (const banned of ["verification of record", "becomes on-demand", "on-demand only", "on-demand verify"]) {
|
|
67
|
+
assert.ok(!delegation.includes(banned), `the native review still replaces verification somewhere: ${banned}`);
|
|
68
|
+
}
|
|
73
69
|
});
|
|
74
70
|
|
|
75
71
|
test("trigger 5 states the native risk tier table exactly once, with all four rows", () => {
|
|
@@ -86,21 +82,14 @@ test("trigger 5 keeps the parent spot check requirement in every tier", () => {
|
|
|
86
82
|
assert.ok(delegation.includes(SPOT_CHECK_SENTENCE), "trigger 5 is missing the parent spot check sentence");
|
|
87
83
|
});
|
|
88
84
|
|
|
89
|
-
test("trigger 5
|
|
90
|
-
assert.equal(countOccurrences(delegation, ON_BRANCH_FALLBACK_SENTENCE), 1, "trigger 5 is missing (or duplicates) the on-branch fallback sentence");
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("the on-branch fallback sentence names all three non-closed triggers and never introduces a forbidden native RDD marker", () => {
|
|
94
|
-
for (const clause of ["decline", "clone-local", "refused START/STATUS"]) {
|
|
95
|
-
assert.ok(ON_BRANCH_FALLBACK_SENTENCE.includes(clause), `on-branch fallback sentence missing: ${clause}`);
|
|
96
|
-
}
|
|
85
|
+
test("trigger 5 never introduces a forbidden native RDD marker", () => {
|
|
97
86
|
for (const marker of ["gentle-ai review status", "next_transition", "review.capture-result", "review.validate", "reviewGate.result"]) {
|
|
98
87
|
assert.ok(!delegation.includes(marker), `stale/forbidden RDD marker introduced: ${marker}`);
|
|
99
88
|
}
|
|
100
89
|
});
|
|
101
90
|
|
|
102
|
-
test("the
|
|
103
|
-
for (const sentence of [
|
|
91
|
+
test("the routing and RDD-on sentences appear exactly once each (normative statement lives only in trigger 5)", () => {
|
|
92
|
+
for (const sentence of [ROUTING_SENTENCE, RDD_ON_SENTENCE]) {
|
|
104
93
|
assert.equal(countOccurrences(delegation, sentence), 1, `expected exactly one occurrence of: ${sentence.slice(0, 60)}...`);
|
|
105
94
|
}
|
|
106
95
|
});
|
|
@@ -110,15 +99,15 @@ test("trigger 5 never restates the retired #661 off/unknown non-trivial judgment
|
|
|
110
99
|
assert.doesNotMatch(delegation, /purely passive documentation with no behavior to verify/);
|
|
111
100
|
});
|
|
112
101
|
|
|
113
|
-
test("the Simple Delegation paragraph references trigger
|
|
102
|
+
test("the Simple Delegation paragraph references trigger 3 instead of restating the on/off/unknown routing", () => {
|
|
114
103
|
assert.match(
|
|
115
104
|
delegation,
|
|
116
|
-
/per the RDD-aware Verification rule \(trigger
|
|
105
|
+
/per the RDD-aware Verification rule \(trigger 3 under Mandatory Delegation Triggers, gentle-pi#661\)/,
|
|
117
106
|
);
|
|
118
|
-
assert.match(delegation, /the normative on\/off\/unknown routing lives
|
|
107
|
+
assert.match(delegation, /the normative on\/off\/unknown routing lives in `orchestrator-verification.md`, not here/);
|
|
119
108
|
});
|
|
120
109
|
|
|
121
|
-
test("delegation overlay's
|
|
110
|
+
test("delegation overlay's Verification rule is RDD-aware", () => {
|
|
122
111
|
assert.match(delegation, /\*\*Verification rule\*\*.*RDD-aware/);
|
|
123
112
|
});
|
|
124
113
|
|
|
@@ -194,8 +183,8 @@ test("delegation asset references the worker's Known environmental failures defi
|
|
|
194
183
|
});
|
|
195
184
|
|
|
196
185
|
test("worker asset never claims completion while a required verification command fails under RDD, except a named environmental failure", () => {
|
|
197
|
-
assert.
|
|
198
|
-
assert.match(worker, /
|
|
186
|
+
assert.doesNotMatch(worker, /verification of record/i);
|
|
187
|
+
assert.match(worker, /this report is your self-verification; the risk tier decides whether an independent verifier also runs/i);
|
|
199
188
|
assert.match(
|
|
200
189
|
worker,
|
|
201
190
|
/never report `status: completed` while a required command under `## Verification` is failing, unless that exact failure is named under `## Known environmental failures`\./i,
|
|
@@ -279,8 +268,7 @@ const SHARED_POLICY_PHRASES: ReadonlyArray<readonly [string, string]> = [
|
|
|
279
268
|
["runtime writer profile", "runtime-recorded model and effort of the pending mutations"],
|
|
280
269
|
["caller profile is only a fallback", "only a fallback when no runtime evidence exists"],
|
|
281
270
|
["conservative small-model bias", "keeps the conservative small-model bias"],
|
|
282
|
-
["
|
|
283
|
-
["unknown is never closed", "unknown is never treated as closed"],
|
|
271
|
+
["native review never replaces verification (verify-always-rdd-high S1)", "native review is an additional outside view"],
|
|
284
272
|
["functional checks still run", "a native code review is not a substitute for applicable functional checks"],
|
|
285
273
|
];
|
|
286
274
|
|
|
@@ -306,3 +306,55 @@ test("the on and off renders are never longer than the unknown (worst-case) rend
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
});
|
|
309
|
+
|
|
310
|
+
// gentle-shell#1029: the rendered RDD line is part of the cached system-prompt
|
|
311
|
+
// prefix. A re-read after the TTL that fails or times out must not flip a
|
|
312
|
+
// known on/off line to "unknown" and back: the last successfully read status
|
|
313
|
+
// stays until the native reader reports a different status.
|
|
314
|
+
test("resolveRddModeStatus keeps the last known status when a later re-read fails", async () => {
|
|
315
|
+
clearRddStatusMemoForTesting();
|
|
316
|
+
const cwd = "/repo-sticky-status";
|
|
317
|
+
let clock = 1_000_000;
|
|
318
|
+
const now = () => clock;
|
|
319
|
+
let fail = false;
|
|
320
|
+
let calls = 0;
|
|
321
|
+
const cli: Pick<NativeReviewCli, "reviewMode"> = {
|
|
322
|
+
async reviewMode() {
|
|
323
|
+
calls += 1;
|
|
324
|
+
if (fail) throw new Error("native review CLI unavailable");
|
|
325
|
+
return modeResult("on", NATIVE_REVIEW_MODE_SOURCE.GLOBAL);
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
const first = await resolveRddModeStatus(cli, cwd, undefined, now);
|
|
329
|
+
assert.equal(first?.effective, "on");
|
|
330
|
+
fail = true;
|
|
331
|
+
clock += RDD_STATUS_MEMO_TTL_MS + 1;
|
|
332
|
+
const second = await resolveRddModeStatus(cli, cwd, undefined, now);
|
|
333
|
+
assert.equal(calls, 2, "the expired memo must still trigger a re-read");
|
|
334
|
+
assert.deepEqual(second, first, "a failed re-read must keep the last known status, not render unknown");
|
|
335
|
+
assert.equal(
|
|
336
|
+
await resolveRddStatusLine(cli, cwd, undefined, now),
|
|
337
|
+
"Receipt-driven development: on (decided by global)",
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("resolveRddModeStatus still follows a real status change after a re-read", async () => {
|
|
342
|
+
clearRddStatusMemoForTesting();
|
|
343
|
+
const cwd = "/repo-status-change";
|
|
344
|
+
let clock = 1_000_000;
|
|
345
|
+
const now = () => clock;
|
|
346
|
+
let effective: "on" | "off" = "on";
|
|
347
|
+
const cli: Pick<NativeReviewCli, "reviewMode"> = {
|
|
348
|
+
async reviewMode() { return modeResult(effective, NATIVE_REVIEW_MODE_SOURCE.GLOBAL); },
|
|
349
|
+
};
|
|
350
|
+
assert.equal((await resolveRddModeStatus(cli, cwd, undefined, now))?.effective, "on");
|
|
351
|
+
effective = "off";
|
|
352
|
+
clock += RDD_STATUS_MEMO_TTL_MS + 1;
|
|
353
|
+
assert.equal((await resolveRddModeStatus(cli, cwd, undefined, now))?.effective, "off");
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("resolveRddModeStatus stays unknown when no status was ever read", async () => {
|
|
357
|
+
clearRddStatusMemoForTesting();
|
|
358
|
+
const cli = fakeReviewMode(() => { throw new Error("never available"); });
|
|
359
|
+
assert.equal(await resolveRddModeStatus(cli, "/repo-never-known"), undefined);
|
|
360
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { closeSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { compare, outputDescriptor, percentile, summarize } from "../scripts/render-cache-performance.mjs";
|
|
7
|
+
|
|
8
|
+
test("summaries preserve raw samples and interpolate percentiles", () => {
|
|
9
|
+
const samples = [4, 1, 3, 2];
|
|
10
|
+
assert.equal(percentile(samples, 0.5), 2.5);
|
|
11
|
+
assert.ok(Math.abs(percentile(samples, 0.95)! - 3.85) < 1e-10);
|
|
12
|
+
assert.deepEqual(samples, [4, 1, 3, 2]);
|
|
13
|
+
assert.deepEqual(summarize([]), { count: 0, median: null, p95: null, max: null });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const run = () => ({ metadata: { piVersion: "1.1.0", editorIdentityVerified: true }, cases: [{
|
|
17
|
+
spec: { tools: 100, scenario: "scroll" }, coldScreen: "cold", screens: ["screen"], wallMs: [2, 2],
|
|
18
|
+
}] });
|
|
19
|
+
|
|
20
|
+
test("comparison requires identical cold and warm outputs and host identity", () => {
|
|
21
|
+
const before = run();
|
|
22
|
+
const after = run();
|
|
23
|
+
after.cases[0]!.wallMs = [1, 1];
|
|
24
|
+
assert.equal(compare(before, after)[0]!.speedup, 2);
|
|
25
|
+
after.cases[0]!.screens = ["changed"];
|
|
26
|
+
assert.throws(() => compare(before, after));
|
|
27
|
+
after.cases[0]!.screens = ["screen"];
|
|
28
|
+
after.cases[0]!.coldScreen = "changed";
|
|
29
|
+
assert.throws(() => compare(before, after), "cold output must also agree");
|
|
30
|
+
after.cases[0]!.coldScreen = "cold";
|
|
31
|
+
after.metadata.piVersion = "other-host";
|
|
32
|
+
assert.throws(() => compare(before, after), "cannot compare different Pi versions");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("report outputs cannot overwrite files or enter protected roots via symlinks", () => {
|
|
36
|
+
const home = mkdtempSync(join(tmpdir(), "render-cache-output-"));
|
|
37
|
+
try {
|
|
38
|
+
const source = join(home, "source"); mkdirSync(source);
|
|
39
|
+
symlinkSync(source, join(home, "alias"), "dir");
|
|
40
|
+
assert.throws(() => outputDescriptor(join(home, "alias", "report.json"), [source]));
|
|
41
|
+
const existing = join(home, "existing.json"); writeFileSync(existing, "keep");
|
|
42
|
+
assert.throws(() => outputDescriptor(existing, [source]));
|
|
43
|
+
symlinkSync(existing, join(home, "link.json"));
|
|
44
|
+
assert.throws(() => outputDescriptor(join(home, "link.json"), [source]));
|
|
45
|
+
assert.equal(readFileSync(existing, "utf8"), "keep");
|
|
46
|
+
closeSync(outputDescriptor(join(home, "new.json"), [source]));
|
|
47
|
+
} finally { rmSync(home, { recursive: true, force: true }); }
|
|
48
|
+
});
|