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
@@ -4,6 +4,519 @@ An interactive RPC host — a client that runs `pi --mode rpc` itself, such as t
4
4
 
5
5
  Source map: [publisher](../lib/agents-rpc-publisher.ts), [wiring](../extensions/gentle-agents.ts), [store](../lib/agents-protocol.ts).
6
6
 
7
+ ## Same-profile orchestrator discovery (Refs #1701)
8
+
9
+ `orchestrator_list` keeps stable raw routing session IDs and adds recorded display
10
+ labels, session workspaces, and up to eight currently owned, unfinished child task
11
+ labels/statuses/launch workspaces. This is a metadata-only view, not the RPC payload
12
+ below: it exports no prompts, transcripts, thinking, or tool output and makes no
13
+ model calls or messaging requests.
14
+
15
+ Metadata lives in an optional private, 16-KiB derived sidecar, bound to the existing
16
+ session hash, presence incarnation/generation, and listener activation. Schema-1
17
+ headers are unchanged: missing or invalid sidecars never hide existing activity peers.
18
+ Only currently runtime-owned active tasks (running, queued, waiting) are published,
19
+ not finished tasks or restored running history: those are not potential future writers.
20
+
21
+ The transport registry selects its newest advertised activation per session (ties
22
+ use its existing deterministic token order). Context joins only that exact routing
23
+ snapshot, never another activation sharing its ID. Multiple matching presence headers,
24
+ malformed records, missing metadata, or an incomplete bounded scan leave context
25
+ unknown without hiding advertised peers. Recent means the existing 15-second presence
26
+ heartbeat window, not verified reachability. Stale records expose no context.
27
+ Reachability remains unknown even with recent metadata.
28
+
29
+ Paths longer than 120 characters or requiring control-character normalization are
30
+ unknown rather than misleadingly shortened. Labels are sanitized and bounded to
31
+ 120 characters; duplicate labels do not merge IDs. Additional child tasks are
32
+ counted as omitted. Task workspaces are recorded launch directories, not proof of
33
+ isolation, ownership locks, or exclusive access.
34
+
35
+ ### Declare a recognizable subject
36
+
37
+ Before delegation or cross-session coordination, call `orchestrator_session_id`
38
+ with a short, non-sensitive `subject`. Do not require a subject declaration for small direct tasks;
39
+ no peer survey or additional model call is needed. The tool
40
+ returns the stable routing ID, **Current alias (CURRENT TASK)**, **Initial alias
41
+ (FIRST TASK)**, and separate human **Session name**. An explicit `subject` updates
42
+ Current even when the session is named; Initial retains the first explicit topic
43
+ on the active branch. It uses Pi's `setSessionName` only when the canonical name
44
+ is empty, preserving existing names and later human renames. Human renames do not
45
+ change task aliases. Subjects are control-stripped, whitespace-normalized, and
46
+ bounded to 120 Unicode characters; invalid types and surrogates are rejected.
47
+ Do not supply arbitrary prompts or secrets.
48
+ Aliases are display hints, never authentication or routing identities.
49
+
50
+ Aliases are optional envelope metadata in the existing branch-local state record,
51
+ restored with `getBranch()` on start/reload/tree navigation. State replacement or
52
+ withdrawal preserves them; no subject preserves both. Subject-only declarations
53
+ preserve state contents, recorded cwd and `recordedAt`: old progress is not a fresh
54
+ status update. Publish subject and state together when changing work. New records
55
+ use null/null until the first declaration; legacy records without aliases keep
56
+ Initial unknown, including when a later Current topic is declared. Names and private
57
+ history never supply missing initial topics. Abandoned branches are not inspected.
58
+
59
+ Activation-bound discovery and metadata consultation expose `aliases.initialAlias`
60
+ and `aliases.currentAlias` separately from the legacy human `label`. Ordinary list
61
+ text shows both; classified session work search uses Current as its display/search
62
+ label, falling back to the legacy label when unknown. Aliases never change catalog
63
+ pagination identity or routing. Invalid alias metadata is withheld without hiding
64
+ legacy activity; existing whole-record and sidecar byte bounds still apply.
65
+
66
+ Presence reads the current canonical Pi name on its existing five-second heartbeat,
67
+ including idle `/name` or session-picker renames; declaration refreshes it immediately.
68
+ An unnamed session retains its workspace-basename display fallback. Session replacement
69
+ or shutdown disposes the previous publisher; a stale name source stops publication.
70
+ Headers remain unchanged; the optional sidecar now also carries `scope`.
71
+
72
+ ### Read orchestrator tool cards
73
+
74
+ All four `orchestrator_*` tools use compact operation cards in the terminal.
75
+ Expand a completed card to see labelled fields and nested sections rather than
76
+ raw JSON or duplicated result dumps; collapse it to return to the summary.
77
+ Empty request blocks are omitted. Session identity cards separate the current
78
+ task aliases, human session name, requested subject, and stable routing ID.
79
+ Initial/current aliases remain unknown for legacy history rather than being
80
+ inferred from the human name. Requests matching the returned current alias are
81
+ not repeated. Older identity results retain their preserved-alias explanation.
82
+ Alias and subject values use accent; labels and the preserved-name note use
83
+ muted, while the routing ID uses dim. Plain text is wrapped before these colors
84
+ are applied, preserving the same height even in narrow terminals.
85
+ Discovery overviews show at most six records, one physical table row each,
86
+ with short display IDs, workspace basenames, and task counts (`+` marks omitted
87
+ tasks; `?` means the count is unknown). Sessions without recent metadata are
88
+ counted together, not expanded into empty records. Classified-work overviews
89
+ use the same row limit and retain non-exhaustive coverage limits. Long cells
90
+ are clipped rather than wrapped, keeping completed overviews within 16 terminal
91
+ rows including its card frame. Short IDs and basenames are display hints,
92
+ never routing selectors or repository identity: use a full session ID with
93
+ `orchestrator_consult` or targeted `orchestrator_list` for detailed context.
94
+ Overview headers use the theme's tool-title color and bold when available;
95
+ aliases use accent, IDs use dim, and workspace/work values use muted. Quantities
96
+ use the numeric color; zero stays muted and unknown task counts use warning.
97
+ Limits use warning, while extra-record and missing-metadata notices remain muted.
98
+ These roles create visual hierarchy, not a green/live reachability indication,
99
+ and are recomputed when rendered so theme changes do not leave stale colors.
100
+ Consultation is not an owner reply; queued messages are not read or delivery
101
+ receipts. Complete model-facing output and permissions remain unchanged.
102
+
103
+ ### Publish curated state (Refs #1702; first slice)
104
+
105
+ `orchestrator_session_id` also accepts optional `state`: strings named `objective`,
106
+ `progress`, `decisions`, and `blockers` (2,048 UTF-8 bytes total). An object replaces
107
+ all fields, `null` withdraws, and omission leaves the current record unchanged.
108
+ Extra keys, controls, and oversized input are rejected before naming or persistence;
109
+ records additionally fit 4 KiB. Never include credentials, internal instructions,
110
+ or raw prompts. Whitelisting is not automatic secret redaction.
111
+
112
+ Pi's public `appendEntry` persists a non-context custom record on the active branch.
113
+ Only that branch's latest typed record is restored on start/reload/tree navigation;
114
+ malformed or foreign records suppress older notes. Manager replacement and shutdown
115
+ clear the cache. Conversation bodies, system prompts, results, and compaction summaries
116
+ are never inspected to derive these notes. Stable reads/heartbeats do not scan history.
117
+
118
+ Targeted `orchestrator_list` readback exposes detached historical notes, generated
119
+ stable owner ID, recorded cwd (or null), and `recordedAt`, not heartbeat freshness.
120
+ Cwd must be native absolute, control/surrogate-free, at most 1,024 UTF-8 bytes,
121
+ and free of the 15 normalized Unicode separators listed below. Invalid generated
122
+ cwd becomes null; malformed non-null readback withholds the note, never rewrites paths.
123
+ Source is `owner-curated`, `ownerReply: false`, `authority: none`: even `decisions`
124
+ is data, never a grant or human consent. Missing/invalid/over-budget notes are unknown;
125
+ withdrawal remains explicit null. Advertising is best-effort; legacy headers/activity
126
+ stay unchanged. Metadata and opt-in helper reasoning are available below; correlated
127
+ owner decisions remain a later protocol unit tracked by #1702.
128
+
129
+ ### Publish and find classified work
130
+
131
+ When useful, include explicit non-sensitive classification in
132
+ `orchestrator_session_id.state.work`, for example
133
+ `{"area":"Auth","topic":"Login","tags":["Review"],"refs":[{"kind":"issue","repository":"github.com/Owner/Repo","id":"12"}]}`.
134
+ An object replaces the whole state; omission of work clears classification, while
135
+ `state: null` withdraws it. Never publish private history as metadata.
136
+ Pass optional `subagent_run.work` explicitly for a child's classification; it is
137
+ not inherited. Keep the returned actual task ID: it is **not** a child session ID.
138
+
139
+ Use `orchestrator_list.filter: {}` to index classified work; omit `filter` for the
140
+ ordinary session list without bulk notes/work. Combine `area`, `topic` (requires
141
+ area), `tag`, literal `text`, exact typed `ref` (public repository + kind + ID), or
142
+ recorded `repository_root` with AND. Bare issue numbers are not cross-repo identity.
143
+ For related work, use `filter: {"related_to":{"session_id":"<stable owner ID>"}}`,
144
+ optionally with `task_id` for an actual task on its current catalog page. Add an
145
+ existing exact `recipient_session_id`/`cursor` only to inspect that recipient's page;
146
+ never automatically page. Source unavailable means no related rows, not refusal.
147
+
148
+ `possible-*-overlap` means literal possible overlap, not a dependency; a
149
+ `shared-declared-reference` is only a declared typed link, not approval. Results
150
+ include unknown, unclassified, omitted and pending-page coverage and are never
151
+ exhaustive. Historical classification, unknown reachability and `authority: none`
152
+ confer no ownership, consent or permission. Querying needs no helper/model call.
153
+
154
+ The existing consented read-only reasoning helper captures validated root work and
155
+ only exact task annotations on the selected owner's current catalog page. Unmatched
156
+ annotations are counted in omissions, never promoted to current work. Classification
157
+ and refs remain untrusted descriptive data, not approval or executable dependencies;
158
+ the existing question/input/output/deadline bounds and cost dialog still apply.
159
+
160
+ ### Classify recorded work
161
+
162
+ Publish classification in the same curated `state`, for example:
163
+
164
+ ```json
165
+ {"state":{"progress":"Reviewing login","work":{"area":"Auth","topic":"Login","tags":["Review"],"refs":[{"kind":"issue","repository":"github.com/Owner/Repo","id":"12"}]}}}
166
+ ```
167
+
168
+ `topic` requires `area`; each is at most 64 UTF-8 bytes. Up to eight tags (64 bytes
169
+ each) and eight refs are allowed. Refs require an explicit public `host/owner/repo`
170
+ (no URL, credentials or inferred repository), and an ID at most 256 bytes; repository
171
+ scope is also at most 256 bytes. Issue/PR IDs are positive canonical decimals;
172
+ task IDs are opaque historical declarations, **not routable peers**. Input case is
173
+ preserved; exact duplicate tags/refs, empty work, unknown keys and unsafe strings
174
+ are rejected. Existing text bytes plus serialized work JSON must fit 2,048 bytes.
175
+
176
+ An object replacement omitting `work` clears classification; `state: null` withdraws
177
+ the whole record. Work uses schema 2 in the same branch entry/cache/timestamp;
178
+ text-only records remain schema 1. Targeted list and metadata consultation readback
179
+ carry detached work with historical `recordedAt`, owner-curated and non-authoritative.
180
+ No refs are resolved and classification publication adds no inheritance behavior. Classification
181
+ itself needs no Git, network or model call. Consented helper capture follows the bounded
182
+ projection described below.
183
+
184
+ ### Search classified work
185
+
186
+ Call `orchestrator_list` with explicit `filter: {}` to index classified work, or
187
+ combine `filter` fields to narrow matches. Without `filter`, the existing session
188
+ list remains unchanged: no bulk curated state or work. Unknown argument/filter
189
+ keys and unsafe input fail before profile/peer reads; the discoverable strict
190
+ schema supplements, not replaces, UTF-8 byte and control validation.
191
+
192
+ Filtered calls return the full bounded `WorkSearchResult` JSON in text and
193
+ `details.gentleAgents.workSearch`, not the default `candidates` envelope. Existing
194
+ `recipient_session_id` and `cursor` select one recorded catalog page; a cursor still
195
+ requires that exact recipient. Source inclusion is internal, not a new lookup.
196
+
197
+ `searchPublishedWork(profile, peers, filter?, selection?, now?)` in
198
+ [`lib/orchestrator-work-search.ts`](../lib/orchestrator-work-search.ts) is a working,
199
+ metadata-only index. An empty filter returns classified sessions and active tasks.
200
+ Optional `area`, `topic` (requires area), `tag`, `text`, `ref`, and `repository_root`
201
+ criteria combine with AND; `validateWorkFilter` rejects unknown/unsafe input before I/O.
202
+ Human comparisons use NFC, trimming and case-insensitive literal matching; public
203
+ spellings remain intact. Refs match exact kind/repository/ID without resolution.
204
+ Text searches labels and descriptor fields only. Roots match recorded repository
205
+ facts, never launch paths or freshly resolved Git; tasks never inherit parent work/roots.
206
+
207
+ The query examines at most 64 deterministically selected unique peers, retaining
208
+ activation ambiguity checks, and reads one catalog page per peer. Historical task
209
+ annotations match only exact owner/task IDs on that current active page.
210
+ `selection: {recipientSessionId, cursor?}` can read an existing targeted catalog page;
211
+ a cursor without a recipient is rejected. There is no automatic paging or query cursor.
212
+ The detached whole JSON result fits 16 KiB by omitting whole matching rows, with exact
213
+ `omittedMatches`. Coverage is never exhaustive: it counts unexamined peers, unknown
214
+ context/catalogs, unclassified nodes, unmatched annotations, catalog omissions and
215
+ peers with pending pages. `recordedAt` is historical, separate from `observedAt`;
216
+ `ownerReply: false`, `authority: none`, and unknown reachability confer no permission.
217
+ Related queries add `related_to: {session_id, task_id?}` using exact stable owner
218
+ and actual task IDs (nonempty, safe, at most 256 UTF-8 bytes each). The source task
219
+ must be on that owner's current published catalog page; annotations alone never
220
+ resolve a source. Root and child classification stay independent. The advertised
221
+ source owner is included within the same 64-peer cap by deterministic replacement,
222
+ retaining all activations. A selected different recipient remains the only match
223
+ recipient; its cursor is never borrowed for source context. No automatic paging occurs.
224
+
225
+ `source` reports `available` with detached public node/classification and `recordedAt`,
226
+ or `unavailable` with an explicit reason and zero matches, never a refusal or broad
227
+ fallback. Provenance is `published-work`; basic queries omit `source` entirely.
228
+ Ordinary filters still combine with AND, but the source need not satisfy them.
229
+ Matches exclude only the exact source entity, not its independently classified siblings.
230
+ At least one reason is required: `shared-declared-reference` means exact typed ref
231
+ identity, not dependency or approval; `possible-area-overlap`, `possible-topic-overlap`
232
+ (also requires shared area), and `possible-tag-overlap` mean only literal possible
233
+ overlap. There is no semantic/model matching. Source information and complete reason
234
+ arrays count toward the same 16-KiB whole-row omission budget and non-exhaustive coverage.
235
+ The public tool adds no registry, Git probes, owner wakes, model calls or UI-cost
236
+ requests. This query adds no helper reasoning; consented helper capture is described below.
237
+
238
+ ### Annotate an allocated task
239
+
240
+ `subagent_run` accepts optional `work` containing only `area`, `topic`, `tags` and
241
+ `refs`. It validates before launch preparation or foreign-repository consent.
242
+ After allocation and ownership, it publishes the whole owner-curated snapshot,
243
+ preserving existing text/classification and adding `state.work.tasks[actualTaskId]`.
244
+ Nothing is added to the child prompt, context or task record; unclassified launches
245
+ and `subagent_continue` do not annotate or inherit work.
246
+
247
+ The curated root allows up to eight `tasks`, each a validated descriptor without
248
+ nested tasks. Nonempty tasks alone are valid work. Keys are exact task IDs, at most
249
+ 256 UTF-8 bytes, with no controls/surrogates or `__proto__`, `prototype`, `constructor`.
250
+ The same 2,048-byte text-plus-work and 4-KiB record bounds apply. Replacement omitting
251
+ `tasks` clears annotations; historical declarations are never silently pruned.
252
+ These IDs are not child session IDs or evidence of current runtime ownership;
253
+ search joins annotations only to the owner's current bounded catalog page.
254
+
255
+ The launch result retains the allocated task and includes `workPublication.status`:
256
+ `recorded` means local curated persistence, **not guaranteed peer advertisement**.
257
+ `unavailable` means publication is unavailable/unknown, including capacity, append,
258
+ transport or caller replacement failures. Do not relaunch the task to retry metadata.
259
+ When the owner session is active, use `orchestrator_session_id.state` to explicitly
260
+ replace the bounded snapshot with the actual ID. The timestamp applies to the whole
261
+ publication, not individual annotation freshness. Foreground waiting and cancellation
262
+ are unchanged; caller replacement prevents a stale `recorded` result.
263
+
264
+ ### Consult a published snapshot
265
+
266
+ Call `orchestrator_consult` with required stable `recipient_session_id`, optional
267
+ `kind: "metadata"` (default), and optional existing opaque catalog `cursor`.
268
+ No free-form question, owner request, human picker or read-consent dialog is used
269
+ for this profile's explicitly published data. Publish `subject` and `state` together
270
+ before work beyond small direct tasks; update at task changes and completion. Keep
271
+ small direct tasks exempt. Batch with setup/progress; do not add a model turn solely
272
+ to publish or emit per-tool/token updates.
273
+
274
+ Use `objective` for the goal, `progress` for current and next scope, and `blockers`
275
+ for anything preventing progress. Use `state.work` for relevant area/topic and
276
+ exact repository-qualified issue/PR refs;
277
+ classify delegated work through `subagent_run.work`. A state object replaces the
278
+ snapshot, so include every field that should remain public. At completion, publish
279
+ the outcome and next scope or withdraw the state with `null`; do not leave completed
280
+ work described as active.
281
+
282
+ Peers read this snapshot while the owner is busy, without an owner reply or waiting
283
+ for idle. Use metadata consultation before sending a question; contact the owner
284
+ only when the published context cannot answer it or an owner decision is needed.
285
+ A search with no matches does not establish that nobody else is working on the feature:
286
+ unknown, stale, unclassified and omitted scope must remain explicit.
287
+
288
+ The JSON receipt is deeply detached and frozen in-process, at most 16 KiB. It
289
+ contains public label/workspace, owned task summaries, recorded scope, one catalog
290
+ page, historical curated state, observation time and presence freshness. Missing
291
+ notes/scope are explicitly unknown; withdrawn notes remain an explicit null record.
292
+ Counts and continuation identify listing gaps. Over-budget snapshots are unavailable,
293
+ never silently truncated. Missing/stale/ambiguous publications and invalid cursors
294
+ are unavailable, not owner refusals. Refresh from page one after public changes.
295
+
296
+ `digest` binds captured public content to the selected activation and incarnation;
297
+ it excludes private activity digests/generation and observation clocks. Heartbeat
298
+ recency is not proof of current notes, Git resolution, reachability or global writer
299
+ ownership: state `recordedAt` and scope `resolvedAt` keep their historical meaning.
300
+ The source is `published_snapshot`, `ownerReply: false`, `authority: none`.
301
+ This is not native consent, a review receipt or a correlated owner decision.
302
+ No transcripts, prompts, threads, results, instructions, profile credentials or
303
+ transport capabilities are exported. No new Git probes, messages, receiver wakes,
304
+ child/helper launches or model calls occur in metadata mode. A question never
305
+ implicitly selects reasoning; unknown metadata never triggers a helper.
306
+
307
+ ### Opt-in read-only reasoning
308
+
309
+ Use `kind: "reasoning"` with a required `question` and the same exact recipient
310
+ and optional catalog cursor. Supported TUI/RPC `ctx.ui.select` supplies model-cost
311
+ permission; JSON/print and SDK contexts without actual dialog UI fail closed.
312
+ Model booleans, curated decisions and helper text cannot authorize invocation or
313
+ impersonate owners. Unknown/irrelevant/oversized arguments fail before effects.
314
+
315
+ One public `ModelRegistry.streamSimple` request receives a static read-only prompt
316
+ and one JSON question/public-snapshot message. Nested field whitelists exclude raw
317
+ extra properties, history, credentials, transport capabilities and catalog cursors.
318
+ Unknowns, omissions and historical source times remain visible; no tools execute.
319
+ The captured `state.work` includes validated root area/topic/tags/typed refs and only
320
+ annotations whose exact task IDs join that owner's **selected current catalog page**.
321
+ Metadata task summaries, old annotations and child session IDs do not prove membership;
322
+ root classification never flows to children. `unmatched-task-annotations:N` in omissions
323
+ counts excluded annotations; unmatched-only work is omitted, not a meaningful empty class.
324
+ Malformed work or a mismatched state owner fails preflight before UI/model calls.
325
+ Classification consumes the same input budget and confers no approval, executable
326
+ dependency, reachability or exclusive writer ownership, even when tags say “granted”.
327
+
328
+ | Bound | Contract |
329
+ |---|---|
330
+ | Input | 16 KiB total system + question JSON; question nonempty, control-free, at most 1,024 UTF-8 bytes |
331
+ | Output | Requested 512 tokens/minimal reasoning; text at most 4,096 UTF-8 bytes, no meaning truncation |
332
+ | Lifetime | Local deadline at most 20 seconds; cancellation/deadline races return without waiting for ignored abort |
333
+ | Concurrency | One execution lease per live SDK model registry, retained across coordinator/runtime replacement until actual provider result settlement |
334
+
335
+ No retries or automatic runs. A hung provider keeps that registry busy; cancel does
336
+ not reopen a potentially billable lease. Host currentness checks fail closed before
337
+ invocation and after completion. Tool-call content, errors, empty/oversized text and
338
+ stale results are explicit unavailable outcomes, never owner refusals. Length-stop
339
+ text is marked partial. Advice carries captured digest/time/target, requested and
340
+ actual model IDs, request caps and only finite nonnegative token/cost totals (or
341
+ unknown). Thinking is dropped; permission claims remain untrusted text with
342
+ `ownerReply: false`, `authority: none`. Abort/token requests are not guaranteed
343
+ remote billing caps. Unit tests use local controlled SDK-compatible streams;
344
+ the SDK fixture below also proves actual nested execution with simulated UI choices.
345
+
346
+ ### Cost permission and revocation
347
+
348
+ `lib/orchestrator-helper-consent.ts` coordinates the public reasoning lane while
349
+ metadata remains unchanged. Supported `ctx.ui.select` in TUI/RPC offers Allow once,
350
+ Allow this target + model for this session, and Decline. Unknown responses and
351
+ headless contexts fail closed. The forecast names the configured provider/model,
352
+ captured public target/time, all core bounds and the non-guaranteed billing limit.
353
+ This is model-cost permission only, never messaging or native-action consent.
354
+
355
+ The host reads the actual SDK context's live getters and canonical bounded public
356
+ source before/after waits. Session start, switch/fork/tree, model selection,
357
+ resource reload and shutdown clear permissions and cancel pending work. Grants bind exact manager,
358
+ session ID, cwd, model object/provider/ID, registry and logical target; at most
359
+ eight targets survive in memory. Updated public snapshots may reuse a session
360
+ grant; once never caches. `kind: "revoke-reasoning"` accepts only the recipient,
361
+ removes its scope and invalidates pending choices without UI or model calls.
362
+ Preflight precedes dialogs; changed public progress/page, replaced/stale/unavailable
363
+ source or caller cancellation discards advice without retry. Canonical routing is
364
+ re-listed after execution, with epoch/model/source checks still owning the reply.
365
+ Private activity and heartbeat changes do not change the public digest.
366
+
367
+ Pi's reload loader disables module caching, so an execution-only global symbol
368
+ holds a weak registry-keyed engine map. No permission or identity survives runtime
369
+ replacement; a new coordinator returns busy without UI while the old ignored-abort
370
+ result remains pending, then requires fresh permission after settlement. This is
371
+ stricter than one run per coordinator. Old clear cannot cancel a successor engine.
372
+ No durable policy file, owner request, correlation or consent receipt is created.
373
+ Tests simulate SDK UI responses, not real human approval. Actual nested-SDK helper
374
+ execution is verified below; interactive human UI proof remains deferred.
375
+
376
+ ### Public-SDK acceptance fixture
377
+
378
+ `tests/orchestrator-consultation-sdk.test.ts` uses installed Pi SDK 1.0.0:
379
+ `DefaultResourceLoader`, `createAgentSession`, `bindExtensions`, local
380
+ `registerProvider` streaming and `session.prompt`. Four separate managers/runtimes
381
+ share one trusted fixture profile: owner, JSON caller, simulated-UI RPC caller,
382
+ and fresh replacement owner. Provider/API IDs are unique per runtime.
383
+ Production Gentle Agents/Shell extensions supply the actual registered tools.
384
+ No private SDK invocation, fabricated tool context or transport adapter is used.
385
+
386
+ The fixture also proves actual SDK JSON/no-UI reasoning denial with exactly two
387
+ existing local driver turns and no nested helper or receiver calls. It proves
388
+ curated branch persistence, preserved human names, frozen
389
+ non-authoritative readback, actual private-message exclusion, opaque pagination
390
+ for nine then ten Git worktrees, public membership invalidation, unchanged-private-
391
+ history continuation, explicit null withdrawal and fresh replacement unknowns.
392
+ Driver tool/final model turns are intentional local iterations; consultation adds
393
+ no receiver model calls or caller Git probes during the business tool execution.
394
+ Intentional owner-publication prompts are counted separately, including during
395
+ the controlled in-flight test. Shell prompt setup still probes Git.
396
+ Work acceptance additionally publishes schema-2 classification through the public
397
+ tool, indexes explicit `{}`, combines area/topic/tag, and distinguishes exact refs
398
+ with the same bare ID across repositories and issue/PR kinds. Related queries use
399
+ the stable source owner ID; a ghost task annotation without a current owned catalog
400
+ row is unavailable, not a child launch. Replacement clears old work and null
401
+ withdrawal/text-only records keep unclassified/unknown coverage honest. Default
402
+ lists and searches exclude private history and curated prose. Scoped counters
403
+ verify no additional owner/nested-helper calls, model-cost dialogs or caller Git
404
+ probes for queries, including a simulated-UI context; ordinary local driver calls
405
+ remain expected. No child execution or 1,000-projection claim is made.
406
+
407
+ Public `AgentSession.bindExtensions(bindings: ExtensionBindings): Promise<void>`
408
+ accepts `mode: "rpc"` and a fully typed `uiContext: ExtensionUIContext`. The fixture
409
+ asserts actual SDK context getters report RPC/hasUI; it never assigns private
410
+ context/mode fields or directly executes a tool. A test-host selector returns
411
+ simulated Decline/unknown/Allow once/session responses; presentation methods are
412
+ explicit RPC stubs, other dialogs throw. This is not a real human grant or RPC
413
+ wire-client test. The original two-record/socket assertion precedes the extra caller.
414
+
415
+ Five actual nested registry requests are observed separately from the exactly two
416
+ main driver turns per tool prompt. Each opted-in request has empty tools, the same
417
+ static read-only system prompt, and exactly one question/public-JSON user message
418
+ (normalized by SDK to two transcript messages). Real caller/owner private-history
419
+ sentinels, parent instructions and catalog cursor capabilities are excluded. The
420
+ provider receives 512 tokens/minimal reasoning/no tool choice/no retries and a live
421
+ abort signal. Known local token/cost usage and requested/actual model IDs match the
422
+ non-authoritative advice envelope; a reply claiming permission grants nothing.
423
+ Explicit owner-tool publication also puts root classification and exact typed refs in
424
+ these existing helper captures; the manually declared ghost task is excluded and
425
+ counted as unmatched. This is not proof of child allocation: actual task annotation
426
+ remains mocked production-runner evidence. The same five helper requests and
427
+ simulated dialog counts remain; restoration uses explicit publication only.
428
+
429
+ Once re-prompts; session permission reuses updated published state for the same
430
+ owner ID without another dialog; revoke adds no dialog/helper and forces a fresh
431
+ choice. Metadata, JSON/no-UI, decline and unknown choices add zero helpers. A
432
+ controlled deferred provider result plus actual owner publication deterministically
433
+ returns stale-source without old advice or retries. Registry lease/replacement and
434
+ ignored-abort races remain controlled unit-test evidence, not this SDK scenario.
435
+
436
+ Outputs have two explicit ownership selectors: a private OS-temp fixture root
437
+ (profile, settings, credentials/model storage, sessions and Git), and production's
438
+ unique `/tmp/gentle-pi-<uid>/<profile-hash>` socket leaf. The fixture checks absence
439
+ before startup, private ownership/canonical containment, and actual socket paths.
440
+ Cleanup aborts sessions and invokes captured production public shutdown handlers
441
+ with actual SDK contexts before dispose (dispose alone does not emit shutdown).
442
+ It waits boundedly for presence withdrawal/empty sockets, revalidates ownership,
443
+ then removes only the exact empty leaf, never its UID parent or historical leaves.
444
+ The owned root is removed afterward; post-cleanup absence is checked. Windows is
445
+ explicitly skipped. This is not interactive TUI, human consent, native review,
446
+ Windows execution or issue-closure evidence; correlated owner decisions remain pending.
447
+
448
+ ### Recorded repository scope
449
+
450
+ Scope reuses `resolveSessionWorktree`: canonical Git root plus a SHA-256 hash of
451
+ canonical common-directory identity, with ambient `GIT_*` routing excluded. Sibling
452
+ worktrees share a clone hash, not a root; separate clones differ. No remote URL or
453
+ credential is read, and neither names nor scope grants authority. Non-Git, missing,
454
+ or unsafe paths are unknown, never guessed or shortened (scope paths: 256 bytes).
455
+ Literal scope paths containing NBSP, U+2000–200A, U+202F, U+205F or U+3000 are
456
+ unknown: the shared spelling resolver maps them to ASCII space and could otherwise
457
+ select a different existing repository. Input, resolved-root output and sidecar
458
+ readback all reject them. Ordinary spaces and Unicode letters remain supported.
459
+
460
+ `scope.host`, child `repository` facts keyed by task ID, and up to eight `registered`
461
+ facts carry `source: recorded-workspace/git` and `resolvedAt` (resolution attempt
462
+ time, not heartbeat age). Registered roots come from the existing session registry's
463
+ durable entries, not another registry. Missing/pruned registrations resolve unknown.
464
+ One bounded derived snapshot caches successful and unknown resolutions by actual Pi
465
+ cwd, admitted launch cwd/membership, and registered roots. Lifecycle changes and
466
+ session replacement invalidate it; stable token updates/heartbeats do not probe Git.
467
+
468
+ `omittedTasks`, `omittedRegistered`, and `complete` describe listing bounds. If the
469
+ sidecar byte budget cannot fit scope lists, both lists are withheld with exact
470
+ omission counts while retaining host context. Bounded recorded-path continuation
471
+ is described below; Git facts beyond the existing prefix remain unknown. #1701 stays open.
472
+ New readers accept legacy sidecars without scope. Old strict optional-sidecar
473
+ readers may show unknown discovery context; activity visibility is unchanged.
474
+ Malformed scope alone falls back to unknown repository facts without hiding IDs.
475
+
476
+ Recorded launch directories do not prove current child cwd or freedom from shared
477
+ artifacts. A shell `cd` does not change Pi's session cwd. Omission counts mean the
478
+ child list is incomplete, not an exhaustive writer inventory. This metadata cannot
479
+ answer arbitrary reasoning questions (#1702).
480
+
481
+ ### Continue recorded metadata
482
+
483
+ Call `orchestrator_list` without arguments as before. Each recent peer can also
484
+ carry `catalog`: eight child summaries (`id`, `label`, `status`, actual recorded
485
+ launch `cwd`) and eight recorded registered-root paths. To continue, pass its exact
486
+ `recipient_session_id` and opaque `catalog.cursor` to the same tool. Aliases are
487
+ for display, not selection. No human picker or recipient wakeup is involved.
488
+
489
+ | Bound | Contract |
490
+ |---|---|
491
+ | Snapshot | One private sibling `gentle-agents/catalog` file per publisher, at most 64 KiB |
492
+ | Entries | At most 64 tasks and 64 registered paths; eight of each per page, at most eight pages |
493
+ | Overflow | Whole entries omitted; exact `omittedTasks` / `omittedRegistered` counts on every page |
494
+ | Paths | Literal absolute recorded facts, at most 256 UTF-8 bytes; controls and normalized separators become `null`, never rewritten |
495
+ | Cursor | At most 1,024 characters; pins session hash, incarnation, transport activation and canonical public-catalog digest plus a publisher-minted page token |
496
+
497
+ Refresh from the first page after a public catalog change or producer replacement.
498
+ Private activity/thread/token updates may advance activity generation without
499
+ invalidating continuation: only the public catalog fields and omission counts
500
+ identify its snapshot. Envelope/header generation must still match on each read.
501
+ Wrong-recipient, changed or malformed cursors return unknown catalog context, not
502
+ a cached old page. Missing/malformed/oversized/symlink/FIFO snapshots likewise leave
503
+ legacy headers and activity visible. Legacy publishers need no catalog. The sibling
504
+ storage cannot inflate the existing bounded presence scan; disposal removes only
505
+ publisher-owned inodes and leaves replacements alone.
506
+
507
+ Derivation explicitly selects summary fields from the existing owned unfinished,
508
+ non-restored task list and durable session registry entries. It detaches caller
509
+ inputs, never reads another task thread, and adds no Git probes, child launches,
510
+ messages or model calls. Each paging read is one bounded local snapshot read, with
511
+ no Git resolution. `updateDiscovery` is the public catalog source, independently
512
+ of activity serialization; production publishes both from the same owned task
513
+ list. Direct publisher callers must refresh discovery when public fields or
514
+ membership change, not infer them from empty/unrelated activity input. Host aliases
515
+ or legacy scope-only changes do not establish a new catalog identity.
516
+ Recorded cwd/root paths are **not** canonical Git identities or
517
+ an exhaustive global writer inventory; the earlier Git prefix retains its own gaps.
518
+ #1702 remains published-status/curated-summary work, not automatic conversation sharing.
519
+
7
520
  ## Turning it on
8
521
 
9
522
  Set `GENTLE_SHELL_INTERACTIVE_HOST=1` on the `pi --mode rpc` process the host spawns directly. `lib/rpc-host.ts`'s `isInteractiveRpcHost(mode, env)` gates the feature on that exact value; any other value, or its absence, keeps RPC headless — the existing subagent-child behavior is byte-identical. `lib/agents-runner.ts` strips the variable from every subagent child's environment, so a subagent spawned by an interactive host never inherits it and stays headless itself.
@@ -0,0 +1,136 @@
1
+ # Removing Gentle Shell
2
+
3
+ `gentle-shell self-uninstall` removes what Gentle Shell created and then the
4
+ `gentle-pi` package. It always prints the full plan first, and nothing is removed
5
+ until you confirm.
6
+
7
+ ```bash
8
+ gentle-shell self-uninstall --dry-run # only print the plan
9
+ gentle-shell self-uninstall # print the plan, then ask
10
+ gentle-shell self-uninstall --yes # remove without asking; keeps shared configuration
11
+ gentle-shell self-uninstall --yes --include-shared
12
+ ```
13
+
14
+ `gentle-shell uninstall <source>` is a different command: it is Pi's own alias
15
+ for `remove`, forwarded to the resolved home, and stays unchanged.
16
+
17
+ ## What it removes
18
+
19
+ In this order:
20
+
21
+ 1. **Gentle Shell's own data**, each only when it is a real directory or file
22
+ (never a symbolic link):
23
+ - `<config home>/main/`: main-channel builds, only when it holds nothing but
24
+ what the main channel writes (`gentle-ai/<commit>/gentle-ai[.exe]`,
25
+ `packages/gentle-pi-*.tgz`, `.build`, `.source`); otherwise it is listed as
26
+ kept.
27
+ - `<config home>/channel.json`: the recorded update channel.
28
+ - `<config home>/dev-binary.json`, only when it points at a main-channel build
29
+ under `<config home>/main/gentle-ai`. A dev binary you registered yourself
30
+ is kept.
31
+ - `<config home>/tools/go`: the Go the installer downloaded for builds, only
32
+ when every entry is a pinned-Go version folder carrying the installer's
33
+ `.gentle-shell-go` marker; otherwise it is listed as kept.
34
+ - The isolated home: `GENTLE_SHELL_HOME`, or `~/.gentle-shell/agent`. It holds
35
+ the sign-ins, chats and settings of Gentle Shell sessions. A
36
+ `GENTLE_SHELL_HOME` directory is removed only when Gentle Shell created it
37
+ (its `.gentle-shell-home` marker, or its setup record in
38
+ `~/.gentle-shell/config.json`); otherwise it is listed as kept.
39
+ - `~/.gentle-shell/config.json`: the launcher settings.
40
+ 2. **Shared Gentle AI configuration**, only when you accept it (see below).
41
+ 3. **The `gentle-pi` package**, with the package manager that owns it:
42
+ `pnpm remove -g gentle-pi` under `PNPM_HOME`, otherwise
43
+ `npm uninstall -g gentle-pi`.
44
+ 4. **`~/.gentle-shell`**, only when it is empty.
45
+
46
+ The config home is `GENTLE_PI_CONFIG_HOME`, or `~/.pi/gentle-ai`.
47
+
48
+ ## Shared configuration
49
+
50
+ Pi with Gentle AI uses the same files in the config home, so they are kept by
51
+ default: `profiles.json`, `profiles.export.json`, `banner.json`,
52
+ `builtin-codemode-optout.json`, `background-subagents.json`,
53
+ `double-esc-cancel.json`, `runtime-guardrails.json` and `persona.json`.
54
+
55
+ - In a terminal, after you confirm the plan, a separate question asks whether
56
+ to remove them; the default is No, and so is end of input (Ctrl-D).
57
+ - With `--yes`, they are kept unless you also pass `--include-shared`.
58
+ - `--include-shared` removes them without the separate question.
59
+
60
+ Only those exact files are removed; anything else in the config home stays.
61
+
62
+ ## What it never touches
63
+
64
+ - Your Pi home (`~/.pi/agent`, `PI_CODING_AGENT_DIR` or
65
+ `GENTLE_SHELL_USER_PI_HOME`) and its `settings.json`.
66
+ - Custom homes used with `--home <path>`, recorded in
67
+ `~/.gentle-shell/config.json`; the plan lists them as not touched.
68
+ - Gentle AI's own state in `~/.gentle-ai`, and each project's `.pi/gentle-ai`
69
+ folder.
70
+ - Tools the web installer may have added. The plan lists them with how to remove
71
+ them yourself: Pi (`pnpm remove -g @earendil-works/pi-coding-agent` or
72
+ `npm uninstall -g @earendil-works/pi-coding-agent`), Engram (installed by Gentle
73
+ AI's setup), the PATH entry `pnpm setup` added and, on Windows,
74
+ `%USERPROFILE%\.pnpm`.
75
+
76
+ ## Refusals and exit codes
77
+
78
+ It refuses, before removing anything, when one of the places it removes from —
79
+ the isolated home, the config home or `~/.gentle-shell` — checked at its real
80
+ path (after following symbolic links, including linked parent folders):
81
+
82
+ - is or contains your home directory;
83
+ - is, contains or lies inside your Pi home (`~/.pi/agent`, `PI_CODING_AGENT_DIR`
84
+ or `GENTLE_SHELL_USER_PI_HOME`) or Gentle AI's state in `~/.gentle-ai`. Inside
85
+ a Gentle Shell session, `PI_CODING_AGENT_DIR` is the isolated home itself and
86
+ your Pi home travels in `GENTLE_SHELL_USER_PI_HOME`: when that variable names
87
+ an existing directory other than the isolated home, a `PI_CODING_AGENT_DIR`
88
+ equal to the isolated home is not treated as your Pi home, so the command
89
+ also works from inside a session;
90
+ - is, contains or lies inside a `.pi` directory, such as a project's `.pi` or
91
+ `.pi/gentle-ai` (containing means a `.pi` directly inside it). The default
92
+ config home, `~/.pi/gentle-ai`, is the only `.pi` location allowed;
93
+ - for the isolated home and the config home: is, contains or lies inside the
94
+ other;
95
+ - would remove a path that is, holds or lies inside a custom `--home` home or
96
+ another path the plan lists as not touched;
97
+ - `GENTLE_SHELL_HOME` or `GENTLE_PI_CONFIG_HOME` is not an absolute path;
98
+ - neither pnpm nor npm owns the installation (an `npm link` of a source checkout,
99
+ for example), or the owning package manager is not on `PATH`. Remove that
100
+ installation the way you made it.
101
+
102
+ | Exit code | Meaning |
103
+ | --- | --- |
104
+ | 0 | Removed, or `--dry-run` printed the plan. |
105
+ | 1 | Refused, cancelled, interrupted, or a removal failed. A refusal exits 1 even with `--dry-run`, since the real run would refuse too. |
106
+ | 2 | Usage error, including no terminal to confirm in without `--yes`. |
107
+
108
+ At the questions:
109
+
110
+ - Ctrl-C at any question stops the whole uninstall: it exits 1 and removes
111
+ nothing (both questions come before any removal).
112
+ - End of input (Ctrl-D, or a closed stdin) answers No: at the first question
113
+ it cancels (exit 1, nothing removed); at the shared-configuration question it
114
+ keeps the shared files and the uninstall goes on.
115
+
116
+ A refused plan lists no Gentle Shell data to remove, so no path ever appears both
117
+ as removed and as not touched.
118
+
119
+ When a removal fails, it stops there: the `gentle-pi` package and everything
120
+ after it are kept, so `gentle-shell self-uninstall` is still there to run again.
121
+ When only the package removal fails, it prints the command to run yourself.
122
+
123
+ It runs before any Pi runtime check, so it also works when Pi is missing.
124
+
125
+ ## Windows
126
+
127
+ pnpm and npm run the same verified way `gentle-shell upgrade` runs them: through
128
+ node.exe and the package manager's own JavaScript entry (or its native `.exe`),
129
+ never a `.cmd` or `.bat` shim, which cannot run without a shell. A package manager
130
+ that resolves only to such a shim counts as missing, and the command refuses
131
+ before removing anything.
132
+
133
+ Removing the running `gentle-pi` package with pnpm or npm on Windows has not been
134
+ verified yet. If the package manager fails, Gentle Shell's data is already gone
135
+ and the command prints the exact `pnpm remove -g gentle-pi` or
136
+ `npm uninstall -g gentle-pi` to run from a new terminal.