@timurproko/a1 0.1.8-dev.472 → 0.1.8-dev.508

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 (370) hide show
  1. package/bin/cli.js +4 -5
  2. package/bin/guardian.js +5 -1
  3. package/bin/module-identity.js +53 -98
  4. package/bin/module-resolver.js +138 -0
  5. package/bin/pinned-pi-public.js +25 -6
  6. package/bin/ui.js +7 -2
  7. package/bin/update-recovery.js +76 -7
  8. package/bin/warmup.js +3 -0
  9. package/dist/{integrations/pi/session-ui → app/session-shell}/clipboard-diagnostics.d.ts +1 -1
  10. package/dist/{integrations/pi/session-ui → app/session-shell}/clipboard-image.js +1 -1
  11. package/dist/app/session-shell/helper-pool.d.ts +33 -0
  12. package/dist/app/session-shell/helper-pool.js +98 -0
  13. package/dist/{integrations/pi/session-ui → app/session-shell}/image-preparation-client.d.ts +1 -1
  14. package/dist/{integrations/pi/session-ui → app/session-shell}/image-preparation-client.js +1 -1
  15. package/dist/{integrations/pi/session-ui → app/session-shell}/image-preparation.js +1 -1
  16. package/dist/{integrations/pi/session-ui → app/session-shell}/image-source.js +1 -1
  17. package/dist/{integrations/pi/session-ui → app/session-shell}/image-worker.js +1 -1
  18. package/dist/app/session-shell/index.d.ts +7 -0
  19. package/dist/app/session-shell/index.js +4 -0
  20. package/dist/app/session-shell/paste-executor.d.ts +18 -0
  21. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-executor.js +50 -29
  22. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-helper.js +1 -1
  23. package/dist/app/session-shell/paste-preparation-client.d.ts +31 -0
  24. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-preparation-client.js +19 -8
  25. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-protocol.d.ts +1 -1
  26. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-protocol.js +1 -1
  27. package/dist/app/session-shell/paste-text-preparation.d.ts +6 -0
  28. package/dist/{integrations/pi/session-ui/paste-text-preparation.d.ts → app/session-shell/paste-types.d.ts} +1 -4
  29. package/dist/{integrations/pi/session-ui → app/session-shell}/path-chip-presentation.d.ts +1 -1
  30. package/dist/{integrations/pi/session-ui → app/session-shell}/prompt-chips.d.ts +5 -1
  31. package/dist/{integrations/pi/session-ui → app/session-shell}/prompt-chips.js +6 -2
  32. package/dist/{integrations/pi/session-ui → app/session-shell}/prompt-history-controller.d.ts +2 -2
  33. package/dist/{integrations/pi/session-ui → app/session-shell}/prompt-history-controller.js +2 -2
  34. package/dist/{integrations/pi/session-ui → app/session-shell}/prompt-suggestion-controller.d.ts +1 -1
  35. package/dist/{integrations/pi/session-ui → app/session-shell}/prompt-suggestion-controller.js +2 -2
  36. package/dist/{integrations/pi/session-ui → app/session-shell}/quit-outro.js +1 -1
  37. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-coordinator.d.ts +1 -1
  38. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-coordinator.js +3 -5
  39. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-helper.js +1 -1
  40. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-protocol.d.ts +1 -1
  41. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-transport.d.ts +10 -2
  42. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-transport.js +45 -19
  43. package/dist/{integrations/pi/session-ui → app/session-shell}/session-shell-root.d.ts +75 -53
  44. package/dist/{integrations/pi/session-ui → app/session-shell}/session-shell-root.js +30 -20
  45. package/dist/{integrations/pi/session-ui → app/session-shell}/session-shell.d.ts +9 -8
  46. package/dist/{integrations/pi/session-ui → app/session-shell}/session-shell.js +108 -67
  47. package/dist/{integrations/pi/session-ui → app/session-shell}/session-viewport-controller.d.ts +5 -5
  48. package/dist/{integrations/pi/session-ui → app/session-shell}/session-viewport-controller.js +5 -5
  49. package/dist/{integrations/pi/session-ui → app/session-shell}/system-clipboard.d.ts +1 -1
  50. package/dist/{integrations/pi/session-ui → app/session-shell}/system-clipboard.js +1 -1
  51. package/dist/cli/index.d.ts +8 -5
  52. package/dist/cli/index.js +4 -5
  53. package/dist/composition/index.d.ts +0 -1
  54. package/dist/composition/index.js +0 -1
  55. package/dist/composition/owned-ui.d.ts +2 -2
  56. package/dist/composition/owned-ui.js +35 -36
  57. package/dist/composition/settings-route-host.d.ts +2 -2
  58. package/dist/contracts/agent-engine/domain.d.ts +6 -1
  59. package/dist/contracts/agent-engine/index.d.ts +11 -8
  60. package/dist/contracts/agent-engine/index.js +6 -8
  61. package/dist/contracts/owned-ui/extension-ui.d.ts +8 -0
  62. package/dist/contracts/owned-ui/index.d.ts +12 -8
  63. package/dist/contracts/owned-ui/index.js +8 -8
  64. package/dist/features/launch/index.d.ts +12 -6
  65. package/dist/features/launch/index.js +6 -6
  66. package/dist/features/launch/intent.d.ts +5 -5
  67. package/dist/features/launch/intent.js +2 -2
  68. package/dist/features/owned-ui/index.d.ts +6 -6
  69. package/dist/features/owned-ui/index.js +4 -6
  70. package/dist/features/owned-ui/run.d.ts +2 -2
  71. package/dist/features/owned-ui/settings-app.d.ts +2 -2
  72. package/dist/features/owned-ui/settings-app.js +18 -5
  73. package/dist/features/prompt-history/service.d.ts +1 -1
  74. package/dist/features/prompt-history/service.js +1 -1
  75. package/dist/features/prompt-history/store.js +3 -7
  76. package/dist/features/prompt-suggestions/diagnostics.js +1 -1
  77. package/dist/features/prompt-suggestions/index.d.ts +2 -1
  78. package/dist/features/prompt-suggestions/index.js +1 -1
  79. package/dist/foundation/launch-guardian/index.d.ts +2 -1
  80. package/dist/foundation/launch-guardian/index.js +1 -1
  81. package/dist/foundation/lifecycle/index.d.ts +11 -6
  82. package/dist/foundation/lifecycle/index.js +5 -6
  83. package/dist/foundation/process-containment/index.d.ts +8 -6
  84. package/dist/foundation/process-containment/index.js +6 -6
  85. package/dist/foundation/process-containment/native-guardian-containment.js +3 -3
  86. package/dist/foundation/protocol/index.d.ts +3 -2
  87. package/dist/foundation/protocol/index.js +2 -2
  88. package/dist/foundation/release/bootstrap.d.ts +0 -4
  89. package/dist/foundation/release/bootstrap.js +1 -82
  90. package/dist/foundation/release/dependency-layer.d.ts +2 -5
  91. package/dist/foundation/release/endpoints.d.ts +4 -0
  92. package/dist/foundation/release/endpoints.js +86 -2
  93. package/dist/foundation/release/index.d.ts +30 -16
  94. package/dist/foundation/release/index.js +16 -16
  95. package/dist/foundation/release/release.d.ts +1 -1
  96. package/dist/foundation/release/types.d.ts +11 -0
  97. package/dist/foundation/release/types.js +1 -0
  98. package/dist/foundation/release/update-transaction.d.ts +1 -1
  99. package/dist/foundation/release/update.d.ts +2 -1
  100. package/dist/foundation/release/update.js +3 -18
  101. package/dist/foundation/startup/index.d.ts +4 -2
  102. package/dist/foundation/startup/index.js +2 -2
  103. package/dist/foundation/startup/startup-descriptor.js +2 -2
  104. package/dist/foundation/storage/control-store.d.ts +1 -45
  105. package/dist/foundation/storage/control-store.js +54 -277
  106. package/dist/foundation/storage/index.d.ts +1 -1
  107. package/dist/foundation/storage/index.js +1 -1
  108. package/dist/foundation/supervision/index.d.ts +2 -2
  109. package/dist/foundation/supervision/index.js +2 -2
  110. package/dist/foundation/supervision/server.d.ts +5 -10
  111. package/dist/foundation/supervision/server.js +7 -7
  112. package/dist/foundation/terminal-cleanup/index.d.ts +3 -2
  113. package/dist/foundation/terminal-cleanup/index.js +2 -2
  114. package/dist/integrations/pi/components/editor-interaction.d.ts +1 -1
  115. package/dist/integrations/pi/components/history-editor-loader.d.ts +1 -1
  116. package/dist/integrations/pi/components/index.d.ts +20 -13
  117. package/dist/integrations/pi/components/index.js +12 -13
  118. package/dist/integrations/pi/components/owned-editor-ux.js +5 -8
  119. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +7 -5
  120. package/dist/integrations/pi/components/resources/builtin-themes.js +7 -5
  121. package/dist/integrations/pi/components/shell-editor-autocomplete.js +1 -1
  122. package/dist/integrations/pi/components/shell-extension-ui.js +2 -1
  123. package/dist/integrations/pi/components/shell-footer-status.js +1 -1
  124. package/dist/integrations/pi/components/shell-presenters-info.d.ts +1 -1
  125. package/dist/integrations/pi/components/shell-presenters-info.js +1 -1
  126. package/dist/integrations/pi/components/shell-presenters-transcript.js +1 -1
  127. package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +9 -3
  128. package/dist/integrations/pi/components/shell-selectors-dialogs.js +9 -6
  129. package/dist/integrations/pi/components/shell-shared-facade.d.ts +3 -1
  130. package/dist/integrations/pi/components/shell-shared-facade.js +4 -2
  131. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +1 -1
  132. package/dist/integrations/pi/components/submitted-prompt-adapter.js +1 -1
  133. package/dist/integrations/pi/components/tool-image-presentation.d.ts +1 -1
  134. package/dist/integrations/pi/components/tool-image-presentation.js +4 -7
  135. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +36 -22
  136. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +43 -7
  137. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  138. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +6 -3
  139. package/dist/integrations/pi/components/upstream/components/daxnuts.d.ts +8 -1
  140. package/dist/integrations/pi/components/upstream/components/daxnuts.js +7 -3
  141. package/dist/integrations/pi/components/upstream/components/earendil-announcement.d.ts +1 -1
  142. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +10 -4
  143. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +7 -4
  144. package/dist/integrations/pi/components/upstream/components/extension-editor.js +7 -4
  145. package/dist/integrations/pi/components/upstream/components/mermaid.js +8 -4
  146. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +9 -5
  147. package/dist/integrations/pi/components/upstream/components/owned-editor.js +10 -6
  148. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +8 -4
  149. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +27 -25
  150. package/dist/integrations/pi/components/upstream/components/session-footer.d.ts +1 -1
  151. package/dist/integrations/pi/components/upstream/components/session-footer.js +8 -10
  152. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +6 -4
  153. package/dist/integrations/pi/components/upstream/components/session-selector.d.ts +1 -1
  154. package/dist/integrations/pi/components/upstream/components/session-selector.js +8 -4
  155. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +7 -5
  156. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +8 -6
  157. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +9 -4
  158. package/dist/integrations/pi/components/upstream/components/status-indicator.js +15 -5
  159. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +8 -2
  160. package/dist/integrations/pi/components/upstream/components/tool-execution.js +58 -37
  161. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +7 -4
  162. package/dist/integrations/pi/components/upstream/components/tree-selector.js +7 -4
  163. package/dist/integrations/pi/components/upstream/components/trust-selector.d.ts +1 -1
  164. package/dist/integrations/pi/components/upstream/components/trust-selector.js +10 -5
  165. package/dist/integrations/pi/components/upstream/external-editor.js +8 -4
  166. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +13 -4
  167. package/dist/integrations/pi/components/upstream/history/editor-core.js +112 -30
  168. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +6 -3
  169. package/dist/integrations/pi/components/upstream/history/kill-ring.js +6 -3
  170. package/dist/integrations/pi/components/upstream/history/printable-key.js +7 -4
  171. package/dist/integrations/pi/components/upstream/history/text-helpers.js +6 -3
  172. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +6 -3
  173. package/dist/integrations/pi/components/upstream/history/undo-stack.js +6 -3
  174. package/dist/integrations/pi/components/upstream/history/word-navigation.js +6 -3
  175. package/dist/integrations/pi/components/upstream/model-search.d.ts +5 -2
  176. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +8 -0
  177. package/dist/integrations/pi/components/upstream/theme/theme-controller.js +0 -3
  178. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +2 -2
  179. package/dist/integrations/pi/components/upstream/theme/theme.js +17 -6
  180. package/dist/integrations/pi/engine/adapter.d.ts +39 -138
  181. package/dist/integrations/pi/engine/adapter.js +338 -3226
  182. package/dist/integrations/pi/engine/command-dispatch.d.ts +41 -0
  183. package/dist/integrations/pi/engine/command-dispatch.js +125 -0
  184. package/dist/integrations/pi/engine/event-delivery.d.ts +100 -0
  185. package/dist/integrations/pi/engine/event-delivery.js +184 -0
  186. package/dist/integrations/pi/engine/extension-ui-binding.d.ts +35 -0
  187. package/dist/integrations/pi/engine/extension-ui-binding.js +81 -0
  188. package/dist/integrations/pi/engine/index.d.ts +18 -14
  189. package/dist/integrations/pi/engine/index.js +10 -14
  190. package/dist/integrations/pi/engine/message-values.d.ts +29 -0
  191. package/dist/integrations/pi/engine/message-values.js +168 -0
  192. package/dist/integrations/pi/engine/pending-delivery.d.ts +2 -2
  193. package/dist/integrations/pi/engine/pending-delivery.js +2 -4
  194. package/dist/integrations/pi/engine/pi-settings-metadata.json +382 -371
  195. package/dist/integrations/pi/engine/prompt-suggestions.d.ts +30 -0
  196. package/dist/integrations/pi/engine/prompt-suggestions.js +102 -0
  197. package/dist/integrations/pi/engine/provider-authentication.d.ts +34 -0
  198. package/dist/integrations/pi/engine/provider-authentication.js +209 -0
  199. package/dist/integrations/pi/engine/resource-catalog.d.ts +49 -0
  200. package/dist/integrations/pi/engine/resource-catalog.js +289 -0
  201. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  202. package/dist/integrations/pi/engine/session-events.d.ts +48 -0
  203. package/dist/integrations/pi/engine/session-events.js +223 -0
  204. package/dist/integrations/pi/engine/session-integration.js +2 -4
  205. package/dist/integrations/pi/engine/session-runtime.d.ts +84 -0
  206. package/dist/integrations/pi/engine/session-runtime.js +249 -0
  207. package/dist/integrations/pi/engine/{settings-effects.d.ts → settings-bridge.d.ts} +57 -2
  208. package/dist/integrations/pi/engine/settings-bridge.js +514 -0
  209. package/dist/integrations/pi/engine/settings-metadata.d.ts +31 -0
  210. package/dist/integrations/pi/engine/settings-metadata.js +67 -0
  211. package/dist/integrations/pi/engine/settings-port.d.ts +42 -0
  212. package/dist/integrations/pi/engine/settings-port.js +353 -0
  213. package/dist/integrations/pi/engine/transcript-projection.d.ts +39 -0
  214. package/dist/integrations/pi/engine/transcript-projection.js +405 -0
  215. package/dist/integrations/pi/engine/usage-view.d.ts +4 -0
  216. package/dist/integrations/pi/engine/usage-view.js +56 -0
  217. package/dist/integrations/pi/engine/workflow-contexts.d.ts +59 -0
  218. package/dist/integrations/pi/engine/workflow-contexts.js +316 -0
  219. package/dist/integrations/pi/engine/workflow-runner.d.ts +60 -0
  220. package/dist/integrations/pi/engine/workflow-runner.js +509 -0
  221. package/dist/integrations/pi/engine/workflow-support.d.ts +33 -0
  222. package/dist/integrations/pi/engine/workflow-support.js +352 -0
  223. package/dist/integrations/pi/engine/workflows.d.ts +63 -2
  224. package/dist/integrations/pi/engine/workflows.js +5 -2
  225. package/dist/integrations/pi/startup-public.js +576 -554
  226. package/dist/integrations/pi/startup-public.manifest.json +1730 -984
  227. package/dist/integrations/pi/tui-runtime/adapter.js +10 -13
  228. package/dist/integrations/pi/tui-runtime/contracts.d.ts +11 -1
  229. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
  230. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +4 -7
  231. package/dist/integrations/pi/tui-runtime/index.d.ts +8 -6
  232. package/dist/integrations/pi/tui-runtime/index.js +4 -6
  233. package/dist/integrations/pi/tui-runtime/mouse-report-input.js +2 -4
  234. package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +2 -2
  235. package/dist/integrations/pi/tui-runtime/overlay-geometry.js +4 -5
  236. package/dist/integrations/pi/tui-runtime/presentation-adapter.js +1 -1
  237. package/dist/native/darwin-arm64/manifest.json +1 -1
  238. package/dist/native/linux-x64/manifest.json +1 -1
  239. package/dist/native/win32-x64/manifest.json +2 -2
  240. package/dist/native/win32-x64/process-guardian.exe +0 -0
  241. package/dist/runtime-payload-inventory.json +51320 -46509
  242. package/dist/ui/apps/index.d.ts +5 -3
  243. package/dist/ui/apps/index.js +3 -3
  244. package/dist/ui/components/index.d.ts +47 -25
  245. package/dist/ui/components/index.js +25 -25
  246. package/dist/ui/components/prompt-input.js +1 -4
  247. package/dist/ui/settings/declarations.d.ts +119 -0
  248. package/dist/ui/settings/declarations.js +20 -11
  249. package/dist/ui/settings/index.d.ts +10 -6
  250. package/dist/ui/settings/index.js +5 -6
  251. package/dist/ui/settings/manager.d.ts +54 -0
  252. package/dist/ui/settings/{session.js → manager.js} +101 -9
  253. package/dist/ui/settings/sections.d.ts +2 -7
  254. package/docs/architecture/boundaries.md +4 -4
  255. package/docs/architecture/history-editor-provenance.md +1 -1
  256. package/docs/architecture/project-structure.md +6 -6
  257. package/docs/architecture/prompt-suggestions.md +1 -1
  258. package/docs/architecture/terminal-host-proof-gate.md +1 -1
  259. package/docs/architecture/terminal-host-spike-evidence.md +1 -1
  260. package/docs/architecture/toolchain.md +8 -0
  261. package/docs/architecture/ui-reference-provenance.md +4 -4
  262. package/docs/ci-release-runbook.md +7 -1
  263. package/docs/features/modal-content-interaction.md +2 -2
  264. package/docs/local-worktree-cleanup.md +4 -2
  265. package/docs/validation.md +6 -4
  266. package/package.json +7 -11
  267. package/bin/pi-tui.d.ts +0 -6
  268. package/bin/pi-tui.js +0 -28
  269. package/bin/sync-pi-tui-proxy.js +0 -97
  270. package/dist/cli/version.d.ts +0 -2
  271. package/dist/cli/version.js +0 -23
  272. package/dist/composition/agent-engine-bridge.d.ts +0 -3
  273. package/dist/composition/agent-engine-bridge.js +0 -108
  274. package/dist/composition/process.d.ts +0 -16
  275. package/dist/composition/process.js +0 -45
  276. package/dist/contracts/workspace/index.d.ts +0 -2
  277. package/dist/contracts/workspace/index.js +0 -2
  278. package/dist/contracts/workspace/model.d.ts +0 -248
  279. package/dist/contracts/workspace/model.js +0 -2
  280. package/dist/contracts/workspace/validation.d.ts +0 -13
  281. package/dist/contracts/workspace/validation.js +0 -335
  282. package/dist/features/owned-ui/customization.d.ts +0 -40
  283. package/dist/features/owned-ui/customization.js +0 -110
  284. package/dist/features/owned-ui/diagnostics.d.ts +0 -34
  285. package/dist/features/owned-ui/diagnostics.js +0 -95
  286. package/dist/features/workspace/capabilities.d.ts +0 -31
  287. package/dist/features/workspace/capabilities.js +0 -75
  288. package/dist/features/workspace/index.d.ts +0 -6
  289. package/dist/features/workspace/index.js +0 -6
  290. package/dist/features/workspace/presentation.d.ts +0 -30
  291. package/dist/features/workspace/presentation.js +0 -70
  292. package/dist/features/workspace/reconciliation.d.ts +0 -15
  293. package/dist/features/workspace/reconciliation.js +0 -82
  294. package/dist/features/workspace/reducer.d.ts +0 -43
  295. package/dist/features/workspace/reducer.js +0 -214
  296. package/dist/features/workspace/router.d.ts +0 -32
  297. package/dist/features/workspace/router.js +0 -125
  298. package/dist/features/workspace/store.d.ts +0 -18
  299. package/dist/features/workspace/store.js +0 -55
  300. package/dist/foundation/native-host-protocol/codec.d.ts +0 -13
  301. package/dist/foundation/native-host-protocol/codec.js +0 -58
  302. package/dist/foundation/native-host-protocol/evidence.d.ts +0 -67
  303. package/dist/foundation/native-host-protocol/evidence.js +0 -141
  304. package/dist/foundation/native-host-protocol/index.d.ts +0 -4
  305. package/dist/foundation/native-host-protocol/index.js +0 -4
  306. package/dist/foundation/native-host-protocol/messages.d.ts +0 -56
  307. package/dist/foundation/native-host-protocol/messages.js +0 -149
  308. package/dist/foundation/native-host-protocol/proof-gate.d.ts +0 -13
  309. package/dist/foundation/native-host-protocol/proof-gate.js +0 -33
  310. package/dist/foundation/structured-agent-runtime/backpressure.d.ts +0 -47
  311. package/dist/foundation/structured-agent-runtime/backpressure.js +0 -119
  312. package/dist/foundation/structured-agent-runtime/commands.d.ts +0 -53
  313. package/dist/foundation/structured-agent-runtime/commands.js +0 -165
  314. package/dist/foundation/structured-agent-runtime/handshake.d.ts +0 -41
  315. package/dist/foundation/structured-agent-runtime/handshake.js +0 -151
  316. package/dist/foundation/structured-agent-runtime/index.d.ts +0 -5
  317. package/dist/foundation/structured-agent-runtime/index.js +0 -5
  318. package/dist/foundation/structured-agent-runtime/reconnection.d.ts +0 -38
  319. package/dist/foundation/structured-agent-runtime/reconnection.js +0 -130
  320. package/dist/foundation/structured-agent-runtime/state.d.ts +0 -57
  321. package/dist/foundation/structured-agent-runtime/state.js +0 -119
  322. package/dist/integrations/pi/components/upstream/components/custom-entry.d.ts +0 -17
  323. package/dist/integrations/pi/components/upstream/components/custom-entry.js +0 -51
  324. package/dist/integrations/pi/components/upstream/components/first-time-setup.d.ts +0 -24
  325. package/dist/integrations/pi/components/upstream/components/first-time-setup.js +0 -105
  326. package/dist/integrations/pi/components/upstream/components/markdown-transform.d.ts +0 -2
  327. package/dist/integrations/pi/components/upstream/components/markdown-transform.js +0 -18
  328. package/dist/integrations/pi/engine/model-auth-integration.d.ts +0 -31
  329. package/dist/integrations/pi/engine/model-auth-integration.js +0 -62
  330. package/dist/integrations/pi/engine/resource-extension-integration.d.ts +0 -32
  331. package/dist/integrations/pi/engine/resource-extension-integration.js +0 -81
  332. package/dist/integrations/pi/engine/settings-effects.js +0 -249
  333. package/dist/integrations/pi/engine/settings-integration.d.ts +0 -43
  334. package/dist/integrations/pi/engine/settings-integration.js +0 -227
  335. package/dist/integrations/pi/engine/workflow-controllers.d.ts +0 -21
  336. package/dist/integrations/pi/engine/workflow-controllers.js +0 -49
  337. package/dist/integrations/pi/session-ui/index.d.ts +0 -5
  338. package/dist/integrations/pi/session-ui/index.js +0 -5
  339. package/dist/integrations/pi/session-ui/paste-executor.d.ts +0 -10
  340. package/dist/integrations/pi/session-ui/paste-preparation-client.d.ts +0 -16
  341. package/dist/integrations/pi/session-ui/route-host.d.ts +0 -5
  342. package/dist/integrations/pi/tui-runtime/conformance.d.ts +0 -18
  343. package/dist/integrations/pi/tui-runtime/conformance.js +0 -145
  344. package/dist/ui/components/prompt-row.d.ts +0 -14
  345. package/dist/ui/components/prompt-row.js +0 -20
  346. package/dist/ui/settings/session.d.ts +0 -36
  347. package/dist/ui/settings/store.d.ts +0 -29
  348. package/dist/ui/settings/store.js +0 -91
  349. package/dist/{integrations/pi/session-ui → app/session-shell}/clipboard-diagnostics.js +2 -2
  350. package/dist/{integrations/pi/session-ui → app/session-shell}/clipboard-image.d.ts +0 -0
  351. package/dist/{integrations/pi/session-ui → app/session-shell}/editor-hyperlink-budget.d.ts +0 -0
  352. package/dist/{integrations/pi/session-ui → app/session-shell}/editor-hyperlink-budget.js +0 -0
  353. package/dist/{integrations/pi/session-ui → app/session-shell}/image-preparation.d.ts +0 -0
  354. package/dist/{integrations/pi/session-ui → app/session-shell}/image-source.d.ts +0 -0
  355. package/dist/{integrations/pi/session-ui → app/session-shell}/image-worker.d.ts +0 -0
  356. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-helper.d.ts +0 -0
  357. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-text-preparation.js +0 -0
  358. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-text-worker.d.ts +0 -0
  359. package/dist/{integrations/pi/session-ui → app/session-shell}/paste-text-worker.js +0 -0
  360. package/dist/{integrations/pi/session-ui/response-copy-helper.d.ts → app/session-shell/paste-types.js} +0 -0
  361. package/dist/{integrations/pi/session-ui → app/session-shell}/path-chip-presentation.js +0 -0
  362. package/dist/{integrations/pi/session-ui → app/session-shell}/quit-outro-effects.d.ts +0 -0
  363. package/dist/{integrations/pi/session-ui → app/session-shell}/quit-outro-effects.js +0 -0
  364. package/dist/{integrations/pi/session-ui → app/session-shell}/quit-outro.d.ts +0 -0
  365. package/dist/{integrations/pi/session-ui/route-host.js → app/session-shell/response-copy-helper.d.ts} +0 -0
  366. package/dist/{integrations/pi/session-ui → app/session-shell}/response-copy-protocol.js +0 -0
  367. package/dist/{integrations/pi/session-ui → app/session-shell}/stream-presentation-coalescer.d.ts +0 -0
  368. package/dist/{integrations/pi/session-ui → app/session-shell}/stream-presentation-coalescer.js +3 -3
  369. /package/dist/{integrations/pi/session-ui → app/session-shell}/text-paste.d.ts +0 -0
  370. /package/dist/{integrations/pi/session-ui → app/session-shell}/text-paste.js +0 -0
