@xopcai/xopc 0.0.230 → 0.0.232

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 (384) hide show
  1. package/README.md +1 -0
  2. package/README.zh-CN.md +1 -0
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/schema/config-schema.d.ts +3 -3
  5. package/dist/extensions/telegram/src/config-schema.d.ts +4 -4
  6. package/dist/extensions/telegram/xopc.extension.json +1 -1
  7. package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
  8. package/dist/gateway/static/root/assets/{activity-store-M0nAY5XB.js → activity-store-VXCWz43N.js} +1 -1
  9. package/dist/gateway/static/root/assets/agent-avatar-dicebear-BXRaZYW8.js +1 -0
  10. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-dR7HMaRX.js +1 -0
  11. package/dist/gateway/static/root/assets/agents-Bileycwe.js +1 -0
  12. package/dist/gateway/static/root/assets/api-wGPgL8xY.js +1 -0
  13. package/dist/gateway/static/root/assets/{app-management-settings-panel-CwAPK4Jm.js → app-management-settings-panel-BJfClfPx.js} +1 -1
  14. package/dist/gateway/static/root/assets/{appearance-settings-DsGLvqTb.js → appearance-settings-C_R0vUAu.js} +1 -1
  15. package/dist/gateway/static/root/assets/{apps-page-Ee9qOQEx.js → apps-page-CBow8pBI.js} +1 -1
  16. package/dist/gateway/static/root/assets/{archive-plugin-7_DXaMTP.js → archive-plugin-DnFHkSHE.js} +1 -1
  17. package/dist/gateway/static/root/assets/{attachment-load-B4qqigAQ.js → attachment-load-DZrEwytM.js} +1 -1
  18. package/dist/gateway/static/root/assets/{automations-page-B8ImehSW.js → automations-page-DpkKajui.js} +1 -1
  19. package/dist/gateway/static/root/assets/automations-workspace-BBntVWgv.js +6 -0
  20. package/dist/gateway/static/root/assets/{binary-plugins-DaJbyYc2.js → binary-plugins-Ckc_Csue.js} +1 -1
  21. package/dist/gateway/static/root/assets/{block-editor-Kl25XWJc.js → block-editor-DAC6w-iV.js} +4 -4
  22. package/dist/gateway/static/root/assets/browser-settings-page-DrsMd-Po.js +8 -0
  23. package/dist/gateway/static/root/assets/browser-workflow-inputs-BGd7R8GO.js +1 -0
  24. package/dist/gateway/static/root/assets/{browser-workflows-page-DjMxs33B.js → browser-workflows-page-DUfj7ntM.js} +2 -2
  25. package/dist/gateway/static/root/assets/capabilities-settings-panel-97gkGeSV.js +7 -0
  26. package/dist/gateway/static/root/assets/channels-settings-CuBsz8UI.js +1 -0
  27. package/dist/gateway/static/root/assets/{channel-recipient-api-C5ABr73b.js → channels-status-swr-CfboECLt.js} +1 -1
  28. package/dist/gateway/static/root/assets/{chat-terminal-dock-BiU_4Rq6.js → chat-terminal-dock-CA9fndbZ.js} +2 -2
  29. package/dist/gateway/static/root/assets/cloud-C4-yfnnk.js +1 -0
  30. package/dist/gateway/static/root/assets/{code-editor-dFzqyDXS.js → code-editor-D4_k-6QN.js} +1 -1
  31. package/dist/gateway/static/root/assets/connectors-page-SuL7td7Z.js +2 -0
  32. package/dist/gateway/static/root/assets/cron-expression-CqPu7HYJ.js +2 -0
  33. package/dist/gateway/static/root/assets/date-picker-C8dJsCgk.js +1 -0
  34. package/dist/gateway/static/root/assets/dependency-picker-Iz2wYimy.js +1 -0
  35. package/dist/gateway/static/root/assets/{desktop-pet-ux9DxchT.js → desktop-pet-C3h40FmG.js} +1 -1
  36. package/dist/gateway/static/root/assets/{desktop-pet-settings-BVVCBgYK.js → desktop-pet-settings-YfeVVzLe.js} +1 -1
  37. package/dist/gateway/static/root/assets/dist-DqPZM2MH2.js +1 -0
  38. package/dist/gateway/static/root/assets/{extension-debug-page-Dh6DDuvQ.js → extension-debug-page-CChgztz_.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-page-8OKQDEat.js → extension-page-DF6ct6_y.js} +1 -1
  40. package/dist/gateway/static/root/assets/extension-settings-page-jgBsjn0F.js +1 -0
  41. package/dist/gateway/static/root/assets/files-Dp8_uGTO.js +1 -0
  42. package/dist/gateway/static/root/assets/{gateway-config-api-Dlc6eaTG.js → gateway-config-api-CVajuIGL.js} +1 -1
  43. package/dist/gateway/static/root/assets/gateway-config-swr-BGQn8duh.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-settings-DqQgiAUv.js → gateway-settings-BbssNGid.js} +1 -1
  45. package/dist/gateway/static/root/assets/{gateway-startup-retry-B_zrtccP.js → gateway-startup-retry-D2Rnh9fX.js} +1 -1
  46. package/dist/gateway/static/root/assets/heartbeat-settings-CJtXu8iD.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-Be1o1AXQ.js +1 -0
  48. package/dist/gateway/static/root/assets/html-workspace-editor-C3DKAkMc.js +1 -0
  49. package/dist/gateway/static/root/assets/{image-generation-api-YKP2me5Z.js → image-generation-api-D7W2p5_8.js} +1 -1
  50. package/dist/gateway/static/root/assets/index-B2OJSXX9.js +70 -0
  51. package/dist/gateway/static/root/assets/index-rHjAElxG.css +2 -0
  52. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BSFNqxzY.js → keyboard-shortcuts-settings-BvHYyNus.js} +1 -1
  53. package/dist/gateway/static/root/assets/local-app-workbench-page-COfelgk7.js +2 -0
  54. package/dist/gateway/static/root/assets/{local-apps-page-DzU6yZ9-.js → local-apps-page-Cb8t2wWM.js} +1 -1
  55. package/dist/gateway/static/root/assets/locale-store-DLwVxS3V.js +1 -0
  56. package/dist/gateway/static/root/assets/logs-page-DA8oDjeB.js +2 -0
  57. package/dist/gateway/static/root/assets/management-settings-B8Jie4-J.js +1 -0
  58. package/dist/gateway/static/root/assets/markdown-editor-nDLmA_LF.js +2 -0
  59. package/dist/gateway/static/root/assets/markdown-split-BD1r4o2i.js +1 -0
  60. package/dist/gateway/static/root/assets/{markdown-view-DvM5PWEH.js → markdown-view-B-BHEcNd.js} +1 -1
  61. package/dist/gateway/static/root/assets/markdown-view-B1bGSQqt.css +1 -0
  62. package/dist/gateway/static/root/assets/{media-plugins-B8vMe5VX.js → media-plugins-BCev8fkW.js} +1 -1
  63. package/dist/gateway/static/root/assets/messages-Dp1OxSKt.js +3 -0
  64. package/dist/gateway/static/root/assets/mobile-device-api-DACoHhhk.js +1 -0
  65. package/dist/gateway/static/root/assets/models-hub-cache-C8zjqmIv.js +1 -0
  66. package/dist/gateway/static/root/assets/{notes-api-BFsOGYkd.js → notes-api-DEdNKw0I.js} +1 -1
  67. package/dist/gateway/static/root/assets/{notes-page-B-YZ7iuK.js → notes-page-BBTLjJwa.js} +1 -1
  68. package/dist/gateway/static/root/assets/notes-workbench-DICgUGPv.js +4 -0
  69. package/dist/gateway/static/root/assets/oauth-api-BNCO2YK5.js +1 -0
  70. package/dist/gateway/static/root/assets/popover-select-3E24E65N.js +1 -0
  71. package/dist/gateway/static/root/assets/{product-open-page-DkWcyki5.js → product-open-page-fEBbRekH.js} +1 -1
  72. package/dist/gateway/static/root/assets/project-detail-page-CqdkznYJ.js +1 -0
  73. package/dist/gateway/static/root/assets/projects-page-dHDXpMCg.js +1 -0
  74. package/dist/gateway/static/root/assets/{registry-api-BFZrVYfy.js → registry-api-Cvr4Qm7N.js} +1 -1
  75. package/dist/gateway/static/root/assets/remote-access-hub-2feZudJw.js +1 -0
  76. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bq_ETeal.js → runtime-tools-settings-panel-BT5B74IH.js} +2 -2
  77. package/dist/gateway/static/root/assets/{schema-form-BogTlrsP.js → schema-form-C4tB34S5.js} +1 -1
  78. package/dist/gateway/static/root/assets/sessions-page-CO2JCFdy.js +1 -0
  79. package/dist/gateway/static/root/assets/settings-advanced-gate-DxMVaqdn.js +1 -0
  80. package/dist/gateway/static/root/assets/{settings-form-section-Coy1Cbp6.js → settings-form-section-D1oXhkgI.js} +1 -1
  81. package/dist/gateway/static/root/assets/settings-loading-skeleton-CldfX6FJ.js +1 -0
  82. package/dist/gateway/static/root/assets/settings-page-c3LJnbvE.js +1 -0
  83. package/dist/gateway/static/root/assets/settings-shell-layer-context-DCp6ykjQ.js +1 -0
  84. package/dist/gateway/static/root/assets/setup-status-panel-DZNHb6A5.js +1 -0
  85. package/dist/gateway/static/root/assets/share-preview-page-DptCK_mk.js +2 -0
  86. package/dist/gateway/static/root/assets/shares-settings-DakZ2AGN.js +1 -0
  87. package/dist/gateway/static/root/assets/skill-reload-api-BOiNkWJC.js +1 -0
  88. package/dist/gateway/static/root/assets/{skills-page-Brxb6QnW.js → skills-page-OHBeBtSg.js} +1 -1
  89. package/dist/gateway/static/root/assets/{skills-page.utils-FB5LtEGm.js → skills-page.utils-B9WZbOLC.js} +1 -1
  90. package/dist/gateway/static/root/assets/{system-settings-panel-ChosWt8n.js → system-settings-panel-Dj_DpOGw.js} +1 -1
  91. package/dist/gateway/static/root/assets/task-detail-page-D5Nbe3C8.js +1 -0
  92. package/dist/gateway/static/root/assets/theme-store-Cpd3Gd5R.js +1 -0
  93. package/dist/gateway/static/root/assets/{use-autosave-2SqnmSKD.js → use-autosave-DCl5Yq7N.js} +1 -1
  94. package/dist/gateway/static/root/assets/user-context-page-CAPSUK8B.js +1 -0
  95. package/dist/gateway/static/root/assets/{vendor-codemirror-DRr7hFaD.js → vendor-codemirror--gTq3YAI.js} +16 -16
  96. package/dist/gateway/static/root/assets/voice-api-key-field-BB_ZQV8F.js +1 -0
  97. package/dist/gateway/static/root/assets/voice-config-api-BNiYmpl5.js +1 -0
  98. package/dist/gateway/static/root/assets/{work-discovery-overlay-CK3aZDdE.js → work-discovery-overlay-BrIdtdum.js} +1 -1
  99. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BjOuddkX.js → workflow-run-setup-panel-hKh-uCLo.js} +2 -2
  100. package/dist/gateway/static/root/assets/workflows-page-ahDvypGO.js +5 -0
  101. package/dist/gateway/static/root/index.html +19 -15
  102. package/dist/package.js +1 -1
  103. package/dist/src/agent/agent-manager.d.ts +1 -2
  104. package/dist/src/agent/agent-manager.js +29 -44
  105. package/dist/src/agent/background-review/run-background-review.js +10 -15
  106. package/dist/src/agent/embedded/run-for-session.js +1 -1
  107. package/dist/src/agent/external-tools/mcp-provider.js +3 -13
  108. package/dist/src/agent/image/generation/runtime.js +1 -1
  109. package/dist/src/agent/image/tool-model-config.js +13 -14
  110. package/dist/src/agent/mcp/bundle-mcp-policy.d.ts +0 -9
  111. package/dist/src/agent/mcp/bundle-mcp-policy.js +1 -13
  112. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  113. package/dist/src/agent/mcp/index.js +2 -2
  114. package/dist/src/agent/media-generation/runtime-shared.d.ts +1 -1
  115. package/dist/src/agent/media-generation/runtime-shared.js +1 -1
  116. package/dist/src/agent/memory/create-memory-manager.js +1 -1
  117. package/dist/src/agent/memory/manager.d.ts +1 -1
  118. package/dist/src/{agent-runtime/memory-runtime.d.ts → agent/memory/runtime.d.ts} +1 -1
  119. package/dist/src/{agent-runtime/memory-runtime.js → agent/memory/runtime.js} +2 -3
  120. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -3
  121. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -3
  122. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +2 -2
  123. package/dist/src/agent/service.d.ts +1 -0
  124. package/dist/src/agent/service.js +5 -3
  125. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  126. package/dist/src/agent/starter-agents.js +1 -8
  127. package/dist/src/agent/tools/executor.d.ts +1 -1
  128. package/dist/src/agent/tools/workflow-tool.js +1 -5
  129. package/dist/src/agent/tools/write.js +9 -12
  130. package/dist/src/agent/tools/xopc-use-tool.js +2 -2
  131. package/dist/src/agent-config/index.d.ts +2 -0
  132. package/dist/src/agent-config/index.js +11 -0
  133. package/dist/src/agent-config/resolver.d.ts +11 -0
  134. package/dist/src/agent-config/resolver.js +113 -0
  135. package/dist/src/agent-config/schema.d.ts +491 -0
  136. package/dist/src/agent-config/schema.js +172 -0
  137. package/dist/src/auth/oauth/index.js +2 -2
  138. package/dist/src/auth/oauth/registry.d.ts +1 -1
  139. package/dist/src/auth/oauth/registry.js +5 -1
  140. package/dist/src/auth/oauth/xopc-cloud.d.ts +1 -0
  141. package/dist/src/auth/oauth/xopc-cloud.js +8 -2
  142. package/dist/src/chat-commands/builtins/config.js +2 -2
  143. package/dist/src/chat-commands/builtins/review.js +1 -1
  144. package/dist/src/chat-commands/config-paths.js +1 -1
  145. package/dist/src/cli/commands/agents.js +2 -1
  146. package/dist/src/cli/commands/config.js +1 -1
  147. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  148. package/dist/src/cli/commands/doctor/checks/provider-auth.js +12 -4
  149. package/dist/src/cli/commands/image.js +3 -4
  150. package/dist/src/cli/commands/models.js +9 -3
  151. package/dist/src/cli/commands/onboard/model.js +12 -11
  152. package/dist/src/cli/commands/onboard.js +1 -1
  153. package/dist/src/cli/commands/tunnel.js +3 -18
  154. package/dist/src/cli/utils/init-workspace-core.d.ts +1 -1
  155. package/dist/src/cli/utils/init-workspace-core.js +1 -1
  156. package/dist/src/commands/agents.config.d.ts +1 -3
  157. package/dist/src/commands/agents.config.js +9 -26
  158. package/dist/src/config/agent-model-intents.d.ts +10 -0
  159. package/dist/src/config/agent-model-intents.js +39 -0
  160. package/dist/src/config/agent-profile.d.ts +7 -9
  161. package/dist/src/config/agent-profile.js +30 -28
  162. package/dist/src/config/default-model.d.ts +1 -11
  163. package/dist/src/config/default-model.js +3 -11
  164. package/dist/src/config/index.js +3 -3
  165. package/dist/src/config/integration.d.ts +1 -1
  166. package/dist/src/config/reload.js +1 -1
  167. package/dist/src/config/rules.js +3 -3
  168. package/dist/src/config/schema.d.ts +187 -452
  169. package/dist/src/config/schema.js +53 -131
  170. package/dist/src/extensions/activation-context.js +7 -11
  171. package/dist/src/files/file-service.d.ts +36 -0
  172. package/dist/src/files/file-service.js +282 -0
  173. package/dist/src/gateway/agent-builtin-tools.d.ts +250 -6
  174. package/dist/src/gateway/agent-builtin-tools.js +284 -46
  175. package/dist/src/gateway/agents-admin.d.ts +20 -62
  176. package/dist/src/gateway/agents-admin.js +36 -228
  177. package/dist/src/gateway/device-routes.d.ts +3 -0
  178. package/dist/src/gateway/device-routes.js +47 -0
  179. package/dist/src/gateway/global-defaults-admin.d.ts +6 -20
  180. package/dist/src/gateway/global-defaults-admin.js +20 -120
  181. package/dist/src/gateway/heartbeat/service.js +1 -1
  182. package/dist/src/gateway/hono/app.js +6 -4
  183. package/dist/src/gateway/hono/lib/config-payload.d.ts +54 -137
  184. package/dist/src/gateway/hono/lib/config-payload.js +2 -4
  185. package/dist/src/gateway/hono/middleware/auth.js +33 -1
  186. package/dist/src/gateway/hono/middleware/scopes.d.ts +2 -12
  187. package/dist/src/gateway/hono/middleware/scopes.js +9 -18
  188. package/dist/src/gateway/hono/routes/agents.js +64 -100
  189. package/dist/src/gateway/hono/routes/connectors.js +1 -1
  190. package/dist/src/gateway/hono/routes/device-push.d.ts +2 -0
  191. package/dist/src/gateway/hono/routes/{mobile.js → device-push.js} +40 -18
  192. package/dist/src/gateway/hono/routes/devices.d.ts +4 -0
  193. package/dist/src/gateway/hono/routes/devices.js +214 -0
  194. package/dist/src/gateway/hono/routes/files.d.ts +3 -0
  195. package/dist/src/gateway/hono/routes/files.js +176 -0
  196. package/dist/src/gateway/hono/routes/global-defaults.js +5 -9
  197. package/dist/src/gateway/hono/routes/index.js +4 -2
  198. package/dist/src/gateway/hono/routes/lazy-bundles.js +12 -20
  199. package/dist/src/gateway/hono/routes/models.js +2 -2
  200. package/dist/src/gateway/hono/routes/projects.js +0 -508
  201. package/dist/src/gateway/hono/routes/realtime.js +8 -1
  202. package/dist/src/gateway/hono/routes/shares.js +410 -21
  203. package/dist/src/gateway/hono/routes/status.js +9 -16
  204. package/dist/src/gateway/hono/routes/tunnel.d.ts +0 -2
  205. package/dist/src/gateway/hono/routes/tunnel.js +10 -199
  206. package/dist/src/gateway/hono/routes/voice.js +1 -1
  207. package/dist/src/gateway/hono/routes/workspace.js +15 -974
  208. package/dist/src/gateway/image-generation-setup.d.ts +2 -2
  209. package/dist/src/gateway/image-generation-setup.js +8 -7
  210. package/dist/src/gateway/public-url.d.ts +1 -1
  211. package/dist/src/gateway/security/gateway-principal.d.ts +11 -0
  212. package/dist/src/gateway/security/gateway-principal.js +12 -0
  213. package/dist/src/gateway/security/gateway-scopes.d.ts +7 -0
  214. package/dist/src/gateway/security/gateway-scopes.js +66 -0
  215. package/dist/src/gateway/security/index.d.ts +2 -1
  216. package/dist/src/gateway/security/index.js +3 -2
  217. package/dist/src/gateway/service.js +4 -4
  218. package/dist/src/gateway/xopc-cloud-capability-setup.js +19 -21
  219. package/dist/src/heartbeat/index.js +1 -1
  220. package/dist/src/migrations/index.d.ts +0 -1
  221. package/dist/src/migrations/index.js +1 -2
  222. package/dist/src/migrations/runner.js +1 -2
  223. package/dist/src/notifications/device-store.d.ts +1 -1
  224. package/dist/src/notifications/device-store.js +11 -11
  225. package/dist/src/notifications/store.js +3 -3
  226. package/dist/src/providers/index.js +1 -1
  227. package/dist/src/providers/model-reference-auditor.js +14 -9
  228. package/dist/src/realtime/runtime.d.ts +2 -0
  229. package/dist/src/realtime/runtime.js +27 -3
  230. package/dist/src/realtime/tickets.d.ts +6 -1
  231. package/dist/src/realtime/tickets.js +2 -1
  232. package/dist/src/remote-access/exposure-manager.js +3 -3
  233. package/dist/src/share/hosted-session-share.d.ts +104 -0
  234. package/dist/src/share/hosted-session-share.js +276 -0
  235. package/dist/src/share/note-share-service.js +4 -24
  236. package/dist/src/share/session-share-projector.d.ts +31 -0
  237. package/dist/src/share/session-share-projector.js +79 -0
  238. package/dist/src/share/session-share-service.d.ts +89 -0
  239. package/dist/src/share/session-share-service.js +325 -0
  240. package/dist/src/share/share-asset-ticket.d.ts +7 -0
  241. package/dist/src/share/share-asset-ticket.js +30 -0
  242. package/dist/src/share/share-landing.d.ts +4 -3
  243. package/dist/src/share/share-landing.js +5 -5
  244. package/dist/src/share/share-store.d.ts +27 -2
  245. package/dist/src/share/share-store.js +71 -8
  246. package/dist/src/share/share-types.d.ts +17 -2
  247. package/dist/src/share/share-url.js +2 -2
  248. package/dist/src/storage/sqlite/device-access-repository.d.ts +54 -0
  249. package/dist/src/storage/sqlite/device-access-repository.js +194 -0
  250. package/dist/src/storage/sqlite/device-pairing-repository.d.ts +22 -0
  251. package/dist/src/storage/sqlite/device-pairing-repository.js +86 -0
  252. package/dist/src/storage/sqlite/gateway-identity-repository.d.ts +10 -0
  253. package/dist/src/storage/sqlite/gateway-identity-repository.js +50 -0
  254. package/dist/src/storage/sqlite/index.d.ts +3 -0
  255. package/dist/src/storage/sqlite/index.js +4 -1
  256. package/dist/src/storage/sqlite/migrations/138_device_access.sql +96 -0
  257. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  258. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  259. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  260. package/dist/src/storage/sqlite/schema.js +1 -1
  261. package/dist/src/tui/backends/embedded-backend.js +1 -1
  262. package/dist/src/tui/backends/gateway-realtime-backend.js +11 -3
  263. package/dist/src/tunnel/consent.d.ts +1 -1
  264. package/dist/src/tunnel/consent.js +1 -1
  265. package/dist/src/tunnel/gateway-lifecycle.js +1 -1
  266. package/dist/src/tunnel/index.d.ts +1 -4
  267. package/dist/src/tunnel/index.js +3 -5
  268. package/dist/src/tunnel/tunnel-audit.d.ts +1 -1
  269. package/dist/src/tunnel/tunnel-config.js +1 -1
  270. package/dist/src/tunnel/tunnel-service.d.ts +2 -3
  271. package/dist/src/tunnel/tunnel-service.js +1 -20
  272. package/dist/src/tunnel/tunnel-types.d.ts +0 -6
  273. package/dist/src/workflows/draft/workflow-draft-service.js +2 -2
  274. package/dist/src/workflows/service/workflow-run-service.js +3 -3
  275. package/package.json +3 -3
  276. package/dist/gateway/static/root/assets/agent-avatar-dicebear-Bp_wmuGW.js +0 -1
  277. package/dist/gateway/static/root/assets/agents-CKG93dlc.js +0 -68
  278. package/dist/gateway/static/root/assets/api-BywYxpaS.js +0 -1
  279. package/dist/gateway/static/root/assets/automations-workspace-BNFAfNwC.js +0 -6
  280. package/dist/gateway/static/root/assets/browser-settings-page-Cg6NgwE_.js +0 -8
  281. package/dist/gateway/static/root/assets/browser-workflow-inputs-8NC2qDRF.js +0 -1
  282. package/dist/gateway/static/root/assets/capabilities-settings-panel-NvJKgF1u.js +0 -7
  283. package/dist/gateway/static/root/assets/capability-presets-api-o0y9WgAI.js +0 -1
  284. package/dist/gateway/static/root/assets/capability-presets-settings-panel-C2uBdALe.js +0 -3
  285. package/dist/gateway/static/root/assets/channels-settings-CIcYKMEs.js +0 -1
  286. package/dist/gateway/static/root/assets/channels-status-swr-38FsOnR0.js +0 -1
  287. package/dist/gateway/static/root/assets/connectors-page-CEEcmUiP.js +0 -2
  288. package/dist/gateway/static/root/assets/cron-expression-Cs_5pUPT.js +0 -2
  289. package/dist/gateway/static/root/assets/date-picker-y1kWrFVU.js +0 -1
  290. package/dist/gateway/static/root/assets/dependency-picker-skc62zrn.js +0 -1
  291. package/dist/gateway/static/root/assets/directory-picker-path-field-V8vZP0Dy.js +0 -1
  292. package/dist/gateway/static/root/assets/dist-J_ySZvz0.js +0 -1
  293. package/dist/gateway/static/root/assets/extension-settings-page-BgSV0Nny.js +0 -1
  294. package/dist/gateway/static/root/assets/file-code-corner-byQA1VfD.js +0 -1
  295. package/dist/gateway/static/root/assets/gateway-config-swr-BWGjnmDl.js +0 -1
  296. package/dist/gateway/static/root/assets/heartbeat-settings-Pxqk5GFH.js +0 -1
  297. package/dist/gateway/static/root/assets/home-page-1xjo6wE4.js +0 -1
  298. package/dist/gateway/static/root/assets/html-workspace-editor-bXK5tq64.js +0 -1
  299. package/dist/gateway/static/root/assets/index-Bbd_dXui.js +0 -70
  300. package/dist/gateway/static/root/assets/index-D_hrEKXM.css +0 -2
  301. package/dist/gateway/static/root/assets/local-app-workbench-page-heQ4-PJ7.js +0 -2
  302. package/dist/gateway/static/root/assets/locale-store-CXhjfe4q.js +0 -1
  303. package/dist/gateway/static/root/assets/logs-page-BblnS6Jy.js +0 -2
  304. package/dist/gateway/static/root/assets/management-settings-B8hM56HS.js +0 -1
  305. package/dist/gateway/static/root/assets/markdown-editor-TWGaF7Xa.js +0 -2
  306. package/dist/gateway/static/root/assets/markdown-split-DRbZjxMK.js +0 -1
  307. package/dist/gateway/static/root/assets/markdown-view-CLzTdVLW.css +0 -1
  308. package/dist/gateway/static/root/assets/messages-BMdD0LWk.js +0 -3
  309. package/dist/gateway/static/root/assets/notes-workbench-CAM09C8b.js +0 -4
  310. package/dist/gateway/static/root/assets/popover-select-CccGri5Y.js +0 -1
  311. package/dist/gateway/static/root/assets/project-detail-page-BIPIwgU2.js +0 -1
  312. package/dist/gateway/static/root/assets/projects-page-B_kzTn1K.js +0 -1
  313. package/dist/gateway/static/root/assets/remote-access-hub-CtD8DsD-.js +0 -1
  314. package/dist/gateway/static/root/assets/sessions-page-B8n9HI1y.js +0 -1
  315. package/dist/gateway/static/root/assets/settings-advanced-gate-xlhdRTME.js +0 -1
  316. package/dist/gateway/static/root/assets/settings-loading-skeleton-B5GU7iCG.js +0 -1
  317. package/dist/gateway/static/root/assets/settings-page-Dd-BRu12.js +0 -1
  318. package/dist/gateway/static/root/assets/setup-status-panel-CwEFAVWx.js +0 -1
  319. package/dist/gateway/static/root/assets/share-preview-page-DzXw9UQJ.js +0 -2
  320. package/dist/gateway/static/root/assets/shares-settings-Bk6UQOwS.js +0 -1
  321. package/dist/gateway/static/root/assets/skill-reload-api-DrmQZ3Au.js +0 -1
  322. package/dist/gateway/static/root/assets/task-detail-page-CW2sJbdc.js +0 -1
  323. package/dist/gateway/static/root/assets/theme-store-DOdCjyuw.js +0 -1
  324. package/dist/gateway/static/root/assets/typed-models-lib-q5-Vfqd8.js +0 -1
  325. package/dist/gateway/static/root/assets/user-context-page-Bq9KB-Oj.js +0 -1
  326. package/dist/gateway/static/root/assets/voice-api-key-field-DtTIF6M8.js +0 -1
  327. package/dist/gateway/static/root/assets/workflows-page-CcbGEQol.js +0 -5
  328. package/dist/src/agent-manifest/index.d.ts +0 -5
  329. package/dist/src/agent-manifest/index.js +0 -10
  330. package/dist/src/agent-manifest/preset-chain.d.ts +0 -10
  331. package/dist/src/agent-manifest/preset-chain.js +0 -30
  332. package/dist/src/agent-manifest/prompt.d.ts +0 -2
  333. package/dist/src/agent-manifest/prompt.js +0 -49
  334. package/dist/src/agent-manifest/resolver.d.ts +0 -32
  335. package/dist/src/agent-manifest/resolver.js +0 -114
  336. package/dist/src/agent-manifest/schema.d.ts +0 -695
  337. package/dist/src/agent-manifest/schema.js +0 -226
  338. package/dist/src/agent-manifest/validator.d.ts +0 -25
  339. package/dist/src/agent-manifest/validator.js +0 -74
  340. package/dist/src/agent-runtime/boundary-guard.d.ts +0 -12
  341. package/dist/src/agent-runtime/boundary-guard.js +0 -21
  342. package/dist/src/agent-runtime/index.d.ts +0 -7
  343. package/dist/src/agent-runtime/index.js +0 -8
  344. package/dist/src/agent-runtime/model-router.d.ts +0 -11
  345. package/dist/src/agent-runtime/model-router.js +0 -14
  346. package/dist/src/agent-runtime/run-trace.d.ts +0 -27
  347. package/dist/src/agent-runtime/run-trace.js +0 -51
  348. package/dist/src/agent-runtime/runtime-profile.d.ts +0 -26
  349. package/dist/src/agent-runtime/runtime-profile.js +0 -42
  350. package/dist/src/agent-runtime/tool-registry.d.ts +0 -28
  351. package/dist/src/agent-runtime/tool-registry.js +0 -50
  352. package/dist/src/agent-runtime/workflow-runtime.d.ts +0 -31
  353. package/dist/src/agent-runtime/workflow-runtime.js +0 -32
  354. package/dist/src/config/agent-typed-models.d.ts +0 -13
  355. package/dist/src/config/agent-typed-models.js +0 -48
  356. package/dist/src/gateway/capability-presets-admin.d.ts +0 -88
  357. package/dist/src/gateway/capability-presets-admin.js +0 -303
  358. package/dist/src/gateway/file-path-classifier.d.ts +0 -30
  359. package/dist/src/gateway/file-path-classifier.js +0 -105
  360. package/dist/src/gateway/file-reference-errors.d.ts +0 -6
  361. package/dist/src/gateway/file-reference-errors.js +0 -21
  362. package/dist/src/gateway/file-reference-registry.d.ts +0 -34
  363. package/dist/src/gateway/file-reference-registry.js +0 -45
  364. package/dist/src/gateway/hono/lib/agent-model.d.ts +0 -35
  365. package/dist/src/gateway/hono/lib/agent-model.js +0 -97
  366. package/dist/src/gateway/hono/routes/capability-presets.d.ts +0 -3
  367. package/dist/src/gateway/hono/routes/capability-presets.js +0 -187
  368. package/dist/src/gateway/hono/routes/mobile.d.ts +0 -3
  369. package/dist/src/gateway/security/operator-scopes.d.ts +0 -37
  370. package/dist/src/gateway/security/operator-scopes.js +0 -147
  371. package/dist/src/migrations/config/default-capability-preset.d.ts +0 -10
  372. package/dist/src/migrations/config/default-capability-preset.js +0 -133
  373. package/dist/src/tunnel/enable-lan-pairing.d.ts +0 -8
  374. package/dist/src/tunnel/enable-lan-pairing.js +0 -41
  375. package/dist/src/tunnel/pair-context.d.ts +0 -36
  376. package/dist/src/tunnel/pair-context.js +0 -77
  377. package/dist/src/tunnel/pair-url.d.ts +0 -43
  378. package/dist/src/tunnel/pair-url.js +0 -117
  379. package/dist/src/tunnel/pairing-rate-limit.d.ts +0 -12
  380. package/dist/src/tunnel/pairing-rate-limit.js +0 -28
  381. package/dist/src/tunnel/pairing.d.ts +0 -21
  382. package/dist/src/tunnel/pairing.js +0 -103
  383. package/dist/src/tunnel/tunnel-qr.d.ts +0 -9
  384. package/dist/src/tunnel/tunnel-qr.js +0 -29
