gentle-pi 3.7.0 → 4.1.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 +155 -10
- package/assets/agents/gentle-ai-explore.md +13 -6
- package/assets/agents/gentle-ai-verify.md +27 -6
- package/assets/agents/gentle-ai-worker.md +13 -15
- 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 +75 -169
- package/assets/orchestrator-memory.md +12 -26
- package/assets/orchestrator-prompts.md +48 -0
- package/assets/orchestrator-skills.md +1 -1
- 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 +30 -38
- 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/assets/support/strict-tdd-verify.md +4 -266
- package/assets/support/strict-tdd.md +8 -360
- package/bin/engram-guard +9 -0
- package/bin/gentle-shell-install.mjs +302 -0
- package/bin/gentle-shell.mjs +956 -50
- 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/bundled-install.md +397 -0
- package/docs/delegated-verification.md +27 -4
- package/docs/gentle-agents-activity.md +537 -0
- package/docs/gentle-shell-uninstall.md +136 -0
- package/docs/gentle-shell.md +165 -51
- package/docs/install-wizard.md +2040 -0
- package/docs/native-authority-architecture.md +3 -3
- package/docs/permission-modes.md +82 -0
- package/docs/prompt-history.md +280 -0
- package/docs/readme-reference.md +364 -231
- package/docs/render-cache-performance.md +28 -0
- package/docs/sound-notifications-proposal.md +191 -0
- package/docs/sound-notifications.md +114 -0
- package/docs/telemetry.md +1 -1
- package/docs/yolo-mode.md +86 -0
- package/extensions/child-context.ts +35 -0
- package/extensions/child-safety.ts +25 -0
- package/extensions/codegraph-tools.ts +18 -5
- package/extensions/gentle-agents.ts +1093 -326
- package/extensions/gentle-ai.ts +1636 -890
- package/extensions/gentle-herdr-activity.ts +81 -0
- package/extensions/gentle-notifications.ts +104 -0
- package/extensions/gentle-shell.ts +1619 -136
- package/extensions/gentle-stats.ts +101 -0
- package/extensions/gentle-todo.ts +126 -20
- package/extensions/history/atomic-write.ts +38 -0
- package/extensions/history/hide-prompts.ts +183 -0
- package/extensions/history/index.ts +1424 -0
- package/extensions/history/load-shared-history.ts +39 -0
- package/extensions/history/selector-helpers.ts +538 -0
- package/extensions/history/session-scan.ts +233 -0
- package/extensions/history/store.ts +1119 -0
- package/extensions/nan-provider.ts +6 -0
- package/extensions/pi-pretty.ts +39 -3
- package/extensions/quiet-tools.ts +254 -92
- package/extensions/resume-hint.ts +60 -0
- package/extensions/skill-registry.ts +191 -58
- package/extensions/startup-banner.ts +71 -33
- package/lib/agent-assets.ts +604 -0
- package/lib/agent-home.ts +10 -1
- package/lib/agent-model-resolution.ts +80 -0
- package/lib/agent-profile-pin.ts +12 -0
- package/lib/agent-profiles.ts +13 -3
- package/lib/agents-completion-delivery.ts +11 -3
- package/lib/agents-message-delivery.ts +181 -0
- package/lib/agents-messaging.ts +1 -1
- package/lib/agents-protocol.ts +99 -0
- package/lib/agents-runner.ts +180 -107
- package/lib/agents-view.ts +26 -3
- package/lib/agents-widget.ts +16 -9
- package/lib/append-system-prompt.ts +21 -0
- package/lib/auto-permission-classifier.ts +280 -0
- package/lib/auto-permission-runtime.ts +268 -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 +220 -0
- package/lib/builtin-codemode-optout.ts +166 -0
- package/lib/card-content-policy.ts +85 -0
- package/lib/card-style-policy.ts +60 -0
- package/lib/child-context-files.ts +166 -0
- package/lib/child-package-injection.ts +62 -0
- package/lib/codemode-renderer.ts +195 -0
- package/lib/command-palette-catalog.ts +5 -10
- package/lib/command-palette.ts +25 -14
- package/lib/context-threshold.ts +26 -0
- package/lib/destructive-command-guard.ts +144 -0
- package/lib/gentle-ai-binary.ts +109 -4
- package/lib/gentle-ai-elapsed-store.ts +87 -0
- package/lib/gentle-ai-renderer.ts +196 -39
- package/lib/gentle-shell-bundled.ts +517 -0
- package/lib/gentle-shell-launcher.ts +89 -27
- package/lib/gentle-shell-resume-hint.ts +176 -0
- 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/history-capture-policy.ts +95 -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 +5 -1
- package/lib/nan-provider.ts +249 -0
- package/lib/native-review-cli.ts +242 -180
- 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-inference.ts +231 -0
- package/lib/odd-phase.ts +141 -0
- 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/overlay-repaint.ts +26 -0
- package/lib/permission-mode-policy.ts +59 -0
- package/lib/pi-tui-keys.ts +53 -0
- package/lib/review-candidate-view-owner.ts +73 -21
- package/lib/review-candidate-view.ts +115 -27
- 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-reminder-receipt.ts +48 -8
- package/lib/review-risk-assessment.ts +227 -56
- package/lib/review-sidebar-state.ts +224 -0
- 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 +527 -0
- package/lib/session-change-capture.ts +5 -4
- package/lib/session-changes.ts +27 -22
- package/lib/session-messaging-grants.ts +135 -0
- package/lib/session-profile-binding.ts +83 -0
- package/lib/session-profile-freeze.ts +266 -0
- package/lib/session-worktree-registry.ts +87 -9
- package/lib/shell-bar.ts +215 -30
- package/lib/shell-card.ts +287 -18
- package/lib/shell-changes-view.ts +42 -14
- package/lib/shell-changes.ts +86 -71
- package/lib/shell-prompt.ts +102 -6
- package/lib/shell-sidebar-layout.ts +83 -15
- package/lib/shell-sidebar.ts +15 -1
- package/lib/shell-todo.ts +84 -31
- package/lib/shell-usage-view.ts +9 -4
- package/lib/shell-usage.ts +70 -13
- package/lib/stats-collector.ts +381 -0
- package/lib/stats-view.ts +431 -0
- package/lib/status-timing-diagnostics.ts +201 -0
- package/lib/telemetry-trigger.ts +3 -1
- package/lib/theme-customization.ts +52 -0
- package/lib/vim-editor-adapter.ts +383 -0
- package/lib/vim-normal-engine.ts +154 -0
- package/lib/vim-operator-engine.ts +416 -0
- package/lib/vim-policy.ts +49 -0
- package/lib/vim-visual-engine.ts +107 -0
- package/lib/visual-customization-policy.ts +119 -0
- package/lib/visual-customize-view.ts +481 -0
- package/lib/visual-profiles.ts +228 -0
- package/lib/writer-surfaces.ts +162 -0
- package/lib/yolo-session-policy.ts +317 -0
- package/package.json +20 -8
- package/runtime/child-package-injection.mjs +63 -0
- package/runtime/gentle-ai-binary.mjs +109 -4
- package/runtime/gentle-shell-bundled.mjs +518 -0
- package/runtime/gentle-shell-launcher.mjs +87 -25
- package/runtime/gentle-shell-resume-hint.mjs +177 -0
- 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 +239 -177
- package/runtime/review-integration-v2.mjs +100 -22
- package/runtime/review-risk-assessment.mjs +225 -54
- 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 +8 -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 +83 -35
- 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/mirror-odd-routing.mjs +2 -2
- package/scripts/npm-pack-result.mjs +31 -0
- package/scripts/render-cache-performance-worker.mjs +205 -0
- package/scripts/render-cache-performance.mjs +115 -0
- package/scripts/run-test-suite.mjs +90 -0
- package/scripts/test-installer-acceptance.sh +161 -0
- package/scripts/test-packed-runner.mjs +54 -19
- package/scripts/types-baseline.json +2 -92
- package/scripts/verify-package-files.mjs +91 -38
- package/skills/branch-pr/SKILL.md +24 -52
- package/skills/chained-pr/SKILL.md +31 -15
- package/skills/chained-pr/references/chaining-details.md +31 -20
- package/skills/gentle-ai/SKILL.md +16 -21
- package/skills/issue-creation/SKILL.md +8 -2
- package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
- package/skills/work-unit-commits/SKILL.md +4 -3
- package/tests/agent-home.test.ts +56 -3
- package/tests/agent-model-resolution.test.ts +113 -0
- package/tests/agent-profiles.test.ts +30 -0
- package/tests/agent-risk-escalation.test.ts +123 -0
- package/tests/agents-completion-delivery.test.ts +17 -0
- package/tests/agents-fake-child.ts +2 -2
- package/tests/agents-message-delivery.test.ts +106 -0
- package/tests/agents-protocol.test.ts +97 -0
- package/tests/agents-queries.test.ts +9 -9
- package/tests/agents-runner-process.test.ts +31 -0
- package/tests/agents-runner.test.ts +467 -93
- package/tests/agents-view-thread-identity.test.ts +169 -0
- package/tests/agents-view.test.ts +8 -2
- package/tests/agents-widget.test.ts +154 -15
- package/tests/append-system-prompt-route.test.ts +160 -0
- package/tests/append-system-prompt.test.ts +46 -0
- package/tests/artifact-language.test.ts +19 -213
- package/tests/ask-user-question.test.ts +44 -1
- package/tests/asset-installation-runtime.test.ts +5 -16
- package/tests/auto-mode-invariants.test.ts +258 -0
- package/tests/auto-mode-sdk.test.ts +57 -0
- package/tests/auto-mode.test.ts +49 -0
- package/tests/auto-permission-classifier.test.ts +283 -0
- package/tests/auto-permission-runtime.test.ts +196 -0
- package/tests/autonomous-guard.test.ts +69 -1
- 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 +146 -0
- package/tests/branch-pr-skill.test.ts +43 -0
- 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 +87 -0
- package/tests/chained-pr-skill.test.ts +124 -0
- package/tests/child-codegraph-bootstrap.test.ts +74 -0
- package/tests/child-context-files.test.ts +255 -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 +94 -0
- package/tests/child-web-package.test.ts +224 -0
- package/tests/codegraph-tools.test.ts +35 -0
- package/tests/codemode-rendering.test.ts +596 -0
- package/tests/command-palette.test.ts +43 -7
- 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 -78
- package/tests/destructive-command-guard.test.ts +84 -0
- package/tests/devbinary/native-review-parity.devtest.ts +171 -3
- package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
- package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
- package/tests/engram-safety.test.ts +288 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
- package/tests/generic-agent-tools.test.ts +69 -0
- package/tests/gentle-agents.test.ts +2804 -346
- package/tests/gentle-ai-binary-isolation.test.ts +135 -0
- package/tests/gentle-ai-binary.test.ts +21 -4
- 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-elapsed-store.test.ts +68 -0
- package/tests/gentle-ai-installer.test.ts +566 -62
- package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
- package/tests/gentle-ai-renderer.test.ts +493 -14
- package/tests/gentle-ai.test.ts +1427 -236
- package/tests/gentle-card-text.ts +2 -1
- package/tests/gentle-herdr-activity.test.ts +100 -0
- package/tests/gentle-notifications.test.ts +427 -0
- package/tests/gentle-shell-bin.test.ts +896 -115
- package/tests/gentle-shell-bundled.test.ts +1002 -0
- package/tests/gentle-shell-launcher.test.ts +333 -65
- package/tests/gentle-shell-resume-hint.test.ts +270 -0
- 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 +4216 -119
- package/tests/gentle-stats.test.ts +152 -0
- package/tests/gentle-theme.test.ts +4 -1
- package/tests/gentle-todo.test.ts +333 -10
- package/tests/herdr-activity.test.ts +243 -0
- package/tests/history-agent-home.test.ts +81 -0
- package/tests/history-atomic-write.test.ts +57 -0
- package/tests/history-capture-policy.test.ts +102 -0
- package/tests/history-child-guard.test.ts +70 -0
- package/tests/history-command-registration.test.ts +164 -0
- package/tests/history-dedupe-entries.test.ts +123 -0
- package/tests/history-delete-backfill.test.ts +190 -0
- package/tests/history-delete-confirm.test.ts +460 -0
- package/tests/history-dispatch.test.ts +180 -0
- package/tests/history-drain-hidden.test.ts +110 -0
- package/tests/history-drain-order.test.ts +98 -0
- package/tests/history-expanded-globals.test.ts +62 -0
- package/tests/history-gc.test.ts +832 -0
- package/tests/history-header-layout.test.ts +265 -0
- package/tests/history-hide-prompts.test.ts +275 -0
- package/tests/history-lazy-windowing.test.ts +508 -0
- package/tests/history-legacy-migrate-v2.test.ts +297 -0
- package/tests/history-load-shared-history.test.ts +53 -0
- package/tests/history-max-results-cap.test.ts +76 -0
- package/tests/history-multi-reader.test.ts +203 -0
- package/tests/history-off-path.test.ts +170 -0
- package/tests/history-openflow-integration.test.ts +173 -0
- package/tests/history-overlay-margin.test.ts +326 -0
- package/tests/history-preview-layout.test.ts +93 -0
- package/tests/history-registry.test.ts +143 -0
- package/tests/history-scope-delete.test.ts +411 -0
- package/tests/history-search-caret-keys.test.ts +142 -0
- package/tests/history-seed-bootstrap.test.ts +170 -0
- package/tests/history-seed-regen.test.ts +129 -0
- package/tests/history-selector-windowing.test.ts +94 -0
- package/tests/history-session-scan-directory.test.ts +87 -0
- package/tests/history-session-scan-extract.test.ts +583 -0
- package/tests/history-session-writer.test.ts +351 -0
- package/tests/history-store-paths.test.ts +79 -0
- package/tests/history-tombstone-exact.test.ts +139 -0
- package/tests/history-wheel-mouse.test.ts +242 -0
- package/tests/inprocess-reviewer.test.ts +49 -19
- 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 +2158 -0
- package/tests/installer-server.test.ts +1567 -0
- package/tests/installer-windows-bootstrap.test.ts +2410 -0
- package/tests/issue-creation-skill.test.ts +61 -0
- package/tests/jobs-view.test.ts +160 -0
- package/tests/main-channel-upgrade.test.ts +389 -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-authority.test.ts +16 -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 +481 -0
- package/tests/native-binary-gate.test.ts +2 -0
- package/tests/native-review-capability-contract.test.ts +13 -1
- package/tests/native-review-cli.test.ts +239 -118
- package/tests/native-review-consent.test.ts +2 -2
- package/tests/native-review-parity-runtime.test.ts +101 -4
- 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 +76 -0
- package/tests/odd-phase-inference.test.ts +213 -0
- package/tests/odd-phase-loader.test.ts +253 -0
- package/tests/odd-phase.test.ts +307 -0
- package/tests/odd-routing-canonical-ratchet.test.ts +60 -14
- package/tests/odd-routing-contract.test.ts +158 -50
- package/tests/orchestrator-budget.test.ts +43 -45
- 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 +8 -7
- 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/overlay-repaint.test.ts +74 -0
- package/tests/package-manifest.test.ts +344 -123
- package/tests/packed-runner-owned-path.test.ts +80 -0
- 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 +10 -18
- package/tests/pi-pretty.test.ts +56 -0
- package/tests/provider-defect-handoff.test.ts +7 -14
- package/tests/quiet-bash-runtime.test.ts +76 -0
- package/tests/quiet-tool-rendering.test.ts +569 -187
- package/tests/rdd-aware-verification-contract.test.ts +103 -40
- package/tests/rdd-status-line.test.ts +9 -4
- package/tests/render-cache-performance.test.ts +48 -0
- package/tests/resume-hint-extension.test.ts +122 -0
- package/tests/review-agent-end-preflight.test.ts +237 -21
- package/tests/review-candidate-owner-retry.test.ts +22 -1
- package/tests/review-candidate-view.test.ts +399 -12
- package/tests/review-contract-prompt.test.ts +138 -44
- package/tests/review-controller-lock-status.test.ts +0 -1
- package/tests/review-controller-native-recovery.test.ts +327 -17
- package/tests/review-controller-native-routing.test.ts +866 -6
- package/tests/review-controller-workspace-root.test.ts +206 -6
- 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 +342 -4
- package/tests/review-host-relay.test.ts +49 -2
- package/tests/review-integration-v2-forward.test.ts +221 -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 +14 -37
- 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-reminder-receipt.test.ts +47 -1
- package/tests/review-risk-assessment.test.ts +594 -26
- 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-sidebar-state.test.ts +402 -0
- package/tests/review-test-fixtures.ts +7 -1
- package/tests/review-transaction.test.ts +18 -1
- package/tests/run-test-suite.test.ts +202 -0
- package/tests/runtime-harness.mjs +186 -800
- package/tests/runtime-metrics-children.test.ts +16 -23
- package/tests/runtime-metrics-extension.test.ts +1 -1
- package/tests/runtime-metrics-native.test.ts +31 -1
- package/tests/selection-engine.test.ts +451 -0
- 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-messaging-grants.test.ts +255 -0
- package/tests/session-profile-binding.test.ts +163 -0
- package/tests/session-profile-freeze.test.ts +381 -0
- package/tests/session-subject-routing-contract.test.ts +34 -0
- package/tests/session-worktree-registry.test.ts +134 -2
- package/tests/shell-bar.test.ts +422 -1
- package/tests/shell-card.test.ts +353 -1
- package/tests/shell-changes-view.test.ts +135 -32
- package/tests/shell-changes.test.ts +61 -62
- package/tests/shell-prompt.test.ts +94 -2
- 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 +351 -22
- package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
- package/tests/shell-todo.test.ts +207 -3
- package/tests/shell-usage-view.test.ts +28 -1
- package/tests/shell-usage.test.ts +108 -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 +357 -2
- package/tests/startup-banner.test.ts +246 -4
- package/tests/startup-home-repo.test.ts +170 -0
- package/tests/stats-collector.test.ts +195 -0
- package/tests/stats-view.test.ts +202 -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 +107 -20
- package/tests/test-strength-contract.test.ts +124 -0
- package/tests/theme-customization.test.ts +72 -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-host-resolution.test.ts +37 -0
- package/tests/vim-editor-adapter.test.ts +804 -0
- package/tests/vim-normal-engine.test.ts +101 -0
- package/tests/vim-operator-engine.test.ts +215 -0
- package/tests/vim-policy.test.ts +19 -0
- package/tests/vim-visual-engine.test.ts +52 -0
- package/tests/visual-customization-policy.test.ts +139 -0
- package/tests/visual-customize-view.test.ts +696 -0
- package/tests/visual-profiles.test.ts +87 -0
- package/tests/writer-edit-surface-scope.test.ts +59 -2
- package/tests/writer-surfaces.test.ts +199 -0
- package/tests/yolo-customize.test.ts +271 -0
- package/tests/yolo-mode-runtime.test.ts +188 -0
- package/tests/yolo-mode.test.ts +289 -0
- package/tests/yolo-session-policy.test.ts +59 -0
- package/themes/Gentle.json +2 -1
- package/themes/Gentleman-Cute.json +2 -1
- package/themes/Gentleman-Sexy.json +2 -1
- package/assets/agents/sdd-apply.md +0 -159
- package/assets/agents/sdd-archive.md +0 -228
- package/assets/agents/sdd-design.md +0 -49
- package/assets/agents/sdd-explore.md +0 -48
- package/assets/agents/sdd-init.md +0 -56
- package/assets/agents/sdd-onboard.md +0 -52
- package/assets/agents/sdd-proposal.md +0 -64
- package/assets/agents/sdd-remediate.md +0 -37
- package/assets/agents/sdd-research.md +0 -49
- package/assets/agents/sdd-spec.md +0 -192
- package/assets/agents/sdd-status.md +0 -54
- package/assets/agents/sdd-tasks.md +0 -108
- package/assets/agents/sdd-verify.md +0 -124
- package/assets/chains/sdd-full.chain.md +0 -83
- package/assets/chains/sdd-plan.chain.md +0 -56
- package/assets/chains/sdd-verify.chain.md +0 -43
- package/assets/sdd-orchestrator-workflow.md +0 -319
- package/assets/support/sdd-status-contract.md +0 -77
- package/docs/assets/diagrams/sdd-cycle.svg +0 -14
- package/extensions/sdd-init.ts +0 -816
- package/lib/openspec-deltas.ts +0 -156
- package/lib/sdd-preflight.ts +0 -1066
- package/lib/sdd-research-capabilities.ts +0 -94
- package/lib/sdd-status.ts +0 -26
- package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
- package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
- package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
- package/tests/openspec-deltas.test.ts +0 -209
- package/tests/sdd-agent-tools.test.ts +0 -156
- package/tests/sdd-archive-replay.test.ts +0 -82
- package/tests/sdd-classical-continuation.test.ts +0 -74
- package/tests/sdd-execution-routing-contract.test.ts +0 -44
- package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
- package/tests/sdd-native-managed-uptake.test.ts +0 -243
- package/tests/sdd-no-attempts-contract.test.ts +0 -15
- package/tests/sdd-odd-integration.test.ts +0 -33
- package/tests/sdd-optional-research.test.ts +0 -124
- package/tests/sdd-planning-routing-contract.test.ts +0 -45
- package/tests/sdd-preflight-rpc-input.test.ts +0 -125
- package/tests/sdd-preflight.test.ts +0 -541
- package/tests/sdd-research-capabilities.test.ts +0 -114
- package/tests/sdd-research-live.test.ts +0 -241
- package/tests/sdd-selection-transport.test.ts +0 -653
- package/tests/sdd-status.test.ts +0 -9
- package/tests/sdd-task-truth.test.ts +0 -43
- /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,4 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { parseNpmPackResult } from "../scripts/npm-pack-result.mjs";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
2
4
|
import { createHash } from "node:crypto";
|
|
3
5
|
import {
|
|
4
6
|
existsSync,
|
|
@@ -16,7 +18,10 @@ import ts from "typescript";
|
|
|
16
18
|
import { fileURLToPath } from "node:url";
|
|
17
19
|
import { applyModelConfig } from "../extensions/gentle-ai.ts";
|
|
18
20
|
import { resolveGentlePiAgentHome } from "../lib/agent-home.ts";
|
|
19
|
-
import { getPackageAssetOwner, installPackageAssets,
|
|
21
|
+
import { getPackageAssetOwner, installPackageAssets, type PackageAssetOwner } from "../lib/agent-assets.ts";
|
|
22
|
+
import { AUDITED_PI_EDITOR_VERSIONS } from "../lib/vim-editor-adapter.ts";
|
|
23
|
+
import { resolveProjectPiSdkVersion } from "../scripts/test-packed-runner.mjs";
|
|
24
|
+
// Package installation is owned by lib/agent-assets.ts, not the retired SDD preflight.
|
|
20
25
|
|
|
21
26
|
const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
22
27
|
const MANAGED_EXEMPLAR_FILE = "gentle-ai-explore.md";
|
|
@@ -56,7 +61,7 @@ const V014_MANAGED_ASSETS = join(
|
|
|
56
61
|
// gentle-ai-explore.md as their exemplar (packaged, absent from the v0.13
|
|
57
62
|
// manifest) after review-refuter.md was retired together with every
|
|
58
63
|
// Pi-authored adversarial review verdict.
|
|
59
|
-
const MANAGED_EXEMPLAR_TOOLS = ["read", "grep", "find", "codegraph"];
|
|
64
|
+
const MANAGED_EXEMPLAR_TOOLS = ["read", "grep", "find", "codegraph", "web_enable", "web_search", "source_check", "fetch_content", "get_search_content"];
|
|
60
65
|
const RETIRED_ADVERSARIAL_AGENTS = ["review-refuter.md", "review-validator.md"];
|
|
61
66
|
|
|
62
67
|
interface ManagedAssetsManifest {
|
|
@@ -76,13 +81,22 @@ interface PackageJsonPiManifest {
|
|
|
76
81
|
extensions?: string[];
|
|
77
82
|
}
|
|
78
83
|
|
|
84
|
+
interface PackageJsonPeerMetadata {
|
|
85
|
+
optional?: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
interface PackageJson {
|
|
89
|
+
description?: string;
|
|
90
|
+
keywords?: string[];
|
|
80
91
|
version?: string;
|
|
81
92
|
files?: string[];
|
|
82
93
|
scripts?: Record<string, string>;
|
|
83
94
|
dependencies?: Record<string, string>;
|
|
84
95
|
peerDependencies?: Record<string, string>;
|
|
96
|
+
peerDependenciesMeta?: Record<string, PackageJsonPeerMetadata>;
|
|
97
|
+
optionalDependencies?: Record<string, string>;
|
|
85
98
|
devDependencies?: Record<string, string>;
|
|
99
|
+
engines?: Record<string, string>;
|
|
86
100
|
bundledDependencies?: string[];
|
|
87
101
|
bundleDependencies?: string[];
|
|
88
102
|
repository?: {
|
|
@@ -102,16 +116,106 @@ function readPackageJson(): PackageJson {
|
|
|
102
116
|
}
|
|
103
117
|
}
|
|
104
118
|
|
|
119
|
+
test("public docs and metadata advertise ODD and review without retired phase workflow", () => {
|
|
120
|
+
const manifest = readPackageJson();
|
|
121
|
+
assert.match(manifest.description ?? "", /ODD|Organic Driven Development/);
|
|
122
|
+
assert.match(manifest.description ?? "", /review/i);
|
|
123
|
+
assert.ok(manifest.keywords?.includes("odd"));
|
|
124
|
+
assert.ok(manifest.keywords?.includes("code-review"));
|
|
125
|
+
assert.ok(manifest.keywords?.every(keyword => !/sdd|openspec/i.test(keyword)));
|
|
126
|
+
for (const path of ["README.md", "docs/gentle-shell.md", "docs/readme-reference.md"]) {
|
|
127
|
+
const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
|
|
128
|
+
assert.match(source, /ODD|Organic Driven Development/, path);
|
|
129
|
+
assert.match(source, /review/i, path);
|
|
130
|
+
assert.doesNotMatch(source, /\bSDD\b|OpenSpec|\/gentle-sdd-init|\/gentle:install-sdd|\/gentle:sdd-preflight|\/sdd-/i, path);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
105
134
|
test("technical reference declares the tested Pi minimum required for agent_settled", () => {
|
|
106
135
|
const manifest = readPackageJson();
|
|
107
|
-
assert.equal(manifest.peerDependencies?.["@earendil-works/pi-coding-agent"], ">=0.
|
|
108
|
-
assert.equal(manifest.devDependencies?.["@earendil-works/pi-coding-agent"], "0.
|
|
136
|
+
assert.equal(manifest.peerDependencies?.["@earendil-works/pi-coding-agent"], ">=0.99.1");
|
|
137
|
+
assert.equal(manifest.devDependencies?.["@earendil-works/pi-coding-agent"], ">=1.0.0");
|
|
138
|
+
assert.equal(manifest.peerDependenciesMeta?.["@earendil-works/pi-coding-agent"]?.optional, true);
|
|
139
|
+
assert.equal(manifest.engines?.node, ">=22.19.0");
|
|
140
|
+
for (const path of ["docs/readme-reference.md", "docs/gentle-shell.md"]) {
|
|
141
|
+
const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
|
|
142
|
+
assert.match(source, /Pi 0\.99\.1 or newer/, path);
|
|
143
|
+
assert.match(source, /open `>=1\.0\.0` development range/, path);
|
|
144
|
+
assert.doesNotMatch(source, /development tests pin Pi/, path);
|
|
145
|
+
// Docs name exactly the audited Vim editor releases, never a future one.
|
|
146
|
+
const auditedReleases = new Intl.ListFormat("en", { style: "long", type: "conjunction" })
|
|
147
|
+
.format(AUDITED_PI_EDITOR_VERSIONS.map(v => `\`${v.replace(/\./g, "\\.")}\``));
|
|
148
|
+
assert.match(source, new RegExp(`audited Pi ${auditedReleases}`), path);
|
|
149
|
+
}
|
|
109
150
|
const reference = readFileSync(join(PACKAGE_ROOT, "docs", "readme-reference.md"), "utf8");
|
|
110
|
-
assert.match(reference, /Pi 0\.85\.1 or newer/);
|
|
111
151
|
assert.match(reference, /agent_settled/);
|
|
112
152
|
assert.match(readFileSync(join(PACKAGE_ROOT, "README.md"), "utf8"), /\]\(docs\/readme-reference\.md(?:#[^)]+)?\)/);
|
|
113
153
|
});
|
|
114
154
|
|
|
155
|
+
test("packed runtime uses optional Pi host peers with one open development range and no duplicate direct dependencies", () => {
|
|
156
|
+
const manifest = readPackageJson();
|
|
157
|
+
for (const name of ["@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
|
|
158
|
+
assert.equal(manifest.peerDependencies?.[name], "*", name);
|
|
159
|
+
assert.equal(manifest.peerDependenciesMeta?.[name]?.optional, true, name);
|
|
160
|
+
}
|
|
161
|
+
// The devDependency specifier is policy (a range); the resolved install is
|
|
162
|
+
// one exact release shared by every Pi host package.
|
|
163
|
+
const installed = new Set<string>();
|
|
164
|
+
for (const name of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
|
|
165
|
+
assert.equal(manifest.devDependencies?.[name], ">=1.0.0", name);
|
|
166
|
+
const metadata = JSON.parse(readFileSync(join(PACKAGE_ROOT, "node_modules", name, "package.json"), "utf8")) as { name: string; version: string };
|
|
167
|
+
assert.equal(metadata.name, name);
|
|
168
|
+
installed.add(metadata.version);
|
|
169
|
+
}
|
|
170
|
+
assert.deepEqual([...installed], [resolveProjectPiSdkVersion(PACKAGE_ROOT)]);
|
|
171
|
+
for (const name of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
|
|
172
|
+
assert.equal(manifest.dependencies?.[name], undefined, name);
|
|
173
|
+
assert.equal(manifest.optionalDependencies?.[name], undefined, name);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Fixture project roots let the resolver's range policy be tested without
|
|
178
|
+
// touching the real install.
|
|
179
|
+
function withPiSdkProject(range: unknown, installed: unknown, run: (root: string) => void): void {
|
|
180
|
+
const root = mkdtempSync(join(tmpdir(), "gentle-pi-sdk-version-"));
|
|
181
|
+
try {
|
|
182
|
+
const sdk = join(root, "node_modules", "@earendil-works", "pi-coding-agent");
|
|
183
|
+
mkdirSync(sdk, { recursive: true });
|
|
184
|
+
writeFileSync(join(root, "package.json"), JSON.stringify({ devDependencies: { "@earendil-works/pi-coding-agent": range } }));
|
|
185
|
+
writeFileSync(join(sdk, "package.json"), JSON.stringify(installed));
|
|
186
|
+
run(root);
|
|
187
|
+
} finally {
|
|
188
|
+
rmSync(root, { recursive: true, force: true });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
test("packed probes install the project-resolved Pi SDK release, never the devDependency specifier", () => {
|
|
193
|
+
const sdk = (version: unknown) => ({ name: "@earendil-works/pi-coding-agent", version });
|
|
194
|
+
for (const [range, version] of [[">=0.99.2", "0.99.2"], [">=0.99.2", "0.99.10"], [">=0.99.2", "1.0.0"], ["0.99.2", "0.99.2"]]) {
|
|
195
|
+
withPiSdkProject(range, sdk(version), (root) => assert.equal(resolveProjectPiSdkVersion(root), version, `${range} ${version}`));
|
|
196
|
+
}
|
|
197
|
+
for (const [range, installed, error] of [
|
|
198
|
+
[">=0.99.2", sdk("0.99.1"), /0\.99\.1 does not satisfy >=0\.99\.2/],
|
|
199
|
+
["0.99.1", sdk("0.99.2"), /0\.99\.2 does not satisfy 0\.99\.1/],
|
|
200
|
+
["*", sdk("0.99.2"), /exact or >= Pi SDK development range/],
|
|
201
|
+
["^0.99.2", sdk("0.99.2"), /exact or >= Pi SDK development range/],
|
|
202
|
+
[undefined, sdk("0.99.2"), /exact or >= Pi SDK development range/],
|
|
203
|
+
[">=0.99.2", sdk(">=0.99.2"), /exact release version/],
|
|
204
|
+
[">=0.99.2", sdk("0.99.3-rc.1"), /exact release version/],
|
|
205
|
+
[">=0.99.2", { name: "impostor", version: "0.99.2" }, /exact release version/],
|
|
206
|
+
] as const) {
|
|
207
|
+
withPiSdkProject(range, installed, (root) => assert.throws(() => resolveProjectPiSdkVersion(root), error, String(range)));
|
|
208
|
+
}
|
|
209
|
+
const installed = JSON.parse(readFileSync(join(PACKAGE_ROOT, "node_modules", "@earendil-works", "pi-coding-agent", "package.json"), "utf8")) as { version: string };
|
|
210
|
+
assert.equal(resolveProjectPiSdkVersion(PACKAGE_ROOT), installed.version);
|
|
211
|
+
const packedRunner = readFileSync(join(PACKAGE_ROOT, "scripts", "test-packed-runner.mjs"), "utf8");
|
|
212
|
+
for (const name of ["testSdkLifecyclePackedSession", "testWindowsStartupTimingPackedHelper", "testWindowsStartupTimingEnvironmentExperiment", "testUnhookedPackedImports"]) {
|
|
213
|
+
const probe = readNamedFunction(packedRunner, name);
|
|
214
|
+
assert.match(probe, /const sdkVersion = resolveProjectPiSdkVersion\(root, "[^"]+"\);/, name);
|
|
215
|
+
assert.doesNotMatch(probe, /devDependencies/, name);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
115
219
|
test("package manifest has no obsolete native activation build surface", () => {
|
|
116
220
|
const packageJson = readPackageJson();
|
|
117
221
|
const manifest = JSON.stringify(packageJson);
|
|
@@ -123,6 +227,16 @@ test("package manifest has no obsolete native activation build surface", () => {
|
|
|
123
227
|
assert.doesNotMatch(packageJson.scripts?.prepublishOnly ?? "", /native:build/);
|
|
124
228
|
});
|
|
125
229
|
|
|
230
|
+
test("package verification excludes the retired init extension while retaining ODD and review resources", () => {
|
|
231
|
+
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
232
|
+
assert.equal(existsSync(join(PACKAGE_ROOT, "extensions", "sdd-init.ts")), false);
|
|
233
|
+
assert.doesNotMatch(verifier, /^\s*"extensions\/sdd-init\.ts",?$/m);
|
|
234
|
+
assert.match(verifier, /existsSync\(join\(root, "extensions\/sdd-init\.ts"\)\)/);
|
|
235
|
+
for (const resource of ["extensions/gentle-ai.ts", "extensions/skill-registry.ts", "assets/orchestrator.md", "assets/orchestrator-delegation.md", "assets/agents/gentle-ai-worker.md", "assets/agents/review-risk.md", "assets/chains/4r-review.chain.md"]) {
|
|
236
|
+
assert.ok(verifier.includes(`"${resource}"`), `${resource} must remain required`);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
126
240
|
test("package verification names the native review runtime boundary and packaged fixtures", () => {
|
|
127
241
|
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
128
242
|
const manifest = readPackageJson();
|
|
@@ -140,6 +254,25 @@ test("package verification names the native review runtime boundary and packaged
|
|
|
140
254
|
);
|
|
141
255
|
});
|
|
142
256
|
|
|
257
|
+
test("double-click installers are attached to the release only after the verified publication", () => {
|
|
258
|
+
const workflow = readFileSync(join(PACKAGE_ROOT, ".github", "workflows", "publish.yml"), "utf8");
|
|
259
|
+
const job = workflow.match(/^ {2}installers:\n([\s\S]*?)(?=^ {2}[A-Za-z0-9_-]+:\n|(?![\s\S]))/m)?.[1];
|
|
260
|
+
assert.ok(job, "publish.yml has an installers job");
|
|
261
|
+
assert.match(job, /^ {4}needs: publish$/m, "installers wait for the verified npm publication");
|
|
262
|
+
assert.match(job, /^ {4}if: github\.repository == 'Gentleman-Programming\/gentle-shell'$/m);
|
|
263
|
+
assert.match(job, /^ {6}contents: write$/m, "only this job may write the release");
|
|
264
|
+
assert.match(job, /ref: \$\{\{ github\.sha \}\}/, "the installers come from the verified release commit");
|
|
265
|
+
assert.match(job, /persist-credentials: false/);
|
|
266
|
+
assert.match(job, /node scripts\/build-installer-bundles\.mjs --out "\$\{RUNNER_TEMP\}\/installers"/);
|
|
267
|
+
assert.match(job, /RELEASE_TAG: \$\{\{ needs\.publish\.outputs\.tag \}\}/, "the tag the publish job verified, not the raw input");
|
|
268
|
+
assert.match(job, /package-manager-cache: false/);
|
|
269
|
+
assert.match(workflow, /^ {4}outputs:\n {6}tag: \$\{\{ steps\.release\.outputs\.tag \}\}$/m, "publish exports its verified tag");
|
|
270
|
+
assert.match(job, /gh release upload "\$\{RELEASE_TAG\}" "\$\{RUNNER_TEMP\}"\/installers\/\* --repo "\$\{GITHUB_REPOSITORY\}" --clobber/);
|
|
271
|
+
const publish = workflow.match(/^ {2}publish:\n([\s\S]*?)(?=^ {2}installers:\n)/m)?.[1];
|
|
272
|
+
assert.ok(publish);
|
|
273
|
+
assert.doesNotMatch(publish, /contents: write/, "the npm publication job keeps read-only contents");
|
|
274
|
+
});
|
|
275
|
+
|
|
143
276
|
test("npm publication is bound to the exact package tag and triggering commit", () => {
|
|
144
277
|
const workflow = readFileSync(join(PACKAGE_ROOT, ".github", "workflows", "publish.yml"), "utf8");
|
|
145
278
|
const packageJson = readPackageJson();
|
|
@@ -298,20 +431,20 @@ test("package manifest installs pi-pretty through a wrapper without bundling nat
|
|
|
298
431
|
);
|
|
299
432
|
});
|
|
300
433
|
|
|
301
|
-
test("package verification binds the published Gentle AI
|
|
434
|
+
test("package verification binds the published Gentle AI v4.1.1 runtime pin", () => {
|
|
302
435
|
const installer = readFileSync(join(PACKAGE_ROOT, "scripts", "gentle-ai-installer.mjs"), "utf8");
|
|
303
436
|
const binary = readFileSync(join(PACKAGE_ROOT, "lib", "gentle-ai-binary.ts"), "utf8");
|
|
304
437
|
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
305
438
|
|
|
306
|
-
assert.match(installer, /INSTALLER_VERSION = "
|
|
439
|
+
assert.match(installer, /INSTALLER_VERSION = "4\.1\.1"/);
|
|
307
440
|
assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_PACKAGE.*GENTLE_AI_WINDOWS_SOURCE_MODULE/);
|
|
308
|
-
assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1
|
|
441
|
+
assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:\+WmZ2IvIOiJ8qtHa7wsjnYKNasem\+PByeOZ6HIjoAL8="/);
|
|
309
442
|
assert.match(installer, /GOTOOLCHAIN: "local"/);
|
|
310
443
|
assert.match(installer, /GOSUMDB: "sum\.golang\.org"/);
|
|
311
444
|
assert.match(binary, /GENTLE_AI_VERSION = INSTALLER_VERSION/);
|
|
312
445
|
assert.match(binary, /GO_SUMDB_SOURCE_BUILD/);
|
|
313
446
|
assert.match(binary, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM/);
|
|
314
|
-
assert.match(verifier, /
|
|
447
|
+
assert.match(verifier, /v4\.1\.1/);
|
|
315
448
|
});
|
|
316
449
|
|
|
317
450
|
|
|
@@ -437,7 +570,7 @@ function readMarkdownSection(source: string, heading: string): string {
|
|
|
437
570
|
|
|
438
571
|
function assertWorkerFallbackRouting(section: string, sectionName: string): void {
|
|
439
572
|
const boundedWriterPolicy = section.match(
|
|
440
|
-
/For bounded
|
|
573
|
+
/For a large task's bounded writes,[\s\S]*?(?=\n\n|\n\s*\d+\.|$)/,
|
|
441
574
|
)?.[0];
|
|
442
575
|
assert.ok(boundedWriterPolicy, `${sectionName} must define bounded writer routing`);
|
|
443
576
|
|
|
@@ -551,6 +684,36 @@ function installedAssetManifest(agentHome: string): ManagedAssetsManifest {
|
|
|
551
684
|
return JSON.parse(readFileSync(join(agentHome, "gentle-ai", "managed-assets.json"), "utf8"));
|
|
552
685
|
}
|
|
553
686
|
|
|
687
|
+
test("ODD delegation assets retain applicable test-first checks and independent review boundaries without SDD routing", () => {
|
|
688
|
+
const support = readFileSync(join(PACKAGE_ROOT, "assets/support/strict-tdd.md"), "utf8");
|
|
689
|
+
const explorer = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-explore.md"), "utf8");
|
|
690
|
+
const verifier = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-verify.md"), "utf8");
|
|
691
|
+
const worker = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-worker.md"), "utf8");
|
|
692
|
+
for (const source of [support, explorer, verifier, worker]) {
|
|
693
|
+
assert.doesNotMatch(source, /openspec\/config\.yaml|sdd-init|SDD phase protocols|generic non-SDD|sdd-verify|sdd\/\{project\}/i);
|
|
694
|
+
}
|
|
695
|
+
assert.match(support, /RED[\s\S]*GREEN[\s\S]*REFACTOR/);
|
|
696
|
+
assert.match(support, /behavior changes with applicable runnable deterministic tests and a clear expected outcome/i);
|
|
697
|
+
assert.match(support, /A test file merely existing is not proof of applicability or RED/i);
|
|
698
|
+
assert.match(support, /no meaningful RED[\s\S]*proportionate ordinary functional or structural verification/i);
|
|
699
|
+
assert.match(support, /Use only exact commands authorized by the parent/i);
|
|
700
|
+
assert.match(explorer, /read-only explorer for generic ODD work/);
|
|
701
|
+
assert.match(verifier, /read-only technical verifier for generic ODD work/);
|
|
702
|
+
assert.match(worker, /allowed edit surfaces/i);
|
|
703
|
+
assert.match(worker, /work-unit commit/i);
|
|
704
|
+
assert.match(worker, /review lifecycle.*parent/i);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test("delegation installation retains strict TDD support without installing SDD assets", () => {
|
|
708
|
+
withIsolatedAssetHome((agentHome) => {
|
|
709
|
+
installPackageAssets(agentHome, false, ["delegation"]);
|
|
710
|
+
const keys = Object.keys(installedAssetManifest(agentHome).assets);
|
|
711
|
+
assert.ok(keys.includes("gentle-ai/support/strict-tdd.md"));
|
|
712
|
+
assert.ok(keys.includes("gentle-ai/support/strict-tdd-verify.md"));
|
|
713
|
+
assert.ok(keys.every(key => !key.startsWith("agents/sdd-") && !key.startsWith("chains/sdd-") && !key.includes("sdd-status-contract")));
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
|
|
554
717
|
test("selective delegation installation owns only generic agents", () => {
|
|
555
718
|
withIsolatedAssetHome((agentHome) => {
|
|
556
719
|
const result = installPackageAssets(agentHome, false, ["delegation"]);
|
|
@@ -558,19 +721,21 @@ test("selective delegation installation owns only generic agents", () => {
|
|
|
558
721
|
"agents/gentle-ai-explore.md",
|
|
559
722
|
"agents/gentle-ai-verify.md",
|
|
560
723
|
"agents/gentle-ai-worker.md",
|
|
724
|
+
"gentle-ai/support/strict-tdd-verify.md",
|
|
725
|
+
"gentle-ai/support/strict-tdd.md",
|
|
561
726
|
]);
|
|
562
|
-
assert.deepEqual(result, { agents: 3, chains: 0, support:
|
|
727
|
+
assert.deepEqual(result, { agents: 3, chains: 0, support: 2, skipped: 0 });
|
|
563
728
|
assert.deepEqual(readdirSync(join(agentHome, "agents")).sort(), [
|
|
564
729
|
"gentle-ai-explore.md", "gentle-ai-verify.md", "gentle-ai-worker.md",
|
|
565
730
|
]);
|
|
566
731
|
assert.equal(existsSync(join(agentHome, "chains")), false);
|
|
567
|
-
assert.
|
|
732
|
+
assert.deepEqual(readdirSync(join(agentHome, "gentle-ai", "support")).sort(), ["strict-tdd-verify.md", "strict-tdd.md"]);
|
|
568
733
|
});
|
|
569
734
|
});
|
|
570
735
|
|
|
571
736
|
test("selective installation retires only assets belonging to the selected owner", () => {
|
|
572
737
|
withIsolatedAssetHome((agentHome) => {
|
|
573
|
-
|
|
738
|
+
installPackageAssets(agentHome, false);
|
|
574
739
|
const manifestPath = join(agentHome, "gentle-ai", "managed-assets.json");
|
|
575
740
|
const manifest = installedAssetManifest(agentHome);
|
|
576
741
|
for (const name of RETIRED_ADVERSARIAL_AGENTS) {
|
|
@@ -578,7 +743,7 @@ test("selective installation retires only assets belonging to the selected owner
|
|
|
578
743
|
manifest.assets[`agents/${name}`] = sha256("Previously managed review agent\n");
|
|
579
744
|
}
|
|
580
745
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
581
|
-
for (const owner of ["delegation"
|
|
746
|
+
for (const owner of ["delegation"] as const) {
|
|
582
747
|
installPackageAssets(agentHome, true, [owner]);
|
|
583
748
|
assert.deepEqual(installedAssetManifest(agentHome), manifest);
|
|
584
749
|
for (const name of RETIRED_ADVERSARIAL_AGENTS) {
|
|
@@ -598,21 +763,13 @@ test("selective installation retires only assets belonging to the selected owner
|
|
|
598
763
|
const EXPECTED_OWNER_ASSETS: Record<PackageAssetOwner, readonly string[]> = {
|
|
599
764
|
delegation: [
|
|
600
765
|
"agents/gentle-ai-explore.md", "agents/gentle-ai-verify.md", "agents/gentle-ai-worker.md",
|
|
766
|
+
"gentle-ai/support/strict-tdd.md", "gentle-ai/support/strict-tdd-verify.md",
|
|
601
767
|
],
|
|
602
768
|
review: [
|
|
603
769
|
"agents/jd-fix-agent.md", "agents/jd-judge-a.md", "agents/jd-judge-b.md",
|
|
604
770
|
"agents/review-readability.md", "agents/review-reliability.md",
|
|
605
771
|
"agents/review-resilience.md", "agents/review-risk.md", "chains/4r-review.chain.md",
|
|
606
772
|
],
|
|
607
|
-
sdd: [
|
|
608
|
-
"agents/sdd-apply.md", "agents/sdd-archive.md", "agents/sdd-design.md",
|
|
609
|
-
"agents/sdd-explore.md", "agents/sdd-init.md", "agents/sdd-onboard.md",
|
|
610
|
-
"agents/sdd-proposal.md", "agents/sdd-remediate.md", "agents/sdd-research.md", "agents/sdd-spec.md",
|
|
611
|
-
"agents/sdd-status.md", "agents/sdd-tasks.md", "agents/sdd-verify.md",
|
|
612
|
-
"chains/sdd-full.chain.md", "chains/sdd-plan.chain.md", "chains/sdd-verify.chain.md",
|
|
613
|
-
"gentle-ai/support/sdd-status-contract.md", "gentle-ai/support/strict-tdd-verify.md",
|
|
614
|
-
"gentle-ai/support/strict-tdd.md",
|
|
615
|
-
],
|
|
616
773
|
};
|
|
617
774
|
|
|
618
775
|
function assetFileKeys(root: string, prefix = ""): string[] {
|
|
@@ -641,7 +798,7 @@ for (const owner of Object.keys(EXPECTED_OWNER_ASSETS) as PackageAssetOwner[]) {
|
|
|
641
798
|
});
|
|
642
799
|
}
|
|
643
800
|
|
|
644
|
-
test("
|
|
801
|
+
test("all-assets installation covers every retained packaged file with explicit ownership", () => {
|
|
645
802
|
const packaged = ["agents", "chains", "support"].flatMap(group =>
|
|
646
803
|
assetFileKeys(join(PACKAGE_ROOT, "assets", group), group === "support" ? "gentle-ai/support/" : `${group}/`),
|
|
647
804
|
).sort();
|
|
@@ -651,24 +808,24 @@ test("legacy all-assets installation covers every packaged file with explicit ow
|
|
|
651
808
|
assert.equal(getPackageAssetOwner(key), undefined, "unknown assets must not default to SDD");
|
|
652
809
|
}
|
|
653
810
|
withIsolatedAssetHome((agentHome) => {
|
|
654
|
-
assert.deepEqual(
|
|
811
|
+
assert.deepEqual(installPackageAssets(agentHome, false), { agents: 10, chains: 1, support: 2, skipped: 0 });
|
|
655
812
|
assert.deepEqual(Object.keys(installedAssetManifest(agentHome).assets).sort(), packaged);
|
|
656
|
-
assert.deepEqual(
|
|
657
|
-
assert.deepEqual(
|
|
813
|
+
assert.deepEqual(installPackageAssets(agentHome, false), { agents: 0, chains: 0, support: 0, skipped: 13 });
|
|
814
|
+
assert.deepEqual(installPackageAssets(agentHome, true), { agents: 10, chains: 1, support: 2, skipped: 0 });
|
|
658
815
|
});
|
|
659
816
|
});
|
|
660
817
|
|
|
661
818
|
test("selective refresh preserves unselected ownership and selected user changes after an all-assets install", () => {
|
|
662
819
|
withIsolatedAssetHome((agentHome) => {
|
|
663
|
-
|
|
820
|
+
installPackageAssets(agentHome, false);
|
|
664
821
|
const manifest = installedAssetManifest(agentHome);
|
|
665
822
|
const selectedUserKey = "agents/gentle-ai-explore.md";
|
|
666
|
-
const unselectedUserKey = "agents/
|
|
823
|
+
const unselectedUserKey = "agents/review-risk.md";
|
|
667
824
|
for (const key of [selectedUserKey, unselectedUserKey, "agents/custom.md"]) {
|
|
668
825
|
writeFileSync(join(agentHome, key), "User-authored instructions\n");
|
|
669
826
|
}
|
|
670
827
|
const before = new Map(assetFileKeys(agentHome).map(key => [key, readFileSync(join(agentHome, key), "utf8")]));
|
|
671
|
-
assert.deepEqual(installPackageAssets(agentHome, true, ["delegation"]), { agents: 2, chains: 0, support:
|
|
828
|
+
assert.deepEqual(installPackageAssets(agentHome, true, ["delegation"]), { agents: 2, chains: 0, support: 2, skipped: 1 });
|
|
672
829
|
delete manifest.assets[selectedUserKey];
|
|
673
830
|
assert.deepEqual(installedAssetManifest(agentHome), manifest);
|
|
674
831
|
for (const [key, content] of before) {
|
|
@@ -705,42 +862,94 @@ test("selective review migration adopts only untouched legacy copies and preserv
|
|
|
705
862
|
assert.equal(manifest.assets["agents/review-risk.md"], sha256(actual));
|
|
706
863
|
}
|
|
707
864
|
assert.equal(existsSync(join(agentHome, "agents", "sdd-apply.md")), false);
|
|
708
|
-
assert.equal(existsSync(join(agentHome, "gentle-ai", "support")),
|
|
865
|
+
assert.equal(existsSync(join(agentHome, "gentle-ai", "support", "strict-tdd.md")), true);
|
|
709
866
|
});
|
|
710
867
|
}
|
|
711
868
|
});
|
|
712
869
|
|
|
713
|
-
test("
|
|
714
|
-
|
|
715
|
-
const
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
870
|
+
test("native pulse audio ships owned TypeScript sources without new dependencies or addons", () => {
|
|
871
|
+
const manifest = readPackageJson();
|
|
872
|
+
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
873
|
+
const sources = [
|
|
874
|
+
"lib/notification-pulse-protocol.ts", "lib/notification-pulse-client.ts",
|
|
875
|
+
"lib/notification-pulse-stream.ts", "lib/notification-audio-native.ts",
|
|
876
|
+
"lib/notification-pulse-worker.ts",
|
|
877
|
+
];
|
|
878
|
+
for (const source of sources) {
|
|
879
|
+
assert.ok(existsSync(join(PACKAGE_ROOT, source)), `${source} must exist`);
|
|
880
|
+
assert.ok(verifier.includes(`"${source}"`), `${source} must be a required package resource`);
|
|
881
|
+
}
|
|
882
|
+
assert.ok(!manifest.files?.includes("native/"), "no native addon directory may ship");
|
|
883
|
+
for (const name of Object.keys(manifest.dependencies ?? {})) assert.doesNotMatch(name, /pulse|audio|sound|native/i, name);
|
|
884
|
+
for (const name of Object.keys(manifest.scripts ?? {})) assert.doesNotMatch(name, /pulse|native:build|audio:install/i, name);
|
|
885
|
+
for (const path of ["lib/notification-pulse-worker.ts", "lib/notification-audio-native.ts"]) {
|
|
886
|
+
const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
|
|
887
|
+
assert.doesNotMatch(source, /@earendil-works|\.node["']|addon/i, path);
|
|
888
|
+
assert.doesNotMatch(source, /postinstall|installer|download/i, path);
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
test("native windows audio ships an owned encoded-command adapter without scripts or dependencies", () => {
|
|
893
|
+
const manifest = readPackageJson();
|
|
894
|
+
const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
|
|
895
|
+
const path = "lib/notification-audio-windows.ts";
|
|
896
|
+
assert.ok(existsSync(join(PACKAGE_ROOT, path)), `${path} must exist`);
|
|
897
|
+
assert.ok(verifier.includes(`"${path}"`), `${path} must be a required package resource`);
|
|
898
|
+
for (const dependency of Object.keys(manifest.dependencies ?? {})) assert.doesNotMatch(dependency, /audio|sound|windows|powershell|native/i, dependency);
|
|
899
|
+
for (const script of Object.keys(manifest.scripts ?? {})) assert.doesNotMatch(script, /windows:build|powershell|audio:install/i, script);
|
|
900
|
+
const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
|
|
901
|
+
assert.match(source, /-EncodedCommand/, "the adapter must drive the trusted built-in PowerShell host with an encoded command");
|
|
902
|
+
assert.doesNotMatch(source, /\.ps1|ExecutionPolicy|\.node["']|addon/i, path);
|
|
903
|
+
assert.doesNotMatch(source, /postinstall|installer|download/i, path);
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
test("packed tarball excludes retired workflow paths while source retains legacy migration proof", () => {
|
|
907
|
+
const fixture = "tests/fixtures/legacy/sdd-research-v2.5.0.md";
|
|
908
|
+
assert.ok(existsSync(join(PACKAGE_ROOT, fixture)), "the historical source fixture must remain available to migration tests");
|
|
909
|
+
const destination = mkdtempSync(join(tmpdir(), "gentle-pi-pack-manifest-"));
|
|
720
910
|
try {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
911
|
+
const output = execFileSync("npm", ["pack", "--ignore-scripts", "--offline", "--json", "--pack-destination", destination], {
|
|
912
|
+
cwd: PACKAGE_ROOT,
|
|
913
|
+
encoding: "utf8",
|
|
914
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
915
|
+
});
|
|
916
|
+
const [packed] = parseNpmPackResult(output);
|
|
917
|
+
assert.ok(packed?.files?.length, "npm pack must return a nonempty tar manifest");
|
|
918
|
+
assert.ok(packed.files.some(file => file.path === "tests/package-manifest.test.ts"), "other tests remain packed");
|
|
919
|
+
for (const path of [
|
|
920
|
+
"extensions/gentle-notifications.ts",
|
|
921
|
+
"lib/notification-audio.ts", "lib/notification-customize.ts", "lib/notification-events.ts", "lib/notification-policy.ts",
|
|
922
|
+
"lib/notification-scheduler.ts", "lib/notification-service.ts", "lib/notification-ui.ts",
|
|
923
|
+
"assets/sounds/success.wav", "assets/sounds/error.wav", "assets/sounds/attention.wav",
|
|
924
|
+
"assets/sounds/LICENSE.md", "docs/sound-notifications.md", "docs/sound-notifications-proposal.md",
|
|
925
|
+
"lib/notification-pulse-protocol.ts", "lib/notification-pulse-client.ts", "lib/notification-pulse-stream.ts",
|
|
926
|
+
"lib/notification-audio-native.ts", "lib/notification-pulse-worker.ts",
|
|
927
|
+
"lib/notification-audio-windows.ts",
|
|
928
|
+
"scripts/npm-pack-result.mjs",
|
|
929
|
+
]) {
|
|
930
|
+
assert.ok(packed.files.some(file => file.path === path), `${path} must be packed`);
|
|
739
931
|
}
|
|
932
|
+
assert.deepEqual(packed.files.filter(file => /sdd|openspec/i.test(file.path)).map(file => file.path), []);
|
|
740
933
|
} finally {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
934
|
+
rmSync(destination, { recursive: true, force: true });
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
test("legacy research retirement requires exact ownership and preserves edited copies", () => {
|
|
939
|
+
const legacy = readFileSync(join(PACKAGE_ROOT, "tests/fixtures/legacy/sdd-research-v2.5.0.md"), "utf8");
|
|
940
|
+
const history = JSON.parse(readFileSync(join(PACKAGE_ROOT, "assets", "migrations", "managed-assets-v2.5.0.json"), "utf8"));
|
|
941
|
+
assert.equal(sha256(legacy), history.assets["agents/sdd-research.md"]);
|
|
942
|
+
for (const edited of [false, true]) {
|
|
943
|
+
withIsolatedAssetHome((agentHome) => {
|
|
944
|
+
mkdirSync(join(agentHome, "agents"), { recursive: true });
|
|
945
|
+
const target = join(agentHome, "agents", "sdd-research.md");
|
|
946
|
+
const content = edited ? `${legacy}\nUser research restrictions.\n` : legacy;
|
|
947
|
+
writeFileSync(target, content);
|
|
948
|
+
installPackageAssets(agentHome, true);
|
|
949
|
+
assert.equal(existsSync(target), edited);
|
|
950
|
+
if (edited) assert.equal(readFileSync(target, "utf8"), content);
|
|
951
|
+
assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-research.md"], undefined);
|
|
952
|
+
});
|
|
744
953
|
}
|
|
745
954
|
});
|
|
746
955
|
|
|
@@ -783,7 +992,7 @@ test("forced package installation preserves same-path user-authored agents and s
|
|
|
783
992
|
mkdirSync(dirname(samePathUserAgent), { recursive: true });
|
|
784
993
|
writeFileSync(samePathUserAgent, userAgentSource);
|
|
785
994
|
|
|
786
|
-
|
|
995
|
+
installPackageAssets(temporaryProject, true);
|
|
787
996
|
|
|
788
997
|
assert.deepEqual(
|
|
789
998
|
readFileSync(samePathUserAgent),
|
|
@@ -861,7 +1070,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
|
|
|
861
1070
|
writeFileSync(installedReviewRisk, routedLegacySource);
|
|
862
1071
|
assert.equal(existsSync(managedAssetsManifest), false, "v0.13 had no ownership manifest");
|
|
863
1072
|
|
|
864
|
-
|
|
1073
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
865
1074
|
|
|
866
1075
|
const migrated = readFileSync(installedReviewRisk, "utf8");
|
|
867
1076
|
const currentPackageSource = readFileSync(
|
|
@@ -897,7 +1106,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
|
|
|
897
1106
|
);
|
|
898
1107
|
assert.notEqual(userEditedMigration, migrated, "the fixture must exercise post-migration drift");
|
|
899
1108
|
writeFileSync(installedReviewRisk, userEditedMigration);
|
|
900
|
-
|
|
1109
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
901
1110
|
assert.deepEqual(
|
|
902
1111
|
readFileSync(installedReviewRisk),
|
|
903
1112
|
Buffer.from(userEditedMigration),
|
|
@@ -932,7 +1141,7 @@ test("first forced sync migrates untouched v0.14 review contracts and preserves
|
|
|
932
1141
|
mkdirSync(dirname(installedReviewRisk), { recursive: true });
|
|
933
1142
|
writeFileSync(installedReviewRisk, routedLegacySource);
|
|
934
1143
|
|
|
935
|
-
|
|
1144
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
936
1145
|
|
|
937
1146
|
const migrated = readFileSync(installedReviewRisk, "utf8");
|
|
938
1147
|
assert.notEqual(migrated, routedLegacySource);
|
|
@@ -969,7 +1178,7 @@ test("first forced sync preserves a body-edited v0.13 asset byte-for-byte", () =
|
|
|
969
1178
|
mkdirSync(dirname(installedReviewRisk), { recursive: true });
|
|
970
1179
|
writeFileSync(installedReviewRisk, editedLegacySource);
|
|
971
1180
|
|
|
972
|
-
|
|
1181
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
973
1182
|
|
|
974
1183
|
assert.deepEqual(readFileSync(installedReviewRisk), Buffer.from(editedLegacySource));
|
|
975
1184
|
const manifest = JSON.parse(
|
|
@@ -1004,7 +1213,7 @@ test("forced package installation refreshes an asset recorded as package-managed
|
|
|
1004
1213
|
|
|
1005
1214
|
try {
|
|
1006
1215
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1007
|
-
|
|
1216
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1008
1217
|
assert.ok(existsSync(installedExemplar), "a missing package asset must install");
|
|
1009
1218
|
assert.ok(
|
|
1010
1219
|
existsSync(managedAssetsManifest),
|
|
@@ -1020,7 +1229,7 @@ test("forced package installation refreshes an asset recorded as package-managed
|
|
|
1020
1229
|
);
|
|
1021
1230
|
writeFileSync(managedAssetsManifest, JSON.stringify(manifest, null, 2));
|
|
1022
1231
|
|
|
1023
|
-
|
|
1232
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1024
1233
|
|
|
1025
1234
|
const refreshed = readAgentDefinition(installedExemplar);
|
|
1026
1235
|
assert.deepEqual(refreshed.tools, MANAGED_EXEMPLAR_TOOLS);
|
|
@@ -1050,13 +1259,13 @@ function assertManagedAgentUserEditIsPreserved(
|
|
|
1050
1259
|
|
|
1051
1260
|
try {
|
|
1052
1261
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1053
|
-
|
|
1262
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1054
1263
|
const installedSource = readFileSync(installedExemplar, "utf8");
|
|
1055
1264
|
const userEditedSource = editSource(installedSource);
|
|
1056
1265
|
assert.notEqual(userEditedSource, installedSource, `${editLabel} must alter the asset`);
|
|
1057
1266
|
writeFileSync(installedExemplar, userEditedSource);
|
|
1058
1267
|
|
|
1059
|
-
|
|
1268
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1060
1269
|
|
|
1061
1270
|
assert.deepEqual(
|
|
1062
1271
|
readFileSync(installedExemplar),
|
|
@@ -1102,8 +1311,8 @@ test("forced package installation preserves a thinking-only edit to a managed ag
|
|
|
1102
1311
|
test("forced package installation preserves an ordinary body edit to a managed agent", () => {
|
|
1103
1312
|
assertManagedAgentUserEditIsPreserved("an ordinary body edit", (source) =>
|
|
1104
1313
|
source.replace(
|
|
1105
|
-
"You are the read-only explorer for generic
|
|
1106
|
-
"Preserve this user-authored body change. You are the read-only explorer for generic
|
|
1314
|
+
"You are the read-only explorer for generic ODD work.",
|
|
1315
|
+
"Preserve this user-authored body change. You are the read-only explorer for generic ODD work.",
|
|
1107
1316
|
),
|
|
1108
1317
|
);
|
|
1109
1318
|
});
|
|
@@ -1122,7 +1331,7 @@ test("package model assignment keeps only package-managed agents owned", () => {
|
|
|
1122
1331
|
|
|
1123
1332
|
try {
|
|
1124
1333
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1125
|
-
|
|
1334
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1126
1335
|
writeFileSync(userAgent, userAgentSource);
|
|
1127
1336
|
|
|
1128
1337
|
applyModelConfig(PACKAGE_ROOT, {
|
|
@@ -1151,7 +1360,7 @@ test("package model assignment keeps only package-managed agents owned", () => {
|
|
|
1151
1360
|
"routing an arbitrary user agent must not relabel it as package-owned",
|
|
1152
1361
|
);
|
|
1153
1362
|
|
|
1154
|
-
|
|
1363
|
+
installPackageAssets(PACKAGE_ROOT, true);
|
|
1155
1364
|
assert.equal(
|
|
1156
1365
|
readFileSync(installedExemplar, "utf8"),
|
|
1157
1366
|
readFileSync(join(PACKAGE_ROOT, "assets", "agents", MANAGED_EXEMPLAR_FILE), "utf8"),
|
|
@@ -1182,20 +1391,23 @@ test("jd-fix-agent packaged allowlist includes write tools", () => {
|
|
|
1182
1391
|
}
|
|
1183
1392
|
});
|
|
1184
1393
|
|
|
1185
|
-
test("
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
"
|
|
1192
|
-
"
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1394
|
+
test("deleted SDD definitions remain absent from the installed catalog", () => {
|
|
1395
|
+
const retired = [
|
|
1396
|
+
...[
|
|
1397
|
+
"apply", "archive", "design", "explore", "init", "onboard", "proposal",
|
|
1398
|
+
"remediate", "research", "spec", "status", "tasks", "verify",
|
|
1399
|
+
].map(name => `agents/sdd-${name}.md`),
|
|
1400
|
+
"chains/sdd-full.chain.md", "chains/sdd-plan.chain.md", "chains/sdd-verify.chain.md",
|
|
1401
|
+
"gentle-ai/support/sdd-status-contract.md",
|
|
1402
|
+
];
|
|
1403
|
+
withIsolatedAssetHome(agentHome => {
|
|
1404
|
+
installPackageAssets(agentHome, false);
|
|
1405
|
+
for (const key of retired) {
|
|
1406
|
+
assert.equal(getPackageAssetOwner(key), undefined, key);
|
|
1407
|
+
assert.equal(installedAssetManifest(agentHome).assets[key], undefined, key);
|
|
1408
|
+
assert.equal(existsSync(join(agentHome, key)), false, key);
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1199
1411
|
});
|
|
1200
1412
|
|
|
1201
1413
|
test("gentle-ai-worker packages the exact scoped writer contract", () => {
|
|
@@ -1296,8 +1508,11 @@ test("gentle-ai-worker packages the exact scoped writer contract", () => {
|
|
|
1296
1508
|
assert.match(memorySafety, /raw untrusted repository/);
|
|
1297
1509
|
|
|
1298
1510
|
const testDiscipline = readMarkdownSection(source, "Test discipline");
|
|
1299
|
-
assert.match(testDiscipline, /
|
|
1300
|
-
assert.match(testDiscipline, /not
|
|
1511
|
+
assert.match(testDiscipline, /Apply the ODD test-first policy by default for behavior changes with applicable runnable deterministic tests and a clear expected outcome/);
|
|
1512
|
+
assert.match(testDiscipline, /Test presence alone does not establish applicability; no TUI toggle or per-task chat choice is needed/);
|
|
1513
|
+
assert.match(testDiscipline, /RED[\s\S]*GREEN[\s\S]*PRESERVE[\s\S]*REFACTOR/);
|
|
1514
|
+
assert.match(testDiscipline, /no meaningful RED[\s\S]*proportionate ordinary functional or structural verification/);
|
|
1515
|
+
assert.match(testDiscipline, /Never claim RED\/GREEN evidence that was not observed/);
|
|
1301
1516
|
assert.match(
|
|
1302
1517
|
testDiscipline,
|
|
1303
1518
|
/Broad suites, builds, formatters, or linters may run only when explicitly authorized by the parent\./,
|
|
@@ -1306,13 +1521,13 @@ test("gentle-ai-worker packages the exact scoped writer contract", () => {
|
|
|
1306
1521
|
assert.doesNotMatch(testDiscipline, /clearly required by the repository contract/);
|
|
1307
1522
|
});
|
|
1308
1523
|
|
|
1309
|
-
test("
|
|
1524
|
+
test("package installation gives gentle-ai-worker a loader-compatible scoped identity", () => {
|
|
1310
1525
|
const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-agent-home-"));
|
|
1311
1526
|
const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
|
|
1312
1527
|
|
|
1313
1528
|
try {
|
|
1314
1529
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1315
|
-
|
|
1530
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1316
1531
|
|
|
1317
1532
|
const installedAgentsDir = join(temporaryAgentHome, "agents");
|
|
1318
1533
|
const installedAgentPath = join(installedAgentsDir, "gentle-ai-worker.md");
|
|
@@ -1398,7 +1613,7 @@ test("asset installation uses PI_CODING_AGENT_DIR as the Pi agent home when no e
|
|
|
1398
1613
|
delete process.env.GENTLE_PI_AGENT_HOME;
|
|
1399
1614
|
process.env.PI_CODING_AGENT_DIR = temporaryPiAgentDir;
|
|
1400
1615
|
|
|
1401
|
-
|
|
1616
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1402
1617
|
|
|
1403
1618
|
const installedPath = join(temporaryPiAgentDir, "agents", "gentle-ai-explore.md");
|
|
1404
1619
|
assert.ok(existsSync(installedPath), "managed agents must install where Pi Subagents reads global definitions");
|
|
@@ -1409,7 +1624,7 @@ test("asset installation uses PI_CODING_AGENT_DIR as the Pi agent home when no e
|
|
|
1409
1624
|
);
|
|
1410
1625
|
|
|
1411
1626
|
process.env.GENTLE_PI_AGENT_HOME = explicitGentleHome;
|
|
1412
|
-
|
|
1627
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1413
1628
|
assert.ok(
|
|
1414
1629
|
existsSync(join(explicitGentleHome, "agents", "gentle-ai-explore.md")),
|
|
1415
1630
|
"GENTLE_PI_AGENT_HOME remains the explicit test/operator override",
|
|
@@ -1433,7 +1648,7 @@ test("global model routing uses PI_CODING_AGENT_DIR for package-installed agents
|
|
|
1433
1648
|
try {
|
|
1434
1649
|
delete process.env.GENTLE_PI_AGENT_HOME;
|
|
1435
1650
|
process.env.PI_CODING_AGENT_DIR = temporaryPiAgentDir;
|
|
1436
|
-
|
|
1651
|
+
installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
|
|
1437
1652
|
|
|
1438
1653
|
const result = applyModelConfig(temporaryProject, {
|
|
1439
1654
|
"gentle-ai-explore": { model: "provider/model", thinking: "high" },
|
|
@@ -1458,7 +1673,7 @@ test("global model routing uses PI_CODING_AGENT_DIR for package-installed agents
|
|
|
1458
1673
|
test("normal and forced installation copy generic agents with complete role contracts", () => {
|
|
1459
1674
|
const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
|
|
1460
1675
|
const expectedTools = {
|
|
1461
|
-
"gentle-ai-explore": ["read", "grep", "find", "codegraph"],
|
|
1676
|
+
"gentle-ai-explore": ["read", "grep", "find", "codegraph", "web_enable", "web_search", "source_check", "fetch_content", "get_search_content"],
|
|
1462
1677
|
"gentle-ai-verify": ["read", "grep", "find", "bash"],
|
|
1463
1678
|
} as const;
|
|
1464
1679
|
|
|
@@ -1467,7 +1682,7 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1467
1682
|
const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-generic-agents-"));
|
|
1468
1683
|
process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
|
|
1469
1684
|
try {
|
|
1470
|
-
|
|
1685
|
+
installPackageAssets(PACKAGE_ROOT, force, ["delegation"]);
|
|
1471
1686
|
|
|
1472
1687
|
for (const [name, tools] of Object.entries(expectedTools)) {
|
|
1473
1688
|
const packagedPath = join(PACKAGE_ROOT, "assets", "agents", `${name}.md`);
|
|
@@ -1476,7 +1691,7 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1476
1691
|
assert.equal(source, readFileSync(packagedPath, "utf8"));
|
|
1477
1692
|
assert.equal(installedName, name);
|
|
1478
1693
|
assert.deepEqual(installedTools, tools);
|
|
1479
|
-
assert.match(source, /generic
|
|
1694
|
+
assert.match(source, /generic ODD work/);
|
|
1480
1695
|
assert.match(source, /Do not (?:fix findings, delegate to child agents|delegate to child agents, commit)/);
|
|
1481
1696
|
if (name === "gentle-ai-explore") {
|
|
1482
1697
|
assert.match(source, /cwd-scoped `codegraph` tool/);
|
|
@@ -1488,9 +1703,9 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1488
1703
|
}
|
|
1489
1704
|
assert.match(source, /Do not (?:edit, write|edit, write, or fix findings)/);
|
|
1490
1705
|
assert.match(source, /compressed (?:handoff|evidence handoff)/);
|
|
1491
|
-
assert.match(source, /Do not use
|
|
1706
|
+
assert.match(source, /Do not use review lenses\. RDD review remains independent and parent-owned\./);
|
|
1492
1707
|
if (name === "gentle-ai-verify") {
|
|
1493
|
-
assert.match(source, /exact test, build, or
|
|
1708
|
+
assert.match(source, /exact test, build, lint, or spec example commands explicitly authorized by the parent/);
|
|
1494
1709
|
assert.match(source, /only outputs the parent explicitly identified as expected/);
|
|
1495
1710
|
assert.match(source, /unexpected mutation as a blocker/);
|
|
1496
1711
|
assert.match(source, /do not clean it up or fix it/);
|
|
@@ -1506,16 +1721,30 @@ test("normal and forced installation copy generic agents with complete role cont
|
|
|
1506
1721
|
}
|
|
1507
1722
|
});
|
|
1508
1723
|
|
|
1509
|
-
test("bounded implementation routing
|
|
1724
|
+
test("bounded implementation routing resolves the explicit canonical fallback reference", () => {
|
|
1510
1725
|
const routing = readFileSync(
|
|
1511
1726
|
join(PACKAGE_ROOT, "assets", "orchestrator-delegation.md"),
|
|
1512
1727
|
"utf8",
|
|
1513
1728
|
);
|
|
1514
|
-
const
|
|
1729
|
+
const reference = "For bounded writes, follow the canonical Writer rule under Mandatory Delegation Triggers.";
|
|
1730
|
+
const resolveSimpleDelegation = (source: string): string => {
|
|
1731
|
+
const simpleDelegation = readMarkdownSection(source, "2. Simple Delegation");
|
|
1732
|
+
assert.ok(simpleDelegation.split("\n").includes(reference), "Simple Delegation must name the exact canonical Writer rule");
|
|
1733
|
+
const canonical = readMarkdownSection(source, "Mandatory Delegation Triggers");
|
|
1734
|
+
assertWorkerFallbackRouting(canonical, "resolved Simple Delegation");
|
|
1735
|
+
return canonical;
|
|
1736
|
+
};
|
|
1515
1737
|
const mandatoryDelegation = readMarkdownSection(routing, "Mandatory Delegation Triggers");
|
|
1516
1738
|
|
|
1517
|
-
assertWorkerFallbackRouting(
|
|
1739
|
+
assertWorkerFallbackRouting(resolveSimpleDelegation(routing), "Simple Delegation");
|
|
1518
1740
|
assertWorkerFallbackRouting(mandatoryDelegation, "Mandatory Delegation Triggers");
|
|
1741
|
+
assert.throws(() => resolveSimpleDelegation(routing.replace(reference, "")), /must name the exact canonical Writer rule/);
|
|
1742
|
+
assert.throws(() => resolveSimpleDelegation(routing.replace(reference, reference.replace("Mandatory Delegation Triggers", "Other Rule"))),
|
|
1743
|
+
/must name the exact canonical Writer rule/);
|
|
1744
|
+
assert.throws(() => resolveSimpleDelegation(routing.replace("#### Mandatory Delegation Triggers", "#### Missing Canonical Rule")),
|
|
1745
|
+
/exactly one Mandatory Delegation Triggers section/);
|
|
1746
|
+
assert.throws(() => resolveSimpleDelegation(routing.replace("user-configured `worker`", "unspecified worker")),
|
|
1747
|
+
/must prefer the package-owned worker before a user-configured worker/);
|
|
1519
1748
|
assert.doesNotMatch(
|
|
1520
1749
|
routing,
|
|
1521
1750
|
/non-normative compatibility quotation|former wording is retained|no-runtime inline exception|superseded by the stop requirement/,
|
|
@@ -1531,15 +1760,12 @@ test("bounded implementation routing uses the same explicit fallback in both pol
|
|
|
1531
1760
|
test("orchestrator routes generic roles without static RDD lens routing", () => {
|
|
1532
1761
|
for (const file of ["orchestrator.md", "orchestrator-delegation.md"]) {
|
|
1533
1762
|
const routing = readFileSync(join(PACKAGE_ROOT, "assets", file), "utf8");
|
|
1534
|
-
assert.match(routing,
|
|
1535
|
-
assert.match(
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
assert.match(routing,
|
|
1540
|
-
assert.match(routing, /SDD roles stay inside SDD|Use `sdd-explore` and `sdd-verify` only inside SDD/);
|
|
1541
|
-
assert.match(routing, /(?:truly local )?read-only check(?:ing)? of (?:known )?1[-–]3 known files|1[-–]3-file read-only check/);
|
|
1542
|
-
assert.match(routing, /(?:verification that |verification commands →).*executes? or delegates?|executing\/delegating verification commands/);
|
|
1763
|
+
assert.match(routing, /`gentle-ai-explore`/);
|
|
1764
|
+
assert.match(routing, /`gentle-ai-worker`/);
|
|
1765
|
+
assert.match(routing, /`gentle-ai-verify`/);
|
|
1766
|
+
assert.match(routing, /focused test and (?:the )?suite/);
|
|
1767
|
+
// The Verification rule line itself must route high risk to the verifier.
|
|
1768
|
+
assert.match(routing, /^\d\. \*\*Verification rule\*\*[^\n]*high[- ]risk[^\n]*`gentle-ai-verify`/m);
|
|
1543
1769
|
assert.match(routing, /missing(?: or |\/)unusable[\s\S]*native `Agent`[\s\S]*(?:the )?same read-only/);
|
|
1544
1770
|
assert.match(routing, /report (?:the )?fallback/);
|
|
1545
1771
|
assert.doesNotMatch(routing, /review lenses? (?:inside|only inside)|review lens routing/i);
|
|
@@ -1563,13 +1789,10 @@ test("pi-pretty wrapper uses cached ESM loading for compiled and pnpm symlink in
|
|
|
1563
1789
|
assert.match(wrapper, /quietToolsEnabled/);
|
|
1564
1790
|
});
|
|
1565
1791
|
|
|
1566
|
-
test("Gentle Shell
|
|
1792
|
+
test("Gentle Shell v4.1.0 package manifest declares the release version", () => {
|
|
1567
1793
|
const packageJson = readPackageJson();
|
|
1568
|
-
assert.equal(packageJson.version, "
|
|
1569
|
-
assert.equal(
|
|
1570
|
-
packageJson.scripts?.test,
|
|
1571
|
-
"node --experimental-strip-types --test tests/*.test.ts && pnpm run check:provider-contract && pnpm run test:harness",
|
|
1572
|
-
);
|
|
1794
|
+
assert.equal(packageJson.version, "4.1.0", "the release manifest must be explicitly pinned to v4.1.0");
|
|
1795
|
+
assert.equal(packageJson.scripts?.test, "node scripts/run-test-suite.mjs");
|
|
1573
1796
|
assert.ok(packageJson.files?.includes("assets/"));
|
|
1574
1797
|
assert.ok(packageJson.files?.includes("contracts/"));
|
|
1575
1798
|
|
|
@@ -1610,13 +1833,13 @@ test("technical reference documents dynamic Gentle AI RDD ownership and the inst
|
|
|
1610
1833
|
});
|
|
1611
1834
|
|
|
1612
1835
|
|
|
1613
|
-
test("package verification
|
|
1614
|
-
assert.
|
|
1836
|
+
test("package verification no longer requires the retired remediation actor", () => {
|
|
1837
|
+
assert.doesNotMatch(readFileSync(join(PACKAGE_ROOT, "scripts/verify-package-files.mjs"), "utf8"), /^\s*"assets\/agents\/sdd-remediate\.md",?$/m);
|
|
1615
1838
|
});
|
|
1616
1839
|
|
|
1617
|
-
test("
|
|
1840
|
+
test("package installation retires owned sync but preserves modified copies and unrelated owners", () => {
|
|
1618
1841
|
withIsolatedAssetHome((agentHome) => {
|
|
1619
|
-
|
|
1842
|
+
installPackageAssets(agentHome, false);
|
|
1620
1843
|
const path = join(agentHome, "agents/sdd-sync.md");
|
|
1621
1844
|
const manifestPath = join(agentHome, "gentle-ai/managed-assets.json");
|
|
1622
1845
|
const legacy = "Previously managed sync executor\n";
|
|
@@ -1625,13 +1848,11 @@ test("SDD installation retires owned sync but preserves modified copies and unre
|
|
|
1625
1848
|
writeFileSync(path, legacy);
|
|
1626
1849
|
writeFileSync(manifestPath, JSON.stringify(manifest));
|
|
1627
1850
|
installPackageAssets(agentHome, true, ["delegation"]);
|
|
1628
|
-
assert.equal(readFileSync(path, "utf8"), legacy);
|
|
1629
|
-
installPackageAssets(agentHome, true, ["sdd"]);
|
|
1630
1851
|
assert.equal(existsSync(path), false);
|
|
1631
1852
|
assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-sync.md"], undefined);
|
|
1632
1853
|
writeFileSync(path, "User-modified sync instructions\n");
|
|
1633
1854
|
writeFileSync(manifestPath, JSON.stringify(manifest));
|
|
1634
|
-
installPackageAssets(agentHome, true, ["
|
|
1855
|
+
installPackageAssets(agentHome, true, ["delegation"]);
|
|
1635
1856
|
assert.equal(readFileSync(path, "utf8"), "User-modified sync instructions\n");
|
|
1636
1857
|
assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-sync.md"], undefined);
|
|
1637
1858
|
});
|