@timurproko/a1 0.1.8-dev.235df0e → 0.1.8-dev.260

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 (485) hide show
  1. package/README.md +107 -67
  2. package/bin/cli.js +28 -10
  3. package/bin/guardian.js +8 -3
  4. package/bin/module-identity.js +69 -35
  5. package/bin/pi-tui.d.ts +6 -0
  6. package/bin/pi-tui.js +28 -0
  7. package/bin/release-cleanup.js +8 -0
  8. package/bin/supervisor.js +2 -2
  9. package/bin/sync-pi-tui-proxy.js +97 -0
  10. package/bin/ui.js +47 -20
  11. package/bin/warmup.js +27 -0
  12. package/dist/cli/capabilities.d.ts +6 -0
  13. package/dist/{src/cli → cli}/capabilities.js +1 -1
  14. package/dist/{src/cli → cli}/dispatch.d.ts +15 -1
  15. package/dist/cli/dispatch.js +261 -0
  16. package/dist/cli/package-messages.d.ts +26 -0
  17. package/dist/cli/package-messages.js +71 -0
  18. package/dist/{src/cli → cli}/packages.d.ts +11 -2
  19. package/dist/{src/cli → cli}/packages.js +24 -27
  20. package/dist/{src/cli → cli}/version-stats.d.ts +6 -0
  21. package/dist/cli/version-stats.js +112 -0
  22. package/dist/composition/agent-engine-bridge.d.ts +3 -0
  23. package/dist/composition/agent-engine-bridge.js +108 -0
  24. package/dist/composition/index.d.ts +3 -0
  25. package/dist/composition/index.js +3 -0
  26. package/dist/composition/owned-ui.d.ts +31 -0
  27. package/dist/composition/owned-ui.js +66 -0
  28. package/dist/composition/process.d.ts +16 -0
  29. package/dist/composition/process.js +45 -0
  30. package/dist/composition/settings-route-host.d.ts +8 -0
  31. package/dist/composition/settings-route-host.js +75 -0
  32. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.d.ts +2 -2
  33. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.js +22 -4
  34. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.d.ts +17 -0
  35. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.d.ts +6 -0
  36. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.d.ts +36 -0
  37. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.js +25 -0
  38. package/dist/{src/features → features}/launch/development-launch.js +11 -3
  39. package/dist/{src/features → features}/launch/index.d.ts +0 -1
  40. package/dist/{src/features → features}/launch/index.js +0 -1
  41. package/dist/features/launch/intent.d.ts +10 -0
  42. package/dist/features/launch/intent.js +8 -0
  43. package/dist/{src/features → features}/launch/prepare-launch.d.ts +0 -2
  44. package/dist/{src/features → features}/launch/prepare-launch.js +2 -9
  45. package/dist/{src/features → features}/launch/profile-paths.d.ts +1 -2
  46. package/dist/{src/features → features}/launch/profile-paths.js +2 -8
  47. package/dist/{src/features → features}/launch/runtime-selection.d.ts +2 -5
  48. package/dist/{src/features → features}/owned-ui/customization.d.ts +3 -1
  49. package/dist/{src/features → features}/owned-ui/customization.js +3 -1
  50. package/dist/{src/features → features}/owned-ui/diagnostics.d.ts +2 -1
  51. package/dist/{src/features → features}/owned-ui/diagnostics.js +1 -0
  52. package/dist/{src/features → features}/owned-ui/index.d.ts +2 -0
  53. package/dist/{src/features → features}/owned-ui/index.js +2 -0
  54. package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
  55. package/dist/features/owned-ui/project-trust-prompt.js +149 -0
  56. package/dist/{src/features → features}/owned-ui/run.d.ts +2 -2
  57. package/dist/{src/features → features}/owned-ui/run.js +2 -0
  58. package/dist/features/owned-ui/session-fork-prompt.d.ts +8 -0
  59. package/dist/features/owned-ui/session-fork-prompt.js +34 -0
  60. package/dist/{src/features → features}/owned-ui/settings-app.d.ts +3 -3
  61. package/dist/{src/features → features}/owned-ui/settings-app.js +103 -54
  62. package/dist/{src/features → features}/workspace/capabilities.d.ts +1 -1
  63. package/dist/{src/features → features}/workspace/reducer.d.ts +2 -1
  64. package/dist/{src/features → features}/workspace/reducer.js +2 -1
  65. package/dist/{src/features → features}/workspace/router.d.ts +2 -1
  66. package/dist/{src/features → features}/workspace/router.js +1 -0
  67. package/dist/{src/features → features}/workspace/store.d.ts +2 -1
  68. package/dist/{src/features → features}/workspace/store.js +1 -0
  69. package/dist/{src/foundation → foundation}/launch-guardian/main.d.ts +2 -0
  70. package/dist/{src/foundation → foundation}/launch-guardian/main.js +18 -5
  71. package/dist/{src/foundation → foundation}/lifecycle/index.d.ts +2 -0
  72. package/dist/{src/foundation → foundation}/lifecycle/index.js +2 -0
  73. package/dist/{src/foundation → foundation}/lifecycle/model.d.ts +1 -1
  74. package/dist/{src/foundation → foundation}/lifecycle/model.js +1 -1
  75. package/dist/foundation/lifecycle/paths.d.ts +30 -0
  76. package/dist/{src/foundation → foundation}/lifecycle/paths.js +29 -1
  77. package/dist/foundation/lifecycle/session-selection.d.ts +9 -0
  78. package/dist/foundation/lifecycle/session-selection.js +39 -0
  79. package/dist/foundation/lifecycle/supervisor-startup.d.ts +30 -0
  80. package/dist/foundation/lifecycle/supervisor-startup.js +106 -0
  81. package/dist/{src/foundation → foundation}/native-host-protocol/codec.d.ts +2 -0
  82. package/dist/{src/foundation → foundation}/native-host-protocol/codec.js +2 -0
  83. package/dist/{src/foundation → foundation}/native-host-protocol/messages.d.ts +1 -1
  84. package/dist/{src/foundation → foundation}/native-host-protocol/messages.js +1 -1
  85. package/dist/foundation/process-containment/darwin-process-inspector.d.ts +5 -0
  86. package/dist/foundation/process-containment/darwin-process-inspector.js +7 -0
  87. package/dist/{src/foundation → foundation}/process-containment/index.d.ts +1 -0
  88. package/dist/{src/foundation → foundation}/process-containment/index.js +1 -0
  89. package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.d.ts +1 -0
  90. package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.js +1 -0
  91. package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.d.ts +1 -0
  92. package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.js +1 -0
  93. package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.d.ts +3 -1
  94. package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +5 -2
  95. package/dist/{src/foundation → foundation}/protocol/client.d.ts +1 -0
  96. package/dist/{src/foundation → foundation}/protocol/client.js +1 -0
  97. package/dist/{src/foundation → foundation}/protocol/messages.d.ts +1 -0
  98. package/dist/{src/foundation → foundation}/protocol/messages.js +1 -0
  99. package/dist/{src/foundation → foundation}/release/bootstrap.d.ts +25 -6
  100. package/dist/{src/foundation → foundation}/release/bootstrap.js +124 -34
  101. package/dist/foundation/release/cohort-state.d.ts +156 -0
  102. package/dist/foundation/release/cohort-state.js +471 -0
  103. package/dist/foundation/release/dependency-layer.d.ts +82 -0
  104. package/dist/foundation/release/dependency-layer.js +497 -0
  105. package/dist/foundation/release/endpoints.d.ts +20 -0
  106. package/dist/foundation/release/endpoints.js +50 -0
  107. package/dist/foundation/release/immutable-platform.d.ts +6 -0
  108. package/dist/foundation/release/immutable-platform.js +13 -0
  109. package/dist/{src/foundation → foundation}/release/index.d.ts +4 -0
  110. package/dist/{src/foundation → foundation}/release/index.js +4 -0
  111. package/dist/foundation/release/release-gc.d.ts +71 -0
  112. package/dist/foundation/release/release-gc.js +734 -0
  113. package/dist/{src/foundation → foundation}/release/release-store.d.ts +7 -3
  114. package/dist/{src/foundation → foundation}/release/release-store.js +65 -13
  115. package/dist/{src/foundation → foundation}/release/release.d.ts +4 -1
  116. package/dist/{src/foundation → foundation}/release/release.js +10 -3
  117. package/dist/foundation/release/restart-certification.d.ts +67 -0
  118. package/dist/foundation/release/restart-certification.js +211 -0
  119. package/dist/{src/foundation → foundation}/release/update-transaction.d.ts +1 -0
  120. package/dist/{src/foundation → foundation}/release/update-transaction.js +1 -0
  121. package/dist/{src/foundation → foundation}/release/update.d.ts +19 -3
  122. package/dist/{src/foundation → foundation}/release/update.js +116 -56
  123. package/dist/foundation/release/warmup.d.ts +3 -0
  124. package/dist/foundation/release/warmup.js +35 -0
  125. package/dist/foundation/startup/index.d.ts +1 -0
  126. package/dist/foundation/startup/index.js +1 -0
  127. package/dist/foundation/startup/startup-runtime.d.ts +36 -0
  128. package/dist/foundation/startup/startup-runtime.js +140 -0
  129. package/dist/{src/foundation → foundation}/storage/control-store.d.ts +2 -1
  130. package/dist/{src/foundation → foundation}/storage/control-store.js +39 -4
  131. package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.d.ts +2 -1
  132. package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.js +2 -1
  133. package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.d.ts +2 -1
  134. package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.js +2 -1
  135. package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.d.ts +1 -1
  136. package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.js +1 -1
  137. package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.d.ts +2 -1
  138. package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.js +2 -1
  139. package/dist/{src/foundation → foundation}/structured-agent-runtime/state.d.ts +2 -1
  140. package/dist/{src/foundation → foundation}/structured-agent-runtime/state.js +2 -1
  141. package/dist/foundation/supervision/index.d.ts +3 -0
  142. package/dist/foundation/supervision/index.js +3 -0
  143. package/dist/foundation/supervision/main.d.ts +1 -0
  144. package/dist/foundation/supervision/main.js +80 -0
  145. package/dist/foundation/supervision/paths.d.ts +1 -0
  146. package/dist/foundation/supervision/paths.js +1 -0
  147. package/dist/{src/foundation → foundation}/supervision/server.d.ts +19 -1
  148. package/dist/{src/foundation → foundation}/supervision/server.js +65 -3
  149. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.d.ts +1 -1
  150. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.d.ts +1 -0
  151. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.js +3 -2
  152. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.d.ts +1 -1
  153. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.js +1 -1
  154. package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
  155. package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
  156. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.d.ts +1 -0
  157. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.js +1 -0
  158. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.js +54 -6
  159. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.d.ts +1 -1
  160. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.d.ts +3 -3
  161. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.js +49 -18
  162. package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
  163. package/dist/integrations/pi/components/shell-presenters-info.js +78 -0
  164. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +25 -0
  165. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-presenters-transcript.js +92 -131
  166. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.d.ts +5 -2
  167. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.js +2 -1
  168. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.d.ts +57 -8
  169. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.js +4 -2
  170. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
  171. package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
  172. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.d.ts +10 -2
  173. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.js +36 -3
  174. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.d.ts +1 -1
  175. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.d.ts +28 -4
  176. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +714 -127
  177. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.d.ts +2 -0
  178. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.js +4 -2
  179. package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
  180. package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
  181. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.d.ts +4 -0
  182. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +4 -0
  183. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.d.ts +2 -1
  184. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.js +1 -0
  185. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.d.ts +1 -1
  186. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.js +32 -26
  187. package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
  188. package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
  189. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.d.ts +2 -1
  190. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.js +1 -0
  191. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.d.ts +19 -1
  192. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +47 -5
  193. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.d.ts +4 -2
  194. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.js +19 -4
  195. package/dist/integrations/pi/engine/session-selection.d.ts +28 -0
  196. package/dist/integrations/pi/engine/session-selection.js +90 -0
  197. package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
  198. package/dist/integrations/pi/engine/settings-effects.js +249 -0
  199. package/dist/integrations/pi/engine/settings-integration.d.ts +43 -0
  200. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/settings-integration.js +102 -108
  201. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.d.ts +3 -2
  202. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.js +1 -0
  203. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.d.ts +18 -1
  204. package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
  205. package/dist/integrations/pi/session-ui/clipboard-image.js +29 -0
  206. package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.d.ts +1 -0
  207. package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.js +1 -0
  208. package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
  209. package/dist/integrations/pi/session-ui/prompt-chips.js +246 -0
  210. package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
  211. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +141 -0
  212. package/dist/integrations/pi/session-ui/session-shell-root.js +1158 -0
  213. package/dist/integrations/pi/session-ui/session-shell.d.ts +55 -0
  214. package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/session-shell.js +479 -719
  215. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +45 -0
  216. package/dist/integrations/pi/session-ui/session-viewport-controller.js +463 -0
  217. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
  218. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
  219. package/dist/integrations/pi/session-ui/system-clipboard.d.ts +20 -0
  220. package/dist/integrations/pi/session-ui/system-clipboard.js +130 -0
  221. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.d.ts +8 -1
  222. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.js +216 -9
  223. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.d.ts +29 -6
  224. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +74 -0
  225. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +380 -0
  226. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.d.ts +2 -0
  227. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.js +2 -0
  228. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
  229. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
  230. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.d.ts +1 -1
  231. package/dist/native/darwin-arm64/manifest.json +4 -4
  232. package/dist/native/darwin-arm64/process-guardian +0 -0
  233. package/dist/native/linux-x64/manifest.json +3 -3
  234. package/dist/native/linux-x64/process-guardian +0 -0
  235. package/dist/native/win32-x64/manifest.json +3 -3
  236. package/dist/native/win32-x64/process-guardian.exe +0 -0
  237. package/dist/{src/product-identity.d.ts → product-identity.d.ts} +3 -3
  238. package/dist/{src/product-identity.js → product-identity.js} +7 -5
  239. package/dist/{src/product-identity.json → product-identity.json} +11 -6
  240. package/dist/runtime-payload-inventory.json +122328 -0
  241. package/dist/{src/foundation/ui-apps → ui/apps}/contracts.d.ts +23 -1
  242. package/dist/{src/foundation/ui-apps → ui/apps}/host.d.ts +1 -1
  243. package/dist/{src/foundation/ui-apps → ui/apps}/host.js +14 -10
  244. package/dist/{src/foundation/ui-apps → ui/apps}/registry.d.ts +1 -0
  245. package/dist/{src/foundation/ui-apps → ui/apps}/registry.js +1 -0
  246. package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.js +5 -3
  247. package/dist/{src/foundation/ui-components → ui/components}/frame.d.ts +1 -0
  248. package/dist/{src/foundation/ui-components → ui/components}/frame.js +1 -0
  249. package/dist/{src/foundation/ui-components → ui/components}/index.d.ts +5 -0
  250. package/dist/{src/foundation/ui-components → ui/components}/index.js +5 -0
  251. package/dist/{src/foundation/ui-components → ui/components}/line-input.d.ts +1 -6
  252. package/dist/{src/foundation/ui-components → ui/components}/line-input.js +4 -9
  253. package/dist/{src/foundation/ui-components → ui/components}/list-view.d.ts +0 -6
  254. package/dist/{src/foundation/ui-components → ui/components}/list-view.js +14 -7
  255. package/dist/{src/foundation/ui-components → ui/components}/mouse.d.ts +10 -0
  256. package/dist/{src/foundation/ui-components → ui/components}/mouse.js +23 -0
  257. package/dist/ui/components/progress-status.d.ts +2 -0
  258. package/dist/ui/components/progress-status.js +4 -0
  259. package/dist/ui/components/prompt-row.d.ts +14 -0
  260. package/dist/ui/components/prompt-row.js +20 -0
  261. package/dist/{src/foundation/ui-components → ui/components}/scrollbar.d.ts +26 -0
  262. package/dist/{src/foundation/ui-components → ui/components}/scrollbar.js +35 -0
  263. package/dist/{src/foundation/ui-components → ui/components}/shortcuts.d.ts +1 -0
  264. package/dist/{src/foundation/ui-components → ui/components}/shortcuts.js +1 -0
  265. package/dist/ui/components/spans.d.ts +25 -0
  266. package/dist/ui/components/spans.js +257 -0
  267. package/dist/ui/components/submitted-prompt.d.ts +23 -0
  268. package/dist/ui/components/submitted-prompt.js +50 -0
  269. package/dist/{src/foundation/ui-components → ui/components}/surface.d.ts +0 -5
  270. package/dist/{src/foundation/ui-components → ui/components}/surface.js +1 -5
  271. package/dist/ui/components/text-selection.d.ts +62 -0
  272. package/dist/ui/components/text-selection.js +208 -0
  273. package/dist/{src/foundation/ui-components → ui/components}/text.d.ts +14 -0
  274. package/dist/{src/foundation/ui-components → ui/components}/text.js +66 -4
  275. package/dist/ui/components/transcript-viewport.d.ts +152 -0
  276. package/dist/ui/components/transcript-viewport.js +631 -0
  277. package/dist/ui/components/visible-hyperlinks.d.ts +19 -0
  278. package/dist/ui/components/visible-hyperlinks.js +64 -0
  279. package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.d.ts +8 -1
  280. package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.js +33 -5
  281. package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.d.ts +1 -1
  282. package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.js +21 -2
  283. package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.d.ts +6 -19
  284. package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.js +32 -23
  285. package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.d.ts +9 -17
  286. package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.js +65 -55
  287. package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.d.ts +1 -0
  288. package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.js +2 -1
  289. package/docs/architecture/boundaries.md +9 -9
  290. package/docs/architecture/code-documentation.md +77 -0
  291. package/docs/architecture/process-guardian-provenance.md +3 -1
  292. package/docs/architecture/project-structure.md +67 -30
  293. package/docs/architecture/resource-and-data-policy.md +1 -1
  294. package/docs/architecture/toolchain.md +10 -10
  295. package/docs/architecture/ui-reference-provenance.md +36 -5
  296. package/docs/ci-release-runbook.md +186 -79
  297. package/docs/features/launch-profiles.md +24 -17
  298. package/docs/manual-ghost-link-baseline.md +89 -0
  299. package/docs/manual-launch-instance-acceptance.md +12 -35
  300. package/docs/manual-owned-ui-checkpoint.md +78 -0
  301. package/docs/manual-pi-boundary-candidate.md +4 -5
  302. package/docs/manual-terminal-colour-check.md +4 -3
  303. package/docs/repository-governance-live-acceptance.md +77 -0
  304. package/package.json +37 -27
  305. package/dist/src/cli/capabilities.d.ts +0 -15
  306. package/dist/src/cli/dispatch.js +0 -177
  307. package/dist/src/cli/version-stats.js +0 -72
  308. package/dist/src/composition/index.d.ts +0 -48
  309. package/dist/src/composition/index.js +0 -258
  310. package/dist/src/features/launch/intent.d.ts +0 -7
  311. package/dist/src/features/launch/intent.js +0 -4
  312. package/dist/src/features/launch/profiles.d.ts +0 -12
  313. package/dist/src/features/launch/profiles.js +0 -26
  314. package/dist/src/foundation/lifecycle/paths.d.ts +0 -10
  315. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +0 -57
  316. package/dist/src/foundation/pi-engine-adapter/settings-integration.d.ts +0 -55
  317. package/dist/src/foundation/pi-owned-ui-integration/route-host.d.ts +0 -29
  318. package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +0 -106
  319. package/dist/src/foundation/release/cohort-state.d.ts +0 -70
  320. package/dist/src/foundation/release/cohort-state.js +0 -202
  321. package/dist/src/foundation/release/release-gc.d.ts +0 -5
  322. package/dist/src/foundation/release/release-gc.js +0 -16
  323. package/dist/src/foundation/supervision/index.d.ts +0 -3
  324. package/dist/src/foundation/supervision/index.js +0 -3
  325. package/dist/src/foundation/supervision/main.d.ts +0 -1
  326. package/dist/src/foundation/supervision/main.js +0 -41
  327. package/dist/src/foundation/supervision/paths.d.ts +0 -1
  328. package/dist/src/foundation/supervision/paths.js +0 -1
  329. package/dist/src/foundation/ui-components/spans.d.ts +0 -7
  330. package/dist/src/foundation/ui-components/spans.js +0 -59
  331. package/docs/manual-transparent-checkpoint.md +0 -53
  332. /package/dist/{src/cli → cli}/index.d.ts +0 -0
  333. /package/dist/{src/cli → cli}/index.js +0 -0
  334. /package/dist/{src/cli → cli}/version.d.ts +0 -0
  335. /package/dist/{src/cli → cli}/version.js +0 -0
  336. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.js +0 -0
  337. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.d.ts +0 -0
  338. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.js +0 -0
  339. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.d.ts +0 -0
  340. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.js +0 -0
  341. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.d.ts +0 -0
  342. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.js +0 -0
  343. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.js +0 -0
  344. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.d.ts +0 -0
  345. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.js +0 -0
  346. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.d.ts +0 -0
  347. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.js +0 -0
  348. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.d.ts +0 -0
  349. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.js +0 -0
  350. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.d.ts +0 -0
  351. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.js +0 -0
  352. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.d.ts +0 -0
  353. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.js +0 -0
  354. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.js +0 -0
  355. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.d.ts +0 -0
  356. /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.d.ts +0 -0
  357. /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.js +0 -0
  358. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.d.ts +0 -0
  359. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.js +0 -0
  360. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.d.ts +0 -0
  361. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.js +0 -0
  362. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.d.ts +0 -0
  363. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.js +0 -0
  364. /package/dist/{src/features → features}/launch/development-launch.d.ts +0 -0
  365. /package/dist/{src/features → features}/launch/initialize-profile.d.ts +0 -0
  366. /package/dist/{src/features → features}/launch/initialize-profile.js +0 -0
  367. /package/dist/{src/features → features}/launch/runtime-selection.js +0 -0
  368. /package/dist/{src/features → features}/workspace/capabilities.js +0 -0
  369. /package/dist/{src/features → features}/workspace/index.d.ts +0 -0
  370. /package/dist/{src/features → features}/workspace/index.js +0 -0
  371. /package/dist/{src/features → features}/workspace/presentation.d.ts +0 -0
  372. /package/dist/{src/features → features}/workspace/presentation.js +0 -0
  373. /package/dist/{src/features → features}/workspace/reconciliation.d.ts +0 -0
  374. /package/dist/{src/features → features}/workspace/reconciliation.js +0 -0
  375. /package/dist/{src/foundation → foundation}/launch-guardian/index.d.ts +0 -0
  376. /package/dist/{src/foundation → foundation}/launch-guardian/index.js +0 -0
  377. /package/dist/{src/foundation → foundation}/lifecycle/commands.d.ts +0 -0
  378. /package/dist/{src/foundation → foundation}/lifecycle/commands.js +0 -0
  379. /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.d.ts +0 -0
  380. /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.js +0 -0
  381. /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.d.ts +0 -0
  382. /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.js +0 -0
  383. /package/dist/{src/foundation → foundation}/native-host-protocol/index.d.ts +0 -0
  384. /package/dist/{src/foundation → foundation}/native-host-protocol/index.js +0 -0
  385. /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.d.ts +0 -0
  386. /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.js +0 -0
  387. /package/dist/{src/foundation → foundation}/process-containment/artifact.d.ts +0 -0
  388. /package/dist/{src/foundation → foundation}/process-containment/artifact.js +0 -0
  389. /package/dist/{src/foundation → foundation}/process-containment/contracts.d.ts +0 -0
  390. /package/dist/{src/foundation → foundation}/process-containment/contracts.js +0 -0
  391. /package/dist/{src/foundation → foundation}/protocol/index.d.ts +0 -0
  392. /package/dist/{src/foundation → foundation}/protocol/index.js +0 -0
  393. /package/dist/{src/foundation → foundation}/release/cohort-selection.d.ts +0 -0
  394. /package/dist/{src/foundation → foundation}/release/cohort-selection.js +0 -0
  395. /package/dist/{src/foundation → foundation}/release/concurrency.d.ts +0 -0
  396. /package/dist/{src/foundation → foundation}/release/concurrency.js +0 -0
  397. /package/dist/{src/foundation → foundation}/release/process-cleanup.d.ts +0 -0
  398. /package/dist/{src/foundation → foundation}/release/process-cleanup.js +0 -0
  399. /package/dist/{src/foundation → foundation}/release/stable-release.d.ts +0 -0
  400. /package/dist/{src/foundation → foundation}/release/stable-release.js +0 -0
  401. /package/dist/{src/foundation → foundation}/storage/index.d.ts +0 -0
  402. /package/dist/{src/foundation → foundation}/storage/index.js +0 -0
  403. /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.d.ts +0 -0
  404. /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.js +0 -0
  405. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.js +0 -0
  406. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.d.ts +0 -0
  407. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.js +0 -0
  408. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.d.ts +0 -0
  409. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.js +0 -0
  410. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.d.ts +0 -0
  411. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.js +0 -0
  412. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.d.ts +0 -0
  413. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.js +0 -0
  414. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.d.ts +0 -0
  415. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.js +0 -0
  416. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.d.ts +0 -0
  417. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.js +0 -0
  418. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.d.ts +0 -0
  419. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.js +0 -0
  420. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.d.ts +0 -0
  421. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.js +0 -0
  422. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.d.ts +0 -0
  423. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.js +0 -0
  424. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.d.ts +0 -0
  425. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.js +0 -0
  426. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.d.ts +0 -0
  427. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.js +0 -0
  428. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.d.ts +0 -0
  429. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.js +0 -0
  430. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.d.ts +0 -0
  431. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.js +0 -0
  432. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.js +0 -0
  433. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.d.ts +0 -0
  434. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.js +0 -0
  435. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.d.ts +0 -0
  436. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.js +0 -0
  437. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.d.ts +0 -0
  438. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.js +0 -0
  439. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.d.ts +0 -0
  440. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.js +0 -0
  441. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.d.ts +0 -0
  442. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.js +0 -0
  443. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.d.ts +0 -0
  444. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.js +0 -0
  445. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.d.ts +0 -0
  446. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.js +0 -0
  447. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.d.ts +0 -0
  448. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.js +0 -0
  449. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.d.ts +0 -0
  450. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.js +0 -0
  451. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.d.ts +0 -0
  452. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.js +0 -0
  453. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/pi-settings-metadata.json +0 -0
  454. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.d.ts +0 -0
  455. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.js +0 -0
  456. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.js +0 -0
  457. /package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/route-host.js +0 -0
  458. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.d.ts +0 -0
  459. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.js +0 -0
  460. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.js +0 -0
  461. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.js +0 -0
  462. /package/dist/{src/foundation/ui-apps → ui/apps}/contracts.js +0 -0
  463. /package/dist/{src/foundation/ui-apps → ui/apps}/index.d.ts +0 -0
  464. /package/dist/{src/foundation/ui-apps → ui/apps}/index.js +0 -0
  465. /package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.d.ts +0 -0
  466. /package/dist/{src/foundation/ui-components → ui/components}/label.d.ts +0 -0
  467. /package/dist/{src/foundation/ui-components → ui/components}/label.js +0 -0
  468. /package/dist/{src/foundation/ui-components → ui/components}/list-block.d.ts +0 -0
  469. /package/dist/{src/foundation/ui-components → ui/components}/list-block.js +0 -0
  470. /package/dist/{src/foundation/ui-components → ui/components}/pane.d.ts +0 -0
  471. /package/dist/{src/foundation/ui-components → ui/components}/pane.js +0 -0
  472. /package/dist/{src/foundation/ui-components → ui/components}/revision.d.ts +0 -0
  473. /package/dist/{src/foundation/ui-components → ui/components}/revision.js +0 -0
  474. /package/dist/{src/foundation/ui-components → ui/components}/status-line.d.ts +0 -0
  475. /package/dist/{src/foundation/ui-components → ui/components}/status-line.js +0 -0
  476. /package/dist/{src/foundation/ui-components → ui/components}/stepper.d.ts +0 -0
  477. /package/dist/{src/foundation/ui-components → ui/components}/stepper.js +0 -0
  478. /package/dist/{src/foundation/ui-components → ui/components}/theme.d.ts +0 -0
  479. /package/dist/{src/foundation/ui-components → ui/components}/theme.js +0 -0
  480. /package/dist/{src/foundation/ui-components → ui/components}/value-menu.d.ts +0 -0
  481. /package/dist/{src/foundation/ui-components → ui/components}/value-menu.js +0 -0
  482. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.d.ts +0 -0
  483. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.js +0 -0
  484. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.d.ts +0 -0
  485. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.js +0 -0
