@xopcai/xopc 0.0.320 → 0.0.323

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 (323) hide show
  1. package/dist/browser-ext/dist/assets/{auth-DKo-NMUY.js → auth-DocRzRlS.js} +95 -21
  2. package/dist/browser-ext/dist/background.js +1 -1
  3. package/dist/browser-ext/dist/sidepanel.html +1 -1
  4. package/dist/browser-ext/dist/sidepanel.js +18 -2
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/extensions/telegram/xopc.extension.json +1 -1
  7. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BXLU0HJa.js → agent-avatar-dicebear-DFzmThVi.js} +1 -1
  8. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CAFHadiy.js +1 -0
  9. package/dist/gateway/static/root/assets/agent-plugin-dialog-DYFYiuig.js +1 -0
  10. package/dist/gateway/static/root/assets/{agents-hrbGiOHn.js → agents-BqIlB5Co.js} +1 -1
  11. package/dist/gateway/static/root/assets/{app-link-nL8iPwEr.js → app-link-C6gA5Nck.js} +1 -1
  12. package/dist/gateway/static/root/assets/{app-management-settings-panel-C0jEvonH.js → app-management-settings-panel-BgvMRGWe.js} +1 -1
  13. package/dist/gateway/static/root/assets/{appearance-settings-ByVRv2Oe.js → appearance-settings-CliHU03A.js} +1 -1
  14. package/dist/gateway/static/root/assets/apps-page-Drt3Foi9.js +1 -0
  15. package/dist/gateway/static/root/assets/{archive-plugin-CMITc1PQ.js → archive-plugin-DnuPpm0u.js} +1 -1
  16. package/dist/gateway/static/root/assets/{attachment-load-B5Z1PKHm.js → attachment-load-BiwaK0ie.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-page-BOcXqVar.js → automations-page-CJSISGQH.js} +1 -1
  18. package/dist/gateway/static/root/assets/automations-workspace-B-Eduqwz.js +7 -0
  19. package/dist/gateway/static/root/assets/{binary-plugins-BkRb9adx.js → binary-plugins-KDjduQZO.js} +1 -1
  20. package/dist/gateway/static/root/assets/{block-editor-DsmDlkC2.js → block-editor-bclvgove.js} +3 -3
  21. package/dist/gateway/static/root/assets/{browser-automation-inputs-BgBH3eFk.js → browser-automation-inputs-CfQ2T9t6.js} +1 -1
  22. package/dist/gateway/static/root/assets/{browser-automations-page-e3KpurLo.js → browser-automations-page-Cxq38Nnp.js} +2 -2
  23. package/dist/gateway/static/root/assets/browser-settings-page-Dwgir6mu.js +3 -0
  24. package/dist/gateway/static/root/assets/capabilities-settings-panel-H5L5vynP.js +8 -0
  25. package/dist/gateway/static/root/assets/capabilities-uFKh3Hd0.js +1 -0
  26. package/dist/gateway/static/root/assets/channels-settings-RFBRYe5S.js +1 -0
  27. package/dist/gateway/static/root/assets/{chat-terminal-dock-DUdkU1C5.js → chat-terminal-dock-DKQC62nQ.js} +2 -2
  28. package/dist/gateway/static/root/assets/{computer-settings-page-C6WR9Syy.js → computer-settings-page-D1whpIqL.js} +1 -1
  29. package/dist/gateway/static/root/assets/{connector-service-page-SVKcySx0.js → connector-service-page-BAuYTgf5.js} +1 -1
  30. package/dist/gateway/static/root/assets/connectors-page-Px-v3Q6Q.js +2 -0
  31. package/dist/gateway/static/root/assets/{date-picker-DBD5yedi.js → date-picker-CfCo3lqh.js} +1 -1
  32. package/dist/gateway/static/root/assets/{dependency-picker-HE41Co5W.js → dependency-picker-DOuVO2M1.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-DH9EU9O3.js → desktop-pet-D9tu6Bhu.js} +1 -1
  34. package/dist/gateway/static/root/assets/{desktop-pet-settings-Br6Z1Vau.js → desktop-pet-settings-CQPXub2f.js} +1 -1
  35. package/dist/gateway/static/root/assets/device-pairing-wizard-DxkOYSut.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-CFjVNb1m.js → extension-debug-page-CtWClPz-.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-BQ3ldBhh.js → extension-page-BHh9HLCz.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-settings-page-CaXnWbRI.js → extension-settings-page-BdT3v5Uh.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-swr-DgFmBSH9.js → gateway-config-swr-1eqyz9vZ.js} +1 -1
  40. package/dist/gateway/static/root/assets/gateway-settings-CZas_Ekx.js +1 -0
  41. package/dist/gateway/static/root/assets/{gateway-startup-retry-C7h3xef0.js → gateway-startup-retry-C4rsW6vJ.js} +1 -1
  42. package/dist/gateway/static/root/assets/home-page-w3_aWeNt.js +1 -0
  43. package/dist/gateway/static/root/assets/{image-generation-api-DJ1xaz2p.js → image-generation-api-B5DXMylk.js} +1 -1
  44. package/dist/gateway/static/root/assets/{imports-page-CaB54QIp.js → imports-page-B1JH0G5j.js} +1 -1
  45. package/dist/gateway/static/root/assets/index--3c0awkr.js +121 -0
  46. package/dist/gateway/static/root/assets/index-CNc4N4TX.css +1 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DnvHvKQJ.js → keyboard-shortcuts-settings-DGrLJ8Yh.js} +1 -1
  48. package/dist/gateway/static/root/assets/local-app-workbench-page-BYKrJpFF.js +1 -0
  49. package/dist/gateway/static/root/assets/local-apps-Bpja8nC6.js +1 -0
  50. package/dist/gateway/static/root/assets/local-apps-page-DqjStqbL.js +1 -0
  51. package/dist/gateway/static/root/assets/{locale-store-C4RjTd0C.js → locale-store-BIkcRr3t.js} +1 -1
  52. package/dist/gateway/static/root/assets/{logs-page-N0q5DxnI.js → logs-page-Dl4kM4Na.js} +2 -2
  53. package/dist/gateway/static/root/assets/management-settings-gCfH4cwH.js +1 -0
  54. package/dist/gateway/static/root/assets/{markdown-view-DkPzc50Z.js → markdown-view-Ck_5MADq.js} +1 -1
  55. package/dist/gateway/static/root/assets/{media-plugins-BzLYE9lj.js → media-plugins-DTsZqgo6.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-7VAhscYe.js +3 -0
  57. package/dist/gateway/static/root/assets/note-detail-panel-j6sioeL1.js +5 -0
  58. package/dist/gateway/static/root/assets/notes-page-CMvvHv0f.js +8 -0
  59. package/dist/gateway/static/root/assets/{page-context-capture-button-DVnGa7Lu.js → page-context-capture-button-DTI_g4tz.js} +1 -1
  60. package/dist/gateway/static/root/assets/{page-tabs-q6lpN9OD.js → page-tabs-CfW_Q-K5.js} +1 -1
  61. package/dist/gateway/static/root/assets/{preview-open-alternatives-Ck63fJaQ.js → preview-open-alternatives-CuPN-vAn.js} +1 -1
  62. package/dist/gateway/static/root/assets/product-delivery-bv3z8Xkh.js +1 -0
  63. package/dist/gateway/static/root/assets/product-open-page-BHjxRz1E.js +1 -0
  64. package/dist/gateway/static/root/assets/project-detail-page-C9K_e-EV.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-Bk-es4i9.js +1 -0
  66. package/dist/gateway/static/root/assets/{registry-api-CRnytFLF.js → registry-api-BAAZUGnU.js} +1 -1
  67. package/dist/gateway/static/root/assets/remote-access-hub-CLGJNA42.js +1 -0
  68. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bu3XyrDI.js → runtime-tools-settings-panel-CHJBJKL1.js} +2 -2
  69. package/dist/gateway/static/root/assets/{scenes-page-B_5HOUzl.js → scenes-page-ClLAD1pz.js} +2 -2
  70. package/dist/gateway/static/root/assets/{schema-form-CbOOKW1B.js → schema-form-FQAit5HL.js} +1 -1
  71. package/dist/gateway/static/root/assets/sessions-page-Xj8MkXN1.js +1 -0
  72. package/dist/gateway/static/root/assets/settings-advanced-gate-DwALV8mi.js +1 -0
  73. package/dist/gateway/static/root/assets/{settings-form-section-D3UN4rb4.js → settings-form-section-BDc6bw1q.js} +1 -1
  74. package/dist/gateway/static/root/assets/{settings-page-BHztZayW.js → settings-page-DnhxBJjV.js} +1 -1
  75. package/dist/gateway/static/root/assets/{settings-page-layout-nskqtzZs.js → settings-page-layout-D3KNSQ5g.js} +1 -1
  76. package/dist/gateway/static/root/assets/{setup-status-panel-BtukdJ-z.js → setup-status-panel-F0rCQ-2a.js} +1 -1
  77. package/dist/gateway/static/root/assets/{share-preview-page-DbYXEqur.js → share-preview-page-DVQCRxwK.js} +1 -1
  78. package/dist/gateway/static/root/assets/shares-settings-C7hf6Cov.js +1 -0
  79. package/dist/gateway/static/root/assets/skill-reload-api-xPrFejRE.js +1 -0
  80. package/dist/gateway/static/root/assets/{skills-page-CK9Jeaur.js → skills-page-RdDYu7Yj.js} +1 -1
  81. package/dist/gateway/static/root/assets/{skills-page.utils-B44aWbyL.js → skills-page.utils-mDwC9UJ-.js} +1 -1
  82. package/dist/gateway/static/root/assets/{system-settings-panel-BwqpUGv_.js → system-settings-panel-Bk7GrMij.js} +1 -1
  83. package/dist/gateway/static/root/assets/task-detail-page-2A966jFY.js +1 -0
  84. package/dist/gateway/static/root/assets/{tunnel-api-BKTZzQIT.js → tunnel-api-D3Aquraj.js} +1 -1
  85. package/dist/gateway/static/root/assets/{use-autosave-BB1JBOCz.js → use-autosave-C1xQ-sHn.js} +1 -1
  86. package/dist/gateway/static/root/assets/user-model-page-CnBxPBVe.js +2 -0
  87. package/dist/gateway/static/root/assets/{voice-api-key-field-C-HsgED9.js → voice-api-key-field-DCNECvcp.js} +1 -1
  88. package/dist/gateway/static/root/assets/{voice-config-api-DvJKYYA0.js → voice-config-api-B-_niUTU.js} +1 -1
  89. package/dist/gateway/static/root/assets/{work-discovery-overlay-K3e5ONUo.js → work-discovery-overlay-BrGx_JS_.js} +1 -1
  90. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-dXRTHBoE.js → workflow-run-setup-panel-CmmC2Pdr.js} +2 -2
  91. package/dist/gateway/static/root/assets/workflows-page-BZVpqw4T.js +6 -0
  92. package/dist/gateway/static/root/index.html +12 -11
  93. package/dist/package.js +1 -1
  94. package/dist/packages/gateway-contract/src/capabilities.js +4 -110
  95. package/dist/packages/gateway-contract/src/chat-previews.js +73 -0
  96. package/dist/packages/gateway-contract/src/index.js +6 -0
  97. package/dist/packages/gateway-contract/src/local-apps.js +215 -0
  98. package/dist/packages/gateway-contract/src/product-delivery.js +62 -17
  99. package/dist/packages/gateway-contract/src/user-turn-document.js +60 -0
  100. package/dist/src/agent/agent-manager.d.ts +1 -0
  101. package/dist/src/agent/agent-manager.js +5 -4
  102. package/dist/src/agent/background-review/run-background-review.js +1 -1
  103. package/dist/src/agent/embedded/model-runtime.js +1 -1
  104. package/dist/src/agent/embedded/run-for-session.js +1 -1
  105. package/dist/src/agent/embedded/transcript-runtime.d.ts +3 -0
  106. package/dist/src/agent/embedded/transcript-runtime.js +6 -0
  107. package/dist/src/agent/external-tools/cliProvider.js +4 -1
  108. package/dist/src/agent/external-tools/composio-provider.js +9 -3
  109. package/dist/src/agent/external-tools/gateway-tools.js +17 -10
  110. package/dist/src/agent/external-tools/mcp-provider.d.ts +3 -1
  111. package/dist/src/agent/external-tools/mcp-provider.js +91 -6
  112. package/dist/src/agent/external-tools/service.d.ts +2 -1
  113. package/dist/src/agent/external-tools/service.js +8 -3
  114. package/dist/src/agent/external-tools/types.d.ts +9 -0
  115. package/dist/src/agent/image/tool-model-config.js +1 -1
  116. package/dist/src/agent/mcp/bundle-mcp-config.js +37 -5
  117. package/dist/src/agent/mcp/bundle-mcp-gateway.d.ts +1 -0
  118. package/dist/src/agent/mcp/bundle-mcp-gateway.js +1 -0
  119. package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
  120. package/dist/src/agent/mcp/bundle-mcp-runtime.js +33 -1
  121. package/dist/src/agent/mcp/bundle-mcp-types.d.ts +4 -0
  122. package/dist/src/agent/mcp/index.js +1 -1
  123. package/dist/src/agent/mcp/mcp-stdio-transport.d.ts +1 -0
  124. package/dist/src/agent/mcp/mcp-stdio-transport.js +10 -0
  125. package/dist/src/agent/mcp/mcp-transport.js +12 -8
  126. package/dist/src/agent/mcp/oauth/index.js +1 -1
  127. package/dist/src/agent/mcp/oauth/mcp-oauth-manager.d.ts +6 -1
  128. package/dist/src/agent/mcp/oauth/mcp-oauth-manager.js +70 -14
  129. package/dist/src/agent/mcp/oauth/mcp-oauth-provider.js +1 -1
  130. package/dist/src/agent/mcp/oauth/mcp-oauth-session.d.ts +2 -0
  131. package/dist/src/agent/mcp/oauth/mcp-oauth-session.js +12 -0
  132. package/dist/src/agent/mcp/oauth/mcp-oauth-store.d.ts +3 -0
  133. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +14 -2
  134. package/dist/src/agent/mcp/plugin-http-fetch.d.ts +2 -0
  135. package/dist/src/agent/mcp/plugin-http-fetch.js +56 -0
  136. package/dist/src/agent/service/process-direct-streaming.js +27 -12
  137. package/dist/src/agent/service.js +3 -2
  138. package/dist/src/agent/service.types.d.ts +2 -0
  139. package/dist/src/agent/session/session-inspector.js +1 -1
  140. package/dist/src/agent/skills/hub-lock.js +1 -1
  141. package/dist/src/agent/skills/hub-pull.js +1 -1
  142. package/dist/src/agent/skills/index.js +8 -1
  143. package/dist/src/agent/skills/skill-manager.d.ts +2 -0
  144. package/dist/src/agent/skills/skill-manager.js +8 -0
  145. package/dist/src/agent/skills/skill-sources.js +17 -0
  146. package/dist/src/agent/skills/types.d.ts +3 -1
  147. package/dist/src/agent/source-context/injector.js +10 -5
  148. package/dist/src/agent/source-context/types.d.ts +3 -0
  149. package/dist/src/agent/source-context/types.js +8 -2
  150. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  151. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
  152. package/dist/src/agent/tool-manuals/xopc-use.js +12 -2
  153. package/dist/src/agent/tools/automation-tool.js +1 -1
  154. package/dist/src/agent/tools/factory.d.ts +1 -0
  155. package/dist/src/agent/tools/factory.js +2 -1
  156. package/dist/src/agent/tools/search/registry.js +4 -1
  157. package/dist/src/agent/tools/workflow-tool.js +1 -1
  158. package/dist/src/agent/tools/write.js +1 -1
  159. package/dist/src/agent/tools/xopc-use-tool.d.ts +4 -2
  160. package/dist/src/agent/tools/xopc-use-tool.js +120 -12
  161. package/dist/src/ai-assist/text-assist.js +1 -1
  162. package/dist/src/auth/credentials.js +2 -2
  163. package/dist/src/auth/oauth/xopc-cloud.js +1 -1
  164. package/dist/src/auth/profiles/store.js +1 -1
  165. package/dist/src/auth/sync-provider-auth.js +2 -2
  166. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  167. package/dist/src/chat-commands/agent-edit.js +1 -1
  168. package/dist/src/chat-previews/index.d.ts +2 -0
  169. package/dist/src/chat-previews/index.js +3 -0
  170. package/dist/src/chat-previews/service.d.ts +27 -0
  171. package/dist/src/chat-previews/service.js +106 -0
  172. package/dist/src/chat-previews/store.d.ts +28 -0
  173. package/dist/src/chat-previews/store.js +77 -0
  174. package/dist/src/cli/commands/agent.js +1 -1
  175. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  176. package/dist/src/cli/commands/doctor/checks/provider-auth.js +3 -3
  177. package/dist/src/cli/commands/extension-agent-plugin.d.ts +8 -0
  178. package/dist/src/cli/commands/extension-agent-plugin.js +82 -0
  179. package/dist/src/cli/commands/extension-marketplace.js +44 -4
  180. package/dist/src/cli/commands/extension.js +35 -3
  181. package/dist/src/cli/commands/models.js +1 -1
  182. package/dist/src/computer/runtime.js +1 -1
  183. package/dist/src/config/index.js +4 -4
  184. package/dist/src/config/loader.js +2 -2
  185. package/dist/src/config/models-json.js +2 -2
  186. package/dist/src/config/schema.js +2 -2
  187. package/dist/src/connectors/account-selection.js +1 -1
  188. package/dist/src/connectors/connection-candidates.d.ts +4 -1
  189. package/dist/src/connectors/connection-candidates.js +8 -2
  190. package/dist/src/connectors/connection-capabilities.d.ts +2 -2
  191. package/dist/src/connectors/connection-capabilities.js +3 -1
  192. package/dist/src/connectors/connection-recovery-service.d.ts +6 -1
  193. package/dist/src/connectors/connection-recovery-service.js +138 -26
  194. package/dist/src/connectors/plugin-mcp-recovery.d.ts +28 -0
  195. package/dist/src/connectors/plugin-mcp-recovery.js +90 -0
  196. package/dist/src/extensions/agent-plugins/auth.d.ts +39 -0
  197. package/dist/src/extensions/agent-plugins/auth.js +156 -0
  198. package/dist/src/extensions/agent-plugins/connection.d.ts +8 -0
  199. package/dist/src/extensions/agent-plugins/connection.js +41 -0
  200. package/dist/src/extensions/agent-plugins/health.d.ts +4 -0
  201. package/dist/src/extensions/agent-plugins/health.js +48 -0
  202. package/dist/src/extensions/agent-plugins/inventory.d.ts +53 -0
  203. package/dist/src/extensions/agent-plugins/inventory.js +34 -0
  204. package/dist/src/extensions/agent-plugins/mcp-adapter.d.ts +3 -0
  205. package/dist/src/extensions/agent-plugins/mcp-adapter.js +47 -0
  206. package/dist/src/extensions/agent-plugins/sources.d.ts +5 -0
  207. package/dist/src/extensions/agent-plugins/sources.js +72 -0
  208. package/dist/src/extensions/agent-plugins/store.d.ts +61 -0
  209. package/dist/src/extensions/agent-plugins/store.js +305 -0
  210. package/dist/src/extensions/agent-plugins/validation.d.ts +59 -0
  211. package/dist/src/extensions/agent-plugins/validation.js +211 -0
  212. package/dist/src/extensions/lockfile.js +1 -1
  213. package/dist/src/extensions/update.js +1 -1
  214. package/dist/src/gateway/agents-admin.js +1 -1
  215. package/dist/src/gateway/chat-stream/mapper.js +10 -3
  216. package/dist/src/gateway/file-path-classifier.js +1 -1
  217. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  218. package/dist/src/gateway/hono/routes/agent-plugins.d.ts +3 -0
  219. package/dist/src/gateway/hono/routes/agent-plugins.js +166 -0
  220. package/dist/src/gateway/hono/routes/agent-stream.js +14 -0
  221. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +4 -2
  222. package/dist/src/gateway/hono/routes/chat-previews.d.ts +3 -0
  223. package/dist/src/gateway/hono/routes/chat-previews.js +41 -0
  224. package/dist/src/gateway/hono/routes/connection-waits.js +4 -2
  225. package/dist/src/gateway/hono/routes/index.js +2 -0
  226. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  227. package/dist/src/gateway/hono/routes/local-apps.js +71 -39
  228. package/dist/src/gateway/hono/routes/mcp.js +48 -21
  229. package/dist/src/gateway/hono/routes/models.js +1 -1
  230. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +4 -0
  231. package/dist/src/gateway/hono/routes/session-input-handler.js +22 -0
  232. package/dist/src/gateway/hono/routes/side-chats.js +11 -0
  233. package/dist/src/gateway/service/agent-runner.js +7 -1
  234. package/dist/src/gateway/service/config-coordinator.js +1 -1
  235. package/dist/src/gateway/service/marketplace-service.d.ts +1 -0
  236. package/dist/src/gateway/service/marketplace-service.js +15 -1
  237. package/dist/src/gateway/service/session-input-coordinator.js +3 -3
  238. package/dist/src/gateway/service.d.ts +5 -1
  239. package/dist/src/gateway/service.js +19 -5
  240. package/dist/src/gateway/side-chat/index.d.ts +3 -1
  241. package/dist/src/gateway/side-chat/index.js +2 -1
  242. package/dist/src/gateway/side-chat/manager.d.ts +16 -0
  243. package/dist/src/gateway/side-chat/manager.js +40 -6
  244. package/dist/src/gateway/side-chat/promotion-service.d.ts +19 -0
  245. package/dist/src/gateway/side-chat/promotion-service.js +111 -0
  246. package/dist/src/gateway/side-chat/run-service.js +1 -0
  247. package/dist/src/gateway/side-chat/types.d.ts +1 -1
  248. package/dist/src/local-apps/artifact-files.d.ts +3 -0
  249. package/dist/src/local-apps/artifact-files.js +45 -0
  250. package/dist/src/local-apps/capabilities/write.js +1 -1
  251. package/dist/src/local-apps/fix-guidance.d.ts +3 -0
  252. package/dist/src/local-apps/fix-guidance.js +75 -0
  253. package/dist/src/local-apps/index.d.ts +2 -1
  254. package/dist/src/local-apps/scaffold.d.ts +5 -0
  255. package/dist/src/local-apps/scaffold.js +18 -5
  256. package/dist/src/local-apps/service.d.ts +18 -3
  257. package/dist/src/local-apps/service.js +106 -64
  258. package/dist/src/local-apps/snapshot-store.d.ts +8 -0
  259. package/dist/src/local-apps/snapshot-store.js +68 -0
  260. package/dist/src/local-apps/types.d.ts +4 -87
  261. package/dist/src/notes/service.js +1 -1
  262. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  263. package/dist/src/providers/index.js +2 -2
  264. package/dist/src/providers/model-catalog-persistence.js +1 -1
  265. package/dist/src/providers/model-registry.js +1 -1
  266. package/dist/src/providers/register-runtime-providers.js +1 -1
  267. package/dist/src/session/client-history.d.ts +3 -1
  268. package/dist/src/session/client-history.js +10 -3
  269. package/dist/src/session/index.d.ts +1 -1
  270. package/dist/src/session/manager.d.ts +4 -0
  271. package/dist/src/session/manager.js +6 -0
  272. package/dist/src/session/session-context-for-llm.d.ts +12 -1
  273. package/dist/src/session/session-context-for-llm.js +16 -2
  274. package/dist/src/session/store.d.ts +14 -0
  275. package/dist/src/session/store.js +17 -0
  276. package/dist/src/session/stored-rows-to-file-entries.js +10 -1
  277. package/dist/src/session/transcript-outline.js +10 -3
  278. package/dist/src/storage/sqlite/connection-wait-repository.js +9 -3
  279. package/dist/src/storage/sqlite/migrations/202_chat_previews.sql +26 -0
  280. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  281. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  282. package/dist/src/storage/sqlite/row-mappers.js +6 -1
  283. package/dist/src/storage/sqlite/schema.js +1 -1
  284. package/dist/src/tui/backends/embedded-backend.js +1 -1
  285. package/dist/src/tui/tui-commands.js +1 -1
  286. package/dist/src/tui/tui-startup-resources.js +1 -1
  287. package/dist/src/tui/tui.js +2 -2
  288. package/dist/src/voice/tts/audio.js +1 -1
  289. package/dist/src/work-discovery/service.js +2 -2
  290. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  291. package/package.json +4 -4
  292. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BGCqlTcR.js +0 -1
  293. package/dist/gateway/static/root/assets/api-DEneywgz.js +0 -1
  294. package/dist/gateway/static/root/assets/apps-page-vC87gAyb.js +0 -1
  295. package/dist/gateway/static/root/assets/automations-workspace-CzYmREol.js +0 -7
  296. package/dist/gateway/static/root/assets/browser-settings-page-BxaSzUIU.js +0 -3
  297. package/dist/gateway/static/root/assets/capabilities-D0S3DuAD.js +0 -1
  298. package/dist/gateway/static/root/assets/capabilities-settings-panel-CFCu-8da.js +0 -8
  299. package/dist/gateway/static/root/assets/channels-settings-CENp82yt.js +0 -1
  300. package/dist/gateway/static/root/assets/connectors-page-g_KTZWCb.js +0 -2
  301. package/dist/gateway/static/root/assets/device-pairing-wizard-DO7jp0ep.js +0 -1
  302. package/dist/gateway/static/root/assets/gateway-settings-BkeSEBxk.js +0 -1
  303. package/dist/gateway/static/root/assets/home-page-KoQXV4hp.js +0 -1
  304. package/dist/gateway/static/root/assets/index-ZxnWUdPv.css +0 -1
  305. package/dist/gateway/static/root/assets/index-u4709aCa.js +0 -89
  306. package/dist/gateway/static/root/assets/local-app-workbench-page-7QX0YFa7.js +0 -2
  307. package/dist/gateway/static/root/assets/local-apps-page-RSAl-NhO.js +0 -1
  308. package/dist/gateway/static/root/assets/management-settings-C_cb0Kue.js +0 -1
  309. package/dist/gateway/static/root/assets/messages-M5xl1fHE.js +0 -3
  310. package/dist/gateway/static/root/assets/note-detail-panel-CVWst-Er.js +0 -5
  311. package/dist/gateway/static/root/assets/notes-page-BFwCgIls.js +0 -8
  312. package/dist/gateway/static/root/assets/product-delivery-chCjIpvu.js +0 -1
  313. package/dist/gateway/static/root/assets/product-open-page-BIGvTs9n.js +0 -1
  314. package/dist/gateway/static/root/assets/project-detail-page-BFEtpkcf.js +0 -1
  315. package/dist/gateway/static/root/assets/projects-page-CHr-P2z4.js +0 -1
  316. package/dist/gateway/static/root/assets/remote-access-hub-PhEyHSOb.js +0 -1
  317. package/dist/gateway/static/root/assets/sessions-page-CmIhlHPS.js +0 -1
  318. package/dist/gateway/static/root/assets/settings-advanced-gate-CCOTu1jb.js +0 -1
  319. package/dist/gateway/static/root/assets/shares-settings-CG1sll8V.js +0 -1
  320. package/dist/gateway/static/root/assets/skill-reload-api-Byq23h9c.js +0 -1
  321. package/dist/gateway/static/root/assets/task-detail-page-D5q-wk_d.js +0 -1
  322. package/dist/gateway/static/root/assets/user-model-page-DE3ZeJL3.js +0 -2
  323. package/dist/gateway/static/root/assets/workflows-page-DGZaETmN.js +0 -6
