@timurproko/a1 0.2.6 → 0.2.7-dev.1221

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 (410) hide show
  1. package/README.md +41 -3
  2. package/bin/automatic-update.js +7 -0
  3. package/bin/cli.js +4 -0
  4. package/bin/guardian.js +5 -0
  5. package/bin/tab-launch-context.d.ts +27 -0
  6. package/bin/tab-launch-context.js +94 -0
  7. package/bin/ui.js +107 -59
  8. package/dist/app/session-shell/clipboard-diagnostics.js +1 -1
  9. package/dist/app/session-shell/dialog-coordinator.d.ts +42 -0
  10. package/dist/app/session-shell/dialog-coordinator.js +133 -0
  11. package/dist/app/session-shell/dock-chrome.d.ts +34 -0
  12. package/dist/app/session-shell/dock-chrome.js +109 -0
  13. package/dist/app/session-shell/exit-notice.d.ts +1 -1
  14. package/dist/app/session-shell/exit-notice.js +1 -1
  15. package/dist/app/session-shell/extension-surface.d.ts +30 -0
  16. package/dist/app/session-shell/extension-surface.js +105 -0
  17. package/dist/app/session-shell/helper-pool.d.ts +3 -5
  18. package/dist/app/session-shell/helper-pool.js +3 -5
  19. package/dist/app/session-shell/input-surface-switch.d.ts +36 -0
  20. package/dist/app/session-shell/input-surface-switch.js +85 -0
  21. package/dist/app/session-shell/login-interaction.d.ts +27 -0
  22. package/dist/app/session-shell/login-interaction.js +91 -0
  23. package/dist/app/session-shell/prompt-submission.d.ts +48 -0
  24. package/dist/app/session-shell/prompt-submission.js +276 -0
  25. package/dist/app/session-shell/resident-tab-coordinator.d.ts +38 -0
  26. package/dist/app/session-shell/resident-tab-coordinator.js +77 -0
  27. package/dist/app/session-shell/response-copy-helper.js +21 -6
  28. package/dist/app/session-shell/response-copy-protocol.d.ts +1 -1
  29. package/dist/app/session-shell/response-copy-transport.d.ts +16 -6
  30. package/dist/app/session-shell/response-copy-transport.js +69 -17
  31. package/dist/app/session-shell/session-concern.d.ts +22 -0
  32. package/dist/app/session-shell/session-concern.js +29 -0
  33. package/dist/app/session-shell/session-lifecycle.d.ts +29 -0
  34. package/dist/app/session-shell/session-lifecycle.js +49 -0
  35. package/dist/app/session-shell/session-shell-root.d.ts +42 -6
  36. package/dist/app/session-shell/session-shell-root.js +196 -908
  37. package/dist/app/session-shell/session-shell.d.ts +3 -8
  38. package/dist/app/session-shell/session-shell.js +324 -835
  39. package/dist/app/session-shell/session-viewport-controller.d.ts +2 -2
  40. package/dist/app/session-shell/session-viewport-controller.js +29 -15
  41. package/dist/app/session-shell/settings-bindings.d.ts +17 -0
  42. package/dist/app/session-shell/settings-bindings.js +91 -0
  43. package/dist/app/session-shell/shell-editor-factory.d.ts +27 -0
  44. package/dist/app/session-shell/shell-editor-factory.js +102 -0
  45. package/dist/app/session-shell/shell-host.d.ts +6 -0
  46. package/dist/app/session-shell/shell-host.js +34 -7
  47. package/dist/app/session-shell/shell-layout.d.ts +64 -0
  48. package/dist/app/session-shell/shell-layout.js +18 -0
  49. package/dist/app/session-shell/suggestion-surface.d.ts +25 -0
  50. package/dist/app/session-shell/suggestion-surface.js +63 -0
  51. package/dist/app/session-shell/transcript-document.d.ts +78 -0
  52. package/dist/app/session-shell/transcript-document.js +365 -0
  53. package/dist/app/session-shell/viewport-layout.d.ts +31 -0
  54. package/dist/app/session-shell/viewport-layout.js +160 -0
  55. package/dist/app/session-shell/workflow-output.d.ts +33 -0
  56. package/dist/app/session-shell/workflow-output.js +174 -0
  57. package/dist/app/session-shell/workflow-router.d.ts +25 -0
  58. package/dist/app/session-shell/workflow-router.js +39 -0
  59. package/dist/cli/dispatch.d.ts +11 -1
  60. package/dist/cli/dispatch.js +79 -5
  61. package/dist/cli/tabs-request.d.ts +7 -0
  62. package/dist/cli/tabs-request.js +1 -0
  63. package/dist/cli/tabs.d.ts +14 -0
  64. package/dist/cli/tabs.js +151 -0
  65. package/dist/cli/version-stats.js +38 -3
  66. package/dist/composition/owned-settings.d.ts +12 -0
  67. package/dist/composition/owned-settings.js +36 -0
  68. package/dist/composition/owned-ui.d.ts +27 -28
  69. package/dist/composition/owned-ui.js +205 -153
  70. package/dist/composition/resident-tab-bridge.d.ts +25 -0
  71. package/dist/composition/resident-tab-bridge.js +180 -0
  72. package/dist/composition/session-backend.d.ts +19 -0
  73. package/dist/composition/session-backend.js +1 -0
  74. package/dist/composition/session-runtime-registry.d.ts +20 -0
  75. package/dist/composition/session-runtime-registry.js +85 -0
  76. package/dist/composition/settings-route-host.d.ts +16 -1
  77. package/dist/composition/settings-route-host.js +29 -10
  78. package/dist/composition/settings-search-input.d.ts +9 -0
  79. package/dist/composition/settings-search-input.js +58 -0
  80. package/dist/composition/startup-route.d.ts +32 -0
  81. package/dist/composition/startup-route.js +72 -0
  82. package/dist/composition/utility-tab.d.ts +28 -0
  83. package/dist/composition/utility-tab.js +242 -0
  84. package/dist/contracts/owned-ui/index.d.ts +1 -1
  85. package/dist/contracts/owned-ui/model.d.ts +3 -0
  86. package/dist/contracts/owned-ui/session-backend.d.ts +3 -0
  87. package/dist/contracts/owned-ui/session-workflows.d.ts +11 -4
  88. package/dist/contracts/presentation/index.d.ts +11 -0
  89. package/dist/contracts/presentation/index.js +12 -0
  90. package/dist/features/launch/development-launch.js +6 -0
  91. package/dist/features/launch/index.d.ts +1 -1
  92. package/dist/features/launch/intent.d.ts +3 -1
  93. package/dist/features/launch/intent.js +7 -4
  94. package/dist/features/launch/profile-paths.js +4 -0
  95. package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
  96. package/dist/features/owned-ui/plus-menu-dialog.js +76 -0
  97. package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
  98. package/dist/features/owned-ui/project-trust-dialog.js +6 -8
  99. package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
  100. package/dist/features/owned-ui/project-trust-prompt.js +7 -3
  101. package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
  102. package/dist/features/owned-ui/reference-screen-app.js +12 -2
  103. package/dist/features/owned-ui/settings-app.d.ts +12 -2
  104. package/dist/features/owned-ui/settings-app.js +116 -81
  105. package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
  106. package/dist/features/owned-ui/settings-search-input.js +1 -0
  107. package/dist/features/prompt-history/index.d.ts +1 -1
  108. package/dist/features/prompt-history/paths.d.ts +2 -1
  109. package/dist/features/prompt-history/paths.js +10 -2
  110. package/dist/features/prompt-history/service.d.ts +5 -0
  111. package/dist/features/prompt-history/service.js +1 -1
  112. package/dist/features/resident-tab/auto-name.d.ts +11 -0
  113. package/dist/features/resident-tab/auto-name.js +44 -0
  114. package/dist/features/resident-tab/index.d.ts +5 -0
  115. package/dist/features/resident-tab/index.js +7 -0
  116. package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
  117. package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
  118. package/dist/features/resident-tab/shortcut-declarations.d.ts +13 -0
  119. package/dist/features/resident-tab/shortcut-declarations.js +26 -0
  120. package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
  121. package/dist/features/resident-tab/shortcut-projection.js +64 -0
  122. package/dist/features/resident-tab/status-deriver.d.ts +10 -0
  123. package/dist/features/resident-tab/status-deriver.js +12 -0
  124. package/dist/foundation/launch-context/index.d.ts +12 -0
  125. package/dist/foundation/launch-context/index.js +26 -0
  126. package/dist/foundation/launch-guardian/exit-watcher.d.ts +14 -0
  127. package/dist/foundation/launch-guardian/exit-watcher.js +94 -0
  128. package/dist/foundation/launch-guardian/main.d.ts +7 -1
  129. package/dist/foundation/launch-guardian/main.js +60 -7
  130. package/dist/foundation/lifecycle/session-repository-context.js +16 -2
  131. package/dist/foundation/process-containment/{native-guardian-containment.d.ts → addon-containment.d.ts} +7 -5
  132. package/dist/foundation/process-containment/addon-containment.js +139 -0
  133. package/dist/foundation/process-containment/addon-process-inspector.d.ts +11 -0
  134. package/dist/foundation/process-containment/addon-process-inspector.js +36 -0
  135. package/dist/foundation/process-containment/addon.d.ts +42 -0
  136. package/dist/foundation/process-containment/addon.js +57 -0
  137. package/dist/foundation/process-containment/artifact.d.ts +1 -1
  138. package/dist/foundation/process-containment/artifact.js +6 -5
  139. package/dist/foundation/process-containment/contracts.d.ts +2 -0
  140. package/dist/foundation/process-containment/index.d.ts +4 -4
  141. package/dist/foundation/process-containment/index.js +3 -3
  142. package/dist/foundation/process-containment/native-process-inspector.d.ts +2 -1
  143. package/dist/foundation/process-containment/native-process-inspector.js +10 -10
  144. package/dist/foundation/release/automatic-update.d.ts +37 -0
  145. package/dist/foundation/release/automatic-update.js +265 -0
  146. package/dist/foundation/release/bootstrap.d.ts +7 -9
  147. package/dist/foundation/release/bootstrap.js +107 -24
  148. package/dist/foundation/release/cohort-state.d.ts +1 -1
  149. package/dist/foundation/release/cohort-state.js +1 -1
  150. package/dist/foundation/release/dependency-certification.js +54 -19
  151. package/dist/foundation/release/early-accent.d.ts +12 -0
  152. package/dist/foundation/release/early-accent.js +59 -0
  153. package/dist/foundation/release/index.d.ts +2 -2
  154. package/dist/foundation/release/index.js +2 -2
  155. package/dist/foundation/release/latest-release.d.ts +24 -2
  156. package/dist/foundation/release/latest-release.js +51 -1
  157. package/dist/foundation/release/progress-palette.generated.d.ts +137 -3
  158. package/dist/foundation/release/progress-palette.generated.js +137 -3
  159. package/dist/foundation/release/release-gc.d.ts +3 -0
  160. package/dist/foundation/release/release-gc.js +59 -8
  161. package/dist/foundation/release/release-store.d.ts +12 -0
  162. package/dist/foundation/release/release-store.js +124 -2
  163. package/dist/foundation/release/update-execution-lease.d.ts +48 -0
  164. package/dist/foundation/release/update-execution-lease.js +161 -0
  165. package/dist/foundation/release/update.d.ts +12 -7
  166. package/dist/foundation/release/update.js +281 -196
  167. package/dist/foundation/resident-tabs/bounded-host-command.d.ts +18 -0
  168. package/dist/foundation/resident-tabs/bounded-host-command.js +39 -0
  169. package/dist/foundation/resident-tabs/bridge-client.d.ts +70 -0
  170. package/dist/foundation/resident-tabs/bridge-client.js +321 -0
  171. package/dist/foundation/resident-tabs/doctor.d.ts +28 -0
  172. package/dist/foundation/resident-tabs/doctor.js +166 -0
  173. package/dist/foundation/resident-tabs/draft-checkpoint.d.ts +27 -0
  174. package/dist/foundation/resident-tabs/draft-checkpoint.js +145 -0
  175. package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +36 -0
  176. package/dist/foundation/resident-tabs/ensure-terminal-host.js +151 -0
  177. package/dist/foundation/resident-tabs/fault-injection.d.ts +8 -0
  178. package/dist/foundation/resident-tabs/fault-injection.js +26 -0
  179. package/dist/foundation/resident-tabs/fixture-control.d.ts +7 -0
  180. package/dist/foundation/resident-tabs/fixture-control.js +35 -0
  181. package/dist/foundation/resident-tabs/host-entry.d.ts +1 -0
  182. package/dist/foundation/resident-tabs/host-entry.js +17 -0
  183. package/dist/foundation/resident-tabs/index.d.ts +12 -0
  184. package/dist/foundation/resident-tabs/index.js +6 -0
  185. package/dist/foundation/resident-tabs/maintenance.d.ts +39 -0
  186. package/dist/foundation/resident-tabs/maintenance.js +75 -0
  187. package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
  188. package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
  189. package/dist/foundation/resident-tabs/progress-observation.d.ts +4 -0
  190. package/dist/foundation/resident-tabs/progress-observation.js +150 -0
  191. package/dist/foundation/resident-tabs/prompt-journal.d.ts +63 -0
  192. package/dist/foundation/resident-tabs/prompt-journal.js +213 -0
  193. package/dist/foundation/resident-tabs/protocol.d.ts +12 -0
  194. package/dist/foundation/resident-tabs/protocol.js +195 -0
  195. package/dist/foundation/resident-tabs/recovery.d.ts +26 -0
  196. package/dist/foundation/resident-tabs/recovery.js +205 -0
  197. package/dist/foundation/resident-tabs/release-holds.d.ts +28 -0
  198. package/dist/foundation/resident-tabs/release-holds.js +75 -0
  199. package/dist/foundation/resident-tabs/routes.d.ts +5 -0
  200. package/dist/foundation/resident-tabs/routes.js +5 -0
  201. package/dist/foundation/resident-tabs/routing.d.ts +11 -0
  202. package/dist/foundation/resident-tabs/routing.js +10 -0
  203. package/dist/foundation/resident-tabs/session-sync.d.ts +14 -0
  204. package/dist/foundation/resident-tabs/session-sync.js +37 -0
  205. package/dist/foundation/resident-tabs/settings.d.ts +12 -0
  206. package/dist/foundation/resident-tabs/settings.js +58 -0
  207. package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +14 -0
  208. package/dist/foundation/resident-tabs/terminal-host-artifact.js +78 -0
  209. package/dist/foundation/resident-tabs/zip-archive.d.ts +9 -0
  210. package/dist/foundation/resident-tabs/zip-archive.js +56 -0
  211. package/dist/foundation/session-writer-lock/index.d.ts +30 -0
  212. package/dist/foundation/session-writer-lock/index.js +203 -0
  213. package/dist/foundation/startup/startup-descriptor.js +2 -2
  214. package/dist/foundation/terminal-cleanup/index.d.ts +1 -1
  215. package/dist/foundation/terminal-cleanup/index.js +1 -1
  216. package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +6 -0
  217. package/dist/foundation/terminal-cleanup/terminal-reset.js +6 -0
  218. package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
  219. package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
  220. package/dist/integrations/pi/components/modal-frame.js +48 -9
  221. package/dist/integrations/pi/components/models-dialog.js +4 -52
  222. package/dist/integrations/pi/components/owned-editor-ux.d.ts +6 -1
  223. package/dist/integrations/pi/components/owned-editor-ux.js +90 -6
  224. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +4 -4
  225. package/dist/integrations/pi/components/resources/builtin-themes.js +4 -4
  226. package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -0
  227. package/dist/integrations/pi/components/share-operation-dialog.js +2 -1
  228. package/dist/integrations/pi/components/shell-editor-autocomplete.js +58 -36
  229. package/dist/integrations/pi/components/shell-extension-ui.js +79 -60
  230. package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
  231. package/dist/integrations/pi/components/shell-footer-status.js +21 -5
  232. package/dist/integrations/pi/components/shell-hotkey-sections.js +1 -1
  233. package/dist/integrations/pi/components/shell-presenters-info.d.ts +5 -2
  234. package/dist/integrations/pi/components/shell-presenters-info.js +18 -4
  235. package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
  236. package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -1
  237. package/dist/integrations/pi/components/shell-shared-facade.d.ts +12 -1
  238. package/dist/integrations/pi/components/skills-dialog.js +2 -2
  239. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
  240. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +17 -4
  241. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  242. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  243. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  244. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  245. package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
  246. package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
  247. package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
  248. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  249. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +8 -6
  250. package/dist/integrations/pi/components/upstream/components/owned-editor.js +16 -9
  251. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  252. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +4 -4
  253. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
  254. package/dist/integrations/pi/components/upstream/components/session-footer.d.ts +2 -1
  255. package/dist/integrations/pi/components/upstream/components/session-footer.js +31 -25
  256. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  257. package/dist/integrations/pi/components/upstream/components/session-selector.js +8 -7
  258. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
  259. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
  260. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +2 -2
  261. package/dist/integrations/pi/components/upstream/components/status-indicator.js +3 -3
  262. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  263. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  264. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +8 -7
  265. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +10 -9
  266. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +2 -6
  267. package/dist/integrations/pi/components/upstream/components/tool-execution.js +103 -101
  268. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +9 -9
  269. package/dist/integrations/pi/components/upstream/components/tree-selector.js +13 -21
  270. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  271. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  272. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +2 -2
  273. package/dist/integrations/pi/components/upstream/history/editor-core.js +7 -5
  274. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  275. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  276. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  277. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  278. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  279. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  280. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  281. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  282. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
  283. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  284. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +5 -0
  285. package/dist/integrations/pi/components/upstream/theme/theme.js +29 -2
  286. package/dist/integrations/pi/engine/adapter.d.ts +5 -77
  287. package/dist/integrations/pi/engine/adapter.js +95 -394
  288. package/dist/integrations/pi/engine/command-dispatch.d.ts +13 -0
  289. package/dist/integrations/pi/engine/command-dispatch.js +57 -0
  290. package/dist/integrations/pi/engine/host.js +2 -2
  291. package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
  292. package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
  293. package/dist/integrations/pi/engine/pi-settings-metadata.json +14 -2
  294. package/dist/integrations/pi/engine/ports.d.ts +56 -0
  295. package/dist/integrations/pi/engine/ports.js +93 -0
  296. package/dist/integrations/pi/engine/prompt-suggestions.d.ts +1 -0
  297. package/dist/integrations/pi/engine/prompt-suggestions.js +40 -0
  298. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  299. package/dist/integrations/pi/engine/runtime-integration.js +102 -29
  300. package/dist/integrations/pi/engine/session-runtime.d.ts +0 -6
  301. package/dist/integrations/pi/engine/session-runtime.js +13 -5
  302. package/dist/integrations/pi/engine/session-selection.d.ts +3 -0
  303. package/dist/integrations/pi/engine/session-selection.js +45 -9
  304. package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
  305. package/dist/integrations/pi/engine/settings-bridge.js +15 -0
  306. package/dist/integrations/pi/engine/settings-port.js +11 -15
  307. package/dist/integrations/pi/engine/view-state.d.ts +42 -0
  308. package/dist/integrations/pi/engine/view-state.js +126 -0
  309. package/dist/integrations/pi/engine/workflow-contexts.js +10 -1
  310. package/dist/integrations/pi/engine/workflow-runner.js +73 -4
  311. package/dist/integrations/pi/engine/workflow-support.d.ts +12 -0
  312. package/dist/integrations/pi/engine/workflow-support.js +36 -0
  313. package/dist/integrations/pi/engine/workflows.d.ts +3 -1
  314. package/dist/integrations/pi/engine/workflows.js +1 -0
  315. package/dist/integrations/pi/startup-public.js +257 -310
  316. package/dist/integrations/pi/startup-public.manifest.json +564 -440
  317. package/dist/integrations/pi/tui-runtime/adapter.d.ts +6 -0
  318. package/dist/integrations/pi/tui-runtime/adapter.js +32 -1
  319. package/dist/integrations/pi/tui-runtime/contracts.d.ts +5 -0
  320. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +12 -1
  321. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +31 -2
  322. package/dist/native/darwin-arm64/manifest.json +10 -7
  323. package/dist/native/darwin-arm64/process-guardian.node +0 -0
  324. package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +10500 -0
  325. package/dist/native/darwin-arm64/terminal-host.manifest.json +46 -0
  326. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  327. package/dist/native/darwin-x64/manifest.json +23 -0
  328. package/dist/native/darwin-x64/process-guardian.node +0 -0
  329. package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10737 -0
  330. package/dist/native/darwin-x64/terminal-host.manifest.json +46 -0
  331. package/dist/native/darwin-x64/terminal-host.node +0 -0
  332. package/dist/native/linux-x64/manifest.json +10 -7
  333. package/dist/native/linux-x64/process-guardian.node +0 -0
  334. package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +11226 -0
  335. package/dist/native/linux-x64/terminal-host.manifest.json +46 -0
  336. package/dist/native/linux-x64/terminal-host.node +0 -0
  337. package/dist/native/win32-x64/manifest.json +10 -7
  338. package/dist/native/win32-x64/process-guardian.node +0 -0
  339. package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10757 -0
  340. package/dist/native/win32-x64/terminal-host.manifest.json +46 -0
  341. package/dist/native/win32-x64/terminal-host.node +0 -0
  342. package/dist/product-identity.d.ts +3 -3
  343. package/dist/product-identity.js +4 -4
  344. package/dist/product-identity.json +16 -2
  345. package/dist/runtime-payload-inventory.json +6330 -6677
  346. package/dist/ui/apps/host.d.ts +2 -0
  347. package/dist/ui/apps/host.js +7 -1
  348. package/dist/ui/components/dialog-panel.js +35 -30
  349. package/dist/ui/components/index.d.ts +2 -2
  350. package/dist/ui/components/index.js +1 -1
  351. package/dist/ui/components/line-input.d.ts +4 -1
  352. package/dist/ui/components/line-input.js +3 -1
  353. package/dist/ui/components/prompt-input.d.ts +11 -8
  354. package/dist/ui/components/prompt-input.js +15 -13
  355. package/dist/ui/components/selection-copy.d.ts +2 -0
  356. package/dist/ui/components/selection-copy.js +13 -0
  357. package/dist/ui/components/spans.js +2 -2
  358. package/dist/ui/components/submitted-prompt.d.ts +9 -6
  359. package/dist/ui/components/submitted-prompt.js +20 -12
  360. package/dist/ui/components/surface.js +4 -2
  361. package/dist/ui/components/text.d.ts +3 -6
  362. package/dist/ui/components/text.js +6 -8
  363. package/dist/ui/components/transcript-viewport.d.ts +9 -2
  364. package/dist/ui/components/transcript-viewport.js +176 -55
  365. package/dist/ui/settings/declarations.d.ts +90 -16
  366. package/dist/ui/settings/declarations.js +67 -14
  367. package/dist/ui/settings/early-accent.d.ts +81 -0
  368. package/dist/ui/settings/early-accent.js +50 -0
  369. package/dist/ui/settings/index.d.ts +4 -2
  370. package/dist/ui/settings/index.js +2 -1
  371. package/dist/ui/settings/manager.d.ts +16 -3
  372. package/dist/ui/settings/manager.js +122 -33
  373. package/dist/ui/settings/migrations.d.ts +6 -0
  374. package/dist/ui/settings/migrations.js +73 -0
  375. package/dist/ui/settings/profile-document.d.ts +26 -0
  376. package/dist/ui/settings/profile-document.js +164 -0
  377. package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
  378. package/dist/ui/settings/progress-palette.generated.js +139 -0
  379. package/dist/ui/settings/sections.d.ts +4 -0
  380. package/dist/ui/settings/sections.js +9 -3
  381. package/docs/architecture/boundaries.md +24 -9
  382. package/docs/architecture/evidence/resident-tabs/linux-x64.md +37 -0
  383. package/docs/architecture/evidence/resident-tabs/macos-arm64.md +36 -0
  384. package/docs/architecture/evidence/resident-tabs/macos-x64.md +35 -0
  385. package/docs/architecture/evidence/resident-tabs/windows-x64.md +36 -0
  386. package/docs/architecture/internal-naming.md +3 -1
  387. package/docs/architecture/process-guardian-provenance.md +18 -10
  388. package/docs/architecture/project-structure.md +8 -0
  389. package/docs/architecture/resident-tabs-requirements.md +18 -0
  390. package/docs/architecture/resident-tabs.md +648 -0
  391. package/docs/architecture/response-copy-delivery.md +1 -1
  392. package/docs/architecture/terminal-host-proof-gate.md +2 -0
  393. package/docs/architecture/terminal-host-provenance.md +16 -4
  394. package/docs/architecture/tool-image-presentation.md +2 -1
  395. package/docs/architecture/toolchain.md +11 -9
  396. package/docs/ci-release-runbook.md +14 -7
  397. package/docs/features/launch-profiles.md +11 -8
  398. package/docs/features/prompt-history.md +41 -20
  399. package/docs/manual-resident-tabs-acceptance.md +51 -0
  400. package/docs/openspec-archive-automation.md +49 -22
  401. package/docs/validation.md +49 -9
  402. package/package.json +19 -6
  403. package/dist/foundation/process-containment/darwin-process-inspector.d.ts +0 -5
  404. package/dist/foundation/process-containment/darwin-process-inspector.js +0 -7
  405. package/dist/foundation/process-containment/native-guardian-containment.js +0 -152
  406. package/dist/foundation/process-containment/windows-process-inspector.d.ts +0 -19
  407. package/dist/foundation/process-containment/windows-process-inspector.js +0 -56
  408. package/dist/native/darwin-arm64/process-guardian +0 -0
  409. package/dist/native/linux-x64/process-guardian +0 -0
  410. package/dist/native/win32-x64/process-guardian.exe +0 -0
