@desplega.ai/agent-swarm 1.20.0 → 1.51.2

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 (561) hide show
  1. package/README.md +271 -169
  2. package/openapi.json +5015 -0
  3. package/package.json +40 -7
  4. package/plugin/commands/close-issue.md +7 -3
  5. package/plugin/commands/create-pr.md +18 -12
  6. package/plugin/commands/implement-issue.md +7 -3
  7. package/plugin/commands/respond-github.md +8 -4
  8. package/plugin/commands/review-pr.md +44 -10
  9. package/plugin/commands/start-leader.md +1 -3
  10. package/plugin/commands/start-worker.md +1 -3
  11. package/plugin/commands/work-on-task.md +22 -3
  12. package/plugin/pi-skills/close-issue/SKILL.md +90 -0
  13. package/plugin/pi-skills/create-pr/SKILL.md +99 -0
  14. package/plugin/pi-skills/implement-issue/SKILL.md +135 -0
  15. package/plugin/pi-skills/investigate-sentry-issue/SKILL.md +138 -0
  16. package/plugin/pi-skills/respond-github/SKILL.md +98 -0
  17. package/plugin/pi-skills/review-offered-task/SKILL.md +45 -0
  18. package/plugin/pi-skills/review-pr/SKILL.md +261 -0
  19. package/plugin/pi-skills/start-leader/SKILL.md +121 -0
  20. package/plugin/pi-skills/start-worker/SKILL.md +60 -0
  21. package/plugin/pi-skills/swarm-chat/SKILL.md +82 -0
  22. package/plugin/pi-skills/todos/SKILL.md +66 -0
  23. package/plugin/pi-skills/work-on-task/SKILL.md +65 -0
  24. package/plugin/skills/artifacts/examples/approval-flow.ts +34 -0
  25. package/plugin/skills/artifacts/examples/hono-dashboard.ts +31 -0
  26. package/plugin/skills/artifacts/examples/multi-artifact.ts +20 -0
  27. package/plugin/skills/artifacts/examples/static-report.sh +17 -0
  28. package/plugin/skills/artifacts/skill.md +71 -0
  29. package/src/agentmail/app.ts +65 -0
  30. package/src/agentmail/handlers.ts +262 -0
  31. package/src/agentmail/index.ts +9 -0
  32. package/src/agentmail/templates.ts +111 -0
  33. package/src/agentmail/types.ts +51 -0
  34. package/src/artifact-sdk/browser-sdk.ts +30 -0
  35. package/src/artifact-sdk/index.ts +2 -0
  36. package/src/artifact-sdk/localtunnel.d.ts +20 -0
  37. package/src/artifact-sdk/port.ts +12 -0
  38. package/src/artifact-sdk/server.ts +156 -0
  39. package/src/artifact-sdk/tunnel.ts +19 -0
  40. package/src/be/chunking.ts +193 -0
  41. package/src/be/db-queries/oauth.ts +90 -0
  42. package/src/be/db-queries/tracker.ts +182 -0
  43. package/src/be/db.ts +3327 -784
  44. package/src/be/embedding.ts +80 -0
  45. package/src/be/migrations/001_initial.sql +409 -0
  46. package/src/be/migrations/002_one_time_schedules.sql +59 -0
  47. package/src/be/migrations/003_workflows.sql +51 -0
  48. package/src/be/migrations/004_workflow_source.sql +81 -0
  49. package/src/be/migrations/005_epic_next_steps.sql +2 -0
  50. package/src/be/migrations/006_vcs_provider.sql +94 -0
  51. package/src/be/migrations/007_task_dir.sql +2 -0
  52. package/src/be/migrations/008_workflow_redesign.sql +85 -0
  53. package/src/be/migrations/009_tracker_integration.sql +144 -0
  54. package/src/be/migrations/010_step_diagnostics.sql +1 -0
  55. package/src/be/migrations/011_step_next_port.sql +1 -0
  56. package/src/be/migrations/012_trigger_schema.sql +1 -0
  57. package/src/be/migrations/013_task_output_schema.sql +2 -0
  58. package/src/be/migrations/014_prompt_templates.sql +33 -0
  59. package/src/be/migrations/015_workflow_workspace.sql +3 -0
  60. package/src/be/migrations/016_active_session_runner_session.sql +4 -0
  61. package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
  62. package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
  63. package/src/be/migrations/runner.ts +188 -0
  64. package/src/be/seed.ts +62 -0
  65. package/src/cli.tsx +231 -299
  66. package/src/commands/artifact.ts +241 -0
  67. package/src/commands/onboard/compose-generator.ts +169 -0
  68. package/src/commands/onboard/env-generator.ts +79 -0
  69. package/src/commands/onboard/manifest.ts +37 -0
  70. package/src/commands/onboard/presets.ts +85 -0
  71. package/src/commands/onboard/service-names.ts +47 -0
  72. package/src/commands/onboard/steps/core-credentials.tsx +111 -0
  73. package/src/commands/onboard/steps/custom-templates.tsx +168 -0
  74. package/src/commands/onboard/steps/generate.tsx +154 -0
  75. package/src/commands/onboard/steps/harness-credentials.tsx +195 -0
  76. package/src/commands/onboard/steps/harness.tsx +21 -0
  77. package/src/commands/onboard/steps/health-check.tsx +171 -0
  78. package/src/commands/onboard/steps/integration-github.tsx +105 -0
  79. package/src/commands/onboard/steps/integration-gitlab.tsx +79 -0
  80. package/src/commands/onboard/steps/integration-menu.tsx +58 -0
  81. package/src/commands/onboard/steps/integration-sentry.tsx +79 -0
  82. package/src/commands/onboard/steps/integration-slack.tsx +165 -0
  83. package/src/commands/onboard/steps/post-connect.tsx +145 -0
  84. package/src/commands/onboard/steps/post-dashboard.tsx +34 -0
  85. package/src/commands/onboard/steps/post-task.tsx +103 -0
  86. package/src/commands/onboard/steps/prereq-check.tsx +178 -0
  87. package/src/commands/onboard/steps/review.tsx +82 -0
  88. package/src/commands/onboard/steps/start.tsx +97 -0
  89. package/src/commands/onboard/templates.ts +34 -0
  90. package/src/commands/onboard/types.ts +259 -0
  91. package/src/commands/onboard.tsx +425 -0
  92. package/src/commands/runner.ts +1540 -630
  93. package/src/commands/setup.tsx +23 -38
  94. package/src/commands/shared/client-config.ts +41 -0
  95. package/src/commands/templates.ts +172 -0
  96. package/src/github/app.ts +8 -0
  97. package/src/github/handlers.ts +384 -151
  98. package/src/github/index.ts +1 -0
  99. package/src/github/mentions-aliases.test.ts +73 -0
  100. package/src/github/mentions.test.ts +3 -3
  101. package/src/github/mentions.ts +32 -6
  102. package/src/github/templates.ts +398 -0
  103. package/src/github/types.ts +1 -0
  104. package/src/gitlab/auth.ts +63 -0
  105. package/src/gitlab/handlers.ts +368 -0
  106. package/src/gitlab/index.ts +19 -0
  107. package/src/gitlab/reactions.ts +104 -0
  108. package/src/gitlab/templates.ts +140 -0
  109. package/src/gitlab/types.ts +130 -0
  110. package/src/heartbeat/heartbeat.ts +434 -0
  111. package/src/heartbeat/index.ts +1 -0
  112. package/src/heartbeat/templates.ts +30 -0
  113. package/src/hooks/hook.ts +555 -4
  114. package/src/hooks/tool-loop-detection.test.ts +158 -0
  115. package/src/hooks/tool-loop-detection.ts +167 -0
  116. package/src/http/active-sessions.ts +199 -0
  117. package/src/http/agents.ts +328 -0
  118. package/src/http/config.ts +191 -0
  119. package/src/http/core.ts +309 -0
  120. package/src/http/db-query.ts +91 -0
  121. package/src/http/ecosystem.ts +63 -0
  122. package/src/http/epics.ts +460 -0
  123. package/src/http/index.ts +216 -0
  124. package/src/http/mcp.ts +77 -0
  125. package/src/http/memory.ts +168 -0
  126. package/src/http/openapi.ts +109 -0
  127. package/src/http/poll.ts +299 -0
  128. package/src/http/prompt-templates.ts +412 -0
  129. package/src/http/repos.ts +195 -0
  130. package/src/http/route-def.ts +123 -0
  131. package/src/http/schedules.ts +426 -0
  132. package/src/http/session-data.ts +241 -0
  133. package/src/http/stats.ts +174 -0
  134. package/src/http/tasks.ts +468 -0
  135. package/src/http/trackers/index.ts +10 -0
  136. package/src/http/trackers/linear.ts +187 -0
  137. package/src/http/types.ts +12 -0
  138. package/src/http/utils.ts +87 -0
  139. package/src/http/webhooks.ts +432 -0
  140. package/src/http/workflows.ts +530 -0
  141. package/src/http.ts +1 -1890
  142. package/src/linear/README.md +65 -0
  143. package/src/linear/app.ts +48 -0
  144. package/src/linear/client.ts +18 -0
  145. package/src/linear/index.ts +1 -0
  146. package/src/linear/oauth.ts +35 -0
  147. package/src/linear/outbound.ts +212 -0
  148. package/src/linear/sync.ts +567 -0
  149. package/src/linear/templates.ts +47 -0
  150. package/src/linear/types.ts +7 -0
  151. package/src/linear/webhook.ts +104 -0
  152. package/src/oauth/README.md +66 -0
  153. package/src/oauth/index.ts +6 -0
  154. package/src/oauth/wrapper.ts +204 -0
  155. package/src/prompts/base-prompt.ts +150 -265
  156. package/src/prompts/defaults.ts +196 -0
  157. package/src/prompts/registry.ts +57 -0
  158. package/src/prompts/resolver.ts +296 -0
  159. package/src/prompts/session-templates.ts +604 -0
  160. package/src/providers/claude-adapter.ts +442 -0
  161. package/src/providers/index.ts +24 -0
  162. package/src/providers/pi-mono-adapter.ts +442 -0
  163. package/src/providers/pi-mono-extension.ts +624 -0
  164. package/src/providers/pi-mono-mcp-client.ts +124 -0
  165. package/src/providers/types.ts +75 -0
  166. package/src/scheduler/scheduler.test.ts +2 -0
  167. package/src/scheduler/scheduler.ts +231 -40
  168. package/src/server.ts +97 -6
  169. package/src/slack/HEURISTICS.md +105 -0
  170. package/src/slack/actions.ts +133 -0
  171. package/src/slack/app.ts +7 -0
  172. package/src/slack/assistant.ts +118 -0
  173. package/src/slack/blocks.ts +233 -0
  174. package/src/slack/channel-activity.ts +177 -0
  175. package/src/slack/commands.ts +31 -17
  176. package/src/slack/files.ts +1 -1
  177. package/src/slack/handlers.test.ts +114 -1
  178. package/src/slack/handlers.ts +230 -55
  179. package/src/slack/responses.ts +120 -67
  180. package/src/slack/router.ts +17 -99
  181. package/src/slack/templates.ts +55 -0
  182. package/src/slack/thread-buffer.ts +213 -0
  183. package/src/slack/watcher.ts +119 -4
  184. package/src/tests/agent-activity.test.ts +247 -0
  185. package/src/tests/agentmail-filters.test.ts +97 -0
  186. package/src/tests/artifact-sdk.test.ts +800 -0
  187. package/src/tests/base-prompt.test.ts +264 -0
  188. package/src/tests/build-pi-skills.test.ts +127 -0
  189. package/src/tests/channel-activity.test.ts +363 -0
  190. package/src/tests/claude-adapter.test.ts +126 -0
  191. package/src/tests/context-versioning.test.ts +425 -0
  192. package/src/tests/db-queries-oauth.test.ts +197 -0
  193. package/src/tests/db-queries-tracker.test.ts +230 -0
  194. package/src/tests/epics.test.ts +3 -3
  195. package/src/tests/error-tracker.test.ts +368 -0
  196. package/src/tests/fetch-resolved-env.test.ts +167 -0
  197. package/src/tests/generate-default-claude-md.test.ts +9 -1
  198. package/src/tests/generate-identity-templates.test.ts +124 -0
  199. package/src/tests/gitlab-auth.test.ts +109 -0
  200. package/src/tests/gitlab-handlers.test.ts +691 -0
  201. package/src/tests/gitlab-vcs-db.test.ts +177 -0
  202. package/src/tests/heartbeat.test.ts +364 -0
  203. package/src/tests/http-api-integration.test.ts +1698 -0
  204. package/src/tests/linear-outbound-sync.test.ts +200 -0
  205. package/src/tests/linear-webhook.test.ts +406 -0
  206. package/src/tests/match-route.test.ts +187 -0
  207. package/src/tests/memory.test.ts +737 -0
  208. package/src/tests/migration-runner-regressions.test.ts +86 -0
  209. package/src/tests/model-control.test.ts +338 -0
  210. package/src/tests/oauth-wrapper.test.ts +147 -0
  211. package/src/tests/onboard-compose.test.ts +138 -0
  212. package/src/tests/onboard-env.test.ts +174 -0
  213. package/src/tests/onboard-manifest.test.ts +137 -0
  214. package/src/tests/pi-mono-adapter.test.ts +234 -0
  215. package/src/tests/pool-session-logs.test.ts +199 -0
  216. package/src/tests/progress-dedup.test.ts +98 -0
  217. package/src/tests/prompt-template-github.test.ts +682 -0
  218. package/src/tests/prompt-template-remaining.test.ts +504 -0
  219. package/src/tests/prompt-template-resolver.test.ts +621 -0
  220. package/src/tests/prompt-template-session.test.ts +363 -0
  221. package/src/tests/prompt-templates-db.test.ts +616 -0
  222. package/src/tests/provider-adapter.test.ts +122 -0
  223. package/src/tests/provider-command-format.test.ts +98 -0
  224. package/src/tests/reload-config.test.ts +170 -0
  225. package/src/tests/runner-polling-api.test.ts +25 -20
  226. package/src/tests/scheduled-tasks.test.ts +104 -0
  227. package/src/tests/scheduler-backoff.test.ts +166 -0
  228. package/src/tests/self-improvement.test.ts +541 -0
  229. package/src/tests/session-attach.test.ts +536 -0
  230. package/src/tests/session-costs.test.ts +267 -1
  231. package/src/tests/slack-actions.test.ts +133 -0
  232. package/src/tests/slack-assistant.test.ts +136 -0
  233. package/src/tests/slack-blocks.test.ts +246 -0
  234. package/src/tests/slack-metadata-inheritance.test.ts +243 -0
  235. package/src/tests/slack-queue-offline.test.ts +174 -0
  236. package/src/tests/slack-router.test.ts +181 -0
  237. package/src/tests/slack-thread-buffer.test.ts +305 -0
  238. package/src/tests/slack-thread-followups.test.ts +298 -0
  239. package/src/tests/slack-watcher.test.ts +101 -0
  240. package/src/tests/structured-output.test.ts +307 -0
  241. package/src/tests/swarm-repos.test.ts +198 -0
  242. package/src/tests/task-cancellation.test.ts +6 -4
  243. package/src/tests/task-working-dir.test.ts +176 -0
  244. package/src/tests/template-fetch.test.ts +490 -0
  245. package/src/tests/tool-annotations.test.ts +371 -0
  246. package/src/tests/tracker-tools.test.ts +184 -0
  247. package/src/tests/update-profile-agentid.test.ts +248 -0
  248. package/src/tests/update-profile-api.test.ts +143 -3
  249. package/src/tests/update-profile-auth.test.ts +195 -0
  250. package/src/tests/validation-adapters.test.ts +86 -0
  251. package/src/tests/vcs-provider.test.ts +27 -0
  252. package/src/tests/workflow-agent-task.test.ts +196 -0
  253. package/src/tests/workflow-async-v2.test.ts +508 -0
  254. package/src/tests/workflow-convergence.test.ts +541 -0
  255. package/src/tests/workflow-definition-validation.test.ts +366 -0
  256. package/src/tests/workflow-engine-v2.test.ts +691 -0
  257. package/src/tests/workflow-executors.test.ts +736 -0
  258. package/src/tests/workflow-http-v2.test.ts +599 -0
  259. package/src/tests/workflow-integration-io.test.ts +902 -0
  260. package/src/tests/workflow-io-schemas.test.ts +624 -0
  261. package/src/tests/workflow-registry.test.ts +592 -0
  262. package/src/tests/workflow-retry-v2.test.ts +401 -0
  263. package/src/tests/workflow-retry-validation.test.ts +282 -0
  264. package/src/tests/workflow-schedule-trigger.test.ts +104 -0
  265. package/src/tests/workflow-template.test.ts +288 -0
  266. package/src/tests/workflow-trigger-schema.test.ts +359 -0
  267. package/src/tests/workflow-triggers-v2.test.ts +264 -0
  268. package/src/tests/workflow-versions.test.ts +208 -0
  269. package/src/tests/workflow-workspace.test.ts +272 -0
  270. package/src/tests/x402-client.test.ts +117 -0
  271. package/src/tests/x402-config.test.ts +182 -0
  272. package/src/tests/x402-spending-tracker.test.ts +185 -0
  273. package/src/tools/cancel-task.ts +2 -0
  274. package/src/tools/context-diff.ts +171 -0
  275. package/src/tools/context-history.ts +138 -0
  276. package/src/tools/create-channel.ts +1 -0
  277. package/src/tools/db-query.ts +78 -0
  278. package/src/tools/delete-channel.ts +132 -0
  279. package/src/tools/epics/assign-task-to-epic.ts +1 -0
  280. package/src/tools/epics/create-epic.ts +3 -2
  281. package/src/tools/epics/delete-epic.ts +2 -0
  282. package/src/tools/epics/get-epic-details.ts +2 -0
  283. package/src/tools/epics/list-epics.ts +2 -0
  284. package/src/tools/epics/unassign-task-from-epic.ts +1 -0
  285. package/src/tools/epics/update-epic.ts +7 -4
  286. package/src/tools/get-swarm.ts +2 -0
  287. package/src/tools/get-task-details.ts +2 -0
  288. package/src/tools/get-tasks.ts +27 -1
  289. package/src/tools/inject-learning.ts +106 -0
  290. package/src/tools/join-swarm.ts +17 -7
  291. package/src/tools/list-channels.ts +2 -0
  292. package/src/tools/list-services.ts +2 -0
  293. package/src/tools/memory-get.ts +56 -0
  294. package/src/tools/memory-search.ts +131 -0
  295. package/src/tools/my-agent-info.ts +2 -0
  296. package/src/tools/poll-task.ts +2 -20
  297. package/src/tools/post-message.ts +1 -0
  298. package/src/tools/prompt-templates/delete.ts +86 -0
  299. package/src/tools/prompt-templates/get.ts +89 -0
  300. package/src/tools/prompt-templates/index.ts +5 -0
  301. package/src/tools/prompt-templates/list.ts +95 -0
  302. package/src/tools/prompt-templates/preview.ts +84 -0
  303. package/src/tools/prompt-templates/set.ts +117 -0
  304. package/src/tools/read-messages.ts +2 -0
  305. package/src/tools/register-agentmail-inbox.ts +166 -0
  306. package/src/tools/register-service.ts +2 -0
  307. package/src/tools/schedules/create-schedule.ts +134 -24
  308. package/src/tools/schedules/delete-schedule.ts +2 -0
  309. package/src/tools/schedules/list-schedules.ts +20 -4
  310. package/src/tools/schedules/run-schedule-now.ts +1 -0
  311. package/src/tools/schedules/update-schedule.ts +49 -17
  312. package/src/tools/send-task.ts +132 -10
  313. package/src/tools/slack-download-file.ts +4 -2
  314. package/src/tools/slack-list-channels.ts +2 -0
  315. package/src/tools/slack-post.ts +2 -0
  316. package/src/tools/slack-read.ts +2 -0
  317. package/src/tools/slack-reply.ts +2 -0
  318. package/src/tools/slack-upload-file.ts +2 -0
  319. package/src/tools/store-progress.ts +205 -4
  320. package/src/tools/swarm-config/delete-config.ts +87 -0
  321. package/src/tools/swarm-config/get-config.ts +108 -0
  322. package/src/tools/swarm-config/index.ts +4 -0
  323. package/src/tools/swarm-config/list-config.ts +99 -0
  324. package/src/tools/swarm-config/set-config.ts +118 -0
  325. package/src/tools/task-action.ts +50 -5
  326. package/src/tools/task-dedup.ts +97 -0
  327. package/src/tools/templates.ts +53 -0
  328. package/src/tools/tool-config.ts +124 -0
  329. package/src/tools/tracker/index.ts +6 -0
  330. package/src/tools/tracker/tracker-link-epic.ts +64 -0
  331. package/src/tools/tracker/tracker-link-task.ts +64 -0
  332. package/src/tools/tracker/tracker-map-agent.ts +57 -0
  333. package/src/tools/tracker/tracker-status.ts +56 -0
  334. package/src/tools/tracker/tracker-sync-status.ts +42 -0
  335. package/src/tools/tracker/tracker-unlink.ts +41 -0
  336. package/src/tools/unregister-service.ts +2 -0
  337. package/src/tools/update-profile.ts +172 -17
  338. package/src/tools/update-service-status.ts +2 -0
  339. package/src/tools/utils.ts +10 -1
  340. package/src/tools/workflows/create-workflow.ts +129 -0
  341. package/src/tools/workflows/delete-workflow.ts +42 -0
  342. package/src/tools/workflows/get-workflow-run.ts +59 -0
  343. package/src/tools/workflows/get-workflow.ts +53 -0
  344. package/src/tools/workflows/index.ts +9 -0
  345. package/src/tools/workflows/list-workflow-runs.ts +48 -0
  346. package/src/tools/workflows/list-workflows.ts +42 -0
  347. package/src/tools/workflows/retry-workflow-run.ts +40 -0
  348. package/src/tools/workflows/trigger-workflow.ts +96 -0
  349. package/src/tools/workflows/update-workflow.ts +133 -0
  350. package/src/tracker/types.ts +51 -0
  351. package/src/types.ts +530 -14
  352. package/src/utils/credentials.test.ts +156 -0
  353. package/src/utils/credentials.ts +50 -0
  354. package/src/utils/error-tracker.ts +190 -0
  355. package/src/vcs/index.ts +15 -0
  356. package/src/vcs/types.ts +5 -0
  357. package/src/workflows/checkpoint.ts +121 -0
  358. package/src/workflows/cooldown.ts +28 -0
  359. package/src/workflows/definition.ts +235 -0
  360. package/src/workflows/engine.ts +580 -0
  361. package/src/workflows/event-bus.ts +29 -0
  362. package/src/workflows/executors/agent-task.ts +103 -0
  363. package/src/workflows/executors/base.ts +86 -0
  364. package/src/workflows/executors/code-match.ts +88 -0
  365. package/src/workflows/executors/index.ts +16 -0
  366. package/src/workflows/executors/notify.ts +93 -0
  367. package/src/workflows/executors/property-match.ts +104 -0
  368. package/src/workflows/executors/raw-llm.ts +83 -0
  369. package/src/workflows/executors/registry.ts +76 -0
  370. package/src/workflows/executors/script.ts +103 -0
  371. package/src/workflows/executors/validate.ts +215 -0
  372. package/src/workflows/executors/vcs.ts +58 -0
  373. package/src/workflows/index.ts +61 -0
  374. package/src/workflows/input.ts +46 -0
  375. package/src/workflows/json-schema-validator.ts +118 -0
  376. package/src/workflows/recovery.ts +139 -0
  377. package/src/workflows/resume.ts +229 -0
  378. package/src/workflows/retry-poller.ts +216 -0
  379. package/src/workflows/template.ts +74 -0
  380. package/src/workflows/templates.ts +86 -0
  381. package/src/workflows/triggers.ts +124 -0
  382. package/src/workflows/validation.ts +104 -0
  383. package/src/workflows/version.ts +44 -0
  384. package/src/x402/cli.ts +140 -0
  385. package/src/x402/client.ts +192 -0
  386. package/src/x402/config.ts +131 -0
  387. package/src/x402/index.ts +37 -0
  388. package/src/x402/openfort-signer.ts +83 -0
  389. package/src/x402/spending-tracker.ts +109 -0
  390. package/templates/official/coder/CLAUDE.md +49 -0
  391. package/templates/official/coder/IDENTITY.md +28 -0
  392. package/templates/official/coder/SOUL.md +43 -0
  393. package/templates/official/coder/TOOLS.md +40 -0
  394. package/templates/official/coder/config.json +23 -0
  395. package/templates/official/coder/start-up.sh +23 -0
  396. package/templates/official/content-reviewer/CLAUDE.md +68 -0
  397. package/templates/official/content-reviewer/IDENTITY.md +28 -0
  398. package/templates/official/content-reviewer/SOUL.md +44 -0
  399. package/templates/official/content-reviewer/TOOLS.md +37 -0
  400. package/templates/official/content-reviewer/config.json +23 -0
  401. package/templates/official/content-reviewer/start-up.sh +23 -0
  402. package/templates/official/content-strategist/CLAUDE.md +63 -0
  403. package/templates/official/content-strategist/IDENTITY.md +33 -0
  404. package/templates/official/content-strategist/SOUL.md +48 -0
  405. package/templates/official/content-strategist/TOOLS.md +47 -0
  406. package/templates/official/content-strategist/config.json +23 -0
  407. package/templates/official/content-strategist/start-up.sh +23 -0
  408. package/templates/official/content-writer/CLAUDE.md +72 -0
  409. package/templates/official/content-writer/IDENTITY.md +30 -0
  410. package/templates/official/content-writer/SOUL.md +46 -0
  411. package/templates/official/content-writer/TOOLS.md +44 -0
  412. package/templates/official/content-writer/config.json +23 -0
  413. package/templates/official/content-writer/start-up.sh +23 -0
  414. package/templates/official/forward-deployed-engineer/CLAUDE.md +54 -0
  415. package/templates/official/forward-deployed-engineer/IDENTITY.md +37 -0
  416. package/templates/official/forward-deployed-engineer/SOUL.md +55 -0
  417. package/templates/official/forward-deployed-engineer/config.json +21 -0
  418. package/templates/official/lead/CLAUDE.md +33 -0
  419. package/templates/official/lead/IDENTITY.md +36 -0
  420. package/templates/official/lead/SOUL.md +51 -0
  421. package/templates/official/lead/config.json +22 -0
  422. package/templates/official/researcher/CLAUDE.md +46 -0
  423. package/templates/official/researcher/IDENTITY.md +28 -0
  424. package/templates/official/researcher/SOUL.md +43 -0
  425. package/templates/official/researcher/config.json +21 -0
  426. package/templates/official/reviewer/CLAUDE.md +63 -0
  427. package/templates/official/reviewer/IDENTITY.md +28 -0
  428. package/templates/official/reviewer/SOUL.md +45 -0
  429. package/templates/official/reviewer/config.json +21 -0
  430. package/templates/official/tester/CLAUDE.md +53 -0
  431. package/templates/official/tester/IDENTITY.md +28 -0
  432. package/templates/official/tester/SOUL.md +55 -0
  433. package/templates/official/tester/config.json +21 -0
  434. package/templates/schema.ts +35 -0
  435. package/.claude/settings.local.json +0 -115
  436. package/.dockerignore +0 -61
  437. package/.editorconfig +0 -15
  438. package/.env.docker.example +0 -39
  439. package/.env.example +0 -40
  440. package/.github/workflows/ci.yml +0 -76
  441. package/.github/workflows/docker-and-deploy.yml +0 -117
  442. package/.wts-config.json +0 -4
  443. package/.wts-setup.ts +0 -102
  444. package/CLAUDE.md +0 -104
  445. package/CONTRIBUTING.md +0 -270
  446. package/DEPLOYMENT.md +0 -605
  447. package/Dockerfile +0 -57
  448. package/Dockerfile.worker +0 -157
  449. package/FAQ.md +0 -19
  450. package/MCP.md +0 -406
  451. package/UI.md +0 -40
  452. package/assets/agent-swarm-logo-orange.png +0 -0
  453. package/assets/agent-swarm-logo.png +0 -0
  454. package/assets/agent-swarm.mp4 +0 -0
  455. package/assets/agent-swarm.png +0 -0
  456. package/biome.json +0 -39
  457. package/deploy/DEPLOY.md +0 -60
  458. package/deploy/agent-swarm.service +0 -17
  459. package/deploy/docker-push.ts +0 -30
  460. package/deploy/install.ts +0 -85
  461. package/deploy/prod-db.ts +0 -42
  462. package/deploy/uninstall.ts +0 -12
  463. package/deploy/update.ts +0 -21
  464. package/docker-compose.example.yml +0 -159
  465. package/docker-entrypoint.sh +0 -352
  466. package/ecosystem.config.cjs +0 -66
  467. package/plugin/README.md +0 -1
  468. package/plugin/hooks/hooks.json +0 -71
  469. package/pyproject.toml +0 -9
  470. package/scripts/generate-mcp-docs.ts +0 -415
  471. package/slack-manifest.json +0 -71
  472. package/src/tests/get-inbox-message.test.ts +0 -145
  473. package/src/tools/get-inbox-message.ts +0 -89
  474. package/src/tools/inbox-delegate.ts +0 -113
  475. package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
  476. package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
  477. package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
  478. package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
  479. package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
  480. package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
  481. package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
  482. package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
  483. package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
  484. package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
  485. package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
  486. package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
  487. package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
  488. package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
  489. package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
  490. package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
  491. package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
  492. package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
  493. package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
  494. package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
  495. package/thoughts/shared/research/.gitkeep +0 -0
  496. package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
  497. package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
  498. package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
  499. package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
  500. package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
  501. package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
  502. package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
  503. package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
  504. package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
  505. package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
  506. package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
  507. package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
  508. package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
  509. package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
  510. package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
  511. package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
  512. package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
  513. package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
  514. package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
  515. package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
  516. package/tsconfig.json +0 -37
  517. package/ui/CLAUDE.md +0 -49
  518. package/ui/bun.lock +0 -771
  519. package/ui/index.html +0 -22
  520. package/ui/package-lock.json +0 -5290
  521. package/ui/package.json +0 -33
  522. package/ui/pnpm-lock.yaml +0 -3341
  523. package/ui/postcss.config.js +0 -6
  524. package/ui/public/logo.png +0 -0
  525. package/ui/src/App.tsx +0 -63
  526. package/ui/src/components/ActivityFeed.tsx +0 -440
  527. package/ui/src/components/AgentDetailPanel.tsx +0 -733
  528. package/ui/src/components/AgentsPanel.tsx +0 -815
  529. package/ui/src/components/ChatPanel.tsx +0 -1920
  530. package/ui/src/components/ConfigModal.tsx +0 -253
  531. package/ui/src/components/Dashboard.tsx +0 -832
  532. package/ui/src/components/EditAgentProfileModal.tsx +0 -433
  533. package/ui/src/components/EpicDetailPage.tsx +0 -741
  534. package/ui/src/components/EpicsPanel.tsx +0 -566
  535. package/ui/src/components/Header.tsx +0 -160
  536. package/ui/src/components/JsonViewer.tsx +0 -171
  537. package/ui/src/components/ScheduledTaskDetailPanel.tsx +0 -517
  538. package/ui/src/components/ScheduledTasksPanel.tsx +0 -639
  539. package/ui/src/components/ServicesPanel.tsx +0 -622
  540. package/ui/src/components/SessionLogPanel.tsx +0 -1219
  541. package/ui/src/components/StatsBar.tsx +0 -321
  542. package/ui/src/components/StatusBadge.tsx +0 -168
  543. package/ui/src/components/TaskDetailPanel.tsx +0 -903
  544. package/ui/src/components/TasksPanel.tsx +0 -614
  545. package/ui/src/components/UsageCharts.tsx +0 -216
  546. package/ui/src/components/UsageTab.tsx +0 -394
  547. package/ui/src/hooks/queries.ts +0 -353
  548. package/ui/src/hooks/useAutoScroll.ts +0 -83
  549. package/ui/src/index.css +0 -257
  550. package/ui/src/lib/api.ts +0 -268
  551. package/ui/src/lib/config.ts +0 -35
  552. package/ui/src/lib/contentPreview.ts +0 -208
  553. package/ui/src/lib/theme.ts +0 -214
  554. package/ui/src/lib/utils.ts +0 -88
  555. package/ui/src/main.tsx +0 -28
  556. package/ui/src/types/api.ts +0 -323
  557. package/ui/src/vite-env.d.ts +0 -1
  558. package/ui/tailwind.config.js +0 -37
  559. package/ui/tsconfig.json +0 -31
  560. package/ui/vite.config.ts +0 -35
  561. /package/{thoughts/shared/plans → templates/community}/.gitkeep +0 -0
