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
|
@@ -9,45 +9,61 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
## Activation Contract
|
|
11
11
|
|
|
12
|
-
Load this skill when a planned PR may exceed **400 changed lines**,
|
|
12
|
+
Load this skill when a planned PR may exceed **400 changed lines**, an ODD feature's forecast or running authored changed-line count from work-unit commits exceeds about 400, or the user asks for chained/stacked PRs, review slices, or reviewer-load control. The per-task advisory 400 authored-line heuristic does not itself require a PR split.
|
|
13
13
|
|
|
14
14
|
## Hard Rules
|
|
15
15
|
|
|
16
|
-
-
|
|
16
|
+
- Recommend slicing PRs over **400 changed lines**; offer the ordered oversized-delivery menu below and follow the user's selection subject to the destination repository's documented contribution/size policy.
|
|
17
|
+
- `size:exception` is a Gentle-owned repository policy, not a universal label requirement. Never request, create, or add this label for generic users unless the destination policy uses it. Preserve that policy's maintainer acceptance gates and protected-label human authorization; selection alone grants neither.
|
|
17
18
|
- The budget constrains how work is **sliced**, never the code itself. Never delete comments, blank lines, docs, or tests, and never compress or restyle code, to fit under the budget.
|
|
18
|
-
- Slicing is bounded: make **one** honest slicing pass. If no cohesive split brings every slice within budget, stop iterating, keep the best cohesive split, and report the final line count
|
|
19
|
+
- Slicing is bounded: make **one** honest slicing pass. If no cohesive split brings every slice within budget, stop iterating, keep the best cohesive split, and report the final line count and rationale. Recommend a size exception only when the destination policy provides that route.
|
|
19
20
|
- Keep each PR reviewable in about **≤60 minutes**.
|
|
20
|
-
-
|
|
21
|
+
- In a chain, use one deliverable work unit per PR; keep tests/docs with the unit they verify. A selected single PR may contain multiple coherent work-unit commits.
|
|
21
22
|
- State start, end, prior dependencies, follow-up work, and out-of-scope items in every chained PR.
|
|
22
23
|
- Every child PR must include a dependency diagram marking the current PR with `📍`.
|
|
23
24
|
- In Feature Branch Chain, create a draft/no-merge tracker PR; child PR #1 targets the tracker branch, later children target the immediate parent branch.
|
|
24
25
|
- Treat polluted diffs as base bugs: retarget or rebase until only the current work unit appears.
|
|
25
26
|
- Do not mix chain strategies after the user chooses one.
|
|
27
|
+
- Before creating branches or PRs, verify the target repository's default branch; use it as the integration base, not an assumed `main`. `stacked-to-main` is the historical strategy token even when the default branch has another name.
|
|
28
|
+
|
|
29
|
+
## Oversized Delivery Menu
|
|
30
|
+
|
|
31
|
+
Offer exactly three choices in this semantic order; English examples are illustrative and localizable, not mandatory copy. Generate the complete user-facing question, every option label, description, and recommendation marker in the active user's conversation language (English for an English user, Spanish for a Spanish user, etc.). Machine strategy tokens remain unchanged and untranslated.
|
|
32
|
+
|
|
33
|
+
1. **Feature/tracker branch chain** — `chain_strategy=feature-branch-chain`; review child slices before final feature integration.
|
|
34
|
+
2. **Verified default/main branch chain** — `chain_strategy=stacked-to-main`; land independently reviewable slices in order on the verified default branch, whatever its name.
|
|
35
|
+
3. **One single PR — least recommended** — `delivery_strategy=single-pr`; keep the entire change in one PR rather than a chain.
|
|
36
|
+
|
|
37
|
+
The third choice overrides the pending chaining path: clear the chain choice as inapplicable and suppress later chain prompts. `single-pr` is not a `chain_strategy` token. Do not automatically select `exception-ok` or imply an accepted policy exception.
|
|
38
|
+
|
|
39
|
+
The least recommended marker applies only to this oversized menu. An oversized single PR increases reviewer cognitive load, slows feedback, and couples rollback of otherwise separable work; a focused single PR within 400 changed lines remains reasonable. Delivery selection does not authorize push, PR creation, merge, or changes to review mode or candidate consent.
|
|
26
40
|
|
|
27
41
|
## Decision Gates
|
|
28
42
|
|
|
29
43
|
| Condition | Action |
|
|
30
44
|
|---|---|
|
|
31
45
|
| PR ≤400 changed lines and focused | Keep single PR. |
|
|
32
|
-
| PR >400, each slice can land independently |
|
|
33
|
-
| PR >400, feature must integrate before
|
|
34
|
-
| Generated/vendor/migration diff cannot split cleanly |
|
|
35
|
-
| No cohesive split fits the budget after one slicing pass | Stop;
|
|
36
|
-
|
|
|
37
|
-
| ODD
|
|
46
|
+
| PR >400, each slice can land independently | Recommend Stacked PRs to the verified default branch; respect the selected delivery strategy. |
|
|
47
|
+
| PR >400, feature must integrate before the default branch | Recommend Feature Branch Chain with tracker; respect the selected delivery strategy. |
|
|
48
|
+
| Generated/vendor/migration diff cannot split cleanly | Report the overage; follow destination policy for any required exception. |
|
|
49
|
+
| No cohesive split fits the budget after one slicing pass | Stop slicing; report the best cohesive split and why it cannot shrink further, then apply the selected delivery strategy and destination policy. |
|
|
50
|
+
| ODD `delivery_strategy` is `ask-on-risk` | When the budget is exceeded, ask once using the menu above for a chain strategy or single PR before the next work-unit commit. |
|
|
51
|
+
| ODD `delivery_strategy` is `auto-chain` | Ask for a chain strategy only when missing; otherwise use the cached choice. |
|
|
52
|
+
| ODD `delivery_strategy` is `single-pr` | Follow the destination repository's documented contribution/size policy for the overage; do not ask for a chain strategy. |
|
|
53
|
+
| ODD `delivery_strategy` is `exception-ok` | Record the explicitly accepted exception under destination policy, including `size:exception` only where applicable; do not ask for a chain strategy. |
|
|
38
54
|
|
|
39
55
|
## Execution Steps
|
|
40
56
|
|
|
41
57
|
1. Estimate changed lines and identify independent work units.
|
|
42
|
-
2.
|
|
43
|
-
3.
|
|
44
|
-
4.
|
|
58
|
+
2. Apply the delivery-strategy gate above; offer the menu only on a chaining path that needs a choice. For `auto-chain`, use a cached chain strategy without prompting again; if missing, offer all three choices.
|
|
59
|
+
3. Verify the target repository's default branch before creating branches/PRs; use the chosen strategy only.
|
|
60
|
+
4. On chaining paths only, add Chain Context to each child PR without replacing the repo PR template.
|
|
45
61
|
5. Verify each PR independently: CI/tests/docs/manual checks, rollback scope, and clean diff.
|
|
46
|
-
6.
|
|
62
|
+
6. For Feature Branch Chain only, keep tracker PR draft/no-merge until all child PRs are reviewed and integrated.
|
|
47
63
|
|
|
48
64
|
## Output Contract
|
|
49
65
|
|
|
50
|
-
Return the chosen strategy, PR order, current PR boundary, dependency diagram
|
|
66
|
+
Return the chosen delivery strategy, review budget (`additions + deletions`), scope, verification plan, and any destination-policy exception rationale. For chaining, also return PR order, current PR boundary, and dependency diagram. For `single-pr`, require no tracker, child dependency diagram, or Chain Context; use the destination PR template without chain-only artifacts.
|
|
51
67
|
|
|
52
68
|
## References
|
|
53
69
|
|
|
@@ -2,19 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## Strategy Notes
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
|
10
|
-
|
|
5
|
+
Before creating branches or PRs, verify the target repository's default branch and use it as `<default branch>` throughout these examples. Do not infer it from the current local branch. The historical strategy token `stacked-to-main` means stacking onto that verified default branch, even when its name is not `main`.
|
|
6
|
+
|
|
7
|
+
The oversized menu has exactly three outcomes in the order below. English examples are illustrative and localizable, not mandatory copy. Generate the complete user-facing question, every option label, description, and recommendation marker in the active user's conversation language (English for an English user, Spanish for a Spanish user, etc.). Machine strategy tokens remain unchanged and untranslated.
|
|
8
|
+
|
|
9
|
+
| Ordered outcome | Feature/tracker branch chain | Default/main branch chain | One single PR — least recommended |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| Mapping | `chain_strategy=feature-branch-chain` | `chain_strategy=stacked-to-main` | `delivery_strategy=single-pr` |
|
|
12
|
+
| Speed | Full feature waits for tracker merge | Each slice can ship in order | All feedback and delivery wait on one large review |
|
|
13
|
+
| Rollback | Revert/hold the whole feature branch | Revert individual merged PRs | Revert the combined change |
|
|
14
|
+
| Risk | Nothing lands until the chain completes | Partial behavior may land | Higher reviewer load and coupled scope |
|
|
15
|
+
| Complexity | Requires tracker and strict diff hygiene | Retarget/rebase after parent merges | No chain artifacts, but harder review isolation |
|
|
16
|
+
|
|
17
|
+
Selecting single PR overrides the pending chaining path: clear the chain choice as inapplicable and suppress later chain prompts. It is not a chain strategy and does not select `exception-ok`. Least recommended applies only to this oversized menu; focused ≤400-line single PRs remain reasonable. Use the destination PR template with scope, changed-line count, verification, and any applicable exception rationale; do not require a tracker, child dependency diagram, or Chain Context.
|
|
18
|
+
|
|
19
|
+
Follow the destination repository's documented contribution/size policy. `size:exception` is a Gentle-owned repository policy, not a universal label requirement. Never request, create, or add the label for generic users unless the destination policy uses it. Preserve applicable maintainer acceptance and protected-label authorization. Delivery selection does not authorize push, PR creation, merge, or review-mode/consent changes.
|
|
11
20
|
|
|
12
21
|
## Feature Branch Chain
|
|
13
22
|
|
|
14
23
|
Use when the feature branch accumulates the final integration while child PRs are reviewed as focused slices.
|
|
15
24
|
|
|
16
25
|
```text
|
|
17
|
-
|
|
26
|
+
<default branch>
|
|
18
27
|
└── feat/my-feature ← tracker/final integration branch
|
|
19
28
|
↑ PR #1 base: feat/my-feature
|
|
20
29
|
└── feat/my-feature-01-core
|
|
@@ -26,27 +35,27 @@ main
|
|
|
26
35
|
|
|
27
36
|
Steps:
|
|
28
37
|
|
|
29
|
-
1. Create the feature/tracker branch from
|
|
30
|
-
2. Open the tracker PR to
|
|
38
|
+
1. Create the feature/tracker branch from the verified `<default branch>`.
|
|
39
|
+
2. Open the tracker PR to `<default branch>`; mark it draft/no-merge.
|
|
31
40
|
3. Create PR #1 from a child branch and target it to the tracker branch.
|
|
32
41
|
4. Create each later child branch from the previous PR branch and target it to that parent branch.
|
|
33
42
|
5. Merge/integrate children in order; merge the tracker only after the chain is complete.
|
|
34
43
|
|
|
35
|
-
## Stacked PRs to
|
|
44
|
+
## Stacked PRs to Default Branch
|
|
36
45
|
|
|
37
|
-
Use when each slice can land on
|
|
46
|
+
Use when each slice can land on the verified `<default branch>` in order.
|
|
38
47
|
|
|
39
48
|
```text
|
|
40
|
-
|
|
49
|
+
<default branch> <- PR 1: foundation
|
|
41
50
|
└── PR 2: feature slice built on PR 1
|
|
42
51
|
└── PR 3: docs/tests built on PR 2
|
|
43
52
|
```
|
|
44
53
|
|
|
45
|
-
After a parent PR merges, rebase/retarget the next PR so GitHub shows only the current slice.
|
|
54
|
+
Base PR #1 on the verified `<default branch>`; base each subsequent PR on its immediate parent until that parent merges. After a parent PR merges, rebase/retarget the next PR so GitHub shows only the current slice.
|
|
46
55
|
|
|
47
56
|
## Chain Context Section
|
|
48
57
|
|
|
49
|
-
|
|
58
|
+
On chaining paths only, append this section to the repo PR template; do not replace required issue/checklist sections. Skip this entire section for a single PR.
|
|
50
59
|
|
|
51
60
|
```markdown
|
|
52
61
|
## Chain Context
|
|
@@ -66,7 +75,7 @@ Append this section to the repo PR template; do not replace required issue/check
|
|
|
66
75
|
### Chain Overview
|
|
67
76
|
|
|
68
77
|
```text
|
|
69
|
-
|
|
78
|
+
<default branch>
|
|
70
79
|
└── #NNN Previous PR
|
|
71
80
|
└── 📍 #NNN This PR
|
|
72
81
|
└── #NNN Next PR
|
|
@@ -85,15 +94,17 @@ main
|
|
|
85
94
|
|
|
86
95
|
## Commands
|
|
87
96
|
|
|
97
|
+
Before any remote read or PR creation, require explicit human authorization for the destination (exact host/repository), operation (PR read or creation), and credential/session. Do not probe credentials or remote targets to resolve ambiguity. Verify the target repository and its default branch using only the authorized session and destination; set `TARGET` to that verified host/repository. Stop if authorization or verification is missing. Each command below binds to that same verified target; the base branches must belong to it.
|
|
98
|
+
|
|
88
99
|
```bash
|
|
89
|
-
gh pr view <PR_NUMBER> --json additions,deletions,changedFiles,title,url
|
|
90
|
-
gh pr create --base feat/my-feature --title "feat(scope): focused slice" --body-file pr-body.md
|
|
91
|
-
gh pr create --base feat/my-feature-01-core --title "feat(scope): next focused slice" --body-file pr-body.md
|
|
100
|
+
gh pr view <PR_NUMBER> --repo "$TARGET" --json additions,deletions,changedFiles,title,url
|
|
101
|
+
gh pr create --repo "$TARGET" --base feat/my-feature --title "feat(scope): focused slice" --body-file pr-body.md
|
|
102
|
+
gh pr create --repo "$TARGET" --base feat/my-feature-01-core --title "feat(scope): next focused slice" --body-file pr-body.md
|
|
92
103
|
```
|
|
93
104
|
|
|
94
105
|
## Reviewer Guidance
|
|
95
106
|
|
|
96
|
-
-
|
|
97
|
-
- Recommend Feature Branch Chain when work must integrate before
|
|
107
|
+
- Recommend a split when a PR exceeds 400 changed lines; respect the selected delivery shape and enforce only the destination's documented size/exception policy.
|
|
108
|
+
- Recommend Feature Branch Chain when work must integrate before the verified `<default branch>`.
|
|
98
109
|
- Recommend stacked PRs when each slice can merge independently.
|
|
99
110
|
- Review child PRs against immediate parent branches; a polluted diff is a branching bug.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gentle-ai
|
|
3
|
-
description: "Use Gentle AI harness discipline for Pi work: clarify first,
|
|
3
|
+
description: "Use Gentle AI harness discipline for Pi work: clarify first, track ODD work, use applicable test-first development by default, delegate when useful, and protect review workload."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# el Gentleman Harness
|
|
7
7
|
|
|
8
|
-
Use this skill
|
|
8
|
+
Use this skill for non-trivial, risky, or multi-step ODD work.
|
|
9
9
|
|
|
10
10
|
## Identity Rule
|
|
11
11
|
|
|
12
|
-
When asked who or what you are, answer as el Gentleman: a Pi-specific coding-agent harness with senior architect persona,
|
|
12
|
+
When asked who or what you are, answer as el Gentleman: a Pi-specific coding-agent harness with senior architect persona, ODD by default, and subagent coordination. Do not answer as a generic assistant.
|
|
13
13
|
|
|
14
14
|
## Compact Rules
|
|
15
15
|
|
|
16
16
|
- Clarify scope, constraints, acceptance criteria, and non-goals before implementation.
|
|
17
|
-
-
|
|
18
|
-
-
|
|
17
|
+
- Size every task by the orchestrator's Task Size section: understood, contained risk, and resumable from the original request plus `git diff`. Counts of files, commands, tests, or fixes never decide it. Track only large work in its task document and mirror.
|
|
18
|
+
- For behavior changes with applicable runnable deterministic tests and a clear expected outcome, use test-first by default: observe RED, GREEN, relevant alternate cases, then REFACTOR and record evidence. Test presence alone does not establish applicability. For passive documentation, non-testable changes, an unavailable runner, or no meaningful RED, state why and run proportionate ordinary functional or structural verification. Never invent RED/GREEN, skip checks, or require a chat/TUI toggle.
|
|
19
19
|
- Keep one parent session responsible for orchestration; child subagents should receive concrete phase work and must not spawn more subagents.
|
|
20
|
-
- Parent-only delegation triggers
|
|
21
|
-
-
|
|
20
|
+
- Parent-only delegation triggers fire one mechanism at a time: an open decision (ask), understanding beyond the evidence budget (explore), high risk (independent verifier), a large task (track), a writer reason (parallel units or context), tooling/worktree incidents, or a parent context past the context backstop.
|
|
21
|
+
- Parallel writers only with disjoint Allowed edit surfaces (runtime-enforced) or isolated worktrees.
|
|
22
22
|
- Forecast review workload before large changes; ask before producing oversized or multi-area diffs.
|
|
23
23
|
- Keep dangerous-command safety independent and authoritative.
|
|
24
24
|
- Never claim persistent memory is available because of el Gentleman itself; memory is provided by separate packages/tools when active.
|
|
@@ -30,29 +30,24 @@ When asked who or what you are, answer as el Gentleman: a Pi-specific coding-age
|
|
|
30
30
|
Use the smallest safe harness:
|
|
31
31
|
|
|
32
32
|
```text
|
|
33
|
-
small
|
|
34
|
-
|
|
35
|
-
large
|
|
33
|
+
small task → inline direct, focused test and suite inline
|
|
34
|
+
understanding is missing → explore, then re-evaluate
|
|
35
|
+
large authorized work → track ODD tasks and implement by work unit
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
For
|
|
38
|
+
For large implementation with subagents:
|
|
39
39
|
|
|
40
40
|
```text
|
|
41
|
-
clarify →
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
For bounded implementation with subagents:
|
|
45
|
-
|
|
46
|
-
```text
|
|
47
|
-
clarify → scout/context-builder when context-heavy → one worker → verify
|
|
41
|
+
clarify → scout/context-builder when context-heavy → inline, or a writer only for a reason → verify
|
|
48
42
|
```
|
|
49
43
|
|
|
50
44
|
Hard delegation triggers:
|
|
51
45
|
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
46
|
+
- **Evidence-budget rule**: read inline only when the evidence fits one parallel batch of at most 3 calls, ~10k tokens (grep and line ranges, never whole large files). When understanding needs more reading or more than ~5 sequential lookups, delegate one explorer that returns a handoff of at most ~2k tokens with `path:line` evidence. Never force delegation for a small targeted question; do not re-read what the handoff covered beyond one spot check.
|
|
47
|
+
- **Writer rule**: a writer only for a reason (parallel units launched together, or context); size and file count never fire it.
|
|
48
|
+
- **Verification rule**: a high-risk change gets an independent verifier; otherwise the change's own focused test and suite run inline.
|
|
54
49
|
- **Incident rule**: after wrong cwd, accidental worktree/repo mutation, merge recovery, confusing test command, or environment workaround, diagnose separately.
|
|
55
|
-
- **
|
|
50
|
+
- **Context backstop**: when the parent context passes ~150k tokens, pause and delegate the next bounded unit of work to a non-review subagent. Keep command output bounded (counts, `--stat`, `tail`).
|
|
56
51
|
|
|
57
52
|
## Review Lens Selection
|
|
58
53
|
|
|
@@ -15,7 +15,9 @@ Discover the target repository's contribution workflow before proposing or publi
|
|
|
15
15
|
|
|
16
16
|
## Safe Discovery
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Before any `gh auth status` or target read, require explicit human authorization for the remote destination (exact host and repository), operation (including discovery and intended issue creation), and credential/session to use. A local checkout is not authorization. If any is missing or ambiguous, stop locally; never probe credentials or sessions to resolve ambiguity. Run the checks below only with the authorized credential/session against the authorized destination; if `gh auth status` would inspect other credentials/sessions, do not run it. Verify the discovered `REPO`, `HOST`, and `TARGET` match the authorized destination before continuing; never switch identities or targets implicitly.
|
|
19
|
+
|
|
20
|
+
After that gate, run read-only checks:
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
23
|
gh auth status
|
|
@@ -31,6 +33,8 @@ gh api --hostname "$HOST" --paginate "repos/$REPO/labels?per_page=100" --jq '.[]
|
|
|
31
33
|
|
|
32
34
|
Inspect `README.md`, contribution instructions, `.github/ISSUE_TEMPLATE/config.yml` contact links, forms, labels, and open and closed issues. For questions/support, follow repository-prescribed Discussions/contact routing when available; otherwise ask or stop. Complete target verification for `REPO`, `HOST`, and `TARGET`. Fail closed before mutation when authentication, target verification, issue availability, policy, form selection, or required metadata is missing or ambiguous. A blank fallback is allowed only when `isBlankIssuesEnabled` is explicitly true.
|
|
33
35
|
|
|
36
|
+
Before building `LABEL_ARGS`, inspect labels declared by the selected YAML form as well as any manually selected labels. Treat `status:approved`, `size:exception`, and any repository-protected label as protected form labels at create-time. Include a protected label only with a current, exact label-specific direct human instruction for this target and creation action, authenticated actor target-host `viewerPermission` of `MAINTAIN` or `ADMIN`, and repository policy permission; do not infer authority from YAML, a publication request, or local credentials. If this proof is missing, skip the protected label only when the form and repository policy permit omitting it; if the protected label is required, fail closed without creating the issue. Do not replace it with another label or use a write to probe permission. For `size:exception`, also require the current human-approved rationale; if recording it needs an unauthorized extra action, stop. This create-time gate does not change post-publication actions.
|
|
37
|
+
|
|
34
38
|
Build `LABEL_ARGS` only from reviewed labels that exist and policy permits the actor to apply:
|
|
35
39
|
|
|
36
40
|
```bash
|
|
@@ -104,6 +108,8 @@ gh issue view "$NUMBER" --repo "$TARGET" --json number,url,title,body,state,labe
|
|
|
104
108
|
|
|
105
109
|
Confirm that read-back identifies the target-host issue and that title and body match after only CRLF-to-LF and trailing-final-newline normalization. Report `confirmed` only after this target-host read-back. Otherwise report `no_write` when an authoritative rejection proves no issue was created, or `unknown` and stop all later mutations.
|
|
106
110
|
|
|
107
|
-
## Triage
|
|
111
|
+
## Triage And Later Actions
|
|
108
112
|
|
|
109
113
|
Before approving or closing an issue, verify it is concrete, non-duplicate, sufficiently evidenced, in scope, and consistent with repository label/status policy. If any point is uncertain, retain the repository review state and request the smallest missing evidence.
|
|
114
|
+
|
|
115
|
+
For any post-publication label/status mutation, follow [delegated workflow actions](references/delegated-workflow-actions.md). Publication is not authorization for a later action. Keep the automated YAML Form path and conditional blank/browser fallback above unchanged.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Delegated post-publication issue/PR actions
|
|
2
|
+
|
|
3
|
+
This guidance applies after publication only. Remote work still requires separate authorization for destination, operation, and credential/session; this document grants none. Keep the YAML Issue Form, conditional blank fallback, and browser handoff in the creation workflow unchanged.
|
|
4
|
+
|
|
5
|
+
## Authority and capability
|
|
6
|
+
|
|
7
|
+
- Require a current direct human instruction binding exact `HOST`, `REPO`, issue-or-PR number, and action, including exact labels to add/remove or the status transition. Never infer these from generated plans, issue text, memory, or a prior publication. Stop when the instruction is missing or ambiguous.
|
|
8
|
+
- Before any mutation, verify the authenticated actor, target host/repository, object type and number, existing labels, and repository policy through target-host reads. Do not switch hosts or identities to gain permission; a local credential alone proves nothing about the target.
|
|
9
|
+
- For protected labels (`status:approved`, `size:exception`, and any repository-protected label), require the authenticated actor's target-host `viewerPermission` to be `MAINTAIN` or `ADMIN` and the direct instruction above. There is no separate target-host proof of the instruction-giver's identity. If permission is unavailable, insufficient, or policy disallows the action, stop without probing capability through a write.
|
|
10
|
+
- For unprotected labels, require that each exact label already exists and that the authenticated actor may apply it under repository policy. Do not create, rename, or substitute a label. A comment, closure, body edit, or unrelated label change requires its own direct instruction.
|
|
11
|
+
|
|
12
|
+
## One bounded action
|
|
13
|
+
|
|
14
|
+
1. Pre-read the exact target-host object, including identity, state, relevant title/body and all labels, plus the existing-label list and actor permission. Check the proposed transition against policy; if already satisfied, report a no-op. For approval, establish concrete, non-duplicate, sufficiently evidenced, in-scope findings first; uncertainty preserves the review state. For `size:exception`, require a current human-approved rationale for the exception and preserve its meaning in the intended record. Never infer approval or rationale from diff size. The roughly 400-line review heuristic is advisory, not authorization to apply the label.
|
|
15
|
+
2. Build only the instructed existing-label changes. A `status:approved` transition must be an atomic update removing observed conflicting status labels and adding `status:approved`, without dropping unrelated labels or exposing an intermediate status. Stop if the target-host API cannot guarantee that update or concurrent state has changed. If recording the `size:exception` rationale requires an additional unauthorized action, stop and seek a scoped instruction instead of silently posting it.
|
|
16
|
+
3. Immediately before posting text, scan and redact the exact text for credentials, private project names, usernames, hostnames, home paths, and private addresses. Use a verified target-host API that supports the intended action, not a guessed CLI sequence. Make one mutation attempt; never retry timeouts or uncertain responses.
|
|
17
|
+
4. Post-read the same target-host object once and compare its identity and requested labels/status against the pre-read, including preservation of unrelated labels. Report `confirmed` only after an unambiguous matching target-host post-readback, `no_write` only after authoritative rejection proving no write, or `unknown` for a timeout, missing identity, conflict, or failed/ambiguous readback. On `unknown`, stop all further mutations; command output alone cannot establish success.
|
|
18
|
+
|
|
19
|
+
Report the exact target/action, actor capability evidence, pre/post-readback outcome, and exception rationale when applicable without leaking private text. Operational checkboxes in the publication form may be marked only from retained agent evidence; personal, legal and user-consent declarations require explicit first-person user affirmation, never a delegated label action or the publication request. For implementation work leading to an issue or PR, retain the applicable ODD default and test-first checks; this action guide does not replace them.
|
|
@@ -30,7 +30,7 @@ Use it for:
|
|
|
30
30
|
| Keep docs with the user-visible change | Docs belong with the feature or workflow they explain. |
|
|
31
31
|
| Tell a story | A reviewer should understand why each commit exists from its diff and message. |
|
|
32
32
|
| Future PR-ready | Each commit should be a candidate chained PR when the change grows. |
|
|
33
|
-
| SDD workload guard | If SDD tasks forecast a >400-line change, group commits into chained PR slices before implementation. |
|
|
33
|
+
| SDD workload guard | If SDD tasks forecast a >400-line change, honor the selected `delivery_strategy`. On chaining paths only, group commits into chained PR slices before implementation. For explicit `single-pr` or `exception-ok`, keep one PR, report the review load, and follow the destination repository's documented contribution/size policy; selection alone does not accept an exception. |
|
|
34
34
|
| Budget is not code-golf | Never shrink a diff by deleting comments, blank lines, docs, or tests, or by compressing code, to fit the review budget (400 by default, or the session `review_budget_lines`). Slice by work unit or report the overage. |
|
|
35
35
|
|
|
36
36
|
## Work Unit Checklist
|
|
@@ -67,8 +67,9 @@ When `sdd-tasks` produces a Review Workload Forecast:
|
|
|
67
67
|
|
|
68
68
|
- Low risk: keep work-unit commits inside one PR.
|
|
69
69
|
- Medium risk: commit by work unit and monitor changed lines before PR creation.
|
|
70
|
-
- High risk: follow SDD `delivery_strategy` — ask on `ask-on-risk`, auto-slice on `auto-chain`,
|
|
71
|
-
-
|
|
70
|
+
- High risk: follow SDD `delivery_strategy` — ask on `ask-on-risk`, auto-slice with the cached chain choice on `auto-chain`, follow the destination repository's documented contribution/size policy on over-budget `single-pr`, or record an explicitly accepted policy exception on `exception-ok`. A single-PR selection does not itself accept an exception.
|
|
71
|
+
- `size:exception` is a Gentle-owned repository policy, not a universal label requirement. Never request, create, or add the label for generic users unless the destination policy uses it; preserve its maintainer acceptance and protected-label authorization gates.
|
|
72
|
+
- Splitting is bounded: after one honest slicing pass, if no cohesive work-unit split fits the budget, stop and report the smallest honest count and rationale. Recommend an exception only where destination policy provides it. Do not iterate shrinking the code to reach the number.
|
|
72
73
|
|
|
73
74
|
Each SDD work unit should map cleanly to a commit or PR with:
|
|
74
75
|
|
package/tests/agent-home.test.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { mkdtempSync, realpathSync, rmSync } from "node:fs";
|
|
3
3
|
import { homedir, tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import test from "node:test";
|
|
6
|
-
import { gentlePiConfigHome } from "../lib/agent-home.ts";
|
|
6
|
+
import { bundledGentlePiAgentHome, gentlePiConfigHome } from "../lib/agent-home.ts";
|
|
7
|
+
import { setBundledInstallForTesting } from "../lib/gentle-shell-bundled.ts";
|
|
7
8
|
|
|
8
9
|
// The two Pi homes: `~/.pi/agent` holds Pi's own agent definitions and
|
|
9
10
|
// `~/.pi/gentle-ai` holds everything the Gentle AI commands own. Both are resolved
|
|
@@ -15,7 +16,9 @@ function isolatedHome(t: test.TestContext): string {
|
|
|
15
16
|
const home = mkdtempSync(join(tmpdir(), "gentle-pi-config-home-"));
|
|
16
17
|
const previousHome = process.env.HOME;
|
|
17
18
|
const previousUserProfile = process.env.USERPROFILE;
|
|
18
|
-
|
|
19
|
+
const previousConfigHome = process.env.GENTLE_PI_CONFIG_HOME;
|
|
20
|
+
// Clear the higher-priority config override as well as isolating both OS homes.
|
|
21
|
+
delete process.env.GENTLE_PI_CONFIG_HOME;
|
|
19
22
|
process.env.HOME = home;
|
|
20
23
|
process.env.USERPROFILE = home;
|
|
21
24
|
t.after(() => {
|
|
@@ -23,6 +26,8 @@ function isolatedHome(t: test.TestContext): string {
|
|
|
23
26
|
else process.env.HOME = previousHome;
|
|
24
27
|
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
|
|
25
28
|
else process.env.USERPROFILE = previousUserProfile;
|
|
29
|
+
if (previousConfigHome === undefined) delete process.env.GENTLE_PI_CONFIG_HOME;
|
|
30
|
+
else process.env.GENTLE_PI_CONFIG_HOME = previousConfigHome;
|
|
26
31
|
rmSync(home, { recursive: true, force: true });
|
|
27
32
|
});
|
|
28
33
|
return home;
|
|
@@ -41,6 +46,25 @@ test("gentlePiConfigHome honours GENTLE_PI_CONFIG_HOME and otherwise falls back
|
|
|
41
46
|
);
|
|
42
47
|
});
|
|
43
48
|
|
|
49
|
+
test("the isolated home restores defined and undefined config overrides", async (t) => {
|
|
50
|
+
const previousConfigHome = process.env.GENTLE_PI_CONFIG_HOME;
|
|
51
|
+
try {
|
|
52
|
+
for (const inherited of [undefined, "/synthetic-inherited-config"]) {
|
|
53
|
+
if (inherited === undefined) delete process.env.GENTLE_PI_CONFIG_HOME;
|
|
54
|
+
else process.env.GENTLE_PI_CONFIG_HOME = inherited;
|
|
55
|
+
await t.test(`inherited override: ${inherited === undefined ? "unset" : "set"}`, (child) => {
|
|
56
|
+
const home = isolatedHome(child);
|
|
57
|
+
assert.equal(process.env.GENTLE_PI_CONFIG_HOME, undefined);
|
|
58
|
+
assert.equal(gentlePiConfigHome(), join(home, ".pi", "gentle-ai"));
|
|
59
|
+
});
|
|
60
|
+
assert.equal(process.env.GENTLE_PI_CONFIG_HOME, inherited);
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
if (previousConfigHome === undefined) delete process.env.GENTLE_PI_CONFIG_HOME;
|
|
64
|
+
else process.env.GENTLE_PI_CONFIG_HOME = previousConfigHome;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
44
68
|
test("the config home ignores the Pi agent-home overrides", (t) => {
|
|
45
69
|
const home = isolatedHome(t);
|
|
46
70
|
// PI_CODING_AGENT_DIR and GENTLE_PI_AGENT_HOME move Pi's agent directory only.
|
|
@@ -50,3 +74,32 @@ test("the config home ignores the Pi agent-home overrides", (t) => {
|
|
|
50
74
|
join(home, ".pi", "gentle-ai"),
|
|
51
75
|
);
|
|
52
76
|
});
|
|
77
|
+
|
|
78
|
+
// S9: a bundled Gentle Shell keeps gentle-pi's config inside its prefix. It is
|
|
79
|
+
// derived from this package's bundled install and the launcher's
|
|
80
|
+
// GENTLE_SHELL_PREFIX, never exported (Gentle AI 4.0.0 reads
|
|
81
|
+
// GENTLE_PI_CONFIG_HOME as a parent folder). The testing overlay stands in for
|
|
82
|
+
// this package running from that install.
|
|
83
|
+
function bundledInstall(t: test.TestContext): string {
|
|
84
|
+
const prefix = realpathSync(mkdtempSync(join(tmpdir(), "gentle-pi-bundled-config-")));
|
|
85
|
+
setBundledInstallForTesting({ root: prefix });
|
|
86
|
+
t.after(() => {
|
|
87
|
+
setBundledInstallForTesting(undefined);
|
|
88
|
+
rmSync(prefix, { recursive: true, force: true });
|
|
89
|
+
});
|
|
90
|
+
return prefix;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
test("a bundled install derives the config home inside its prefix and the agent home from Pi's", (t) => {
|
|
94
|
+
isolatedHome(t);
|
|
95
|
+
const prefix = bundledInstall(t);
|
|
96
|
+
const env = { GENTLE_SHELL_PREFIX: prefix, GENTLE_PI_CONFIG_HOME: "/home/ana/.pi/gentle-ai", PI_CODING_AGENT_DIR: "/agent" };
|
|
97
|
+
assert.equal(gentlePiConfigHome(env), join(prefix, "config", "gentle-ai"));
|
|
98
|
+
assert.equal(bundledGentlePiAgentHome(env), "/agent");
|
|
99
|
+
// Another prefix, or none, is not this install: everything stays as before.
|
|
100
|
+
for (const other of [{ GENTLE_PI_CONFIG_HOME: "/custom" }, { GENTLE_SHELL_PREFIX: join(prefix, "other"), GENTLE_PI_CONFIG_HOME: "/custom" }]) {
|
|
101
|
+
assert.equal(gentlePiConfigHome(other), "/custom");
|
|
102
|
+
assert.equal(bundledGentlePiAgentHome({ ...other, PI_CODING_AGENT_DIR: "/agent" }), undefined);
|
|
103
|
+
}
|
|
104
|
+
assert.equal(gentlePiConfigHome({ GENTLE_PI_CONFIG_HOME: "" }), join(homedir(), ".pi", "gentle-ai"));
|
|
105
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import test, { after } from "node:test";
|
|
6
|
+
import { resolveAgentHomeDirectory, resolveEffectiveAgentModel, resolvePinnedAgentProfile } from "../lib/agent-model-resolution.ts";
|
|
7
|
+
import type { AgentDefinition } from "../lib/agents-config.ts";
|
|
8
|
+
|
|
9
|
+
// gentle-shell#1731 S3/AC3: the subagent launch and the harness model-routing
|
|
10
|
+
// fact resolve the effective subagent model through one helper, so the fact
|
|
11
|
+
// can never disagree with the model a launch would actually use.
|
|
12
|
+
|
|
13
|
+
const root = mkdtempSync(join(tmpdir(), "gentle-pi-agent-model-resolution-"));
|
|
14
|
+
after(() => rmSync(root, { recursive: true, force: true }));
|
|
15
|
+
|
|
16
|
+
function fixture(name: string) {
|
|
17
|
+
const base = join(root, name);
|
|
18
|
+
const home = join(base, "home");
|
|
19
|
+
const agentHome = join(base, "agent-home");
|
|
20
|
+
const cwd = join(base, "project");
|
|
21
|
+
const commonDir = join(base, "git-common");
|
|
22
|
+
const configHome = join(base, "config");
|
|
23
|
+
for (const dir of [home, join(agentHome, "agents"), cwd, commonDir, configHome]) mkdirSync(dir, { recursive: true });
|
|
24
|
+
return {
|
|
25
|
+
roots: { cwd, home, agentHome },
|
|
26
|
+
cwd,
|
|
27
|
+
configHome,
|
|
28
|
+
resolveWorktree: () => ({ root: cwd, commonDir }),
|
|
29
|
+
writeAgent(agentName: string, model?: string) {
|
|
30
|
+
writeFileSync(join(agentHome, "agents", `${agentName}.md`), `---\nname: ${agentName}\ndescription: Test agent.\n${model === undefined ? "" : `model: ${model}\n`}---\nBody.\n`);
|
|
31
|
+
},
|
|
32
|
+
writeSubagents(config: Record<string, unknown>) {
|
|
33
|
+
writeFileSync(join(agentHome, "subagents.json"), JSON.stringify(config));
|
|
34
|
+
},
|
|
35
|
+
writePinnedProfile(profiles: Record<string, unknown>, pin: string) {
|
|
36
|
+
writeFileSync(join(configHome, "profiles.json"), JSON.stringify({ kind: "gentle-pi.agent_model_profiles", version: 1, profiles }));
|
|
37
|
+
mkdirSync(join(commonDir, "gentle-ai"), { recursive: true });
|
|
38
|
+
writeFileSync(join(commonDir, "gentle-ai", "profile-pin.json"), JSON.stringify({ kind: "gentle-pi.agent_model_profile_pin", version: 1, profile: pin }));
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const orchestrator = { provider: "anthropic", id: "fable" };
|
|
44
|
+
|
|
45
|
+
test("the effective worker model comes from the global subagent profile", () => {
|
|
46
|
+
const f = fixture("global-profile");
|
|
47
|
+
f.writeAgent("gentle-ai-worker");
|
|
48
|
+
f.writeSubagents({ model_profiles: { "gentle-ai-worker": { model: "anthropic/opus" } } });
|
|
49
|
+
assert.deepEqual(
|
|
50
|
+
resolveEffectiveAgentModel("gentle-ai-worker", { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree, fallback: orchestrator }),
|
|
51
|
+
{ agent: "gentle-ai-worker", model: { provider: "anthropic", id: "opus" }, inherited: false },
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("a repository profile pin replaces global routing for the effective worker model", () => {
|
|
56
|
+
const f = fixture("pinned-profile");
|
|
57
|
+
f.writeAgent("gentle-ai-worker");
|
|
58
|
+
f.writeSubagents({ model_profiles: { "gentle-ai-worker": { model: "anthropic/opus" } } });
|
|
59
|
+
f.writePinnedProfile({ cheap: { "gentle-ai-worker": { model: "openai/mini" } } }, "cheap");
|
|
60
|
+
assert.deepEqual(
|
|
61
|
+
resolveEffectiveAgentModel("gentle-ai-worker", { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree, fallback: orchestrator })?.model,
|
|
62
|
+
{ provider: "openai", id: "mini" },
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("the agent definition model applies when no profile routes the agent", () => {
|
|
67
|
+
const f = fixture("definition-model");
|
|
68
|
+
f.writeAgent("gentle-ai-worker", "openai/defined");
|
|
69
|
+
assert.deepEqual(
|
|
70
|
+
resolveEffectiveAgentModel("gentle-ai-worker", { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree, fallback: orchestrator })?.model,
|
|
71
|
+
{ provider: "openai", id: "defined" },
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("an unrouted agent inherits the fallback session model", () => {
|
|
76
|
+
const f = fixture("inherit");
|
|
77
|
+
f.writeAgent("gentle-ai-worker");
|
|
78
|
+
assert.deepEqual(
|
|
79
|
+
resolveEffectiveAgentModel("gentle-ai-worker", { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree, fallback: orchestrator }),
|
|
80
|
+
{ agent: "gentle-ai-worker", model: orchestrator, inherited: true },
|
|
81
|
+
);
|
|
82
|
+
assert.deepEqual(
|
|
83
|
+
resolveEffectiveAgentModel("gentle-ai-worker", { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree }),
|
|
84
|
+
{ agent: "gentle-ai-worker", model: undefined, inherited: true },
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("an undiscovered agent resolves to undefined", () => {
|
|
89
|
+
const f = fixture("missing-agent");
|
|
90
|
+
assert.equal(
|
|
91
|
+
resolveEffectiveAgentModel("gentle-ai-worker", { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree, fallback: orchestrator }),
|
|
92
|
+
undefined,
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("resolvePinnedAgentProfile returns the launch profile with its model and thinking", () => {
|
|
97
|
+
const f = fixture("launch-profile");
|
|
98
|
+
f.writePinnedProfile({ deep: { explore: { model: "openai/alpha", thinking: "minimal" } } }, "deep");
|
|
99
|
+
const agent: AgentDefinition = { name: "explore", description: "", filePath: "", scope: "global", instructions: "", model: undefined, thinking: undefined, mode: undefined, tools: [] };
|
|
100
|
+
const profile = resolvePinnedAgentProfile(agent, { roots: f.roots, pinCwd: f.cwd, configHome: f.configHome, resolveWorktree: f.resolveWorktree });
|
|
101
|
+
assert.deepEqual(profile.model, { provider: "openai", id: "alpha" });
|
|
102
|
+
assert.equal(profile.thinking, "minimal");
|
|
103
|
+
assert.equal(profile.source.model, "profile");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("resolveAgentHomeDirectory follows the environment, expands tildes, and keeps explicit overrides literal", () => {
|
|
107
|
+
const home = "/home/tester";
|
|
108
|
+
assert.equal(resolveAgentHomeDirectory({ env: { GENTLE_PI_AGENT_HOME: "/opt/agents" }, home }), resolve("/opt/agents"));
|
|
109
|
+
assert.equal(resolveAgentHomeDirectory({ env: { PI_CODING_AGENT_DIR: "~/pi-agent" }, home }), resolve(join(home, "pi-agent")));
|
|
110
|
+
assert.equal(resolveAgentHomeDirectory({ env: { GENTLE_PI_AGENT_HOME: "~" }, home }), resolve(home));
|
|
111
|
+
assert.equal(resolveAgentHomeDirectory({ env: { GENTLE_PI_AGENT_HOME: "/ignored" }, home, homeOverridden: true }), resolve(join(home, ".pi", "agent")));
|
|
112
|
+
assert.equal(resolveAgentHomeDirectory({ env: {}, home, agentHome: "/explicit" }), resolve("/explicit"));
|
|
113
|
+
});
|
|
@@ -437,6 +437,24 @@ test("normalizeProfilesFile drops an active marker that points nowhere", () => {
|
|
|
437
437
|
assert.equal(normalized?.drops.droppedProfiles.length, 0);
|
|
438
438
|
});
|
|
439
439
|
|
|
440
|
+
test("normalizeProfilesFile accepts effort as alias for thinking in profile entries (#1403)", () => {
|
|
441
|
+
const normalized = normalizeProfilesFile(
|
|
442
|
+
JSON.parse(
|
|
443
|
+
profilesText({
|
|
444
|
+
hybrid: {
|
|
445
|
+
"example-agent": { model: "anthropic/claude-sonnet-4", effort: "medium" },
|
|
446
|
+
"worker": { effort: "high" },
|
|
447
|
+
},
|
|
448
|
+
}),
|
|
449
|
+
),
|
|
450
|
+
);
|
|
451
|
+
assert.deepEqual(normalized?.file.profiles.hybrid, {
|
|
452
|
+
"example-agent": { model: "anthropic/claude-sonnet-4", thinking: "medium" },
|
|
453
|
+
"worker": { model: undefined, thinking: "high" },
|
|
454
|
+
});
|
|
455
|
+
assert.equal(normalized?.drops.droppedAgents.length, 0);
|
|
456
|
+
});
|
|
457
|
+
|
|
440
458
|
test("bootstrapProfilesFile seeds a current profile, active only when routing is non-empty", () => {
|
|
441
459
|
const empty = bootstrapProfilesFile({});
|
|
442
460
|
assert.deepEqual(empty, {
|
|
@@ -749,3 +767,15 @@ test("formatOrchestratorSelection separates set, inherit, and inherit-with-think
|
|
|
749
767
|
"nan/glm5.3 · max",
|
|
750
768
|
);
|
|
751
769
|
});
|
|
770
|
+
|
|
771
|
+
test("buildProfileListItems marks the session-bound profile ahead of the pinned one", () => {
|
|
772
|
+
const file = createProfile(createProfile(emptyProfilesFile(), "work", { worker: { model: "zai/glm-4.7" } }), "personal", { solo: { model: "openai/o4-mini" } });
|
|
773
|
+
const items = buildProfileListItems(file, "work", "personal");
|
|
774
|
+
assert.equal(items.find((item) => item.id === "personal")?.label, "personal (session)");
|
|
775
|
+
assert.equal(items.find((item) => item.id === "work")?.label, "work (pinned)");
|
|
776
|
+
assert.equal(items.find((item) => item.id === "personal")?.description, "1 role");
|
|
777
|
+
const both = buildProfileListItems(file, "work", "work");
|
|
778
|
+
assert.equal(both.find((item) => item.id === "work")?.label, "work (session)", "the session marker outranks the pin marker on the same profile");
|
|
779
|
+
const unbound = buildProfileListItems(file, "work");
|
|
780
|
+
assert.equal(unbound.find((item) => item.id === "personal")?.label, "personal", "no session marker without a binding");
|
|
781
|
+
});
|