@@ -0,0 +1,44 @@
1
+ export const AUTO_NAME_MAX_LENGTH = 16;
2
+ export const AUTO_NAME_TIMEOUT_MS = 30_000;
3
+ // Rationale: reasoning models can spend a small ceiling on hidden thinking and emit no title, so an
4
+ // answerless attempt retries with a larger bound; budgets stay strictly increasing, as in v2.
5
+ export const AUTO_NAME_TOKEN_BUDGETS = [4_096, 32_768];
6
+ export function normalizeAutoName(value) {
7
+ const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-");
8
+ if (!normalized)
9
+ return null;
10
+ if (normalized.length <= AUTO_NAME_MAX_LENGTH)
11
+ return normalized;
12
+ const clipped = normalized.slice(0, AUTO_NAME_MAX_LENGTH + 1);
13
+ const boundary = clipped.lastIndexOf("-");
14
+ const result = (boundary >= 4 ? clipped.slice(0, boundary) : normalized.slice(0, AUTO_NAME_MAX_LENGTH)).replace(/-+$/g, "");
15
+ return result || null;
16
+ }
17
+ export function fallbackAutoName(prompt) {
18
+ const words = prompt.toLowerCase().match(/[a-z0-9]+/g) ?? [];
19
+ return normalizeAutoName(words.slice(0, 3).join("-")) ?? "new-task";
20
+ }
21
+ export async function generateAutoName(firstPrompt, complete, timeoutMs = AUTO_NAME_TIMEOUT_MS) {
22
+ for (const maxTokens of AUTO_NAME_TOKEN_BUDGETS) {
23
+ const controller = new AbortController();
24
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
25
+ timer.unref?.();
26
+ try {
27
+ const response = await complete({
28
+ prompt: `Name this coding task with a lowercase hyphenated title of at most ${AUTO_NAME_MAX_LENGTH} characters. Reply only with the title.\n\n${firstPrompt.slice(0, 500)}`,
29
+ maxTokens,
30
+ signal: controller.signal,
31
+ });
32
+ const name = response === null ? null : normalizeAutoName(response);
33
+ if (name !== null)
34
+ return name;
35
+ }
36
+ catch {
37
+ // Rationale: naming is best effort; the larger bounded attempt precedes the deterministic fallback.
38
+ }
39
+ finally {
40
+ clearTimeout(timer);
41
+ }
42
+ }
43
+ return fallbackAutoName(firstPrompt);
44
+ }
@@ -0,0 +1,5 @@
1
+ export { AUTO_NAME_MAX_LENGTH, AUTO_NAME_TIMEOUT_MS, AUTO_NAME_TOKEN_BUDGETS, fallbackAutoName, generateAutoName, normalizeAutoName, type AutoNameCompletion, } from "./auto-name.js";
2
+ export { RESIDENT_TAB_SHORTCUTS, type ResidentTabAction, type ResidentTabShortcut, } from "./shortcut-declarations.js";
3
+ export { projectResidentTabShortcuts, RESIDENT_TAB_GLOBAL_SHORTCUTS, type ResidentTabGlobalAction, type ResidentTabShortcutConflict, type ResidentTabShortcutProjection, type ShortcutBindings, } from "./shortcut-projection.js";
4
+ export { readShortcutBindingsFile } from "./shortcut-bindings-file.js";
5
+ export { deriveResidentTabStatus, type ResidentTabDerivedStatus, type ResidentTabFacts, } from "./status-deriver.js";
@@ -0,0 +1,7 @@
1
+ export { AUTO_NAME_MAX_LENGTH, AUTO_NAME_TIMEOUT_MS, AUTO_NAME_TOKEN_BUDGETS, fallbackAutoName, generateAutoName, normalizeAutoName, } from "./auto-name.js";
2
+ // Performance: the registry builder lives in `shortcuts.ts`, outside this barrel, so startup
3
+ // presentation can read the declarations without loading the component registry.
4
+ export { RESIDENT_TAB_SHORTCUTS, } from "./shortcut-declarations.js";
5
+ export { projectResidentTabShortcuts, RESIDENT_TAB_GLOBAL_SHORTCUTS, } from "./shortcut-projection.js";
6
+ export { readShortcutBindingsFile } from "./shortcut-bindings-file.js";
7
+ export { deriveResidentTabStatus, } from "./status-deriver.js";
@@ -0,0 +1,8 @@
1
+ import type { ShortcutBindings } from "./shortcut-projection.js";
2
+ /** Largest `keybindings.json` the projection reads; a larger file counts as absent. */
3
+ export declare const MAX_SHORTCUT_BINDINGS_BYTES: number;
4
+ /**
5
+ * Reads the user's `keybindings.json` as shortcut bindings, keeping `null` entries so an
6
+ * explicit unbind survives, and treating any unreadable or malformed file as empty.
7
+ */
8
+ export declare function readShortcutBindingsFile(agentDir: string): ShortcutBindings;
@@ -0,0 +1,40 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /** Largest `keybindings.json` the projection reads; a larger file counts as absent. */
4
+ export const MAX_SHORTCUT_BINDINGS_BYTES = 256 * 1024;
5
+ /**
6
+ * Reads the user's `keybindings.json` as shortcut bindings, keeping `null` entries so an
7
+ * explicit unbind survives, and treating any unreadable or malformed file as empty.
8
+ */
9
+ export function readShortcutBindingsFile(agentDir) {
10
+ let text;
11
+ try {
12
+ text = readFileSync(join(agentDir, "keybindings.json"), "utf8");
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ if (text.length > MAX_SHORTCUT_BINDINGS_BYTES)
18
+ return {};
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(text.replace(/^/u, ""));
22
+ }
23
+ catch {
24
+ return {};
25
+ }
26
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
27
+ return {};
28
+ const bindings = {};
29
+ for (const [action, value] of Object.entries(parsed)) {
30
+ if (action === "$schema")
31
+ continue;
32
+ if (value === null || typeof value === "string") {
33
+ bindings[action] = value;
34
+ continue;
35
+ }
36
+ if (Array.isArray(value))
37
+ bindings[action] = value.filter((key) => typeof key === "string");
38
+ }
39
+ return bindings;
40
+ }
@@ -0,0 +1,13 @@
1
+ export type ResidentTabAction = "tabs.new" | "tabs.close" | "tabs.rename" | "tabs.settings" | "tabs.changelog" | "tabs.commands" | "tabs.retry" | "tabs.fresh" | "tabs.next" | "tabs.previous" | "tabs.moveRight" | "tabs.moveLeft" | `tabs.jump${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10}`;
2
+ export interface ResidentTabShortcut {
3
+ readonly id: ResidentTabAction;
4
+ readonly defaultKey: string | null;
5
+ readonly scope: "global" | "failed-banner";
6
+ readonly description: string;
7
+ }
8
+ /**
9
+ * The tab shortcut declarations, in the order that decides which action keeps a duplicated key.
10
+ * This module stays dependency-free so startup presentation and the resident projection can
11
+ * read it without loading the component registry.
12
+ */
13
+ export declare const RESIDENT_TAB_SHORTCUTS: readonly ResidentTabShortcut[];
@@ -0,0 +1,26 @@
1
+ const jumps = Array.from({ length: 10 }, (_, index) => ({
2
+ id: `tabs.jump${index + 1}`,
3
+ defaultKey: `alt+${(index + 1) % 10}`,
4
+ scope: "global",
5
+ description: `View A1 tab ${index + 1}`,
6
+ }));
7
+ /**
8
+ * The tab shortcut declarations, in the order that decides which action keeps a duplicated key.
9
+ * This module stays dependency-free so startup presentation and the resident projection can
10
+ * read it without loading the component registry.
11
+ */
12
+ export const RESIDENT_TAB_SHORTCUTS = Object.freeze([
13
+ { id: "tabs.new", defaultKey: "alt+a", scope: "global", description: "New A1 tab" },
14
+ { id: "tabs.close", defaultKey: "alt+w", scope: "global", description: "Close A1 tab" },
15
+ { id: "tabs.rename", defaultKey: "f2", scope: "global", description: "Rename A1 tab" },
16
+ { id: "tabs.settings", defaultKey: "alt+,", scope: "global", description: "Open Settings tab" },
17
+ { id: "tabs.changelog", defaultKey: null, scope: "global", description: "Open Changelog tab" },
18
+ { id: "tabs.commands", defaultKey: "alt+/", scope: "global", description: "Open command palette" },
19
+ ...jumps,
20
+ { id: "tabs.next", defaultKey: null, scope: "global", description: "View next A1 tab" },
21
+ { id: "tabs.previous", defaultKey: null, scope: "global", description: "View previous A1 tab" },
22
+ { id: "tabs.moveRight", defaultKey: null, scope: "global", description: "Move A1 tab right" },
23
+ { id: "tabs.moveLeft", defaultKey: null, scope: "global", description: "Move A1 tab left" },
24
+ { id: "tabs.retry", defaultKey: "r", scope: "failed-banner", description: "Retry failed A1 tab" },
25
+ { id: "tabs.fresh", defaultKey: "f", scope: "failed-banner", description: "Start failed A1 tab fresh" },
26
+ ]);
@@ -0,0 +1,29 @@
1
+ import { type ResidentTabAction } from "./shortcut-declarations.js";
2
+ /** Key assignments as `keybindings.json` and the keybinding manager express them. */
3
+ export type ShortcutBindings = Readonly<Record<string, string | readonly string[] | null | undefined>>;
4
+ export type ResidentTabGlobalAction = Exclude<ResidentTabAction, "tabs.retry" | "tabs.fresh">;
5
+ export interface ResidentTabShortcutConflict {
6
+ readonly id: ResidentTabGlobalAction;
7
+ readonly key: string;
8
+ /** `reserved` keys belong to an A1 action; `duplicate` keys were claimed by an earlier tab action. */
9
+ readonly reason: "reserved" | "duplicate";
10
+ }
11
+ /** The effective tab shortcuts the resident shell dispatches and every presentation shows. */
12
+ export interface ResidentTabShortcutProjection {
13
+ readonly assignments: Readonly<Record<ResidentTabGlobalAction, string | null>>;
14
+ readonly conflicts: readonly ResidentTabShortcutConflict[];
15
+ }
16
+ export interface ResidentTabShortcutInput {
17
+ /** The user's `keybindings.json`, including any `tabs.*` entries; `null` unbinds an action. */
18
+ readonly configured?: ShortcutBindings | undefined;
19
+ /** The effective A1 declarations (defaults plus customization) whose keys tab actions may not take. */
20
+ readonly reserved?: ShortcutBindings | undefined;
21
+ }
22
+ /** The declarations the projection covers, in the order that decides duplicate claims. */
23
+ export declare const RESIDENT_TAB_GLOBAL_SHORTCUTS: import("./shortcut-declarations.js").ResidentTabShortcut[];
24
+ /**
25
+ * Projects the effective A1 declarations and the user's customization into one tab shortcut
26
+ * assignment per action. A key an A1 action holds after customization never becomes a tab
27
+ * shortcut; between tab actions the earlier declaration keeps a duplicated key.
28
+ */
29
+ export declare function projectResidentTabShortcuts(input?: ResidentTabShortcutInput): ResidentTabShortcutProjection;
@@ -0,0 +1,64 @@
1
+ import { RESIDENT_TAB_SHORTCUTS } from "./shortcut-declarations.js";
2
+ /** The declarations the projection covers, in the order that decides duplicate claims. */
3
+ export const RESIDENT_TAB_GLOBAL_SHORTCUTS = RESIDENT_TAB_SHORTCUTS.filter(shortcut => shortcut.scope === "global");
4
+ function normalizeKey(key) {
5
+ return key.trim().toLowerCase();
6
+ }
7
+ function keysOf(value) {
8
+ if (value === null || value === undefined)
9
+ return value;
10
+ if (typeof value === "string")
11
+ return [value];
12
+ return value.filter((key) => typeof key === "string");
13
+ }
14
+ /**
15
+ * Projects the effective A1 declarations and the user's customization into one tab shortcut
16
+ * assignment per action. A key an A1 action holds after customization never becomes a tab
17
+ * shortcut; between tab actions the earlier declaration keeps a duplicated key.
18
+ */
19
+ export function projectResidentTabShortcuts(input = {}) {
20
+ const configured = input.configured ?? {};
21
+ const claimedByOwnedActions = new Map();
22
+ for (const [action, value] of Object.entries(input.reserved ?? {})) {
23
+ if (action.startsWith("tabs."))
24
+ continue;
25
+ claimedByOwnedActions.set(action, keysOf(value) ?? []);
26
+ }
27
+ for (const [action, value] of Object.entries(configured)) {
28
+ if (action.startsWith("tabs.") || action === "$schema")
29
+ continue;
30
+ claimedByOwnedActions.set(action, keysOf(value) ?? []);
31
+ }
32
+ const reserved = new Set();
33
+ for (const keys of claimedByOwnedActions.values())
34
+ for (const key of keys)
35
+ reserved.add(normalizeKey(key));
36
+ const claimed = new Set();
37
+ const conflicts = [];
38
+ const assignments = {};
39
+ for (const shortcut of RESIDENT_TAB_GLOBAL_SHORTCUTS) {
40
+ const id = shortcut.id;
41
+ const custom = configured[id];
42
+ const candidates = custom === undefined
43
+ ? (shortcut.defaultKey === null ? [] : [shortcut.defaultKey])
44
+ : (keysOf(custom) ?? []);
45
+ let assigned = null;
46
+ for (const candidate of candidates.map(normalizeKey)) {
47
+ if (candidate.length === 0)
48
+ continue;
49
+ if (reserved.has(candidate)) {
50
+ conflicts.push({ id, key: candidate, reason: "reserved" });
51
+ continue;
52
+ }
53
+ if (claimed.has(candidate)) {
54
+ conflicts.push({ id, key: candidate, reason: "duplicate" });
55
+ continue;
56
+ }
57
+ assigned = candidate;
58
+ claimed.add(candidate);
59
+ break;
60
+ }
61
+ assignments[id] = assigned;
62
+ }
63
+ return { assignments, conflicts };
64
+ }
@@ -0,0 +1,10 @@
1
+ /** How the tab's last agent turn settled; it persists until the next turn starts. */
2
+ export type ResidentTabTurnSettlement = "done" | "aborted" | "error";
3
+ export type ResidentTabDerivedStatus = "starting" | "working" | "needs-input" | "idle" | "failed" | ResidentTabTurnSettlement;
4
+ export interface ResidentTabFacts {
5
+ readonly lifecycle: string;
6
+ readonly pendingRequests: number;
7
+ readonly queuedInput: number;
8
+ readonly lastTurn?: ResidentTabTurnSettlement;
9
+ }
10
+ export declare function deriveResidentTabStatus(facts: ResidentTabFacts): ResidentTabDerivedStatus;
@@ -0,0 +1,12 @@
1
+ // Invariant: `failed` is reserved for a failed tab lifecycle; a turn that errored reports `error`.
2
+ export function deriveResidentTabStatus(facts) {
3
+ if (facts.lifecycle === "failed")
4
+ return "failed";
5
+ if (facts.pendingRequests > 0)
6
+ return "needs-input";
7
+ if (facts.lifecycle === "busy" || facts.queuedInput > 0)
8
+ return "working";
9
+ if (facts.lifecycle === "starting")
10
+ return "starting";
11
+ return facts.lastTurn ?? "idle";
12
+ }
@@ -6,7 +6,12 @@ export declare const PRIVATE_ENVIRONMENT: Readonly<{
6
6
  releaseDigest: "LAUNCH_CONTEXT_RELEASE_DIGEST";
7
7
  releaseLayers: "LAUNCH_CONTEXT_RELEASE_LAYERS";
8
8
  launchProfile: "LAUNCH_CONTEXT_PROFILE";
9
+ launchMode: "LAUNCH_CONTEXT_MODE";
10
+ updateVersion: "LAUNCH_CONTEXT_UPDATE_VERSION";
9
11
  immutableWarmup: "LAUNCH_CONTEXT_WARMUP";
12
+ residentRootExecutable: "LAUNCH_CONTEXT_RESIDENT_ROOT_EXECUTABLE";
13
+ residentRootArguments: "LAUNCH_CONTEXT_RESIDENT_ROOT_ARGUMENTS";
14
+ residentFallback: "LAUNCH_CONTEXT_RESIDENT_FALLBACK";
10
15
  }>;
