@xopcai/xopc 0.0.118 → 0.0.119

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 (468) hide show
  1. package/README.md +2 -1
  2. package/README.zh-CN.md +2 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dzUrQoeZ.js → agent-avatar-dicebear-CU8J6zou.js} +1 -1
  6. package/dist/gateway/static/root/assets/agents-B0hkpLhP.js +2 -0
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-B9vfYoEr.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-ClOzIO24.js +1 -0
  9. package/dist/gateway/static/root/assets/{apps-page--wMEL00f.js → apps-page-DU0dz9Zo.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-Cki4SfU2.js → archive-plugin-BkVIgZzA.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-D-KnS2Do.js → attachment-load-CaCMWh1D.js} +1 -1
  12. package/dist/gateway/static/root/assets/automation-suggestion-card-DhGDpKP3.js +1 -0
  13. package/dist/gateway/static/root/assets/automations-page-CTedroVo.js +1 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-D2sgvJja.js → binary-plugins-B4TO_bsn.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-DIq-4Gvb.js → block-editor-DJRWwWNI.js} +28 -28
  16. package/dist/gateway/static/root/assets/browser-settings-page-FCDwOOBK.js +8 -0
  17. package/dist/gateway/static/root/assets/capability-presets-api-Befi89CL.js +1 -0
  18. package/dist/gateway/static/root/assets/capability-presets-settings-panel-_G8eb2vJ.js +1 -0
  19. package/dist/gateway/static/root/assets/channel-recipient-api-BNSuJb5f.js +1 -0
  20. package/dist/gateway/static/root/assets/channels-settings-C3d5JBJX.js +1 -0
  21. package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +1 -0
  22. package/dist/gateway/static/root/assets/connectors-page-yaUNvt5u.js +2 -0
  23. package/dist/gateway/static/root/assets/cron-expression-B3B1eqnr.js +2 -0
  24. package/dist/gateway/static/root/assets/dreaming-settings-DNrdg1Ve.js +1 -0
  25. package/dist/gateway/static/root/assets/{extension-debug-page-DYu1KaFQ.js → extension-debug-page-DYh402XV.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-B3W6QwlZ.js → extension-page-Cr_TizrN.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-D7VQ-cxE.js → extension-settings-page-BU1KoKRj.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-B7xDPu-R.js → fetch-Y7AEX4H3.js} +1 -1
  29. package/dist/gateway/static/root/assets/format-cron-label-arqgGlVV.js +1 -0
  30. package/dist/gateway/static/root/assets/{gateway-config-api-BTBLSeUu.js → gateway-config-api-RbMmAOpX.js} +1 -1
  31. package/dist/gateway/static/root/assets/gateway-settings-C79wkXef.js +1 -0
  32. package/dist/gateway/static/root/assets/{gateway-startup-retry-CYj9FWCp.js → gateway-startup-retry-DiD_Tx4N.js} +1 -1
  33. package/dist/gateway/static/root/assets/goal-detail-page-9paXuHdo.js +1 -0
  34. package/dist/gateway/static/root/assets/{goals-config-api-CQQgzPr3.js → goals-config-api-DqxVi0p5.js} +1 -1
  35. package/dist/gateway/static/root/assets/{goals-page-BHitvJAv.js → goals-page-CS0R-Af2.js} +2 -2
  36. package/dist/gateway/static/root/assets/goals-settings-CSuzZ8Ae.js +1 -0
  37. package/dist/gateway/static/root/assets/heartbeat-settings-DXPaYJm3.js +1 -0
  38. package/dist/gateway/static/root/assets/index-BoKafJIZ.js +191 -0
  39. package/dist/gateway/static/root/assets/index-CArhCcYn.css +1 -0
  40. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-Dvg53qnd.js +1 -0
  41. package/dist/gateway/static/root/assets/{logs-page-C2Uqvae9.js → logs-page-DLXPcksQ.js} +2 -2
  42. package/dist/gateway/static/root/assets/{markdown-split-BwOFrJ2E.js → markdown-split-CpHxbtWJ.js} +1 -1
  43. package/dist/gateway/static/root/assets/{media-plugins-Cnz6Q5G6.js → media-plugins-SFPQRSxq.js} +1 -1
  44. package/dist/gateway/static/root/assets/messages-CrDHEbss.js +3 -0
  45. package/dist/gateway/static/root/assets/models-hub-panel-BDF2iyRk.js +2 -0
  46. package/dist/gateway/static/root/assets/note-detail-page-CSb_hwig.js +2 -0
  47. package/dist/gateway/static/root/assets/{note-image-lightbox-B-Svpmza.js → note-image-lightbox-BUYURRgn.js} +1 -1
  48. package/dist/gateway/static/root/assets/notes-page-BsIBSFyZ.js +1 -0
  49. package/dist/gateway/static/root/assets/{preview-open-alternatives-Bss4TiwP.js → preview-open-alternatives-BHz9iWYA.js} +1 -1
  50. package/dist/gateway/static/root/assets/remote-access-hub-CwzSovcS.js +1 -0
  51. package/dist/gateway/static/root/assets/{save-bar-controls-BRNjdgKq.js → save-bar-controls-CefkOlRg.js} +1 -1
  52. package/dist/gateway/static/root/assets/schedule-field-CmTRoOcE.js +1 -0
  53. package/dist/gateway/static/root/assets/{schema-form-Dub9sy8r.js → schema-form-FMKv1vGu.js} +1 -1
  54. package/dist/gateway/static/root/assets/sessions-page-PHmX-NmA.js +1 -0
  55. package/dist/gateway/static/root/assets/settings-advanced-gate-BRAeKJN4.js +1 -0
  56. package/dist/gateway/static/root/assets/{settings-collapsible-section-BeFLavGi.js → settings-collapsible-section-BouO6JTi.js} +1 -1
  57. package/dist/gateway/static/root/assets/{settings-form-section-dmyaPOTG.js → settings-form-section-D-4lBl6X.js} +1 -1
  58. package/dist/gateway/static/root/assets/settings-page-KKrbFjy8.js +1 -0
  59. package/dist/gateway/static/root/assets/settings-page-layout-BJ4Gsef5.js +1 -0
  60. package/dist/gateway/static/root/assets/setup-status-panel-CrUjHPQo.js +1 -0
  61. package/dist/gateway/static/root/assets/{share-preview-page-C8glrdqe.js → share-preview-page-BDy2btRN.js} +1 -1
  62. package/dist/gateway/static/root/assets/shares-settings-B18OBmH5.js +1 -0
  63. package/dist/gateway/static/root/assets/skill-reload-api-C28-2uKQ.js +1 -0
  64. package/dist/gateway/static/root/assets/skills-page-Bm2ebkwl.js +2 -0
  65. package/dist/gateway/static/root/assets/system-settings-panel-CRngrlnZ.js +1 -0
  66. package/dist/gateway/static/root/assets/typed-models-lib-BltBc0b-.js +1 -0
  67. package/dist/gateway/static/root/assets/{use-channel-catalog-DqlWTsDb.js → use-channel-catalog-CjN-51e6.js} +1 -1
  68. package/dist/gateway/static/root/assets/user-profile-settings-panel-DJ1dKwZy.js +1 -0
  69. package/dist/gateway/static/root/assets/utils-B5M5-YvK.js +1 -0
  70. package/dist/gateway/static/root/assets/{voice-api-key-field-C73IVZeC.js → voice-api-key-field-CeEevm7z.js} +1 -1
  71. package/dist/gateway/static/root/assets/{voice-player-store-C_ArLJPM.js → voice-player-store-B7ykUlHM.js} +1 -1
  72. package/dist/gateway/static/root/assets/workflow-run-setup-panel-C4PzUQjB.js +3 -0
  73. package/dist/gateway/static/root/assets/workflows-page-BL84_-Ky.js +18 -0
  74. package/dist/gateway/static/root/index.html +6 -7
  75. package/dist/package.js +1 -1
  76. package/dist/src/agent/agent-manager.d.ts +4 -5
  77. package/dist/src/agent/agent-manager.js +4 -8
  78. package/dist/src/agent/agent-manager.js.map +1 -1
  79. package/dist/src/agent/embedded/run-for-session.js +102 -14
  80. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  81. package/dist/src/agent/fallback/candidates.d.ts +0 -8
  82. package/dist/src/agent/fallback/candidates.js.map +1 -1
  83. package/dist/src/agent/index.js +1 -1
  84. package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -3
  85. package/dist/src/agent/lifecycle/handlers/compaction.js +1 -16
  86. package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
  87. package/dist/src/agent/lifecycle/progress.d.ts +0 -1
  88. package/dist/src/agent/lifecycle/progress.js +1 -6
  89. package/dist/src/agent/lifecycle/progress.js.map +1 -1
  90. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -2
  91. package/dist/src/agent/lifecycle/timeout-wrapper.js +1 -7
  92. package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
  93. package/dist/src/agent/middleware/self-verify.d.ts +0 -1
  94. package/dist/src/agent/middleware/self-verify.js +0 -2
  95. package/dist/src/agent/middleware/self-verify.js.map +1 -1
  96. package/dist/src/agent/models/index.d.ts +1 -1
  97. package/dist/src/agent/models/manager.d.ts +4 -20
  98. package/dist/src/agent/models/manager.js +9 -126
  99. package/dist/src/agent/models/manager.js.map +1 -1
  100. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
  101. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -9
  102. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  103. package/dist/src/agent/prompt/sections/tooling.js +2 -2
  104. package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
  105. package/dist/src/agent/prompt/service-prompt-builder.d.ts +0 -1
  106. package/dist/src/agent/prompt/service-prompt-builder.js +0 -12
  107. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  108. package/dist/src/agent/prompt/subagent-context.js +1 -1
  109. package/dist/src/agent/prompt/subagent-context.js.map +1 -1
  110. package/dist/src/agent/prompt/types.d.ts +1 -1
  111. package/dist/src/agent/service.d.ts +1 -9
  112. package/dist/src/agent/service.js +3 -40
  113. package/dist/src/agent/service.js.map +1 -1
  114. package/dist/src/agent/service.types.d.ts +2 -2
  115. package/dist/src/agent/session/session-config-service.d.ts +11 -11
  116. package/dist/src/agent/session/session-config-service.js +14 -14
  117. package/dist/src/agent/session/session-config-service.js.map +1 -1
  118. package/dist/src/agent/session/session-inspector.js +3 -2
  119. package/dist/src/agent/session/session-inspector.js.map +1 -1
  120. package/dist/src/agent/starter-agents.js +12 -12
  121. package/dist/src/agent/starter-agents.js.map +1 -1
  122. package/dist/src/agent/tools/automation-tool.d.ts +14 -0
  123. package/dist/src/agent/tools/automation-tool.js +102 -0
  124. package/dist/src/agent/tools/automation-tool.js.map +1 -0
  125. package/dist/src/agent/tools/delegate-tool.js +1 -1
  126. package/dist/src/agent/tools/delegate-tool.js.map +1 -1
  127. package/dist/src/agent/tools/factory.d.ts +3 -3
  128. package/dist/src/agent/tools/factory.js +2 -2
  129. package/dist/src/agent/tools/factory.js.map +1 -1
  130. package/dist/src/agent/tools/index.d.ts +1 -1
  131. package/dist/src/agent/tools/index.js +2 -2
  132. package/dist/src/agent-manifest/resolver.d.ts +1 -0
  133. package/dist/src/agent-manifest/resolver.js +1 -0
  134. package/dist/src/agent-manifest/resolver.js.map +1 -1
  135. package/dist/src/agent-manifest/schema.d.ts +6 -0
  136. package/dist/src/agent-manifest/schema.js +12 -3
  137. package/dist/src/agent-manifest/schema.js.map +1 -1
  138. package/dist/src/ai-assist/text-assist.d.ts +1 -1
  139. package/dist/src/ai-assist/text-assist.js +56 -0
  140. package/dist/src/ai-assist/text-assist.js.map +1 -1
  141. package/dist/src/auth/profiles/store.js.map +1 -1
  142. package/dist/src/automations/api/routes.d.ts +3 -0
  143. package/dist/src/automations/api/routes.js +193 -0
  144. package/dist/src/automations/api/routes.js.map +1 -0
  145. package/dist/src/automations/domain/index.d.ts +3 -0
  146. package/dist/src/automations/domain/index.js +3 -0
  147. package/dist/src/automations/domain/schedule.d.ts +4 -0
  148. package/dist/src/automations/domain/schedule.js +37 -0
  149. package/dist/src/automations/domain/schedule.js.map +1 -0
  150. package/dist/src/automations/domain/types.d.ts +160 -0
  151. package/dist/src/automations/domain/validation.d.ts +370 -0
  152. package/dist/src/automations/domain/validation.js +149 -0
  153. package/dist/src/automations/domain/validation.js.map +1 -0
  154. package/dist/src/automations/draft/automation-draft-prompt.d.ts +26 -0
  155. package/dist/src/automations/draft/automation-draft-prompt.js +127 -0
  156. package/dist/src/automations/draft/automation-draft-prompt.js.map +1 -0
  157. package/dist/src/automations/draft/automation-draft-service.d.ts +12 -0
  158. package/dist/src/automations/draft/automation-draft-service.js +135 -0
  159. package/dist/src/automations/draft/automation-draft-service.js.map +1 -0
  160. package/dist/src/automations/draft/automation-draft-validator.d.ts +99 -0
  161. package/dist/src/automations/draft/automation-draft-validator.js +105 -0
  162. package/dist/src/automations/draft/automation-draft-validator.js.map +1 -0
  163. package/dist/src/automations/draft/automation-draft.types.d.ts +40 -0
  164. package/dist/src/automations/draft/index.d.ts +3 -0
  165. package/dist/src/automations/draft/index.js +3 -0
  166. package/dist/src/automations/index.d.ts +3 -0
  167. package/dist/src/automations/index.js +8 -0
  168. package/dist/src/automations/product-events.d.ts +5 -0
  169. package/dist/src/automations/product-events.js +21 -0
  170. package/dist/src/automations/product-events.js.map +1 -0
  171. package/dist/src/automations/service/action-executor.d.ts +9 -0
  172. package/dist/src/automations/service/action-executor.js +157 -0
  173. package/dist/src/automations/service/action-executor.js.map +1 -0
  174. package/dist/src/automations/service/automation-service.d.ts +54 -0
  175. package/dist/src/automations/service/automation-service.js +404 -0
  176. package/dist/src/automations/service/automation-service.js.map +1 -0
  177. package/dist/src/automations/service/index.d.ts +2 -0
  178. package/dist/src/automations/service/index.js +3 -0
  179. package/dist/src/automations/storage/automation-repository.d.ts +6 -0
  180. package/dist/src/automations/storage/automation-repository.js +61 -0
  181. package/dist/src/automations/storage/automation-repository.js.map +1 -0
  182. package/dist/src/automations/storage/automation-run-repository.d.ts +17 -0
  183. package/dist/src/automations/storage/automation-run-repository.js +130 -0
  184. package/dist/src/automations/storage/automation-run-repository.js.map +1 -0
  185. package/dist/src/automations/storage/index.d.ts +2 -0
  186. package/dist/src/automations/storage/index.js +3 -0
  187. package/dist/src/channels/plugin-types.d.ts +3 -0
  188. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  189. package/dist/src/cli/command-catalog.js +0 -39
  190. package/dist/src/cli/command-catalog.js.map +1 -1
  191. package/dist/src/cli/command-loaders.js +0 -1
  192. package/dist/src/cli/command-loaders.js.map +1 -1
  193. package/dist/src/cli/command-manifest.js +0 -4
  194. package/dist/src/cli/command-manifest.js.map +1 -1
  195. package/dist/src/cli/commands/agents.js +7 -6
  196. package/dist/src/cli/commands/agents.js.map +1 -1
  197. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  198. package/dist/src/cli/commands/doctor/checks/{cron-health.d.ts → migrations.d.ts} +1 -1
  199. package/dist/src/cli/commands/doctor/checks/migrations.js +40 -0
  200. package/dist/src/cli/commands/doctor/checks/migrations.js.map +1 -0
  201. package/dist/src/cli/commands/doctor/flow.js +2 -2
  202. package/dist/src/cli/commands/doctor/flow.js.map +1 -1
  203. package/dist/src/cli/commands/gateway/call.js +2 -2
  204. package/dist/src/cli/commands/gateway/call.js.map +1 -1
  205. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  206. package/dist/src/cli/commands/gateway/run-foreground.js +4 -2
  207. package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
  208. package/dist/src/cli/commands/init.js +26 -8
  209. package/dist/src/cli/commands/init.js.map +1 -1
  210. package/dist/src/cli/commands/tui.js +24 -2
  211. package/dist/src/cli/commands/tui.js.map +1 -1
  212. package/dist/src/cli/utils/init-workspace-core.js +2 -0
  213. package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
  214. package/dist/src/commands/agents.config.d.ts +9 -0
  215. package/dist/src/commands/agents.config.js +40 -2
  216. package/dist/src/commands/agents.config.js.map +1 -1
  217. package/dist/src/config/agent-profile.js +4 -3
  218. package/dist/src/config/agent-profile.js.map +1 -1
  219. package/dist/src/config/agent-typed-models.js.map +1 -1
  220. package/dist/src/config/config-surface.d.ts +3 -0
  221. package/dist/src/config/index.d.ts +0 -1
  222. package/dist/src/config/index.js +3 -3
  223. package/dist/src/config/index.js.map +1 -1
  224. package/dist/src/config/paths.d.ts +0 -9
  225. package/dist/src/config/paths.js +1 -14
  226. package/dist/src/config/paths.js.map +1 -1
  227. package/dist/src/config/profile.js +0 -1
  228. package/dist/src/config/profile.js.map +1 -1
  229. package/dist/src/config/rules.js +0 -5
  230. package/dist/src/config/rules.js.map +1 -1
  231. package/dist/src/config/schema.d.ts +13 -12
  232. package/dist/src/config/schema.js +22 -26
  233. package/dist/src/config/schema.js.map +1 -1
  234. package/dist/src/config/web-patch.d.ts +0 -12
  235. package/dist/src/config/web-patch.js +2 -29
  236. package/dist/src/config/web-patch.js.map +1 -1
  237. package/dist/src/extensions/api.d.ts +2 -0
  238. package/dist/src/extensions/api.js +10 -0
  239. package/dist/src/extensions/api.js.map +1 -1
  240. package/dist/src/extensions/extension-registry-impl.d.ts +4 -1
  241. package/dist/src/extensions/extension-registry-impl.js +8 -0
  242. package/dist/src/extensions/extension-registry-impl.js.map +1 -1
  243. package/dist/src/extensions/loader.d.ts +3 -3
  244. package/dist/src/extensions/loader.js +3 -3
  245. package/dist/src/extensions/loader.js.map +1 -1
  246. package/dist/src/extensions/sdk/testing.d.ts +2 -0
  247. package/dist/src/extensions/sdk/testing.js +7 -0
  248. package/dist/src/extensions/sdk/testing.js.map +1 -1
  249. package/dist/src/extensions/types/core.d.ts +10 -1
  250. package/dist/src/extensions/types/index.d.ts +1 -1
  251. package/dist/src/extensions/types/{phase4.d.ts → registration.d.ts} +2 -2
  252. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  253. package/dist/src/gateway/agent-builtin-tools.js +1 -1
  254. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  255. package/dist/src/gateway/agents-admin.d.ts +1 -0
  256. package/dist/src/gateway/agents-admin.js +13 -15
  257. package/dist/src/gateway/agents-admin.js.map +1 -1
  258. package/dist/src/gateway/capability-presets-admin.d.ts +1 -0
  259. package/dist/src/gateway/capability-presets-admin.js +19 -10
  260. package/dist/src/gateway/capability-presets-admin.js.map +1 -1
  261. package/dist/src/gateway/dreaming-automation-reconciler.d.ts +11 -0
  262. package/dist/src/gateway/dreaming-automation-reconciler.js +105 -0
  263. package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -0
  264. package/dist/src/gateway/heartbeat/service.d.ts +0 -2
  265. package/dist/src/gateway/heartbeat/service.js +0 -7
  266. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  267. package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -6
  268. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  269. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  270. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  271. package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
  272. package/dist/src/gateway/hono/routes/config-patch/misc.js +12 -6
  273. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  274. package/dist/src/gateway/hono/routes/dreaming.js +27 -37
  275. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  276. package/dist/src/gateway/hono/routes/home.d.ts +2 -2
  277. package/dist/src/gateway/hono/routes/home.js +34 -25
  278. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  279. package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -6
  280. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  281. package/dist/src/gateway/hono/routes/migrations.d.ts +3 -0
  282. package/dist/src/gateway/hono/routes/migrations.js +35 -0
  283. package/dist/src/gateway/hono/routes/migrations.js.map +1 -0
  284. package/dist/src/gateway/hono/routes/public-gateway.js +2 -1
  285. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  286. package/dist/src/gateway/hono/routes/sessions.js +14 -0
  287. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  288. package/dist/src/gateway/run-loop.js +2 -0
  289. package/dist/src/gateway/run-loop.js.map +1 -1
  290. package/dist/src/gateway/security/operator-scopes.js +5 -1
  291. package/dist/src/gateway/security/operator-scopes.js.map +1 -1
  292. package/dist/src/gateway/service/config-coordinator.d.ts +4 -4
  293. package/dist/src/gateway/service/config-coordinator.js +14 -8
  294. package/dist/src/gateway/service/config-coordinator.js.map +1 -1
  295. package/dist/src/gateway/service/sessions-api.d.ts +2 -1
  296. package/dist/src/gateway/service/sessions-api.js +6 -1
  297. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  298. package/dist/src/gateway/service.d.ts +7 -3
  299. package/dist/src/gateway/service.js +61 -27
  300. package/dist/src/gateway/service.js.map +1 -1
  301. package/dist/src/goals/goal-service.js +45 -4
  302. package/dist/src/goals/goal-service.js.map +1 -1
  303. package/dist/src/infra/update-restart.js +1 -1
  304. package/dist/src/migrations/config/default-capability-preset.d.ts +10 -0
  305. package/dist/src/migrations/config/default-capability-preset.js +135 -0
  306. package/dist/src/migrations/config/default-capability-preset.js.map +1 -0
  307. package/dist/src/migrations/index.d.ts +4 -0
  308. package/dist/src/migrations/index.js +4 -0
  309. package/dist/src/migrations/registry.d.ts +8 -0
  310. package/dist/src/migrations/registry.js +18 -0
  311. package/dist/src/migrations/registry.js.map +1 -0
  312. package/dist/src/migrations/runner.d.ts +17 -0
  313. package/dist/src/migrations/runner.js +191 -0
  314. package/dist/src/migrations/runner.js.map +1 -0
  315. package/dist/src/migrations/types.d.ts +34 -0
  316. package/dist/src/notes/service.js +24 -1
  317. package/dist/src/notes/service.js.map +1 -1
  318. package/dist/src/providers/model-registry.d.ts +0 -1
  319. package/dist/src/providers/model-registry.js +0 -3
  320. package/dist/src/providers/model-registry.js.map +1 -1
  321. package/dist/src/routing/resolve-tui-session-key.d.ts +3 -0
  322. package/dist/src/routing/resolve-tui-session-key.js +14 -3
  323. package/dist/src/routing/resolve-tui-session-key.js.map +1 -1
  324. package/dist/src/session/transcript-outline.d.ts +47 -0
  325. package/dist/src/session/transcript-outline.js +481 -0
  326. package/dist/src/session/transcript-outline.js.map +1 -0
  327. package/dist/src/storage/sqlite/index.d.ts +0 -2
  328. package/dist/src/storage/sqlite/index.js +1 -3
  329. package/dist/src/storage/sqlite/migrations/016_automations.sql +47 -0
  330. package/dist/src/storage/sqlite/migrations/017_automation_run_events.sql +14 -0
  331. package/dist/src/storage/sqlite/migrations/018_automation_safety.sql +1 -0
  332. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  333. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  334. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  335. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  336. package/dist/src/storage/sqlite/schema.js +1 -1
  337. package/dist/src/storage/sqlite/schema.sql +56 -46
  338. package/dist/src/tui/backends/embedded-backend.d.ts +6 -0
  339. package/dist/src/tui/backends/embedded-backend.js +18 -7
  340. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  341. package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -0
  342. package/dist/src/tui/backends/gateway-sse-backend.js +14 -0
  343. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  344. package/dist/src/tui/tui-backend.d.ts +4 -0
  345. package/dist/src/tui/tui-commands.d.ts +5 -0
  346. package/dist/src/tui/tui-commands.js +43 -0
  347. package/dist/src/tui/tui-commands.js.map +1 -1
  348. package/dist/src/tui/tui-transcript-tree.d.ts +1 -1
  349. package/dist/src/tui/tui-transcript-tree.js +17 -257
  350. package/dist/src/tui/tui-transcript-tree.js.map +1 -1
  351. package/dist/src/tui/tui-types.d.ts +2 -0
  352. package/dist/src/tui/tui-types.js.map +1 -1
  353. package/dist/src/tui/tui.js +7 -2
  354. package/dist/src/tui/tui.js.map +1 -1
  355. package/dist/src/workflows/domain/index.js +1 -1
  356. package/dist/src/workflows/domain/run.d.ts +7 -7
  357. package/dist/src/workflows/domain/run.js.map +1 -1
  358. package/dist/src/workflows/index.js +2 -2
  359. package/dist/src/workflows/service/workflow-run-service.d.ts +2 -0
  360. package/dist/src/workflows/service/workflow-run-service.js +31 -9
  361. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  362. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -1
  363. package/package.json +4 -2
  364. package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +0 -2
  365. package/dist/gateway/static/root/assets/app-management-settings-panel-bxYJVJpx.js +0 -1
  366. package/dist/gateway/static/root/assets/appearance-settings-BCIykXlI.js +0 -1
  367. package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +0 -8
  368. package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +0 -1
  369. package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +0 -1
  370. package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +0 -1
  371. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
  372. package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +0 -2
  373. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
  374. package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +0 -1
  375. package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
  376. package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +0 -3
  377. package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +0 -1
  378. package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +0 -2
  379. package/dist/gateway/static/root/assets/format-interval-label-BzxafKxR.js +0 -1
  380. package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +0 -1
  381. package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +0 -1
  382. package/dist/gateway/static/root/assets/goals-settings-CYVY4NGp.js +0 -1
  383. package/dist/gateway/static/root/assets/heartbeat-config-api-DriO_CN9.js +0 -1
  384. package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +0 -1
  385. package/dist/gateway/static/root/assets/index-C17Tsd_b.css +0 -1
  386. package/dist/gateway/static/root/assets/index-Cc41r16l.js +0 -191
  387. package/dist/gateway/static/root/assets/interval-presets-DFPCKW_W.js +0 -1
  388. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CcVcqstx.js +0 -1
  389. package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +0 -3
  390. package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +0 -2
  391. package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +0 -2
  392. package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +0 -1
  393. package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +0 -1
  394. package/dist/gateway/static/root/assets/schedule-field-CUCKODde.js +0 -1
  395. package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +0 -1
  396. package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +0 -1
  397. package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +0 -1
  398. package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +0 -1
  399. package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +0 -1
  400. package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +0 -1
  401. package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +0 -2
  402. package/dist/gateway/static/root/assets/system-settings-panel-DI-LN_8G.js +0 -1
  403. package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +0 -1
  404. package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +0 -1
  405. package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +0 -1
  406. package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +0 -18
  407. package/dist/src/agent/fallback/error.d.ts +0 -22
  408. package/dist/src/agent/fallback/error.js +0 -32
  409. package/dist/src/agent/fallback/error.js.map +0 -1
  410. package/dist/src/agent/fallback/index.d.ts +0 -5
  411. package/dist/src/agent/fallback/index.js +0 -9
  412. package/dist/src/agent/fallback/index.js.map +0 -1
  413. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +0 -29
  414. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +0 -76
  415. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +0 -1
  416. package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +0 -6
  417. package/dist/src/agent/service/reconcile-dreaming-cron.js +0 -84
  418. package/dist/src/agent/service/reconcile-dreaming-cron.js.map +0 -1
  419. package/dist/src/agent/tools/cronjob-tool.d.ts +0 -29
  420. package/dist/src/agent/tools/cronjob-tool.js +0 -274
  421. package/dist/src/agent/tools/cronjob-tool.js.map +0 -1
  422. package/dist/src/cli/commands/cron-cli.d.ts +0 -2
  423. package/dist/src/cli/commands/cron-cli.js +0 -15
  424. package/dist/src/cli/commands/cron-cli.js.map +0 -1
  425. package/dist/src/cli/commands/cron.d.ts +0 -4
  426. package/dist/src/cli/commands/cron.js +0 -188
  427. package/dist/src/cli/commands/cron.js.map +0 -1
  428. package/dist/src/cli/commands/doctor/checks/cron-health.js +0 -35
  429. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +0 -1
  430. package/dist/src/cron/execution-types.d.ts +0 -42
  431. package/dist/src/cron/executor.d.ts +0 -67
  432. package/dist/src/cron/executor.js +0 -669
  433. package/dist/src/cron/executor.js.map +0 -1
  434. package/dist/src/cron/index.d.ts +0 -7
  435. package/dist/src/cron/index.js +0 -7
  436. package/dist/src/cron/job-content.d.ts +0 -5
  437. package/dist/src/cron/job-content.js +0 -15
  438. package/dist/src/cron/job-content.js.map +0 -1
  439. package/dist/src/cron/run-log-store.d.ts +0 -12
  440. package/dist/src/cron/run-log-store.js +0 -58
  441. package/dist/src/cron/run-log-store.js.map +0 -1
  442. package/dist/src/cron/schedule.d.ts +0 -10
  443. package/dist/src/cron/schedule.js +0 -85
  444. package/dist/src/cron/schedule.js.map +0 -1
  445. package/dist/src/cron/service.d.ts +0 -58
  446. package/dist/src/cron/service.js +0 -419
  447. package/dist/src/cron/service.js.map +0 -1
  448. package/dist/src/cron/types.d.ts +0 -183
  449. package/dist/src/cron/validation.d.ts +0 -500
  450. package/dist/src/cron/validation.js +0 -192
  451. package/dist/src/cron/validation.js.map +0 -1
  452. package/dist/src/cron/workflow-run-completion.d.ts +0 -23
  453. package/dist/src/cron/workflow-run-completion.js +0 -72
  454. package/dist/src/cron/workflow-run-completion.js.map +0 -1
  455. package/dist/src/extensions/types/phase4.js +0 -1
  456. package/dist/src/gateway/hono/routes/cron.d.ts +0 -3
  457. package/dist/src/gateway/hono/routes/cron.js +0 -109
  458. package/dist/src/gateway/hono/routes/cron.js.map +0 -1
  459. package/dist/src/storage/sqlite/cron-job-repository.d.ts +0 -6
  460. package/dist/src/storage/sqlite/cron-job-repository.js +0 -70
  461. package/dist/src/storage/sqlite/cron-job-repository.js.map +0 -1
  462. package/dist/src/storage/sqlite/cron-run-repository.d.ts +0 -5
  463. package/dist/src/storage/sqlite/cron-run-repository.js +0 -96
  464. package/dist/src/storage/sqlite/cron-run-repository.js.map +0 -1
  465. /package/dist/src/{cron → automations/domain}/types.js +0 -0
  466. /package/dist/src/{config/defaults.d.ts → automations/draft/automation-draft.types.js} +0 -0
  467. /package/dist/src/{config/defaults.js → extensions/types/registration.js} +0 -0
  468. /package/dist/src/{cron/execution-types.js → migrations/types.js} +0 -0
