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
@@ -0,0 +1,161 @@
1
+ #!/bin/sh
2
+ # Opt-in Linux clean-machine acceptance for the browser installation wizard.
3
+ # Runs the real bootstrap and wizard inside a disposable debian:bookworm-slim
4
+ # container as a non-root user. Network access happens only inside that
5
+ # container; nothing reads or writes the host HOME. Not part of CI.
6
+ #
7
+ # Usage: sh scripts/test-installer-acceptance.sh [--worktree]
8
+ # default bundle = `git archive HEAD`
9
+ # --worktree bundle = tracked files as they are in the working tree,
10
+ # including uncommitted modifications (untracked files excluded)
11
+ # GENTLE_ACCEPTANCE_KEEP=1 keeps a failed run's container for inspection.
12
+ set -eu
13
+ fail() { printf 'acceptance: %s\n' "$1" >&2; exit 1; }
14
+ note() { printf 'acceptance: %s\n' "$1"; }
15
+ source_mode='head'
16
+ case $# in
17
+ 0) ;;
18
+ 1) [ "$1" = --worktree ] || fail "unknown argument: $1"; source_mode=worktree;;
19
+ *) fail 'usage: sh scripts/test-installer-acceptance.sh [--worktree]';;
20
+ esac
21
+ image=debian:bookworm-slim
22
+ # Upper bound for the whole installation inside the container.
23
+ install_limit=${GENTLE_ACCEPTANCE_INSTALL_SECONDS:-1500}
24
+ case $install_limit in ''|*[!0-9]*) fail 'GENTLE_ACCEPTANCE_INSTALL_SECONDS must be a whole number';; esac
25
+ command -v docker >/dev/null 2>&1 || fail 'Docker is required; refusing to run anything on the host'
26
+ docker info >/dev/null 2>&1 || fail 'Docker daemon is unavailable; refusing to run anything on the host'
27
+ command -v git >/dev/null 2>&1 || fail 'git is required to package the bundle'
28
+ repo=$(git rev-parse --show-toplevel) || fail 'run from inside the repository'
29
+ started=$(date +%s)
30
+ elapsed() { printf '%ss' "$(( $(date +%s) - started ))"; }
31
+ name=gentle-install-acceptance-$$-$started
32
+ container=
33
+ passed=0
34
+ cleanup() {
35
+ if [ -n "$container" ] && [ "$passed" = 0 ] && [ "${GENTLE_ACCEPTANCE_KEEP:-}" = 1 ]; then
36
+ printf 'acceptance: kept %s; inspect with: docker exec -it -u tester %s bash; remove with: docker rm -f %s\n' "$container" "$container" "$container" >&2
37
+ elif [ -n "$container" ]; then
38
+ docker rm -f "$container" >/dev/null 2>&1 || printf 'acceptance: could not remove container %s\n' "$container" >&2
39
+ fi
40
+ }
41
+ trap cleanup EXIT
42
+ trap 'exit 1' HUP INT TERM
43
+
44
+ note "image $image, bundle from $source_mode"
45
+ docker run -d --name "$name" --pull missing "$image" sleep infinity >/dev/null || fail 'cannot start the container'
46
+ container=$name
47
+ # Clean machine: no Node, npm, pnpm, Pi or Gentle Shell. curl and CA roots are
48
+ # bootstrap prerequisites that a stock Debian desktop already has.
49
+ docker exec "$container" sh -c 'export DEBIAN_FRONTEND=noninteractive
50
+ apt-get update -qq >/dev/null && apt-get install -y -qq --no-install-recommends ca-certificates curl >/dev/null
51
+ useradd --create-home --shell /bin/bash tester
52
+ mkdir /opt/bundle
53
+ for tool in node npm pnpm pi gentle-shell; do if command -v "$tool" >/dev/null; then echo "unexpected $tool" >&2; exit 1; fi; done' \
54
+ || fail 'container preparation failed'
55
+ # gentle-shell setup makes 2 anonymous GitHub API requests (upstream Gentle AI's
56
+ # latest-engram lookup), limited to 60 per hour per public IP. /rate_limit does
57
+ # not consume quota. Stop early instead of failing deep inside setup.
58
+ quota=$(docker exec "$container" sh -c 'curl -fsS --max-time 20 -H "Accept: application/vnd.github+json" https://api.github.com/rate_limit' | tr -d ' \n') \
59
+ || fail 'cannot query the GitHub API rate limit from the container'
60
+ rate=$(printf '%s' "$quota" | sed -n 's/.*"rate":{\([^}]*\)}.*/\1/p')
61
+ remaining=$(printf '%s' "$rate" | sed -n 's/.*"remaining":\([0-9]*\).*/\1/p')
62
+ reset=$(printf '%s' "$rate" | sed -n 's/.*"reset":\([0-9]*\).*/\1/p')
63
+ [ -n "$remaining" ] && [ -n "$reset" ] || fail 'unexpected GitHub rate limit response'
64
+ reset_at=$(date -u -d "@$reset" '+%Y-%m-%d %H:%M:%S UTC' 2>/dev/null || date -u -r "$reset" '+%Y-%m-%d %H:%M:%S UTC' 2>/dev/null || printf 'epoch %s' "$reset")
65
+ if [ "$remaining" -lt 5 ]; then
66
+ fail "only $remaining anonymous GitHub API requests remain on this network (setup needs 2); the quota resets at $reset_at. Not starting."
67
+ fi
68
+ note "GitHub API quota: $remaining anonymous requests left (resets at $reset_at)"
69
+ if [ "$source_mode" = head ]; then
70
+ git -C "$repo" archive --format=tar HEAD
71
+ else
72
+ git -C "$repo" ls-files -z | tar -C "$repo" --null -T - -cf -
73
+ fi | docker exec -i "$container" tar --no-same-owner -xf - -C /opt/bundle || fail 'cannot copy the bundle'
74
+ note "prepared in $(elapsed)"
75
+
76
+ bootstrap_started=$(date +%s)
77
+ # A terminal session exports SHELL (the user's login shell); docker exec does
78
+ # not. pnpm setup needs it to pick the profile to edit, and fails with
79
+ # ERR_PNPM_UNKNOWN_SHELL without it.
80
+ docker exec -d -u tester -w /home/tester -e SHELL=/bin/bash "$container" sh -c \
81
+ 'sh /opt/bundle/scripts/bootstrap.sh > "$HOME/bootstrap.log" 2>&1; echo $? > "$HOME/bootstrap.status"' \
82
+ || fail 'cannot start the bootstrap'
83
+
84
+ # Headless browser stand-in: the same requests the wizard page makes.
85
+ driver=$(cat <<'DRIVER'
86
+ set -eu
87
+ log=$HOME/bootstrap.log
88
+ say() { printf 'driver: %s\n' "$1"; }
89
+ stop() { say "$1"; cat "$log" 2>/dev/null || :; exit 1; }
90
+ waited=0
91
+ while :; do
92
+ url=$(grep -o 'http://127\.0\.0\.1:[0-9]*/session?code=[A-Za-z0-9_-]*' "$log" 2>/dev/null | head -n 1) || url=
93
+ [ -z "$url" ] || break
94
+ [ ! -f "$HOME/bootstrap.status" ] || stop 'bootstrap exited before printing the session URL'
95
+ waited=$((waited + 1)); [ "$waited" -lt 600 ] || stop 'no session URL after 600 s'
96
+ sleep 1
97
+ done
98
+ say "session URL after ${waited}s"
99
+ origin=${url%%/session*}
100
+ jar=$HOME/acceptance-cookies
101
+ curl -fsS -c "$jar" -b "$jar" -o /dev/null "$url" || stop 'session redemption failed'
102
+ api() { curl -fsS -b "$jar" -H 'X-Gentle-Install: 1' "$@"; }
103
+ post() { api -X POST -H "Origin: $origin" -H 'Content-Type: application/json' --data "$1" "$origin$2"; }
104
+ plan=$(api "$origin/api/plan") || stop 'plan request failed'
105
+ case $plan in *'"blockers":[]'*) ;; *) stop "plan has blockers: $plan";; esac
106
+ plan_id=$(printf '%s' "$plan" | sed -n 's/.*"planId":"\([^"]*\)".*/\1/p')
107
+ [ -n "$plan_id" ] || stop "plan has no planId: $plan"
108
+ say "plan: $(printf '%s' "$plan" | grep -o '"actions":\[[^]]*\]' | grep -o '"id":"[^"]*"' | cut -d'"' -f4 | tr '\n' ' ')"
109
+ post "{\"planId\":\"$plan_id\",\"consent\":true}" /api/install >/dev/null || stop 'install request rejected'
110
+ seq=0
111
+ polls=0
112
+ while :; do
113
+ progress=$(api "$origin/api/progress?after=$seq") || stop 'progress request failed'
114
+ printf '%s' "$progress" | grep -o '"step":"[^"]*","status":"[^"]*"' | sed 's/"step":"\([^"]*\)","status":"\([^"]*\)"/ step \1: \2/' || :
115
+ last=$(printf '%s' "$progress" | grep -o '"seq":[0-9]*' | tail -n 1 | cut -d: -f2) || last=
116
+ [ -z "$last" ] || seq=$last
117
+ case $progress in *'"running":false'*'"outcome":{'*) break;; esac
118
+ polls=$((polls + 1)); [ "$polls" -lt "$INSTALL_LIMIT" ] || stop "installation still running after $INSTALL_LIMIT s"
119
+ sleep 1
120
+ done
121
+ outcome=$(printf '%s' "$progress" | sed -n 's/.*"outcome":{"outcome":"\([a-z-]*\)".*/\1/p')
122
+ say "outcome: $outcome"
123
+ post '{}' /api/shutdown >/dev/null || stop 'shutdown request rejected'
124
+ waited=0
125
+ until [ -f "$HOME/bootstrap.status" ]; do
126
+ waited=$((waited + 1)); [ "$waited" -lt 60 ] || stop 'bootstrap still running 60 s after shutdown'
127
+ sleep 1
128
+ done
129
+ status=$(cat "$HOME/bootstrap.status")
130
+ say "bootstrap exit status: $status"
131
+ cat "$log"
132
+ case $outcome in ready|terminal-action-required) [ "$status" = 0 ] || exit 1;; *) exit 1;; esac
133
+ DRIVER
134
+ )
135
+ printf '%s\n' "$driver" | docker exec -i -u tester -w /home/tester -e INSTALL_LIMIT="$install_limit" "$container" sh -s \
136
+ || fail "wizard flow failed after $(elapsed)"
137
+ note "bootstrap and wizard finished in $(( $(date +%s) - bootstrap_started ))s"
138
+
139
+ # A fresh interactive shell must find the persisted stack; the bootstrap tools
140
+ # must be gone. bash -i without a terminal warns about job control; harmless.
141
+ checks=$(cat <<'CHECKS'
142
+ set -eu
143
+ for tool in node npm pnpm gentle-shell; do printf '%s -> %s\n' "$tool" "$(command -v "$tool")"; done
144
+ printf 'node %s, npm %s, pnpm %s\n' "$(node --version)" "$(npm --version)" "$(pnpm --version)"
145
+ gentle-shell --version
146
+ for dir in "$HOME"/.gentle-shell-bootstrap-tools.*; do
147
+ if [ -e "$dir" ] || [ -L "$dir" ]; then echo "bootstrap tools left behind: $dir" >&2; exit 1; fi
148
+ done
149
+ echo 'bootstrap tools removed'
150
+ CHECKS
151
+ )
152
+ docker exec -u tester -w /home/tester "$container" bash -ic "$checks" || fail "fresh-terminal checks failed after $(elapsed)"
153
+ # Informational: pnpm setup edits only ~/.bashrc, which non-interactive login
154
+ # shells skip on Debian (see docs/install-wizard.md).
155
+ if docker exec -u tester -w /home/tester "$container" bash -lc 'command -v gentle-shell' >/dev/null 2>&1; then
156
+ note 'bash -lc resolves gentle-shell'
157
+ else
158
+ note 'bash -lc does not resolve gentle-shell (expected: ~/.profile is not edited)'
159
+ fi
160
+ passed=1
161
+ note "PASS in $(elapsed)"
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import assert from "node:assert/strict";
4
+ import { normalizeNpmPackResult, parseNpmPackResult } from "./npm-pack-result.mjs";
4
5
  import { execFileSync, spawn } from "node:child_process";
