@xopcai/xopc 0.0.83 → 0.0.85

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 (457) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +3 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/plugin.d.ts +2 -0
  6. package/dist/extensions/feishu/src/plugin.js +10 -0
  7. package/dist/extensions/feishu/src/plugin.js.map +1 -1
  8. package/dist/extensions/feishu/src/workflow-progress.d.ts +27 -0
  9. package/dist/extensions/feishu/src/workflow-progress.js +99 -0
  10. package/dist/extensions/feishu/src/workflow-progress.js.map +1 -0
  11. package/dist/extensions/telegram/src/plugin.d.ts +2 -0
  12. package/dist/extensions/telegram/src/plugin.js +11 -1
  13. package/dist/extensions/telegram/src/plugin.js.map +1 -1
  14. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  15. package/dist/extensions/telegram/src/workflow-progress.d.ts +24 -0
  16. package/dist/extensions/telegram/src/workflow-progress.js +73 -0
  17. package/dist/extensions/telegram/src/workflow-progress.js.map +1 -0
  18. package/dist/extensions/telegram/xopc.extension.json +1 -1
  19. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +158 -0
  20. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -0
  21. package/dist/extensions/weixin/src/api/api.js +2 -2
  22. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  23. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  24. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  25. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  26. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  27. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  28. package/dist/extensions/weixin/src/plugin.d.ts +2 -0
  29. package/dist/extensions/weixin/src/plugin.js +11 -1
  30. package/dist/extensions/weixin/src/plugin.js.map +1 -1
  31. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  32. package/dist/extensions/weixin/src/workflow-progress.d.ts +26 -0
  33. package/dist/extensions/weixin/src/workflow-progress.js +99 -0
  34. package/dist/extensions/weixin/src/workflow-progress.js.map +1 -0
  35. package/dist/gateway/static/root/assets/agents-D3_-kNlZ.js +222 -0
  36. package/dist/gateway/static/root/assets/apps-page-D7v7649T.js +1 -0
  37. package/dist/gateway/static/root/assets/channels-settings-nCaMb0a7.js +1 -0
  38. package/dist/gateway/static/root/assets/channels-status-swr-C1gZBcJV.js +8 -0
  39. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
  40. package/dist/gateway/static/root/assets/cron-api-CoYK0hlm.js +1 -0
  41. package/dist/gateway/static/root/assets/cron-page-DeGo-Vjc.js +1 -0
  42. package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +45 -0
  43. package/dist/gateway/static/root/assets/{dist-BpQxde0t.js → dist-DaK4dsss.js} +1 -1
  44. package/dist/gateway/static/root/assets/{extension-debug-page-CY27wj_p.js → extension-debug-page-BZngZWbO.js} +1 -1
  45. package/dist/gateway/static/root/assets/extension-page-D6JSyV27.js +1 -0
  46. package/dist/gateway/static/root/assets/extension-settings-page-8PZcmWI7.js +1 -0
  47. package/dist/gateway/static/root/assets/fetch-B2MYHbWg.js +1 -0
  48. package/dist/gateway/static/root/assets/{field-primitives-fa_hiQcX.js → field-primitives-Zzl22MvN.js} +1 -1
  49. package/dist/gateway/static/root/assets/heartbeat-config-api-BtIcpG0O.js +1 -0
  50. package/dist/gateway/static/root/assets/index-D4vM3-P7.js +4700 -0
  51. package/dist/gateway/static/root/assets/index-ew_2L2We.css +1 -0
  52. package/dist/gateway/static/root/assets/logs-page-_d4UJ-qQ.js +1 -0
  53. package/dist/gateway/static/root/assets/sessions-page-5N4aF2Wk.js +1 -0
  54. package/dist/gateway/static/root/assets/settings-form-section-D_tgb8r2.js +1 -0
  55. package/dist/gateway/static/root/assets/settings-page-C18xBt4X.js +3 -0
  56. package/dist/gateway/static/root/assets/share-preview-page-D4EG_vM1.js +2 -0
  57. package/dist/gateway/static/root/assets/skills-page-sPAXhh8w.js +2 -0
  58. package/dist/gateway/static/root/assets/theme-store-DryYl3qD.js +1 -0
  59. package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +3 -0
  60. package/dist/gateway/static/root/assets/utils-CYO9eTCM.js +1 -0
  61. package/dist/gateway/static/root/assets/voice-api-key-field-Ds51havm.js +1 -0
  62. package/dist/gateway/static/root/index.html +7 -6
  63. package/dist/package.js +1 -1
  64. package/dist/src/agent/agent-manager.js +7 -7
  65. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  66. package/dist/src/agent/context/workspace-seed.js +3 -3
  67. package/dist/src/agent/embedded/map-stream-events.js +6 -0
  68. package/dist/src/agent/embedded/map-stream-events.js.map +1 -1
  69. package/dist/src/agent/embedded/subscribe-session.js +24 -0
  70. package/dist/src/agent/embedded/subscribe-session.js.map +1 -1
  71. package/dist/src/agent/embedded/types.d.ts +19 -0
  72. package/dist/src/agent/goals/goal-locale.js +2 -2
  73. package/dist/src/agent/goals/goal-run-store.js +4 -4
  74. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  75. package/dist/src/agent/goals/post-turn.js +2 -2
  76. package/dist/src/agent/image/load-image-media.js +2 -2
  77. package/dist/src/agent/ipc/bus.js +1 -1
  78. package/dist/src/agent/ipc/inbox.js +2 -2
  79. package/dist/src/agent/ipc/socket.js +1 -1
  80. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  81. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  82. package/dist/src/agent/memory/dreaming/events.js +1 -1
  83. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  84. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  85. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  86. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  87. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  88. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  89. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  90. package/dist/src/agent/models/manager.js +1 -1
  91. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  92. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  93. package/dist/src/agent/reply/startup-context.d.ts +3 -0
  94. package/dist/src/agent/reply/startup-context.js +25 -2
  95. package/dist/src/agent/reply/startup-context.js.map +1 -1
  96. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  97. package/dist/src/agent/sandbox/path-policy.js +2 -2
  98. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  99. package/dist/src/agent/service.d.ts +1 -0
  100. package/dist/src/agent/service.js +10 -4
  101. package/dist/src/agent/service.js.map +1 -1
  102. package/dist/src/agent/session/session-inspector.js +1 -1
  103. package/dist/src/agent/skills/config.js +1 -1
  104. package/dist/src/agent/skills/hub-hash.js +2 -2
  105. package/dist/src/agent/skills/hub-lock.js +1 -1
  106. package/dist/src/agent/skills/hub-pull.js +3 -3
  107. package/dist/src/agent/skills/index.js +1 -1
  108. package/dist/src/agent/skills/managed-store.js +1 -1
  109. package/dist/src/agent/skills/scanner.js +1 -1
  110. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  111. package/dist/src/agent/skills/skill-manager.js +1 -1
  112. package/dist/src/agent/tools/create-share-tool.d.ts +27 -0
  113. package/dist/src/agent/tools/create-share-tool.js +237 -0
  114. package/dist/src/agent/tools/create-share-tool.js.map +1 -0
  115. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  116. package/dist/src/agent/tools/factory.js +35 -1
  117. package/dist/src/agent/tools/factory.js.map +1 -1
  118. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  119. package/dist/src/agent/tools/index.d.ts +2 -0
  120. package/dist/src/agent/tools/index.js +3 -1
  121. package/dist/src/agent/tools/send-media.js +1 -1
  122. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  123. package/dist/src/agent/tools/workflow-tool.d.ts +41 -0
  124. package/dist/src/agent/tools/workflow-tool.js +271 -0
  125. package/dist/src/agent/tools/workflow-tool.js.map +1 -0
  126. package/dist/src/agent/tools/write.js +1 -1
  127. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +9 -0
  128. package/dist/src/agent/workflow/builtins/audit-repo.js +115 -0
  129. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -0
  130. package/dist/src/agent/workflow/builtins/index.d.ts +15 -0
  131. package/dist/src/agent/workflow/builtins/index.js +28 -0
  132. package/dist/src/agent/workflow/builtins/index.js.map +1 -0
  133. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +9 -0
  134. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +113 -0
  135. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -0
  136. package/dist/src/agent/workflow/builtins/research.d.ts +9 -0
  137. package/dist/src/agent/workflow/builtins/research.js +129 -0
  138. package/dist/src/agent/workflow/builtins/research.js.map +1 -0
  139. package/dist/src/agent/workflow/catalog.d.ts +51 -0
  140. package/dist/src/agent/workflow/catalog.js +155 -0
  141. package/dist/src/agent/workflow/catalog.js.map +1 -0
  142. package/dist/src/agent/workflow/channel-capability.d.ts +76 -0
  143. package/dist/src/agent/workflow/channel-capability.js +1 -0
  144. package/dist/src/agent/workflow/index.d.ts +11 -0
  145. package/dist/src/agent/workflow/index.js +10 -0
  146. package/dist/src/agent/workflow/last-run-memory.d.ts +42 -0
  147. package/dist/src/agent/workflow/last-run-memory.js +60 -0
  148. package/dist/src/agent/workflow/last-run-memory.js.map +1 -0
  149. package/dist/src/agent/workflow/parser.d.ts +20 -0
  150. package/dist/src/agent/workflow/parser.js +137 -0
  151. package/dist/src/agent/workflow/parser.js.map +1 -0
  152. package/dist/src/agent/workflow/progress-broker.d.ts +80 -0
  153. package/dist/src/agent/workflow/progress-broker.js +263 -0
  154. package/dist/src/agent/workflow/progress-broker.js.map +1 -0
  155. package/dist/src/agent/workflow/runtime.d.ts +31 -0
  156. package/dist/src/agent/workflow/runtime.js +301 -0
  157. package/dist/src/agent/workflow/runtime.js.map +1 -0
  158. package/dist/src/agent/workflow/snapshot.d.ts +18 -0
  159. package/dist/src/agent/workflow/snapshot.js +144 -0
  160. package/dist/src/agent/workflow/snapshot.js.map +1 -0
  161. package/dist/src/agent/workflow/structured-output-tool.d.ts +33 -0
  162. package/dist/src/agent/workflow/structured-output-tool.js +58 -0
  163. package/dist/src/agent/workflow/structured-output-tool.js.map +1 -0
  164. package/dist/src/agent/workflow/subagent-runner.d.ts +42 -0
  165. package/dist/src/agent/workflow/subagent-runner.js +104 -0
  166. package/dist/src/agent/workflow/subagent-runner.js.map +1 -0
  167. package/dist/src/agent/workflow/types.d.ts +137 -0
  168. package/dist/src/agent/workflow/types.js +1 -0
  169. package/dist/src/auth/credentials.js +3 -3
  170. package/dist/src/auth/profiles/store.js +1 -1
  171. package/dist/src/auth/sync-provider-auth.js +1 -1
  172. package/dist/src/browser/cache-dir-policy.js +1 -1
  173. package/dist/src/browser/cdp-local-launcher.js +2 -2
  174. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  175. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  176. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  177. package/dist/src/browser/stealth.js +1 -1
  178. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  179. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  180. package/dist/src/channels/outbound/persist-store.js +1 -1
  181. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  182. package/dist/src/channels/pairing/pairing-store.js +2 -2
  183. package/dist/src/chat-commands/builtins/config.js +2 -2
  184. package/dist/src/chat-commands/builtins/model.js +40 -23
  185. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  186. package/dist/src/chat-commands/builtins/system.js +30 -15
  187. package/dist/src/chat-commands/builtins/system.js.map +1 -1
  188. package/dist/src/chat-commands/builtins/workflow.d.ts +18 -0
  189. package/dist/src/chat-commands/builtins/workflow.js +167 -0
  190. package/dist/src/chat-commands/builtins/workflow.js.map +1 -0
  191. package/dist/src/chat-commands/context.js +1 -1
  192. package/dist/src/chat-commands/format-output.d.ts +28 -0
  193. package/dist/src/chat-commands/format-output.js +45 -0
  194. package/dist/src/chat-commands/format-output.js.map +1 -0
  195. package/dist/src/chat-commands/index.d.ts +1 -0
  196. package/dist/src/chat-commands/index.js +3 -1
  197. package/dist/src/chat-commands/index.js.map +1 -1
  198. package/dist/src/cli/command-catalog.js +110 -8
  199. package/dist/src/cli/command-catalog.js.map +1 -1
  200. package/dist/src/cli/command-loaders.js +2 -0
  201. package/dist/src/cli/command-loaders.js.map +1 -1
  202. package/dist/src/cli/command-manifest.js +9 -1
  203. package/dist/src/cli/command-manifest.js.map +1 -1
  204. package/dist/src/cli/commands/config.js +71 -20
  205. package/dist/src/cli/commands/config.js.map +1 -1
  206. package/dist/src/cli/commands/cron-cli.d.ts +2 -0
  207. package/dist/src/cli/commands/cron-cli.js +15 -0
  208. package/dist/src/cli/commands/cron-cli.js.map +1 -0
  209. package/dist/src/cli/commands/cron.d.ts +4 -1
  210. package/dist/src/cli/commands/cron.js +76 -41
  211. package/dist/src/cli/commands/cron.js.map +1 -1
  212. package/dist/src/cli/commands/doctor/checks/channel-config.js +1 -1
  213. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
  214. package/dist/src/cli/commands/doctor/checks/config-health.js +2 -2
  215. package/dist/src/cli/commands/doctor/checks/config-health.js.map +1 -1
  216. package/dist/src/cli/commands/doctor/checks/cron-health.js +1 -1
  217. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -1
  218. package/dist/src/cli/commands/doctor/checks/gateway-health.js +2 -2
  219. package/dist/src/cli/commands/doctor/checks/gateway-health.js.map +1 -1
  220. package/dist/src/cli/commands/doctor/checks/gateway-service.js +2 -2
  221. package/dist/src/cli/commands/doctor/checks/gateway-service.js.map +1 -1
  222. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  223. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  224. package/dist/src/cli/commands/doctor/checks/state-integrity.js +2 -2
  225. package/dist/src/cli/commands/doctor/checks/state-integrity.js.map +1 -1
  226. package/dist/src/cli/commands/doctor/checks/workspace-status.js +4 -4
  227. package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
  228. package/dist/src/cli/commands/extension-dev.js +1 -1
  229. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  230. package/dist/src/cli/commands/extension-pack.js +1 -1
  231. package/dist/src/cli/commands/gateway/index.d.ts +1 -1
  232. package/dist/src/cli/commands/gateway/index.js +2 -2
  233. package/dist/src/cli/commands/gateway/lifecycle.js +10 -4
  234. package/dist/src/cli/commands/gateway/lifecycle.js.map +1 -1
  235. package/dist/src/cli/commands/gateway/service.d.ts +4 -0
  236. package/dist/src/cli/commands/gateway/service.js +17 -2
  237. package/dist/src/cli/commands/gateway/service.js.map +1 -1
  238. package/dist/src/cli/commands/gateway/shared.js +1 -1
  239. package/dist/src/cli/commands/gateway/subcommands.js +1 -4
  240. package/dist/src/cli/commands/gateway/subcommands.js.map +1 -1
  241. package/dist/src/cli/commands/image.js +1 -1
  242. package/dist/src/cli/commands/init.js +31 -4
  243. package/dist/src/cli/commands/init.js.map +1 -1
  244. package/dist/src/cli/commands/models.d.ts +4 -1
  245. package/dist/src/cli/commands/models.js +86 -74
  246. package/dist/src/cli/commands/models.js.map +1 -1
  247. package/dist/src/cli/commands/onboard.js +4 -2
  248. package/dist/src/cli/commands/onboard.js.map +1 -1
  249. package/dist/src/cli/commands/profile.d.ts +3 -5
  250. package/dist/src/cli/commands/profile.js +31 -31
  251. package/dist/src/cli/commands/profile.js.map +1 -1
  252. package/dist/src/cli/commands/setup.js +6 -1
  253. package/dist/src/cli/commands/setup.js.map +1 -1
  254. package/dist/src/cli/commands/tunnel.js +2 -2
  255. package/dist/src/cli/gateway-run-argv.js +15 -5
  256. package/dist/src/cli/gateway-run-argv.js.map +1 -1
  257. package/dist/src/cli/utils/gateway-client.js +1 -1
  258. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  259. package/dist/src/config/agent-profile.js +1 -1
  260. package/dist/src/config/gateway-bind.js +1 -1
  261. package/dist/src/config/index.js +5 -5
  262. package/dist/src/config/loader.js +2 -2
  263. package/dist/src/config/models-json.js +2 -2
  264. package/dist/src/config/paths-state.js +1 -1
  265. package/dist/src/config/profile.js +2 -2
  266. package/dist/src/config/public-url.d.ts +28 -0
  267. package/dist/src/config/public-url.js +103 -0
  268. package/dist/src/config/public-url.js.map +1 -0
  269. package/dist/src/config/schema.d.ts +82 -0
  270. package/dist/src/config/schema.js +130 -1
  271. package/dist/src/config/schema.js.map +1 -1
  272. package/dist/src/config/workspace-path.js +1 -1
  273. package/dist/src/cron/executor.js +2 -2
  274. package/dist/src/cron/persistence.js +1 -1
  275. package/dist/src/cron/run-log-store.js +1 -1
  276. package/dist/src/daemon/constants.js +1 -1
  277. package/dist/src/daemon/install-plan.js +3 -3
  278. package/dist/src/daemon/install-plan.js.map +1 -1
  279. package/dist/src/daemon/launchd.js +2 -2
  280. package/dist/src/daemon/schtasks.js +38 -1
  281. package/dist/src/daemon/schtasks.js.map +1 -1
  282. package/dist/src/daemon/systemd.js +2 -2
  283. package/dist/src/extensions/bundle-mcp.js +1 -1
  284. package/dist/src/extensions/discover-extensions.js +1 -1
  285. package/dist/src/extensions/health.js +1 -1
  286. package/dist/src/extensions/loader.js +1 -1
  287. package/dist/src/extensions/lockfile.js +2 -2
  288. package/dist/src/gateway/agents-admin.js +2 -2
  289. package/dist/src/gateway/file-path-classifier.js +2 -2
  290. package/dist/src/gateway/heartbeat/service.js +1 -1
  291. package/dist/src/gateway/hono/app.js +33 -2
  292. package/dist/src/gateway/hono/app.js.map +1 -1
  293. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  294. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  295. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  296. package/dist/src/gateway/hono/oauth.js +1 -1
  297. package/dist/src/gateway/hono/routes/agents.js +1 -1
  298. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  299. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  300. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  301. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  302. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  303. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  304. package/dist/src/gateway/hono/routes/models.js +1 -1
  305. package/dist/src/gateway/hono/routes/shares.js +631 -34
  306. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  307. package/dist/src/gateway/hono/routes/site-shares.d.ts +3 -0
  308. package/dist/src/gateway/hono/routes/site-shares.js +228 -0
  309. package/dist/src/gateway/hono/routes/site-shares.js.map +1 -0
  310. package/dist/src/gateway/hono/routes/tunnel.js +97 -8
  311. package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
  312. package/dist/src/gateway/hono/routes/workspace.js +5 -5
  313. package/dist/src/gateway/hono/sse.js +2 -2
  314. package/dist/src/gateway/host.d.ts +3 -1
  315. package/dist/src/gateway/host.js +3 -1
  316. package/dist/src/gateway/host.js.map +1 -1
  317. package/dist/src/gateway/lock.js +3 -3
  318. package/dist/src/gateway/ports.d.ts +6 -0
  319. package/dist/src/gateway/ports.js +38 -2
  320. package/dist/src/gateway/ports.js.map +1 -1
  321. package/dist/src/gateway/public-url.d.ts +8 -0
  322. package/dist/src/gateway/public-url.js +10 -0
  323. package/dist/src/gateway/public-url.js.map +1 -0
  324. package/dist/src/gateway/security/origin-check.d.ts +9 -1
  325. package/dist/src/gateway/security/origin-check.js +4 -0
  326. package/dist/src/gateway/security/origin-check.js.map +1 -1
  327. package/dist/src/gateway/server.js +15 -0
  328. package/dist/src/gateway/server.js.map +1 -1
  329. package/dist/src/gateway/service/agent-runner.js +2 -2
  330. package/dist/src/gateway/service/marketplace-service.js +2 -2
  331. package/dist/src/gateway/service/run-gateway-agent.js +2 -2
  332. package/dist/src/gateway/service.js +3 -2
  333. package/dist/src/gateway/service.js.map +1 -1
  334. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  335. package/dist/src/heartbeat/index.js +1 -1
  336. package/dist/src/i18n/goals-bundle.js +1 -1
  337. package/dist/src/i18n/index.d.ts +1 -0
  338. package/dist/src/i18n/index.js +2 -1
  339. package/dist/src/i18n/locales/share-tool.en.js +15 -0
  340. package/dist/src/i18n/locales/share-tool.en.js.map +1 -0
  341. package/dist/src/i18n/locales/share-tool.zh.js +15 -0
  342. package/dist/src/i18n/locales/share-tool.zh.js.map +1 -0
  343. package/dist/src/i18n/share-tool-bundle.d.ts +20 -0
  344. package/dist/src/i18n/share-tool-bundle.js +56 -0
  345. package/dist/src/i18n/share-tool-bundle.js.map +1 -0
  346. package/dist/src/infra/gateway-processes.js +1 -0
  347. package/dist/src/infra/gateway-processes.js.map +1 -1
  348. package/dist/src/infra/restart.js +2 -2
  349. package/dist/src/infra/update-check.js +1 -1
  350. package/dist/src/infra/update-lock.js +3 -3
  351. package/dist/src/infra/update-runner.js +1 -1
  352. package/dist/src/infra/update-startup.js +2 -2
  353. package/dist/src/infra/write-file-atomic.js +2 -2
  354. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  355. package/dist/src/providers/index.js +2 -2
  356. package/dist/src/providers/model-registry.js +1 -1
  357. package/dist/src/session/config-store.js +2 -2
  358. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  359. package/dist/src/session/parity/sessions-json-file.js +1 -1
  360. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  361. package/dist/src/session/parity/transcript-paths.js +1 -1
  362. package/dist/src/session/search-index-cache.js +1 -1
  363. package/dist/src/session/search-index.js +1 -1
  364. package/dist/src/session/session-title.js +3 -2
  365. package/dist/src/session/session-title.js.map +1 -1
  366. package/dist/src/session/store.js +5 -5
  367. package/dist/src/share/share-auto.d.ts +74 -0
  368. package/dist/src/share/share-auto.js +247 -0
  369. package/dist/src/share/share-auto.js.map +1 -0
  370. package/dist/src/share/share-config.js +63 -4
  371. package/dist/src/share/share-config.js.map +1 -1
  372. package/dist/src/share/share-landing.d.ts +28 -2
  373. package/dist/src/share/share-landing.js +155 -34
  374. package/dist/src/share/share-landing.js.map +1 -1
  375. package/dist/src/share/share-store.d.ts +48 -4
  376. package/dist/src/share/share-store.js +322 -51
  377. package/dist/src/share/share-store.js.map +1 -1
  378. package/dist/src/share/share-thumbnail.d.ts +35 -0
  379. package/dist/src/share/share-thumbnail.js +277 -0
  380. package/dist/src/share/share-thumbnail.js.map +1 -0
  381. package/dist/src/share/share-types.d.ts +68 -10
  382. package/dist/src/share/share-types.js +18 -1
  383. package/dist/src/share/share-types.js.map +1 -1
  384. package/dist/src/share/share-url.js +1 -1
  385. package/dist/src/share/share-zip.d.ts +35 -0
  386. package/dist/src/share/share-zip.js +303 -0
  387. package/dist/src/share/share-zip.js.map +1 -0
  388. package/dist/src/share/site-proxy.d.ts +35 -0
  389. package/dist/src/share/site-proxy.js +234 -0
  390. package/dist/src/share/site-proxy.js.map +1 -0
  391. package/dist/src/share/site-share-config.d.ts +11 -0
  392. package/dist/src/share/site-share-config.js +103 -0
  393. package/dist/src/share/site-share-config.js.map +1 -0
  394. package/dist/src/share/site-share-router.d.ts +23 -0
  395. package/dist/src/share/site-share-router.js +147 -0
  396. package/dist/src/share/site-share-router.js.map +1 -0
  397. package/dist/src/share/site-share-store.d.ts +53 -0
  398. package/dist/src/share/site-share-store.js +400 -0
  399. package/dist/src/share/site-share-store.js.map +1 -0
  400. package/dist/src/share/site-share-types.d.ts +103 -0
  401. package/dist/src/share/site-share-types.js +41 -0
  402. package/dist/src/share/site-share-types.js.map +1 -0
  403. package/dist/src/share/site-static-serve.d.ts +10 -0
  404. package/dist/src/share/site-static-serve.js +145 -0
  405. package/dist/src/share/site-static-serve.js.map +1 -0
  406. package/dist/src/tui/clipboard-image.js +3 -3
  407. package/dist/src/tui/theme-manager.js +1 -1
  408. package/dist/src/tui/tui-commands.js +18 -0
  409. package/dist/src/tui/tui-commands.js.map +1 -1
  410. package/dist/src/tui/tui-keybindings-file.js +1 -1
  411. package/dist/src/tui/tui-scoped-models.js +2 -2
  412. package/dist/src/tui/tui-settings.js +1 -1
  413. package/dist/src/tui/tui-workflow-slash.d.ts +32 -0
  414. package/dist/src/tui/tui-workflow-slash.js +63 -0
  415. package/dist/src/tui/tui-workflow-slash.js.map +1 -0
  416. package/dist/src/tui/tui.js +2 -2
  417. package/dist/src/tunnel/enable-lan-pairing.js +1 -1
  418. package/dist/src/tunnel/frpc-binary.js +3 -3
  419. package/dist/src/tunnel/frpc-config.js +1 -1
  420. package/dist/src/tunnel/frpc-extract.js +1 -1
  421. package/dist/src/tunnel/index.js +2 -2
  422. package/dist/src/tunnel/pair-context.d.ts +7 -1
  423. package/dist/src/tunnel/pair-context.js +25 -9
  424. package/dist/src/tunnel/pair-context.js.map +1 -1
  425. package/dist/src/tunnel/pair-url.d.ts +14 -1
  426. package/dist/src/tunnel/pair-url.js +14 -1
  427. package/dist/src/tunnel/pair-url.js.map +1 -1
  428. package/dist/src/tunnel/tunnel-service.js +2 -2
  429. package/dist/src/tunnel/tunnel-state.js +1 -1
  430. package/dist/src/utils/logger/audit.js +1 -1
  431. package/dist/src/utils/logger/log-store.js +1 -1
  432. package/dist/src/utils/logger/rotation.js +1 -1
  433. package/dist/src/voice/tts/audio.js +1 -1
  434. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  435. package/package.json +3 -2
  436. package/dist/gateway/static/root/assets/agents-CrpYTHJS.js +0 -222
  437. package/dist/gateway/static/root/assets/apps-page-1mcKh5Rh.js +0 -1
  438. package/dist/gateway/static/root/assets/button-KafIU8dx.js +0 -1
  439. package/dist/gateway/static/root/assets/channels-settings-zd6QNKPx.js +0 -1
  440. package/dist/gateway/static/root/assets/channels-status-swr-uRAuhiUo.js +0 -8
  441. package/dist/gateway/static/root/assets/cron-api-O2Q_ruV6.js +0 -1
  442. package/dist/gateway/static/root/assets/cron-page-By09AQD-.js +0 -1
  443. package/dist/gateway/static/root/assets/dist-C57OMHW8.js +0 -48
  444. package/dist/gateway/static/root/assets/extension-page-C-Ed5ZmP.js +0 -1
  445. package/dist/gateway/static/root/assets/extension-settings-page-raLux7E7.js +0 -1
  446. package/dist/gateway/static/root/assets/fetch-2iRFmd3n.js +0 -3
  447. package/dist/gateway/static/root/assets/heartbeat-config-api-BVl5VHvL.js +0 -1
  448. package/dist/gateway/static/root/assets/index-BuFldCsB.css +0 -1
  449. package/dist/gateway/static/root/assets/index-Y-iqo-gL.js +0 -4693
  450. package/dist/gateway/static/root/assets/logs-page-BdH2n7ZW.js +0 -1
  451. package/dist/gateway/static/root/assets/sessions-page-Vpchzdp-.js +0 -1
  452. package/dist/gateway/static/root/assets/settings-form-section-Kk1yAGBl.js +0 -1
  453. package/dist/gateway/static/root/assets/settings-page-KBm0u6Dz.js +0 -3
  454. package/dist/gateway/static/root/assets/skills-page-BjeXXaOn.js +0 -2
  455. package/dist/gateway/static/root/assets/theme-store-D01dJt95.js +0 -1
  456. package/dist/gateway/static/root/assets/utils-DpTxN4AF.js +0 -1
  457. package/dist/gateway/static/root/assets/voice-api-key-field-CwO8Cf01.js +0 -1