@@ -1,668 +1,14 @@
1
- import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput } from "../ui-components/index.js";
2
- import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../pi-engine-adapter/index.js";
3
- import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, piTheme, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../pi-component-adapter/index.js";
4
- import { PiTuiRuntimeAdapter, } from "../pi-tui-runtime-adapter/index.js";
5
- export class OwnedUiSessionShellRoot {
6
- editor;
7
- header;
8
- resources;
9
- #cwd;
10
- #transcript = new Map();
11
- #transcriptOrder = [];
12
- #view;
13
- #status;
14
- #footer;
15
- #queued;
16
- #extensionRenderers;
17
- #componentRuntime;
18
- #toolsExpanded = false;
19
- #thinkingVisible = true;
20
- #workflowTranscriptSequence = 0;
21
- #workflowStatusAnchors = new Map();
22
- #workflowStatusMessages = new Map();
23
- #lastWorkflowStatusId;
24
- #inputSurface;
25
- #extensionHeader = null;
26
- #extensionFooter = null;
27
- #extensionWidgets = new Map();
28
- #extensionStatuses = new Map();
29
- #extensionWorkingMessage;
30
- #extensionWorkingVisible = true;
31
- constructor(view, cwd, handlers, startup = {}, agentDir, extensionRenderers = {
32
- getMessageRenderer: () => undefined,
33
- getToolDefinition: () => undefined,
34
- }) {
35
- this.#view = view;
36
- this.#cwd = cwd;
37
- this.#extensionRenderers = extensionRenderers;
38
- this.#componentRuntime = handlers;
39
- this.header = createPiShellHeader(startup);
40
- this.resources = createPiShellLoadedResources(startup.resources ?? [], startup.expanded ?? false);
41
- this.#status = createPiShellStatus(view, handlers);
42
- this.#footer = createPiShellFooter(this.#viewWithExtensionStatuses(view), cwd);
43
- this.#queued = createPiQueuedInputStatus(view.editor.queuedSubmissions);
44
- this.editor = createPiShellEditor({
45
- ...handlers,
46
- cwd,
47
- ...(agentDir === undefined ? {} : { agentDir }),
48
- onToolsExpand: () => this.#setToolsExpanded(!this.#toolsExpanded),
49
- });
50
- this.editor.setThinkingLevel(view.thinkingLevel);
51
- this.#inputSurface = this.editor;
52
- for (const block of view.transcript) {
53
- if (block.kind === "user")
54
- this.editor.addToHistory(block.text);
55
- }
56
- this.#syncTranscript(view.transcript);
57
- }
58
- update(view) {
59
- this.#view = view;
60
- this.#status.update(view);
61
- this.#footer.update(this.#viewWithExtensionStatuses(view));
62
- this.#queued.update(view.editor.queuedSubmissions);
63
- this.#syncTranscript(view.transcript);
64
- this.editor.setSubmitEnabled(view.lifecycle !== "stopping" && view.lifecycle !== "stopped" && view.lifecycle !== "failed");
65
- this.editor.setThinkingLevel(view.thinkingLevel);
66
- this.invalidate();
67
- }
68
- render(width) {
69
- const queued = this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width);
70
- return [
71
- ...this.#renderDocument(width),
72
- ...queued,
73
- ...this.#renderStatus(width),
74
- ...this.#renderWidgets("aboveEditor", width),
75
- ...this.#inputSurface.render(width),
76
- ...this.#renderWidgets("belowEditor", width),
77
- ...this.#renderFooter(width),
78
- ];
79
- }
80
- layoutRoot() {
81
- const document = layoutPort(width => this.#renderDocument(width), () => this.invalidate());
82
- const queued = layoutPort(width => this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width), () => this.#queued.invalidate());
83
- const aboveWidgets = layoutPort(width => this.#renderWidgets("aboveEditor", width), () => this.#invalidateExtensions());
84
- const status = layoutPort(width => this.#renderStatus(width), () => this.#status.invalidate());
85
- const editor = layoutPort(width => this.#inputSurface.render(width), () => this.#inputSurface.invalidate(), data => this.#inputSurface.handleInput?.(data));
86
- const belowWidgets = layoutPort(width => this.#renderWidgets("belowEditor", width), () => this.#invalidateExtensions());
87
- const footer = layoutPort(width => this.#renderFooter(width), () => (this.#extensionFooter ?? this.#footer).invalidate());
88
- return {
89
- type: "stack",
90
- direction: "vertical",
91
- children: [
92
- {
93
- basis: 0,
94
- grow: 1,
95
- shrink: 1,
96
- minSize: 1,
97
- node: {
98
- type: "scroll",
99
- id: "transcript",
100
- follow: "end",
101
- primary: true,
102
- overscroll: "chain",
103
- scrollbar: "auto",
104
- scrollbarStyle: text => piTheme().bg("scrollbarThumb", text),
105
- child: { type: "component", component: document },
106
- },
107
- },
108
- {
109
- basis: "auto",
110
- grow: 0,
111
- shrink: 1,
112
- minSize: 1,
113
- node: {
114
- type: "stack",
115
- direction: "vertical",
116
- children: [
117
- { shrink: 1, minSize: 0, node: { type: "component", component: queued } },
118
- { shrink: 1, minSize: 0, node: { type: "component", component: status } },
119
- { shrink: 1, minSize: 0, node: { type: "component", component: aboveWidgets } },
120
- { shrink: 1, minSize: 3, node: { type: "component", component: editor } },
121
- { shrink: 1, minSize: 0, node: { type: "component", component: belowWidgets } },
122
- { shrink: 1, minSize: 1, node: { type: "component", component: footer } },
123
- ],
124
- },
125
- },
126
- ],
127
- };
128
- }
129
- #renderDocument(width) {
130
- const transcript = this.#transcriptOrder.flatMap((id, index) => {
131
- const block = this.#view.transcript.find(item => item.id === id);
132
- if (!this.#thinkingVisible && block?.kind === "thinking")
133
- return [];
134
- const rows = this.#transcript.get(id)?.render(width) ?? [];
135
- if (index > 0 && block?.kind === "user")
136
- return ["", ...rows];
137
- return rows;
138
- });
139
- const diagnostics = this.#view.diagnostics;
140
- const startupRows = diagnostics
141
- .filter(diagnostic => diagnostic.code === "engine-startup")
142
- .flatMap(diagnostic => renderPiShellStartupDiagnostic(diagnostic, width));
143
- const packageUpdateRows = diagnostics
144
- .filter(diagnostic => diagnostic.code === "package-updates")
145
- .flatMap(diagnostic => renderPiShellPackageUpdateNotice(diagnostic.message.split("\n").filter(line => line.startsWith("- ")).map(line => line.slice(2)), width));
146
- const diagnosticRows = diagnostics
147
- .filter(diagnostic => diagnostic.code !== "engine-startup" && diagnostic.code !== "package-updates")
148
- .slice(-3)
149
- .flatMap(diagnostic => renderPiShellTranscriptBlock({
150
- id: `diagnostic-${diagnostic.sequence}`,
151
- kind: diagnostic.severity === "error" ? "error" : "system",
152
- status: "finalized",
153
- revision: diagnostic.sequence,
154
- title: diagnostic.code,
155
- text: diagnostic.message,
156
- payload: {},
157
- }, width, this.#cwd));
158
- const resourceRows = [...this.resources.render(width)];
159
- if (resourceRows.at(-1) === "")
160
- resourceRows.pop();
161
- return [
162
- ...startupRows,
163
- ...(this.#extensionHeader ?? this.header).render(width),
164
- ...resourceRows,
165
- ...transcript,
166
- ...packageUpdateRows,
167
- ...diagnosticRows,
168
- ];
169
- }
170
- transcriptComponent(id) {
171
- return this.#transcript.get(id);
172
- }
173
- appendWorkflowStatus(message) {
174
- const previousId = this.#lastWorkflowStatusId;
175
- if (previousId !== undefined
176
- && this.#transcriptOrder.at(-1) === previousId
177
- && this.#workflowStatusAnchors.get(previousId) === this.#view.transcript.length) {
178
- this.#workflowStatusMessages.set(previousId, message);
179
- this.invalidate();
180
- return;
181
- }
182
- const id = this.#appendAnchoredWorkflowComponent(width => [
183
- "",
184
- ...renderPiShellStatusText(this.#workflowStatusMessages.get(id) ?? message, width),
185
- ]);
186
- this.#workflowStatusMessages.set(id, message);
187
- this.#lastWorkflowStatusId = id;
188
- }
189
- appendWorkflowResult(result) {
190
- if (result.command === "reload" && result.outcome === "completed") {
191
- this.appendWorkflowStatus(result.message);
192
- return;
193
- }
194
- if (result.command === "session" && result.outcome === "completed" && result.presentation?.kind === "session-info") {
195
- this.#lastWorkflowStatusId = undefined;
196
- const sessionInfo = createPiShellSessionInfo(result.presentation);
197
- this.#appendAnchoredWorkflowComponent(width => sessionInfo.render(width), () => sessionInfo.dispose?.());
198
- return;
199
- }
200
- if (result.command === "hotkeys" && result.outcome === "completed") {
201
- this.#lastWorkflowStatusId = undefined;
202
- const hotkeys = createPiShellHotkeys();
203
- this.#appendAnchoredWorkflowComponent(width => hotkeys.render(width), () => hotkeys.dispose?.());
204
- return;
205
- }
206
- if (result.command === "changelog" && result.outcome === "completed") {
207
- this.#lastWorkflowStatusId = undefined;
208
- const changelog = createPiShellChangelog(result.detail ?? "No changelog entries found.");
209
- this.#appendAnchoredWorkflowComponent(width => changelog.render(width), () => changelog.dispose?.());
210
- return;
211
- }
212
- if (result.outcome === "failed") {
213
- this.#lastWorkflowStatusId = undefined;
214
- const warning = (result.command === "name" && result.message.startsWith("Usage:"))
215
- || (result.command === "reload" && result.message.startsWith("Wait for "));
216
- const prefix = warning ? "Warning" : "Error";
217
- const color = warning ? "warning" : "error";
218
- this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg(color, `${prefix}: ${result.message}`)}`]);
219
- return;
220
- }
221
- if (result.outcome === "completed" && (result.command === "quit" || result.command === "compact"))
222
- return;
223
- if (result.command === "new" && result.outcome === "completed") {
224
- this.#lastWorkflowStatusId = undefined;
225
- this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg("accent", result.message)}`]);
226
- return;
227
- }
228
- if (result.command === "name" && result.outcome === "completed") {
229
- this.#lastWorkflowStatusId = undefined;
230
- this.#appendAnchoredWorkflowComponent(() => [
231
- ...(result.detail ? ["", ` ${piTheme().fg("warning", `Warning: ${result.detail}`)}`] : []),
232
- "",
233
- ` ${piTheme().fg("dim", result.message)}`,
234
- ]);
235
- return;
236
- }
237
- if (result.command === "debug" && result.outcome === "completed") {
238
- this.#lastWorkflowStatusId = undefined;
239
- this.#appendAnchoredWorkflowComponent(() => [
240
- "",
241
- ` ${piTheme().fg("accent", result.message)}`,
242
- ...(result.detail ? [` ${piTheme().fg("muted", result.detail)}`] : []),
243
- ]);
244
- return;
245
- }
246
- if (result.command === "arminsayshi" && result.outcome === "completed") {
247
- this.#lastWorkflowStatusId = undefined;
248
- const armin = createPiShellArmin(this.#componentRuntime);
249
- this.#appendAnchoredWorkflowComponent(width => ["", ...armin.render(width)], () => armin.dispose?.());
250
- return;
251
- }
252
- if (result.command === "dementedelves" && result.outcome === "completed") {
253
- this.#lastWorkflowStatusId = undefined;
254
- const announcement = createPiShellEarendilAnnouncement();
255
- this.#appendAnchoredWorkflowComponent(width => ["", ...announcement.render(width)], () => announcement.dispose?.());
256
- return;
257
- }
258
- const message = result.command === "share" && result.detail
259
- ? `${result.message}\nGist: ${result.detail}`
260
- : result.message;
261
- this.appendWorkflowStatus(message);
262
- }
263
- appendDaxnuts() {
264
- this.#lastWorkflowStatusId = undefined;
265
- const daxnuts = createPiShellDaxnuts(this.#componentRuntime);
266
- this.#appendAnchoredWorkflowComponent(width => ["", ...daxnuts.render(width)], () => daxnuts.dispose?.());
267
- }
268
- toggleThinkingVisibility() {
269
- this.#thinkingVisible = !this.#thinkingVisible;
270
- this.invalidate();
271
- }
272
- get toolsExpanded() {
273
- return this.#toolsExpanded;
274
- }
275
- setToolsExpanded(expanded) {
276
- this.#setToolsExpanded(expanded);
277
- }
278
- setExtensionWidget(key, component, placement) {
279
- const previous = this.#extensionWidgets.get(key)?.component;
280
- if (component === null)
281
- this.#extensionWidgets.delete(key);
282
- else
283
- this.#extensionWidgets.set(key, { component, placement });
284
- if (previous !== undefined && previous !== component)
285
- previous.dispose?.();
286
- this.invalidate();
287
- }
288
- setExtensionHeader(component) {
289
- if (this.#extensionHeader !== component)
290
- this.#extensionHeader?.dispose?.();
291
- this.#extensionHeader = component;
292
- this.invalidate();
293
- }
294
- setExtensionFooter(component) {
295
- if (this.#extensionFooter !== component)
296
- this.#extensionFooter?.dispose?.();
297
- this.#extensionFooter = component;
298
- this.invalidate();
299
- }
300
- setExtensionStatus(key, text) {
301
- if (text === undefined)
302
- this.#extensionStatuses.delete(key);
303
- else
304
- this.#extensionStatuses.set(key, text);
305
- this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
306
- this.invalidate();
307
- }
308
- setExtensionWorking(message, visible = this.#extensionWorkingVisible) {
309
- this.#extensionWorkingMessage = message;
310
- this.#extensionWorkingVisible = visible;
311
- this.#status.setWorkingOverride(visible ? message : undefined);
312
- this.invalidate();
313
- }
314
- resetWorkflowPresentation() {
315
- for (const id of this.#workflowStatusAnchors.keys()) {
316
- this.#transcript.get(id)?.dispose?.();
317
- this.#transcript.delete(id);
318
- }
319
- this.#workflowStatusAnchors.clear();
320
- this.#workflowStatusMessages.clear();
321
- this.#transcriptOrder = this.#transcriptOrder.filter(id => !id.startsWith("workflow-status-"));
322
- this.#lastWorkflowStatusId = undefined;
323
- this.invalidate();
324
- }
325
- resetExtensionUi() {
326
- this.#extensionHeader?.dispose?.();
327
- this.#extensionFooter?.dispose?.();
328
- for (const { component } of this.#extensionWidgets.values())
329
- component.dispose?.();
330
- this.#extensionHeader = null;
331
- this.#extensionFooter = null;
332
- this.#extensionWidgets.clear();
333
- this.#extensionStatuses.clear();
334
- this.#extensionWorkingMessage = undefined;
335
- this.#status.setWorkingOverride(undefined);
336
- this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
337
- this.invalidate();
338
- }
339
- addExtensionNotification(message, type) {
340
- if (type === "info") {
341
- this.appendWorkflowStatus(message);
342
- return;
343
- }
344
- this.#lastWorkflowStatusId = undefined;
345
- const prefix = type === "warning" ? "Warning" : "Error";
346
- this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg(type, `${prefix}: ${message}`)}`]);
347
- }
348
- extensionFooterData() {
349
- return {
350
- getGitBranch: () => this.#view.status.footer?.branch ?? null,
351
- getExtensionStatuses: () => new Map(this.#extensionStatuses),
352
- getAvailableProviderCount: () => this.#view.status.footer?.availableProviderCount ?? 1,
353
- onBranchChange: () => () => { },
354
- };
355
- }
356
- setInputSurface(component, disposePrevious = true) {
357
- const next = component ?? this.editor;
358
- if (next === this.#inputSurface)
359
- return;
360
- this.#inputSurface.setFocused?.(false);
361
- if (disposePrevious && this.#inputSurface !== this.editor)
362
- this.#inputSurface.dispose?.();
363
- this.#inputSurface = next;
364
- this.#inputSurface.setFocused?.(true);
365
- this.invalidate();
366
- }
367
- handleInput(data) {
368
- this.#inputSurface.handleInput?.(data);
369
- }
370
- invalidate() {
371
- this.header.invalidate();
372
- this.resources.invalidate();
373
- for (const component of this.#transcript.values())
374
- component.invalidate();
375
- this.editor.invalidate();
376
- if (this.#inputSurface !== this.editor)
377
- this.#inputSurface.invalidate();
378
- this.#invalidateExtensions();
379
- this.#status.invalidate();
380
- this.#footer.invalidate();
381
- this.#queued.invalidate();
382
- }
383
- setFocused(focused) {
384
- this.#inputSurface.setFocused?.(focused);
385
- }
386
- dispose() {
387
- this.header.dispose?.();
388
- this.resources.dispose?.();
389
- for (const component of this.#transcript.values())
390
- component.dispose?.();
391
- this.#transcript.clear();
392
- if (this.#inputSurface !== this.editor)
393
- this.#inputSurface.dispose?.();
394
- this.#extensionHeader?.dispose?.();
395
- this.#extensionFooter?.dispose?.();
396
- for (const { component } of this.#extensionWidgets.values())
397
- component.dispose?.();
398
- this.#extensionWidgets.clear();
399
- this.editor.dispose?.();
400
- this.#status.dispose?.();
401
- this.#footer.dispose?.();
402
- this.#queued.dispose?.();
403
- }
404
- #syncTranscript(blocks) {
405
- const nextIds = new Set(blocks.map(block => block.id));
406
- for (const [id, component] of this.#transcript) {
407
- if (id.startsWith("workflow-status-") || nextIds.has(id))
408
- continue;
409
- component.dispose?.();
410
- this.#transcript.delete(id);
411
- }
412
- for (const block of blocks) {
413
- const component = this.#transcript.get(block.id);
414
- if (component === undefined) {
415
- const created = createPiShellTranscriptComponent(block, this.#cwd, this.#extensionRenderers);
416
- created.setExpanded(this.#toolsExpanded);
417
- this.#transcript.set(block.id, created);
418
- }
419
- else if (component.revision !== block.revision) {
420
- component.update(block);
421
- }
422
- }
423
- const statusIds = [...this.#workflowStatusAnchors.keys()];
424
- const order = [];
425
- for (let index = 0; index <= blocks.length; index += 1) {
426
- for (const statusId of statusIds) {
427
- if (this.#workflowStatusAnchors.get(statusId) === index)
428
- order.push(statusId);
429
- }
430
- const block = blocks[index];
431
- if (block !== undefined)
432
- order.push(block.id);
433
- }
434
- for (const statusId of statusIds) {
435
- if (!order.includes(statusId))
436
- order.push(statusId);
437
- }
438
- this.#transcriptOrder = order;
439
- }
440
- #appendAnchoredWorkflowComponent(render, dispose) {
441
- this.#workflowTranscriptSequence += 1;
442
- const id = `workflow-status-${this.#workflowTranscriptSequence}`;
443
- const component = {
444
- id,
445
- revision: 1,
446
- render,
447
- handleInput() { },
448
- invalidate() { },
449
- update() { },
450
- setExpanded() { },
451
- ...(dispose === undefined ? {} : { dispose }),
452
- };
453
- this.#transcript.set(id, component);
454
- this.#workflowStatusAnchors.set(id, this.#view.transcript.length);
455
- this.#transcriptOrder.push(id);
456
- this.invalidate();
457
- return id;
458
- }
459
- #renderWidgets(placement, width) {
460
- const rows = [...this.#extensionWidgets.values()]
461
- .filter(widget => widget.placement === placement)
462
- .flatMap(widget => widget.component.render(width));
463
- return placement === "aboveEditor" ? ["", ...rows] : rows;
464
- }
465
- #renderStatus(width) {
466
- return this.#status.render(width);
467
- }
468
- #renderFooter(width) {
469
- return (this.#extensionFooter ?? this.#footer).render(width);
470
- }
471
- #viewWithExtensionStatuses(view) {
472
- const footer = view.status.footer;
473
- const statuses = new Map(footer?.extensionStatuses ?? []);
474
- for (const [key, text] of this.#extensionStatuses)
475
- statuses.set(key, text);
476
- return {
477
- ...view,
478
- status: {
479
- ...view.status,
480
- footer: {
481
- branch: footer?.branch ?? null,
482
- sessionName: footer?.sessionName ?? null,
483
- availableProviderCount: footer?.availableProviderCount ?? 1,
484
- extensionStatuses: [...statuses],
485
- },
486
- },
487
- };
488
- }
489
- #invalidateExtensions() {
490
- this.#extensionHeader?.invalidate();
491
- this.#extensionFooter?.invalidate();
492
- for (const { component } of this.#extensionWidgets.values())
493
- component.invalidate();
494
- }
495
- #setToolsExpanded(expanded) {
496
- this.#toolsExpanded = expanded;
497
- this.header.setExpanded(expanded);
498
- this.resources.setExpanded(expanded);
499
- for (const component of this.#transcript.values())
500
- component.setExpanded(expanded);
501
- this.invalidate();
502
- }
503
- }
504
- function layoutPort(render, invalidate, handleInput) {
505
- return {
506
- render,
507
- invalidate,
508
- ...(handleInput === undefined ? {} : { handleInput }),
509
- };
510
- }
511
- function shellResourceEntries(backend) {
512
- const resources = backend.nonVisualResources().map(resource => ({
513
- section: resource.kind === "skill"
514
- ? "Skills"
515
- : resource.kind === "prompt-template"
516
- ? "Prompts"
517
- : resource.kind === "theme"
518
- ? "Themes"
519
- : "Context",
520
- label: resource.kind === "prompt-template"
521
- ? `/${resource.label}`
522
- : resource.kind === "agent-context" || resource.kind === "system-prompt"
523
- ? compactResourceLabel(resource.sourcePath ?? resource.label)
524
- : resource.label,
525
- sourcePath: resource.sourcePath,
526
- diagnostic: resource.diagnostic,
527
- }));
528
- const extensions = backend.extensionResources().filter(extension => !extension.hidden);
529
- const loadedExtensions = extensions.filter(extension => extension.diagnostic === null);
530
- const extensionLabels = compactExtensionLabels(loadedExtensions);
531
- for (const extension of extensions) {
532
- const labelIndex = loadedExtensions.indexOf(extension);
533
- resources.push({
534
- section: "Extensions",
535
- label: extensionLabels[labelIndex] ?? compactResourceLabel(extension.sourcePath ?? extension.resolvedPath ?? "extension"),
536
- sourcePath: extension.sourcePath ?? extension.resolvedPath,
537
- diagnostic: extension.diagnostic,
538
- });
539
- }
540
- return resources;
541
- }
542
- function compactResourceLabel(path) {
543
- const segments = compactPathSegments(path);
544
- const leaf = segments.at(-1) ?? path;
545
- if ((leaf === "index.ts" || leaf === "index.js") && segments.length > 1)
546
- return segments.at(-2) ?? leaf;
547
- return leaf;
548
- }
549
- /**
550
- * Pinned from InteractiveMode's compact extension-label helpers at Pi commit
551
- * 914cf1472e715297caa30db4b9535d534a9eb718. The source metadata crosses an
552
- * A1-owned boundary first; the owned shell never inspects Pi's private root.
553
- */
554
- function compactExtensionLabels(extensions) {
555
- const localExtensions = extensions
556
- .filter(extension => !isPackageExtensionSource(extension.sourceInfo))
557
- .map(extension => {
558
- const path = extension.sourcePath ?? extension.resolvedPath ?? "extension";
559
- const segments = compactPathSegments(path);
560
- if (segments.length > 1 && (segments.at(-1) === "index.ts" || segments.at(-1) === "index.js"))
561
- segments.pop();
562
- return { extension, segments };
563
- });
564
- return extensions.map(extension => {
565
- const resourcePath = extension.sourcePath ?? extension.resolvedPath ?? "extension";
566
- if (isPackageExtensionSource(extension.sourceInfo)) {
567
- return compactPackageExtensionLabel(resourcePath, extension.sourceInfo);
568
- }
569
- const localIndex = localExtensions.findIndex(item => item.extension === extension);
570
- const segments = localExtensions[localIndex]?.segments;
571
- if (!segments || segments.length === 0)
572
- return compactResourceLabel(resourcePath);
573
- for (let count = 1; count <= segments.length; count += 1) {
574
- const candidate = segments.slice(-count).join("/");
575
- if (localExtensions.every((item, itemIndex) => itemIndex === localIndex || item.segments.slice(-count).join("/") !== candidate)) {
576
- return candidate;
577
- }
578
- }
579
- return segments.join("/");
580
- });
581
- }
582
- function compactPackageExtensionLabel(resourcePath, sourceInfo) {
583
- const sourceLabel = compactPackageSourceLabel(sourceInfo.source);
584
- if (!sourceLabel)
585
- return compactResourceLabel(resourcePath);
586
- const shortPath = shortPackagePath(resourcePath, sourceInfo).replaceAll("\\", "/");
587
- const packagePath = shortPath.startsWith("extensions/") ? shortPath.slice("extensions/".length) : shortPath;
588
- const slash = packagePath.lastIndexOf("/");
589
- const fileName = slash < 0 ? packagePath : packagePath.slice(slash + 1);
590
- const directory = slash < 0 ? "" : packagePath.slice(0, slash);
591
- const extension = fileName.lastIndexOf(".");
592
- const name = extension <= 0 ? fileName : fileName.slice(0, extension);
593
- if (name === "index")
594
- return !directory || directory === "." ? sourceLabel : `${sourceLabel}:${directory}`;
595
- return `${sourceLabel}:${packagePath}`;
596
- }
597
- function compactPackageSourceLabel(source) {
598
- if (source.startsWith("npm:"))
599
- return source.slice("npm:".length) || source;
600
- if (!source.startsWith("git:"))
601
- return source;
602
- const gitSource = source.slice("git:".length).trim();
603
- let repositoryPath;
604
- const scpLike = gitSource.match(/^git@[^:]+:(.+)$/);
605
- if (scpLike?.[1]) {
606
- repositoryPath = scpLike[1];
607
- }
608
- else if (/^[a-z]+:\/\//i.test(gitSource)) {
609
- try {
610
- repositoryPath = new URL(gitSource).pathname.replace(/^\/+/, "");
611
- }
612
- catch {
613
- return source;
614
- }
615
- }
616
- else {
617
- const slash = gitSource.indexOf("/");
618
- if (slash >= 0)
619
- repositoryPath = gitSource.slice(slash + 1);
620
- }
621
- if (!repositoryPath)
622
- return source;
623
- const ref = repositoryPath.indexOf("@");
624
- const withoutRef = ref < 0 ? repositoryPath : repositoryPath.slice(0, ref);
625
- return withoutRef.replace(/\.git$/, "") || source;
626
- }
627
- function shortPackagePath(resourcePath, sourceInfo) {
628
- const fullPath = normalizeResourcePath(resourcePath);
629
- const baseDir = sourceInfo.baseDir === null ? undefined : normalizeResourcePath(sourceInfo.baseDir).replace(/\/$/, "");
630
- if (baseDir) {
631
- const npmRoot = baseDir.match(/^(.*\/node_modules)\/(@?[^/]+(?:\/[^/]+)?)$/);
632
- if (npmRoot?.[1] && fullPath.startsWith(`${npmRoot[1]}/`))
633
- return relativeResourcePath(baseDir, fullPath);
634
- if (fullPath === baseDir)
635
- return ".";
636
- if (fullPath.startsWith(`${baseDir}/`))
637
- return fullPath.slice(baseDir.length + 1);
638
- }
639
- const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
640
- if (npmMatch?.[2] && sourceInfo.source.startsWith("npm:"))
641
- return npmMatch[2];
642
- const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
643
- if (gitMatch?.[1] && sourceInfo.source.startsWith("git:"))
644
- return gitMatch[1];
645
- return resourcePath;
646
- }
647
- function relativeResourcePath(from, to) {
648
- const fromSegments = from.split("/").filter(Boolean);
649
- const toSegments = to.split("/").filter(Boolean);
650
- let common = 0;
651
- while (common < fromSegments.length && common < toSegments.length
652
- && fromSegments[common]?.toLowerCase() === toSegments[common]?.toLowerCase())
653
- common += 1;
654
- return [...fromSegments.slice(common).map(() => ".."), ...toSegments.slice(common)].join("/") || ".";
655
- }
656
- function compactPathSegments(path) {
657
- return normalizeResourcePath(path).split("/").filter(segment => segment.length > 0 && segment !== "~");
658
- }
659
- function normalizeResourcePath(path) {
660
- return path.replaceAll("\\", "/");
661
- }
662
- function isPackageExtensionSource(sourceInfo) {
663
- const source = sourceInfo?.source ?? "";
664
- return source.startsWith("npm:") || source.startsWith("git:");
665
- }
1
+ import { PRODUCT_TEXT } from "../../../product-identity.js";
2
+ import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput, readVisibleHyperlinks } from "../../../ui/components/index.js";
3
+ import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../engine/index.js";
4
+ import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, onPiThemeChange, piTheme, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../components/index.js";
5
+ import { DamageAwareTerminalAdapter, PiTuiRuntimeAdapter, classifyPiTuiInput, } from "../tui-runtime/index.js";
6
+ import { canonicalizeClipboardImage } from "./clipboard-image.js";
7
+ import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
8
+ import { preloadSystemClipboard, readSystemClipboardContent, writeSystemClipboardText, } from "./system-clipboard.js";
9
+ import { OwnedUiSessionShellRoot, shellResourceEntries, } from "./session-shell-root.js";
10
+ export { OwnedUiSessionShellRoot } from "./session-shell-root.js";
11
+ /** Coordinates backend, owned presentation, and Pi TUI lifecycles for one interactive session. */
666
12
  export class OwnedUiSessionShell {
667
13
  backend;
668
14
  root;
@@ -674,13 +20,28 @@ export class OwnedUiSessionShell {
674
20
  #stopped;
675
21
  #resolveStopped;
676
22
  #dialogId;
23
+ #dialogSource;
677
24
  #routeHost;
678
25
  #dialogHandle;
679
26
  #sequence = 0;
680
27
  #started = false;
681
28
  #disposed = false;
29
+ #pointerReporting = false;
30
+ #customViewport;
31
+ #damageTerminal;
32
+ #streamPresentation;
33
+ #removeViewportPreInput;
34
+ #unsubscribeSettings;
35
+ #unbindPiSettings;
36
+ #unbindTerminalSettings;
37
+ #unbindShutdownSettings;
38
+ #terminalProgressEnabled = false;
39
+ #showImages = true;
40
+ #imageWidthCells = 80;
41
+ #fullscreenExitOutput = "transcript";
682
42
  #compactionQueue = [];
683
43
  #lastClearTime = 0;
44
+ #lastEscapeTime = 0;
684
45
  #activeLoginDialog;
685
46
  #sessionGeneration;
686
47
  constructor(options) {
@@ -688,14 +49,27 @@ export class OwnedUiSessionShell {
688
49
  this.#sessionGeneration = this.backend.sessionGeneration;
689
50
  this.#cwd = options.cwd;
690
51
  this.#routeHost = options.routeHost ?? null;
52
+ this.#customViewport = options.sessionLayout === "custom-viewport";
53
+ if (this.#customViewport && options.clipboard === undefined)
54
+ preloadSystemClipboard();
691
55
  this.#stopped = new Promise(resolve => {
692
56
  this.#resolveStopped = resolve;
693
57
  });
694
58
  let runtime;
59
+ let damageTerminal;
60
+ let streamPresentation;
61
+ let pendingClipboardWrite = Promise.resolve();
695
62
  this.root = new OwnedUiSessionShellRoot(this.backend.view(), options.cwd, {
696
63
  getColumns: () => runtime?.viewport().columns ?? options.terminal?.columns ?? 80,
697
64
  getRows: () => runtime?.viewport().rows ?? options.terminal?.rows ?? 24,
698
- requestRender: () => runtime?.requestRender(),
65
+ requestRender: force => runtime?.requestRender(force),
66
+ requestHyperlinkCleanup: () => damageTerminal?.requestHyperlinkCleanup(),
67
+ onViewportFrame: frame => damageTerminal?.arm(frame.descriptor, {
68
+ overlayActive: runtime?.hasOverlay() ?? false,
69
+ selectionActive: this.root.hasActiveSelection(),
70
+ replacementSurfaceActive: !this.root.usesDefaultInputSurface(),
71
+ }),
72
+ enableDockInputReuse: options.inputPresentation?.viewportReuse !== false,
699
73
  onSubmit: text => { void this.submit(text); },
700
74
  onInterrupt: () => { void this.interrupt(); },
701
75
  onClear: () => { void this.clearOrExit(); },
@@ -710,19 +84,189 @@ export class OwnedUiSessionShell {
710
84
  onMessageCopy: () => { void this.runWorkflow({ command: "copy", argument: "" }); },
711
85
  onFollowUp: () => { void this.queueFollowUp(); },
712
86
  onDequeue: () => this.restoreQueuedInput(),
87
+ onCopyText: text => {
88
+ runtime?.writeControl(`\u001b]52;c;${Buffer.from(text, "utf8").toString("base64")}\u0007`);
89
+ const write = options.clipboard === undefined
90
+ ? writeSystemClipboardText(text)
91
+ : options.clipboard.writeText?.(text) ?? Promise.resolve();
92
+ pendingClipboardWrite = write.catch(() => { });
93
+ },
94
+ readClipboardContent: async () => {
95
+ await pendingClipboardWrite;
96
+ if (options.clipboard === undefined)
97
+ return readSystemClipboardContent();
98
+ try {
99
+ const image = await options.clipboard.readImage?.();
100
+ if (image !== null && image !== undefined) {
101
+ const canonical = canonicalizeClipboardImage(image);
102
+ if (canonical !== null)
103
+ return { kind: "image", ...canonical };
104
+ }
105
+ }
106
+ catch {
107
+ // Compatibility: treat an unavailable or malformed image as text-capable clipboard input.
108
+ }
109
+ const text = await options.clipboard.readText();
110
+ return text === null ? null : { kind: "text", text };
111
+ },
713
112
  }, {
714
113
  ...options.startup,
715
114
  resources: options.startup?.resources ?? shellResourceEntries(this.backend),
716
115
  }, this.backend.agentDir, {
717
116
  getMessageRenderer: customType => this.backend.pinnedMessageRenderer(customType),
718
117
  getToolDefinition: toolName => this.backend.pinnedToolDefinition(toolName),
118
+ }, options.sessionLayout, {
119
+ resolve: assetId => this.backend.resolveTranscriptImage(assetId),
719
120
  });
720
- const tuiMode = this.backend.disposed ? "regular" : this.backend.pinnedSettingsSnapshot().tuiMode;
721
- const runtimeOptions = options.terminal === undefined
722
- ? { root: this.root, mode: tuiMode, layoutRoot: this.root.layoutRoot(), hardwareCursor: this.backend.view().terminal.hardwareCursor }
723
- : { root: this.root, mode: tuiMode, layoutRoot: this.root.layoutRoot(), terminal: options.terminal, hardwareCursor: this.backend.view().terminal.hardwareCursor };
121
+ // Invariant: bare A1 owns a bounded viewport and therefore always runs on the alternate
122
+ // fullscreen surface. The pinned comparison profiles still honor Pi's mode.
123
+ const tuiMode = this.#customViewport
124
+ ? "fullscreen"
125
+ : this.backend.disposed ? "regular" : this.backend.pinnedSettingsSnapshot().tuiMode;
126
+ const runtimeOptions = {
127
+ root: this.root,
128
+ mode: tuiMode,
129
+ ...(this.#customViewport ? {
130
+ decorateTerminal: (terminal) => {
131
+ damageTerminal = new DamageAwareTerminalAdapter(terminal, {
132
+ regionalScroll: process.env.TERM !== "dumb",
133
+ inspectHyperlinks: readVisibleHyperlinks,
134
+ onResize: () => streamPresentation?.noteImmediatePresentation(),
135
+ onHyperlinkCleanupRequired: () => runtime?.requestRender(true),
136
+ });
137
+ return damageTerminal;
138
+ },
139
+ ...(options.inputPresentation?.coordination === false ? {} : {
140
+ inputCoordination: {
141
+ classify: (data, focusedOverlay) => classifyPiTuiInput(data, focusedOverlay ?? this.root.inputCoordinationSurface()),
142
+ onReceipt: () => streamPresentation?.noteImmediatePresentation(),
143
+ ...(options.inputPresentation?.scheduler === undefined
144
+ ? {}
145
+ : { scheduler: options.inputPresentation.scheduler }),
146
+ },
147
+ }),
148
+ } : { layoutRoot: this.root.layoutRoot() }),
149
+ ...(options.inputPresentation?.onEvent === undefined ? {} : {
150
+ inputDiagnostics: {
151
+ onEvent: options.inputPresentation.onEvent,
152
+ ...(options.inputPresentation.now === undefined ? {} : { now: options.inputPresentation.now }),
153
+ },
154
+ }),
155
+ ...(options.terminal === undefined ? {} : { terminal: options.terminal }),
156
+ hardwareCursor: this.backend.view().terminal.hardwareCursor,
157
+ };
724
158
  runtime = new PiTuiRuntimeAdapter(runtimeOptions);
725
159
  this.runtime = runtime;
160
+ this.#damageTerminal = damageTerminal ?? null;
161
+ const presentationInterval = options.streamPresentation?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS;
162
+ streamPresentation = options.streamPresentation?.scheduler === undefined
163
+ ? new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval)
164
+ : new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval, options.streamPresentation.scheduler);
165
+ this.#streamPresentation = streamPresentation;
166
+ const initialPiSettings = this.backend.pinnedSettingsSnapshot();
167
+ this.runtime.setHardwareCursor(initialPiSettings.showHardwareCursor);
168
+ this.runtime.setClearOnShrink(initialPiSettings.clearOnShrink);
169
+ this.#terminalProgressEnabled = initialPiSettings.showTerminalProgress;
170
+ this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
171
+ this.#unbindShutdownSettings = this.backend.bindSettingsOwner("shutdown", {
172
+ fullscreenExitOutput: { apply() { } },
173
+ });
174
+ this.#unbindTerminalSettings = this.backend.bindSettingsOwner("terminal", {
175
+ showHardwareCursor: { apply: value => {
176
+ if (typeof value !== "boolean")
177
+ throw new TypeError("Hardware cursor setting is invalid");
178
+ this.runtime.setHardwareCursor(value);
179
+ } },
180
+ clearOnShrink: { apply: value => {
181
+ if (typeof value !== "boolean")
182
+ throw new TypeError("Clear-on-shrink setting is invalid");
183
+ this.runtime.setClearOnShrink(value);
184
+ } },
185
+ showTerminalProgress: { apply: value => {
186
+ if (typeof value !== "boolean")
187
+ throw new TypeError("Terminal progress setting is invalid");
188
+ this.#terminalProgressEnabled = value;
189
+ this.#syncTerminalProgress(this.view());
190
+ } },
191
+ });
192
+ this.#removeViewportPreInput = this.#customViewport
193
+ ? this.runtime.addPreInputListener(data => {
194
+ if (options.inputPresentation?.coordination === false)
195
+ this.#streamPresentation.noteImmediatePresentation();
196
+ // Invariant: an overlay or editor-replacement screen owns its entire pointer
197
+ // surface. Letting the transcript pre-router inspect those reports
198
+ // steals settings value menus and numeric +/- controls before the
199
+ // settings app can receive them.
200
+ if (this.runtime.hasOverlay() || !this.root.usesDefaultInputSurface())
201
+ return undefined;
202
+ const routed = this.root.handleViewportPreInput(data, true);
203
+ if (routed.copyText !== undefined) {
204
+ this.runtime.writeControl(`\u001b]52;c;${Buffer.from(routed.copyText, "utf8").toString("base64")}\u0007`);
205
+ }
206
+ if (!routed.consumed)
207
+ return routed.data === data ? undefined : { data: routed.data };
208
+ return routed.data.length === 0 ? { consume: true } : { data: routed.data };
209
+ })
210
+ : () => { };
211
+ const applyViewportSettings = () => {
212
+ const snapshot = options.viewportSettings?.snapshot();
213
+ this.root.setViewportConfig(snapshot ?? {
214
+ scrollbarAppearance: "auto",
215
+ scrollbarStyle: "thin",
216
+ scrollbarSpeed: "normal",
217
+ });
218
+ };
219
+ applyViewportSettings();
220
+ this.#unsubscribeSettings = this.#customViewport && options.viewportSettings
221
+ ? options.viewportSettings.onChange(settings => this.root.setViewportConfig(settings))
222
+ : () => { };
223
+ this.root.setEditorPaddingX(initialPiSettings.editorPaddingX);
224
+ this.root.setAutocompleteMaxVisible(initialPiSettings.autocompleteMaxVisible);
225
+ this.root.setOutputPad(initialPiSettings.outputPad);
226
+ this.root.setHideThinkingBlock(initialPiSettings.hideThinkingBlock);
227
+ this.root.setMermaidRenderingMode(initialPiSettings.mermaidRenderingMode);
228
+ this.#showImages = initialPiSettings.showImages;
229
+ this.#imageWidthCells = initialPiSettings.imageWidthCells;
230
+ this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
231
+ this.#unbindPiSettings = this.backend.bindSettingsOwner("shell", {
232
+ editorPaddingX: { apply: value => {
233
+ if (typeof value !== "number")
234
+ throw new TypeError("Editor padding is invalid");
235
+ this.root.setEditorPaddingX(value);
236
+ } },
237
+ autocompleteMaxVisible: { apply: value => {
238
+ if (typeof value !== "number")
239
+ throw new TypeError("Autocomplete maximum is invalid");
240
+ this.root.setAutocompleteMaxVisible(value);
241
+ } },
242
+ outputPad: { apply: value => {
243
+ if (value !== 0 && value !== 1)
244
+ throw new TypeError("Output padding is invalid");
245
+ this.root.setOutputPad(value);
246
+ } },
247
+ hideThinkingBlock: { apply: value => {
248
+ if (typeof value !== "boolean")
249
+ throw new TypeError("Thinking-block visibility is invalid");
250
+ this.root.setHideThinkingBlock(value);
251
+ } },
252
+ mermaidRenderingMode: { apply: value => {
253
+ if (value !== "off" && value !== "final" && value !== "streaming")
254
+ throw new TypeError("Mermaid mode is invalid");
255
+ this.root.setMermaidRenderingMode(value);
256
+ } },
257
+ showImages: { apply: value => {
258
+ if (typeof value !== "boolean")
259
+ throw new TypeError("Image visibility is invalid");
260
+ this.#showImages = value;
261
+ this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
262
+ } },
263
+ imageWidthCells: { apply: value => {
264
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
265
+ throw new TypeError("Image width is invalid");
266
+ this.#imageWidthCells = value;
267
+ this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
268
+ } },
269
+ });
726
270
  this.#extensionBridge = createPiExtensionUiBridge({
