@timurproko/a1 0.1.0

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 (455) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -0
  3. package/bin/addone-supervisor.js +7 -0
  4. package/bin/addone-ui.js +20 -0
  5. package/bin/addone.js +26 -0
  6. package/dist/src/cli/dispatch.d.ts +26 -0
  7. package/dist/src/cli/dispatch.d.ts.map +1 -0
  8. package/dist/src/cli/dispatch.js +35 -0
  9. package/dist/src/cli/dispatch.js.map +1 -0
  10. package/dist/src/cli/index.d.ts +4 -0
  11. package/dist/src/cli/index.d.ts.map +1 -0
  12. package/dist/src/cli/index.js +4 -0
  13. package/dist/src/cli/index.js.map +1 -0
  14. package/dist/src/cli/version-stats.d.ts +17 -0
  15. package/dist/src/cli/version-stats.d.ts.map +1 -0
  16. package/dist/src/cli/version-stats.js +68 -0
  17. package/dist/src/cli/version-stats.js.map +1 -0
  18. package/dist/src/cli/version.d.ts +3 -0
  19. package/dist/src/cli/version.d.ts.map +1 -0
  20. package/dist/src/cli/version.js +23 -0
  21. package/dist/src/cli/version.js.map +1 -0
  22. package/dist/src/features/launch/development-launch.d.ts +9 -0
  23. package/dist/src/features/launch/development-launch.d.ts.map +1 -0
  24. package/dist/src/features/launch/development-launch.js +27 -0
  25. package/dist/src/features/launch/development-launch.js.map +1 -0
  26. package/dist/src/features/launch/index.d.ts +8 -0
  27. package/dist/src/features/launch/index.d.ts.map +1 -0
  28. package/dist/src/features/launch/index.js +8 -0
  29. package/dist/src/features/launch/index.js.map +1 -0
  30. package/dist/src/features/launch/initialize-profile.d.ts +7 -0
  31. package/dist/src/features/launch/initialize-profile.d.ts.map +1 -0
  32. package/dist/src/features/launch/initialize-profile.js +59 -0
  33. package/dist/src/features/launch/initialize-profile.js.map +1 -0
  34. package/dist/src/features/launch/intent.d.ts +8 -0
  35. package/dist/src/features/launch/intent.d.ts.map +1 -0
  36. package/dist/src/features/launch/intent.js +5 -0
  37. package/dist/src/features/launch/intent.js.map +1 -0
  38. package/dist/src/features/launch/prepare-launch.d.ts +14 -0
  39. package/dist/src/features/launch/prepare-launch.d.ts.map +1 -0
  40. package/dist/src/features/launch/prepare-launch.js +22 -0
  41. package/dist/src/features/launch/prepare-launch.js.map +1 -0
  42. package/dist/src/features/launch/profile-paths.d.ts +16 -0
  43. package/dist/src/features/launch/profile-paths.d.ts.map +1 -0
  44. package/dist/src/features/launch/profile-paths.js +30 -0
  45. package/dist/src/features/launch/profile-paths.js.map +1 -0
  46. package/dist/src/features/launch/profiles.d.ts +13 -0
  47. package/dist/src/features/launch/profiles.d.ts.map +1 -0
  48. package/dist/src/features/launch/profiles.js +27 -0
  49. package/dist/src/features/launch/profiles.js.map +1 -0
  50. package/dist/src/features/launch/runtime-selection.d.ts +15 -0
  51. package/dist/src/features/launch/runtime-selection.d.ts.map +1 -0
  52. package/dist/src/features/launch/runtime-selection.js +14 -0
  53. package/dist/src/features/launch/runtime-selection.js.map +1 -0
  54. package/dist/src/features/owned-ui/customization.d.ts +36 -0
  55. package/dist/src/features/owned-ui/customization.d.ts.map +1 -0
  56. package/dist/src/features/owned-ui/customization.js +110 -0
  57. package/dist/src/features/owned-ui/customization.js.map +1 -0
  58. package/dist/src/features/owned-ui/diagnostics.d.ts +34 -0
  59. package/dist/src/features/owned-ui/diagnostics.d.ts.map +1 -0
  60. package/dist/src/features/owned-ui/diagnostics.js +95 -0
  61. package/dist/src/features/owned-ui/diagnostics.js.map +1 -0
  62. package/dist/src/features/owned-ui/index.d.ts +5 -0
  63. package/dist/src/features/owned-ui/index.d.ts.map +1 -0
  64. package/dist/src/features/owned-ui/index.js +5 -0
  65. package/dist/src/features/owned-ui/index.js.map +1 -0
  66. package/dist/src/features/owned-ui/pi-session-shell.d.ts +97 -0
  67. package/dist/src/features/owned-ui/pi-session-shell.d.ts.map +1 -0
  68. package/dist/src/features/owned-ui/pi-session-shell.js +1437 -0
  69. package/dist/src/features/owned-ui/pi-session-shell.js.map +1 -0
  70. package/dist/src/features/owned-ui/run.d.ts +9 -0
  71. package/dist/src/features/owned-ui/run.d.ts.map +1 -0
  72. package/dist/src/features/owned-ui/run.js +21 -0
  73. package/dist/src/features/owned-ui/run.js.map +1 -0
  74. package/dist/src/features/workspace/capabilities.d.ts +32 -0
  75. package/dist/src/features/workspace/capabilities.d.ts.map +1 -0
  76. package/dist/src/features/workspace/capabilities.js +76 -0
  77. package/dist/src/features/workspace/capabilities.js.map +1 -0
  78. package/dist/src/features/workspace/index.d.ts +7 -0
  79. package/dist/src/features/workspace/index.d.ts.map +1 -0
  80. package/dist/src/features/workspace/index.js +7 -0
  81. package/dist/src/features/workspace/index.js.map +1 -0
  82. package/dist/src/features/workspace/presentation.d.ts +31 -0
  83. package/dist/src/features/workspace/presentation.d.ts.map +1 -0
  84. package/dist/src/features/workspace/presentation.js +69 -0
  85. package/dist/src/features/workspace/presentation.js.map +1 -0
  86. package/dist/src/features/workspace/reconciliation.d.ts +16 -0
  87. package/dist/src/features/workspace/reconciliation.d.ts.map +1 -0
  88. package/dist/src/features/workspace/reconciliation.js +83 -0
  89. package/dist/src/features/workspace/reconciliation.js.map +1 -0
  90. package/dist/src/features/workspace/reducer.d.ts +43 -0
  91. package/dist/src/features/workspace/reducer.d.ts.map +1 -0
  92. package/dist/src/features/workspace/reducer.js +214 -0
  93. package/dist/src/features/workspace/reducer.js.map +1 -0
  94. package/dist/src/features/workspace/router.d.ts +32 -0
  95. package/dist/src/features/workspace/router.d.ts.map +1 -0
  96. package/dist/src/features/workspace/router.js +125 -0
  97. package/dist/src/features/workspace/router.js.map +1 -0
  98. package/dist/src/features/workspace/store.d.ts +18 -0
  99. package/dist/src/features/workspace/store.d.ts.map +1 -0
  100. package/dist/src/features/workspace/store.js +55 -0
  101. package/dist/src/features/workspace/store.js.map +1 -0
  102. package/dist/src/foundation/lifecycle/index.d.ts +3 -0
  103. package/dist/src/foundation/lifecycle/index.d.ts.map +1 -0
  104. package/dist/src/foundation/lifecycle/index.js +3 -0
  105. package/dist/src/foundation/lifecycle/index.js.map +1 -0
  106. package/dist/src/foundation/lifecycle/model.d.ts +101 -0
  107. package/dist/src/foundation/lifecycle/model.d.ts.map +1 -0
  108. package/dist/src/foundation/lifecycle/model.js +40 -0
  109. package/dist/src/foundation/lifecycle/model.js.map +1 -0
  110. package/dist/src/foundation/lifecycle/paths.d.ts +11 -0
  111. package/dist/src/foundation/lifecycle/paths.d.ts.map +1 -0
  112. package/dist/src/foundation/lifecycle/paths.js +26 -0
  113. package/dist/src/foundation/lifecycle/paths.js.map +1 -0
  114. package/dist/src/foundation/native-host-protocol/codec.d.ts +12 -0
  115. package/dist/src/foundation/native-host-protocol/codec.d.ts.map +1 -0
  116. package/dist/src/foundation/native-host-protocol/codec.js +57 -0
  117. package/dist/src/foundation/native-host-protocol/codec.js.map +1 -0
  118. package/dist/src/foundation/native-host-protocol/evidence.d.ts +68 -0
  119. package/dist/src/foundation/native-host-protocol/evidence.d.ts.map +1 -0
  120. package/dist/src/foundation/native-host-protocol/evidence.js +141 -0
  121. package/dist/src/foundation/native-host-protocol/evidence.js.map +1 -0
  122. package/dist/src/foundation/native-host-protocol/index.d.ts +5 -0
  123. package/dist/src/foundation/native-host-protocol/index.d.ts.map +1 -0
  124. package/dist/src/foundation/native-host-protocol/index.js +5 -0
  125. package/dist/src/foundation/native-host-protocol/index.js.map +1 -0
  126. package/dist/src/foundation/native-host-protocol/messages.d.ts +57 -0
  127. package/dist/src/foundation/native-host-protocol/messages.d.ts.map +1 -0
  128. package/dist/src/foundation/native-host-protocol/messages.js +149 -0
  129. package/dist/src/foundation/native-host-protocol/messages.js.map +1 -0
  130. package/dist/src/foundation/native-host-protocol/proof-gate.d.ts +14 -0
  131. package/dist/src/foundation/native-host-protocol/proof-gate.d.ts.map +1 -0
  132. package/dist/src/foundation/native-host-protocol/proof-gate.js +34 -0
  133. package/dist/src/foundation/native-host-protocol/proof-gate.js.map +1 -0
  134. package/dist/src/foundation/owned-ui-contracts/extension-ui.d.ts +303 -0
  135. package/dist/src/foundation/owned-ui-contracts/extension-ui.d.ts.map +1 -0
  136. package/dist/src/foundation/owned-ui-contracts/extension-ui.js +69 -0
  137. package/dist/src/foundation/owned-ui-contracts/extension-ui.js.map +1 -0
  138. package/dist/src/foundation/owned-ui-contracts/index.d.ts +4 -0
  139. package/dist/src/foundation/owned-ui-contracts/index.d.ts.map +1 -0
  140. package/dist/src/foundation/owned-ui-contracts/index.js +4 -0
  141. package/dist/src/foundation/owned-ui-contracts/index.js.map +1 -0
  142. package/dist/src/foundation/owned-ui-contracts/model.d.ts +242 -0
  143. package/dist/src/foundation/owned-ui-contracts/model.d.ts.map +1 -0
  144. package/dist/src/foundation/owned-ui-contracts/model.js +2 -0
  145. package/dist/src/foundation/owned-ui-contracts/model.js.map +1 -0
  146. package/dist/src/foundation/owned-ui-contracts/validation.d.ts +12 -0
  147. package/dist/src/foundation/owned-ui-contracts/validation.d.ts.map +1 -0
  148. package/dist/src/foundation/owned-ui-contracts/validation.js +396 -0
  149. package/dist/src/foundation/owned-ui-contracts/validation.js.map +1 -0
  150. package/dist/src/foundation/pi-component-adapter/components.d.ts +5 -0
  151. package/dist/src/foundation/pi-component-adapter/components.d.ts.map +1 -0
  152. package/dist/src/foundation/pi-component-adapter/components.js +65 -0
  153. package/dist/src/foundation/pi-component-adapter/components.js.map +1 -0
  154. package/dist/src/foundation/pi-component-adapter/conformance.d.ts +17 -0
  155. package/dist/src/foundation/pi-component-adapter/conformance.d.ts.map +1 -0
  156. package/dist/src/foundation/pi-component-adapter/conformance.js +63 -0
  157. package/dist/src/foundation/pi-component-adapter/conformance.js.map +1 -0
  158. package/dist/src/foundation/pi-component-adapter/index.d.ts +13 -0
  159. package/dist/src/foundation/pi-component-adapter/index.d.ts.map +1 -0
  160. package/dist/src/foundation/pi-component-adapter/index.js +13 -0
  161. package/dist/src/foundation/pi-component-adapter/index.js.map +1 -0
  162. package/dist/src/foundation/pi-component-adapter/shell-components.d.ts +7 -0
  163. package/dist/src/foundation/pi-component-adapter/shell-components.d.ts.map +1 -0
  164. package/dist/src/foundation/pi-component-adapter/shell-components.js +7 -0
  165. package/dist/src/foundation/pi-component-adapter/shell-components.js.map +1 -0
  166. package/dist/src/foundation/pi-component-adapter/shell-editor-autocomplete.d.ts +12 -0
  167. package/dist/src/foundation/pi-component-adapter/shell-editor-autocomplete.d.ts.map +1 -0
  168. package/dist/src/foundation/pi-component-adapter/shell-editor-autocomplete.js +165 -0
  169. package/dist/src/foundation/pi-component-adapter/shell-editor-autocomplete.js.map +1 -0
  170. package/dist/src/foundation/pi-component-adapter/shell-extension-ui.d.ts +36 -0
  171. package/dist/src/foundation/pi-component-adapter/shell-extension-ui.d.ts.map +1 -0
  172. package/dist/src/foundation/pi-component-adapter/shell-extension-ui.js +280 -0
  173. package/dist/src/foundation/pi-component-adapter/shell-extension-ui.js.map +1 -0
  174. package/dist/src/foundation/pi-component-adapter/shell-footer-status.d.ts +8 -0
  175. package/dist/src/foundation/pi-component-adapter/shell-footer-status.d.ts.map +1 -0
  176. package/dist/src/foundation/pi-component-adapter/shell-footer-status.js +246 -0
  177. package/dist/src/foundation/pi-component-adapter/shell-footer-status.js.map +1 -0
  178. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +43 -0
  179. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts.map +1 -0
  180. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.js +397 -0
  181. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.js.map +1 -0
  182. package/dist/src/foundation/pi-component-adapter/shell-selectors-dialogs.d.ts +106 -0
  183. package/dist/src/foundation/pi-component-adapter/shell-selectors-dialogs.d.ts.map +1 -0
  184. package/dist/src/foundation/pi-component-adapter/shell-selectors-dialogs.js +234 -0
  185. package/dist/src/foundation/pi-component-adapter/shell-selectors-dialogs.js.map +1 -0
  186. package/dist/src/foundation/pi-component-adapter/shell-shared-facade.d.ts +117 -0
  187. package/dist/src/foundation/pi-component-adapter/shell-shared-facade.d.ts.map +1 -0
  188. package/dist/src/foundation/pi-component-adapter/shell-shared-facade.js +88 -0
  189. package/dist/src/foundation/pi-component-adapter/shell-shared-facade.js.map +1 -0
  190. package/dist/src/foundation/pi-component-adapter/theme.d.ts +2 -0
  191. package/dist/src/foundation/pi-component-adapter/theme.d.ts.map +1 -0
  192. package/dist/src/foundation/pi-component-adapter/theme.js +2 -0
  193. package/dist/src/foundation/pi-component-adapter/theme.js.map +1 -0
  194. package/dist/src/foundation/pi-component-adapter/upstream/adjacent/core/keybindings.d.ts +423 -0
  195. package/dist/src/foundation/pi-component-adapter/upstream/adjacent/core/keybindings.d.ts.map +1 -0
  196. package/dist/src/foundation/pi-component-adapter/upstream/adjacent/core/keybindings.js +297 -0
  197. package/dist/src/foundation/pi-component-adapter/upstream/adjacent/core/keybindings.js.map +1 -0
  198. package/dist/src/foundation/pi-component-adapter/upstream/components/countdown-timer.d.ts +11 -0
  199. package/dist/src/foundation/pi-component-adapter/upstream/components/countdown-timer.d.ts.map +1 -0
  200. package/dist/src/foundation/pi-component-adapter/upstream/components/countdown-timer.js +30 -0
  201. package/dist/src/foundation/pi-component-adapter/upstream/components/countdown-timer.js.map +1 -0
  202. package/dist/src/foundation/pi-component-adapter/upstream/components/custom-entry.d.ts +18 -0
  203. package/dist/src/foundation/pi-component-adapter/upstream/components/custom-entry.d.ts.map +1 -0
  204. package/dist/src/foundation/pi-component-adapter/upstream/components/custom-entry.js +52 -0
  205. package/dist/src/foundation/pi-component-adapter/upstream/components/custom-entry.js.map +1 -0
  206. package/dist/src/foundation/pi-component-adapter/upstream/components/daxnuts.d.ts +23 -0
  207. package/dist/src/foundation/pi-component-adapter/upstream/components/daxnuts.d.ts.map +1 -0
  208. package/dist/src/foundation/pi-component-adapter/upstream/components/daxnuts.js +143 -0
  209. package/dist/src/foundation/pi-component-adapter/upstream/components/daxnuts.js.map +1 -0
  210. package/dist/src/foundation/pi-component-adapter/upstream/components/earendil-announcement.d.ts +5 -0
  211. package/dist/src/foundation/pi-component-adapter/upstream/components/earendil-announcement.d.ts.map +1 -0
  212. package/dist/src/foundation/pi-component-adapter/upstream/components/earendil-announcement.js +43 -0
  213. package/dist/src/foundation/pi-component-adapter/upstream/components/earendil-announcement.js.map +1 -0
  214. package/dist/src/foundation/pi-component-adapter/upstream/components/extension-editor.d.ts +18 -0
  215. package/dist/src/foundation/pi-component-adapter/upstream/components/extension-editor.d.ts.map +1 -0
  216. package/dist/src/foundation/pi-component-adapter/upstream/components/extension-editor.js +82 -0
  217. package/dist/src/foundation/pi-component-adapter/upstream/components/extension-editor.js.map +1 -0
  218. package/dist/src/foundation/pi-component-adapter/upstream/components/first-time-setup.d.ts +25 -0
  219. package/dist/src/foundation/pi-component-adapter/upstream/components/first-time-setup.d.ts.map +1 -0
  220. package/dist/src/foundation/pi-component-adapter/upstream/components/first-time-setup.js +106 -0
  221. package/dist/src/foundation/pi-component-adapter/upstream/components/first-time-setup.js.map +1 -0
  222. package/dist/src/foundation/pi-component-adapter/upstream/components/markdown-transform.d.ts +3 -0
  223. package/dist/src/foundation/pi-component-adapter/upstream/components/markdown-transform.d.ts.map +1 -0
  224. package/dist/src/foundation/pi-component-adapter/upstream/components/markdown-transform.js +19 -0
  225. package/dist/src/foundation/pi-component-adapter/upstream/components/markdown-transform.js.map +1 -0
  226. package/dist/src/foundation/pi-component-adapter/upstream/components/mermaid.d.ts +10 -0
  227. package/dist/src/foundation/pi-component-adapter/upstream/components/mermaid.d.ts.map +1 -0
  228. package/dist/src/foundation/pi-component-adapter/upstream/components/mermaid.js +78 -0
  229. package/dist/src/foundation/pi-component-adapter/upstream/components/mermaid.js.map +1 -0
  230. package/dist/src/foundation/pi-component-adapter/upstream/components/scoped-models-selector.d.ts +56 -0
  231. package/dist/src/foundation/pi-component-adapter/upstream/components/scoped-models-selector.d.ts.map +1 -0
  232. package/dist/src/foundation/pi-component-adapter/upstream/components/scoped-models-selector.js +343 -0
  233. package/dist/src/foundation/pi-component-adapter/upstream/components/scoped-models-selector.js.map +1 -0
  234. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector-search.d.ts +23 -0
  235. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector-search.d.ts.map +1 -0
  236. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector-search.js +160 -0
  237. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector-search.js.map +1 -0
  238. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector.d.ts +96 -0
  239. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector.d.ts.map +1 -0
  240. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector.js +890 -0
  241. package/dist/src/foundation/pi-component-adapter/upstream/components/session-selector.js.map +1 -0
  242. package/dist/src/foundation/pi-component-adapter/upstream/components/skill-invocation-message.d.ts +20 -0
  243. package/dist/src/foundation/pi-component-adapter/upstream/components/skill-invocation-message.d.ts.map +1 -0
  244. package/dist/src/foundation/pi-component-adapter/upstream/components/skill-invocation-message.js +45 -0
  245. package/dist/src/foundation/pi-component-adapter/upstream/components/skill-invocation-message.js.map +1 -0
  246. package/dist/src/foundation/pi-component-adapter/upstream/components/status-indicator.d.ts +31 -0
  247. package/dist/src/foundation/pi-component-adapter/upstream/components/status-indicator.d.ts.map +1 -0
  248. package/dist/src/foundation/pi-component-adapter/upstream/components/status-indicator.js +60 -0
  249. package/dist/src/foundation/pi-component-adapter/upstream/components/status-indicator.js.map +1 -0
  250. package/dist/src/foundation/pi-component-adapter/upstream/components/tree-selector.d.ts +99 -0
  251. package/dist/src/foundation/pi-component-adapter/upstream/components/tree-selector.d.ts.map +1 -0
  252. package/dist/src/foundation/pi-component-adapter/upstream/components/tree-selector.js +1273 -0
  253. package/dist/src/foundation/pi-component-adapter/upstream/components/tree-selector.js.map +1 -0
  254. package/dist/src/foundation/pi-component-adapter/upstream/components/trust-selector.d.ts +34 -0
  255. package/dist/src/foundation/pi-component-adapter/upstream/components/trust-selector.d.ts.map +1 -0
  256. package/dist/src/foundation/pi-component-adapter/upstream/components/trust-selector.js +77 -0
  257. package/dist/src/foundation/pi-component-adapter/upstream/components/trust-selector.js.map +1 -0
  258. package/dist/src/foundation/pi-component-adapter/upstream/external-editor.d.ts +10 -0
  259. package/dist/src/foundation/pi-component-adapter/upstream/external-editor.d.ts.map +1 -0
  260. package/dist/src/foundation/pi-component-adapter/upstream/external-editor.js +40 -0
  261. package/dist/src/foundation/pi-component-adapter/upstream/external-editor.js.map +1 -0
  262. package/dist/src/foundation/pi-component-adapter/upstream/model-search.d.ts +16 -0
  263. package/dist/src/foundation/pi-component-adapter/upstream/model-search.d.ts.map +1 -0
  264. package/dist/src/foundation/pi-component-adapter/upstream/model-search.js +15 -0
  265. package/dist/src/foundation/pi-component-adapter/upstream/model-search.js.map +1 -0
  266. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme-controller.d.ts +26 -0
  267. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme-controller.d.ts.map +1 -0
  268. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme-controller.js +118 -0
  269. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme-controller.js.map +1 -0
  270. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme.d.ts +54 -0
  271. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme.d.ts.map +1 -0
  272. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme.js +311 -0
  273. package/dist/src/foundation/pi-component-adapter/upstream/theme/theme.js.map +1 -0
  274. package/dist/src/foundation/pi-engine-adapter/adapter.d.ts +343 -0
  275. package/dist/src/foundation/pi-engine-adapter/adapter.d.ts.map +1 -0
  276. package/dist/src/foundation/pi-engine-adapter/adapter.js +2365 -0
  277. package/dist/src/foundation/pi-engine-adapter/adapter.js.map +1 -0
  278. package/dist/src/foundation/pi-engine-adapter/conformance.d.ts +14 -0
  279. package/dist/src/foundation/pi-engine-adapter/conformance.d.ts.map +1 -0
  280. package/dist/src/foundation/pi-engine-adapter/conformance.js +85 -0
  281. package/dist/src/foundation/pi-engine-adapter/conformance.js.map +1 -0
  282. package/dist/src/foundation/pi-engine-adapter/index.d.ts +4 -0
  283. package/dist/src/foundation/pi-engine-adapter/index.d.ts.map +1 -0
  284. package/dist/src/foundation/pi-engine-adapter/index.js +4 -0
  285. package/dist/src/foundation/pi-engine-adapter/index.js.map +1 -0
  286. package/dist/src/foundation/pi-engine-adapter/workflows.d.ts +165 -0
  287. package/dist/src/foundation/pi-engine-adapter/workflows.d.ts.map +1 -0
  288. package/dist/src/foundation/pi-engine-adapter/workflows.js +61 -0
  289. package/dist/src/foundation/pi-engine-adapter/workflows.js.map +1 -0
  290. package/dist/src/foundation/pi-tui-runtime-adapter/adapter.d.ts +34 -0
  291. package/dist/src/foundation/pi-tui-runtime-adapter/adapter.d.ts.map +1 -0
  292. package/dist/src/foundation/pi-tui-runtime-adapter/adapter.js +485 -0
  293. package/dist/src/foundation/pi-tui-runtime-adapter/adapter.js.map +1 -0
  294. package/dist/src/foundation/pi-tui-runtime-adapter/conformance.d.ts +14 -0
  295. package/dist/src/foundation/pi-tui-runtime-adapter/conformance.d.ts.map +1 -0
  296. package/dist/src/foundation/pi-tui-runtime-adapter/conformance.js +132 -0
  297. package/dist/src/foundation/pi-tui-runtime-adapter/conformance.js.map +1 -0
  298. package/dist/src/foundation/pi-tui-runtime-adapter/contracts.d.ts +122 -0
  299. package/dist/src/foundation/pi-tui-runtime-adapter/contracts.d.ts.map +1 -0
  300. package/dist/src/foundation/pi-tui-runtime-adapter/contracts.js +2 -0
  301. package/dist/src/foundation/pi-tui-runtime-adapter/contracts.js.map +1 -0
  302. package/dist/src/foundation/pi-tui-runtime-adapter/index.d.ts +4 -0
  303. package/dist/src/foundation/pi-tui-runtime-adapter/index.d.ts.map +1 -0
  304. package/dist/src/foundation/pi-tui-runtime-adapter/index.js +4 -0
  305. package/dist/src/foundation/pi-tui-runtime-adapter/index.js.map +1 -0
  306. package/dist/src/foundation/protocol/client.d.ts +17 -0
  307. package/dist/src/foundation/protocol/client.d.ts.map +1 -0
  308. package/dist/src/foundation/protocol/client.js +127 -0
  309. package/dist/src/foundation/protocol/client.js.map +1 -0
  310. package/dist/src/foundation/protocol/index.d.ts +3 -0
  311. package/dist/src/foundation/protocol/index.d.ts.map +1 -0
  312. package/dist/src/foundation/protocol/index.js +3 -0
  313. package/dist/src/foundation/protocol/index.js.map +1 -0
  314. package/dist/src/foundation/protocol/messages.d.ts +90 -0
  315. package/dist/src/foundation/protocol/messages.d.ts.map +1 -0
  316. package/dist/src/foundation/protocol/messages.js +99 -0
  317. package/dist/src/foundation/protocol/messages.js.map +1 -0
  318. package/dist/src/foundation/release/bootstrap.d.ts +30 -0
  319. package/dist/src/foundation/release/bootstrap.d.ts.map +1 -0
  320. package/dist/src/foundation/release/bootstrap.js +283 -0
  321. package/dist/src/foundation/release/bootstrap.js.map +1 -0
  322. package/dist/src/foundation/release/cohort-selection.d.ts +40 -0
  323. package/dist/src/foundation/release/cohort-selection.d.ts.map +1 -0
  324. package/dist/src/foundation/release/cohort-selection.js +76 -0
  325. package/dist/src/foundation/release/cohort-selection.js.map +1 -0
  326. package/dist/src/foundation/release/cohort-state.d.ts +68 -0
  327. package/dist/src/foundation/release/cohort-state.d.ts.map +1 -0
  328. package/dist/src/foundation/release/cohort-state.js +201 -0
  329. package/dist/src/foundation/release/cohort-state.js.map +1 -0
  330. package/dist/src/foundation/release/development-preview-release.d.ts +49 -0
  331. package/dist/src/foundation/release/development-preview-release.d.ts.map +1 -0
  332. package/dist/src/foundation/release/development-preview-release.js +113 -0
  333. package/dist/src/foundation/release/development-preview-release.js.map +1 -0
  334. package/dist/src/foundation/release/index.d.ts +12 -0
  335. package/dist/src/foundation/release/index.d.ts.map +1 -0
  336. package/dist/src/foundation/release/index.js +12 -0
  337. package/dist/src/foundation/release/index.js.map +1 -0
  338. package/dist/src/foundation/release/process-cleanup.d.ts +15 -0
  339. package/dist/src/foundation/release/process-cleanup.d.ts.map +1 -0
  340. package/dist/src/foundation/release/process-cleanup.js +67 -0
  341. package/dist/src/foundation/release/process-cleanup.js.map +1 -0
  342. package/dist/src/foundation/release/release-gc.d.ts +6 -0
  343. package/dist/src/foundation/release/release-gc.d.ts.map +1 -0
  344. package/dist/src/foundation/release/release-gc.js +17 -0
  345. package/dist/src/foundation/release/release-gc.js.map +1 -0
  346. package/dist/src/foundation/release/release-store.d.ts +11 -0
  347. package/dist/src/foundation/release/release-store.d.ts.map +1 -0
  348. package/dist/src/foundation/release/release-store.js +115 -0
  349. package/dist/src/foundation/release/release-store.js.map +1 -0
  350. package/dist/src/foundation/release/release.d.ts +24 -0
  351. package/dist/src/foundation/release/release.d.ts.map +1 -0
  352. package/dist/src/foundation/release/release.js +151 -0
  353. package/dist/src/foundation/release/release.js.map +1 -0
  354. package/dist/src/foundation/release/stable-release.d.ts +30 -0
  355. package/dist/src/foundation/release/stable-release.d.ts.map +1 -0
  356. package/dist/src/foundation/release/stable-release.js +38 -0
  357. package/dist/src/foundation/release/stable-release.js.map +1 -0
  358. package/dist/src/foundation/release/update-transaction.d.ts +31 -0
  359. package/dist/src/foundation/release/update-transaction.d.ts.map +1 -0
  360. package/dist/src/foundation/release/update-transaction.js +88 -0
  361. package/dist/src/foundation/release/update-transaction.js.map +1 -0
  362. package/dist/src/foundation/release/update.d.ts +55 -0
  363. package/dist/src/foundation/release/update.d.ts.map +1 -0
  364. package/dist/src/foundation/release/update.js +316 -0
  365. package/dist/src/foundation/release/update.js.map +1 -0
  366. package/dist/src/foundation/storage/control-store.d.ts +61 -0
  367. package/dist/src/foundation/storage/control-store.d.ts.map +1 -0
  368. package/dist/src/foundation/storage/control-store.js +459 -0
  369. package/dist/src/foundation/storage/control-store.js.map +1 -0
  370. package/dist/src/foundation/storage/index.d.ts +2 -0
  371. package/dist/src/foundation/storage/index.d.ts.map +1 -0
  372. package/dist/src/foundation/storage/index.js +2 -0
  373. package/dist/src/foundation/storage/index.js.map +1 -0
  374. package/dist/src/foundation/structured-agent-runtime/backpressure.d.ts +47 -0
  375. package/dist/src/foundation/structured-agent-runtime/backpressure.d.ts.map +1 -0
  376. package/dist/src/foundation/structured-agent-runtime/backpressure.js +119 -0
  377. package/dist/src/foundation/structured-agent-runtime/backpressure.js.map +1 -0
  378. package/dist/src/foundation/structured-agent-runtime/commands.d.ts +53 -0
  379. package/dist/src/foundation/structured-agent-runtime/commands.d.ts.map +1 -0
  380. package/dist/src/foundation/structured-agent-runtime/commands.js +165 -0
  381. package/dist/src/foundation/structured-agent-runtime/commands.js.map +1 -0
  382. package/dist/src/foundation/structured-agent-runtime/handshake.d.ts +42 -0
  383. package/dist/src/foundation/structured-agent-runtime/handshake.d.ts.map +1 -0
  384. package/dist/src/foundation/structured-agent-runtime/handshake.js +151 -0
  385. package/dist/src/foundation/structured-agent-runtime/handshake.js.map +1 -0
  386. package/dist/src/foundation/structured-agent-runtime/index.d.ts +6 -0
  387. package/dist/src/foundation/structured-agent-runtime/index.d.ts.map +1 -0
  388. package/dist/src/foundation/structured-agent-runtime/index.js +6 -0
  389. package/dist/src/foundation/structured-agent-runtime/index.js.map +1 -0
  390. package/dist/src/foundation/structured-agent-runtime/reconnection.d.ts +38 -0
  391. package/dist/src/foundation/structured-agent-runtime/reconnection.d.ts.map +1 -0
  392. package/dist/src/foundation/structured-agent-runtime/reconnection.js +130 -0
  393. package/dist/src/foundation/structured-agent-runtime/reconnection.js.map +1 -0
  394. package/dist/src/foundation/structured-agent-runtime/state.d.ts +57 -0
  395. package/dist/src/foundation/structured-agent-runtime/state.d.ts.map +1 -0
  396. package/dist/src/foundation/structured-agent-runtime/state.js +119 -0
  397. package/dist/src/foundation/structured-agent-runtime/state.js.map +1 -0
  398. package/dist/src/foundation/supervision/index.d.ts +4 -0
  399. package/dist/src/foundation/supervision/index.d.ts.map +1 -0
  400. package/dist/src/foundation/supervision/index.js +4 -0
  401. package/dist/src/foundation/supervision/index.js.map +1 -0
  402. package/dist/src/foundation/supervision/main.d.ts +2 -0
  403. package/dist/src/foundation/supervision/main.d.ts.map +1 -0
  404. package/dist/src/foundation/supervision/main.js +40 -0
  405. package/dist/src/foundation/supervision/main.js.map +1 -0
  406. package/dist/src/foundation/supervision/paths.d.ts +2 -0
  407. package/dist/src/foundation/supervision/paths.d.ts.map +1 -0
  408. package/dist/src/foundation/supervision/paths.js +2 -0
  409. package/dist/src/foundation/supervision/paths.js.map +1 -0
  410. package/dist/src/foundation/supervision/server.d.ts +21 -0
  411. package/dist/src/foundation/supervision/server.d.ts.map +1 -0
  412. package/dist/src/foundation/supervision/server.js +283 -0
  413. package/dist/src/foundation/supervision/server.js.map +1 -0
  414. package/dist/src/foundation/transparent-terminal/command-resolution.d.ts +14 -0
  415. package/dist/src/foundation/transparent-terminal/command-resolution.d.ts.map +1 -0
  416. package/dist/src/foundation/transparent-terminal/command-resolution.js +70 -0
  417. package/dist/src/foundation/transparent-terminal/command-resolution.js.map +1 -0
  418. package/dist/src/foundation/transparent-terminal/foreground-broker.d.ts +33 -0
  419. package/dist/src/foundation/transparent-terminal/foreground-broker.d.ts.map +1 -0
  420. package/dist/src/foundation/transparent-terminal/foreground-broker.js +88 -0
  421. package/dist/src/foundation/transparent-terminal/foreground-broker.js.map +1 -0
  422. package/dist/src/foundation/transparent-terminal/index.d.ts +4 -0
  423. package/dist/src/foundation/transparent-terminal/index.d.ts.map +1 -0
  424. package/dist/src/foundation/transparent-terminal/index.js +4 -0
  425. package/dist/src/foundation/transparent-terminal/index.js.map +1 -0
  426. package/dist/src/foundation/transparent-terminal/main.d.ts +10 -0
  427. package/dist/src/foundation/transparent-terminal/main.d.ts.map +1 -0
  428. package/dist/src/foundation/transparent-terminal/main.js +107 -0
  429. package/dist/src/foundation/transparent-terminal/main.js.map +1 -0
  430. package/dist/src/foundation/transparent-terminal/native-launcher.d.ts +26 -0
  431. package/dist/src/foundation/transparent-terminal/native-launcher.d.ts.map +1 -0
  432. package/dist/src/foundation/transparent-terminal/native-launcher.js +147 -0
  433. package/dist/src/foundation/transparent-terminal/native-launcher.js.map +1 -0
  434. package/dist/src/foundation/workspace-contracts/index.d.ts +3 -0
  435. package/dist/src/foundation/workspace-contracts/index.d.ts.map +1 -0
  436. package/dist/src/foundation/workspace-contracts/index.js +3 -0
  437. package/dist/src/foundation/workspace-contracts/index.js.map +1 -0
  438. package/dist/src/foundation/workspace-contracts/model.d.ts +249 -0
  439. package/dist/src/foundation/workspace-contracts/model.d.ts.map +1 -0
  440. package/dist/src/foundation/workspace-contracts/model.js +3 -0
  441. package/dist/src/foundation/workspace-contracts/model.js.map +1 -0
  442. package/dist/src/foundation/workspace-contracts/validation.d.ts +14 -0
  443. package/dist/src/foundation/workspace-contracts/validation.d.ts.map +1 -0
  444. package/dist/src/foundation/workspace-contracts/validation.js +336 -0
  445. package/dist/src/foundation/workspace-contracts/validation.js.map +1 -0
  446. package/docs/architecture/boundaries.md +46 -0
  447. package/docs/architecture/project-structure.md +81 -0
  448. package/docs/architecture/resource-and-data-policy.md +55 -0
  449. package/docs/architecture/terminal-host-proof-gate.md +32 -0
  450. package/docs/architecture/terminal-host-provenance.md +69 -0
  451. package/docs/architecture/terminal-host-spike-evidence.md +39 -0
  452. package/docs/architecture/toolchain.md +66 -0
  453. package/docs/features/launch-profiles.md +50 -0
  454. package/docs/manual-transparent-checkpoint.md +53 -0
  455. package/package.json +73 -0