@@ -0,0 +1,86 @@
1
+ import type { WorkflowDefinition, WorkflowTemplate } from "../types";
2
+
3
+ /**
4
+ * Validate that all required template variables are provided.
5
+ * Returns a list of missing required variable names.
6
+ */
7
+ export function validateTemplateVariables(
8
+ template: WorkflowTemplate,
9
+ provided: Record<string, unknown>,
10
+ ): string[] {
11
+ const missing: string[] = [];
12
+ for (const variable of template.variables) {
13
+ if (variable.required && !(variable.name in provided)) {
14
+ // Check if there's a default value
15
+ if (variable.default === undefined) {
16
+ missing.push(variable.name);
17
+ }
18
+ }
19
+ }
20
+ return missing;
21
+ }
22
+
23
+ /**
24
+ * Instantiate a workflow template with the given variables.
25
+ *
26
+ * 1. Validates all required variables are provided
27
+ * 2. Deep-clones the template definition
28
+ * 3. Replaces `{{variable}}` placeholders in all string fields
29
+ * 4. Returns a valid WorkflowDefinition
30
+ */
31
+ export function instantiateTemplate(
32
+ template: WorkflowTemplate,
33
+ variables: Record<string, unknown>,
34
+ ): WorkflowDefinition {
35
+ // Validate required variables
36
+ const missing = validateTemplateVariables(template, variables);
37
+ if (missing.length > 0) {
38
+ throw new Error(`Missing required template variables: ${missing.join(", ")}`);
39
+ }
40
+
41
+ // Build resolved variables (apply defaults for missing optional vars)
42
+ const resolved: Record<string, unknown> = {};
43
+ for (const variable of template.variables) {
44
+ if (variable.name in variables) {
45
+ resolved[variable.name] = variables[variable.name];
46
+ } else if (variable.default !== undefined) {
47
+ resolved[variable.name] = variable.default;
48
+ }
49
+ }
50
+
51
+ // Deep-clone the definition and replace placeholders
52
+ const cloned = JSON.parse(JSON.stringify(template.definition)) as WorkflowDefinition;
53
+ return replaceVariables(cloned, resolved);
54
+ }
55
+
56
+ /**
57
+ * Deep-replace `{{variableName}}` placeholders in all string fields of an object.
58
+ */
59
+ function replaceVariables<T>(obj: T, variables: Record<string, unknown>): T {
60
+ if (typeof obj === "string") {
61
+ return replaceStringPlaceholders(obj, variables) as T;
62
+ }
63
+ if (Array.isArray(obj)) {
64
+ return obj.map((item) => replaceVariables(item, variables)) as T;
65
+ }
66
+ if (obj !== null && typeof obj === "object") {
67
+ const result: Record<string, unknown> = {};
68
+ for (const [key, value] of Object.entries(obj)) {
69
+ result[key] = replaceVariables(value, variables);
70
+ }
71
+ return result as T;
72
+ }
73
+ return obj;
74
+ }
75
+
76
+ /**
77
+ * Replace `{{variableName}}` patterns in a string with variable values.
78
+ */
79
+ function replaceStringPlaceholders(template: string, variables: Record<string, unknown>): string {
80
+ return template.replace(/\{\{(\w+)\}\}/g, (_match, name: string) => {
81
+ const value = variables[name];
82
+ if (value === undefined) return _match; // Leave unresolved placeholders as-is
83
+ if (typeof value === "object" && value !== null) return JSON.stringify(value);
84
+ return String(value);
85
+ });
86
+ }
@@ -0,0 +1,124 @@
1
+ import crypto from "node:crypto";
2
+ import { getWorkflow, getWorkflowsByScheduleId } from "../be/db";
3
+ import type { ScheduledTask, TriggerConfig } from "../types";
4
+ import { startWorkflowExecution } from "./engine";
5
+ import type { ExecutorRegistry } from "./executors/registry";
6
+
7
+ /**
8
+ * Handle an incoming webhook trigger for a workflow.
9
+ *
10
+ * 1. Loads the workflow and finds a webhook trigger in `triggers[]`
11
+ * 2. If `hmacSecret` is set, verifies HMAC-SHA256 signature
12
+ * 3. Starts the workflow execution with the webhook payload
13
+ */
14
+ export async function handleWebhookTrigger(
15
+ workflowId: string,
16
+ payload: unknown,
17
+ signature: string | undefined,
18
+ signatureHeader: string | undefined,
19
+ registry: ExecutorRegistry,
20
+ ): Promise<{ runId: string }> {
21
+ const workflow = getWorkflow(workflowId);
22
+ if (!workflow) {
23
+ throw new WebhookError("Workflow not found", 404);
24
+ }
25
+
26
+ if (!workflow.enabled) {
27
+ throw new WebhookError("Workflow is disabled", 400);
28
+ }
29
+
30
+ // Find webhook trigger in triggers[]
31
+ const webhookTrigger = workflow.triggers.find((t: TriggerConfig) => t.type === "webhook");
32
+
33
+ // If the workflow has a webhook trigger with an hmacSecret, verify the signature
34
+ if (webhookTrigger && webhookTrigger.type === "webhook" && webhookTrigger.hmacSecret) {
35
+ if (!signature && !signatureHeader) {
36
+ throw new WebhookError("Missing signature", 401);
37
+ }
38
+
39
+ const rawSignature = signatureHeader || signature || "";
40
+ const isValid = verifyHmacSignature(
41
+ webhookTrigger.hmacSecret,
42
+ typeof payload === "string" ? payload : JSON.stringify(payload),
43
+ rawSignature,
44
+ );
45
+
46
+ if (!isValid) {
47
+ throw new WebhookError("Invalid signature", 401);
48
+ }
49
+ }
50
+
51
+ const runId = await startWorkflowExecution(workflow, payload, registry);
52
+ return { runId };
53
+ }
54
+
55
+ /**
56
+ * Handle a schedule trigger: find workflows linked to this schedule and execute them.
57
+ * Returns an array of workflow run IDs. Empty array means no workflows matched
58
+ * (caller should fall through to standalone task creation).
59
+ */
60
+ export async function handleScheduleTrigger(
61
+ scheduleId: string,
62
+ schedule: ScheduledTask,
63
+ registry: ExecutorRegistry,
64
+ ): Promise<string[]> {
65
+ const workflows = getWorkflowsByScheduleId(scheduleId);
66
+ if (workflows.length === 0) return [];
67
+
68
+ const runIds: string[] = [];
69
+ for (const workflow of workflows) {
70
+ const triggerData = {
71
+ scheduleId,
72
+ scheduleName: schedule.name,
73
+ firedAt: new Date().toISOString(),
74
+ };
75
+ const runId = await startWorkflowExecution(workflow, triggerData, registry);
76
+ runIds.push(runId);
77
+ console.log(
78
+ `[Triggers] Schedule "${schedule.name}" triggered workflow "${workflow.name}" (run: ${runId})`,
79
+ );
80
+ }
81
+ return runIds;
82
+ }
83
+
84
+ /**
85
+ * Verify HMAC-SHA256 signature.
86
+ * Supports both `sha256=<hex>` format and raw hex.
87
+ */
88
+ export function verifyHmacSignature(
89
+ secret: string,
90
+ body: string,
91
+ providedSignature: string,
92
+ ): boolean {
93
+ const hmac = crypto.createHmac("sha256", secret);
94
+ hmac.update(body);
95
+ const expectedHex = hmac.digest("hex");
96
+
97
+ // Support "sha256=<hex>" format (GitHub-style)
98
+ const normalizedProvided = providedSignature.startsWith("sha256=")
99
+ ? providedSignature.slice(7)
100
+ : providedSignature;
101
+
102
+ // Constant-time comparison
103
+ try {
104
+ return crypto.timingSafeEqual(
105
+ Buffer.from(normalizedProvided, "hex"),
106
+ Buffer.from(expectedHex, "hex"),
107
+ );
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Error class for webhook-specific errors with HTTP status codes.
115
+ */
116
+ export class WebhookError extends Error {
117
+ constructor(
118
+ message: string,
119
+ public readonly statusCode: number,
120
+ ) {
121
+ super(message);
122
+ this.name = "WebhookError";
123
+ }
124
+ }
@@ -0,0 +1,104 @@
1
+ import type { ExecutorMeta, WorkflowNode } from "../types";
2
+ import type { ExecutorRegistry } from "./executors/registry";
3
+
4
+ export type ValidationOutcome = "pass" | "halt" | "retry";
5
+
6
+ export interface ValidationRunResult {
7
+ outcome: ValidationOutcome;
8
+ /** Context additions if retry is needed */
9
+ retryContext?: Record<string, unknown>;
10
+ }
11
+
12
+ /**
13
+ * Normalize executor output to a pass/fail boolean.
14
+ *
15
+ * Different executors use different output shapes to indicate success.
16
+ * This adapter maps each executor type's convention to a uniform boolean.
17
+ */
18
+ export function extractPassResult(executorType: string, output: unknown): boolean {
19
+ if (!output || typeof output !== "object") return false;
20
+ const o = output as Record<string, unknown>;
21
+
22
+ switch (executorType) {
23
+ case "validate":
24
+ return o.pass === true;
25
+ case "script":
26
+ return o.exitCode === 0;
27
+ case "property-match":
28
+ return o.passed === true;
29
+ case "raw-llm":
30
+ // For raw-llm used as validator, check if the LLM output contains a structured pass result
31
+ if (typeof o.result === "object" && o.result !== null) {
32
+ return (o.result as Record<string, unknown>).pass === true;
33
+ }
34
+ return false;
35
+ default:
36
+ // Generic fallback: check for common pass indicators
37
+ return o.pass === true || o.passed === true || o.exitCode === 0;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Run per-step validation after a step completes.
43
+ *
44
+ * If the node has no validation config, returns "pass" immediately.
45
+ * Otherwise runs the validation executor and returns the outcome.
46
+ */
47
+ export async function runStepValidation(
48
+ registry: ExecutorRegistry,
49
+ stepNode: WorkflowNode,
50
+ stepOutput: unknown,
51
+ context: Record<string, unknown>,
52
+ meta: ExecutorMeta,
53
+ ): Promise<ValidationRunResult> {
54
+ if (!stepNode.validation) {
55
+ return { outcome: "pass" };
56
+ }
57
+
58
+ const validation = stepNode.validation;
59
+ const executorType = validation.executor || "validate";
60
+
61
+ const executor = registry.get(executorType);
62
+ const validationConfig = {
63
+ targetNodeId: meta.nodeId,
64
+ ...validation.config,
65
+ };
66
+
67
+ // Build a context that includes the step output under its nodeId
68
+ const validationContext: Record<string, unknown> = {
69
+ ...context,
70
+ [meta.nodeId]: stepOutput,
71
+ };
72
+
73
+ const result = await executor.run({
74
+ config: validationConfig,
75
+ context: validationContext,
76
+ meta: {
77
+ ...meta,
78
+ stepId: crypto.randomUUID(), // Validation gets its own step ID
79
+ },
80
+ });
81
+
82
+ const passed = result.status === "success" && extractPassResult(executorType, result.output);
83
+
84
+ if (passed) {
85
+ return { outcome: "pass" };
86
+ }
87
+
88
+ // Validation failed
89
+ if (validation.mustPass) {
90
+ if (validation.retry) {
91
+ return {
92
+ outcome: "retry",
93
+ retryContext: {
94
+ previousOutput: stepOutput,
95
+ validationResult: result.output,
96
+ },
97
+ };
98
+ }
99
+ return { outcome: "halt" };
100
+ }
101
+
102
+ // mustPass is false — treat failure as pass (advisory validation)
103
+ return { outcome: "pass" };
104
+ }
@@ -0,0 +1,44 @@
1
+ import { createWorkflowVersion, getWorkflow, getWorkflowVersions } from "../be/db";
2
+ import type { WorkflowSnapshot, WorkflowVersion } from "../types";
3
+
4
+ /**
5
+ * Create a version snapshot of a workflow's current state.
6
+ *
7
+ * Call this BEFORE applying an update to preserve the pre-update state.
8
+ *
9
+ * 1. Load current workflow state
10
+ * 2. Get max version number for this workflow
11
+ * 3. Insert workflow_versions row with version+1 and full snapshot
12
+ */
13
+ export function snapshotWorkflow(workflowId: string, changedByAgentId?: string): WorkflowVersion {
14
+ const workflow = getWorkflow(workflowId);
15
+ if (!workflow) {
16
+ throw new Error(`Workflow ${workflowId} not found — cannot create snapshot`);
17
+ }
18
+
19
+ // Get existing versions to determine next version number
20
+ const existingVersions = getWorkflowVersions(workflowId);
21
+ const maxVersion = existingVersions.length > 0 ? existingVersions[0]!.version : 0;
22
+ const nextVersion = maxVersion + 1;
23
+
24
+ // Build snapshot of current state
25
+ const snapshot: WorkflowSnapshot = {
26
+ name: workflow.name,
27
+ description: workflow.description,
28
+ definition: workflow.definition,
29
+ triggers: workflow.triggers,
30
+ cooldown: workflow.cooldown,
31
+ input: workflow.input,
32
+ triggerSchema: workflow.triggerSchema,
33
+ dir: workflow.dir,
34
+ vcsRepo: workflow.vcsRepo,
35
+ enabled: workflow.enabled,
36
+ };
37
+
38
+ return createWorkflowVersion({
39
+ workflowId,
40
+ version: nextVersion,
41
+ snapshot,
42
+ changedByAgentId,
43
+ });
44
+ }
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * x402 CLI — Test x402 payments from the command line.
4
+ *
5
+ * Usage:
6
+ * bun src/x402/cli.ts fetch <url> Make a paid request to a URL
7
+ * bun src/x402/cli.ts status Show spending summary
8
+ * bun src/x402/cli.ts check Check if x402 is configured
9
+ *
10
+ * Signer backends (auto-detected):
11
+ * Openfort: OPENFORT_API_KEY + OPENFORT_WALLET_SECRET
12
+ * Viem: EVM_PRIVATE_KEY (0x-prefixed hex)
13
+ *
14
+ * Environment:
15
+ * X402_SIGNER_TYPE "openfort" or "viem" (auto-detected if not set)
16
+ * OPENFORT_API_KEY Openfort API key (sk_test_ or sk_live_)
17
+ * OPENFORT_WALLET_SECRET Openfort wallet secret (base64 P-256 key)
18
+ * EVM_PRIVATE_KEY Raw wallet private key (0x-prefixed)
19
+ * X402_MAX_AUTO_APPROVE Max USD per request (default: 1.00)
20
+ * X402_DAILY_LIMIT Daily USD limit (default: 10.00)
21
+ * X402_NETWORK CAIP-2 network ID (default: eip155:84532)
22
+ */
23
+
24
+ import { createX402Client } from "./client.ts";
25
+
26
+ const args = process.argv.slice(2);
27
+ const command = args[0];
28
+
29
+ async function main() {
30
+ switch (command) {
31
+ case "fetch": {
32
+ const url = args[1];
33
+ if (!url) {
34
+ console.error("Usage: x402 fetch <url>");
35
+ process.exit(1);
36
+ }
37
+
38
+ const method = (args[2] || "GET").toUpperCase();
39
+ console.log(`Making ${method} request to ${url} with x402 payment support...\n`);
40
+
41
+ const client = await createX402Client();
42
+ const summary = client.getSpendingSummary();
43
+ console.log(`Signer: ${client.config.signerType} | Wallet: ${client.walletAddress}`);
44
+ console.log(
45
+ `Spending limits: $${summary.maxPerRequest.toFixed(2)}/request, ` +
46
+ `$${summary.dailyLimit.toFixed(2)}/day ` +
47
+ `($${summary.dailyRemaining.toFixed(2)} remaining)\n`,
48
+ );
49
+
50
+ const response = await client.fetch(url, { method });
51
+
52
+ console.log(`Status: ${response.status} ${response.statusText}`);
53
+ console.log("Headers:");
54
+ for (const [key, value] of response.headers.entries()) {
55
+ if (key.toLowerCase().startsWith("payment") || key.toLowerCase() === "content-type") {
56
+ console.log(` ${key}: ${value}`);
57
+ }
58
+ }
59
+
60
+ const contentType = response.headers.get("content-type") || "";
61
+ if (contentType.includes("json")) {
62
+ const body = await response.json();
63
+ console.log("\nResponse body:");
64
+ console.log(JSON.stringify(body, null, 2));
65
+ } else {
66
+ const body = await response.text();
67
+ console.log(`\nResponse body (${body.length} chars):`);
68
+ console.log(body.slice(0, 2000));
69
+ if (body.length > 2000) console.log("... (truncated)");
70
+ }
71
+
72
+ const updatedSummary = client.getSpendingSummary();
73
+ console.log(
74
+ `\nSpending: $${updatedSummary.todaySpent.toFixed(2)} today ` +
75
+ `(${updatedSummary.todayCount} payments, ` +
76
+ `$${updatedSummary.dailyRemaining.toFixed(2)} remaining)`,
77
+ );
78
+ break;
79
+ }
80
+
81
+ case "status": {
82
+ const client = await createX402Client();
83
+ const summary = client.getSpendingSummary();
84
+ console.log("x402 Spending Status");
85
+ console.log("====================");
86
+ console.log(`Signer: ${client.config.signerType}`);
87
+ console.log(`Wallet: ${client.walletAddress}`);
88
+ console.log(`Per-request limit: $${summary.maxPerRequest.toFixed(2)}`);
89
+ console.log(`Daily limit: $${summary.dailyLimit.toFixed(2)}`);
90
+ console.log(`Today spent: $${summary.todaySpent.toFixed(2)}`);
91
+ console.log(`Today remaining: $${summary.dailyRemaining.toFixed(2)}`);
92
+ console.log(`Today payments: ${summary.todayCount}`);
93
+ break;
94
+ }
95
+
96
+ case "check": {
97
+ try {
98
+ const client = await createX402Client();
99
+ console.log("x402 Configuration");
100
+ console.log("==================");
101
+ console.log(`Signer type: ${client.config.signerType}`);
102
+ console.log(`Wallet address: ${client.walletAddress}`);
103
+ console.log(`Max per request: $${client.config.maxAutoApprove.toFixed(2)}`);
104
+ console.log(`Daily limit: $${client.config.dailyLimit.toFixed(2)}`);
105
+ console.log(`Network: ${client.config.network}`);
106
+ console.log("\nx402 is configured and ready.");
107
+ } catch (error) {
108
+ console.error(
109
+ `x402 configuration error: ${error instanceof Error ? error.message : String(error)}`,
110
+ );
111
+ process.exit(1);
112
+ }
113
+ break;
114
+ }
115
+
116
+ default:
117
+ console.log("x402 CLI — Test x402 payments\n");
118
+ console.log("Commands:");
119
+ console.log(" fetch <url> [method] Make a paid request (default: GET)");
120
+ console.log(" status Show spending summary");
121
+ console.log(" check Check if x402 is configured");
122
+ console.log("\nSigner backends (auto-detected):");
123
+ console.log(" Openfort: OPENFORT_API_KEY + OPENFORT_WALLET_SECRET");
124
+ console.log(" Viem: EVM_PRIVATE_KEY (0x-prefixed hex)");
125
+ console.log("\nEnvironment variables:");
126
+ console.log(" X402_SIGNER_TYPE 'openfort' or 'viem' (auto-detected)");
127
+ console.log(" OPENFORT_API_KEY Openfort API key");
128
+ console.log(" OPENFORT_WALLET_SECRET Openfort wallet auth secret");
129
+ console.log(" EVM_PRIVATE_KEY Raw private key (0x-prefixed)");
130
+ console.log(" X402_MAX_AUTO_APPROVE Max USD per request (default: 1.00)");
131
+ console.log(" X402_DAILY_LIMIT Daily USD limit (default: 10.00)");
132
+ console.log(" X402_NETWORK CAIP-2 network ID (default: eip155:84532)");
133
+ break;
134
+ }
135
+ }
136
+
137
+ main().catch((error) => {
138
+ console.error("Error:", error instanceof Error ? error.message : String(error));
139
+ process.exit(1);
140
+ });
@@ -0,0 +1,192 @@
1
+ /**
2
+ * x402 Payment Client
3
+ *
4
+ * A reusable payment client that wraps fetch() with automatic x402 payment handling
5
+ * and configurable spending limits.
6
+ *
7
+ * Supports two signer backends:
8
+ * - Openfort (default) — managed backend wallet, no raw keys in env
9
+ * - viem — raw EVM_PRIVATE_KEY for local signing
10
+ *
11
+ * Usage:
12
+ * import { createX402Fetch, createX402Client } from "@/x402";
13
+ *
14
+ * // Quick: get a paid fetch function
15
+ * const paidFetch = await createX402Fetch();
16
+ * const response = await paidFetch("https://api.example.com/paid-endpoint");
17
+ *
18
+ * // Advanced: get the full client with spending info
19
+ * const client = await createX402Client();
20
+ * const response = await client.fetch("https://api.example.com/paid-endpoint");
21
+ * console.log(client.getSpendingSummary());
22
+ */
23
+
24
+ import { x402Client } from "@x402/core/client";
25
+ import type { ClientEvmSigner } from "@x402/evm";
26
+ import { toClientEvmSigner } from "@x402/evm";
27
+ import { registerExactEvmScheme } from "@x402/evm/exact/client";
28
+ import { wrapFetchWithPayment } from "@x402/fetch";
29
+ import { createPublicClient, http } from "viem";
30
+ import { privateKeyToAccount } from "viem/accounts";
31
+ import { base, baseSepolia } from "viem/chains";
32
+ import { loadX402Config, type X402Config, type X402SafeConfig } from "./config.ts";
33
+ import { createOpenfortSigner } from "./openfort-signer.ts";
34
+ import { SpendingTracker } from "./spending-tracker.ts";
35
+
36
+ export interface X402PaymentClient {
37
+ /** A fetch function that automatically handles x402 402 responses */
38
+ fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
39
+ /** The underlying x402Client instance */
40
+ x402Client: x402Client;
41
+ /** The spending tracker for monitoring limits */
42
+ spendingTracker: SpendingTracker;
43
+ /** Get a summary of today's spending */
44
+ getSpendingSummary: () => ReturnType<SpendingTracker["getSummary"]>;
45
+ /** The wallet address used for payments */
46
+ walletAddress: `0x${string}`;
47
+ /** Safe config subset (no secrets) */
48
+ config: X402SafeConfig;
49
+ }
50
+
51
+ /**
52
+ * Map CAIP-2 network ID to viem chain config.
53
+ */
54
+ function getChainForNetwork(network: string) {
55
+ if (network === "eip155:8453") return base;
56
+ return baseSepolia; // Default to testnet
57
+ }
58
+
59
+ /**
60
+ * Create a signer based on the config's signerType.
61
+ */
62
+ async function buildSigner(
63
+ config: X402Config,
64
+ ): Promise<{ signer: ClientEvmSigner; walletAddress: `0x${string}` }> {
65
+ if (config.signerType === "openfort") {
66
+ if (!config.openfortApiKey || !config.openfortWalletSecret) {
67
+ throw new Error("Openfort signer requires OPENFORT_API_KEY and OPENFORT_WALLET_SECRET.");
68
+ }
69
+
70
+ const chain = getChainForNetwork(config.network);
71
+ const signer = await createOpenfortSigner({
72
+ apiKey: config.openfortApiKey,
73
+ walletSecret: config.openfortWalletSecret,
74
+ walletAddress: config.openfortWalletAddress,
75
+ chain,
76
+ });
77
+
78
+ return { signer, walletAddress: signer.address };
79
+ }
80
+
81
+ // viem signer (raw private key)
82
+ if (!config.evmPrivateKey) {
83
+ throw new Error("Viem signer requires EVM_PRIVATE_KEY.");
84
+ }
85
+
86
+ const account = privateKeyToAccount(config.evmPrivateKey);
87
+ const chain = getChainForNetwork(config.network);
88
+ const publicClient = createPublicClient({ chain, transport: http() });
89
+ const signer = toClientEvmSigner(account, publicClient);
90
+
91
+ return { signer, walletAddress: account.address };
92
+ }
93
+
94
+ /**
95
+ * Create a full x402 payment client with spending controls.
96
+ *
97
+ * NOTE: This is async because Openfort signer requires API calls to create/retrieve wallets.
98
+ *
99
+ * @param configOverrides - Optional config overrides (otherwise loaded from env vars)
100
+ * @returns An X402PaymentClient with fetch, spending tracker, and config
101
+ */
102
+ export async function createX402Client(
103
+ configOverrides?: Partial<X402Config>,
104
+ ): Promise<X402PaymentClient> {
105
+ const envConfig = loadX402Config();
106
+ const config = { ...envConfig, ...configOverrides };
107
+
108
+ // Build the signer (async for Openfort, instant for viem)
109
+ const { signer, walletAddress } = await buildSigner(config);
110
+
111
+ // Create and configure x402 client
112
+ const client = new x402Client();
113
+ registerExactEvmScheme(client, { signer });
114
+
115
+ // Create spending tracker
116
+ const spendingTracker = new SpendingTracker(config.maxAutoApprove, config.dailyLimit);
117
+
118
+ // Register a spending-limit hook that blocks over-budget payments.
119
+ // NOTE: This check has a TOCTOU race — concurrent requests could both pass the
120
+ // limit check before either records its payment. Acceptable for agent workloads
121
+ // (typically sequential), but not suitable for high-concurrency scenarios.
122
+ client.onBeforePaymentCreation(async (context) => {
123
+ const { selectedRequirements } = context;
124
+
125
+ // V2 PaymentRequirements uses `amount` (smallest unit, e.g. "10000" for $0.01 USDC)
126
+ const rawValue = selectedRequirements.amount;
127
+ const amountUsd = usdcToUsd(rawValue);
128
+
129
+ const url = context.paymentRequired.resource?.url || "unknown";
130
+ const blockReason = spendingTracker.checkSpendingLimit(amountUsd, url);
131
+
132
+ if (blockReason) {
133
+ return { abort: true, reason: blockReason };
134
+ }
135
+ });
136
+
137
+ // Track successful payments
138
+ client.onAfterPaymentCreation(async (context) => {
139
+ const rawValue = context.selectedRequirements.amount;
140
+ const amountUsd = usdcToUsd(rawValue);
141
+ const url = context.paymentRequired.resource?.url || "unknown";
142
+ spendingTracker.recordPayment(amountUsd, url);
143
+ });
144
+
145
+ // Wrap fetch with payment handling
146
+ const paidFetch = wrapFetchWithPayment(globalThis.fetch, client);
147
+
148
+ // Expose a safe config subset — never leak secrets
149
+ const {
150
+ evmPrivateKey: _key,
151
+ openfortApiKey: _apiKey,
152
+ openfortWalletSecret: _secret,
153
+ ...safeConfig
154
+ } = config;
155
+
156
+ return {
157
+ fetch: paidFetch as (input: string | URL | Request, init?: RequestInit) => Promise<Response>,
158
+ x402Client: client,
159
+ spendingTracker,
160
+ getSpendingSummary: () => spendingTracker.getSummary(),
161
+ walletAddress,
162
+ config: safeConfig,
163
+ };
164
+ }
165
+
166
+ /**
167
+ * Create a simple paid fetch function.
168
+ * This is the easiest way to get started — just replace `fetch` with this.
169
+ *
170
+ * @param configOverrides - Optional config overrides
171
+ * @returns A fetch function that automatically handles x402 payments
172
+ */
173
+ export async function createX402Fetch(
174
+ configOverrides?: Partial<X402Config>,
175
+ ): Promise<(input: string | URL | Request, init?: RequestInit) => Promise<Response>> {
176
+ return (await createX402Client(configOverrides)).fetch;
177
+ }
178
+
179
+ /**
180
+ * Convert USDC raw value (6 decimals) to USD.
181
+ * USDC uses 6 decimal places, so 1000000 = $1.00
182
+ */
183
+ function usdcToUsd(rawValue: string): number {
184
+ try {
185
+ return Number(BigInt(rawValue)) / 1_000_000;
186
+ } catch {
187
+ // If the value can't be parsed as BigInt, fall back to parseFloat
188
+ const parsed = Number.parseFloat(rawValue);
189
+ if (Number.isNaN(parsed)) return 0;
190
+ return parsed / 1_000_000;
191
+ }
192
+ }