@@ -0,0 +1,271 @@
1
+ import { createLogger } from "../../utils/logger/index.js";
2
+ import { init_logger } from "../../utils/logger.js";
3
+ import { parseWorkflowScript } from "../workflow/parser.js";
4
+ import { getLastWorkflowMemory } from "../workflow/last-run-memory.js";
5
+ import { previewValue, recomputeCounts, renderWorkflowText } from "../workflow/snapshot.js";
6
+ import { runWorkflow } from "../workflow/runtime.js";
7
+ import { DelegateSubagentRunner } from "../workflow/subagent-runner.js";
8
+ import "../workflow/index.js";
9
+ import { Type } from "@sinclair/typebox";
10
+ //#region src/agent/tools/workflow-tool.ts
11
+ /**
12
+ * `workflow` — the AgentTool the parent model calls to spawn a fan-out run.
13
+ *
14
+ * Shape mirrors `delegate-tool`: factory builds a closure over deps; `execute`
15
+ * parses the script, instantiates the {@link DelegateSubagentRunner}, drives the
16
+ * {@link runWorkflow} runtime, and pushes a live text snapshot through
17
+ * `onUpdate` for streaming UIs (TUI, gateway console).
18
+ *
19
+ * Why this lives in `src/agent/tools/` (not under `src/agent/workflow/`):
20
+ * the runtime is reusable infrastructure; the AgentTool wrapping is a
21
+ * presentation concern that depends on the AgentToolsFactory wiring. Keeping
22
+ * the wrapper here matches how `delegate-tool` and `execute-code-tool` are
23
+ * organised today.
24
+ */
25
+ init_logger();
26
+ const log = createLogger("workflow-tool");
27
+ const DEFAULT_TIMEOUT_SEC = 1800;
28
+ const MAX_TIMEOUT_SEC = 14400;
29
+ const DEFAULT_MAX_CONCURRENCY = 16;
30
+ const DEFAULT_MAX_SUBAGENTS = 1e3;
31
+ const WorkflowToolSchema = Type.Object({
32
+ name: Type.Optional(Type.String({ description: "Name of a saved workflow to run. Either `name` or `script` is required. Use `name` whenever the user references a known workflow (built-in or in ~/.xopc/workflows/)." })),
33
+ script: Type.Optional(Type.String({ description: [
34
+ "Raw JavaScript workflow script (no Markdown fences, no TypeScript syntax). Ignored when `name` is set.",
35
+ "First statement: export const meta = { name: 'snake_case', description: 'short, human-readable' }.",
36
+ "Use phase(title), agent(prompt, opts), parallel(arrayOfFunctions), pipeline(items, ...stages), log(message), args, and budget.",
37
+ "The script must call agent() at least once.",
38
+ "parallel() requires functions: await parallel(items.map(item => () => agent(...)))."
39
+ ].join(" ") })),
40
+ args: Type.Optional(Type.Any({ description: "Optional JSON value exposed to the workflow script as the global `args`." }))
41
+ });
42
+ function createWorkflowTool(deps) {
43
+ return {
44
+ name: "workflow",
45
+ label: "◆ Workflow",
46
+ description: [
47
+ "Run a deterministic JavaScript workflow that orchestrates multiple isolated subagents through agent(), parallel(), and pipeline().",
48
+ "Two ways to invoke:",
49
+ " 1. `name`: run a saved workflow from the catalog (built-in or ~/.xopc/workflows/). Prefer this when the user references a known name.",
50
+ " 2. `script`: provide a raw JS workflow inline. Use when no saved workflow fits. Header is required: export const meta = { name, description }.",
51
+ "Named-workflow triggers — call this tool with `{ name: \"<name>\" }` IMMEDIATELY when the user message is any of:",
52
+ " • a bare workflow name like \"/audit_repo\", \"/research\", or \"audit_repo\"",
53
+ " • \"run the audit_repo workflow\", \"kick off research\", \"do a multi_perspective_review on X\" (extract args.target when natural)",
54
+ " • after /workflows lists saved workflows and the user picks one",
55
+ "Use phase(title) at runtime to mark progress groups. Each agent() returns a string, or a schema-validated object when opts.schema is set.",
56
+ "Prefer for decomposable work: repo audits, multi-perspective review, fan-out research, large refactors. Do not use for a single quick read/edit.",
57
+ "parallel() takes thunks, not promises: parallel(items.map(item => () => agent(...))).",
58
+ "pipeline(items, ...stages) interleaves items across stages — fastest path by default; only use parallel() when you genuinely need a cross-item barrier.",
59
+ "Failed agent()/parallel()/pipeline() entries resolve to null; check before synthesizing.",
60
+ "Do not use Date.now(), Math.random(), new Date(), require, import, fs, or network APIs — they are unavailable for determinism.",
61
+ "Always end with a synthesis agent() that consolidates findings, especially when you fan out for review or research."
62
+ ].join("\n\n"),
63
+ parameters: WorkflowToolSchema,
64
+ async execute(_toolCallId, params, signal, onUpdate) {
65
+ let script;
66
+ let resolvedSource = "script";
67
+ try {
68
+ const resolved = resolveScript(params, deps.catalog);
69
+ script = resolved.script;
70
+ resolvedSource = resolved.source;
71
+ } catch (e) {
72
+ const message = e instanceof Error ? e.message : String(e);
73
+ return {
74
+ content: [{
75
+ type: "text",
76
+ text: `workflow: ${message}`
77
+ }],
78
+ details: { error: message }
79
+ };
80
+ }
81
+ const wfCfg = deps.getConfig()?.agents?.defaults?.workflow;
82
+ const concurrency = wfCfg?.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY;
83
+ const maxSubagents = wfCfg?.maxSubagents ?? DEFAULT_MAX_SUBAGENTS;
84
+ const timeoutSec = clampTimeout(wfCfg?.defaultTimeoutSec);
85
+ let meta;
86
+ try {
87
+ meta = parseWorkflowScript(script).meta;
88
+ } catch (e) {
89
+ const message = e instanceof Error ? e.message : String(e);
90
+ return {
91
+ content: [{
92
+ type: "text",
93
+ text: resolvedSource === "name" ? `workflow "${params.name}" failed to parse: ${message}` : `workflow parse error: ${message}`
94
+ }],
95
+ details: { error: message }
96
+ };
97
+ }
98
+ const snapshot = {
99
+ name: meta.name,
100
+ description: meta.description,
101
+ phases: [],
102
+ logs: [],
103
+ agents: [],
104
+ agentCount: 0,
105
+ runningCount: 0,
106
+ doneCount: 0,
107
+ errorCount: 0,
108
+ skippedCount: 0
109
+ };
110
+ const pushUpdate = (completed = false) => {
111
+ recomputeCounts(snapshot);
112
+ onUpdate?.({
113
+ content: [{
114
+ type: "text",
115
+ text: renderWorkflowText(snapshot, completed, { showResultPreviews: false })
116
+ }],
117
+ details: snapshot
118
+ });
119
+ };
120
+ const runner = new DelegateSubagentRunner({
121
+ workspace: deps.workspace,
122
+ bus: deps.bus,
123
+ getDefaultModel: deps.getSubagentModel,
124
+ getConfig: deps.getConfig,
125
+ toolExecutorConfig: deps.toolExecutorConfig,
126
+ buildChildTools: deps.buildChildTools
127
+ });
128
+ const controller = new AbortController();
129
+ const onParentAbort = () => controller.abort();
130
+ signal?.addEventListener("abort", onParentAbort, { once: true });
131
+ const timeoutHandle = timeoutSec > 0 ? setTimeout(() => controller.abort(), timeoutSec * 1e3) : void 0;
132
+ pushUpdate();
133
+ try {
134
+ const result = await runWorkflow(script, { runner }, {
135
+ cwd: deps.workspace,
136
+ args: params.args,
137
+ signal: controller.signal,
138
+ concurrency,
139
+ maxSubagents,
140
+ onLog: (message) => {
141
+ snapshot.logs.push(message);
142
+ pushUpdate();
143
+ },
144
+ onPhase: (title) => {
145
+ snapshot.currentPhase = title;
146
+ if (!snapshot.phases.includes(title)) snapshot.phases.push(title);
147
+ pushUpdate();
148
+ },
149
+ onAgentStart: (event) => {
150
+ snapshot.agents.push({
151
+ id: event.id,
152
+ label: event.label,
153
+ phase: event.phase,
154
+ prompt: event.prompt,
155
+ status: "running"
156
+ });
157
+ pushUpdate();
158
+ },
159
+ onAgentEnd: (event) => {
160
+ const agent = findAgentById(snapshot.agents, event.id);
161
+ if (agent) {
162
+ agent.status = event.status;
163
+ agent.resultPreview = previewValue(event.result);
164
+ }
165
+ pushUpdate();
166
+ }
167
+ });
168
+ if (result.agentCount === 0) {
169
+ const reason = "workflow scripts must call agent() at least once; this workflow declared phases but never ran a subagent.";
170
+ snapshot.logs.push(reason);
171
+ pushUpdate(true);
172
+ return {
173
+ content: [{
174
+ type: "text",
175
+ text: reason
176
+ }],
177
+ details: snapshot
178
+ };
179
+ }
180
+ snapshot.result = result.result;
181
+ snapshot.durationMs = result.durationMs;
182
+ pushUpdate(true);
183
+ try {
184
+ getLastWorkflowMemory().record(deps.getCurrentSessionKey?.(), {
185
+ script,
186
+ metaName: result.meta.name,
187
+ source: resolvedSource,
188
+ recordedAt: Date.now()
189
+ });
190
+ } catch {}
191
+ return {
192
+ content: [{
193
+ type: "text",
194
+ text: `workflow ${result.meta.name} completed: ${result.agentCount} subagent(s), ${snapshot.errorCount} error(s).\n\nResult:\n${safeStringify(result.result)}`
195
+ }],
196
+ details: snapshot
197
+ };
198
+ } catch (e) {
199
+ if (controller.signal.aborted) {
200
+ for (const a of snapshot.agents) if (a.status === "running") {
201
+ a.status = "skipped";
202
+ a.error = "aborted";
203
+ }
204
+ pushUpdate(true);
205
+ return {
206
+ content: [{
207
+ type: "text",
208
+ text: signal?.aborted ? "workflow aborted" : `workflow timed out after ${timeoutSec}s`
209
+ }],
210
+ details: snapshot
211
+ };
212
+ }
213
+ const message = e instanceof Error ? e.message : String(e);
214
+ log.warn({
215
+ err: e,
216
+ errorMessage: message,
217
+ workflow: meta.name
218
+ }, `workflow failed: ${message}`);
219
+ snapshot.logs.push(`workflow failed: ${message}`);
220
+ pushUpdate(true);
221
+ return {
222
+ content: [{
223
+ type: "text",
224
+ text: `workflow failed: ${message}`
225
+ }],
226
+ details: snapshot
227
+ };
228
+ } finally {
229
+ if (timeoutHandle) clearTimeout(timeoutHandle);
230
+ signal?.removeEventListener("abort", onParentAbort);
231
+ }
232
+ }
233
+ };
234
+ }
235
+ function normalizeScript(script) {
236
+ let text = script.trim();
237
+ const fence = text.match(/^```(?:js|javascript)?\s*\n([\s\S]*?)\n```$/i);
238
+ if (fence) text = fence[1].trim();
239
+ return text;
240
+ }
241
+ function resolveScript(params, catalog) {
242
+ const name = params.name?.trim();
243
+ if (name) return {
244
+ script: catalog.load(name).script,
245
+ source: "name"
246
+ };
247
+ if (!params.script || !params.script.trim()) throw new Error("either `name` or `script` is required.");
248
+ return {
249
+ script: normalizeScript(params.script),
250
+ source: "script"
251
+ };
252
+ }
253
+ function clampTimeout(requested) {
254
+ const v = typeof requested === "number" && Number.isFinite(requested) ? requested : DEFAULT_TIMEOUT_SEC;
255
+ if (v <= 0) return 0;
256
+ return Math.min(MAX_TIMEOUT_SEC, Math.max(1, Math.floor(v)));
257
+ }
258
+ function findAgentById(agents, id) {
259
+ for (let i = agents.length - 1; i >= 0; i--) if (agents[i].id === id) return agents[i];
260
+ }
261
+ function safeStringify(value) {
262
+ try {
263
+ return JSON.stringify(value, null, 2);
264
+ } catch {
265
+ return String(value);
266
+ }
267
+ }
268
+ //#endregion
269
+ export { createWorkflowTool };
270
+
271
+ //# sourceMappingURL=workflow-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-tool.js","names":[],"sources":["../../../../src/agent/tools/workflow-tool.ts"],"sourcesContent":["/**\n * `workflow` — the AgentTool the parent model calls to spawn a fan-out run.\n *\n * Shape mirrors `delegate-tool`: factory builds a closure over deps; `execute`\n * parses the script, instantiates the {@link DelegateSubagentRunner}, drives the\n * {@link runWorkflow} runtime, and pushes a live text snapshot through\n * `onUpdate` for streaming UIs (TUI, gateway console).\n *\n * Why this lives in `src/agent/tools/` (not under `src/agent/workflow/`):\n * the runtime is reusable infrastructure; the AgentTool wrapping is a\n * presentation concern that depends on the AgentToolsFactory wiring. Keeping\n * the wrapper here matches how `delegate-tool` and `execute-code-tool` are\n * organised today.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport type { BuildChildToolsOptions } from '../child-agent-factory.js';\nimport {\n DelegateSubagentRunner,\n getLastWorkflowMemory,\n parseWorkflowScript,\n previewValue,\n recomputeCounts,\n renderWorkflowText,\n runWorkflow,\n type WorkflowAgentSnapshot,\n type WorkflowCatalog,\n type WorkflowMeta,\n type WorkflowSnapshot,\n} from '../workflow/index.js';\nimport type { ToolExecutorConfig } from './executor.js';\n\nconst log = createLogger('workflow-tool');\n\nconst DEFAULT_TIMEOUT_SEC = 30 * 60;\nconst MAX_TIMEOUT_SEC = 4 * 60 * 60;\nconst DEFAULT_MAX_CONCURRENCY = 16;\nconst DEFAULT_MAX_SUBAGENTS = 1000;\n\nconst WorkflowToolSchema = Type.Object({\n name: Type.Optional(\n Type.String({\n description:\n 'Name of a saved workflow to run. Either `name` or `script` is required. ' +\n 'Use `name` whenever the user references a known workflow (built-in or in ~/.xopc/workflows/).',\n }),\n ),\n script: Type.Optional(\n Type.String({\n description: [\n 'Raw JavaScript workflow script (no Markdown fences, no TypeScript syntax). Ignored when `name` is set.',\n \"First statement: export const meta = { name: 'snake_case', description: 'short, human-readable' }.\",\n 'Use phase(title), agent(prompt, opts), parallel(arrayOfFunctions), pipeline(items, ...stages), log(message), args, and budget.',\n 'The script must call agent() at least once.',\n 'parallel() requires functions: await parallel(items.map(item => () => agent(...))).',\n ].join(' '),\n }),\n ),\n args: Type.Optional(\n Type.Any({\n description: 'Optional JSON value exposed to the workflow script as the global `args`.',\n }),\n ),\n});\n\nexport type WorkflowToolInput = {\n name?: string;\n script?: string;\n args?: unknown;\n};\n\nexport interface WorkflowToolDeps {\n workspace: string;\n bus: MessageBus;\n /** Returns the parent agent's primary model — subagents default to this. */\n getSubagentModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n /** Same injection point delegate-tool uses; supplied by AgentToolsFactory. */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /** Catalog for `name` lookups (built-in + ~/.xopc/workflows/). */\n catalog: WorkflowCatalog;\n /** Per-call sessionKey lookup — used to record \"last successful workflow\" for /workflow save. */\n getCurrentSessionKey?: () => string | undefined;\n}\n\nexport function createWorkflowTool(deps: WorkflowToolDeps): AgentTool {\n return {\n name: 'workflow',\n label: '◆ Workflow',\n description: [\n 'Run a deterministic JavaScript workflow that orchestrates multiple isolated subagents through agent(), parallel(), and pipeline().',\n 'Two ways to invoke:',\n ' 1. `name`: run a saved workflow from the catalog (built-in or ~/.xopc/workflows/). Prefer this when the user references a known name.',\n ' 2. `script`: provide a raw JS workflow inline. Use when no saved workflow fits. Header is required: export const meta = { name, description }.',\n 'Named-workflow triggers — call this tool with `{ name: \"<name>\" }` IMMEDIATELY when the user message is any of:',\n ' • a bare workflow name like \"/audit_repo\", \"/research\", or \"audit_repo\"',\n ' • \"run the audit_repo workflow\", \"kick off research\", \"do a multi_perspective_review on X\" (extract args.target when natural)',\n ' • after /workflows lists saved workflows and the user picks one',\n 'Use phase(title) at runtime to mark progress groups. Each agent() returns a string, or a schema-validated object when opts.schema is set.',\n 'Prefer for decomposable work: repo audits, multi-perspective review, fan-out research, large refactors. Do not use for a single quick read/edit.',\n 'parallel() takes thunks, not promises: parallel(items.map(item => () => agent(...))).',\n 'pipeline(items, ...stages) interleaves items across stages — fastest path by default; only use parallel() when you genuinely need a cross-item barrier.',\n 'Failed agent()/parallel()/pipeline() entries resolve to null; check before synthesizing.',\n 'Do not use Date.now(), Math.random(), new Date(), require, import, fs, or network APIs — they are unavailable for determinism.',\n 'Always end with a synthesis agent() that consolidates findings, especially when you fan out for review or research.',\n ].join('\\n\\n'),\n parameters: WorkflowToolSchema,\n\n async execute(\n _toolCallId: string,\n params: WorkflowToolInput,\n signal?: AbortSignal,\n onUpdate?: (update: AgentToolResult<WorkflowSnapshot | undefined>) => void,\n ): Promise<AgentToolResult<WorkflowSnapshot | { error: string }>> {\n let script: string;\n let resolvedSource: 'name' | 'script' = 'script';\n try {\n const resolved = resolveScript(params, deps.catalog);\n script = resolved.script;\n resolvedSource = resolved.source;\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return {\n content: [{ type: 'text', text: `workflow: ${message}` }],\n details: { error: message },\n };\n }\n\n const cfg = deps.getConfig();\n const wfCfg = cfg?.agents?.defaults?.workflow;\n const concurrency = wfCfg?.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY;\n const maxSubagents = wfCfg?.maxSubagents ?? DEFAULT_MAX_SUBAGENTS;\n const timeoutSec = clampTimeout(wfCfg?.defaultTimeoutSec);\n\n // Parse early so a bad script returns an error result instead of throwing\n // through the agent loop. The runtime parses again, but that's cheap.\n let meta: WorkflowMeta;\n try {\n meta = parseWorkflowScript(script).meta;\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return {\n content: [\n {\n type: 'text',\n text:\n resolvedSource === 'name'\n ? `workflow \"${params.name}\" failed to parse: ${message}`\n : `workflow parse error: ${message}`,\n },\n ],\n details: { error: message },\n };\n }\n\n const snapshot: WorkflowSnapshot = {\n name: meta.name,\n description: meta.description,\n phases: [],\n logs: [],\n agents: [],\n agentCount: 0,\n runningCount: 0,\n doneCount: 0,\n errorCount: 0,\n skippedCount: 0,\n };\n\n const pushUpdate = (completed = false) => {\n recomputeCounts(snapshot);\n onUpdate?.({\n content: [\n {\n type: 'text',\n text: renderWorkflowText(snapshot, completed, { showResultPreviews: false }),\n },\n ],\n details: snapshot,\n });\n };\n\n const runner = new DelegateSubagentRunner({\n workspace: deps.workspace,\n bus: deps.bus,\n getDefaultModel: deps.getSubagentModel,\n getConfig: deps.getConfig,\n toolExecutorConfig: deps.toolExecutorConfig,\n buildChildTools: deps.buildChildTools,\n });\n\n // Combined abort: parent signal + per-run timeout.\n const controller = new AbortController();\n const onParentAbort = () => controller.abort();\n signal?.addEventListener('abort', onParentAbort, { once: true });\n const timeoutHandle =\n timeoutSec > 0\n ? setTimeout(() => controller.abort(), timeoutSec * 1000)\n : undefined;\n\n pushUpdate();\n\n try {\n const result = await runWorkflow(script, { runner }, {\n cwd: deps.workspace,\n args: params.args,\n signal: controller.signal,\n concurrency,\n maxSubagents,\n onLog: (message) => {\n snapshot.logs.push(message);\n pushUpdate();\n },\n onPhase: (title) => {\n snapshot.currentPhase = title;\n if (!snapshot.phases.includes(title)) snapshot.phases.push(title);\n pushUpdate();\n },\n onAgentStart: (event) => {\n snapshot.agents.push({\n id: event.id,\n label: event.label,\n phase: event.phase,\n prompt: event.prompt,\n status: 'running',\n });\n pushUpdate();\n },\n onAgentEnd: (event) => {\n const agent = findAgentById(snapshot.agents, event.id);\n if (agent) {\n agent.status = event.status;\n agent.resultPreview = previewValue(event.result);\n }\n pushUpdate();\n },\n });\n\n if (result.agentCount === 0) {\n const reason =\n 'workflow scripts must call agent() at least once; this workflow declared phases but never ran a subagent.';\n snapshot.logs.push(reason);\n pushUpdate(true);\n return {\n content: [{ type: 'text', text: reason }],\n details: snapshot,\n };\n }\n\n snapshot.result = result.result;\n snapshot.durationMs = result.durationMs;\n pushUpdate(true);\n\n // Record for /workflow save — last successful run per session.\n // Failures are intentionally skipped so users do not save broken scripts.\n try {\n getLastWorkflowMemory().record(deps.getCurrentSessionKey?.(), {\n script,\n metaName: result.meta.name,\n source: resolvedSource,\n recordedAt: Date.now(),\n });\n } catch {\n // Memory recording is best-effort; never break a successful run on it.\n }\n\n return {\n content: [\n {\n type: 'text',\n text: `workflow ${result.meta.name} completed: ${result.agentCount} subagent(s), ${snapshot.errorCount} error(s).\\n\\nResult:\\n${safeStringify(result.result)}`,\n },\n ],\n details: snapshot,\n };\n } catch (e) {\n if (controller.signal.aborted) {\n for (const a of snapshot.agents) {\n if (a.status === 'running') {\n a.status = 'skipped';\n a.error = 'aborted';\n }\n }\n pushUpdate(true);\n const reason = signal?.aborted ? 'workflow aborted' : `workflow timed out after ${timeoutSec}s`;\n return {\n content: [{ type: 'text', text: reason }],\n details: snapshot,\n };\n }\n const message = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, errorMessage: message, workflow: meta.name }, `workflow failed: ${message}`);\n snapshot.logs.push(`workflow failed: ${message}`);\n pushUpdate(true);\n return {\n content: [{ type: 'text', text: `workflow failed: ${message}` }],\n details: snapshot,\n };\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n signal?.removeEventListener('abort', onParentAbort);\n }\n },\n } as unknown as AgentTool;\n}\n\n// ---------------------------------------------------------------------------\n\nfunction normalizeScript(script: string): string {\n let text = script.trim();\n const fence = text.match(/^```(?:js|javascript)?\\s*\\n([\\s\\S]*?)\\n```$/i);\n if (fence) text = fence[1].trim();\n return text;\n}\n\nfunction resolveScript(\n params: WorkflowToolInput,\n catalog: WorkflowCatalog,\n): { script: string; source: 'name' | 'script' } {\n const name = params.name?.trim();\n if (name) {\n const loaded = catalog.load(name);\n return { script: loaded.script, source: 'name' };\n }\n if (!params.script || !params.script.trim()) {\n throw new Error('either `name` or `script` is required.');\n }\n return { script: normalizeScript(params.script), source: 'script' };\n}\n\nfunction clampTimeout(requested: number | undefined): number {\n const v = typeof requested === 'number' && Number.isFinite(requested) ? requested : DEFAULT_TIMEOUT_SEC;\n if (v <= 0) return 0;\n return Math.min(MAX_TIMEOUT_SEC, Math.max(1, Math.floor(v)));\n}\n\nfunction findAgentById(agents: WorkflowAgentSnapshot[], id: number): WorkflowAgentSnapshot | undefined {\n // Linear scan — agent lists are small in practice (capped at maxSubagents).\n for (let i = agents.length - 1; i >= 0; i--) {\n if (agents[i].id === id) return agents[i];\n }\n return undefined;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { checkFileSafety } from "../prompt/safety.js";
2
2
  import { resolvePathUnderWorkspace } from "./tool-paths.js";
