@xopcai/xopc 0.0.88 → 0.0.90

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 (275) hide show
  1. package/README.md +8 -1
  2. package/README.zh-CN.md +8 -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/agents-cPvvYLXo.js +222 -0
  6. package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +1 -0
  7. package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +1 -0
  8. package/dist/gateway/static/root/assets/{channels-status-swr-DIsl75Y3.js → channels-status-swr-BrtH2VzC.js} +1 -1
  9. package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
  10. package/dist/gateway/static/root/assets/cron-api-CyqbgfHM.js +1 -0
  11. package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
  12. package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +1 -0
  13. package/dist/gateway/static/root/assets/dist-BpAiK86n.js +1 -0
  14. package/dist/gateway/static/root/assets/{extension-debug-page-BVJohZoZ.js → extension-debug-page-D6Ak0STa.js} +1 -1
  15. package/dist/gateway/static/root/assets/{extension-page-BT2tmElC.js → extension-page-Q0P3d6DW.js} +1 -1
  16. package/dist/gateway/static/root/assets/{extension-settings-page-BSS47c2j.js → extension-settings-page-CL55LwU_.js} +1 -1
  17. package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +1 -0
  18. package/dist/gateway/static/root/assets/{fetch-BaFNUtkE.js → fetch-Dqa9iTWl.js} +1 -1
  19. package/dist/gateway/static/root/assets/{field-primitives-QwYEq6Hz.js → field-primitives-HUR6JElP.js} +1 -1
  20. package/dist/gateway/static/root/assets/{heartbeat-config-api-BVSidEDJ.js → heartbeat-config-api-DusckjUX.js} +1 -1
  21. package/dist/gateway/static/root/assets/{index-qNrVJp-y.js → index-BYcGfwcE.js} +97 -97
  22. package/dist/gateway/static/root/assets/index-V7MQ7834.css +1 -0
  23. package/dist/gateway/static/root/assets/{logs-page-DDonPVLn.js → logs-page-_HcZ2fgK.js} +1 -1
  24. package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +1 -0
  25. package/dist/gateway/static/root/assets/{settings-form-section-B8N3A3Zo.js → settings-form-section-a0qGVOlr.js} +1 -1
  26. package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +3 -0
  27. package/dist/gateway/static/root/assets/{share-preview-page-Q7KqkO-u.js → share-preview-page-DExl7CJy.js} +1 -1
  28. package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +2 -0
  29. package/dist/gateway/static/root/assets/{theme-store-BbRc5ugR.js → theme-store-C0Ehmdo5.js} +1 -1
  30. package/dist/gateway/static/root/assets/url-fxyYANfA.js +3 -0
  31. package/dist/gateway/static/root/assets/{utils-CxDGduqK.js → utils-DRQryzdn.js} +1 -1
  32. package/dist/gateway/static/root/assets/voice-api-key-field-D0viACE2.js +1 -0
  33. package/dist/gateway/static/root/assets/workflow-page.utils-DnG8JBhV.js +1 -0
  34. package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +27 -0
  35. package/dist/gateway/static/root/index.html +7 -6
  36. package/dist/package.js +1 -1
  37. package/dist/src/agent/agent-manager.d.ts +2 -0
  38. package/dist/src/agent/agent-manager.js +1 -0
  39. package/dist/src/agent/agent-manager.js.map +1 -1
  40. package/dist/src/agent/service.js +2 -1
  41. package/dist/src/agent/service.js.map +1 -1
  42. package/dist/src/agent/service.types.d.ts +3 -1
  43. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
  44. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
  45. package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
  46. package/dist/src/agent/tools/cronjob-tool.js +76 -10
  47. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  48. package/dist/src/agent/tools/edit.d.ts +5 -1
  49. package/dist/src/agent/tools/edit.js +7 -5
  50. package/dist/src/agent/tools/edit.js.map +1 -1
  51. package/dist/src/agent/tools/factory.d.ts +3 -0
  52. package/dist/src/agent/tools/factory.js +4 -25
  53. package/dist/src/agent/tools/factory.js.map +1 -1
  54. package/dist/src/agent/tools/workflow-tool.d.ts +6 -28
  55. package/dist/src/agent/tools/workflow-tool.js +60 -260
  56. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  57. package/dist/src/agent/tools/write.d.ts +5 -1
  58. package/dist/src/agent/tools/write.js +7 -5
  59. package/dist/src/agent/tools/write.js.map +1 -1
  60. package/dist/src/agent/workflow/agent-progress.js +2 -0
  61. package/dist/src/agent/workflow/agent-progress.js.map +1 -1
  62. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
  63. package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
  64. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
  65. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
  66. package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
  67. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
  68. package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
  69. package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
  70. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
  71. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
  72. package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
  73. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
  74. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
  75. package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
  76. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
  77. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
  78. package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
  79. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
  80. package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
  81. package/dist/src/agent/workflow/builtins/index.js +46 -1
  82. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  83. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
  84. package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
  85. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
  86. package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
  87. package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
  88. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
  89. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
  90. package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
  91. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
  92. package/dist/src/agent/workflow/step-labels.js +2 -2
  93. package/dist/src/agent/workflow/step-labels.js.map +1 -1
  94. package/dist/src/agent/workflow/subagent-runner.js +3 -1
  95. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  96. package/dist/src/agent/workflow/types.d.ts +4 -0
  97. package/dist/src/agent/workflow/workflow-child-tools.d.ts +4 -0
  98. package/dist/src/agent/workflow/workflow-child-tools.js +21 -0
  99. package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -0
  100. package/dist/src/auth/credentials.d.ts +14 -2
  101. package/dist/src/auth/credentials.js +38 -13
  102. package/dist/src/auth/credentials.js.map +1 -1
  103. package/dist/src/auth/oauth/types.d.ts +16 -0
  104. package/dist/src/chat-commands/agent-edit.d.ts +4 -0
  105. package/dist/src/chat-commands/agent-edit.js +136 -0
  106. package/dist/src/chat-commands/agent-edit.js.map +1 -0
  107. package/dist/src/chat-commands/index.d.ts +1 -0
  108. package/dist/src/chat-commands/index.js +3 -1
  109. package/dist/src/chat-commands/index.js.map +1 -1
  110. package/dist/src/cli/bin.js +2 -0
  111. package/dist/src/cli/bin.js.map +1 -1
  112. package/dist/src/cli/commands/auth.js +6 -0
  113. package/dist/src/cli/commands/auth.js.map +1 -1
  114. package/dist/src/cli/commands/cron.js +42 -3
  115. package/dist/src/cli/commands/cron.js.map +1 -1
  116. package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
  117. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  118. package/dist/src/cli/commands/onboard/model.js +6 -0
  119. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  120. package/dist/src/cli/commands/update.js +86 -79
  121. package/dist/src/cli/commands/update.js.map +1 -1
  122. package/dist/src/commands/agents.config.d.ts +3 -2
  123. package/dist/src/commands/agents.config.js +5 -2
  124. package/dist/src/commands/agents.config.js.map +1 -1
  125. package/dist/src/config/agent-typed-models.d.ts +2 -7
  126. package/dist/src/config/agent-typed-models.js +3 -14
  127. package/dist/src/config/agent-typed-models.js.map +1 -1
  128. package/dist/src/config/localized-text.d.ts +6 -0
  129. package/dist/src/config/localized-text.js +42 -0
  130. package/dist/src/config/localized-text.js.map +1 -0
  131. package/dist/src/config/models-json.d.ts +6 -6
  132. package/dist/src/config/schema.d.ts +6 -21
  133. package/dist/src/config/schema.js +4 -4
  134. package/dist/src/config/schema.js.map +1 -1
  135. package/dist/src/cron/executor.d.ts +4 -0
  136. package/dist/src/cron/executor.js +169 -5
  137. package/dist/src/cron/executor.js.map +1 -1
  138. package/dist/src/cron/job-content.js +2 -1
  139. package/dist/src/cron/job-content.js.map +1 -1
  140. package/dist/src/cron/types.d.ts +28 -1
  141. package/dist/src/cron/validation.d.ts +80 -0
  142. package/dist/src/cron/validation.js +30 -4
  143. package/dist/src/cron/validation.js.map +1 -1
  144. package/dist/src/cron/workflow-run-completion.d.ts +23 -0
  145. package/dist/src/cron/workflow-run-completion.js +72 -0
  146. package/dist/src/cron/workflow-run-completion.js.map +1 -0
  147. package/dist/src/extensions/update.d.ts +51 -0
  148. package/dist/src/extensions/update.js +260 -0
  149. package/dist/src/extensions/update.js.map +1 -0
  150. package/dist/src/gateway/agents-admin.d.ts +15 -8
  151. package/dist/src/gateway/agents-admin.js +77 -28
  152. package/dist/src/gateway/agents-admin.js.map +1 -1
  153. package/dist/src/gateway/gateway-workflow-host.types.d.ts +17 -0
  154. package/dist/src/gateway/gateway-workflow-host.types.js +1 -0
  155. package/dist/src/gateway/heartbeat/service.js +1 -1
  156. package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -0
  157. package/dist/src/gateway/hono/lib/config-payload.js +2 -1
  158. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  159. package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
  160. package/dist/src/gateway/hono/middleware/auth.js +12 -7
  161. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  162. package/dist/src/gateway/hono/oauth-async.js +40 -15
  163. package/dist/src/gateway/hono/oauth-async.js.map +1 -1
  164. package/dist/src/gateway/hono/oauth.js +31 -6
  165. package/dist/src/gateway/hono/oauth.js.map +1 -1
  166. package/dist/src/gateway/hono/routes/agents.js +55 -12
  167. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  168. package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
  169. package/dist/src/gateway/hono/routes/models.js +11 -5
  170. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  171. package/dist/src/gateway/hono/routes/update.js +55 -107
  172. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  173. package/dist/src/gateway/hono/routes/workflows.js +72 -191
  174. package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
  175. package/dist/src/gateway/server.js +2 -0
  176. package/dist/src/gateway/server.js.map +1 -1
  177. package/dist/src/gateway/service.d.ts +5 -0
  178. package/dist/src/gateway/service.js +24 -3
  179. package/dist/src/gateway/service.js.map +1 -1
  180. package/dist/src/heartbeat/index.js +1 -1
  181. package/dist/src/infra/brew.d.ts +4 -0
  182. package/dist/src/infra/brew.js +20 -0
  183. package/dist/src/infra/brew.js.map +1 -0
  184. package/dist/src/infra/package-json.d.ts +2 -0
  185. package/dist/src/infra/package-json.js +23 -0
  186. package/dist/src/infra/package-json.js.map +1 -0
  187. package/dist/src/infra/package-update-steps.d.ts +35 -0
  188. package/dist/src/infra/package-update-steps.js +304 -0
  189. package/dist/src/infra/package-update-steps.js.map +1 -0
  190. package/dist/src/infra/path-env.d.ts +11 -0
  191. package/dist/src/infra/path-env.js +90 -0
  192. package/dist/src/infra/path-env.js.map +1 -0
  193. package/dist/src/infra/path-prepend.d.ts +7 -0
  194. package/dist/src/infra/path-prepend.js +44 -0
  195. package/dist/src/infra/path-prepend.js.map +1 -0
  196. package/dist/src/infra/stable-node-path.d.ts +2 -0
  197. package/dist/src/infra/stable-node-path.js +28 -0
  198. package/dist/src/infra/stable-node-path.js.map +1 -0
  199. package/dist/src/infra/update-global.d.ts +30 -23
  200. package/dist/src/infra/update-global.js +113 -64
  201. package/dist/src/infra/update-global.js.map +1 -1
  202. package/dist/src/infra/update-log.d.ts +1 -0
  203. package/dist/src/infra/update-log.js +12 -0
  204. package/dist/src/infra/update-log.js.map +1 -0
  205. package/dist/src/infra/update-restart.d.ts +20 -0
  206. package/dist/src/infra/update-restart.js +165 -0
  207. package/dist/src/infra/update-restart.js.map +1 -0
  208. package/dist/src/infra/update-runner.d.ts +89 -1
  209. package/dist/src/infra/update-runner.js +604 -173
  210. package/dist/src/infra/update-runner.js.map +1 -1
  211. package/dist/src/infra/update-startup.d.ts +3 -0
  212. package/dist/src/infra/update-startup.js +8 -4
  213. package/dist/src/infra/update-startup.js.map +1 -1
  214. package/dist/src/providers/index.d.ts +8 -0
  215. package/dist/src/providers/index.js +51 -12
  216. package/dist/src/providers/index.js.map +1 -1
  217. package/dist/src/routing/resolve-route.d.ts +3 -1
  218. package/dist/src/routing/resolve-route.js.map +1 -1
  219. package/dist/src/session/store.d.ts +5 -3
  220. package/dist/src/session/store.js +66 -20
  221. package/dist/src/session/store.js.map +1 -1
  222. package/dist/src/share/site-share-config.d.ts +3 -2
  223. package/dist/src/share/site-share-config.js.map +1 -1
  224. package/dist/src/utils/logger/stats.d.ts +1 -1
  225. package/dist/src/workflows/domain/command.d.ts +2 -1
  226. package/dist/src/workflows/domain/definition-utils.d.ts +14 -0
  227. package/dist/src/workflows/domain/definition-utils.js +50 -0
  228. package/dist/src/workflows/domain/definition-utils.js.map +1 -0
  229. package/dist/src/workflows/domain/event.d.ts +3 -0
  230. package/dist/src/workflows/domain/index.d.ts +2 -0
  231. package/dist/src/workflows/domain/index.js +3 -1
  232. package/dist/src/workflows/domain/run.d.ts +60 -0
  233. package/dist/src/workflows/domain/run.js.map +1 -1
  234. package/dist/src/workflows/domain/validation.d.ts +19 -0
  235. package/dist/src/workflows/domain/validation.js +66 -0
  236. package/dist/src/workflows/domain/validation.js.map +1 -0
  237. package/dist/src/workflows/engine/projector.js +17 -0
  238. package/dist/src/workflows/engine/projector.js.map +1 -1
  239. package/dist/src/workflows/engine/workflow-engine.d.ts +2 -1
  240. package/dist/src/workflows/engine/workflow-engine.js +128 -0
  241. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  242. package/dist/src/workflows/index.d.ts +4 -0
  243. package/dist/src/workflows/index.js +9 -2
  244. package/dist/src/workflows/service/run-view-to-snapshot.d.ts +4 -0
  245. package/dist/src/workflows/service/run-view-to-snapshot.js +63 -0
  246. package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -0
  247. package/dist/src/workflows/service/workflow-run-service.d.ts +37 -0
  248. package/dist/src/workflows/service/workflow-run-service.js +282 -0
  249. package/dist/src/workflows/service/workflow-run-service.js.map +1 -0
  250. package/dist/src/workflows/service/workflow-run-service.types.d.ts +47 -0
  251. package/dist/src/workflows/service/workflow-run-service.types.js +1 -0
  252. package/dist/src/workflows/service/workflow-session-bridge.d.ts +29 -0
  253. package/dist/src/workflows/service/workflow-session-bridge.js +177 -0
  254. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -0
  255. package/dist/src/workflows/service/workflow-session-key.d.ts +3 -0
  256. package/dist/src/workflows/service/workflow-session-key.js +21 -0
  257. package/dist/src/workflows/service/workflow-session-key.js.map +1 -0
  258. package/dist/src/workflows/store/run-store.js +1 -0
  259. package/dist/src/workflows/store/run-store.js.map +1 -1
  260. package/package.json +1 -1
  261. package/dist/gateway/static/root/assets/agents-CRxETUZx.js +0 -222
  262. package/dist/gateway/static/root/assets/apps-page-wKWf3l57.js +0 -1
  263. package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +0 -1
  264. package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +0 -1
  265. package/dist/gateway/static/root/assets/cron-api-N9hvuRrn.js +0 -1
  266. package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
  267. package/dist/gateway/static/root/assets/cron-page-tlNGNxhP.js +0 -1
  268. package/dist/gateway/static/root/assets/dist-CJwfHYvT.js +0 -1
  269. package/dist/gateway/static/root/assets/index-CqZzHNEg.css +0 -1
  270. package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +0 -1
  271. package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +0 -3
  272. package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +0 -2
  273. package/dist/gateway/static/root/assets/url-D6jvVYIA.js +0 -7
  274. package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +0 -1
  275. package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +0 -27
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","names":[],"sources":["../../../src/cron/validation.ts"],"sourcesContent":["// Cron input validation using Zod\nimport { z } from 'zod';\nimport nodeCron from 'node-cron';\n\n// Custom cron validation\nconst cronExpression = z.string().superRefine((val, ctx) => {\n if (!nodeCron.validate(val)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid cron expression: ${val}`,\n });\n }\n});\n\n// Valid timezones (subset of IANA timezones)\nconst validTimezones = [\n 'UTC',\n 'America/New_York',\n 'America/Chicago',\n 'America/Denver',\n 'America/Los_Angeles',\n 'America/Toronto',\n 'Europe/London',\n 'Europe/Paris',\n 'Europe/Berlin',\n 'Europe/Moscow',\n 'Asia/Tokyo',\n 'Asia/Shanghai',\n 'Asia/Hong_Kong',\n 'Asia/Singapore',\n 'Asia/Seoul',\n 'Asia/Dubai',\n 'Asia/Mumbai',\n 'Australia/Sydney',\n 'Pacific/Auckland',\n];\n\nconst CronDeliveryMode = z.enum(['none', 'announce', 'direct']);\n\n/** Treat `''` / `null` / whitespace-only as absent so optional fields do not fail `.min(1)` */\nfunction optionalTrimmedString(max: number, min = 1) {\n return z.preprocess((v) => {\n if (v === null || v === undefined) return undefined;\n if (typeof v !== 'string') return v;\n const t = v.trim();\n return t.length === 0 ? undefined : t;\n }, z.string().min(min).max(max).optional());\n}\n\n/** Optional agent id on create; empty string → undefined. */\nconst optionalJobAgentId = optionalTrimmedString(64, 1);\n\n/** Optional absolute workspace path on create; empty string → undefined. */\nconst optionalJobWorkingDirectory = optionalTrimmedString(4096, 1);\n\n/**\n * PATCH: set string, or `null` / empty to clear `workingDirectory` on the job.\n */\nconst patchJobWorkingDirectory = z.preprocess((v) => {\n if (v === null) return null;\n if (v === undefined) return undefined;\n if (typeof v !== 'string') return v;\n const t = v.trim();\n return t.length === 0 ? null : t;\n}, z.union([z.string().min(1).max(4096), z.null()]).optional());\n\n/**\n * PATCH: set string, or `null` / empty to clear `agentId` on the job.\n */\nconst patchJobAgentId = z.preprocess((v) => {\n if (v === null) return null;\n if (v === undefined) return undefined;\n if (typeof v !== 'string') return v;\n const t = v.trim();\n return t.length === 0 ? null : t;\n}, z.union([z.string().min(1).max(64), z.null()]).optional());\n\n// CronPayload validation\nconst CronSystemEventPayloadSchema = z.object({\n kind: z.literal('systemEvent'),\n text: z.string().min(1).max(50000),\n});\n\nconst CronAgentTurnPayloadSchema = z.object({\n kind: z.literal('agentTurn'),\n message: z.string().min(1).max(50000),\n model: optionalTrimmedString(100, 1),\n timeoutSeconds: z.number().int().min(10).max(3600).optional(),\n});\n\nconst CronPayloadSchema = z.union([\n CronSystemEventPayloadSchema,\n CronAgentTurnPayloadSchema,\n]);\n\n// CronDelivery validation — channel must match gateway UI / message bus ids (telegram, weixin, cli, local, …)\nconst CronDeliverySchema = z.object({\n mode: CronDeliveryMode.default('none'),\n channel: optionalTrimmedString(32, 1),\n to: z.preprocess(\n (v) => (v === '' || v === null || v === undefined ? undefined : v),\n z.string().max(100).optional(),\n ),\n bestEffort: z.boolean().optional(),\n});\n\nexport const JobDataSchema = z\n .object({\n id: z.string().min(1).max(32),\n name: z.string().max(100).optional(),\n schedule: cronExpression,\n enabled: z.boolean(),\n timezone: z.string().superRefine((val, ctx) => {\n if (val && !validTimezones.includes(val)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid timezone: ${val}. Use IANA timezone names.`,\n });\n }\n }).optional(),\n maxRetries: z.number().int().min(0).max(10).default(3),\n timeout: z.number().int().min(1000).max(300000).default(180000),\n created_at: z.string().datetime(),\n updated_at: z.string().datetime(),\n sessionTarget: z.enum(['main', 'isolated']).optional(),\n agentId: optionalTrimmedString(64, 1),\n workingDirectory: optionalJobWorkingDirectory,\n payload: CronPayloadSchema,\n delivery: CronDeliverySchema.optional(),\n model: optionalTrimmedString(100, 1),\n state: z.any().optional(),\n })\n .strict();\n\nexport const AddJobRequestSchema = z.object({\n schedule: cronExpression,\n name: z.string().max(100).optional(),\n timezone: z.string().optional(),\n maxRetries: z.number().int().min(0).max(10).optional(),\n timeout: z.number().int().min(1000).max(300000).optional(),\n sessionTarget: z.enum(['main', 'isolated']).optional(),\n agentId: optionalJobAgentId,\n workingDirectory: optionalJobWorkingDirectory,\n payload: CronPayloadSchema,\n delivery: CronDeliverySchema.optional(),\n model: optionalTrimmedString(100, 1),\n});\n\nexport const UpdateJobRequestSchema = z.object({\n name: z.string().max(100).optional(),\n schedule: cronExpression.optional(),\n timezone: z.string().optional(),\n maxRetries: z.number().int().min(0).max(10).optional(),\n timeout: z.number().int().min(1000).max(300000).optional(),\n enabled: z.boolean().optional(),\n sessionTarget: z.enum(['main', 'isolated']).optional(),\n agentId: patchJobAgentId,\n workingDirectory: patchJobWorkingDirectory,\n payload: CronPayloadSchema.optional(),\n delivery: CronDeliverySchema.optional(),\n model: optionalTrimmedString(100, 1),\n}).refine(\n (data) => Object.keys(data).length > 0,\n { message: 'At least one field must be provided for update' }\n);\n\nexport type ValidatedJobData = z.infer<typeof JobDataSchema>;\nexport type ValidatedAddJobRequest = z.infer<typeof AddJobRequestSchema>;\nexport type ValidatedUpdateJobRequest = z.infer<typeof UpdateJobRequestSchema>;\nexport type ValidatedCronPayload = z.infer<typeof CronPayloadSchema>;\nexport type ValidatedCronDelivery = z.infer<typeof CronDeliverySchema>;\n\n// Re-export common validation helpers\nexport { cronExpression };\n"],"mappings":"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"}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../../src/cron/validation.ts"],"sourcesContent":["// Cron input validation using Zod\nimport { z } from 'zod';\nimport nodeCron from 'node-cron';\n\n// Custom cron validation\nconst cronExpression = z.string().superRefine((val, ctx) => {\n if (!nodeCron.validate(val)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid cron expression: ${val}`,\n });\n }\n});\n\n// Valid timezones (subset of IANA timezones)\nconst validTimezones = [\n 'UTC',\n 'America/New_York',\n 'America/Chicago',\n 'America/Denver',\n 'America/Los_Angeles',\n 'America/Toronto',\n 'Europe/London',\n 'Europe/Paris',\n 'Europe/Berlin',\n 'Europe/Moscow',\n 'Asia/Tokyo',\n 'Asia/Shanghai',\n 'Asia/Hong_Kong',\n 'Asia/Singapore',\n 'Asia/Seoul',\n 'Asia/Dubai',\n 'Asia/Mumbai',\n 'Australia/Sydney',\n 'Pacific/Auckland',\n];\n\nconst CronDeliveryMode = z.enum(['none', 'announce', 'direct']);\n\n/** Treat `''` / `null` / whitespace-only as absent so optional fields do not fail `.min(1)` */\nfunction optionalTrimmedString(max: number, min = 1) {\n return z.preprocess((v) => {\n if (v === null || v === undefined) return undefined;\n if (typeof v !== 'string') return v;\n const t = v.trim();\n return t.length === 0 ? undefined : t;\n }, z.string().min(min).max(max).optional());\n}\n\n/** Optional agent id on create; empty string → undefined. */\nconst optionalJobAgentId = optionalTrimmedString(64, 1);\n\n/** Optional absolute workspace path on create; empty string → undefined. */\nconst optionalJobWorkingDirectory = optionalTrimmedString(4096, 1);\n\n/**\n * PATCH: set string, or `null` / empty to clear `workingDirectory` on the job.\n */\nconst patchJobWorkingDirectory = z.preprocess((v) => {\n if (v === null) return null;\n if (v === undefined) return undefined;\n if (typeof v !== 'string') return v;\n const t = v.trim();\n return t.length === 0 ? null : t;\n}, z.union([z.string().min(1).max(4096), z.null()]).optional());\n\n/**\n * PATCH: set string, or `null` / empty to clear `agentId` on the job.\n */\nconst patchJobAgentId = z.preprocess((v) => {\n if (v === null) return null;\n if (v === undefined) return undefined;\n if (typeof v !== 'string') return v;\n const t = v.trim();\n return t.length === 0 ? null : t;\n}, z.union([z.string().min(1).max(64), z.null()]).optional());\n\n// CronPayload validation\nconst CronSystemEventPayloadSchema = z.object({\n kind: z.literal('systemEvent'),\n text: z.string().min(1).max(50000),\n});\n\nconst CronAgentTurnPayloadSchema = z.object({\n kind: z.literal('agentTurn'),\n message: z.string().min(1).max(50000),\n model: optionalTrimmedString(100, 1),\n timeoutSeconds: z.number().int().min(10).max(3600).optional(),\n});\n\nconst WorkflowRunInputEnvelopeSchema = z.object({\n payload: z.unknown(),\n goal: optionalTrimmedString(5000, 1),\n variables: z.record(z.string(), z.unknown()).optional(),\n context: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst CronWorkflowRunPayloadSchema = z.object({\n kind: z.literal('workflowRun'),\n definitionId: z.string().min(1).max(200),\n input: z.unknown().optional(),\n inputEnvelope: WorkflowRunInputEnvelopeSchema.optional(),\n goal: optionalTrimmedString(5000, 1),\n agentId: optionalTrimmedString(64, 1),\n sessionKey: optionalTrimmedString(300, 1),\n waitForCompletion: z.boolean().optional(),\n source: z.object({\n kind: z.literal('cron').optional(),\n scheduleId: optionalTrimmedString(200, 1),\n fireId: optionalTrimmedString(200, 1),\n scheduledAtMs: z.number().int().nonnegative().optional(),\n }).optional(),\n});\n\nconst CronPayloadSchema = z.union([\n CronSystemEventPayloadSchema,\n CronAgentTurnPayloadSchema,\n CronWorkflowRunPayloadSchema,\n]);\n\n// CronDelivery validation — channel must match gateway UI / message bus ids (telegram, weixin, cli, local, …)\nconst CronDeliverySchema = z.object({\n mode: CronDeliveryMode.default('none'),\n channel: optionalTrimmedString(32, 1),\n to: z.preprocess(\n (v) => (v === '' || v === null || v === undefined ? undefined : v),\n z.string().max(100).optional(),\n ),\n bestEffort: z.boolean().optional(),\n});\n\nexport const JobDataSchema = z\n .object({\n id: z.string().min(1).max(32),\n name: z.string().max(100).optional(),\n schedule: cronExpression,\n enabled: z.boolean(),\n timezone: z.string().superRefine((val, ctx) => {\n if (val && !validTimezones.includes(val)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid timezone: ${val}. Use IANA timezone names.`,\n });\n }\n }).optional(),\n maxRetries: z.number().int().min(0).max(10).default(3),\n timeout: z.number().int().min(1000).max(7_200_000).default(180000),\n created_at: z.string().datetime(),\n updated_at: z.string().datetime(),\n sessionTarget: z.enum(['main', 'isolated']).optional(),\n agentId: optionalTrimmedString(64, 1),\n workingDirectory: optionalJobWorkingDirectory,\n payload: CronPayloadSchema,\n delivery: CronDeliverySchema.optional(),\n model: optionalTrimmedString(100, 1),\n state: z.any().optional(),\n })\n .strict();\n\nexport const AddJobRequestSchema = z.object({\n schedule: cronExpression,\n name: z.string().max(100).optional(),\n timezone: z.string().optional(),\n maxRetries: z.number().int().min(0).max(10).optional(),\n timeout: z.number().int().min(1000).max(7_200_000).optional(),\n sessionTarget: z.enum(['main', 'isolated']).optional(),\n agentId: optionalJobAgentId,\n workingDirectory: optionalJobWorkingDirectory,\n payload: CronPayloadSchema,\n delivery: CronDeliverySchema.optional(),\n model: optionalTrimmedString(100, 1),\n});\n\nexport const UpdateJobRequestSchema = z.object({\n name: z.string().max(100).optional(),\n schedule: cronExpression.optional(),\n timezone: z.string().optional(),\n maxRetries: z.number().int().min(0).max(10).optional(),\n timeout: z.number().int().min(1000).max(7_200_000).optional(),\n enabled: z.boolean().optional(),\n sessionTarget: z.enum(['main', 'isolated']).optional(),\n agentId: patchJobAgentId,\n workingDirectory: patchJobWorkingDirectory,\n payload: CronPayloadSchema.optional(),\n delivery: CronDeliverySchema.optional(),\n model: optionalTrimmedString(100, 1),\n}).refine(\n (data) => Object.keys(data).length > 0,\n { message: 'At least one field must be provided for update' }\n);\n\nexport type ValidatedJobData = z.infer<typeof JobDataSchema>;\nexport type ValidatedAddJobRequest = z.infer<typeof AddJobRequestSchema>;\nexport type ValidatedUpdateJobRequest = z.infer<typeof UpdateJobRequestSchema>;\nexport type ValidatedCronPayload = z.infer<typeof CronPayloadSchema>;\nexport type ValidatedCronDelivery = z.infer<typeof CronDeliverySchema>;\n\n// Re-export common validation helpers\nexport { cronExpression };\n"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { WorkflowRunView } from '../workflows/domain/index.js';
2
+ /** Default wait budget for cron workflow runs (35 minutes). */
3
+ export declare const DEFAULT_WORKFLOW_CRON_WAIT_MS: number;
4
+ export declare const WORKFLOW_CRON_POLL_MS = 3000;
5
+ export declare function resolveWorkflowCronWaitMs(jobTimeoutMs: number | undefined): number;
6
+ export declare function waitForWorkflowRunView(params: {
7
+ readView: (runId: string) => Promise<WorkflowRunView | null>;
8
+ runId: string;
9
+ signal: AbortSignal;
10
+ timeoutMs: number;
11
+ pollIntervalMs?: number;
12
+ }): Promise<{
13
+ kind: 'terminal';
14
+ view: WorkflowRunView;
15
+ } | {
16
+ kind: 'timeout';
17
+ lastView: WorkflowRunView | null;
18
+ } | {
19
+ kind: 'aborted';
20
+ }>;
21
+ export declare function buildWorkflowRunCronSummary(view: WorkflowRunView): string;
22
+ export declare function isWorkflowRunCronSuccess(view: WorkflowRunView): boolean;
23
+ export declare function buildWorkflowRunDeliveryText(view: WorkflowRunView): string;
@@ -0,0 +1,72 @@
1
+ import { renderWorkflowText } from "../agent/workflow/snapshot.js";
2
+ import { isTerminalWorkflowRunStatus } from "../workflows/domain/run.js";
3
+ import "../workflows/domain/index.js";
4
+ import { runViewToSnapshot } from "../workflows/service/run-view-to-snapshot.js";
5
+ //#region src/cron/workflow-run-completion.ts
6
+ /** Default wait budget for cron workflow runs (35 minutes). */
7
+ const DEFAULT_WORKFLOW_CRON_WAIT_MS = 2100 * 1e3;
8
+ const WORKFLOW_CRON_POLL_MS = 3e3;
9
+ function resolveWorkflowCronWaitMs(jobTimeoutMs) {
10
+ return Math.max(jobTimeoutMs && Number.isFinite(jobTimeoutMs) ? jobTimeoutMs : 0, DEFAULT_WORKFLOW_CRON_WAIT_MS);
11
+ }
12
+ async function waitForWorkflowRunView(params) {
13
+ const pollIntervalMs = params.pollIntervalMs ?? 3e3;
14
+ const deadline = Date.now() + params.timeoutMs;
15
+ let lastView = null;
16
+ while (Date.now() < deadline) {
17
+ if (params.signal.aborted) return { kind: "aborted" };
18
+ const view = await params.readView(params.runId);
19
+ if (view) {
20
+ lastView = view;
21
+ if (isTerminalWorkflowRunStatus(view.run.status)) return {
22
+ kind: "terminal",
23
+ view
24
+ };
25
+ }
26
+ await sleep(pollIntervalMs, params.signal);
27
+ }
28
+ return {
29
+ kind: "timeout",
30
+ lastView
31
+ };
32
+ }
33
+ function buildWorkflowRunCronSummary(view) {
34
+ const status = view.run.status;
35
+ const label = view.run.goal.trim() || view.run.definitionId;
36
+ if (status === "succeeded") return `Workflow ${view.run.definitionId} succeeded: ${label}`;
37
+ if (status === "failed") {
38
+ const detail = view.run.error?.message?.trim();
39
+ return detail ? `Workflow ${view.run.definitionId} failed: ${detail}` : `Workflow ${view.run.definitionId} failed`;
40
+ }
41
+ if (status === "timeout") return `Workflow ${view.run.definitionId} timed out`;
42
+ if (status === "cancelled") return `Workflow ${view.run.definitionId} cancelled`;
43
+ return `Workflow ${view.run.definitionId} finished (${status})`;
44
+ }
45
+ function isWorkflowRunCronSuccess(view) {
46
+ return view.run.status === "succeeded";
47
+ }
48
+ function buildWorkflowRunDeliveryText(view) {
49
+ const body = renderWorkflowText(runViewToSnapshot(view), view.run.status === "succeeded", { showResultPreviews: true });
50
+ return `${buildWorkflowRunCronSummary(view)}\n\n${body}`;
51
+ }
52
+ function sleep(ms, signal) {
53
+ return new Promise((resolve, reject) => {
54
+ if (signal.aborted) {
55
+ reject(/* @__PURE__ */ new Error("aborted"));
56
+ return;
57
+ }
58
+ const timer = setTimeout(resolve, ms);
59
+ const onAbort = () => {
60
+ clearTimeout(timer);
61
+ reject(/* @__PURE__ */ new Error("aborted"));
62
+ };
63
+ signal.addEventListener("abort", onAbort, { once: true });
64
+ }).catch((err) => {
65
+ if (signal.aborted || err instanceof Error && err.message === "aborted") return;
66
+ throw err;
67
+ });
68
+ }
69
+ //#endregion
70
+ export { DEFAULT_WORKFLOW_CRON_WAIT_MS, WORKFLOW_CRON_POLL_MS, buildWorkflowRunCronSummary, buildWorkflowRunDeliveryText, isWorkflowRunCronSuccess, resolveWorkflowCronWaitMs, waitForWorkflowRunView };
71
+
72
+ //# sourceMappingURL=workflow-run-completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-run-completion.js","names":[],"sources":["../../../src/cron/workflow-run-completion.ts"],"sourcesContent":["import { renderWorkflowText } from '../agent/workflow/snapshot.js';\nimport type { WorkflowRunView } from '../workflows/domain/index.js';\nimport { isTerminalWorkflowRunStatus } from '../workflows/domain/index.js';\nimport { runViewToSnapshot } from '../workflows/service/run-view-to-snapshot.js';\n\n/** Default wait budget for cron workflow runs (35 minutes). */\nexport const DEFAULT_WORKFLOW_CRON_WAIT_MS = 35 * 60 * 1000;\nexport const WORKFLOW_CRON_POLL_MS = 3000;\n\nexport function resolveWorkflowCronWaitMs(jobTimeoutMs: number | undefined): number {\n const configured = jobTimeoutMs && Number.isFinite(jobTimeoutMs) ? jobTimeoutMs : 0;\n return Math.max(configured, DEFAULT_WORKFLOW_CRON_WAIT_MS);\n}\n\nexport async function waitForWorkflowRunView(params: {\n readView: (runId: string) => Promise<WorkflowRunView | null>;\n runId: string;\n signal: AbortSignal;\n timeoutMs: number;\n pollIntervalMs?: number;\n}): Promise<\n | { kind: 'terminal'; view: WorkflowRunView }\n | { kind: 'timeout'; lastView: WorkflowRunView | null }\n | { kind: 'aborted' }\n> {\n const pollIntervalMs = params.pollIntervalMs ?? WORKFLOW_CRON_POLL_MS;\n const deadline = Date.now() + params.timeoutMs;\n let lastView: WorkflowRunView | null = null;\n\n while (Date.now() < deadline) {\n if (params.signal.aborted) {\n return { kind: 'aborted' };\n }\n\n const view = await params.readView(params.runId);\n if (view) {\n lastView = view;\n if (isTerminalWorkflowRunStatus(view.run.status)) {\n return { kind: 'terminal', view };\n }\n }\n\n await sleep(pollIntervalMs, params.signal);\n }\n\n return { kind: 'timeout', lastView };\n}\n\nexport function buildWorkflowRunCronSummary(view: WorkflowRunView): string {\n const status = view.run.status;\n const label = view.run.goal.trim() || view.run.definitionId;\n if (status === 'succeeded') {\n return `Workflow ${view.run.definitionId} succeeded: ${label}`;\n }\n if (status === 'failed') {\n const detail = view.run.error?.message?.trim();\n return detail\n ? `Workflow ${view.run.definitionId} failed: ${detail}`\n : `Workflow ${view.run.definitionId} failed`;\n }\n if (status === 'timeout') {\n return `Workflow ${view.run.definitionId} timed out`;\n }\n if (status === 'cancelled') {\n return `Workflow ${view.run.definitionId} cancelled`;\n }\n return `Workflow ${view.run.definitionId} finished (${status})`;\n}\n\nexport function isWorkflowRunCronSuccess(view: WorkflowRunView): boolean {\n return view.run.status === 'succeeded';\n}\n\nexport function buildWorkflowRunDeliveryText(view: WorkflowRunView): string {\n const snapshot = runViewToSnapshot(view);\n const completed = view.run.status === 'succeeded';\n const body = renderWorkflowText(snapshot, completed, { showResultPreviews: true });\n const header = buildWorkflowRunCronSummary(view);\n return `${header}\\n\\n${body}`;\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal.aborted) {\n reject(new Error('aborted'));\n return;\n }\n const timer = setTimeout(resolve, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(new Error('aborted'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }).catch((err) => {\n if (signal.aborted || (err instanceof Error && err.message === 'aborted')) {\n return;\n }\n throw err;\n });\n}\n"],"mappings":";;;;;;AAMA,MAAa,gCAAgC,OAAU;AACvD,MAAa,wBAAwB;AAErC,SAAgB,0BAA0B,cAA0C;AAElF,QAAO,KAAK,IADO,gBAAgB,OAAO,SAAS,aAAa,GAAG,eAAe,GACtD,8BAA8B;;AAG5D,eAAsB,uBAAuB,QAU3C;CACA,MAAM,iBAAiB,OAAO,kBAAA;CAC9B,MAAM,WAAW,KAAK,KAAK,GAAG,OAAO;CACrC,IAAI,WAAmC;AAEvC,QAAO,KAAK,KAAK,GAAG,UAAU;AAC5B,MAAI,OAAO,OAAO,QAChB,QAAO,EAAE,MAAM,WAAW;EAG5B,MAAM,OAAO,MAAM,OAAO,SAAS,OAAO,MAAM;AAChD,MAAI,MAAM;AACR,cAAW;AACX,OAAI,4BAA4B,KAAK,IAAI,OAAO,CAC9C,QAAO;IAAE,MAAM;IAAY;IAAM;;AAIrC,QAAM,MAAM,gBAAgB,OAAO,OAAO;;AAG5C,QAAO;EAAE,MAAM;EAAW;EAAU;;AAGtC,SAAgB,4BAA4B,MAA+B;CACzE,MAAM,SAAS,KAAK,IAAI;CACxB,MAAM,QAAQ,KAAK,IAAI,KAAK,MAAM,IAAI,KAAK,IAAI;AAC/C,KAAI,WAAW,YACb,QAAO,YAAY,KAAK,IAAI,aAAa,cAAc;AAEzD,KAAI,WAAW,UAAU;EACvB,MAAM,SAAS,KAAK,IAAI,OAAO,SAAS,MAAM;AAC9C,SAAO,SACH,YAAY,KAAK,IAAI,aAAa,WAAW,WAC7C,YAAY,KAAK,IAAI,aAAa;;AAExC,KAAI,WAAW,UACb,QAAO,YAAY,KAAK,IAAI,aAAa;AAE3C,KAAI,WAAW,YACb,QAAO,YAAY,KAAK,IAAI,aAAa;AAE3C,QAAO,YAAY,KAAK,IAAI,aAAa,aAAa,OAAO;;AAG/D,SAAgB,yBAAyB,MAAgC;AACvE,QAAO,KAAK,IAAI,WAAW;;AAG7B,SAAgB,6BAA6B,MAA+B;CAG1E,MAAM,OAAO,mBAFI,kBAAkB,KAEK,EADtB,KAAK,IAAI,WAAW,aACe,EAAE,oBAAoB,MAAM,CAAC;AAElF,QAAO,GADQ,4BAA4B,KAC3B,CAAC,MAAM;;AAGzB,SAAS,MAAM,IAAY,QAAoC;AAC7D,QAAO,IAAI,SAAe,SAAS,WAAW;AAC5C,MAAI,OAAO,SAAS;AAClB,0BAAO,IAAI,MAAM,UAAU,CAAC;AAC5B;;EAEF,MAAM,QAAQ,WAAW,SAAS,GAAG;EACrC,MAAM,gBAAgB;AACpB,gBAAa,MAAM;AACnB,0BAAO,IAAI,MAAM,UAAU,CAAC;;AAE9B,SAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;GACzD,CAAC,OAAO,QAAQ;AAChB,MAAI,OAAO,WAAY,eAAe,SAAS,IAAI,YAAY,UAC7D;AAEF,QAAM;GACN"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Post-update extension sync — refresh lockfile-managed npm / store extensions.
3
+ */
4
+ import type { Config } from '../config/schema.js';
5
+ import type { UpdateChannel } from '../infra/update-channels.js';
6
+ export type ExtensionUpdateLogger = {
7
+ info?: (message: string) => void;
8
+ warn?: (message: string) => void;
9
+ error?: (message: string) => void;
10
+ };
11
+ export type ExtensionUpdateStatus = 'updated' | 'unchanged' | 'skipped' | 'error';
12
+ export type ExtensionUpdateOutcome = {
13
+ extensionId: string;
14
+ status: ExtensionUpdateStatus;
15
+ message: string;
16
+ currentVersion?: string;
17
+ nextVersion?: string;
18
+ };
19
+ export type ExtensionChannelSyncSummary = {
20
+ skippedBundled: string[];
21
+ warnings: string[];
22
+ };
23
+ export type ExtensionPostUpdateResult = {
24
+ status: 'ok' | 'error' | 'skipped';
25
+ outcomes: ExtensionUpdateOutcome[];
26
+ channelSync?: ExtensionChannelSyncSummary;
27
+ };
28
+ export declare function syncExtensionsForUpdateChannel(params: {
29
+ channel: UpdateChannel;
30
+ config?: Config;
31
+ logger?: ExtensionUpdateLogger;
32
+ }): Promise<{
33
+ skipIds: Set<string>;
34
+ summary: ExtensionChannelSyncSummary;
35
+ }>;
36
+ export declare function updateNpmInstalledExtensions(params: {
37
+ extensionIds?: string[];
38
+ skipIds?: Set<string>;
39
+ config?: Config;
40
+ timeoutMs?: number;
41
+ logger?: ExtensionUpdateLogger;
42
+ }): Promise<{
43
+ outcomes: ExtensionUpdateOutcome[];
44
+ status: 'ok' | 'error' | 'skipped';
45
+ }>;
46
+ export declare function runPostUpdateExtensionSync(params: {
47
+ channel: UpdateChannel;
48
+ config?: Config;
49
+ timeoutMs?: number;
50
+ logger?: ExtensionUpdateLogger;
51
+ }): Promise<ExtensionPostUpdateResult>;
@@ -0,0 +1,260 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
3
+ import { init_paths, resolveBundledExtensionsDir, resolveExtensionsDir } from "../config/paths.js";
4
+ import { init_loader, loadConfig } from "../config/loader.js";
5
+ import { getExtensionLockfileManager } from "./lockfile.js";
6
+ import { installExtensionFromStoreZip, installFromNpm } from "./install.js";
7
+ import { findExtension } from "./marketplace.js";
8
+ import { downloadExtensionStoreZipBuffer, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl } from "../agent/skills/marketplace/adapters/store/store-api-client.js";
9
+ import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import semver from "semver";
12
+ //#region src/extensions/update.ts
13
+ /**
14
+ * Post-update extension sync — refresh lockfile-managed npm / store extensions.
15
+ */
16
+ init_paths();
17
+ init_loader();
18
+ init_logger();
19
+ const log = createLogger("ExtensionUpdate");
20
+ const MANIFEST = "xopc.extension.json";
21
+ function readInstalledExtensionVersion(targetDir, extensionId) {
22
+ const manifestPath = join(targetDir, extensionId, MANIFEST);
23
+ if (!existsSync(manifestPath)) return;
24
+ try {
25
+ const raw = JSON.parse(readFileSync(manifestPath, "utf-8"));
26
+ return (typeof raw.version === "string" ? semver.valid(raw.version) : null) ?? void 0;
27
+ } catch {
28
+ return;
29
+ }
30
+ }
31
+ async function resolveNpmPackageForId(extensionId) {
32
+ return (await findExtension(extensionId))?.npmPackage;
33
+ }
34
+ async function upsertNpmExtensionLock(lock, targetDir, result, spec) {
35
+ if (!result.extensionId) return;
36
+ const reg = await findExtension(result.extensionId);
37
+ const resolved = reg?.npmPackage ?? spec;
38
+ let ver = reg?.version ?? "0.0.0";
39
+ try {
40
+ const raw = readFileSync(join(targetDir, result.extensionId, MANIFEST), "utf-8");
41
+ const m = JSON.parse(raw);
42
+ const mv = typeof m.version === "string" ? semver.valid(m.version) : null;
43
+ if (mv) ver = mv;
44
+ } catch {}
45
+ await lock.upsert(result.extensionId, {
46
+ name: result.extensionId,
47
+ version: ver,
48
+ resolved,
49
+ source: "npm"
50
+ });
51
+ }
52
+ async function installExtensionFromStoreWithLock(params) {
53
+ try {
54
+ const { downloadUrl, version } = await resolveExtensionZipDownloadUrl(params.storeBase, params.packageName, params.version);
55
+ const result = await installExtensionFromStoreZip(await downloadExtensionStoreZipBuffer(params.storeBase, downloadUrl), params.targetDir);
56
+ if (!result.ok || !result.extensionId) return {
57
+ ok: false,
58
+ error: result.error ?? "install failed"
59
+ };
60
+ await params.lock.upsert(result.extensionId, {
61
+ name: result.extensionId,
62
+ version,
63
+ resolved: params.packageName,
64
+ source: "store"
65
+ });
66
+ return {
67
+ ok: true,
68
+ extensionId: result.extensionId,
69
+ version
70
+ };
71
+ } catch (err) {
72
+ return {
73
+ ok: false,
74
+ error: err instanceof Error ? err.message : String(err)
75
+ };
76
+ }
77
+ }
78
+ function listBundledExtensionIds() {
79
+ const ids = /* @__PURE__ */ new Set();
80
+ const bundledDir = resolveBundledExtensionsDir();
81
+ if (!bundledDir || !existsSync(bundledDir)) return ids;
82
+ for (const entry of readdirSync(bundledDir, { withFileTypes: true })) if (entry.isDirectory()) ids.add(entry.name);
83
+ return ids;
84
+ }
85
+ async function syncExtensionsForUpdateChannel(params) {
86
+ const logger = params.logger ?? {};
87
+ const summary = {
88
+ skippedBundled: [],
89
+ warnings: []
90
+ };
91
+ const skipIds = /* @__PURE__ */ new Set();
92
+ if (params.channel !== "dev") return {
93
+ skipIds,
94
+ summary
95
+ };
96
+ const data = await getExtensionLockfileManager().load();
97
+ const bundledIds = listBundledExtensionIds();
98
+ for (const extensionId of Object.keys(data.extensions)) {
99
+ if (!bundledIds.has(extensionId)) continue;
100
+ skipIds.add(extensionId);
101
+ summary.skippedBundled.push(extensionId);
102
+ logger.info?.(`Skipping "${extensionId}" on dev channel (bundled copy preferred).`);
103
+ }
104
+ return {
105
+ skipIds,
106
+ summary
107
+ };
108
+ }
109
+ async function updateSingleExtension(params) {
110
+ const { extensionId, entry, targetDir, storeBase, lock, timeoutMs, logger } = params;
111
+ const currentVersion = readInstalledExtensionVersion(targetDir, extensionId);
112
+ if (entry.source === "store") {
113
+ const pkgName = entry.resolved?.trim() || extensionId;
114
+ if (existsSync(join(targetDir, extensionId))) rmSync(join(targetDir, extensionId), {
115
+ recursive: true,
116
+ force: true
117
+ });
118
+ const result = await installExtensionFromStoreWithLock({
119
+ storeBase,
120
+ packageName: pkgName,
121
+ targetDir,
122
+ lock
123
+ });
124
+ if (result.ok === false) {
125
+ logger.error?.(`Failed to update ${extensionId}: ${result.error}`);
126
+ return {
127
+ extensionId,
128
+ status: "error",
129
+ message: result.error,
130
+ currentVersion
131
+ };
132
+ }
133
+ const nextVersion = result.version;
134
+ const status = currentVersion && nextVersion && currentVersion === nextVersion ? "unchanged" : "updated";
135
+ return {
136
+ extensionId,
137
+ status,
138
+ currentVersion,
139
+ nextVersion,
140
+ message: status === "unchanged" ? `${extensionId} is up to date (${currentVersion}).` : `Updated ${extensionId}: ${currentVersion ?? "unknown"} -> ${nextVersion}.`
141
+ };
142
+ }
143
+ if (entry.source !== "npm") return {
144
+ extensionId,
145
+ status: "skipped",
146
+ message: `Skipping "${extensionId}" (source: ${entry.source}).`
147
+ };
148
+ const spec = entry.resolved?.trim() || await resolveNpmPackageForId(extensionId);
149
+ if (!spec) return {
150
+ extensionId,
151
+ status: "skipped",
152
+ message: `Skipping "${extensionId}" (could not resolve npm package).`
153
+ };
154
+ if (existsSync(join(targetDir, extensionId))) rmSync(join(targetDir, extensionId), {
155
+ recursive: true,
156
+ force: true
157
+ });
158
+ const installResult = await installFromNpm(spec, targetDir, timeoutMs);
159
+ if (!installResult.ok) {
160
+ const message = installResult.error ?? "npm install failed";
161
+ logger.error?.(`Failed to update ${extensionId}: ${message}`);
162
+ return {
163
+ extensionId,
164
+ status: "error",
165
+ message,
166
+ currentVersion
167
+ };
168
+ }
169
+ await upsertNpmExtensionLock(lock, targetDir, installResult, spec);
170
+ const nextVersion = (installResult.extensionId ? readInstalledExtensionVersion(targetDir, installResult.extensionId) : void 0) ?? entry.version;
171
+ const resolvedId = installResult.extensionId ?? extensionId;
172
+ const status = currentVersion && nextVersion && currentVersion === nextVersion ? "unchanged" : "updated";
173
+ return {
174
+ extensionId: resolvedId,
175
+ status,
176
+ currentVersion,
177
+ nextVersion,
178
+ message: status === "unchanged" ? `${resolvedId} is up to date (${currentVersion}).` : `Updated ${resolvedId}: ${currentVersion ?? "unknown"} -> ${nextVersion}.`
179
+ };
180
+ }
181
+ async function updateNpmInstalledExtensions(params) {
182
+ const logger = params.logger ?? {};
183
+ const config = params.config ?? loadConfig();
184
+ const targetDir = resolveExtensionsDir();
185
+ const storeBase = resolveExtensionsStoreBaseUrl(config);
186
+ const lock = getExtensionLockfileManager();
187
+ const data = await lock.load();
188
+ const ids = params.extensionIds?.length ? params.extensionIds : Object.keys(data.extensions);
189
+ if (ids.length === 0) return {
190
+ outcomes: [],
191
+ status: "skipped"
192
+ };
193
+ const outcomes = [];
194
+ let hasError = false;
195
+ for (const extensionId of ids) {
196
+ if (params.skipIds?.has(extensionId)) {
197
+ outcomes.push({
198
+ extensionId,
199
+ status: "skipped",
200
+ message: `Skipping "${extensionId}" (channel sync).`
201
+ });
202
+ continue;
203
+ }
204
+ const entry = data.extensions[extensionId];
205
+ if (!entry) {
206
+ outcomes.push({
207
+ extensionId,
208
+ status: "skipped",
209
+ message: `No lockfile entry for "${extensionId}".`
210
+ });
211
+ continue;
212
+ }
213
+ const outcome = await updateSingleExtension({
214
+ extensionId,
215
+ entry,
216
+ targetDir,
217
+ storeBase,
218
+ lock,
219
+ timeoutMs: params.timeoutMs,
220
+ logger
221
+ });
222
+ outcomes.push(outcome);
223
+ if (outcome.status === "error") hasError = true;
224
+ else if (outcome.status === "updated") log.info({
225
+ extensionId: outcome.extensionId,
226
+ nextVersion: outcome.nextVersion
227
+ }, outcome.message);
228
+ }
229
+ return {
230
+ outcomes,
231
+ status: hasError ? "error" : "ok"
232
+ };
233
+ }
234
+ async function runPostUpdateExtensionSync(params) {
235
+ const logger = params.logger ?? {
236
+ info: (message) => log.info(message),
237
+ warn: (message) => log.warn(message),
238
+ error: (message) => log.error(message)
239
+ };
240
+ const channelSyncResult = await syncExtensionsForUpdateChannel({
241
+ channel: params.channel,
242
+ config: params.config,
243
+ logger
244
+ });
245
+ const updateResult = await updateNpmInstalledExtensions({
246
+ skipIds: channelSyncResult.skipIds,
247
+ config: params.config,
248
+ timeoutMs: params.timeoutMs,
249
+ logger
250
+ });
251
+ return {
252
+ status: updateResult.status,
253
+ outcomes: updateResult.outcomes,
254
+ channelSync: channelSyncResult.summary
255
+ };
256
+ }
257
+ //#endregion
258
+ export { runPostUpdateExtensionSync, syncExtensionsForUpdateChannel, updateNpmInstalledExtensions };
259
+
260
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","names":["marketplace.findExtension"],"sources":["../../../src/extensions/update.ts"],"sourcesContent":["/**\n * Post-update extension sync — refresh lockfile-managed npm / store extensions.\n */\n\nimport { existsSync, readFileSync, readdirSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport semver from 'semver';\n\nimport {\n downloadExtensionStoreZipBuffer,\n resolveExtensionZipDownloadUrl,\n resolveExtensionsStoreBaseUrl,\n} from '../agent/skills/marketplace/adapters/store/store-api-client.js';\nimport type { Config } from '../config/schema.js';\nimport { resolveBundledExtensionsDir, resolveExtensionsDir } from '../config/paths.js';\nimport { loadConfig } from '../config/loader.js';\nimport type { UpdateChannel } from '../infra/update-channels.js';\nimport { createLogger } from '../utils/logger.js';\nimport {\n installExtensionFromStoreZip,\n installFromNpm,\n type InstallResult,\n} from './install.js';\nimport {\n getExtensionLockfileManager,\n type ExtensionLockEntry,\n} from './lockfile.js';\nimport * as marketplace from './marketplace.js';\n\nconst log = createLogger('ExtensionUpdate');\n\nconst MANIFEST = 'xopc.extension.json';\n\nexport type ExtensionUpdateLogger = {\n info?: (message: string) => void;\n warn?: (message: string) => void;\n error?: (message: string) => void;\n};\n\nexport type ExtensionUpdateStatus = 'updated' | 'unchanged' | 'skipped' | 'error';\n\nexport type ExtensionUpdateOutcome = {\n extensionId: string;\n status: ExtensionUpdateStatus;\n message: string;\n currentVersion?: string;\n nextVersion?: string;\n};\n\nexport type ExtensionChannelSyncSummary = {\n skippedBundled: string[];\n warnings: string[];\n};\n\nexport type ExtensionPostUpdateResult = {\n status: 'ok' | 'error' | 'skipped';\n outcomes: ExtensionUpdateOutcome[];\n channelSync?: ExtensionChannelSyncSummary;\n};\n\nfunction readInstalledExtensionVersion(targetDir: string, extensionId: string): string | undefined {\n const manifestPath = join(targetDir, extensionId, MANIFEST);\n if (!existsSync(manifestPath)) {\n return undefined;\n }\n try {\n const raw = JSON.parse(readFileSync(manifestPath, 'utf-8')) as { version?: string };\n const version = typeof raw.version === 'string' ? semver.valid(raw.version) : null;\n return version ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function resolveNpmPackageForId(extensionId: string): Promise<string | undefined> {\n const found = await marketplace.findExtension(extensionId);\n return found?.npmPackage;\n}\n\nasync function upsertNpmExtensionLock(\n lock: ReturnType<typeof getExtensionLockfileManager>,\n targetDir: string,\n result: InstallResult,\n spec: string,\n): Promise<void> {\n if (!result.extensionId) return;\n const reg = await marketplace.findExtension(result.extensionId);\n const resolved = reg?.npmPackage ?? spec;\n let ver = reg?.version ?? '0.0.0';\n try {\n const raw = readFileSync(join(targetDir, result.extensionId, MANIFEST), 'utf-8');\n const m = JSON.parse(raw) as { version?: string };\n const mv = typeof m.version === 'string' ? semver.valid(m.version) : null;\n if (mv) ver = mv;\n } catch {\n // keep registry / fallback version\n }\n await lock.upsert(result.extensionId, {\n name: result.extensionId,\n version: ver,\n resolved,\n source: 'npm',\n });\n}\n\nasync function installExtensionFromStoreWithLock(params: {\n storeBase: string;\n packageName: string;\n version?: string;\n targetDir: string;\n lock: ReturnType<typeof getExtensionLockfileManager>;\n}): Promise<{ ok: true; extensionId: string; version: string } | { ok: false; error: string }> {\n try {\n const { downloadUrl, version } = await resolveExtensionZipDownloadUrl(\n params.storeBase,\n params.packageName,\n params.version,\n );\n const buf = await downloadExtensionStoreZipBuffer(params.storeBase, downloadUrl);\n const result = await installExtensionFromStoreZip(buf, params.targetDir);\n if (!result.ok || !result.extensionId) {\n return { ok: false, error: result.error ?? 'install failed' };\n }\n await params.lock.upsert(result.extensionId, {\n name: result.extensionId,\n version,\n resolved: params.packageName,\n source: 'store',\n });\n return { ok: true, extensionId: result.extensionId, version };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\nfunction listBundledExtensionIds(): Set<string> {\n const ids = new Set<string>();\n const bundledDir = resolveBundledExtensionsDir();\n if (!bundledDir || !existsSync(bundledDir)) {\n return ids;\n }\n for (const entry of readdirSync(bundledDir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n ids.add(entry.name);\n }\n }\n return ids;\n}\n\nexport async function syncExtensionsForUpdateChannel(params: {\n channel: UpdateChannel;\n config?: Config;\n logger?: ExtensionUpdateLogger;\n}): Promise<{ skipIds: Set<string>; summary: ExtensionChannelSyncSummary }> {\n const logger = params.logger ?? {};\n const summary: ExtensionChannelSyncSummary = {\n skippedBundled: [],\n warnings: [],\n };\n const skipIds = new Set<string>();\n\n if (params.channel !== 'dev') {\n return { skipIds, summary };\n }\n\n const lock = getExtensionLockfileManager();\n const data = await lock.load();\n const bundledIds = listBundledExtensionIds();\n\n for (const extensionId of Object.keys(data.extensions)) {\n if (!bundledIds.has(extensionId)) {\n continue;\n }\n skipIds.add(extensionId);\n summary.skippedBundled.push(extensionId);\n logger.info?.(`Skipping \"${extensionId}\" on dev channel (bundled copy preferred).`);\n }\n\n return { skipIds, summary };\n}\n\nasync function updateSingleExtension(params: {\n extensionId: string;\n entry: ExtensionLockEntry;\n targetDir: string;\n storeBase: string;\n lock: ReturnType<typeof getExtensionLockfileManager>;\n timeoutMs?: number;\n logger?: ExtensionUpdateLogger;\n}): Promise<ExtensionUpdateOutcome> {\n const { extensionId, entry, targetDir, storeBase, lock, timeoutMs, logger } = params;\n const currentVersion = readInstalledExtensionVersion(targetDir, extensionId);\n\n if (entry.source === 'store') {\n const pkgName = entry.resolved?.trim() || extensionId;\n if (existsSync(join(targetDir, extensionId))) {\n rmSync(join(targetDir, extensionId), { recursive: true, force: true });\n }\n const result = await installExtensionFromStoreWithLock({\n storeBase,\n packageName: pkgName,\n targetDir,\n lock,\n });\n if (result.ok === false) {\n logger.error?.(`Failed to update ${extensionId}: ${result.error}`);\n return {\n extensionId,\n status: 'error',\n message: result.error,\n currentVersion,\n };\n }\n const nextVersion = result.version;\n const status =\n currentVersion && nextVersion && currentVersion === nextVersion ? 'unchanged' : 'updated';\n return {\n extensionId,\n status,\n currentVersion,\n nextVersion,\n message:\n status === 'unchanged'\n ? `${extensionId} is up to date (${currentVersion}).`\n : `Updated ${extensionId}: ${currentVersion ?? 'unknown'} -> ${nextVersion}.`,\n };\n }\n\n if (entry.source !== 'npm') {\n return {\n extensionId,\n status: 'skipped',\n message: `Skipping \"${extensionId}\" (source: ${entry.source}).`,\n };\n }\n\n const spec = entry.resolved?.trim() || (await resolveNpmPackageForId(extensionId));\n if (!spec) {\n return {\n extensionId,\n status: 'skipped',\n message: `Skipping \"${extensionId}\" (could not resolve npm package).`,\n };\n }\n\n if (existsSync(join(targetDir, extensionId))) {\n rmSync(join(targetDir, extensionId), { recursive: true, force: true });\n }\n\n const installResult = await installFromNpm(spec, targetDir, timeoutMs);\n if (!installResult.ok) {\n const message = installResult.error ?? 'npm install failed';\n logger.error?.(`Failed to update ${extensionId}: ${message}`);\n return {\n extensionId,\n status: 'error',\n message,\n currentVersion,\n };\n }\n\n await upsertNpmExtensionLock(lock, targetDir, installResult, spec);\n const nextVersion =\n (installResult.extensionId\n ? readInstalledExtensionVersion(targetDir, installResult.extensionId)\n : undefined) ?? entry.version;\n const resolvedId = installResult.extensionId ?? extensionId;\n const status =\n currentVersion && nextVersion && currentVersion === nextVersion ? 'unchanged' : 'updated';\n return {\n extensionId: resolvedId,\n status,\n currentVersion,\n nextVersion,\n message:\n status === 'unchanged'\n ? `${resolvedId} is up to date (${currentVersion}).`\n : `Updated ${resolvedId}: ${currentVersion ?? 'unknown'} -> ${nextVersion}.`,\n };\n}\n\nexport async function updateNpmInstalledExtensions(params: {\n extensionIds?: string[];\n skipIds?: Set<string>;\n config?: Config;\n timeoutMs?: number;\n logger?: ExtensionUpdateLogger;\n}): Promise<{ outcomes: ExtensionUpdateOutcome[]; status: 'ok' | 'error' | 'skipped' }> {\n const logger = params.logger ?? {};\n const config = params.config ?? loadConfig();\n const targetDir = resolveExtensionsDir();\n const storeBase = resolveExtensionsStoreBaseUrl(config);\n const lock = getExtensionLockfileManager();\n const data = await lock.load();\n\n const ids = params.extensionIds?.length\n ? params.extensionIds\n : Object.keys(data.extensions);\n\n if (ids.length === 0) {\n return { outcomes: [], status: 'skipped' };\n }\n\n const outcomes: ExtensionUpdateOutcome[] = [];\n let hasError = false;\n\n for (const extensionId of ids) {\n if (params.skipIds?.has(extensionId)) {\n outcomes.push({\n extensionId,\n status: 'skipped',\n message: `Skipping \"${extensionId}\" (channel sync).`,\n });\n continue;\n }\n\n const entry = data.extensions[extensionId];\n if (!entry) {\n outcomes.push({\n extensionId,\n status: 'skipped',\n message: `No lockfile entry for \"${extensionId}\".`,\n });\n continue;\n }\n\n const outcome = await updateSingleExtension({\n extensionId,\n entry,\n targetDir,\n storeBase,\n lock,\n timeoutMs: params.timeoutMs,\n logger,\n });\n outcomes.push(outcome);\n if (outcome.status === 'error') {\n hasError = true;\n } else if (outcome.status === 'updated') {\n log.info(\n { extensionId: outcome.extensionId, nextVersion: outcome.nextVersion },\n outcome.message,\n );\n }\n }\n\n return { outcomes, status: hasError ? 'error' : 'ok' };\n}\n\nexport async function runPostUpdateExtensionSync(params: {\n channel: UpdateChannel;\n config?: Config;\n timeoutMs?: number;\n logger?: ExtensionUpdateLogger;\n}): Promise<ExtensionPostUpdateResult> {\n const logger = params.logger ?? {\n info: (message) => log.info(message),\n warn: (message) => log.warn(message),\n error: (message) => log.error(message),\n };\n\n const channelSyncResult = await syncExtensionsForUpdateChannel({\n channel: params.channel,\n config: params.config,\n logger,\n });\n\n const updateResult = await updateNpmInstalledExtensions({\n skipIds: channelSyncResult.skipIds,\n config: params.config,\n timeoutMs: params.timeoutMs,\n logger,\n });\n\n return {\n status: updateResult.status,\n outcomes: updateResult.outcomes,\n channelSync: channelSyncResult.summary,\n };\n}\n"],"mappings":"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"}
@@ -2,16 +2,20 @@
2
2
  * Gateway REST helpers for multi-agent management.
3
3
  */
4
4
  import type { Config } from '../config/schema.js';
5
+ import type { LocalizedText } from '../config/localized-text.js';
5
6
  import type { AgentTypedModel } from '../config/schema.js';
6
7
  export type GatewayAgentTypedModelsInfo = {
7
8
  defaults: AgentTypedModel[];
8
- entry?: AgentTypedModel[];
9
9
  effective: AgentTypedModel[];
10
10
  };
11
11
  export type GatewayAgentRow = {
12
12
  id: string;
13
13
  name?: string;
14
14
  description?: string;
15
+ localized?: {
16
+ name?: LocalizedText;
17
+ description?: LocalizedText;
18
+ };
15
19
  /** Value from `IDENTITY.md` **Avatar:** line when present (may be URL, `xopc:…`, etc.). */
16
20
  avatar?: string;
17
21
  workspace: string;
@@ -41,20 +45,24 @@ export type GatewayAgentsListResponse = {
41
45
  };
42
46
  /** Extract `**Avatar:**` value from profile IDENTITY.md (same line shape as the gateway console parser). */
43
47
  export declare function extractAvatarFromIdentityMarkdown(content: string): string | undefined;
44
- export declare function listGatewayAgents(cfg: Config): Promise<GatewayAgentsListResponse>;
48
+ export declare function listGatewayAgents(cfg: Config, options?: {
49
+ locale?: string;
50
+ }): Promise<GatewayAgentsListResponse>;
45
51
  export type CreateAgentBody = {
46
52
  /** Display name stored on the agent entry. */
47
- name: string;
53
+ name: LocalizedText;
48
54
  /** Optional id seed; normalized agent id defaults from `name` when omitted. */
49
55
  id?: string;
50
56
  workspace: string;
51
57
  model?: string;
52
58
  agentDir?: string;
53
- description?: string;
59
+ description?: LocalizedText;
54
60
  /** Initial `agents.list[].tools.disable` for the new entry. */
55
61
  toolsDisable?: string[];
56
62
  /** Profile markdown files to write after seeding (e.g. `IDENTITY.md`, `SOUL.md`). */
57
63
  profileFiles?: Record<string, string>;
64
+ /** Clone from an existing agent id — copies config entry fields and profile directory. */
65
+ cloneFrom?: string;
58
66
  };
59
67
  export type AgentAdminHttpStatus = 400 | 404 | 409;
60
68
  export type AgentAdminResult<T> = {
@@ -80,10 +88,11 @@ export declare function prepareCreateAgentsBatch(cfg: Config, bodies: CreateAgen
80
88
  }>;
81
89
  export declare function finalizeCreateAgentDirs(cfg: Config, agentId: string, opts?: {
82
90
  profileFiles?: Record<string, string>;
91
+ cloneFrom?: string;
83
92
  }): Promise<AgentAdminResult<void>>;
84
93
  export type UpdateAgentBody = {
85
- name?: string;
86
- description?: string | null;
94
+ name?: LocalizedText;
95
+ description?: LocalizedText | null;
87
96
  workspace?: string;
88
97
  model?: string | null;
89
98
  agentDir?: string | null;
@@ -92,8 +101,6 @@ export type UpdateAgentBody = {
92
101
  skills?: string[] | null;
93
102
  /** Replace `agents.list[].tools.disable`; `null` clears entry-level disables. */
94
103
  toolsDisable?: string[] | null;
95
- /** Replace `agents.list[].models`; `null` removes entry overrides (inherit defaults). */
96
- models?: AgentTypedModel[] | null;
97
104
  };
98
105
  export declare function prepareUpdateAgent(cfg: Config, agentIdRaw: string, body: UpdateAgentBody): AgentAdminResult<{
99
106
  nextConfig: Config;