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
|
@@ -30,6 +30,23 @@ const binUrl = new URL("../bin/gentle-shell.mjs", import.meta.url);
|
|
|
30
30
|
const binPath = fileURLToPath(binUrl);
|
|
31
31
|
const packageRoot = dirname(dirname(binPath));
|
|
32
32
|
|
|
33
|
+
test("Herdr activity is discoverable through the isolated launcher package", async () => {
|
|
34
|
+
const { buildPiInvocation } = await import("../lib/gentle-shell-launcher.ts");
|
|
35
|
+
const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
36
|
+
assert.ok(manifest.pi.extensions.includes("./extensions"));
|
|
37
|
+
assert.ok(existsSync(join(packageRoot, "extensions", "gentle-herdr-activity.ts")));
|
|
38
|
+
for (const takeOver of [false, true]) {
|
|
39
|
+
const invocation = buildPiInvocation({
|
|
40
|
+
runtime: { kind: "path", command: "fake-pi", args: [] },
|
|
41
|
+
home: { mode: "isolated", source: "default", dir: "/fake/home" },
|
|
42
|
+
packageRoot, declaration: undefined, takeOver, otherPackagePaths: [],
|
|
43
|
+
passthrough: [], baseEnv: {}, homedir: "/fake", cwd: "/fake/cwd",
|
|
44
|
+
});
|
|
45
|
+
assert.ok(invocation.args.includes(packageRoot));
|
|
46
|
+
assert.equal(invocation.env.PI_CODING_AGENT_DIR, "/fake/home");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
33
50
|
test("real adjacent Pi resolves through its public entry without PATH or a runtime override", (t) => {
|
|
34
51
|
const f = fixture(t);
|
|
35
52
|
const result = spawnSync(process.execPath, [binPath, "--version"], {
|
|
@@ -53,16 +70,20 @@ function standaloneLauncher(t: test.TestContext) {
|
|
|
53
70
|
writeFileSync(join(root, "bin", "gentle-shell.mjs"), readFileSync(binPath));
|
|
54
71
|
writeFileSync(join(root, "package.json"), readFileSync(join(packageRoot, "package.json")));
|
|
55
72
|
for (const dir of ["runtime", "scripts"]) symlinkSync(join(packageRoot, dir), join(root, dir), "junction");
|
|
56
|
-
const env = {
|
|
73
|
+
const env = {
|
|
74
|
+
HOME: f.home, USERPROFILE: f.home, PATH: `${root}${delimiter}${dirname(process.execPath)}`, GENTLE_SHELL_NO_AUTO_SETUP: "1",
|
|
75
|
+
// Keep executable discovery isolated without making cmd shims unlaunchable.
|
|
76
|
+
...(process.platform === "win32" ? { ComSpec: process.env.ComSpec, SystemRoot: process.env.SystemRoot } : {}),
|
|
77
|
+
};
|
|
57
78
|
return { ...f, root, env, launcher: join(root, "bin", "gentle-shell.mjs") };
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
test("a genuinely absent adjacent peer falls back to PATH", (t) => {
|
|
61
82
|
const f = standaloneLauncher(t);
|
|
62
|
-
|
|
83
|
+
writePathPiScript(f.root, "1.2.1");
|
|
63
84
|
const result = spawnSync(process.execPath, [f.launcher, "--version"], { env: f.env, encoding: "utf8" });
|
|
64
85
|
assert.equal(result.status, 0, result.stderr);
|
|
65
|
-
assert.match(result.stdout, /pi
|
|
86
|
+
assert.match(result.stdout, /pi 1\.2\.1/);
|
|
66
87
|
});
|
|
67
88
|
|
|
68
89
|
test("malformed adjacent metadata never silently falls back to PATH; env override still wins", (t) => {
|
|
@@ -70,9 +91,8 @@ test("malformed adjacent metadata never silently falls back to PATH; env overrid
|
|
|
70
91
|
const peer = join(f.root, "node_modules", "@earendil-works", "pi-coding-agent");
|
|
71
92
|
mkdirSync(join(peer, "dist", "bundle"), { recursive: true });
|
|
72
93
|
writeFileSync(join(peer, "dist", "index.js"), "");
|
|
73
|
-
writePiScript(join(peer, "dist", "bundle", "cli.js"), "
|
|
74
|
-
const fallback =
|
|
75
|
-
writePiScript(fallback, "0.99.2");
|
|
94
|
+
writePiScript(join(peer, "dist", "bundle", "cli.js"), "1.2.0");
|
|
95
|
+
const fallback = writePathPiScript(f.root, "1.2.1");
|
|
76
96
|
const base = { name: "@earendil-works/pi-coding-agent", type: "module", exports: { ".": { import: "./dist/index.js" } }, bin: { pi: "dist/bundle/cli.js" } };
|
|
77
97
|
for (const metadata of [{ ...base, name: "impostor" }, { ...base, bin: { pi: "../outside.js" } }, { ...base, bin: {} }, "malformed"]) {
|
|
78
98
|
writeFileSync(join(peer, "package.json"), metadata === "malformed" ? "{" : JSON.stringify(metadata));
|
|
@@ -83,7 +103,7 @@ test("malformed adjacent metadata never silently falls back to PATH; env overrid
|
|
|
83
103
|
writeFileSync(join(peer, "package.json"), JSON.stringify({ ...base, name: "impostor" }));
|
|
84
104
|
const override = spawnSync(process.execPath, [f.launcher, "--version"], { env: { ...f.env, GENTLE_SHELL_PI: fallback }, encoding: "utf8" });
|
|
85
105
|
assert.equal(override.status, 0, override.stderr);
|
|
86
|
-
assert.match(override.stdout, /pi
|
|
106
|
+
assert.match(override.stdout, /pi 1\.2\.1/);
|
|
87
107
|
});
|
|
88
108
|
|
|
89
109
|
// The launcher's own gentle-pi version, exactly as `ownPackageVersion()` in
|
|
@@ -107,7 +127,7 @@ function fixture(t: test.TestContext) {
|
|
|
107
127
|
const home = join(root, "home");
|
|
108
128
|
mkdirSync(home, { recursive: true });
|
|
109
129
|
const piScript = join(root, "fake-pi.mjs");
|
|
110
|
-
writePiScript(piScript, "
|
|
130
|
+
writePiScript(piScript, "1.2.0");
|
|
111
131
|
const gentleShellHome = join(root, "gentle-shell-home");
|
|
112
132
|
const env: NodeJS.ProcessEnv = {
|
|
113
133
|
...process.env,
|
|
@@ -117,6 +137,9 @@ function fixture(t: test.TestContext) {
|
|
|
117
137
|
GENTLE_SHELL_PI: piScript,
|
|
118
138
|
GENTLE_SHELL_NO_AUTO_SETUP: "1",
|
|
119
139
|
};
|
|
140
|
+
// A suite launched from inside a Gentle Shell session inherits the outer
|
|
141
|
+
// session's recorded user Pi home, which --link now honours first (#2015).
|
|
142
|
+
delete env.GENTLE_SHELL_USER_PI_HOME;
|
|
120
143
|
return { root, home, gentleShellHome, piScript, env };
|
|
121
144
|
}
|
|
122
145
|
|
|
@@ -152,6 +175,7 @@ function writePiScript(path: string, version: string, removeExitCode = 0) {
|
|
|
152
175
|
" PI_CODING_AGENT_DIR: process.env.PI_CODING_AGENT_DIR,",
|
|
153
176
|
" GENTLE_PI_AGENT_HOME: process.env.GENTLE_PI_AGENT_HOME,",
|
|
154
177
|
" GENTLE_SHELL_USER_PI_HOME: process.env.GENTLE_SHELL_USER_PI_HOME,",
|
|
178
|
+
" GENTLE_SHELL_CHILD_PACKAGE_INJECTION: process.env.GENTLE_SHELL_CHILD_PACKAGE_INJECTION,",
|
|
155
179
|
"}));",
|
|
156
180
|
"process.exit(0);",
|
|
157
181
|
"",
|
|
@@ -160,6 +184,17 @@ function writePiScript(path: string, version: string, removeExitCode = 0) {
|
|
|
160
184
|
chmodSync(path, 0o755);
|
|
161
185
|
}
|
|
162
186
|
|
|
187
|
+
// Match the real platform lookup: POSIX accepts the shebang executable,
|
|
188
|
+
// Windows discovers a .cmd shim via PATHEXT. Bundled JS peers stay unchanged.
|
|
189
|
+
function writePathPiScript(root: string, version: string): string {
|
|
190
|
+
const script = join(root, process.platform === "win32" ? "pi-fixture.mjs" : "pi");
|
|
191
|
+
writePiScript(script, version);
|
|
192
|
+
if (process.platform !== "win32") return script;
|
|
193
|
+
const command = join(root, "pi.cmd");
|
|
194
|
+
writeFileSync(command, `@echo off\r\n"${process.execPath}" "${script}" %*\r\nexit /b %errorlevel%\r\n`);
|
|
195
|
+
return command;
|
|
196
|
+
}
|
|
197
|
+
|
|
163
198
|
function run(env: NodeJS.ProcessEnv, args: string[], options: { cwd?: string } = {}) {
|
|
164
199
|
return spawnSync(process.execPath, [binPath, ...args], { encoding: "utf8", env, ...options });
|
|
165
200
|
}
|
|
@@ -461,7 +496,7 @@ function writeGentleAiScriptDeclaringGentlePi(path: string, extraSources: string
|
|
|
461
496
|
// the invocation), this models what a real `pi remove` does to settings.json
|
|
462
497
|
// closely enough to prove a later plain launch sees the declaration gone and
|
|
463
498
|
// resumes the launcher's own injection.
|
|
464
|
-
function writePiScriptEditingSettingsOnRemove(path: string, version = "
|
|
499
|
+
function writePiScriptEditingSettingsOnRemove(path: string, version = "1.2.0") {
|
|
465
500
|
writeFileSync(
|
|
466
501
|
path,
|
|
467
502
|
[
|
|
@@ -642,6 +677,20 @@ test("forwarded args reach pi after the injected extension flags, in order", (t)
|
|
|
642
677
|
assert.equal(payload.GENTLE_PI_AGENT_HOME, f.gentleShellHome);
|
|
643
678
|
});
|
|
644
679
|
|
|
680
|
+
// #1690: the spawned pi must carry the launcher's own -e set so the subagent
|
|
681
|
+
// runner can forward it to delegated children; a stale inherited value is replaced.
|
|
682
|
+
test("an isolated launch without a gentle-pi declaration signals its package injection to pi", (t) => {
|
|
683
|
+
const f = fixture(t);
|
|
684
|
+
const stale = JSON.stringify({ version: 1, noExtensions: true, extensionPaths: [join(f.root, "outer")] });
|
|
685
|
+
for (const inherited of [undefined, stale]) {
|
|
686
|
+
const result = run({ ...f.env, GENTLE_SHELL_CHILD_PACKAGE_INJECTION: inherited }, ["--mode", "rpc"]);
|
|
687
|
+
assert.equal(result.status, 0, result.stderr);
|
|
688
|
+
const payload = JSON.parse(result.stdout);
|
|
689
|
+
assert.deepEqual(payload.args.slice(0, 2), ["-e", packageRoot]);
|
|
690
|
+
assert.deepEqual(JSON.parse(payload.GENTLE_SHELL_CHILD_PACKAGE_INJECTION), { version: 1, noExtensions: false, extensionPaths: [packageRoot] });
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
|
|
645
694
|
test("an isolated launch keeps its own agent home and carries the user's original Pi home, even when nested", (t) => {
|
|
646
695
|
const f = fixture(t);
|
|
647
696
|
const base = { ...f.env };
|
|
@@ -667,6 +716,10 @@ test("an isolated launch keeps its own agent home and carries the user's origina
|
|
|
667
716
|
const linked = launch({ PI_CODING_AGENT_DIR: customHome }, ["--link"]);
|
|
668
717
|
assert.equal(linked.PI_CODING_AGENT_DIR, customHome);
|
|
669
718
|
assert.equal(linked.GENTLE_SHELL_USER_PI_HOME, customHome);
|
|
719
|
+
// --link from inside an isolated session reuses the preserved original home (#2015).
|
|
720
|
+
const nestedLinked = launch({ PI_CODING_AGENT_DIR: f.gentleShellHome, GENTLE_SHELL_USER_PI_HOME: customHome }, ["--link"]);
|
|
721
|
+
assert.equal(nestedLinked.PI_CODING_AGENT_DIR, customHome);
|
|
722
|
+
assert.equal(nestedLinked.GENTLE_SHELL_USER_PI_HOME, customHome);
|
|
670
723
|
assert.equal(existsSync(join(customHome, "sessions")), false);
|
|
671
724
|
});
|
|
672
725
|
|
|
@@ -768,7 +821,7 @@ test("a too-old pi exits 1 naming both versions", (t) => {
|
|
|
768
821
|
const result = run(f.env, []);
|
|
769
822
|
assert.equal(result.status, 1);
|
|
770
823
|
assert.match(result.stderr, /0\.80\.0/);
|
|
771
|
-
assert.match(result.stderr, /
|
|
824
|
+
assert.match(result.stderr, /1\.2\.0/);
|
|
772
825
|
});
|
|
773
826
|
|
|
774
827
|
test("--version prints three lines", (t) => {
|
|
@@ -778,7 +831,7 @@ test("--version prints three lines", (t) => {
|
|
|
778
831
|
const lines = result.stdout.trim().split("\n");
|
|
779
832
|
assert.equal(lines.length, 3);
|
|
780
833
|
assert.match(lines[0], /^gentle-shell /);
|
|
781
|
-
assert.match(lines[1], /^pi
|
|
834
|
+
assert.match(lines[1], /^pi 1\.2\.0$/);
|
|
782
835
|
assert.match(lines[2], /^home isolated /);
|
|
783
836
|
});
|
|
784
837
|
|
|
@@ -801,7 +854,10 @@ test("gentle-shell setup provisions the resolved home through the pinned gentle-
|
|
|
801
854
|
assert.deepEqual(payload.args, ["install", "--agent", "pi", "--scope", "global"]);
|
|
802
855
|
assert.equal(payload.PI_CODING_AGENT_DIR, f.gentleShellHome);
|
|
803
856
|
assert.equal(payload.GENTLE_PI_AGENT_HOME, f.gentleShellHome);
|
|
804
|
-
|
|
857
|
+
// First the temporary `pi` that runs the resolved runtime, then the runtime's own folder.
|
|
858
|
+
const [launcher, runtimeDir] = payload.PATH.split(delimiter);
|
|
859
|
+
assert.match(launcher, /gentle-shell-pi-/, payload.PATH);
|
|
860
|
+
assert.equal(runtimeDir, dirname(f.piScript), payload.PATH);
|
|
805
861
|
|
|
806
862
|
// Home resolution runs exactly as a normal run: the isolated home gets
|
|
807
863
|
// created with its bootstrap TUI setting, same as a plain `gentle-shell`.
|
|
@@ -847,6 +903,119 @@ test("gentle-shell setup passes through the gentle-ai exit code", (t) => {
|
|
|
847
903
|
assert.equal(result.status, 3);
|
|
848
904
|
});
|
|
849
905
|
|
|
906
|
+
// Windows cannot execute a shebang fixture directly; use the launcher's
|
|
907
|
+
// existing .cmd support without changing the runtime under test.
|
|
908
|
+
function setupMCPExecutable(path: string): string {
|
|
909
|
+
chmodSync(path, 0o755);
|
|
910
|
+
if (process.platform !== "win32") return path;
|
|
911
|
+
const wrapper = `${path}.cmd`;
|
|
912
|
+
writeFileSync(wrapper, `@echo off\r\n"${process.execPath}" "${path}" %*\r\n`);
|
|
913
|
+
return wrapper;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
test("setup MCP migration warns without re-enabling configured servers", async (t) => {
|
|
917
|
+
for (const mode of ["link", "path"] as const) {
|
|
918
|
+
await t.test(mode, (t) => {
|
|
919
|
+
const f = fixture(t);
|
|
920
|
+
const target = mode === "link" ? join(f.home, ".pi", "agent") : f.gentleShellHome;
|
|
921
|
+
mkdirSync(join(target, "npm"), { recursive: true });
|
|
922
|
+
const settingsPath = join(target, "settings.json");
|
|
923
|
+
const settings = { theme: "kanagawa", packages: ["npm:pi-mcp-adapter", "npm:other"], extensions: ["-builtin:mcp", "user-extension.ts"] };
|
|
924
|
+
writeFileSync(settingsPath, JSON.stringify(settings));
|
|
925
|
+
const npmPath = join(target, "npm", "package.json");
|
|
926
|
+
writeFileSync(npmPath, JSON.stringify({ dependencies: { "pi-mcp-adapter": "^3.0.0", other: "1.0.0" } }));
|
|
927
|
+
const mcpPath = join(target, "mcp.json");
|
|
928
|
+
const mcpText = '{"mcpServers":{"context7":{"command":"npx","args":["context7-mcp"]}}}';
|
|
929
|
+
writeFileSync(mcpPath, mcpText);
|
|
930
|
+
const installer = join(f.root, "retire-adapter.mjs");
|
|
931
|
+
writeFileSync(installer, [
|
|
932
|
+
"#!/usr/bin/env node",
|
|
933
|
+
'import { readFileSync, writeFileSync } from "node:fs";',
|
|
934
|
+
'import { join } from "node:path";',
|
|
935
|
+
'const home = process.env.PI_CODING_AGENT_DIR;',
|
|
936
|
+
'const settingsPath = join(home, "settings.json");',
|
|
937
|
+
'const settings = JSON.parse(readFileSync(settingsPath, "utf8"));',
|
|
938
|
+
'settings.packages = settings.packages.filter(p => p !== "npm:pi-mcp-adapter");',
|
|
939
|
+
'writeFileSync(settingsPath, JSON.stringify(settings));',
|
|
940
|
+
'const npmPath = join(home, "npm", "package.json");',
|
|
941
|
+
'const manifest = JSON.parse(readFileSync(npmPath, "utf8"));',
|
|
942
|
+
'delete manifest.dependencies["pi-mcp-adapter"];',
|
|
943
|
+
'writeFileSync(npmPath, JSON.stringify(manifest));',
|
|
944
|
+
'console.log("installed");',
|
|
945
|
+
].join("\n"));
|
|
946
|
+
assert.equal(readFileSync(installer, "utf8").split("\n")[0], "#!/usr/bin/env node");
|
|
947
|
+
const args = mode === "link" ? ["--link", "setup"] : ["--home", target, "setup"];
|
|
948
|
+
const result = run({ ...f.env, PI_CODING_AGENT_DIR: target, GENTLE_SHELL_PI: setupMCPExecutable(f.piScript), GENTLE_SHELL_GENTLE_AI_BIN: setupMCPExecutable(installer) }, args);
|
|
949
|
+
assert.equal(result.status, 0, result.stderr);
|
|
950
|
+
assert.equal(result.stdout, "installed\n");
|
|
951
|
+
assert.equal(result.stderr, `gentle-shell: provisioning ${target} with the gentle-ai companion packages\n` +
|
|
952
|
+
`gentle-shell: WARNING: Pi built-in MCP is disabled in ${settingsPath}; pi-mcp-adapter is absent or inactive, so servers in ${mcpPath} will not load. If you want these servers enabled, remove -builtin:mcp from extensions in ${settingsPath}, then restart Pi. If MCP is intentionally disabled, keep the setting.\n`);
|
|
953
|
+
assert.deepEqual(JSON.parse(readFileSync(settingsPath, "utf8")), { ...settings, packages: ["npm:other"] });
|
|
954
|
+
assert.deepEqual(JSON.parse(readFileSync(npmPath, "utf8")), { dependencies: { other: "1.0.0" } });
|
|
955
|
+
assert.equal(readFileSync(mcpPath, "utf8"), mcpText);
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
test("setup MCP migration keeps enabled, unconfigured and dry-run homes unchanged", async (t) => {
|
|
961
|
+
for (const scenario of ["enabled", "unconfigured", "dry-run", "active-adapter"] as const) {
|
|
962
|
+
await t.test(scenario, (t) => {
|
|
963
|
+
const f = fixture(t);
|
|
964
|
+
const target = join(f.home, ".pi", "agent");
|
|
965
|
+
mkdirSync(target, { recursive: true });
|
|
966
|
+
const settingsPath = join(target, "settings.json");
|
|
967
|
+
const settingsText = JSON.stringify({ extensions: scenario === "enabled" ? [] : ["-builtin:mcp"], packages: scenario === "active-adapter" ? ["npm:pi-mcp-adapter@3.0.0"] : [] });
|
|
968
|
+
writeFileSync(settingsPath, settingsText);
|
|
969
|
+
const mcpPath = join(target, "mcp.json");
|
|
970
|
+
const mcpText = JSON.stringify({ mcpServers: scenario === "unconfigured" ? {} : { context7: { command: "npx" } } });
|
|
971
|
+
writeFileSync(mcpPath, mcpText);
|
|
972
|
+
const installer = join(f.root, "fake-gentle-ai.mjs");
|
|
973
|
+
writeGentleAiScript(installer);
|
|
974
|
+
const dryRun = scenario === "dry-run";
|
|
975
|
+
const result = run({ ...f.env, PI_CODING_AGENT_DIR: target, GENTLE_SHELL_PI: setupMCPExecutable(f.piScript), GENTLE_SHELL_GENTLE_AI_BIN: setupMCPExecutable(installer) }, ["--link", "setup", ...(dryRun ? ["--dry-run"] : [])]);
|
|
976
|
+
assert.equal(result.status, 0, result.stderr);
|
|
977
|
+
assert.deepEqual(JSON.parse(result.stdout).args, ["install", "--agent", "pi", "--scope", "global", ...(dryRun ? ["--dry-run"] : [])]);
|
|
978
|
+
assert.doesNotMatch(result.stderr, /WARNING:|built-in MCP/);
|
|
979
|
+
assert.equal(readFileSync(settingsPath, "utf8"), settingsText);
|
|
980
|
+
assert.equal(readFileSync(mcpPath, "utf8"), mcpText);
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
test("setup MCP migration warns when adapter resource loading is disabled", async (t) => {
|
|
986
|
+
for (const adapter of [
|
|
987
|
+
{ source: "npm:pi-mcp-adapter", autoload: false },
|
|
988
|
+
{ source: "npm:pi-mcp-adapter", autoload: false, extensions: ["!**"] },
|
|
989
|
+
{ source: "npm:pi-mcp-adapter", extensions: ["!**"] },
|
|
990
|
+
{ source: "npm:pi-mcp-adapter", extensions: ["index.ts"] },
|
|
991
|
+
]) {
|
|
992
|
+
await t.test(JSON.stringify(adapter), (t) => {
|
|
993
|
+
const f = fixture(t);
|
|
994
|
+
const target = join(f.home, ".pi", "agent");
|
|
995
|
+
mkdirSync(target, { recursive: true });
|
|
996
|
+
const settingsPath = join(target, "settings.json");
|
|
997
|
+
const uncertain = "extensions" in adapter && adapter.extensions.includes("index.ts");
|
|
998
|
+
const settingsText = JSON.stringify({ extensions: ["-builtin:mcp"], packages: [adapter] });
|
|
999
|
+
writeFileSync(settingsPath, settingsText);
|
|
1000
|
+
const mcpPath = join(target, "mcp.json");
|
|
1001
|
+
const mcpText = '{"mcpServers":{"context7":{"command":"npx"}}}';
|
|
1002
|
+
writeFileSync(mcpPath, mcpText);
|
|
1003
|
+
const installer = join(f.root, "fake-gentle-ai.mjs");
|
|
1004
|
+
writeGentleAiScript(installer);
|
|
1005
|
+
const result = run({ ...f.env, PI_CODING_AGENT_DIR: target, GENTLE_SHELL_PI: setupMCPExecutable(f.piScript), GENTLE_SHELL_GENTLE_AI_BIN: setupMCPExecutable(installer) }, ["--link", "setup"]);
|
|
1006
|
+
assert.equal(result.status, 0, result.stderr);
|
|
1007
|
+
assert.deepEqual(JSON.parse(result.stdout).args, ["install", "--agent", "pi", "--scope", "global"]);
|
|
1008
|
+
const diagnosis = uncertain
|
|
1009
|
+
? "pi-mcp-adapter activity cannot be confirmed from its extension filters, so servers in " + mcpPath + " may not load"
|
|
1010
|
+
: "pi-mcp-adapter is absent or inactive, so servers in " + mcpPath + " will not load";
|
|
1011
|
+
assert.equal(result.stderr, `gentle-shell: provisioning ${target} with the gentle-ai companion packages\n` +
|
|
1012
|
+
`gentle-shell: WARNING: Pi built-in MCP is disabled in ${settingsPath}; ${diagnosis}. If you want these servers enabled, remove -builtin:mcp from extensions in ${settingsPath}, then restart Pi. If MCP is intentionally disabled, keep the setting.\n`);
|
|
1013
|
+
assert.equal(readFileSync(settingsPath, "utf8"), settingsText);
|
|
1014
|
+
assert.equal(readFileSync(mcpPath, "utf8"), mcpText);
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
|
|
850
1019
|
// --- setup subcommand's self-heal for a missing package-local binary -------
|
|
851
1020
|
//
|
|
852
1021
|
// `npm install -g <tarball>` on a machine whose npm config disables lifecycle
|
|
@@ -1109,7 +1278,7 @@ test("gentle-shell setup propagates a non-zero pi remove exit code with an actio
|
|
|
1109
1278
|
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1110
1279
|
writeGentleAiScriptDeclaringConflict(gentleAiScript);
|
|
1111
1280
|
const failingPiScript = join(f.root, "fake-pi-remove-fails.mjs");
|
|
1112
|
-
writePiScript(failingPiScript, "
|
|
1281
|
+
writePiScript(failingPiScript, "1.2.0", 7);
|
|
1113
1282
|
const env = { ...f.env, GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_PI: failingPiScript };
|
|
1114
1283
|
|
|
1115
1284
|
const result = run(env, ["setup"]);
|
|
@@ -1130,7 +1299,7 @@ test("gentle-shell setup --home <dir> includes --home <dir> in the failing-remov
|
|
|
1130
1299
|
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1131
1300
|
writeGentleAiScriptDeclaringConflict(gentleAiScript);
|
|
1132
1301
|
const failingPiScript = join(f.root, "fake-pi-remove-fails.mjs");
|
|
1133
|
-
writePiScript(failingPiScript, "
|
|
1302
|
+
writePiScript(failingPiScript, "1.2.0", 7);
|
|
1134
1303
|
const env = { ...f.env, GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_PI: failingPiScript };
|
|
1135
1304
|
|
|
1136
1305
|
const result = run(env, ["--home", target, "setup"]);
|
|
@@ -1154,7 +1323,7 @@ test("gentle-shell setup shell-quotes a --home path containing a space in the fa
|
|
|
1154
1323
|
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1155
1324
|
writeGentleAiScriptDeclaringConflict(gentleAiScript);
|
|
1156
1325
|
const failingPiScript = join(f.root, "fake-pi-remove-fails.mjs");
|
|
1157
|
-
writePiScript(failingPiScript, "
|
|
1326
|
+
writePiScript(failingPiScript, "1.2.0", 7);
|
|
1158
1327
|
const env = { ...f.env, GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_PI: failingPiScript };
|
|
1159
1328
|
|
|
1160
1329
|
const result = run(env, ["--home", target, "setup"]);
|
|
@@ -1676,6 +1845,81 @@ test("an empty or nonexistent --home is still auto-provisioned", (t) => {
|
|
|
1676
1845
|
assert.equal(readFileSync(counterPath, "utf8").trim().split("\n").length, 1, "a fresh --home must still be auto-provisioned");
|
|
1677
1846
|
});
|
|
1678
1847
|
|
|
1848
|
+
// #2106: both installers finish with `gentle-shell setup`; the first launch
|
|
1849
|
+
// after it must not install the companion packages again.
|
|
1850
|
+
// Gentle AI requires a `pi` on its PATH and runs `pi install npm:gentle-pi`.
|
|
1851
|
+
// When gentle-shell runs a Pi that is not itself on PATH (the adjacent
|
|
1852
|
+
// package, or GENTLE_SHELL_PI), setup must give Gentle AI that same Pi.
|
|
1853
|
+
test("setup gives Gentle AI a `pi` on its PATH that runs the same Pi gentle-shell resolved", { skip: process.platform === "win32" }, (t) => {
|
|
1854
|
+
const f = fixture(t);
|
|
1855
|
+
const probe = join(f.root, "pi-from-gentle-ai.txt");
|
|
1856
|
+
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1857
|
+
writeFileSync(gentleAiScript, ["#!/usr/bin/env node", "import { spawnSync } from 'node:child_process';", "import { writeFileSync } from 'node:fs';",
|
|
1858
|
+
"const pi = spawnSync('pi', ['--version'], { encoding: 'utf8' });",
|
|
1859
|
+
`writeFileSync(${JSON.stringify(probe)}, JSON.stringify({ status: pi.status, error: pi.error?.code ?? null, stdout: pi.stdout }));`,
|
|
1860
|
+
"process.exit(0);", ""].join("\n"), { mode: 0o755 });
|
|
1861
|
+
// No `pi` anywhere on the user's PATH: only node and the system tools.
|
|
1862
|
+
const temp = join(f.root, "tmp");
|
|
1863
|
+
mkdirSync(temp);
|
|
1864
|
+
const env = { ...f.env, TMPDIR: temp, PATH: [dirname(process.execPath), "/usr/bin", "/bin"].join(":"), GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_GENTLE_AI_PIN: "3.6.0" };
|
|
1865
|
+
|
|
1866
|
+
const result = run(env, ["setup"]);
|
|
1867
|
+
assert.equal(result.status, 0, result.stderr);
|
|
1868
|
+
assert.deepEqual(JSON.parse(readFileSync(probe, "utf8")), { status: 0, error: null, stdout: "1.2.0\n" });
|
|
1869
|
+
// The launcher is temporary: nothing is left behind in the temp folder it used.
|
|
1870
|
+
assert.deepEqual(readdirSync(temp), []);
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1873
|
+
test("setup without a usable temp folder runs as before, without the temporary pi", { skip: process.platform === "win32" }, (t) => {
|
|
1874
|
+
const f = fixture(t);
|
|
1875
|
+
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1876
|
+
writeGentleAiScriptCountingRuns(gentleAiScript, join(f.root, "runs.log"));
|
|
1877
|
+
const env = { ...f.env, TMPDIR: join(f.root, "missing-tmp"), GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_GENTLE_AI_PIN: "3.6.0" };
|
|
1878
|
+
const result = run(env, ["setup"]);
|
|
1879
|
+
assert.equal(result.status, 0, result.stderr);
|
|
1880
|
+
assert.doesNotMatch(result.stderr, /mkdtemp|gentle-shell-pi-/);
|
|
1881
|
+
});
|
|
1882
|
+
|
|
1883
|
+
test("a successful manual setup records the isolated home, so the first launch does not set it up again", (t) => {
|
|
1884
|
+
const f = fixture(t);
|
|
1885
|
+
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1886
|
+
const counterPath = join(f.root, "gentle-ai-runs.log");
|
|
1887
|
+
writeGentleAiScriptCountingRuns(gentleAiScript, counterPath);
|
|
1888
|
+
const env = enableAutoProvision({ ...f.env, GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_GENTLE_AI_PIN: "3.6.0" });
|
|
1889
|
+
|
|
1890
|
+
const setup = run(env, ["setup"]);
|
|
1891
|
+
assert.equal(setup.status, 0, setup.stderr);
|
|
1892
|
+
const config = JSON.parse(readFileSync(join(f.home, ".gentle-shell", "config.json"), "utf8"));
|
|
1893
|
+
const homeKey = realpathSync(f.gentleShellHome);
|
|
1894
|
+
assert.equal(config.provisioned[homeKey].gentleAi, "3.6.0");
|
|
1895
|
+
assert.equal(config.provisioned[homeKey].gentlePi, ownGentlePiVersion());
|
|
1896
|
+
|
|
1897
|
+
const launch = run(env, ["--mode", "rpc"]);
|
|
1898
|
+
assert.equal(launch.status, 0, launch.stderr);
|
|
1899
|
+
assert.doesNotMatch(launch.stderr, /first run in/);
|
|
1900
|
+
assert.equal(readFileSync(counterPath, "utf8").trim().split("\n").length, 1, "gentle-ai ran only for the manual setup");
|
|
1901
|
+
});
|
|
1902
|
+
|
|
1903
|
+
test("manual setup records nothing for a dry run, a failed setup or pi's own default agent home", (t) => {
|
|
1904
|
+
const f = fixture(t);
|
|
1905
|
+
const configPath = join(f.home, ".gentle-shell", "config.json");
|
|
1906
|
+
const provisioned = () => (existsSync(configPath) ? JSON.parse(readFileSync(configPath, "utf8")).provisioned ?? {} : {});
|
|
1907
|
+
const gentleAiScript = join(f.root, "fake-gentle-ai.mjs");
|
|
1908
|
+
const failingScript = join(f.root, "failing-gentle-ai.mjs");
|
|
1909
|
+
writeGentleAiScriptCountingRuns(gentleAiScript, join(f.root, "runs.log"));
|
|
1910
|
+
writeGentleAiScriptCountingRuns(failingScript, join(f.root, "failed-runs.log"), 3);
|
|
1911
|
+
const env = { ...f.env, PI_CODING_AGENT_DIR: undefined, GENTLE_SHELL_GENTLE_AI_BIN: gentleAiScript, GENTLE_SHELL_GENTLE_AI_PIN: "3.6.0" };
|
|
1912
|
+
|
|
1913
|
+
assert.equal(run(env, ["setup", "--dry-run"]).status, 0);
|
|
1914
|
+
assert.deepEqual(provisioned(), {}, "dry run");
|
|
1915
|
+
assert.notEqual(run({ ...env, GENTLE_SHELL_GENTLE_AI_BIN: failingScript }, ["setup"]).status, 0);
|
|
1916
|
+
assert.deepEqual(provisioned(), {}, "failed setup");
|
|
1917
|
+
const defaultPiHome = join(f.home, ".pi", "agent");
|
|
1918
|
+
const own = run(env, ["--home", defaultPiHome, "setup"]);
|
|
1919
|
+
assert.equal(own.status, 0, own.stderr);
|
|
1920
|
+
assert.deepEqual(provisioned(), {}, "pi's own default agent home is never recorded, so it is never auto-provisioned later");
|
|
1921
|
+
});
|
|
1922
|
+
|
|
1679
1923
|
test("a --home equal to pi's own default agent home is never auto-provisioned, even when empty", (t) => {
|
|
1680
1924
|
const f = fixture(t);
|
|
1681
1925
|
const defaultPiHome = join(f.home, ".pi", "agent");
|
|
@@ -1927,7 +2171,7 @@ test("a hung 'pi remove' during post-install cleanup is killed after the timeout
|
|
|
1927
2171
|
[
|
|
1928
2172
|
"#!/usr/bin/env node",
|
|
1929
2173
|
"const args = process.argv.slice(2);",
|
|
1930
|
-
'if (args.includes("--version")) { console.log("
|
|
2174
|
+
'if (args.includes("--version")) { console.log("1.2.0"); process.exit(0); }',
|
|
1931
2175
|
"if (args[0] === 'remove') { await new Promise((resolve) => setTimeout(resolve, 60000)); process.exit(0); }",
|
|
1932
2176
|
"console.log(JSON.stringify({ args, PI_CODING_AGENT_DIR: process.env.PI_CODING_AGENT_DIR }));",
|
|
1933
2177
|
"process.exit(0);",
|
|
@@ -2942,7 +3186,7 @@ function writeHandoffPiScript(path: string, exitCode = 0) {
|
|
|
2942
3186
|
"#!/usr/bin/env node",
|
|
2943
3187
|
"const { writeFileSync } = require('node:fs');",
|
|
2944
3188
|
"const args = process.argv.slice(2);",
|
|
2945
|
-
"if (args.includes('--version')) { console.log('
|
|
3189
|
+
"if (args.includes('--version')) { console.log('1.2.0'); process.exit(0); }",
|
|
2946
3190
|
"const handoff = process.env.GENTLE_SHELL_RESUME_HANDOFF;",
|
|
2947
3191
|
"if (handoff) writeFileSync(handoff, JSON.stringify({ sessionId: 'abc' }));",
|
|
2948
3192
|
"if (process.env.PI_STUB_PRINT_ENV) console.log(JSON.stringify({ args, handoff }));",
|
|
@@ -3043,7 +3287,7 @@ function writeWaitingPiScript(path: string) {
|
|
|
3043
3287
|
[
|
|
3044
3288
|
"#!/usr/bin/env node",
|
|
3045
3289
|
"const { writeFileSync } = require('node:fs');",
|
|
3046
|
-
"if (process.argv.includes('--version')) { console.log('
|
|
3290
|
+
"if (process.argv.includes('--version')) { console.log('1.2.0'); process.exit(0); }",
|
|
3047
3291
|
"writeFileSync(process.env.GENTLE_SHELL_RESUME_HANDOFF, JSON.stringify({ sessionId: 'abc' }));",
|
|
3048
3292
|
"const quit = () => { process.stdout.write('To resume this session: pi --session abc\\n'); process.exit(0); };",
|
|
3049
3293
|
"process.on('SIGHUP', quit);",
|
|
@@ -3085,7 +3329,7 @@ test("on a TTY a cross-project session resumes by its session file", { skip: !ha
|
|
|
3085
3329
|
[
|
|
3086
3330
|
"#!/usr/bin/env node",
|
|
3087
3331
|
"const { writeFileSync } = require('node:fs');",
|
|
3088
|
-
"if (process.argv.includes('--version')) { console.log('
|
|
3332
|
+
"if (process.argv.includes('--version')) { console.log('1.2.0'); process.exit(0); }",
|
|
3089
3333
|
`writeFileSync(process.env.GENTLE_SHELL_RESUME_HANDOFF, JSON.stringify({ sessionId: 'abc', sessionFile: ${JSON.stringify(sessionFile)} }));`,
|
|
3090
3334
|
"process.stdout.write('To resume this session: pi --session abc\\n');",
|
|
3091
3335
|
"",
|