11
16
  /**
12
17
  * Keys published by releases that predate the neutral cutover. They are read when
@@ -30,8 +35,15 @@ export interface LaunchContext {
30
35
  readonly releaseDigest?: string;
31
36
  readonly releaseLayers?: string;
32
37
  readonly launchProfile?: "a1" | "pi";
38
+ readonly launchMode?: "tabs" | "solo";
39
+ readonly updateVersion?: string;
33
40
  readonly immutableWarmup?: "1";
41
+ readonly residentRootExecutable?: string;
42
+ readonly residentRootArguments?: string;
43
+ readonly residentFallback?: string;
34
44
  }
45
+ /** The Tabs settings configure resident tabs; a direct-route launch, by `a1 solo` or by a fallback, hides them. */
46
+ export declare function hidesTabSettings(context: Pick<LaunchContext, "launchMode" | "residentFallback">): boolean;
35
47
  export type LaunchContextRequirement = "optional" | "profile" | "release" | "warmup";
36
48
  /** Read current keys, fall back to superseded keys per field, with bounded diagnostics. */
37
49
  export declare function readLaunchContext(environment: NodeJS.ProcessEnv, requirement?: LaunchContextRequirement, platform?: NodeJS.Platform): LaunchContext;
@@ -6,7 +6,12 @@ export const PRIVATE_ENVIRONMENT = Object.freeze({
6
6
  releaseDigest: "LAUNCH_CONTEXT_RELEASE_DIGEST",
7
7
  releaseLayers: "LAUNCH_CONTEXT_RELEASE_LAYERS",
8
8
  launchProfile: "LAUNCH_CONTEXT_PROFILE",
9
+ launchMode: "LAUNCH_CONTEXT_MODE",
10
+ updateVersion: "LAUNCH_CONTEXT_UPDATE_VERSION",
9
11
  immutableWarmup: "LAUNCH_CONTEXT_WARMUP",
12
+ residentRootExecutable: "LAUNCH_CONTEXT_RESIDENT_ROOT_EXECUTABLE",
13
+ residentRootArguments: "LAUNCH_CONTEXT_RESIDENT_ROOT_ARGUMENTS",
14
+ residentFallback: "LAUNCH_CONTEXT_RESIDENT_FALLBACK",
10
15
  });
