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.
Files changed (425) hide show
  1. package/README.md +157 -18
  2. package/assets/agents/gentle-ai-explore.md +11 -4
  3. package/assets/agents/gentle-ai-verify.md +23 -4
  4. package/assets/agents/gentle-ai-worker.md +6 -6
  5. package/assets/install-wizard/index.html +47 -0
  6. package/assets/install-wizard/wizard.css +1279 -0
  7. package/assets/install-wizard/wizard.js +951 -0
  8. package/assets/orchestrator-delegation.md +70 -163
  9. package/assets/orchestrator-memory.md +11 -4
  10. package/assets/orchestrator-prompts.md +48 -0
  11. package/assets/orchestrator-tracking.md +53 -0
  12. package/assets/orchestrator-verification.md +28 -0
  13. package/assets/orchestrator-writer.md +38 -0
  14. package/assets/orchestrator.md +29 -25
  15. package/assets/sounds/LICENSE.md +52 -0
  16. package/assets/sounds/attention.wav +0 -0
  17. package/assets/sounds/error.wav +0 -0
  18. package/assets/sounds/success.wav +0 -0
  19. package/bin/engram-guard +9 -0
  20. package/bin/gentle-shell-install.mjs +302 -0
  21. package/bin/gentle-shell.mjs +708 -22
  22. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +7 -7
  23. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/manifest.json +2 -2
  24. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/orchestration/pi.md +16 -4
  25. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-capabilities.baseline.json +2 -2
  26. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-roles.baseline.json +1 -1
  27. package/docs/auto-permission-answers.md +25 -0
  28. package/docs/auto-permission-evidence.md +39 -0
  29. package/docs/bundled-install.md +399 -0
  30. package/docs/delegated-verification.md +3 -5
  31. package/docs/gentle-agents-activity.md +513 -0
  32. package/docs/gentle-shell-uninstall.md +136 -0
  33. package/docs/gentle-shell.md +90 -33
  34. package/docs/install-wizard.md +2040 -0
  35. package/docs/native-authority-architecture.md +1 -1
  36. package/docs/permission-modes.md +127 -0
  37. package/docs/prompt-history.md +1 -1
  38. package/docs/readme-reference.md +310 -47
  39. package/docs/render-cache-performance.md +28 -0
  40. package/docs/session-profile-format.md +39 -0
  41. package/docs/sound-notifications-proposal.md +191 -0
  42. package/docs/sound-notifications.md +114 -0
  43. package/docs/yolo-mode.md +11 -10
  44. package/extensions/ask-user-choice.ts +4 -0
  45. package/extensions/ask-user-question.ts +6 -1
  46. package/extensions/child-context.ts +11 -2
  47. package/extensions/child-safety.ts +4 -2
  48. package/extensions/codegraph-tools.ts +18 -5
  49. package/extensions/gentle-agents.ts +718 -87
  50. package/extensions/gentle-ai.ts +991 -263
  51. package/extensions/gentle-herdr-activity.ts +81 -0
  52. package/extensions/gentle-notifications.ts +104 -0
  53. package/extensions/gentle-shell.ts +271 -80
  54. package/extensions/gentle-todo.ts +123 -18
  55. package/extensions/history/index.ts +11 -6
  56. package/extensions/pi-pretty.ts +39 -3
  57. package/extensions/quiet-tools.ts +91 -21
  58. package/extensions/skill-registry.ts +175 -46
  59. package/extensions/startup-banner.ts +11 -2
  60. package/lib/agent-home.ts +10 -1
  61. package/lib/agent-model-resolution.ts +80 -0
  62. package/lib/agent-profiles.ts +13 -3
  63. package/lib/agents-completion-delivery.ts +11 -3
  64. package/lib/agents-messaging.ts +1 -1
  65. package/lib/agents-protocol.ts +40 -1
  66. package/lib/agents-runner.ts +90 -15
  67. package/lib/auto-permission-answers.ts +133 -0
  68. package/lib/auto-permission-classifier.ts +459 -0
  69. package/lib/auto-permission-evidence.ts +88 -0
  70. package/lib/auto-permission-memory.ts +69 -0
  71. package/lib/auto-permission-runtime.ts +484 -0
  72. package/lib/auto-permission-tool-context.ts +61 -0
  73. package/lib/background-jobs-tools.ts +202 -0
  74. package/lib/background-jobs.ts +253 -0
  75. package/lib/background-monitor.ts +154 -0
  76. package/lib/bounded-writer-admission.ts +83 -10
  77. package/lib/builtin-codemode-optout.ts +166 -0
  78. package/lib/card-content-policy.ts +85 -0
  79. package/lib/child-package-injection.ts +62 -0
  80. package/lib/codemode-renderer.ts +14 -4
  81. package/lib/command-palette-catalog.ts +3 -2
  82. package/lib/context-threshold.ts +26 -0
  83. package/lib/destructive-command-guard.ts +104 -28
  84. package/lib/gentle-ai-binary.ts +109 -4
  85. package/lib/gentle-shell-bundled.ts +535 -0
  86. package/lib/gentle-shell-launcher.ts +75 -24
  87. package/lib/gentle-shell-startup-flow.ts +54 -0
  88. package/lib/gentle-shell-startup-update.ts +92 -0
  89. package/lib/gentle-shell-uninstall.ts +840 -0
  90. package/lib/gentle-shell-update-panel.ts +231 -0
  91. package/lib/herdr-activity.ts +183 -0
  92. package/lib/inprocess-reviewer.ts +3 -0
  93. package/lib/jobs-sidebar-state.ts +20 -0
  94. package/lib/jobs-view.ts +161 -0
  95. package/lib/model-price-ratio.ts +83 -0
  96. package/lib/model-routing-authority.ts +6 -1
  97. package/lib/nan-provider.ts +33 -11
  98. package/lib/native-review-cli.ts +194 -73
  99. package/lib/notification-audio-native.ts +162 -0
  100. package/lib/notification-audio-windows.ts +399 -0
  101. package/lib/notification-audio.ts +332 -0
  102. package/lib/notification-customize.ts +241 -0
  103. package/lib/notification-events.ts +113 -0
  104. package/lib/notification-policy.ts +148 -0
  105. package/lib/notification-pulse-client.ts +367 -0
  106. package/lib/notification-pulse-protocol.ts +305 -0
  107. package/lib/notification-pulse-stream.ts +213 -0
  108. package/lib/notification-pulse-worker.ts +66 -0
  109. package/lib/notification-scheduler.ts +173 -0
  110. package/lib/notification-service.ts +202 -0
  111. package/lib/notification-ui.ts +87 -0
  112. package/lib/odd-phase.ts +1 -1
  113. package/lib/orchestrator-alias.ts +20 -0
  114. package/lib/orchestrator-catalog.ts +79 -0
  115. package/lib/orchestrator-consultation.ts +61 -0
  116. package/lib/orchestrator-discovery.ts +49 -0
  117. package/lib/orchestrator-helper-consent.ts +122 -0
  118. package/lib/orchestrator-helper.ts +167 -0
  119. package/lib/orchestrator-message-card.ts +105 -0
  120. package/lib/orchestrator-presence.ts +115 -14
  121. package/lib/orchestrator-scope.ts +80 -0
  122. package/lib/orchestrator-state.ts +107 -0
  123. package/lib/orchestrator-tool-card.ts +280 -0
  124. package/lib/orchestrator-work-search.ts +218 -0
  125. package/lib/orchestrator-work.ts +79 -0
  126. package/lib/permission-mode-policy.ts +59 -0
  127. package/lib/review-candidate-view-owner.ts +8 -6
  128. package/lib/review-candidate-view.ts +3 -2
  129. package/lib/review-compact-contract.ts +2 -2
  130. package/lib/review-host-relay.ts +7 -2
  131. package/lib/review-integration-v2.ts +100 -22
  132. package/lib/review-publication-gate.ts +1 -1
  133. package/lib/review-risk-assessment.ts +77 -51
  134. package/lib/review-sidebar-state.ts +2 -1
  135. package/lib/review-transaction.ts +72 -3
  136. package/lib/runtime-metrics-children.ts +1 -1
  137. package/lib/runtime-metrics-native.ts +3 -2
  138. package/lib/selection-engine.ts +22 -7
  139. package/lib/session-change-capture.ts +5 -4
  140. package/lib/session-changes.ts +27 -22
  141. package/lib/session-profile-binding.ts +83 -0
  142. package/lib/session-profile-freeze.ts +261 -0
  143. package/lib/session-profile-persistence.ts +187 -0
  144. package/lib/session-worktree-registry.ts +74 -8
  145. package/lib/shell-bar.ts +41 -11
  146. package/lib/shell-changes-view.ts +40 -13
  147. package/lib/shell-changes.ts +88 -71
  148. package/lib/shell-prompt.ts +6 -4
  149. package/lib/shell-sidebar-layout.ts +5 -1
  150. package/lib/shell-todo.ts +81 -26
  151. package/lib/shell-usage.ts +4 -3
  152. package/lib/status-timing-diagnostics.ts +201 -0
  153. package/lib/telemetry-trigger.ts +3 -1
  154. package/lib/vim-editor-adapter.ts +27 -5
  155. package/lib/visual-customization-policy.ts +20 -9
  156. package/lib/visual-customize-view.ts +171 -20
  157. package/lib/writer-surfaces.ts +162 -0
  158. package/lib/yolo-session-policy.ts +198 -121
  159. package/package.json +5 -5
  160. package/runtime/child-package-injection.mjs +63 -0
  161. package/runtime/gentle-ai-binary.mjs +109 -4
  162. package/runtime/gentle-shell-bundled.mjs +536 -0
  163. package/runtime/gentle-shell-launcher.mjs +74 -23
  164. package/runtime/gentle-shell-startup-flow.mjs +55 -0
  165. package/runtime/gentle-shell-startup-update.mjs +93 -0
  166. package/runtime/gentle-shell-uninstall.mjs +841 -0
  167. package/runtime/gentle-shell-update-panel.mjs +232 -0
  168. package/runtime/native-review-cli.mjs +191 -70
  169. package/runtime/review-integration-v2.mjs +100 -22
  170. package/runtime/review-risk-assessment.mjs +77 -51
  171. package/runtime/status-timing-diagnostics.mjs +202 -0
  172. package/runtime/telemetry-trigger.mjs +3 -1
  173. package/scripts/bootstrap.cmd +255 -0
  174. package/scripts/bootstrap.sh +168 -0
  175. package/scripts/build-distribution.mjs +157 -0
  176. package/scripts/build-installer-bundles.mjs +136 -0
  177. package/scripts/build-runtime-modules.mjs +7 -0
  178. package/scripts/bundled-install.mjs +1308 -0
  179. package/scripts/bundled-wizard.mjs +399 -0
  180. package/scripts/check-types.mjs +4 -6
  181. package/scripts/gentle-ai-installer.mjs +79 -32
  182. package/scripts/install-gentle-ai.mjs +48 -1
  183. package/scripts/install-tui-mode-setting.mjs +10 -1
  184. package/scripts/install-wizard-preview.mjs +154 -0
  185. package/scripts/installer-downloads.mjs +648 -0
  186. package/scripts/installer-preflight.mjs +387 -0
  187. package/scripts/installer-probes.mjs +564 -0
  188. package/scripts/installer-runner.mjs +1102 -0
  189. package/scripts/installer-server.mjs +881 -0
  190. package/scripts/installer-windows-artifacts.json +15 -0
  191. package/scripts/installer-windows.mjs +752 -0
  192. package/scripts/main-channel.mjs +452 -0
  193. package/scripts/npm-pack-result.mjs +31 -0
  194. package/scripts/pi-update.mjs +223 -0
  195. package/scripts/render-cache-performance-worker.mjs +205 -0
  196. package/scripts/render-cache-performance.mjs +115 -0
  197. package/scripts/run-test-suite.mjs +22 -8
  198. package/scripts/test-installer-acceptance.sh +161 -0
  199. package/scripts/test-packed-runner.mjs +23 -5
  200. package/scripts/types-baseline.json +2 -92
  201. package/scripts/verify-package-files.mjs +82 -18
  202. package/skills/gentle-ai/SKILL.md +12 -11
  203. package/tests/agent-home.test.ts +56 -3
  204. package/tests/agent-model-resolution.test.ts +113 -0
  205. package/tests/agent-profiles.test.ts +12 -0
  206. package/tests/agent-risk-escalation.test.ts +123 -0
  207. package/tests/agents-completion-delivery.test.ts +17 -0
  208. package/tests/agents-protocol.test.ts +57 -0
  209. package/tests/agents-queries.test.ts +9 -9
  210. package/tests/agents-runner-process.test.ts +31 -0
  211. package/tests/agents-runner.test.ts +89 -4
  212. package/tests/append-system-prompt-route.test.ts +18 -1
  213. package/tests/auto-mode-human-answers.test.ts +68 -0
  214. package/tests/auto-mode-invariants.test.ts +276 -0
  215. package/tests/auto-mode-sdk.test.ts +84 -0
  216. package/tests/auto-mode.test.ts +49 -0
  217. package/tests/auto-permission-answers.test.ts +170 -0
  218. package/tests/auto-permission-classifier.test.ts +634 -0
  219. package/tests/auto-permission-compound.test.ts +24 -0
  220. package/tests/auto-permission-evidence.test.ts +88 -0
  221. package/tests/auto-permission-memory.test.ts +46 -0
  222. package/tests/auto-permission-public-regressions.test.ts +111 -0
  223. package/tests/auto-permission-runtime.test.ts +454 -0
  224. package/tests/autonomous-guard.test.ts +86 -16
  225. package/tests/background-cache-warming.test.ts +2 -1
  226. package/tests/background-jobs.test.ts +227 -0
  227. package/tests/background-monitor.test.ts +195 -0
  228. package/tests/background-subagents-default-mode.test.ts +28 -5
  229. package/tests/bounded-stop-contract.test.ts +85 -0
  230. package/tests/bounded-writer-admission.test.ts +52 -1
  231. package/tests/bridge-wake-lifecycle.test.ts +129 -0
  232. package/tests/bridge-wake-rendering.test.ts +56 -0
  233. package/tests/build-distribution.test.ts +269 -0
  234. package/tests/builtin-codemode-optout.test.ts +242 -0
  235. package/tests/bundled-install.test.ts +1319 -0
  236. package/tests/bundled-wizard.test.ts +505 -0
  237. package/tests/card-content-policy.test.ts +68 -0
  238. package/tests/card-style-policy.test.ts +34 -2
  239. package/tests/child-codegraph-bootstrap.test.ts +74 -0
  240. package/tests/child-package-entrypoints.test.ts +65 -0
  241. package/tests/child-package-injection.test.ts +74 -0
  242. package/tests/child-safety.test.ts +12 -0
  243. package/tests/child-web-package.test.ts +224 -0
  244. package/tests/codegraph-tools.test.ts +35 -0
  245. package/tests/codemode-rendering.test.ts +107 -2
  246. package/tests/command-palette.test.ts +5 -5
  247. package/tests/context-threshold.test.ts +31 -0
  248. package/tests/delegate-for-reason-contract.test.ts +327 -0
  249. package/tests/delegated-key-learnings-contract.test.ts +3 -2
  250. package/tests/devbinary/native-review-parity.devtest.ts +1 -1
  251. package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
  252. package/tests/engram-safety.test.ts +316 -0
  253. package/tests/generic-agent-tools.test.ts +16 -1
  254. package/tests/gentle-agents.test.ts +1895 -76
  255. package/tests/gentle-ai-binary-isolation.test.ts +135 -0
  256. package/tests/gentle-ai-binary.test.ts +19 -2
  257. package/tests/gentle-ai-child-guards.test.ts +202 -0
  258. package/tests/gentle-ai-dev-binary-surfacing.test.ts +125 -15
  259. package/tests/gentle-ai-installer.test.ts +548 -58
  260. package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
  261. package/tests/gentle-ai-renderer.test.ts +6 -6
  262. package/tests/gentle-ai.test.ts +999 -31
  263. package/tests/gentle-herdr-activity.test.ts +100 -0
  264. package/tests/gentle-notifications.test.ts +427 -0
  265. package/tests/gentle-shell-bin.test.ts +263 -19
  266. package/tests/gentle-shell-bundled.test.ts +1036 -0
  267. package/tests/gentle-shell-launcher.test.ts +251 -25
  268. package/tests/gentle-shell-startup-flow.test.ts +75 -0
  269. package/tests/gentle-shell-startup-update.test.ts +85 -0
  270. package/tests/gentle-shell-uninstall.test.ts +978 -0
  271. package/tests/gentle-shell-update-panel.test.ts +158 -0
  272. package/tests/gentle-shell.test.ts +611 -100
  273. package/tests/gentle-todo.test.ts +317 -14
  274. package/tests/herdr-activity.test.ts +243 -0
  275. package/tests/history-agent-home.test.ts +81 -0
  276. package/tests/history-child-guard.test.ts +70 -0
  277. package/tests/inprocess-reviewer.test.ts +20 -0
  278. package/tests/install-gentle-ai-failure.test.ts +69 -0
  279. package/tests/install-tui-mode-setting.test.ts +15 -0
  280. package/tests/install-wizard.test.ts +1223 -0
  281. package/tests/installer-bundles.test.ts +122 -0
  282. package/tests/installer-posix-bootstrap.test.ts +1201 -0
  283. package/tests/installer-preflight.test.ts +750 -0
  284. package/tests/installer-probes.test.ts +1106 -0
  285. package/tests/installer-runner.test.ts +2159 -0
  286. package/tests/installer-server.test.ts +1567 -0
  287. package/tests/installer-windows-bootstrap.test.ts +2410 -0
  288. package/tests/jobs-view.test.ts +160 -0
  289. package/tests/main-channel-upgrade.test.ts +395 -0
  290. package/tests/main-channel.test.ts +344 -0
  291. package/tests/maintainer/provider-relay.maintest.ts +13 -12
  292. package/tests/model-price-ratio.test.ts +116 -0
  293. package/tests/model-profiles-preservation.test.ts +153 -0
  294. package/tests/model-routing-package.test.ts +10 -0
  295. package/tests/nan-provider-runtime.test.ts +156 -0
  296. package/tests/nan-provider.test.ts +28 -18
  297. package/tests/native-binary-gate.test.ts +2 -0
  298. package/tests/native-review-capability-contract.test.ts +7 -1
  299. package/tests/native-review-cli.test.ts +236 -1
  300. package/tests/native-review-consent.test.ts +2 -2
  301. package/tests/native-review-parity-runtime.test.ts +1 -1
  302. package/tests/native-review-parity.test.ts +12 -48
  303. package/tests/native-risk-evidence-parity.test.ts +21 -0
  304. package/tests/no-self-pause-contract.test.ts +87 -0
  305. package/tests/notification-audio-native.test.ts +281 -0
  306. package/tests/notification-audio-windows.test.ts +581 -0
  307. package/tests/notification-audio.test.ts +548 -0
  308. package/tests/notification-customize.test.ts +655 -0
  309. package/tests/notification-events.test.ts +115 -0
  310. package/tests/notification-policy.test.ts +201 -0
  311. package/tests/notification-pulse-client.test.ts +356 -0
  312. package/tests/notification-pulse-protocol.test.ts +213 -0
  313. package/tests/notification-pulse-stream.test.ts +320 -0
  314. package/tests/notification-scheduler.test.ts +258 -0
  315. package/tests/notification-ui.test.ts +157 -0
  316. package/tests/npm-pack-result.test.ts +41 -0
  317. package/tests/odd-integration.test.ts +14 -5
  318. package/tests/odd-routing-canonical-ratchet.test.ts +53 -12
  319. package/tests/odd-routing-contract.test.ts +80 -23
  320. package/tests/odd-runtime-delegation-gate.test.ts +4 -1
  321. package/tests/orchestrator-budget.test.ts +29 -6
  322. package/tests/orchestrator-catalog.test.ts +146 -0
  323. package/tests/orchestrator-consultation-sdk.test.ts +614 -0
  324. package/tests/orchestrator-consultation.test.ts +111 -0
  325. package/tests/orchestrator-discovery.test.ts +241 -0
  326. package/tests/orchestrator-helper-consent.test.ts +171 -0
  327. package/tests/orchestrator-helper.test.ts +297 -0
  328. package/tests/orchestrator-message-card.test.ts +190 -0
  329. package/tests/orchestrator-presence.test.ts +23 -0
  330. package/tests/orchestrator-rdd-ownership.test.ts +6 -5
  331. package/tests/orchestrator-scope.test.ts +107 -0
  332. package/tests/orchestrator-state.test.ts +114 -0
  333. package/tests/orchestrator-status-publication-contract.test.ts +34 -0
  334. package/tests/orchestrator-tool-card.test.ts +398 -0
  335. package/tests/orchestrator-work-search.test.ts +318 -0
  336. package/tests/orchestrator-work.test.ts +147 -0
  337. package/tests/package-manifest.test.ts +105 -21
  338. package/tests/packed-runner-owned-path.test.ts +35 -1
  339. package/tests/parallel-reason-contract.test.ts +21 -0
  340. package/tests/parallel-writer-admission.test.ts +210 -0
  341. package/tests/permission-mode-policy.test.ts +194 -0
  342. package/tests/persona-single-channel.test.ts +4 -12
  343. package/tests/pi-pretty.test.ts +56 -0
  344. package/tests/pi-update-launcher.test.ts +87 -0
  345. package/tests/pi-update.test.ts +186 -0
  346. package/tests/provider-defect-handoff.test.ts +4 -3
  347. package/tests/quiet-tool-rendering.test.ts +160 -3
  348. package/tests/rdd-aware-verification-contract.test.ts +29 -41
  349. package/tests/rdd-status-line.test.ts +52 -0
  350. package/tests/render-cache-performance.test.ts +48 -0
  351. package/tests/review-agent-end-preflight.test.ts +62 -10
  352. package/tests/review-candidate-view.test.ts +101 -12
  353. package/tests/review-contract-prompt.test.ts +33 -4
  354. package/tests/review-controller-native-recovery.test.ts +327 -17
  355. package/tests/review-controller-native-routing.test.ts +255 -1
  356. package/tests/review-controller-workspace-root.test.ts +43 -2
  357. package/tests/review-controller.test.ts +2 -2
  358. package/tests/review-correction-lifecycle.test.ts +2 -1
  359. package/tests/review-gate.test.ts +7 -4
  360. package/tests/review-graph-schema.test.ts +2 -2
  361. package/tests/review-host-relay-routing.test.ts +5 -3
  362. package/tests/review-host-relay.test.ts +49 -2
  363. package/tests/review-integration-v2-forward.test.ts +21 -1
  364. package/tests/review-json-arguments.test.ts +167 -0
  365. package/tests/review-last-event-closure.test.ts +157 -8
  366. package/tests/review-ledger-contract.test.ts +5 -4
  367. package/tests/review-policy-judgment-day.test.ts +1 -1
  368. package/tests/review-policy-ordinary.test.ts +2 -2
  369. package/tests/review-relay-transport-agent.test.ts +66 -1
  370. package/tests/review-risk-assessment.test.ts +109 -33
  371. package/tests/review-session-standing-permission-controller.test.ts +16 -17
  372. package/tests/review-session-standing-permission-ipc.test.ts +6 -5
  373. package/tests/review-test-fixtures.ts +7 -1
  374. package/tests/review-transaction.test.ts +18 -1
  375. package/tests/run-test-suite.test.ts +83 -5
  376. package/tests/runtime-harness.mjs +42 -15
  377. package/tests/runtime-metrics-extension.test.ts +1 -1
  378. package/tests/runtime-metrics-native.test.ts +31 -1
  379. package/tests/selection-engine.test.ts +65 -5
  380. package/tests/session-change-capture.test.ts +10 -10
  381. package/tests/session-changes-shell.test.ts +242 -48
  382. package/tests/session-changes.test.ts +17 -24
  383. package/tests/session-profile-binding.test.ts +163 -0
  384. package/tests/session-profile-freeze.test.ts +394 -0
  385. package/tests/session-profile-persistence.test.ts +334 -0
  386. package/tests/session-subject-routing-contract.test.ts +34 -0
  387. package/tests/session-worktree-registry.test.ts +57 -2
  388. package/tests/shell-bar.test.ts +40 -0
  389. package/tests/shell-changes-view.test.ts +85 -34
  390. package/tests/shell-changes.test.ts +79 -62
  391. package/tests/shell-render-cache-runtime.test.ts +69 -0
  392. package/tests/shell-render-cache.test.ts +129 -0
  393. package/tests/shell-sidebar-layout.test.ts +27 -2
  394. package/tests/shell-todo.test.ts +132 -11
  395. package/tests/shell-usage-view.test.ts +1 -1
  396. package/tests/shell-usage.test.ts +35 -0
  397. package/tests/short-check-routing-contract.test.ts +49 -0
  398. package/tests/skill-registry-watcher.test.ts +119 -0
  399. package/tests/skill-registry.test.ts +311 -5
  400. package/tests/startup-banner.test.ts +117 -3
  401. package/tests/startup-home-repo.test.ts +170 -0
  402. package/tests/status-timing-diagnostics.test.ts +283 -0
  403. package/tests/support/orchestrator-modules.ts +19 -0
  404. package/tests/task-size-routing-contract.test.ts +241 -0
  405. package/tests/telemetry-trigger.test.ts +27 -1
  406. package/tests/test-strength-contract.test.ts +124 -0
  407. package/tests/verify-agent-contract.test.ts +90 -0
  408. package/tests/verify-first-launch-contract.test.ts +139 -0
  409. package/tests/verify-package-files.test.ts +56 -0
  410. package/tests/vim-editor-adapter.test.ts +47 -21
  411. package/tests/visual-customization-policy.test.ts +32 -3
  412. package/tests/visual-customize-view.test.ts +288 -10
  413. package/tests/writer-edit-surface-scope.test.ts +59 -2
  414. package/tests/writer-surfaces.test.ts +199 -0
  415. package/tests/yolo-customize.test.ts +18 -3
  416. package/tests/yolo-mode-runtime.test.ts +37 -10
  417. package/tests/yolo-mode.test.ts +38 -5
  418. package/tests/yolo-session-policy.test.ts +1 -1
  419. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/README.md +0 -0
  420. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/lens.schema.json +0 -0
  421. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/refuter.schema.json +0 -0
  422. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/targeted-validator.schema.json +0 -0
  423. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/lens.json +0 -0
  424. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/refuter.json +0 -0
  425. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/targeted-validator.json +0 -0
