@timurproko/a1 0.2.6 → 0.2.7-dev.1222

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 (419) 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 +197 -908
  37. package/dist/app/session-shell/session-shell.d.ts +3 -8
  38. package/dist/app/session-shell/session-shell.js +327 -835
  39. package/dist/app/session-shell/session-viewport-controller.d.ts +2 -1
  40. package/dist/app/session-shell/session-viewport-controller.js +41 -38
  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 +105 -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 +207 -153
  70. package/dist/composition/reference-selection-options.d.ts +3 -0
  71. package/dist/composition/reference-selection-options.js +16 -0
  72. package/dist/composition/resident-tab-bridge.d.ts +25 -0
  73. package/dist/composition/resident-tab-bridge.js +180 -0
  74. package/dist/composition/session-backend.d.ts +19 -0
  75. package/dist/composition/session-backend.js +1 -0
  76. package/dist/composition/session-runtime-registry.d.ts +20 -0
  77. package/dist/composition/session-runtime-registry.js +85 -0
  78. package/dist/composition/settings-route-host.d.ts +16 -2
  79. package/dist/composition/settings-route-host.js +42 -17
  80. package/dist/composition/settings-search-input.d.ts +9 -0
  81. package/dist/composition/settings-search-input.js +61 -0
  82. package/dist/composition/startup-route.d.ts +32 -0
  83. package/dist/composition/startup-route.js +72 -0
  84. package/dist/composition/utility-tab.d.ts +28 -0
  85. package/dist/composition/utility-tab.js +244 -0
  86. package/dist/contracts/owned-ui/index.d.ts +1 -1
  87. package/dist/contracts/owned-ui/model.d.ts +3 -0
  88. package/dist/contracts/owned-ui/session-backend.d.ts +3 -0
  89. package/dist/contracts/owned-ui/session-workflows.d.ts +11 -4
  90. package/dist/contracts/presentation/index.d.ts +11 -0
  91. package/dist/contracts/presentation/index.js +12 -0
  92. package/dist/features/launch/development-launch.js +6 -0
  93. package/dist/features/launch/index.d.ts +1 -1
  94. package/dist/features/launch/intent.d.ts +3 -1
  95. package/dist/features/launch/intent.js +7 -4
  96. package/dist/features/launch/profile-paths.js +4 -0
  97. package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
  98. package/dist/features/owned-ui/plus-menu-dialog.js +84 -0
  99. package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
  100. package/dist/features/owned-ui/project-trust-dialog.js +6 -8
  101. package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
  102. package/dist/features/owned-ui/project-trust-prompt.js +7 -3
  103. package/dist/features/owned-ui/reference-document-selection.d.ts +30 -0
  104. package/dist/features/owned-ui/reference-document-selection.js +179 -0
  105. package/dist/features/owned-ui/reference-screen-app.d.ts +6 -1
  106. package/dist/features/owned-ui/reference-screen-app.js +51 -10
  107. package/dist/features/owned-ui/settings-app.d.ts +13 -2
  108. package/dist/features/owned-ui/settings-app.js +136 -97
  109. package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
  110. package/dist/features/owned-ui/settings-search-input.js +1 -0
  111. package/dist/features/prompt-history/index.d.ts +1 -1
  112. package/dist/features/prompt-history/paths.d.ts +2 -1
  113. package/dist/features/prompt-history/paths.js +10 -2
  114. package/dist/features/prompt-history/service.d.ts +5 -0
  115. package/dist/features/prompt-history/service.js +1 -1
  116. package/dist/features/resident-tab/auto-name.d.ts +11 -0
  117. package/dist/features/resident-tab/auto-name.js +44 -0
  118. package/dist/features/resident-tab/index.d.ts +5 -0
  119. package/dist/features/resident-tab/index.js +7 -0
  120. package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
  121. package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
  122. package/dist/features/resident-tab/shortcut-declarations.d.ts +13 -0
  123. package/dist/features/resident-tab/shortcut-declarations.js +26 -0
  124. package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
  125. package/dist/features/resident-tab/shortcut-projection.js +64 -0
  126. package/dist/features/resident-tab/status-deriver.d.ts +10 -0
  127. package/dist/features/resident-tab/status-deriver.js +12 -0
  128. package/dist/foundation/launch-context/index.d.ts +12 -0
  129. package/dist/foundation/launch-context/index.js +26 -0
  130. package/dist/foundation/launch-guardian/exit-watcher.d.ts +14 -0
  131. package/dist/foundation/launch-guardian/exit-watcher.js +94 -0
  132. package/dist/foundation/launch-guardian/main.d.ts +7 -1
  133. package/dist/foundation/launch-guardian/main.js +60 -7
  134. package/dist/foundation/lifecycle/session-repository-context.js +16 -2
  135. package/dist/foundation/process-containment/{native-guardian-containment.d.ts → addon-containment.d.ts} +7 -5
  136. package/dist/foundation/process-containment/addon-containment.js +139 -0
  137. package/dist/foundation/process-containment/addon-process-inspector.d.ts +11 -0
  138. package/dist/foundation/process-containment/addon-process-inspector.js +36 -0
  139. package/dist/foundation/process-containment/addon.d.ts +42 -0
  140. package/dist/foundation/process-containment/addon.js +57 -0
  141. package/dist/foundation/process-containment/artifact.d.ts +1 -1
  142. package/dist/foundation/process-containment/artifact.js +6 -5
  143. package/dist/foundation/process-containment/contracts.d.ts +2 -0
  144. package/dist/foundation/process-containment/index.d.ts +4 -4
  145. package/dist/foundation/process-containment/index.js +3 -3
  146. package/dist/foundation/process-containment/native-process-inspector.d.ts +2 -1
  147. package/dist/foundation/process-containment/native-process-inspector.js +10 -10
  148. package/dist/foundation/release/automatic-update.d.ts +37 -0
  149. package/dist/foundation/release/automatic-update.js +265 -0
  150. package/dist/foundation/release/bootstrap.d.ts +7 -9
  151. package/dist/foundation/release/bootstrap.js +107 -24
  152. package/dist/foundation/release/cohort-state.d.ts +1 -1
  153. package/dist/foundation/release/cohort-state.js +1 -1
  154. package/dist/foundation/release/dependency-certification.js +54 -19
  155. package/dist/foundation/release/early-accent.d.ts +12 -0
  156. package/dist/foundation/release/early-accent.js +59 -0
  157. package/dist/foundation/release/index.d.ts +2 -2
  158. package/dist/foundation/release/index.js +2 -2
  159. package/dist/foundation/release/latest-release.d.ts +24 -2
  160. package/dist/foundation/release/latest-release.js +51 -1
  161. package/dist/foundation/release/progress-palette.generated.d.ts +137 -3
  162. package/dist/foundation/release/progress-palette.generated.js +137 -3
  163. package/dist/foundation/release/release-gc.d.ts +3 -0
  164. package/dist/foundation/release/release-gc.js +59 -8
  165. package/dist/foundation/release/release-store.d.ts +12 -0
  166. package/dist/foundation/release/release-store.js +124 -2
  167. package/dist/foundation/release/update-execution-lease.d.ts +48 -0
  168. package/dist/foundation/release/update-execution-lease.js +161 -0
  169. package/dist/foundation/release/update.d.ts +12 -7
  170. package/dist/foundation/release/update.js +281 -196
  171. package/dist/foundation/resident-tabs/bounded-host-command.d.ts +18 -0
  172. package/dist/foundation/resident-tabs/bounded-host-command.js +39 -0
  173. package/dist/foundation/resident-tabs/bridge-client.d.ts +70 -0
  174. package/dist/foundation/resident-tabs/bridge-client.js +321 -0
  175. package/dist/foundation/resident-tabs/doctor.d.ts +28 -0
  176. package/dist/foundation/resident-tabs/doctor.js +166 -0
  177. package/dist/foundation/resident-tabs/draft-checkpoint.d.ts +27 -0
  178. package/dist/foundation/resident-tabs/draft-checkpoint.js +145 -0
  179. package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +36 -0
  180. package/dist/foundation/resident-tabs/ensure-terminal-host.js +151 -0
  181. package/dist/foundation/resident-tabs/fault-injection.d.ts +8 -0
  182. package/dist/foundation/resident-tabs/fault-injection.js +26 -0
  183. package/dist/foundation/resident-tabs/fixture-control.d.ts +7 -0
  184. package/dist/foundation/resident-tabs/fixture-control.js +35 -0
  185. package/dist/foundation/resident-tabs/host-entry.d.ts +1 -0
  186. package/dist/foundation/resident-tabs/host-entry.js +17 -0
  187. package/dist/foundation/resident-tabs/index.d.ts +12 -0
  188. package/dist/foundation/resident-tabs/index.js +6 -0
  189. package/dist/foundation/resident-tabs/maintenance.d.ts +39 -0
  190. package/dist/foundation/resident-tabs/maintenance.js +75 -0
  191. package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
  192. package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
  193. package/dist/foundation/resident-tabs/progress-observation.d.ts +4 -0
  194. package/dist/foundation/resident-tabs/progress-observation.js +150 -0
  195. package/dist/foundation/resident-tabs/prompt-journal.d.ts +63 -0
  196. package/dist/foundation/resident-tabs/prompt-journal.js +213 -0
  197. package/dist/foundation/resident-tabs/protocol.d.ts +12 -0
  198. package/dist/foundation/resident-tabs/protocol.js +195 -0
  199. package/dist/foundation/resident-tabs/recovery.d.ts +26 -0
  200. package/dist/foundation/resident-tabs/recovery.js +205 -0
  201. package/dist/foundation/resident-tabs/release-holds.d.ts +28 -0
  202. package/dist/foundation/resident-tabs/release-holds.js +75 -0
  203. package/dist/foundation/resident-tabs/routes.d.ts +5 -0
  204. package/dist/foundation/resident-tabs/routes.js +5 -0
  205. package/dist/foundation/resident-tabs/routing.d.ts +11 -0
  206. package/dist/foundation/resident-tabs/routing.js +10 -0
  207. package/dist/foundation/resident-tabs/session-sync.d.ts +14 -0
  208. package/dist/foundation/resident-tabs/session-sync.js +37 -0
  209. package/dist/foundation/resident-tabs/settings.d.ts +12 -0
  210. package/dist/foundation/resident-tabs/settings.js +58 -0
  211. package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +14 -0
  212. package/dist/foundation/resident-tabs/terminal-host-artifact.js +78 -0
  213. package/dist/foundation/resident-tabs/zip-archive.d.ts +9 -0
  214. package/dist/foundation/resident-tabs/zip-archive.js +56 -0
  215. package/dist/foundation/session-writer-lock/index.d.ts +30 -0
  216. package/dist/foundation/session-writer-lock/index.js +203 -0
  217. package/dist/foundation/startup/startup-descriptor.js +2 -2
  218. package/dist/foundation/terminal-cleanup/index.d.ts +1 -1
  219. package/dist/foundation/terminal-cleanup/index.js +1 -1
  220. package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +6 -0
  221. package/dist/foundation/terminal-cleanup/terminal-reset.js +6 -0
  222. package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
  223. package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
  224. package/dist/integrations/pi/components/modal-frame.js +48 -9
  225. package/dist/integrations/pi/components/models-dialog.js +4 -52
  226. package/dist/integrations/pi/components/owned-editor-ux.d.ts +6 -1
  227. package/dist/integrations/pi/components/owned-editor-ux.js +138 -11
  228. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +4 -4
  229. package/dist/integrations/pi/components/resources/builtin-themes.js +4 -4
  230. package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -0
  231. package/dist/integrations/pi/components/share-operation-dialog.js +2 -1
  232. package/dist/integrations/pi/components/shell-editor-autocomplete.js +58 -36
  233. package/dist/integrations/pi/components/shell-extension-ui.js +79 -60
  234. package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
  235. package/dist/integrations/pi/components/shell-footer-status.js +21 -5
  236. package/dist/integrations/pi/components/shell-hotkey-sections.js +1 -1
  237. package/dist/integrations/pi/components/shell-presenters-info.d.ts +5 -2
  238. package/dist/integrations/pi/components/shell-presenters-info.js +18 -4
  239. package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
  240. package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -1
  241. package/dist/integrations/pi/components/shell-shared-facade.d.ts +12 -1
  242. package/dist/integrations/pi/components/skills-dialog.js +2 -2
  243. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
  244. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +17 -4
  245. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  246. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  247. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  248. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  249. package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
  250. package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
  251. package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
  252. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  253. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +8 -6
  254. package/dist/integrations/pi/components/upstream/components/owned-editor.js +16 -9
  255. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  256. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +4 -4
  257. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
  258. package/dist/integrations/pi/components/upstream/components/session-footer.d.ts +2 -1
  259. package/dist/integrations/pi/components/upstream/components/session-footer.js +31 -25
  260. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  261. package/dist/integrations/pi/components/upstream/components/session-selector.js +8 -7
  262. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
  263. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
  264. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +2 -2
  265. package/dist/integrations/pi/components/upstream/components/status-indicator.js +3 -3
  266. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  267. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  268. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +8 -7
  269. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +10 -9
  270. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +2 -6
  271. package/dist/integrations/pi/components/upstream/components/tool-execution.js +103 -101
  272. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +9 -9
  273. package/dist/integrations/pi/components/upstream/components/tree-selector.js +13 -21
  274. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  275. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  276. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +2 -2
  277. package/dist/integrations/pi/components/upstream/history/editor-core.js +7 -5
  278. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  279. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  280. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  281. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  282. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  283. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  284. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  285. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  286. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
  287. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  288. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +5 -0
  289. package/dist/integrations/pi/components/upstream/theme/theme.js +29 -2
  290. package/dist/integrations/pi/engine/adapter.d.ts +5 -77
  291. package/dist/integrations/pi/engine/adapter.js +95 -394
  292. package/dist/integrations/pi/engine/command-dispatch.d.ts +13 -0
  293. package/dist/integrations/pi/engine/command-dispatch.js +57 -0
  294. package/dist/integrations/pi/engine/host.js +2 -2
  295. package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
  296. package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
  297. package/dist/integrations/pi/engine/pi-settings-metadata.json +14 -2
  298. package/dist/integrations/pi/engine/ports.d.ts +56 -0
  299. package/dist/integrations/pi/engine/ports.js +93 -0
  300. package/dist/integrations/pi/engine/prompt-suggestions.d.ts +1 -0
  301. package/dist/integrations/pi/engine/prompt-suggestions.js +40 -0
  302. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  303. package/dist/integrations/pi/engine/runtime-integration.js +102 -29
  304. package/dist/integrations/pi/engine/session-runtime.d.ts +0 -6
  305. package/dist/integrations/pi/engine/session-runtime.js +13 -5
  306. package/dist/integrations/pi/engine/session-selection.d.ts +3 -0
  307. package/dist/integrations/pi/engine/session-selection.js +45 -9
  308. package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
  309. package/dist/integrations/pi/engine/settings-bridge.js +15 -0
  310. package/dist/integrations/pi/engine/settings-port.js +11 -15
  311. package/dist/integrations/pi/engine/view-state.d.ts +42 -0
  312. package/dist/integrations/pi/engine/view-state.js +126 -0
  313. package/dist/integrations/pi/engine/workflow-contexts.js +10 -1
  314. package/dist/integrations/pi/engine/workflow-runner.js +74 -5
  315. package/dist/integrations/pi/engine/workflow-support.d.ts +12 -0
  316. package/dist/integrations/pi/engine/workflow-support.js +36 -0
  317. package/dist/integrations/pi/engine/workflows.d.ts +3 -1
  318. package/dist/integrations/pi/engine/workflows.js +1 -0
  319. package/dist/integrations/pi/startup-public.js +257 -310
  320. package/dist/integrations/pi/startup-public.manifest.json +564 -440
  321. package/dist/integrations/pi/tui-runtime/adapter.d.ts +6 -0
  322. package/dist/integrations/pi/tui-runtime/adapter.js +32 -1
  323. package/dist/integrations/pi/tui-runtime/contracts.d.ts +5 -0
  324. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +12 -1
  325. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +31 -2
  326. package/dist/native/darwin-arm64/manifest.json +10 -7
  327. package/dist/native/darwin-arm64/process-guardian.node +0 -0
  328. package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +10500 -0
  329. package/dist/native/darwin-arm64/terminal-host.manifest.json +46 -0
  330. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  331. package/dist/native/darwin-x64/manifest.json +23 -0
  332. package/dist/native/darwin-x64/process-guardian.node +0 -0
  333. package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10737 -0
  334. package/dist/native/darwin-x64/terminal-host.manifest.json +46 -0
  335. package/dist/native/darwin-x64/terminal-host.node +0 -0
  336. package/dist/native/linux-x64/manifest.json +10 -7
  337. package/dist/native/linux-x64/process-guardian.node +0 -0
  338. package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +11226 -0
  339. package/dist/native/linux-x64/terminal-host.manifest.json +46 -0
  340. package/dist/native/linux-x64/terminal-host.node +0 -0
  341. package/dist/native/win32-x64/manifest.json +10 -7
  342. package/dist/native/win32-x64/process-guardian.node +0 -0
  343. package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10757 -0
  344. package/dist/native/win32-x64/terminal-host.manifest.json +46 -0
  345. package/dist/native/win32-x64/terminal-host.node +0 -0
  346. package/dist/product-identity.d.ts +3 -3
  347. package/dist/product-identity.js +4 -4
  348. package/dist/product-identity.json +16 -2
  349. package/dist/runtime-payload-inventory.json +6330 -6677
  350. package/dist/ui/apps/host.d.ts +2 -0
  351. package/dist/ui/apps/host.js +7 -1
  352. package/dist/ui/components/dialog-panel.d.ts +17 -8
  353. package/dist/ui/components/dialog-panel.js +117 -41
  354. package/dist/ui/components/index.d.ts +5 -5
  355. package/dist/ui/components/index.js +4 -4
  356. package/dist/ui/components/line-input.d.ts +4 -1
  357. package/dist/ui/components/line-input.js +3 -1
  358. package/dist/ui/components/prompt-input.d.ts +11 -8
  359. package/dist/ui/components/prompt-input.js +15 -13
  360. package/dist/ui/components/scrollbar.d.ts +1 -1
  361. package/dist/ui/components/scrollbar.js +1 -1
  362. package/dist/ui/components/selection-copy.d.ts +3 -3
  363. package/dist/ui/components/selection-copy.js +16 -1
  364. package/dist/ui/components/spans.js +2 -2
  365. package/dist/ui/components/submitted-prompt.d.ts +9 -6
  366. package/dist/ui/components/submitted-prompt.js +20 -12
  367. package/dist/ui/components/surface.js +4 -2
  368. package/dist/ui/components/text-selection.d.ts +1 -2
  369. package/dist/ui/components/text-selection.js +5 -2
  370. package/dist/ui/components/text.d.ts +3 -6
  371. package/dist/ui/components/text.js +6 -8
  372. package/dist/ui/components/transcript-viewport.d.ts +9 -2
  373. package/dist/ui/components/transcript-viewport.js +179 -58
  374. package/dist/ui/settings/declarations.d.ts +90 -16
  375. package/dist/ui/settings/declarations.js +67 -14
  376. package/dist/ui/settings/early-accent.d.ts +81 -0
  377. package/dist/ui/settings/early-accent.js +50 -0
  378. package/dist/ui/settings/index.d.ts +4 -2
  379. package/dist/ui/settings/index.js +2 -1
  380. package/dist/ui/settings/manager.d.ts +16 -3
  381. package/dist/ui/settings/manager.js +122 -33
  382. package/dist/ui/settings/migrations.d.ts +6 -0
  383. package/dist/ui/settings/migrations.js +73 -0
  384. package/dist/ui/settings/profile-document.d.ts +26 -0
  385. package/dist/ui/settings/profile-document.js +164 -0
  386. package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
  387. package/dist/ui/settings/progress-palette.generated.js +139 -0
  388. package/dist/ui/settings/sections.d.ts +4 -0
  389. package/dist/ui/settings/sections.js +9 -3
  390. package/docs/architecture/boundaries.md +24 -9
  391. package/docs/architecture/evidence/resident-tabs/linux-x64.md +37 -0
  392. package/docs/architecture/evidence/resident-tabs/macos-arm64.md +36 -0
  393. package/docs/architecture/evidence/resident-tabs/macos-x64.md +35 -0
  394. package/docs/architecture/evidence/resident-tabs/windows-x64.md +36 -0
  395. package/docs/architecture/internal-naming.md +3 -1
  396. package/docs/architecture/process-guardian-provenance.md +18 -10
  397. package/docs/architecture/project-structure.md +8 -0
  398. package/docs/architecture/resident-tabs-requirements.md +18 -0
  399. package/docs/architecture/resident-tabs.md +649 -0
  400. package/docs/architecture/response-copy-delivery.md +1 -1
  401. package/docs/architecture/terminal-host-proof-gate.md +2 -0
  402. package/docs/architecture/terminal-host-provenance.md +16 -4
  403. package/docs/architecture/tool-image-presentation.md +2 -1
  404. package/docs/architecture/toolchain.md +11 -9
  405. package/docs/ci-release-runbook.md +14 -7
  406. package/docs/features/launch-profiles.md +11 -8
  407. package/docs/features/prompt-history.md +41 -20
  408. package/docs/manual-resident-tabs-acceptance.md +51 -0
  409. package/docs/openspec-archive-automation.md +49 -22
  410. package/docs/validation.md +49 -9
  411. package/package.json +19 -6
  412. package/dist/foundation/process-containment/darwin-process-inspector.d.ts +0 -5
  413. package/dist/foundation/process-containment/darwin-process-inspector.js +0 -7
  414. package/dist/foundation/process-containment/native-guardian-containment.js +0 -152
  415. package/dist/foundation/process-containment/windows-process-inspector.d.ts +0 -19
  416. package/dist/foundation/process-containment/windows-process-inspector.js +0 -56
  417. package/dist/native/darwin-arm64/process-guardian +0 -0
  418. package/dist/native/linux-x64/process-guardian +0 -0
  419. package/dist/native/win32-x64/process-guardian.exe +0 -0