727
271
  runtime: {
728
272
  getColumns: () => this.runtime.viewport().columns,
@@ -730,7 +274,7 @@ export class OwnedUiSessionShell {
730
274
  requestRender: () => this.runtime.requestRender(),
731
275
  },
732
276
  agentDir: this.backend.agentDir,
733
- setInputSurface: component => this.root.setInputSurface(component),
277
+ setInputSurface: component => this.root.setInputSurface(component, true, "opaque"),
734
278
  showOverlay: (component, overlayOptions) => this.runtime.showOverlay(component, overlayOptions),
735
279
  listenInput: handler => this.runtime.addInputListener(handler),
736
280
  replaceWidget: (key, component, placement) => this.root.setExtensionWidget(key, component, placement),
@@ -744,7 +288,7 @@ export class OwnedUiSessionShell {
744
288
  setEditorText: text => this.root.editor.setText(text),
745
289
  pasteToEditor: text => this.root.editor.insertText(text),
746
290
  addAutocompleteProvider: factory => this.root.editor.addAutocompleteProvider(factory),
747
- setCustomEditor: component => this.root.setInputSurface(component),
291
+ setCustomEditor: component => this.root.setInputSurface(component, true, "opaque"),
748
292
  getFooterData: () => this.root.extensionFooterData(),
749
293
  getToolsExpanded: () => this.root.toolsExpanded,
750
294
  setToolsExpanded: expanded => this.root.setToolsExpanded(expanded),
@@ -753,13 +297,26 @@ export class OwnedUiSessionShell {
753
297
  startLogin: request => this.#startWorkflowLogin(request),
754
298
  prompt: request => this.#requestWorkflowInput(request),
755
299
  notify: event => this.#notifyWorkflowLogin(event),
300
+ publish: message => {
301
+ this.root.appendWorkflowMessage(message);
302
+ this.runtime.requestRender();
303
+ },
756
304
  finishLogin: () => this.#finishWorkflowLogin(),
757
305
  });
758
306
  this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
759
307
  this.#unsubscribe = this.backend.onEvent(event => {
760
- // One view read per event: the model is built by the backend, and building it
761
- // twice per streamed chunk is what made a long session cost more per chunk.
762
- const view = this.#syncView();
308
+ // Performance: a streamed chunk names one block, and touching only that block is what keeps the
309
+ // cost of a chunk the same in a long session as in a new one. Everything else
310
+ // resynchronizes the view, which is cheap next to re-reading the transcript.
311
+ if (event.type === "agent-run-started")
312
+ this.root.resumeViewportFollowing();
313
+ if (event.type === "assistant-message-completed")
314
+ this.root.noteCompletedAssistantMessage();
315
+ const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
316
+ const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.sessionGeneration
317
+ ? this.#syncBlock(event.block)
318
+ : semanticOnly ? this.view() : this.#syncView();
319
+ this.#syncTerminalProgress(view);
763
320
  if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
764
321
  void this.#flushCompactionQueue();
765
322
  if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
@@ -771,11 +328,17 @@ export class OwnedUiSessionShell {
771
328
  view() {
772
329
  return this.backend.view();
773
330
  }
331
+ damagePresentationDecision() {
332
+ return this.#damageTerminal?.lastDecision ?? null;
333
+ }
774
334
  start() {
775
335
  if (this.#started)
776
336
  return;
777
337
  this.#started = true;
778
338
  this.runtime.start();
339
+ this.#syncTerminalProgress(this.view());
340
+ if (this.#customViewport)
341
+ this.#setPointerReporting(true);
779
342
  void this.backend.bindExtensionUi(this.#extensionBridge.context, () => { void this.shutdown(); });
780
343
  this.#syncView();
781
344
  }
@@ -788,16 +351,18 @@ export class OwnedUiSessionShell {
788
351
  return this.#stopped;
789
352
  }
790
353
  async submit(text) {
791
- const input = text.trim();
792
- if (!input)
354
+ const displayInput = text.trim();
355
+ if (!displayInput)
793
356
  return { outcome: "completed", diagnostic: null };
794
- if (input.startsWith("/"))
795
- return this.#slashCommand(input);
357
+ if (displayInput.startsWith("/"))
358
+ return this.#slashCommand(displayInput);
359
+ const prepared = this.root.preparePromptSubmission(displayInput);
360
+ const input = prepared.text.trim();
796
361
  if (input.startsWith("!")) {
797
362
  const excludeFromContext = input.startsWith("!!");
798
363
  const command = input.slice(excludeFromContext ? 2 : 1).trim();
799
364
  if (command) {
800
- this.root.editor.addToHistory(input);
365
+ this.root.editor.addToHistory(displayInput);
801
366
  try {
802
367
  const result = await this.backend.executeBashWorkflow(command, excludeFromContext);
803
368
  const workflow = {
@@ -819,19 +384,25 @@ export class OwnedUiSessionShell {
819
384
  }
820
385
  }
821
386
  if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
822
- this.root.editor.addToHistory(input);
823
- this.#compactionQueue.push({ text: input, type: "steer" });
387
+ this.root.editor.addToHistory(displayInput);
388
+ this.#compactionQueue.push({
389
+ text: input,
390
+ type: "steer",
391
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
392
+ });
824
393
  this.root.appendWorkflowResult({ command: "compact", outcome: "completed", message: `Queued during compaction: ${input}` });
825
394
  this.runtime.requestRender();
826
395
  return { outcome: "completed", diagnostic: null };
827
396
  }
828
397
  const type = this.view().lifecycle === "busy" ? "steer" : "prompt";
829
- this.root.editor.addToHistory(input);
398
+ this.root.editor.addToHistory(displayInput);
399
+ this.root.resumeViewportFollowing();
830
400
  return this.#execute({
831
401
  type,
832
402
  correlationId: this.#correlation(type),
833
403
  sessionId: this.backend.sessionId,
834
404
  text: input,
405
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
835
406
  });
836
407
  }
837
408
  async clearOrExit(now = Date.now()) {
@@ -842,14 +413,29 @@ export class OwnedUiSessionShell {
842
413
  this.runtime.requestRender();
843
414
  return { outcome: "completed", diagnostic: null };
844
415
  }
845
- async interrupt() {
416
+ async interrupt(now = Date.now()) {
846
417
  if (this.view().lifecycle === "busy")
847
418
  return this.abort();
848
- if (this.root.editor.getText().length > 0) {
419
+ if (this.root.editor.getText().trim().length > 0) {
849
420
  this.root.editor.setText("");
850
421
  return { outcome: "completed", diagnostic: null };
851
422
  }
852
- return { outcome: "rejected", diagnostic: "nothing to interrupt" };
423
+ // Compatibility: match Pi: with an empty editor, two escapes inside 500 ms open the
424
+ // configured session navigator. The first escape intentionally does not
425
+ // interrupt or mutate the prompt.
426
+ const action = this.backend.pinnedSettingsSnapshot().doubleEscapeAction;
427
+ if (action === "none")
428
+ return { outcome: "rejected", diagnostic: "nothing to interrupt" };
429
+ if (now - this.#lastEscapeTime < 500) {
430
+ this.#lastEscapeTime = 0;
431
+ if (action === "tree")
432
+ this.showTreeSelector();
433
+ else
434
+ this.showForkSelector();
435
+ return { outcome: "completed", diagnostic: null };
436
+ }
437
+ this.#lastEscapeTime = now;
438
+ return { outcome: "completed", diagnostic: null };
853
439
  }
854
440
  async abort() {
855
441
  return this.#execute(this.#simple("abort"));
@@ -901,13 +487,20 @@ export class OwnedUiSessionShell {
901
487
  return workflowAdapterResult(result);
902
488
  }
903
489
  async queueFollowUp() {
904
- const text = this.root.editor.getText().trim();
905
- if (!text)
490
+ const displayInput = this.root.editor.getText().trim();
491
+ if (!displayInput)
906
492
  return rejected("nothing to queue");
907
- this.root.editor.addToHistory(text);
493
+ const prepared = this.root.preparePromptSubmission(displayInput);
494
+ const text = prepared.text.trim();
495
+ this.root.editor.addToHistory(displayInput);
908
496
  this.root.editor.setText("");
497
+ this.root.resumeViewportFollowing();
909
498
  if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
910
- this.#compactionQueue.push({ text, type: "follow-up" });
499
+ this.#compactionQueue.push({
500
+ text,
501
+ type: "follow-up",
502
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
503
+ });
911
504
  return { outcome: "completed", diagnostic: null };
912
505
  }
913
506
  return this.#execute({
@@ -915,6 +508,7 @@ export class OwnedUiSessionShell {
915
508
  correlationId: this.#correlation("follow-up"),
916
509
  sessionId: this.backend.sessionId,
917
510
  text,
511
+ ...(prepared.images.length === 0 ? {} : { images: prepared.images }),
918
512
  });
919
513
  }
920
514
  restoreQueuedInput() {
@@ -927,6 +521,8 @@ export class OwnedUiSessionShell {
927
521
  }
928
522
  showSelector(title, options, onSelect, onCancel) {
929
523
  this.#dialogHandle?.hide();
524
+ this.#dialogSource = "local";
525
+ this.#dialogId = undefined;
930
526
  const component = createPiShellSelector({
931
527
  title,
932
528
  options,
@@ -934,18 +530,25 @@ export class OwnedUiSessionShell {
934
530
  onSelect(id);
935
531
  this.#dialogHandle?.hide();
936
532
  this.#dialogHandle = undefined;
533
+ this.#dialogSource = undefined;
937
534
  },
938
535
  onCancel: () => {
939
536
  this.#dialogHandle?.hide();
940
537
  this.#dialogHandle = undefined;
538
+ this.#dialogSource = undefined;
941
539
  onCancel?.();
942
540
  },
943
541
  });
944
- const handle = this.runtime.showOverlay(component, { width: "70%", maxHeight: "80%", anchor: "center" });
542
+ const handle = this.runtime.showOverlay(component, {
543
+ width: "70%",
544
+ maxHeight: "80%",
545
+ anchor: "center",
546
+ inputCoordination: "owned",
547
+ });
945
548
  this.#dialogHandle = handle;
946
549
  return handle;
947
550
  }
948
- showModelSelector() {
551
+ showModelSelector(initialSearchInput) {
949
552
  const context = this.backend.pinnedModelSelectorContext();
950
553
  const close = () => {
951
554
  this.root.setInputSurface(null);
@@ -958,6 +561,7 @@ export class OwnedUiSessionShell {
958
561
  getRows: () => this.runtime.viewport().rows,
959
562
  requestRender: () => this.runtime.requestRender(),
960
563
  },
564
+ ...(initialSearchInput === undefined ? {} : { initialSearchInput }),
961
565
  onSelect: model => {
962
566
  close();
963
567
  void this.runWorkflow({ command: "model", argument: "", selection: modelReference(model) });
@@ -970,7 +574,7 @@ export class OwnedUiSessionShell {
970
574
  showForkSelector() {
971
575
  const options = this.backend.pinnedForkOptions();
972
576
  if (options.length === 0) {
973
- this.root.appendWorkflowResult({ command: "fork", outcome: "failed", message: "No user messages available to fork from" });
577
+ this.root.appendWorkflowResult({ command: "fork", outcome: "completed", message: "No messages to fork from", messageKind: "status" });
974
578
  this.runtime.requestRender();
975
579
  return;
976
580
  }
@@ -986,9 +590,21 @@ export class OwnedUiSessionShell {
986
590
  this.runtime.requestRender();
987
591
  }
988
592
  async showLogoutSelector() {
989
- const options = await this.backend.pinnedLogoutOptions();
593
+ let options;
594
+ try {
595
+ options = await this.backend.pinnedLogoutOptions();
596
+ }
597
+ catch (error) {
598
+ this.root.appendWorkflowResult({
599
+ command: "logout",
600
+ outcome: "failed",
601
+ message: `Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`,
602
+ });
603
+ this.runtime.requestRender();
604
+ return;
605
+ }
990
606
  if (options.length === 0) {
991
- this.root.appendWorkflowStatus("No authenticated providers available.");
607
+ this.root.appendWorkflowStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
992
608
  this.runtime.requestRender();
993
609
  return;
994
610
  }
@@ -1141,6 +757,10 @@ export class OwnedUiSessionShell {
1141
757
  return;
1142
758
  }
1143
759
  if (callback === "onTuiModeChange") {
760
+ // Invariant: the custom bare-A1 surface is permanently fullscreen; this callback
761
+ // remains available only to pinned comparison profiles.
762
+ if (this.#customViewport)
763
+ return;
1144
764
  if (value !== "regular" && value !== "fullscreen")
1145
765
  return;
1146
766
  if (!this.runtime.switchMode(value)) {
@@ -1148,13 +768,18 @@ export class OwnedUiSessionShell {
1148
768
  this.runtime.requestRender();
1149
769
  return;
1150
770
  }
771
+ if (this.#customViewport) {
772
+ this.#pointerReporting = false;
773
+ this.#setPointerReporting(true);
774
+ }
1151
775
  }
1152
- const result = this.backend.applyPinnedSettingValue(callback, value);
1153
- if (result.outcome === "failed")
1154
- this.root.appendWorkflowResult(result);
1155
- else if (callback === "onTuiModeChange")
1156
- this.root.appendWorkflowStatus(`TUI mode: ${value}`);
1157
- this.runtime.requestRender();
776
+ void this.backend.applyPinnedSettingValue(callback, value).then(result => {
777
+ if (result.outcome === "failed")
778
+ this.root.appendWorkflowResult(result);
779
+ else if (callback === "onTuiModeChange")
780
+ this.root.appendWorkflowStatus(`TUI mode: ${value}`);
781
+ this.runtime.requestRender();
782
+ });
1158
783
  },
1159
784
  onCancel: close,
1160
785
  });
@@ -1200,10 +825,6 @@ export class OwnedUiSessionShell {
1200
825
  await this.showLogoutSelector();
1201
826
  return { outcome: "completed", diagnostic: null };
1202
827
  }
1203
- if (request.command === "import" && request.confirmed === undefined && request.argument.trim().length > 0) {
1204
- const confirmed = await this.#extensionBridge.context.confirm("Import session", `Replace current session with ${request.argument.trim()}?`);
1205
- return this.runWorkflow({ ...request, confirmed: confirmed === true });
1206
- }
1207
828
  if (request.command === "tree" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
1208
829
  this.showTreeSelector();
1209
830
  return { outcome: "completed", diagnostic: null };
@@ -1212,22 +833,21 @@ export class OwnedUiSessionShell {
1212
833
  this.root.resetExtensionUi();
1213
834
  this.root.resetWorkflowPresentation();
1214
835
  }
1215
- const operationSurface = request.command === "share"
836
+ const shareSurface = request.command === "share"
1216
837
  ? createPiShellOperationLoader({
1217
838
  getColumns: () => this.runtime.viewport().columns,
1218
839
  getRows: () => this.runtime.viewport().rows,
1219
840
  requestRender: () => this.runtime.requestRender(),
1220
841
  }, "Creating gist...")
1221
- : request.command === "reload"
1222
- ? createPiShellReloadBox()
1223
- : undefined;
842
+ : undefined;
843
+ const operationSurface = shareSurface ?? (request.command === "reload" ? createPiShellReloadBox() : undefined);
1224
844
  if (operationSurface) {
1225
845
  this.root.setInputSurface(operationSurface);
1226
846
  this.runtime.requestRender();
1227
847
  }
1228
848
  let result;
1229
849
  try {
1230
- result = await this.backend.executeWorkflow(request);
850
+ result = await this.backend.executeWorkflow(shareSurface === undefined ? request : { ...request, signal: shareSurface.signal });
1231
851
  }
1232
852
  finally {
1233
853
  if (operationSurface) {
@@ -1235,10 +855,27 @@ export class OwnedUiSessionShell {
1235
855
  this.runtime.requestRender();
1236
856
  }
1237
857
  }
858
+ if (result.outcome === "requires-selection" && request.command === "model") {
859
+ if (result.messages !== undefined) {
860
+ for (const message of result.messages)
861
+ this.root.appendWorkflowMessage(message);
862
+ }
863
+ this.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
864
+ return { outcome: "completed", diagnostic: null };
865
+ }
1238
866
  if (result.outcome === "requires-confirmation" && request.command === "resume") {
1239
867
  const confirmed = await this.#extensionBridge.context.confirm("Session cwd not found", result.message);
1240
868
  return this.runWorkflow({ ...request, confirmed: confirmed === true });
1241
869
  }
870
+ if (result.outcome === "requires-confirmation" && request.command === "import") {
871
+ const recoveringCwd = result.detail !== undefined;
872
+ const confirmed = await this.#extensionBridge.context.confirm(recoveringCwd ? "Session cwd not found" : "Import session", result.message);
873
+ return this.runWorkflow({
874
+ ...request,
875
+ confirmed: confirmed === true,
876
+ ...(confirmed === true && result.detail ? { cwdOverride: result.detail } : {}),
877
+ });
878
+ }
1242
879
  if (result.outcome === "requires-selection" || result.outcome === "requires-confirmation") {
1243
880
  this.root.appendWorkflowResult({ command: request.command, outcome: "failed", message: `Owned controller missing for ${request.command}` });
1244
881
  this.runtime.requestRender();
@@ -1353,22 +990,85 @@ export class OwnedUiSessionShell {
1353
990
  this.root.appendDaxnuts();
1354
991
  }
1355
992
  }
993
+ // Invariant: pointer reporting is disabled on every path that ends the owning screen.
994
+ #setPointerReporting(enabled, forceOff = false) {
995
+ const effective = forceOff ? false : this.#customViewport || enabled;
996
+ if (this.#pointerReporting === effective)
997
+ return;
998
+ this.#pointerReporting = effective;
999
+ if (!this.runtime.active)
1000
+ return;
1001
+ this.runtime.writeControl(effective ? MOUSE_TRACKING_ON : MOUSE_TRACKING_OFF);
1002
+ }
1356
1003
  async dispose() {
1357
1004
  if (this.#disposed)
1358
1005
  return;
1359
1006
  this.#disposed = true;
1007
+ this.root.clearViewportPointerState();
1008
+ this.#setPointerReporting(false, true);
1009
+ this.#removeViewportPreInput();
1010
+ this.#streamPresentation.dispose();
1011
+ this.#unsubscribeSettings();
1012
+ const exitMode = this.backend.disposed
1013
+ ? this.#fullscreenExitOutput
1014
+ : this.backend.pinnedSettingsSnapshot().fullscreenExitOutput;
1015
+ const exitTranscript = this.root.exitTranscript(this.runtime.viewport().columns);
1016
+ const resume = this.backend.currentSessionResumeMetadata();
1017
+ const resumeHint = resume === null
1018
+ ? ""
1019
+ : `${dim("To resume this session:")} ${formatSessionResumeCommand(resume)}`;
1020
+ const fullscreenExitText = this.runtime.mode !== "fullscreen"
1021
+ ? ""
1022
+ : exitMode === "resume-hint"
1023
+ ? resumeHint
1024
+ : [exitTranscript, resumeHint].filter(Boolean).join("\n\n");
1025
+ this.#unbindPiSettings();
1026
+ this.#unbindTerminalSettings();
1027
+ this.#unbindShutdownSettings();
1360
1028
  this.#unsubscribe();
1361
1029
  this.#dialogHandle?.hide();
1362
1030
  await this.backend.unbindExtensionUi();
1363
1031
  this.#extensionBridge.dispose();
1364
1032
  await this.runtime.dispose();
1033
+ if (fullscreenExitText.length > 0)
1034
+ this.runtime.writeAfterStop(`${fullscreenExitText}\n`);
1035
+ }
1036
+ // Invariant: incremental block updates notify listeners with the same complete view contract.
1037
+ #syncBlock(block) {
1038
+ this.root.applyTranscriptBlock(block);
1039
+ if (this.#customViewport && block.status === "live" && isCoalescedStreamBlock(block.kind)) {
1040
+ this.#streamPresentation.request();
1041
+ }
1042
+ else if (this.#streamPresentation.pending) {
1043
+ this.#streamPresentation.flush();
1044
+ }
1045
+ else {
1046
+ this.#streamPresentation.presentImmediate();
1047
+ }
1048
+ const view = this.view();
1049
+ for (const listener of this.#listeners)
1050
+ listener(view);
1051
+ return view;
1052
+ }
1053
+ #syncTerminalProgress(view) {
1054
+ if (!this.runtime.active)
1055
+ return;
1056
+ this.runtime.setTerminalProgress(this.#terminalProgressEnabled && view.lifecycle === "busy");
1365
1057
  }
1366
1058
  #syncView() {
1059
+ this.#streamPresentation.noteImmediatePresentation();
1367
1060
  const view = this.view();
1368
1061
  if (this.backend.sessionGeneration !== this.#sessionGeneration) {
1369
1062
  this.#sessionGeneration = this.backend.sessionGeneration;
1370
1063
  this.#activeLoginDialog = undefined;
1371
1064
  this.#extensionBridge.reset();
1065
+ // Invariant: a replaced session takes its transient viewport and owned-route state with it.
1066
+ this.root.resetViewport();
1067
+ this.#dialogHandle?.hide();
1068
+ this.#dialogHandle = undefined;
1069
+ this.#dialogId = undefined;
1070
+ this.#dialogSource = undefined;
1071
+ this.#setPointerReporting(false);
1372
1072
  this.root.setInputSurface(null);
1373
1073
  this.root.resetExtensionUi();
1374
1074
  this.root.resetWorkflowPresentation();
@@ -1387,10 +1087,11 @@ export class OwnedUiSessionShell {
1387
1087
  if (!this.runtime.active)
1388
1088
  return { outcome: "failed", diagnostic: "runtime is not active" };
1389
1089
  this.#dialogHandle?.hide();
1390
- // Any-event reporting: hover and drag are what the screen is driven by, and
1090
+ this.#dialogSource = "route";
1091
+ // Protocol: any-event reporting: hover and drag are what the screen is driven by, and
1391
1092
  // it also stops the terminal treating a drag as a text selection.
1392
- this.runtime.writeControl(MOUSE_TRACKING_ON);
1393
- // The interrupt chord is global, so it is watched on raw input rather than
1093
+ this.#setPointerReporting(true);
1094
+ // Protocol: the interrupt chord is global, so it is watched on raw input rather than
1394
1095
  // through the overlay: the pinned shell handles that key before an overlay
1395
1096
  // ever sees it, which is why an owned screen must not rely on being asked.
1396
1097
  let armedAt = 0;
@@ -1406,17 +1107,36 @@ export class OwnedUiSessionShell {
1406
1107
  }
1407
1108
  armedAt = now;
1408
1109
  this.runtime.requestRender();
1409
- // The presented screen owns the chord, so the pinned shell never sees a
1110
+ // Invariant: the presented screen owns the chord, so the pinned shell never sees a
1410
1111
  // stray interrupt while it is up.
1411
1112
  return { consume: true };
1412
1113
  });
1114
+ let removeSurfacePreInput = () => { };
1413
1115
  const closeSurface = () => {
1116
+ removeSurfacePreInput();
1414
1117
  removeInterruptWatch();
1415
- this.runtime.writeControl(MOUSE_TRACKING_OFF);
1118
+ this.#setPointerReporting(false);
1416
1119
  this.#dialogHandle?.hide();
1417
1120
  this.#dialogHandle = undefined;
1418
1121
  this.#dialogId = undefined;
1122
+ this.#dialogSource = undefined;
1419
1123
  };
1124
+ // Compatibility: fullscreen Pi owns a fallback text-selection layer before focused overlay
1125
+ // components see pointer input. Route every mouse report to the owned screen
1126
+ // at the pre-input boundary so dropdowns, value hover, and numeric +/- work,
1127
+ // and consume even unhandled reports so settings content is never selected.
1128
+ removeSurfacePreInput = this.runtime.addPreInputListener(data => {
1129
+ const { events, rest } = parseMouseInput(data);
1130
+ if (events.length === 0)
1131
+ return undefined;
1132
+ for (const event of events)
1133
+ surface.handleMouse(event);
1134
+ if (surface.isClosed())
1135
+ closeSurface();
1136
+ else
1137
+ this.runtime.requestRender();
1138
+ return rest.length === 0 ? { consume: true } : { data: rest };
1139
+ });
1420
1140
  const rows = () => Math.max(1, this.runtime.viewport().rows);
1421
1141
  const component = {
1422
1142
  render: (width) => [...surface.render(Math.max(1, width), rows())],
@@ -1439,7 +1159,12 @@ export class OwnedUiSessionShell {
1439
1159
  closeSurface();
1440
1160
  void this.shutdown();
1441
1161
  });
1442
- this.#dialogHandle = this.runtime.showOverlay(component, { width: "100%", maxHeight: "100%", anchor: "top-left" });
1162
+ this.#dialogHandle = this.runtime.showOverlay(component, {
1163
+ width: "100%",
1164
+ maxHeight: "100%",
1165
+ anchor: "top-left",
1166
+ inputCoordination: "owned",
1167
+ });
1443
1168
  this.#dialogId = surface.id;
1444
1169
  return { outcome: "completed", diagnostic: null };
1445
1170
  }
@@ -1447,25 +1172,40 @@ export class OwnedUiSessionShell {
1447
1172
  if (!this.runtime.active)
1448
1173
  return;
1449
1174
  if (dialog === null) {
1175
+ // Invariant: locally owned routes (notably /settings) are independent of backend
1176
+ // lifecycle/status events and remain open while an agent is working.
1177
+ if (this.#dialogSource !== "backend")
1178
+ return;
1450
1179
  this.#dialogHandle?.hide();
1451
1180
  this.#dialogHandle = undefined;
1452
1181
  this.#dialogId = undefined;
1182
+ this.#dialogSource = undefined;
1453
1183
  return;
1454
1184
  }
1455
- if (this.#dialogId === dialog.id)
1185
+ if (this.#dialogSource === "backend" && this.#dialogId === dialog.id)
1456
1186
  return;
1457
1187
  this.#dialogHandle?.hide();
1188
+ this.#dialogSource = "backend";
1458
1189
  const component = createPiShellDialog(dialog, {
1459
1190
  onSelect: () => {
1460
1191
  this.#dialogHandle?.hide();
1461
1192
  this.#dialogHandle = undefined;
1193
+ this.#dialogId = undefined;
1194
+ this.#dialogSource = undefined;
1462
1195
  },
1463
1196
  onCancel: () => {
1464
1197
  this.#dialogHandle?.hide();
1465
1198
  this.#dialogHandle = undefined;
1199
+ this.#dialogId = undefined;
1200
+ this.#dialogSource = undefined;
1466
1201
  },
1467
1202
  });
1468
- this.#dialogHandle = this.runtime.showOverlay(component, { width: "70%", maxHeight: "80%", anchor: "center" });
1203
+ this.#dialogHandle = this.runtime.showOverlay(component, {
1204
+ width: "70%",
1205
+ maxHeight: "80%",
1206
+ anchor: "center",
1207
+ inputCoordination: "owned",
1208
+ });
1469
1209
  this.#dialogId = dialog.id;
1470
1210
  }
1471
1211
  async #slashCommand(text) {
@@ -1477,8 +1217,9 @@ export class OwnedUiSessionShell {
1477
1217
  return this.#openOwnedRoute(name);
1478
1218
  if (isWorkflowRoute(name))
1479
1219
  return this.runWorkflow({ command: name, argument });
1480
- // Unknown slash input, prompt templates, skills, and extension commands remain Pi prompt input.
1220
+ // Compatibility: unknown slash input, prompt templates, skills, and extension commands remain Pi prompt input.
1481
1221
  this.root.editor.addToHistory(text);
1222
+ this.root.resumeViewportFollowing();
1482
1223
  return this.#execute({
1483
1224
  type: this.view().lifecycle === "busy" ? "steer" : "prompt",
1484
1225
  correlationId: this.#correlation("prompt-command"),
@@ -1600,6 +1341,7 @@ export class OwnedUiSessionShell {
1600
1341
  correlationId: this.#correlation(`compaction-${item.type}`),
1601
1342
  sessionId: this.backend.sessionId,
1602
1343
  text: item.text,
1344
+ ...(item.images === undefined ? {} : { images: item.images }),
1603
1345
  });
1604
1346
  }
1605
1347
  }
@@ -1614,6 +1356,24 @@ export class OwnedUiSessionShell {
1614
1356
  return `pi-shell-${prefix}-${this.#sequence}`;
1615
1357
  }
1616
1358
  }
1359
+ function isCoalescedStreamBlock(kind) {
1360
+ return kind === "assistant" || kind === "thinking" || kind === "tool-call" || kind === "tool-result";
1361
+ }
1362
+ export function formatSessionResumeCommand(metadata) {
1363
+ const args = [PRODUCT_TEXT.commandName];
1364
+ if (!metadata.usesDefaultSessionDir)
1365
+ args.push("--session-dir", quoteCommandArgument(metadata.sessionDir));
1366
+ args.push("--session", metadata.sessionId);
1367
+ return args.join(" ");
1368
+ }
1369
+ export function quoteCommandArgument(value) {
1370
+ if (value.length > 0 && !/[^a-zA-Z0-9_\-./~:@]/.test(value))
1371
+ return value;
1372
+ return `'${value.replaceAll("'", `'\\''`)}'`;
1373
+ }
1374
+ function dim(value) {
1375
+ return `\u001b[2m${value}\u001b[22m`;
1376
+ }
1617
1377
  function modelReference(model) {
1618
1378
  if (typeof model !== "object" || model === null)
1619
1379
  return "";