@timurproko/a1 0.1.8-dev.3b54f21 → 0.1.8-dev.402

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 (642) hide show
  1. package/README.md +159 -65
  2. package/bin/cli.js +28 -10
  3. package/bin/guardian.js +12 -6
  4. package/bin/module-identity.js +69 -35
  5. package/bin/pi-tui.d.ts +6 -0
  6. package/bin/pi-tui.js +28 -0
  7. package/bin/release-cleanup.js +8 -0
  8. package/bin/supervisor.js +2 -2
  9. package/bin/sync-pi-tui-proxy.js +97 -0
  10. package/bin/ui.js +62 -21
  11. package/bin/update-recovery.js +274 -0
  12. package/bin/warmup.js +27 -0
  13. package/dist/cli/capabilities.d.ts +6 -0
  14. package/dist/{src/cli → cli}/capabilities.js +1 -1
  15. package/dist/{src/cli → cli}/dispatch.d.ts +15 -1
  16. package/dist/cli/dispatch.js +261 -0
  17. package/dist/cli/package-messages.d.ts +26 -0
  18. package/dist/cli/package-messages.js +71 -0
  19. package/dist/{src/cli → cli}/packages.d.ts +11 -2
  20. package/dist/{src/cli → cli}/packages.js +24 -27
  21. package/dist/{src/cli → cli}/version-stats.d.ts +6 -0
  22. package/dist/cli/version-stats.js +112 -0
  23. package/dist/composition/agent-engine-bridge.d.ts +3 -0
  24. package/dist/composition/agent-engine-bridge.js +108 -0
  25. package/dist/composition/index.d.ts +3 -0
  26. package/dist/composition/index.js +3 -0
  27. package/dist/composition/owned-ui.d.ts +35 -0
  28. package/dist/composition/owned-ui.js +118 -0
  29. package/dist/composition/process.d.ts +16 -0
  30. package/dist/composition/process.js +45 -0
  31. package/dist/composition/settings-route-host.d.ts +8 -0
  32. package/dist/composition/settings-route-host.js +75 -0
  33. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.d.ts +2 -2
  34. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.js +22 -4
  35. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.d.ts +17 -0
  36. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.d.ts +6 -0
  37. package/dist/contracts/owned-ui/image-attachments.d.ts +36 -0
  38. package/dist/contracts/owned-ui/image-attachments.js +67 -0
  39. package/dist/contracts/owned-ui/index.d.ts +8 -0
  40. package/dist/contracts/owned-ui/index.js +8 -0
  41. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.d.ts +123 -0
  42. package/dist/contracts/owned-ui/prompt-history.d.ts +55 -0
  43. package/dist/contracts/owned-ui/prompt-history.js +23 -0
  44. package/dist/contracts/owned-ui/prompt-suggestions.d.ts +3 -0
  45. package/dist/contracts/owned-ui/prompt-suggestions.js +44 -0
  46. package/dist/contracts/owned-ui/suggestion-diagnostics.d.ts +22 -0
  47. package/dist/contracts/owned-ui/suggestion-diagnostics.js +9 -0
  48. package/dist/contracts/owned-ui/transcript-lifecycle.d.ts +5 -0
  49. package/dist/contracts/owned-ui/transcript-lifecycle.js +33 -0
  50. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.d.ts +5 -1
  51. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.js +129 -4
  52. package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.d.ts +8 -0
  53. package/dist/{src/features → features}/launch/development-launch.js +11 -3
  54. package/dist/{src/features → features}/launch/index.d.ts +0 -1
  55. package/dist/{src/features → features}/launch/index.js +0 -1
  56. package/dist/features/launch/intent.d.ts +10 -0
  57. package/dist/features/launch/intent.js +8 -0
  58. package/dist/{src/features → features}/launch/prepare-launch.d.ts +0 -2
  59. package/dist/{src/features → features}/launch/prepare-launch.js +2 -9
  60. package/dist/{src/features → features}/launch/profile-paths.d.ts +3 -2
  61. package/dist/{src/features → features}/launch/profile-paths.js +13 -8
  62. package/dist/{src/features → features}/launch/runtime-selection.d.ts +2 -5
  63. package/dist/{src/features → features}/owned-ui/customization.d.ts +3 -1
  64. package/dist/{src/features → features}/owned-ui/customization.js +3 -1
  65. package/dist/{src/features → features}/owned-ui/diagnostics.d.ts +2 -1
  66. package/dist/{src/features → features}/owned-ui/diagnostics.js +1 -0
  67. package/dist/{src/features → features}/owned-ui/index.d.ts +2 -0
  68. package/dist/{src/features → features}/owned-ui/index.js +2 -0
  69. package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
  70. package/dist/features/owned-ui/project-trust-prompt.js +149 -0
  71. package/dist/{src/features → features}/owned-ui/run.d.ts +2 -2
  72. package/dist/features/owned-ui/run.js +32 -0
  73. package/dist/features/owned-ui/session-fork-prompt.d.ts +8 -0
  74. package/dist/features/owned-ui/session-fork-prompt.js +34 -0
  75. package/dist/{src/features → features}/owned-ui/settings-app.d.ts +3 -3
  76. package/dist/{src/features → features}/owned-ui/settings-app.js +105 -56
  77. package/dist/features/prompt-history/image-sidecar.d.ts +32 -0
  78. package/dist/features/prompt-history/image-sidecar.js +130 -0
  79. package/dist/features/prompt-history/index.d.ts +4 -0
  80. package/dist/features/prompt-history/index.js +3 -0
  81. package/dist/features/prompt-history/paths.d.ts +5 -0
  82. package/dist/features/prompt-history/paths.js +17 -0
  83. package/dist/features/prompt-history/service.d.ts +54 -0
  84. package/dist/features/prompt-history/service.js +425 -0
  85. package/dist/features/prompt-history/store.d.ts +16 -0
  86. package/dist/features/prompt-history/store.js +223 -0
  87. package/dist/features/prompt-history/worker.d.ts +9 -0
  88. package/dist/features/prompt-history/worker.js +45 -0
  89. package/dist/features/prompt-suggestions/diagnostics.d.ts +18 -0
  90. package/dist/features/prompt-suggestions/diagnostics.js +82 -0
  91. package/dist/features/prompt-suggestions/index.d.ts +1 -0
  92. package/dist/features/prompt-suggestions/index.js +1 -0
  93. package/dist/{src/features → features}/workspace/capabilities.d.ts +1 -1
  94. package/dist/{src/features → features}/workspace/reducer.d.ts +2 -1
  95. package/dist/{src/features → features}/workspace/reducer.js +2 -1
  96. package/dist/{src/features → features}/workspace/router.d.ts +2 -1
  97. package/dist/{src/features → features}/workspace/router.js +1 -0
  98. package/dist/{src/features → features}/workspace/store.d.ts +2 -1
  99. package/dist/{src/features → features}/workspace/store.js +1 -0
  100. package/dist/foundation/launch-context/index.d.ts +59 -0
  101. package/dist/foundation/launch-context/index.js +136 -0
  102. package/dist/{src/foundation → foundation}/launch-guardian/main.d.ts +2 -0
  103. package/dist/{src/foundation → foundation}/launch-guardian/main.js +23 -8
  104. package/dist/{src/foundation → foundation}/lifecycle/index.d.ts +2 -0
  105. package/dist/{src/foundation → foundation}/lifecycle/index.js +2 -0
  106. package/dist/{src/foundation → foundation}/lifecycle/model.d.ts +1 -1
  107. package/dist/{src/foundation → foundation}/lifecycle/model.js +1 -1
  108. package/dist/foundation/lifecycle/paths.d.ts +30 -0
  109. package/dist/{src/foundation → foundation}/lifecycle/paths.js +29 -1
  110. package/dist/foundation/lifecycle/session-selection.d.ts +9 -0
  111. package/dist/foundation/lifecycle/session-selection.js +39 -0
  112. package/dist/foundation/lifecycle/supervisor-startup.d.ts +30 -0
  113. package/dist/foundation/lifecycle/supervisor-startup.js +106 -0
  114. package/dist/{src/foundation → foundation}/native-host-protocol/codec.d.ts +2 -0
  115. package/dist/{src/foundation → foundation}/native-host-protocol/codec.js +2 -0
  116. package/dist/{src/foundation → foundation}/native-host-protocol/messages.d.ts +1 -1
  117. package/dist/{src/foundation → foundation}/native-host-protocol/messages.js +1 -1
  118. package/dist/foundation/process-containment/darwin-process-inspector.d.ts +5 -0
  119. package/dist/foundation/process-containment/darwin-process-inspector.js +7 -0
  120. package/dist/{src/foundation → foundation}/process-containment/index.d.ts +1 -0
  121. package/dist/{src/foundation → foundation}/process-containment/index.js +1 -0
  122. package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.d.ts +1 -0
  123. package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.js +1 -0
  124. package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.d.ts +1 -0
  125. package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.js +1 -0
  126. package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.d.ts +3 -1
  127. package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +5 -2
  128. package/dist/{src/foundation → foundation}/protocol/client.d.ts +1 -0
  129. package/dist/{src/foundation → foundation}/protocol/client.js +1 -0
  130. package/dist/{src/foundation → foundation}/protocol/messages.d.ts +1 -0
  131. package/dist/{src/foundation → foundation}/protocol/messages.js +1 -0
  132. package/dist/foundation/release/bootstrap.d.ts +55 -0
  133. package/dist/{src/foundation → foundation}/release/bootstrap.js +219 -46
  134. package/dist/foundation/release/cohort-state.d.ts +157 -0
  135. package/dist/foundation/release/cohort-state.js +472 -0
  136. package/dist/foundation/release/dependency-certification-retention.d.ts +7 -0
  137. package/dist/foundation/release/dependency-certification-retention.js +88 -0
  138. package/dist/foundation/release/dependency-certification.d.ts +24 -0
  139. package/dist/foundation/release/dependency-certification.js +266 -0
  140. package/dist/foundation/release/dependency-layer.d.ts +81 -0
  141. package/dist/foundation/release/dependency-layer.js +466 -0
  142. package/dist/foundation/release/endpoints.d.ts +20 -0
  143. package/dist/foundation/release/endpoints.js +50 -0
  144. package/dist/foundation/release/immutable-platform.d.ts +6 -0
  145. package/dist/foundation/release/immutable-platform.js +13 -0
  146. package/dist/{src/foundation → foundation}/release/index.d.ts +6 -0
  147. package/dist/{src/foundation → foundation}/release/index.js +6 -0
  148. package/dist/foundation/release/release-gc.d.ts +71 -0
  149. package/dist/foundation/release/release-gc.js +764 -0
  150. package/dist/{src/foundation → foundation}/release/release-store.d.ts +9 -3
  151. package/dist/{src/foundation → foundation}/release/release-store.js +74 -14
  152. package/dist/{src/foundation → foundation}/release/release.d.ts +6 -1
  153. package/dist/{src/foundation → foundation}/release/release.js +15 -4
  154. package/dist/foundation/release/restart-certification.d.ts +68 -0
  155. package/dist/foundation/release/restart-certification.js +227 -0
  156. package/dist/foundation/release/update-launch.d.ts +6 -0
  157. package/dist/foundation/release/update-launch.js +17 -0
  158. package/dist/foundation/release/update-recovery.d.ts +76 -0
  159. package/dist/foundation/release/update-recovery.js +356 -0
  160. package/dist/{src/foundation → foundation}/release/update-transaction.d.ts +11 -0
  161. package/dist/{src/foundation → foundation}/release/update-transaction.js +13 -1
  162. package/dist/{src/foundation → foundation}/release/update.d.ts +40 -4
  163. package/dist/{src/foundation → foundation}/release/update.js +196 -78
  164. package/dist/foundation/release/warmup.d.ts +3 -0
  165. package/dist/foundation/release/warmup.js +47 -0
  166. package/dist/foundation/startup/index.d.ts +1 -0
  167. package/dist/foundation/startup/index.js +1 -0
  168. package/dist/foundation/startup/startup-runtime.d.ts +36 -0
  169. package/dist/foundation/startup/startup-runtime.js +142 -0
  170. package/dist/{src/foundation → foundation}/storage/control-store.d.ts +2 -1
  171. package/dist/{src/foundation → foundation}/storage/control-store.js +39 -4
  172. package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.d.ts +2 -1
  173. package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.js +2 -1
  174. package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.d.ts +2 -1
  175. package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.js +2 -1
  176. package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.d.ts +1 -1
  177. package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.js +1 -1
  178. package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.d.ts +2 -1
  179. package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.js +2 -1
  180. package/dist/{src/foundation → foundation}/structured-agent-runtime/state.d.ts +2 -1
  181. package/dist/{src/foundation → foundation}/structured-agent-runtime/state.js +2 -1
  182. package/dist/foundation/supervision/index.d.ts +3 -0
  183. package/dist/foundation/supervision/index.js +3 -0
  184. package/dist/foundation/supervision/main.d.ts +1 -0
  185. package/dist/foundation/supervision/main.js +84 -0
  186. package/dist/foundation/supervision/paths.d.ts +1 -0
  187. package/dist/foundation/supervision/paths.js +1 -0
  188. package/dist/foundation/supervision/server.d.ts +51 -0
  189. package/dist/{src/foundation → foundation}/supervision/server.js +142 -20
  190. package/dist/foundation/terminal-cleanup/fatal-exit.d.ts +12 -0
  191. package/dist/foundation/terminal-cleanup/fatal-exit.js +85 -0
  192. package/dist/foundation/terminal-cleanup/index.d.ts +2 -0
  193. package/dist/foundation/terminal-cleanup/index.js +2 -0
  194. package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +4 -0
  195. package/dist/foundation/terminal-cleanup/terminal-reset.js +40 -0
  196. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.d.ts +1 -1
  197. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.d.ts +1 -0
  198. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.js +3 -2
  199. package/dist/integrations/pi/components/editor-interaction.d.ts +38 -0
  200. package/dist/integrations/pi/components/history-editor-loader.d.ts +5 -0
  201. package/dist/integrations/pi/components/history-editor-loader.js +5 -0
  202. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.d.ts +2 -1
  203. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.js +2 -1
  204. package/dist/integrations/pi/components/owned-editor-ux.d.ts +74 -0
  205. package/dist/integrations/pi/components/owned-editor-ux.js +1093 -0
  206. package/dist/integrations/pi/components/path-word-ranges.d.ts +2 -0
  207. package/dist/integrations/pi/components/path-word-ranges.js +37 -0
  208. package/dist/integrations/pi/components/prompt-input-port.d.ts +18 -0
  209. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.d.ts +1 -0
  210. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.js +1 -0
  211. package/dist/integrations/pi/components/shell-editor-autocomplete.js +297 -0
  212. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.d.ts +1 -1
  213. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.d.ts +4 -4
  214. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.js +58 -23
  215. package/dist/integrations/pi/components/shell-presenters-info.d.ts +43 -0
  216. package/dist/integrations/pi/components/shell-presenters-info.js +114 -0
  217. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +29 -0
  218. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-presenters-transcript.js +174 -170
  219. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.d.ts +8 -4
  220. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.js +10 -6
  221. package/dist/integrations/pi/components/shell-shared-facade.d.ts +213 -0
  222. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.js +5 -2
  223. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +15 -0
  224. package/dist/integrations/pi/components/submitted-prompt-adapter.js +43 -0
  225. package/dist/integrations/pi/components/tool-image-presentation.d.ts +21 -0
  226. package/dist/integrations/pi/components/tool-image-presentation.js +86 -0
  227. package/dist/integrations/pi/components/tool-result-adapter.d.ts +6 -0
  228. package/dist/integrations/pi/components/tool-result-adapter.js +27 -0
  229. package/dist/integrations/pi/components/transcript-image-resolver.d.ts +7 -0
  230. package/dist/integrations/pi/components/transcript-image-resolver.js +19 -0
  231. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.d.ts +11 -2
  232. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.js +41 -3
  233. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +12 -0
  234. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +42 -0
  235. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +40 -0
  236. package/dist/integrations/pi/components/upstream/components/owned-editor.js +166 -0
  237. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.d.ts +1 -1
  238. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.js +3 -1
  239. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.d.ts +3 -2
  240. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.js +12 -7
  241. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +61 -0
  242. package/dist/integrations/pi/components/upstream/components/tool-execution.js +344 -0
  243. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +280 -0
  244. package/dist/integrations/pi/components/upstream/history/editor-core.js +2062 -0
  245. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +32 -0
  246. package/dist/integrations/pi/components/upstream/history/kill-ring.js +48 -0
  247. package/dist/integrations/pi/components/upstream/history/printable-key.d.ts +1 -0
  248. package/dist/integrations/pi/components/upstream/history/printable-key.js +40 -0
  249. package/dist/integrations/pi/components/upstream/history/text-helpers.d.ts +14 -0
  250. package/dist/integrations/pi/components/upstream/history/text-helpers.js +28 -0
  251. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +22 -0
  252. package/dist/integrations/pi/components/upstream/history/undo-stack.js +36 -0
  253. package/dist/integrations/pi/components/upstream/history/word-navigation.d.ts +24 -0
  254. package/dist/integrations/pi/components/upstream/history/word-navigation.js +100 -0
  255. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.d.ts +74 -6
  256. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +1340 -228
  257. package/dist/integrations/pi/engine/changelog.d.ts +2 -0
  258. package/dist/integrations/pi/engine/changelog.js +63 -0
  259. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.d.ts +4 -2
  260. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.js +15 -5
  261. package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
  262. package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
  263. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.d.ts +4 -0
  264. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +4 -0
  265. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.d.ts +2 -1
  266. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.js +1 -0
  267. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.d.ts +1 -1
  268. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.js +32 -26
  269. package/dist/integrations/pi/engine/pending-delivery.d.ts +30 -0
  270. package/dist/integrations/pi/engine/pending-delivery.js +158 -0
  271. package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
  272. package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
  273. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.d.ts +2 -1
  274. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.js +1 -0
  275. package/dist/integrations/pi/engine/resources/changelog.json +12 -0
  276. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.d.ts +19 -1
  277. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +56 -5
  278. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.d.ts +4 -2
  279. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.js +19 -4
  280. package/dist/integrations/pi/engine/session-selection.d.ts +28 -0
  281. package/dist/integrations/pi/engine/session-selection.js +90 -0
  282. package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
  283. package/dist/integrations/pi/engine/settings-effects.js +249 -0
  284. package/dist/integrations/pi/engine/settings-integration.d.ts +43 -0
  285. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/settings-integration.js +102 -108
  286. package/dist/integrations/pi/engine/tool-rendering.d.ts +13 -0
  287. package/dist/integrations/pi/engine/tool-rendering.js +145 -0
  288. package/dist/integrations/pi/engine/transcript-image-assets.d.ts +11 -0
  289. package/dist/integrations/pi/engine/transcript-image-assets.js +86 -0
  290. package/dist/integrations/pi/engine/windows-filesystem-hygiene.d.ts +21 -0
  291. package/dist/integrations/pi/engine/windows-filesystem-hygiene.js +55 -0
  292. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.d.ts +3 -2
  293. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.js +1 -0
  294. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.d.ts +19 -2
  295. package/dist/integrations/pi/session-ui/clipboard-diagnostics.d.ts +16 -0
  296. package/dist/integrations/pi/session-ui/clipboard-diagnostics.js +65 -0
  297. package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
  298. package/dist/integrations/pi/session-ui/clipboard-image.js +38 -0
  299. package/dist/integrations/pi/session-ui/editor-hyperlink-budget.d.ts +9 -0
  300. package/dist/integrations/pi/session-ui/editor-hyperlink-budget.js +23 -0
  301. package/dist/integrations/pi/session-ui/image-preparation-client.d.ts +20 -0
  302. package/dist/integrations/pi/session-ui/image-preparation-client.js +145 -0
  303. package/dist/integrations/pi/session-ui/image-preparation.d.ts +18 -0
  304. package/dist/integrations/pi/session-ui/image-preparation.js +126 -0
  305. package/dist/integrations/pi/session-ui/image-source.d.ts +13 -0
  306. package/dist/integrations/pi/session-ui/image-source.js +171 -0
  307. package/dist/integrations/pi/session-ui/image-worker.d.ts +17 -0
  308. package/dist/integrations/pi/session-ui/image-worker.js +23 -0
  309. package/dist/integrations/pi/session-ui/index.d.ts +5 -0
  310. package/dist/integrations/pi/session-ui/index.js +5 -0
  311. package/dist/integrations/pi/session-ui/paste-executor.d.ts +10 -0
  312. package/dist/integrations/pi/session-ui/paste-executor.js +232 -0
  313. package/dist/integrations/pi/session-ui/paste-helper.d.ts +1 -0
  314. package/dist/integrations/pi/session-ui/paste-helper.js +173 -0
  315. package/dist/integrations/pi/session-ui/paste-preparation-client.d.ts +16 -0
  316. package/dist/integrations/pi/session-ui/paste-preparation-client.js +159 -0
  317. package/dist/integrations/pi/session-ui/paste-protocol.d.ts +78 -0
  318. package/dist/integrations/pi/session-ui/paste-protocol.js +18 -0
  319. package/dist/integrations/pi/session-ui/paste-text-preparation.d.ts +20 -0
  320. package/dist/integrations/pi/session-ui/paste-text-preparation.js +134 -0
  321. package/dist/integrations/pi/session-ui/paste-text-worker.d.ts +1 -0
  322. package/dist/integrations/pi/session-ui/paste-text-worker.js +12 -0
  323. package/dist/integrations/pi/session-ui/path-chip-presentation.d.ts +7 -0
  324. package/dist/integrations/pi/session-ui/path-chip-presentation.js +24 -0
  325. package/dist/integrations/pi/session-ui/prompt-chips.d.ts +72 -0
  326. package/dist/integrations/pi/session-ui/prompt-chips.js +503 -0
  327. package/dist/integrations/pi/session-ui/prompt-history-controller.d.ts +36 -0
  328. package/dist/integrations/pi/session-ui/prompt-history-controller.js +170 -0
  329. package/dist/integrations/pi/session-ui/prompt-suggestion-controller.d.ts +35 -0
  330. package/dist/integrations/pi/session-ui/prompt-suggestion-controller.js +207 -0
  331. package/dist/integrations/pi/session-ui/response-copy-coordinator.d.ts +27 -0
  332. package/dist/integrations/pi/session-ui/response-copy-coordinator.js +189 -0
  333. package/dist/integrations/pi/session-ui/response-copy-helper.d.ts +1 -0
  334. package/dist/integrations/pi/session-ui/response-copy-helper.js +122 -0
  335. package/dist/integrations/pi/session-ui/response-copy-protocol.d.ts +56 -0
  336. package/dist/integrations/pi/session-ui/response-copy-protocol.js +5 -0
  337. package/dist/integrations/pi/session-ui/response-copy-transport.d.ts +31 -0
  338. package/dist/integrations/pi/session-ui/response-copy-transport.js +187 -0
  339. package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
  340. package/dist/integrations/pi/session-ui/route-host.js +1 -0
  341. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +221 -0
  342. package/dist/integrations/pi/session-ui/session-shell-root.js +1305 -0
  343. package/dist/integrations/pi/session-ui/session-shell.d.ts +55 -0
  344. package/dist/integrations/pi/session-ui/session-shell.js +1792 -0
  345. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +56 -0
  346. package/dist/integrations/pi/session-ui/session-viewport-controller.js +569 -0
  347. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
  348. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
  349. package/dist/integrations/pi/session-ui/system-clipboard.d.ts +20 -0
  350. package/dist/integrations/pi/session-ui/system-clipboard.js +156 -0
  351. package/dist/integrations/pi/session-ui/text-paste.d.ts +5 -0
  352. package/dist/integrations/pi/session-ui/text-paste.js +16 -0
  353. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.d.ts +10 -1
  354. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.js +255 -11
  355. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.d.ts +32 -6
  356. package/dist/integrations/pi/tui-runtime/contracts.js +1 -0
  357. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +81 -0
  358. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +424 -0
  359. package/dist/integrations/pi/tui-runtime/index.d.ts +7 -0
  360. package/dist/integrations/pi/tui-runtime/index.js +7 -0
  361. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
  362. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
  363. package/dist/integrations/pi/tui-runtime/mouse-report-input.d.ts +13 -0
  364. package/dist/integrations/pi/tui-runtime/mouse-report-input.js +59 -0
  365. package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +32 -0
  366. package/dist/integrations/pi/tui-runtime/overlay-geometry.js +159 -0
  367. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.d.ts +1 -1
  368. package/dist/native/darwin-arm64/manifest.json +4 -4
  369. package/dist/native/darwin-arm64/process-guardian +0 -0
  370. package/dist/native/linux-x64/manifest.json +3 -3
  371. package/dist/native/linux-x64/process-guardian +0 -0
  372. package/dist/native/win32-x64/manifest.json +3 -3
  373. package/dist/native/win32-x64/process-guardian.exe +0 -0
  374. package/dist/{src/product-identity.d.ts → product-identity.d.ts} +4 -4
  375. package/dist/{src/product-identity.js → product-identity.js} +7 -38
  376. package/dist/{src/product-identity.json → product-identity.json} +13 -27
  377. package/dist/runtime-payload-inventory.json +122333 -0
  378. package/dist/{src/foundation/ui-apps → ui/apps}/contracts.d.ts +23 -1
  379. package/dist/{src/foundation/ui-apps → ui/apps}/host.d.ts +1 -1
  380. package/dist/{src/foundation/ui-apps → ui/apps}/host.js +14 -10
  381. package/dist/{src/foundation/ui-apps → ui/apps}/registry.d.ts +1 -0
  382. package/dist/{src/foundation/ui-apps → ui/apps}/registry.js +1 -0
  383. package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.js +5 -3
  384. package/dist/{src/foundation/ui-components → ui/components}/frame.d.ts +1 -0
  385. package/dist/{src/foundation/ui-components → ui/components}/frame.js +1 -0
  386. package/dist/{src/foundation/ui-components → ui/components}/index.d.ts +7 -0
  387. package/dist/{src/foundation/ui-components → ui/components}/index.js +7 -0
  388. package/dist/{src/foundation/ui-components → ui/components}/line-input.d.ts +2 -8
  389. package/dist/{src/foundation/ui-components → ui/components}/line-input.js +7 -28
  390. package/dist/{src/foundation/ui-components → ui/components}/list-view.d.ts +0 -6
  391. package/dist/{src/foundation/ui-components → ui/components}/list-view.js +14 -7
  392. package/dist/{src/foundation/ui-components → ui/components}/mouse.d.ts +10 -0
  393. package/dist/{src/foundation/ui-components → ui/components}/mouse.js +24 -0
  394. package/dist/ui/components/progress-status.d.ts +2 -0
  395. package/dist/ui/components/progress-status.js +4 -0
  396. package/dist/ui/components/prompt-input.d.ts +32 -0
  397. package/dist/ui/components/prompt-input.js +54 -0
  398. package/dist/ui/components/prompt-row.d.ts +14 -0
  399. package/dist/ui/components/prompt-row.js +20 -0
  400. package/dist/{src/foundation/ui-components → ui/components}/scrollbar.d.ts +26 -0
  401. package/dist/{src/foundation/ui-components → ui/components}/scrollbar.js +35 -0
  402. package/dist/ui/components/selection-copy.d.ts +24 -0
  403. package/dist/ui/components/selection-copy.js +39 -0
  404. package/dist/{src/foundation/ui-components → ui/components}/shortcuts.d.ts +1 -0
  405. package/dist/{src/foundation/ui-components → ui/components}/shortcuts.js +1 -0
  406. package/dist/ui/components/spans.d.ts +28 -0
  407. package/dist/ui/components/spans.js +266 -0
  408. package/dist/ui/components/submitted-prompt.d.ts +23 -0
  409. package/dist/ui/components/submitted-prompt.js +50 -0
  410. package/dist/{src/foundation/ui-components → ui/components}/surface.d.ts +0 -5
  411. package/dist/{src/foundation/ui-components → ui/components}/surface.js +1 -5
  412. package/dist/ui/components/text-selection.d.ts +62 -0
  413. package/dist/ui/components/text-selection.js +210 -0
  414. package/dist/{src/foundation/ui-components → ui/components}/text.d.ts +14 -0
  415. package/dist/{src/foundation/ui-components → ui/components}/text.js +67 -5
  416. package/dist/ui/components/transcript-viewport.d.ts +173 -0
  417. package/dist/ui/components/transcript-viewport.js +753 -0
  418. package/dist/ui/components/visible-hyperlinks.d.ts +26 -0
  419. package/dist/ui/components/visible-hyperlinks.js +97 -0
  420. package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.d.ts +8 -1
  421. package/dist/ui/settings/declarations.js +94 -0
  422. package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.d.ts +1 -1
  423. package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.js +28 -2
  424. package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.d.ts +6 -19
  425. package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.js +41 -22
  426. package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.d.ts +9 -17
  427. package/dist/ui/settings/session.js +164 -0
  428. package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.d.ts +1 -0
  429. package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.js +2 -1
  430. package/docs/architecture/boundaries.md +14 -10
  431. package/docs/architecture/code-documentation.md +77 -0
  432. package/docs/architecture/history-editor-provenance.md +100 -0
  433. package/docs/architecture/internal-naming.md +91 -0
  434. package/docs/architecture/process-guardian-provenance.md +3 -1
  435. package/docs/architecture/project-structure.md +69 -30
  436. package/docs/architecture/prompt-suggestions.md +68 -0
  437. package/docs/architecture/resource-and-data-policy.md +28 -2
  438. package/docs/architecture/response-copy-delivery.md +83 -0
  439. package/docs/architecture/tool-image-presentation.md +62 -0
  440. package/docs/architecture/toolchain.md +24 -10
  441. package/docs/architecture/ui-reference-provenance.md +59 -5
  442. package/docs/ci-release-runbook.md +236 -79
  443. package/docs/features/launch-profiles.md +24 -17
  444. package/docs/features/modal-content-interaction.md +37 -0
  445. package/docs/features/prompt-history.md +149 -0
  446. package/docs/manual-code-streaming-cleanup.md +88 -0
  447. package/docs/manual-ghost-link-baseline.md +89 -0
  448. package/docs/manual-launch-instance-acceptance.md +12 -35
  449. package/docs/manual-owned-ui-checkpoint.md +78 -0
  450. package/docs/manual-pi-boundary-candidate.md +4 -5
  451. package/docs/manual-terminal-colour-check.md +4 -3
  452. package/docs/openspec-archive-automation.md +124 -0
  453. package/docs/repository-governance-live-acceptance.md +77 -0
  454. package/package.json +45 -28
  455. package/dist/src/cli/capabilities.d.ts +0 -15
  456. package/dist/src/cli/dispatch.js +0 -142
  457. package/dist/src/cli/version-stats.js +0 -72
  458. package/dist/src/composition/index.d.ts +0 -48
  459. package/dist/src/composition/index.js +0 -258
  460. package/dist/src/features/launch/intent.d.ts +0 -7
  461. package/dist/src/features/launch/intent.js +0 -4
  462. package/dist/src/features/launch/profiles.d.ts +0 -12
  463. package/dist/src/features/launch/profiles.js +0 -26
  464. package/dist/src/features/owned-ui/run.js +0 -15
  465. package/dist/src/foundation/lifecycle/paths.d.ts +0 -10
  466. package/dist/src/foundation/owned-ui-contracts/index.d.ts +0 -3
  467. package/dist/src/foundation/owned-ui-contracts/index.js +0 -3
  468. package/dist/src/foundation/owned-ui-settings/declarations.js +0 -39
  469. package/dist/src/foundation/owned-ui-settings/session.js +0 -145
  470. package/dist/src/foundation/pi-component-adapter/shell-editor-autocomplete.js +0 -162
  471. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +0 -57
  472. package/dist/src/foundation/pi-component-adapter/shell-shared-facade.d.ts +0 -116
  473. package/dist/src/foundation/pi-component-adapter/upstream/components/earendil-announcement.js +0 -19
  474. package/dist/src/foundation/pi-component-adapter/upstream/components/owned-editor.d.ts +0 -18
  475. package/dist/src/foundation/pi-component-adapter/upstream/components/owned-editor.js +0 -55
  476. package/dist/src/foundation/pi-engine-adapter/settings-integration.d.ts +0 -55
  477. package/dist/src/foundation/pi-owned-ui-integration/index.d.ts +0 -2
  478. package/dist/src/foundation/pi-owned-ui-integration/index.js +0 -2
  479. package/dist/src/foundation/pi-owned-ui-integration/route-host.d.ts +0 -29
  480. package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +0 -106
  481. package/dist/src/foundation/pi-owned-ui-integration/session-shell.js +0 -1518
  482. package/dist/src/foundation/pi-tui-runtime-adapter/index.d.ts +0 -4
  483. package/dist/src/foundation/pi-tui-runtime-adapter/index.js +0 -4
  484. package/dist/src/foundation/release/bootstrap.d.ts +0 -29
  485. package/dist/src/foundation/release/cohort-state.d.ts +0 -70
  486. package/dist/src/foundation/release/cohort-state.js +0 -202
  487. package/dist/src/foundation/release/release-gc.d.ts +0 -5
  488. package/dist/src/foundation/release/release-gc.js +0 -16
  489. package/dist/src/foundation/supervision/index.d.ts +0 -3
  490. package/dist/src/foundation/supervision/index.js +0 -3
  491. package/dist/src/foundation/supervision/main.d.ts +0 -1
  492. package/dist/src/foundation/supervision/main.js +0 -41
  493. package/dist/src/foundation/supervision/paths.d.ts +0 -1
  494. package/dist/src/foundation/supervision/paths.js +0 -1
  495. package/dist/src/foundation/supervision/server.d.ts +0 -22
  496. package/dist/src/foundation/ui-components/spans.d.ts +0 -7
  497. package/dist/src/foundation/ui-components/spans.js +0 -59
  498. package/docs/manual-transparent-checkpoint.md +0 -53
  499. /package/dist/{src/cli → cli}/index.d.ts +0 -0
  500. /package/dist/{src/cli → cli}/index.js +0 -0
  501. /package/dist/{src/cli → cli}/version.d.ts +0 -0
  502. /package/dist/{src/cli → cli}/version.js +0 -0
  503. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.js +0 -0
  504. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.d.ts +0 -0
  505. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.js +0 -0
  506. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.d.ts +0 -0
  507. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.js +0 -0
  508. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.d.ts +0 -0
  509. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.js +0 -0
  510. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.js +0 -0
  511. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.d.ts +0 -0
  512. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.js +0 -0
  513. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.d.ts +0 -0
  514. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.js +0 -0
  515. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.d.ts +0 -0
  516. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.js +0 -0
  517. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.d.ts +0 -0
  518. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.js +0 -0
  519. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.js +0 -0
  520. /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.js +0 -0
  521. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.d.ts +0 -0
  522. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.js +0 -0
  523. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.d.ts +0 -0
  524. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.js +0 -0
  525. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.d.ts +0 -0
  526. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.js +0 -0
  527. /package/dist/{src/features → features}/launch/development-launch.d.ts +0 -0
  528. /package/dist/{src/features → features}/launch/initialize-profile.d.ts +0 -0
  529. /package/dist/{src/features → features}/launch/initialize-profile.js +0 -0
  530. /package/dist/{src/features → features}/launch/runtime-selection.js +0 -0
  531. /package/dist/{src/features → features}/workspace/capabilities.js +0 -0
  532. /package/dist/{src/features → features}/workspace/index.d.ts +0 -0
  533. /package/dist/{src/features → features}/workspace/index.js +0 -0
  534. /package/dist/{src/features → features}/workspace/presentation.d.ts +0 -0
  535. /package/dist/{src/features → features}/workspace/presentation.js +0 -0
  536. /package/dist/{src/features → features}/workspace/reconciliation.d.ts +0 -0
  537. /package/dist/{src/features → features}/workspace/reconciliation.js +0 -0
  538. /package/dist/{src/foundation → foundation}/launch-guardian/index.d.ts +0 -0
  539. /package/dist/{src/foundation → foundation}/launch-guardian/index.js +0 -0
  540. /package/dist/{src/foundation → foundation}/lifecycle/commands.d.ts +0 -0
  541. /package/dist/{src/foundation → foundation}/lifecycle/commands.js +0 -0
  542. /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.d.ts +0 -0
  543. /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.js +0 -0
  544. /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.d.ts +0 -0
  545. /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.js +0 -0
  546. /package/dist/{src/foundation → foundation}/native-host-protocol/index.d.ts +0 -0
  547. /package/dist/{src/foundation → foundation}/native-host-protocol/index.js +0 -0
  548. /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.d.ts +0 -0
  549. /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.js +0 -0
  550. /package/dist/{src/foundation → foundation}/process-containment/artifact.d.ts +0 -0
  551. /package/dist/{src/foundation → foundation}/process-containment/artifact.js +0 -0
  552. /package/dist/{src/foundation → foundation}/process-containment/contracts.d.ts +0 -0
  553. /package/dist/{src/foundation → foundation}/process-containment/contracts.js +0 -0
  554. /package/dist/{src/foundation → foundation}/protocol/index.d.ts +0 -0
  555. /package/dist/{src/foundation → foundation}/protocol/index.js +0 -0
  556. /package/dist/{src/foundation → foundation}/release/cohort-selection.d.ts +0 -0
  557. /package/dist/{src/foundation → foundation}/release/cohort-selection.js +0 -0
  558. /package/dist/{src/foundation → foundation}/release/concurrency.d.ts +0 -0
  559. /package/dist/{src/foundation → foundation}/release/concurrency.js +0 -0
  560. /package/dist/{src/foundation → foundation}/release/process-cleanup.d.ts +0 -0
  561. /package/dist/{src/foundation → foundation}/release/process-cleanup.js +0 -0
  562. /package/dist/{src/foundation → foundation}/release/stable-release.d.ts +0 -0
  563. /package/dist/{src/foundation → foundation}/release/stable-release.js +0 -0
  564. /package/dist/{src/foundation → foundation}/storage/index.d.ts +0 -0
  565. /package/dist/{src/foundation → foundation}/storage/index.js +0 -0
  566. /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.d.ts +0 -0
  567. /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.js +0 -0
  568. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.js +0 -0
  569. /package/dist/{src/foundation/pi-owned-ui-integration/route-host.js → integrations/pi/components/editor-interaction.js} +0 -0
  570. /package/dist/{src/foundation/pi-tui-runtime-adapter/contracts.js → integrations/pi/components/prompt-input-port.js} +0 -0
  571. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.d.ts +0 -0
  572. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.js +0 -0
  573. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.d.ts +0 -0
  574. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.js +0 -0
  575. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.d.ts +0 -0
  576. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.js +0 -0
  577. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.d.ts +0 -0
  578. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.js +0 -0
  579. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.d.ts +0 -0
  580. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.js +0 -0
  581. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.d.ts +0 -0
  582. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.js +0 -0
  583. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.d.ts +0 -0
  584. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.d.ts +0 -0
  585. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.js +0 -0
  586. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.d.ts +0 -0
  587. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.js +0 -0
  588. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.d.ts +0 -0
  589. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.js +0 -0
  590. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.d.ts +0 -0
  591. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.js +0 -0
  592. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.d.ts +0 -0
  593. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.js +0 -0
  594. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.d.ts +0 -0
  595. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.js +0 -0
  596. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.d.ts +0 -0
  597. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.js +0 -0
  598. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.d.ts +0 -0
  599. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.js +0 -0
  600. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.d.ts +0 -0
  601. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.js +0 -0
  602. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.d.ts +0 -0
  603. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.js +0 -0
  604. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.d.ts +0 -0
  605. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.js +0 -0
  606. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.d.ts +0 -0
  607. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.js +0 -0
  608. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.d.ts +0 -0
  609. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.js +0 -0
  610. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.d.ts +0 -0
  611. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.js +0 -0
  612. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/pi-settings-metadata.json +0 -0
  613. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.d.ts +0 -0
  614. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.js +0 -0
  615. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.js +0 -0
  616. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.d.ts +0 -0
  617. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.js +0 -0
  618. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.js +0 -0
  619. /package/dist/{src/foundation/ui-apps → ui/apps}/contracts.js +0 -0
  620. /package/dist/{src/foundation/ui-apps → ui/apps}/index.d.ts +0 -0
  621. /package/dist/{src/foundation/ui-apps → ui/apps}/index.js +0 -0
  622. /package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.d.ts +0 -0
  623. /package/dist/{src/foundation/ui-components → ui/components}/label.d.ts +0 -0
  624. /package/dist/{src/foundation/ui-components → ui/components}/label.js +0 -0
  625. /package/dist/{src/foundation/ui-components → ui/components}/list-block.d.ts +0 -0
  626. /package/dist/{src/foundation/ui-components → ui/components}/list-block.js +0 -0
  627. /package/dist/{src/foundation/ui-components → ui/components}/pane.d.ts +0 -0
  628. /package/dist/{src/foundation/ui-components → ui/components}/pane.js +0 -0
  629. /package/dist/{src/foundation/ui-components → ui/components}/revision.d.ts +0 -0
  630. /package/dist/{src/foundation/ui-components → ui/components}/revision.js +0 -0
  631. /package/dist/{src/foundation/ui-components → ui/components}/status-line.d.ts +0 -0
  632. /package/dist/{src/foundation/ui-components → ui/components}/status-line.js +0 -0
  633. /package/dist/{src/foundation/ui-components → ui/components}/stepper.d.ts +0 -0
  634. /package/dist/{src/foundation/ui-components → ui/components}/stepper.js +0 -0
  635. /package/dist/{src/foundation/ui-components → ui/components}/theme.d.ts +0 -0
  636. /package/dist/{src/foundation/ui-components → ui/components}/theme.js +0 -0
  637. /package/dist/{src/foundation/ui-components → ui/components}/value-menu.d.ts +0 -0
  638. /package/dist/{src/foundation/ui-components → ui/components}/value-menu.js +0 -0
  639. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.d.ts +0 -0
  640. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.js +0 -0
  641. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.d.ts +0 -0
  642. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.js +0 -0
