@xopcai/xopc 0.0.117 → 0.0.118

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 (277) hide show
  1. package/README.md +24 -23
  2. package/README.zh-CN.md +45 -42
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BBLhJ2C6.js → agent-avatar-dicebear-dzUrQoeZ.js} +1 -1
  6. package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +2 -0
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-CBpLONvG.js → app-management-settings-panel-bxYJVJpx.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-CGcc54yj.js → appearance-settings-BCIykXlI.js} +1 -1
  9. package/dist/gateway/static/root/assets/{apps-page-DdDx0V4z.js → apps-page--wMEL00f.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-DZsVqMhU.js → archive-plugin-Cki4SfU2.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CIol6JWX.js → attachment-load-D-KnS2Do.js} +1 -1
  12. package/dist/gateway/static/root/assets/{binary-plugins-B3UauMfp.js → binary-plugins-D2sgvJja.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-2HJoFchH.js → block-editor-DIq-4Gvb.js} +27 -27
  14. package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +8 -0
  15. package/dist/gateway/static/root/assets/{capability-presets-api-XQoMTI0A.js → capability-presets-api-CorhiHlg.js} +1 -1
  16. package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +1 -0
  17. package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +1 -0
  18. package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +2 -0
  19. package/dist/gateway/static/root/assets/{cron-api-R41aQCX9.js → cron-api-qGwmL-24.js} +1 -1
  20. package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +3 -0
  21. package/dist/gateway/static/root/assets/{dreaming-settings-Bceaw1PG.js → dreaming-settings-Dw89Obml.js} +1 -1
  22. package/dist/gateway/static/root/assets/{extension-debug-page-DX5WRE_t.js → extension-debug-page-DYu1KaFQ.js} +1 -1
  23. package/dist/gateway/static/root/assets/{extension-page-Buah7Bw-.js → extension-page-B3W6QwlZ.js} +1 -1
  24. package/dist/gateway/static/root/assets/{extension-settings-page-DuroLVnf.js → extension-settings-page-D7VQ-cxE.js} +1 -1
  25. package/dist/gateway/static/root/assets/{fetch-B5zdl27C.js → fetch-B7xDPu-R.js} +1 -1
  26. package/dist/gateway/static/root/assets/{format-interval-label-Dn_QKIqb.js → format-interval-label-BzxafKxR.js} +1 -1
  27. package/dist/gateway/static/root/assets/{gateway-config-api-gT4ZhE7h.js → gateway-config-api-BTBLSeUu.js} +1 -1
  28. package/dist/gateway/static/root/assets/{gateway-settings-iISWAZRm.js → gateway-settings-Cmwy58rS.js} +1 -1
  29. package/dist/gateway/static/root/assets/{gateway-startup-retry-B3kL8KGY.js → gateway-startup-retry-CYj9FWCp.js} +1 -1
  30. package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +1 -0
  31. package/dist/gateway/static/root/assets/{goals-config-api-AR-fVh0P.js → goals-config-api-CQQgzPr3.js} +1 -1
  32. package/dist/gateway/static/root/assets/{goals-page-Cpb21ezg.js → goals-page-BHitvJAv.js} +2 -2
  33. package/dist/gateway/static/root/assets/{goals-settings-CPAuFwoD.js → goals-settings-CYVY4NGp.js} +1 -1
  34. package/dist/gateway/static/root/assets/{heartbeat-config-api-D7bKFEeO.js → heartbeat-config-api-DriO_CN9.js} +1 -1
  35. package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +1 -0
  36. package/dist/gateway/static/root/assets/index-C17Tsd_b.css +1 -0
  37. package/dist/gateway/static/root/assets/{index-CwhK8qCh.js → index-Cc41r16l.js} +120 -51
  38. package/dist/gateway/static/root/assets/{interval-presets-0DtsnxE0.js → interval-presets-DFPCKW_W.js} +1 -1
  39. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BPREtN8B.js → keyboard-shortcuts-settings-CcVcqstx.js} +1 -1
  40. package/dist/gateway/static/root/assets/{logs-page-DefCgF4o.js → logs-page-C2Uqvae9.js} +2 -2
  41. package/dist/gateway/static/root/assets/{markdown-split-ChbR9LGO.js → markdown-split-BwOFrJ2E.js} +1 -1
  42. package/dist/gateway/static/root/assets/{media-plugins-B82oP80n.js → media-plugins-Cnz6Q5G6.js} +1 -1
  43. package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +3 -0
  44. package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +2 -0
  45. package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +2 -0
  46. package/dist/gateway/static/root/assets/{note-image-lightbox-CDknITM3.js → note-image-lightbox-B-Svpmza.js} +1 -1
  47. package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +1 -0
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-DV3xQsWB.js → preview-open-alternatives-Bss4TiwP.js} +1 -1
  49. package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +1 -0
  50. package/dist/gateway/static/root/assets/{save-bar-controls-BODCXnvY.js → save-bar-controls-BRNjdgKq.js} +1 -1
  51. package/dist/gateway/static/root/assets/{schedule-field-CgJSCD3B.js → schedule-field-CUCKODde.js} +1 -1
  52. package/dist/gateway/static/root/assets/{schema-form-qtfEI6QM.js → schema-form-Dub9sy8r.js} +1 -1
  53. package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +1 -0
  54. package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +1 -0
  55. package/dist/gateway/static/root/assets/{settings-collapsible-section-BHZKjVcS.js → settings-collapsible-section-BeFLavGi.js} +1 -1
  56. package/dist/gateway/static/root/assets/{settings-form-section-5i35D-J1.js → settings-form-section-dmyaPOTG.js} +1 -1
  57. package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +1 -0
  58. package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +1 -0
  59. package/dist/gateway/static/root/assets/{share-preview-page-B0H63tDv.js → share-preview-page-C8glrdqe.js} +1 -1
  60. package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +1 -0
  61. package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +1 -0
  62. package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +2 -0
  63. package/dist/gateway/static/root/assets/{system-settings-panel-DXs2VmBt.js → system-settings-panel-DI-LN_8G.js} +1 -1
  64. package/dist/gateway/static/root/assets/{typed-models-lib-4gPuydz_.js → typed-models-lib-kX9duch4.js} +1 -1
  65. package/dist/gateway/static/root/assets/{use-channel-catalog-BCjP_VHb.js → use-channel-catalog-DqlWTsDb.js} +1 -1
  66. package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +1 -0
  67. package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +1 -0
  68. package/dist/gateway/static/root/assets/voice-api-key-field-C73IVZeC.js +1 -0
  69. package/dist/gateway/static/root/assets/{voice-player-store-BlF9V05n.js → voice-player-store-C_ArLJPM.js} +1 -1
  70. package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +18 -0
  71. package/dist/gateway/static/root/index.html +5 -5
  72. package/dist/package.js +1 -1
  73. package/dist/src/agent/agent-manager.js +2 -1
  74. package/dist/src/agent/agent-manager.js.map +1 -1
  75. package/dist/src/agent/agent-scope.js +0 -2
  76. package/dist/src/agent/agent-scope.js.map +1 -1
  77. package/dist/src/agent/background-review/prompts.d.ts +2 -2
  78. package/dist/src/agent/background-review/prompts.js +2 -2
  79. package/dist/src/agent/background-review/prompts.js.map +1 -1
  80. package/dist/src/agent/background-review/settings.d.ts +1 -1
  81. package/dist/src/agent/background-review/settings.js +7 -8
  82. package/dist/src/agent/background-review/settings.js.map +1 -1
  83. package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
  84. package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
  85. package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
  86. package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
  87. package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
  88. package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
  89. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
  90. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  91. package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
  92. package/dist/src/agent/bootstrap/load-bootstrap-files.js +17 -16
  93. package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
  94. package/dist/src/agent/bootstrap/types.d.ts +1 -1
  95. package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
  96. package/dist/src/agent/context/workspace.d.ts +4 -2
  97. package/dist/src/agent/context/workspace.js +5 -4
  98. package/dist/src/agent/context/workspace.js.map +1 -1
  99. package/dist/src/agent/embedded/run-for-session.js +4 -1
  100. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  101. package/dist/src/agent/fallback/candidates.js +10 -11
  102. package/dist/src/agent/fallback/candidates.js.map +1 -1
  103. package/dist/src/agent/memory/builtin-memory-store.d.ts +4 -2
  104. package/dist/src/agent/memory/builtin-memory-store.js +11 -6
  105. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  106. package/dist/src/agent/memory/builtin-provider.js +36 -7
  107. package/dist/src/agent/memory/builtin-provider.js.map +1 -1
  108. package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
  109. package/dist/src/agent/memory/candidate-extractor.js +60 -0
  110. package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
  111. package/dist/src/agent/memory/manager.d.ts +2 -1
  112. package/dist/src/agent/memory/manager.js +27 -3
  113. package/dist/src/agent/memory/manager.js.map +1 -1
  114. package/dist/src/agent/memory/memory-config.js +3 -0
  115. package/dist/src/agent/memory/memory-config.js.map +1 -1
  116. package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
  117. package/dist/src/agent/memory/types.d.ts +27 -4
  118. package/dist/src/agent/prompt/memory/index.d.ts +4 -2
  119. package/dist/src/agent/prompt/memory/index.js +18 -12
  120. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  121. package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
  122. package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
  123. package/dist/src/agent/prompt/service-prompt-builder.js +4 -19
  124. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  125. package/dist/src/agent/reply/post-compaction-context.js +1 -3
  126. package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
  127. package/dist/src/agent/reply/startup-context.js +1 -5
  128. package/dist/src/agent/reply/startup-context.js.map +1 -1
  129. package/dist/src/agent/service.d.ts +3 -3
  130. package/dist/src/agent/service.js +7 -8
  131. package/dist/src/agent/service.js.map +1 -1
  132. package/dist/src/agent/tools/curated-memory-tool.js +57 -2
  133. package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
  134. package/dist/src/agent/tools/web-extract.js +6 -8
  135. package/dist/src/agent/tools/web-extract.js.map +1 -1
  136. package/dist/src/agent-manifest/index.js +2 -2
  137. package/dist/src/agent-manifest/resolver.d.ts +3 -2
  138. package/dist/src/agent-manifest/resolver.js +5 -3
  139. package/dist/src/agent-manifest/resolver.js.map +1 -1
  140. package/dist/src/agent-manifest/schema.d.ts +232 -0
  141. package/dist/src/agent-manifest/schema.js +4 -2
  142. package/dist/src/agent-manifest/schema.js.map +1 -1
  143. package/dist/src/agent-manifest/validator.d.ts +3 -2
  144. package/dist/src/agent-manifest/validator.js +2 -1
  145. package/dist/src/agent-manifest/validator.js.map +1 -1
  146. package/dist/src/channels/pipeline.d.ts +1 -1
  147. package/dist/src/channels/pipeline.js.map +1 -1
  148. package/dist/src/chat-commands/agent-edit.js +0 -1
  149. package/dist/src/chat-commands/agent-edit.js.map +1 -1
  150. package/dist/src/chat-commands/builtins/model.js +2 -2
  151. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  152. package/dist/src/cli/command-manifest.d.ts +1 -1
  153. package/dist/src/cli/command-manifest.js +1 -1
  154. package/dist/src/cli/command-manifest.js.map +1 -1
  155. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  156. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -0
  157. package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
  158. package/dist/src/cli/commands/doctor/checks/workspace-status.js +0 -1
  159. package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
  160. package/dist/src/cli/commands/init.js +7 -6
  161. package/dist/src/cli/commands/init.js.map +1 -1
  162. package/dist/src/cli/commands/models.js +13 -31
  163. package/dist/src/cli/commands/models.js.map +1 -1
  164. package/dist/src/cli/commands/onboard/model.js +17 -10
  165. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  166. package/dist/src/cli/commands/onboard.js +2 -2
  167. package/dist/src/cli/commands/onboard.js.map +1 -1
  168. package/dist/src/cli/commands/tui.js +2 -2
  169. package/dist/src/cli/commands/tui.js.map +1 -1
  170. package/dist/src/cli/index.d.ts +1 -0
  171. package/dist/src/cli/index.js +10 -5
  172. package/dist/src/cli/index.js.map +1 -1
  173. package/dist/src/cli/registry.js +1 -1
  174. package/dist/src/cli/registry.js.map +1 -1
  175. package/dist/src/cli/templates.d.ts +1 -1
  176. package/dist/src/cli/templates.js +1 -11
  177. package/dist/src/cli/templates.js.map +1 -1
  178. package/dist/src/commands/agents.config.js +2 -10
  179. package/dist/src/commands/agents.config.js.map +1 -1
  180. package/dist/src/config/agent-profile.js +3 -2
  181. package/dist/src/config/agent-profile.js.map +1 -1
  182. package/dist/src/config/agent-typed-models.js +3 -5
  183. package/dist/src/config/agent-typed-models.js.map +1 -1
  184. package/dist/src/config/index.js +2 -2
  185. package/dist/src/config/paths.d.ts +8 -1
  186. package/dist/src/config/paths.js +16 -3
  187. package/dist/src/config/paths.js.map +1 -1
  188. package/dist/src/config/schema.d.ts +32 -32
  189. package/dist/src/config/schema.js +46 -26
  190. package/dist/src/config/schema.js.map +1 -1
  191. package/dist/src/gateway/agents-admin.d.ts +7 -0
  192. package/dist/src/gateway/agents-admin.js +51 -20
  193. package/dist/src/gateway/agents-admin.js.map +1 -1
  194. package/dist/src/gateway/chat-stream/mapper.js +9 -2
  195. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  196. package/dist/src/gateway/global-defaults-admin.d.ts +36 -0
  197. package/dist/src/gateway/global-defaults-admin.js +146 -0
  198. package/dist/src/gateway/global-defaults-admin.js.map +1 -0
  199. package/dist/src/gateway/hono/routes/agents.js +33 -1
  200. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  201. package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
  202. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  203. package/dist/src/gateway/hono/routes/global-defaults.d.ts +3 -0
  204. package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
  205. package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
  206. package/dist/src/gateway/hono/routes/lazy-bundles.js +11 -3
  207. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  208. package/dist/src/gateway/hono/routes/memory.js +75 -4
  209. package/dist/src/gateway/hono/routes/memory.js.map +1 -1
  210. package/dist/src/gateway/hono/routes/models.js +1 -1
  211. package/dist/src/gateway/service/marketplace-service.d.ts +4 -4
  212. package/dist/src/gateway/service/marketplace-service.js +11 -7
  213. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  214. package/dist/src/notes/service.js +3 -1
  215. package/dist/src/notes/service.js.map +1 -1
  216. package/dist/src/providers/index.d.ts +4 -5
  217. package/dist/src/providers/index.js +16 -16
  218. package/dist/src/providers/index.js.map +1 -1
  219. package/dist/src/session/session-workspace.js +2 -7
  220. package/dist/src/session/session-workspace.js.map +1 -1
  221. package/dist/src/session/store.js +0 -5
  222. package/dist/src/session/store.js.map +1 -1
  223. package/dist/src/storage/sqlite/index.d.ts +1 -1
  224. package/dist/src/storage/sqlite/index.js +2 -2
  225. package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
  226. package/dist/src/storage/sqlite/memory-index-repository.js +15 -14
  227. package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
  228. package/dist/src/storage/sqlite/memory-records-repository.d.ts +44 -1
  229. package/dist/src/storage/sqlite/memory-records-repository.js +164 -20
  230. package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
  231. package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
  232. package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
  233. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  234. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  235. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  236. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  237. package/dist/src/storage/sqlite/schema.js +1 -1
  238. package/dist/src/tui/backends/embedded-backend.d.ts +3 -0
  239. package/dist/src/tui/backends/embedded-backend.js +37 -20
  240. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  241. package/dist/src/tui/backends/gateway-sse-backend.d.ts +1 -0
  242. package/dist/src/tui/backends/gateway-sse-backend.js +16 -3
  243. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  244. package/dist/src/tui/components/tui-header.d.ts +0 -1
  245. package/dist/src/tui/components/tui-header.js +3 -8
  246. package/dist/src/tui/components/tui-header.js.map +1 -1
  247. package/dist/src/tui/tui-startup-resources.js +2 -1
  248. package/dist/src/tui/tui-startup-resources.js.map +1 -1
  249. package/dist/src/tui/tui-startup-text.js +12 -12
  250. package/dist/src/tui/tui-startup-text.js.map +1 -1
  251. package/dist/src/tui/tui.js +4 -1
  252. package/dist/src/tui/tui.js.map +1 -1
  253. package/package.json +1 -1
  254. package/dist/gateway/static/root/assets/agents-C6xgagZd.js +0 -71
  255. package/dist/gateway/static/root/assets/browser-settings-page-CUOO-PQk.js +0 -8
  256. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CfqF-kGr.js +0 -1
  257. package/dist/gateway/static/root/assets/channels-settings-BYyRzsex.js +0 -1
  258. package/dist/gateway/static/root/assets/connectors-page-DIvEz4NX.js +0 -2
  259. package/dist/gateway/static/root/assets/cron-page-D97nFqQD.js +0 -3
  260. package/dist/gateway/static/root/assets/goal-detail-page-DCUROLMQ.js +0 -1
  261. package/dist/gateway/static/root/assets/heartbeat-settings-CC69vNx0.js +0 -1
  262. package/dist/gateway/static/root/assets/index-CyfhARL-.css +0 -1
  263. package/dist/gateway/static/root/assets/messages-Cf1O9JB0.js +0 -3
  264. package/dist/gateway/static/root/assets/models-hub-panel-DmKiIihT.js +0 -2
  265. package/dist/gateway/static/root/assets/note-detail-page-CxxfLRJZ.js +0 -2
  266. package/dist/gateway/static/root/assets/notes-page-X2slSx7V.js +0 -1
  267. package/dist/gateway/static/root/assets/remote-access-hub-BvmUWqgu.js +0 -1
  268. package/dist/gateway/static/root/assets/sessions-page-B0yESuuL.js +0 -1
  269. package/dist/gateway/static/root/assets/settings-advanced-gate-q2M8RKOo.js +0 -1
  270. package/dist/gateway/static/root/assets/settings-page-CGozabLD.js +0 -1
  271. package/dist/gateway/static/root/assets/setup-status-panel-FoOSe6nU.js +0 -1
  272. package/dist/gateway/static/root/assets/shares-settings-Cy5zWyYQ.js +0 -1
  273. package/dist/gateway/static/root/assets/skill-reload-api-DaZNFro9.js +0 -1
  274. package/dist/gateway/static/root/assets/skills-page-CnwtUzvw.js +0 -2
  275. package/dist/gateway/static/root/assets/voice-api-key-field-DvKiOglO.js +0 -1
  276. package/dist/gateway/static/root/assets/workflows-page-CAVZcONQ.js +0 -18
  277. package/dist/src/agent/context/workspace-templates/USER.md +0 -24