package/bin/cli.js CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  const commandStartedAtMs = performance.timeOrigin + performance.now();
4
4
  const packageRoot = new URL("..", import.meta.url);
5
+ // Invariant: one terminal module identity per process, decided before any A1 or Pi module loads.
6
+ const [{ installPinnedPiTuiResolver }, { fileURLToPath: toPath }] = await Promise.all([import("./module-resolver.js"), import("node:url")]);
7
+ installPinnedPiTuiResolver(toPath(packageRoot));
5
8
  const startup = await import("../dist/foundation/startup/startup-runtime.js");
6
9
  const startupProfile = process.argv[2] === "pi" ? "pi" : "a1";
7
10
  startup.initializeStartupTrace(process.env, startupProfile, commandStartedAtMs);
@@ -20,16 +23,12 @@ const capabilities = cliCapabilities(JSON.parse(await readFile(new URL("package.
20
23
 
21
24
  process.exitCode = await dispatchCli(process.argv.slice(2), {
22
25
  launch: async intent => {
23
- const [{ prepareInteractiveLaunch }, { runBootstrap }, { healModuleIdentityAtLaunch, releaseCopyIsLaunchable }] = await Promise.all([
26
+ const [{ prepareInteractiveLaunch }, { runBootstrap }, { releaseCopyIsLaunchable }] = await Promise.all([
24
27
  import("../dist/features/launch/prepare-launch.js"),
25
28
  import("../dist/foundation/release/bootstrap.js"),
26
29
  import("./module-identity.js"),
27
30
  ]);
28
- // Compatibility: self-heal the installed tree before the release store copies it: npm 12
29
- // blocks install scripts by default, so the postinstall that normally
30
- // repairs module identity may never have run (see bin/module-identity.js).
31
31
  const packageRootPath = fileURLToPath(packageRoot);
32
- await healModuleIdentityAtLaunch(packageRootPath, message => process.stderr.write(message));
33
32
  const prepared = await prepareInteractiveLaunch(intent);
34
33
  return await runBootstrap({
35
34
  packageRoot: packageRootPath,
package/bin/guardian.js CHANGED
@@ -11,9 +11,13 @@ const { readLaunchContext } = await import("../dist/foundation/launch-context/in
11
11
  const launchContext = readLaunchContext(process.env, "release");
12
12
  const releaseRoot = launchContext.releaseRoot;
13
13
  const profileId = readLaunchContext(process.env, "profile").launchProfile;
14
+ // Invariant: the "release" and "profile" requirements above already refused an environment without
15
+ // these values; the checks give the type checker the same certainty.
16
+ if (releaseRoot === undefined || profileId === undefined) throw new Error("A1 launch context is incomplete");
14
17
 
18
+ const sessionSelection = parseSessionSelection(process.argv.slice(2));
15
19
  Promise.resolve().then(() => runLaunchGuardian({
16
- sessionSelection: parseSessionSelection(process.argv.slice(2)),
20
+ ...(sessionSelection === undefined ? {} : { sessionSelection }),
17
21
  profileId,
18
22
  releaseRoot,
19
23
  uiEntry: resolve(releaseRoot, "bin", "ui.js"),
@@ -1,101 +1,58 @@
1
1
  /**
2
- * One pi-tui module identity per process.
2
+ * One pi-tui module identity per process: the check that the resolver hook worked.
3
3
  *
4
- * npm materializes @earendil-works/pi-tui twice under A1's package root: once
5
- * as A1's direct dependency at the node_modules root, and once nested inside
6
- * @earendil-works/pi-coding-agent, whose published npm-shrinkwrap.json makes
7
- * npm build its dependency tree exactly as shrinkwrapped instead of sharing a
8
- * hoisted copy. Both are the same version; npm just cannot tell them apart.
4
+ * bin/module-resolver.js decides identity at the loader by rewriting every pi-tui module
5
+ * URL to the copy pinned Pi resolves. What remains here is the assertion, made by asking
6
+ * Node itself: with the hook installed, resolving `@earendil-works/pi-tui` from A1's own
7
+ * package root must answer with the same real path pinned Pi answers with. When it does not,
8
+ * launch says so loudly and once, instead of leaving a user to discover it as missing
9
+ * extension UI.
9
10
  *
10
- * Two copies means two of every TUI class. Pinned Pi hands extensions the
11
- * nested copy its extension loader aliases the specifier to whatever it
12
- * resolves from its own directory — so an extension's `instanceof` check and
13
- * its prototype patches land on classes A1's renderer never uses. Extension
14
- * chrome silently disappears and routed input dead-ends, with no error.
15
- *
16
- * A1 therefore does not import the specifier at all. Its package declares the
17
- * subpath import `#pi-tui`, resolving to bin/pi-tui.js — a proxy that
18
- * re-exports pinned Pi's nested copy. The hop through the proxy is load-bearing:
19
- * Node rejects package-imports targets containing a `node_modules` path segment
20
- * (Invalid Package Target) and silently falls through to any fallback, which is
21
- * exactly how an earlier alias that named the nested path directly reintroduced
22
- * the split while appearing to declare the opposite. A plain import specifier
23
- * inside a module carries no such restriction.
24
- *
25
- * What remains here is the check that it worked. The alias is resolved by
26
- * asking Node itself — never by reimplementing resolution, which is how the
27
- * earlier check reported "unified" for a target Node had rejected — and the
28
- * proxy hop is followed to the module it re-exports. When that disagrees with
29
- * what pinned Pi resolves, launch says so, loudly and once, instead of leaving
30
- * a user to discover it as missing extension UI.
31
- *
32
- * This lives in bin/ (shipped, plain JS) because it inspects dependency
33
- * resolution, which the Pi API boundary policy rightly forbids ordinary
34
- * production code from touching.
11
+ * This lives in bin/ (shipped, plain JS) because it inspects dependency resolution, which
12
+ * the Pi API boundary policy rightly forbids ordinary production code from touching.
35
13
  */
36
14
  import { createRequire } from "node:module";
37
15
  import { existsSync, readFileSync, realpathSync } from "node:fs";
38
16
  import { dirname, join } from "node:path";
39
- import { pathToFileURL } from "node:url";
17
+ import { fileURLToPath, pathToFileURL } from "node:url";
18
+ import { pinnedPiTuiPackageRoot } from "./module-resolver.js";
40
19
 
41
20
  /**
42
- * What A1's own modules resolve `#pi-tui` to, as a real path.
43
- *
44
- * Node answers for the alias itself (require.resolve honors package imports for
45
- * the package the parent belongs to). When the answer is A1's proxy file, the
46
- * module it re-exports is what A1 actually renders with, so the proxy's one
47
- * static `export * from` specifier is followed to its target.
21
+ * @typedef {{ kind: "unified"; path: string } | { kind: "split"; own: string; pinned: string } | { kind: "unresolved"; side: "a1" | "pi"; message: string }} ModuleIdentityOutcome
48
22
  */
49
- function resolveOwnPiTui(packageRoot) {
50
- const requireFromRoot = createRequire(pathToFileURL(join(packageRoot, "package.json")).href);
51
- let resolved;
52
- try {
53
- resolved = requireFromRoot.resolve("#pi-tui");
54
- } catch (error) {
55
- throw new Error(`#pi-tui does not resolve: ${message(error)}`);
56
- }
57
- return canonical(followProxyReExport(resolved));
58
- }
23
+
24
+
25
+ const OWN_PACKAGE_ROOT = canonical(fileURLToPath(new URL("..", import.meta.url)));
59
26
 
60
27
  /**
61
- * Follow A1's proxy hop: one relative `export * from "..."` per file, at most
62
- * one hop. A resolution that is not the proxy (or any file without such a
63
- * re-export) is returned as-is.
28
+ * What A1's own modules resolve `@earendil-works/pi-tui` to, as a real path.
29
+ *
30
+ * Compatibility: the resolver hook governs ESM loading, and on Node 22 CommonJS resolution does
31
+ * not consult synchronous hooks at all, so the process's own package is measured through the ESM
32
+ * resolver from this file, which sits in that package. Any other root is measured by plain
33
+ * resolution, which is what its own entries would see before installing the hook. A test
34
+ * transformer that offers no `import.meta.resolve` falls back to plain resolution too.
35
+ * @param {string} packageRoot
64
36
  */
65
- function followProxyReExport(resolvedPath) {
66
- let source;
67
- try {
68
- source = readFileSync(resolvedPath, "utf8");
69
- } catch {
70
- return resolvedPath;
71
- }
72
- const reExport = source.match(/^export \* from "(\.\.?\/[^"]+)";?$/m);
73
- if (!reExport) return resolvedPath;
74
- const target = join(dirname(resolvedPath), reExport[1]);
75
- if (!existsSync(target)) {
76
- throw new Error(`#pi-tui proxy ${resolvedPath} re-exports a missing file: ${target}`);
37
+ function resolveOwnPiTui(packageRoot) {
38
+ if (canonical(packageRoot) === OWN_PACKAGE_ROOT && typeof import.meta.resolve === "function") {
39
+ return canonical(fileURLToPath(import.meta.resolve("@earendil-works/pi-tui")));
77
40
  }
78
- return target;
41
+ const requireFromRoot = createRequire(pathToFileURL(join(packageRoot, "package.json")).href);
42
+ return canonical(requireFromRoot.resolve("@earendil-works/pi-tui"));
79
43
  }
80
44
 
81
45
  /**
82
- * What pinned Pi resolves the same specifier to, as a real path — asked from
83
- * inside Pi's own directory, which is where Pi asks it.
84
- *
85
- * Pi's directory is located by walking node_modules outward, the way Node
86
- * itself would, rather than by resolving Pi's entry: its `exports` map offers
87
- * no CommonJS condition, so an ordinary require cannot name it. From there a
88
- * require resolves pi-tui, which publishes no `exports` map at all.
46
+ * What pinned Pi resolves `@earendil-works/pi-tui` to, as a real path.
47
+ * @param {string} packageRoot
89
48
  */
90
49
  export function resolvePinnedPiTui(packageRoot) {
91
- const pinnedRoot = resolvePinnedPiRoot(packageRoot);
92
- return canonical(createRequire(pathToFileURL(join(pinnedRoot, "package.json")).href).resolve("@earendil-works/pi-tui"));
50
+ return canonical(join(pinnedPiTuiPackageRoot(packageRoot), "dist", "index.js"));
93
51
  }
94
52
 
95
53
  /**
96
- * Bind Pi's documented package-asset override to the exact public package root.
97
- * The generated startup facade otherwise inherits its own A1 `import.meta.url`,
98
- * which would make Pi read A1's package metadata and themes.
54
+ * @param {string} packageRoot
55
+ * @param {NodeJS.ProcessEnv} [environment]
99
56
  */
100
57
  export function configurePinnedPiPublicPackage(packageRoot, environment = process.env) {
101
58
  const pinnedRoot = resolvePinnedPiRoot(packageRoot);
@@ -107,6 +64,7 @@ export function configurePinnedPiPublicPackage(packageRoot, environment = proces
107
64
  return { root: pinnedRoot, version: manifest.version };
108
65
  }
109
66
 
67
+ /** @param {string} packageRoot */
110
68
  function resolvePinnedPiRoot(packageRoot) {
111
69
  let directory = packageRoot;
112
70
  while (true) {
@@ -118,6 +76,7 @@ function resolvePinnedPiRoot(packageRoot) {
118
76
  }
119
77
  }
120
78
 
79
+ /** @param {string} path */
121
80
  function canonical(path) {
122
81
  try {
123
82
  return realpathSync.native(path);
@@ -127,8 +86,10 @@ function canonical(path) {
127
86
  }
128
87
 
129
88
  /**
130
- * Report whether A1 and pinned Pi resolve pi-tui to the same file.
131
- * Returns a discriminated outcome; never throws.
89
+ * Compare what A1 and pinned Pi resolve. With the resolver hook installed in this process the
90
+ * two agree whatever layout npm built; without it they agree only when npm hoisted one copy.
91
+ * @param {string} packageRoot
92
+ * @returns {ModuleIdentityOutcome}
132
93
  */
133
94
  export function inspectPiTuiModuleIdentity(packageRoot) {
134
95
  let own;
@@ -146,38 +107,32 @@ export function inspectPiTuiModuleIdentity(packageRoot) {
146
107
  return own === pinned ? { kind: "unified", path: own } : { kind: "split", own, pinned };
147
108
  }
148
109
 
110
+ /** @param {unknown} error */
149
111
  function message(error) {
150
112
  return error instanceof Error ? error.message : String(error);
151
113
  }
152
114
 
153
115
  /**
154
- * Launch-entry self-heal: when A1 and pinned Pi disagree on the terminal
155
- * module, rewrite the proxy to the copy Pi resolves before anything copies
156
- * this tree. npm 12 blocks install scripts unless allowScripts covers the
157
- * package, so the postinstall that normally rewrites the proxy may never
158
- * have run and the installed tree may still carry the published placeholder
159
- * path. Named neutrally so the launch entries that call it stay free of
160
- * terminal implementation identifiers, as the bootstrap boundary requires.
116
+ * A release copy is launchable when pinned Pi inside it resolves its terminal package.
117
+ * @param {string} releaseRoot
161
118
  */
162
- export async function healModuleIdentityAtLaunch(packageRoot, warn) {
163
- if (inspectPiTuiModuleIdentity(packageRoot).kind === "unified") return;
164
- const { syncPiTuiProxy } = await import("./sync-pi-tui-proxy.js");
165
- const outcome = syncPiTuiProxy(packageRoot);
166
- if (outcome.kind === "unresolved") {
167
- warn(`a1: could not point the terminal module proxy at pinned Pi's copy (${outcome.message}); extension UI may not render.\n`);
168
- }
169
- }
170
-
171
- /** Whether a materialized release copy resolves one terminal module for both A1 and Pi. */
172
119
  export function releaseCopyIsLaunchable(releaseRoot) {
173
- return inspectPiTuiModuleIdentity(releaseRoot).kind === "unified";
120
+ try {
121
+ resolvePinnedPiTui(releaseRoot);
122
+ return true;
123
+ } catch {
124
+ return false;
125
+ }
174
126
  }
175
127
 
176
- /** Launch-entry wrapper: warn on stderr when the two sides disagree. */
128
+ /**
129
+ * @param {string} packageRoot
130
+ * @param {(message: string) => void} warn
131
+ */
177
132
  export function assertSinglePiTuiModuleAtLaunch(packageRoot, warn) {
178
133
  const outcome = inspectPiTuiModuleIdentity(packageRoot);
179
134
  if (outcome.kind === "split") {
180
- warn(`a1: pi-tui resolves to two different copies (${outcome.own} for a1, ${outcome.pinned} for Pi); extension UI may not render. The #pi-tui alias in a1's package.json no longer names Pi's copy.\n`);
135
+ warn(`a1: pi-tui resolves to two different copies (${outcome.own} for a1, ${outcome.pinned} for Pi); extension UI may not render. The pinned pi-tui resolver hook is not active in this process.\n`);
181
136
  } else if (outcome.kind === "unresolved") {
182
137
  warn(`a1: could not resolve pi-tui from ${outcome.side === "a1" ? "a1" : "pinned Pi"} (${outcome.message}); extension UI may not render.\n`);
183
138
  }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * One pi-tui module identity per process, decided at the loader.
3
+ *
4
+ * npm may materialize @earendil-works/pi-tui twice under A1's package root: as A1's own
5
+ * dependency at the node_modules root and nested inside @earendil-works/pi-coding-agent,
6
+ * whose shrinkwrap pins its own copy. Two copies means two of every TUI class: pinned Pi
7
+ * hands extensions the copy it resolves itself, so an extension's `instanceof` check and
8
+ * prototype patches would land on classes A1's renderer never uses, and extension chrome
9
+ * would silently vanish.
10
+ *
11
+ * Rather than repairing the layout after the fact, this module asks Node which copy pinned
12
+ * Pi resolves and installs a synchronous resolve hook that rewrites every pi-tui module URL,
13
+ * from any importer and in any form (bare specifier, subpath, or an absolute path into the
14
+ * other copy), to that one copy. When npm hoisted a single copy the two answers coincide and
15
+ * the hook changes nothing. The hook is registered by the bin/ entries before any A1 module
16
+ * loads, so the composition, the bundled Pi public artifact, and Pi's own extension loader
17
+ * all share one module. bin/module-identity.js keeps the launch-time assertion that it
18
+ * worked.
19
+ *
20
+ * This lives in bin/ (shipped, plain JS) because it inspects dependency resolution, which
21
+ * the Pi API boundary policy rightly forbids ordinary production code from touching.
22
+ */
23
+ import { createRequire, registerHooks } from "node:module";
24
+ import { existsSync, realpathSync } from "node:fs";
25
+ import { dirname, isAbsolute, join, relative } from "node:path";
26
+ import { fileURLToPath, pathToFileURL } from "node:url";
27
+
28
+ const PACKAGE = "@earendil-works/pi-tui";
29
+ const SEGMENT = `/node_modules/${PACKAGE}/`;
30
+
31
+ /** @type {string | null} */
32
+ let installed = null;
33
+
34
+ /**
35
+ * The package root pinned Pi resolves `@earendil-works/pi-tui` to, as a real path.
36
+ * @param {string} packageRoot
37
+ * @returns {string}
38
+ */
39
+ export function pinnedPiTuiPackageRoot(packageRoot) {
40
+ return pinnedPiTuiLayout(packageRoot).pinnedRoot;
41
+ }
42
+
43
+ /**
44
+ * Where pinned Pi lives and which pi-tui copy it resolves. The installation root is the directory
45
+ * whose node_modules holds pinned Pi; the hook rewrites only modules beneath it, so fixture trees
46
+ * and other release copies inspected from this process keep their own resolution.
47
+ * @param {string} packageRoot
48
+ * @returns {{ installationRoot: string; pinnedRoot: string }}
49
+ */
50
+ export function pinnedPiTuiLayout(packageRoot) {
51
+ const piRoot = pinnedPiRoot(packageRoot);
52
+ const requireFromPi = createRequire(pathToFileURL(join(piRoot, "package.json")).href);
53
+ return {
54
+ installationRoot: dirname(dirname(dirname(piRoot))),
55
+ pinnedRoot: packageRootOf(canonical(requireFromPi.resolve(PACKAGE))),
56
+ };
57
+ }
58
+
59
+ // Rationale: pinned Pi exports no `./package.json` subpath, so its directory is found by walking
60
+ // up from the package root the way Node itself would, never by reimplementing export resolution.
61
+ /** @param {string} packageRoot */
62
+ function pinnedPiRoot(packageRoot) {
63
+ let directory = packageRoot;
64
+ while (true) {
65
+ const candidate = join(directory, "node_modules", "@earendil-works", "pi-coding-agent");
66
+ if (existsSync(join(candidate, "package.json"))) return canonical(candidate);
67
+ const parent = dirname(directory);
68
+ if (parent === directory) throw new Error("pinned Pi is not installed beneath this package root");
69
+ directory = parent;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Install the resolve hook once per process. Returns the pinned package root URL. Idempotent:
75
+ * every bin/ entry calls it and only the first call registers.
76
+ * @param {string} packageRoot
77
+ * @returns {string}
78
+ */
79
+ export function installPinnedPiTuiResolver(packageRoot) {
80
+ if (installed !== null) return installed;
81
+ const layout = pinnedPiTuiLayout(packageRoot);
82
+ registerHooks({
83
+ resolve(specifier, context, nextResolve) {
84
+ const result = nextResolve(specifier, context);
85
+ const rewritten = redirectToPinned(result.url, layout);
86
+ return rewritten === result.url ? result : { ...result, url: rewritten };
87
+ },
88
+ });
89
+ installed = pathToFileURL(layout.pinnedRoot).href.replace(/\/$/, "");
90
+ return installed;
91
+ }
92
+
93
+ /**
94
+ * Rewrite a resolved pi-tui module URL beneath the installation root to the pinned copy; any
95
+ * other URL is returned unchanged. Paths are compared as canonical real paths, never as URL
96
+ * strings: a temp directory reached by its short 8.3 name or a different drive-letter case is
97
+ * still the same installation.
98
+ * @param {string} url
99
+ * @param {{ installationRoot: string; pinnedRoot: string }} layout
100
+ * @returns {string}
101
+ */
102
+ export function redirectToPinned(url, layout) {
103
+ if (!url.startsWith("file:")) return url;
104
+ const index = url.lastIndexOf(SEGMENT);
105
+ if (index < 0) return url;
106
+ const packagePath = canonical(fileURLToPath(url.slice(0, index + SEGMENT.length - 1)));
107
+ if (packagePath === layout.pinnedRoot || !isWithin(layout.installationRoot, packagePath)) return url;
108
+ return `${pathToFileURL(layout.pinnedRoot).href.replace(/\/$/, "")}${url.slice(index + SEGMENT.length - 1)}`;
109
+ }
110
+
111
+ /**
112
+ * @param {string} root
113
+ * @param {string} path
114
+ */
115
+ function isWithin(root, path) {
116
+ const relativePath = relative(root, path);
117
+ return relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath);
118
+ }
119
+
120
+ /** @param {string} path */
121
+ function canonical(path) {
122
+ try {
123
+ return realpathSync.native(path);
124
+ } catch {
125
+ return path;
126
+ }
127
+ }
128
+
129
+ /** @param {string} modulePath */
130
+ function packageRootOf(modulePath) {
131
+ let directory = dirname(modulePath);
132
+ while (!directory.endsWith(join("node_modules", "@earendil-works", "pi-tui"))) {
133
+ const parent = dirname(directory);
134
+ if (parent === directory) throw new Error(`${modulePath} is not inside a ${PACKAGE} package`);
135
+ directory = parent;
136
+ }
137
+ return directory;
138
+ }
@@ -2,7 +2,10 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { dirname, posix, resolve, sep } from "node:path";
3
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
4
 
5
- /** Bind the generated facade to the package reached through Pi's public entry. */
5
+ /**
6
+ * Bind the generated facade to the package reached through Pi's public entry.
7
+ * @param {string | URL} entryUrl
8
+ */
6
9
  export function configurePinnedPiPublicPackageEntry(entryUrl) {
7
10
  const root = dirname(dirname(fileURLToPath(entryUrl)));
8
11
  const manifest = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
@@ -13,7 +16,10 @@ export function configurePinnedPiPublicPackageEntry(entryUrl) {
13
16
  return { root, version: manifest.version };
14
17
  }
15
18
 
16
- /** Preserve one bundled Pi module's original public-package URL semantics. */
19
+ /**
20
+ * Preserve one bundled Pi module's original public-package URL semantics.
21
+ * @param {string} relativeModule
22
+ */
17
23
  export function pinnedPiModuleUrl(relativeModule) {
18
24
  if (typeof relativeModule !== "string" || relativeModule.includes("\\") || relativeModule.startsWith("/")
19
25
  || posix.normalize(relativeModule).startsWith("../") || !relativeModule.endsWith(".js")) {
@@ -22,7 +28,10 @@ export function pinnedPiModuleUrl(relativeModule) {
22
28
  return pathToFileURL(resolve(pinnedRoot(), "dist", relativeModule)).href;
23
29
  }
24
30
 
25
- /** Resolve documented Pi dependency exports from the pinned public package tree. */
31
+ /**
32
+ * Resolve documented Pi dependency exports from the pinned public package tree.
33
+ * @param {string} specifier
34
+ */
26
35
  export function resolvePinnedPiImport(specifier) {
27
36
  if (typeof specifier !== "string" || specifier.includes("\\") || specifier.includes("\0")) {
28
37
  throw new Error("pinned Pi import specifier is invalid");
@@ -31,7 +40,7 @@ export function resolvePinnedPiImport(specifier) {
31
40
  if (specifier === "@earendil-works/pi-coding-agent") return pathToFileURL(resolve(root, "dist", "index.js")).href;
32
41
  const match = /^(@[^/]+\/[^/]+|[^/]+)(\/.*)?$/.exec(specifier);
33
42
  if (match === null) throw new Error(`pinned Pi import is invalid: ${specifier}`);
34
- const packageName = match[1];
43
+ const packageName = match[1] ?? "";
35
44
  const subpath = match[2]?.slice(1) ?? "";
36
45
  const packageRoot = resolve(root, "node_modules", ...packageName.split("/"));
37
46
  const manifestPath = resolve(packageRoot, "package.json");
@@ -51,11 +60,16 @@ function pinnedRoot() {
51
60
  return resolve(root);
52
61
  }
53
62
 
63
+ /**
64
+ * @param {unknown} exports
65
+ * @param {string} subpath
66
+ * @returns {string | undefined}
67
+ */
54
68
  function exportedTarget(exports, subpath) {
55
69
  const key = subpath.length === 0 ? "." : `./${subpath}`;
56
70
  if (typeof exports === "string") return subpath.length === 0 ? exports : undefined;
57
71
  if (!exports || typeof exports !== "object") return undefined;
58
- const exact = exports[key];
72
+ const exact = /** @type {Record<string, unknown>} */ (exports)[key];
59
73
  if (exact !== undefined) return importCondition(exact);
60
74
  for (const [pattern, value] of Object.entries(exports)) {
61
75
  const star = pattern.indexOf("*");
@@ -67,8 +81,13 @@ function exportedTarget(exports, subpath) {
67
81
  return undefined;
68
82
  }
69
83
 
84
+ /**
85
+ * @param {unknown} value
86
+ * @returns {string | undefined}
87
+ */
70
88
  function importCondition(value) {
71
89
  if (typeof value === "string") return value;
72
90
  if (!value || typeof value !== "object") return undefined;
73
- return importCondition(value.import ?? value.default);
91
+ const conditions = /** @type {{ import?: unknown; default?: unknown }} */ (value);
92
+ return importCondition(conditions.import ?? conditions.default);
74
93
  }
package/bin/ui.js CHANGED
@@ -1,17 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Invariant: one terminal module identity per process, decided before any A1 or Pi module loads.
4
+ const { installPinnedPiTuiResolver } = await import("./module-resolver.js");
5
+ installPinnedPiTuiResolver(new URL("..", import.meta.url).pathname.replace(/^\/(.:)/, "$1").replace(/\/$/, ""));
3
6
  const startup = await import("../dist/foundation/startup/startup-runtime.js");
4
7
  startup.enableEnvironmentCompileCache(process.env);
5
8
  const { readLaunchContext } = await import("../dist/foundation/launch-context/index.js");
6
9
  const launchContext = readLaunchContext(process.env, "profile");
7
10
  const profile = launchContext.launchProfile;
11
+ if (profile === undefined) throw new Error("A1 launch profile is missing");
8
12
  const { installFatalExit } = await import("../dist/foundation/terminal-cleanup/fatal-exit.js");
9
13
  const { resolveProductPaths } = await import("../dist/foundation/lifecycle/paths.js");
10
14
  const { join } = await import("node:path");
15
+ /** @type {{ dispose(): void | Promise<unknown> } | undefined} */
11
16
  let runningApplication;
12
17
  const fatal = profile === "a1" ? installFatalExit({
13
18
  directory: join(resolveProductPaths().runtimeDir, "crashes"),
14
- releaseId: launchContext.releaseId,
19
+ ...(launchContext.releaseId === undefined ? {} : { releaseId: launchContext.releaseId }),
15
20
  dispose: () => runningApplication?.dispose(),
16
21
  }) : undefined;
17
22
  const [{ fileURLToPath }, identity, descriptor] = await Promise.all([
@@ -36,7 +41,7 @@ const [
36
41
 
37
42
  // Compatibility: before the composition uses pinned Pi's terminal stack: confirm A1 and Pi
38
43
  // resolve it to the same copy, so extensions and the owned UI share one module identity.
39
- identity.assertSinglePiTuiModuleAtLaunch(packageRootPath, message => process.stderr.write(message));
44
+ identity.assertSinglePiTuiModuleAtLaunch(packageRootPath, (/** @type {string} */ message) => process.stderr.write(message));
40
45
  await startup.markStartupPhase(process.env, "ui-modules-loaded");
41
46
 
42
47
  const sessionSelection = parseSessionSelection(process.argv.slice(2));