@@ -1,152 +1,21 @@
1
- import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
2
- import { validateWritePath } from "../../../agent/sandbox/path-policy.js";
3
- import { isPathUnderWorkspace, resolveWorkspaceSafePath, toWorkspaceRelativePosix } from "../../workspace-editor-path.js";
4
- import { getWorkspacePath } from "../../../config/workspace-path-helpers.js";
5
- import { buildFilePathClassifierContext, classifyFileLocation, displayNameForPath, fileRefSessionKeysMatch, resolveFileReferenceCandidate } from "../../file-path-classifier.js";
6
- import { classifyFileReferenceFsError } from "../../file-reference-errors.js";
7
- import { fileReferenceRegistry } from "../../file-reference-registry.js";
8
1
  import { resolveHeartbeatMdPath } from "../../workspace-heartbeat-path.js";
9
2
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
10
- import { runRipgrepInDirectory } from "../../workspace-ripgrep.js";
11
- import { fuzzySearchWorkspaceFiles } from "../../workspace-file-search.js";
12
- import { basename, dirname, join, resolve } from "node:path";
13
- import { constants } from "node:fs";
14
- import { randomUUID } from "node:crypto";
15
- import { copyFile, link, mkdir, readFile, readdir, rename, stat, unlink, writeFile } from "node:fs/promises";
3
+ import { readFile, writeFile } from "node:fs/promises";
16
4
  //#region src/gateway/hono/routes/workspace.ts