@@ -1,10 +1,11 @@
1
- import { join, resolve as resolvePath } from "node:path";
1
+ import { isAbsolute, join, resolve as resolvePath } from "node:path";
2
+ import { CHILD_PACKAGE_INJECTION_ENV, encodeChildPackageInjection, type ChildPackageInjection } from "./child-package-injection.ts";
2
3
 
3
4
  // The gentle-shell launcher: pure, side-effect-free functions over injected
4
5
  // env/fs/exec. `bin/gentle-shell.mjs` (T2) wires these into the real process,
5
6
  // filesystem and child process so this module stays fully unit-testable.
6
7
 
7
- export type LauncherCommand = "home" | "setup";
8
+ export type LauncherCommand = "home" | "setup" | "upgrade" | "self-uninstall";
8
9
 
9
10
  // pi's own package-management subcommands (see pi's cli/args.ts printHelp
10
11
  // "Commands" list): each is dispatched by pi itself, before pi's own flag
@@ -35,11 +36,12 @@ export interface ParsedLauncherArgs {
35
36
  error?: string;
36
37
  }
37
38
 
38
- // Home-subcommand parsing is deliberately shallow: `home` only counts as the
39
- // subcommand when it is argv[0], and everything after it is handed over
39
+ // Home-, upgrade- and self-uninstall-subcommand parsing is deliberately shallow:
40
+ // each only counts as the subcommand when it is argv[0], and everything after it is handed over
40
41
  // untouched as commandArgs — T2 owns interpreting `home link|isolated|<path>`.