@@ -1,5 +1,6 @@
1
1
  import { createLogger } from "../../../utils/logger/index.js";
2
2
  import { init_logger } from "../../../utils/logger.js";
3
+ import { parseUserTurnDocument, userTurnDocumentRefIds } from "../../../../packages/gateway-contract/src/user-turn-document.js";
3
4
  import { browserPageContextsInputSchema } from "../../../../packages/gateway-contract/src/browser-page-context.js";
4
5
  import { init_src } from "../../../../packages/gateway-contract/src/index.js";
5
6
  import { endpointTurnClaimSchema, init_src as init_src$1 } from "../../../../packages/endpoint-tools-protocol/src/index.js";
@@ -24,6 +25,13 @@ init_providers();
24
25
  init_logger();
25
26
  const MAX_TURN_CONTEXTS = 5;
26
27
  const log = createLogger("Gateway:SessionInput");
28
+ function contextDocumentIsValid(content, refs) {
29
+ if (!refs) return false;
30
+ const document = parseUserTurnDocument(content);
31
+ if (!document) return true;
32
+ const available = new Set(refs.flatMap((ref) => ref.refId ? [ref.refId] : []));
33
+ return userTurnDocumentRefIds(document).every((refId) => available.has(refId));
34
+ }
27
35
  async function submitSessionInput(c, deps, conversationId, options) {
28
36
  const body = await c.req.json().catch(() => null);
29
37
  if (!body || !conversationId) return c.json({
@@ -51,6 +59,13 @@ async function submitSessionInput(c, deps, conversationId, options) {
51
59
  }
52
60
  }, 400);
53
61
  const content = typeof body.content === "string" ? body.content : "";
62
+ if (!contextDocumentIsValid(content, contextRefs)) return c.json({
63
+ ok: false,
64
+ error: {
65
+ code: "BAD_REQUEST",
66
+ message: "Input contains an unknown context reference"
67
+ }
68
+ }, 400);
54
69
  if (options?.taskConversation && isTaskDestructiveCommand(content)) return c.json({
55
70
  ok: false,
56
71
  error: {
@@ -239,6 +254,13 @@ async function replaceLatestSessionTurn(c, deps, conversationId, targetTurnId) {
239
254
  }
240
255
  }, 400);
241
256
  const content = typeof body.content === "string" ? body.content : "";
257
+ if (!contextDocumentIsValid(content, contextRefs)) return c.json({
258
+ ok: false,
259
+ error: {
260
+ code: "BAD_REQUEST",
261
+ message: "Input contains an unknown context reference"
262
+ }
263
+ }, 400);
242
264
  const contentError = validateWebchatContent(content);
243
265
  if (contentError) return c.json({
244
266
  ok: false,
@@ -157,6 +157,17 @@ function registerSideChatRoutes(authenticated, deps) {
157
157
  return respondSideChatError(c, error);
158
158
  }
159
159
  });
160
+ authenticated.post("/api/side-chats/:sideChatId/promote", deps.chatRateLimitMiddleware, async (c) => {
161
+ try {
162
+ const result = await service.sideChatPromotions.promote(c.req.param("sideChatId"), readClientInstanceId(c));
163
+ return c.json({
164
+ ok: true,
165
+ ...result
166
+ }, result.created ? 201 : 200);
167
+ } catch (error) {
168
+ return respondSideChatError(c, error);
169
+ }
170
+ });
160
171
  authenticated.delete("/api/side-chats/:sideChatId", async (c) => {
161
172
  try {
162
173
  return await service.sideChatRuns.dispose(c.req.param("sideChatId"), readClientInstanceId(c)) ? c.json({ ok: true }) : c.json({
@@ -87,7 +87,13 @@ var GatewayAgentRunner = class {
87
87
  });
88
88
  }
89
89
  if (unique.size > MAX_TURN_CONTEXTS) throw new Error(`A message can reference at most ${MAX_TURN_CONTEXTS} sources`);
90
- const contexts = await Promise.all([...unique.values()].map((ref) => opts.resolveTurnContext(ref, conversationId)));
90
+ const contexts = await Promise.all([...unique.values()].map(async (ref) => {
91
+ const context = await opts.resolveTurnContext(ref, conversationId);
92
+ return context && ref.refId ? {
93
+ ...context,
94
+ refId: ref.refId
95
+ } : context;
96
+ }));
91
97
  if (contexts.some((context) => context === null)) throw new Error("A referenced source is unavailable or has changed; select it again");
92
98
  return fitSourceContextsToBudget(contexts.filter((context) => context !== null));
93
99
  },
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { getModelRegistry } from "../../providers/model-registry.js";
4
3
  import { loadConfig, saveConfig } from "../../config/loader.js";
4
+ import { getModelRegistry } from "../../providers/model-registry.js";
5
5
  import { init_providers } from "../../providers/index.js";
6
6
  import { disposeAllSessionMcpRuntimes } from "../../agent/mcp/bundle-mcp-runtime.js";
7
7
  import { reloadImageGenerationProviders } from "../../agent/image/generation/provider-registry.js";
@@ -52,6 +52,7 @@ export interface SkillSourceInstallResultPayload extends SkillInstallResultPaylo
52
52
  contentHash: string;
53
53
  }
54
54
  export interface ExtensionMarketplacePackageDetailPayload extends MarketplacePackageDetail {
55
+ format?: 'native-extension' | 'agent-plugin';
55
56
  installability: {
56
57
  available: boolean;
57
58
  reason?: string;
@@ -2,12 +2,14 @@ import { resolveStateDir } from "../../config/paths-state.js";
2
2
  import { createLogger } from "../../utils/logger/index.js";
3
3
  import { init_logger } from "../../utils/logger.js";
4
4
  import { init_paths, resolveExtensionsDir } from "../../config/paths.js";
5
+ import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
6
+ import { AgentPluginStore } from "../../extensions/agent-plugins/store.js";
5
7
  import { createSkillConfigManager } from "../../agent/skills/config.js";
6
8
  import { resolveWorkspaceSkillsDir, resolveWorkspaceSkillsLockPath } from "../../agent/skills/workspace-skills-dir.js";
7
9
  import { removeSkillsLockEntry } from "../../agent/skills/hub-lock.js";
8
10
  import { deleteManagedSkill, installSkillFromZip, listManagedSkillDirs } from "../../agent/skills/managed-store.js";
9
11
  import { normalizeSkillInstallTarget } from "../../agent/skills/install-target.js";
10
- import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
12
+ import { isAgentPluginArchive, withAgentPluginArchive } from "../../extensions/agent-plugins/sources.js";
11
13
  import { existsSync, rmSync } from "node:fs";
12
14
  //#region src/gateway/service/marketplace-service.ts
13
15
  /**
@@ -206,6 +208,18 @@ var GatewayMarketplaceService = class {
206
208
  const resolved = await resolveExtensionZipDownloadUrl(base, packageName.trim());
207
209
  const buffer = await downloadExtensionStoreZipBuffer(base, resolved.downloadUrl);
208
210
  verifyStoreArtifactSha256(buffer, resolved.sha256);
211
+ if (isAgentPluginArchive(buffer)) {
212
+ const plan = withAgentPluginArchive(buffer, (path) => new AgentPluginStore().inspect(path));
213
+ return {
214
+ ...detail,
215
+ format: "agent-plugin",
216
+ manifest: plan.manifest,
217
+ installability: {
218
+ available: true,
219
+ sha256: resolved.sha256
220
+ }
221
+ };
222
+ }
209
223
  const { peekExtensionManifestFromStoreZip, peekExtensionPackageJsonFromStoreZip } = await import("../../extensions/install.js");
210
224
  const manifest = peekExtensionManifestFromStoreZip(buffer);
211
225
  const packageJson = peekExtensionPackageJsonFromStoreZip(buffer);
@@ -24,11 +24,11 @@ function sameAppContext(input, existing) {
24
24
  return isDeepStrictEqual(identity(input.sourceContexts), identity(existing.contextSnapshots));
25
25
  }
26
26
  function contextRefsMatchFrozenSnapshot(requested, frozen) {
27
- const editable = frozen?.filter((ref) => ref.kind === "note" || ref.kind === "task") ?? [];
27
+ const editable = frozen?.filter((ref) => ref.kind === "note" || ref.kind === "task" || ref.kind === "file" || ref.kind === "session" || ref.kind === "browser_tab" || ref.kind === "mcp_resource") ?? [];
28
28
  if (requested.length !== editable.length) return false;
29
29
  return requested.every((ref, index) => {
30
30
  const snapshot = editable[index];
31
- return snapshot?.kind === ref.kind && snapshot.sourceId === ref.sourceId && ref.expectedVersion === snapshot.version;
31
+ return snapshot?.kind === ref.kind && snapshot.sourceId === ref.sourceId && snapshot.refId === ref.refId && ref.expectedVersion === snapshot.version;
32
32
  });
33
33
  }
34
34
  var SessionInputCoordinator = class {
@@ -311,7 +311,7 @@ var SessionInputCoordinator = class {
311
311
  const existing = getSessionInputById(conversationId, id);
312
312
  if (!contextRefsMatchFrozenSnapshot(body.contextRefs, existing?.contextRefs)) try {
313
313
  const resolved = await this.deps.prepareContexts(conversationId, body.contextRefs) ?? [];
314
- sourceContexts = fitSourceContextsToBudget([...existing?.contextSnapshots?.filter((source) => source.kind !== "note" && source.kind !== "task") ?? [], ...resolved]);
314
+ sourceContexts = fitSourceContextsToBudget([...existing?.contextSnapshots?.filter((source) => source.kind === "app_context" || source.kind === "browser_page") ?? [], ...resolved]);
315
315
  } catch (err) {
316
316
  log.warn({
317
317
  err,
@@ -8,12 +8,13 @@ import { NotesService } from '../notes/index.js';
8
8
  import { WorkflowRunService } from '../workflows/service/workflow-run-service.js';
9
9
  import { ExtensionLoader } from '../extensions/index.js';
10
10
  import { SessionIndex } from '../session/index.js';
11
- import { EphemeralSideChatManager, SideChatRunService } from './side-chat/index.js';
11
+ import { EphemeralSideChatManager, SideChatPromotionService, SideChatRunService } from './side-chat/index.js';
12
12
  import type { Config } from '../config/schema.js';
13
13
  import { type ResolvedGatewayAuth } from './auth.js';
14
14
  import { ModelCatalogSyncService } from '../providers/model-catalog-sync-service.js';
15
15
  import { ProjectService } from '../projects/index.js';
16
16
  import { LocalAppService } from '../local-apps/index.js';
17
+ import { ChatPreviewService } from '../chat-previews/index.js';
17
18
  import { TaskConversationRepository } from '../tasks/task-conversation-repository.js';
18
19
  import { type BrowserAutomationService } from '../browser/automations/index.js';
19
20
  import { GatewaySessionsApi } from './service/sessions-api.js';
@@ -86,6 +87,7 @@ export declare class GatewayService {
86
87
  /** Process-local, non-persistent side conversations forked from durable sessions. */
87
88
  readonly sideChats: EphemeralSideChatManager;
88
89
  readonly sideChatRuns: SideChatRunService;
90
+ readonly sideChatPromotions: SideChatPromotionService;
89
91
  /**
90
92
  * Session CRUD / search / compaction / tag-archive-pin / stats — the gateway
91
93
  * REST surface for sessions. Routes should depend on this narrow service
@@ -107,6 +109,8 @@ export declare class GatewayService {
107
109
  readonly discussionSealer: DiscussionSealer;
108
110
  /** Local user-created apps, their coder projects, previews, and installs. */
109
111
  readonly localApps: LocalAppService;
112
+ /** Immutable, conversation-scoped UI previews that do not create projects. */
113
+ readonly chatPreviews: ChatPreviewService;
110
114
  get sceneAccess(): SceneAccess | undefined;
111
115
  constructor(serviceConfig?: GatewayServiceConfig);
112
116
  /** Lazy AgentService — constructed on first use or during `start()`. */
@@ -18,17 +18,17 @@ import { getSessionConfig } from "../storage/sqlite/config-repository.js";
18
18
  import "../storage/sqlite/index.js";
19
19
  import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
20
20
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
21
+ import { init_agent_session_key, resolveAgentMainConversationId } from "../routing/agent-session-key.js";
22
+ import { init_session_key, resolveConversationId, sanitizeSegment } from "../routing/session-key.js";
23
+ import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
24
+ import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
21
25
  import { init_paths, resolveConfigPath, resolveExtensionsDir } from "../config/paths.js";
22
- import { prewarmModelRegistry } from "../providers/model-registry.js";
23
26
  import { areExtensionsGloballyDisabled } from "../extensions/discover-extensions.js";
24
27
  import { buildExtensionMetadataSnapshot } from "../extensions/extension-metadata-snapshot.js";
25
28
  import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, init_channel_catalog_service } from "../channels/catalog/channel-catalog-service.js";
26
29
  import { loadConfig, saveConfig } from "../config/loader.js";
27
- import { init_agent_session_key, resolveAgentMainConversationId } from "../routing/agent-session-key.js";
28
- import { init_session_key, resolveConversationId, sanitizeSegment } from "../routing/session-key.js";
29
- import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
30
+ import { prewarmModelRegistry } from "../providers/model-registry.js";
30
31
  import { init_providers, providers_exports } from "../providers/index.js";
31
- import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
32
32
  import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
33
33
  import { getEmbeddedExecutionSession } from "../agent/embedded/execution-context.js";
34
34
  import { disposeAllSessionMcpRuntimes } from "../agent/mcp/bundle-mcp-runtime.js";
@@ -64,6 +64,8 @@ import { ensureStarterAgentsInitialized } from "../agent/starter-agents.js";
64
64
  import { setPairingBroadcastSink } from "../channels/pairing/pairing-events.js";
65
65
  import { registerClarificationChannelRuntime } from "./clarify-runtime.js";
66
66
  import { ChannelManager } from "../channels/manager.js";
67
+ import { ChatPreviewService } from "../chat-previews/service.js";
68
+ import "../chat-previews/index.js";
67
69
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
68
70
  import "../config/index.js";
69
71
  import { ManagedComposioEventPoller } from "../connectors/composio-managed-events.js";
@@ -100,6 +102,7 @@ import { WorkflowRunService } from "../workflows/service/workflow-run-service.js
100
102
  import { WorkflowSessionBridge } from "../workflows/service/workflow-session-bridge.js";
101
103
  import { EphemeralSideChatManager } from "./side-chat/manager.js";
102
104
  import { SideChatRunService } from "./side-chat/run-service.js";
105
+ import { SideChatPromotionService } from "./side-chat/promotion-service.js";
103
106
  import "./side-chat/index.js";
104
107
  import { wireTunnelEventsToGateway } from "../tunnel/gateway-lifecycle.js";
105
108
  import { getExposureManager } from "../remote-access/exposure-manager.js";
@@ -301,6 +304,7 @@ var GatewayService = class {
301
304
  /** Process-local, non-persistent side conversations forked from durable sessions. */
302
305
  sideChats;
303
306
  sideChatRuns;
307
+ sideChatPromotions;
304
308
  /**
305
309
  * Session CRUD / search / compaction / tag-archive-pin / stats — the gateway
306
310
  * REST surface for sessions. Routes should depend on this narrow service
@@ -329,6 +333,8 @@ var GatewayService = class {
329
333
  discussionSealer;
330
334
  /** Local user-created apps, their coder projects, previews, and installs. */
331
335
  localApps;
336
+ /** Immutable, conversation-scoped UI previews that do not create projects. */
337
+ chatPreviews;
332
338
  get sceneAccess() {
333
339
  return this.sceneHost ? {
334
340
  services: this.sceneHost.http,
@@ -467,6 +473,7 @@ var GatewayService = class {
467
473
  getExtensionLoader: () => this.extensionLoader,
468
474
  emit: (type, payload) => this.emit(type, payload)
469
475
  });
476
+ this.chatPreviews = new ChatPreviewService({ localApps: this.localApps });
470
477
  this.agentRunner = new GatewayAgentRunner({
471
478
  validateConnectionResume: async (input) => {
472
479
  for (const source of input.contextSnapshots ?? []) if (source.kind === "app_context") await checkAppContextAccess(source, this.appContextDispatcher(), this.auth);
@@ -529,6 +536,7 @@ var GatewayService = class {
529
536
  let sideChatRuns;
530
537
  this.sideChats = new EphemeralSideChatManager({
531
538
  getParentMetadata: (conversationId) => this.sessionIndex.getSessionMetadata(conversationId),
539
+ getParentConfig: async (conversationId) => getSessionConfig(conversationId),
532
540
  loadParentMessages: (conversationId) => this.sessionIndex.getStore().load(conversationId),
533
541
  getDefaultModelRef: (conversationId) => this.ensureAgentService().getModelForSession(conversationId),
534
542
  getDefaultThinkingLevel: (conversationId) => this.ensureAgentService().getThinkingLevelForSession(conversationId),
@@ -550,6 +558,11 @@ var GatewayService = class {
550
558
  publishRealtime: (topic, event, data) => this.realtime.broker.publish(topic, event, data),
551
559
  completeRealtimeTopic: (topic) => this.realtime.completeTopic(topic)
552
560
  });
561
+ this.sideChatPromotions = new SideChatPromotionService({
562
+ manager: this.sideChats,
563
+ sessionIndex: this.sessionIndex,
564
+ getAgentService: () => this.ensureAgentService()
565
+ });
553
566
  this.sessions = new GatewaySessionsApi({
554
567
  sessionIndex: this.sessionIndex,
555
568
  getAgentService: () => this.ensureAgentService(),
@@ -627,6 +640,7 @@ var GatewayService = class {
627
640
  getProjectService: () => this.projects,
628
641
  getWorkDiscovery: () => this._workDiscovery ?? void 0,
629
642
  getLocalAppService: () => this.localApps,
643
+ getChatPreviewService: () => this.chatPreviews,
630
644
  dispatchTaskEvents: () => this.dispatchTaskEvents(),
631
645
  dispatchTaskRuns: () => this.dispatchTaskRuns(),
632
646
  getWorkflowRunService: () => this.createWorkflowRunService(),
@@ -1,5 +1,7 @@
1
1
  export { EphemeralSideChatManager, SideChatError, parseThinkingLevel } from './manager.js';
2
- export type { EphemeralSideChatManagerOptions } from './manager.js';
2
+ export type { EphemeralSideChatManagerOptions, SideChatPromotionSnapshot } from './manager.js';
3
3
  export { validateSideChatSelections } from './context-snapshot.js';
4
4
  export { SideChatRunService } from './run-service.js';
5
+ export { SideChatPromotionService } from './promotion-service.js';
6
+ export type { SideChatPromotionResult, SideChatPromotionServiceOptions } from './promotion-service.js';
5
7
  export type { CreateSideChatInput, SideChatConfig, SideChatContextSnapshot, SideChatSelection, SideChatStatus, SideChatView, } from './types.js';
@@ -1,4 +1,5 @@
1
1
  import { validateSideChatSelections } from "./context-snapshot.js";
2
2
  import { EphemeralSideChatManager, SideChatError, parseThinkingLevel } from "./manager.js";
3
3
  import { SideChatRunService } from "./run-service.js";
4
- export { EphemeralSideChatManager, SideChatError, SideChatRunService, parseThinkingLevel, validateSideChatSelections };
4
+ import { SideChatPromotionService } from "./promotion-service.js";
5
+ export { EphemeralSideChatManager, SideChatError, SideChatPromotionService, SideChatRunService, parseThinkingLevel, validateSideChatSelections };
@@ -1,7 +1,18 @@
1
1
  import type { AgentMessage, ThinkingLevel } from '@earendil-works/pi-agent-core';
2
2
  import { InMemoryTranscriptRuntime } from '../../agent/embedded/transcript-runtime.js';
3
+ import type { SessionAgentConfig } from '../../session/config-types.js';
4
+ import type { TranscriptStoredRow } from '../../session/session-context-for-llm.js';
3
5
  import type { SessionMetadata } from '../../session/types.js';
4
6
  import type { CreateSideChatInput, SideChatConfig, SideChatStatus, SideChatView } from './types.js';
7
+ export interface SideChatPromotionSnapshot {
8
+ id: string;
9
+ parentMetadata: SessionMetadata;
10
+ parentConfig: SessionAgentConfig | null;
11
+ context: SideChatView['context'];
12
+ config: SideChatConfig;
13
+ contextMessages: AgentMessage[];
14
+ conversationRows: TranscriptStoredRow[];
15
+ }
5
16
  export declare class SideChatError extends Error {
6
17
  readonly code: 'INVALID_REQUEST' | 'NOT_FOUND' | 'PARENT_NOT_FOUND' | 'LIMIT_REACHED' | 'CAPACITY_REACHED' | 'CONFLICT' | 'EXPIRED';
7
18
  readonly reason?: 'idle' | 'waiting';
@@ -9,6 +20,7 @@ export declare class SideChatError extends Error {
9
20
  }
10
21
  export interface EphemeralSideChatManagerOptions {
11
22
  getParentMetadata: (conversationId: string) => Promise<SessionMetadata | null>;
23
+ getParentConfig?: (conversationId: string) => Promise<SessionAgentConfig | null>;
12
24
  loadParentMessages: (conversationId: string) => Promise<AgentMessage[]>;
13
25
  getDefaultModelRef: (conversationId: string) => string;
14
26
  getDefaultThinkingLevel?: (conversationId: string) => ThinkingLevel;
@@ -39,12 +51,16 @@ export declare class EphemeralSideChatManager {
39
51
  get(id: string, clientInstanceId: string): SideChatView;
40
52
  getRuntime(id: string, clientInstanceId: string): InMemoryTranscriptRuntime;
41
53
  getMessages(id: string, clientInstanceId: string): AgentMessage[];
54
+ beginPromotion(id: string, clientInstanceId: string): SideChatPromotionSnapshot;
55
+ cancelPromotion(id: string, clientInstanceId: string): void;
42
56
  updateConfig(id: string, clientInstanceId: string, patch: Partial<SideChatConfig>): SideChatView;
43
57
  heartbeat(id: string, clientInstanceId: string): SideChatView;
44
58
  extend(id: string, clientInstanceId: string): SideChatView;
45
59
  setStatus(id: string, clientInstanceId: string, status: SideChatStatus, runId?: string): SideChatView;
46
60
  waitForInput(id: string, clientInstanceId: string, clarification: NonNullable<SideChatView['clarification']>, status?: 'waiting-input' | 'waiting-approval'): void;
47
61
  dispose(id: string, clientInstanceId: string): Promise<boolean>;
62
+ disposePromoted(id: string, clientInstanceId: string): Promise<boolean>;
63
+ private disposeEntry;
48
64
  disposeClient(clientInstanceId: string): Promise<number>;
49
65
  sweepExpired(at?: number): Promise<number>;
50
66
  disposeAll(): Promise<void>;
@@ -70,6 +70,7 @@ var EphemeralSideChatManager = class {
70
70
  const metadata = await this.options.getParentMetadata(parentConversationId);
71
71
  if (!metadata || !metadata.transcriptId) throw new SideChatError("Parent session not found", "PARENT_NOT_FOUND");
72
72
  const parentMessages = await this.options.loadParentMessages(parentConversationId);
73
+ const parentConfig = await this.options.getParentConfig?.(parentConversationId) ?? null;
73
74
  if (this.stopped) throw new SideChatError("Gateway is stopping", "CAPACITY_REACHED");
74
75
  let selections;
75
76
  try {
@@ -110,7 +111,9 @@ var EphemeralSideChatManager = class {
110
111
  createdAt
111
112
  }),
112
113
  config,
113
- runtime
114
+ runtime,
115
+ parentMetadata: structuredClone(metadata),
116
+ parentConfig: structuredClone(parentConfig)
114
117
  };
115
118
  this.entries.set(id, entry);
116
119
  return this.toView(entry);
@@ -127,6 +130,29 @@ var EphemeralSideChatManager = class {
127
130
  entry.messageCount = messages.length;
128
131
  return structuredClone(messages);
129
132
  }
133
+ beginPromotion(id, clientInstanceId) {
134
+ const entry = this.requireEntry(id, clientInstanceId);
135
+ if (entry.status !== "idle") throw new SideChatError("Side chat is busy", "CONFLICT");
136
+ const conversationRows = entry.runtime.loadConversationRows();
137
+ if (entry.runtime.loadConversationMessages().length === 0) throw new SideChatError("Side chat has no messages to save", "INVALID_REQUEST");
138
+ entry.status = "promoting";
139
+ entry.expiresAt = null;
140
+ return structuredClone({
141
+ id: entry.id,
142
+ parentMetadata: entry.parentMetadata,
143
+ parentConfig: entry.parentConfig,
144
+ context: entry.context,
145
+ config: entry.config,
146
+ contextMessages: entry.runtime.loadBaselineMessages(),
147
+ conversationRows
148
+ });
149
+ }
150
+ cancelPromotion(id, clientInstanceId) {
151
+ const entry = this.requireEntry(id, clientInstanceId);
152
+ if (entry.status !== "promoting") return;
153
+ entry.status = "idle";
154
+ this.touchEntry(entry);
155
+ }
130
156
  updateConfig(id, clientInstanceId, patch) {
131
157
  const entry = this.requireEntry(id, clientInstanceId);
132
158
  if (entry.status !== "idle") throw new SideChatError("Cannot change config while a run is active", "CONFLICT");
@@ -162,6 +188,14 @@ var EphemeralSideChatManager = class {
162
188
  this.requireEntry(id, clientInstanceId).clarification = clarification;
163
189
  }
164
190
  async dispose(id, clientInstanceId) {
191
+ const entry = this.entries.get(id);
192
+ if (entry?.clientInstanceId === clientInstanceId && entry.status === "promoting") throw new SideChatError("Side chat is being saved", "CONFLICT");
193
+ return this.disposeEntry(id, clientInstanceId);
194
+ }
195
+ disposePromoted(id, clientInstanceId) {
196
+ return this.disposeEntry(id, clientInstanceId);
197
+ }
198
+ async disposeEntry(id, clientInstanceId) {
165
199
  const entry = this.entries.get(id);
166
200
  if (!entry) {
167
201
  const pending = this.disposals.get(id);
@@ -187,8 +221,8 @@ var EphemeralSideChatManager = class {
187
221
  return cleanup;
188
222
  }
189
223
  async disposeClient(clientInstanceId) {
190
- const ids = [...this.entries.values()].filter((entry) => entry.clientInstanceId === clientInstanceId).map((entry) => entry.id);
191
- await Promise.all(ids.map((id) => this.dispose(id, clientInstanceId)));
224
+ const ids = [...this.entries.values()].filter((entry) => entry.clientInstanceId === clientInstanceId && entry.status !== "promoting").map((entry) => entry.id);
225
+ await Promise.all(ids.map((id) => this.disposeEntry(id, clientInstanceId)));
192
226
  return ids.length;
193
227
  }
194
228
  async sweepExpired(at = this.now()) {
@@ -201,7 +235,7 @@ var EphemeralSideChatManager = class {
201
235
  if (this.sweepTimer) clearInterval(this.sweepTimer);
202
236
  this.stopped = true;
203
237
  const entries = [...this.entries.values()];
204
- await Promise.all(entries.map((entry) => this.dispose(entry.id, entry.clientInstanceId)));
238
+ await Promise.all(entries.map((entry) => this.disposeEntry(entry.id, entry.clientInstanceId)));
205
239
  await Promise.all([...this.disposals.values()].map((entry) => entry.promise));
206
240
  this.expired.clear();
207
241
  }
@@ -229,7 +263,7 @@ var EphemeralSideChatManager = class {
229
263
  removeAt: this.now() + DEFAULT_IDLE_TTL_MS
230
264
  });
231
265
  this.pruneExpiredRecords(this.now());
232
- const cleanup = this.dispose(entry.id, entry.clientInstanceId);
266
+ const cleanup = this.disposeEntry(entry.id, entry.clientInstanceId);
233
267
  try {
234
268
  this.options.onExpired?.(entry.id, entry.clientInstanceId, reason);
235
269
  } catch (err) {
@@ -245,7 +279,7 @@ var EphemeralSideChatManager = class {
245
279
  while (this.expired.size > MAX_EXPIRED_RECORDS) this.expired.delete(this.expired.keys().next().value);
246
280
  }
247
281
  toView(entry) {
248
- const { runtime: _runtime, ...view } = entry;
282
+ const { runtime: _runtime, parentMetadata: _parentMetadata, parentConfig: _parentConfig, ...view } = entry;
249
283
  return structuredClone({
250
284
  ...view,
251
285
  serverNow: new Date(this.now()).toISOString()
@@ -0,0 +1,19 @@
1
+ import type { AgentService } from '../../agent/service.js';
2
+ import type { SessionIndex } from '../../session/manager.js';
3
+ import type { SessionMetadata } from '../../session/types.js';
4
+ import { EphemeralSideChatManager } from './manager.js';
5
+ export interface SideChatPromotionResult {
6
+ conversationId: string;
7
+ created: boolean;
8
+ session: SessionMetadata;
9
+ }
10
+ export interface SideChatPromotionServiceOptions {
11
+ manager: EphemeralSideChatManager;
12
+ sessionIndex: SessionIndex;
13
+ getAgentService: () => AgentService;
14
+ }
15
+ export declare class SideChatPromotionService {
16
+ private readonly options;
17
+ constructor(options: SideChatPromotionServiceOptions);
18
+ promote(sideChatId: string, clientInstanceId: string): Promise<SideChatPromotionResult>;
19
+ }
@@ -0,0 +1,111 @@
1
+ import { createLogger } from "../../utils/logger/index.js";
2
+ import { init_logger } from "../../utils/logger.js";
3
+ import { init_session_context_for_llm, isRuntimeOnlyTranscriptMessage } from "../../session/session-context-for-llm.js";
4
+ import { SideChatError } from "./manager.js";
5
+ //#region src/gateway/side-chat/promotion-service.ts
6
+ init_session_context_for_llm();
7
+ init_logger();
8
+ const log = createLogger("Gateway:SideChatPromotion");
9
+ var SideChatPromotionService = class {
10
+ constructor(options) {
11
+ this.options = options;
12
+ }
13
+ async promote(sideChatId, clientInstanceId) {
14
+ const existing = await this.options.sessionIndex.getSessionMetadata(sideChatId);
15
+ if (existing) {
16
+ if (existing.customData?.promotedFromSideChatId !== sideChatId) throw new SideChatError("A session already uses this side chat id", "CONFLICT");
17
+ return {
18
+ conversationId: sideChatId,
19
+ created: false,
20
+ session: existing
21
+ };
22
+ }
23
+ const snapshot = this.options.manager.beginPromotion(sideChatId, clientInstanceId);
24
+ const parent = snapshot.parentMetadata;
25
+ const agentId = parent.routing?.agentId?.trim() || parent.agentId;
26
+ const chatId = `chat_${sideChatId}`;
27
+ const rows = [{
28
+ type: "side_chat_origin",
29
+ version: 1,
30
+ parentConversationId: snapshot.context.parentConversationId,
31
+ parentTranscriptId: snapshot.context.parentTranscriptId,
32
+ createdAt: snapshot.context.createdAt,
33
+ contentHash: snapshot.context.contentHash,
34
+ contextMessages: snapshot.contextMessages
35
+ }, ...snapshot.conversationRows.filter((row) => !isRuntimeOnlyTranscriptMessage(row))];
36
+ try {
37
+ await this.options.sessionIndex.createSessionFromRows({
38
+ targetKey: sideChatId,
39
+ cwd: parent.cwd || "",
40
+ metadata: {
41
+ agentId,
42
+ sourceChannel: "webchat",
43
+ sourceChatId: `default:direct:${chatId}`,
44
+ sessionType: "chat",
45
+ tags: [...new Set([...parent.tags ?? [], "side-chat"])],
46
+ projectId: parent.projectId,
47
+ parentConversationId: snapshot.context.parentConversationId,
48
+ hiddenFromSessionList: false,
49
+ routing: {
50
+ agentId,
51
+ source: "webchat",
52
+ accountId: "default",
53
+ peerKind: "direct",
54
+ peerId: chatId
55
+ },
56
+ customData: {
57
+ genericNewChatShell: false,
58
+ promotedFromSideChatId: sideChatId,
59
+ promotedFromParentTranscriptId: snapshot.context.parentTranscriptId,
60
+ sideChatContextHash: snapshot.context.contentHash,
61
+ promotedAt: (/* @__PURE__ */ new Date()).toISOString()
62
+ }
63
+ },
64
+ rows,
65
+ config: {
66
+ ...snapshot.parentConfig ?? {},
67
+ modelOverride: snapshot.config.modelRef,
68
+ thinkingLevel: snapshot.config.thinkingLevel
69
+ }
70
+ });
71
+ } catch (error) {
72
+ this.options.manager.cancelPromotion(sideChatId, clientInstanceId);
73
+ throw error;
74
+ }
75
+ const firstUserText = snapshot.conversationRows.find((row) => isAgentMessageWithRole(row, "user"));
76
+ if (firstUserText) try {
77
+ this.options.getAgentService().enqueueProvisionalSessionTitle(sideChatId, messageText(firstUserText));
78
+ } catch (err) {
79
+ log.warn({
80
+ err,
81
+ sideChatId,
82
+ phase: "side_chat_promote_title"
83
+ }, "Saved side chat but title generation could not start");
84
+ }
85
+ await this.options.manager.disposePromoted(sideChatId, clientInstanceId).catch((err) => {
86
+ log.warn({
87
+ err,
88
+ sideChatId,
89
+ phase: "side_chat_promote_cleanup"
90
+ }, "Saved side chat but cleanup failed");
91
+ });
92
+ const session = await this.options.sessionIndex.getSessionMetadata(sideChatId);
93
+ if (!session) throw new Error(`Promoted session not found: ${sideChatId}`);
94
+ return {
95
+ conversationId: sideChatId,
96
+ created: true,
97
+ session
98
+ };
99
+ }
100
+ };
101
+ function isAgentMessageWithRole(row, role) {
102
+ return Boolean(row && typeof row === "object" && row.role === role);
103
+ }
104
+ function messageText(message) {
105
+ const content = message.content;
106
+ if (typeof content === "string") return content.trim();
107
+ if (!Array.isArray(content)) return "";
108
+ return content.filter((part) => Boolean(part && typeof part === "object" && part.type === "text" && typeof part.text === "string")).map((part) => part.text).join("\n").trim();
109
+ }
110
+ //#endregion
111
+ export { SideChatPromotionService };
@@ -16,6 +16,7 @@ var SideChatRunService = class {
16
16
  const text = input.content.trim();
17
17
  if (!text && !input.attachments?.length) throw new SideChatError("content or attachments are required", "INVALID_REQUEST");
18
18
  const sideChat = this.options.manager.get(sideChatId, clientInstanceId);
19
+ if (sideChat.status !== "idle") throw new SideChatError("A side chat run is already active", "CONFLICT");
19
20
  if (this.activeBySideChat.has(sideChatId)) throw new SideChatError("A side chat run is already active", "CONFLICT");
20
21
  const run = {
21
22
  sideChatId,
@@ -1,5 +1,5 @@
1
1
  import type { ThinkingLevel } from '@earendil-works/pi-agent-core';
2
- export type SideChatStatus = 'idle' | 'running' | 'waiting-approval' | 'waiting-input' | 'closing';
2
+ export type SideChatStatus = 'idle' | 'running' | 'waiting-approval' | 'waiting-input' | 'promoting' | 'closing';
3
3
  export type SideChatSelection = {
4
4
  id: string;
5
5
  type: 'message';
@@ -0,0 +1,3 @@
1
+ export declare function shouldCopyLocalAppPath(path: string): boolean;
2
+ export declare function hashLocalAppDirectory(root: string): string;
3
+ export declare function localAppFileHashes(root: string): Map<string, string>;
@@ -0,0 +1,45 @@
1
+ import { basename, join, relative } from "node:path";
2
+ import { readFileSync, readdirSync } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+ //#region src/local-apps/artifact-files.ts
5
+ const EXCLUDED_NAMES = new Set([
6
+ ".git",
7
+ "node_modules",
8
+ ".DS_Store"
9
+ ]);
10
+ function shouldCopyLocalAppPath(path) {
11
+ return !EXCLUDED_NAMES.has(basename(path));
12
+ }
13
+ function hashLocalAppDirectory(root) {
14
+ const hash = createHash("sha256");
15
+ const visit = (dir) => {
16
+ const entries = readdirSync(dir, { withFileTypes: true }).filter((entry) => !EXCLUDED_NAMES.has(entry.name)).toSorted((a, b) => a.name.localeCompare(b.name));
17
+ for (const entry of entries) {
18
+ const path = join(dir, entry.name);
19
+ const relativePath = relative(root, path);
20
+ hash.update(relativePath);
21
+ if (entry.isDirectory()) visit(path);
22
+ else if (entry.isFile()) hash.update(readFileSync(path));
23
+ else throw new Error(`Unsupported local app entry: ${relativePath}`);
24
+ }
25
+ };
26
+ visit(root);
27
+ return hash.digest("hex");
28
+ }
29
+ function localAppFileHashes(root) {
30
+ const hashes = /* @__PURE__ */ new Map();
31
+ const visit = (dir) => {
32
+ const entries = readdirSync(dir, { withFileTypes: true }).filter((entry) => !EXCLUDED_NAMES.has(entry.name)).toSorted((a, b) => a.name.localeCompare(b.name));
33
+ for (const entry of entries) {
34
+ const path = join(dir, entry.name);
35
+ const relativePath = relative(root, path);
36
+ if (entry.isDirectory()) visit(path);
37
+ else if (entry.isFile()) hashes.set(relativePath, createHash("sha256").update(readFileSync(path)).digest("hex"));
38
+ else throw new Error(`Unsupported local app entry: ${relativePath}`);
39
+ }
40
+ };
41
+ visit(root);
42
+ return hashes;
43
+ }
44
+ //#endregion
45
+ export { hashLocalAppDirectory, localAppFileHashes, shouldCopyLocalAppPath };