@@ -0,0 +1,1792 @@
1
+ import { ResponseCopyCoordinator } from "./response-copy-coordinator.js";
2
+ import { createResponseCopyExecutor, hasAsyncClipboardOutput, responseCopyDestination } from "./response-copy-transport.js";
3
+ import { MAX_COPY_CONTROL_BYTES } from "./response-copy-protocol.js";
4
+ import { PromptHistoryController } from "./prompt-history-controller.js";
5
+ import { PRODUCT_TEXT } from "../../../product-identity.js";
6
+ import { boundedCleanup } from "../../../foundation/terminal-cleanup/index.js";
7
+ import { assertOwnedUiCommand, assertPromptImages, ImageAttachmentError } from "../../../contracts/owned-ui/index.js";
8
+ import { ContextualPromptSuggestionController } from "./prompt-suggestion-controller.js";
9
+ import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput, readVisibleHyperlinks } from "../../../ui/components/index.js";
10
+ import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../engine/index.js";
11
+ import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, onPiThemeChange, piTheme, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../components/index.js";
12
+ import { DamageAwareTerminalAdapter, PiTuiRuntimeAdapter, classifyPiTuiInput, } from "../tui-runtime/index.js";
13
+ import { runImageWorker } from "./image-preparation-client.js";
14
+ import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
15
+ import { writeSystemClipboardText, } from "./system-clipboard.js";
16
+ import { OwnedUiSessionShellRoot, shellResourceEntries, } from "./session-shell-root.js";
17
+ export { OwnedUiSessionShellRoot } from "./session-shell-root.js";
18
+ /** Coordinates backend, owned presentation, and Pi TUI lifecycles for one interactive session. */
19
+ export class OwnedUiSessionShell {
20
+ backend;
21
+ root;
22
+ runtime;
23
+ #cwd;
24
+ #listeners = new Set();
25
+ #unsubscribe;
26
+ #unsubscribePromptSuggestions;
27
+ #promptSuggestions;
28
+ #promptHistory = null;
29
+ #promptHistoryImageSidecar;
30
+ #extensionBridge;
31
+ #stopped;
32
+ #resolveStopped;
33
+ #dialogId;
34
+ #dialogSource;
35
+ #routeHost;
36
+ #dialogHandle;
37
+ #sequence = 0;
38
+ #editorRevision = 0;
39
+ #started = false;
40
+ #disposed = false;
41
+ #pointerReporting = false;
42
+ #customViewport;
43
+ #responseCopy;
44
+ #unbindClipboardWriter;
45
+ #damageTerminal;
46
+ #streamPresentation;
47
+ #removeViewportPreInput;
48
+ #unsubscribeSettings;
49
+ #unbindPiSettings;
50
+ #unbindTerminalSettings;
51
+ #unbindShutdownSettings;
52
+ #terminalProgressEnabled = false;
53
+ #showImages = true;
54
+ #imageWidthCells = 80;
55
+ #fullscreenExitOutput = "transcript";
56
+ #compactionQueue = [];
57
+ #waitingImages = new Map();
58
+ #lastClearTime = 0;
59
+ #lastEscapeTime = 0;
60
+ #activeLoginDialog;
61
+ #sessionGeneration;
62
+ #sessionBindingGeneration;
63
+ #suggestionModelKey;
64
+ constructor(options) {
65
+ this.backend = options.backend;
66
+ this.#sessionGeneration = this.backend.sessionGeneration;
67
+ this.#sessionBindingGeneration = this.backend.sessionBindingGeneration;
68
+ this.#suggestionModelKey = modelKey(this.backend.view());
69
+ this.#cwd = options.cwd;
70
+ this.#routeHost = options.routeHost ?? null;
71
+ this.#customViewport = options.sessionLayout === "custom-viewport";
72
+ this.#stopped = new Promise(resolve => {
73
+ this.#resolveStopped = resolve;
74
+ });
75
+ let runtime;
76
+ let damageTerminal;
77
+ let streamPresentation;
78
+ let pendingClipboardWrite = Promise.resolve();
79
+ let promptSuggestionController = null;
80
+ const terminalCopy = options.terminal !== undefined || hasAsyncClipboardOutput();
81
+ this.#responseCopy = this.#customViewport ? new ResponseCopyCoordinator({
82
+ execute: options.responseCopy?.execute ?? createResponseCopyExecutor({
83
+ ...(options.terminal === undefined && options.clipboard === undefined ? {} : { destination: "terminal" }),
84
+ ...(options.clipboard?.writeText === undefined ? {} : { writeText: (text, signal) => options.clipboard.writeText(text, signal) }),
85
+ ...(terminalCopy ? { terminal: { submit: async (control, signal) => {
86
+ if (signal.aborted || this.#disposed || !runtime?.active)
87
+ throw new Error("Copy canceled");
88
+ // Performance: never grow the real terminal's pending buffer with another clipboard payload.
89
+ if (options.terminal === undefined && process.stdout.writableLength + control.length > MAX_COPY_CONTROL_BYTES) {
90
+ throw new Error("Clipboard terminal is busy");
91
+ }
92
+ runtime.writeControl(control);
93
+ } } } : {}),
94
+ }),
95
+ ...(options.responseCopy?.onEvent === undefined ? {} : { onEvent: options.responseCopy.onEvent }),
96
+ onFailure: result => {
97
+ if (this.#disposed || !runtime?.active)
98
+ return;
99
+ this.root.appendWorkflowStatus(result.outcome === "timed-out" ? "Copy timed out; the clipboard did not respond."
100
+ : result.failure === "size" ? "Selection exceeds this clipboard route's size limit."
101
+ : "Could not copy the selection; the clipboard is unavailable.");
102
+ runtime.requestRender();
103
+ },
104
+ }) : null;
105
+ const readClipboard = async (signal) => {
106
+ if (signal.aborted)
107
+ throw new ImageAttachmentError("image-canceled");
108
+ if (options.clipboard === undefined)
109
+ return runImageWorker({ kind: "clipboard" }, signal);
110
+ try {
111
+ const image = await options.clipboard.readImage?.(signal);
112
+ if (image !== null && image !== undefined) {
113
+ const canonical = await runImageWorker({ kind: "canonicalize", source: image }, signal);
114
+ if (canonical !== null)
115
+ return { kind: "image", ...canonical };
116
+ }
117
+ }
118
+ catch (error) {
119
+ if (error instanceof ImageAttachmentError)
120
+ throw error;
121
+ // Compatibility: an unavailable image reader can still provide text.
122
+ }
123
+ const text = await options.clipboard.readText(signal);
124
+ return text === null ? null : { kind: "text", text };
125
+ };
126
+ this.root = new OwnedUiSessionShellRoot(this.backend.view(), options.cwd, {
127
+ getColumns: () => runtime?.viewport().columns ?? options.terminal?.columns ?? 80,
128
+ getRows: () => runtime?.viewport().rows ?? options.terminal?.rows ?? 24,
129
+ requestRender: force => runtime?.requestRender(force),
130
+ requestHyperlinkCleanup: rows => damageTerminal?.requestHyperlinkCleanup(rows),
131
+ onViewportFrame: frame => damageTerminal?.arm(frame.descriptor, {
132
+ overlayActive: runtime?.hasOverlay() ?? false,
133
+ selectionActive: this.root.hasActiveSelection(),
134
+ replacementSurfaceActive: !this.root.usesDefaultInputSurface(),
135
+ }),
136
+ enableDockInputReuse: options.inputPresentation?.viewportReuse !== false,
137
+ persistentHistory: this.#customViewport && options.promptHistory !== undefined,
138
+ ...(options.promptHistory === undefined ? {} : { historyEditor: options.promptHistory.editor }),
139
+ onSubmit: text => { void this.submit(text).catch(() => this.#reportSubmissionError()); },
140
+ onPasteRejected: error => this.#reportSubmissionError(error),
141
+ onInterrupt: () => { void this.interrupt(); },
142
+ onClear: () => { void this.clearOrExit(); },
143
+ onExit: () => { void this.shutdown(); },
144
+ onModelSelect: () => this.showModelSelector(),
145
+ onModelCycle: direction => { void this.cycleModel(direction); },
146
+ onThinkingCycle: () => { void this.cycleThinkingLevel(); },
147
+ onThinkingToggle: () => {
148
+ this.root.toggleThinkingVisibility();
149
+ this.runtime.requestRender();
150
+ },
151
+ onMessageCopy: () => { void this.runWorkflow({ command: "copy", argument: "" }); },
152
+ onFollowUp: () => { void this.queueFollowUp().catch(() => this.#reportSubmissionError()); },
153
+ onDequeue: () => this.restoreQueuedInput(),
154
+ onEditorChange: () => { this.#editorRevision++; promptSuggestionController?.invalidate(); },
155
+ onPromptSuggestionAccepted: () => promptSuggestionController?.accept(),
156
+ onInputSurfaceChanged: () => {
157
+ promptSuggestionController?.invalidate();
158
+ this.#promptHistory?.synchronize();
159
+ },
160
+ onCopyText: text => {
161
+ if (this.#responseCopy !== null) {
162
+ void this.#responseCopy.submitText(text);
163
+ return;
164
+ }
165
+ const write = () => {
166
+ if (this.#disposed)
167
+ return Promise.resolve();
168
+ runtime?.writeControl(`\u001b]52;c;${Buffer.from(text, "utf8").toString("base64")}\u0007`);
169
+ return options.clipboard === undefined ? writeSystemClipboardText(text)
170
+ : options.clipboard.writeText?.(text) ?? Promise.resolve();
171
+ };
172
+ // Compatibility: comparison profiles retain their existing clipboard path.
173
+ pendingClipboardWrite = write().catch(() => { });
174
+ },
175
+ readClipboardContent: async (signal = new AbortController().signal) => {
176
+ await pendingClipboardWrite;
177
+ return readClipboard(signal);
178
+ },
179
+ captureClipboardPaste: () => {
180
+ const before = this.#responseCopy?.capturePasteBarrier() ?? (async () => true);
181
+ if (options.clipboard !== undefined)
182
+ return { kind: "provided", read: readClipboard, before };
183
+ if (responseCopyDestination(process.env) === "terminal")
184
+ return {
185
+ kind: "provided", before, read: async () => { throw new ImageAttachmentError("paste-unavailable"); },
186
+ };
187
+ return { kind: "native", before };
188
+ },
189
+ ...(options.pasteDiagnostics === undefined ? {} : { pasteDiagnostics: options.pasteDiagnostics }),
190
+ }, {
191
+ ...options.startup,
192
+ resources: options.startup?.resources ?? shellResourceEntries(this.backend),
193
+ }, this.backend.agentDir, {
194
+ getMessageRenderer: customType => this.backend.pinnedMessageRenderer(customType),
195
+ getToolDefinition: toolName => this.backend.pinnedToolDefinition(toolName),
196
+ getShortcuts: bindings => this.backend.pinnedShortcutDescriptions(bindings),
197
+ }, options.sessionLayout, {
198
+ resolve: assetId => this.backend.resolveTranscriptImage(assetId),
199
+ });
200
+ // Invariant: bare A1 owns a bounded viewport and therefore always runs on the alternate
201
+ // fullscreen surface. The pinned comparison profiles still honor Pi's mode.
202
+ const tuiMode = this.#customViewport
203
+ ? "fullscreen"
204
+ : this.backend.disposed ? "regular" : this.backend.pinnedSettingsSnapshot().tuiMode;
205
+ const runtimeOptions = {
206
+ root: this.root,
207
+ mode: tuiMode,
208
+ ...(this.#customViewport ? {
209
+ onOverlayGeometry: surfaces => this.root.setViewportOverlaySurfaces(surfaces),
210
+ decorateTerminal: (terminal) => {
211
+ damageTerminal = new DamageAwareTerminalAdapter(terminal, {
212
+ regionalScroll: process.env.TERM !== "dumb",
213
+ inspectHyperlinks: readVisibleHyperlinks,
214
+ onResize: () => streamPresentation?.noteImmediatePresentation(),
215
+ onHyperlinkCleanupRequired: () => runtime?.requestRender(true),
216
+ });
217
+ return damageTerminal;
218
+ },
219
+ ...(options.inputPresentation?.coordination === false ? {} : {
220
+ inputCoordination: {
221
+ classify: (data, focusedOverlay) => classifyPiTuiInput(data, focusedOverlay ?? this.root.inputCoordinationSurface()),
222
+ onReceipt: () => streamPresentation?.noteImmediatePresentation(),
223
+ ...(options.inputPresentation?.scheduler === undefined
224
+ ? {}
225
+ : { scheduler: options.inputPresentation.scheduler }),
226
+ },
227
+ }),
228
+ } : { layoutRoot: this.root.layoutRoot() }),
229
+ ...(options.inputPresentation?.onEvent === undefined ? {} : {
230
+ inputDiagnostics: {
231
+ onEvent: options.inputPresentation.onEvent,
232
+ ...(options.inputPresentation.now === undefined ? {} : { now: options.inputPresentation.now }),
233
+ },
234
+ }),
235
+ ...(options.terminal === undefined ? {} : { terminal: options.terminal }),
236
+ hardwareCursor: this.backend.view().terminal.hardwareCursor,
237
+ };
238
+ runtime = new PiTuiRuntimeAdapter(runtimeOptions);
239
+ this.runtime = runtime;
240
+ this.#damageTerminal = damageTerminal ?? null;
241
+ const presentationInterval = options.streamPresentation?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS;
242
+ streamPresentation = options.streamPresentation?.scheduler === undefined
243
+ ? new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval)
244
+ : new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval, options.streamPresentation.scheduler);
245
+ this.#streamPresentation = streamPresentation;
246
+ const promptSuggestionOptions = this.#customViewport ? options.promptSuggestions : undefined;
247
+ promptSuggestionController = promptSuggestionOptions === undefined ? null : new ContextualPromptSuggestionController({
248
+ generator: promptSuggestionOptions.generator,
249
+ enabled: promptSuggestionOptions.enabled(),
250
+ ...(promptSuggestionOptions.diagnostics === undefined ? {} : { diagnostics: promptSuggestionOptions.diagnostics }),
251
+ surface: {
252
+ canPresent: identity => this.#promptSuggestionPresentationBlockReason(identity) === null,
253
+ presentationBlockReason: identity => this.#promptSuggestionPresentationBlockReason(identity),
254
+ present: text => {
255
+ if (!this.root.canPresentPromptSuggestion())
256
+ return false;
257
+ this.root.setPromptSuggestion(text);
258
+ return true;
259
+ },
260
+ clear: () => this.root.setPromptSuggestion(null),
261
+ requestRender: () => this.runtime.requestRender(),
262
+ },
263
+ });
264
+ this.#promptSuggestions = promptSuggestionController;
265
+ this.#unsubscribePromptSuggestions = promptSuggestionOptions === undefined
266
+ ? () => { }
267
+ : promptSuggestionOptions.onChange(enabled => this.#promptSuggestions?.setEnabled(enabled));
268
+ const initialPiSettings = this.backend.pinnedSettingsSnapshot();
269
+ this.runtime.setHardwareCursor(initialPiSettings.showHardwareCursor);
270
+ this.runtime.setClearOnShrink(initialPiSettings.clearOnShrink);
271
+ this.#terminalProgressEnabled = initialPiSettings.showTerminalProgress;
272
+ this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
273
+ this.#unbindShutdownSettings = this.backend.bindSettingsOwner("shutdown", {
274
+ fullscreenExitOutput: { apply() { } },
275
+ });
276
+ this.#unbindTerminalSettings = this.backend.bindSettingsOwner("terminal", {
277
+ showHardwareCursor: { apply: value => {
278
+ if (typeof value !== "boolean")
279
+ throw new TypeError("Hardware cursor setting is invalid");
280
+ this.runtime.setHardwareCursor(value);
281
+ } },
282
+ clearOnShrink: { apply: value => {
283
+ if (typeof value !== "boolean")
284
+ throw new TypeError("Clear-on-shrink setting is invalid");
285
+ this.runtime.setClearOnShrink(value);
286
+ } },
287
+ showTerminalProgress: { apply: value => {
288
+ if (typeof value !== "boolean")
289
+ throw new TypeError("Terminal progress setting is invalid");
290
+ this.#terminalProgressEnabled = value;
291
+ this.#syncTerminalProgress(this.view());
292
+ } },
293
+ });
294
+ this.#removeViewportPreInput = this.#customViewport
295
+ ? this.runtime.addPreInputListener(data => {
296
+ if (options.inputPresentation?.coordination === false)
297
+ this.#streamPresentation.noteImmediatePresentation();
298
+ // Compatibility: Pi's fullscreen renderer also intercepts plain Home/End.
299
+ // Deliver them to the focused owned input before that outer scroll handler;
300
+ // overlays retain Pi's normal dispatch, and comparison profiles never enter here.
301
+ if (!this.runtime.hasOverlay() && (this.root.editor.matchesTerminalKey(data, "home")
302
+ || this.root.editor.matchesTerminalKey(data, "end"))) {
303
+ if (this.root.usesDefaultInputSurface())
304
+ this.root.handleViewportPreInput(data, true);
305
+ this.root.handleInput(data);
306
+ this.runtime.requestRender();
307
+ return { consume: true };
308
+ }
309
+ // Invariant: geometry must belong to the painted frame, including newly opened/nested
310
+ // surfaces. Steady pointer input does not trigger a synchronous composition.
311
+ const viewport = this.runtime.viewport();
312
+ if (data.includes("\u001b[<") && !this.root.viewportInputGeometryReady(viewport.columns, viewport.rows)) {
313
+ this.runtime.renderNow();
314
+ }
315
+ const routed = this.root.handleViewportPreInput(data, true, Date.now(), this.root.usesDefaultInputSurface() && !this.runtime.hasFocusedOverlay());
316
+ if (routed.copySelection !== undefined) {
317
+ void this.#responseCopy?.submit(routed.copySelection, pendingClipboardWrite);
318
+ }
319
+ if (!routed.consumed)
320
+ return routed.data === data ? undefined : { data: routed.data };
321
+ return routed.data.length === 0 ? { consume: true } : { data: routed.data };
322
+ })
323
+ : () => { };
324
+ const applyViewportSettings = () => {
325
+ const snapshot = options.viewportSettings?.snapshot();
326
+ this.root.setViewportConfig(snapshot ?? {
327
+ scrollbarAppearance: "auto",
328
+ scrollbarStyle: "thin",
329
+ scrollbarSpeed: "normal",
330
+ });
331
+ };
332
+ applyViewportSettings();
333
+ this.#unsubscribeSettings = this.#customViewport && options.viewportSettings
334
+ ? options.viewportSettings.onChange(settings => this.root.setViewportConfig(settings))
335
+ : () => { };
336
+ this.root.setEditorPaddingX(initialPiSettings.editorPaddingX);
337
+ this.root.setAutocompleteMaxVisible(initialPiSettings.autocompleteMaxVisible);
338
+ this.root.setOutputPad(initialPiSettings.outputPad);
339
+ this.root.setHideThinkingBlock(initialPiSettings.hideThinkingBlock);
340
+ this.root.setMermaidRenderingMode(initialPiSettings.mermaidRenderingMode);
341
+ this.#showImages = initialPiSettings.showImages;
342
+ this.#imageWidthCells = initialPiSettings.imageWidthCells;
343
+ this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
344
+ this.#unbindPiSettings = this.backend.bindSettingsOwner("shell", {
345
+ editorPaddingX: { apply: value => {
346
+ if (typeof value !== "number")
347
+ throw new TypeError("Editor padding is invalid");
348
+ this.root.setEditorPaddingX(value);
349
+ } },
350
+ autocompleteMaxVisible: { apply: value => {
351
+ if (typeof value !== "number")
352
+ throw new TypeError("Autocomplete maximum is invalid");
353
+ this.root.setAutocompleteMaxVisible(value);
354
+ } },
355
+ outputPad: { apply: value => {
356
+ if (value !== 0 && value !== 1)
357
+ throw new TypeError("Output padding is invalid");
358
+ this.root.setOutputPad(value);
359
+ } },
360
+ hideThinkingBlock: { apply: value => {
361
+ if (typeof value !== "boolean")
362
+ throw new TypeError("Thinking-block visibility is invalid");
363
+ this.root.setHideThinkingBlock(value);
364
+ } },
365
+ mermaidRenderingMode: { apply: value => {
366
+ if (value !== "off" && value !== "final" && value !== "streaming")
367
+ throw new TypeError("Mermaid mode is invalid");
368
+ this.root.setMermaidRenderingMode(value);
369
+ } },
370
+ showImages: { apply: value => {
371
+ if (typeof value !== "boolean")
372
+ throw new TypeError("Image visibility is invalid");
373
+ this.#showImages = value;
374
+ this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
375
+ } },
376
+ imageWidthCells: { apply: value => {
377
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
378
+ throw new TypeError("Image width is invalid");
379
+ this.#imageWidthCells = value;
380
+ this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
381
+ } },
382
+ });
383
+ if (this.#customViewport && options.promptHistory !== undefined) {
384
+ this.#promptHistoryImageSidecar = options.promptHistory.imageSidecar;
385
+ const sidecar = this.#promptHistoryImageSidecar;
386
+ this.#promptHistory = new PromptHistoryController({
387
+ editor: this.root.editor,
388
+ store: options.promptHistory.store,
389
+ limit: options.promptHistory.limit,
390
+ fallback: this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []),
391
+ active: () => this.root.usesDefaultInputSurface(),
392
+ render: () => this.runtime.requestRender(),
393
+ rehydrate: value => this.root.rehydrateHistoryText(value, id => sidecar?.readAttachment(id) ?? null),
394
+ });
395
+ }
396
+ this.#extensionBridge = createPiExtensionUiBridge({
397
+ runtime: {
398
+ getColumns: () => this.runtime.viewport().columns,
399
+ getRows: () => this.runtime.viewport().rows,
400
+ requestRender: () => this.runtime.requestRender(),
401
+ },
402
+ agentDir: this.backend.agentDir,
403
+ setInputSurface: component => this.root.setInputSurface(component, true, "opaque"),
404
+ showOverlay: (component, overlayOptions) => this.runtime.showOverlay(component, overlayOptions),
405
+ listenInput: handler => this.runtime.addInputListener(handler),
406
+ replaceWidget: (key, component, placement) => this.root.setExtensionWidget(key, component, placement),
407
+ replaceHeader: component => this.root.setExtensionHeader(component),
408
+ replaceFooter: component => this.root.setExtensionFooter(component),
409
+ setStatus: (key, text) => this.root.setExtensionStatus(key, text),
410
+ setWorking: (message, visible) => this.root.setExtensionWorking(message, visible),
411
+ notify: (message, type) => this.root.addExtensionNotification(message, type),
412
+ setTitle: title => this.runtime.setTitle(title),
413
+ getEditorText: () => this.root.editor.getText(),
414
+ setEditorText: text => this.root.editor.setText(text),
415
+ pasteToEditor: text => this.root.editor.insertText(text),
416
+ addAutocompleteProvider: factory => this.root.editor.addAutocompleteProvider(factory),
417
+ setCustomEditor: component => this.root.setInputSurface(component, true, "opaque"),
418
+ getFooterData: () => this.root.extensionFooterData(),
419
+ getToolsExpanded: () => this.root.toolsExpanded,
420
+ setToolsExpanded: expanded => this.root.setToolsExpanded(expanded),
421
+ });
422
+ this.backend.setWorkflowInteractionHost({
423
+ startLogin: request => this.#startWorkflowLogin(request),
424
+ prompt: request => this.#requestWorkflowInput(request),
425
+ notify: event => this.#notifyWorkflowLogin(event),
426
+ publish: message => {
427
+ this.root.appendWorkflowMessage(message);
428
+ this.runtime.requestRender();
429
+ },
430
+ finishLogin: () => this.#finishWorkflowLogin(),
431
+ });
432
+ this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
433
+ this.#unsubscribe = this.backend.onEvent(event => {
434
+ // Performance: a streamed chunk names one block, and touching only that block is what keeps the
435
+ // cost of a chunk the same in a long session as in a new one. Everything else
436
+ // resynchronizes the view, which is cheap next to re-reading the transcript.
437
+ if (event.type === "agent-run-started") {
438
+ this.#promptSuggestions?.invalidate();
439
+ this.root.resumeViewportFollowing();
440
+ }
441
+ if (event.type === "assistant-message-completed") {
442
+ this.root.noteCompletedAssistantMessage();
443
+ const identity = {
444
+ sessionId: event.sessionId,
445
+ sessionGeneration: event.sessionGeneration,
446
+ runSequence: event.runSequence,
447
+ responseSequence: event.responseSequence,
448
+ model: event.model,
449
+ };
450
+ if (event.model === null)
451
+ this.#promptSuggestions?.skip(identity, "no-model");
452
+ else
453
+ this.#promptSuggestions?.consider({ ...identity, model: event.model }, !event.successful ? "failed-response"
454
+ : event.toolContinuation || event.stopReason === "toolUse" ? "tool-continuation"
455
+ : event.stopReason !== "stop" ? "incomplete-response"
456
+ : event.assistantMessageCount < 2 ? "early-conversation"
457
+ : this.root.promptSuggestionPrepareBlockReason());
458
+ }
459
+ const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
460
+ const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.sessionGeneration
461
+ ? this.#syncBlock(event.block)
462
+ : semanticOnly ? this.view() : this.#syncView();
463
+ this.#syncTerminalProgress(view);
464
+ const currentModelKey = modelKey(view);
465
+ if (this.backend.sessionGeneration !== this.#sessionGeneration || currentModelKey !== this.#suggestionModelKey) {
466
+ this.#promptSuggestions?.invalidate();
467
+ this.#suggestionModelKey = currentModelKey;
468
+ }
469
+ if (event.type === "status" && /^(Retrying|Compacting)/.test(event.status.workingMessage ?? "")) {
470
+ this.#promptSuggestions?.invalidate();
471
+ }
472
+ if (event.type === "agent-run-settled" && event.model !== null) {
473
+ this.#promptSuggestions?.settle({
474
+ sessionId: event.sessionId,
475
+ sessionGeneration: event.sessionGeneration,
476
+ runSequence: event.runSequence,
477
+ responseSequence: event.responseSequence,
478
+ model: event.model,
479
+ });
480
+ }
481
+ if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
482
+ void this.#flushCompactionQueue();
483
+ if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
484
+ this.#resolveStopped?.();
485
+ });
486
+ this.#unbindClipboardWriter = this.#responseCopy === null ? () => { } : this.backend.bindClipboardWriter(async (text) => {
487
+ const result = await this.#responseCopy.submitText(text);
488
+ if (result.outcome === "delivered")
489
+ return true;
490
+ if (result.outcome === "submitted-unverified")
491
+ return false;
492
+ throw new Error(result.outcome === "timed-out" ? "Clipboard delivery timed out" : "Clipboard delivery could not be completed");
493
+ });
494
+ if (this.backend.view().lifecycle === "stopped")
495
+ this.#resolveStopped?.();
496
+ }
497
+ view() {
498
+ return this.backend.view();
499
+ }
500
+ #promptSuggestionPresentationBlockReason(identity) {
501
+ const view = this.view();
502
+ if (this.#disposed)
503
+ return "disposed";
504
+ if (identity.sessionId !== view.sessionId || identity.sessionGeneration !== this.backend.sessionGeneration
505
+ || modelKey(view) !== `${identity.model.providerId}/${identity.model.modelId}`)
506
+ return "stale-identity";
507
+ return this.root.promptSuggestionPresentationBlockReason();
508
+ }
509
+ damagePresentationDecision() {
510
+ return this.#damageTerminal?.lastDecision ?? null;
511
+ }
512
+ start() {
513
+ if (this.#started)
514
+ return;
515
+ this.#started = true;
516
+ this.runtime.start();
517
+ this.#promptHistory?.start();
518
+ this.#syncTerminalProgress(this.view());
519
+ if (this.#customViewport)
520
+ this.#setPointerReporting(true);
521
+ void this.backend.bindExtensionUi(this.#extensionBridge.context, () => { void this.shutdown(); });
522
+ this.#syncView();
523
+ }
524
+ onView(listener) {
525
+ this.#listeners.add(listener);
526
+ listener(this.view());
527
+ return () => this.#listeners.delete(listener);
528
+ }
529
+ waitUntilStopped() {
530
+ return this.#stopped;
531
+ }
532
+ async submit(text) {
533
+ return this.#submitWhenReady(text, () => this.#submit(text));
534
+ }
535
+ #submitWhenReady(draft, action) {
536
+ const previous = this.#waitingImages.get(draft);
537
+ if (previous !== undefined)
538
+ return previous.result;
539
+ if (!this.root.hasPendingPastes(draft))
540
+ return this.#guardSubmission(draft, action);
541
+ const controller = new AbortController();
542
+ const generation = this.backend.sessionGeneration;
543
+ const result = this.#guardSubmission(draft, async () => {
544
+ await this.root.waitForPromptPastes(draft, controller.signal);
545
+ if (controller.signal.aborted || this.#disposed || this.backend.sessionGeneration !== generation)
546
+ return rejected("image submission canceled");
547
+ return action();
548
+ }).finally(() => {
549
+ this.#waitingImages.delete(draft);
550
+ if (!this.#disposed)
551
+ this.#showWaitingImages();
552
+ });
553
+ this.#waitingImages.set(draft, { controller, result });
554
+ if (this.root.editor.getText() === draft)
555
+ this.root.editor.setText("");
556
+ this.#showWaitingImages();
557
+ return result;
558
+ }
559
+ #showWaitingImages() {
560
+ const count = this.#waitingImages.size;
561
+ this.root.setExtensionWidget("owned-image-preparation", count === 0 ? null : {
562
+ render: width => [...renderPiShellStatusText(`Waiting for images (${count} submission${count === 1 ? "" : "s"}) — Esc cancels; dequeue restores`, width)],
563
+ invalidate: () => { },
564
+ }, "aboveEditor");
565
+ this.runtime.requestRender();
566
+ }
567
+ #cancelWaitingImages() {
568
+ for (const item of this.#waitingImages.values())
569
+ item.controller.abort();
570
+ }
571
+ #rememberInput(text, kind) {
572
+ this.root.editor.addToHistory(text);
573
+ if (this.#promptHistory !== null) {
574
+ const reusable = this.root.prepareHistoryText(text);
575
+ if (reusable.length === 0)
576
+ this.#promptHistory.rememberRecovery(text);
577
+ else {
578
+ this.#persistImageSidecars(text);
579
+ this.#promptHistory.capture(reusable, kind, this.#cwd, this.backend.sessionId);
580
+ }
581
+ }
582
+ }
583
+ // Rationale: write the image chip payloads referenced by an editor draft to the sidecar
584
+ // directory before their history row commits. Missing sidecar dependency = silent skip; the
585
+ // recall path treats an absent sidecar the same as a corrupt one.
586
+ #persistImageSidecars(text) {
587
+ const sidecar = this.#promptHistoryImageSidecar;
588
+ if (sidecar === undefined)
589
+ return;
590
+ for (const record of this.root.imageChipAttachmentsFromEditor(text)) {
591
+ sidecar.write(record.id, { tag: record.tag, data: record.image.data, mimeType: record.image.mimeType, savedAt: new Date().toISOString() });
592
+ }
593
+ }
594
+ async #submit(text) {
595
+ this.#promptSuggestions?.invalidate();
596
+ const displayInput = text.trim();
597
+ if (!displayInput)
598
+ return { outcome: "completed", diagnostic: null };
599
+ if (displayInput.startsWith("/"))
600
+ return this.#slashCommand(displayInput);
601
+ const prepared = this.root.preparePromptSubmission(displayInput);
602
+ assertPromptImages(prepared.images);
603
+ const input = prepared.text.trim();
604
+ if (input.startsWith("!")) {
605
+ const excludeFromContext = input.startsWith("!!");
606
+ const command = input.slice(excludeFromContext ? 2 : 1).trim();
607
+ if (command) {
608
+ this.#rememberInput(displayInput, "bash");
609
+ try {
610
+ const result = await this.backend.executeBashWorkflow(command, excludeFromContext);
611
+ const workflow = {
612
+ command: "debug",
613
+ outcome: result.cancelled ? "cancelled" : result.exitCode === 0 || result.exitCode === undefined ? "completed" : "failed",
614
+ message: result.cancelled ? "Bash command cancelled" : `Bash exited ${result.exitCode ?? 0}: ${command}`,
615
+ ...(result.output ? { detail: result.output } : {}),
616
+ };
617
+ this.root.appendWorkflowResult(workflow);
618
+ this.runtime.requestRender();
619
+ return workflow.outcome === "failed" ? rejected(workflow.message) : { outcome: "completed", diagnostic: null };
620
+ }
621
+ catch (error) {
622
+ const message = `Bash command failed: ${error instanceof Error ? error.message : String(error)}`;
623
+ this.root.appendWorkflowResult({ command: "debug", outcome: "failed", message });
624
+ this.runtime.requestRender();
625
+ return rejected(message);
626
+ }
627
+ }
628
+ }
629
+ if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
630
+ this.#rememberInput(displayInput, "steer");
631
+ this.#compactionQueue.push({
632
+ text: input,
633
+ draft: displayInput,
634
+ type: "steer",
635
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
636
+ });
637
+ this.root.appendWorkflowResult({ command: "compact", outcome: "completed", message: `Queued during compaction: ${input}` });
638
+ this.runtime.requestRender();
639
+ return { outcome: "completed", diagnostic: null };
640
+ }
641
+ const type = this.view().lifecycle === "busy" ? "steer" : "prompt";
642
+ this.#rememberInput(displayInput, type);
643
+ this.root.resumeViewportFollowing();
644
+ return this.#execute({
645
+ type,
646
+ correlationId: this.#correlation(type),
647
+ sessionId: this.backend.sessionId,
648
+ text: input,
649
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
650
+ }, displayInput);
651
+ }
652
+ async clearOrExit(now = Date.now()) {
653
+ this.#promptSuggestions?.invalidate();
654
+ if (now - this.#lastClearTime < 500)
655
+ return this.shutdown();
656
+ this.root.editor.setText("");
657
+ this.#lastClearTime = now;
658
+ this.runtime.requestRender();
659
+ return { outcome: "completed", diagnostic: null };
660
+ }
661
+ async interrupt(now = Date.now()) {
662
+ this.#promptSuggestions?.invalidate();
663
+ if (this.#waitingImages.size > 0) {
664
+ this.#cancelWaitingImages();
665
+ return { outcome: "completed", diagnostic: null };
666
+ }
667
+ if (this.view().lifecycle === "busy")
668
+ return this.abort();
669
+ if (this.root.editor.getText().trim().length > 0) {
670
+ this.root.editor.setText("");
671
+ return { outcome: "completed", diagnostic: null };
672
+ }
673
+ // Compatibility: match Pi: with an empty editor, two escapes inside 500 ms open the
674
+ // configured session navigator. The first escape intentionally does not
675
+ // interrupt or mutate the prompt.
676
+ const action = this.backend.pinnedSettingsSnapshot().doubleEscapeAction;
677
+ if (action === "none")
678
+ return { outcome: "rejected", diagnostic: "nothing to interrupt" };
679
+ if (now - this.#lastEscapeTime < 500) {
680
+ this.#lastEscapeTime = 0;
681
+ if (action === "tree")
682
+ this.showTreeSelector();
683
+ else
684
+ this.showForkSelector();
685
+ return { outcome: "completed", diagnostic: null };
686
+ }
687
+ this.#lastEscapeTime = now;
688
+ return { outcome: "completed", diagnostic: null };
689
+ }
690
+ async abort() {
691
+ return this.#execute(this.#simple("abort"));
692
+ }
693
+ async retry() {
694
+ this.#promptSuggestions?.invalidate();
695
+ return this.#execute(this.#simple("retry"));
696
+ }
697
+ async compact() {
698
+ this.#promptSuggestions?.invalidate();
699
+ return this.#execute(this.#simple("compact"));
700
+ }
701
+ async newSession() {
702
+ this.#promptSuggestions?.invalidate();
703
+ return this.#execute(this.#simple("new-session"));
704
+ }
705
+ async resumeSession(sessionPath) {
706
+ this.#promptSuggestions?.invalidate();
707
+ return this.#execute({
708
+ type: "resume-session",
709
+ correlationId: this.#correlation("resume"),
710
+ sessionId: this.backend.sessionId,
711
+ sessionPath,
712
+ });
713
+ }
714
+ async setModel(providerId, modelId) {
715
+ this.#promptSuggestions?.invalidate();
716
+ return this.#execute({
717
+ type: "set-model",
718
+ correlationId: this.#correlation("model"),
719
+ sessionId: this.backend.sessionId,
720
+ model: { providerId, modelId, displayName: modelId },
721
+ });
722
+ }
723
+ async setThinkingLevel(thinkingLevel) {
724
+ return this.#execute({
725
+ type: "set-thinking-level",
726
+ correlationId: this.#correlation("thinking"),
727
+ sessionId: this.backend.sessionId,
728
+ thinkingLevel,
729
+ });
730
+ }
731
+ async cycleThinkingLevel() {
732
+ const levels = ["off", "minimal", "low", "medium", "high", "xhigh"];
733
+ const current = Math.max(0, levels.indexOf(this.view().thinkingLevel));
734
+ return this.setThinkingLevel(levels[(current + 1) % levels.length] ?? "off");
735
+ }
736
+ async cycleModel(direction) {
737
+ const result = await this.backend.cycleModelWorkflow(direction);
738
+ this.root.appendWorkflowResult(result);
739
+ if (result.outcome === "completed")
740
+ this.#showDaxnutsForActiveModel();
741
+ this.runtime.requestRender();
742
+ return workflowAdapterResult(result);
743
+ }
744
+ async queueFollowUp() {
745
+ const draft = this.root.editor.getText();
746
+ return this.#submitWhenReady(draft, () => this.#queueFollowUp(draft));
747
+ }
748
+ async #queueFollowUp(draft) {
749
+ const displayInput = draft.trim();
750
+ if (!displayInput)
751
+ return rejected("nothing to queue");
752
+ const prepared = this.root.preparePromptSubmission(displayInput);
753
+ assertPromptImages(prepared.images);
754
+ const text = prepared.text.trim();
755
+ this.#rememberInput(displayInput, "follow-up");
756
+ if (this.root.editor.getText() === draft)
757
+ this.root.editor.setText("");
758
+ this.root.resumeViewportFollowing();
759
+ if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
760
+ this.#compactionQueue.push({
761
+ text,
762
+ draft: displayInput,
763
+ type: "follow-up",
764
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
765
+ });
766
+ return { outcome: "completed", diagnostic: null };
767
+ }
768
+ return this.#execute({
769
+ type: "follow-up",
770
+ correlationId: this.#correlation("follow-up"),
771
+ sessionId: this.backend.sessionId,
772
+ text,
773
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
774
+ }, displayInput);
775
+ }
776
+ restoreQueuedInput() {
777
+ const queued = [...this.#waitingImages.keys(), ...this.backend.clearQueuedWorkflows(), ...this.#compactionQueue.map(item => item.draft)];
778
+ this.#cancelWaitingImages();
779
+ this.#compactionQueue = [];
780
+ if (queued.length === 0)
781
+ return;
782
+ this.root.editor.setText(queued.join("\n"));
783
+ this.runtime.requestRender();
784
+ }
785
+ showSelector(title, options, onSelect, onCancel) {
786
+ this.#dialogHandle?.hide();
787
+ this.#dialogSource = "local";
788
+ this.#dialogId = undefined;
789
+ const component = createPiShellSelector({
790
+ title,
791
+ options,
792
+ onSelect: id => {
793
+ onSelect(id);
794
+ this.#dialogHandle?.hide();
795
+ this.#dialogHandle = undefined;
796
+ this.#dialogSource = undefined;
797
+ },
798
+ onCancel: () => {
799
+ this.#dialogHandle?.hide();
800
+ this.#dialogHandle = undefined;
801
+ this.#dialogSource = undefined;
802
+ onCancel?.();
803
+ },
804
+ });
805
+ const handle = this.runtime.showOverlay(component, {
806
+ width: "70%",
807
+ maxHeight: "80%",
808
+ anchor: "center",
809
+ inputCoordination: "owned",
810
+ });
811
+ this.#dialogHandle = handle;
812
+ return handle;
813
+ }
814
+ showModelSelector(initialSearchInput) {
815
+ const context = this.backend.pinnedModelSelectorContext();
816
+ const close = () => {
817
+ this.root.setInputSurface(null);
818
+ this.runtime.requestRender();
819
+ };
820
+ const component = createPiShellModelSelector({
821
+ ...context,
822
+ runtime: {
823
+ getColumns: () => this.runtime.viewport().columns,
824
+ getRows: () => this.runtime.viewport().rows,
825
+ requestRender: () => this.runtime.requestRender(),
826
+ },
827
+ ...(initialSearchInput === undefined ? {} : { initialSearchInput }),
828
+ onSelect: model => {
829
+ close();
830
+ void this.runWorkflow({ command: "model", argument: "", selection: modelReference(model) });
831
+ },
832
+ onCancel: close,
833
+ });
834
+ this.root.setInputSurface(component);
835
+ this.runtime.requestRender();
836
+ }
837
+ showForkSelector() {
838
+ const options = this.backend.pinnedForkOptions();
839
+ if (options.length === 0) {
840
+ this.root.appendWorkflowResult({ command: "fork", outcome: "completed", message: "No messages to fork from", messageKind: "status" });
841
+ this.runtime.requestRender();
842
+ return;
843
+ }
844
+ const close = () => {
845
+ this.root.setInputSurface(null);
846
+ this.runtime.requestRender();
847
+ };
848
+ const component = createPiShellUserMessageSelector(options, selection => {
849
+ close();
850
+ void this.runWorkflow({ command: "fork", argument: "", selection });
851
+ }, close);
852
+ this.root.setInputSurface(component);
853
+ this.runtime.requestRender();
854
+ }
855
+ async showLogoutSelector() {
856
+ let options;
857
+ try {
858
+ options = await this.backend.pinnedLogoutOptions();
859
+ }
860
+ catch (error) {
861
+ this.root.appendWorkflowResult({
862
+ command: "logout",
863
+ outcome: "failed",
864
+ message: `Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`,
865
+ });
866
+ this.runtime.requestRender();
867
+ return;
868
+ }
869
+ if (options.length === 0) {
870
+ this.root.appendWorkflowStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
871
+ this.runtime.requestRender();
872
+ return;
873
+ }
874
+ const close = () => {
875
+ this.root.setInputSurface(null);
876
+ this.runtime.requestRender();
877
+ };
878
+ const component = createPiShellAuthProviderSelector("logout", options, selection => {
879
+ close();
880
+ void this.runWorkflow({ command: "logout", argument: "", selection });
881
+ }, close);
882
+ this.root.setInputSurface(component);
883
+ this.runtime.requestRender();
884
+ }
885
+ showLoginMethodSelector(providerReference) {
886
+ const method = this.backend.pinnedLoginMethodOptions(providerReference);
887
+ if (method.options.length === 0) {
888
+ this.showLoginProviderSelector(undefined, providerReference);
889
+ return;
890
+ }
891
+ if (method.options.length === 1) {
892
+ const selection = method.options[0]?.id;
893
+ if (selection)
894
+ void this.runWorkflow({ command: "login", argument: "", selection });
895
+ return;
896
+ }
897
+ const close = () => {
898
+ this.root.setInputSurface(null);
899
+ this.runtime.requestRender();
900
+ };
901
+ const labels = method.options.map(option => option.label);
902
+ const component = createPiShellExtensionSelector(method.title, labels, label => {
903
+ const selection = method.options.find(option => option.label === label)?.id;
904
+ if (!selection)
905
+ return;
906
+ close();
907
+ void this.runWorkflow({ command: "login", argument: "", selection });
908
+ }, close);
909
+ this.root.setInputSurface(component);
910
+ this.runtime.requestRender();
911
+ }
912
+ showTreeSelector(initialSelectedId) {
913
+ const context = this.backend.pinnedTreeSelectorContext();
914
+ if (context.tree.length === 0) {
915
+ this.root.appendWorkflowStatus("No entries in session");
916
+ this.runtime.requestRender();
917
+ return;
918
+ }
919
+ const close = () => {
920
+ this.root.setInputSurface(null);
921
+ this.runtime.requestRender();
922
+ };
923
+ const component = createPiShellTreeSelector({
924
+ tree: context.tree,
925
+ currentLeafId: context.currentLeafId,
926
+ terminalHeight: this.runtime.viewport().rows,
927
+ initialFilterMode: context.filterMode,
928
+ ...(initialSelectedId === undefined ? {} : { initialSelectedId }),
929
+ onLabelChange: context.appendLabelChange,
930
+ onCopy: text => {
931
+ if (!text) {
932
+ this.root.appendWorkflowResult({ command: "tree", outcome: "failed", message: "Selected entry has no text to copy" });
933
+ this.runtime.requestRender();
934
+ return;
935
+ }
936
+ const generation = this.backend.sessionBindingGeneration;
937
+ void this.backend.copyWorkflowText(text).then(acknowledged => {
938
+ if (this.#disposed || generation !== this.backend.sessionBindingGeneration)
939
+ return;
940
+ this.root.appendWorkflowStatus(acknowledged ? "Copied selected message to clipboard" : "Submitted selected message to clipboard");
941
+ this.runtime.requestRender();
942
+ }).catch(error => {
943
+ if (this.#disposed || generation !== this.backend.sessionBindingGeneration)
944
+ return;
945
+ this.root.appendWorkflowResult({ command: "tree", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
946
+ this.runtime.requestRender();
947
+ });
948
+ },
949
+ onCancel: close,
950
+ onSelect: entryId => {
951
+ close();
952
+ if (entryId === context.currentLeafId) {
953
+ this.root.appendWorkflowStatus("Already at this point");
954
+ this.runtime.requestRender();
955
+ return;
956
+ }
957
+ void this.#completeTreeSelection(entryId, context.skipSummaryPrompt);
958
+ },
959
+ });
960
+ this.root.setInputSurface(component);
961
+ this.runtime.requestRender();
962
+ }
963
+ showLoginAuthTypeSelector() {
964
+ const close = () => {
965
+ this.root.setInputSurface(null);
966
+ this.runtime.requestRender();
967
+ };
968
+ const labels = ["Sign in with an account", "Sign in with an API key"];
969
+ const component = createPiShellExtensionSelector("Select authentication method:", labels, label => {
970
+ close();
971
+ this.showLoginProviderSelector(label === labels[0] ? "oauth" : "api_key");
972
+ }, close);
973
+ this.root.setInputSurface(component);
974
+ this.runtime.requestRender();
975
+ }
976
+ showLoginProviderSelector(authType, initialSearchInput) {
977
+ const options = this.backend.pinnedLoginOptions(authType);
978
+ if (options.length === 0) {
979
+ this.root.appendWorkflowStatus(authType === "oauth" ? "No subscription providers available." : authType === "api_key" ? "No API key providers available." : "No login providers available.");
980
+ this.runtime.requestRender();
981
+ return;
982
+ }
983
+ const close = () => {
984
+ this.root.setInputSurface(null);
985
+ this.runtime.requestRender();
986
+ };
987
+ const component = createPiShellAuthProviderSelector("login", options, id => {
988
+ close();
989
+ void this.runWorkflow({ command: "login", argument: "", selection: id });
990
+ }, () => {
991
+ close();
992
+ if (authType !== undefined)
993
+ this.showLoginAuthTypeSelector();
994
+ }, initialSearchInput);
995
+ this.root.setInputSurface(component);
996
+ this.runtime.requestRender();
997
+ }
998
+ showSessionSelector() {
999
+ const context = this.backend.pinnedSessionSelectorContext();
1000
+ const close = () => {
1001
+ this.root.setInputSurface(null);
1002
+ this.runtime.requestRender();
1003
+ };
1004
+ const component = createPiShellSessionSelector({
1005
+ currentSessionsLoader: context.loadCurrentSessions,
1006
+ allSessionsLoader: context.loadAllSessions,
1007
+ currentSessionFilePath: context.currentSessionFilePath,
1008
+ renameSession: context.renameSession,
1009
+ requestRender: () => this.runtime.requestRender(),
1010
+ onSelect: sessionPath => {
1011
+ close();
1012
+ void this.runWorkflow({ command: "resume", argument: sessionPath });
1013
+ },
1014
+ onCancel: close,
1015
+ onExit: () => {
1016
+ close();
1017
+ void this.shutdown();
1018
+ },
1019
+ });
1020
+ this.root.setInputSurface(component);
1021
+ this.runtime.requestRender();
1022
+ }
1023
+ showSettingsSelector() {
1024
+ const snapshot = this.backend.pinnedSettingsSnapshot();
1025
+ const close = () => {
1026
+ this.root.setInputSurface(null);
1027
+ this.runtime.requestRender();
1028
+ };
1029
+ const component = createPiShellSettingsSelector({
1030
+ config: {
1031
+ ...snapshot,
1032
+ availableThinkingLevels: [...snapshot.availableThinkingLevels],
1033
+ availableThemes: [...snapshot.availableThemes],
1034
+ warnings: { ...snapshot.warnings },
1035
+ },
1036
+ onChange: (callback, value) => {
1037
+ if (callback === "onCancel") {
1038
+ close();
1039
+ return;
1040
+ }
1041
+ if (callback === "onTuiModeChange") {
1042
+ // Invariant: the custom bare-A1 surface is permanently fullscreen; this callback
1043
+ // remains available only to pinned comparison profiles.
1044
+ if (this.#customViewport)
1045
+ return;
1046
+ if (value !== "regular" && value !== "fullscreen")
1047
+ return;
1048
+ if (!this.runtime.switchMode(value)) {
1049
+ this.root.appendWorkflowStatus("Close active overlays before changing TUI mode");
1050
+ this.runtime.requestRender();
1051
+ return;
1052
+ }
1053
+ if (this.#customViewport) {
1054
+ this.#pointerReporting = false;
1055
+ this.#setPointerReporting(true);
1056
+ }
1057
+ }
1058
+ void this.backend.applyPinnedSettingValue(callback, value).then(result => {
1059
+ if (result.outcome === "failed")
1060
+ this.root.appendWorkflowResult(result);
1061
+ else if (callback === "onTuiModeChange")
1062
+ this.root.appendWorkflowStatus(`TUI mode: ${value}`);
1063
+ this.runtime.requestRender();
1064
+ });
1065
+ },
1066
+ onCancel: close,
1067
+ });
1068
+ this.root.setInputSurface(component);
1069
+ this.runtime.requestRender();
1070
+ }
1071
+ async shutdown() {
1072
+ return this.runWorkflow({ command: "quit", argument: "" });
1073
+ }
1074
+ async runWorkflow(request) {
1075
+ const copyGeneration = request.command === "copy" ? this.backend.sessionBindingGeneration : undefined;
1076
+ if (request.command === "login" && request.selection !== undefined) {
1077
+ const setup = this.backend.pinnedAmbientAuthentication(request.selection);
1078
+ if (setup) {
1079
+ const close = () => {
1080
+ this.root.setInputSurface(null);
1081
+ this.runtime.requestRender();
1082
+ };
1083
+ const dialog = createPiShellLoginDialog({
1084
+ getColumns: () => this.runtime.viewport().columns,
1085
+ getRows: () => this.runtime.viewport().rows,
1086
+ requestRender: () => this.runtime.requestRender(),
1087
+ }, setup.providerId, close, setup.providerName, setup.title);
1088
+ dialog.showInfo(setup.message, [], true);
1089
+ this.root.setInputSurface(dialog);
1090
+ this.runtime.requestRender();
1091
+ return { outcome: "completed", diagnostic: null };
1092
+ }
1093
+ }
1094
+ if (request.command === "scoped-models" && request.selection === undefined && request.confirmed === undefined) {
1095
+ this.showScopedModelsSelector();
1096
+ return { outcome: "completed", diagnostic: null };
1097
+ }
1098
+ if (request.command === "model" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
1099
+ this.showModelSelector();
1100
+ return { outcome: "completed", diagnostic: null };
1101
+ }
1102
+ if (request.command === "fork" && request.selection === undefined && request.confirmed === undefined) {
1103
+ this.showForkSelector();
1104
+ return { outcome: "completed", diagnostic: null };
1105
+ }
1106
+ if (request.command === "trust" && request.selection === undefined && request.confirmed === undefined) {
1107
+ this.showTrustSelector();
1108
+ return { outcome: "completed", diagnostic: null };
1109
+ }
1110
+ if (request.command === "settings" && request.selection === undefined && request.confirmed === undefined) {
1111
+ this.showSettingsSelector();
1112
+ return { outcome: "completed", diagnostic: null };
1113
+ }
1114
+ if (request.command === "resume" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
1115
+ this.showSessionSelector();
1116
+ return { outcome: "completed", diagnostic: null };
1117
+ }
1118
+ if (request.command === "login" && request.selection === undefined && request.confirmed === undefined) {
1119
+ if (request.argument.trim().length === 0)
1120
+ this.showLoginAuthTypeSelector();
1121
+ else
1122
+ this.showLoginMethodSelector(request.argument);
1123
+ return { outcome: "completed", diagnostic: null };
1124
+ }
1125
+ if (request.command === "logout" && request.selection === undefined && request.confirmed === undefined) {
1126
+ await this.showLogoutSelector();
1127
+ return { outcome: "completed", diagnostic: null };
1128
+ }
1129
+ if (request.command === "tree" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
1130
+ this.showTreeSelector();
1131
+ return { outcome: "completed", diagnostic: null };
1132
+ }
1133
+ if (request.command === "reload") {
1134
+ const blocked = this.backend.reloadBlockedResult();
1135
+ if (blocked) {
1136
+ this.root.appendWorkflowResult(blocked);
1137
+ this.runtime.requestRender();
1138
+ return workflowAdapterResult(blocked);
1139
+ }
1140
+ this.root.resetExtensionUi();
1141
+ }
1142
+ const shareSurface = request.command === "share"
1143
+ ? createPiShellOperationLoader({
1144
+ getColumns: () => this.runtime.viewport().columns,
1145
+ getRows: () => this.runtime.viewport().rows,
1146
+ requestRender: () => this.runtime.requestRender(),
1147
+ }, "Creating gist...")
1148
+ : undefined;
1149
+ const operationSurface = shareSurface ?? (request.command === "reload" ? createPiShellReloadBox() : undefined);
1150
+ if (operationSurface) {
1151
+ this.root.setInputSurface(operationSurface);
1152
+ this.runtime.requestRender();
1153
+ }
1154
+ let result;
1155
+ try {
1156
+ result = await this.backend.executeWorkflow(shareSurface === undefined ? request : { ...request, signal: shareSurface.signal });
1157
+ }
1158
+ finally {
1159
+ if (operationSurface) {
1160
+ this.root.setInputSurface(null);
1161
+ this.runtime.requestRender();
1162
+ }
1163
+ }
1164
+ if (copyGeneration !== undefined && (this.#disposed || copyGeneration !== this.backend.sessionBindingGeneration)) {
1165
+ return workflowAdapterResult({ command: "copy", outcome: "cancelled", message: "" });
1166
+ }
1167
+ if (result.outcome === "requires-selection" && request.command === "model") {
1168
+ if (result.messages !== undefined) {
1169
+ for (const message of result.messages)
1170
+ this.root.appendWorkflowMessage(message);
1171
+ }
1172
+ this.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
1173
+ return { outcome: "completed", diagnostic: null };
1174
+ }
1175
+ if (result.outcome === "requires-confirmation" && request.command === "resume") {
1176
+ const confirmed = await this.#extensionBridge.context.confirm("Session cwd not found", result.message);
1177
+ return this.runWorkflow({ ...request, confirmed: confirmed === true });
1178
+ }
1179
+ if (result.outcome === "requires-confirmation" && request.command === "import") {
1180
+ const recoveringCwd = result.detail !== undefined;
1181
+ const confirmed = await this.#extensionBridge.context.confirm(recoveringCwd ? "Session cwd not found" : "Import session", result.message);
1182
+ return this.runWorkflow({
1183
+ ...request,
1184
+ confirmed: confirmed === true,
1185
+ ...(confirmed === true && result.detail ? { cwdOverride: result.detail } : {}),
1186
+ });
1187
+ }
1188
+ if (result.outcome === "requires-selection" || result.outcome === "requires-confirmation") {
1189
+ this.root.appendWorkflowResult({ command: request.command, outcome: "failed", message: `Owned controller missing for ${request.command}` });
1190
+ this.runtime.requestRender();
1191
+ return { outcome: "failed", diagnostic: `Owned controller missing for ${request.command}` };
1192
+ }
1193
+ if (request.command === "reload" && result.outcome === "completed") {
1194
+ this.root.resetWorkflowPresentation();
1195
+ this.root.editor.reloadKeybindings();
1196
+ this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
1197
+ }
1198
+ this.root.appendWorkflowResult(result);
1199
+ if (request.command === "model" && result.outcome === "completed")
1200
+ this.#showDaxnutsForActiveModel();
1201
+ this.runtime.requestRender();
1202
+ return workflowAdapterResult(result);
1203
+ }
1204
+ showTrustSelector() {
1205
+ const context = this.backend.pinnedProjectTrustContext();
1206
+ const close = () => {
1207
+ this.root.setInputSurface(null);
1208
+ this.runtime.requestRender();
1209
+ };
1210
+ const component = createPiShellTrustSelector({
1211
+ ...context,
1212
+ onSelect: selection => {
1213
+ try {
1214
+ this.backend.persistProjectTrust(selection.updates);
1215
+ close();
1216
+ this.root.appendWorkflowStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
1217
+ }
1218
+ catch (error) {
1219
+ close();
1220
+ this.root.appendWorkflowResult({ command: "trust", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
1221
+ }
1222
+ this.runtime.requestRender();
1223
+ },
1224
+ onCancel: close,
1225
+ });
1226
+ this.root.setInputSurface(component);
1227
+ this.runtime.requestRender();
1228
+ }
1229
+ showScopedModelsSelector() {
1230
+ const initial = this.backend.pinnedScopedModelsContext();
1231
+ let currentEnabledIds = initial.enabledModelIds === null ? null : [...initial.enabledModelIds];
1232
+ let selectionChanged = false;
1233
+ let disposed = false;
1234
+ let timedOut = false;
1235
+ const controller = new AbortController();
1236
+ const timeout = setTimeout(() => {
1237
+ timedOut = true;
1238
+ controller.abort();
1239
+ }, 15_000);
1240
+ const close = () => {
1241
+ disposed = true;
1242
+ clearTimeout(timeout);
1243
+ controller.abort();
1244
+ this.root.setInputSurface(null);
1245
+ this.runtime.requestRender();
1246
+ };
1247
+ const selector = createPiShellScopedModelsSelector({
1248
+ models: initial.models,
1249
+ enabledModelIds: currentEnabledIds,
1250
+ refreshStatus: "Refreshing model catalogs…",
1251
+ onChange: enabledIds => {
1252
+ selectionChanged = true;
1253
+ currentEnabledIds = enabledIds === null ? null : [...enabledIds];
1254
+ this.backend.updateScopedModels(currentEnabledIds);
1255
+ this.runtime.requestRender();
1256
+ },
1257
+ onPersist: enabledIds => {
1258
+ currentEnabledIds = enabledIds === null ? null : [...enabledIds];
1259
+ this.backend.persistScopedModels(currentEnabledIds);
1260
+ this.root.appendWorkflowStatus("Model selection saved to settings");
1261
+ this.runtime.requestRender();
1262
+ },
1263
+ onCancel: close,
1264
+ });
1265
+ const component = {
1266
+ ...selector,
1267
+ dispose: () => {
1268
+ disposed = true;
1269
+ clearTimeout(timeout);
1270
+ controller.abort();
1271
+ selector.dispose?.();
1272
+ },
1273
+ };
1274
+ this.root.setInputSurface(component);
1275
+ this.runtime.requestRender();
1276
+ void this.backend.refreshScopedModels(controller.signal).then(refreshed => {
1277
+ if (disposed)
1278
+ return;
1279
+ if (!selectionChanged) {
1280
+ currentEnabledIds = refreshed.enabledModelIds === null ? null : [...refreshed.enabledModelIds];
1281
+ component.updateModels(refreshed.models, currentEnabledIds);
1282
+ }
1283
+ else {
1284
+ component.updateModels(refreshed.models);
1285
+ this.backend.updateScopedModels(currentEnabledIds);
1286
+ }
1287
+ component.setRefreshStatus(timedOut ? "Model refresh timed out; showing cached models." : refreshed.status, timedOut ? "warning" : refreshed.statusKind);
1288
+ this.runtime.requestRender();
1289
+ }).catch(error => {
1290
+ if (disposed)
1291
+ return;
1292
+ component.setRefreshStatus(timedOut
1293
+ ? "Model refresh timed out; showing cached models."
1294
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`, "warning");
1295
+ this.runtime.requestRender();
1296
+ }).finally(() => clearTimeout(timeout));
1297
+ }
1298
+ #showDaxnutsForActiveModel() {
1299
+ const model = this.view().activeModel;
1300
+ if (model?.providerId === "opencode" && model.modelId.toLowerCase().includes("kimi-k2.5")) {
1301
+ this.root.appendDaxnuts();
1302
+ }
1303
+ }
1304
+ // Invariant: pointer reporting is disabled on every path that ends the owning screen.
1305
+ #setPointerReporting(enabled, forceOff = false) {
1306
+ const effective = forceOff ? false : this.#customViewport || enabled;
1307
+ if (this.#pointerReporting === effective)
1308
+ return;
1309
+ this.#pointerReporting = effective;
1310
+ if (!this.runtime.active)
1311
+ return;
1312
+ this.runtime.writeControl(effective ? MOUSE_TRACKING_ON : MOUSE_TRACKING_OFF);
1313
+ }
1314
+ async dispose() {
1315
+ if (this.#disposed)
1316
+ return;
1317
+ this.#disposed = true;
1318
+ this.#responseCopy?.dispose();
1319
+ this.#cancelWaitingImages();
1320
+ const failures = [];
1321
+ const attempt = (action) => { try {
1322
+ action();
1323
+ }
1324
+ catch (error) {
1325
+ failures.push(error);
1326
+ } };
1327
+ let pasteCleanup = Promise.resolve();
1328
+ let historyCleanup = Promise.resolve(true);
1329
+ attempt(() => { historyCleanup = this.#promptHistory?.close() ?? Promise.resolve(true); });
1330
+ attempt(() => { pasteCleanup = this.root.disposePendingPastes(); });
1331
+ attempt(() => this.root.clearViewportPointerState());
1332
+ attempt(() => this.#setPointerReporting(false, true));
1333
+ attempt(() => this.#removeViewportPreInput());
1334
+ attempt(() => this.#streamPresentation.dispose());
1335
+ attempt(() => this.#promptSuggestions?.dispose());
1336
+ attempt(() => this.#unsubscribePromptSuggestions());
1337
+ attempt(() => this.#unsubscribeSettings());
1338
+ let fullscreenExitText = "";
1339
+ attempt(() => {
1340
+ const exitMode = this.backend.disposed ? this.#fullscreenExitOutput : this.backend.pinnedSettingsSnapshot().fullscreenExitOutput;
1341
+ const exitTranscript = this.root.exitTranscript(this.runtime.viewport().columns);
1342
+ const resume = this.backend.currentSessionResumeMetadata();
1343
+ const resumeHint = resume === null ? "" : `${dim("To resume this session:")} ${formatSessionResumeCommand(resume)}`;
1344
+ fullscreenExitText = this.runtime.mode !== "fullscreen" ? ""
1345
+ : exitMode === "resume-hint" ? resumeHint : [exitTranscript, resumeHint].filter(Boolean).join("\n\n");
1346
+ });
1347
+ attempt(() => this.#unbindClipboardWriter());
1348
+ attempt(() => this.#unbindPiSettings());
1349
+ attempt(() => this.#unbindTerminalSettings());
1350
+ attempt(() => this.#unbindShutdownSettings());
1351
+ attempt(() => this.#unsubscribe());
1352
+ attempt(() => this.#dialogHandle?.hide());
1353
+ attempt(() => this.#extensionBridge.dispose());
1354
+ // Invariant: terminal restoration precedes any potentially stalled backend teardown.
1355
+ await this.runtime.dispose().catch(error => failures.push(error));
1356
+ await historyCleanup.catch(() => false); // Security: background durability outcomes never enter terminal output.
1357
+ await boundedCleanup(() => pasteCleanup).catch(error => failures.push(error));
1358
+ await boundedCleanup(() => this.backend.unbindExtensionUi()).catch(error => failures.push(error));
1359
+ if (failures.length > 0)
1360
+ throw new AggregateError(failures, "Owned UI disposal failed");
1361
+ if (fullscreenExitText.length > 0)
1362
+ this.runtime.writeAfterStop(`${fullscreenExitText}\n`);
1363
+ }
1364
+ // Invariant: incremental block updates notify listeners with the same complete view contract.
1365
+ #syncBlock(block) {
1366
+ this.root.applyTranscriptBlock(block);
1367
+ if (this.#customViewport && block.status === "live" && isCoalescedStreamBlock(block.kind)) {
1368
+ this.#streamPresentation.request();
1369
+ }
1370
+ else if (this.#streamPresentation.pending) {
1371
+ this.#streamPresentation.flush();
1372
+ }
1373
+ else {
1374
+ this.#streamPresentation.presentImmediate();
1375
+ }
1376
+ const view = this.view();
1377
+ for (const listener of this.#listeners)
1378
+ listener(view);
1379
+ return view;
1380
+ }
1381
+ #syncTerminalProgress(view) {
1382
+ if (!this.runtime.active)
1383
+ return;
1384
+ this.runtime.setTerminalProgress(this.#terminalProgressEnabled && view.lifecycle === "busy");
1385
+ }
1386
+ #syncView() {
1387
+ this.#streamPresentation.noteImmediatePresentation();
1388
+ const view = this.view();
1389
+ if (this.backend.sessionGeneration !== this.#sessionGeneration) {
1390
+ this.#responseCopy?.reset();
1391
+ this.#cancelWaitingImages();
1392
+ this.root.resetPendingPastes();
1393
+ this.#promptSuggestions?.invalidate();
1394
+ this.#sessionGeneration = this.backend.sessionGeneration;
1395
+ // Invariant: delivery recovery invalidates callbacks, not same-session local recall or its draft.
1396
+ if (this.#sessionBindingGeneration !== this.backend.sessionBindingGeneration) {
1397
+ this.#sessionBindingGeneration = this.backend.sessionBindingGeneration;
1398
+ this.root.resetTranscript();
1399
+ this.#promptHistory?.reset(view.transcript.flatMap(block => block.kind === "user" ? [block.text] : []));
1400
+ }
1401
+ this.#activeLoginDialog = undefined;
1402
+ this.#extensionBridge.reset();
1403
+ // Invariant: a replaced session takes its transient viewport and owned-route state with it.
1404
+ this.root.resetViewport();
1405
+ this.#dialogHandle?.hide();
1406
+ this.#dialogHandle = undefined;
1407
+ this.#dialogId = undefined;
1408
+ this.#dialogSource = undefined;
1409
+ this.#setPointerReporting(false);
1410
+ this.root.setInputSurface(null);
1411
+ this.root.resetExtensionUi();
1412
+ this.root.resetWorkflowPresentation();
1413
+ }
1414
+ this.root.update(view);
1415
+ this.#syncDialog(view.dialog);
1416
+ this.runtime.requestRender();
1417
+ for (const listener of this.#listeners)
1418
+ listener(view);
1419
+ return view;
1420
+ }
1421
+ #openOwnedRoute(route) {
1422
+ const surface = this.#routeHost?.open(route) ?? null;
1423
+ if (surface === null)
1424
+ return { outcome: "failed", diagnostic: `route is unavailable: ${route}` };
1425
+ if (!this.runtime.active)
1426
+ return { outcome: "failed", diagnostic: "runtime is not active" };
1427
+ this.#dialogHandle?.hide();
1428
+ this.#dialogSource = "route";
1429
+ // Protocol: any-event reporting: hover and drag are what the screen is driven by, and
1430
+ // it also stops the terminal treating a drag as a text selection.
1431
+ this.#setPointerReporting(true);
1432
+ // Protocol: the interrupt chord is global, so it is watched on raw input rather than
1433
+ // through the overlay: the pinned shell handles that key before an overlay
1434
+ // ever sees it, which is why an owned screen must not rely on being asked.
1435
+ let armedAt = 0;
1436
+ const removeInterruptWatch = this.runtime.addInputListener(data => {
1437
+ if (!data.includes(INTERRUPT))
1438
+ return undefined;
1439
+ const now = Date.now();
1440
+ if (armedAt !== 0 && now - armedAt <= INTERRUPT_CHORD_MS) {
1441
+ armedAt = 0;
1442
+ closeSurface();
1443
+ void this.shutdown();
1444
+ return { consume: true };
1445
+ }
1446
+ armedAt = now;
1447
+ this.runtime.requestRender();
1448
+ // Invariant: the presented screen owns the chord, so the pinned shell never sees a
1449
+ // stray interrupt while it is up.
1450
+ return { consume: true };
1451
+ });
1452
+ let removeSurfacePreInput = () => { };
1453
+ const closeSurface = () => {
1454
+ removeSurfacePreInput();
1455
+ removeInterruptWatch();
1456
+ this.#setPointerReporting(false);
1457
+ this.#dialogHandle?.hide();
1458
+ this.#dialogHandle = undefined;
1459
+ this.#dialogId = undefined;
1460
+ this.#dialogSource = undefined;
1461
+ };
1462
+ // Compatibility: fullscreen Pi owns a fallback text-selection layer before focused overlay
1463
+ // components see pointer input. Route every mouse report to the owned screen
1464
+ // at the pre-input boundary so dropdowns, value hover, and numeric +/- work,
1465
+ // and consume even unhandled reports so settings content is never selected.
1466
+ removeSurfacePreInput = this.runtime.addPreInputListener(data => {
1467
+ const { events, rest } = parseMouseInput(data);
1468
+ if (events.length === 0)
1469
+ return undefined;
1470
+ for (const event of events)
1471
+ surface.handleMouse(event);
1472
+ if (surface.isClosed())
1473
+ closeSurface();
1474
+ else
1475
+ this.runtime.requestRender();
1476
+ return rest.length === 0 ? { consume: true } : { data: rest };
1477
+ });
1478
+ const rows = () => Math.max(1, this.runtime.viewport().rows);
1479
+ const component = {
1480
+ render: (width) => [...surface.render(Math.max(1, width), rows())],
1481
+ handleInput: (data) => {
1482
+ const { events, rest } = parseMouseInput(data);
1483
+ for (const event of events)
1484
+ surface.handleMouse(event);
1485
+ if (rest.length > 0)
1486
+ surface.handleInput(rest);
1487
+ if (surface.isClosed()) {
1488
+ closeSurface();
1489
+ return;
1490
+ }
1491
+ this.runtime.requestRender();
1492
+ },
1493
+ invalidate: () => this.runtime.requestRender(),
1494
+ };
1495
+ surface.onRenderRequested(() => this.runtime.requestRender());
1496
+ surface.onExitRequested(() => {
1497
+ closeSurface();
1498
+ void this.shutdown();
1499
+ });
1500
+ this.#dialogHandle = this.runtime.showOverlay(component, {
1501
+ width: "100%",
1502
+ maxHeight: "100%",
1503
+ anchor: "top-left",
1504
+ inputCoordination: "owned",
1505
+ });
1506
+ this.#dialogId = surface.id;
1507
+ return { outcome: "completed", diagnostic: null };
1508
+ }
1509
+ #syncDialog(dialog) {
1510
+ if (!this.runtime.active)
1511
+ return;
1512
+ if (dialog === null) {
1513
+ // Invariant: locally owned routes (notably /settings) are independent of backend
1514
+ // lifecycle/status events and remain open while an agent is working.
1515
+ if (this.#dialogSource !== "backend")
1516
+ return;
1517
+ this.#dialogHandle?.hide();
1518
+ this.#dialogHandle = undefined;
1519
+ this.#dialogId = undefined;
1520
+ this.#dialogSource = undefined;
1521
+ return;
1522
+ }
1523
+ if (this.#dialogSource === "backend" && this.#dialogId === dialog.id)
1524
+ return;
1525
+ this.#dialogHandle?.hide();
1526
+ this.#dialogSource = "backend";
1527
+ const component = createPiShellDialog(dialog, {
1528
+ onSelect: () => {
1529
+ this.#dialogHandle?.hide();
1530
+ this.#dialogHandle = undefined;
1531
+ this.#dialogId = undefined;
1532
+ this.#dialogSource = undefined;
1533
+ },
1534
+ onCancel: () => {
1535
+ this.#dialogHandle?.hide();
1536
+ this.#dialogHandle = undefined;
1537
+ this.#dialogId = undefined;
1538
+ this.#dialogSource = undefined;
1539
+ },
1540
+ });
1541
+ this.#dialogHandle = this.runtime.showOverlay(component, {
1542
+ width: "70%",
1543
+ maxHeight: "80%",
1544
+ anchor: "center",
1545
+ inputCoordination: "owned",
1546
+ });
1547
+ this.#dialogId = dialog.id;
1548
+ }
1549
+ async #slashCommand(text) {
1550
+ const body = text.slice(1).trim();
1551
+ const separator = body.search(/\s/);
1552
+ const name = separator < 0 ? body : body.slice(0, separator);
1553
+ const argument = separator < 0 ? "" : body.slice(separator + 1).trimStart();
1554
+ if (this.#routeHost?.claims(name))
1555
+ return this.#openOwnedRoute(name);
1556
+ if (isWorkflowRoute(name))
1557
+ return this.runWorkflow({ command: name, argument });
1558
+ // Compatibility: unknown slash input, prompt templates, skills, and extension commands remain Pi prompt input.
1559
+ this.#rememberInput(text, "slash");
1560
+ this.root.resumeViewportFollowing();
1561
+ return this.#execute({
1562
+ type: this.view().lifecycle === "busy" ? "steer" : "prompt",
1563
+ correlationId: this.#correlation("prompt-command"),
1564
+ sessionId: this.backend.sessionId,
1565
+ text,
1566
+ });
1567
+ }
1568
+ async #completeTreeSelection(entryId, skipSummaryPrompt) {
1569
+ let summarize = false;
1570
+ let customInstructions;
1571
+ if (!skipSummaryPrompt) {
1572
+ while (true) {
1573
+ const choice = await this.#extensionBridge.context.select("Summarize branch?", [
1574
+ "No summary",
1575
+ "Summarize",
1576
+ "Summarize with custom prompt",
1577
+ ]);
1578
+ if (choice === undefined) {
1579
+ this.showTreeSelector(entryId);
1580
+ return;
1581
+ }
1582
+ summarize = choice !== "No summary";
1583
+ if (choice === "Summarize with custom prompt") {
1584
+ customInstructions = await this.#extensionBridge.context.editor("Custom summarization instructions", "");
1585
+ if (customInstructions === undefined)
1586
+ continue;
1587
+ }
1588
+ break;
1589
+ }
1590
+ }
1591
+ const result = await this.runWorkflow({
1592
+ command: "tree",
1593
+ argument: "",
1594
+ selection: entryId,
1595
+ treeSummary: {
1596
+ summarize,
1597
+ ...(customInstructions === undefined ? {} : { customInstructions }),
1598
+ },
1599
+ });
1600
+ if (result.diagnostic === "Branch summarization cancelled")
1601
+ this.showTreeSelector(entryId);
1602
+ }
1603
+ #startWorkflowLogin(request) {
1604
+ this.#finishWorkflowLogin();
1605
+ const dialog = createPiShellLoginDialog({
1606
+ getColumns: () => this.runtime.viewport().columns,
1607
+ getRows: () => this.runtime.viewport().rows,
1608
+ requestRender: () => this.runtime.requestRender(),
1609
+ }, request.providerId, success => {
1610
+ if (!success)
1611
+ this.#finishWorkflowLogin();
1612
+ }, request.providerName);
1613
+ this.#activeLoginDialog = dialog;
1614
+ this.root.setInputSurface(dialog);
1615
+ this.runtime.requestRender();
1616
+ }
1617
+ #requestWorkflowInput(request) {
1618
+ const dialog = this.#activeLoginDialog;
1619
+ if (!dialog)
1620
+ return Promise.resolve(null);
1621
+ if (request.type === "select") {
1622
+ return new Promise(resolve => {
1623
+ const options = request.options ?? [];
1624
+ const labels = options.map(option => option.label);
1625
+ const restoreDialog = () => {
1626
+ if (this.#activeLoginDialog === dialog)
1627
+ this.root.setInputSurface(dialog);
1628
+ this.runtime.requestRender();
1629
+ };
1630
+ const selector = createPiShellExtensionSelector(request.message, labels, label => {
1631
+ const id = options.find(option => option.label === label)?.id;
1632
+ restoreDialog();
1633
+ resolve(id ?? null);
1634
+ }, () => {
1635
+ restoreDialog();
1636
+ resolve(null);
1637
+ });
1638
+ this.root.setInputSurface(selector, false);
1639
+ this.runtime.requestRender();
1640
+ });
1641
+ }
1642
+ const response = request.type === "manual-code"
1643
+ ? dialog.showManualInput(request.message)
1644
+ : dialog.showPrompt(request.message, request.placeholder);
1645
+ this.runtime.requestRender();
1646
+ return response.then(value => value, () => null);
1647
+ }
1648
+ #notifyWorkflowLogin(event) {
1649
+ const dialog = this.#activeLoginDialog;
1650
+ if (!dialog)
1651
+ return;
1652
+ if (event.type === "auth_url")
1653
+ dialog.showAuth(event.url, event.instructions);
1654
+ else if (event.type === "device_code") {
1655
+ dialog.showDeviceCode(event);
1656
+ dialog.showWaiting("Waiting for authentication...");
1657
+ }
1658
+ else if (event.type === "info")
1659
+ dialog.showInfo(event.message, event.links);
1660
+ else if (event.type === "waiting")
1661
+ dialog.showWaiting(event.message);
1662
+ else
1663
+ dialog.showProgress(event.message);
1664
+ this.runtime.requestRender();
1665
+ }
1666
+ #finishWorkflowLogin() {
1667
+ if (!this.#activeLoginDialog)
1668
+ return;
1669
+ this.#activeLoginDialog = undefined;
1670
+ this.root.setInputSurface(null);
1671
+ this.runtime.requestRender();
1672
+ }
1673
+ async #flushCompactionQueue() {
1674
+ const queued = this.#compactionQueue;
1675
+ this.#compactionQueue = [];
1676
+ for (const item of queued) {
1677
+ await this.#execute({
1678
+ type: item.type,
1679
+ correlationId: this.#correlation(`compaction-${item.type}`),
1680
+ sessionId: this.backend.sessionId,
1681
+ text: item.text,
1682
+ ...(item.images === undefined ? {} : { images: item.images }),
1683
+ }, item.draft);
1684
+ }
1685
+ }
1686
+ async #execute(command, draft) {
1687
+ if (draft === undefined)
1688
+ return this.backend.execute(command);
1689
+ const revision = this.#editorRevision;
1690
+ try {
1691
+ assertOwnedUiCommand(command);
1692
+ }
1693
+ catch (error) {
1694
+ return this.#recoverSubmission(draft, revision, error);
1695
+ }
1696
+ try {
1697
+ const result = await this.backend.execute(command);
1698
+ if (result.outcome === "rejected")
1699
+ return this.#recoverSubmission(draft, revision);
1700
+ return result;
1701
+ }
1702
+ catch {
1703
+ // Security: dispatch might already have reached the provider. Never retry automatically.
1704
+ this.root.editor.addToHistory(draft);
1705
+ this.#promptHistory?.rememberRecovery(draft);
1706
+ this.#reportSubmissionError(undefined, "Submission failed; delivery is uncertain. Check the conversation before retrying. Press Up to recover the draft.");
1707
+ return { outcome: "failed", diagnostic: "submission delivery is uncertain" };
1708
+ }
1709
+ }
1710
+ async #guardSubmission(draft, action) {
1711
+ const revision = this.#editorRevision;
1712
+ try {
1713
+ return await action();
1714
+ }
1715
+ catch (error) {
1716
+ if (error instanceof ImageAttachmentError && error.code === "image-canceled")
1717
+ return rejected("image submission canceled");
1718
+ return this.#recoverSubmission(draft, revision, error);
1719
+ }
1720
+ }
1721
+ #recoverSubmission(draft, revision, error) {
1722
+ this.root.editor.addToHistory(draft);
1723
+ this.#promptHistory?.rememberRecovery(draft);
1724
+ // Concurrency: never overwrite input typed (even typed and cleared) after this submission.
1725
+ if (revision === this.#editorRevision && this.root.editor.getText().length === 0)
1726
+ this.root.editor.setText(draft);
1727
+ const message = error instanceof ImageAttachmentError ? error.message : "Submission rejected. Check the prompt and attachments.";
1728
+ this.#reportSubmissionError(error, `${message} Press Up to recover the draft.`);
1729
+ return rejected(message);
1730
+ }
1731
+ #reportSubmissionError(error, message) {
1732
+ // Security: arbitrary provider/extension error messages can contain the entire request.
1733
+ try {
1734
+ this.root.appendWorkflowResult({ command: "debug", outcome: "failed", message: message
1735
+ ?? (error instanceof ImageAttachmentError ? error.message : "Submission failed. Check the prompt and try again.") });
1736
+ this.runtime.requestRender();
1737
+ }
1738
+ catch { /* Security: error presentation cannot create another rejected submission callback. */ }
1739
+ }
1740
+ #simple(type) {
1741
+ return { type, correlationId: this.#correlation(type), sessionId: this.backend.sessionId };
1742
+ }
1743
+ #correlation(prefix) {
1744
+ this.#sequence += 1;
1745
+ return `pi-shell-${prefix}-${this.#sequence}`;
1746
+ }
1747
+ }
1748
+ function isCoalescedStreamBlock(kind) {
1749
+ return kind === "assistant" || kind === "thinking" || kind === "tool-call" || kind === "tool-result";
1750
+ }
1751
+ export function formatSessionResumeCommand(metadata) {
1752
+ const args = [PRODUCT_TEXT.commandName];
1753
+ if (!metadata.usesDefaultSessionDir)
1754
+ args.push("--session-dir", quoteCommandArgument(metadata.sessionDir));
1755
+ args.push("--session", metadata.sessionId);
1756
+ return args.join(" ");
1757
+ }
1758
+ export function quoteCommandArgument(value) {
1759
+ if (value.length > 0 && !/[^a-zA-Z0-9_\-./~:@]/.test(value))
1760
+ return value;
1761
+ return `'${value.replaceAll("'", `'\\''`)}'`;
1762
+ }
1763
+ function dim(value) {
1764
+ return `\u001b[2m${value}\u001b[22m`;
1765
+ }
1766
+ function modelReference(model) {
1767
+ if (typeof model !== "object" || model === null)
1768
+ return "";
1769
+ const value = model;
1770
+ const provider = typeof value.provider === "string" ? value.provider : "";
1771
+ const id = typeof value.id === "string" ? value.id : typeof value.modelId === "string" ? value.modelId : "";
1772
+ return provider && id ? `${provider}/${id}` : "";
1773
+ }
1774
+ function rejected(diagnostic) {
1775
+ return { outcome: "rejected", diagnostic };
1776
+ }
1777
+ function modelKey(view) {
1778
+ return view.activeModel === null ? "" : `${view.activeModel.providerId}/${view.activeModel.modelId}`;
1779
+ }
1780
+ function workflowAdapterResult(result) {
1781
+ if (result.outcome === "completed")
1782
+ return { outcome: "completed", diagnostic: null };
1783
+ if (result.outcome === "failed")
1784
+ return { outcome: "failed", diagnostic: result.message };
1785
+ return { outcome: "rejected", diagnostic: result.message };
1786
+ }
1787
+ const INTERRUPT = "\u0003";
1788
+ const INTERRUPT_CHORD_MS = 1_500;
1789
+ function isWorkflowRoute(value) {
1790
+ return PINNED_PI_WORKFLOW_COMMAND_NAMES.includes(value)
1791
+ || PINNED_PI_HIDDEN_COMMAND_NAMES.includes(value);
1792
+ }