42
+ // `self-uninstall` is not `uninstall`, which stays pi's own alias for `remove`.
41
43
  export function parseLauncherArgs(argv: string[]): ParsedLauncherArgs {
42
- if (argv[0] === "home") {
44
+ if (argv[0] === "home" || argv[0] === "upgrade" || argv[0] === "self-uninstall") {
43
45
  return {
44
46
  link: false,
45
47
  isolated: false,
@@ -47,7 +49,7 @@ export function parseLauncherArgs(argv: string[]): ParsedLauncherArgs {
47
49
  packageRoot: undefined,
48
50
  help: false,
49
51
  version: false,
50
- command: "home",
52
+ command: argv[0],
51
53
  commandArgs: argv.slice(1),
52
54
  passthrough: [],
53
55
  piSubcommand: undefined,
@@ -188,35 +190,36 @@ export interface ResolveHomeInput {
188
190
  config: LauncherConfig | undefined;
189
191
  }
190
192
 
191
- // Pi Subagents resolves `PI_CODING_AGENT_DIR || ~/.pi/agent`; `--link` reuses
192
- // that exact home so gentle-shell never diverges from the user's own pi.
193
+ // Pi Subagents resolves `PI_CODING_AGENT_DIR || ~/.pi/agent`; this is the
194
+ // user's own pi home when no Gentle Shell session is involved.
193
195
  function linkDir(env: Record<string, string | undefined>, homedir: string): string {
194
196
  return env.PI_CODING_AGENT_DIR || join(homedir, ".pi", "agent");
195
197
  }
196
198
 
197
199
  // The isolated home replaces PI_CODING_AGENT_DIR for the whole session, so the
198
200
  // user's own Pi home travels in this variable for read-only features such as
199
- // /gentle:stats. An inherited value wins: a gentle-shell launched from inside
200
- // a Gentle Shell session sees the outer isolated home as PI_CODING_AGENT_DIR.
201
+ // /gentle:stats and for `--link`. An inherited value wins: a gentle-shell
202
+ // launched from inside a Gentle Shell session sees the outer isolated home as
203
+ // PI_CODING_AGENT_DIR, so `--link` must not re-select it (#2015).
201
204
  export const USER_PI_HOME_ENV = "GENTLE_SHELL_USER_PI_HOME";
202
205
 
203
206
  export function userPiHome(env: Record<string, string | undefined>, homedir: string): string {
204
207
  return env[USER_PI_HOME_ENV] || linkDir(env, homedir);
205
208
  }
206
209
 
207
- function isolatedDir(env: Record<string, string | undefined>, homedir: string): string {
210
+ export function isolatedDir(env: Record<string, string | undefined>, homedir: string): string {
208
211
  return env.GENTLE_SHELL_HOME || join(homedir, ".gentle-shell", "agent");
209
212
  }
210
213
 
211
214
  export function resolveHome(input: ResolveHomeInput): ResolvedHome {
212
215
  const { args, env, homedir, config } = input;
213
216
 
214
- if (args.link) return { mode: "link", dir: linkDir(env, homedir), source: "flag" };
217
+ if (args.link) return { mode: "link", dir: userPiHome(env, homedir), source: "flag" };
215
218
  if (args.isolated) return { mode: "isolated", dir: isolatedDir(env, homedir), source: "flag" };
216
219
  if (args.home !== undefined) return { mode: "path", dir: args.home, source: "flag" };
217
220
 
218
221
  if (config !== undefined) {
219
- if (config.mode === "link") return { mode: "link", dir: linkDir(env, homedir), source: "config" };
222
+ if (config.mode === "link") return { mode: "link", dir: userPiHome(env, homedir), source: "config" };
220
223
  if (config.mode === "isolated") return { mode: "isolated", dir: isolatedDir(env, homedir), source: "config" };
221
224
  return { mode: "path", dir: config.dir, source: "config" };
222
225
  }
@@ -389,7 +392,7 @@ export function missingPiMessage(): string {
389
392
 
390
393
  // --- pi version gate ---------------------------------------------------------
391
394
 
392
- export const MIN_PI_VERSION = "0.99.1";
395
+ export const MIN_PI_VERSION = "1.2.0";
393
396
 
394
397
  export type PiVersionCheck = { ok: true; version: string } | { ok: false; message: string; version?: string };
395
398
 
@@ -878,6 +881,10 @@ export interface BuildPiInvocationInput {
878
881
  baseEnv: Record<string, string | undefined>;
879
882
  // The OS home behind userPiHome's conventional ~/.pi/agent fallback.
880
883
  homedir: string;
884
+ // The directory pi is spawned in, which pi resolves a relative -e path
885
+ // against. bin/gentle-shell.mjs spawns pi without a cwd, so this is the
886
+ // launcher's own process.cwd().
887
+ cwd: string;
881
888
  }
882
889
 
883
890
  export interface PiInvocation {
@@ -919,8 +926,15 @@ export interface PiInvocation {
919
926
  // - Not takeOver, with a declaration: no injection at all — the target
920
927
  // settings already load a gentle-pi the launcher accepts as-is (the
921
928
  // `--link` case with a pi-managed install matching this launcher).
929
+ //
930
+ // The two injecting cases also export CHILD_PACKAGE_INJECTION_ENV (#1690) so
931
+ // the subagent runner can give delegated children the same package. It holds
932
+ // only the launcher's own computed -e set; passthrough -e flags (the managed
933
+ // herdr extension, or one the user typed) are not part of it. Every other case
934
+ // removes an inherited value, so a nested launch never leaks a stale signal.
922
935
  export function buildPiInvocation(input: BuildPiInvocationInput): PiInvocation {
923
936
  const args = [...input.runtime.args];
937
+ let childInjection: ChildPackageInjection | undefined;
924
938
 
925
939
  if (input.piSubcommand !== undefined) {
926
940
  // No injection at all: pi must see the bare subcommand as argv[0].
@@ -945,23 +959,36 @@ export function buildPiInvocation(input: BuildPiInvocationInput): PiInvocation {
945
959
  injected.add(input.packageRoot);
946
960
  args.push("-e", input.packageRoot);
947
961
  }
948
-
962
+ // The argv dedupe above compares raw strings; the signal dedupes again
963
+ // after absolutizing, so a relative and an absolute spelling of the same
964
+ // file appear once, in first-occurrence order.
965
+ const signalPaths = new Set([...injected].map((path) => absoluteExtensionPath(path, input.cwd)));
966
+ childInjection = { noExtensions: true, extensionPaths: [...signalPaths] };
949
967
  } else if (input.declaration === undefined) {
950
968
  args.push("-e", input.packageRoot);
969
+ childInjection = { noExtensions: false, extensionPaths: [absoluteExtensionPath(input.packageRoot, input.cwd)] };
951
970
  }
952
971
 
953
972
  args.push(...input.passthrough);
954
973
 
955
- return {
956
- command: input.runtime.command,
957
- args,
958
- env: {
959
- ...input.baseEnv,
960
- PI_CODING_AGENT_DIR: input.home.dir,
961
- GENTLE_PI_AGENT_HOME: input.home.dir,
962
- [USER_PI_HOME_ENV]: userPiHome(input.baseEnv, input.homedir),
963
- },
974
+ const env: Record<string, string | undefined> = {
975
+ ...input.baseEnv,
976
+ PI_CODING_AGENT_DIR: input.home.dir,
977
+ GENTLE_PI_AGENT_HOME: input.home.dir,
978
+ [USER_PI_HOME_ENV]: userPiHome(input.baseEnv, input.homedir),
964
979
  };
980
+ if (childInjection === undefined) delete env[CHILD_PACKAGE_INJECTION_ENV];
981
+ else env[CHILD_PACKAGE_INJECTION_ENV] = encodeChildPackageInjection(childInjection);
982
+
983
+ return { command: input.runtime.command, args, env };
984
+ }
985
+
986
+ // pi resolves a relative -e path against its spawn cwd. Children may run
987
+ // elsewhere, so the signal carries the same file as an absolute path. Loose
988
+ // entries can be relative when the isolated or linked home comes from a
989
+ // relative env value.
990
+ function absoluteExtensionPath(path: string, cwd: string): string {
991
+ return isAbsolute(path) ? path : resolvePath(cwd, path);
965
992
  }
966
993
 
967
994
  // --- spawn planning ------------------------------------------------------------
@@ -1148,6 +1175,9 @@ export function helpText(): string {
1148
1175
  "Usage: gentle-shell [options] [-- pi-args...]",
1149
1176
  " gentle-shell home [link|isolated|<path>]",
1150
1177
  " gentle-shell [home selectors] setup [--dry-run]",
1178
+ " gentle-shell upgrade [--channel release|main]",
1179
+ " gentle-shell upgrade --rollback",
1180
+ " gentle-shell self-uninstall [--dry-run] [--yes] [--include-shared]",
1151
1181
  "",
1152
1182
  "Opens pi with the Gentle Shell package loaded, without touching your",
1153
1183
  "vanilla pi installation.",
@@ -1167,19 +1197,40 @@ export function helpText(): string {
1167
1197
  " (runs the package-local gentle-ai 'install --agent pi --scope global').",
1168
1198
  " Accepts --dry-run, forwarded to gentle-ai. Accepts a home selector",
1169
1199
  " (--link, --isolated, --home <dir>) before it.",
1200
+ " Warns if configured MCP servers remain disabled; never re-enables them.",
1201
+ " upgrade Update Gentle Shell along its channel: the latest release, or the latest",
1202
+ " main commits of Gentle Shell and Gentle AI (built locally; needs Go and",
1203
+ " pnpm). --channel switches the channel first. A bundled install (the web",
1204
+ " installer's own Node, pnpm and Pi) follows the release channel only:",
1205
+ " it installs the new version beside the current one, verifies it, then",
1206
+ " switches; --rollback switches back to the previous kept version.",
1207
+ " self-uninstall Remove Gentle Shell: its own data, the isolated home and the gentle-pi",
1208
+ " package. Shows the plan first and asks before removing (--yes skips",
1209
+ " the question). The shared ~/.pi/gentle-ai configuration is kept unless",
1210
+ " you accept or pass --include-shared; --dry-run only shows the plan.",
1211
+ " Never touches your pi home or custom --home homes.",
1170
1212
  "",
1171
1213
  "Managing packages:",
1172
1214
  " gentle-shell install npm:<pkg> Run pi's own 'install' against the resolved home.",
1173
1215
  " gentle-shell remove <source> Run pi's own 'remove' against the resolved home.",
1174
1216
  " gentle-shell list Run pi's own 'list' against the resolved home.",
1175
1217
  " gentle-shell update [target] Run pi's own 'update' against the resolved home.",
1218
+ " In a bundled install Pi ships pinned: 'update' without a package",
1219
+ " runs 'gentle-shell upgrade' instead of updating Pi.",
1176
1220
  " gentle-shell config Run pi's own 'config' against the resolved home.",
1177
1221
  " gentle-shell auth <command> Run pi's own 'auth' against the resolved home.",
1222
+ " 'gentle-shell uninstall <source>' is pi's own alias for 'remove'; to remove Gentle",
1223
+ " Shell itself, use 'gentle-shell self-uninstall'.",
1178
1224
  " These run pi's own commands, forwarded verbatim, against the --isolated home",
1179
1225
  " (or your own pi home with --link). Running 'gentle-shell install npm:gentle-pi'",
1180
1226
  " inside the isolated home is unnecessary: gentle-shell already loads the",
1181
1227
  " package itself.",
1182
1228
  "",
1229
+ "Bundled interactive startup:",
1230
+ " Before opening Pi, checks for a newer release (at most 1.5 seconds).",
1231
+ " Choose Update now to upgrade and reopen, Not now, or Skip this version.",
1232
+ " Offline, unavailable checks, commands and noninteractive runs open normally.",
1233
+ "",
1183
1234
  "Environment variables:",
1184
1235
  " GENTLE_SHELL_PI Path to the pi executable to run.",
1185
1236
  " GENTLE_SHELL_HOME Directory for the isolated home (default: ~/.gentle-shell/agent).",
@@ -0,0 +1,54 @@
1
+ import { realpathSync, readFileSync } from "node:fs";
2
+ import { join, relative, isAbsolute } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ // Resolve through the switched version, never the old launcher's captured pins.
6
+ export async function resolveStartupRelaunch(input: {
7
+ root: string; home: string; platform: NodeJS.Platform; env: NodeJS.ProcessEnv; argv: string[];
8
+ }): Promise<{ command: string; args: string[]; env: NodeJS.ProcessEnv }> {
9
+ const { activeVersion, prefixLayout } = await import("../scripts/bundled-install.mjs");
10
+ const layout = prefixLayout(input);
11
+ const id = activeVersion(layout);
12
+ if (!id) throw new Error("No active Gentle Shell after upgrade");
13
+ const versions = realpathSync(layout.versions);
14
+ const version = realpathSync(join(versions, id));
15
+ const inside = (root: string, file: string) => {
16
+ const path = relative(root, file);
17
+ return path !== "" && !path.startsWith("..") && !isAbsolute(path);
18
+ };
19
+ if (!inside(versions, version) || readFileSync(join(version, ".gentle-shell-version"), "utf8") !== `${id}\n`) {
20
+ throw new Error("Invalid active Gentle Shell version");
21
+ }
22
+ const pkg = join(version, "node_modules", "gentle-pi");
23
+ const modulePath = realpathSync(join(pkg, "scripts", "bundled-install.mjs"));
24
+ const entry = realpathSync(join(pkg, "bin", "gentle-shell.mjs"));
25
+ if (!inside(version, modulePath) || !inside(version, entry)) throw new Error("Active launcher escaped its version");
26
+ const release = await import(pathToFileURL(modulePath).href);
27
+ const next = release.prefixLayout(input);
28
+ return { command: next.node, args: [entry, ...input.argv], env: { ...input.env, GENTLE_SHELL_SKIP_STARTUP_UPDATE: "1" } };
29
+ }
30
+
31
+ // Only an explicit update selection may cross the existing upgrade boundary.
32
+ export async function applyStartupChoice(choice: "update" | "skip" | "omit" | "cancel", effects: {
33
+ omit: () => void;
34
+ upgrade: () => Promise<number>;
35
+ relaunch: () => Promise<number>;
36
+ warn?: (message: string) => void;
37
+ }): Promise<number | undefined> {
38
+ if (choice === "cancel") return 130;
39
+ if (choice === "omit") {
40
+ try { effects.omit(); }
41
+ catch { effects.warn?.("Could not remember the skipped release; continuing without saving."); }
42
+ }
43
+ if (choice !== "update") return undefined;
44
+ if (await effects.upgrade() !== 0) return undefined;
45
+ // A failed relaunch must not fall through to the captured old packageRoot.
46
+ return effects.relaunch();
47
+ }
48
+
49
+ export function omitStartupVersion(read: () => string | undefined, write: (text: string) => void, version: string): void {
50
+ const text = read();
51
+ const config = text === undefined ? {} : JSON.parse(text);
52
+ if (config === null || typeof config !== "object" || Array.isArray(config)) throw new Error("Invalid launcher config");
53
+ write(`${JSON.stringify({ ...config, skippedStartupRelease: version }, null, 2)}\n`);
54
+ }
@@ -0,0 +1,92 @@
1
+ import type { ParsedLauncherArgs } from "./gentle-shell-launcher.ts";
2
+
3
+ export interface StartupUpdateOffer {
4
+ current: string;
5
+ latest: string;
6
+ notesUrl: string;
7
+ }
8
+
9
+ export interface StartupUpdateCheckOptions {
10
+ args: ParsedLauncherArgs;
11
+ env: Record<string, string | undefined>;
12
+ bundled: boolean;
13
+ inputTTY: boolean;
14
+ outputTTY: boolean;
15
+ }
16
+
17
+ export interface StartupUpdateLookupOptions {
18
+ current: string;
19
+ skipped?: string;
20
+ lookup: (signal: AbortSignal) => Promise<string | undefined>;
21
+ timeoutMs?: number;
22
+ }
23
+
24
+ export function shouldCheckStartupUpdate({ args, env, bundled, inputTTY, outputTTY }: StartupUpdateCheckOptions): boolean {
25
+ if (!bundled || !inputTTY || !outputTTY || args.command || args.piSubcommand || args.error || args.help || args.version || args.packageRoot !== undefined) {
26
+ return false;
27
+ }
28
+ if (env.GENTLE_PI_AGENTS_CHILD || env.PI_OFFLINE || env.GENTLE_SHELL_SKIP_STARTUP_UPDATE) {
29
+ return false;
30
+ }
31
+
32
+ // An allowlist keeps new command modes from accidentally showing a prompt.
33
+ for (let i = 0; i < args.passthrough.length; i += 1) {
34
+ const token = args.passthrough[i];
35
+ if (token === "--continue" || token === "-c") continue;
36
+ if (token.startsWith("--resume=") && token.length > "--resume=".length) continue;
37
+ if (token === "--resume" || token === "-r") {
38
+ const next = args.passthrough[i + 1];
39
+ if (next !== undefined && !next.startsWith("-")) i += 1;
40
+ continue;
41
+ }
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+
47
+ function stableParts(version: string): string[] | undefined {
48
+ // No leading zeros, prefixes, whitespace, prereleases or build metadata.
49
+ const match = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/.exec(version);
50
+ return match && match[0] === version ? match.slice(1) : undefined;
51
+ }
52
+
53
+ function isNewer(latest: string[], current: string[]): boolean {
54
+ for (let i = 0; i < 3; i += 1) {
55
+ if (latest[i] === current[i]) continue;
56
+ // Decimal string comparison avoids rounding even for arbitrarily large parts.
57
+ return latest[i].length !== current[i].length
58
+ ? latest[i].length > current[i].length
59
+ : latest[i] > current[i];
60
+ }
61
+ return false;
62
+ }
63
+
64
+ export async function findStartupUpdate({ current, skipped, lookup, timeoutMs = 1500 }: StartupUpdateLookupOptions): Promise<StartupUpdateOffer | undefined> {
65
+ const currentParts = stableParts(current);
66
+ if (!currentParts) return undefined;
67
+ const controller = new AbortController();
68
+ const deadline = Number.isFinite(timeoutMs) && timeoutMs >= 0 && timeoutMs <= 2_147_483_647 ? timeoutMs : 1500;
69
+ let timer: ReturnType<typeof setTimeout> | undefined;
70
+ try {
71
+ const timeout = new Promise<undefined>((resolve) => {
72
+ timer = setTimeout(() => {
73
+ resolve(undefined);
74
+ controller.abort();
75
+ }, deadline);
76
+ });
77
+ // The race bounds startup even if the injected lookup ignores cancellation.
78
+ const latest = await Promise.race([lookup(controller.signal), timeout]);
79
+ if (latest === undefined || latest === skipped) return undefined;
80
+ const latestParts = stableParts(latest);
81
+ if (!latestParts || !isNewer(latestParts, currentParts)) return undefined;
82
+ return {
83
+ current,
84
+ latest,
85
+ notesUrl: `https://github.com/Gentleman-Programming/gentle-shell/releases/tag/v${latest}`,
86
+ };
87
+ } catch {
88
+ return undefined;
89
+ } finally {
90
+ clearTimeout(timer);
91
+ }
92
+ }