@@ -13,9 +13,10 @@ import type { TypedEventBus } from './events.js';
13
13
  import type { ExtensionHookEvent, ExtensionHookHandler, HookOptions, HookHandlerMap } from './hooks.js';
14
14
  import type { ChannelPlugin } from '../../channels/plugin-types.js';
15
15
  import type { SessionMetadata } from '../../session/types.js';
16
- import type { FlagConfig, FlagValue, ShortcutConfig } from './phase4.js';
16
+ import type { FlagConfig, FlagValue, ShortcutConfig } from './registration.js';
17
17
  import type { ProviderPlugin } from './providers.js';
18
18
  import type { TuiExtensionRegistrar } from './tui.js';
19
+ import type { Migration } from '../../migrations/types.js';
19
20
  export interface ExtensionDefinition {
20
21
  /** Unique extension identifier */
21
22
  id: string;
@@ -120,6 +121,8 @@ export interface ExtensionApi {
120
121
  * Register a reload handler when config paths matching this extension change during hot reload.
121
122
  */
122
123
  registerReload(handler: ExtensionReloadHandler): void;
124
+ /** Register a migration contributed by this extension. */
125
+ registerMigration(migration: Migration): void;
123
126
  registerService(service: ExtensionService): void;
124
127
  registerGatewayMethod(method: string, handler: GatewayMethodHandler): void;
125
128
  /**
@@ -199,6 +202,10 @@ export interface ExtensionReloadRegistration {
199
202
  /** Config path prefixes this handler cares about. Empty = any extension-related change passed to matcher. */
200
203
  configPrefixes: string[];
201
204
  }
205
+ export interface ExtensionMigrationRegistration {
206
+ extensionId: string;
207
+ migration: Migration;
208
+ }
202
209
  /**
203
210
  * Chat command registered by an extension (bridged into CommandRegistry with category `extension`).
204
211
  */
@@ -237,4 +244,6 @@ export interface ExtensionRegistry {
237
244
  getCommand(name: string): ExtensionCommand | undefined;
238
245
  addCliRegistration(reg: ExtensionCliRegistration): void;
239
246
  getCliRegistrations(): readonly ExtensionCliRegistration[];
247
+ addMigrationRegistration?(reg: ExtensionMigrationRegistration): void;
248
+ getMigrationRegistrations?(): readonly ExtensionMigrationRegistration[];
240
249
  }
@@ -9,6 +9,6 @@ export * from './tools.js';
9
9
  export * from './hooks.js';
10
10
  export * from './events.js';
11
11
  export * from './loader.js';
12
- export type { ProviderConfig, ProviderApiType, ModelConfig, OAuthConfig, OAuthCallbacks, OAuthCredentials, FlagConfig, FlagValue, ShortcutConfig, ShortcutHandler } from './phase4.js';
12
+ export type { ProviderConfig, ProviderApiType, ModelConfig, OAuthConfig, OAuthCallbacks, OAuthCredentials, FlagConfig, FlagValue, ShortcutConfig, ShortcutHandler } from './registration.js';
13
13
  export * from './providers.js';
14
14
  export * from './tui.js';
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Extension System Types
2
+ * Extension registration types.
3
3
  *
4
- * Advanced features: Provider, Flag, Shortcut registration.
4
+ * Provider, flag, and shortcut registration contracts.
5
5
  */
6
6
  export interface ProviderConfig {
7
7
  name: string;
@@ -2,5 +2,5 @@
2
2
  * Built-in agent tool `name` values for gateway admin UI (disable toggles).
3
3
  * Extension tools are not listed; users can still add arbitrary strings in config.
4
4
  */
5
- export declare const GATEWAY_BUILTIN_TOOL_IDS: readonly ["read_file", "write_file", "edit_file", "list_dir", "grep", "find", "shell", "session_status", "dreaming", "tool_manual", "clarify", "todo", "skills_list", "skill_view", "skill_manage", "web_search", "web_fetch", "web_extract", "send_message", "send_media", "read_media", "create_share", "text_to_speech", "memory_search", "memory_get", "curated_memory", "session_search", "cronjob", "workflow", "delegate_task", "execute_code", "image", "image_generate", "browser_use", "extensions", "bundle-mcp"];
5
+ export declare const GATEWAY_BUILTIN_TOOL_IDS: readonly ["read_file", "write_file", "edit_file", "list_dir", "grep", "find", "shell", "session_status", "dreaming", "tool_manual", "clarify", "todo", "skills_list", "skill_view", "skill_manage", "web_search", "web_fetch", "web_extract", "send_message", "send_media", "read_media", "create_share", "text_to_speech", "memory_search", "memory_get", "curated_memory", "session_search", "automation", "workflow", "delegate_task", "execute_code", "image", "image_generate", "browser_use", "extensions", "bundle-mcp"];
6
6
  export type GatewayBuiltinToolId = (typeof GATEWAY_BUILTIN_TOOL_IDS)[number];
@@ -31,7 +31,7 @@ const GATEWAY_BUILTIN_TOOL_IDS = [
31
31
  "memory_get",
32
32
  "curated_memory",
33
33
  "session_search",
34
- "cronjob",
34
+ "automation",
35
35
  "workflow",
36
36
  "delegate_task",
37
37
  "execute_code",
@@ -1 +1 @@
1
- {"version":3,"file":"agent-builtin-tools.js","names":[],"sources":["../../../src/gateway/agent-builtin-tools.ts"],"sourcesContent":["/**\n * Built-in agent tool `name` values for gateway admin UI (disable toggles).\n * Extension tools are not listed; users can still add arbitrary strings in config.\n */\nexport const GATEWAY_BUILTIN_TOOL_IDS = [\n 'read_file',\n 'write_file',\n 'edit_file',\n 'list_dir',\n 'grep',\n 'find',\n 'shell',\n 'session_status',\n 'dreaming',\n 'tool_manual',\n 'clarify',\n 'todo',\n 'skills_list',\n 'skill_view',\n 'skill_manage',\n 'web_search',\n 'web_fetch',\n 'web_extract',\n 'send_message',\n 'send_media',\n 'read_media',\n 'create_share',\n 'text_to_speech',\n 'memory_search',\n 'memory_get',\n 'curated_memory',\n 'session_search',\n 'cronjob',\n 'workflow',\n 'delegate_task',\n 'execute_code',\n 'image',\n 'image_generate',\n 'browser_use',\n 'extensions',\n 'bundle-mcp',\n] as const;\n\nexport type GatewayBuiltinToolId = (typeof GATEWAY_BUILTIN_TOOL_IDS)[number];\n"],"mappings":";;;;;AAIA,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"agent-builtin-tools.js","names":[],"sources":["../../../src/gateway/agent-builtin-tools.ts"],"sourcesContent":["/**\n * Built-in agent tool `name` values for gateway admin UI (disable toggles).\n * Extension tools are not listed; users can still add arbitrary strings in config.\n */\nexport const GATEWAY_BUILTIN_TOOL_IDS = [\n 'read_file',\n 'write_file',\n 'edit_file',\n 'list_dir',\n 'grep',\n 'find',\n 'shell',\n 'session_status',\n 'dreaming',\n 'tool_manual',\n 'clarify',\n 'todo',\n 'skills_list',\n 'skill_view',\n 'skill_manage',\n 'web_search',\n 'web_fetch',\n 'web_extract',\n 'send_message',\n 'send_media',\n 'read_media',\n 'create_share',\n 'text_to_speech',\n 'memory_search',\n 'memory_get',\n 'curated_memory',\n 'session_search',\n 'automation',\n 'workflow',\n 'delegate_task',\n 'execute_code',\n 'image',\n 'image_generate',\n 'browser_use',\n 'extensions',\n 'bundle-mcp',\n] as const;\n\nexport type GatewayBuiltinToolId = (typeof GATEWAY_BUILTIN_TOOL_IDS)[number];\n"],"mappings":";;;;;AAIA,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
@@ -95,6 +95,7 @@ export type UpdateAgentBody = {
95
95
  defaultRole?: string | null;
96
96
  roles?: Record<string, {
97
97
  model: string;
98
+ fallbacks?: string[];
98
99
  description?: string;
99
100
  }>;
100
101
  } | null;
@@ -1,10 +1,10 @@
1
- import { DEFAULT_AGENT_ID, init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
1
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
+ import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
3
3
  import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { WORKSPACE_FILES, init_paths, resolveUserProfilePath } from "../config/paths.js";
5
5
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
6
6
  import { isPathUnderWorkspace, resolveWorkspaceSafePath } from "./workspace-editor-path.js";
7
- import { applyAgentConfig, findAgentEntryIndex, pruneAgentConfig, removeAgentDirsFromDisk } from "../commands/agents.config.js";
7
+ import { applyAgentConfig, findAgentEntryIndex, getAgentDeleteBlocker, pruneAgentConfig, removeAgentDirsFromDisk } from "../commands/agents.config.js";
8
8
  import { resolveEffectiveTypedModels } from "../config/agent-typed-models.js";
9
9
  import { GATEWAY_BUILTIN_TOOL_IDS } from "./agent-builtin-tools.js";
10
10
  import { seedAgentProfileMarkdownFiles } from "../agent/context/workspace-seed.js";
@@ -133,14 +133,6 @@ function getGatewayAgentEffectiveManifest(cfg, agentIdRaw) {
133
133
  };
134
134
  }
135
135
  }
136
- function requireNonMain(id) {
137
- if (normalizeAgentId(id) === "main") return {
138
- ok: false,
139
- error: `"${DEFAULT_AGENT_ID}" is reserved`,
140
- status: 400
141
- };
142
- return null;
143
- }
144
136
  function prepareCreateAgent(cfg, body) {
145
137
  const workspace = body.workspace?.trim() ?? "";
146
138
  if (!workspace) return {
@@ -325,11 +317,13 @@ function prepareUpdateAgent(cfg, agentIdRaw, body) {
325
317
  const roles = Object.fromEntries(Object.entries(body.models.roles).map(([id, row]) => ({
326
318
  id: id.trim(),
327
319
  model: row.model.trim(),
320
+ fallbacks: (row.fallbacks ?? []).map((ref) => ref.trim()).filter(Boolean),
328
321
  description: row.description?.trim()
329
- })).filter((row) => row.id && row.model).map((row) => [row.id, row.description ? {
322
+ })).filter((row) => row.id && row.model).map((row) => [row.id, {
330
323
  model: row.model,
331
- description: row.description
332
- } : { model: row.model }]));
324
+ ...row.fallbacks.length > 0 ? { fallbacks: row.fallbacks } : {},
325
+ ...row.description ? { description: row.description } : {}
326
+ }]));
333
327
  entry.models = {
334
328
  defaultRole: entry.models?.defaultRole ?? Object.keys(roles)[0] ?? "deep",
335
329
  roles,
@@ -386,8 +380,12 @@ function prepareUpdateAgent(cfg, agentIdRaw, body) {
386
380
  }
387
381
  function prepareDeleteAgent(cfg, agentIdRaw) {
388
382
  const agentId = normalizeAgentId(agentIdRaw);
389
- const reserved = requireNonMain(agentId);
390
- if (reserved) return reserved;
383
+ const blocker = getAgentDeleteBlocker(cfg, agentId);
384
+ if (blocker) return {
385
+ ok: false,
386
+ error: blocker,
387
+ status: 400
388
+ };
391
389
  if (findAgentEntryIndex(listAgentEntries(cfg), agentId) < 0) return {
392
390
  ok: false,
393
391
  error: `agent "${agentId}" not found`,
@@ -1 +1 @@
1
- {"version":3,"file":"agents-admin.js","names":["pathResolve"],"sources":["../../../src/gateway/agents-admin.ts"],"sourcesContent":["/**\n * Gateway REST helpers for multi-agent management.\n */\n\nimport { cp, mkdir, readdir, readFile, realpath, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve as pathResolve } from 'node:path';\n\nimport {\n DEFAULT_AGENT_ID,\n listAgentEntries,\n normalizeAgentId,\n resolveAgentDir,\n resolveAgentProfileDir,\n resolveAgentWorkspaceDir,\n resolveDefaultAgentId,\n resolveUserPath,\n validateAgentIdForNewAgent,\n} from '../agent/agent-scope.js';\nimport {\n AGENT_PROFILE_MARKDOWN_SYSTEM_FILES,\n REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET,\n} from '../agent/context/workspace.js';\nimport { seedAgentProfileMarkdownFiles } from '../agent/context/workspace-seed.js';\nimport {\n resolveEffectiveAgentManifest,\n type ResolveManifestResult,\n} from '../agent-manifest/resolver.js';\nimport {\n applyAgentConfig,\n findAgentEntryIndex,\n pruneAgentConfig,\n removeAgentDirsFromDisk,\n} from '../commands/agents.config.js';\nimport type { AgentModelsConfig, Config } from '../config/schema.js';\nimport { resolveUserProfilePath, WORKSPACE_FILES } from '../config/paths.js';\nimport { resolveEffectiveAgentProfile } from '../config/agent-profile.js';\nimport type { AgentTypedModel } from '../config/schema.js';\nimport { resolveEffectiveTypedModels } from '../config/agent-typed-models.js';\nimport { GATEWAY_BUILTIN_TOOL_IDS } from './agent-builtin-tools.js';\nimport { isPathUnderWorkspace, resolveWorkspaceSafePath } from './workspace-editor-path.js';\n\nconst EDITABLE_PROFILE_MARKDOWN_NAMES = new Set<string>([...AGENT_PROFILE_MARKDOWN_SYSTEM_FILES]);\n\nexport type GatewayAgentTypedModelsInfo = {\n defaultRole: string;\n preset: AgentTypedModel[];\n entry?: AgentTypedModel[];\n effective: AgentTypedModel[];\n};\n\nexport type GatewayAgentRow = {\n id: string;\n name?: string;\n description?: string;\n language?: string;\n /** Value from `IDENTITY.md` **Avatar:** line when present (may be URL, `xopc:…`, etc.). */\n avatar?: string;\n workspace: string;\n /** Absolute directory for profile Markdown (`SOUL.md`, …) and gateway avatars: `agents/<id>/profile/`. */\n profileDir: string;\n model?: { primary?: string; fallbacks?: string[] };\n typedModels: GatewayAgentTypedModelsInfo;\n extends: string[];\n isDefault: boolean;\n skills: {\n preset: string[];\n entry?: string[];\n effectiveAllowlist?: string[];\n };\n tools: {\n presetDenied: string[];\n entryDisable: string[];\n effectiveDisable: string[];\n };\n};\n\nexport type GatewayAgentsListResponse = {\n defaultId: string;\n agents: GatewayAgentRow[];\n builtinToolIds: string[];\n};\n\nexport type GatewayAgentEffectiveManifestResponse = ResolveManifestResult;\n\nfunction collectAgentIdsForList(cfg: Config): string[] {\n const entries = listAgentEntries(cfg).filter((e) => e.enabled !== false);\n const defaultId = resolveDefaultAgentId(cfg);\n if (entries.length === 0) {\n return [defaultId];\n }\n const ids = new Set<string>();\n for (const e of entries) {\n ids.add(normalizeAgentId(e.id));\n }\n ids.add(defaultId);\n return [...ids];\n}\n\nfunction rolesToTypedModels(\n roles: Record<string, { model: string; description?: string }> | undefined,\n): AgentTypedModel[] {\n return Object.entries(roles ?? {})\n .map(([id, role]) => ({ id, ...role }))\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n\n/** Extract `**Avatar:**` value from profile IDENTITY.md (same line shape as the gateway console parser). */\nexport function extractAvatarFromIdentityMarkdown(content: string): string | undefined {\n return parseIdentityMarkdown(content).avatar || undefined;\n}\n\nexport function parseIdentityMarkdown(content: string): {\n name?: string;\n description?: string;\n language?: string;\n avatar?: string;\n} {\n const out: { name?: string; description?: string; language?: string; avatar?: string } = {};\n for (const line of content.split('\\n')) {\n const match = line.match(/^[-*]\\s+\\*\\*(Name|Description|Language|Avatar):\\*\\*\\s*(.*)/i);\n if (match) {\n const key = match[1]?.toLowerCase();\n const v = match[2]?.trim() ?? '';\n if (!v || /^_\\(.*\\)_$/.test(v)) continue;\n if (key === 'name') out.name = v;\n if (key === 'description') out.description = v;\n if (key === 'language') out.language = v;\n if (key === 'avatar') out.avatar = v;\n }\n }\n return out;\n}\n\nexport async function listGatewayAgents(\n cfg: Config,\n _options: { locale?: string } = {},\n): Promise<GatewayAgentsListResponse> {\n const defaultId = resolveDefaultAgentId(cfg);\n const agents: GatewayAgentRow[] = [];\n const presetSkills: string[] | undefined = undefined;\n const presetDenied: string[] = [];\n const presetTypedModels: ReturnType<typeof rolesToTypedModels> = [];\n for (const id of collectAgentIdsForList(cfg)) {\n const profile = resolveEffectiveAgentProfile(cfg, id);\n const entry = listAgentEntries(cfg).find((e) => normalizeAgentId(e.id) === id);\n const model =\n profile.primaryModelRef || profile.fallbacks.length > 0\n ? {\n ...(profile.primaryModelRef ? { primary: profile.primaryModelRef } : {}),\n ...(profile.fallbacks.length > 0 ? { fallbacks: profile.fallbacks } : {}),\n }\n : undefined;\n const entrySkills = entry?.skills.mode === 'allowlist' ? entry.skills.allow ?? [] : undefined;\n const entryDisable = Object.entries(entry?.tools.builtin ?? {})\n .filter(([, policy]) => policy.mode === 'deny')\n .map(([name]) => name);\n const entryTypedModels = rolesToTypedModels(entry?.models?.roles);\n const effectiveTypedModels = [...resolveEffectiveTypedModels(cfg, id).values()].sort((a, b) =>\n a.id.localeCompare(b.id),\n );\n let identity: ReturnType<typeof parseIdentityMarkdown> = {};\n try {\n const identityPath = join(resolveAgentProfileDir(cfg, id), WORKSPACE_FILES.IDENTITY);\n const content = await readFile(identityPath, 'utf-8');\n identity = parseIdentityMarkdown(content);\n } catch {\n /* missing IDENTITY.md or unreadable */\n }\n agents.push({\n id,\n ...(identity.name ? { name: identity.name } : {}),\n ...(identity.description ? { description: identity.description } : {}),\n ...(identity.language ? { language: identity.language } : {}),\n ...(identity.avatar ? { avatar: identity.avatar } : {}),\n workspace: profile.resolvedWorkspacePath,\n profileDir: resolveAgentProfileDir(cfg, id),\n ...(model ? { model } : {}),\n typedModels: {\n defaultRole: profile.manifest.models.defaultRole,\n preset: [...presetTypedModels],\n ...(entryTypedModels.length > 0 ? { entry: entryTypedModels } : {}),\n effective: effectiveTypedModels,\n },\n extends: [...(entry?.extends ?? [])],\n isDefault: id === defaultId,\n skills: {\n preset: presetSkills ? [...presetSkills] : [],\n ...(entrySkills !== undefined ? { entry: [...entrySkills] } : {}),\n ...(profile.skillsAllowlist !== undefined\n ? { effectiveAllowlist: [...profile.skillsAllowlist] }\n : {}),\n },\n tools: {\n presetDenied: [...presetDenied],\n entryDisable: [...entryDisable],\n effectiveDisable: [...profile.tools.denied].sort((a, b) => a.localeCompare(b)),\n },\n });\n }\n agents.sort((a, b) => a.id.localeCompare(b.id));\n return { defaultId, agents, builtinToolIds: [...GATEWAY_BUILTIN_TOOL_IDS] };\n}\n\nexport function getGatewayAgentEffectiveManifest(\n cfg: Config,\n agentIdRaw: string,\n): AgentAdminResult<GatewayAgentEffectiveManifestResponse> {\n const agentId = normalizeAgentId(agentIdRaw);\n const entry = listAgentEntries(cfg).find((e) => normalizeAgentId(e.id) === agentId);\n if (!entry) {\n return { ok: false, error: `agent \"${agentId}\" not found`, status: 404 };\n }\n try {\n return {\n ok: true,\n data: resolveEffectiveAgentManifest({\n agent: entry,\n presets: cfg.agents.capabilityPresets,\n defaultPresetId: cfg.agents.defaultPreset,\n }),\n };\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n status: 400,\n };\n }\n}\n\nexport type CreateAgentBody = {\n /** Optional id seed; normalized agent id defaults from `profileFiles[\"IDENTITY.md\"]` name when omitted. */\n id?: string;\n workspace: string;\n models?: AgentModelsConfig;\n /** Initial `agents.list[].skills` for the new entry. */\n skills?: string[];\n /** Initial `agents.list[].tools` for the new entry. */\n tools?: NonNullable<Config['agents']['list']>[number]['tools'];\n /** Profile markdown files to write after seeding (e.g. `IDENTITY.md`, `SOUL.md`). */\n profileFiles?: Record<string, string>;\n /** Clone from an existing agent id — copies config entry fields and profile directory. */\n cloneFrom?: string;\n};\n\nexport type AgentAdminHttpStatus = 400 | 404 | 409;\n\nexport type AgentAdminResult<T> =\n | { ok: true; data: T }\n | { ok: false; error: string; status?: AgentAdminHttpStatus };\n\nfunction requireNonMain(id: string): AgentAdminResult<never> | null {\n if (normalizeAgentId(id) === DEFAULT_AGENT_ID) {\n return { ok: false, error: `\"${DEFAULT_AGENT_ID}\" is reserved`, status: 400 };\n }\n return null;\n}\n\nexport function prepareCreateAgent(\n cfg: Config,\n body: CreateAgentBody,\n): AgentAdminResult<{ nextConfig: Config; agentId: string; workspace: string }> {\n const workspace = body.workspace?.trim() ?? '';\n if (!workspace) {\n return { ok: false, error: 'workspace is required', status: 400 };\n }\n if (body.profileFiles !== undefined) {\n if (typeof body.profileFiles !== 'object' || body.profileFiles === null || Array.isArray(body.profileFiles)) {\n return { ok: false, error: 'profileFiles must be an object', status: 400 };\n }\n for (const [name, content] of Object.entries(body.profileFiles)) {\n const bad = assertAllowedFile(name);\n if (bad) {\n return bad;\n }\n if (typeof content !== 'string') {\n return { ok: false, error: `profileFiles[\"${name}\"] must be a string`, status: 400 };\n }\n }\n }\n if (!body.cloneFrom && typeof body.profileFiles?.[WORKSPACE_FILES.IDENTITY] !== 'string') {\n return { ok: false, error: `profileFiles[\"${WORKSPACE_FILES.IDENTITY}\"] is required`, status: 400 };\n }\n\n const identity = body.profileFiles?.[WORKSPACE_FILES.IDENTITY]\n ? parseIdentityMarkdown(body.profileFiles[WORKSPACE_FILES.IDENTITY])\n : {};\n const nameSeed = identity.name ?? body.id ?? '';\n const idRes = validateAgentIdForNewAgent(body.id, nameSeed);\n if (idRes.ok === false) {\n return { ok: false, error: idRes.error, status: 400 };\n }\n const agentId = idRes.agentId;\n if (findAgentEntryIndex(listAgentEntries(cfg), agentId) >= 0) {\n return { ok: false, error: `agent \"${agentId}\" already exists`, status: 409 };\n }\n\n // Resolve fields from cloneFrom source when present\n let cloneSourceEntry: ReturnType<typeof listAgentEntries>[number] | undefined;\n if (body.cloneFrom) {\n const srcId = normalizeAgentId(body.cloneFrom);\n cloneSourceEntry = listAgentEntries(cfg).find((e) => normalizeAgentId(e.id) === srcId);\n if (!cloneSourceEntry && srcId !== resolveDefaultAgentId(cfg)) {\n return { ok: false, error: `source agent \"${srcId}\" not found`, status: 404 };\n }\n }\n\n const wsAbs = resolveUserPath(workspace);\n\n const rawModels = body.models ?? cloneSourceEntry?.models;\n const effectiveModels =\n rawModels?.roles\n ? {\n defaultRole: rawModels.defaultRole ?? Object.keys(rawModels.roles)[0] ?? 'deep',\n roles: rawModels.roles,\n }\n : undefined;\n if (effectiveModels && !effectiveModels.roles[effectiveModels.defaultRole]) {\n return { ok: false, error: 'models.defaultRole must reference models.roles', status: 400 };\n }\n\n let next = applyAgentConfig(cfg, {\n agentId,\n workspace: wsAbs,\n ...(effectiveModels ? { models: effectiveModels } : {}),\n ...(body.skills !== undefined\n ? { skills: body.skills.map((s) => String(s).trim()).filter(Boolean) }\n : cloneSourceEntry?.skills.mode === 'allowlist' && body.cloneFrom\n ? { skills: [...(cloneSourceEntry.skills.allow ?? [])] }\n : {}),\n ...(body.tools !== undefined ? { tools: body.tools } : cloneSourceEntry?.tools && body.cloneFrom ? { tools: cloneSourceEntry.tools } : {}),\n });\n\n return { ok: true, data: { nextConfig: next, agentId, workspace: wsAbs } };\n}\n\nexport async function finalizeCreateAgentDirs(\n cfg: Config,\n agentId: string,\n opts?: { profileFiles?: Record<string, string>; cloneFrom?: string },\n): Promise<AgentAdminResult<void>> {\n const wsPath = resolveAgentWorkspaceDir(cfg, agentId);\n const profilePath = resolveAgentProfileDir(cfg, agentId);\n const adPath = resolveAgentDir(cfg, agentId);\n await mkdir(wsPath, { recursive: true });\n await mkdir(profilePath, { recursive: true });\n await mkdir(adPath, { recursive: true });\n const id = normalizeAgentId(agentId);\n const displayName = opts?.profileFiles?.[WORKSPACE_FILES.IDENTITY]\n ? (parseIdentityMarkdown(opts.profileFiles[WORKSPACE_FILES.IDENTITY]).name ?? id)\n : id;\n\n // When cloning, copy the entire source profile directory instead of seeding\n if (opts?.cloneFrom) {\n const srcProfilePath = resolveAgentProfileDir(cfg, normalizeAgentId(opts.cloneFrom));\n try {\n const srcStat = await stat(srcProfilePath);\n if (srcStat.isDirectory()) {\n const srcFiles = await readdir(srcProfilePath);\n for (const fileName of srcFiles) {\n const srcFile = join(srcProfilePath, fileName);\n const dstFile = join(profilePath, fileName);\n try {\n const fileStat = await stat(srcFile);\n if (fileStat.isFile()) {\n await cp(srcFile, dstFile);\n }\n } catch {\n /* skip unreadable files */\n }\n }\n }\n } catch {\n // Source profile dir doesn't exist — fall through to normal seed\n seedAgentProfileMarkdownFiles(profilePath, wsPath, { displayName });\n }\n } else {\n seedAgentProfileMarkdownFiles(profilePath, wsPath, { displayName });\n }\n\n const profileFiles = opts?.profileFiles;\n if (profileFiles && Object.keys(profileFiles).length > 0) {\n for (const [name, content] of Object.entries(profileFiles)) {\n const written = await writeAgentProfileFile(cfg, agentId, name, content);\n if (written.ok === false) {\n return written;\n }\n }\n }\n\n return { ok: true, data: undefined };\n}\n\nexport type UpdateAgentBody = {\n workspace?: string;\n extends?: string[];\n models?: {\n defaultRole?: string | null;\n roles?: Record<string, { model: string; description?: string }>;\n } | null;\n setDefault?: boolean;\n /** Replace `agents.list[].skills`; `null` resets to all skills. */\n skills?: string[] | null;\n /** Replace `agents.list[].tools`; `null` resets to no explicit policies. */\n tools?: NonNullable<Config['agents']['list']>[number]['tools'] | null;\n /** Replace `agents.list[].memory`; every agent manifest owns its memory policy. */\n memory?: NonNullable<Config['agents']['list']>[number]['memory'];\n};\n\nexport function prepareUpdateAgent(\n cfg: Config,\n agentIdRaw: string,\n body: UpdateAgentBody,\n): AgentAdminResult<{ nextConfig: Config }> {\n const agentId = normalizeAgentId(agentIdRaw);\n let list = [...listAgentEntries(cfg)];\n let idx = findAgentEntryIndex(list, agentId);\n if (idx < 0 && agentId === resolveDefaultAgentId(cfg)) {\n list = [...list, {\n id: agentId,\n enabled: true as const,\n identity: { name: agentId, role: 'Agent', language: 'en', tone: 'direct' },\n responsibilities: { primary: ['Help the user complete tasks'] },\n workspace: { root: `~/.xopc/workspace/${agentId}` },\n tools: { builtin: {} },\n skills: { mode: 'all' },\n memory: { mode: 'confirmWrite', sources: ['session', 'curated'], writePolicy: { curated: 'confirm' } },\n workflows: {},\n boundaries: { requiresConfirmation: [], forbidden: [], escalation: [] },\n }];\n idx = list.length - 1;\n }\n if (idx < 0) {\n return { ok: false, error: `agent \"${agentId}\" not found`, status: 404 };\n }\n\n type Entry = (typeof list)[number];\n const entry: Entry = { ...list[idx] };\n\n if (body.workspace !== undefined) {\n const w = body.workspace.trim();\n if (w) {\n entry.workspace = { root: resolveUserPath(w) };\n }\n }\n if (body.extends !== undefined) {\n const nextExtends = Array.from(new Set(body.extends.map((id) => normalizeAgentId(id)).filter(Boolean)));\n for (const presetId of nextExtends) {\n if (!cfg.agents.capabilityPresets[presetId]) {\n return { ok: false, error: `capability preset \"${presetId}\" not found`, status: 400 };\n }\n }\n if (nextExtends.length > 0) {\n entry.extends = nextExtends;\n } else {\n delete entry.extends;\n }\n }\n if (body.models !== undefined) {\n if (body.models === null) {\n delete entry.models;\n } else {\n if (body.models.defaultRole !== undefined) {\n if (body.models.defaultRole === null || !body.models.defaultRole.trim()) {\n return { ok: false, error: 'models.defaultRole must be a non-empty string', status: 400 };\n }\n entry.models = {\n defaultRole: body.models.defaultRole.trim(),\n roles: entry.models?.roles ?? {},\n ...(entry.models?.policy ? { policy: entry.models.policy } : {}),\n };\n }\n if (Object.hasOwn(body.models, 'roles')) {\n if (body.models.roles !== undefined) {\n const roles = Object.fromEntries(\n Object.entries(body.models.roles)\n .map(([id, row]) => ({\n id: id.trim(),\n model: row.model.trim(),\n description: row.description?.trim(),\n }))\n .filter((row) => row.id && row.model)\n .map((row) => [\n row.id,\n row.description ? { model: row.model, description: row.description } : { model: row.model },\n ]),\n );\n entry.models = {\n defaultRole: entry.models?.defaultRole ?? Object.keys(roles)[0] ?? 'deep',\n roles,\n ...(entry.models?.policy ? { policy: entry.models.policy } : {}),\n };\n }\n }\n const roles = entry.models?.roles ?? {};\n const defaultRole = entry.models?.defaultRole ?? Object.keys(roles)[0];\n if (!defaultRole || !roles[defaultRole]) {\n return { ok: false, error: 'models.defaultRole must reference models.roles', status: 400 };\n }\n entry.models = { ...entry.models, defaultRole };\n }\n }\n\n if (body.skills !== undefined) {\n if (body.skills === null) {\n entry.skills = { mode: 'all' };\n } else {\n const next = body.skills.map((s) => String(s).trim()).filter(Boolean);\n if (next.length === 0) {\n entry.skills = { mode: 'allowlist', allow: [] };\n } else {\n entry.skills = { mode: 'allowlist', allow: next };\n }\n }\n }\n\n if (body.tools !== undefined) {\n if (body.tools === null) {\n entry.tools = { builtin: {} };\n } else {\n entry.tools = body.tools;\n }\n }\n\n if (body.memory !== undefined) {\n entry.memory = body.memory;\n }\n\n list[idx] = entry;\n let next: Config = {\n ...cfg,\n agents: {\n ...cfg.agents,\n list,\n },\n };\n\n if (body.setDefault === true) {\n next = {\n ...next,\n agents: {\n ...next.agents,\n default: agentId,\n },\n };\n }\n return { ok: true, data: { nextConfig: next } };\n}\n\nexport function prepareDeleteAgent(\n cfg: Config,\n agentIdRaw: string,\n): AgentAdminResult<{ nextConfig: Config; agentId: string }> {\n const agentId = normalizeAgentId(agentIdRaw);\n const reserved = requireNonMain(agentId);\n if (reserved) {\n return reserved;\n }\n if (findAgentEntryIndex(listAgentEntries(cfg), agentId) < 0) {\n return { ok: false, error: `agent \"${agentId}\" not found`, status: 404 };\n }\n const { config: pruned } = pruneAgentConfig(cfg, agentId);\n return { ok: true, data: { nextConfig: pruned, agentId } };\n}\n\nexport async function runAfterDeletePurge(cfg: Config, agentId: string): Promise<void> {\n await removeAgentDirsFromDisk(cfg, agentId);\n}\n\nexport type AgentFileEntry = {\n name: string;\n missing: boolean;\n size?: number;\n updatedAtMs?: number;\n};\n\nasync function profileMarkdownRootReal(cfg: Config, agentId: string): Promise<string> {\n const dir = resolveAgentProfileDir(cfg, agentId);\n await mkdir(dir, { recursive: true });\n try {\n return await realpath(dir);\n } catch {\n return pathResolve(dir);\n }\n}\n\nfunction assertAllowedFile(name: string): AgentAdminResult<never> | null {\n if (!name || name.includes('/') || name.includes('\\\\') || !EDITABLE_PROFILE_MARKDOWN_NAMES.has(name)) {\n return { ok: false, error: `unsupported file \"${name}\"`, status: 400 };\n }\n return null;\n}\n\nexport async function listAgentProfileFiles(\n cfg: Config,\n agentId: string,\n): Promise<AgentAdminResult<{ agentId: string; profileDir: string; files: AgentFileEntry[] }>> {\n const id = normalizeAgentId(agentId);\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n const root = await profileMarkdownRootReal(cfg, id);\n const names = [...EDITABLE_PROFILE_MARKDOWN_NAMES];\n const files: AgentFileEntry[] = [];\n for (const name of names.sort((a, b) => a.localeCompare(b))) {\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n continue;\n }\n try {\n const st = await stat(abs);\n if (!st.isFile()) {\n continue;\n }\n files.push({\n name,\n missing: false,\n size: st.size,\n updatedAtMs: st.mtimeMs,\n });\n } catch {\n if (!REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET.has(name)) {\n continue;\n }\n files.push({ name, missing: true });\n }\n }\n files.sort((a, b) => a.name.localeCompare(b.name));\n return { ok: true, data: { agentId: id, profileDir: root, files } };\n}\n\nexport async function readAgentProfileFile(\n cfg: Config,\n agentId: string,\n name: string,\n): Promise<AgentAdminResult<{ agentId: string; content: string; path: string }>> {\n const bad = assertAllowedFile(name);\n if (bad) {\n return bad;\n }\n const id = normalizeAgentId(agentId);\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n const root = await profileMarkdownRootReal(cfg, id);\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n return { ok: false, error: 'invalid path', status: 400 };\n }\n try {\n const content = await readFile(abs, 'utf-8');\n return { ok: true, data: { agentId: id, content, path: abs } };\n } catch {\n return { ok: false, error: 'file not found', status: 404 };\n }\n}\n\nexport async function writeAgentProfileFile(\n cfg: Config,\n agentId: string,\n name: string,\n content: string,\n): Promise<AgentAdminResult<{ agentId: string; path: string }>> {\n const bad = assertAllowedFile(name);\n if (bad) {\n return bad;\n }\n const id = normalizeAgentId(agentId);\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n const root = await profileMarkdownRootReal(cfg, id);\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n return { ok: false, error: 'invalid path', status: 400 };\n }\n const rootReal = await profileMarkdownRootReal(cfg, id);\n if (!isPathUnderWorkspace(rootReal, abs)) {\n return { ok: false, error: 'path escapes profile markdown root', status: 400 };\n }\n await writeFile(abs, content, 'utf-8');\n return { ok: true, data: { agentId: id, path: abs } };\n}\n\nexport async function readUserProfileFile(): Promise<AgentAdminResult<{ content: string; path: string }>> {\n const path = resolveUserProfilePath();\n try {\n const content = await readFile(path, 'utf-8');\n return { ok: true, data: { content, path } };\n } catch {\n return { ok: true, data: { content: '', path } };\n }\n}\n\nexport async function writeUserProfileFile(\n content: string,\n): Promise<AgentAdminResult<{ path: string }>> {\n const path = resolveUserProfilePath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n return { ok: true, data: { path } };\n}\n\n// ---------------------------------------------------------------------------\n// Binary agent avatar (profile markdown root dir, not a SOUL/IDENTITY markdown file)\n// ---------------------------------------------------------------------------\n\nconst AGENT_AVATAR_MAX_BYTES = 512 * 1024;\nconst AGENT_AVATAR_BASENAME = 'agent-avatar';\n\nconst AGENT_AVATAR_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp'] as const;\n\nfunction agentAvatarFilenames(): string[] {\n return AGENT_AVATAR_EXTENSIONS.map((ext) => `${AGENT_AVATAR_BASENAME}${ext}`);\n}\n\nfunction mimeToExt(mime: string): '.png' | '.jpg' | '.jpeg' | '.webp' | null {\n const m = mime.toLowerCase().trim();\n if (m === 'image/png') return '.png';\n if (m === 'image/jpeg' || m === 'image/jpg') return '.jpg';\n if (m === 'image/webp') return '.webp';\n return null;\n}\n\nfunction detectImageMimeFromBytes(buf: Uint8Array): 'image/png' | 'image/jpeg' | 'image/webp' | null {\n if (buf.length >= 8 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {\n return 'image/png';\n }\n if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) {\n return 'image/jpeg';\n }\n if (\n buf.length >= 12 &&\n buf[0] === 0x52 &&\n buf[1] === 0x49 &&\n buf[2] === 0x46 &&\n buf[3] === 0x46 &&\n buf[8] === 0x57 &&\n buf[9] === 0x45 &&\n buf[10] === 0x42 &&\n buf[11] === 0x50\n ) {\n return 'image/webp';\n }\n return null;\n}\n\nfunction assertAgentExistsForAvatar(cfg: Config, id: string): AgentAdminResult<never> | null {\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n return null;\n}\n\nexport async function readAgentAvatarFile(\n cfg: Config,\n agentId: string,\n): Promise<AgentAdminResult<{ agentId: string; buffer: Buffer; contentType: string; path: string }>> {\n const missingAgent = assertAgentExistsForAvatar(cfg, agentId);\n if (missingAgent) {\n return missingAgent;\n }\n const id = normalizeAgentId(agentId);\n const root = await profileMarkdownRootReal(cfg, id);\n for (const name of agentAvatarFilenames()) {\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n continue;\n }\n try {\n const st = await stat(abs);\n if (!st.isFile() || st.size <= 0 || st.size > AGENT_AVATAR_MAX_BYTES) {\n continue;\n }\n const buffer = await readFile(abs);\n const detected = detectImageMimeFromBytes(buffer);\n if (!detected) {\n continue;\n }\n return { ok: true, data: { agentId: id, buffer, contentType: detected, path: abs } };\n } catch {\n /* try next */\n }\n }\n return { ok: false, error: 'avatar not found', status: 404 };\n}\n\nexport async function writeAgentAvatarFromBase64(\n cfg: Config,\n agentId: string,\n base64: string,\n mimeType: string,\n): Promise<AgentAdminResult<{ agentId: string; path: string }>> {\n const missingAgent = assertAgentExistsForAvatar(cfg, agentId);\n if (missingAgent) {\n return missingAgent;\n }\n const id = normalizeAgentId(agentId);\n const ext = mimeToExt(mimeType);\n if (!ext) {\n return { ok: false, error: 'unsupported mimeType (use image/png, image/jpeg, or image/webp)', status: 400 };\n }\n let raw: Buffer;\n try {\n raw = Buffer.from(base64, 'base64');\n } catch {\n return { ok: false, error: 'invalid base64', status: 400 };\n }\n if (raw.length === 0 || raw.length > AGENT_AVATAR_MAX_BYTES) {\n return { ok: false, error: `avatar must be non-empty and at most ${AGENT_AVATAR_MAX_BYTES} bytes`, status: 400 };\n }\n const detected = detectImageMimeFromBytes(raw);\n if (!detected || !extMatchesDetectedMime(ext, detected)) {\n return { ok: false, error: 'file content does not match declared image type', status: 400 };\n }\n\n const root = await profileMarkdownRootReal(cfg, id);\n const rootReal = await profileMarkdownRootReal(cfg, id);\n const targetName = `${AGENT_AVATAR_BASENAME}${ext}`;\n const abs = resolveWorkspaceSafePath(root, targetName);\n if (!abs || !isPathUnderWorkspace(rootReal, abs)) {\n return { ok: false, error: 'invalid path', status: 400 };\n }\n for (const name of agentAvatarFilenames()) {\n if (name === targetName) {\n continue;\n }\n const other = resolveWorkspaceSafePath(root, name);\n if (other && isPathUnderWorkspace(rootReal, other)) {\n try {\n await unlink(other);\n } catch {\n /* absent */\n }\n }\n }\n await writeFile(abs, raw);\n return { ok: true, data: { agentId: id, path: abs } };\n}\n\nfunction mimeToExtToMime(ext: '.png' | '.jpg' | '.jpeg' | '.webp'): 'image/png' | 'image/jpeg' | 'image/webp' {\n if (ext === '.png') return 'image/png';\n if (ext === '.webp') return 'image/webp';\n return 'image/jpeg';\n}\n\nfunction extMatchesDetectedMime(\n ext: '.png' | '.jpg' | '.jpeg' | '.webp',\n detected: 'image/png' | 'image/jpeg' | 'image/webp',\n): boolean {\n return detected === mimeToExtToMime(ext);\n}\n\n/** Remove any `agent-avatar.*` in the agent profile markdown root. Idempotent: ok even when no file existed. */\nexport async function deleteAgentAvatarFile(cfg: Config, agentId: string): Promise<AgentAdminResult<{ agentId: string }>> {\n const missingAgent = assertAgentExistsForAvatar(cfg, agentId);\n if (missingAgent) {\n return missingAgent;\n }\n const id = normalizeAgentId(agentId);\n const root = await profileMarkdownRootReal(cfg, id);\n const rootReal = await profileMarkdownRootReal(cfg, id);\n for (const name of agentAvatarFilenames()) {\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs || !isPathUnderWorkspace(rootReal, abs)) {\n continue;\n }\n try {\n await unlink(abs);\n } catch {\n /* absent */\n }\n }\n return { ok: true, data: { agentId: id } };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agents-admin.js","names":["pathResolve"],"sources":["../../../src/gateway/agents-admin.ts"],"sourcesContent":["/**\n * Gateway REST helpers for multi-agent management.\n */\n\nimport { cp, mkdir, readdir, readFile, realpath, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve as pathResolve } from 'node:path';\n\nimport {\n listAgentEntries,\n normalizeAgentId,\n resolveAgentDir,\n resolveAgentProfileDir,\n resolveAgentWorkspaceDir,\n resolveDefaultAgentId,\n resolveUserPath,\n validateAgentIdForNewAgent,\n} from '../agent/agent-scope.js';\nimport {\n AGENT_PROFILE_MARKDOWN_SYSTEM_FILES,\n REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET,\n} from '../agent/context/workspace.js';\nimport { seedAgentProfileMarkdownFiles } from '../agent/context/workspace-seed.js';\nimport {\n resolveEffectiveAgentManifest,\n type ResolveManifestResult,\n} from '../agent-manifest/resolver.js';\nimport {\n applyAgentConfig,\n findAgentEntryIndex,\n getAgentDeleteBlocker,\n pruneAgentConfig,\n removeAgentDirsFromDisk,\n} from '../commands/agents.config.js';\nimport type { AgentModelsConfig, Config } from '../config/schema.js';\nimport { resolveUserProfilePath, WORKSPACE_FILES } from '../config/paths.js';\nimport { resolveEffectiveAgentProfile } from '../config/agent-profile.js';\nimport type { AgentTypedModel } from '../config/schema.js';\nimport { resolveEffectiveTypedModels } from '../config/agent-typed-models.js';\nimport { GATEWAY_BUILTIN_TOOL_IDS } from './agent-builtin-tools.js';\nimport { isPathUnderWorkspace, resolveWorkspaceSafePath } from './workspace-editor-path.js';\n\nconst EDITABLE_PROFILE_MARKDOWN_NAMES = new Set<string>([...AGENT_PROFILE_MARKDOWN_SYSTEM_FILES]);\n\nexport type GatewayAgentTypedModelsInfo = {\n defaultRole: string;\n preset: AgentTypedModel[];\n entry?: AgentTypedModel[];\n effective: AgentTypedModel[];\n};\n\nexport type GatewayAgentRow = {\n id: string;\n name?: string;\n description?: string;\n language?: string;\n /** Value from `IDENTITY.md` **Avatar:** line when present (may be URL, `xopc:…`, etc.). */\n avatar?: string;\n workspace: string;\n /** Absolute directory for profile Markdown (`SOUL.md`, …) and gateway avatars: `agents/<id>/profile/`. */\n profileDir: string;\n model?: { primary?: string; fallbacks?: string[] };\n typedModels: GatewayAgentTypedModelsInfo;\n extends: string[];\n isDefault: boolean;\n skills: {\n preset: string[];\n entry?: string[];\n effectiveAllowlist?: string[];\n };\n tools: {\n presetDenied: string[];\n entryDisable: string[];\n effectiveDisable: string[];\n };\n};\n\nexport type GatewayAgentsListResponse = {\n defaultId: string;\n agents: GatewayAgentRow[];\n builtinToolIds: string[];\n};\n\nexport type GatewayAgentEffectiveManifestResponse = ResolveManifestResult;\n\nfunction collectAgentIdsForList(cfg: Config): string[] {\n const entries = listAgentEntries(cfg).filter((e) => e.enabled !== false);\n const defaultId = resolveDefaultAgentId(cfg);\n if (entries.length === 0) {\n return [defaultId];\n }\n const ids = new Set<string>();\n for (const e of entries) {\n ids.add(normalizeAgentId(e.id));\n }\n ids.add(defaultId);\n return [...ids];\n}\n\nfunction rolesToTypedModels(\n roles: Record<string, { model: string; fallbacks?: string[]; description?: string }> | undefined,\n): AgentTypedModel[] {\n return Object.entries(roles ?? {})\n .map(([id, role]) => ({ id, ...role }))\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n\n/** Extract `**Avatar:**` value from profile IDENTITY.md (same line shape as the gateway console parser). */\nexport function extractAvatarFromIdentityMarkdown(content: string): string | undefined {\n return parseIdentityMarkdown(content).avatar || undefined;\n}\n\nexport function parseIdentityMarkdown(content: string): {\n name?: string;\n description?: string;\n language?: string;\n avatar?: string;\n} {\n const out: { name?: string; description?: string; language?: string; avatar?: string } = {};\n for (const line of content.split('\\n')) {\n const match = line.match(/^[-*]\\s+\\*\\*(Name|Description|Language|Avatar):\\*\\*\\s*(.*)/i);\n if (match) {\n const key = match[1]?.toLowerCase();\n const v = match[2]?.trim() ?? '';\n if (!v || /^_\\(.*\\)_$/.test(v)) continue;\n if (key === 'name') out.name = v;\n if (key === 'description') out.description = v;\n if (key === 'language') out.language = v;\n if (key === 'avatar') out.avatar = v;\n }\n }\n return out;\n}\n\nexport async function listGatewayAgents(\n cfg: Config,\n _options: { locale?: string } = {},\n): Promise<GatewayAgentsListResponse> {\n const defaultId = resolveDefaultAgentId(cfg);\n const agents: GatewayAgentRow[] = [];\n const presetSkills: string[] | undefined = undefined;\n const presetDenied: string[] = [];\n const presetTypedModels: ReturnType<typeof rolesToTypedModels> = [];\n for (const id of collectAgentIdsForList(cfg)) {\n const profile = resolveEffectiveAgentProfile(cfg, id);\n const entry = listAgentEntries(cfg).find((e) => normalizeAgentId(e.id) === id);\n const model =\n profile.primaryModelRef || profile.fallbacks.length > 0\n ? {\n ...(profile.primaryModelRef ? { primary: profile.primaryModelRef } : {}),\n ...(profile.fallbacks.length > 0 ? { fallbacks: profile.fallbacks } : {}),\n }\n : undefined;\n const entrySkills = entry?.skills.mode === 'allowlist' ? entry.skills.allow ?? [] : undefined;\n const entryDisable = Object.entries(entry?.tools.builtin ?? {})\n .filter(([, policy]) => policy.mode === 'deny')\n .map(([name]) => name);\n const entryTypedModels = rolesToTypedModels(entry?.models?.roles);\n const effectiveTypedModels = [...resolveEffectiveTypedModels(cfg, id).values()].sort((a, b) =>\n a.id.localeCompare(b.id),\n );\n let identity: ReturnType<typeof parseIdentityMarkdown> = {};\n try {\n const identityPath = join(resolveAgentProfileDir(cfg, id), WORKSPACE_FILES.IDENTITY);\n const content = await readFile(identityPath, 'utf-8');\n identity = parseIdentityMarkdown(content);\n } catch {\n /* missing IDENTITY.md or unreadable */\n }\n agents.push({\n id,\n ...(identity.name ? { name: identity.name } : {}),\n ...(identity.description ? { description: identity.description } : {}),\n ...(identity.language ? { language: identity.language } : {}),\n ...(identity.avatar ? { avatar: identity.avatar } : {}),\n workspace: profile.resolvedWorkspacePath,\n profileDir: resolveAgentProfileDir(cfg, id),\n ...(model ? { model } : {}),\n typedModels: {\n defaultRole: profile.manifest.models.defaultRole,\n preset: [...presetTypedModels],\n ...(entryTypedModels.length > 0 ? { entry: entryTypedModels } : {}),\n effective: effectiveTypedModels,\n },\n extends: [...(entry?.extends ?? [])],\n isDefault: id === defaultId,\n skills: {\n preset: presetSkills ? [...presetSkills] : [],\n ...(entrySkills !== undefined ? { entry: [...entrySkills] } : {}),\n ...(profile.skillsAllowlist !== undefined\n ? { effectiveAllowlist: [...profile.skillsAllowlist] }\n : {}),\n },\n tools: {\n presetDenied: [...presetDenied],\n entryDisable: [...entryDisable],\n effectiveDisable: [...profile.tools.denied].sort((a, b) => a.localeCompare(b)),\n },\n });\n }\n agents.sort((a, b) => a.id.localeCompare(b.id));\n return { defaultId, agents, builtinToolIds: [...GATEWAY_BUILTIN_TOOL_IDS] };\n}\n\nexport function getGatewayAgentEffectiveManifest(\n cfg: Config,\n agentIdRaw: string,\n): AgentAdminResult<GatewayAgentEffectiveManifestResponse> {\n const agentId = normalizeAgentId(agentIdRaw);\n const entry = listAgentEntries(cfg).find((e) => normalizeAgentId(e.id) === agentId);\n if (!entry) {\n return { ok: false, error: `agent \"${agentId}\" not found`, status: 404 };\n }\n try {\n return {\n ok: true,\n data: resolveEffectiveAgentManifest({\n agent: entry,\n presets: cfg.agents.capabilityPresets,\n defaultPresetId: cfg.agents.defaultPreset,\n }),\n };\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n status: 400,\n };\n }\n}\n\nexport type CreateAgentBody = {\n /** Optional id seed; normalized agent id defaults from `profileFiles[\"IDENTITY.md\"]` name when omitted. */\n id?: string;\n workspace: string;\n models?: AgentModelsConfig;\n /** Initial `agents.list[].skills` for the new entry. */\n skills?: string[];\n /** Initial `agents.list[].tools` for the new entry. */\n tools?: NonNullable<Config['agents']['list']>[number]['tools'];\n /** Profile markdown files to write after seeding (e.g. `IDENTITY.md`, `SOUL.md`). */\n profileFiles?: Record<string, string>;\n /** Clone from an existing agent id — copies config entry fields and profile directory. */\n cloneFrom?: string;\n};\n\nexport type AgentAdminHttpStatus = 400 | 404 | 409;\n\nexport type AgentAdminResult<T> =\n | { ok: true; data: T }\n | { ok: false; error: string; status?: AgentAdminHttpStatus };\n\nexport function prepareCreateAgent(\n cfg: Config,\n body: CreateAgentBody,\n): AgentAdminResult<{ nextConfig: Config; agentId: string; workspace: string }> {\n const workspace = body.workspace?.trim() ?? '';\n if (!workspace) {\n return { ok: false, error: 'workspace is required', status: 400 };\n }\n if (body.profileFiles !== undefined) {\n if (typeof body.profileFiles !== 'object' || body.profileFiles === null || Array.isArray(body.profileFiles)) {\n return { ok: false, error: 'profileFiles must be an object', status: 400 };\n }\n for (const [name, content] of Object.entries(body.profileFiles)) {\n const bad = assertAllowedFile(name);\n if (bad) {\n return bad;\n }\n if (typeof content !== 'string') {\n return { ok: false, error: `profileFiles[\"${name}\"] must be a string`, status: 400 };\n }\n }\n }\n if (!body.cloneFrom && typeof body.profileFiles?.[WORKSPACE_FILES.IDENTITY] !== 'string') {\n return { ok: false, error: `profileFiles[\"${WORKSPACE_FILES.IDENTITY}\"] is required`, status: 400 };\n }\n\n const identity = body.profileFiles?.[WORKSPACE_FILES.IDENTITY]\n ? parseIdentityMarkdown(body.profileFiles[WORKSPACE_FILES.IDENTITY])\n : {};\n const nameSeed = identity.name ?? body.id ?? '';\n const idRes = validateAgentIdForNewAgent(body.id, nameSeed);\n if (idRes.ok === false) {\n return { ok: false, error: idRes.error, status: 400 };\n }\n const agentId = idRes.agentId;\n if (findAgentEntryIndex(listAgentEntries(cfg), agentId) >= 0) {\n return { ok: false, error: `agent \"${agentId}\" already exists`, status: 409 };\n }\n\n // Resolve fields from cloneFrom source when present\n let cloneSourceEntry: ReturnType<typeof listAgentEntries>[number] | undefined;\n if (body.cloneFrom) {\n const srcId = normalizeAgentId(body.cloneFrom);\n cloneSourceEntry = listAgentEntries(cfg).find((e) => normalizeAgentId(e.id) === srcId);\n if (!cloneSourceEntry && srcId !== resolveDefaultAgentId(cfg)) {\n return { ok: false, error: `source agent \"${srcId}\" not found`, status: 404 };\n }\n }\n\n const wsAbs = resolveUserPath(workspace);\n\n const rawModels = body.models ?? cloneSourceEntry?.models;\n const effectiveModels =\n rawModels?.roles\n ? {\n defaultRole: rawModels.defaultRole ?? Object.keys(rawModels.roles)[0] ?? 'deep',\n roles: rawModels.roles,\n }\n : undefined;\n if (effectiveModels && !effectiveModels.roles[effectiveModels.defaultRole]) {\n return { ok: false, error: 'models.defaultRole must reference models.roles', status: 400 };\n }\n\n let next = applyAgentConfig(cfg, {\n agentId,\n workspace: wsAbs,\n ...(effectiveModels ? { models: effectiveModels } : {}),\n ...(body.skills !== undefined\n ? { skills: body.skills.map((s) => String(s).trim()).filter(Boolean) }\n : cloneSourceEntry?.skills.mode === 'allowlist' && body.cloneFrom\n ? { skills: [...(cloneSourceEntry.skills.allow ?? [])] }\n : {}),\n ...(body.tools !== undefined ? { tools: body.tools } : cloneSourceEntry?.tools && body.cloneFrom ? { tools: cloneSourceEntry.tools } : {}),\n });\n\n return { ok: true, data: { nextConfig: next, agentId, workspace: wsAbs } };\n}\n\nexport async function finalizeCreateAgentDirs(\n cfg: Config,\n agentId: string,\n opts?: { profileFiles?: Record<string, string>; cloneFrom?: string },\n): Promise<AgentAdminResult<void>> {\n const wsPath = resolveAgentWorkspaceDir(cfg, agentId);\n const profilePath = resolveAgentProfileDir(cfg, agentId);\n const adPath = resolveAgentDir(cfg, agentId);\n await mkdir(wsPath, { recursive: true });\n await mkdir(profilePath, { recursive: true });\n await mkdir(adPath, { recursive: true });\n const id = normalizeAgentId(agentId);\n const displayName = opts?.profileFiles?.[WORKSPACE_FILES.IDENTITY]\n ? (parseIdentityMarkdown(opts.profileFiles[WORKSPACE_FILES.IDENTITY]).name ?? id)\n : id;\n\n // When cloning, copy the entire source profile directory instead of seeding\n if (opts?.cloneFrom) {\n const srcProfilePath = resolveAgentProfileDir(cfg, normalizeAgentId(opts.cloneFrom));\n try {\n const srcStat = await stat(srcProfilePath);\n if (srcStat.isDirectory()) {\n const srcFiles = await readdir(srcProfilePath);\n for (const fileName of srcFiles) {\n const srcFile = join(srcProfilePath, fileName);\n const dstFile = join(profilePath, fileName);\n try {\n const fileStat = await stat(srcFile);\n if (fileStat.isFile()) {\n await cp(srcFile, dstFile);\n }\n } catch {\n /* skip unreadable files */\n }\n }\n }\n } catch {\n // Source profile dir doesn't exist — fall through to normal seed\n seedAgentProfileMarkdownFiles(profilePath, wsPath, { displayName });\n }\n } else {\n seedAgentProfileMarkdownFiles(profilePath, wsPath, { displayName });\n }\n\n const profileFiles = opts?.profileFiles;\n if (profileFiles && Object.keys(profileFiles).length > 0) {\n for (const [name, content] of Object.entries(profileFiles)) {\n const written = await writeAgentProfileFile(cfg, agentId, name, content);\n if (written.ok === false) {\n return written;\n }\n }\n }\n\n return { ok: true, data: undefined };\n}\n\nexport type UpdateAgentBody = {\n workspace?: string;\n extends?: string[];\n models?: {\n defaultRole?: string | null;\n roles?: Record<string, { model: string; fallbacks?: string[]; description?: string }>;\n } | null;\n setDefault?: boolean;\n /** Replace `agents.list[].skills`; `null` resets to all skills. */\n skills?: string[] | null;\n /** Replace `agents.list[].tools`; `null` resets to no explicit policies. */\n tools?: NonNullable<Config['agents']['list']>[number]['tools'] | null;\n /** Replace `agents.list[].memory`; every agent manifest owns its memory policy. */\n memory?: NonNullable<Config['agents']['list']>[number]['memory'];\n};\n\nexport function prepareUpdateAgent(\n cfg: Config,\n agentIdRaw: string,\n body: UpdateAgentBody,\n): AgentAdminResult<{ nextConfig: Config }> {\n const agentId = normalizeAgentId(agentIdRaw);\n let list = [...listAgentEntries(cfg)];\n let idx = findAgentEntryIndex(list, agentId);\n if (idx < 0 && agentId === resolveDefaultAgentId(cfg)) {\n list = [...list, {\n id: agentId,\n enabled: true as const,\n identity: { name: agentId, role: 'Agent', language: 'en', tone: 'direct' },\n responsibilities: { primary: ['Help the user complete tasks'] },\n workspace: { root: `~/.xopc/workspace/${agentId}` },\n tools: { builtin: {} },\n skills: { mode: 'all' },\n memory: { mode: 'confirmWrite', sources: ['session', 'curated'], writePolicy: { curated: 'confirm' } },\n workflows: {},\n boundaries: { requiresConfirmation: [], forbidden: [], escalation: [] },\n }];\n idx = list.length - 1;\n }\n if (idx < 0) {\n return { ok: false, error: `agent \"${agentId}\" not found`, status: 404 };\n }\n\n type Entry = (typeof list)[number];\n const entry: Entry = { ...list[idx] };\n\n if (body.workspace !== undefined) {\n const w = body.workspace.trim();\n if (w) {\n entry.workspace = { root: resolveUserPath(w) };\n }\n }\n if (body.extends !== undefined) {\n const nextExtends = Array.from(new Set(body.extends.map((id) => normalizeAgentId(id)).filter(Boolean)));\n for (const presetId of nextExtends) {\n if (!cfg.agents.capabilityPresets[presetId]) {\n return { ok: false, error: `capability preset \"${presetId}\" not found`, status: 400 };\n }\n }\n if (nextExtends.length > 0) {\n entry.extends = nextExtends;\n } else {\n delete entry.extends;\n }\n }\n if (body.models !== undefined) {\n if (body.models === null) {\n delete entry.models;\n } else {\n if (body.models.defaultRole !== undefined) {\n if (body.models.defaultRole === null || !body.models.defaultRole.trim()) {\n return { ok: false, error: 'models.defaultRole must be a non-empty string', status: 400 };\n }\n entry.models = {\n defaultRole: body.models.defaultRole.trim(),\n roles: entry.models?.roles ?? {},\n ...(entry.models?.policy ? { policy: entry.models.policy } : {}),\n };\n }\n if (Object.hasOwn(body.models, 'roles')) {\n if (body.models.roles !== undefined) {\n const roles = Object.fromEntries(\n Object.entries(body.models.roles)\n .map(([id, row]) => ({\n id: id.trim(),\n model: row.model.trim(),\n fallbacks: (row.fallbacks ?? []).map((ref) => ref.trim()).filter(Boolean),\n description: row.description?.trim(),\n }))\n .filter((row) => row.id && row.model)\n .map((row) => [\n row.id,\n {\n model: row.model,\n ...(row.fallbacks.length > 0 ? { fallbacks: row.fallbacks } : {}),\n ...(row.description ? { description: row.description } : {}),\n },\n ]),\n );\n entry.models = {\n defaultRole: entry.models?.defaultRole ?? Object.keys(roles)[0] ?? 'deep',\n roles,\n ...(entry.models?.policy ? { policy: entry.models.policy } : {}),\n };\n }\n }\n const roles = entry.models?.roles ?? {};\n const defaultRole = entry.models?.defaultRole ?? Object.keys(roles)[0];\n if (!defaultRole || !roles[defaultRole]) {\n return { ok: false, error: 'models.defaultRole must reference models.roles', status: 400 };\n }\n entry.models = { ...entry.models, defaultRole };\n }\n }\n\n if (body.skills !== undefined) {\n if (body.skills === null) {\n entry.skills = { mode: 'all' };\n } else {\n const next = body.skills.map((s) => String(s).trim()).filter(Boolean);\n if (next.length === 0) {\n entry.skills = { mode: 'allowlist', allow: [] };\n } else {\n entry.skills = { mode: 'allowlist', allow: next };\n }\n }\n }\n\n if (body.tools !== undefined) {\n if (body.tools === null) {\n entry.tools = { builtin: {} };\n } else {\n entry.tools = body.tools;\n }\n }\n\n if (body.memory !== undefined) {\n entry.memory = body.memory;\n }\n\n list[idx] = entry;\n let next: Config = {\n ...cfg,\n agents: {\n ...cfg.agents,\n list,\n },\n };\n\n if (body.setDefault === true) {\n next = {\n ...next,\n agents: {\n ...next.agents,\n default: agentId,\n },\n };\n }\n return { ok: true, data: { nextConfig: next } };\n}\n\nexport function prepareDeleteAgent(\n cfg: Config,\n agentIdRaw: string,\n): AgentAdminResult<{ nextConfig: Config; agentId: string }> {\n const agentId = normalizeAgentId(agentIdRaw);\n const blocker = getAgentDeleteBlocker(cfg, agentId);\n if (blocker) {\n return { ok: false, error: blocker, status: 400 };\n }\n if (findAgentEntryIndex(listAgentEntries(cfg), agentId) < 0) {\n return { ok: false, error: `agent \"${agentId}\" not found`, status: 404 };\n }\n const { config: pruned } = pruneAgentConfig(cfg, agentId);\n return { ok: true, data: { nextConfig: pruned, agentId } };\n}\n\nexport async function runAfterDeletePurge(cfg: Config, agentId: string): Promise<void> {\n await removeAgentDirsFromDisk(cfg, agentId);\n}\n\nexport type AgentFileEntry = {\n name: string;\n missing: boolean;\n size?: number;\n updatedAtMs?: number;\n};\n\nasync function profileMarkdownRootReal(cfg: Config, agentId: string): Promise<string> {\n const dir = resolveAgentProfileDir(cfg, agentId);\n await mkdir(dir, { recursive: true });\n try {\n return await realpath(dir);\n } catch {\n return pathResolve(dir);\n }\n}\n\nfunction assertAllowedFile(name: string): AgentAdminResult<never> | null {\n if (!name || name.includes('/') || name.includes('\\\\') || !EDITABLE_PROFILE_MARKDOWN_NAMES.has(name)) {\n return { ok: false, error: `unsupported file \"${name}\"`, status: 400 };\n }\n return null;\n}\n\nexport async function listAgentProfileFiles(\n cfg: Config,\n agentId: string,\n): Promise<AgentAdminResult<{ agentId: string; profileDir: string; files: AgentFileEntry[] }>> {\n const id = normalizeAgentId(agentId);\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n const root = await profileMarkdownRootReal(cfg, id);\n const names = [...EDITABLE_PROFILE_MARKDOWN_NAMES];\n const files: AgentFileEntry[] = [];\n for (const name of names.sort((a, b) => a.localeCompare(b))) {\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n continue;\n }\n try {\n const st = await stat(abs);\n if (!st.isFile()) {\n continue;\n }\n files.push({\n name,\n missing: false,\n size: st.size,\n updatedAtMs: st.mtimeMs,\n });\n } catch {\n if (!REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET.has(name)) {\n continue;\n }\n files.push({ name, missing: true });\n }\n }\n files.sort((a, b) => a.name.localeCompare(b.name));\n return { ok: true, data: { agentId: id, profileDir: root, files } };\n}\n\nexport async function readAgentProfileFile(\n cfg: Config,\n agentId: string,\n name: string,\n): Promise<AgentAdminResult<{ agentId: string; content: string; path: string }>> {\n const bad = assertAllowedFile(name);\n if (bad) {\n return bad;\n }\n const id = normalizeAgentId(agentId);\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n const root = await profileMarkdownRootReal(cfg, id);\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n return { ok: false, error: 'invalid path', status: 400 };\n }\n try {\n const content = await readFile(abs, 'utf-8');\n return { ok: true, data: { agentId: id, content, path: abs } };\n } catch {\n return { ok: false, error: 'file not found', status: 404 };\n }\n}\n\nexport async function writeAgentProfileFile(\n cfg: Config,\n agentId: string,\n name: string,\n content: string,\n): Promise<AgentAdminResult<{ agentId: string; path: string }>> {\n const bad = assertAllowedFile(name);\n if (bad) {\n return bad;\n }\n const id = normalizeAgentId(agentId);\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n const root = await profileMarkdownRootReal(cfg, id);\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n return { ok: false, error: 'invalid path', status: 400 };\n }\n const rootReal = await profileMarkdownRootReal(cfg, id);\n if (!isPathUnderWorkspace(rootReal, abs)) {\n return { ok: false, error: 'path escapes profile markdown root', status: 400 };\n }\n await writeFile(abs, content, 'utf-8');\n return { ok: true, data: { agentId: id, path: abs } };\n}\n\nexport async function readUserProfileFile(): Promise<AgentAdminResult<{ content: string; path: string }>> {\n const path = resolveUserProfilePath();\n try {\n const content = await readFile(path, 'utf-8');\n return { ok: true, data: { content, path } };\n } catch {\n return { ok: true, data: { content: '', path } };\n }\n}\n\nexport async function writeUserProfileFile(\n content: string,\n): Promise<AgentAdminResult<{ path: string }>> {\n const path = resolveUserProfilePath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n return { ok: true, data: { path } };\n}\n\n// ---------------------------------------------------------------------------\n// Binary agent avatar (profile markdown root dir, not a SOUL/IDENTITY markdown file)\n// ---------------------------------------------------------------------------\n\nconst AGENT_AVATAR_MAX_BYTES = 512 * 1024;\nconst AGENT_AVATAR_BASENAME = 'agent-avatar';\n\nconst AGENT_AVATAR_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp'] as const;\n\nfunction agentAvatarFilenames(): string[] {\n return AGENT_AVATAR_EXTENSIONS.map((ext) => `${AGENT_AVATAR_BASENAME}${ext}`);\n}\n\nfunction mimeToExt(mime: string): '.png' | '.jpg' | '.jpeg' | '.webp' | null {\n const m = mime.toLowerCase().trim();\n if (m === 'image/png') return '.png';\n if (m === 'image/jpeg' || m === 'image/jpg') return '.jpg';\n if (m === 'image/webp') return '.webp';\n return null;\n}\n\nfunction detectImageMimeFromBytes(buf: Uint8Array): 'image/png' | 'image/jpeg' | 'image/webp' | null {\n if (buf.length >= 8 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {\n return 'image/png';\n }\n if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) {\n return 'image/jpeg';\n }\n if (\n buf.length >= 12 &&\n buf[0] === 0x52 &&\n buf[1] === 0x49 &&\n buf[2] === 0x46 &&\n buf[3] === 0x46 &&\n buf[8] === 0x57 &&\n buf[9] === 0x45 &&\n buf[10] === 0x42 &&\n buf[11] === 0x50\n ) {\n return 'image/webp';\n }\n return null;\n}\n\nfunction assertAgentExistsForAvatar(cfg: Config, id: string): AgentAdminResult<never> | null {\n if (collectAgentIdsForList(cfg).every((x) => x !== id)) {\n return { ok: false, error: `agent \"${id}\" not found`, status: 404 };\n }\n return null;\n}\n\nexport async function readAgentAvatarFile(\n cfg: Config,\n agentId: string,\n): Promise<AgentAdminResult<{ agentId: string; buffer: Buffer; contentType: string; path: string }>> {\n const missingAgent = assertAgentExistsForAvatar(cfg, agentId);\n if (missingAgent) {\n return missingAgent;\n }\n const id = normalizeAgentId(agentId);\n const root = await profileMarkdownRootReal(cfg, id);\n for (const name of agentAvatarFilenames()) {\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs) {\n continue;\n }\n try {\n const st = await stat(abs);\n if (!st.isFile() || st.size <= 0 || st.size > AGENT_AVATAR_MAX_BYTES) {\n continue;\n }\n const buffer = await readFile(abs);\n const detected = detectImageMimeFromBytes(buffer);\n if (!detected) {\n continue;\n }\n return { ok: true, data: { agentId: id, buffer, contentType: detected, path: abs } };\n } catch {\n /* try next */\n }\n }\n return { ok: false, error: 'avatar not found', status: 404 };\n}\n\nexport async function writeAgentAvatarFromBase64(\n cfg: Config,\n agentId: string,\n base64: string,\n mimeType: string,\n): Promise<AgentAdminResult<{ agentId: string; path: string }>> {\n const missingAgent = assertAgentExistsForAvatar(cfg, agentId);\n if (missingAgent) {\n return missingAgent;\n }\n const id = normalizeAgentId(agentId);\n const ext = mimeToExt(mimeType);\n if (!ext) {\n return { ok: false, error: 'unsupported mimeType (use image/png, image/jpeg, or image/webp)', status: 400 };\n }\n let raw: Buffer;\n try {\n raw = Buffer.from(base64, 'base64');\n } catch {\n return { ok: false, error: 'invalid base64', status: 400 };\n }\n if (raw.length === 0 || raw.length > AGENT_AVATAR_MAX_BYTES) {\n return { ok: false, error: `avatar must be non-empty and at most ${AGENT_AVATAR_MAX_BYTES} bytes`, status: 400 };\n }\n const detected = detectImageMimeFromBytes(raw);\n if (!detected || !extMatchesDetectedMime(ext, detected)) {\n return { ok: false, error: 'file content does not match declared image type', status: 400 };\n }\n\n const root = await profileMarkdownRootReal(cfg, id);\n const rootReal = await profileMarkdownRootReal(cfg, id);\n const targetName = `${AGENT_AVATAR_BASENAME}${ext}`;\n const abs = resolveWorkspaceSafePath(root, targetName);\n if (!abs || !isPathUnderWorkspace(rootReal, abs)) {\n return { ok: false, error: 'invalid path', status: 400 };\n }\n for (const name of agentAvatarFilenames()) {\n if (name === targetName) {\n continue;\n }\n const other = resolveWorkspaceSafePath(root, name);\n if (other && isPathUnderWorkspace(rootReal, other)) {\n try {\n await unlink(other);\n } catch {\n /* absent */\n }\n }\n }\n await writeFile(abs, raw);\n return { ok: true, data: { agentId: id, path: abs } };\n}\n\nfunction mimeToExtToMime(ext: '.png' | '.jpg' | '.jpeg' | '.webp'): 'image/png' | 'image/jpeg' | 'image/webp' {\n if (ext === '.png') return 'image/png';\n if (ext === '.webp') return 'image/webp';\n return 'image/jpeg';\n}\n\nfunction extMatchesDetectedMime(\n ext: '.png' | '.jpg' | '.jpeg' | '.webp',\n detected: 'image/png' | 'image/jpeg' | 'image/webp',\n): boolean {\n return detected === mimeToExtToMime(ext);\n}\n\n/** Remove any `agent-avatar.*` in the agent profile markdown root. Idempotent: ok even when no file existed. */\nexport async function deleteAgentAvatarFile(cfg: Config, agentId: string): Promise<AgentAdminResult<{ agentId: string }>> {\n const missingAgent = assertAgentExistsForAvatar(cfg, agentId);\n if (missingAgent) {\n return missingAgent;\n }\n const id = normalizeAgentId(agentId);\n const root = await profileMarkdownRootReal(cfg, id);\n const rootReal = await profileMarkdownRootReal(cfg, id);\n for (const name of agentAvatarFilenames()) {\n const abs = resolveWorkspaceSafePath(root, name);\n if (!abs || !isPathUnderWorkspace(rootReal, abs)) {\n continue;\n }\n try {\n await unlink(abs);\n } catch {\n /* absent */\n }\n }\n return { ok: true, data: { agentId: id } };\n}\n"],"mappings":"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"}
@@ -16,6 +16,7 @@ export type CapabilityPresetRow = CapabilityPreset & {
16
16
  usage: CapabilityPresetAgentUsage[];
17
17
  };
18
18
  export type CapabilityPresetsListResponse = {
19
+ defaultPresetId: string;
19
20
  presets: CapabilityPresetRow[];
20
21
  agents: Array<{
21
22
  id: string;
@@ -9,7 +9,8 @@ function normalizePresetId(id) {
9
9
  return id.trim().toLowerCase();
10
10
  }
11
11
  function agentUsage(cfg, presetId) {
12
- return cfg.agents.list.filter((agent) => (agent.extends ?? []).includes(presetId)).map((agent) => ({
12
+ const defaultPresetId = cfg.agents.defaultPreset || "default";
13
+ return cfg.agents.list.filter((agent) => presetId === defaultPresetId || (agent.extends ?? []).includes(presetId)).map((agent) => ({
13
14
  agentId: agent.id,
14
15
  ...agent.identity.name ? { agentName: agent.identity.name } : {}
15
16
  })).sort((a, b) => a.agentId.localeCompare(b.agentId));
@@ -91,16 +92,19 @@ function nextConfigWithPresets(cfg, presets) {
91
92
  };
92
93
  }
93
94
  function listCapabilityPresets(cfg) {
95
+ const presets = Object.values(presetMap(cfg)).map((preset) => ({
96
+ ...preset,
97
+ usage: agentUsage(cfg, preset.id)
98
+ })).sort((a, b) => a.id.localeCompare(b.id));
99
+ const agents = cfg.agents.list.map((agent) => ({
100
+ id: agent.id,
101
+ ...agent.identity.name ? { name: agent.identity.name } : {},
102
+ extends: [...agent.extends ?? []]
103
+ })).sort((a, b) => a.id.localeCompare(b.id));
94
104
  return {
95
- presets: Object.values(presetMap(cfg)).map((preset) => ({
96
- ...preset,
97
- usage: agentUsage(cfg, preset.id)
98
- })).sort((a, b) => a.id.localeCompare(b.id)),
99
- agents: cfg.agents.list.map((agent) => ({
100
- id: agent.id,
101
- ...agent.identity.name ? { name: agent.identity.name } : {},
102
- extends: [...agent.extends ?? []]
103
- })).sort((a, b) => a.id.localeCompare(b.id)),
105
+ defaultPresetId: cfg.agents.defaultPreset,
106
+ presets,
107
+ agents,
104
108
  builtinToolIds: [...GATEWAY_BUILTIN_TOOL_IDS]
105
109
  };
106
110
  }
@@ -198,6 +202,11 @@ function prepareDeleteCapabilityPreset(cfg, presetIdRaw) {
198
202
  error: `capability preset "${presetId}" not found`,
199
203
  status: 404
200
204
  };
205
+ if (presetId === cfg.agents.defaultPreset) return {
206
+ ok: false,
207
+ error: `capability preset "${presetId}" is the global default and cannot be deleted`,
208
+ status: 409
209
+ };
201
210
  const usage = agentUsage(cfg, presetId);
202
211
  if (usage.length > 0) return {
203
212
  ok: false,
@@ -1 +1 @@
1
- {"version":3,"file":"capability-presets-admin.js","names":[],"sources":["../../../src/gateway/capability-presets-admin.ts"],"sourcesContent":["import { CapabilityPresetSchema, type CapabilityPreset } from '../agent-manifest/schema.js';\nimport type { Config } from '../config/schema.js';\nimport { GATEWAY_BUILTIN_TOOL_IDS } from './agent-builtin-tools.js';\n\nexport type CapabilityPresetAdminResult<T> =\n | { ok: true; data: T }\n | { ok: false; error: string; status?: 400 | 404 | 409 | 500 };\n\nexport type CapabilityPresetAgentUsage = {\n agentId: string;\n agentName?: string;\n};\n\nexport type CapabilityPresetRow = CapabilityPreset & {\n usage: CapabilityPresetAgentUsage[];\n};\n\nexport type CapabilityPresetsListResponse = {\n presets: CapabilityPresetRow[];\n agents: Array<{ id: string; name?: string; extends: string[] }>;\n builtinToolIds: string[];\n};\n\nexport type CreateCapabilityPresetBody = {\n id?: string;\n name?: string;\n description?: string;\n};\n\nexport type UpdateCapabilityPresetBody = {\n name?: string;\n description?: string | null;\n version?: number;\n extends?: string[] | null;\n models?: CapabilityPreset['models'] | null;\n tools?: CapabilityPreset['tools'] | null;\n skills?: CapabilityPreset['skills'] | null;\n memory?: CapabilityPreset['memory'] | null;\n workflows?: CapabilityPreset['workflows'] | null;\n boundaries?: CapabilityPreset['boundaries'] | null;\n runtime?: CapabilityPreset['runtime'] | null;\n locks?: string[] | null;\n};\n\nfunction presetMap(cfg: Config): Record<string, CapabilityPreset> {\n return cfg.agents.capabilityPresets ?? {};\n}\n\nfunction normalizePresetId(id: string): string {\n return id.trim().toLowerCase();\n}\n\nfunction agentUsage(cfg: Config, presetId: string): CapabilityPresetAgentUsage[] {\n return cfg.agents.list\n .filter((agent) => (agent.extends ?? []).includes(presetId))\n .map((agent) => ({\n agentId: agent.id,\n ...(agent.identity.name ? { agentName: agent.identity.name } : {}),\n }))\n .sort((a, b) => a.agentId.localeCompare(b.agentId));\n}\n\nfunction validatePresetReferences(\n presets: Record<string, CapabilityPreset>,\n): CapabilityPresetAdminResult<void> {\n for (const [id, preset] of Object.entries(presets)) {\n for (const parent of preset.extends ?? []) {\n if (!presets[parent]) {\n return { ok: false, error: `capability preset \"${id}\" extends missing preset \"${parent}\"`, status: 400 };\n }\n }\n }\n\n const visiting = new Set<string>();\n const visited = new Set<string>();\n const visit = (id: string, stack: string[]): CapabilityPresetAdminResult<void> => {\n if (visiting.has(id)) {\n return { ok: false, error: `capability preset cycle detected: ${[...stack, id].join(' -> ')}`, status: 400 };\n }\n if (visited.has(id)) {\n return { ok: true, data: undefined };\n }\n visiting.add(id);\n for (const parent of presets[id]?.extends ?? []) {\n const res = visit(parent, [...stack, id]);\n if (!res.ok) return res;\n }\n visiting.delete(id);\n visited.add(id);\n return { ok: true, data: undefined };\n };\n\n for (const id of Object.keys(presets)) {\n const res = visit(id, []);\n if (!res.ok) return res;\n }\n return { ok: true, data: undefined };\n}\n\nfunction validateAgentPresetReferences(cfg: Config): CapabilityPresetAdminResult<void> {\n const presets = presetMap(cfg);\n for (const agent of cfg.agents.list) {\n for (const presetId of agent.extends ?? []) {\n if (!presets[presetId]) {\n return { ok: false, error: `agent \"${agent.id}\" extends missing preset \"${presetId}\"`, status: 400 };\n }\n }\n }\n return { ok: true, data: undefined };\n}\n\nfunction nextConfigWithPresets(\n cfg: Config,\n presets: Record<string, CapabilityPreset>,\n): CapabilityPresetAdminResult<{ nextConfig: Config }> {\n const refs = validatePresetReferences(presets);\n if (refs.ok === false) return { ok: false, error: refs.error, status: refs.status };\n const nextConfig: Config = {\n ...cfg,\n agents: {\n ...cfg.agents,\n capabilityPresets: presets,\n },\n };\n const agentRefs = validateAgentPresetReferences(nextConfig);\n if (agentRefs.ok === false) return { ok: false, error: agentRefs.error, status: agentRefs.status };\n return { ok: true, data: { nextConfig } };\n}\n\nexport function listCapabilityPresets(cfg: Config): CapabilityPresetsListResponse {\n const presets = Object.values(presetMap(cfg))\n .map((preset) => ({ ...preset, usage: agentUsage(cfg, preset.id) }))\n .sort((a, b) => a.id.localeCompare(b.id));\n const agents = cfg.agents.list\n .map((agent) => ({\n id: agent.id,\n ...(agent.identity.name ? { name: agent.identity.name } : {}),\n extends: [...(agent.extends ?? [])],\n }))\n .sort((a, b) => a.id.localeCompare(b.id));\n return { presets, agents, builtinToolIds: [...GATEWAY_BUILTIN_TOOL_IDS] };\n}\n\nexport function prepareCreateCapabilityPreset(\n cfg: Config,\n body: CreateCapabilityPresetBody,\n): CapabilityPresetAdminResult<{ nextConfig: Config; presetId: string }> {\n const id = normalizePresetId(body.id ?? '');\n const name = body.name?.trim() || id;\n const description = body.description?.trim();\n const parsed = CapabilityPresetSchema.safeParse({\n id,\n name,\n version: 1,\n ...(description ? { description } : {}),\n });\n if (!parsed.success) {\n return { ok: false, error: parsed.error.issues[0]?.message ?? 'capability preset is invalid', status: 400 };\n }\n const presets = presetMap(cfg);\n if (presets[id]) {\n return { ok: false, error: `capability preset \"${id}\" already exists`, status: 409 };\n }\n const next = nextConfigWithPresets(cfg, { ...presets, [id]: parsed.data });\n if (next.ok === false) return { ok: false, error: next.error, status: next.status };\n return { ok: true, data: { ...next.data, presetId: id } };\n}\n\nexport function prepareUpdateCapabilityPreset(\n cfg: Config,\n presetIdRaw: string,\n body: UpdateCapabilityPresetBody,\n): CapabilityPresetAdminResult<{ nextConfig: Config }> {\n const presetId = normalizePresetId(presetIdRaw);\n const presets = presetMap(cfg);\n const current = presets[presetId];\n if (!current) {\n return { ok: false, error: `capability preset \"${presetId}\" not found`, status: 404 };\n }\n const nextPreset: CapabilityPreset = { ...current };\n\n if (body.name !== undefined) {\n const name = body.name.trim();\n if (!name) {\n return { ok: false, error: 'name must be a non-empty string', status: 400 };\n }\n nextPreset.name = name;\n }\n if (body.description !== undefined) {\n if (body.description === null || !body.description.trim()) {\n delete nextPreset.description;\n } else {\n nextPreset.description = body.description.trim();\n }\n }\n if (body.version !== undefined) nextPreset.version = body.version;\n for (const key of ['extends', 'models', 'tools', 'skills', 'memory', 'workflows', 'boundaries', 'runtime', 'locks'] as const) {\n if (body[key] === undefined) continue;\n if (body[key] === null) {\n delete nextPreset[key];\n } else {\n (nextPreset as Record<string, unknown>)[key] = body[key];\n }\n }\n\n const parsed = CapabilityPresetSchema.safeParse(nextPreset);\n if (!parsed.success) {\n return { ok: false, error: parsed.error.issues[0]?.message ?? 'capability preset is invalid', status: 400 };\n }\n return nextConfigWithPresets(cfg, { ...presets, [presetId]: parsed.data });\n}\n\nexport function prepareDeleteCapabilityPreset(\n cfg: Config,\n presetIdRaw: string,\n): CapabilityPresetAdminResult<{ nextConfig: Config }> {\n const presetId = normalizePresetId(presetIdRaw);\n const presets = presetMap(cfg);\n if (!presets[presetId]) {\n return { ok: false, error: `capability preset \"${presetId}\" not found`, status: 404 };\n }\n const usage = agentUsage(cfg, presetId);\n if (usage.length > 0) {\n return {\n ok: false,\n error: `capability preset \"${presetId}\" is used by agents: ${usage.map((u) => u.agentId).join(', ')}`,\n status: 409,\n };\n }\n const nextPresets = { ...presets };\n delete nextPresets[presetId];\n return nextConfigWithPresets(cfg, nextPresets);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"capability-presets-admin.js","names":[],"sources":["../../../src/gateway/capability-presets-admin.ts"],"sourcesContent":["import {\n CapabilityPresetSchema,\n DEFAULT_CAPABILITY_PRESET_ID,\n type CapabilityPreset,\n} from '../agent-manifest/schema.js';\nimport type { Config } from '../config/schema.js';\nimport { GATEWAY_BUILTIN_TOOL_IDS } from './agent-builtin-tools.js';\n\nexport type CapabilityPresetAdminResult<T> =\n | { ok: true; data: T }\n | { ok: false; error: string; status?: 400 | 404 | 409 | 500 };\n\nexport type CapabilityPresetAgentUsage = {\n agentId: string;\n agentName?: string;\n};\n\nexport type CapabilityPresetRow = CapabilityPreset & {\n usage: CapabilityPresetAgentUsage[];\n};\n\nexport type CapabilityPresetsListResponse = {\n defaultPresetId: string;\n presets: CapabilityPresetRow[];\n agents: Array<{ id: string; name?: string; extends: string[] }>;\n builtinToolIds: string[];\n};\n\nexport type CreateCapabilityPresetBody = {\n id?: string;\n name?: string;\n description?: string;\n};\n\nexport type UpdateCapabilityPresetBody = {\n name?: string;\n description?: string | null;\n version?: number;\n extends?: string[] | null;\n models?: CapabilityPreset['models'] | null;\n tools?: CapabilityPreset['tools'] | null;\n skills?: CapabilityPreset['skills'] | null;\n memory?: CapabilityPreset['memory'] | null;\n workflows?: CapabilityPreset['workflows'] | null;\n boundaries?: CapabilityPreset['boundaries'] | null;\n runtime?: CapabilityPreset['runtime'] | null;\n locks?: string[] | null;\n};\n\nfunction presetMap(cfg: Config): Record<string, CapabilityPreset> {\n return cfg.agents.capabilityPresets ?? {};\n}\n\nfunction normalizePresetId(id: string): string {\n return id.trim().toLowerCase();\n}\n\nfunction agentUsage(cfg: Config, presetId: string): CapabilityPresetAgentUsage[] {\n const defaultPresetId = cfg.agents.defaultPreset || DEFAULT_CAPABILITY_PRESET_ID;\n return cfg.agents.list\n .filter((agent) => presetId === defaultPresetId || (agent.extends ?? []).includes(presetId))\n .map((agent) => ({\n agentId: agent.id,\n ...(agent.identity.name ? { agentName: agent.identity.name } : {}),\n }))\n .sort((a, b) => a.agentId.localeCompare(b.agentId));\n}\n\nfunction validatePresetReferences(\n presets: Record<string, CapabilityPreset>,\n): CapabilityPresetAdminResult<void> {\n for (const [id, preset] of Object.entries(presets)) {\n for (const parent of preset.extends ?? []) {\n if (!presets[parent]) {\n return { ok: false, error: `capability preset \"${id}\" extends missing preset \"${parent}\"`, status: 400 };\n }\n }\n }\n\n const visiting = new Set<string>();\n const visited = new Set<string>();\n const visit = (id: string, stack: string[]): CapabilityPresetAdminResult<void> => {\n if (visiting.has(id)) {\n return { ok: false, error: `capability preset cycle detected: ${[...stack, id].join(' -> ')}`, status: 400 };\n }\n if (visited.has(id)) {\n return { ok: true, data: undefined };\n }\n visiting.add(id);\n for (const parent of presets[id]?.extends ?? []) {\n const res = visit(parent, [...stack, id]);\n if (!res.ok) return res;\n }\n visiting.delete(id);\n visited.add(id);\n return { ok: true, data: undefined };\n };\n\n for (const id of Object.keys(presets)) {\n const res = visit(id, []);\n if (!res.ok) return res;\n }\n return { ok: true, data: undefined };\n}\n\nfunction validateAgentPresetReferences(cfg: Config): CapabilityPresetAdminResult<void> {\n const presets = presetMap(cfg);\n for (const agent of cfg.agents.list) {\n for (const presetId of agent.extends ?? []) {\n if (!presets[presetId]) {\n return { ok: false, error: `agent \"${agent.id}\" extends missing preset \"${presetId}\"`, status: 400 };\n }\n }\n }\n return { ok: true, data: undefined };\n}\n\nfunction nextConfigWithPresets(\n cfg: Config,\n presets: Record<string, CapabilityPreset>,\n): CapabilityPresetAdminResult<{ nextConfig: Config }> {\n const refs = validatePresetReferences(presets);\n if (refs.ok === false) return { ok: false, error: refs.error, status: refs.status };\n const nextConfig: Config = {\n ...cfg,\n agents: {\n ...cfg.agents,\n capabilityPresets: presets,\n },\n };\n const agentRefs = validateAgentPresetReferences(nextConfig);\n if (agentRefs.ok === false) return { ok: false, error: agentRefs.error, status: agentRefs.status };\n return { ok: true, data: { nextConfig } };\n}\n\nexport function listCapabilityPresets(cfg: Config): CapabilityPresetsListResponse {\n const presets = Object.values(presetMap(cfg))\n .map((preset) => ({ ...preset, usage: agentUsage(cfg, preset.id) }))\n .sort((a, b) => a.id.localeCompare(b.id));\n const agents = cfg.agents.list\n .map((agent) => ({\n id: agent.id,\n ...(agent.identity.name ? { name: agent.identity.name } : {}),\n extends: [...(agent.extends ?? [])],\n }))\n .sort((a, b) => a.id.localeCompare(b.id));\n return { defaultPresetId: cfg.agents.defaultPreset, presets, agents, builtinToolIds: [...GATEWAY_BUILTIN_TOOL_IDS] };\n}\n\nexport function prepareCreateCapabilityPreset(\n cfg: Config,\n body: CreateCapabilityPresetBody,\n): CapabilityPresetAdminResult<{ nextConfig: Config; presetId: string }> {\n const id = normalizePresetId(body.id ?? '');\n const name = body.name?.trim() || id;\n const description = body.description?.trim();\n const parsed = CapabilityPresetSchema.safeParse({\n id,\n name,\n version: 1,\n ...(description ? { description } : {}),\n });\n if (!parsed.success) {\n return { ok: false, error: parsed.error.issues[0]?.message ?? 'capability preset is invalid', status: 400 };\n }\n const presets = presetMap(cfg);\n if (presets[id]) {\n return { ok: false, error: `capability preset \"${id}\" already exists`, status: 409 };\n }\n const next = nextConfigWithPresets(cfg, { ...presets, [id]: parsed.data });\n if (next.ok === false) return { ok: false, error: next.error, status: next.status };\n return { ok: true, data: { ...next.data, presetId: id } };\n}\n\nexport function prepareUpdateCapabilityPreset(\n cfg: Config,\n presetIdRaw: string,\n body: UpdateCapabilityPresetBody,\n): CapabilityPresetAdminResult<{ nextConfig: Config }> {\n const presetId = normalizePresetId(presetIdRaw);\n const presets = presetMap(cfg);\n const current = presets[presetId];\n if (!current) {\n return { ok: false, error: `capability preset \"${presetId}\" not found`, status: 404 };\n }\n const nextPreset: CapabilityPreset = { ...current };\n\n if (body.name !== undefined) {\n const name = body.name.trim();\n if (!name) {\n return { ok: false, error: 'name must be a non-empty string', status: 400 };\n }\n nextPreset.name = name;\n }\n if (body.description !== undefined) {\n if (body.description === null || !body.description.trim()) {\n delete nextPreset.description;\n } else {\n nextPreset.description = body.description.trim();\n }\n }\n if (body.version !== undefined) nextPreset.version = body.version;\n for (const key of ['extends', 'models', 'tools', 'skills', 'memory', 'workflows', 'boundaries', 'runtime', 'locks'] as const) {\n if (body[key] === undefined) continue;\n if (body[key] === null) {\n delete nextPreset[key];\n } else {\n (nextPreset as Record<string, unknown>)[key] = body[key];\n }\n }\n\n const parsed = CapabilityPresetSchema.safeParse(nextPreset);\n if (!parsed.success) {\n return { ok: false, error: parsed.error.issues[0]?.message ?? 'capability preset is invalid', status: 400 };\n }\n return nextConfigWithPresets(cfg, { ...presets, [presetId]: parsed.data });\n}\n\nexport function prepareDeleteCapabilityPreset(\n cfg: Config,\n presetIdRaw: string,\n): CapabilityPresetAdminResult<{ nextConfig: Config }> {\n const presetId = normalizePresetId(presetIdRaw);\n const presets = presetMap(cfg);\n if (!presets[presetId]) {\n return { ok: false, error: `capability preset \"${presetId}\" not found`, status: 404 };\n }\n if (presetId === cfg.agents.defaultPreset) {\n return { ok: false, error: `capability preset \"${presetId}\" is the global default and cannot be deleted`, status: 409 };\n }\n const usage = agentUsage(cfg, presetId);\n if (usage.length > 0) {\n return {\n ok: false,\n error: `capability preset \"${presetId}\" is used by agents: ${usage.map((u) => u.agentId).join(', ')}`,\n status: 409,\n };\n }\n const nextPresets = { ...presets };\n delete nextPresets[presetId];\n return nextConfigWithPresets(cfg, nextPresets);\n}\n"],"mappings":";;;aAIqC;AA6CrC,SAAS,UAAU,KAA+C;AAChE,QAAO,IAAI,OAAO,qBAAqB,EAAE;;AAG3C,SAAS,kBAAkB,IAAoB;AAC7C,QAAO,GAAG,MAAM,CAAC,aAAa;;AAGhC,SAAS,WAAW,KAAa,UAAgD;CAC/E,MAAM,kBAAkB,IAAI,OAAO,iBAAA;AACnC,QAAO,IAAI,OAAO,KACf,QAAQ,UAAU,aAAa,oBAAoB,MAAM,WAAW,EAAE,EAAE,SAAS,SAAS,CAAC,CAC3F,KAAK,WAAW;EACf,SAAS,MAAM;EACf,GAAI,MAAM,SAAS,OAAO,EAAE,WAAW,MAAM,SAAS,MAAM,GAAG,EAAE;EAClE,EAAE,CACF,MAAM,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,QAAQ,CAAC;;AAGvD,SAAS,yBACP,SACmC;AACnC,MAAK,MAAM,CAAC,IAAI,WAAW,OAAO,QAAQ,QAAQ,CAChD,MAAK,MAAM,UAAU,OAAO,WAAW,EAAE,CACvC,KAAI,CAAC,QAAQ,QACX,QAAO;EAAE,IAAI;EAAO,OAAO,sBAAsB,GAAG,4BAA4B,OAAO;EAAI,QAAQ;EAAK;CAK9G,MAAM,2BAAW,IAAI,KAAa;CAClC,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,SAAS,IAAY,UAAuD;AAChF,MAAI,SAAS,IAAI,GAAG,CAClB,QAAO;GAAE,IAAI;GAAO,OAAO,qCAAqC,CAAC,GAAG,OAAO,GAAG,CAAC,KAAK,OAAO;GAAI,QAAQ;GAAK;AAE9G,MAAI,QAAQ,IAAI,GAAG,CACjB,QAAO;GAAE,IAAI;GAAM,MAAM,KAAA;GAAW;AAEtC,WAAS,IAAI,GAAG;AAChB,OAAK,MAAM,UAAU,QAAQ,KAAK,WAAW,EAAE,EAAE;GAC/C,MAAM,MAAM,MAAM,QAAQ,CAAC,GAAG,OAAO,GAAG,CAAC;AACzC,OAAI,CAAC,IAAI,GAAI,QAAO;;AAEtB,WAAS,OAAO,GAAG;AACnB,UAAQ,IAAI,GAAG;AACf,SAAO;GAAE,IAAI;GAAM,MAAM,KAAA;GAAW;;AAGtC,MAAK,MAAM,MAAM,OAAO,KAAK,QAAQ,EAAE;EACrC,MAAM,MAAM,MAAM,IAAI,EAAE,CAAC;AACzB,MAAI,CAAC,IAAI,GAAI,QAAO;;AAEtB,QAAO;EAAE,IAAI;EAAM,MAAM,KAAA;EAAW;;AAGtC,SAAS,8BAA8B,KAAgD;CACrF,MAAM,UAAU,UAAU,IAAI;AAC9B,MAAK,MAAM,SAAS,IAAI,OAAO,KAC7B,MAAK,MAAM,YAAY,MAAM,WAAW,EAAE,CACxC,KAAI,CAAC,QAAQ,UACX,QAAO;EAAE,IAAI;EAAO,OAAO,UAAU,MAAM,GAAG,4BAA4B,SAAS;EAAI,QAAQ;EAAK;AAI1G,QAAO;EAAE,IAAI;EAAM,MAAM,KAAA;EAAW;;AAGtC,SAAS,sBACP,KACA,SACqD;CACrD,MAAM,OAAO,yBAAyB,QAAQ;AAC9C,KAAI,KAAK,OAAO,MAAO,QAAO;EAAE,IAAI;EAAO,OAAO,KAAK;EAAO,QAAQ,KAAK;EAAQ;CACnF,MAAM,aAAqB;EACzB,GAAG;EACH,QAAQ;GACN,GAAG,IAAI;GACP,mBAAmB;GACpB;EACF;CACD,MAAM,YAAY,8BAA8B,WAAW;AAC3D,KAAI,UAAU,OAAO,MAAO,QAAO;EAAE,IAAI;EAAO,OAAO,UAAU;EAAO,QAAQ,UAAU;EAAQ;AAClG,QAAO;EAAE,IAAI;EAAM,MAAM,EAAE,YAAY;EAAE;;AAG3C,SAAgB,sBAAsB,KAA4C;CAChF,MAAM,UAAU,OAAO,OAAO,UAAU,IAAI,CAAC,CAC1C,KAAK,YAAY;EAAE,GAAG;EAAQ,OAAO,WAAW,KAAK,OAAO,GAAG;EAAE,EAAE,CACnE,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC;CAC3C,MAAM,SAAS,IAAI,OAAO,KACvB,KAAK,WAAW;EACf,IAAI,MAAM;EACV,GAAI,MAAM,SAAS,OAAO,EAAE,MAAM,MAAM,SAAS,MAAM,GAAG,EAAE;EAC5D,SAAS,CAAC,GAAI,MAAM,WAAW,EAAE,CAAE;EACpC,EAAE,CACF,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC;AAC3C,QAAO;EAAE,iBAAiB,IAAI,OAAO;EAAe;EAAS;EAAQ,gBAAgB,CAAC,GAAG,yBAAyB;EAAE;;AAGtH,SAAgB,8BACd,KACA,MACuE;CACvE,MAAM,KAAK,kBAAkB,KAAK,MAAM,GAAG;CAC3C,MAAM,OAAO,KAAK,MAAM,MAAM,IAAI;CAClC,MAAM,cAAc,KAAK,aAAa,MAAM;CAC5C,MAAM,SAAS,uBAAuB,UAAU;EAC9C;EACA;EACA,SAAS;EACT,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;EACvC,CAAC;AACF,KAAI,CAAC,OAAO,QACV,QAAO;EAAE,IAAI;EAAO,OAAO,OAAO,MAAM,OAAO,IAAI,WAAW;EAAgC,QAAQ;EAAK;CAE7G,MAAM,UAAU,UAAU,IAAI;AAC9B,KAAI,QAAQ,IACV,QAAO;EAAE,IAAI;EAAO,OAAO,sBAAsB,GAAG;EAAmB,QAAQ;EAAK;CAEtF,MAAM,OAAO,sBAAsB,KAAK;EAAE,GAAG;GAAU,KAAK,OAAO;EAAM,CAAC;AAC1E,KAAI,KAAK,OAAO,MAAO,QAAO;EAAE,IAAI;EAAO,OAAO,KAAK;EAAO,QAAQ,KAAK;EAAQ;AACnF,QAAO;EAAE,IAAI;EAAM,MAAM;GAAE,GAAG,KAAK;GAAM,UAAU;GAAI;EAAE;;AAG3D,SAAgB,8BACd,KACA,aACA,MACqD;CACrD,MAAM,WAAW,kBAAkB,YAAY;CAC/C,MAAM,UAAU,UAAU,IAAI;CAC9B,MAAM,UAAU,QAAQ;AACxB,KAAI,CAAC,QACH,QAAO;EAAE,IAAI;EAAO,OAAO,sBAAsB,SAAS;EAAc,QAAQ;EAAK;CAEvF,MAAM,aAA+B,EAAE,GAAG,SAAS;AAEnD,KAAI,KAAK,SAAS,KAAA,GAAW;EAC3B,MAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,MAAI,CAAC,KACH,QAAO;GAAE,IAAI;GAAO,OAAO;GAAmC,QAAQ;GAAK;AAE7E,aAAW,OAAO;;AAEpB,KAAI,KAAK,gBAAgB,KAAA,EACvB,KAAI,KAAK,gBAAgB,QAAQ,CAAC,KAAK,YAAY,MAAM,CACvD,QAAO,WAAW;KAElB,YAAW,cAAc,KAAK,YAAY,MAAM;AAGpD,KAAI,KAAK,YAAY,KAAA,EAAW,YAAW,UAAU,KAAK;AAC1D,MAAK,MAAM,OAAO;EAAC;EAAW;EAAU;EAAS;EAAU;EAAU;EAAa;EAAc;EAAW;EAAQ,EAAW;AAC5H,MAAI,KAAK,SAAS,KAAA,EAAW;AAC7B,MAAI,KAAK,SAAS,KAChB,QAAO,WAAW;MAEjB,YAAuC,OAAO,KAAK;;CAIxD,MAAM,SAAS,uBAAuB,UAAU,WAAW;AAC3D,KAAI,CAAC,OAAO,QACV,QAAO;EAAE,IAAI;EAAO,OAAO,OAAO,MAAM,OAAO,IAAI,WAAW;EAAgC,QAAQ;EAAK;AAE7G,QAAO,sBAAsB,KAAK;EAAE,GAAG;GAAU,WAAW,OAAO;EAAM,CAAC;;AAG5E,SAAgB,8BACd,KACA,aACqD;CACrD,MAAM,WAAW,kBAAkB,YAAY;CAC/C,MAAM,UAAU,UAAU,IAAI;AAC9B,KAAI,CAAC,QAAQ,UACX,QAAO;EAAE,IAAI;EAAO,OAAO,sBAAsB,SAAS;EAAc,QAAQ;EAAK;AAEvF,KAAI,aAAa,IAAI,OAAO,cAC1B,QAAO;EAAE,IAAI;EAAO,OAAO,sBAAsB,SAAS;EAAgD,QAAQ;EAAK;CAEzH,MAAM,QAAQ,WAAW,KAAK,SAAS;AACvC,KAAI,MAAM,SAAS,EACjB,QAAO;EACL,IAAI;EACJ,OAAO,sBAAsB,SAAS,uBAAuB,MAAM,KAAK,MAAM,EAAE,QAAQ,CAAC,KAAK,KAAK;EACnG,QAAQ;EACT;CAEH,MAAM,cAAc,EAAE,GAAG,SAAS;AAClC,QAAO,YAAY;AACnB,QAAO,sBAAsB,KAAK,YAAY"}
@@ -0,0 +1,11 @@
1
+ import type { Config } from '../config/schema.js';
2
+ import type { AutomationService } from '../automations/index.js';
3
+ export type DreamingAutomationReconcileResult = {
4
+ created: string[];
5
+ updated: string[];
6
+ disabled: string[];
7
+ };
8
+ export declare function reconcileDreamingAutomations(params: {
9
+ config: Config;
10
+ automationService: AutomationService;
11
+ }): Promise<DreamingAutomationReconcileResult>;