@@ -0,0 +1,39 @@
1
+ import { spawn } from "node:child_process";
2
+ /**
3
+ * Runs one terminal-host command whose report is small. An oversized report kills the command and
4
+ * reports a failed exchange; a command that outlives its deadline is killed and rejected.
5
+ */
6
+ export async function runBoundedHostCommand(command, arguments_, limits) {
7
+ return await new Promise((resolvePromise, rejectPromise) => {
8
+ const child = spawn(command.executable, [command.entry, ...arguments_], {
9
+ env: limits.environment,
10
+ windowsHide: true,
11
+ stdio: ["ignore", "pipe", "ignore"],
12
+ });
13
+ const stdout = [];
14
+ let size = 0;
15
+ let overflowed = false;
16
+ child.stdout.on("data", chunk => {
17
+ size += chunk.length;
18
+ // Security: an oversized answer is a failed exchange, never a truncated report to parse.
19
+ if (size > limits.maxStdoutBytes) {
20
+ overflowed = true;
21
+ child.kill("SIGKILL");
22
+ }
23
+ else
24
+ stdout.push(Buffer.from(chunk));
25
+ });
26
+ child.once("error", rejectPromise);
27
+ child.once("close", code => {
28
+ clearTimeout(timer);
29
+ resolvePromise(overflowed
30
+ ? { code: code === 0 || code === null ? 1 : code, stdout: "" }
31
+ : { code: code ?? 1, stdout: Buffer.concat(stdout).toString("utf8") });
32
+ });
33
+ const timer = setTimeout(() => {
34
+ child.kill("SIGKILL");
35
+ rejectPromise(new Error(`${limits.label} timed out`));
36
+ }, limits.timeoutMs);
37
+ timer.unref();
38
+ });
39
+ }
@@ -0,0 +1,70 @@
1
+ import { type ResidentTabRoute } from "./routes.js";
2
+ export type ResidentTabStatus = "starting" | "working" | "needs-input" | "done-unseen" | "done" | "aborted" | "error" | "idle" | "unresponsive" | "crashed" | "restarting" | "failed";
3
+ export { residentUtilityRoute, type ResidentTabRoute } from "./routes.js";
4
+ export interface TabBridgeCredentials {
5
+ readonly tabId: string;
6
+ readonly token: string;
7
+ readonly endpoint: string;
8
+ readonly releaseId?: string;
9
+ }
10
+ export interface TabAttachment {
11
+ readonly clientId: string;
12
+ readonly controllerRevision: number;
13
+ }
14
+ export type TabBridgeCommand = {
15
+ readonly type: "visibility";
16
+ readonly visible: boolean;
17
+ } | {
18
+ readonly type: "rename";
19
+ readonly name: string;
20
+ readonly nameSource: "default" | "user" | "auto";
21
+ } | {
22
+ readonly type: "route";
23
+ readonly route: ResidentTabRoute;
24
+ } | {
25
+ readonly type: "stop";
26
+ readonly deadlineMs: number;
27
+ };
28
+ interface BridgeTransport {
29
+ write(bytes: Uint8Array): boolean;
30
+ destroy(): void;
31
+ once(event: "connect" | "error" | "close", listener: (...args: unknown[]) => void): unknown;
32
+ on(event: "data", listener: (bytes: Buffer) => void): unknown;
33
+ }
34
+ export interface TabBridgeOptions {
35
+ readonly credentials: TabBridgeCredentials;
36
+ readonly pid?: number;
37
+ readonly startIdentity?: string;
38
+ readonly build?: string;
39
+ readonly connect?: (endpoint: string) => BridgeTransport;
40
+ readonly heartbeatIntervalMs?: number;
41
+ readonly setInterval?: (callback: () => void, milliseconds: number) => unknown;
42
+ readonly clearInterval?: (timer: unknown) => void;
43
+ }
44
+ /** Metadata-only advisory bridge. Terminal input and transcript bytes have no API here. */
45
+ export declare class TabBridgeClient {
46
+ #private;
47
+ constructor(options: TabBridgeOptions);
48
+ get tabId(): string;
49
+ get available(): boolean;
50
+ captureAttachment(): TabAttachment | null;
51
+ onCommand(listener: (command: TabBridgeCommand) => void): () => void;
52
+ start(timeoutMs?: number): Promise<boolean>;
53
+ status(state: ResidentTabStatus, degraded?: boolean, pendingRequests?: number, queuedInput?: number): void;
54
+ degraded(degraded: boolean): void;
55
+ accent(accent: string): void;
56
+ session(file: string | null, name: string | null, nameSource?: "default" | "user" | "auto"): void;
57
+ prompt(interrupted: boolean): void;
58
+ /** Publishes the effective tab shortcut assignments so the host dispatches and labels the same keys. */
59
+ shortcuts(assignments: Readonly<Record<string, string | null>>): void;
60
+ requestDetach(origin?: TabAttachment | null, timeoutMs?: number): Promise<boolean>;
61
+ requestRestart(origin?: TabAttachment | null, timeoutMs?: number): Promise<boolean>;
62
+ requestClose(origin?: TabAttachment | null, timeoutMs?: number): Promise<boolean>;
63
+ consumeControllerBoundaryInput(data: string): string;
64
+ close(): void;
65
+ /**
66
+ * Asks the server to act for the client that controls this tab, as `origin`: leave it, restart or close the tab,
67
+ * or open the tab bar's Plus Menu dialog (`configure-plus`).
68
+ */
69
+ requestAction(action: "detach" | "restart" | "close" | "configure-plus", origin?: TabAttachment | null, timeoutMs?: number): Promise<boolean>;
70
+ }
@@ -0,0 +1,321 @@
1
+ import { connect } from "node:net";
2
+ import { encodeResidentFrame, ResidentFrameDecoder } from "./protocol.js";
3
+ import { RESIDENT_TAB_ROUTES } from "./routes.js";
4
+ export { residentUtilityRoute } from "./routes.js";
5
+ const RESIDENT_TAB_ROUTE_SET = new Set(RESIDENT_TAB_ROUTES);
6
+ /** Metadata-only advisory bridge. Terminal input and transcript bytes have no API here. */
7
+ export class TabBridgeClient {
8
+ #options;
9
+ #transport = null;
10
+ #connected = false;
11
+ #available = true;
12
+ #features = new Set();
13
+ #sequence = 0;
14
+ #request = 0;
15
+ #attachment = null;
16
+ #closed = false;
17
+ #retry = null;
18
+ #latestStatus = null;
19
+ #accent = null;
20
+ #latestSession = null;
21
+ #latestShortcuts = null;
22
+ #heartbeat = null;
23
+ #pending = new Map();
24
+ #startWaiter = null;
25
+ #commandListeners = new Set();
26
+ #pendingCommands = [];
27
+ #boundaryInputRemainder = "";
28
+ constructor(options) { this.#options = options; }
29
+ get tabId() { return this.#options.credentials.tabId; }
30
+ get available() { return this.#available && this.#connected; }
31
+ captureAttachment() { return this.#attachment === null ? null : { ...this.#attachment }; }
32
+ onCommand(listener) {
33
+ this.#commandListeners.add(listener);
34
+ for (const command of this.#pendingCommands.splice(0))
35
+ listener(command);
36
+ return () => this.#commandListeners.delete(listener);
37
+ }
38
+ async start(timeoutMs = 4_000) {
39
+ if (this.#closed || this.#transport !== null)
40
+ return this.available;
41
+ const transport = (this.#options.connect ?? (endpoint => connect(endpoint)))(this.#options.credentials.endpoint);
42
+ this.#transport = transport;
43
+ const decoder = new ResidentFrameDecoder();
44
+ transport.on("data", bytes => {
45
+ try {
46
+ for (const message of decoder.push(bytes))
47
+ this.#receive(message);
48
+ }
49
+ catch {
50
+ if (this.#transport === transport)
51
+ this.#fail();
52
+ }
53
+ });
54
+ transport.once("close", () => { if (this.#transport === transport)
55
+ this.#fail(); });
56
+ transport.once("error", () => { if (this.#transport === transport)
57
+ this.#fail(); });
58
+ return await new Promise(resolvePromise => {
59
+ let settled = false;
60
+ let timer;
61
+ const finish = (value) => {
62
+ if (settled)
63
+ return;
64
+ settled = true;
65
+ if (timer !== undefined)
66
+ clearTimeout(timer);
67
+ this.#startWaiter = null;
68
+ resolvePromise(value);
69
+ };
70
+ this.#startWaiter = finish;
71
+ transport.once("connect", () => {
72
+ this.#send("hello", {
73
+ role: "bridge", generation: 1, build: this.#options.build ?? "a1", releaseId: this.#options.credentials.releaseId,
74
+ features: ["bridge-status", "bridge-detach", "bridge-heartbeat", "bridge-restart", "bridge-visibility", "bridge-rename", "bridge-route", "bridge-stop", "bridge-shortcuts", "controller-boundary", "recovery-journal"],
75
+ token: [...Buffer.from(this.#options.credentials.token, "base64")], tabId: this.#options.credentials.tabId,
76
+ pid: this.#options.pid ?? process.pid, startIdentity: this.#options.startIdentity ?? `${process.pid}:node`,
77
+ }, ++this.#request);
78
+ });
79
+ transport.once("error", () => finish(false));
80
+ timer = setTimeout(() => { this.#fail(); finish(false); }, timeoutMs);
81
+ timer.unref();
82
+ });
83
+ }
84
+ status(state, degraded = false, pendingRequests = 0, queuedInput = 0) {
85
+ this.#latestStatus = { state, degraded, accent: this.#accent, pendingRequests, queuedInput };
86
+ const recoveryState = state === "unresponsive" || state === "crashed" || state === "restarting" || state === "failed";
87
+ if (recoveryState && !this.#supports("recovery-status"))
88
+ return;
89
+ this.#send("bridge.status", {
90
+ seq: ++this.#sequence,
91
+ state,
92
+ pendingRequests: Math.max(0, Math.trunc(pendingRequests)),
93
+ queuedInput: Math.max(0, Math.trunc(queuedInput)),
94
+ ...(this.#accent === null ? {} : { accent: this.#accent }),
95
+ ...(degraded && this.#supports("recovery-status") ? { degraded: true } : {}),
96
+ });
97
+ }
98
+ degraded(degraded) {
99
+ this.status(this.#latestStatus?.state ?? "idle", degraded);
100
+ }
101
+ accent(accent) {
102
+ this.#accent = accent;
103
+ if (this.#latestStatus !== null)
104
+ this.status(this.#latestStatus.state, this.#latestStatus.degraded, this.#latestStatus.pendingRequests, this.#latestStatus.queuedInput);
105
+ }
106
+ session(file, name, nameSource = "default") {
107
+ this.#latestSession = { file, name, nameSource };
108
+ this.#send("bridge.session", { file, name, nameSource });
109
+ }
110
+ prompt(interrupted) {
111
+ this.#send("bridge.prompt", { interrupted });
112
+ }
113
+ /** Publishes the effective tab shortcut assignments so the host dispatches and labels the same keys. */
114
+ shortcuts(assignments) {
115
+ this.#latestShortcuts = Object.entries(assignments).map(([action, key]) => [action, key]);
116
+ this.#sendShortcuts();
117
+ }
118
+ #sendShortcuts() {
119
+ if (this.#latestShortcuts === null || !this.#supports("bridge-shortcuts"))
120
+ return;
121
+ this.#send("bridge.shortcuts", { assignments: this.#latestShortcuts.map(([action, key]) => [action, key]) });
122
+ }
123
+ requestDetach(origin = this.captureAttachment(), timeoutMs = 1_000) {
124
+ return this.requestAction("detach", origin, timeoutMs);
125
+ }
126
+ requestRestart(origin = this.captureAttachment(), timeoutMs = 1_000) {
127
+ return this.requestAction("restart", origin, timeoutMs);
128
+ }
129
+ requestClose(origin = this.captureAttachment(), timeoutMs = 1_000) {
130
+ return this.requestAction("close", origin, timeoutMs);
131
+ }
132
+ consumeControllerBoundaryInput(data) {
133
+ const prefix = "\x1bP+a1;controller=";
134
+ const suffix = "\x1b\\";
135
+ let pending = this.#boundaryInputRemainder + data;
136
+ this.#boundaryInputRemainder = "";
137
+ let output = "";
138
+ while (pending.length > 0) {
139
+ const start = pending.indexOf(prefix);
140
+ if (start === -1) {
141
+ let retained = 0;
142
+ const maximum = Math.min(prefix.length - 1, pending.length);
143
+ // Invariant: a lone trailing Esc is a user key and passes at once; only `\x1bP` or more is withheld.
144
+ for (let length = maximum; length > 1; length--) {
145
+ if (pending.endsWith(prefix.slice(0, length))) {
146
+ retained = length;
147
+ break;
148
+ }
149
+ }
150
+ const split = pending.length - retained;
151
+ output += pending.slice(0, split);
152
+ this.#boundaryInputRemainder = pending.slice(split);
153
+ break;
154
+ }
155
+ output += pending.slice(0, start);
156
+ const end = pending.indexOf(suffix, start + prefix.length);
157
+ if (end === -1) {
158
+ this.#boundaryInputRemainder = pending.slice(start);
159
+ break;
160
+ }
161
+ const body = pending.slice(start + prefix.length, end);
162
+ const separator = body.indexOf(";");
163
+ const generation = Number(body.slice(0, separator));
164
+ const nonceHex = body.slice(separator + 1);
165
+ if (separator > 0 && Number.isSafeInteger(generation) && generation > 0 && /^[0-9a-f]{32}$/u.test(nonceHex)) {
166
+ this.#send("bridge.boundary", {
167
+ generation,
168
+ nonce: [...Buffer.from(nonceHex, "hex")],
169
+ });
170
+ }
171
+ else {
172
+ output += pending.slice(start, end + suffix.length);
173
+ }
174
+ pending = pending.slice(end + suffix.length);
175
+ }
176
+ return output;
177
+ }
178
+ close() {
179
+ this.#closed = true;
180
+ if (this.#retry !== null)
181
+ clearTimeout(this.#retry);
182
+ this.#retry = null;
183
+ this.#stopHeartbeat();
184
+ const transport = this.#transport;
185
+ this.#transport = null;
186
+ transport?.destroy();
187
+ this.#fail(false);
188
+ }
189
+ #emitCommand(command) {
190
+ if (this.#commandListeners.size === 0) {
191
+ if (this.#pendingCommands.length >= 16)
192
+ this.#pendingCommands.shift();
193
+ this.#pendingCommands.push(command);
194
+ return;
195
+ }
196
+ for (const listener of this.#commandListeners)
197
+ listener(command);
198
+ }
199
+ #send(type, body, requestId) {
200
+ if (this.#transport === null || (!this.#connected && type !== "hello"))
201
+ return;
202
+ try {
203
+ this.#transport.write(encodeResidentFrame({ type, ...(requestId === undefined ? {} : { requestId }), body }));
204
+ }
205
+ catch {
206
+ this.#fail();
207
+ }
208
+ }
209
+ #receive(message) {
210
+ if (message.type === "welcome" && message.body["generation"] === 1) {
211
+ const id = this.#options.credentials.releaseId;
212
+ if (id !== undefined && message.body["releaseId"] !== id) {
213
+ this.#fail(false);
214
+ return;
215
+ }
216
+ const advertised = message.body["features"];
217
+ this.#features = new Set(Array.isArray(advertised) ? advertised.filter((feature) => typeof feature === "string") : []);
218
+ this.#connected = true;
219
+ this.#available = true;
220
+ this.#startWaiter?.(true);
221
+ if (this.#supports("bridge-heartbeat"))
222
+ this.#startHeartbeat();
223
+ if (this.#latestStatus !== null)
224
+ this.status(this.#latestStatus.state, this.#latestStatus.degraded, this.#latestStatus.pendingRequests, this.#latestStatus.queuedInput);
225
+ if (this.#latestSession !== null)
226
+ this.#send("bridge.session", this.#latestSession);
227
+ this.#sendShortcuts();
228
+ return;
229
+ }
230
+ if (message.type === "incompatible-generation") {
231
+ this.#fail();
232
+ return;
233
+ }
234
+ if (message.type === "bridge.visibility" && typeof message.body["visible"] === "boolean") {
235
+ this.#emitCommand({ type: "visibility", visible: message.body["visible"] });
236
+ return;
237
+ }
238
+ if (message.type === "bridge.rename" && typeof message.body["name"] === "string") {
239
+ const source = message.body["nameSource"];
240
+ this.#emitCommand({ type: "rename", name: message.body["name"], nameSource: source === "auto" || source === "default" ? source : "user" });
241
+ return;
242
+ }
243
+ if (message.type === "bridge.route" && RESIDENT_TAB_ROUTE_SET.has(message.body["route"])) {
244
+ this.#emitCommand({ type: "route", route: message.body["route"] });
245
+ return;
246
+ }
247
+ if (message.type === "bridge.stop" && typeof message.body["deadlineMs"] === "number") {
248
+ this.#emitCommand({ type: "stop", deadlineMs: message.body["deadlineMs"] });
249
+ return;
250
+ }
251
+ if (message.type === "attachment") {
252
+ const clientId = message.body["clientId"];
253
+ const revision = message.body["controllerRevision"];
254
+ if (typeof clientId === "string" && typeof revision === "number")
255
+ this.#attachment = { clientId, controllerRevision: revision };
256
+ return;
257
+ }
258
+ if ((message.type === "bridge.result" || message.type === "result") && typeof message.requestId === "number") {
259
+ const resolvePromise = this.#pending.get(message.requestId);
260
+ if (resolvePromise) {
261
+ this.#pending.delete(message.requestId);
262
+ resolvePromise(message.body["accepted"] === true);
263
+ }
264
+ }
265
+ }
266
+ /**
267
+ * Asks the server to act for the client that controls this tab, as `origin`: leave it, restart or close the tab,
268
+ * or open the tab bar's Plus Menu dialog (`configure-plus`).
269
+ */
270
+ async requestAction(action, origin = this.captureAttachment(), timeoutMs = 1_000) {
271
+ if (!this.available || origin === null || (action === "restart" && !this.#supports("bridge-restart")))
272
+ return false;
273
+ const requestId = ++this.#request;
274
+ const result = new Promise(resolvePromise => this.#pending.set(requestId, resolvePromise));
275
+ this.#send("bridge.request", { action, clientId: origin.clientId, controllerRevision: origin.controllerRevision }, requestId);
276
+ const timeout = new Promise(resolvePromise => {
277
+ const timer = setTimeout(() => { this.#pending.delete(requestId); resolvePromise(false); }, timeoutMs);
278
+ timer.unref();
279
+ });
280
+ return await Promise.race([result, timeout]);
281
+ }
282
+ #startHeartbeat() {
283
+ if (this.#heartbeat !== null)
284
+ return;
285
+ const schedule = this.#options.setInterval ?? ((callback, milliseconds) => setInterval(callback, milliseconds));
286
+ this.#heartbeat = schedule(() => this.#send("bridge.heartbeat", { seq: ++this.#sequence }), this.#options.heartbeatIntervalMs ?? 5_000);
287
+ this.#heartbeat.unref?.();
288
+ }
289
+ #stopHeartbeat() {
290
+ if (this.#heartbeat === null)
291
+ return;
292
+ (this.#options.clearInterval ?? (timer => clearInterval(timer)))(this.#heartbeat);
293
+ this.#heartbeat = null;
294
+ }
295
+ #supports(feature) {
296
+ return this.#features.has("crash-recovery") || this.#features.has(feature);
297
+ }
298
+ #fail(retry = true) {
299
+ const transport = this.#transport;
300
+ this.#stopHeartbeat();
301
+ this.#available = false;
302
+ this.#connected = false;
303
+ this.#features.clear();
304
+ this.#attachment = null;
305
+ this.#transport = null;
306
+ transport?.destroy();
307
+ this.#startWaiter?.(false);
308
+ this.#startWaiter = null;
309
+ for (const resolvePromise of this.#pending.values())
310
+ resolvePromise(false);
311
+ this.#pending.clear();
312
+ if (retry && !this.#closed && this.#retry === null) {
313
+ this.#retry = setTimeout(() => {
314
+ this.#retry = null;
315
+ void this.start().then(connected => { if (!connected)
316
+ this.#fail(); });
317
+ }, 250);
318
+ this.#retry.unref();
319
+ }
320
+ }
321
+ }
@@ -0,0 +1,28 @@
1
+ import type { MaintenanceReport } from "./maintenance.js";
2
+ export declare const DOCTOR_MAX_BYTES: number;
3
+ export interface DoctorOptions {
4
+ /** The profile's resident state directory, as reported by the terminal host. */
5
+ readonly stateDir: string;
6
+ readonly hostStatus: MaintenanceReport;
7
+ readonly releaseRoots: readonly string[];
8
+ readonly settings: {
9
+ readonly tabsAutoName: boolean;
10
+ };
11
+ readonly home?: string;
12
+ readonly platform?: NodeJS.Platform;
13
+ readonly architecture?: string;
14
+ readonly now?: Date;
15
+ readonly maxBytes?: number;
16
+ }
17
+ export interface DoctorBundle {
18
+ readonly path: string;
19
+ readonly bytes: number;
20
+ readonly dropped: readonly string[];
21
+ }
22
+ /**
23
+ * Writes an owner-only diagnostic bundle by allowlist: structured logs, crash records, host
24
+ * status, a redacted registry, the owner marker without secrets, artifact verification, platform
25
+ * facts, and the Tabs settings. Secrets, tokens, environment values, prompt journals, drafts,
26
+ * last screens, the private child-stderr sink, and terminal content are never read.
27
+ */
28
+ export declare function writeDoctorBundle(options: DoctorOptions): Promise<DoctorBundle>;
@@ -0,0 +1,166 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
3
+ import { homedir, release as osRelease } from "node:os";
4
+ import { basename, dirname, resolve, sep } from "node:path";
5
+ import { resolveTerminalHostPath } from "./ensure-terminal-host.js";
6
+ import { TERMINAL_HOST_MANIFEST_FILENAME, verifyTerminalHostArtifact } from "./terminal-host-artifact.js";
7
+ import { encodeZip } from "./zip-archive.js";
8
+ export const DOCTOR_MAX_BYTES = 25 * 1024 * 1024;
9
+ const LOG_NAME = /^terminal-host-[a-z0-9-]+\.log(?:\.(\d{1,2}))?$/u;
10
+ const CRASH_NAME = /^crash-[a-z0-9-]+\.json$/u;
11
+ /**
12
+ * Writes an owner-only diagnostic bundle by allowlist: structured logs, crash records, host
13
+ * status, a redacted registry, the owner marker without secrets, artifact verification, platform
14
+ * facts, and the Tabs settings. Secrets, tokens, environment values, prompt journals, drafts,
15
+ * last screens, the private child-stderr sink, and terminal content are never read.
16
+ */
17
+ export async function writeDoctorBundle(options) {
18
+ const home = options.home ?? homedir();
19
+ const redact = (value) => homeRelative(value, home);
20
+ const now = options.now ?? new Date();
21
+ const maxBytes = options.maxBytes ?? DOCTOR_MAX_BYTES;
22
+ const diagnostics = resolve(options.stateDir, "diagnostics");
23
+ const names = await readdir(diagnostics).catch(() => []);
24
+ const fixed = [
25
+ json("host-status.json", redactHostStatus(options.hostStatus, redact)),
26
+ json("registry.json", await redactedRegistry(resolve(options.stateDir, "registry.json"), redact)),
27
+ json("server-marker.json", await redactedMarker(resolve(options.stateDir, "server.json"), redact)),
28
+ json("artifacts.json", await artifactFacts(options.releaseRoots, options.platform ?? process.platform, options.architecture ?? process.arch, redact)),
29
+ json("platform.json", {
30
+ platform: options.platform ?? process.platform,
31
+ architecture: options.architecture ?? process.arch,
32
+ osRelease: osRelease(),
33
+ node: process.version,
34
+ detachmentMode: options.hostStatus.result?.detachmentMode ?? null,
35
+ }),
36
+ json("settings.json", { tabsAutoName: options.settings.tabsAutoName }),
37
+ ];
38
+ const crashes = [];
39
+ for (const name of names.filter(name => CRASH_NAME.test(name)).sort()) {
40
+ crashes.push({ name: `crashes/${name}`, data: await readFile(resolve(diagnostics, name)) });
41
+ }
42
+ // Rationale: when the bundle would exceed its cap, the oldest log generations go first.
43
+ const logs = names
44
+ .filter(name => LOG_NAME.test(name))
45
+ .map(name => ({ name, generation: Number(LOG_NAME.exec(name)?.[1] ?? 0) }))
46
+ .sort((left, right) => left.generation - right.generation || left.name.localeCompare(right.name));
47
+ const dropped = [];
48
+ const included = [...fixed, ...crashes];
49
+ let budget = maxBytes - 64 * 1024 - included.reduce((total, entry) => total + entry.data.length, 0);
50
+ for (const log of logs) {
51
+ const size = (await stat(resolve(diagnostics, log.name))).size;
52
+ if (size > budget) {
53
+ dropped.push(log.name);
54
+ continue;
55
+ }
56
+ budget -= size;
57
+ included.push({ name: `logs/${log.name}`, data: await readFile(resolve(diagnostics, log.name)) });
58
+ }
59
+ const manifest = [
60
+ "a1 tabs doctor bundle",
61
+ `created: ${now.toISOString()}`,
62
+ ...included.map(entry => `included: ${entry.name}`),
63
+ ...dropped.map(name => `dropped to stay within ${maxBytes} bytes: logs/${name}`),
64
+ "",
65
+ ].join("\n");
66
+ const archive = encodeZip([{ name: "manifest.txt", data: Buffer.from(manifest, "utf8") }, ...included], now);
67
+ const directory = resolve(options.stateDir, "doctor");
68
+ await mkdir(directory, { recursive: true, mode: 0o700 });
69
+ const path = resolve(directory, `a1-tabs-doctor-${now.toISOString().replace(/[:.]/gu, "-")}.zip`);
70
+ await writeFile(path, archive, { mode: 0o600, flag: "wx" });
71
+ return { path, bytes: archive.length, dropped };
72
+ }
73
+ function json(name, value) {
74
+ return { name, data: Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8") };
75
+ }
76
+ function stableHash(value) {
77
+ return createHash("sha256").update(value).digest("hex").slice(0, 16);
78
+ }
79
+ function homeRelative(value, home) {
80
+ const normalized = resolve(value);
81
+ const root = resolve(home);
82
+ const comparable = (path) => process.platform === "win32" ? path.toLowerCase() : path;
83
+ if (comparable(normalized) === comparable(root))
84
+ return "~";
85
+ return comparable(normalized).startsWith(comparable(`${root}${sep}`)) ? `~${normalized.slice(root.length).replaceAll("\\", "/")}` : normalized;
86
+ }
87
+ function redactHostStatus(report, redact) {
88
+ const result = report.result ? { ...report.result } : undefined;
89
+ if (result && Array.isArray(result.logs))
90
+ result.logs = result.logs.map(path => typeof path === "string" ? basename(path) : null);
91
+ if (result && typeof result.release === "string")
92
+ result.release = redact(result.release);
93
+ return {
94
+ host: report.host,
95
+ pid: report.pid ?? null,
96
+ exitCode: report.exitCode,
97
+ result: result ?? null,
98
+ };
99
+ }
100
+ async function redactedRegistry(path, redact) {
101
+ let document;
102
+ try {
103
+ document = JSON.parse(await readFile(path, "utf8"));
104
+ }
105
+ catch (error) {
106
+ return { readable: false, reason: error instanceof Error && "code" in error ? String(error.code) : "unparseable" };
107
+ }
108
+ const tabs = Array.isArray(document.tabs) ? document.tabs : [];
109
+ const text = (value) => typeof value === "string" ? value : null;
110
+ return {
111
+ readable: true,
112
+ registryRevision: document.registryRevision ?? null,
113
+ epoch: document.epoch ?? null,
114
+ tabs: tabs.map(tab => {
115
+ const sessionFile = text(tab.sessionFile);
116
+ return {
117
+ tabId: text(tab.tabId),
118
+ // Security: names can be generated from prompts, so only a stable hash is kept.
119
+ nameHash: text(tab.displayName) === null ? null : stableHash(text(tab.displayName)),
120
+ nameSource: text(tab.nameSource),
121
+ order: tab.order ?? null,
122
+ cwd: text(tab.cwd) === null ? null : redact(text(tab.cwd)),
123
+ sessionDirectory: sessionFile === null ? null : redact(dirname(sessionFile)),
124
+ sessionFileHash: sessionFile === null ? null : stableHash(basename(sessionFile)),
125
+ desired: text(tab.desired),
126
+ lifecycle: text(tab.lifecycle),
127
+ incarnation: tab.incarnation ?? null,
128
+ holderPid: tab.holderPid ?? null,
129
+ childPid: tab.childPid ?? null,
130
+ release: text(tab.release) === null ? null : redact(text(tab.release)),
131
+ lastExit: text(tab.lastExit),
132
+ restarts: tab.restarts ?? null,
133
+ };
134
+ }),
135
+ };
136
+ }
137
+ async function redactedMarker(path, redact) {
138
+ try {
139
+ const marker = JSON.parse(await readFile(path, "utf8"));
140
+ return {
141
+ present: true,
142
+ pid: marker.pid ?? null,
143
+ generation: marker.generation ?? null,
144
+ verified: marker.verified ?? null,
145
+ detachmentMode: marker.detachmentMode ?? null,
146
+ releaseRoot: typeof marker.releaseRoot === "string" ? redact(marker.releaseRoot) : null,
147
+ };
148
+ }
149
+ catch {
150
+ return { present: false };
151
+ }
152
+ }
153
+ async function artifactFacts(roots, platform, architecture, redact) {
154
+ const facts = [];
155
+ for (const root of roots) {
156
+ const addon = resolveTerminalHostPath(root, {}, platform, architecture);
157
+ const manifest = await readFile(resolve(dirname(addon), TERMINAL_HOST_MANIFEST_FILENAME), "utf8")
158
+ .then(text => JSON.parse(text))
159
+ .catch(() => null);
160
+ const verification = await verifyTerminalHostArtifact(addon, platform, architecture)
161
+ .then(() => "verified")
162
+ .catch((error) => error instanceof Error && "code" in error ? String(error.code) : "failed");
163
+ facts.push({ releaseRoot: redact(root), verification, manifest });
164
+ }
165
+ return facts;
166
+ }
@@ -0,0 +1,27 @@
1
+ import { ResidentTabFaultInjection } from "./fault-injection.js";
2
+ export interface DraftCheckpointState {
3
+ readonly text: string;
4
+ readonly savedAt: string;
5
+ }
6
+ export interface DraftCheckpointOptions {
7
+ readonly intervalMs?: number;
8
+ readonly maximumDirtyMs?: number;
9
+ readonly faults?: ResidentTabFaultInjection;
10
+ readonly now?: () => number;
11
+ readonly onDegraded?: (degraded: boolean) => void;
12
+ readonly write?: (path: string, text: string) => Promise<void>;
13
+ readonly move?: (from: string, to: string) => Promise<void>;
14
+ readonly schedule?: (callback: () => void | Promise<void>, delayMs: number) => unknown;
15
+ readonly cancel?: (timer: unknown) => void;
16
+ }
17
+ /** Periodic rather than inactivity-debounced: continuous input still checkpoints every interval. */
18
+ export declare class DraftCheckpointer {
19
+ #private;
20
+ readonly path: string;
21
+ constructor(path: string, options?: DraftCheckpointOptions);
22
+ get degraded(): boolean;
23
+ change(text: string): void;
24
+ restore(): Promise<DraftCheckpointState | null>;
25
+ flush(): Promise<void>;
26
+ close(): Promise<void>;
27
+ }