@timurproko/a1 0.1.8-dev.50ebb19 → 0.1.8-dev.510

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