11
16
  /**
12
17
  * Keys published by releases that predate the neutral cutover. They are read when
@@ -27,6 +32,10 @@ const SUPERSEDED_ENTRIES = Object.entries(SUPERSEDED_ENVIRONMENT);
27
32
  const PRIVATE_KEYS = new Set([...Object.values(PRIVATE_ENVIRONMENT), ...Object.values(SUPERSEDED_ENVIRONMENT)]);
28
33
  const LOGICAL_KEYS = new Map(PRIVATE_ENTRIES.map(([logical, key]) => [key, logical]));
29
34
  const SUPERSEDED_LOGICAL_KEYS = new Map(SUPERSEDED_ENTRIES.map(([logical, key]) => [key, logical]));
35
+ /** The Tabs settings configure resident tabs; a direct-route launch, by `a1 solo` or by a fallback, hides them. */
36
+ export function hidesTabSettings(context) {
37
+ return context.launchMode === "solo" || context.residentFallback !== undefined;
38
+ }
30
39
  /** Read current keys, fall back to superseded keys per field, with bounded diagnostics. */
31
40
  export function readLaunchContext(environment, requirement = "optional", platform = process.platform) {
32
41
  const values = {};
@@ -61,8 +70,25 @@ export function readLaunchContext(environment, requirement = "optional", platfor
61
70
  if (values.launchProfile !== undefined && values.launchProfile !== "a1" && values.launchProfile !== "pi") {
62
71
  throw invalidContext("launchProfile", "unsupported profile");
63
72
  }
73
+ if (values.launchMode !== undefined && values.launchMode !== "tabs" && values.launchMode !== "solo") {
74
+ throw invalidContext("launchMode", "unsupported launch mode");
75
+ }
76
+ if (values.launchProfile === "pi" && values.launchMode === "tabs")
77
+ throw invalidContext("launchMode", "Pi comparison cannot use tabs");
64
78
  if (values.immutableWarmup !== undefined && values.immutableWarmup !== "1")
65
79
  throw invalidContext("immutableWarmup", "invalid permission flag");
80
+ if ((values.residentRootExecutable === undefined) !== (values.residentRootArguments === undefined))
81
+ throw invalidContext("residentRootExecutable", "resident root command is incomplete");
82
+ if (values.residentRootArguments !== undefined) {
83
+ try {
84
+ const argumentsValue = JSON.parse(values.residentRootArguments);
85
+ if (!Array.isArray(argumentsValue) || argumentsValue.some(value => typeof value !== "string"))
86
+ throw new Error("not string arguments");
87
+ }
88
+ catch {
89
+ throw invalidContext("residentRootArguments", "invalid JSON argument list");
90
+ }
91
+ }
66
92
  if (values.releaseDigest !== undefined && !/^[a-f0-9]{64}$/.test(values.releaseDigest))
67
93
  throw invalidContext("releaseDigest", "invalid digest");
68
94
  if (requirement === "profile")
@@ -0,0 +1,14 @@
1
+ import { type ProcessGuardianAddon } from "../process-containment/index.js";
2
+ interface ExitWatcherOptions {
3
+ readonly guardianPid: number;
4
+ readonly noticePath: string;
5
+ readonly encodedModes: string;
6
+ readonly addonPath: string;
7
+ readonly runtimePid: number;
8
+ readonly processGroup: number | null;
9
+ readonly foregroundGroup: number | null;
10
+ }
11
+ /** Waits outside launch containment, then performs the cleanup its dead guardian could not. */
12
+ export declare function runExitWatcher(arguments_: readonly string[], platform?: NodeJS.Platform, loadAddon?: (path: string) => ProcessGuardianAddon): Promise<number>;
13
+ export declare function exitWatcherArguments(options: ExitWatcherOptions): string[];
14
+ export {};
@@ -0,0 +1,94 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { resolve } from "node:path";
3
+ import { loadProcessGuardianAddon } from "../process-containment/index.js";
4
+ /** Waits outside launch containment, then performs the cleanup its dead guardian could not. */
5
+ export async function runExitWatcher(arguments_, platform = process.platform, loadAddon = loadProcessGuardianAddon) {
6
+ const options = parseArguments(arguments_);
7
+ const addon = loadAddon(options.addonPath);
8
+ if (platform === "win32")
9
+ addon.ignoreConsoleControl();
10
+ else {
11
+ process.on("SIGINT", ignoreSignal);
12
+ process.on("SIGTTOU", ignoreSignal);
13
+ }
14
+ try {
15
+ await addon.waitForProcessExit(options.guardianPid);
16
+ if (platform === "win32") {
17
+ // Rationale: job termination is asynchronous; keep the runtime's final frame ahead of the notice.
18
+ await Promise.race([
19
+ addon.waitForProcessExit(options.runtimePid),
20
+ delay(2_000),
21
+ ]);
22
+ }
23
+ else if (options.processGroup !== null) {
24
+ addon.stopProcessGroup(options.processGroup);
25
+ if (options.foregroundGroup !== null)
26
+ addon.restoreForegroundGroup(options.foregroundGroup);
27
+ }
28
+ addon.deliverExitNotice(options.noticePath, options.encodedModes);
29
+ return 0;
30
+ }
31
+ finally {
32
+ if (platform !== "win32") {
33
+ process.off("SIGINT", ignoreSignal);
34
+ process.off("SIGTTOU", ignoreSignal);
35
+ }
36
+ }
37
+ }
38
+ export function exitWatcherArguments(options) {
39
+ return [
40
+ "--guardian-pid", String(options.guardianPid),
41
+ "--notice", options.noticePath,
42
+ "--modes", options.encodedModes,
43
+ "--addon", options.addonPath,
44
+ "--runtime-pid", String(options.runtimePid),
45
+ ...(options.processGroup === null ? [] : ["--process-group", String(options.processGroup)]),
46
+ ...(options.foregroundGroup === null ? [] : ["--foreground-group", String(options.foregroundGroup)]),
47
+ ];
48
+ }
49
+ function parseArguments(arguments_) {
50
+ const values = new Map();
51
+ for (let index = 0; index < arguments_.length; index += 2) {
52
+ const name = arguments_[index];
53
+ const value = arguments_[index + 1];
54
+ if (!name?.startsWith("--") || value === undefined || values.has(name))
55
+ throw new TypeError("exit watcher arguments are malformed");
56
+ values.set(name, value);
57
+ }
58
+ const guardianPid = positiveInteger(values.get("--guardian-pid"), "guardian PID");
59
+ const runtimePid = positiveInteger(values.get("--runtime-pid"), "runtime PID");
60
+ const noticePath = boundedValue(values.get("--notice"), "notice path");
61
+ const encodedModes = boundedValue(values.get("--modes"), "terminal modes", 32_768);
62
+ const addonPath = boundedValue(values.get("--addon"), "addon path");
63
+ const processGroup = optionalPositiveInteger(values.get("--process-group"), "process group");
64
+ const foregroundGroup = optionalPositiveInteger(values.get("--foreground-group"), "foreground group");
65
+ const expected = 5 + (processGroup === null ? 0 : 1) + (foregroundGroup === null ? 0 : 1);
66
+ if (values.size !== expected)
67
+ throw new TypeError("exit watcher received an unknown argument");
68
+ return { guardianPid, noticePath, encodedModes, addonPath, runtimePid, processGroup, foregroundGroup };
69
+ }
70
+ function positiveInteger(value, name) {
71
+ const parsed = Number(value);
72
+ if (!Number.isSafeInteger(parsed) || parsed <= 0)
73
+ throw new TypeError(`exit watcher ${name} must be a positive safe integer`);
74
+ return parsed;
75
+ }
76
+ function optionalPositiveInteger(value, name) {
77
+ return value === undefined ? null : positiveInteger(value, name);
78
+ }
79
+ function boundedValue(value, name, limit = 4_096) {
80
+ if (!value || value.length > limit || value.includes("\0"))
81
+ throw new TypeError(`exit watcher ${name} is invalid`);
82
+ return value;
83
+ }
84
+ function delay(milliseconds) {
85
+ return new Promise(resolvePromise => setTimeout(resolvePromise, milliseconds));
86
+ }
87
+ function ignoreSignal() { }
88
+ const invokedPath = process.argv[1] ? resolve(process.argv[1]) : null;
89
+ if (invokedPath === fileURLToPath(import.meta.url)) {
90
+ void runExitWatcher(process.argv.slice(2)).then(code => process.exit(code), error => {
91
+ process.stderr.write(`a1 exit watcher: ${error instanceof Error ? error.message : String(error)}\n`);
92
+ process.exit(2);
93
+ });
94
+ }
@@ -1,6 +1,6 @@
1
1
  import type { LaunchInstanceStopIntent, LaunchProfileId, SupervisorCommand } from "../lifecycle/index.js";
2
2
  import { type SessionSelection } from "../lifecycle/index.js";
3
- import { type NativeProcessInspector, type ProcessContainment } from "../process-containment/index.js";
3
+ import { type NativeProcessInspector, type ProcessContainment, type ProcessGuardianAddon } from "../process-containment/index.js";
4
4
  interface GuardianControl {
5
5
  connect(endpoint: string, timeoutMs?: number): Promise<unknown>;
6
6
  command(command: SupervisorCommand): Promise<{
@@ -16,17 +16,23 @@ interface GuardianControl {
16
16
  off(event: "disconnect", listener: () => void): unknown;
17
17
  close(): void;
18
18
  }
19
+ export interface LaunchGuardianRootCommand {
20
+ readonly executable: string;
21
+ readonly arguments: readonly string[];
22
+ }
19
23
  export interface LaunchGuardianOptions {
20
24
  readonly profileId: LaunchProfileId;
21
25
  readonly releaseRoot: string;
22
26
  readonly uiEntry: string;
23
27
  readonly sessionSelection?: SessionSelection;
28
+ readonly rootCommand?: LaunchGuardianRootCommand;
24
29
  readonly environment?: NodeJS.ProcessEnv;
25
30
  readonly cwd?: string;
26
31
  readonly helperPath?: string;
27
32
  readonly inspector?: NativeProcessInspector;
28
33
  readonly control?: GuardianControl;
29
34
  readonly containment?: ProcessContainment;
35
+ readonly addon?: ProcessGuardianAddon;
30
36
  readonly ensureHelper?: (path: string) => Promise<void>;
31
37
  }
32
38
  export declare function runLaunchGuardian(options: LaunchGuardianOptions): Promise<number>;
@@ -1,11 +1,14 @@
1
+ import { spawn } from "node:child_process";
1
2
  import { randomUUID } from "node:crypto";
3
+ import { fileURLToPath } from "node:url";
2
4
  import { PRODUCT_TEXT } from "../../product-identity.js";
3
5
  import { readLaunchContext } from "../launch-context/index.js";
4
6
  import { resolve } from "node:path";
5
7
  import { assertLaunchProfileId, resolveCohortEndpoint, resolveProductPaths, sessionSelectionArguments } from "../lifecycle/index.js";
6
- import { closeVerifiedContainment, DarwinNativeProcessInspector, LinuxNativeProcessInspector, NativeGuardianContainment, resolveProcessGuardianPath, verifyProcessGuardianArtifact, WindowsNativeProcessInspector, } from "../process-containment/index.js";
8
+ import { AddonContainment, AddonProcessInspector, closeVerifiedContainment, LinuxNativeProcessInspector, loadProcessGuardianAddon, resolveProcessGuardianPath, verifyProcessGuardianArtifact, } from "../process-containment/index.js";
7
9
  import { SupervisorClient } from "../protocol/index.js";
8
10
  import { markStartupPhase } from "../startup/index.js";
11
+ import { exitWatcherArguments } from "./exit-watcher.js";
9
12
  export async function runLaunchGuardian(options) {
10
13
  assertLaunchProfileId(options.profileId);
11
14
  const sessionArgs = sessionSelectionArguments(options.sessionSelection);
@@ -15,8 +18,11 @@ export async function runLaunchGuardian(options) {
15
18
  const paths = resolveProductPaths(environment);
16
19
  const instanceId = randomUUID();
17
20
  const helperPath = options.helperPath ?? resolveProcessGuardianPath(options.releaseRoot, environment);
18
- const inspector = options.inspector ?? platformInspector(helperPath);
19
21
  await (options.ensureHelper ?? verifyProcessGuardianArtifact)(helperPath);
22
+ // Rationale: tests that inject both process boundaries need no native module; every production
23
+ // path loads the exact artifact only after its manifest and digest have been verified.
24
+ const addon = options.addon ?? (options.containment && options.inspector ? null : loadProcessGuardianAddon(helperPath));
25
+ const inspector = options.inspector ?? platformInspector(requireAddon(addon));
20
26
  const guardianIdentity = await inspector.observe(process.pid);
21
27
  if (!guardianIdentity)
22
28
  throw diagnosticError("launch guardian cannot verify its own native process identity", "PROCESS_IDENTITY_UNAVAILABLE");
@@ -30,7 +36,8 @@ export async function runLaunchGuardian(options) {
30
36
  : paths.endpoint;
31
37
  await client.connect(endpoint);
32
38
  await markStartupPhase(environment, "guardian-connected");
33
- const containment = options.containment ?? new NativeGuardianContainment(instanceId, helperPath, resolve(paths.runtimeDir, "launch-instances", `${instanceId}.ready.json`), resolve(paths.runtimeDir, "launch-instances", `${instanceId}.exit-notice`));
39
+ const exitNoticePath = resolve(paths.runtimeDir, "launch-instances", `${instanceId}.exit-notice`);
40
+ const containment = options.containment ?? new AddonContainment(instanceId, helperPath, exitNoticePath, requireAddon(addon));
34
41
  const stop = stopRequests(client, instanceId);
35
42
  let rootIdentity = null;
36
43
  try {
@@ -43,13 +50,26 @@ export async function runLaunchGuardian(options) {
43
50
  guardianIdentity,
44
51
  });
45
52
  let handle;
53
+ let encodedModes = null;
46
54
  try {
47
- handle = await containment.spawn(process.execPath, [options.uiEntry, ...sessionArgs], {
55
+ const rootCommand = options.rootCommand ?? { executable: process.execPath, arguments: [options.uiEntry, ...sessionArgs] };
56
+ encodedModes = addon?.captureTerminalModes() ?? null;
57
+ handle = await containment.spawn(rootCommand.executable, [...rootCommand.arguments], {
48
58
  cwd: options.cwd ?? process.cwd(),
49
59
  environment: environmentEntries(environment),
50
60
  ...(environment.TERM ? { terminalType: environment.TERM } : {}),
51
61
  });
52
62
  rootIdentity = handle.identity;
63
+ if (addon && encodedModes !== null) {
64
+ await startExitWatcher(addon, {
65
+ addonPath: helperPath,
66
+ noticePath: exitNoticePath,
67
+ encodedModes,
68
+ runtimePid: handle.identity.pid,
69
+ processGroup: handle.processGroup ?? null,
70
+ foregroundGroup: handle.foregroundGroup ?? null,
71
+ });
72
+ }
53
73
  await requireAccepted(client, {
54
74
  type: "activate-launch-instance",
55
75
  requestId: randomUUID(),
@@ -88,6 +108,10 @@ export async function runLaunchGuardian(options) {
88
108
  return result.outcome;
89
109
  }),
90
110
  ]);
111
+ // Invariant: the root removes a clean notice. If it left the notice armed, the guardian claims,
112
+ // restores, and prints it before closing the native containment handle.
113
+ if (addon && encodedModes !== null)
114
+ addon.deliverExitNotice(exitNoticePath, encodedModes);
91
115
  await containment.close();
92
116
  if (outcome.kind !== "interrupted" || outcome.reason !== "supervisor-disconnect") {
93
117
  await completeBestEffort(client, instanceId, outcome.kind === "interrupted" || outcome.kind === "cleanup-error" ? "interrupted" : "completed", outcome);
@@ -103,15 +127,44 @@ export async function runLaunchGuardian(options) {
103
127
  client.close();
104
128
  }
105
129
  }
106
- function platformInspector(helperPath) {
130
+ async function startExitWatcher(addon, options) {
131
+ const entry = fileURLToPath(new URL("./exit-watcher.js", import.meta.url));
132
+ const arguments_ = [entry, ...exitWatcherArguments({
133
+ guardianPid: process.pid,
134
+ ...options,
135
+ })];
136
+ if (process.platform === "win32") {
137
+ addon.spawnWatcher({ executable: process.execPath, arguments: arguments_ });
138
+ return;
139
+ }
140
+ await new Promise((resolvePromise, rejectPromise) => {
141
+ const watcher = spawn(process.execPath, arguments_, {
142
+ stdio: "inherit",
143
+ detached: false,
144
+ windowsHide: false,
145
+ });
146
+ watcher.once("error", rejectPromise);
147
+ watcher.once("spawn", () => {
148
+ watcher.off("error", rejectPromise);
149
+ watcher.unref();
150
+ resolvePromise();
151
+ });
152
+ });
153
+ }
154
+ function platformInspector(addon) {
107
155
  if (process.platform === "win32")
108
- return new WindowsNativeProcessInspector(helperPath);
156
+ return new AddonProcessInspector(addon, "windows-filetime:");
109
157
  if (process.platform === "linux")
110
158
  return new LinuxNativeProcessInspector();
111
159
  if (process.platform === "darwin")
112
- return new DarwinNativeProcessInspector(helperPath);
160
+ return new AddonProcessInspector(addon, "darwin-proc-start:");
113
161
  throw diagnosticError(`launch-instance process containment is unsupported on ${process.platform}`, "CONTAINMENT_UNSUPPORTED");
114
162
  }
163
+ function requireAddon(addon) {
164
+ if (!addon)
165
+ throw diagnosticError("process guardian addon is unavailable", "CONTAINMENT_ARTIFACT_MISSING");
166
+ return addon;
167
+ }
115
168
  function stopRequests(client, instanceId) {
116
169
  let resolveStop;
117
170
  let settled = false;