3
3
  import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
4
- import { mkdir, writeFile } from "fs/promises";
5
4
  import { dirname } from "path";
5
+ import { mkdir, writeFile } from "fs/promises";
6
6
  import { Type } from "@sinclair/typebox";
7
7
  //#region src/agent/tools/write.ts
8
8
  const MAX_FILE_SIZE = 10 * 1024 * 1024;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Built-in workflow: `audit_repo`
3
+ *
4
+ * Fan-out repo audit. Phase 1 inventories the repo; phase 2 spawns N reviewers
5
+ * in parallel, one per dimension (bugs / perf / security / tests / style);
6
+ * phase 3 synthesises into a structured report. The script is kept readable so
7
+ * users can copy it into `~/.xopc/workflows/` as a starting point.
8
+ */
9
+ export declare const AUDIT_REPO_SCRIPT = "export const meta = {\n name: 'audit_repo',\n description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',\n whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',\n phases: [\n { title: 'Inventory' },\n { title: 'Review' },\n { title: 'Synthesize' },\n ],\n}\n\nconst DIMENSIONS = [\n { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },\n { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },\n { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },\n { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },\n { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },\n]\n\nphase('Inventory')\nconst inventory = await agent(\n 'Produce a compact map of this repository: top-level layout, main modules, the 5\u201310 most important files, and any obvious entry points. Be terse and structured.',\n { label: 'repo inventory' },\n)\n\nphase('Review')\nconst findings = await parallel(\n DIMENSIONS.map((d) => () =>\n agent(\n 'Review the repository through the ' + d.key + ' lens.\\n' +\n 'Focus: ' + d.focus + '\\n\\n' +\n 'Inventory for orientation:\\n' + inventory + '\\n\\n' +\n 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',\n {\n label: d.key + ' review',\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n line: { type: ['number', 'string'] },\n severity: { type: 'string', enum: ['low', 'med', 'high'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst live = findings.filter(Boolean)\nif (!live.length) {\n return { ok: true, summary: 'No findings.', byDimension: {} }\n}\nconst byDimension = {}\nfor (let i = 0; i < DIMENSIONS.length; i++) {\n byDimension[DIMENSIONS[i].key] = live[i]?.findings ?? []\n}\n\nconst summary = await agent(\n 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +\n 'Order by severity (high \u2192 low). Cap at 20 entries. Return JSON.\\n\\n' +\n JSON.stringify(byDimension, null, 2),\n {\n label: 'report synthesis',\n schema: {\n type: 'object',\n properties: {\n topFindings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['dimension', 'file', 'severity', 'title'],\n },\n },\n summary: { type: 'string' },\n },\n required: ['topFindings', 'summary'],\n },\n },\n)\n\nreturn { ok: true, ...(summary ?? { topFindings: [], summary: 'synthesis failed' }), byDimension }\n";
@@ -0,0 +1,115 @@
1
+ //#region src/agent/workflow/builtins/audit-repo.ts
2
+ /**
3
+ * Built-in workflow: `audit_repo`
4
+ *
5
+ * Fan-out repo audit. Phase 1 inventories the repo; phase 2 spawns N reviewers
6
+ * in parallel, one per dimension (bugs / perf / security / tests / style);
7
+ * phase 3 synthesises into a structured report. The script is kept readable so
8
+ * users can copy it into `~/.xopc/workflows/` as a starting point.
9
+ */
10
+ const AUDIT_REPO_SCRIPT = `export const meta = {
11
+ name: 'audit_repo',
12
+ description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',
13
+ whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',
14
+ phases: [
15
+ { title: 'Inventory' },
16
+ { title: 'Review' },
17
+ { title: 'Synthesize' },
18
+ ],
19
+ }
20
+
21
+ const DIMENSIONS = [
22
+ { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },
23
+ { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },
24
+ { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },
25
+ { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },
26
+ { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },
27
+ ]
28
+
29
+ phase('Inventory')
30
+ const inventory = await agent(
31
+ 'Produce a compact map of this repository: top-level layout, main modules, the 5–10 most important files, and any obvious entry points. Be terse and structured.',
32
+ { label: 'repo inventory' },
33
+ )
34
+
35
+ phase('Review')
36
+ const findings = await parallel(
37
+ DIMENSIONS.map((d) => () =>
38
+ agent(
39
+ 'Review the repository through the ' + d.key + ' lens.\\n' +
40
+ 'Focus: ' + d.focus + '\\n\\n' +
41
+ 'Inventory for orientation:\\n' + inventory + '\\n\\n' +
42
+ 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',
43
+ {
44
+ label: d.key + ' review',
45
+ schema: {
46
+ type: 'object',
47
+ properties: {
48
+ findings: {
49
+ type: 'array',
50
+ items: {
51
+ type: 'object',
52
+ properties: {
53
+ file: { type: 'string' },
54
+ line: { type: ['number', 'string'] },
55
+ severity: { type: 'string', enum: ['low', 'med', 'high'] },
56
+ title: { type: 'string' },
57
+ fix: { type: 'string' },
58
+ },
59
+ required: ['file', 'severity', 'title', 'fix'],
60
+ },
61
+ },
62
+ },
63
+ required: ['findings'],
64
+ },
65
+ },
66
+ ),
67
+ ),
68
+ )
69
+
70
+ phase('Synthesize')
71
+ const live = findings.filter(Boolean)
72
+ if (!live.length) {
73
+ return { ok: true, summary: 'No findings.', byDimension: {} }
74
+ }
75
+ const byDimension = {}
76
+ for (let i = 0; i < DIMENSIONS.length; i++) {
77
+ byDimension[DIMENSIONS[i].key] = live[i]?.findings ?? []
78
+ }
79
+
80
+ const summary = await agent(
81
+ 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +
82
+ 'Order by severity (high → low). Cap at 20 entries. Return JSON.\\n\\n' +
83
+ JSON.stringify(byDimension, null, 2),
84
+ {
85
+ label: 'report synthesis',
86
+ schema: {
87
+ type: 'object',
88
+ properties: {
89
+ topFindings: {
90
+ type: 'array',
91
+ items: {
92
+ type: 'object',
93
+ properties: {
94
+ dimension: { type: 'string' },
95
+ file: { type: 'string' },
96
+ severity: { type: 'string' },
97
+ title: { type: 'string' },
98
+ fix: { type: 'string' },
99
+ },
100
+ required: ['dimension', 'file', 'severity', 'title'],
101
+ },
102
+ },
103
+ summary: { type: 'string' },
104
+ },
105
+ required: ['topFindings', 'summary'],
106
+ },
107
+ },
108
+ )
109
+
110
+ return { ok: true, ...(summary ?? { topFindings: [], summary: 'synthesis failed' }), byDimension }
111
+ `;
112
+ //#endregion
113
+ export { AUDIT_REPO_SCRIPT };
114
+
115
+ //# sourceMappingURL=audit-repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-repo.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/audit-repo.ts"],"sourcesContent":["/**\n * Built-in workflow: `audit_repo`\n *\n * Fan-out repo audit. Phase 1 inventories the repo; phase 2 spawns N reviewers\n * in parallel, one per dimension (bugs / perf / security / tests / style);\n * phase 3 synthesises into a structured report. The script is kept readable so\n * users can copy it into `~/.xopc/workflows/` as a starting point.\n */\n\nexport const AUDIT_REPO_SCRIPT = `export const meta = {\n name: 'audit_repo',\n description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',\n whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',\n phases: [\n { title: 'Inventory' },\n { title: 'Review' },\n { title: 'Synthesize' },\n ],\n}\n\nconst DIMENSIONS = [\n { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },\n { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },\n { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },\n { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },\n { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },\n]\n\nphase('Inventory')\nconst inventory = await agent(\n 'Produce a compact map of this repository: top-level layout, main modules, the 5–10 most important files, and any obvious entry points. Be terse and structured.',\n { label: 'repo inventory' },\n)\n\nphase('Review')\nconst findings = await parallel(\n DIMENSIONS.map((d) => () =>\n agent(\n 'Review the repository through the ' + d.key + ' lens.\\\\n' +\n 'Focus: ' + d.focus + '\\\\n\\\\n' +\n 'Inventory for orientation:\\\\n' + inventory + '\\\\n\\\\n' +\n 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',\n {\n label: d.key + ' review',\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n line: { type: ['number', 'string'] },\n severity: { type: 'string', enum: ['low', 'med', 'high'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst live = findings.filter(Boolean)\nif (!live.length) {\n return { ok: true, summary: 'No findings.', byDimension: {} }\n}\nconst byDimension = {}\nfor (let i = 0; i < DIMENSIONS.length; i++) {\n byDimension[DIMENSIONS[i].key] = live[i]?.findings ?? []\n}\n\nconst summary = await agent(\n 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +\n 'Order by severity (high → low). Cap at 20 entries. Return JSON.\\\\n\\\\n' +\n JSON.stringify(byDimension, null, 2),\n {\n label: 'report synthesis',\n schema: {\n type: 'object',\n properties: {\n topFindings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['dimension', 'file', 'severity', 'title'],\n },\n },\n summary: { type: 'string' },\n },\n required: ['topFindings', 'summary'],\n },\n },\n)\n\nreturn { ok: true, ...(summary ?? { topFindings: [], summary: 'synthesis failed' }), byDimension }\n`\n"],"mappings":";;;;;;;;;AASA,MAAa,oBAAoB"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Bundled workflow templates. These are shipped with xopc and discoverable
3
+ * via the catalog alongside user workflows in `~/.xopc/workflows/`. A user
4
+ * workflow with the same `name` always wins — built-ins are starting points,
5
+ * not authority.
6
+ */
7
+ import { AUDIT_REPO_SCRIPT } from './audit-repo.js';
8
+ import { MULTI_PERSPECTIVE_REVIEW_SCRIPT } from './multi-perspective-review.js';
9
+ import { RESEARCH_SCRIPT } from './research.js';
10
+ export interface BuiltinWorkflow {
11
+ name: string;
12
+ script: string;
13
+ }
14
+ export declare const BUILTIN_WORKFLOWS: readonly BuiltinWorkflow[];
15
+ export { AUDIT_REPO_SCRIPT, MULTI_PERSPECTIVE_REVIEW_SCRIPT, RESEARCH_SCRIPT };
@@ -0,0 +1,28 @@
1
+ import { AUDIT_REPO_SCRIPT } from "./audit-repo.js";
2
+ import { MULTI_PERSPECTIVE_REVIEW_SCRIPT } from "./multi-perspective-review.js";
3
+ import { RESEARCH_SCRIPT } from "./research.js";
4
+ //#region src/agent/workflow/builtins/index.ts
5
+ /**
6
+ * Bundled workflow templates. These are shipped with xopc and discoverable
7
+ * via the catalog alongside user workflows in `~/.xopc/workflows/`. A user
8
+ * workflow with the same `name` always wins — built-ins are starting points,
9
+ * not authority.
10
+ */
11
+ const BUILTIN_WORKFLOWS = Object.freeze([
12
+ {
13
+ name: "audit_repo",
14
+ script: AUDIT_REPO_SCRIPT
15
+ },
16
+ {
17
+ name: "multi_perspective_review",
18
+ script: MULTI_PERSPECTIVE_REVIEW_SCRIPT
19
+ },
20
+ {
21
+ name: "research",
22
+ script: RESEARCH_SCRIPT
23
+ }
24
+ ]);
25
+ //#endregion
26
+ export { AUDIT_REPO_SCRIPT, BUILTIN_WORKFLOWS, MULTI_PERSPECTIVE_REVIEW_SCRIPT, RESEARCH_SCRIPT };
27
+
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/index.ts"],"sourcesContent":["/**\n * Bundled workflow templates. These are shipped with xopc and discoverable\n * via the catalog alongside user workflows in `~/.xopc/workflows/`. A user\n * workflow with the same `name` always wins — built-ins are starting points,\n * not authority.\n */\n\nimport { AUDIT_REPO_SCRIPT } from './audit-repo.js';\nimport { MULTI_PERSPECTIVE_REVIEW_SCRIPT } from './multi-perspective-review.js';\nimport { RESEARCH_SCRIPT } from './research.js';\n\nexport interface BuiltinWorkflow {\n name: string;\n script: string;\n}\n\nexport const BUILTIN_WORKFLOWS: readonly BuiltinWorkflow[] = Object.freeze([\n { name: 'audit_repo', script: AUDIT_REPO_SCRIPT },\n { name: 'multi_perspective_review', script: MULTI_PERSPECTIVE_REVIEW_SCRIPT },\n { name: 'research', script: RESEARCH_SCRIPT },\n]);\n\nexport { AUDIT_REPO_SCRIPT, MULTI_PERSPECTIVE_REVIEW_SCRIPT, RESEARCH_SCRIPT };\n"],"mappings":";;;;;;;;;;AAgBA,MAAa,oBAAgD,OAAO,OAAO;CACzE;EAAE,MAAM;EAAc,QAAQ;EAAmB;CACjD;EAAE,MAAM;EAA4B,QAAQ;EAAiC;CAC7E;EAAE,MAAM;EAAY,QAAQ;EAAiB;CAC9C,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Built-in workflow: `multi_perspective_review`
3
+ *
4
+ * Reviews a target (file, PR, design doc, plan — passed via args.target) from
5
+ * several independent perspectives, then asks an adversarial judge to decide
6
+ * what would actually break in practice. Useful for sanity-checking decisions
7
+ * before they ship.
8
+ */
9
+ export declare const MULTI_PERSPECTIVE_REVIEW_SCRIPT = "export const meta = {\n name: 'multi_perspective_review',\n description: 'Review a target from N independent perspectives, then adversarially judge what would actually break.',\n whenToUse: 'User wants a stress-test of a design, plan, PR, or proposal before committing to it.',\n phases: [\n { title: 'Lenses' },\n { title: 'Adversarial' },\n { title: 'Synthesize' },\n ],\n}\n\nconst target = args && typeof args === 'object' && args.target\n ? String(args.target)\n : 'No explicit target was provided. Treat the currently focused file or recent context as the target.'\n\nconst LENSES = [\n { name: 'User', angle: 'How a real user experiences this. Friction, confusion, surprise paths, accessibility.' },\n { name: 'Operator', angle: 'How an on-call engineer experiences this in production. Failure modes, observability, rollback.' },\n { name: 'Skeptic', angle: 'Hidden assumptions. What is being implied but not stated. What would break under load or weird input.' },\n { name: 'Maintainer', angle: 'Six-month-later view. Clarity, naming, layering, ease of changing nearby code.' },\n]\n\nphase('Lenses')\nconst lensViews = await parallel(\n LENSES.map((l) => () =>\n agent(\n 'Review the following target through the ' + l.name + ' lens.\\n' +\n 'Lens focus: ' + l.angle + '\\n\\n' +\n 'TARGET:\\n' + target + '\\n\\n' +\n 'Return 3\u20137 concrete observations. Each entry: title (5\u201310 words), why-it-matters (1 sentence), risk (low/med/high).',\n {\n label: l.name + ' lens',\n schema: {\n type: 'object',\n properties: {\n observations: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n why: { type: 'string' },\n risk: { type: 'string', enum: ['low', 'med', 'high'] },\n },\n required: ['title', 'why', 'risk'],\n },\n },\n },\n required: ['observations'],\n },\n },\n ),\n ),\n)\n\nphase('Adversarial')\nconst valid = lensViews.filter(Boolean)\nconst allObs = valid.flatMap((v, i) =>\n (v?.observations ?? []).map((o) => ({ lens: LENSES[i].name, ...o })),\n)\n\nconst verdict = await agent(\n 'You are an adversarial judge. Given these multi-lens observations of a target, decide which would actually cause real harm if shipped as-is. ' +\n 'Default to refuted=true unless an observation has clear, mechanism-level evidence.\\n\\n' +\n JSON.stringify(allObs, null, 2),\n {\n label: 'adversarial verdict',\n schema: {\n type: 'object',\n properties: {\n verdicts: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n lens: { type: 'string' },\n realRisk: { type: 'boolean' },\n reason: { type: 'string' },\n },\n required: ['title', 'lens', 'realRisk', 'reason'],\n },\n },\n },\n required: ['verdicts'],\n },\n },\n)\n\nphase('Synthesize')\nconst confirmed = (verdict?.verdicts ?? []).filter((v) => v.realRisk)\nreturn {\n ok: true,\n target,\n observationCount: allObs.length,\n confirmedRiskCount: confirmed.length,\n topRisks: confirmed.slice(0, 10),\n allVerdicts: verdict?.verdicts ?? [],\n}\n";
@@ -0,0 +1,113 @@
1
+ //#region src/agent/workflow/builtins/multi-perspective-review.ts
2
+ /**
3
+ * Built-in workflow: `multi_perspective_review`
4
+ *
5
+ * Reviews a target (file, PR, design doc, plan — passed via args.target) from
6
+ * several independent perspectives, then asks an adversarial judge to decide
7
+ * what would actually break in practice. Useful for sanity-checking decisions
8
+ * before they ship.
9
+ */
10
+ const MULTI_PERSPECTIVE_REVIEW_SCRIPT = `export const meta = {
11
+ name: 'multi_perspective_review',
12
+ description: 'Review a target from N independent perspectives, then adversarially judge what would actually break.',
13
+ whenToUse: 'User wants a stress-test of a design, plan, PR, or proposal before committing to it.',
14
+ phases: [
15
+ { title: 'Lenses' },
16
+ { title: 'Adversarial' },
17
+ { title: 'Synthesize' },
18
+ ],
19
+ }
20
+
21
+ const target = args && typeof args === 'object' && args.target
22
+ ? String(args.target)
23
+ : 'No explicit target was provided. Treat the currently focused file or recent context as the target.'
24
+
25
+ const LENSES = [
26
+ { name: 'User', angle: 'How a real user experiences this. Friction, confusion, surprise paths, accessibility.' },
27
+ { name: 'Operator', angle: 'How an on-call engineer experiences this in production. Failure modes, observability, rollback.' },
28
+ { name: 'Skeptic', angle: 'Hidden assumptions. What is being implied but not stated. What would break under load or weird input.' },
29
+ { name: 'Maintainer', angle: 'Six-month-later view. Clarity, naming, layering, ease of changing nearby code.' },
30
+ ]
31
+
32
+ phase('Lenses')
33
+ const lensViews = await parallel(
34
+ LENSES.map((l) => () =>
35
+ agent(
36
+ 'Review the following target through the ' + l.name + ' lens.\\n' +
37
+ 'Lens focus: ' + l.angle + '\\n\\n' +
38
+ 'TARGET:\\n' + target + '\\n\\n' +
39
+ 'Return 3–7 concrete observations. Each entry: title (5–10 words), why-it-matters (1 sentence), risk (low/med/high).',
40
+ {
41
+ label: l.name + ' lens',
42
+ schema: {
43
+ type: 'object',
44
+ properties: {
45
+ observations: {
46
+ type: 'array',
47
+ items: {
48
+ type: 'object',
49
+ properties: {
50
+ title: { type: 'string' },
51
+ why: { type: 'string' },
52
+ risk: { type: 'string', enum: ['low', 'med', 'high'] },
53
+ },
54
+ required: ['title', 'why', 'risk'],
55
+ },
56
+ },
57
+ },
58
+ required: ['observations'],
59
+ },
60
+ },
61
+ ),
62
+ ),
63
+ )
64
+
65
+ phase('Adversarial')
66
+ const valid = lensViews.filter(Boolean)
67
+ const allObs = valid.flatMap((v, i) =>
68
+ (v?.observations ?? []).map((o) => ({ lens: LENSES[i].name, ...o })),
69
+ )
70
+
71
+ const verdict = await agent(
72
+ 'You are an adversarial judge. Given these multi-lens observations of a target, decide which would actually cause real harm if shipped as-is. ' +
73
+ 'Default to refuted=true unless an observation has clear, mechanism-level evidence.\\n\\n' +
74
+ JSON.stringify(allObs, null, 2),
75
+ {
76
+ label: 'adversarial verdict',
77
+ schema: {
78
+ type: 'object',
79
+ properties: {
80
+ verdicts: {
81
+ type: 'array',
82
+ items: {
83
+ type: 'object',
84
+ properties: {
85
+ title: { type: 'string' },
86
+ lens: { type: 'string' },
87
+ realRisk: { type: 'boolean' },
88
+ reason: { type: 'string' },
89
+ },
90
+ required: ['title', 'lens', 'realRisk', 'reason'],
91
+ },
92
+ },
93
+ },
94
+ required: ['verdicts'],
95
+ },
96
+ },
97
+ )
98
+
99
+ phase('Synthesize')
100
+ const confirmed = (verdict?.verdicts ?? []).filter((v) => v.realRisk)
101
+ return {
102
+ ok: true,
103
+ target,
104
+ observationCount: allObs.length,
105
+ confirmedRiskCount: confirmed.length,
106
+ topRisks: confirmed.slice(0, 10),
107
+ allVerdicts: verdict?.verdicts ?? [],
108
+ }
109
+ `;
110
+ //#endregion
111
+ export { MULTI_PERSPECTIVE_REVIEW_SCRIPT };
112
+
113
+ //# sourceMappingURL=multi-perspective-review.js.map