@@ -17,6 +17,19 @@ function normalizeGatewayModelChoice(model) {
17
17
  id
18
18
  };
19
19
  }
20
+ function isRecord(value) {
21
+ return !!value && typeof value === "object" && !Array.isArray(value);
22
+ }
23
+ function normalizeGatewaySseEvent(evt) {
24
+ if (evt.event !== "agent.stream" || !isRecord(evt.data)) return evt;
25
+ const inner = evt.data.event;
26
+ if (!isRecord(inner) || typeof inner.type !== "string" || !inner.type) return evt;
27
+ return {
28
+ event: inner.type,
29
+ data: inner,
30
+ source: evt.source
31
+ };
32
+ }
20
33
  /** Fetch wrapper that adds auth headers. */
21
34
  async function gatewayFetch(baseUrl, path, token, init) {
22
35
  const headers = {
@@ -738,11 +751,11 @@ var GatewaySseBackend = class {
738
751
  return;
739
752
  }
740
753
  const data = parseSSEData(sseEvent.data);
741
- if (data !== null) this.onEvent?.({
754
+ if (data !== null) this.onEvent?.(normalizeGatewaySseEvent({
742
755
  event: sseEvent.event,
743
756
  data,
744
757
  source: "broadcast"
745
- });
758
+ }));
746
759
  }, this.eventAbort.signal);
747
760
  if (!this.eventAbort?.signal.aborted) {
748
761
  this.onDisconnected?.("stream closed");
@@ -769,6 +782,6 @@ var GatewaySseBackend = class {
769
782
  }
770
783
  };
771
784
  //#endregion
772
- export { GatewaySseBackend };
785
+ export { GatewaySseBackend, normalizeGatewaySseEvent };
773
786
 