5
6
  import { createHash } from "node:crypto";
6
7
  import { existsSync, lstatSync, mkdtempSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
@@ -599,6 +600,23 @@ function runWindowsStartupTimingProbe(runtimeScript, env, cwd) {
599
600
  });
600
601
  }
601
602
 
603
+ export function createHookedPackedConsumerManifest(installDirectory, tarball) {
604
+ const ownedTarball = assertOwnedRegularFile(dirname(tarball), basename(tarball));
605
+ const consumer = realpathSync.native(installDirectory);
606
+ const canonicalTarball = realpathSync.native(ownedTarball);
607
+ const filePath = relative(consumer, canonicalTarball);
608
+ if (isAbsolute(filePath)) throw new Error("packed tarball must share the consumer filesystem root");
609
+ const fileSpec = `file:${filePath.split(sep).join("/")}`;
610
+ if (realpathSync.native(resolve(consumer, fileSpec.slice(5))) !== canonicalTarball) throw new Error("script approval does not resolve to the packed tarball");
611
+ // npm 12 matches local dependencies by their resolved file spec, not name.
612
+ // Absolute installs on npm 12 retain an absolute node.resolved; the relative
613
+ // key alone was empirically blocked. Both keys identify this same tarball.
614
+ // Older npm ignores this consumer-only field. No transitive script is approved.
615
+ const absoluteSpec = `file:${canonicalTarball.split(sep).join("/")}`;
616
+ if (realpathSync.native(absoluteSpec.slice(5)) !== canonicalTarball) throw new Error("absolute script approval does not resolve to the packed tarball");
617
+ return { name: "gentle-pi-packed-runner-test", private: true, allowScripts: { [fileSpec]: true, [absoluteSpec]: true } };
618
+ }
619
+
602
620
  async function testHookedPackedRunner() {
603
621
  const temporary = mkdtempSync(join(tmpdir(), "gentle-pi-packed-runner-"));
604
622
  const packDirectory = join(temporary, "pack");
@@ -615,14 +633,14 @@ async function testHookedPackedRunner() {
615
633
  mkdirSync(piAgentHome);
616
634
  const originalSettings = '{ "tuiMode": "regular", "theme": "packed-fixture" }\n';
617
635
  writeFileSync(join(agentHome, "settings.json"), originalSettings);
618
- const packed = JSON.parse(runNpm(["pack", "--ignore-scripts", "--json", "--pack-destination", packDirectory], {
636
+ const packed = parseNpmPackResult(runNpm(["pack", "--ignore-scripts", "--json", "--pack-destination", packDirectory], {
619
637
  cwd: root,
620
638
  encoding: "utf8",
621
639
  stdio: ["ignore", "pipe", "inherit"],
622
640
  }));
623
641
  if (packed.length !== 1 || typeof packed[0]?.filename !== "string") throw new Error("npm pack did not return one tarball");
624
- const tarball = join(packDirectory, packed[0].filename);
625
- writeFileSync(join(installDirectory, "package.json"), JSON.stringify({ name: "gentle-pi-packed-runner-test", private: true }), "utf8");
642
+ const { tarball } = assertPackResult(packed, packDirectory, newUnhookedReceipt());
643
+ writeFileSync(join(installDirectory, "package.json"), JSON.stringify(createHookedPackedConsumerManifest(installDirectory, tarball)), "utf8");
626
644
  runNpm(["install", "--ignore-scripts=false", "--no-audit", "--no-fund", "--package-lock=false", "--omit=dev", "--legacy-peer-deps", tarball], {
627
645
  cwd: installDirectory,
628
646
  stdio: "inherit",
@@ -657,6 +675,7 @@ async function testHookedPackedRunner() {
657
675
  assert.ok(!abandonAuthorization.includes("evidence_records_present"));
658
676
  // Accept prerelease pins too: a stable-only pattern here was a second,
659
677
  // silent pin that refused the first prerelease version directory.
678
+ if (!existsSync(join(packageRoot, ".gentle-ai"))) throw new Error("packed postinstall did not create .gentle-ai; npm may have blocked lifecycle scripts — check the consumer allowScripts exact tarball approval and installer output");
660
679
  const versions = readdirSync(join(packageRoot, ".gentle-ai"), { withFileTypes: true }).filter((entry) => entry.isDirectory() && /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z][0-9A-Za-z.]*)?$/.test(entry.name));
661
680
  if (versions.length !== 1) throw new Error("packed install did not contain exactly one package-local Gentle AI version");
662
681
  const executable = join(packageRoot, ".gentle-ai", versions[0].name, process.platform === "win32" ? "gentle-ai.exe" : "gentle-ai");
@@ -801,8 +820,7 @@ export function validateWindowsStartupTimingMachinePaths(delta, operations = { l
801
820
 
802
821
  function assertPackResult(packed, packDirectory, receipt) {
803
822
  selectUnhookedCheck(receipt, "pack-metadata");
804
- if (!Array.isArray(packed) || packed.length !== 1 || !packed[0] || typeof packed[0] !== "object") throw new Error("npm pack did not return exactly one package");
805
- const entry = packed[0];
823
+ const [entry] = normalizeNpmPackResult(packed);
806
824
  if (entry.name !== "gentle-pi" || typeof entry.filename !== "string" || entry.filename !== basename(entry.filename)) throw new Error("npm pack returned an unsafe package identity");
807
825
  if (typeof entry.integrity !== "string" || !/^sha512-[A-Za-z0-9+/]+={0,2}$/.test(entry.integrity)) throw new Error("npm pack did not report a sha512 integrity");
808
826
  const tarball = resolve(packDirectory, entry.filename);
@@ -1,95 +1,5 @@
1
1
  {
2
2
  "note": "Recorded TypeScript diagnostics. Regenerate with `node scripts/check-types.mjs --update` after fixing or deliberately accepting diagnostics. This file may only shrink without a review decision.",
3
- "total": 200,
4
- "byFileAndCode": {
5
- "extensions/codegraph-tools.ts TS2339": 1,
6
- "extensions/codegraph-tools.ts TS2345": 1,
7
- "extensions/gentle-agents.ts TS2322": 3,
8
- "extensions/gentle-ai.ts TS2322": 5,
9
- "extensions/gentle-ai.ts TS2339": 11,
10
- "extensions/gentle-ai.ts TS2345": 15,
11
- "extensions/gentle-ai.ts TS2365": 1,
12
- "extensions/gentle-ai.ts TS2488": 2,
13
- "extensions/gentle-ai.ts TS2554": 1,
14
- "extensions/gentle-ai.ts TS2740": 1,
15
- "extensions/gentle-shell.ts TS2556": 1,
16
- "extensions/quiet-tools.ts TS2339": 1,
17
- "extensions/quiet-tools.ts TS2352": 2,
18
- "lib/agents-messaging.ts TS2322": 1,
19
- "lib/native-review-cli.ts TS2304": 6,
20
- "lib/native-review-cli.ts TS2339": 1,
21
- "lib/native-review-cli.ts TS2345": 1,
22
- "lib/review-candidate-view.ts TS2353": 2,
23
- "lib/review-compact-contract.ts TS2322": 2,
24
- "lib/review-compact-contract.ts TS2365": 1,
25
- "lib/review-integration-v2.ts TS2322": 2,
26
- "lib/review-integration-v2.ts TS2352": 2,
27
- "lib/review-publication-gate.ts TS2365": 2,
28
- "lib/review-transaction.ts TS2322": 1,
29
- "lib/review-transaction.ts TS2345": 1,
30
- "lib/runtime-metrics-children.ts TS2345": 2,
31
- "lib/sdd-preflight.ts TS2352": 1,
32
- "lib/sdd-preflight.ts TS2365": 1,
33
- "lib/shell-sidebar-layout.ts TS2341": 1,
34
- "tests/agents-queries.test.ts TS2322": 1,
35
- "tests/agents-queries.test.ts TS2345": 3,
36
- "tests/agents-runner-process.test.ts TS2322": 1,
37
- "tests/devbinary/native-review-parity.devtest.ts TS2339": 1,
38
- "tests/devbinary/pi-host-relay.devtest.ts TS2339": 3,
39
- "tests/gentle-ai-binary.test.ts TS2339": 2,
40
- "tests/gentle-ai-installer.test.ts TS2339": 7,
41
- "tests/gentle-ai-installer.test.ts TS2556": 1,
42
- "tests/gentle-ai-renderer.test.ts TS2345": 6,
43
- "tests/gentle-ai.test.ts TS2339": 1,
44
- "tests/gentle-ai.test.ts TS2352": 8,
45
- "tests/gentle-ai.test.ts TS2353": 1,
46
- "tests/gentle-shell.test.ts TS2352": 1,
47
- "tests/gentle-shell.test.ts TS2540": 1,
48
- "tests/gentle-shell.test.ts TS2554": 1,
49
- "tests/maintainer/provider-relay.maintest.ts TS2339": 17,
50
- "tests/maintainer/provider-relay.maintest.ts TS2345": 1,
51
- "tests/maintainer/provider-relay.maintest.ts TS2540": 2,
52
- "tests/native-binary-gate.test.ts TS2339": 2,
53
- "tests/native-review-consent.test.ts TS2554": 1,
54
- "tests/native-review-parity-runtime.test.ts TS2339": 1,
55
- "tests/quiet-tool-rendering.test.ts TS2339": 1,
56
- "tests/quiet-tool-rendering.test.ts TS2345": 1,
57
- "tests/review-agent-end-preflight.test.ts TS2339": 2,
58
- "tests/review-agent-end-preflight.test.ts TS2345": 1,
59
- "tests/review-candidate-view.test.ts TS2353": 4,
60
- "tests/review-candidate-view.test.ts TS2540": 2,
61
- "tests/review-candidate-view.test.ts TS2554": 2,
62
- "tests/review-controller-native-recovery.test.ts TS2345": 1,
63
- "tests/review-controller-native-routing.test.ts TS2339": 2,
64
- "tests/review-controller-workspace-root.test.ts TS2322": 2,
65
- "tests/review-correction-lifecycle.test.ts TS2339": 4,
66
- "tests/review-gate.test.ts TS2322": 5,
67
- "tests/review-gate.test.ts TS2345": 4,
68
- "tests/review-gate.test.ts TS2740": 1,
69
- "tests/review-graph-schema.test.ts TS2352": 2,
70
- "tests/review-host-relay-routing.test.ts TS2345": 1,
71
- "tests/review-host-relay-routing.test.ts TS2739": 1,
72
- "tests/review-integration-v2-forward.test.ts TS2322": 1,
73
- "tests/review-last-event-closure.test.ts TS2322": 1,
74
- "tests/review-policy-judgment-day.test.ts TS2345": 1,
75
- "tests/review-policy-ordinary.test.ts TS2345": 1,
76
- "tests/review-policy-ordinary.test.ts TS2554": 1,
77
- "tests/review-risk-assessment.test.ts TS2345": 1,
78
- "tests/review-risk-assessment.test.ts TS2352": 1,
79
- "tests/review-session-standing-permission-controller.test.ts TS2339": 1,
80
- "tests/review-session-standing-permission-controller.test.ts TS2345": 1,
81
- "tests/review-session-standing-permission-controller.test.ts TS2352": 1,
82
- "tests/review-session-standing-permission-ipc.test.ts TS2322": 4,
83
- "tests/review-test-fixtures.ts TS2739": 1,
84
- "tests/review-transaction.test.ts TS2339": 1,
85
- "tests/runtime-metrics-extension.test.ts TS2345": 1,
86
- "tests/sdd-preflight.test.ts TS2352": 1,
87
- "tests/sdd-preflight.test.ts TS2554": 2,
88
- "tests/sdd-research-live.test.ts TS2322": 1,
89
- "tests/shell-sidebar-layout.test.ts TS2339": 1,
90
- "tests/shell-sidebar-layout.test.ts TS2345": 1,
91
- "tests/shell-usage-view.test.ts TS2322": 1,
92
- "tests/skill-registry.test.ts TS2345": 5,
93
- "tests/writer-edit-surface-scope.test.ts TS2352": 1
94
- }
3
+ "total": 0,
4
+ "byFileAndCode": {}
95
5
  }
@@ -7,10 +7,56 @@ import { fileURLToPath, pathToFileURL } from "node:url";
7
7
 
8
8
  const root = join(fileURLToPath(new URL("..", import.meta.url)));
9
9
 
10
- const requiredPaths = [
10
+ // Browser installation wizard: bootstrap scripts, entry, host and static assets.
11
+ export const installerPaths = Object.freeze([
12
+ "bin/gentle-shell-install.mjs",
13
+ "scripts/installer-server.mjs",
14
+ "scripts/installer-runner.mjs",
15
+ "scripts/installer-preflight.mjs",
16
+ "scripts/installer-probes.mjs",
17
+ "scripts/installer-downloads.mjs",
18
+ "scripts/main-channel.mjs",
19
+ "scripts/installer-windows.mjs",
20
+ "scripts/installer-windows-artifacts.json",
21
+ "scripts/bundled-wizard.mjs",
22
+ "scripts/bundled-install.mjs",
23
+ "scripts/bootstrap.sh",
24
+ "scripts/bootstrap.cmd",
25
+ "assets/install-wizard/index.html",
26
+ "assets/install-wizard/wizard.js",
27
+ "assets/install-wizard/wizard.css",
28
+ ]);
29
+
30
+ export const requiredPaths = [
11
31
  "bin/gentle-shell.mjs",
32
+ ...installerPaths,
33
+ "extensions/gentle-notifications.ts",
34
+ "lib/notification-audio.ts",
35
+ "lib/notification-audio-native.ts",
36
+ "lib/notification-audio-windows.ts",
37
+ "lib/notification-pulse-protocol.ts",
38
+ "lib/notification-pulse-client.ts",
39
+ "lib/notification-pulse-stream.ts",
40
+ "lib/notification-pulse-worker.ts",
41
+ "lib/notification-customize.ts",
42
+ "lib/notification-events.ts",
43
+ "lib/notification-policy.ts",
44
+ "lib/notification-scheduler.ts",
45
+ "lib/notification-service.ts",
46
+ "lib/notification-ui.ts",
47
+ "assets/sounds/success.wav",
48
+ "assets/sounds/error.wav",
49
+ "assets/sounds/attention.wav",
50
+ "assets/sounds/LICENSE.md",
51
+ "docs/sound-notifications.md",
52
+ "docs/sound-notifications-proposal.md",
53
+ "scripts/npm-pack-result.mjs",
12
54
  "assets/orchestrator.md",
13
55
  "assets/orchestrator-delegation.md",
56
+ "assets/orchestrator-tracking.md",
57
+ "assets/orchestrator-verification.md",
58
+ "assets/orchestrator-writer.md",
59
+ "assets/orchestrator-prompts.md",
14
60
  "assets/orchestrator-memory.md",
15
61
  "assets/orchestrator-skills.md",
16
62
  "assets/agents/gentle-ai-explore.md",
@@ -36,20 +82,33 @@ const requiredPaths = [
36
82
  "extensions/gentle-ai.ts",
37
83
  "extensions/resume-hint.ts",
38
84
  "extensions/skill-registry.ts",
85
+ "lib/child-package-injection.ts",
39
86
  "lib/gentle-ai-binary.ts",
40
87
  "lib/gentle-shell-launcher.ts",
88
+ "lib/gentle-shell-bundled.ts",
89
+ "lib/gentle-shell-startup-update.ts",
90
+ "lib/gentle-shell-update-panel.ts",
91
+ "lib/gentle-shell-startup-flow.ts",
41
92
  "lib/gentle-shell-resume-hint.ts",
42
93
  "lib/native-review-cli.ts",
94
+ "lib/status-timing-diagnostics.ts",
43
95
  "lib/provider-contract-bundle.ts",
44
96
  "lib/review-host-relay.ts",
45
97
  "lib/review-integration-v2.ts",
46
98
  "lib/review-relay-contract.ts",
47
99
  "lib/agent-assets.ts",
48
100
  "lib/telemetry-trigger.ts",
101
+ "runtime/child-package-injection.mjs",
49
102
  "runtime/gentle-ai-binary.mjs",
50
103
  "runtime/gentle-shell-launcher.mjs",
104
+ "runtime/gentle-shell-bundled.mjs",
105
+ "runtime/gentle-shell-startup-update.mjs",
106
+ "runtime/gentle-shell-update-panel.mjs",
107
+ "runtime/gentle-shell-startup-flow.mjs",
51
108
  "runtime/gentle-shell-resume-hint.mjs",
109
+ "runtime/gentle-shell-uninstall.mjs",
52
110
  "runtime/native-review-cli.mjs",
111
+ "runtime/status-timing-diagnostics.mjs",
53
112
  "runtime/review-integration-v2.mjs",
54
113
  "runtime/review-risk-assessment.mjs",
55
114
  "runtime/review-relay-contract.mjs",
@@ -72,17 +131,17 @@ const requiredPaths = [
72
131
  // exact bytes are pinned by the lock-driven scripts/check-provider-contract.mjs
73
132
  // drift check, which runs in the same pnpm test flow.
74
133
  "contracts/review-provider-contract-mirror/provider-contract.lock.json",
75
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/README.md",
76
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/manifest.json",
77
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/orchestration/pi.md",
78
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/schemas/lens.schema.json",
79
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/schemas/refuter.schema.json",
80
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/schemas/targeted-validator.schema.json",
81
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/vectors/lens.json",
82
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/vectors/refuter.json",
83
- "contracts/review-provider-contract-mirror/v1.2.0/bundle/vectors/targeted-validator.json",
84
- "contracts/review-provider-contract-mirror/v1.2.0/generated/provider-capabilities.baseline.json",
85
- "contracts/review-provider-contract-mirror/v1.2.0/generated/provider-roles.baseline.json",
134
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/README.md",
135
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/manifest.json",
136
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/orchestration/pi.md",
137
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/schemas/lens.schema.json",
138
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/schemas/refuter.schema.json",
139
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/schemas/targeted-validator.schema.json",
140
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/vectors/lens.json",
141
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/vectors/refuter.json",
142
+ "contracts/review-provider-contract-mirror/v1.3.0/bundle/vectors/targeted-validator.json",
143
+ "contracts/review-provider-contract-mirror/v1.3.0/generated/provider-capabilities.baseline.json",
144
+ "contracts/review-provider-contract-mirror/v1.3.0/generated/provider-roles.baseline.json",
86
145
  "prompts/skill-creation.md",
87
146
  "skills/_shared/review-ledger-contract.md",
88
147
  "skills/branch-pr/SKILL.md",
@@ -173,6 +232,14 @@ const contractHashes = {
173
232
 
174
233
  requiredPaths.push(...Object.keys(contractHashes));
175
234
 
235
+ // Required package-relative paths that are missing or are not regular files.
236
+ export function missingRequiredPaths(packageRoot, paths) {
237
+ return paths.filter((relativePath) => {
238
+ const absolutePath = join(packageRoot, relativePath);
239
+ return !existsSync(absolutePath) || !statSync(absolutePath).isFile();
240
+ });
241
+ }
242
+
176
243
  function listFilesRecursively(directory) {
177
244
  return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
178
245
  const absolutePath = join(directory, entry.name);
@@ -287,10 +354,7 @@ async function main() {
287
354
  process.exit(1);
288
355
  }
289
356
 
290
- const missing = requiredPaths.filter((relativePath) => {
291
- const absolutePath = join(root, relativePath);
292
- return !existsSync(absolutePath) || !statSync(absolutePath).isFile();
293
- });
357
+ const missing = missingRequiredPaths(root, requiredPaths);
294
358
 
295
359
  if (missing.length > 0) {
296
360
  console.error("gentle-pi package is missing required Pi resources:");
@@ -331,7 +395,7 @@ async function main() {
331
395
  });
332
396
 
333
397
  if (driftedContracts.length > 0) {
334
- console.error("gentle-pi packaged review-integration/v1 and review-integration/v2 contract bytes drifted from the pinned v4.0.0 runtime's vendored Gentle AI contract artifacts:");
398
+ console.error("gentle-pi packaged review-integration/v1 and review-integration/v2 contract bytes drifted from the pinned v4.1.1 runtime's vendored Gentle AI contract artifacts:");
335
399
  for (const drift of driftedContracts) console.error(`- ${drift.relativePath}: expected ${drift.expected}, got ${drift.actual}`);
336
400
  process.exit(1);
337
401
  }
@@ -376,7 +440,7 @@ async function main() {
376
440
  process.exit(1);
377
441
  }
378
442
 
379
- console.log(`gentle-pi package resource check passed (${requiredPaths.length} files; ${Object.keys(contractHashes).length} exact byte-pinned contract artifacts for the v4.0.0 runtime).`);
443
+ console.log(`gentle-pi package resource check passed (${requiredPaths.length} files; ${Object.keys(contractHashes).length} exact byte-pinned contract artifacts for the v4.1.1 runtime).`);
380
444
  }
381
445
 
382
446
  const isMainModule = process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href;
@@ -14,11 +14,11 @@ When asked who or what you are, answer as el Gentleman: a Pi-specific coding-age
14
14
  ## Compact Rules
15
15
 
16
16
  - Clarify scope, constraints, acceptance criteria, and non-goals before implementation.
17
- - For substantial authorized ODD work, track the feature in its task document and mirror.
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
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 apply after complexity appears: reading beyond the evidence budget, 2+ non-trivial files to write, tooling/worktree incidents, or a parent context past the context backstop.
21
- - Keep writes single-threaded unless the user explicitly approves isolated parallel worktrees.
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,23 +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 + known context → inline direct
34
- unknown / context-heavy → simple delegation
35
- substantial authorized work → track ODD tasks and implement by work unit
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 bounded implementation with subagents:
38
+ For large implementation with subagents:
39
39
 
40
40
  ```text
41
- 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
42
42
  ```
43
43
 
44
44
  Hard delegation triggers:
45
45
 
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). Larger reading, more than ~5 sequential lookups, or a long session ahead means 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
- - **Multi-file write rule**: touching 2+ non-trivial files means use one worker.
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.
48
49
  - **Incident rule**: after wrong cwd, accidental worktree/repo mutation, merge recovery, confusing test command, or environment workaround, diagnose separately.
49
- - **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`) and send full suites and builds to a verifier.
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`).
50
51
 
51
52
  ## Review Lens Selection
52
53
 
@@ -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
- // Isolation must cover POSIX and Windows, the way homedir() resolves each.
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
+ });