17
- init_agent_scope();
18
5
  const log = createGatewayRouteLogger("Workspace");
19
- function isKnownEditorAgentId(cfg, id) {
20
- const n = normalizeAgentId(id);
21
- if (n === resolveDefaultAgentId(cfg)) return true;
22
- return listAgentEntries(cfg).some((e) => normalizeAgentId(e.id) === n);
23
- }
24
- function resolveEditorWorkspaceRoot(cfg, agentIdRaw) {
25
- const trimmed = typeof agentIdRaw === "string" ? agentIdRaw.trim() : "";
26
- if (!trimmed) {
27
- const root = getWorkspacePath(cfg);
28
- if (!root) return {
29
- ok: false,
30
- message: "Workspace not configured"
31
- };
32
- return {
33
- ok: true,
34
- root
35
- };
36
- }
37
- const id = normalizeAgentId(trimmed);
38
- if (!isKnownEditorAgentId(cfg, id)) return {
39
- ok: false,
40
- message: "Unknown agent"
41
- };
42
- return {
43
- ok: true,
44
- root: resolveAgentWorkspaceDir(cfg, id)
45
- };
46
- }
47
- /** Prefer `sessionKey` (per-session workspace override) over `agentId`. */
48
- async function resolveEditorWorkspaceRootAsync(service, cfg, sessionKeyRaw, agentIdRaw) {
49
- const sk = typeof sessionKeyRaw === "string" ? sessionKeyRaw.trim() : "";
50
- if (sk) try {
51
- return {
52
- ok: true,
53
- root: await service.sessions.getEffectiveWorkspacePath(sk)
54
- };
55
- } catch (err) {
56
- const em = err instanceof Error ? err.message : String(err);
57
- log.warn({
58
- err,
59
- sessionKey: sk
60
- }, "Session workspace root resolution failed");
61
- return {
62
- ok: false,
63
- message: em || "Session workspace resolution failed"
64
- };
65
- }
66
- return resolveEditorWorkspaceRoot(cfg, agentIdRaw);
67
- }
68
- function resolveWorkspaceImportConfig(cfg) {
69
- const raw = cfg.workspace?.import;
70
- return {
71
- targetDir: raw?.targetDir?.trim() || "imports",
72
- maxBytes: raw?.maxBytes ?? 104857600,
73
- allowOverwrite: raw?.allowOverwrite ?? true
74
- };
75
- }
76
- /** Strip path separators, NULs and control chars from a basename so it stays in the destination dir. */
77
- function sanitizeImportBasename(name) {
78
- return name.replace(/[\\/]/g, "").replace(/[\x00-\x1f\x7f]/g, "").trim();
79
- }
80
- /**
81
- * Race-safe target picker for the `rename`-on-conflict strategy. Uses `link(tmp, target)`
82
- * which atomically fails with EEXIST when the candidate is taken; on success the tmp
83
- * file is left in place for the caller to unlink. Returns the linked target path.
84
- */
85
- async function pickAvailableTargetWithLink(tmpAbs, initialDestAbs, maxAttempts = 1e3) {
86
- const dir = dirname(initialDestAbs);
87
- const original = basename(initialDestAbs);
88
- const dotIdx = original.lastIndexOf(".");
89
- const stem = dotIdx > 0 ? original.slice(0, dotIdx) : original;
90
- const ext = dotIdx > 0 ? original.slice(dotIdx) : "";
91
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
92
- const candidate = attempt === 1 ? initialDestAbs : join(dir, `${stem}-${attempt}${ext}`);
93
- try {
94
- await link(tmpAbs, candidate);
95
- return {
96
- ok: true,
97
- path: candidate,
98
- attempts: attempt
99
- };
100
- } catch (err) {
101
- if (err?.code !== "EEXIST") throw err;
102
- }
103
- }
104
- return {
105
- ok: false,
106
- attempts: maxAttempts
107
- };
108
- }
109
- function fileReferenceCapabilities(scope, isDirectory, locationKind) {
110
- if (scope === "workspace") return isDirectory ? [
111
- "openExternal",
112
- "revealInFolder",
113
- "copyPath"
114
- ] : [
115
- "preview",
116
- "edit",
117
- "openExternal",
118
- "revealInFolder",
119
- "copyPath"
120
- ];
121
- if (scope === "external" || scope === "agent-profile" || scope === "session-artifact") {
122
- const base = [
123
- "openExternal",
124
- "revealInFolder",
125
- "copyPath"
126
- ];
127
- if (!isDirectory && locationKind !== "xopc-config") base.push("importToWorkspace");
128
- return base;
129
- }
130
- if (scope === "missing") return ["copyPath"];
131
- return [];
132
- }
133
- function isFileReferenceAction(action) {
134
- return action === "openExternal" || action === "revealInFolder";
135
- }
136
6
  function registerWorkspaceRoutes(authenticated, deps) {
137
7
  const { service } = deps;
138
8
  authenticated.get("/api/workspace/heartbeat-md", async (c) => {
139
- const abs = resolveHeartbeatMdPath(service.currentConfig);
140
- if (!abs) return c.json({
9
+ const path = resolveHeartbeatMdPath(service.currentConfig);
10
+ if (!path) return c.json({
141
11
  ok: false,
142
12
  error: { message: "Workspace not configured" }
143
13
  }, 400);
144
14
  try {
145
- const content = await readFile(abs, "utf-8");
146
15
  return c.json({
147
16
  ok: true,
148
17
  payload: {
149
- content,
18
+ content: await readFile(path, "utf8"),
150
19
  file: "HEARTBEAT.md"
151
20
  }
152
21
  });
@@ -161,861 +30,33 @@ function registerWorkspaceRoutes(authenticated, deps) {
161
30
  }
162
31
  });
163
32
  authenticated.put("/api/workspace/heartbeat-md", async (c) => {
164
- const abs = resolveHeartbeatMdPath(service.currentConfig);
165
- if (!abs) return c.json({
33
+ const path = resolveHeartbeatMdPath(service.currentConfig);
34
+ if (!path) return c.json({
166
35
  ok: false,
167
36
  error: { message: "Workspace not configured" }
168
37
  }, 400);
169
- let body;
170
- try {
171
- body = await c.req.json();
172
- } catch {
173
- return c.json({
174
- ok: false,
175
- error: { message: "Invalid JSON" }
176
- }, 400);
177
- }
178
- const content = typeof body === "object" && body !== null && "content" in body && typeof body.content === "string" ? body.content : "";
179
- try {
180
- await writeFile(abs, content, "utf-8");
181
- return c.json({
182
- ok: true,
183
- payload: { file: "HEARTBEAT.md" }
184
- });
185
- } catch (err) {
186
- log.error({
187
- err,
188
- path: abs
189
- }, "Failed to write HEARTBEAT.md");
190
- return c.json({
191
- ok: false,
192
- error: { message: "Write failed" }
193
- }, 500);
194
- }
195
- });
196
- authenticated.get("/api/workspace/editor/list", async (c) => {
197
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
198
- if (ws.ok === false) return c.json({
199
- ok: false,
200
- error: { message: ws.message }
201
- }, 400);
202
- const workspaceRoot = ws.root;
203
- const absDir = resolveWorkspaceSafePath(workspaceRoot, typeof c.req.query("dir") === "string" ? c.req.query("dir") : "");
204
- if (!absDir) return c.json({
205
- ok: false,
206
- error: { message: "Invalid path" }
207
- }, 400);
208
- let st;
209
- try {
210
- st = await stat(absDir);
211
- } catch {
212
- return c.json({
213
- ok: false,
214
- error: { message: "Not found" }
215
- }, 404);
216
- }
217
- if (!st.isDirectory()) return c.json({
218
- ok: false,
219
- error: { message: "Not a directory" }
220
- }, 400);
221
- const dirents = await readdir(absDir, { withFileTypes: true });
222
- const entries = [];
223
- for (const entry of dirents) {
224
- if (entry.name.startsWith(".")) continue;
225
- const fullPath = join(absDir, entry.name);
226
- if (entry.isDirectory()) entries.push({
227
- name: entry.name,
228
- path: toWorkspaceRelativePosix(workspaceRoot, fullPath),
229
- absolutePath: fullPath,
230
- isDirectory: true
231
- });
232
- else entries.push({
233
- name: entry.name,
234
- path: toWorkspaceRelativePosix(workspaceRoot, fullPath),
235
- absolutePath: fullPath,
236
- isDirectory: false
237
- });
238
- }
239
- entries.sort((a, b) => {
240
- if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
241
- return a.name.localeCompare(b.name);
242
- });
243
- return c.json({
244
- ok: true,
245
- payload: {
246
- root: workspaceRoot,
247
- entries
248
- }
249
- });
250
- });
251
- authenticated.get("/api/workspace/editor/read", async (c) => {
252
- const pathRel = typeof c.req.query("path") === "string" ? c.req.query("path") : "";
253
- if (!pathRel.trim()) return c.json({
254
- ok: false,
255
- error: { message: "Missing path" }
256
- }, 400);
257
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
258
- if (ws.ok === false) return c.json({
259
- ok: false,
260
- error: { message: ws.message }
261
- }, 400);
262
- const workspaceRoot = ws.root;
263
- const abs = resolveWorkspaceSafePath(workspaceRoot, pathRel);
264
- if (!abs) return c.json({
265
- ok: false,
266
- error: { message: "Invalid path" }
267
- }, 400);
268
- let st;
269
- try {
270
- st = await stat(abs);
271
- } catch {
272
- return c.json({
273
- ok: false,
274
- error: { message: "Not found" }
275
- }, 404);
276
- }
277
- if (!st.isFile()) return c.json({
278
- ok: false,
279
- error: { message: "Not a file" }
280
- }, 400);
281
- try {
282
- const content = await readFile(abs, "utf-8");
283
- return c.json({
284
- ok: true,
285
- payload: {
286
- content,
287
- path: toWorkspaceRelativePosix(workspaceRoot, abs),
288
- absolutePath: abs,
289
- mtimeMs: st.mtimeMs
290
- }
291
- });
292
- } catch {
293
- return c.json({
294
- ok: false,
295
- error: { message: "Read failed" }
296
- }, 500);
297
- }
298
- });
299
- /** Read file as raw bytes and return base64 (for PDF/images in workspace preview — avoids UTF-8 corruption). */
300
- authenticated.get("/api/workspace/editor/read-base64", async (c) => {
301
- const pathRel = typeof c.req.query("path") === "string" ? c.req.query("path") : "";
302
- if (!pathRel.trim()) return c.json({
303
- ok: false,
304
- error: { message: "Missing path" }
305
- }, 400);
306
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
307
- if (ws.ok === false) return c.json({
308
- ok: false,
309
- error: { message: ws.message }
310
- }, 400);
311
- const workspaceRoot = ws.root;
312
- const abs = resolveWorkspaceSafePath(workspaceRoot, pathRel);
313
- if (!abs) return c.json({
314
- ok: false,
315
- error: { message: "Invalid path" }
316
- }, 400);
317
- let st;
318
- try {
319
- st = await stat(abs);
320
- } catch {
321
- return c.json({
322
- ok: false,
323
- error: { message: "Not found" }
324
- }, 404);
325
- }
326
- if (!st.isFile()) return c.json({
327
- ok: false,
328
- error: { message: "Not a file" }
329
- }, 400);
330
- try {
331
- const buf = await readFile(abs);
332
- return c.json({
333
- ok: true,
334
- payload: {
335
- contentBase64: buf.toString("base64"),
336
- path: toWorkspaceRelativePosix(workspaceRoot, abs),
337
- /** Host absolute path — Electron can open with the default app (shell.openPath). */
338
- absolutePath: abs,
339
- mtimeMs: st.mtimeMs
340
- }
341
- });
342
- } catch {
343
- return c.json({
344
- ok: false,
345
- error: { message: "Read failed" }
346
- }, 500);
347
- }
348
- });
349
- /** Map an absolute host path to a workspace-relative path (if under this session’s workspace). */
350
- authenticated.get("/api/workspace/editor/resolve-path", async (c) => {
351
- const raw = c.req.query("absolutePath");
352
- if (!raw || typeof raw !== "string" || !raw.trim()) return c.json({
353
- ok: false,
354
- error: { message: "Missing absolutePath" }
355
- }, 400);
356
- const absolutePath = raw.trim();
357
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
358
- if (ws.ok === false) return c.json({
359
- ok: false,
360
- error: { message: ws.message }
361
- }, 400);
362
- const workspaceRoot = ws.root;
363
- const normalized = resolve(absolutePath);
364
- if (!isPathUnderWorkspace(workspaceRoot, normalized)) return c.json({
365
- ok: false,
366
- error: { message: "Path not under workspace" }
367
- }, 403);
368
- const rel = toWorkspaceRelativePosix(workspaceRoot, normalized);
369
- return c.json({
370
- ok: true,
371
- payload: { workspaceRelativePath: rel }
372
- });
373
- });
374
- authenticated.get("/api/workspace/editor/resolve-reference", async (c) => {
375
- const rawPath = typeof c.req.query("path") === "string" ? c.req.query("path").trim() : "";
376
- if (!rawPath) return c.json({
377
- ok: false,
378
- error: {
379
- code: "INVALID_PATH",
380
- message: "Missing path"
381
- }
382
- }, 400);
383
- const sessionKey = typeof c.req.query("sessionKey") === "string" ? c.req.query("sessionKey").trim() : "";
384
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, sessionKey, c.req.query("agentId"));
385
- if (ws.ok === false) return c.json({
386
- ok: false,
387
- error: {
388
- code: "WORKSPACE_RESOLUTION_FAILED",
389
- message: ws.message
390
- }
391
- }, 400);
392
- const workspaceRoot = ws.root;
393
- const classifierCtx = {
394
- ...buildFilePathClassifierContext(service.currentConfig, sessionKey),
395
- workspaceRoot
396
- };
397
- const displayName = displayNameForPath(rawPath);
398
- const { candidate, invalid } = await resolveFileReferenceCandidate(rawPath, workspaceRoot, classifierCtx);
399
- if (!candidate || invalid) return c.json({
400
- ok: true,
401
- payload: {
402
- inputPath: rawPath,
403
- displayName,
404
- scope: "invalid",
405
- exists: false,
406
- capabilities: [],
407
- errorCode: "INVALID_PATH"
408
- }
409
- });
410
- let st = null;
411
- let statError = null;
412
- try {
413
- st = await stat(candidate);
414
- } catch (err) {
415
- statError = err;
416
- }
417
- if (!st) {
418
- const failure = classifyFileReferenceFsError(statError);
419
- if (failure.code !== "FILE_NOT_FOUND") {
420
- log.warn({
421
- err: statError,
422
- sessionKey,
423
- workspaceRoot,
424
- candidate,
425
- errorCode: failure.code
426
- }, `Workspace file reference access failed: ${failure.message}`);
427
- return c.json({
428
- ok: false,
429
- error: {
430
- code: failure.code,
431
- message: failure.message
432
- }
433
- }, failure.status === 403 ? 403 : 500);
434
- }
435
- return c.json({
436
- ok: true,
437
- payload: {
438
- inputPath: rawPath,
439
- displayName,
440
- scope: "missing",
441
- exists: false,
442
- absolutePath: candidate,
443
- capabilities: fileReferenceCapabilities("missing", false),
444
- errorCode: "FILE_NOT_FOUND"
445
- }
446
- });
447
- }
448
- const { scope, locationKind, manageRoute } = classifyFileLocation(candidate, classifierCtx);
449
- const inWorkspace = scope === "workspace";
450
- const isDirectory = st.isDirectory();
451
- const capabilities = fileReferenceCapabilities(scope, isDirectory, locationKind);
452
- const ref = fileReferenceRegistry.register({
453
- absolutePath: candidate,
454
- sessionKey: sessionKey || void 0,
455
- scope,
456
- locationKind,
457
- capabilities
458
- });
459
- return c.json({
460
- ok: true,
461
- payload: {
462
- fileRefId: ref.id,
463
- inputPath: rawPath,
464
- displayName,
465
- scope,
466
- locationKind,
467
- manageRoute,
468
- exists: true,
469
- isDirectory,
470
- absolutePath: candidate,
471
- workspaceRelativePath: inWorkspace ? toWorkspaceRelativePosix(workspaceRoot, candidate) : void 0,
472
- capabilities,
473
- mtimeMs: st.mtimeMs
474
- }
475
- });
476
- });
477
- authenticated.post("/api/workspace/file-ref/:id/resolve-action", async (c) => {
478
- const id = c.req.param("id")?.trim() ?? "";
479
- if (!id) return c.json({
480
- ok: false,
481
- error: {
482
- code: "INVALID_FILE_REF",
483
- message: "Missing file reference"
484
- }
485
- }, 400);
486
- const ref = fileReferenceRegistry.resolve(id);
487
- if (!ref) return c.json({
488
- ok: false,
489
- error: {
490
- code: "FILE_REF_EXPIRED",
491
- message: "File reference expired"
492
- }
493
- }, 404);
494
- const sessionKey = typeof c.req.query("sessionKey") === "string" ? c.req.query("sessionKey").trim() : "";
495
- if (!fileRefSessionKeysMatch(ref.sessionKey, sessionKey)) return c.json({
496
- ok: false,
497
- error: {
498
- code: "FILE_REF_FORBIDDEN",
499
- message: "File reference forbidden"
500
- }
501
- }, 403);
502
- const action = (await c.req.json().catch(() => ({}))).action;
503
- if (!isFileReferenceAction(action)) return c.json({
504
- ok: false,
505
- error: {
506
- code: "INVALID_ACTION",
507
- message: "Invalid action"
508
- }
509
- }, 400);
510
- if (!ref.capabilities.includes(action)) return c.json({
511
- ok: false,
512
- error: {
513
- code: "ACTION_NOT_ALLOWED",
514
- message: "Action not allowed"
515
- }
516
- }, 403);
517
- let st;
518
- try {
519
- st = await stat(ref.absolutePath);
520
- } catch {
521
- return c.json({
522
- ok: false,
523
- error: {
524
- code: "FILE_NOT_FOUND",
525
- message: "File not found"
526
- }
527
- }, 404);
528
- }
529
- return c.json({
530
- ok: true,
531
- payload: {
532
- absolutePath: ref.absolutePath,
533
- isDirectory: st.isDirectory()
534
- }
535
- });
536
- });
537
- authenticated.post("/api/workspace/import-file-ref/:id", async (c) => {
538
- const id = c.req.param("id")?.trim() ?? "";
539
- if (!id) return c.json({
540
- ok: false,
541
- error: {
542
- code: "INVALID_FILE_REF",
543
- message: "Missing file reference"
544
- }
545
- }, 400);
546
- const ref = fileReferenceRegistry.resolve(id);
547
- if (!ref) return c.json({
548
- ok: false,
549
- error: {
550
- code: "FILE_REF_EXPIRED",
551
- message: "File reference expired"
552
- }
553
- }, 404);
554
- const sessionKey = typeof c.req.query("sessionKey") === "string" ? c.req.query("sessionKey").trim() : "";
555
- if (!fileRefSessionKeysMatch(ref.sessionKey, sessionKey)) return c.json({
556
- ok: false,
557
- error: {
558
- code: "FILE_REF_FORBIDDEN",
559
- message: "File reference forbidden"
560
- }
561
- }, 403);
562
- if (!ref.capabilities.includes("importToWorkspace")) return c.json({
563
- ok: false,
564
- error: {
565
- code: "IMPORT_NOT_ALLOWED",
566
- message: "Import not allowed for this file"
567
- }
568
- }, 403);
569
- let sourceStat;
570
- try {
571
- sourceStat = await stat(ref.absolutePath);
572
- } catch {
573
- fileReferenceRegistry.expireById(id);
574
- return c.json({
575
- ok: false,
576
- error: {
577
- code: "SOURCE_NOT_FOUND",
578
- message: "Source file no longer exists"
579
- }
580
- }, 404);
581
- }
582
- if (!sourceStat.isFile()) return c.json({
583
- ok: false,
584
- error: {
585
- code: "SOURCE_NOT_FILE",
586
- message: "Source is not a regular file"
587
- }
588
- }, 400);
589
- const importCfg = resolveWorkspaceImportConfig(service.currentConfig);
590
- if (sourceStat.size > importCfg.maxBytes) return c.json({
591
- ok: false,
592
- error: {
593
- code: "SOURCE_TOO_LARGE",
594
- message: `Source exceeds maximum import size (${importCfg.maxBytes} bytes)`
595
- }
596
- }, 413);
597
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, sessionKey, void 0);
598
- if (ws.ok === false) return c.json({
599
- ok: false,
600
- error: {
601
- code: "WORKSPACE_RESOLUTION_FAILED",
602
- message: ws.message
603
- }
604
- }, 400);
605
- const workspaceRoot = ws.root;
606
- let body;
607
- try {
608
- body = await c.req.json().catch(() => ({}));
609
- } catch {
610
- body = {};
611
- }
612
- const requestedDestRaw = typeof body.destination === "string" ? body.destination.trim() : "";
613
- const onConflictRaw = typeof body.onConflict === "string" ? body.onConflict : "rename";
614
- if (onConflictRaw !== "rename" && onConflictRaw !== "overwrite" && onConflictRaw !== "error") return c.json({
615
- ok: false,
616
- error: {
617
- code: "INVALID_CONFLICT_MODE",
618
- message: "Invalid onConflict value"
619
- }
620
- }, 400);
621
- const onConflict = onConflictRaw;
622
- if (onConflict === "overwrite" && !importCfg.allowOverwrite) return c.json({
623
- ok: false,
624
- error: {
625
- code: "OVERWRITE_DISABLED",
626
- message: "Overwrite is disabled by config"
627
- }
628
- }, 403);
629
- const sourceBasename = sanitizeImportBasename(basename(ref.absolutePath)) || "imported-file";
630
- let requestedRel;
631
- if (!requestedDestRaw) requestedRel = `${importCfg.targetDir}/${sourceBasename}`;
632
- else {
633
- const trimmedDest = requestedDestRaw.replace(/\\/g, "/");
634
- requestedRel = trimmedDest.endsWith("/") ? `${trimmedDest}${sourceBasename}` : trimmedDest;
635
- }
636
- let initialDestAbs = resolveWorkspaceSafePath(workspaceRoot, requestedRel);
637
- if (!initialDestAbs) return c.json({
38
+ const body = await c.req.json().catch(() => null);
39
+ if (!body || typeof body.content !== "string") return c.json({
638
40
  ok: false,
639
- error: {
640
- code: "INVALID_DESTINATION",
641
- message: "Invalid destination path"
642
- }
41
+ error: { message: "content is required" }
643
42
  }, 400);
644
- const writePolicy = validateWritePath(initialDestAbs, workspaceRoot);
645
- if (!writePolicy.allowed) return c.json({
646
- ok: false,
647
- error: {
648
- code: "DESTINATION_BLOCKED",
649
- message: writePolicy.reason ?? "Destination blocked"
650
- }
651
- }, 403);
652
- if (resolve(ref.absolutePath) === resolve(initialDestAbs)) return c.json({
653
- ok: false,
654
- error: {
655
- code: "SAME_LOCATION",
656
- message: "Destination is the same as source"
657
- }
658
- }, 400);
659
- const destDir = dirname(initialDestAbs);
660
43
  try {
661
- await mkdir(destDir, { recursive: true });
662
- } catch (err) {
663
- log.warn({
664
- err,
665
- destDir
666
- }, "Failed to create import destination directory");
667
- return c.json({
668
- ok: false,
669
- error: {
670
- code: "IMPORT_FAILED",
671
- message: "Failed to prepare destination"
672
- }
673
- }, 500);
674
- }
675
- const tmpAbs = join(destDir, `.${basename(initialDestAbs)}.import-${randomUUID()}.tmp`);
676
- const started = Date.now();
677
- let renamed = false;
678
- let overwrote = false;
679
- let finalDestAbs = initialDestAbs;
680
- try {
681
- try {
682
- await copyFile(ref.absolutePath, tmpAbs, constants.COPYFILE_FICLONE);
683
- } catch (err) {
684
- await unlink(tmpAbs).catch(() => {});
685
- log.warn({
686
- err,
687
- source: ref.absolutePath,
688
- tmpAbs
689
- }, "Failed to copy source into staging tmp");
690
- return c.json({
691
- ok: false,
692
- error: {
693
- code: "IMPORT_FAILED",
694
- message: "Failed to copy source file"
695
- }
696
- }, 500);
697
- }
698
- if (onConflict === "overwrite") {
699
- overwrote = await stat(initialDestAbs).then(() => true).catch(() => false);
700
- try {
701
- await rename(tmpAbs, initialDestAbs);
702
- } catch (err) {
703
- await unlink(tmpAbs).catch(() => {});
704
- log.warn({
705
- err,
706
- target: initialDestAbs
707
- }, "Atomic rename failed");
708
- return c.json({
709
- ok: false,
710
- error: {
711
- code: "IMPORT_FAILED",
712
- message: "Failed to finalize import"
713
- }
714
- }, 500);
715
- }
716
- } else if (onConflict === "error") {
717
- if (await stat(initialDestAbs).then(() => true).catch(() => false)) {
718
- await unlink(tmpAbs).catch(() => {});
719
- return c.json({
720
- ok: false,
721
- error: {
722
- code: "DESTINATION_EXISTS",
723
- message: "Destination already exists"
724
- }
725
- }, 409);
726
- }
727
- try {
728
- await link(tmpAbs, initialDestAbs);
729
- await unlink(tmpAbs).catch(() => {});
730
- } catch (err) {
731
- await unlink(tmpAbs).catch(() => {});
732
- log.warn({
733
- err,
734
- target: initialDestAbs
735
- }, "Hard link to destination failed");
736
- return c.json({
737
- ok: false,
738
- error: {
739
- code: "IMPORT_FAILED",
740
- message: "Failed to finalize import"
741
- }
742
- }, 500);
743
- }
744
- } else {
745
- const picked = await pickAvailableTargetWithLink(tmpAbs, initialDestAbs);
746
- if (!picked.ok) {
747
- await unlink(tmpAbs).catch(() => {});
748
- log.warn({
749
- target: initialDestAbs,
750
- attempts: picked.attempts
751
- }, "Failed to find free import target name");
752
- return c.json({
753
- ok: false,
754
- error: {
755
- code: "IMPORT_FAILED",
756
- message: "No free destination name available"
757
- }
758
- }, 500);
759
- }
760
- await unlink(tmpAbs).catch(() => {});
761
- finalDestAbs = picked.path;
762
- renamed = picked.path !== initialDestAbs;
763
- }
764
- } catch (err) {
765
- await unlink(tmpAbs).catch(() => {});
766
- log.error({ err }, "Import file unexpected failure");
767
- return c.json({
768
- ok: false,
769
- error: {
770
- code: "IMPORT_FAILED",
771
- message: "Import failed"
772
- }
773
- }, 500);
774
- }
775
- let finalMtime;
776
- try {
777
- finalMtime = (await stat(finalDestAbs)).mtimeMs;
778
- } catch {
779
- finalMtime = Date.now();
780
- }
781
- const workspaceRel = toWorkspaceRelativePosix(workspaceRoot, finalDestAbs);
782
- fileReferenceRegistry.expireById(id);
783
- const newRef = fileReferenceRegistry.register({
784
- absolutePath: finalDestAbs,
785
- sessionKey: sessionKey || void 0,
786
- scope: "workspace",
787
- capabilities: fileReferenceCapabilities("workspace", false)
788
- });
789
- const sourceScope = ref.scope;
790
- const sourceLocationKind = ref.locationKind;
791
- service.emit("workspace.file-imported", {
792
- sessionKey: sessionKey || void 0,
793
- workspaceRelativePath: workspaceRel,
794
- absolutePath: finalDestAbs,
795
- bytes: sourceStat.size,
796
- sourceScope,
797
- sourceLocationKind
798
- });
799
- log.info({
800
- sessionKey,
801
- fileRefId: id,
802
- sourceAbsolutePath: ref.absolutePath,
803
- sourceScope,
804
- sourceLocationKind,
805
- destWorkspaceRelativePath: workspaceRel,
806
- bytes: sourceStat.size,
807
- renamed,
808
- overwrote,
809
- durationMs: Date.now() - started
810
- }, "Workspace file import succeeded");
811
- return c.json({
812
- ok: true,
813
- payload: {
814
- workspaceRelativePath: workspaceRel,
815
- absolutePath: finalDestAbs,
816
- bytesCopied: sourceStat.size,
817
- sourceAbsolutePath: ref.absolutePath,
818
- sourceScope,
819
- sourceLocationKind,
820
- renamed,
821
- overwrote,
822
- mtimeMs: finalMtime,
823
- newFileRefId: newRef.id
824
- }
825
- });
826
- });
827
- /**
828
- * Serve a workspace file as raw bytes (e.g. <img> after auth fetch + blob URL).
829
- * Path is workspace-relative; scope via sessionKey / agentId like other editor routes.
830
- */
831
- authenticated.get("/api/workspace/editor/raw", async (c) => {
832
- const pathRel = typeof c.req.query("path") === "string" ? c.req.query("path") : "";
833
- if (!pathRel.trim()) return c.json({
834
- ok: false,
835
- error: { message: "Missing path" }
836
- }, 400);
837
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
838
- if (ws.ok === false) return c.json({
839
- ok: false,
840
- error: { message: ws.message }
841
- }, 400);
842
- const workspaceRoot = ws.root;
843
- const abs = resolveWorkspaceSafePath(workspaceRoot, pathRel);
844
- if (!abs) return c.json({
845
- ok: false,
846
- error: { message: "Invalid path" }
847
- }, 400);
848
- let st;
849
- try {
850
- st = await stat(abs);
851
- } catch {
852
- return c.json({
853
- ok: false,
854
- error: { message: "Not found" }
855
- }, 404);
856
- }
857
- if (!st.isFile()) return c.json({
858
- ok: false,
859
- error: { message: "Not a file" }
860
- }, 400);
861
- const contentType = {
862
- png: "image/png",
863
- jpg: "image/jpeg",
864
- jpeg: "image/jpeg",
865
- gif: "image/gif",
866
- webp: "image/webp",
867
- bmp: "image/bmp",
868
- svg: "image/svg+xml",
869
- pdf: "application/pdf",
870
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
871
- xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
872
- pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
873
- txt: "text/plain",
874
- md: "text/markdown",
875
- json: "application/json",
876
- html: "text/html",
877
- css: "text/css",
878
- js: "text/javascript",
879
- ts: "text/typescript",
880
- mp3: "audio/mpeg",
881
- wav: "audio/wav",
882
- ogg: "audio/ogg",
883
- webm: "video/webm",
884
- mp4: "video/mp4",
885
- mov: "video/quicktime"
886
- }[pathRel.split(".").pop()?.toLowerCase() ?? ""] || "application/octet-stream";
887
- try {
888
- const buf = await readFile(abs);
889
- return new Response(buf, { headers: {
890
- "Content-Type": contentType,
891
- "Cache-Control": "private, max-age=3600"
892
- } });
893
- } catch {
894
- return c.json({
895
- ok: false,
896
- error: { message: "Read failed" }
897
- }, 500);
898
- }
899
- });
900
- authenticated.put("/api/workspace/editor/write", async (c) => {
901
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
902
- if (ws.ok === false) return c.json({
903
- ok: false,
904
- error: { message: ws.message }
905
- }, 400);
906
- const workspaceRoot = ws.root;
907
- let body;
908
- try {
909
- body = await c.req.json();
910
- } catch {
911
- return c.json({
912
- ok: false,
913
- error: { message: "Invalid JSON" }
914
- }, 400);
915
- }
916
- const pathRel = typeof body === "object" && body !== null && "path" in body && typeof body.path === "string" ? body.path : "";
917
- const content = typeof body === "object" && body !== null && "content" in body && typeof body.content === "string" ? body.content : "";
918
- if (!pathRel.trim()) return c.json({
919
- ok: false,
920
- error: { message: "Missing path" }
921
- }, 400);
922
- const abs = resolveWorkspaceSafePath(workspaceRoot, pathRel);
923
- if (!abs) return c.json({
924
- ok: false,
925
- error: { message: "Invalid path" }
926
- }, 400);
927
- let st;
928
- try {
929
- st = await stat(abs);
930
- } catch {
931
- st = void 0;
932
- }
933
- if (st && !st.isFile()) return c.json({
934
- ok: false,
935
- error: { message: "Not a file" }
936
- }, 400);
937
- try {
938
- await writeFile(abs, content, "utf-8");
939
- let mtimeMs;
940
- try {
941
- mtimeMs = (await stat(abs)).mtimeMs;
942
- } catch {
943
- mtimeMs = Date.now();
944
- }
44
+ await writeFile(path, body.content, "utf8");
945
45
  return c.json({
946
46
  ok: true,
947
- payload: {
948
- path: toWorkspaceRelativePosix(workspaceRoot, abs),
949
- mtimeMs
950
- }
47
+ payload: { file: "HEARTBEAT.md" }
951
48
  });
952
- } catch (err) {
49
+ } catch (error) {
953
50
  log.error({
954
- err,
955
- path: abs
956
- }, "workspace editor write failed");
51
+ err: error,
52
+ path
53
+ }, "Failed to write HEARTBEAT.md");
957
54
  return c.json({
958
55
  ok: false,
959
56
  error: { message: "Write failed" }
960
57
  }, 500);
961
58
  }
962
59
  });
963
- authenticated.get("/api/workspace/editor/search", async (c) => {
964
- const q = typeof c.req.query("q") === "string" ? c.req.query("q").trim() : "";
965
- const dirRel = typeof c.req.query("dir") === "string" ? c.req.query("dir") : "";
966
- if (!q) return c.json({
967
- ok: true,
968
- payload: { results: [] }
969
- });
970
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
971
- if (ws.ok === false) return c.json({
972
- ok: false,
973
- error: { message: ws.message }
974
- }, 400);
975
- const workspaceRoot = ws.root;
976
- const absDir = resolveWorkspaceSafePath(workspaceRoot, dirRel);
977
- if (!absDir) return c.json({
978
- ok: false,
979
- error: { message: "Invalid path" }
980
- }, 400);
981
- let st;
982
- try {
983
- st = await stat(absDir);
984
- } catch {
985
- return c.json({
986
- ok: false,
987
- error: { message: "Not found" }
988
- }, 404);
989
- }
990
- if (!st.isDirectory()) return c.json({
991
- ok: false,
992
- error: { message: "Not a directory" }
993
- }, 400);
994
- const results = (await runRipgrepInDirectory(q, absDir)).filter((r) => isPathUnderWorkspace(workspaceRoot, r.filePath)).map((r) => ({
995
- ...r,
996
- filePath: toWorkspaceRelativePosix(workspaceRoot, resolve(r.filePath))
997
- }));
998
- return c.json({
999
- ok: true,
1000
- payload: { results }
1001
- });
1002
- });
1003
- /** Fuzzy filename / path search over the session workspace (ripgrep `--files` + subsequence scoring). */
1004
- authenticated.get("/api/workspace/editor/files/search", async (c) => {
1005
- const q = typeof c.req.query("q") === "string" ? c.req.query("q").trim() : "";
1006
- const limitRaw = c.req.query("limit");
1007
- const limit = Math.min(Math.max(parseInt(typeof limitRaw === "string" ? limitRaw : "15", 10) || 15, 1), 50);
1008
- const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
1009
- if (ws.ok === false) return c.json({
1010
- ok: false,
1011
- error: { message: ws.message }
1012
- }, 400);
1013
- const entries = await fuzzySearchWorkspaceFiles(ws.root, q, limit);
1014
- return c.json({
1015
- ok: true,
1016
- payload: { entries }
1017
- });
1018
- });
1019
60
  }
1020
61
  //#endregion
1021
62
  export { registerWorkspaceRoutes };