774
787
  //# sourceMappingURL=gateway-sse-backend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-sse-backend.js","names":[],"sources":["../../../../src/tui/backends/gateway-sse-backend.ts"],"sourcesContent":["import { prependEnvelopeTimestamp } from '../../channels/envelope-timestamp.js';\nimport { parseModelRef } from '../../agent/models/selection.js';\nimport type { ExportFormat } from '../../session/types.js';\nimport type { TranscriptStoredRow } from '../../session/session-context-for-llm.js';\nimport { transcriptRowsToClientHistory } from '../../session/client-history.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { consumeSSEStream, parseSSEData } from '../sse-consumer.js';\nimport type {\n ChatSendOptions,\n HistoryMessage,\n TuiBackend,\n TuiCompactionResult,\n TuiEvent,\n TuiModelChoice,\n TuiShareRequest,\n TuiShareResult,\n TuiSessionStats,\n TuiSessionItem,\n TuiStartupResources,\n TuiTranscriptTreeEntry,\n TuiAgentInfo,\n TuiWorkspaceFileSearchEntry,\n TuiWorkflowRunStartRequest,\n TuiWorkflowRunStartResult,\n} from '../tui-backend.js';\nimport type { SessionInfo } from '../tui-types.js';\nimport { computeTuiSessionStats } from '../tui-session-stats.js';\nimport { buildTuiTranscriptTree, transcriptTreeEntryIdToRowNumber } from '../tui-transcript-tree.js';\n\nconst log = createLogger('TUI:GatewaySSE');\n\ninterface GatewaySSEOptions {\n url: string;\n token?: string;\n}\n\nfunction normalizeGatewayModelChoice(model: TuiModelChoice): TuiModelChoice {\n const providerPrefix = `${model.provider}/`;\n const id = model.id.startsWith(providerPrefix)\n ? model.id.slice(providerPrefix.length)\n : model.id;\n return { ...model, id };\n}\n\n/** Fetch wrapper that adds auth headers. */\nasync function gatewayFetch(\n baseUrl: string,\n path: string,\n token: string | undefined,\n init?: RequestInit,\n): Promise<Response> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n ...(init?.headers as Record<string, string> | undefined),\n };\n return fetch(`${baseUrl}${path}`, { ...init, headers });\n}\n\n/**\n * TUI backend that communicates with a running xopc gateway via HTTP + SSE.\n *\n * - Agent streaming: `POST /api/agent` with `Accept: text/event-stream`\n * - Broadcast events: `GET /api/events` via long-lived SSE\n * - REST calls for sessions, models, etc.\n */\nexport class GatewaySseBackend implements TuiBackend {\n private readonly baseUrl: string;\n private readonly token: string | undefined;\n private eventAbort: AbortController | null = null;\n private chatAbort: AbortController | null = null;\n\n onEvent?: (evt: TuiEvent) => void;\n onConnected?: () => void;\n onDisconnected?: (reason: string) => void;\n onGap?: (info: { expected: number; received: number }) => void;\n\n constructor(opts: GatewaySSEOptions) {\n this.baseUrl = opts.url.replace(/\\/+$/, '');\n this.token = opts.token;\n }\n\n get connectionLabel(): string {\n return this.baseUrl;\n }\n\n start(): void {\n this.startEventStream();\n }\n\n stop(): void {\n this.eventAbort?.abort();\n this.eventAbort = null;\n this.chatAbort?.abort();\n this.chatAbort = null;\n }\n\n getActiveSignal(): AbortSignal | undefined {\n const signal = this.chatAbort?.signal;\n return signal && !signal.aborted ? signal : undefined;\n }\n\n // ── Agent chat (POST /api/agent → SSE response body) ──\n\n async sendChat(opts: ChatSendOptions): Promise<{ runId: string }> {\n this.chatAbort?.abort();\n this.chatAbort = new AbortController();\n const signal = this.chatAbort.signal;\n const runId = crypto.randomUUID();\n\n\n // Fire-and-forget: run the HTTP request + SSE consumption in background\n // so the TUI event loop stays responsive for keyboard input.\n void (async () => {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agent', this.token, {\n method: 'POST',\n headers: { Accept: 'text/event-stream' },\n body: JSON.stringify({\n // Prepend envelope timestamp for regular messages so the model knows\n // the current date/time. Skip for slash commands — parseSlashCommand\n // requires lines starting with '/'.\n message: opts.message.trimStart().startsWith('/')\n ? opts.message\n : prependEnvelopeTimestamp(opts.message),\n channel: 'webchat',\n sessionKey: opts.sessionKey,\n attachments: opts.attachments,\n thinking: opts.thinking,\n }),\n signal,\n });\n\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: { message?: string } };\n this.onEvent?.({\n event: 'error',\n data: {\n type: 'error',\n runId,\n sessionKey: opts.sessionKey,\n timestamp: Date.now(),\n payload: { code: 'GATEWAY_ERROR', message: body.error?.message ?? `Gateway error: ${res.status}` },\n },\n source: 'agent-response',\n });\n return;\n }\n\n const contentType = res.headers.get('Content-Type') ?? '';\n\n if (contentType.includes('text/event-stream') && res.body) {\n await consumeSSEStream(\n res.body,\n (sseEvent) => {\n if (signal.aborted) return;\n const data = parseSSEData<Record<string, unknown>>(sseEvent.data);\n if (!data) return;\n this.onEvent?.({ event: sseEvent.event, data, source: 'agent-response' });\n },\n signal,\n );\n } else {\n const json = (await res.json()) as { ok?: boolean; payload?: { content?: string } };\n if (json.ok && json.payload?.content) {\n const messageId = `msg_${runId}_1`;\n const base = { runId, sessionKey: opts.sessionKey, timestamp: Date.now() };\n this.onEvent?.({ event: 'run_start', data: { ...base, type: 'run_start', payload: { channel: 'webchat' } }, source: 'agent-response' });\n this.onEvent?.({ event: 'assistant_message_start', data: { ...base, type: 'assistant_message_start', payload: { messageId } }, source: 'agent-response' });\n this.onEvent?.({ event: 'assistant_delta', data: { ...base, type: 'assistant_delta', payload: { messageId, delta: json.payload.content } }, source: 'agent-response' });\n this.onEvent?.({ event: 'assistant_message_end', data: { ...base, type: 'assistant_message_end', payload: { messageId } }, source: 'agent-response' });\n this.onEvent?.({ event: 'run_end', data: { ...base, type: 'run_end', payload: { status: 'success' } }, source: 'agent-response' });\n }\n }\n } catch (error) {\n if (signal.aborted) return;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.onEvent?.({\n event: 'error',\n data: { type: 'error', runId, sessionKey: opts.sessionKey, timestamp: Date.now(), payload: { code: 'NETWORK_ERROR', message: errorMessage } },\n source: 'agent-response',\n });\n }\n })();\n\n return { runId };\n }\n\n async searchWorkspaceFiles(\n sessionKey: string,\n query: string,\n options?: { limit?: number },\n ): Promise<TuiWorkspaceFileSearchEntry[]> {\n try {\n const params = new URLSearchParams();\n params.set('q', query);\n params.set('limit', String(options?.limit ?? 15));\n params.set('sessionKey', sessionKey);\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/workspace/editor/files/search?${params.toString()}`,\n this.token,\n );\n if (!res.ok) return [];\n const json = (await res.json()) as {\n ok?: boolean;\n payload?: { entries?: TuiWorkspaceFileSearchEntry[] };\n };\n return json.payload?.entries ?? [];\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.warn({ err, sessionKey, errorMessage }, `Gateway workspace file search failed: ${errorMessage}`);\n return [];\n }\n }\n\n async startWorkflowRun(opts: TuiWorkflowRunStartRequest): Promise<TuiWorkflowRunStartResult> {\n const goal = opts.goal?.trim();\n const res = await gatewayFetch(this.baseUrl, '/api/workflows/runs', this.token, {\n method: 'POST',\n body: JSON.stringify({\n definitionId: opts.definitionId,\n agentId: opts.agentId,\n parentSessionKey: opts.sessionKey,\n source: { kind: 'chat', sessionKey: opts.sessionKey },\n ...(goal ? { goal } : {}),\n ...(opts.input !== undefined ? { input: opts.input } : {}),\n }),\n });\n const json = (await res.json().catch(() => ({}))) as {\n runId?: string;\n sessionKey?: string;\n error?: string;\n code?: string;\n };\n if (!res.ok || !json.runId || !json.sessionKey) {\n throw new Error(json.error ?? `Workflow start failed (${res.status})`);\n }\n return {\n runId: json.runId,\n sessionKey: json.sessionKey,\n definitionId: opts.definitionId,\n };\n }\n\n async resumeChat(opts: { sessionKey: string; runId: string }): Promise<{ ok: boolean; reason?: string }> {\n this.chatAbort?.abort();\n this.chatAbort = new AbortController();\n const signal = this.chatAbort.signal;\n this.onEvent?.({\n event: 'run_start',\n data: { type: 'run_start', runId: opts.runId, sessionKey: opts.sessionKey, timestamp: Date.now(), payload: { channel: 'webchat' } },\n source: 'agent-resume',\n });\n\n let res: Response;\n try {\n res = await gatewayFetch(this.baseUrl, '/api/agent/resume', this.token, {\n method: 'POST',\n headers: { Accept: 'text/event-stream' },\n body: JSON.stringify({ runId: opts.runId, sessionKey: opts.sessionKey }),\n signal,\n });\n } catch (error) {\n if (signal.aborted) return { ok: false, reason: 'resume aborted' };\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { ok: false, reason: errorMessage };\n }\n\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: { message?: string } };\n return { ok: false, reason: body.error?.message ?? `Resume failed: ${res.status}` };\n }\n\n const contentType = res.headers.get('Content-Type') ?? '';\n if (!contentType.includes('text/event-stream') || !res.body) {\n return { ok: false, reason: 'Resume endpoint did not return an SSE stream' };\n }\n\n void (async () => {\n try {\n await consumeSSEStream(\n res.body,\n (sseEvent) => {\n if (signal.aborted) return;\n const data = parseSSEData<Record<string, unknown>>(sseEvent.data);\n if (!data) return;\n this.onEvent?.({ event: sseEvent.event, data, source: 'agent-resume' });\n },\n signal,\n );\n } catch (error) {\n if (signal.aborted) return;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.onEvent?.({\n event: 'error',\n data: { type: 'error', runId: opts.runId, sessionKey: opts.sessionKey, timestamp: Date.now(), payload: { code: 'NETWORK_ERROR', message: errorMessage } },\n source: 'agent-resume',\n });\n }\n })();\n\n return { ok: true };\n }\n\n async abortChat(opts: { sessionKey: string; runId: string }): Promise<{ ok: boolean }> {\n this.chatAbort?.abort();\n this.chatAbort = null;\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agent/abort', this.token, {\n method: 'POST',\n body: JSON.stringify({ runId: opts.runId }),\n });\n const json = (await res.json()) as { ok?: boolean };\n return { ok: json.ok ?? false };\n } catch {\n return { ok: false };\n }\n }\n\n async steerChat(opts: { sessionKey: string; message: string }): Promise<{ ok: boolean }> {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agent/steer', this.token, {\n method: 'POST',\n body: JSON.stringify({ sessionKey: opts.sessionKey, message: opts.message }),\n });\n if (!res.ok) return { ok: false };\n const json = (await res.json()) as { ok?: boolean };\n return { ok: json.ok === true };\n } catch {\n return { ok: false };\n }\n }\n\n // ── REST helpers ──\n\n async getStartupResources(sessionKey: string): Promise<TuiStartupResources> {\n const empty: TuiStartupResources = { context: [], skills: [], workflows: [], connectors: [] };\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/tui/startup-resources?sessionKey=${encodeURIComponent(sessionKey)}`,\n this.token,\n );\n if (!res.ok) return empty;\n const json = (await res.json()) as { payload?: Partial<TuiStartupResources> };\n return {\n context: Array.isArray(json.payload?.context) ? json.payload.context : [],\n skills: Array.isArray(json.payload?.skills) ? json.payload.skills : [],\n workflows: Array.isArray(json.payload?.workflows) ? json.payload.workflows : [],\n connectors: Array.isArray(json.payload?.connectors) ? json.payload.connectors : [],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, sessionKey, errorMessage }, `Failed to load startup resources: ${errorMessage}`);\n return empty;\n }\n }\n\n async loadHistory(opts: {\n sessionKey: string;\n limit?: number;\n }): Promise<{ messages: HistoryMessage[] }> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(opts.sessionKey)}?include=transcriptRows`,\n this.token,\n );\n if (!res.ok) return { messages: [] };\n const json = (await res.json()) as {\n session?: { transcriptRows?: unknown[] };\n };\n const rows = Array.isArray(json.session?.transcriptRows)\n ? (json.session.transcriptRows as TranscriptStoredRow[])\n : [];\n return { messages: transcriptRowsToClientHistory(rows, { limit: opts.limit }) };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, errorMessage }, `Failed to load history: ${errorMessage}`);\n return { messages: [] };\n }\n }\n\n async loadTranscriptTree(sessionKey: string): Promise<TuiTranscriptTreeEntry[]> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}?include=transcriptRows`,\n this.token,\n );\n if (!res.ok) return [];\n const json = (await res.json()) as {\n session?: { transcriptRows?: unknown[] };\n };\n const rows = Array.isArray(json.session?.transcriptRows)\n ? (json.session.transcriptRows as TranscriptStoredRow[])\n : [];\n return buildTuiTranscriptTree(rows);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, sessionKey, errorMessage }, `Failed to load transcript tree: ${errorMessage}`);\n return [];\n }\n }\n\n async getSessionStats(sessionKey: string): Promise<TuiSessionStats> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}?include=transcriptRows`,\n this.token,\n );\n if (!res.ok) return computeTuiSessionStats([]);\n const json = (await res.json()) as {\n session?: { transcriptRows?: unknown[] };\n };\n const rows = Array.isArray(json.session?.transcriptRows)\n ? (json.session.transcriptRows as TranscriptStoredRow[])\n : [];\n return computeTuiSessionStats(rows);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, sessionKey, errorMessage }, `Failed to load session stats: ${errorMessage}`);\n return computeTuiSessionStats([]);\n }\n }\n\n async listSessions(): Promise<TuiSessionItem[]> {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/sessions', this.token);\n if (!res.ok) return [];\n const json = (await res.json()) as {\n items?: Array<{\n key: string;\n name?: string;\n updatedAt?: string;\n estimatedTokens?: number;\n messageCount?: number;\n customData?: Record<string, unknown>;\n cwd?: string;\n }>;\n };\n return (json.items ?? []).map((s) => ({\n key: s.key,\n displayName: s.name,\n updatedAt: s.updatedAt ? Date.parse(s.updatedAt) : undefined,\n totalTokens: s.estimatedTokens ?? null,\n messageCount: typeof s.messageCount === 'number' ? s.messageCount : undefined,\n model:\n typeof s.customData?.model === 'string'\n ? s.customData.model\n : typeof s.customData?.modelRef === 'string'\n ? s.customData.modelRef\n : null,\n forkedFromSessionKey:\n typeof s.customData?.forkedFromSessionKey === 'string'\n ? s.customData.forkedFromSessionKey\n : undefined,\n cwd: typeof s.cwd === 'string' ? s.cwd : undefined,\n }));\n } catch {\n return [];\n }\n }\n\n async listAgents(): Promise<TuiAgentInfo[]> {\n const agents = new Map<string, TuiAgentInfo>();\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agents', this.token);\n if (res.ok) {\n const json = (await res.json()) as {\n payload?: { agents?: Array<{ id?: unknown; name?: unknown }> };\n };\n for (const row of json.payload?.agents ?? []) {\n if (typeof row.id !== 'string' || !row.id.trim()) continue;\n const id = row.id.trim().toLowerCase();\n agents.set(id, {\n id,\n enabled: true,\n ...(typeof row.name === 'string' && row.name.trim()\n ? { displayName: row.name.trim() }\n : {}),\n });\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, errorMessage }, `Failed to load agents: ${errorMessage}`);\n }\n return [...agents.values()].sort((a, b) => a.id.localeCompare(b.id));\n }\n\n async getSessionInfo(sessionKey: string): Promise<SessionInfo> {\n const out: SessionInfo = {};\n try {\n const sessionPath = `/api/sessions/${encodeURIComponent(sessionKey)}`;\n const [sessionRes, agentCfgRes] = await Promise.all([\n gatewayFetch(this.baseUrl, sessionPath, this.token),\n gatewayFetch(this.baseUrl, `${sessionPath}/agent-config`, this.token),\n ]);\n\n type SessionRow = {\n name?: string;\n estimatedTokens?: number;\n customData?: Record<string, unknown>;\n };\n let session: SessionRow | undefined;\n\n if (sessionRes.ok) {\n const json = (await sessionRes.json()) as { session?: SessionRow };\n session = json.session;\n if (session) {\n if (session.name) out.displayName = session.name;\n if (session.estimatedTokens != null) out.totalTokens = session.estimatedTokens;\n }\n }\n\n if (agentCfgRes.ok) {\n const json = (await agentCfgRes.json()) as {\n ok?: boolean;\n payload?: {\n model?: string;\n thinkingLevel?: string;\n reasoningLevel?: string;\n verboseLevel?: string;\n effectiveWorkspacePath?: string;\n workingDirectoryLocked?: boolean;\n };\n };\n const p = json.payload;\n if (p?.model && typeof p.model === 'string') {\n const parsed = parseModelRef(p.model);\n if (parsed) {\n out.model = parsed.model;\n out.modelProvider = parsed.provider;\n } else {\n out.model = p.model;\n }\n }\n if (p?.thinkingLevel && typeof p.thinkingLevel === 'string') {\n out.thinkingLevel = p.thinkingLevel;\n }\n if (p?.reasoningLevel && typeof p.reasoningLevel === 'string') {\n out.reasoningLevel = p.reasoningLevel;\n }\n if (p?.verboseLevel && typeof p.verboseLevel === 'string') {\n out.verboseLevel = p.verboseLevel;\n }\n if (p?.effectiveWorkspacePath && typeof p.effectiveWorkspacePath === 'string') {\n out.effectiveWorkspacePath = p.effectiveWorkspacePath;\n }\n if (typeof p?.workingDirectoryLocked === 'boolean') {\n out.workingDirectoryLocked = p.workingDirectoryLocked;\n }\n }\n\n if (!out.model && session?.customData) {\n const cd = session.customData;\n const ref =\n typeof cd.model === 'string'\n ? cd.model\n : typeof cd.modelRef === 'string'\n ? cd.modelRef\n : undefined;\n if (ref) {\n const parsed = parseModelRef(ref);\n if (parsed) {\n out.model = parsed.model;\n out.modelProvider = parsed.provider;\n } else {\n out.model = ref;\n }\n }\n if (!out.modelProvider && typeof cd.modelProvider === 'string') {\n out.modelProvider = cd.modelProvider;\n }\n }\n\n if (out.totalTokens != null) {\n const models = await this.listModels();\n const match = models.find(\n (m) =>\n m.id === out.model &&\n (!out.modelProvider || m.provider === out.modelProvider),\n );\n const contextWindow = match?.contextWindow ?? 128_000;\n out.contextWindow = contextWindow;\n out.contextUsagePercent =\n contextWindow > 0\n ? Math.min(100, Math.round((out.totalTokens / contextWindow) * 100))\n : null;\n }\n\n return out;\n } catch {\n return {};\n }\n }\n\n async listModels(): Promise<TuiModelChoice[]> {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/models', this.token);\n if (!res.ok) return [];\n const json = (await res.json()) as {\n ok?: boolean;\n payload?: { models?: TuiModelChoice[] };\n };\n return (json.payload?.models ?? []).map(normalizeGatewayModelChoice);\n } catch {\n return [];\n }\n }\n\n async resetSession(sessionKey: string): Promise<void> {\n await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/reset`,\n this.token,\n { method: 'POST' },\n ).catch(() => {});\n }\n\n async compactSession(\n sessionKey: string,\n options?: { force?: boolean; instructions?: string },\n ): Promise<TuiCompactionResult> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/compaction/run`,\n this.token,\n {\n method: 'POST',\n body: JSON.stringify({\n force: options?.force ?? true,\n instructions: options?.instructions,\n }),\n },\n );\n if (!res.ok) {\n return { compacted: false, summary: `Compaction failed (${res.status})` };\n }\n const json = (await res.json()) as {\n ok?: boolean;\n payload?: {\n result?: {\n compacted?: boolean;\n summary?: string;\n tokensBefore?: number;\n tokensAfter?: number;\n };\n };\n };\n const result = json.payload?.result;\n if (!result?.compacted) {\n return { compacted: false, summary: 'Nothing to compact' };\n }\n return {\n compacted: true,\n summary: `Compacted (${result.tokensBefore ?? '?'} → ${result.tokensAfter ?? '?'} tokens)`,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n transcriptSummary: result.summary,\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return { compacted: false, summary: errorMessage };\n }\n }\n\n async exportSession(sessionKey: string, format: ExportFormat): Promise<string> {\n const params = new URLSearchParams({ format });\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/export?${params.toString()}`,\n this.token,\n );\n if (!res.ok) {\n throw new Error(`Export failed (${res.status})`);\n }\n const json = (await res.json()) as { content?: string };\n return json.content ?? '';\n }\n\n async importSession(\n targetSessionKey: string,\n jsonContent: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n const res = await gatewayFetch(\n this.baseUrl,\n '/api/sessions/import',\n this.token,\n { method: 'POST', body: JSON.stringify({ targetKey: targetSessionKey, content: jsonContent }) },\n );\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n sessionKey?: string;\n rowCount?: number;\n };\n if (!res.ok || json.ok === false || !json.sessionKey) {\n throw new Error(json.error ?? `Import failed (${res.status})`);\n }\n return { sessionKey: json.sessionKey, rowCount: json.rowCount ?? 0 };\n }\n\n async createShare(\n sessionKey: string,\n request: TuiShareRequest,\n options?: { agentId?: string },\n ): Promise<TuiShareResult> {\n const res = await gatewayFetch(this.baseUrl, '/api/shares/auto', this.token, {\n method: 'POST',\n body: JSON.stringify({\n path: request.path,\n audience: request.audience,\n mode: request.mode,\n title: request.title,\n description: request.description,\n sessionKey,\n agentId: options?.agentId,\n }),\n });\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: { message?: string };\n payload?: {\n share?: {\n kind?: string;\n title?: string;\n description?: string;\n shareUrl?: string;\n reachability?: string;\n reachabilityHint?: string | null;\n expiresAt?: string;\n maxViews?: number | null;\n };\n thumbnail?: { url?: string };\n routing?: { reason?: string; hint?: string };\n };\n };\n if (!res.ok || json.ok === false || !json.payload?.share?.shareUrl) {\n throw new Error(json.error?.message ?? `Share failed (${res.status})`);\n }\n const share = json.payload.share;\n return {\n kind: share.kind ?? 'share',\n shareUrl: share.shareUrl,\n title: share.title,\n description: share.description,\n thumbnailUrl: json.payload.thumbnail?.url,\n reachability: share.reachability,\n reachabilityHint: share.reachabilityHint,\n expiresAt: share.expiresAt,\n maxViews: share.maxViews,\n routingReason: json.payload.routing?.reason,\n routingHint: json.payload.routing?.hint,\n };\n }\n\n async btwQuery(sessionKey: string, question: string): Promise<{ text: string; error?: string }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/btw`,\n this.token,\n { method: 'POST', body: JSON.stringify({ question }) },\n );\n if (!res.ok) {\n return { text: '', error: `BTW failed (${res.status})` };\n }\n return (await res.json()) as { text: string; error?: string };\n }\n\n async forkSession(\n sourceSessionKey: string,\n targetSessionKey: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sourceSessionKey)}/fork`,\n this.token,\n { method: 'POST', body: JSON.stringify({ targetKey: targetSessionKey }) },\n );\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n sessionKey?: string;\n rowCount?: number;\n };\n if (!res.ok || json.ok === false || !json.sessionKey) {\n throw new Error(json.error ?? `Fork failed (${res.status})`);\n }\n return { sessionKey: json.sessionKey, rowCount: json.rowCount ?? 0 };\n }\n\n async forkSessionAt(\n sourceSessionKey: string,\n targetSessionKey: string,\n entryId: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n const throughRow = transcriptTreeEntryIdToRowNumber(entryId);\n if (throughRow == null) {\n throw new Error(`Invalid transcript entry: ${entryId}`);\n }\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sourceSessionKey)}/fork-row`,\n this.token,\n { method: 'POST', body: JSON.stringify({ targetKey: targetSessionKey, throughRow }) },\n );\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n sessionKey?: string;\n rowCount?: number;\n };\n if (!res.ok || json.ok === false || !json.sessionKey) {\n throw new Error(json.error ?? `Fork failed (${res.status})`);\n }\n return { sessionKey: json.sessionKey, rowCount: json.rowCount ?? 0 };\n }\n\n async setTranscriptLabel(\n sessionKey: string,\n entryId: string,\n label: string | undefined,\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/label`,\n this.token,\n { method: 'POST', body: JSON.stringify({ targetId: entryId, label }) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Label update failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async appendCustomEntry(\n sessionKey: string,\n customType: string,\n data?: unknown,\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/custom`,\n this.token,\n { method: 'POST', body: JSON.stringify({ customType, data }) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Custom entry append failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async appendCustomMessage(\n sessionKey: string,\n message: {\n customType: string;\n content?: string | unknown[];\n display?: boolean;\n details?: unknown;\n },\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/custom-message`,\n this.token,\n { method: 'POST', body: JSON.stringify(message) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Custom message append failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async appendBashExecution(\n sessionKey: string,\n entry: {\n command: string;\n output?: string;\n exitCode?: number | null;\n signal?: string | null;\n excludeFromContext?: boolean;\n truncated?: boolean;\n fullOutputPath?: string;\n },\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/bash`,\n this.token,\n { method: 'POST', body: JSON.stringify(entry) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Bash execution append failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async patchSession(sessionKey: string, patch: Record<string, unknown>): Promise<void> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/agent-config`,\n this.token,\n { method: 'PATCH', body: JSON.stringify(patch) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Session config patch failed (${res.status})`);\n }\n }\n\n async renameSession(sessionKey: string, name: string): Promise<{ ok: boolean }> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/rename`,\n this.token,\n { method: 'POST', body: JSON.stringify({ name }) },\n );\n return { ok: res.ok };\n } catch {\n return { ok: false };\n }\n }\n\n async deleteSession(sessionKey: string): Promise<{ ok: boolean }> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}`,\n this.token,\n { method: 'DELETE' },\n );\n if (!res.ok) return { ok: false };\n const json = (await res.json()) as { deleted?: boolean };\n return { ok: json.deleted !== false };\n } catch {\n return { ok: false };\n }\n }\n\n // ── Broadcast SSE (GET /api/events) ──\n\n private startEventStream(): void {\n this.eventAbort?.abort();\n this.eventAbort = new AbortController();\n\n const url = new URL(`${this.baseUrl}/api/events`);\n if (this.token) url.searchParams.set('token', this.token);\n\n const connect = async () => {\n try {\n const res = await fetch(url.toString(), {\n signal: this.eventAbort!.signal,\n headers: { Accept: 'text/event-stream' },\n });\n\n if (!res.ok || !res.body) {\n this.onDisconnected?.(`event stream error: ${res.status}`);\n this.scheduleReconnect();\n return;\n }\n\n this.onConnected?.();\n\n await consumeSSEStream(\n res.body,\n (sseEvent) => {\n if (sseEvent.event === 'connected') return;\n if (sseEvent.event === 'gap') {\n const gapData = parseSSEData(sseEvent.data) as {\n expected?: unknown;\n received?: unknown;\n } | null;\n if (\n gapData &&\n typeof gapData.expected === 'number' &&\n typeof gapData.received === 'number'\n ) {\n this.onGap?.({ expected: gapData.expected, received: gapData.received });\n }\n return;\n }\n const data = parseSSEData(sseEvent.data);\n if (data !== null) {\n this.onEvent?.({ event: sseEvent.event, data, source: 'broadcast' });\n }\n },\n this.eventAbort!.signal,\n );\n\n // Stream ended normally\n if (!this.eventAbort?.signal.aborted) {\n this.onDisconnected?.('stream closed');\n this.scheduleReconnect();\n }\n } catch (error) {\n if (this.eventAbort?.signal.aborted) return;\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, errorMessage }, `Event stream failed: ${errorMessage}`);\n this.onDisconnected?.(errorMessage);\n this.scheduleReconnect();\n }\n };\n\n void connect();\n }\n\n private scheduleReconnect(): void {\n if (this.eventAbort?.signal.aborted) return;\n setTimeout(() => {\n if (!this.eventAbort?.signal.aborted) {\n this.startEventStream();\n }\n }, 3000);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gateway-sse-backend.js","names":[],"sources":["../../../../src/tui/backends/gateway-sse-backend.ts"],"sourcesContent":["import { prependEnvelopeTimestamp } from '../../channels/envelope-timestamp.js';\nimport { parseModelRef } from '../../agent/models/selection.js';\nimport type { ExportFormat } from '../../session/types.js';\nimport type { TranscriptStoredRow } from '../../session/session-context-for-llm.js';\nimport { transcriptRowsToClientHistory } from '../../session/client-history.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { consumeSSEStream, parseSSEData } from '../sse-consumer.js';\nimport type {\n ChatSendOptions,\n HistoryMessage,\n TuiBackend,\n TuiCompactionResult,\n TuiEvent,\n TuiModelChoice,\n TuiShareRequest,\n TuiShareResult,\n TuiSessionStats,\n TuiSessionItem,\n TuiStartupResources,\n TuiTranscriptTreeEntry,\n TuiAgentInfo,\n TuiWorkspaceFileSearchEntry,\n TuiWorkflowRunStartRequest,\n TuiWorkflowRunStartResult,\n} from '../tui-backend.js';\nimport type { SessionInfo } from '../tui-types.js';\nimport { computeTuiSessionStats } from '../tui-session-stats.js';\nimport { buildTuiTranscriptTree, transcriptTreeEntryIdToRowNumber } from '../tui-transcript-tree.js';\n\nconst log = createLogger('TUI:GatewaySSE');\n\ninterface GatewaySSEOptions {\n url: string;\n token?: string;\n}\n\nfunction normalizeGatewayModelChoice(model: TuiModelChoice): TuiModelChoice {\n const providerPrefix = `${model.provider}/`;\n const id = model.id.startsWith(providerPrefix)\n ? model.id.slice(providerPrefix.length)\n : model.id;\n return { ...model, id };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function normalizeGatewaySseEvent(evt: TuiEvent): TuiEvent {\n if (evt.event !== 'agent.stream' || !isRecord(evt.data)) return evt;\n const inner = evt.data.event;\n if (!isRecord(inner) || typeof inner.type !== 'string' || !inner.type) return evt;\n return { event: inner.type, data: inner, source: evt.source };\n}\n\n/** Fetch wrapper that adds auth headers. */\nasync function gatewayFetch(\n baseUrl: string,\n path: string,\n token: string | undefined,\n init?: RequestInit,\n): Promise<Response> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n ...(init?.headers as Record<string, string> | undefined),\n };\n return fetch(`${baseUrl}${path}`, { ...init, headers });\n}\n\n/**\n * TUI backend that communicates with a running xopc gateway via HTTP + SSE.\n *\n * - Agent streaming: `POST /api/agent` with `Accept: text/event-stream`\n * - Broadcast events: `GET /api/events` via long-lived SSE\n * - REST calls for sessions, models, etc.\n */\nexport class GatewaySseBackend implements TuiBackend {\n private readonly baseUrl: string;\n private readonly token: string | undefined;\n private eventAbort: AbortController | null = null;\n private chatAbort: AbortController | null = null;\n\n onEvent?: (evt: TuiEvent) => void;\n onConnected?: () => void;\n onDisconnected?: (reason: string) => void;\n onGap?: (info: { expected: number; received: number }) => void;\n\n constructor(opts: GatewaySSEOptions) {\n this.baseUrl = opts.url.replace(/\\/+$/, '');\n this.token = opts.token;\n }\n\n get connectionLabel(): string {\n return this.baseUrl;\n }\n\n start(): void {\n this.startEventStream();\n }\n\n stop(): void {\n this.eventAbort?.abort();\n this.eventAbort = null;\n this.chatAbort?.abort();\n this.chatAbort = null;\n }\n\n getActiveSignal(): AbortSignal | undefined {\n const signal = this.chatAbort?.signal;\n return signal && !signal.aborted ? signal : undefined;\n }\n\n // ── Agent chat (POST /api/agent → SSE response body) ──\n\n async sendChat(opts: ChatSendOptions): Promise<{ runId: string }> {\n this.chatAbort?.abort();\n this.chatAbort = new AbortController();\n const signal = this.chatAbort.signal;\n const runId = crypto.randomUUID();\n\n\n // Fire-and-forget: run the HTTP request + SSE consumption in background\n // so the TUI event loop stays responsive for keyboard input.\n void (async () => {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agent', this.token, {\n method: 'POST',\n headers: { Accept: 'text/event-stream' },\n body: JSON.stringify({\n // Prepend envelope timestamp for regular messages so the model knows\n // the current date/time. Skip for slash commands — parseSlashCommand\n // requires lines starting with '/'.\n message: opts.message.trimStart().startsWith('/')\n ? opts.message\n : prependEnvelopeTimestamp(opts.message),\n channel: 'webchat',\n sessionKey: opts.sessionKey,\n attachments: opts.attachments,\n thinking: opts.thinking,\n }),\n signal,\n });\n\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: { message?: string } };\n this.onEvent?.({\n event: 'error',\n data: {\n type: 'error',\n runId,\n sessionKey: opts.sessionKey,\n timestamp: Date.now(),\n payload: { code: 'GATEWAY_ERROR', message: body.error?.message ?? `Gateway error: ${res.status}` },\n },\n source: 'agent-response',\n });\n return;\n }\n\n const contentType = res.headers.get('Content-Type') ?? '';\n\n if (contentType.includes('text/event-stream') && res.body) {\n await consumeSSEStream(\n res.body,\n (sseEvent) => {\n if (signal.aborted) return;\n const data = parseSSEData<Record<string, unknown>>(sseEvent.data);\n if (!data) return;\n this.onEvent?.({ event: sseEvent.event, data, source: 'agent-response' });\n },\n signal,\n );\n } else {\n const json = (await res.json()) as { ok?: boolean; payload?: { content?: string } };\n if (json.ok && json.payload?.content) {\n const messageId = `msg_${runId}_1`;\n const base = { runId, sessionKey: opts.sessionKey, timestamp: Date.now() };\n this.onEvent?.({ event: 'run_start', data: { ...base, type: 'run_start', payload: { channel: 'webchat' } }, source: 'agent-response' });\n this.onEvent?.({ event: 'assistant_message_start', data: { ...base, type: 'assistant_message_start', payload: { messageId } }, source: 'agent-response' });\n this.onEvent?.({ event: 'assistant_delta', data: { ...base, type: 'assistant_delta', payload: { messageId, delta: json.payload.content } }, source: 'agent-response' });\n this.onEvent?.({ event: 'assistant_message_end', data: { ...base, type: 'assistant_message_end', payload: { messageId } }, source: 'agent-response' });\n this.onEvent?.({ event: 'run_end', data: { ...base, type: 'run_end', payload: { status: 'success' } }, source: 'agent-response' });\n }\n }\n } catch (error) {\n if (signal.aborted) return;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.onEvent?.({\n event: 'error',\n data: { type: 'error', runId, sessionKey: opts.sessionKey, timestamp: Date.now(), payload: { code: 'NETWORK_ERROR', message: errorMessage } },\n source: 'agent-response',\n });\n }\n })();\n\n return { runId };\n }\n\n async searchWorkspaceFiles(\n sessionKey: string,\n query: string,\n options?: { limit?: number },\n ): Promise<TuiWorkspaceFileSearchEntry[]> {\n try {\n const params = new URLSearchParams();\n params.set('q', query);\n params.set('limit', String(options?.limit ?? 15));\n params.set('sessionKey', sessionKey);\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/workspace/editor/files/search?${params.toString()}`,\n this.token,\n );\n if (!res.ok) return [];\n const json = (await res.json()) as {\n ok?: boolean;\n payload?: { entries?: TuiWorkspaceFileSearchEntry[] };\n };\n return json.payload?.entries ?? [];\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.warn({ err, sessionKey, errorMessage }, `Gateway workspace file search failed: ${errorMessage}`);\n return [];\n }\n }\n\n async startWorkflowRun(opts: TuiWorkflowRunStartRequest): Promise<TuiWorkflowRunStartResult> {\n const goal = opts.goal?.trim();\n const res = await gatewayFetch(this.baseUrl, '/api/workflows/runs', this.token, {\n method: 'POST',\n body: JSON.stringify({\n definitionId: opts.definitionId,\n agentId: opts.agentId,\n parentSessionKey: opts.sessionKey,\n source: { kind: 'chat', sessionKey: opts.sessionKey },\n ...(goal ? { goal } : {}),\n ...(opts.input !== undefined ? { input: opts.input } : {}),\n }),\n });\n const json = (await res.json().catch(() => ({}))) as {\n runId?: string;\n sessionKey?: string;\n error?: string;\n code?: string;\n };\n if (!res.ok || !json.runId || !json.sessionKey) {\n throw new Error(json.error ?? `Workflow start failed (${res.status})`);\n }\n return {\n runId: json.runId,\n sessionKey: json.sessionKey,\n definitionId: opts.definitionId,\n };\n }\n\n async resumeChat(opts: { sessionKey: string; runId: string }): Promise<{ ok: boolean; reason?: string }> {\n this.chatAbort?.abort();\n this.chatAbort = new AbortController();\n const signal = this.chatAbort.signal;\n this.onEvent?.({\n event: 'run_start',\n data: { type: 'run_start', runId: opts.runId, sessionKey: opts.sessionKey, timestamp: Date.now(), payload: { channel: 'webchat' } },\n source: 'agent-resume',\n });\n\n let res: Response;\n try {\n res = await gatewayFetch(this.baseUrl, '/api/agent/resume', this.token, {\n method: 'POST',\n headers: { Accept: 'text/event-stream' },\n body: JSON.stringify({ runId: opts.runId, sessionKey: opts.sessionKey }),\n signal,\n });\n } catch (error) {\n if (signal.aborted) return { ok: false, reason: 'resume aborted' };\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { ok: false, reason: errorMessage };\n }\n\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: { message?: string } };\n return { ok: false, reason: body.error?.message ?? `Resume failed: ${res.status}` };\n }\n\n const contentType = res.headers.get('Content-Type') ?? '';\n if (!contentType.includes('text/event-stream') || !res.body) {\n return { ok: false, reason: 'Resume endpoint did not return an SSE stream' };\n }\n\n void (async () => {\n try {\n await consumeSSEStream(\n res.body,\n (sseEvent) => {\n if (signal.aborted) return;\n const data = parseSSEData<Record<string, unknown>>(sseEvent.data);\n if (!data) return;\n this.onEvent?.({ event: sseEvent.event, data, source: 'agent-resume' });\n },\n signal,\n );\n } catch (error) {\n if (signal.aborted) return;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.onEvent?.({\n event: 'error',\n data: { type: 'error', runId: opts.runId, sessionKey: opts.sessionKey, timestamp: Date.now(), payload: { code: 'NETWORK_ERROR', message: errorMessage } },\n source: 'agent-resume',\n });\n }\n })();\n\n return { ok: true };\n }\n\n async abortChat(opts: { sessionKey: string; runId: string }): Promise<{ ok: boolean }> {\n this.chatAbort?.abort();\n this.chatAbort = null;\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agent/abort', this.token, {\n method: 'POST',\n body: JSON.stringify({ runId: opts.runId }),\n });\n const json = (await res.json()) as { ok?: boolean };\n return { ok: json.ok ?? false };\n } catch {\n return { ok: false };\n }\n }\n\n async steerChat(opts: { sessionKey: string; message: string }): Promise<{ ok: boolean }> {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agent/steer', this.token, {\n method: 'POST',\n body: JSON.stringify({ sessionKey: opts.sessionKey, message: opts.message }),\n });\n if (!res.ok) return { ok: false };\n const json = (await res.json()) as { ok?: boolean };\n return { ok: json.ok === true };\n } catch {\n return { ok: false };\n }\n }\n\n // ── REST helpers ──\n\n async getStartupResources(sessionKey: string): Promise<TuiStartupResources> {\n const empty: TuiStartupResources = { context: [], skills: [], workflows: [], connectors: [] };\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/tui/startup-resources?sessionKey=${encodeURIComponent(sessionKey)}`,\n this.token,\n );\n if (!res.ok) return empty;\n const json = (await res.json()) as { payload?: Partial<TuiStartupResources> };\n return {\n context: Array.isArray(json.payload?.context) ? json.payload.context : [],\n skills: Array.isArray(json.payload?.skills) ? json.payload.skills : [],\n workflows: Array.isArray(json.payload?.workflows) ? json.payload.workflows : [],\n connectors: Array.isArray(json.payload?.connectors) ? json.payload.connectors : [],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, sessionKey, errorMessage }, `Failed to load startup resources: ${errorMessage}`);\n return empty;\n }\n }\n\n async loadHistory(opts: {\n sessionKey: string;\n limit?: number;\n }): Promise<{ messages: HistoryMessage[] }> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(opts.sessionKey)}?include=transcriptRows`,\n this.token,\n );\n if (!res.ok) return { messages: [] };\n const json = (await res.json()) as {\n session?: { transcriptRows?: unknown[] };\n };\n const rows = Array.isArray(json.session?.transcriptRows)\n ? (json.session.transcriptRows as TranscriptStoredRow[])\n : [];\n return { messages: transcriptRowsToClientHistory(rows, { limit: opts.limit }) };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, errorMessage }, `Failed to load history: ${errorMessage}`);\n return { messages: [] };\n }\n }\n\n async loadTranscriptTree(sessionKey: string): Promise<TuiTranscriptTreeEntry[]> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}?include=transcriptRows`,\n this.token,\n );\n if (!res.ok) return [];\n const json = (await res.json()) as {\n session?: { transcriptRows?: unknown[] };\n };\n const rows = Array.isArray(json.session?.transcriptRows)\n ? (json.session.transcriptRows as TranscriptStoredRow[])\n : [];\n return buildTuiTranscriptTree(rows);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, sessionKey, errorMessage }, `Failed to load transcript tree: ${errorMessage}`);\n return [];\n }\n }\n\n async getSessionStats(sessionKey: string): Promise<TuiSessionStats> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}?include=transcriptRows`,\n this.token,\n );\n if (!res.ok) return computeTuiSessionStats([]);\n const json = (await res.json()) as {\n session?: { transcriptRows?: unknown[] };\n };\n const rows = Array.isArray(json.session?.transcriptRows)\n ? (json.session.transcriptRows as TranscriptStoredRow[])\n : [];\n return computeTuiSessionStats(rows);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, sessionKey, errorMessage }, `Failed to load session stats: ${errorMessage}`);\n return computeTuiSessionStats([]);\n }\n }\n\n async listSessions(): Promise<TuiSessionItem[]> {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/sessions', this.token);\n if (!res.ok) return [];\n const json = (await res.json()) as {\n items?: Array<{\n key: string;\n name?: string;\n updatedAt?: string;\n estimatedTokens?: number;\n messageCount?: number;\n customData?: Record<string, unknown>;\n cwd?: string;\n }>;\n };\n return (json.items ?? []).map((s) => ({\n key: s.key,\n displayName: s.name,\n updatedAt: s.updatedAt ? Date.parse(s.updatedAt) : undefined,\n totalTokens: s.estimatedTokens ?? null,\n messageCount: typeof s.messageCount === 'number' ? s.messageCount : undefined,\n model:\n typeof s.customData?.model === 'string'\n ? s.customData.model\n : typeof s.customData?.modelRef === 'string'\n ? s.customData.modelRef\n : null,\n forkedFromSessionKey:\n typeof s.customData?.forkedFromSessionKey === 'string'\n ? s.customData.forkedFromSessionKey\n : undefined,\n cwd: typeof s.cwd === 'string' ? s.cwd : undefined,\n }));\n } catch {\n return [];\n }\n }\n\n async listAgents(): Promise<TuiAgentInfo[]> {\n const agents = new Map<string, TuiAgentInfo>();\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/agents', this.token);\n if (res.ok) {\n const json = (await res.json()) as {\n payload?: { agents?: Array<{ id?: unknown; name?: unknown }> };\n };\n for (const row of json.payload?.agents ?? []) {\n if (typeof row.id !== 'string' || !row.id.trim()) continue;\n const id = row.id.trim().toLowerCase();\n agents.set(id, {\n id,\n enabled: true,\n ...(typeof row.name === 'string' && row.name.trim()\n ? { displayName: row.name.trim() }\n : {}),\n });\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, errorMessage }, `Failed to load agents: ${errorMessage}`);\n }\n return [...agents.values()].sort((a, b) => a.id.localeCompare(b.id));\n }\n\n async getSessionInfo(sessionKey: string): Promise<SessionInfo> {\n const out: SessionInfo = {};\n try {\n const sessionPath = `/api/sessions/${encodeURIComponent(sessionKey)}`;\n const [sessionRes, agentCfgRes] = await Promise.all([\n gatewayFetch(this.baseUrl, sessionPath, this.token),\n gatewayFetch(this.baseUrl, `${sessionPath}/agent-config`, this.token),\n ]);\n\n type SessionRow = {\n name?: string;\n estimatedTokens?: number;\n customData?: Record<string, unknown>;\n };\n let session: SessionRow | undefined;\n\n if (sessionRes.ok) {\n const json = (await sessionRes.json()) as { session?: SessionRow };\n session = json.session;\n if (session) {\n if (session.name) out.displayName = session.name;\n if (session.estimatedTokens != null) out.totalTokens = session.estimatedTokens;\n }\n }\n\n if (agentCfgRes.ok) {\n const json = (await agentCfgRes.json()) as {\n ok?: boolean;\n payload?: {\n model?: string;\n thinkingLevel?: string;\n reasoningLevel?: string;\n verboseLevel?: string;\n effectiveWorkspacePath?: string;\n workingDirectoryLocked?: boolean;\n };\n };\n const p = json.payload;\n if (p?.model && typeof p.model === 'string') {\n const parsed = parseModelRef(p.model);\n if (parsed) {\n out.model = parsed.model;\n out.modelProvider = parsed.provider;\n } else {\n out.model = p.model;\n }\n }\n if (p?.thinkingLevel && typeof p.thinkingLevel === 'string') {\n out.thinkingLevel = p.thinkingLevel;\n }\n if (p?.reasoningLevel && typeof p.reasoningLevel === 'string') {\n out.reasoningLevel = p.reasoningLevel;\n }\n if (p?.verboseLevel && typeof p.verboseLevel === 'string') {\n out.verboseLevel = p.verboseLevel;\n }\n if (p?.effectiveWorkspacePath && typeof p.effectiveWorkspacePath === 'string') {\n out.effectiveWorkspacePath = p.effectiveWorkspacePath;\n }\n if (typeof p?.workingDirectoryLocked === 'boolean') {\n out.workingDirectoryLocked = p.workingDirectoryLocked;\n }\n }\n\n if (!out.model && session?.customData) {\n const cd = session.customData;\n const ref =\n typeof cd.model === 'string'\n ? cd.model\n : typeof cd.modelRef === 'string'\n ? cd.modelRef\n : undefined;\n if (ref) {\n const parsed = parseModelRef(ref);\n if (parsed) {\n out.model = parsed.model;\n out.modelProvider = parsed.provider;\n } else {\n out.model = ref;\n }\n }\n if (!out.modelProvider && typeof cd.modelProvider === 'string') {\n out.modelProvider = cd.modelProvider;\n }\n }\n\n if (out.totalTokens != null) {\n const models = await this.listModels();\n const match = models.find(\n (m) =>\n m.id === out.model &&\n (!out.modelProvider || m.provider === out.modelProvider),\n );\n const contextWindow = match?.contextWindow ?? 128_000;\n out.contextWindow = contextWindow;\n out.contextUsagePercent =\n contextWindow > 0\n ? Math.min(100, Math.round((out.totalTokens / contextWindow) * 100))\n : null;\n }\n\n return out;\n } catch {\n return {};\n }\n }\n\n async listModels(): Promise<TuiModelChoice[]> {\n try {\n const res = await gatewayFetch(this.baseUrl, '/api/models', this.token);\n if (!res.ok) return [];\n const json = (await res.json()) as {\n ok?: boolean;\n payload?: { models?: TuiModelChoice[] };\n };\n return (json.payload?.models ?? []).map(normalizeGatewayModelChoice);\n } catch {\n return [];\n }\n }\n\n async resetSession(sessionKey: string): Promise<void> {\n await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/reset`,\n this.token,\n { method: 'POST' },\n ).catch(() => {});\n }\n\n async compactSession(\n sessionKey: string,\n options?: { force?: boolean; instructions?: string },\n ): Promise<TuiCompactionResult> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/compaction/run`,\n this.token,\n {\n method: 'POST',\n body: JSON.stringify({\n force: options?.force ?? true,\n instructions: options?.instructions,\n }),\n },\n );\n if (!res.ok) {\n return { compacted: false, summary: `Compaction failed (${res.status})` };\n }\n const json = (await res.json()) as {\n ok?: boolean;\n payload?: {\n result?: {\n compacted?: boolean;\n summary?: string;\n tokensBefore?: number;\n tokensAfter?: number;\n };\n };\n };\n const result = json.payload?.result;\n if (!result?.compacted) {\n return { compacted: false, summary: 'Nothing to compact' };\n }\n return {\n compacted: true,\n summary: `Compacted (${result.tokensBefore ?? '?'} → ${result.tokensAfter ?? '?'} tokens)`,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n transcriptSummary: result.summary,\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return { compacted: false, summary: errorMessage };\n }\n }\n\n async exportSession(sessionKey: string, format: ExportFormat): Promise<string> {\n const params = new URLSearchParams({ format });\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/export?${params.toString()}`,\n this.token,\n );\n if (!res.ok) {\n throw new Error(`Export failed (${res.status})`);\n }\n const json = (await res.json()) as { content?: string };\n return json.content ?? '';\n }\n\n async importSession(\n targetSessionKey: string,\n jsonContent: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n const res = await gatewayFetch(\n this.baseUrl,\n '/api/sessions/import',\n this.token,\n { method: 'POST', body: JSON.stringify({ targetKey: targetSessionKey, content: jsonContent }) },\n );\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n sessionKey?: string;\n rowCount?: number;\n };\n if (!res.ok || json.ok === false || !json.sessionKey) {\n throw new Error(json.error ?? `Import failed (${res.status})`);\n }\n return { sessionKey: json.sessionKey, rowCount: json.rowCount ?? 0 };\n }\n\n async createShare(\n sessionKey: string,\n request: TuiShareRequest,\n options?: { agentId?: string },\n ): Promise<TuiShareResult> {\n const res = await gatewayFetch(this.baseUrl, '/api/shares/auto', this.token, {\n method: 'POST',\n body: JSON.stringify({\n path: request.path,\n audience: request.audience,\n mode: request.mode,\n title: request.title,\n description: request.description,\n sessionKey,\n agentId: options?.agentId,\n }),\n });\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: { message?: string };\n payload?: {\n share?: {\n kind?: string;\n title?: string;\n description?: string;\n shareUrl?: string;\n reachability?: string;\n reachabilityHint?: string | null;\n expiresAt?: string;\n maxViews?: number | null;\n };\n thumbnail?: { url?: string };\n routing?: { reason?: string; hint?: string };\n };\n };\n if (!res.ok || json.ok === false || !json.payload?.share?.shareUrl) {\n throw new Error(json.error?.message ?? `Share failed (${res.status})`);\n }\n const share = json.payload.share;\n return {\n kind: share.kind ?? 'share',\n shareUrl: share.shareUrl,\n title: share.title,\n description: share.description,\n thumbnailUrl: json.payload.thumbnail?.url,\n reachability: share.reachability,\n reachabilityHint: share.reachabilityHint,\n expiresAt: share.expiresAt,\n maxViews: share.maxViews,\n routingReason: json.payload.routing?.reason,\n routingHint: json.payload.routing?.hint,\n };\n }\n\n async btwQuery(sessionKey: string, question: string): Promise<{ text: string; error?: string }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/btw`,\n this.token,\n { method: 'POST', body: JSON.stringify({ question }) },\n );\n if (!res.ok) {\n return { text: '', error: `BTW failed (${res.status})` };\n }\n return (await res.json()) as { text: string; error?: string };\n }\n\n async forkSession(\n sourceSessionKey: string,\n targetSessionKey: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sourceSessionKey)}/fork`,\n this.token,\n { method: 'POST', body: JSON.stringify({ targetKey: targetSessionKey }) },\n );\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n sessionKey?: string;\n rowCount?: number;\n };\n if (!res.ok || json.ok === false || !json.sessionKey) {\n throw new Error(json.error ?? `Fork failed (${res.status})`);\n }\n return { sessionKey: json.sessionKey, rowCount: json.rowCount ?? 0 };\n }\n\n async forkSessionAt(\n sourceSessionKey: string,\n targetSessionKey: string,\n entryId: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n const throughRow = transcriptTreeEntryIdToRowNumber(entryId);\n if (throughRow == null) {\n throw new Error(`Invalid transcript entry: ${entryId}`);\n }\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sourceSessionKey)}/fork-row`,\n this.token,\n { method: 'POST', body: JSON.stringify({ targetKey: targetSessionKey, throughRow }) },\n );\n const json = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n sessionKey?: string;\n rowCount?: number;\n };\n if (!res.ok || json.ok === false || !json.sessionKey) {\n throw new Error(json.error ?? `Fork failed (${res.status})`);\n }\n return { sessionKey: json.sessionKey, rowCount: json.rowCount ?? 0 };\n }\n\n async setTranscriptLabel(\n sessionKey: string,\n entryId: string,\n label: string | undefined,\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/label`,\n this.token,\n { method: 'POST', body: JSON.stringify({ targetId: entryId, label }) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Label update failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async appendCustomEntry(\n sessionKey: string,\n customType: string,\n data?: unknown,\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/custom`,\n this.token,\n { method: 'POST', body: JSON.stringify({ customType, data }) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Custom entry append failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async appendCustomMessage(\n sessionKey: string,\n message: {\n customType: string;\n content?: string | unknown[];\n display?: boolean;\n details?: unknown;\n },\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/custom-message`,\n this.token,\n { method: 'POST', body: JSON.stringify(message) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Custom message append failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async appendBashExecution(\n sessionKey: string,\n entry: {\n command: string;\n output?: string;\n exitCode?: number | null;\n signal?: string | null;\n excludeFromContext?: boolean;\n truncated?: boolean;\n fullOutputPath?: string;\n },\n ): Promise<{ ok: boolean }> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/transcript/bash`,\n this.token,\n { method: 'POST', body: JSON.stringify(entry) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Bash execution append failed (${res.status})`);\n }\n return { ok: true };\n }\n\n async patchSession(sessionKey: string, patch: Record<string, unknown>): Promise<void> {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/agent-config`,\n this.token,\n { method: 'PATCH', body: JSON.stringify(patch) },\n );\n const json = (await res.json().catch(() => ({}))) as { ok?: boolean; error?: string };\n if (!res.ok || json.ok === false) {\n throw new Error(json.error ?? `Session config patch failed (${res.status})`);\n }\n }\n\n async renameSession(sessionKey: string, name: string): Promise<{ ok: boolean }> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}/rename`,\n this.token,\n { method: 'POST', body: JSON.stringify({ name }) },\n );\n return { ok: res.ok };\n } catch {\n return { ok: false };\n }\n }\n\n async deleteSession(sessionKey: string): Promise<{ ok: boolean }> {\n try {\n const res = await gatewayFetch(\n this.baseUrl,\n `/api/sessions/${encodeURIComponent(sessionKey)}`,\n this.token,\n { method: 'DELETE' },\n );\n if (!res.ok) return { ok: false };\n const json = (await res.json()) as { deleted?: boolean };\n return { ok: json.deleted !== false };\n } catch {\n return { ok: false };\n }\n }\n\n // ── Broadcast SSE (GET /api/events) ──\n\n private startEventStream(): void {\n this.eventAbort?.abort();\n this.eventAbort = new AbortController();\n\n const url = new URL(`${this.baseUrl}/api/events`);\n if (this.token) url.searchParams.set('token', this.token);\n\n const connect = async () => {\n try {\n const res = await fetch(url.toString(), {\n signal: this.eventAbort!.signal,\n headers: { Accept: 'text/event-stream' },\n });\n\n if (!res.ok || !res.body) {\n this.onDisconnected?.(`event stream error: ${res.status}`);\n this.scheduleReconnect();\n return;\n }\n\n this.onConnected?.();\n\n await consumeSSEStream(\n res.body,\n (sseEvent) => {\n if (sseEvent.event === 'connected') return;\n if (sseEvent.event === 'gap') {\n const gapData = parseSSEData(sseEvent.data) as {\n expected?: unknown;\n received?: unknown;\n } | null;\n if (\n gapData &&\n typeof gapData.expected === 'number' &&\n typeof gapData.received === 'number'\n ) {\n this.onGap?.({ expected: gapData.expected, received: gapData.received });\n }\n return;\n }\n const data = parseSSEData(sseEvent.data);\n if (data !== null) {\n this.onEvent?.(normalizeGatewaySseEvent({ event: sseEvent.event, data, source: 'broadcast' }));\n }\n },\n this.eventAbort!.signal,\n );\n\n // Stream ended normally\n if (!this.eventAbort?.signal.aborted) {\n this.onDisconnected?.('stream closed');\n this.scheduleReconnect();\n }\n } catch (error) {\n if (this.eventAbort?.signal.aborted) return;\n const errorMessage = error instanceof Error ? error.message : String(error);\n log.warn({ err: error, errorMessage }, `Event stream failed: ${errorMessage}`);\n this.onDisconnected?.(errorMessage);\n this.scheduleReconnect();\n }\n };\n\n void connect();\n }\n\n private scheduleReconnect(): void {\n if (this.eventAbort?.signal.aborted) return;\n setTimeout(() => {\n if (!this.eventAbort?.signal.aborted) {\n this.startEventStream();\n }\n }, 3000);\n }\n}\n"],"mappings":"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"}