@@ -0,0 +1,2365 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { copyToClipboard, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, getPackageDir, ProjectTrustStore, SessionManager, } from "@earendil-works/pi-coding-agent";
7
+ import { OWNED_UI_EXTENSION_CONTRACT_VERSION, OWNED_UI_EXTENSION_RENDER_CALLBACKS, OWNED_UI_EXTENSION_UI_CALLBACKS, OWNED_UI_EXTENSION_UI_PROPERTIES, assertOwnedUiCommand, assertOwnedUiExtensionUiPort, assertOwnedUiSnapshot, } from "../owned-ui-contracts/index.js";
8
+ import { PINNED_PI_SETTINGS_CALLBACKS, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "./workflows.js";
9
+ const execFileAsync = promisify(execFile);
10
+ const DEFAULT_SURFACE = {
11
+ columns: 100,
12
+ rows: 32,
13
+ focusedRegion: "editor",
14
+ hardwareCursor: false,
15
+ };
16
+ export class PiEngineAdapter {
17
+ #runtimeFactory;
18
+ #cwd;
19
+ #agentDir;
20
+ #sessionId;
21
+ #workflowHost;
22
+ #workflowInteraction;
23
+ #listeners = new Set();
24
+ #runtime;
25
+ #session;
26
+ #unsubscribe;
27
+ #sequence = 0;
28
+ #viewRevision = 0;
29
+ #lifecycle = "starting";
30
+ #editor = {
31
+ text: "",
32
+ queuedSubmissions: [],
33
+ selection: null,
34
+ cursorOffset: 0,
35
+ historyRevision: 0,
36
+ submitEnabled: false,
37
+ };
38
+ #sessionGeneration = 0;
39
+ #status = {
40
+ title: "Pi",
41
+ workingMessage: null,
42
+ diagnostics: [],
43
+ badges: [],
44
+ };
45
+ #terminal = DEFAULT_SURFACE;
46
+ #activeModel = null;
47
+ #thinkingLevel = "medium";
48
+ #activeCommandIds = [];
49
+ #completedCommands = new Map();
50
+ #transcript = [];
51
+ #messageBlockIds = new WeakMap();
52
+ #messageFallbackIds = new Map();
53
+ #toolBlockIds = new Map();
54
+ #nextBlockSequence = 0;
55
+ #diagnostics = [];
56
+ #eventQueue = [];
57
+ #eventQueueProcessing;
58
+ #droppedEventCount = 0;
59
+ #lastPrompt = null;
60
+ #gitBranch = null;
61
+ #extensionUi;
62
+ #extensionShutdown;
63
+ #extensionBound = false;
64
+ #disposed = false;
65
+ constructor(options = {}) {
66
+ this.#cwd = options.cwd ?? process.cwd();
67
+ this.#agentDir = options.agentDir ?? getAgentDir();
68
+ this.#sessionId = options.sessionId ?? "owned-session-1";
69
+ this.#runtimeFactory = options.createRuntime ?? createDefaultPiRuntime;
70
+ this.#workflowHost = options.workflowHost ?? defaultWorkflowHost();
71
+ this.#workflowInteraction = { prompt: async () => null, notify() { } };
72
+ }
73
+ setWorkflowInteractionHost(interaction) {
74
+ this.#workflowInteraction = interaction;
75
+ }
76
+ get sessionId() {
77
+ return this.#sessionId;
78
+ }
79
+ get sessionGeneration() {
80
+ return this.#sessionGeneration;
81
+ }
82
+ get agentDir() {
83
+ return this.#agentDir;
84
+ }
85
+ get disposed() {
86
+ return this.#disposed;
87
+ }
88
+ async start() {
89
+ if (this.#runtime)
90
+ return this.view();
91
+ const runtime = await this.#runtimeFactory({
92
+ cwd: this.#cwd,
93
+ agentDir: this.#agentDir,
94
+ sessionId: this.#sessionId,
95
+ }).catch(error => {
96
+ this.#lifecycle = "failed";
97
+ this.#addDiagnostic("error", "engine-startup", error instanceof Error ? error.message : String(error), false);
98
+ throw error;
99
+ });
100
+ this.#runtime = runtime;
101
+ this.#gitBranch = await readGitBranch(this.#cwd);
102
+ this.#terminal = {
103
+ ...this.#terminal,
104
+ hardwareCursor: runtime.services.settingsManager?.getShowHardwareCursor?.() ?? this.#terminal.hardwareCursor,
105
+ };
106
+ runtime.setRebindSession(async (session) => {
107
+ this.#bindSession(session);
108
+ this.#emitView();
109
+ });
110
+ for (const diagnostic of [...runtime.diagnostics, ...runtime.services.diagnostics]) {
111
+ this.#addDiagnostic(diagnostic.type === "error" ? "error" : diagnostic.type === "warning" ? "warning" : "info", "engine-startup", diagnostic.message, diagnostic.type !== "error");
112
+ }
113
+ this.#bindSession(runtime.session);
114
+ this.#lifecycle = "ready";
115
+ this.#editor = { ...this.#editor, submitEnabled: true };
116
+ this.#emitEvent({ type: "session-lifecycle", lifecycle: "ready", reason: null });
117
+ this.#emitView();
118
+ return this.view();
119
+ }
120
+ onEvent(listener) {
121
+ this.#listeners.add(listener);
122
+ listener(this.#event({ type: "session-view", view: this.view() }));
123
+ return () => this.#listeners.delete(listener);
124
+ }
125
+ async flushEvents() {
126
+ while (this.#eventQueueProcessing)
127
+ await this.#eventQueueProcessing;
128
+ }
129
+ nonVisualResources() {
130
+ const loader = this.#runtime?.services.resourceLoader;
131
+ if (!loader)
132
+ return [];
133
+ const resources = [];
134
+ const skills = collectionResult(loader.getSkills(), "skills");
135
+ for (const [index, skill] of skills.values.entries()) {
136
+ resources.push({
137
+ kind: "skill",
138
+ id: `skill-${index}-${stringProperty(skill, "name") ?? "unknown"}`,
139
+ label: stringProperty(skill, "name") ?? "Unnamed skill",
140
+ sourcePath: stringProperty(skill, "filePath") ?? stringProperty(skill, "path") ?? stringProperty(skill, "location") ?? null,
141
+ diagnostic: null,
142
+ });
143
+ }
144
+ resources.push(...skills.diagnostics.map((diagnostic, index) => ({
145
+ kind: "skill",
146
+ id: `skill-diagnostic-${index}`,
147
+ label: "Skill diagnostic",
148
+ sourcePath: null,
149
+ diagnostic,
150
+ })));
151
+ const prompts = collectionResult(loader.getPrompts(), "prompts");
152
+ for (const [index, prompt] of prompts.values.entries()) {
153
+ resources.push({
154
+ kind: "prompt-template",
155
+ id: `prompt-${index}-${stringProperty(prompt, "name") ?? "unknown"}`,
156
+ label: stringProperty(prompt, "name") ?? "Prompt template",
157
+ sourcePath: stringProperty(prompt, "filePath") ?? stringProperty(prompt, "path") ?? null,
158
+ diagnostic: null,
159
+ });
160
+ }
161
+ resources.push(...prompts.diagnostics.map((diagnostic, index) => ({
162
+ kind: "prompt-template",
163
+ id: `prompt-diagnostic-${index}`,
164
+ label: "Prompt diagnostic",
165
+ sourcePath: null,
166
+ diagnostic,
167
+ })));
168
+ const agentsFilesResult = loader.getAgentsFiles();
169
+ const agentsFiles = unknownArray(isRecord(agentsFilesResult) ? agentsFilesResult.agentsFiles : undefined);
170
+ for (const [index, file] of agentsFiles.entries()) {
171
+ resources.push({
172
+ kind: "agent-context",
173
+ id: `agent-context-${index}`,
174
+ label: "Agent context",
175
+ sourcePath: stringProperty(file, "path") ?? null,
176
+ diagnostic: null,
177
+ });
178
+ }
179
+ const systemPrompt = loader.getSystemPromptSource();
180
+ if (isRecord(systemPrompt) && typeof systemPrompt.path === "string") {
181
+ resources.push({
182
+ kind: "system-prompt",
183
+ id: "system-prompt",
184
+ label: "System prompt",
185
+ sourcePath: systemPrompt.path,
186
+ diagnostic: null,
187
+ });
188
+ }
189
+ for (const [index, source] of unknownArray(loader.getAppendSystemPromptSources()).entries()) {
190
+ resources.push({
191
+ kind: "system-prompt",
192
+ id: `append-system-prompt-${index}`,
193
+ label: "Append system prompt",
194
+ sourcePath: stringProperty(source, "path") ?? null,
195
+ diagnostic: null,
196
+ });
197
+ }
198
+ if (loader.getThemes !== undefined) {
199
+ const themes = collectionResult(loader.getThemes(), "themes");
200
+ for (const [index, theme] of themes.values.entries()) {
201
+ const sourcePath = stringProperty(theme, "sourcePath");
202
+ if (!sourcePath)
203
+ continue;
204
+ resources.push({
205
+ kind: "theme",
206
+ id: `theme-${index}-${stringProperty(theme, "name") ?? "unknown"}`,
207
+ label: stringProperty(theme, "name") ?? compactResourceLabel(sourcePath),
208
+ sourcePath,
209
+ diagnostic: null,
210
+ });
211
+ }
212
+ resources.push(...themes.diagnostics.map((diagnostic, index) => ({
213
+ kind: "theme",
214
+ id: `theme-diagnostic-${index}`,
215
+ label: "Theme diagnostic",
216
+ sourcePath: null,
217
+ diagnostic,
218
+ })));
219
+ }
220
+ return resources;
221
+ }
222
+ extensionResources() {
223
+ const loader = this.#runtime?.services.resourceLoader;
224
+ if (loader?.getExtensions === undefined)
225
+ return [];
226
+ let result;
227
+ try {
228
+ result = loader.getExtensions();
229
+ }
230
+ catch (error) {
231
+ return [extensionResourceDiagnostic(0, null, `Extension discovery failed: ${error instanceof Error ? error.message : String(error)}`)];
232
+ }
233
+ if (!isRecord(result))
234
+ return [extensionResourceDiagnostic(0, null, "Extension discovery returned a malformed result")];
235
+ const resources = [];
236
+ if (!Array.isArray(result.extensions)) {
237
+ resources.push(extensionResourceDiagnostic(resources.length, null, "Extension discovery returned a malformed extensions collection"));
238
+ }
239
+ else {
240
+ for (const extension of result.extensions) {
241
+ if (!isRecord(extension) || typeof extension.path !== "string" || extension.path.length === 0
242
+ || typeof extension.resolvedPath !== "string" || extension.resolvedPath.length === 0
243
+ || (extension.hidden !== undefined && typeof extension.hidden !== "boolean")) {
244
+ resources.push(extensionResourceDiagnostic(resources.length, null, "Extension discovery returned malformed extension metadata"));
245
+ continue;
246
+ }
247
+ resources.push({
248
+ kind: "extension",
249
+ id: `extension-${resources.length}`,
250
+ sourcePath: extension.path,
251
+ resolvedPath: extension.resolvedPath,
252
+ loaded: true,
253
+ hidden: extension.hidden === true,
254
+ diagnostic: null,
255
+ });
256
+ }
257
+ }
258
+ if (!Array.isArray(result.errors)) {
259
+ resources.push(extensionResourceDiagnostic(resources.length, null, "Extension discovery returned a malformed errors collection"));
260
+ }
261
+ else {
262
+ for (const error of result.errors) {
263
+ if (!isRecord(error) || typeof error.path !== "string" || typeof error.error !== "string") {
264
+ resources.push(extensionResourceDiagnostic(resources.length, null, "Extension discovery returned malformed error metadata"));
265
+ continue;
266
+ }
267
+ resources.push(extensionResourceDiagnostic(resources.length, error.path, error.error));
268
+ }
269
+ }
270
+ return resources;
271
+ }
272
+ visualExtensionSupport() {
273
+ return {
274
+ available: this.#extensionBound,
275
+ contractComplete: true,
276
+ contractVersion: OWNED_UI_EXTENSION_CONTRACT_VERSION,
277
+ binding: this.#extensionBound ? "bound" : "unbound",
278
+ uiCallbacks: OWNED_UI_EXTENSION_UI_CALLBACKS,
279
+ uiProperties: OWNED_UI_EXTENSION_UI_PROPERTIES,
280
+ renderCallbacks: OWNED_UI_EXTENSION_RENDER_CALLBACKS,
281
+ diagnostic: this.#extensionBound
282
+ ? "Pinned public extension UI lifecycle is bound through the AddOne-owned bridge."
283
+ : "The complete AddOne-owned extension UI contract is available; the active session has not been bound to the owned UI bridge.",
284
+ };
285
+ }
286
+ async bindExtensionUi(ui, shutdown) {
287
+ assertPiExtensionUiContext(ui);
288
+ this.#extensionUi = ui;
289
+ this.#extensionShutdown = shutdown;
290
+ await this.#bindExtensionUiToSession();
291
+ }
292
+ async unbindExtensionUi() {
293
+ this.#extensionUi = undefined;
294
+ this.#extensionShutdown = undefined;
295
+ this.#extensionBound = false;
296
+ }
297
+ workflowAutocompleteCommands() {
298
+ const commands = [
299
+ {
300
+ name: "model",
301
+ description: "Select model (opens selector UI)",
302
+ argumentHint: "<provider/model>",
303
+ argumentOptions: this.#modelOptions(),
304
+ source: "builtin",
305
+ },
306
+ {
307
+ name: "login",
308
+ description: "Configure provider authentication",
309
+ argumentHint: "<provider>",
310
+ argumentOptions: this.#loginOptions().map(option => ({ ...option, id: option.id.split(":").at(-1) ?? option.id })),
311
+ source: "builtin",
312
+ },
313
+ ];
314
+ const usedNames = new Set(PINNED_PI_WORKFLOW_COMMAND_NAMES);
315
+ const loader = this.#runtime?.services.resourceLoader;
316
+ if (!loader)
317
+ return commands;
318
+ const prompts = collectionResult(loader.getPrompts(), "prompts");
319
+ for (const prompt of prompts.values) {
320
+ const name = stringProperty(prompt, "name");
321
+ if (!name || usedNames.has(name))
322
+ continue;
323
+ const argumentHint = stringProperty(prompt, "argumentHint");
324
+ commands.push({
325
+ name,
326
+ description: stringProperty(prompt, "description") ?? "Prompt template",
327
+ ...(argumentHint === undefined ? {} : { argumentHint }),
328
+ source: "prompt",
329
+ });
330
+ usedNames.add(name);
331
+ }
332
+ const settings = this.#runtime?.services.settingsManager;
333
+ const skillsEnabled = settings?.getEnableSkillCommands?.() !== false;
334
+ if (skillsEnabled) {
335
+ const skills = collectionResult(loader.getSkills(), "skills");
336
+ for (const skill of skills.values) {
337
+ const resourceName = stringProperty(skill, "name");
338
+ const name = resourceName ? `skill:${resourceName}` : undefined;
339
+ if (!name || usedNames.has(name))
340
+ continue;
341
+ commands.push({ name, description: stringProperty(skill, "description") ?? "Skill", source: "skill" });
342
+ usedNames.add(name);
343
+ }
344
+ }
345
+ const extensionCommands = this.#session?.extensionRunner?.getCommands?.();
346
+ if (Array.isArray(extensionCommands)) {
347
+ for (const command of extensionCommands.filter(isRecord)) {
348
+ const name = stringProperty(command, "name");
349
+ if (!name || usedNames.has(name))
350
+ continue;
351
+ commands.push({ name, description: stringProperty(command, "description") ?? "Extension command", source: "extension" });
352
+ usedNames.add(name);
353
+ }
354
+ }
355
+ return commands;
356
+ }
357
+ async cycleModelWorkflow(direction) {
358
+ try {
359
+ const session = this.#requireWorkflowSession();
360
+ const result = await requireCapability(session.cycleModel, "cycleModel").call(session, direction);
361
+ if (!isRecord(result) || !isRecord(result.model)) {
362
+ return workflowResult("model", "cancelled", "No other model is available");
363
+ }
364
+ const model = readModel(result.model);
365
+ if (model)
366
+ this.#activeModel = model;
367
+ if (result.thinkingLevel !== undefined)
368
+ this.#thinkingLevel = readThinkingLevel(result.thinkingLevel);
369
+ this.#emitView();
370
+ return workflowResult("model", "completed", model ? `Selected model ${model.providerId}/${model.modelId}` : "Selected model");
371
+ }
372
+ catch (error) {
373
+ return workflowResult("model", "failed", error instanceof Error ? error.message : String(error));
374
+ }
375
+ }
376
+ pinnedModelSelectorContext() {
377
+ const session = this.#requireWorkflowSession();
378
+ const runtime = this.#runtime;
379
+ if (!runtime)
380
+ throw new Error("engine runtime is unavailable");
381
+ const scoped = session.getScopedModels?.() ?? session.scopedModels;
382
+ const modelRuntime = runtime.services.modelRuntime;
383
+ const selectorRuntime = typeof modelRuntime.getAvailableSnapshot === "function"
384
+ ? modelRuntime
385
+ : {
386
+ getAvailableSnapshot: () => session.model === undefined ? [] : [session.model],
387
+ getModel: (providerId, modelId) => modelRuntime.getModel(providerId, modelId),
388
+ getError: () => undefined,
389
+ refresh: async () => undefined,
390
+ };
391
+ const settingsManager = runtime.services.settingsManager;
392
+ const selectorSettings = typeof settingsManager?.setDefaultModelAndProvider === "function"
393
+ ? settingsManager
394
+ : { setDefaultModelAndProvider() { } };
395
+ return {
396
+ currentModel: session.model,
397
+ settingsManager: selectorSettings,
398
+ modelRuntime: selectorRuntime,
399
+ scopedModels: Array.isArray(scoped) ? scoped : [],
400
+ };
401
+ }
402
+ pinnedProjectTrustContext() {
403
+ const runtime = this.#runtime;
404
+ if (!runtime)
405
+ throw new Error("engine runtime is unavailable");
406
+ const cwd = resolve(this.#cwd);
407
+ const parent = dirname(cwd);
408
+ const trustStore = new ProjectTrustStore(this.#agentDir);
409
+ const trustOptions = [
410
+ { label: "Trust", trusted: true, updates: [{ path: cwd, decision: true }], savedPath: cwd },
411
+ ...(parent === cwd ? [] : [{
412
+ label: `Trust parent folder (${parent})`,
413
+ trusted: true,
414
+ updates: [{ path: parent, decision: true }, { path: cwd, decision: null }],
415
+ savedPath: parent,
416
+ }]),
417
+ { label: "Do not trust", trusted: false, updates: [{ path: cwd, decision: false }], savedPath: cwd },
418
+ ];
419
+ return {
420
+ cwd,
421
+ savedDecision: trustStore.getEntry(cwd),
422
+ projectTrusted: runtime.services.settingsManager?.isProjectTrusted?.() === true,
423
+ trustOptions,
424
+ };
425
+ }
426
+ persistProjectTrust(updates) {
427
+ new ProjectTrustStore(this.#agentDir).setMany([...updates]);
428
+ }
429
+ pinnedSessionSelectorContext() {
430
+ const session = this.#requireWorkflowSession();
431
+ const manager = session.sessionManager;
432
+ const cwd = manager?.getCwd?.();
433
+ const sessionDir = manager?.getSessionDir?.();
434
+ const currentSessionFilePath = manager?.getSessionFile?.();
435
+ const usesDefaultSessionDir = manager?.usesDefaultSessionDir?.() === true;
436
+ const resolvedCwd = typeof cwd === "string" ? cwd : this.#cwd;
437
+ const resolvedSessionDir = typeof sessionDir === "string" ? sessionDir : undefined;
438
+ return {
439
+ currentSessionFilePath: typeof currentSessionFilePath === "string" ? currentSessionFilePath : undefined,
440
+ loadCurrentSessions: onProgress => SessionManager.list(resolvedCwd, resolvedSessionDir, onProgress),
441
+ loadAllSessions: onProgress => usesDefaultSessionDir
442
+ ? SessionManager.listAll(onProgress)
443
+ : resolvedSessionDir === undefined ? SessionManager.listAll(onProgress) : SessionManager.listAll(resolvedSessionDir, onProgress),
444
+ renameSession: async (sessionFilePath, nextName) => {
445
+ const next = (nextName ?? "").trim();
446
+ if (!next)
447
+ return;
448
+ SessionManager.open(sessionFilePath).appendSessionInfo(next);
449
+ },
450
+ };
451
+ }
452
+ pinnedScopedModelsContext() {
453
+ const session = this.#requireWorkflowSession();
454
+ const runtime = this.#runtime;
455
+ if (!runtime)
456
+ throw new Error("engine runtime is unavailable");
457
+ const models = scopedModelRecords(runtime.services.modelRuntime);
458
+ const scoped = session.getScopedModels?.() ?? session.scopedModels;
459
+ if (Array.isArray(scoped) && scoped.length > 0) {
460
+ return {
461
+ models: models.map(item => item.descriptor),
462
+ enabledModelIds: scoped.map(scopedModelReference).filter((id) => id !== undefined),
463
+ };
464
+ }
465
+ const patterns = runtime.services.settingsManager?.getEnabledModels?.();
466
+ return {
467
+ models: models.map(item => item.descriptor),
468
+ enabledModelIds: Array.isArray(patterns)
469
+ ? resolveConfiguredModelIds(patterns.filter((value) => typeof value === "string"), models)
470
+ : null,
471
+ };
472
+ }
473
+ updateScopedModels(enabledModelIds) {
474
+ const session = this.#requireWorkflowSession();
475
+ const runtime = this.#runtime;
476
+ if (!runtime)
477
+ throw new Error("engine runtime is unavailable");
478
+ const models = scopedModelRecords(runtime.services.modelRuntime);
479
+ const availableIds = new Set(models.map(item => `${item.descriptor.provider}/${item.descriptor.id}`));
480
+ const selected = enabledModelIds?.filter(id => availableIds.has(id)) ?? [];
481
+ const allAvailableEnabled = enabledModelIds !== null && availableIds.size > 0 && selected.length === availableIds.size;
482
+ const scoped = enabledModelIds !== null && selected.length > 0 && !allAvailableEnabled
483
+ ? selected.flatMap(id => {
484
+ const item = models.find(candidate => `${candidate.descriptor.provider}/${candidate.descriptor.id}` === id);
485
+ return item === undefined ? [] : [{ model: item.model }];
486
+ })
487
+ : [];
488
+ requireCapability(session.setScopedModels, "setScopedModels").call(session, scoped);
489
+ this.#emitView();
490
+ }
491
+ persistScopedModels(enabledModelIds) {
492
+ const runtime = this.#runtime;
493
+ if (!runtime)
494
+ throw new Error("engine runtime is unavailable");
495
+ const availableCount = scopedModelRecords(runtime.services.modelRuntime).length;
496
+ const patterns = enabledModelIds === null || enabledModelIds.length === availableCount
497
+ ? undefined
498
+ : [...enabledModelIds];
499
+ requireCapability(runtime.services.settingsManager?.setEnabledModels, "setEnabledModels").call(runtime.services.settingsManager, patterns === undefined ? undefined : [...patterns]);
500
+ }
501
+ async refreshScopedModels(signal) {
502
+ const runtime = this.#runtime;
503
+ if (!runtime)
504
+ throw new Error("engine runtime is unavailable");
505
+ const result = await runtime.services.modelRuntime.refresh?.({ signal });
506
+ const context = this.pinnedScopedModelsContext();
507
+ if (isRecord(result) && result.aborted === true) {
508
+ return { ...context, status: "Model refresh timed out; showing cached models.", statusKind: "warning" };
509
+ }
510
+ const errors = isRecord(result) ? result.errors : undefined;
511
+ if (errors instanceof Map && errors.size > 0) {
512
+ return {
513
+ ...context,
514
+ status: `Could not refresh ${[...errors.keys()].join(", ")}; showing cached models.`,
515
+ statusKind: "warning",
516
+ };
517
+ }
518
+ return { ...context, status: "Model catalogs refreshed.", statusKind: "success" };
519
+ }
520
+ pinnedLoginOptions(authType) {
521
+ return this.#loginOptions(authType);
522
+ }
523
+ pinnedLoginMethodOptions(providerReference) {
524
+ const runtime = this.#runtime;
525
+ if (!runtime)
526
+ throw new Error("engine runtime is unavailable");
527
+ const modelRuntime = runtime.services.modelRuntime;
528
+ const normalized = providerReference.trim().toLowerCase();
529
+ const providers = modelRuntime.getProviders?.();
530
+ const matches = Array.isArray(providers) ? providers.filter(isRecord).filter(candidate => stringProperty(candidate, "id")?.toLowerCase() === normalized
531
+ || stringProperty(candidate, "name")?.toLowerCase() === normalized) : [];
532
+ const providerId = matches.length === 1 ? stringProperty(matches[0], "id") ?? providerReference : providerReference;
533
+ const provider = modelRuntime.getProvider?.(providerId);
534
+ const providerName = stringProperty(provider, "name") ?? providerId;
535
+ const oauth = dynamicObject(dynamicObject(provider, "auth"), "oauth");
536
+ const loginLabel = stringProperty(oauth, "loginLabel") ?? "Sign in with an account";
537
+ const options = this.#loginOptions().filter(option => option.id.endsWith(`:${providerId}`)).map(option => ({
538
+ ...option,
539
+ label: option.id.startsWith("api_key:") ? "Sign in with an API key" : loginLabel,
540
+ }));
541
+ return { title: `Select authentication method for ${providerName}:`, options };
542
+ }
543
+ pinnedLogoutOptions() {
544
+ return this.#logoutOptions();
545
+ }
546
+ pinnedForkOptions() {
547
+ const session = this.#requireWorkflowSession();
548
+ const messages = requireCapability(session.getUserMessagesForForking, "getUserMessagesForForking").call(session);
549
+ return workflowOptions(messages, "entryId", "text");
550
+ }
551
+ pinnedTreeSelectorContext() {
552
+ const manager = this.#requireWorkflowSession().sessionManager;
553
+ const settings = this.#runtime?.services.settingsManager;
554
+ const tree = manager?.getTree?.();
555
+ const leaf = manager?.getLeafId?.();
556
+ const configuredFilter = settings?.getTreeFilterMode?.();
557
+ const filterMode = configuredFilter === "no-tools" || configuredFilter === "user-only" || configuredFilter === "labeled-only" || configuredFilter === "all"
558
+ ? configuredFilter
559
+ : "default";
560
+ return {
561
+ tree: Array.isArray(tree) ? tree : [],
562
+ currentLeafId: typeof leaf === "string" ? leaf : null,
563
+ filterMode,
564
+ skipSummaryPrompt: settings?.getBranchSummarySkipPrompt?.() === true,
565
+ appendLabelChange: (entryId, label) => {
566
+ requireCapability(manager?.appendLabelChange, "appendLabelChange").call(manager, entryId, label);
567
+ },
568
+ };
569
+ }
570
+ pinnedSettingsSnapshot() {
571
+ const session = this.#requireWorkflowSession();
572
+ const settings = this.#runtime?.services.settingsManager;
573
+ const setting = (getter, fallback) => {
574
+ const value = getter?.call(settings);
575
+ return value === undefined ? fallback : value;
576
+ };
577
+ const levels = session.getAvailableThinkingLevels?.();
578
+ const themes = collectionResult(this.#runtime?.services.resourceLoader?.getThemes?.(), "themes").values
579
+ .map(theme => stringProperty(theme, "name"))
580
+ .filter((name) => !!name);
581
+ return {
582
+ autoCompact: typeof session.autoCompactionEnabled === "boolean"
583
+ ? session.autoCompactionEnabled
584
+ : setting(settings?.getCompactionEnabled, true),
585
+ showImages: setting(settings?.getShowImages, true),
586
+ imageWidthCells: setting(settings?.getImageWidthCells, 80),
587
+ autoResizeImages: setting(settings?.getImageAutoResize, true),
588
+ blockImages: setting(settings?.getBlockImages, false),
589
+ enableSkillCommands: setting(settings?.getEnableSkillCommands, true),
590
+ steeringMode: session.steeringMode ?? setting(settings?.getSteeringMode, "one-at-a-time"),
591
+ followUpMode: session.followUpMode ?? setting(settings?.getFollowUpMode, "one-at-a-time"),
592
+ transport: setting(settings?.getTransport, "sse"),
593
+ httpIdleTimeoutMs: setting(settings?.getHttpIdleTimeoutMs, 300_000),
594
+ thinkingLevel: readThinkingLevel(session.thinkingLevel),
595
+ availableThinkingLevels: Array.isArray(levels) ? levels.map(readThinkingLevel) : ["off", "minimal", "low", "medium", "high", "xhigh"],
596
+ currentTheme: setting(settings?.getThemeSetting, setting(settings?.getTheme, "dark")),
597
+ terminalTheme: setting(settings?.getTerminalTheme, "dark"),
598
+ availableThemes: themes.length > 0 ? themes : ["dark", "light"],
599
+ hideThinkingBlock: setting(settings?.getHideThinkingBlock, false),
600
+ mermaidRenderingMode: setting(settings?.getMermaidRenderingMode, "off"),
601
+ showCacheMissNotices: setting(settings?.getShowCacheMissNotices, false),
602
+ collapseChangelog: setting(settings?.getCollapseChangelog, true),
603
+ enableInstallTelemetry: setting(settings?.getEnableInstallTelemetry, true),
604
+ doubleEscapeAction: setting(settings?.getDoubleEscapeAction, "tree"),
605
+ treeFilterMode: setting(settings?.getTreeFilterMode, "default"),
606
+ showHardwareCursor: setting(settings?.getShowHardwareCursor, false),
607
+ editorPaddingX: setting(settings?.getEditorPaddingX, 0),
608
+ outputPad: setting(settings?.getOutputPad, 1),
609
+ autocompleteMaxVisible: setting(settings?.getAutocompleteMaxVisible, 5),
610
+ quietStartup: setting(settings?.getQuietStartup, false),
611
+ defaultProjectTrust: setting(settings?.getDefaultProjectTrust, "ask"),
612
+ clearOnShrink: setting(settings?.getClearOnShrink, false),
613
+ showTerminalProgress: setting(settings?.getShowTerminalProgress, false),
614
+ tuiMode: setting(settings?.getTuiMode, "regular"),
615
+ fullscreenExitOutput: setting(settings?.getFullscreenExitOutput, "transcript"),
616
+ fullscreenScrollbar: setting(settings?.getFullscreenScrollbar, "auto"),
617
+ warnings: setting(settings?.getWarnings, { anthropicExtraUsage: true }),
618
+ };
619
+ }
620
+ pinnedMessageRenderer(customType) {
621
+ return this.#requireWorkflowSession().extensionRunner?.getMessageRenderer?.(customType);
622
+ }
623
+ pinnedToolDefinition(toolName) {
624
+ return this.#requireWorkflowSession().extensionRunner?.getToolDefinition?.(toolName);
625
+ }
626
+ clearQueuedWorkflows() {
627
+ const session = this.#requireWorkflowSession();
628
+ const result = session.clearQueue?.();
629
+ if (!isRecord(result))
630
+ return [];
631
+ return [...readStringArray(result.steering), ...readStringArray(result.followUp)];
632
+ }
633
+ abortBashWorkflow() {
634
+ this.#requireWorkflowSession().abortBash?.();
635
+ }
636
+ async executeBashWorkflow(command, excludeFromContext) {
637
+ const session = this.#requireWorkflowSession();
638
+ const result = await requireCapability(session.executeBash, "executeBash").call(session, command, undefined, { excludeFromContext });
639
+ if (!isRecord(result))
640
+ throw new Error("Pi bash workflow returned a malformed result");
641
+ return {
642
+ command,
643
+ output: typeof result.output === "string" ? result.output : "",
644
+ exitCode: typeof result.exitCode === "number" ? result.exitCode : undefined,
645
+ cancelled: result.cancelled === true,
646
+ truncated: result.truncated === true,
647
+ excludeFromContext,
648
+ };
649
+ }
650
+ applyPinnedSettingValue(callback, value) {
651
+ try {
652
+ return this.#applyPinnedSetting(callback, value, true);
653
+ }
654
+ catch (error) {
655
+ return workflowResult("settings", "failed", error instanceof Error ? error.message : String(error));
656
+ }
657
+ }
658
+ async executeWorkflow(request) {
659
+ try {
660
+ return await this.#performWorkflow(request);
661
+ }
662
+ catch (error) {
663
+ const message = error instanceof Error ? error.message : String(error);
664
+ const contextualMessage = request.command === "export"
665
+ ? `Failed to export session: ${message}`
666
+ : request.command === "reload" ? `Reload failed: ${message}` : message;
667
+ return workflowResult(request.command, "failed", contextualMessage);
668
+ }
669
+ }
670
+ view() {
671
+ return {
672
+ contractVersion: 1,
673
+ sessionId: this.#sessionId,
674
+ revision: this.#viewRevision,
675
+ lifecycle: this.#lifecycle,
676
+ transcript: this.#transcript.map(block => ({ ...block })),
677
+ editor: { ...this.#editor, queuedSubmissions: [...this.#editor.queuedSubmissions] },
678
+ status: {
679
+ ...this.#status,
680
+ diagnostics: [...this.#status.diagnostics],
681
+ badges: [...this.#status.badges],
682
+ usage: this.#readUsage(),
683
+ footer: {
684
+ branch: this.#gitBranch,
685
+ sessionName: this.#session?.sessionManager?.getSessionName() ?? null,
686
+ availableProviderCount: new Set(this.#runtime?.services.modelRuntime.getAvailableSnapshot?.().map(model => model.provider).filter(provider => provider !== undefined) ?? []).size || 1,
687
+ extensionStatuses: [],
688
+ },
689
+ },
690
+ terminal: { ...this.#terminal },
691
+ activeModel: this.#activeModel === null ? null : { ...this.#activeModel },
692
+ thinkingLevel: this.#thinkingLevel,
693
+ activeCommandIds: [...this.#activeCommandIds],
694
+ dialog: null,
695
+ overlay: null,
696
+ customizations: [],
697
+ diagnostics: this.#diagnostics.map(diagnostic => ({ ...diagnostic })),
698
+ };
699
+ }
700
+ snapshot() {
701
+ const snapshot = {
702
+ contractVersion: 1,
703
+ snapshotId: `snapshot-${this.#viewRevision}`,
704
+ sessionId: this.#sessionId,
705
+ sequence: this.#sequence,
706
+ view: this.view(),
707
+ };
708
+ assertOwnedUiSnapshot(snapshot);
709
+ return snapshot;
710
+ }
711
+ async execute(command) {
712
+ assertOwnedUiCommand(command);
713
+ if (command.sessionId !== this.#sessionId) {
714
+ return this.#finishCommand(command, "rejected", "command targets a different owned session");
715
+ }
716
+ if (this.#disposed || !this.#runtime || !this.#session) {
717
+ return this.#finishCommand(command, "rejected", "engine adapter is not running");
718
+ }
719
+ const existing = this.#completedCommands.get(command.correlationId);
720
+ if (existing)
721
+ return existing;
722
+ if (this.#activeCommandIds.includes(command.correlationId)) {
723
+ return this.#finishCommand(command, "rejected", "duplicate engine command correlation id");
724
+ }
725
+ this.#activeCommandIds.push(command.correlationId);
726
+ this.#emitEvent({
727
+ type: "command-outcome",
728
+ correlationId: command.correlationId,
729
+ outcome: "accepted",
730
+ diagnostic: null,
731
+ });
732
+ try {
733
+ await this.#perform(command);
734
+ this.#emitView();
735
+ return this.#recordCommand(command, "completed", null);
736
+ }
737
+ catch (error) {
738
+ const diagnostic = error instanceof Error ? error.message : String(error);
739
+ this.#addDiagnostic("error", "engine-command", diagnostic, true);
740
+ this.#emitView();
741
+ return this.#recordCommand(command, "failed", diagnostic);
742
+ }
743
+ }
744
+ async dispose() {
745
+ if (this.#disposed)
746
+ return;
747
+ this.#disposed = true;
748
+ this.#extensionBound = false;
749
+ this.#extensionUi = undefined;
750
+ this.#extensionShutdown = undefined;
751
+ this.#lifecycle = "stopping";
752
+ this.#emitEvent({ type: "session-lifecycle", lifecycle: "stopping", reason: null });
753
+ this.#unsubscribe?.();
754
+ this.#unsubscribe = undefined;
755
+ await this.#runtime?.dispose();
756
+ this.#lifecycle = "stopped";
757
+ this.#emitEvent({ type: "session-lifecycle", lifecycle: "stopped", reason: null });
758
+ this.#emitView();
759
+ await this.flushEvents();
760
+ }
761
+ async #performWorkflow(request) {
762
+ const session = this.#requireWorkflowSession();
763
+ const runtime = this.#runtime;
764
+ if (!runtime)
765
+ throw new Error("engine runtime is unavailable");
766
+ const argument = request.argument.trim();
767
+ const selected = request.selection?.trim();
768
+ const selection = selected && selected.length > 0 ? selected : undefined;
769
+ switch (request.command) {
770
+ case "settings": {
771
+ if (!selection)
772
+ return workflowResult(request.command, "failed", "Settings requires the owned settings controller");
773
+ return this.#applyPinnedSetting(selection);
774
+ }
775
+ case "model": {
776
+ const reference = selection ?? argument;
777
+ if (!reference)
778
+ return workflowResult(request.command, "failed", "Model requires the owned model controller");
779
+ const [providerId, modelId] = reference.split("/", 2);
780
+ if (!providerId || !modelId)
781
+ return workflowResult(request.command, "failed", "Model requires provider/model");
782
+ const model = runtime.services.modelRuntime.getModel(providerId, modelId);
783
+ if (!model)
784
+ return workflowResult(request.command, "failed", `Model is unavailable: ${reference}`);
785
+ await session.setModel(model);
786
+ this.#activeModel = { providerId, modelId, displayName: stringProperty(model, "name") ?? modelId };
787
+ this.#emitView();
788
+ return workflowResult(request.command, "completed", `Model: ${modelId}`);
789
+ }
790
+ case "scoped-models": {
791
+ if (!selection)
792
+ return workflowResult(request.command, "failed", "Scoped models requires the owned scoped-model controller");
793
+ const [providerId, modelId] = selection.split("/", 2);
794
+ const model = providerId && modelId ? runtime.services.modelRuntime.getModel(providerId, modelId) : undefined;
795
+ if (!model)
796
+ return workflowResult(request.command, "failed", `Model is unavailable: ${selection}`);
797
+ requireCapability(session.setScopedModels, "setScopedModels").call(session, [{ model }]);
798
+ return workflowResult(request.command, "completed", `Enabled scoped model ${selection}`);
799
+ }
800
+ case "export": {
801
+ const path = pathArgument(argument);
802
+ const file = path?.toLowerCase().endsWith(".jsonl")
803
+ ? requireCapability(session.exportToJsonl, "exportToJsonl").call(session, path)
804
+ : await requireCapability(session.exportToHtml, "exportToHtml").call(session, path);
805
+ return workflowResult(request.command, "completed", `Session exported to: ${String(file)}`);
806
+ }
807
+ case "import": {
808
+ const path = pathArgument(argument);
809
+ if (!path)
810
+ return workflowResult(request.command, "failed", "Usage: /import <path.jsonl>");
811
+ if (request.confirmed === undefined) {
812
+ return workflowConfirmation(request.command, `Replace current session with ${path}?`);
813
+ }
814
+ if (!request.confirmed)
815
+ return workflowResult(request.command, "cancelled", "Import cancelled");
816
+ const result = await requireCapability(runtime.importFromJsonl, "importFromJsonl").call(runtime, path);
817
+ if (isRecord(result) && result.cancelled === true)
818
+ return workflowResult(request.command, "cancelled", "Import cancelled");
819
+ return workflowResult(request.command, "completed", `Session imported from: ${path}`);
820
+ }
821
+ case "share": {
822
+ const auth = await this.#workflowHost.runCommand("gh", ["auth", "status"]).catch(error => {
823
+ throw new Error(`GitHub CLI is unavailable or not logged in: ${error instanceof Error ? error.message : String(error)}`);
824
+ });
825
+ if (auth.stderr && !auth.stdout)
826
+ throw new Error(auth.stderr.trim());
827
+ const temporary = join(tmpdir(), `addone-pi-session-${process.pid}.html`);
828
+ try {
829
+ await requireCapability(session.exportToHtml, "exportToHtml").call(session, temporary);
830
+ const gist = await this.#workflowHost.runCommand("gh", ["gist", "create", "--public=false", temporary]);
831
+ const gistUrl = gist.stdout.trim();
832
+ const gistId = gistUrl.split("/").at(-1);
833
+ if (!gistId)
834
+ throw new Error("Failed to parse gist ID from gh output");
835
+ return workflowResult(request.command, "completed", `Share URL: https://pi.gptscript.ai/gist/${gistId}`, gistUrl);
836
+ }
837
+ finally {
838
+ await rm(temporary, { force: true });
839
+ }
840
+ }
841
+ case "copy": {
842
+ const text = requireCapability(session.getLastAssistantText, "getLastAssistantText").call(session);
843
+ if (typeof text !== "string" || text.length === 0)
844
+ return workflowResult(request.command, "failed", "No agent messages to copy yet.");
845
+ await this.#workflowHost.copyText(text);
846
+ return workflowResult(request.command, "completed", "Copied last agent message to clipboard");
847
+ }
848
+ case "name": {
849
+ const manager = session.sessionManager;
850
+ if (!argument) {
851
+ const current = manager?.getSessionName();
852
+ return typeof current === "string"
853
+ ? workflowResult(request.command, "completed", `Session name: ${current}`)
854
+ : workflowResult(request.command, "failed", "Usage: /name <name>");
855
+ }
856
+ requireCapability(session.setSessionName, "setSessionName").call(session, argument);
857
+ const normalized = manager?.getSessionName();
858
+ const actual = typeof normalized === "string" ? normalized : argument;
859
+ return workflowResult(request.command, "completed", `Session name set: ${actual}`, actual === argument ? undefined : `Session name was normalized from ${JSON.stringify(argument)} to ${JSON.stringify(actual)}`);
860
+ }
861
+ case "session": {
862
+ const manager = session.sessionManager;
863
+ const stats = requireCapability(session.getSessionStats, "getSessionStats").call(session);
864
+ const entries = manager?.getEntries();
865
+ return {
866
+ ...workflowResult(request.command, "completed", "Session Info"),
867
+ presentation: pinnedSessionInfoPresentation(stats, manager?.getSessionName(), Array.isArray(entries) ? entries : [], runtime.services.modelRuntime),
868
+ };
869
+ }
870
+ case "changelog": {
871
+ const changelog = await this.#workflowHost.readChangelog();
872
+ return workflowResult(request.command, "completed", "What's New", changelog);
873
+ }
874
+ case "hotkeys":
875
+ return workflowResult(request.command, "completed", "Keyboard Shortcuts", pinnedHotkeySummary());
876
+ case "fork": {
877
+ if (!selection)
878
+ return workflowResult(request.command, "failed", "Fork requires the owned user-message controller");
879
+ const result = await requireCapability(runtime.fork, "fork").call(runtime, selection, { position: "before" });
880
+ if (isRecord(result) && result.cancelled === true)
881
+ return workflowResult(request.command, "cancelled", "Fork cancelled");
882
+ return workflowResult(request.command, "completed", "Forked to new session");
883
+ }
884
+ case "clone": {
885
+ const manager = session.sessionManager;
886
+ const leaf = manager?.getLeafId?.();
887
+ if (typeof leaf !== "string")
888
+ return workflowResult(request.command, "failed", "No session position is available to clone");
889
+ const result = await requireCapability(runtime.fork, "fork").call(runtime, leaf, { position: "at" });
890
+ if (isRecord(result) && result.cancelled === true)
891
+ return workflowResult(request.command, "cancelled", "Clone cancelled");
892
+ return workflowResult(request.command, "completed", "Cloned to new session");
893
+ }
894
+ case "tree": {
895
+ if (!selection)
896
+ return workflowResult(request.command, "failed", "Tree navigation requires the owned tree controller");
897
+ const navigateTree = requireCapability(session.navigateTree, "navigateTree");
898
+ const result = request.treeSummary === undefined
899
+ ? await navigateTree.call(session, selection)
900
+ : await navigateTree.call(session, selection, {
901
+ summarize: request.treeSummary.summarize,
902
+ ...(request.treeSummary.customInstructions === undefined ? {} : { customInstructions: request.treeSummary.customInstructions }),
903
+ });
904
+ if (isRecord(result) && result.aborted === true)
905
+ return workflowResult(request.command, "cancelled", "Branch summarization cancelled");
906
+ if (isRecord(result) && result.cancelled === true)
907
+ return workflowResult(request.command, "cancelled", "Navigation cancelled");
908
+ return workflowResult(request.command, "completed", "Navigated to selected point");
909
+ }
910
+ case "trust": {
911
+ if (!selection)
912
+ return workflowResult(request.command, "failed", "Trust requires the owned trust controller");
913
+ requireCapability(runtime.services.settingsManager?.setProjectTrusted, "setProjectTrusted").call(runtime.services.settingsManager, selection === "trust");
914
+ return workflowResult(request.command, "completed", selection === "trust" ? "Project trusted" : "Project trust removed");
915
+ }
916
+ case "login": {
917
+ if (!selection && !argument)
918
+ return workflowResult(request.command, "failed", "Login requires the owned authentication controller");
919
+ const modelRuntime = runtime.services.modelRuntime;
920
+ let loginSelection = selection ?? argument;
921
+ if (!selection && argument && !argument.includes(":")) {
922
+ const normalized = argument.toLowerCase();
923
+ const providers = modelRuntime.getProviders?.();
924
+ const providerMatches = Array.isArray(providers) ? providers.filter(isRecord).filter(candidate => stringProperty(candidate, "id")?.toLowerCase() === normalized
925
+ || stringProperty(candidate, "name")?.toLowerCase() === normalized) : [];
926
+ const providerReference = providerMatches.length === 1 ? stringProperty(providerMatches[0], "id") ?? argument : argument;
927
+ const matching = this.#loginOptions().filter(option => option.id.endsWith(`:${providerReference}`));
928
+ if (matching.length > 1) {
929
+ const provider = modelRuntime.getProvider?.(providerReference);
930
+ const providerName = stringProperty(provider, "name") ?? providerReference;
931
+ return workflowResult(request.command, "failed", `Authentication method for ${providerName} requires the owned authentication controller`);
932
+ }
933
+ if (matching[0])
934
+ loginSelection = matching[0].id;
935
+ }
936
+ const [authTypeValue = "oauth", providerId = loginSelection] = loginSelection.includes(":")
937
+ ? loginSelection.split(":", 2)
938
+ : ["oauth", loginSelection];
939
+ const authType = authTypeValue === "api_key" ? "api_key" : "oauth";
940
+ const provider = modelRuntime.getProvider?.(providerId);
941
+ const providerName = stringProperty(provider, "name") ?? providerId;
942
+ this.#workflowInteraction.startLogin?.({ providerId, providerName, authType });
943
+ try {
944
+ await requireCapability(modelRuntime.login, "login").call(modelRuntime, providerId, authType, {
945
+ signal: AbortSignal.timeout(120_000),
946
+ prompt: async (prompt) => {
947
+ const promptType = stringProperty(prompt, "type");
948
+ const options = isRecord(prompt) && Array.isArray(prompt.options)
949
+ ? prompt.options.filter(isRecord).flatMap(option => {
950
+ const id = stringProperty(option, "id");
951
+ const label = stringProperty(option, "label");
952
+ return id && label ? [{ id, label }] : [];
953
+ })
954
+ : [];
955
+ const response = await this.#workflowInteraction.prompt({
956
+ type: promptType === "select"
957
+ ? "select"
958
+ : promptType === "manual_code"
959
+ ? "manual-code"
960
+ : authType === "api_key"
961
+ ? "secret"
962
+ : "text",
963
+ message: stringProperty(prompt, "message") ?? `Authenticate ${providerName}`,
964
+ ...(stringProperty(prompt, "placeholder") === undefined ? {} : { placeholder: stringProperty(prompt, "placeholder") }),
965
+ ...(options.length === 0 ? {} : { options }),
966
+ });
967
+ if (response === null)
968
+ throw new Error("Login cancelled");
969
+ return response;
970
+ },
971
+ notify: (event) => {
972
+ const notification = workflowLoginNotification(event);
973
+ if (notification)
974
+ this.#workflowInteraction.notify(notification);
975
+ },
976
+ });
977
+ }
978
+ catch (error) {
979
+ if (error instanceof Error && error.message === "Login cancelled")
980
+ return workflowResult(request.command, "cancelled", "Login cancelled");
981
+ throw error;
982
+ }
983
+ finally {
984
+ this.#workflowInteraction.finishLogin?.();
985
+ }
986
+ return workflowResult(request.command, "completed", `Logged in to ${providerName}. Credentials saved to ${join(this.#agentDir, "auth.json")}`);
987
+ }
988
+ case "logout": {
989
+ if (!selection)
990
+ return workflowResult(request.command, "failed", "Logout requires the owned authentication controller");
991
+ const [credentialType = "oauth", providerId = selection] = selection.includes(":") ? selection.split(":", 2) : ["oauth", selection];
992
+ const modelRuntime = runtime.services.modelRuntime;
993
+ await requireCapability(modelRuntime.logout, "logout").call(modelRuntime, providerId, { signal: AbortSignal.timeout(15_000) });
994
+ const provider = modelRuntime.getProvider?.(providerId);
995
+ const providerName = stringProperty(provider, "name") ?? providerId;
996
+ return workflowResult(request.command, "completed", credentialType === "api_key"
997
+ ? `Removed stored API key for ${providerName}. Environment variables and models.json config are unchanged.`
998
+ : `Logged out of ${providerName}`);
999
+ }
1000
+ case "new": {
1001
+ const result = await runtime.newSession();
1002
+ if (isRecord(result) && result.cancelled === true)
1003
+ return workflowResult(request.command, "cancelled", "New session cancelled");
1004
+ return workflowResult(request.command, "completed", "✓ New session started");
1005
+ }
1006
+ case "compact": {
1007
+ await session.compact(argument || undefined);
1008
+ return workflowResult(request.command, "completed", "Compaction requested");
1009
+ }
1010
+ case "resume": {
1011
+ if (!selection && !argument)
1012
+ return workflowResult(request.command, "failed", "Resume requires the owned session controller");
1013
+ const sessionPath = selection ?? argument;
1014
+ try {
1015
+ const result = await runtime.switchSession(sessionPath);
1016
+ if (isRecord(result) && result.cancelled === true)
1017
+ return workflowResult(request.command, "cancelled", "Resume cancelled");
1018
+ return workflowResult(request.command, "completed", "Resumed session");
1019
+ }
1020
+ catch (error) {
1021
+ const issue = isRecord(error) && isRecord(error.issue) ? error.issue : undefined;
1022
+ const fallbackCwd = issue === undefined ? undefined : stringProperty(issue, "fallbackCwd");
1023
+ if (fallbackCwd === undefined)
1024
+ throw error;
1025
+ if (request.confirmed === undefined) {
1026
+ const sessionCwd = stringProperty(issue, "sessionCwd") ?? "the session working directory";
1027
+ return workflowConfirmation(request.command, `cwd from session file does not exist\n${sessionCwd}\n\ncontinue in current cwd\n${fallbackCwd}`);
1028
+ }
1029
+ if (!request.confirmed)
1030
+ return workflowResult(request.command, "cancelled", "Resume cancelled");
1031
+ const result = await runtime.switchSession(sessionPath, { cwdOverride: fallbackCwd });
1032
+ if (isRecord(result) && result.cancelled === true)
1033
+ return workflowResult(request.command, "cancelled", "Resume cancelled");
1034
+ return workflowResult(request.command, "completed", "Resumed session in current cwd");
1035
+ }
1036
+ }
1037
+ case "reload": {
1038
+ if (session.isStreaming)
1039
+ return workflowResult(request.command, "failed", "Wait for the current response to finish before reloading.");
1040
+ if (session.isCompacting)
1041
+ return workflowResult(request.command, "failed", "Wait for compaction to finish before reloading.");
1042
+ await requireCapability(session.reload, "reload").call(session);
1043
+ await this.#bindExtensionUiToSession();
1044
+ return workflowResult(request.command, "completed", "Reloaded keybindings, extensions, skills, prompts, themes, and context files");
1045
+ }
1046
+ case "quit": {
1047
+ await this.dispose();
1048
+ return workflowResult(request.command, "completed", "Shutdown complete");
1049
+ }
1050
+ case "debug": {
1051
+ const debugPath = join(this.#agentDir, "pi-debug.log");
1052
+ await mkdir(dirname(debugPath), { recursive: true });
1053
+ await writeFile(debugPath, `${JSON.stringify(this.snapshot(), null, 2)}\n`, "utf8");
1054
+ return workflowResult(request.command, "completed", "✓ Debug log written", debugPath);
1055
+ }
1056
+ case "arminsayshi":
1057
+ return workflowResult(request.command, "completed", "Armin says hi");
1058
+ case "dementedelves":
1059
+ return workflowResult(request.command, "completed", "Demented elves announcement");
1060
+ }
1061
+ }
1062
+ #requireWorkflowSession() {
1063
+ if (this.#disposed || !this.#runtime || !this.#session)
1064
+ throw new Error("engine adapter is not running");
1065
+ return this.#session;
1066
+ }
1067
+ #modelOptions() {
1068
+ const runtime = this.#runtime;
1069
+ if (!runtime)
1070
+ return [];
1071
+ const models = runtime.services.modelRuntime.getAvailableSnapshot?.();
1072
+ if (!Array.isArray(models)) {
1073
+ const active = this.#activeModel;
1074
+ return active ? [{ id: `${active.providerId}/${active.modelId}`, label: active.displayName, description: `${active.providerId}/${active.modelId}` }] : [];
1075
+ }
1076
+ return models.filter(isRecord).flatMap(model => {
1077
+ const provider = stringProperty(model, "provider");
1078
+ const id = stringProperty(model, "id");
1079
+ if (!provider || !id)
1080
+ return [];
1081
+ return [{ id: `${provider}/${id}`, label: stringProperty(model, "name") ?? id, description: `${provider}/${id}` }];
1082
+ });
1083
+ }
1084
+ #loginOptions(authType) {
1085
+ const runtime = this.#runtime;
1086
+ const providers = runtime?.services.modelRuntime.getProviders?.();
1087
+ if (!Array.isArray(providers))
1088
+ return [];
1089
+ return providers.filter(isRecord).flatMap(provider => {
1090
+ const id = stringProperty(provider, "id");
1091
+ if (!id)
1092
+ return [];
1093
+ const name = stringProperty(provider, "name") ?? id;
1094
+ const auth = isRecord(provider.auth) ? provider.auth : {};
1095
+ return [
1096
+ ...(authType !== "api_key" && auth.oauth ? [{ id: `oauth:${id}`, label: name, description: "Account / OAuth" }] : []),
1097
+ ...(authType !== "oauth" && auth.apiKey ? [{ id: `api_key:${id}`, label: name, description: "API key" }] : []),
1098
+ ];
1099
+ });
1100
+ }
1101
+ async #logoutOptions() {
1102
+ const runtime = this.#runtime;
1103
+ if (!runtime)
1104
+ return [];
1105
+ const modelRuntime = runtime.services.modelRuntime;
1106
+ const credentials = await requireCapability(modelRuntime.listCredentials, "listCredentials").call(modelRuntime, { signal: AbortSignal.timeout(15_000) });
1107
+ if (!Array.isArray(credentials))
1108
+ return [];
1109
+ return credentials.filter(isRecord).flatMap(credential => {
1110
+ const providerId = stringProperty(credential, "providerId");
1111
+ if (!providerId)
1112
+ return [];
1113
+ const credentialType = stringProperty(credential, "type") === "api_key" ? "api_key" : "oauth";
1114
+ const provider = modelRuntime.getProvider?.(providerId);
1115
+ return [{
1116
+ id: `${credentialType}:${providerId}`,
1117
+ label: stringProperty(provider, "name") ?? providerId,
1118
+ description: credentialType,
1119
+ }];
1120
+ });
1121
+ }
1122
+ async #sessionOptions() {
1123
+ const session = this.#requireWorkflowSession();
1124
+ const manager = session.sessionManager;
1125
+ const runtimeSessions = await this.#runtime?.listSessions?.();
1126
+ if (Array.isArray(runtimeSessions))
1127
+ return sessionInfoOptions(runtimeSessions);
1128
+ const cwd = manager?.getCwd?.();
1129
+ const sessionDir = manager?.getSessionDir?.();
1130
+ if (typeof cwd !== "string")
1131
+ return [];
1132
+ return sessionInfoOptions(await SessionManager.list(cwd, typeof sessionDir === "string" ? sessionDir : undefined));
1133
+ }
1134
+ #applyPinnedSetting(selection, selectedValue, hasSelectedValue = false) {
1135
+ if (!PINNED_PI_SETTINGS_CALLBACKS.includes(selection)) {
1136
+ return workflowResult("settings", "failed", `Unknown setting callback: ${selection}`);
1137
+ }
1138
+ const callback = selection;
1139
+ if (callback === "onCancel")
1140
+ return workflowResult("settings", "cancelled", "Settings cancelled");
1141
+ if (callback === "onThemePreview")
1142
+ return workflowResult("settings", "completed", "Theme preview refreshed");
1143
+ if (!hasSelectedValue) {
1144
+ const snapshot = this.pinnedSettingsSnapshot();
1145
+ const currentValues = {
1146
+ onAutoCompactChange: snapshot.autoCompact,
1147
+ onShowImagesChange: snapshot.showImages,
1148
+ onImageWidthCellsChange: snapshot.imageWidthCells,
1149
+ onAutoResizeImagesChange: snapshot.autoResizeImages,
1150
+ onBlockImagesChange: snapshot.blockImages,
1151
+ onEnableSkillCommandsChange: snapshot.enableSkillCommands,
1152
+ onSteeringModeChange: snapshot.steeringMode,
1153
+ onFollowUpModeChange: snapshot.followUpMode,
1154
+ onTransportChange: snapshot.transport,
1155
+ onHttpIdleTimeoutMsChange: snapshot.httpIdleTimeoutMs,
1156
+ onThinkingLevelChange: snapshot.thinkingLevel,
1157
+ onThemeChange: snapshot.currentTheme,
1158
+ onHideThinkingBlockChange: snapshot.hideThinkingBlock,
1159
+ onMermaidRenderingModeChange: snapshot.mermaidRenderingMode,
1160
+ onShowCacheMissNoticesChange: snapshot.showCacheMissNotices,
1161
+ onCollapseChangelogChange: snapshot.collapseChangelog,
1162
+ onEnableInstallTelemetryChange: snapshot.enableInstallTelemetry,
1163
+ onQuietStartupChange: snapshot.quietStartup,
1164
+ onDefaultProjectTrustChange: snapshot.defaultProjectTrust,
1165
+ onDoubleEscapeActionChange: snapshot.doubleEscapeAction,
1166
+ onTreeFilterModeChange: snapshot.treeFilterMode,
1167
+ onShowHardwareCursorChange: snapshot.showHardwareCursor,
1168
+ onEditorPaddingXChange: snapshot.editorPaddingX,
1169
+ onOutputPadChange: snapshot.outputPad,
1170
+ onAutocompleteMaxVisibleChange: snapshot.autocompleteMaxVisible,
1171
+ onClearOnShrinkChange: snapshot.clearOnShrink,
1172
+ onShowTerminalProgressChange: snapshot.showTerminalProgress,
1173
+ onTuiModeChange: snapshot.tuiMode,
1174
+ onFullscreenExitOutputChange: snapshot.fullscreenExitOutput,
1175
+ onFullscreenScrollbarChange: snapshot.fullscreenScrollbar,
1176
+ onWarningsChange: snapshot.warnings,
1177
+ };
1178
+ selectedValue = currentValues[callback];
1179
+ hasSelectedValue = true;
1180
+ }
1181
+ const settings = this.#runtime?.services.settingsManager;
1182
+ if (!settings)
1183
+ return workflowResult("settings", "failed", "Settings are unavailable");
1184
+ const session = this.#requireWorkflowSession();
1185
+ const apply = (setter, name) => requireCapability(setter, name).call(settings, selectedValue);
1186
+ switch (callback) {
1187
+ case "onAutoCompactChange":
1188
+ session.setAutoCompactionEnabled?.(selectedValue);
1189
+ apply(settings.setCompactionEnabled, "setCompactionEnabled");
1190
+ break;
1191
+ case "onThinkingLevelChange":
1192
+ session.setThinkingLevel(selectedValue);
1193
+ break;
1194
+ case "onShowImagesChange":
1195
+ apply(settings.setShowImages, "setShowImages");
1196
+ break;
1197
+ case "onImageWidthCellsChange":
1198
+ apply(settings.setImageWidthCells, "setImageWidthCells");
1199
+ break;
1200
+ case "onAutoResizeImagesChange":
1201
+ apply(settings.setImageAutoResize, "setImageAutoResize");
1202
+ break;
1203
+ case "onBlockImagesChange":
1204
+ apply(settings.setBlockImages, "setBlockImages");
1205
+ break;
1206
+ case "onEnableSkillCommandsChange":
1207
+ apply(settings.setEnableSkillCommands, "setEnableSkillCommands");
1208
+ break;
1209
+ case "onSteeringModeChange":
1210
+ apply(settings.setSteeringMode, "setSteeringMode");
1211
+ break;
1212
+ case "onFollowUpModeChange":
1213
+ apply(settings.setFollowUpMode, "setFollowUpMode");
1214
+ break;
1215
+ case "onTransportChange":
1216
+ apply(settings.setTransport, "setTransport");
1217
+ break;
1218
+ case "onHttpIdleTimeoutMsChange":
1219
+ apply(settings.setHttpIdleTimeoutMs, "setHttpIdleTimeoutMs");
1220
+ break;
1221
+ case "onThemeChange":
1222
+ apply(settings.setTheme, "setTheme");
1223
+ break;
1224
+ case "onHideThinkingBlockChange":
1225
+ apply(settings.setHideThinkingBlock, "setHideThinkingBlock");
1226
+ break;
1227
+ case "onMermaidRenderingModeChange":
1228
+ apply(settings.setMermaidRenderingMode, "setMermaidRenderingMode");
1229
+ break;
1230
+ case "onShowCacheMissNoticesChange":
1231
+ apply(settings.setShowCacheMissNotices, "setShowCacheMissNotices");
1232
+ break;
1233
+ case "onCollapseChangelogChange":
1234
+ apply(settings.setCollapseChangelog, "setCollapseChangelog");
1235
+ break;
1236
+ case "onEnableInstallTelemetryChange":
1237
+ apply(settings.setEnableInstallTelemetry, "setEnableInstallTelemetry");
1238
+ break;
1239
+ case "onQuietStartupChange":
1240
+ apply(settings.setQuietStartup, "setQuietStartup");
1241
+ break;
1242
+ case "onDefaultProjectTrustChange":
1243
+ apply(settings.setDefaultProjectTrust, "setDefaultProjectTrust");
1244
+ break;
1245
+ case "onDoubleEscapeActionChange":
1246
+ apply(settings.setDoubleEscapeAction, "setDoubleEscapeAction");
1247
+ break;
1248
+ case "onTreeFilterModeChange":
1249
+ apply(settings.setTreeFilterMode, "setTreeFilterMode");
1250
+ break;
1251
+ case "onShowHardwareCursorChange":
1252
+ apply(settings.setShowHardwareCursor, "setShowHardwareCursor");
1253
+ break;
1254
+ case "onEditorPaddingXChange":
1255
+ apply(settings.setEditorPaddingX, "setEditorPaddingX");
1256
+ break;
1257
+ case "onOutputPadChange":
1258
+ apply(settings.setOutputPad, "setOutputPad");
1259
+ break;
1260
+ case "onAutocompleteMaxVisibleChange":
1261
+ apply(settings.setAutocompleteMaxVisible, "setAutocompleteMaxVisible");
1262
+ break;
1263
+ case "onClearOnShrinkChange":
1264
+ apply(settings.setClearOnShrink, "setClearOnShrink");
1265
+ break;
1266
+ case "onShowTerminalProgressChange":
1267
+ apply(settings.setShowTerminalProgress, "setShowTerminalProgress");
1268
+ break;
1269
+ case "onTuiModeChange":
1270
+ apply(settings.setTuiMode, "setTuiMode");
1271
+ break;
1272
+ case "onFullscreenExitOutputChange":
1273
+ apply(settings.setFullscreenExitOutput, "setFullscreenExitOutput");
1274
+ break;
1275
+ case "onFullscreenScrollbarChange":
1276
+ apply(settings.setFullscreenScrollbar, "setFullscreenScrollbar");
1277
+ break;
1278
+ case "onWarningsChange":
1279
+ apply(settings.setWarnings, "setWarnings");
1280
+ break;
1281
+ default: return workflowResult("settings", "failed", `${settingLabel(callback)} is unavailable in this runtime`);
1282
+ }
1283
+ this.#emitView();
1284
+ return workflowResult("settings", "completed", `${settingLabel(callback)}: ${String(selectedValue)}`);
1285
+ }
1286
+ async #perform(command) {
1287
+ const runtime = this.#runtime;
1288
+ const session = this.#session;
1289
+ if (!runtime || !session)
1290
+ throw new Error("engine session is unavailable");
1291
+ switch (command.type) {
1292
+ case "prompt": {
1293
+ this.#lastPrompt = command.text;
1294
+ await session.prompt(command.text, session.isStreaming ? { streamingBehavior: "followUp" } : undefined);
1295
+ return;
1296
+ }
1297
+ case "steer":
1298
+ this.#lastPrompt = command.text;
1299
+ await session.steer(command.text);
1300
+ return;
1301
+ case "follow-up":
1302
+ this.#lastPrompt = command.text;
1303
+ await session.followUp(command.text);
1304
+ return;
1305
+ case "abort":
1306
+ if (session.isRetrying)
1307
+ session.abortRetry();
1308
+ if (session.isCompacting)
1309
+ session.abortCompaction();
1310
+ await session.abort();
1311
+ return;
1312
+ case "retry":
1313
+ if (this.#lastPrompt === null)
1314
+ throw new Error("no previous prompt is available to retry");
1315
+ await session.prompt(this.#lastPrompt, session.isStreaming ? { streamingBehavior: "followUp" } : undefined);
1316
+ return;
1317
+ case "compact":
1318
+ await session.compact();
1319
+ return;
1320
+ case "set-model": {
1321
+ const model = runtime.services.modelRuntime.getModel(command.model.providerId, command.model.modelId);
1322
+ if (!model) {
1323
+ throw new Error(`model is unavailable: ${command.model.providerId}/${command.model.modelId}`);
1324
+ }
1325
+ await session.setModel(model);
1326
+ this.#activeModel = { ...command.model };
1327
+ return;
1328
+ }
1329
+ case "set-thinking-level":
1330
+ session.setThinkingLevel(command.thinkingLevel);
1331
+ this.#thinkingLevel = command.thinkingLevel;
1332
+ return;
1333
+ case "new-session":
1334
+ await runtime.newSession();
1335
+ return;
1336
+ case "resume-session":
1337
+ await runtime.switchSession(command.sessionPath);
1338
+ return;
1339
+ case "resize-surface":
1340
+ this.#terminal = { ...command.surface };
1341
+ this.#emitEvent({ type: "terminal-surface", surface: this.#terminal });
1342
+ return;
1343
+ case "shutdown":
1344
+ await this.dispose();
1345
+ return;
1346
+ case "set-setting":
1347
+ case "apply-customization":
1348
+ case "remove-customization":
1349
+ throw new Error("owned UI state commands belong to the owned UI layer, not the Pi engine adapter");
1350
+ }
1351
+ }
1352
+ #bindSession(session) {
1353
+ this.#unsubscribe?.();
1354
+ this.#sessionGeneration += 1;
1355
+ this.#session = session;
1356
+ this.#activeCommandIds = [];
1357
+ this.#completedCommands.clear();
1358
+ this.#lastPrompt = null;
1359
+ this.#editor = {
1360
+ text: "",
1361
+ queuedSubmissions: [],
1362
+ selection: null,
1363
+ cursorOffset: 0,
1364
+ historyRevision: this.#editor.historyRevision + 1,
1365
+ submitEnabled: true,
1366
+ };
1367
+ this.#status = { ...this.#status, workingMessage: null, badges: [] };
1368
+ this.#activeModel = readModel(session.model);
1369
+ this.#thinkingLevel = readThinkingLevel(session.thinkingLevel);
1370
+ this.#rebuildTranscript(session.messages, "finalized");
1371
+ this.#unsubscribe = session.subscribe(event => this.#handlePiEvent(event));
1372
+ if (this.#extensionUi !== undefined)
1373
+ void this.#bindExtensionUiToSession();
1374
+ }
1375
+ async #bindExtensionUiToSession() {
1376
+ const session = this.#session;
1377
+ const ui = this.#extensionUi;
1378
+ if (session === undefined || ui === undefined || session.bindExtensions === undefined) {
1379
+ this.#extensionBound = false;
1380
+ return;
1381
+ }
1382
+ try {
1383
+ await session.bindExtensions({
1384
+ uiContext: ui,
1385
+ mode: "tui",
1386
+ shutdownHandler: () => this.#extensionShutdown?.(),
1387
+ onError: error => {
1388
+ const message = isRecord(error) && typeof error.error === "string"
1389
+ ? error.error
1390
+ : error instanceof Error ? error.message : String(error);
1391
+ this.#addDiagnostic("warning", "extension-ui", message, true);
1392
+ this.#emitView();
1393
+ },
1394
+ });
1395
+ this.#extensionBound = true;
1396
+ this.#emitView();
1397
+ }
1398
+ catch (error) {
1399
+ this.#extensionBound = false;
1400
+ this.#addDiagnostic("error", "extension-ui-bind", error instanceof Error ? error.message : String(error), true);
1401
+ this.#emitView();
1402
+ }
1403
+ }
1404
+ #handlePiEvent(event) {
1405
+ if (!isRecord(event) || typeof event.type !== "string")
1406
+ return;
1407
+ switch (event.type) {
1408
+ case "agent_start":
1409
+ this.#lifecycle = "busy";
1410
+ this.#status = { ...this.#status, workingMessage: "Working..." };
1411
+ this.#emitEvent({ type: "session-lifecycle", lifecycle: "busy", reason: null });
1412
+ this.#emitEvent({ type: "status", status: this.#status });
1413
+ return;
1414
+ case "message_start":
1415
+ this.#upsertMessageBlock(event.message, "live");
1416
+ return;
1417
+ case "message_update": {
1418
+ const block = this.#upsertMessageBlock(event.message, "live");
1419
+ if (block && isRecord(event.assistantMessageEvent) && typeof event.assistantMessageEvent.delta === "string") {
1420
+ this.#upsertTranscriptBlock({
1421
+ ...block,
1422
+ text: block.text.endsWith(event.assistantMessageEvent.delta)
1423
+ ? block.text
1424
+ : `${block.text}${event.assistantMessageEvent.delta}`,
1425
+ });
1426
+ }
1427
+ return;
1428
+ }
1429
+ case "message_end":
1430
+ this.#upsertMessageBlock(event.message, "finalized");
1431
+ return;
1432
+ case "turn_end":
1433
+ this.#upsertMessageBlock(event.message, "finalized");
1434
+ if (Array.isArray(event.toolResults)) {
1435
+ for (const result of event.toolResults)
1436
+ this.#upsertMessageBlock(result, "finalized");
1437
+ }
1438
+ return;
1439
+ case "tool_execution_start":
1440
+ case "tool_execution_update":
1441
+ case "tool_execution_end":
1442
+ this.#upsertToolExecutionBlock(event);
1443
+ return;
1444
+ case "agent_settled":
1445
+ case "agent_end": {
1446
+ if (event.type === "agent_end" && event.willRetry === true)
1447
+ return;
1448
+ const finalMessages = Array.isArray(event.messages) && event.messages.length > 0
1449
+ ? event.messages
1450
+ : this.#session?.messages ?? [];
1451
+ if (finalMessages.length > 0)
1452
+ this.#rebuildTranscript(finalMessages, "finalized");
1453
+ else
1454
+ this.#transcript = this.#transcript.map(block => block.status === "live" ? { ...block, status: "finalized" } : block);
1455
+ this.#lifecycle = "ready";
1456
+ this.#status = { ...this.#status, workingMessage: null };
1457
+ this.#emitEvent({ type: "session-lifecycle", lifecycle: "ready", reason: null });
1458
+ this.#emitEvent({ type: "status", status: this.#status });
1459
+ this.#emitView();
1460
+ return;
1461
+ }
1462
+ case "queue_update": {
1463
+ const steering = readStringArray(event.steering);
1464
+ const followUp = readStringArray(event.followUp);
1465
+ this.#editor = {
1466
+ ...this.#editor,
1467
+ queuedSubmissions: [...steering, ...followUp],
1468
+ historyRevision: this.#editor.historyRevision + 1,
1469
+ };
1470
+ this.#emitEvent({ type: "editor-state", editor: this.#editor });
1471
+ return;
1472
+ }
1473
+ case "auto_retry_start":
1474
+ this.#lifecycle = "busy";
1475
+ this.#status = { ...this.#status, workingMessage: "Retrying…" };
1476
+ this.#emitEvent({ type: "status", status: this.#status });
1477
+ return;
1478
+ case "auto_retry_end":
1479
+ case "compaction_end":
1480
+ this.#lifecycle = "ready";
1481
+ this.#status = { ...this.#status, workingMessage: null };
1482
+ this.#emitEvent({ type: "status", status: this.#status });
1483
+ return;
1484
+ case "compaction_start":
1485
+ this.#lifecycle = "busy";
1486
+ this.#status = { ...this.#status, workingMessage: "Compacting…" };
1487
+ this.#emitEvent({ type: "status", status: this.#status });
1488
+ return;
1489
+ case "thinking_level_changed":
1490
+ this.#thinkingLevel = readThinkingLevel(event.level);
1491
+ return;
1492
+ default:
1493
+ return;
1494
+ }
1495
+ }
1496
+ #readUsage() {
1497
+ let input = 0;
1498
+ let output = 0;
1499
+ let cacheRead = 0;
1500
+ let cacheWrite = 0;
1501
+ let cost = 0;
1502
+ let latestCacheHitRate = null;
1503
+ let latestPrompt = null;
1504
+ const entries = this.#session?.sessionManager?.getEntries()
1505
+ ?? (this.#session?.messages ?? []).map(message => ({ type: "message", message }));
1506
+ for (const entry of entries) {
1507
+ if (!isRecord(entry))
1508
+ continue;
1509
+ const message = entry.type === "message" && isRecord(entry.message) ? entry.message : undefined;
1510
+ const usage = message !== undefined && isRecord(message.usage)
1511
+ ? message.usage
1512
+ : (entry.type === "branch_summary" || entry.type === "compaction") && isRecord(entry.usage) ? entry.usage : undefined;
1513
+ if (usage === undefined)
1514
+ continue;
1515
+ input += finiteNumber(usage.input);
1516
+ output += finiteNumber(usage.output);
1517
+ cacheRead += finiteNumber(usage.cacheRead);
1518
+ cacheWrite += finiteNumber(usage.cacheWrite);
1519
+ cost += isRecord(usage.cost) ? finiteNumber(usage.cost.total) : 0;
1520
+ if (message?.role === "assistant") {
1521
+ latestPrompt = {
1522
+ input: finiteNumber(usage.input),
1523
+ cacheRead: finiteNumber(usage.cacheRead),
1524
+ cacheWrite: finiteNumber(usage.cacheWrite),
1525
+ };
1526
+ const promptTokens = latestPrompt.input + latestPrompt.cacheRead + latestPrompt.cacheWrite;
1527
+ latestCacheHitRate = promptTokens > 0 ? (latestPrompt.cacheRead / promptTokens) * 100 : null;
1528
+ }
1529
+ }
1530
+ const context = this.#session?.getContextUsage?.();
1531
+ const providerId = this.#activeModel?.providerId;
1532
+ const usingSubscription = providerId === "kimi-coding"
1533
+ || (providerId !== undefined && this.#runtime?.services.modelRuntime.isUsingSubscription?.(providerId) === true);
1534
+ return {
1535
+ input,
1536
+ output,
1537
+ cacheRead,
1538
+ cacheWrite,
1539
+ cost,
1540
+ latestCacheHitRate,
1541
+ latestPrompt,
1542
+ contextAvailable: context !== undefined,
1543
+ contextTokens: context?.tokens ?? null,
1544
+ contextWindow: context?.contextWindow ?? 0,
1545
+ contextPercent: context?.percent ?? null,
1546
+ usingSubscription,
1547
+ autoCompactEnabled: this.#runtime?.services.settingsManager?.getCompactionEnabled?.() ?? true,
1548
+ };
1549
+ }
1550
+ #rebuildTranscript(messages, status) {
1551
+ const blocks = [];
1552
+ const blockIndexes = new Map();
1553
+ const occurrences = new Map();
1554
+ for (const [index, message] of messages.entries()) {
1555
+ const key = messageFallbackKey(message, index);
1556
+ const occurrence = occurrences.get(key) ?? 0;
1557
+ occurrences.set(key, occurrence + 1);
1558
+ for (const block of this.#messageBlocks(message, status, index, occurrence)) {
1559
+ const existingIndex = blockIndexes.get(block.id);
1560
+ if (existingIndex === undefined) {
1561
+ blockIndexes.set(block.id, blocks.length);
1562
+ blocks.push(block);
1563
+ continue;
1564
+ }
1565
+ const existing = blocks[existingIndex];
1566
+ if (existing !== undefined) {
1567
+ blocks[existingIndex] = {
1568
+ ...block,
1569
+ payload: {
1570
+ ...(isRecord(existing.payload) ? existing.payload : {}),
1571
+ ...(isRecord(block.payload) ? block.payload : {}),
1572
+ },
1573
+ };
1574
+ }
1575
+ }
1576
+ }
1577
+ this.#transcript = blocks;
1578
+ }
1579
+ #upsertMessageBlock(message, status) {
1580
+ const blocks = this.#messageBlocks(message, status, this.#transcript.length);
1581
+ const first = blocks[0];
1582
+ for (const block of blocks)
1583
+ this.#upsertTranscriptBlock(block);
1584
+ return first;
1585
+ }
1586
+ #messageBlocks(message, status, fallbackIndex, occurrence) {
1587
+ if (!isRecord(message) || typeof message.role !== "string")
1588
+ return [];
1589
+ const baseId = this.#messageBlockId(message, fallbackIndex, status, occurrence);
1590
+ if (message.role === "user") {
1591
+ return [{
1592
+ id: baseId,
1593
+ kind: "user",
1594
+ status,
1595
+ revision: this.#nextBlockRevision(baseId),
1596
+ title: "User",
1597
+ text: textFromContent(message.content),
1598
+ payload: { role: "user", imageCount: contentImageCount(message.content) },
1599
+ }];
1600
+ }
1601
+ if (message.role === "bashExecution") {
1602
+ return [{
1603
+ id: baseId,
1604
+ kind: "bash",
1605
+ status,
1606
+ revision: this.#nextBlockRevision(baseId),
1607
+ title: stringValue(message.command) ?? "Bash",
1608
+ text: stringValue(message.output) ?? "",
1609
+ payload: {
1610
+ role: "bashExecution",
1611
+ command: stringValue(message.command) ?? "",
1612
+ exitCode: typeof message.exitCode === "number" ? message.exitCode : null,
1613
+ cancelled: message.cancelled === true,
1614
+ truncated: message.truncated === true,
1615
+ fullOutputPath: stringValue(message.fullOutputPath) ?? null,
1616
+ excludeFromContext: message.excludeFromContext === true,
1617
+ },
1618
+ }];
1619
+ }
1620
+ if (message.role === "custom") {
1621
+ if (message.display === false)
1622
+ return [];
1623
+ return [{
1624
+ id: baseId,
1625
+ kind: "custom",
1626
+ status,
1627
+ revision: this.#nextBlockRevision(baseId),
1628
+ title: stringValue(message.customType) ?? "Custom",
1629
+ text: textFromContent(message.content),
1630
+ payload: {
1631
+ role: "custom",
1632
+ customType: stringValue(message.customType) ?? "custom",
1633
+ display: true,
1634
+ details: message.details,
1635
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : 0,
1636
+ },
1637
+ }];
1638
+ }
1639
+ if (message.role === "compactionSummary" || message.role === "branchSummary") {
1640
+ return [{
1641
+ id: baseId,
1642
+ kind: "compaction",
1643
+ status,
1644
+ revision: this.#nextBlockRevision(baseId),
1645
+ title: message.role === "branchSummary" ? "Branch summary" : "Compaction summary",
1646
+ text: stringValue(message.summary) ?? "",
1647
+ payload: {
1648
+ role: message.role,
1649
+ tokensBefore: typeof message.tokensBefore === "number" ? message.tokensBefore : 0,
1650
+ fromId: stringValue(message.fromId) ?? null,
1651
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : 0,
1652
+ },
1653
+ }];
1654
+ }
1655
+ if (message.role === "toolResult") {
1656
+ const toolCallId = stringValue(message.toolCallId);
1657
+ const blockId = toolCallId === undefined
1658
+ ? baseId
1659
+ : this.#toolBlockIds.get(toolCallId) ?? `tool-${toolCallId}`;
1660
+ if (toolCallId !== undefined)
1661
+ this.#toolBlockIds.set(toolCallId, blockId);
1662
+ const existing = this.#transcript.find(block => block.id === blockId);
1663
+ const existingPayload = isRecord(existing?.payload) ? existing.payload : undefined;
1664
+ return [{
1665
+ id: blockId,
1666
+ kind: "tool-result",
1667
+ status,
1668
+ revision: this.#nextBlockRevision(blockId),
1669
+ title: stringValue(message.toolName) ?? existing?.title ?? "Tool result",
1670
+ text: textFromContent(message.content),
1671
+ payload: {
1672
+ ...(existingPayload ?? {}),
1673
+ role: "toolResult",
1674
+ toolCallId: toolCallId ?? null,
1675
+ toolName: stringValue(message.toolName) ?? stringValue(existingPayload?.toolName) ?? "unknown",
1676
+ argsComplete: true,
1677
+ isError: message.isError === true,
1678
+ details: jsonSummary(message.details),
1679
+ },
1680
+ }];
1681
+ }
1682
+ if (message.role !== "assistant" || !Array.isArray(message.content))
1683
+ return [];
1684
+ const blocks = [{
1685
+ id: baseId,
1686
+ kind: "assistant",
1687
+ status,
1688
+ revision: this.#nextBlockRevision(baseId),
1689
+ title: "Assistant",
1690
+ text: textFromContent(message.content),
1691
+ payload: {
1692
+ role: "assistant",
1693
+ content: assistantContent(message.content),
1694
+ provider: stringValue(message.provider) ?? null,
1695
+ model: stringValue(message.model) ?? null,
1696
+ api: stringValue(message.api) ?? null,
1697
+ usage: sanitizeJson(message.usage),
1698
+ stopReason: stringValue(message.stopReason) ?? null,
1699
+ errorMessage: stringValue(message.errorMessage) ?? null,
1700
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : 0,
1701
+ },
1702
+ }];
1703
+ for (const item of message.content) {
1704
+ if (!isRecord(item) || item.type !== "toolCall")
1705
+ continue;
1706
+ const toolCallId = stringValue(item.id) ?? `${baseId}:${blocks.length}`;
1707
+ const blockId = this.#toolBlockIds.get(toolCallId) ?? `tool-${toolCallId}`;
1708
+ this.#toolBlockIds.set(toolCallId, blockId);
1709
+ blocks.push({
1710
+ id: blockId,
1711
+ kind: "tool-call",
1712
+ status,
1713
+ revision: this.#nextBlockRevision(blockId),
1714
+ title: stringValue(item.name) ?? "Tool",
1715
+ text: jsonSummary(item.arguments).summary,
1716
+ payload: {
1717
+ toolCallId,
1718
+ toolName: stringValue(item.name) ?? "unknown",
1719
+ arguments: jsonSummary(item.arguments),
1720
+ argsComplete: status === "finalized",
1721
+ },
1722
+ });
1723
+ }
1724
+ return blocks;
1725
+ }
1726
+ #upsertToolExecutionBlock(event) {
1727
+ const toolCallId = stringValue(event.toolCallId);
1728
+ if (!toolCallId)
1729
+ return;
1730
+ const blockId = this.#toolBlockIds.get(toolCallId) ?? `tool-${toolCallId}`;
1731
+ this.#toolBlockIds.set(toolCallId, blockId);
1732
+ const ended = event.type === "tool_execution_end";
1733
+ const source = ended ? event.result : event.partialResult;
1734
+ this.#upsertTranscriptBlock({
1735
+ id: blockId,
1736
+ kind: ended ? "tool-result" : "tool-call",
1737
+ status: ended ? "finalized" : "live",
1738
+ revision: this.#nextBlockRevision(blockId),
1739
+ title: stringValue(event.toolName) ?? "Tool",
1740
+ text: textFromContent(isRecord(source) ? source.content : source),
1741
+ payload: {
1742
+ toolCallId,
1743
+ toolName: stringValue(event.toolName) ?? "unknown",
1744
+ arguments: jsonSummary(event.args),
1745
+ result: jsonSummary(source),
1746
+ partialResult: event.type === "tool_execution_update",
1747
+ argsComplete: ended,
1748
+ isError: event.isError === true,
1749
+ },
1750
+ });
1751
+ }
1752
+ #upsertTranscriptBlock(block) {
1753
+ const index = this.#transcript.findIndex(existing => existing.id === block.id);
1754
+ if (index >= 0)
1755
+ this.#transcript[index] = block;
1756
+ else
1757
+ this.#transcript.push(block);
1758
+ this.#emitEvent({ type: "transcript-block", block });
1759
+ }
1760
+ #messageBlockId(message, fallbackIndex, status, occurrence) {
1761
+ const existing = this.#messageBlockIds.get(message);
1762
+ if (existing)
1763
+ return existing;
1764
+ const fallback = messageFallbackKey(message, fallbackIndex);
1765
+ const cached = this.#messageFallbackIds.get(fallback) ?? [];
1766
+ let id;
1767
+ if (occurrence !== undefined) {
1768
+ id = cached[occurrence];
1769
+ if (id === undefined) {
1770
+ id = `${fallback}-${occurrence}`;
1771
+ cached[occurrence] = id;
1772
+ }
1773
+ }
1774
+ else {
1775
+ id = [...cached].reverse().find(candidate => this.#transcript.some(block => block.id === candidate && block.status === "live"));
1776
+ if (id === undefined && status === "finalized")
1777
+ id = cached.at(-1);
1778
+ if (id === undefined) {
1779
+ id = `${fallback}-${cached.length}`;
1780
+ cached.push(id);
1781
+ }
1782
+ }
1783
+ this.#messageFallbackIds.set(fallback, cached);
1784
+ this.#messageBlockIds.set(message, id);
1785
+ return id;
1786
+ }
1787
+ #nextBlockRevision(id) {
1788
+ const existing = this.#transcript.find(block => block.id === id);
1789
+ if (existing)
1790
+ return existing.revision + 1;
1791
+ this.#nextBlockSequence += 1;
1792
+ return this.#nextBlockSequence;
1793
+ }
1794
+ #recordCommand(command, outcome, diagnostic) {
1795
+ const result = this.#finishCommand(command, outcome, diagnostic);
1796
+ this.#completedCommands.set(command.correlationId, result);
1797
+ if (this.#completedCommands.size > 256) {
1798
+ const oldest = this.#completedCommands.keys().next().value;
1799
+ if (oldest)
1800
+ this.#completedCommands.delete(oldest);
1801
+ }
1802
+ return result;
1803
+ }
1804
+ #finishCommand(command, outcome, diagnostic) {
1805
+ this.#activeCommandIds = this.#activeCommandIds.filter(id => id !== command.correlationId);
1806
+ this.#emitEvent({
1807
+ type: "command-outcome",
1808
+ correlationId: command.correlationId,
1809
+ outcome,
1810
+ diagnostic,
1811
+ });
1812
+ return { outcome, diagnostic };
1813
+ }
1814
+ #addDiagnostic(severity, code, message, recoverable) {
1815
+ const diagnostic = this.#recordDiagnostic(severity, code, message, recoverable);
1816
+ this.#emitEvent({ type: "diagnostic", diagnostic });
1817
+ }
1818
+ #emitView() {
1819
+ this.#viewRevision += 1;
1820
+ this.#emitEvent({ type: "session-view", view: this.view() });
1821
+ }
1822
+ #emitEvent(value) {
1823
+ const event = this.#event(value);
1824
+ if (event.type !== "session-view")
1825
+ this.#viewRevision += 1;
1826
+ this.#enqueueEvent(event);
1827
+ }
1828
+ #enqueueEvent(event) {
1829
+ const capacity = 1_024;
1830
+ if (this.#eventQueue.length >= capacity) {
1831
+ const coalescible = this.#eventQueue.findIndex(queued => queued.type === "session-view"
1832
+ || queued.type === "status"
1833
+ || queued.type === "editor-state"
1834
+ || queued.type === "transcript-block");
1835
+ if (coalescible >= 0)
1836
+ this.#eventQueue.splice(coalescible, 1);
1837
+ else
1838
+ this.#eventQueue.shift();
1839
+ this.#droppedEventCount += 1;
1840
+ if (this.#droppedEventCount === 1 || this.#droppedEventCount % 128 === 0) {
1841
+ this.#recordDiagnostic("warning", "event-backpressure", `owned UI coalesced ${this.#droppedEventCount} engine events under backpressure`, true);
1842
+ }
1843
+ }
1844
+ this.#eventQueue.push(event);
1845
+ this.#eventQueueProcessing ??= Promise.resolve().then(() => this.#processEventQueue());
1846
+ }
1847
+ async #processEventQueue() {
1848
+ try {
1849
+ while (this.#eventQueue.length > 0) {
1850
+ const event = this.#eventQueue.shift();
1851
+ if (!event)
1852
+ continue;
1853
+ for (const listener of this.#listeners) {
1854
+ try {
1855
+ listener(event);
1856
+ }
1857
+ catch (error) {
1858
+ this.#recordDiagnostic("warning", "event-listener", error instanceof Error ? error.message : String(error), true);
1859
+ }
1860
+ }
1861
+ }
1862
+ }
1863
+ finally {
1864
+ this.#eventQueueProcessing = undefined;
1865
+ if (this.#eventQueue.length > 0) {
1866
+ this.#eventQueueProcessing = Promise.resolve().then(() => this.#processEventQueue());
1867
+ }
1868
+ }
1869
+ }
1870
+ #recordDiagnostic(severity, code, message, recoverable) {
1871
+ const diagnostic = {
1872
+ sequence: this.#diagnostics.length,
1873
+ code,
1874
+ severity,
1875
+ message,
1876
+ recoverable,
1877
+ };
1878
+ this.#diagnostics.push(diagnostic);
1879
+ if (this.#diagnostics.length > 100)
1880
+ this.#diagnostics.shift();
1881
+ this.#status = {
1882
+ ...this.#status,
1883
+ diagnostics: [...this.#status.diagnostics, message].slice(-8),
1884
+ };
1885
+ return diagnostic;
1886
+ }
1887
+ #event(value) {
1888
+ this.#sequence += 1;
1889
+ return { ...value, sessionId: this.#sessionId, sequence: this.#sequence };
1890
+ }
1891
+ }
1892
+ export async function createPiEngineAdapter(options = {}) {
1893
+ const adapter = new PiEngineAdapter(options);
1894
+ await adapter.start();
1895
+ return adapter;
1896
+ }
1897
+ async function createDefaultPiRuntime(input) {
1898
+ const sessionManager = SessionManager.create(input.cwd, process.env.PI_CODING_AGENT_SESSION_DIR);
1899
+ const createRuntime = async ({ cwd, sessionManager: targetSessionManager, sessionStartEvent, }) => {
1900
+ const services = await createAgentSessionServices({ cwd, agentDir: input.agentDir });
1901
+ const created = await createAgentSessionFromServices({
1902
+ services,
1903
+ sessionManager: targetSessionManager,
1904
+ ...(sessionStartEvent ? { sessionStartEvent } : {}),
1905
+ });
1906
+ return {
1907
+ ...created,
1908
+ services,
1909
+ diagnostics: services.diagnostics,
1910
+ };
1911
+ };
1912
+ const runtime = await createAgentSessionRuntime(createRuntime, {
1913
+ cwd: input.cwd,
1914
+ agentDir: input.agentDir,
1915
+ sessionManager,
1916
+ });
1917
+ return runtime;
1918
+ }
1919
+ function pinnedSessionInfoPresentation(value, sessionName, entries, modelRuntime) {
1920
+ const stats = isRecord(value) ? value : {};
1921
+ const tokens = dynamicObject(stats, "tokens");
1922
+ return {
1923
+ kind: "session-info",
1924
+ ...(sessionName === undefined ? {} : { sessionName }),
1925
+ stats: {
1926
+ ...(stringProperty(stats, "sessionFile") === undefined ? {} : { sessionFile: stringProperty(stats, "sessionFile") }),
1927
+ sessionId: stringProperty(stats, "sessionId") ?? "unknown",
1928
+ userMessages: finiteNumber(stats.userMessages),
1929
+ assistantMessages: finiteNumber(stats.assistantMessages),
1930
+ toolCalls: finiteNumber(stats.toolCalls),
1931
+ toolResults: finiteNumber(stats.toolResults),
1932
+ totalMessages: finiteNumber(stats.totalMessages),
1933
+ tokens: {
1934
+ input: finiteNumber(tokens.input),
1935
+ output: finiteNumber(tokens.output),
1936
+ cacheRead: finiteNumber(tokens.cacheRead),
1937
+ cacheWrite: finiteNumber(tokens.cacheWrite),
1938
+ total: finiteNumber(tokens.total),
1939
+ },
1940
+ cost: finiteNumber(stats.cost),
1941
+ },
1942
+ cacheWaste: pinnedCacheWaste(entries, modelRuntime),
1943
+ usageBreakdown: pinnedUsageCostBreakdown(entries),
1944
+ };
1945
+ }
1946
+ function pinnedUsageCostBreakdown(entries) {
1947
+ const totals = new Map();
1948
+ for (const entry of entries) {
1949
+ if (!isRecord(entry))
1950
+ continue;
1951
+ let key;
1952
+ let usage;
1953
+ const message = dynamicObject(entry, "message");
1954
+ if (entry.type === "message" && message.role === "assistant") {
1955
+ const provider = stringProperty(message, "provider");
1956
+ const model = stringProperty(message, "responseModel") ?? stringProperty(message, "model");
1957
+ if (provider && model)
1958
+ key = `${provider}/${model}`;
1959
+ usage = dynamicObject(message, "usage");
1960
+ }
1961
+ else if (entry.type === "message" && message.role === "toolResult" && isRecord(message.usage)) {
1962
+ key = "Tools/summaries";
1963
+ usage = message.usage;
1964
+ }
1965
+ else if ((entry.type === "branch_summary" || entry.type === "compaction") && isRecord(entry.usage)) {
1966
+ key = "Tools/summaries";
1967
+ usage = entry.usage;
1968
+ }
1969
+ if (!key || !usage)
1970
+ continue;
1971
+ const cost = finiteNumber(dynamicObject(usage, "cost").total);
1972
+ const tokens = finiteNumber(usage.input) + finiteNumber(usage.output)
1973
+ + finiteNumber(usage.cacheRead) + finiteNumber(usage.cacheWrite);
1974
+ const current = totals.get(key) ?? { cost: 0, tokens: 0 };
1975
+ current.cost += cost;
1976
+ current.tokens += tokens;
1977
+ totals.set(key, current);
1978
+ }
1979
+ return [...totals].map(([key, total]) => ({ key, ...total }))
1980
+ .filter(entry => entry.cost > 0 || entry.tokens > 0)
1981
+ .sort((a, b) => b.cost - a.cost);
1982
+ }
1983
+ function pinnedCacheWaste(entries, modelRuntime) {
1984
+ let previous;
1985
+ const totals = { missedTokens: 0, missedCost: 0, missCount: 0 };
1986
+ for (const entry of entries) {
1987
+ if (!isRecord(entry))
1988
+ continue;
1989
+ if (entry.type === "compaction" || entry.type === "branch_summary") {
1990
+ previous = undefined;
1991
+ continue;
1992
+ }
1993
+ const message = dynamicObject(entry, "message");
1994
+ if (entry.type !== "message" || message.role !== "assistant")
1995
+ continue;
1996
+ const usage = dynamicObject(message, "usage");
1997
+ const input = finiteNumber(usage.input);
1998
+ const cacheRead = finiteNumber(usage.cacheRead);
1999
+ const cacheWrite = finiteNumber(usage.cacheWrite);
2000
+ const promptTokens = input + cacheRead + cacheWrite;
2001
+ if (previous && promptTokens > 0 && (cacheRead + cacheWrite > 0 || previous.reportedCache)) {
2002
+ const missedTokens = Math.min(previous.promptTokens, promptTokens) - cacheRead;
2003
+ if (missedTokens > 1024) {
2004
+ const cost = dynamicObject(usage, "cost");
2005
+ const paidTokens = input + cacheWrite;
2006
+ const paidRate = paidTokens > 0 ? (finiteNumber(cost.input) + finiteNumber(cost.cacheWrite)) / paidTokens : 0;
2007
+ const provider = stringProperty(message, "provider") ?? "";
2008
+ const modelId = stringProperty(message, "model") ?? "";
2009
+ const model = modelRuntime.getModel(provider, modelId);
2010
+ const modelCost = dynamicObject(dynamicObject(model, "cost"));
2011
+ const readRate = cacheRead > 0
2012
+ ? finiteNumber(cost.cacheRead) / cacheRead
2013
+ : finiteNumber(modelCost.cacheRead) / 1_000_000;
2014
+ totals.missedTokens += missedTokens;
2015
+ totals.missedCost += missedTokens * Math.max(0, paidRate - readRate);
2016
+ totals.missCount += 1;
2017
+ }
2018
+ }
2019
+ if (promptTokens > 0) {
2020
+ const provider = stringProperty(message, "provider") ?? "";
2021
+ const model = stringProperty(message, "model") ?? "";
2022
+ previous = {
2023
+ promptTokens,
2024
+ modelKey: `${provider}/${model}`,
2025
+ timestamp: finiteNumber(message.timestamp),
2026
+ reportedCache: (previous?.reportedCache ?? false) || cacheRead + cacheWrite > 0,
2027
+ };
2028
+ }
2029
+ }
2030
+ return totals;
2031
+ }
2032
+ function defaultWorkflowHost() {
2033
+ return {
2034
+ copyText: copyToClipboard,
2035
+ async runCommand(command, arguments_) {
2036
+ const result = await execFileAsync(command, [...arguments_], { encoding: "utf8" });
2037
+ return { stdout: result.stdout, stderr: result.stderr };
2038
+ },
2039
+ readChangelog: async () => pinnedChangelogMarkdown(await readFile(join(getPackageDir(), "CHANGELOG.md"), "utf8")),
2040
+ };
2041
+ }
2042
+ function workflowLoginNotification(event) {
2043
+ if (!isRecord(event))
2044
+ return undefined;
2045
+ if (event.type === "auth_url") {
2046
+ const url = stringProperty(event, "url");
2047
+ if (!url)
2048
+ return undefined;
2049
+ const instructions = stringProperty(event, "instructions");
2050
+ return { type: "auth_url", url, ...(instructions === undefined ? {} : { instructions }) };
2051
+ }
2052
+ if (event.type === "device_code") {
2053
+ const verificationUri = stringProperty(event, "verificationUri");
2054
+ const userCode = stringProperty(event, "userCode");
2055
+ return verificationUri && userCode ? { type: "device_code", verificationUri, userCode } : undefined;
2056
+ }
2057
+ const message = stringProperty(event, "message");
2058
+ if (!message)
2059
+ return undefined;
2060
+ if (event.type === "info") {
2061
+ const links = Array.isArray(event.links) ? event.links.filter(isRecord).flatMap(link => {
2062
+ const url = stringProperty(link, "url");
2063
+ if (!url)
2064
+ return [];
2065
+ const label = stringProperty(link, "label");
2066
+ return [{ ...(label === undefined ? {} : { label }), url }];
2067
+ }) : [];
2068
+ return { type: "info", message, ...(links.length === 0 ? {} : { links }) };
2069
+ }
2070
+ return { type: event.type === "waiting" ? "waiting" : "progress", message };
2071
+ }
2072
+ function workflowResult(command, outcome, message, detail) {
2073
+ return { command, outcome, message, ...(detail === undefined ? {} : { detail }) };
2074
+ }
2075
+ function workflowConfirmation(command, message) {
2076
+ return {
2077
+ command,
2078
+ outcome: "requires-confirmation",
2079
+ message,
2080
+ selectorTitle: "Confirm",
2081
+ options: [
2082
+ { id: "yes", label: "Yes" },
2083
+ { id: "no", label: "No" },
2084
+ ],
2085
+ };
2086
+ }
2087
+ function workflowOptions(value, idKey, labelKey) {
2088
+ if (!Array.isArray(value))
2089
+ return [];
2090
+ return value.filter(isRecord).flatMap(item => {
2091
+ const id = stringProperty(item, idKey);
2092
+ if (!id)
2093
+ return [];
2094
+ return [{ id, label: stringProperty(item, labelKey) ?? id }];
2095
+ });
2096
+ }
2097
+ function sessionInfoOptions(value) {
2098
+ return value.filter(isRecord).flatMap(info => {
2099
+ const path = stringProperty(info, "path");
2100
+ if (!path)
2101
+ return [];
2102
+ const modified = info.modified instanceof Date ? info.modified.toISOString() : stringProperty(info, "modified") ?? "unknown time";
2103
+ const messageCount = typeof info.messageCount === "number" ? info.messageCount : 0;
2104
+ return [{
2105
+ id: path,
2106
+ label: stringProperty(info, "name") ?? stringProperty(info, "firstMessage") ?? stringProperty(info, "id") ?? path,
2107
+ description: `${messageCount} messages · ${modified}`,
2108
+ }];
2109
+ });
2110
+ }
2111
+ function assertPiExtensionUiContext(value) {
2112
+ assertOwnedUiExtensionUiPort(value);
2113
+ }
2114
+ function dynamicObject(value, key) {
2115
+ const candidate = key === undefined ? value : isRecord(value) ? value[key] : undefined;
2116
+ return isRecord(candidate) ? candidate : {};
2117
+ }
2118
+ function requireCapability(capability, name) {
2119
+ if (typeof capability !== "function")
2120
+ throw new Error(`Pi workflow capability is unavailable: ${name}`);
2121
+ return capability;
2122
+ }
2123
+ function pathArgument(value) {
2124
+ if (!value)
2125
+ return undefined;
2126
+ const quote = value[0];
2127
+ if (quote === '"' || quote === "'") {
2128
+ const closing = value.indexOf(quote, 1);
2129
+ return closing < 0 ? undefined : value.slice(1, closing);
2130
+ }
2131
+ return value.split(/\s/, 1)[0] || undefined;
2132
+ }
2133
+ function settingLabel(callback) {
2134
+ return callback
2135
+ .replace(/^on/, "")
2136
+ .replace(/Change$|Preview$|Cancel$/, "")
2137
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
2138
+ .replace(/^./, character => character.toUpperCase());
2139
+ }
2140
+ function pinnedHotkeySummary() {
2141
+ return [
2142
+ "Enter: send message · Alt+Enter: queue follow-up",
2143
+ "Escape: cancel/abort · Ctrl+C: clear/exit · Ctrl+D: exit when empty",
2144
+ "Shift+Tab: cycle thinking · Ctrl+P/Shift+Ctrl+P: cycle models · Ctrl+L: select model",
2145
+ "Ctrl+O: expand tools · Ctrl+T: toggle thinking · Ctrl+X: copy message",
2146
+ "Alt+Up: restore queued messages · /: commands · !/!!: bash",
2147
+ ].join("\n");
2148
+ }
2149
+ function scopedModelRecords(modelRuntime) {
2150
+ const snapshot = modelRuntime.getAvailableSnapshot?.() ?? [];
2151
+ return snapshot.flatMap(model => {
2152
+ if (!isRecord(model))
2153
+ return [];
2154
+ const provider = stringValue(model.provider);
2155
+ const id = stringValue(model.id);
2156
+ if (!provider || !id)
2157
+ return [];
2158
+ return [{ descriptor: { provider, id, name: stringValue(model.name) ?? id }, model }];
2159
+ });
2160
+ }
2161
+ function scopedModelReference(value) {
2162
+ if (!isRecord(value) || !isRecord(value.model))
2163
+ return undefined;
2164
+ const provider = stringValue(value.model.provider);
2165
+ const id = stringValue(value.model.id);
2166
+ return provider && id ? `${provider}/${id}` : undefined;
2167
+ }
2168
+ function resolveConfiguredModelIds(patterns, models) {
2169
+ const references = models.map(item => `${item.descriptor.provider}/${item.descriptor.id}`);
2170
+ const resolved = [];
2171
+ for (const pattern of patterns) {
2172
+ const thinkingSuffix = /:(?:off|minimal|low|medium|high|xhigh)$/.exec(pattern);
2173
+ const modelPattern = thinkingSuffix === null ? pattern : pattern.slice(0, -thinkingSuffix[0].length);
2174
+ const matcher = wildcardMatcher(modelPattern);
2175
+ const matches = references.filter((reference, index) => matcher.test(reference) || matcher.test(models[index]?.descriptor.id ?? ""));
2176
+ if (matches.length === 0) {
2177
+ resolved.push(pattern);
2178
+ }
2179
+ else {
2180
+ for (const match of matches)
2181
+ if (!resolved.includes(match))
2182
+ resolved.push(match);
2183
+ }
2184
+ }
2185
+ return resolved;
2186
+ }
2187
+ function wildcardMatcher(pattern) {
2188
+ let source = "";
2189
+ for (const character of pattern) {
2190
+ if (character === "*")
2191
+ source += ".*";
2192
+ else if (character === "?")
2193
+ source += ".";
2194
+ else
2195
+ source += character.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
2196
+ }
2197
+ return new RegExp(`^${source}$`, "i");
2198
+ }
2199
+ function readModel(value) {
2200
+ if (!isRecord(value))
2201
+ return null;
2202
+ const providerId = stringValue(value.provider) ?? stringValue(value.providerId);
2203
+ const modelId = stringValue(value.id) ?? stringValue(value.modelId);
2204
+ if (!providerId || !modelId)
2205
+ return null;
2206
+ return {
2207
+ providerId,
2208
+ modelId,
2209
+ displayName: stringValue(value.name) ?? modelId,
2210
+ };
2211
+ }
2212
+ function readThinkingLevel(value) {
2213
+ return value === "off" || value === "minimal" || value === "low" || value === "medium"
2214
+ || value === "high" || value === "xhigh"
2215
+ ? value
2216
+ : "medium";
2217
+ }
2218
+ function readStringArray(value) {
2219
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
2220
+ }
2221
+ function stringValue(value) {
2222
+ return typeof value === "string" && value.length > 0 ? value : undefined;
2223
+ }
2224
+ function messageFallbackKey(message, fallbackIndex) {
2225
+ if (!isRecord(message))
2226
+ return `message-unknown-${fallbackIndex}`;
2227
+ const timestamp = typeof message.timestamp === "number" && Number.isSafeInteger(message.timestamp)
2228
+ ? message.timestamp
2229
+ : `index-${fallbackIndex}`;
2230
+ return `message-${stringValue(message.role) ?? "unknown"}-${timestamp}`;
2231
+ }
2232
+ function extensionResourceDiagnostic(index, sourcePath, diagnostic) {
2233
+ return {
2234
+ kind: "extension",
2235
+ id: `extension-diagnostic-${index}`,
2236
+ sourcePath,
2237
+ resolvedPath: null,
2238
+ loaded: false,
2239
+ hidden: false,
2240
+ diagnostic,
2241
+ };
2242
+ }
2243
+ function collectionResult(value, key) {
2244
+ if (!isRecord(value))
2245
+ return { values: [], diagnostics: [] };
2246
+ const diagnostics = unknownArray(value.diagnostics).map(diagnostic => {
2247
+ if (typeof diagnostic === "string")
2248
+ return diagnostic;
2249
+ if (isRecord(diagnostic)) {
2250
+ const message = stringProperty(diagnostic, "message") ?? String(diagnostic);
2251
+ const path = stringProperty(diagnostic, "path");
2252
+ return path ? `${path}: ${message}` : message;
2253
+ }
2254
+ return String(diagnostic);
2255
+ });
2256
+ return { values: unknownArray(value[key]), diagnostics };
2257
+ }
2258
+ function unknownArray(value) {
2259
+ return Array.isArray(value) ? value : [];
2260
+ }
2261
+ function stringProperty(value, key) {
2262
+ if (!isRecord(value))
2263
+ return undefined;
2264
+ const item = value[key];
2265
+ return typeof item === "string" && item.length > 0 ? item : undefined;
2266
+ }
2267
+ function compactResourceLabel(path) {
2268
+ const segments = path.replaceAll("\\", "/").split("/").filter(Boolean);
2269
+ return segments.at(-1) ?? path;
2270
+ }
2271
+ function textFromContent(content) {
2272
+ if (typeof content === "string")
2273
+ return content;
2274
+ if (!Array.isArray(content))
2275
+ return "";
2276
+ return content
2277
+ .map(item => isRecord(item) && item.type === "text" ? stringValue(item.text) ?? "" : "")
2278
+ .filter(text => text.length > 0)
2279
+ .join("\n");
2280
+ }
2281
+ function assistantContent(content) {
2282
+ const result = [];
2283
+ for (const item of content) {
2284
+ if (!isRecord(item))
2285
+ continue;
2286
+ if (item.type === "text")
2287
+ result.push({ type: "text", text: stringValue(item.text) ?? "" });
2288
+ else if (item.type === "thinking") {
2289
+ result.push({
2290
+ type: "thinking",
2291
+ thinking: stringValue(item.thinking) ?? "",
2292
+ ...(item.redacted === true ? { redacted: true } : {}),
2293
+ });
2294
+ }
2295
+ else if (item.type === "toolCall") {
2296
+ result.push({
2297
+ type: "toolCall",
2298
+ id: stringValue(item.id) ?? "",
2299
+ name: stringValue(item.name) ?? "unknown",
2300
+ arguments: sanitizeJson(item.arguments),
2301
+ });
2302
+ }
2303
+ }
2304
+ return result;
2305
+ }
2306
+ function contentImageCount(content) {
2307
+ return Array.isArray(content)
2308
+ ? content.filter(item => isRecord(item) && item.type === "image").length
2309
+ : 0;
2310
+ }
2311
+ function pinnedChangelogMarkdown(content) {
2312
+ const entries = content.split(/^##\s+/m).slice(1).flatMap(section => {
2313
+ const markdown = `## ${section}`.trim();
2314
+ return /^##\s+\[?\d+\.\d+\.\d+\]?/.test(markdown) ? [markdown] : [];
2315
+ });
2316
+ return entries.reverse().join("\n\n") || "No changelog entries found.";
2317
+ }
2318
+ function jsonSummary(value) {
2319
+ const json = sanitizeJson(value);
2320
+ let summary = "";
2321
+ try {
2322
+ summary = JSON.stringify(json);
2323
+ }
2324
+ catch {
2325
+ summary = String(value);
2326
+ }
2327
+ if (summary.length > 512)
2328
+ summary = `${summary.slice(0, 509)}...`;
2329
+ return { summary, json };
2330
+ }
2331
+ function sanitizeJson(value, depth = 0) {
2332
+ if (typeof value === "bigint")
2333
+ return value.toString();
2334
+ if (value === null || ["string", "number", "boolean"].includes(typeof value))
2335
+ return value;
2336
+ if (depth >= 8)
2337
+ return "[truncated]";
2338
+ if (Array.isArray(value))
2339
+ return value.slice(0, 100).map(item => sanitizeJson(item, depth + 1));
2340
+ if (isRecord(value)) {
2341
+ const output = {};
2342
+ for (const [key, item] of Object.entries(value).slice(0, 100)) {
2343
+ output[key] = sanitizeJson(item, depth + 1);
2344
+ }
2345
+ return output;
2346
+ }
2347
+ return String(value);
2348
+ }
2349
+ async function readGitBranch(cwd) {
2350
+ try {
2351
+ const { stdout } = await execFileAsync("git", ["branch", "--show-current"], { cwd, windowsHide: true });
2352
+ const branch = stdout.trim();
2353
+ return branch.length > 0 ? branch : null;
2354
+ }
2355
+ catch {
2356
+ return null;
2357
+ }
2358
+ }
2359
+ function finiteNumber(value) {
2360
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
2361
+ }
2362
+ function isRecord(value) {
2363
+ return typeof value === "object" && value !== null;
2364
+ }
2365
+ //# sourceMappingURL=adapter.js.map