@@ -17,7 +17,6 @@ export declare class TuiHeader implements Component {
17
17
  setCustomComponent(component: Component | undefined): void;
18
18
  invalidate(): void;
19
19
  private getCompactHints;
20
- private getExpandedHints;
21
20
  render(width: number): string[];
22
21
  private customComponent;
23
22
  }
@@ -1,9 +1,9 @@
1
1
  import { theme } from "../theme.js";
2
2
  import { formatKeyIds } from "../format-tui-hotkeys.js";
3
- import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
3
+ import { truncateToWidth } from "@earendil-works/pi-tui";
4
4
  //#region src/tui/components/tui-header.ts
5
5
  const COMPACT_HINTS = "escape interrupt · ctrl+c/ctrl+d clear/exit · / commands · ! bash · ctrl+o tools";
6
- const EXPANDED_HINTS = ["Press /start to show full startup help and loaded resources.", "xopc can use skills, workflows, connectors, and project context."];
6
+ const STARTUP_HELP_HINT = "Press /start to show full startup help and loaded resources.";
7
7
  /** Collapsible startup header (pi-style hints subset). */
8
8
  var TuiHeader = class {
9
9
  extensionLines = [];
@@ -26,18 +26,13 @@ var TuiHeader = class {
26
26
  if (!this.keybindings) return COMPACT_HINTS;
27
27
  return `${formatKeyIds(this.keybindings, "app.interrupt", { capitalize: false })} interrupt · ${formatKeyIds(this.keybindings, "app.clear", { capitalize: false })}/${formatKeyIds(this.keybindings, "app.exit", { capitalize: false })} clear/exit · / commands · ! bash · ${formatKeyIds(this.keybindings, "app.tools.expand", { capitalize: false })} tools`;
28
28
  }
29
- getExpandedHints() {
30
- if (!this.keybindings) return EXPANDED_HINTS;
31
- return EXPANDED_HINTS;
32
- }
33
29
  render(width) {
34
30
  if (this.customComponent) return this.customComponent.render(width).map((line) => truncateToWidth(line, width, theme.dim("…")));
35
31
  const { version, connectionLabel, sessionKey, showHints } = this.getModel();
36
32
  const lines = [truncateToWidth(theme.header(`xopc tui v${version} — ${connectionLabel} — ${sessionKey}`), width, theme.dim("…"))];
37
33
  if (showHints) {
38
34
  lines.push(truncateToWidth(theme.dim(this.getCompactHints()), width, theme.dim("…")));
39
- for (const hint of this.getExpandedHints()) if (visibleWidth(hint) <= width) lines.push(theme.dim(hint));
40
- else lines.push(truncateToWidth(theme.dim(hint), width, theme.dim("…")));
35
+ lines.push(truncateToWidth(theme.dim(STARTUP_HELP_HINT), width, theme.dim("…")));
41
36
  }
42
37
  for (const extLine of this.extensionLines) lines.push(truncateToWidth(theme.dim(extLine), width, theme.dim("…")));
43
38
  for (const component of this.extensionComponents) for (const line of component.render(width)) lines.push(truncateToWidth(line, width, theme.dim("…")));
@@ -1 +1 @@
1
- {"version":3,"file":"tui-header.js","names":[],"sources":["../../../../src/tui/components/tui-header.ts"],"sourcesContent":["import type { Component, KeybindingsManager } from '@earendil-works/pi-tui';\nimport { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport { theme } from '../theme.js';\nimport { formatKeyIds } from '../format-tui-hotkeys.js';\n\nexport type TuiHeaderModel = {\n version: string;\n connectionLabel: string;\n sessionKey: string;\n showHints: boolean;\n};\n\nconst COMPACT_HINTS =\n 'escape interrupt · ctrl+c/ctrl+d clear/exit · / commands · ! bash · ctrl+o tools';\n\nconst EXPANDED_HINTS = [\n 'Press /start to show full startup help and loaded resources.',\n 'xopc can use skills, workflows, connectors, and project context.',\n];\n\n/** Collapsible startup header (pi-style hints subset). */\nexport class TuiHeader implements Component {\n private extensionLines: string[] = [];\n private extensionComponents: Component[] = [];\n\n constructor(\n private readonly getModel: () => TuiHeaderModel,\n private readonly keybindings?: KeybindingsManager,\n ) {}\n\n setExtensionLines(lines: string[]): void {\n this.extensionLines = lines;\n }\n\n setExtensionComponents(components: Component[]): void {\n this.extensionComponents = components;\n }\n\n setCustomComponent(component: Component | undefined): void {\n this.customComponent = component;\n }\n\n invalidate(): void {}\n\n private getCompactHints(): string {\n if (!this.keybindings) return COMPACT_HINTS;\n const interrupt = formatKeyIds(this.keybindings, 'app.interrupt', { capitalize: false });\n const clear = formatKeyIds(this.keybindings, 'app.clear', { capitalize: false });\n const exit = formatKeyIds(this.keybindings, 'app.exit', { capitalize: false });\n const tools = formatKeyIds(this.keybindings, 'app.tools.expand', { capitalize: false });\n return `${interrupt} interrupt · ${clear}/${exit} clear/exit · / commands · ! bash · ${tools} tools`;\n }\n\n private getExpandedHints(): string[] {\n if (!this.keybindings) return EXPANDED_HINTS;\n return EXPANDED_HINTS;\n }\n\n render(width: number): string[] {\n if (this.customComponent) {\n const rendered = this.customComponent.render(width);\n return rendered.map((line) => truncateToWidth(line, width, theme.dim('…')));\n }\n\n const { version, connectionLabel, sessionKey, showHints } = this.getModel();\n const title = theme.header(`xopc tui v${version} — ${connectionLabel} — ${sessionKey}`);\n const lines = [truncateToWidth(title, width, theme.dim('…'))];\n\n if (showHints) {\n lines.push(truncateToWidth(theme.dim(this.getCompactHints()), width, theme.dim('…')));\n for (const hint of this.getExpandedHints()) {\n if (visibleWidth(hint) <= width) {\n lines.push(theme.dim(hint));\n } else {\n lines.push(truncateToWidth(theme.dim(hint), width, theme.dim('…')));\n }\n }\n }\n\n for (const extLine of this.extensionLines) {\n lines.push(truncateToWidth(theme.dim(extLine), width, theme.dim('…')));\n }\n for (const component of this.extensionComponents) {\n for (const line of component.render(width)) {\n lines.push(truncateToWidth(line, width, theme.dim('…')));\n }\n }\n\n return lines;\n }\n\n private customComponent: Component | undefined;\n}\n"],"mappings":";;;;AAaA,MAAM,gBACJ;AAEF,MAAM,iBAAiB,CACrB,gEACA,mEACD;;AAGD,IAAa,YAAb,MAA4C;CAC1C,iBAAmC,EAAE;CACrC,sBAA2C,EAAE;CAE7C,YACE,UACA,aACA;AAFiB,OAAA,WAAA;AACA,OAAA,cAAA;;CAGnB,kBAAkB,OAAuB;AACvC,OAAK,iBAAiB;;CAGxB,uBAAuB,YAA+B;AACpD,OAAK,sBAAsB;;CAG7B,mBAAmB,WAAwC;AACzD,OAAK,kBAAkB;;CAGzB,aAAmB;CAEnB,kBAAkC;AAChC,MAAI,CAAC,KAAK,YAAa,QAAO;AAK9B,SAAO,GAJW,aAAa,KAAK,aAAa,iBAAiB,EAAE,YAAY,OAAO,CAIpE,CAAC,eAHN,aAAa,KAAK,aAAa,aAAa,EAAE,YAAY,OAAO,CAGvC,CAAC,GAF5B,aAAa,KAAK,aAAa,YAAY,EAAE,YAAY,OAAO,CAE7B,CAAC,sCADnC,aAAa,KAAK,aAAa,oBAAoB,EAAE,YAAY,OAAO,CACM,CAAC;;CAG/F,mBAAqC;AACnC,MAAI,CAAC,KAAK,YAAa,QAAO;AAC9B,SAAO;;CAGT,OAAO,OAAyB;AAC9B,MAAI,KAAK,gBAEP,QADiB,KAAK,gBAAgB,OAAO,MAC9B,CAAC,KAAK,SAAS,gBAAgB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;EAG7E,MAAM,EAAE,SAAS,iBAAiB,YAAY,cAAc,KAAK,UAAU;EAE3E,MAAM,QAAQ,CAAC,gBADD,MAAM,OAAO,aAAa,QAAQ,KAAK,gBAAgB,KAAK,aACtC,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAE7D,MAAI,WAAW;AACb,SAAM,KAAK,gBAAgB,MAAM,IAAI,KAAK,iBAAiB,CAAC,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AACrF,QAAK,MAAM,QAAQ,KAAK,kBAAkB,CACxC,KAAI,aAAa,KAAK,IAAI,MACxB,OAAM,KAAK,MAAM,IAAI,KAAK,CAAC;OAE3B,OAAM,KAAK,gBAAgB,MAAM,IAAI,KAAK,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;;AAKzE,OAAK,MAAM,WAAW,KAAK,eACzB,OAAM,KAAK,gBAAgB,MAAM,IAAI,QAAQ,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAExE,OAAK,MAAM,aAAa,KAAK,oBAC3B,MAAK,MAAM,QAAQ,UAAU,OAAO,MAAM,CACxC,OAAM,KAAK,gBAAgB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAI5D,SAAO;;CAGT"}
1
+ {"version":3,"file":"tui-header.js","names":[],"sources":["../../../../src/tui/components/tui-header.ts"],"sourcesContent":["import type { Component, KeybindingsManager } from '@earendil-works/pi-tui';\nimport { truncateToWidth } from '@earendil-works/pi-tui';\n\nimport { theme } from '../theme.js';\nimport { formatKeyIds } from '../format-tui-hotkeys.js';\n\nexport type TuiHeaderModel = {\n version: string;\n connectionLabel: string;\n sessionKey: string;\n showHints: boolean;\n};\n\nconst COMPACT_HINTS =\n 'escape interrupt · ctrl+c/ctrl+d clear/exit · / commands · ! bash · ctrl+o tools';\nconst STARTUP_HELP_HINT = 'Press /start to show full startup help and loaded resources.';\n\n/** Collapsible startup header (pi-style hints subset). */\nexport class TuiHeader implements Component {\n private extensionLines: string[] = [];\n private extensionComponents: Component[] = [];\n\n constructor(\n private readonly getModel: () => TuiHeaderModel,\n private readonly keybindings?: KeybindingsManager,\n ) {}\n\n setExtensionLines(lines: string[]): void {\n this.extensionLines = lines;\n }\n\n setExtensionComponents(components: Component[]): void {\n this.extensionComponents = components;\n }\n\n setCustomComponent(component: Component | undefined): void {\n this.customComponent = component;\n }\n\n invalidate(): void {}\n\n private getCompactHints(): string {\n if (!this.keybindings) return COMPACT_HINTS;\n const interrupt = formatKeyIds(this.keybindings, 'app.interrupt', { capitalize: false });\n const clear = formatKeyIds(this.keybindings, 'app.clear', { capitalize: false });\n const exit = formatKeyIds(this.keybindings, 'app.exit', { capitalize: false });\n const tools = formatKeyIds(this.keybindings, 'app.tools.expand', { capitalize: false });\n return `${interrupt} interrupt · ${clear}/${exit} clear/exit · / commands · ! bash · ${tools} tools`;\n }\n\n render(width: number): string[] {\n if (this.customComponent) {\n const rendered = this.customComponent.render(width);\n return rendered.map((line) => truncateToWidth(line, width, theme.dim('…')));\n }\n\n const { version, connectionLabel, sessionKey, showHints } = this.getModel();\n const title = theme.header(`xopc tui v${version} — ${connectionLabel} — ${sessionKey}`);\n const lines = [truncateToWidth(title, width, theme.dim('…'))];\n\n if (showHints) {\n lines.push(truncateToWidth(theme.dim(this.getCompactHints()), width, theme.dim('…')));\n lines.push(truncateToWidth(theme.dim(STARTUP_HELP_HINT), width, theme.dim('…')));\n }\n\n for (const extLine of this.extensionLines) {\n lines.push(truncateToWidth(theme.dim(extLine), width, theme.dim('…')));\n }\n for (const component of this.extensionComponents) {\n for (const line of component.render(width)) {\n lines.push(truncateToWidth(line, width, theme.dim('…')));\n }\n }\n\n return lines;\n }\n\n private customComponent: Component | undefined;\n}\n"],"mappings":";;;;AAaA,MAAM,gBACJ;AACF,MAAM,oBAAoB;;AAG1B,IAAa,YAAb,MAA4C;CAC1C,iBAAmC,EAAE;CACrC,sBAA2C,EAAE;CAE7C,YACE,UACA,aACA;AAFiB,OAAA,WAAA;AACA,OAAA,cAAA;;CAGnB,kBAAkB,OAAuB;AACvC,OAAK,iBAAiB;;CAGxB,uBAAuB,YAA+B;AACpD,OAAK,sBAAsB;;CAG7B,mBAAmB,WAAwC;AACzD,OAAK,kBAAkB;;CAGzB,aAAmB;CAEnB,kBAAkC;AAChC,MAAI,CAAC,KAAK,YAAa,QAAO;AAK9B,SAAO,GAJW,aAAa,KAAK,aAAa,iBAAiB,EAAE,YAAY,OAAO,CAIpE,CAAC,eAHN,aAAa,KAAK,aAAa,aAAa,EAAE,YAAY,OAAO,CAGvC,CAAC,GAF5B,aAAa,KAAK,aAAa,YAAY,EAAE,YAAY,OAAO,CAE7B,CAAC,sCADnC,aAAa,KAAK,aAAa,oBAAoB,EAAE,YAAY,OAAO,CACM,CAAC;;CAG/F,OAAO,OAAyB;AAC9B,MAAI,KAAK,gBAEP,QADiB,KAAK,gBAAgB,OAAO,MAC9B,CAAC,KAAK,SAAS,gBAAgB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;EAG7E,MAAM,EAAE,SAAS,iBAAiB,YAAY,cAAc,KAAK,UAAU;EAE3E,MAAM,QAAQ,CAAC,gBADD,MAAM,OAAO,aAAa,QAAQ,KAAK,gBAAgB,KAAK,aACtC,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAE7D,MAAI,WAAW;AACb,SAAM,KAAK,gBAAgB,MAAM,IAAI,KAAK,iBAAiB,CAAC,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AACrF,SAAM,KAAK,gBAAgB,MAAM,IAAI,kBAAkB,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;;AAGlF,OAAK,MAAM,WAAW,KAAK,eACzB,OAAM,KAAK,gBAAgB,MAAM,IAAI,QAAQ,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAExE,OAAK,MAAM,aAAa,KAAK,oBAC3B,MAAK,MAAM,QAAQ,UAAU,OAAO,MAAM,CACxC,OAAM,KAAK,gBAAgB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAI5D,SAAO;;CAGT"}
@@ -1,6 +1,6 @@
1
1
  import { resolveStateDir } from "../config/paths-state.js";
2
2
  import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
3
- import { init_paths, resolveAgentProfileDir, resolveBundledSkillsDir } from "../config/paths.js";
3
+ import { init_paths, resolveAgentProfileDir, resolveBundledSkillsDir, resolveUserProfilePath } from "../config/paths.js";
4
4
  import { resolveBootstrapFilesSync } from "../agent/bootstrap/bootstrap-files.js";
5
5
  import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
6
6
  import { createSkillConfigManager, isSkillEnabled } from "../agent/skills/config.js";
@@ -20,6 +20,7 @@ function collectTuiStartupResources(config, sessionKey) {
20
20
  const workspaceDir = profile.resolvedWorkspacePath || getWorkspacePath(config);
21
21
  const context = uniqueSorted(resolveBootstrapFilesSync({
22
22
  profileDir,
23
+ userProfilePath: resolveUserProfilePath(),
23
24
  sessionKey
24
25
  }).filter((file) => !file.missing).map((file) => file.name || basename(file.path)));
25
26
  const skillsConfig = createSkillConfigManager(resolveStateDir()).load();
@@ -1 +1 @@
1
- {"version":3,"file":"tui-startup-resources.js","names":[],"sources":["../../../src/tui/tui-startup-resources.ts"],"sourcesContent":["import { basename } from 'node:path';\n\nimport { resolveBootstrapFilesSync } from '../agent/bootstrap/bootstrap-files.js';\nimport { loadSkills } from '../agent/skills/index.js';\nimport { isSkillEnabled, createSkillConfigManager } from '../agent/skills/config.js';\nimport { createWorkflowCatalog } from '../agent/workflow/catalog.js';\nimport { resolveEffectiveAgentProfileForSession } from '../config/agent-profile.js';\nimport { getWorkspacePath } from '../config/index.js';\nimport { resolveAgentProfileDir, resolveBundledSkillsDir, resolveStateDir } from '../config/paths.js';\nimport { listConnectorInstances } from '../connectors/instances.js';\nimport type { Config } from '../config/schema.js';\nimport type { TuiStartupResources } from './tui-backend.js';\n\nfunction uniqueSorted(values: Iterable<string>): string[] {\n return [...new Set([...values].map((value) => value.trim()).filter(Boolean))]\n .sort((a, b) => a.localeCompare(b));\n}\n\nexport function collectTuiStartupResources(config: Config, sessionKey?: string): TuiStartupResources {\n const profile = resolveEffectiveAgentProfileForSession(config, sessionKey);\n const profileDir = resolveAgentProfileDir(config, profile.agentId);\n const workspaceDir = profile.resolvedWorkspacePath || getWorkspacePath(config);\n\n const context = uniqueSorted(\n resolveBootstrapFilesSync({ profileDir, sessionKey })\n .filter((file) => !file.missing)\n .map((file) => file.name || basename(file.path)),\n );\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const skills = uniqueSorted(\n loadSkills({\n workspaceDir,\n builtinDir: resolveBundledSkillsDir() ?? undefined,\n }).skills\n .filter((skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig))\n .map((skill) => skill.name),\n );\n\n const workflows = uniqueSorted(createWorkflowCatalog().list().map((entry) => entry.name));\n const connectors = uniqueSorted(\n listConnectorInstances(config).map((instance) => instance.displayName || instance.connectorId || instance.instanceId),\n );\n\n return { context, skills, workflows, connectors };\n}\n"],"mappings":";;;;;;;;;;;;YAQsG;AAKtG,SAAS,aAAa,QAAoC;AACxD,QAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAC1E,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;;AAGvC,SAAgB,2BAA2B,QAAgB,YAA0C;CACnG,MAAM,UAAU,uCAAuC,QAAQ,WAAW;CAC1E,MAAM,aAAa,uBAAuB,QAAQ,QAAQ,QAAQ;CAClE,MAAM,eAAe,QAAQ,yBAAyB,iBAAiB,OAAO;CAE9E,MAAM,UAAU,aACd,0BAA0B;EAAE;EAAY;EAAY,CAAC,CAClD,QAAQ,SAAS,CAAC,KAAK,QAAQ,CAC/B,KAAK,SAAS,KAAK,QAAQ,SAAS,KAAK,KAAK,CAAC,CACnD;CAED,MAAM,eAAe,yBAAyB,iBAAiB,CAAC,CAAC,MAAM;AAevE,QAAO;EAAE;EAAS,QAdH,aACb,WAAW;GACT;GACA,YAAY,yBAAyB,IAAI,KAAA;GAC1C,CAAC,CAAC,OACA,QAAQ,UAAU,CAAC,MAAM,0BAA0B,eAAe,OAAO,aAAa,CAAC,CACvF,KAAK,UAAU,MAAM,KAAK,CAQP;EAAE,WALR,aAAa,uBAAuB,CAAC,MAAM,CAAC,KAAK,UAAU,MAAM,KAAK,CAKrD;EAAE,YAJlB,aACjB,uBAAuB,OAAO,CAAC,KAAK,aAAa,SAAS,eAAe,SAAS,eAAe,SAAS,WAAW,CAGxE;EAAE"}
1
+ {"version":3,"file":"tui-startup-resources.js","names":[],"sources":["../../../src/tui/tui-startup-resources.ts"],"sourcesContent":["import { basename } from 'node:path';\n\nimport { resolveBootstrapFilesSync } from '../agent/bootstrap/bootstrap-files.js';\nimport { loadSkills } from '../agent/skills/index.js';\nimport { isSkillEnabled, createSkillConfigManager } from '../agent/skills/config.js';\nimport { createWorkflowCatalog } from '../agent/workflow/catalog.js';\nimport { resolveEffectiveAgentProfileForSession } from '../config/agent-profile.js';\nimport { getWorkspacePath } from '../config/index.js';\nimport {\n resolveAgentProfileDir,\n resolveBundledSkillsDir,\n resolveStateDir,\n resolveUserProfilePath,\n} from '../config/paths.js';\nimport { listConnectorInstances } from '../connectors/instances.js';\nimport type { Config } from '../config/schema.js';\nimport type { TuiStartupResources } from './tui-backend.js';\n\nfunction uniqueSorted(values: Iterable<string>): string[] {\n return [...new Set([...values].map((value) => value.trim()).filter(Boolean))]\n .sort((a, b) => a.localeCompare(b));\n}\n\nexport function collectTuiStartupResources(config: Config, sessionKey?: string): TuiStartupResources {\n const profile = resolveEffectiveAgentProfileForSession(config, sessionKey);\n const profileDir = resolveAgentProfileDir(config, profile.agentId);\n const workspaceDir = profile.resolvedWorkspacePath || getWorkspacePath(config);\n\n const context = uniqueSorted(\n resolveBootstrapFilesSync({ profileDir, userProfilePath: resolveUserProfilePath(), sessionKey })\n .filter((file) => !file.missing)\n .map((file) => file.name || basename(file.path)),\n );\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const skills = uniqueSorted(\n loadSkills({\n workspaceDir,\n builtinDir: resolveBundledSkillsDir() ?? undefined,\n }).skills\n .filter((skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig))\n .map((skill) => skill.name),\n );\n\n const workflows = uniqueSorted(createWorkflowCatalog().list().map((entry) => entry.name));\n const connectors = uniqueSorted(\n listConnectorInstances(config).map((instance) => instance.displayName || instance.connectorId || instance.instanceId),\n );\n\n return { context, skills, workflows, connectors };\n}\n"],"mappings":";;;;;;;;;;;;YAa4B;AAK5B,SAAS,aAAa,QAAoC;AACxD,QAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAC1E,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;;AAGvC,SAAgB,2BAA2B,QAAgB,YAA0C;CACnG,MAAM,UAAU,uCAAuC,QAAQ,WAAW;CAC1E,MAAM,aAAa,uBAAuB,QAAQ,QAAQ,QAAQ;CAClE,MAAM,eAAe,QAAQ,yBAAyB,iBAAiB,OAAO;CAE9E,MAAM,UAAU,aACd,0BAA0B;EAAE;EAAY,iBAAiB,wBAAwB;EAAE;EAAY,CAAC,CAC7F,QAAQ,SAAS,CAAC,KAAK,QAAQ,CAC/B,KAAK,SAAS,KAAK,QAAQ,SAAS,KAAK,KAAK,CAAC,CACnD;CAED,MAAM,eAAe,yBAAyB,iBAAiB,CAAC,CAAC,MAAM;AAevE,QAAO;EAAE;EAAS,QAdH,aACb,WAAW;GACT;GACA,YAAY,yBAAyB,IAAI,KAAA;GAC1C,CAAC,CAAC,OACA,QAAQ,UAAU,CAAC,MAAM,0BAA0B,eAAe,OAAO,aAAa,CAAC,CACvF,KAAK,UAAU,MAAM,KAAK,CAQP;EAAE,WALR,aAAa,uBAAuB,CAAC,MAAM,CAAC,KAAK,UAAU,MAAM,KAAK,CAKrD;EAAE,YAJlB,aACjB,uBAAuB,OAAO,CAAC,KAAK,aAAa,SAAS,eAAe,SAAS,eAAe,SAAS,WAAW,CAGxE;EAAE"}
@@ -37,18 +37,18 @@ function formatTuiStartupText(input) {
37
37
  lines.push("");
38
38
  }
39
39
  lines.push(compactKeyLine(input.keybindings));
40
- lines.push("Press /start to show full startup help and loaded resources.");
41
- lines.push("");
42
- lines.push("xopc can use skills, workflows, connectors, and project context. Ask it how to automate or connect services.");
43
- if (expanded) lines.push("", "Ask xopc:", " \"what workflows are available?\"", " \"use a connector to check issues or docs\"", " \"what skills can help with this task?\"");
44
- lines.push("");
45
- lines.push(...formatResourceSection("Context", input.resources?.context, { expanded }));
46
- lines.push("");
47
- lines.push(...formatResourceSection("Skills", input.resources?.skills, { expanded }));
48
- lines.push("");
49
- lines.push(...formatResourceSection("Workflows", input.resources?.workflows, { expanded }));
50
- lines.push("");
51
- lines.push(...formatResourceSection("Connectors", input.resources?.connectors, { expanded }));
40
+ lines.push("Press /start to show full startup help.");
41
+ if (expanded) lines.push("", "xopc can use skills, workflows, connectors, and project context. Ask it how to automate or connect services.", "", "Ask xopc:", " \"what workflows are available?\"", " \"use a connector to check issues or docs\"", " \"what skills can help with this task?\"");
42
+ if (expanded) {
43
+ lines.push("");
44
+ lines.push(...formatResourceSection("Context", input.resources?.context, { expanded }));
45
+ lines.push("");
46
+ lines.push(...formatResourceSection("Skills", input.resources?.skills, { expanded }));
47
+ lines.push("");
48
+ lines.push(...formatResourceSection("Workflows", input.resources?.workflows, { expanded }));
49
+ lines.push("");
50
+ lines.push(...formatResourceSection("Connectors", input.resources?.connectors, { expanded }));
51
+ }
52
52
  if (expanded) lines.push("", "Useful commands:", " /help — Show all commands and shortcuts", " /workflow list — List saved workflows", " /models — List available models", " /settings — Open TUI settings", " /export — Export current session");
53
53
  return lines.join("\n");
54
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tui-startup-text.js","names":[],"sources":["../../../src/tui/tui-startup-text.ts"],"sourcesContent":["import type { KeybindingsManager } from '@earendil-works/pi-tui';\n\nimport { formatKeyIds } from './format-tui-hotkeys.js';\nimport { formatModelLabel } from './tui-command-formatters.js';\nimport type { TuiStartupResources } from './tui-backend.js';\nimport type { TuiState } from './tui-types.js';\n\nconst DEFAULT_LIMIT = 6;\n\nfunction keyLabel(\n keybindings: KeybindingsManager | undefined,\n id: Parameters<KeybindingsManager['getKeys']>[0],\n fallback: string,\n): string {\n return keybindings ? formatKeyIds(keybindings, id, { capitalize: false }) : fallback;\n}\n\nfunction compactKeyLine(keybindings?: KeybindingsManager): string {\n const interrupt = keyLabel(keybindings, 'app.interrupt', 'escape');\n const clear = keyLabel(keybindings, 'app.clear', 'ctrl+c');\n const exit = keyLabel(keybindings, 'app.exit', 'ctrl+d');\n const tools = keyLabel(keybindings, 'app.tools.expand', 'ctrl+o');\n return `${interrupt} interrupt · ${clear}/${exit} clear/exit · / commands · ! bash · ${tools} tools`;\n}\n\nfunction formatResourceSection(\n title: string,\n values: readonly string[] | undefined,\n options: { expanded: boolean },\n): string[] {\n const list = [...new Set((values ?? []).map((v) => v.trim()).filter(Boolean))]\n .sort((a, b) => a.localeCompare(b));\n const lines = [`[${title}]`];\n if (list.length === 0) {\n lines.push(' none');\n return lines;\n }\n if (!options.expanded) {\n const visible = list.slice(0, DEFAULT_LIMIT);\n const suffix = list.length > visible.length ? `, ... ${list.length - visible.length} more` : '';\n lines.push(` ${visible.join(', ')}${suffix}`);\n return lines;\n }\n const visible = list.slice(0, 30);\n for (const value of visible) {\n lines.push(` ${value}`);\n }\n if (list.length > visible.length) {\n lines.push(` ... ${list.length - visible.length} more`);\n }\n return lines;\n}\n\nexport function formatTuiStartupText(input: {\n state: TuiState;\n isLocal: boolean;\n keybindings?: KeybindingsManager;\n resources?: TuiStartupResources;\n expanded?: boolean;\n}): string {\n const expanded = input.expanded === true;\n const lines: string[] = [];\n\n if (expanded) {\n lines.push('xopc TUI', '');\n lines.push(`Session: ${input.state.currentSessionKey}`);\n lines.push(`Mode: ${input.isLocal ? 'local embedded' : 'gateway'}`);\n lines.push(`Model: ${formatModelLabel(input.state)}`);\n lines.push('');\n }\n\n lines.push(compactKeyLine(input.keybindings));\n lines.push('Press /start to show full startup help and loaded resources.');\n lines.push('');\n lines.push(\n 'xopc can use skills, workflows, connectors, and project context. Ask it how to automate or connect services.',\n );\n\n if (expanded) {\n lines.push(\n '',\n 'Ask xopc:',\n ' \"what workflows are available?\"',\n ' \"use a connector to check issues or docs\"',\n ' \"what skills can help with this task?\"',\n );\n }\n\n lines.push('');\n lines.push(...formatResourceSection('Context', input.resources?.context, { expanded }));\n lines.push('');\n lines.push(...formatResourceSection('Skills', input.resources?.skills, { expanded }));\n lines.push('');\n lines.push(...formatResourceSection('Workflows', input.resources?.workflows, { expanded }));\n lines.push('');\n lines.push(...formatResourceSection('Connectors', input.resources?.connectors, { expanded }));\n\n if (expanded) {\n lines.push(\n '',\n 'Useful commands:',\n ' /help — Show all commands and shortcuts',\n ' /workflow list — List saved workflows',\n ' /models — List available models',\n ' /settings — Open TUI settings',\n ' /export — Export current session',\n );\n }\n\n return lines.join('\\n');\n}\n"],"mappings":";;;AAOA,MAAM,gBAAgB;AAEtB,SAAS,SACP,aACA,IACA,UACQ;AACR,QAAO,cAAc,aAAa,aAAa,IAAI,EAAE,YAAY,OAAO,CAAC,GAAG;;AAG9E,SAAS,eAAe,aAA0C;AAKhE,QAAO,GAJW,SAAS,aAAa,iBAAiB,SAItC,CAAC,eAHN,SAAS,aAAa,aAAa,SAGT,CAAC,GAF5B,SAAS,aAAa,YAAY,SAEC,CAAC,sCADnC,SAAS,aAAa,oBAAoB,SACoC,CAAC;;AAG/F,SAAS,sBACP,OACA,QACA,SACU;CACV,MAAM,OAAO,CAAC,GAAG,IAAI,KAAK,UAAU,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAC3E,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;CACrC,MAAM,QAAQ,CAAC,IAAI,MAAM,GAAG;AAC5B,KAAI,KAAK,WAAW,GAAG;AACrB,QAAM,KAAK,SAAS;AACpB,SAAO;;AAET,KAAI,CAAC,QAAQ,UAAU;EACrB,MAAM,UAAU,KAAK,MAAM,GAAG,cAAc;EAC5C,MAAM,SAAS,KAAK,SAAS,QAAQ,SAAS,SAAS,KAAK,SAAS,QAAQ,OAAO,SAAS;AAC7F,QAAM,KAAK,KAAK,QAAQ,KAAK,KAAK,GAAG,SAAS;AAC9C,SAAO;;CAET,MAAM,UAAU,KAAK,MAAM,GAAG,GAAG;AACjC,MAAK,MAAM,SAAS,QAClB,OAAM,KAAK,KAAK,QAAQ;AAE1B,KAAI,KAAK,SAAS,QAAQ,OACxB,OAAM,KAAK,SAAS,KAAK,SAAS,QAAQ,OAAO,OAAO;AAE1D,QAAO;;AAGT,SAAgB,qBAAqB,OAM1B;CACT,MAAM,WAAW,MAAM,aAAa;CACpC,MAAM,QAAkB,EAAE;AAE1B,KAAI,UAAU;AACZ,QAAM,KAAK,YAAY,GAAG;AAC1B,QAAM,KAAK,YAAY,MAAM,MAAM,oBAAoB;AACvD,QAAM,KAAK,SAAS,MAAM,UAAU,mBAAmB,YAAY;AACnE,QAAM,KAAK,UAAU,iBAAiB,MAAM,MAAM,GAAG;AACrD,QAAM,KAAK,GAAG;;AAGhB,OAAM,KAAK,eAAe,MAAM,YAAY,CAAC;AAC7C,OAAM,KAAK,+DAA+D;AAC1E,OAAM,KAAK,GAAG;AACd,OAAM,KACJ,+GACD;AAED,KAAI,SACF,OAAM,KACJ,IACA,aACA,uCACA,iDACA,6CACD;AAGH,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,GAAG,sBAAsB,WAAW,MAAM,WAAW,SAAS,EAAE,UAAU,CAAC,CAAC;AACvF,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,GAAG,sBAAsB,UAAU,MAAM,WAAW,QAAQ,EAAE,UAAU,CAAC,CAAC;AACrF,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,GAAG,sBAAsB,aAAa,MAAM,WAAW,WAAW,EAAE,UAAU,CAAC,CAAC;AAC3F,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,GAAG,sBAAsB,cAAc,MAAM,WAAW,YAAY,EAAE,UAAU,CAAC,CAAC;AAE7F,KAAI,SACF,OAAM,KACJ,IACA,oBACA,6CACA,2CACA,qCACA,mCACA,qCACD;AAGH,QAAO,MAAM,KAAK,KAAK"}
1
+ {"version":3,"file":"tui-startup-text.js","names":[],"sources":["../../../src/tui/tui-startup-text.ts"],"sourcesContent":["import type { KeybindingsManager } from '@earendil-works/pi-tui';\n\nimport { formatKeyIds } from './format-tui-hotkeys.js';\nimport { formatModelLabel } from './tui-command-formatters.js';\nimport type { TuiStartupResources } from './tui-backend.js';\nimport type { TuiState } from './tui-types.js';\n\nconst DEFAULT_LIMIT = 6;\n\nfunction keyLabel(\n keybindings: KeybindingsManager | undefined,\n id: Parameters<KeybindingsManager['getKeys']>[0],\n fallback: string,\n): string {\n return keybindings ? formatKeyIds(keybindings, id, { capitalize: false }) : fallback;\n}\n\nfunction compactKeyLine(keybindings?: KeybindingsManager): string {\n const interrupt = keyLabel(keybindings, 'app.interrupt', 'escape');\n const clear = keyLabel(keybindings, 'app.clear', 'ctrl+c');\n const exit = keyLabel(keybindings, 'app.exit', 'ctrl+d');\n const tools = keyLabel(keybindings, 'app.tools.expand', 'ctrl+o');\n return `${interrupt} interrupt · ${clear}/${exit} clear/exit · / commands · ! bash · ${tools} tools`;\n}\n\nfunction formatResourceSection(\n title: string,\n values: readonly string[] | undefined,\n options: { expanded: boolean },\n): string[] {\n const list = [...new Set((values ?? []).map((v) => v.trim()).filter(Boolean))]\n .sort((a, b) => a.localeCompare(b));\n const lines = [`[${title}]`];\n if (list.length === 0) {\n lines.push(' none');\n return lines;\n }\n if (!options.expanded) {\n const visible = list.slice(0, DEFAULT_LIMIT);\n const suffix = list.length > visible.length ? `, ... ${list.length - visible.length} more` : '';\n lines.push(` ${visible.join(', ')}${suffix}`);\n return lines;\n }\n const visible = list.slice(0, 30);\n for (const value of visible) {\n lines.push(` ${value}`);\n }\n if (list.length > visible.length) {\n lines.push(` ... ${list.length - visible.length} more`);\n }\n return lines;\n}\n\nexport function formatTuiStartupText(input: {\n state: TuiState;\n isLocal: boolean;\n keybindings?: KeybindingsManager;\n resources?: TuiStartupResources;\n expanded?: boolean;\n}): string {\n const expanded = input.expanded === true;\n const lines: string[] = [];\n\n if (expanded) {\n lines.push('xopc TUI', '');\n lines.push(`Session: ${input.state.currentSessionKey}`);\n lines.push(`Mode: ${input.isLocal ? 'local embedded' : 'gateway'}`);\n lines.push(`Model: ${formatModelLabel(input.state)}`);\n lines.push('');\n }\n\n lines.push(compactKeyLine(input.keybindings));\n lines.push('Press /start to show full startup help.');\n\n if (expanded) {\n lines.push(\n '',\n 'xopc can use skills, workflows, connectors, and project context. Ask it how to automate or connect services.',\n '',\n 'Ask xopc:',\n ' \"what workflows are available?\"',\n ' \"use a connector to check issues or docs\"',\n ' \"what skills can help with this task?\"',\n );\n }\n\n if (expanded) {\n lines.push('');\n lines.push(...formatResourceSection('Context', input.resources?.context, { expanded }));\n lines.push('');\n lines.push(...formatResourceSection('Skills', input.resources?.skills, { expanded }));\n lines.push('');\n lines.push(...formatResourceSection('Workflows', input.resources?.workflows, { expanded }));\n lines.push('');\n lines.push(...formatResourceSection('Connectors', input.resources?.connectors, { expanded }));\n }\n\n if (expanded) {\n lines.push(\n '',\n 'Useful commands:',\n ' /help — Show all commands and shortcuts',\n ' /workflow list — List saved workflows',\n ' /models — List available models',\n ' /settings — Open TUI settings',\n ' /export — Export current session',\n );\n }\n\n return lines.join('\\n');\n}\n"],"mappings":";;;AAOA,MAAM,gBAAgB;AAEtB,SAAS,SACP,aACA,IACA,UACQ;AACR,QAAO,cAAc,aAAa,aAAa,IAAI,EAAE,YAAY,OAAO,CAAC,GAAG;;AAG9E,SAAS,eAAe,aAA0C;AAKhE,QAAO,GAJW,SAAS,aAAa,iBAAiB,SAItC,CAAC,eAHN,SAAS,aAAa,aAAa,SAGT,CAAC,GAF5B,SAAS,aAAa,YAAY,SAEC,CAAC,sCADnC,SAAS,aAAa,oBAAoB,SACoC,CAAC;;AAG/F,SAAS,sBACP,OACA,QACA,SACU;CACV,MAAM,OAAO,CAAC,GAAG,IAAI,KAAK,UAAU,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAC3E,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;CACrC,MAAM,QAAQ,CAAC,IAAI,MAAM,GAAG;AAC5B,KAAI,KAAK,WAAW,GAAG;AACrB,QAAM,KAAK,SAAS;AACpB,SAAO;;AAET,KAAI,CAAC,QAAQ,UAAU;EACrB,MAAM,UAAU,KAAK,MAAM,GAAG,cAAc;EAC5C,MAAM,SAAS,KAAK,SAAS,QAAQ,SAAS,SAAS,KAAK,SAAS,QAAQ,OAAO,SAAS;AAC7F,QAAM,KAAK,KAAK,QAAQ,KAAK,KAAK,GAAG,SAAS;AAC9C,SAAO;;CAET,MAAM,UAAU,KAAK,MAAM,GAAG,GAAG;AACjC,MAAK,MAAM,SAAS,QAClB,OAAM,KAAK,KAAK,QAAQ;AAE1B,KAAI,KAAK,SAAS,QAAQ,OACxB,OAAM,KAAK,SAAS,KAAK,SAAS,QAAQ,OAAO,OAAO;AAE1D,QAAO;;AAGT,SAAgB,qBAAqB,OAM1B;CACT,MAAM,WAAW,MAAM,aAAa;CACpC,MAAM,QAAkB,EAAE;AAE1B,KAAI,UAAU;AACZ,QAAM,KAAK,YAAY,GAAG;AAC1B,QAAM,KAAK,YAAY,MAAM,MAAM,oBAAoB;AACvD,QAAM,KAAK,SAAS,MAAM,UAAU,mBAAmB,YAAY;AACnE,QAAM,KAAK,UAAU,iBAAiB,MAAM,MAAM,GAAG;AACrD,QAAM,KAAK,GAAG;;AAGhB,OAAM,KAAK,eAAe,MAAM,YAAY,CAAC;AAC7C,OAAM,KAAK,0CAA0C;AAErD,KAAI,SACF,OAAM,KACJ,IACA,gHACA,IACA,aACA,uCACA,iDACA,6CACD;AAGH,KAAI,UAAU;AACZ,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,sBAAsB,WAAW,MAAM,WAAW,SAAS,EAAE,UAAU,CAAC,CAAC;AACvF,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,sBAAsB,UAAU,MAAM,WAAW,QAAQ,EAAE,UAAU,CAAC,CAAC;AACrF,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,sBAAsB,aAAa,MAAM,WAAW,WAAW,EAAE,UAAU,CAAC,CAAC;AAC3F,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,sBAAsB,cAAc,MAAM,WAAW,YAAY,EAAE,UAAU,CAAC,CAAC;;AAG/F,KAAI,SACF,OAAM,KACJ,IACA,oBACA,6CACA,2CACA,qCACA,mCACA,qCACD;AAGH,QAAO,MAAM,KAAK,KAAK"}
@@ -1976,9 +1976,12 @@ async function runTui(opts) {
1976
1976
  }
1977
1977
  await refreshSessionInfoWithBorder();
1978
1978
  await refreshModelChoices();
1979
- await refreshStartupResources();
1980
1979
  await loadSessionHistory({ merge: true });
1981
1980
  showStartupCardOnce();
1981
+ refreshStartupResources().then(() => {
1982
+ updateFooter();
1983
+ tui.requestRender();
1984
+ });
1982
1985
  if (state.activeRunId) recoverActiveRunFromHistory("broadcast reconnect");
1983
1986
  updateHeader();
1984
1987
  updateFooter();