crewswarm 0.8.1-beta

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 (362) hide show
  1. package/.env.example +155 -0
  2. package/LICENSE +21 -0
  3. package/README.md +316 -0
  4. package/apps/dashboard/dist/assets/chat-core-BwSoInmZ.js +1 -0
  5. package/apps/dashboard/dist/assets/chat-core-BwSoInmZ.js.br +0 -0
  6. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js +1 -0
  7. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
  8. package/apps/dashboard/dist/assets/components-CSUb80ze.js +1 -0
  9. package/apps/dashboard/dist/assets/components-CSUb80ze.js.br +0 -0
  10. package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js +1 -0
  11. package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js.br +0 -0
  12. package/apps/dashboard/dist/assets/index-CF0aJRtC.css +1 -0
  13. package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
  14. package/apps/dashboard/dist/assets/index-Px49zu76.js +2 -0
  15. package/apps/dashboard/dist/assets/index-Px49zu76.js.br +0 -0
  16. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js +1 -0
  17. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
  18. package/apps/dashboard/dist/assets/setup-wizard-i3eEixlo.js +1 -0
  19. package/apps/dashboard/dist/assets/setup-wizard-i3eEixlo.js.br +0 -0
  20. package/apps/dashboard/dist/assets/tab-agents-tab-BThdsdJY.js +1 -0
  21. package/apps/dashboard/dist/assets/tab-agents-tab-BThdsdJY.js.br +0 -0
  22. package/apps/dashboard/dist/assets/tab-benchmarks-tab-DfCuAClu.js +1 -0
  23. package/apps/dashboard/dist/assets/tab-comms-tab-eHpOSBhG.js +1 -0
  24. package/apps/dashboard/dist/assets/tab-comms-tab-eHpOSBhG.js.br +0 -0
  25. package/apps/dashboard/dist/assets/tab-contacts-tab-yEegNyO4.js +1 -0
  26. package/apps/dashboard/dist/assets/tab-contacts-tab-yEegNyO4.js.br +0 -0
  27. package/apps/dashboard/dist/assets/tab-engines-tab-C3DYxTwy.js +1 -0
  28. package/apps/dashboard/dist/assets/tab-engines-tab-C3DYxTwy.js.br +0 -0
  29. package/apps/dashboard/dist/assets/tab-memory-tab-C59BYFQD.js +1 -0
  30. package/apps/dashboard/dist/assets/tab-memory-tab-C59BYFQD.js.br +0 -0
  31. package/apps/dashboard/dist/assets/tab-models-tab-9Ur7pXWA.js +1 -0
  32. package/apps/dashboard/dist/assets/tab-models-tab-9Ur7pXWA.js.br +0 -0
  33. package/apps/dashboard/dist/assets/tab-pm-loop-tab-D7mnDelU.js +1 -0
  34. package/apps/dashboard/dist/assets/tab-pm-loop-tab-D7mnDelU.js.br +0 -0
  35. package/apps/dashboard/dist/assets/tab-projects-tab-C6h2Mv1K.js +1 -0
  36. package/apps/dashboard/dist/assets/tab-projects-tab-C6h2Mv1K.js.br +0 -0
  37. package/apps/dashboard/dist/assets/tab-prompts-tab-C0wZvWK3.js +1 -0
  38. package/apps/dashboard/dist/assets/tab-prompts-tab-C0wZvWK3.js.br +0 -0
  39. package/apps/dashboard/dist/assets/tab-services-tab-DBj_w3bc.js +1 -0
  40. package/apps/dashboard/dist/assets/tab-services-tab-DBj_w3bc.js.br +0 -0
  41. package/apps/dashboard/dist/assets/tab-settings-tab-ezeqAjZk.js +1 -0
  42. package/apps/dashboard/dist/assets/tab-settings-tab-ezeqAjZk.js.br +0 -0
  43. package/apps/dashboard/dist/assets/tab-skills-tab-BYdU2whk.js +1 -0
  44. package/apps/dashboard/dist/assets/tab-skills-tab-BYdU2whk.js.br +0 -0
  45. package/apps/dashboard/dist/assets/tab-spending-tab-Bg6w9t_p.js +1 -0
  46. package/apps/dashboard/dist/assets/tab-spending-tab-Bg6w9t_p.js.br +0 -0
  47. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BBV9HB2X.js +1 -0
  48. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BBV9HB2X.js.br +0 -0
  49. package/apps/dashboard/dist/assets/tab-swarm-tab-ChqLlEVs.js +1 -0
  50. package/apps/dashboard/dist/assets/tab-swarm-tab-ChqLlEVs.js.br +0 -0
  51. package/apps/dashboard/dist/assets/tab-usage-tab-B2UWXenJ.js +1 -0
  52. package/apps/dashboard/dist/assets/tab-usage-tab-B2UWXenJ.js.br +0 -0
  53. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js +1 -0
  54. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
  55. package/apps/dashboard/dist/assets/tab-workflows-tab-6QSXLJ0i.js +1 -0
  56. package/apps/dashboard/dist/assets/tab-workflows-tab-6QSXLJ0i.js.br +0 -0
  57. package/apps/dashboard/dist/favicon.png +0 -0
  58. package/apps/dashboard/dist/index.html +6466 -0
  59. package/apps/dashboard/dist/index.html.br +0 -0
  60. package/apps/dashboard/dist/index.html.gz +0 -0
  61. package/apps/dashboard/dist/signup.html +446 -0
  62. package/apps/dashboard/index.html +6442 -0
  63. package/apps/dashboard/package.json +15 -0
  64. package/apps/dashboard/src/app.js +2823 -0
  65. package/apps/dashboard/src/app.js.br +0 -0
  66. package/apps/dashboard/src/app.js.gz +0 -0
  67. package/apps/dashboard/src/chat/chat-actions.js +1847 -0
  68. package/apps/dashboard/src/chat/chat-actions.js.br +0 -0
  69. package/apps/dashboard/src/chat/unified-messages.js +327 -0
  70. package/apps/dashboard/src/chat/unified-messages.js.br +0 -0
  71. package/apps/dashboard/src/cli-process.js +208 -0
  72. package/apps/dashboard/src/cli-process.js.br +0 -0
  73. package/apps/dashboard/src/cli-process.js.gz +0 -0
  74. package/apps/dashboard/src/components/active-tasks-panel.js +175 -0
  75. package/apps/dashboard/src/components/active-tasks-panel.js.br +0 -0
  76. package/apps/dashboard/src/core/api.js +18 -0
  77. package/apps/dashboard/src/core/api.js.br +0 -0
  78. package/apps/dashboard/src/core/dom.js +220 -0
  79. package/apps/dashboard/src/core/dom.js.br +0 -0
  80. package/apps/dashboard/src/core/state.js +91 -0
  81. package/apps/dashboard/src/core/state.js.br +0 -0
  82. package/apps/dashboard/src/core/task-manager.js +134 -0
  83. package/apps/dashboard/src/core/task-manager.js.br +0 -0
  84. package/apps/dashboard/src/orchestration-status.js +127 -0
  85. package/apps/dashboard/src/orchestration-status.js.br +0 -0
  86. package/apps/dashboard/src/setup-wizard.js +555 -0
  87. package/apps/dashboard/src/setup-wizard.js.br +0 -0
  88. package/apps/dashboard/src/styles.css +2085 -0
  89. package/apps/dashboard/src/styles.css.br +0 -0
  90. package/apps/dashboard/src/styles.css.gz +0 -0
  91. package/apps/dashboard/src/tabs/agents-tab.js +2237 -0
  92. package/apps/dashboard/src/tabs/agents-tab.js.br +0 -0
  93. package/apps/dashboard/src/tabs/benchmarks-tab.js +229 -0
  94. package/apps/dashboard/src/tabs/benchmarks-tab.js.br +0 -0
  95. package/apps/dashboard/src/tabs/comms-tab.js +955 -0
  96. package/apps/dashboard/src/tabs/comms-tab.js.br +0 -0
  97. package/apps/dashboard/src/tabs/contacts-tab.js +654 -0
  98. package/apps/dashboard/src/tabs/contacts-tab.js.br +0 -0
  99. package/apps/dashboard/src/tabs/engines-tab.js +175 -0
  100. package/apps/dashboard/src/tabs/engines-tab.js.br +0 -0
  101. package/apps/dashboard/src/tabs/memory-tab.js +182 -0
  102. package/apps/dashboard/src/tabs/memory-tab.js.br +0 -0
  103. package/apps/dashboard/src/tabs/models-tab.js +441 -0
  104. package/apps/dashboard/src/tabs/models-tab.js.br +0 -0
  105. package/apps/dashboard/src/tabs/pm-loop-tab.js +185 -0
  106. package/apps/dashboard/src/tabs/pm-loop-tab.js.br +0 -0
  107. package/apps/dashboard/src/tabs/projects-tab.js +663 -0
  108. package/apps/dashboard/src/tabs/projects-tab.js.br +0 -0
  109. package/apps/dashboard/src/tabs/projects-tab.js.gz +0 -0
  110. package/apps/dashboard/src/tabs/prompts-tab.js +160 -0
  111. package/apps/dashboard/src/tabs/prompts-tab.js.br +0 -0
  112. package/apps/dashboard/src/tabs/services-tab.js +202 -0
  113. package/apps/dashboard/src/tabs/services-tab.js.br +0 -0
  114. package/apps/dashboard/src/tabs/settings-tab.js +803 -0
  115. package/apps/dashboard/src/tabs/settings-tab.js.br +0 -0
  116. package/apps/dashboard/src/tabs/skills-tab.js +284 -0
  117. package/apps/dashboard/src/tabs/skills-tab.js.br +0 -0
  118. package/apps/dashboard/src/tabs/spending-tab.js +173 -0
  119. package/apps/dashboard/src/tabs/spending-tab.js.br +0 -0
  120. package/apps/dashboard/src/tabs/swarm-chat-tab.js +660 -0
  121. package/apps/dashboard/src/tabs/swarm-chat-tab.js.br +0 -0
  122. package/apps/dashboard/src/tabs/swarm-tab.js +538 -0
  123. package/apps/dashboard/src/tabs/swarm-tab.js.br +0 -0
  124. package/apps/dashboard/src/tabs/usage-tab.js +390 -0
  125. package/apps/dashboard/src/tabs/usage-tab.js.br +0 -0
  126. package/apps/dashboard/src/tabs/waves-tab.js +238 -0
  127. package/apps/dashboard/src/tabs/waves-tab.js.br +0 -0
  128. package/apps/dashboard/src/tabs/workflows-tab.js +747 -0
  129. package/apps/dashboard/src/tabs/workflows-tab.js.br +0 -0
  130. package/apps/vibe/.crew/agent-memory/pipeline.json +249 -0
  131. package/apps/vibe/.crew/cost.json +17 -0
  132. package/apps/vibe/.crew/json-parse-metrics.jsonl +22 -0
  133. package/apps/vibe/.crew/pipeline-metrics.jsonl +22 -0
  134. package/apps/vibe/.crew/pipeline-runs/pipeline-0f90c392-2425-4ae5-850c-bd9d17b1d690.jsonl +5 -0
  135. package/apps/vibe/.crew/pipeline-runs/pipeline-1c269dd9-a63f-4fba-af81-5cf08048ef06.jsonl +5 -0
  136. package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +1 -0
  137. package/apps/vibe/.crew/pipeline-runs/pipeline-2c78fd22-a657-4bd1-bc49-0679fb384409.jsonl +5 -0
  138. package/apps/vibe/.crew/pipeline-runs/pipeline-3e6fe08d-3264-404a-8df3-aab7efef10e7.jsonl +5 -0
  139. package/apps/vibe/.crew/pipeline-runs/pipeline-42eec610-57fe-4e09-9e7e-b315038495c2.jsonl +5 -0
  140. package/apps/vibe/.crew/pipeline-runs/pipeline-4438eb4c-ae13-42b1-90e2-b043d8983be8.jsonl +5 -0
  141. package/apps/vibe/.crew/pipeline-runs/pipeline-4740a9f5-86e7-44b6-a394-de433e291727.jsonl +5 -0
  142. package/apps/vibe/.crew/pipeline-runs/pipeline-49e1da6a-957e-48fd-9220-415019e4f8e2.jsonl +5 -0
  143. package/apps/vibe/.crew/pipeline-runs/pipeline-4c9251db-be68-427b-a3fc-a264f2b5778d.jsonl +5 -0
  144. package/apps/vibe/.crew/pipeline-runs/pipeline-65e29a57-664d-4196-8109-017e364f182e.jsonl +5 -0
  145. package/apps/vibe/.crew/pipeline-runs/pipeline-6aa04bc5-9593-4b1f-b58d-3bf2978cb602.jsonl +5 -0
  146. package/apps/vibe/.crew/pipeline-runs/pipeline-6e1cba53-9b70-457e-99e0-59199149dd21.jsonl +5 -0
  147. package/apps/vibe/.crew/pipeline-runs/pipeline-749f41cc-4dac-4204-be64-873a6080a0d2.jsonl +5 -0
  148. package/apps/vibe/.crew/pipeline-runs/pipeline-74d68121-e181-4864-bd9a-c3211341dfaf.jsonl +5 -0
  149. package/apps/vibe/.crew/pipeline-runs/pipeline-8509bc24-142d-4e07-b44a-a50bf99d1103.jsonl +5 -0
  150. package/apps/vibe/.crew/pipeline-runs/pipeline-960339c6-07ca-43ce-9900-f6e1702b39b9.jsonl +5 -0
  151. package/apps/vibe/.crew/pipeline-runs/pipeline-9c6480a9-7031-4146-b241-825b9a2d1de1.jsonl +5 -0
  152. package/apps/vibe/.crew/pipeline-runs/pipeline-9fd42426-8492-4157-9d5f-e1537c060489.jsonl +2 -0
  153. package/apps/vibe/.crew/pipeline-runs/pipeline-ad6d40a3-2f5e-46a9-a345-47caaccc51aa.jsonl +5 -0
  154. package/apps/vibe/.crew/pipeline-runs/pipeline-bc606133-8d5b-4535-8d85-f1a29cdaa981.jsonl +5 -0
  155. package/apps/vibe/.crew/pipeline-runs/pipeline-c1a13ccd-634a-4d01-a4a7-1177b8a752ff.jsonl +5 -0
  156. package/apps/vibe/.crew/pipeline-runs/pipeline-c7d27b42-249e-4bd4-8f26-6aa998110b8a.jsonl +5 -0
  157. package/apps/vibe/.crew/pipeline-runs/pipeline-cca2e9b9-4a34-4d25-a311-5c793fa7e91e.jsonl +5 -0
  158. package/apps/vibe/.crew/sandbox.json +7 -0
  159. package/apps/vibe/.crew/session.json +285 -0
  160. package/apps/vibe/.crew/training-data.jsonl +0 -0
  161. package/apps/vibe/.github/workflows/studio-quality.yml +37 -0
  162. package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +12 -0
  163. package/apps/vibe/.studio-data/project-messages/general.jsonl +54 -0
  164. package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +10 -0
  165. package/apps/vibe/ARCHITECTURE.md +3393 -0
  166. package/apps/vibe/QUICK-REFERENCE.md +211 -0
  167. package/apps/vibe/README.md +76 -0
  168. package/apps/vibe/ROADMAP.md +41 -0
  169. package/apps/vibe/STUDIO-SETUP-COMPLETE.md +35 -0
  170. package/apps/vibe/VISUAL-GUIDE.md +378 -0
  171. package/apps/vibe/capture-demo.mjs +160 -0
  172. package/apps/vibe/capture-vibe-assets.mjs +71 -0
  173. package/apps/vibe/capture-vibe-video.mjs +260 -0
  174. package/apps/vibe/check-buttons.js +41 -0
  175. package/apps/vibe/diagnose.html +106 -0
  176. package/apps/vibe/fix-buttons.js +103 -0
  177. package/apps/vibe/index.html +3401 -0
  178. package/apps/vibe/package-lock.json +920 -0
  179. package/apps/vibe/package.json +31 -0
  180. package/apps/vibe/public/favicon.png +0 -0
  181. package/apps/vibe/scripts/studio-pty-host.py +117 -0
  182. package/apps/vibe/server.mjs +1835 -0
  183. package/apps/vibe/src/main.js +2846 -0
  184. package/apps/vibe/src/register-all-languages.js +98 -0
  185. package/apps/vibe/start-studio.sh +11 -0
  186. package/apps/vibe/test/accessibility-tests.js +77 -0
  187. package/apps/vibe/test/browser-performance-audit.mjs +205 -0
  188. package/apps/vibe/test/performance-tests.js +120 -0
  189. package/apps/vibe/test/security-tests.js +213 -0
  190. package/apps/vibe/tests/e2e.local.mjs +54 -0
  191. package/apps/vibe/tests/server.smoke.mjs +106 -0
  192. package/apps/vibe/update_website.mjs +74 -0
  193. package/apps/vibe/vite.config.js +19 -0
  194. package/apps/vibe/watch-server.mjs +108 -0
  195. package/contrib/openclaw-plugin/README.md +199 -0
  196. package/contrib/openclaw-plugin/index.ts +306 -0
  197. package/contrib/openclaw-plugin/openclaw.plugin.json +41 -0
  198. package/contrib/openclaw-plugin/package.json +27 -0
  199. package/contrib/openclaw-plugin/skills/crewswarm/SKILL.md +88 -0
  200. package/crew-lead.mjs +649 -0
  201. package/engines/claude-code.json +36 -0
  202. package/engines/codex.json +37 -0
  203. package/engines/crew-cli.json +42 -0
  204. package/engines/cursor.json +40 -0
  205. package/engines/docker-sandbox.json +38 -0
  206. package/engines/gemini-cli.json +75 -0
  207. package/engines/opencode.json +31 -0
  208. package/gateway-bridge.mjs +1575 -0
  209. package/install.sh +738 -0
  210. package/lib/agent-registry.mjs +232 -0
  211. package/lib/agents/daemon.mjs +121 -0
  212. package/lib/agents/dispatch.mjs +225 -0
  213. package/lib/agents/permissions.mjs +90 -0
  214. package/lib/agents/platform-formatting.mjs +102 -0
  215. package/lib/agents/registry.mjs +81 -0
  216. package/lib/agents/tool-instructions.mjs +257 -0
  217. package/lib/agents/validation.mjs +75 -0
  218. package/lib/approval/policy-manager.mjs +221 -0
  219. package/lib/autoharness/index.mjs +391 -0
  220. package/lib/bridges/cli-executor.mjs +332 -0
  221. package/lib/bridges/gateway-ws.mjs +345 -0
  222. package/lib/bridges/integration.mjs +229 -0
  223. package/lib/bridges/rag-helper.mjs +90 -0
  224. package/lib/browser/opencode-passthrough-filter.js +44 -0
  225. package/lib/browser/passthrough-stderr.js +109 -0
  226. package/lib/chat/autonomous-mentions.mjs +373 -0
  227. package/lib/chat/history.mjs +82 -0
  228. package/lib/chat/mention-routing-intent.mjs +136 -0
  229. package/lib/chat/participants.mjs +95 -0
  230. package/lib/chat/project-messages-rag.mjs +265 -0
  231. package/lib/chat/project-messages.mjs +479 -0
  232. package/lib/chat/shared-chat-prompt-overlay.mjs +52 -0
  233. package/lib/chat/thread-binding.mjs +34 -0
  234. package/lib/chat/unified-history.mjs +223 -0
  235. package/lib/chat/unified-wrapper.mjs +41 -0
  236. package/lib/cli-process-tracker.mjs +228 -0
  237. package/lib/collections/index.mjs +433 -0
  238. package/lib/contacts/identity-linker.mjs +248 -0
  239. package/lib/contacts/index.mjs +341 -0
  240. package/lib/crew-judge/PROMPT.md +93 -0
  241. package/lib/crew-judge/judge.mjs +260 -0
  242. package/lib/crew-lead/agent-manager.mjs +125 -0
  243. package/lib/crew-lead/background.mjs +270 -0
  244. package/lib/crew-lead/brain.mjs +110 -0
  245. package/lib/crew-lead/chat-handler.mjs +2603 -0
  246. package/lib/crew-lead/chat-handler.mjs.bak +1274 -0
  247. package/lib/crew-lead/classifier.mjs +83 -0
  248. package/lib/crew-lead/http-server.mjs +4824 -0
  249. package/lib/crew-lead/intent.mjs +102 -0
  250. package/lib/crew-lead/interval-manager.mjs +41 -0
  251. package/lib/crew-lead/llm-caller.mjs +544 -0
  252. package/lib/crew-lead/prompts.mjs +392 -0
  253. package/lib/crew-lead/retry-manager.mjs +118 -0
  254. package/lib/crew-lead/tools.mjs +318 -0
  255. package/lib/crew-lead/wave-dispatcher.mjs +798 -0
  256. package/lib/crew-lead/waves-config.json +73 -0
  257. package/lib/crew-lead/waves-loader.mjs +110 -0
  258. package/lib/crew-lead/ws-router.mjs +428 -0
  259. package/lib/dispatch/parsers.mjs +299 -0
  260. package/lib/domain-planning/detector.mjs +196 -0
  261. package/lib/domain-planning/prompts/crew-pm-cli.md +96 -0
  262. package/lib/domain-planning/prompts/crew-pm-core.md +122 -0
  263. package/lib/domain-planning/prompts/crew-pm-frontend.md +111 -0
  264. package/lib/engines/crew-cli-sandbox.mjs +422 -0
  265. package/lib/engines/crew-cli.mjs +155 -0
  266. package/lib/engines/cursor-launcher.mjs +110 -0
  267. package/lib/engines/engine-registry.mjs +253 -0
  268. package/lib/engines/llm-direct.mjs +184 -0
  269. package/lib/engines/opencode.mjs +256 -0
  270. package/lib/engines/ouroboros.mjs +114 -0
  271. package/lib/engines/rt-envelope.mjs +1643 -0
  272. package/lib/engines/rt-envelope.mjs.backup-current +870 -0
  273. package/lib/engines/runners.mjs +1367 -0
  274. package/lib/gemini-cli-passthrough-noise.mjs +37 -0
  275. package/lib/integrations/code-search.mjs +259 -0
  276. package/lib/integrations/greptile.mjs +148 -0
  277. package/lib/integrations/multimodal.mjs +313 -0
  278. package/lib/integrations/telegram-streaming.mjs +153 -0
  279. package/lib/integrations/tts.mjs +312 -0
  280. package/lib/integrations/twitter-links.mjs +294 -0
  281. package/lib/memory/shared-adapter.mjs +296 -0
  282. package/lib/pipeline/manager.mjs +539 -0
  283. package/lib/preferences/extractor.mjs +347 -0
  284. package/lib/project-dir.mjs +20 -0
  285. package/lib/runtime/config.mjs +388 -0
  286. package/lib/runtime/dlq.mjs +170 -0
  287. package/lib/runtime/log-rotation.mjs +82 -0
  288. package/lib/runtime/logger.mjs +58 -0
  289. package/lib/runtime/memory.mjs +421 -0
  290. package/lib/runtime/paths.mjs +76 -0
  291. package/lib/runtime/project-dir.mjs +127 -0
  292. package/lib/runtime/spending.mjs +204 -0
  293. package/lib/runtime/startup-guard.mjs +291 -0
  294. package/lib/runtime/task-lease.mjs +234 -0
  295. package/lib/runtime/telemetry-schema.mjs +208 -0
  296. package/lib/runtime/telemetry.mjs +101 -0
  297. package/lib/runtime/utils.mjs +64 -0
  298. package/lib/skills/index.mjs +265 -0
  299. package/lib/tools/browser.mjs +135 -0
  300. package/lib/tools/executor.mjs +913 -0
  301. package/lib/types.d.ts +57 -0
  302. package/package.json +106 -0
  303. package/pm-loop.mjs +1626 -0
  304. package/prompts/coder-back.md +27 -0
  305. package/prompts/coder-front.md +27 -0
  306. package/prompts/coder.md +28 -0
  307. package/prompts/copywriter.md +17 -0
  308. package/prompts/fixer.md +39 -0
  309. package/prompts/frontend.md +23 -0
  310. package/prompts/github.md +24 -0
  311. package/prompts/main.md +39 -0
  312. package/prompts/pm-cli.md +95 -0
  313. package/prompts/pm-core.md +121 -0
  314. package/prompts/pm-frontend.md +110 -0
  315. package/prompts/pm.md +234 -0
  316. package/prompts/qa.md +44 -0
  317. package/prompts/security.md +19 -0
  318. package/scripts/build-crew-chat.sh +28 -0
  319. package/scripts/build-llms-full.mjs +52 -0
  320. package/scripts/chatmock-login.sh +16 -0
  321. package/scripts/chatmock-serve.sh +16 -0
  322. package/scripts/check-dashboard.mjs +88 -0
  323. package/scripts/crew-scribe.mjs +326 -0
  324. package/scripts/dashboard-helpers.mjs +391 -0
  325. package/scripts/dashboard-validation.mjs +198 -0
  326. package/scripts/dashboard.mjs +9717 -0
  327. package/scripts/dlq-replay.mjs +61 -0
  328. package/scripts/doctor.mjs +196 -0
  329. package/scripts/file-lock.mjs +186 -0
  330. package/scripts/fresh-machine-smoke.sh +323 -0
  331. package/scripts/generate-changelog.mjs +227 -0
  332. package/scripts/generate-openapi.mjs +334 -0
  333. package/scripts/health-check.mjs +229 -0
  334. package/scripts/install-docker.sh +213 -0
  335. package/scripts/mcp-server.mjs +1625 -0
  336. package/scripts/opencrew-rt-daemon.mjs +568 -0
  337. package/scripts/openswitchctl +646 -0
  338. package/scripts/refactor-configs.mjs +39 -0
  339. package/scripts/release-check.sh +46 -0
  340. package/scripts/resolve-node-bin.sh +25 -0
  341. package/scripts/restart-all-from-repo.sh +329 -0
  342. package/scripts/restart-crew-lead.sh +98 -0
  343. package/scripts/restart-dashboard.sh +104 -0
  344. package/scripts/restart-service.sh +274 -0
  345. package/scripts/run-accessibility-audit.mjs +356 -0
  346. package/scripts/run-integration-bounded.mjs +188 -0
  347. package/scripts/run-scheduled-pipeline.mjs +230 -0
  348. package/scripts/run.mjs +41 -0
  349. package/scripts/scan-skills.mjs +79 -0
  350. package/scripts/setup-firewall.sh +128 -0
  351. package/scripts/smoke-dispatch.mjs +149 -0
  352. package/scripts/smoke.sh +163 -0
  353. package/scripts/start-crew.mjs +328 -0
  354. package/scripts/start.mjs +146 -0
  355. package/scripts/swiftbar-restart-service.sh +19 -0
  356. package/scripts/sync-agents.mjs +152 -0
  357. package/scripts/sync-prompts.mjs +79 -0
  358. package/scripts/validate-config.mjs +337 -0
  359. package/scripts/wow.mjs +89 -0
  360. package/telegram-bridge.mjs +2421 -0
  361. package/unified-orchestrator.mjs +519 -0
  362. package/whatsapp-bridge.mjs +1481 -0
@@ -0,0 +1,232 @@
1
+ // Shared crewswarm agent registry.
2
+ // Dynamically loads agents from ~/.crewswarm/crewswarm.json so new agents
3
+ // are automatically discovered without code changes.
4
+
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import os from "node:os";
8
+
9
+ // Minimal built-in fallback for core coordinator agents
10
+ // Plus agents used in tests (so tests pass on CI without config file)
11
+ const CORE_AGENTS = [
12
+ "crew-main",
13
+ "crew-pm",
14
+ "crew-pm-cli",
15
+ "crew-pm-frontend",
16
+ "crew-pm-core",
17
+ "crew-orchestrator",
18
+ "crew-lead",
19
+ "crew-judge",
20
+ // Test agents (needed for CI)
21
+ "crew-coder",
22
+ "crew-coder-back",
23
+ "crew-coder-front",
24
+ "crew-researcher",
25
+ "crew-qa",
26
+ "crew-copywriter",
27
+ "crew-fixer",
28
+ "crew-github",
29
+ "crew-frontend",
30
+ "crew-security",
31
+ ];
32
+
33
+ const CORE_MAP = {
34
+ "crew-main": "main",
35
+ "crew-pm": "pm",
36
+ "crew-pm-cli": "pm-cli",
37
+ "crew-pm-frontend": "pm-frontend",
38
+ "crew-pm-core": "pm-core",
39
+ "crew-orchestrator": "orchestrator",
40
+ "crew-lead": "lead",
41
+ "crew-judge": "judge",
42
+ // Test agents
43
+ "crew-coder": "coder",
44
+ "crew-coder-back": "coder-back",
45
+ "crew-coder-front": "coder-front",
46
+ "crew-researcher": "researcher",
47
+ "crew-qa": "qa",
48
+ "crew-copywriter": "copywriter",
49
+ "crew-fixer": "fixer",
50
+ "crew-github": "github",
51
+ "crew-frontend": "frontend",
52
+ "crew-security": "security",
53
+ };
54
+
55
+ /**
56
+ * Build agent registry dynamically from config files.
57
+ * Reads ~/.crewswarm/crewswarm.json and discovers all configured agents.
58
+ */
59
+ function buildAgentRegistry() {
60
+ const map = { ...CORE_MAP };
61
+ const listSet = new Set(CORE_AGENTS);
62
+
63
+ const cfgPaths = [
64
+ path.join(os.homedir(), ".crewswarm", "crewswarm.json"),
65
+ path.join(os.homedir(), ".openclaw", "openclaw.json"),
66
+ ];
67
+
68
+ for (const cfgPath of cfgPaths) {
69
+ try {
70
+ const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
71
+ const agents = Array.isArray(cfg.agents) ? cfg.agents
72
+ : Array.isArray(cfg.agents?.list) ? cfg.agents.list
73
+ : [];
74
+
75
+ for (const agent of agents) {
76
+ const rawId = String(agent.id || "").trim();
77
+ if (!rawId) continue;
78
+
79
+ // Normalize to RT format (crew-xxx)
80
+ const bareId = rawId.replace(/^crew-/, "");
81
+ const rtId = rawId.startsWith("crew-") ? rawId : `crew-${bareId}`;
82
+
83
+ // Always keep canonical RT IDs in the exported list
84
+ if (!map[rtId]) {
85
+ map[rtId] = bareId;
86
+ listSet.add(rtId);
87
+ }
88
+ // Support bare alias lookup (e.g. "orchestrator", "security")
89
+ // without adding duplicate non-RT IDs to BUILT_IN_RT_AGENTS.
90
+ if (rawId === bareId && !map[bareId]) {
91
+ map[bareId] = bareId;
92
+ }
93
+ }
94
+ } catch (err) {
95
+ // Config file not found or invalid JSON — use core agents only
96
+ if (process.env.DEBUG) {
97
+ console.warn(`[agent-registry] Could not load ${cfgPath}: ${err.message}`);
98
+ }
99
+ }
100
+ }
101
+
102
+ return { list: [...listSet].sort(), map };
103
+ }
104
+
105
+ // Build registry on module load
106
+ const { list, map } = buildAgentRegistry();
107
+
108
+ export const BUILT_IN_RT_AGENTS = list;
109
+ export const RT_TO_GATEWAY_AGENT_MAP = map;
110
+
111
+ // Core agents that MUST exist - system breaks if missing
112
+ export const REQUIRED_AGENTS = new Set([
113
+ "crew-lead", // Fatal: no chat handler, no dispatch
114
+ "crew-main", // Fatal: no synthesis, no fallback coordinator
115
+ "crew-pm", // Fatal: PM-loop breaks, no roadmap processing
116
+ "crew-orchestrator", // Fatal: pipeline dispatch fails
117
+ "crew-coder", // Fatal: PM-loop's default worker
118
+ "crew-judge" // Fatal: PM-loop judge decisions fail (if PM_USE_JUDGE=on)
119
+ ]);
120
+
121
+ // Coordinator agents that can dispatch to other agents
122
+ export const COORDINATOR_AGENT_IDS = [
123
+ "crew-main",
124
+ "crew-pm",
125
+ "crew-pm-cli",
126
+ "crew-pm-frontend",
127
+ "crew-pm-core",
128
+ "crew-orchestrator"
129
+ ];
130
+
131
+ // Backward-compatible alias for a misspelled import introduced by recent edits.
132
+ export const coordinate_aget_ids = COORDINATOR_AGENT_IDS;
133
+
134
+ /**
135
+ * Agents whose tasks assume the configured engine runs (read_file / write_file / git / CLI).
136
+ * If Codex/Cursor/OpenCode fails, we must NOT silently fall back to direct LLM — the user would
137
+ * get prose with no qa-report.md, no audits, etc.
138
+ */
139
+ export const AGENTS_NO_ENGINE_LLM_FALLBACK = new Set([
140
+ "crew-coder",
141
+ "crew-coder-back",
142
+ "crew-coder-front",
143
+ "crew-frontend",
144
+ "crew-fixer",
145
+ "crew-architect",
146
+ "crew-qa",
147
+ "crew-security",
148
+ "crew-github",
149
+ "crew-copywriter",
150
+ "crew-researcher",
151
+ "crew-seo",
152
+ "crew-ml",
153
+ "crew-mega",
154
+ "crew-pm",
155
+ "crew-pm-cli",
156
+ "crew-pm-frontend",
157
+ "crew-pm-core",
158
+ "crew-orchestrator",
159
+ ]);
160
+
161
+ /**
162
+ * True when engine failure should surface an error instead of LLM-only fallback (rt-envelope).
163
+ * @param {string} agentId
164
+ * @returns {boolean}
165
+ */
166
+ export function agentMustNotUseEngineLlmFallback(agentId = "") {
167
+ const id = normalizeRtAgentId(String(agentId || "").trim());
168
+ if (!id) return false;
169
+ if (AGENTS_NO_ENGINE_LLM_FALLBACK.has(id)) return true;
170
+ // Dynamic coding-style workers
171
+ if (/^crew-[\w-]*(coder|fixer)(-|$)/i.test(id)) return true;
172
+ if (/^crew-[\w-]*frontend(-|$)/i.test(id)) return true;
173
+ return false;
174
+ }
175
+
176
+ /**
177
+ * Check if an agent ID is a coordinator (can dispatch to other agents)
178
+ * Handles both RT format (crew-xxx) and bare aliases (xxx)
179
+ * @param {string} agentId - Agent ID to check
180
+ * @returns {boolean} True if agent is a coordinator
181
+ */
182
+ export function isCoordinator(agentId = "") {
183
+ const id = String(agentId || "").trim();
184
+ if (!id) return false;
185
+
186
+ // Check RT format directly
187
+ if (COORDINATOR_AGENT_IDS.includes(id)) return true;
188
+
189
+ // Check bare alias by normalizing to RT format
190
+ const rtId = normalizeRtAgentId(id);
191
+ return COORDINATOR_AGENT_IDS.includes(rtId);
192
+ }
193
+
194
+ /**
195
+ * Validate that all required agents exist in config
196
+ * @param {Array} agents - Agent list from config
197
+ * @returns {Object} { valid: boolean, missing: string[] }
198
+ */
199
+ export function validateRequiredAgents(agents = []) {
200
+ const agentIds = new Set(
201
+ agents
202
+ .map((a) => normalizeRtAgentId(a?.id))
203
+ .filter(Boolean)
204
+ );
205
+ const missing = [];
206
+
207
+ for (const required of REQUIRED_AGENTS) {
208
+ if (!agentIds.has(required)) {
209
+ missing.push(required);
210
+ }
211
+ }
212
+
213
+ return {
214
+ valid: missing.length === 0,
215
+ missing
216
+ };
217
+ }
218
+
219
+ // Agents that don't get "crew-" prefix normalization
220
+ export const NO_PREFIX_AGENT_IDS = new Set(["security"]);
221
+
222
+ /**
223
+ * Normalize agent ID to RT format (crew-xxx).
224
+ * @param {string} agentId - Raw agent ID
225
+ * @returns {string} Normalized RT agent ID
226
+ */
227
+ export function normalizeRtAgentId(agentId = "") {
228
+ const id = String(agentId || "").trim();
229
+ if (!id) return "";
230
+ if (id.startsWith("crew-") || NO_PREFIX_AGENT_IDS.has(id)) return id;
231
+ return `crew-${id}`;
232
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Agent daemon utilities — spawn, PID, heartbeat, resolve spawn targets.
3
+ * Extracted from gateway-bridge.mjs.
4
+ * Dependencies: fs, path, os, spawn from child_process
5
+ */
6
+
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { spawn } from "node:child_process";
10
+ import {
11
+ SWARM_RUNTIME_DIR,
12
+ SWARM_STATUS_LOG,
13
+ CREWSWARM_RT_CHANNELS,
14
+ CREWSWARM_REPO_ROOT,
15
+ } from "../runtime/config.mjs";
16
+ import { CREWSWARM_RT_SWARM_AGENTS } from "./registry.mjs";
17
+
18
+ function agentRuntimeDir() {
19
+ const dir = path.join(SWARM_RUNTIME_DIR, "rt-agents");
20
+ fs.mkdirSync(dir, { recursive: true });
21
+ return dir;
22
+ }
23
+
24
+ export function agentPidPath(agent) {
25
+ return path.join(agentRuntimeDir(), `${agent}.pid`);
26
+ }
27
+
28
+ export function agentLogPath(agent) {
29
+ return path.join(agentRuntimeDir(), `${agent}.log`);
30
+ }
31
+
32
+ export function readPid(agent) {
33
+ try {
34
+ return Number(fs.readFileSync(agentPidPath(agent), "utf8").trim());
35
+ } catch {
36
+ return 0;
37
+ }
38
+ }
39
+
40
+ export function isPidAlive(pid) {
41
+ if (!pid || Number.isNaN(pid)) return false;
42
+ try {
43
+ process.kill(pid, 0);
44
+ return true;
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ export function latestHeartbeatAgeSec(agent) {
51
+ try {
52
+ if (!fs.existsSync(SWARM_STATUS_LOG)) return null;
53
+ const lines = fs.readFileSync(SWARM_STATUS_LOG, "utf8").split("\n");
54
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
55
+ const line = lines[i].trim();
56
+ if (!line) continue;
57
+ let row;
58
+ try { row = JSON.parse(line); } catch { continue; }
59
+ if (row?.type !== "agent.heartbeat") continue;
60
+ const hbAgent = row?.payload?.agent || row?.from;
61
+ if (hbAgent !== agent) continue;
62
+ const ts = Date.parse(row?.ts || "");
63
+ if (!Number.isFinite(ts)) return null;
64
+ return (Date.now() - ts) / 1000;
65
+ }
66
+ return null;
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ export function isAgentDaemonRunning(agent) {
73
+ const SWARM_HEARTBEAT_WINDOW_SEC = Number(process.env.CREWSWARM_RT_HEARTBEAT_WINDOW_SEC || "90");
74
+ const heartbeatAge = latestHeartbeatAgeSec(agent);
75
+ if (heartbeatAge !== null && heartbeatAge <= SWARM_HEARTBEAT_WINDOW_SEC) return true;
76
+ const pid = readPid(agent);
77
+ if (isPidAlive(pid)) return true;
78
+ return false;
79
+ }
80
+
81
+ export function spawnAgentDaemon(agent) {
82
+ if (isAgentDaemonRunning(agent)) {
83
+ return { agent, status: "already_running" };
84
+ }
85
+ const logFile = agentLogPath(agent);
86
+ const out = fs.openSync(logFile, "a");
87
+ const child = spawn(
88
+ process.execPath,
89
+ [path.join(CREWSWARM_REPO_ROOT, "gateway-bridge.mjs"), "--rt-daemon"],
90
+ {
91
+ cwd: CREWSWARM_REPO_ROOT,
92
+ detached: true,
93
+ stdio: ["ignore", out, out],
94
+ env: {
95
+ ...process.env,
96
+ CREWSWARM_RT_AGENT: agent,
97
+ CREWSWARM_RT_CHANNELS,
98
+ },
99
+ },
100
+ );
101
+ child.unref();
102
+ fs.writeFileSync(agentPidPath(agent), `${child.pid}`);
103
+ return { agent, status: "started", pid: child.pid, logFile };
104
+ }
105
+
106
+ export function resolveSpawnTargets(payload) {
107
+ const all = [...new Set(CREWSWARM_RT_SWARM_AGENTS)];
108
+ if (Array.isArray(payload?.agents)) {
109
+ const agents = payload.agents.map((a) => String(a).trim()).filter(Boolean);
110
+ return agents.length ? agents : all;
111
+ }
112
+ if (typeof payload?.agent === "string" && payload.agent.trim()) {
113
+ if (payload.agent.trim().toLowerCase() === "all") return all;
114
+ return [payload.agent.trim()];
115
+ }
116
+ if (typeof payload?.target === "string" && payload.target.trim()) {
117
+ if (payload.target.trim().toLowerCase() === "all") return all;
118
+ return [payload.target.trim()];
119
+ }
120
+ return all;
121
+ }
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Dispatch guard, task lease, and task helpers — extracted from gateway-bridge.mjs.
3
+ * File-based lease and done records for dispatch deduplication.
4
+ * Dependencies: fs, path, crypto
5
+ */
6
+
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import crypto from "node:crypto";
10
+ import {
11
+ SWARM_DISPATCH_DIR,
12
+ CREWSWARM_RT_AGENT,
13
+ CREWSWARM_RT_TASK_STATE_TTL_MS,
14
+ CREWSWARM_RT_DISPATCH_ENABLED,
15
+ } from "../runtime/config.mjs";
16
+
17
+ function transientError(err) {
18
+ const msg = String(err?.message ?? err ?? "").toLowerCase();
19
+ return ["timeout", "timed out", "econnrefused", "ehostunreach", "econnreset", "socket hang up", "websocket is not open", "connection closed", "broken pipe"].some((s) => msg.includes(s));
20
+ }
21
+
22
+ function ensureDispatchDir() {
23
+ fs.mkdirSync(SWARM_DISPATCH_DIR, { recursive: true });
24
+ return SWARM_DISPATCH_DIR;
25
+ }
26
+
27
+ function safeReadJson(filePath) {
28
+ try {
29
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+
35
+ function isoNow() {
36
+ return new Date().toISOString();
37
+ }
38
+
39
+ export function dispatchKeyForTask({ taskId, incomingType, prompt, idempotencyKey }) {
40
+ const stableTaskId = String(taskId || "").trim();
41
+ if (stableTaskId) return `task-${stableTaskId}`;
42
+ const stableIdempotency = String(idempotencyKey || "").trim();
43
+ if (stableIdempotency) return `idem-${stableIdempotency}`;
44
+ const hash = crypto.createHash("sha256")
45
+ .update(`${incomingType || "event"}\n${prompt || ""}`, "utf8")
46
+ .digest("hex")
47
+ .slice(0, 24);
48
+ return `hash-${hash}`;
49
+ }
50
+
51
+ export function leasePathForKey(key) {
52
+ return path.join(ensureDispatchDir(), `${key}.lease`);
53
+ }
54
+
55
+ export function donePathForKey(key) {
56
+ return path.join(ensureDispatchDir(), `${key}.done.json`);
57
+ }
58
+
59
+ export function readTaskDoneRecord(key) {
60
+ return safeReadJson(donePathForKey(key));
61
+ }
62
+
63
+ export function isDoneRecordFresh(record) {
64
+ if (!record?.doneAt) return false;
65
+ const doneAtMs = Date.parse(record.doneAt);
66
+ if (!Number.isFinite(doneAtMs)) return false;
67
+ return (Date.now() - doneAtMs) <= CREWSWARM_RT_TASK_STATE_TTL_MS;
68
+ }
69
+
70
+ export function readLeaseRecord(leaseDir) {
71
+ return safeReadJson(path.join(leaseDir, "lease.json"));
72
+ }
73
+
74
+ export function writeLeaseRecord(leaseDir, leaseRecord) {
75
+ fs.writeFileSync(path.join(leaseDir, "lease.json"), JSON.stringify(leaseRecord, null, 2));
76
+ }
77
+
78
+ export function acquireTaskLease({ key, source, incomingType, from, leaseMs }) {
79
+ const leaseDir = leasePathForKey(key);
80
+ const donePath = donePathForKey(key);
81
+ const doneRecord = readTaskDoneRecord(key);
82
+ if (doneRecord) {
83
+ if (isDoneRecordFresh(doneRecord)) {
84
+ return { acquired: false, reason: "already_done", doneRecord };
85
+ }
86
+ try {
87
+ fs.rmSync(donePath, { force: true });
88
+ } catch {}
89
+ }
90
+
91
+ const now = Date.now();
92
+ const claimId = `${CREWSWARM_RT_AGENT}-${process.pid}-${crypto.randomUUID()}`;
93
+ const leaseRecord = {
94
+ key,
95
+ claimId,
96
+ agent: CREWSWARM_RT_AGENT,
97
+ source,
98
+ from,
99
+ incomingType,
100
+ leaseMs,
101
+ leasedAt: isoNow(),
102
+ leaseExpiresAt: new Date(now + leaseMs).toISOString(),
103
+ updatedAt: isoNow(),
104
+ };
105
+
106
+ const writeNewLease = () => {
107
+ fs.mkdirSync(leaseDir);
108
+ writeLeaseRecord(leaseDir, leaseRecord);
109
+ return { acquired: true, claimId, leaseDir };
110
+ };
111
+
112
+ try {
113
+ return writeNewLease();
114
+ } catch (err) {
115
+ if (err?.code !== "EEXIST") throw err;
116
+ }
117
+
118
+ const existing = readLeaseRecord(leaseDir);
119
+ const existingExpiry = Date.parse(existing?.leaseExpiresAt || "");
120
+ if (Number.isFinite(existingExpiry) && existingExpiry > now) {
121
+ return {
122
+ acquired: false,
123
+ reason: "claimed",
124
+ claimedBy: existing?.agent || "unknown",
125
+ leaseExpiresAt: existing?.leaseExpiresAt || null,
126
+ };
127
+ }
128
+
129
+ try {
130
+ fs.rmSync(leaseDir, { recursive: true, force: true });
131
+ return writeNewLease();
132
+ } catch {
133
+ return {
134
+ acquired: false,
135
+ reason: "claimed",
136
+ claimedBy: existing?.agent || "unknown",
137
+ leaseExpiresAt: existing?.leaseExpiresAt || null,
138
+ };
139
+ }
140
+ }
141
+
142
+ export function renewTaskLease({ key, claimId, leaseMs }) {
143
+ const leaseDir = leasePathForKey(key);
144
+ const current = readLeaseRecord(leaseDir);
145
+ if (!current || current.claimId !== claimId || current.agent !== CREWSWARM_RT_AGENT) return false;
146
+ const now = Date.now();
147
+ current.updatedAt = isoNow();
148
+ current.leaseMs = leaseMs;
149
+ current.leaseExpiresAt = new Date(now + leaseMs).toISOString();
150
+ writeLeaseRecord(leaseDir, current);
151
+ return true;
152
+ }
153
+
154
+ export function releaseTaskLease({ key, claimId }) {
155
+ const leaseDir = leasePathForKey(key);
156
+ try {
157
+ const current = readLeaseRecord(leaseDir);
158
+ if (!current || current.claimId !== claimId || current.agent !== CREWSWARM_RT_AGENT) return false;
159
+ fs.rmSync(leaseDir, { recursive: true, force: true });
160
+ return true;
161
+ } catch {
162
+ return false;
163
+ }
164
+ }
165
+
166
+ export function markTaskDone({ key, claimId, taskId, incomingType, from, attempt, idempotencyKey, reply }) {
167
+ const donePath = donePathForKey(key);
168
+ const replyText = String(reply || "");
169
+ const doneRecord = {
170
+ key,
171
+ taskId,
172
+ incomingType,
173
+ from,
174
+ claimId,
175
+ idempotencyKey,
176
+ agent: CREWSWARM_RT_AGENT,
177
+ attempt,
178
+ reply: replyText.slice(0, 24000),
179
+ replyHash: crypto.createHash("sha256").update(replyText, "utf8").digest("hex"),
180
+ doneAt: isoNow(),
181
+ };
182
+ fs.writeFileSync(donePath, JSON.stringify(doneRecord, null, 2));
183
+ }
184
+
185
+ export function shouldUseDispatchGuard(incomingType) {
186
+ if (!CREWSWARM_RT_DISPATCH_ENABLED) return false;
187
+ return incomingType === "command.run_task" || incomingType === "task.assigned" || incomingType === "task.reassigned";
188
+ }
189
+
190
+ export function shouldRetryTaskFailure(err) {
191
+ const msg = String(err?.message ?? err ?? "");
192
+ if (!msg) return false;
193
+ if (msg.includes("MEMORY_PROTOCOL_MISSING") || msg.includes("MEMORY_LOAD_FAILED")) return false;
194
+ if (msg.includes("CODING_ARTIFACT_MISSING")) return true;
195
+ return transientError(err) || msg.toLowerCase().includes("timeout");
196
+ }
197
+
198
+ export function isCodingTask(incomingType, prompt, payload) {
199
+ if (!incomingType) return false;
200
+ const codingTypes = ["command.run_task", "task.assigned", "task.reassigned"];
201
+ if (!codingTypes.includes(incomingType)) return false;
202
+
203
+ const action = String(payload?.action || "").toLowerCase();
204
+ if (action === "collect_status" || action === "status" || action === "heartbeat") return false;
205
+
206
+ const text = String(prompt || "").toLowerCase();
207
+ if (text.includes("report status") || text.includes("reply with agent id")) return false;
208
+ if (text.includes("busy/idle") || text.includes("active task")) return false;
209
+
210
+ const codingKeywords = [
211
+ "implement", "build", "create", "fix", "refactor", "add", "update", "modify",
212
+ "code", "function", "class", "component", "api", "endpoint", "route", "test",
213
+ "bug", "error", "issue", "file", "script", "module", "package"
214
+ ];
215
+ return codingKeywords.some(kw => text.includes(kw));
216
+ }
217
+
218
+ export function looksLikeCodingTask(prompt = "") {
219
+ const p = String(prompt).toLowerCase();
220
+ return [
221
+ "implement", "write code", "refactor", "fix bug", "unit test", "integration test",
222
+ "build", "compile", "typescript", "javascript", "python", "go ", "rust",
223
+ "repo", "pull request", "pr ", "commit", "lint", "migrate",
224
+ ].some((kw) => p.includes(kw));
225
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Agent tool permission helpers — extracted from crew-lead.mjs
3
+ * Reads/writes per-agent tool permissions from crewswarm.json.
4
+ */
5
+
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import os from "os";
9
+ import { applySharedChatPromptOverlay } from "../chat/shared-chat-prompt-overlay.mjs";
10
+
11
+ function tryRead(p) {
12
+ try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch { return null; }
13
+ }
14
+
15
+ export const CREWSWARM_TOOL_NAMES = new Set([
16
+ "write_file","read_file","mkdir","run_cmd","git","dispatch","telegram","web_search","web_fetch","skill","define_skill","browser",
17
+ ]);
18
+
19
+ export const AGENT_TOOL_ROLE_DEFAULTS = {
20
+ "crew-qa": ["read_file"],
21
+ "crew-security": ["read_file","run_cmd"],
22
+ "crew-coder": ["write_file","read_file","mkdir","run_cmd","browser"],
23
+ "crew-coder-front": ["write_file","read_file","mkdir","run_cmd","browser"],
24
+ "crew-coder-back": ["write_file","read_file","mkdir","run_cmd","browser"],
25
+ "crew-frontend": ["write_file","read_file","mkdir","run_cmd"],
26
+ "crew-fixer": ["write_file","read_file","mkdir","run_cmd","browser"],
27
+ "crew-github": ["read_file","run_cmd","git"],
28
+ "crew-copywriter": ["write_file","read_file","web_search","web_fetch"],
29
+ "crew-main": ["write_file","read_file","mkdir","run_cmd","dispatch","web_search","web_fetch"],
30
+ "crew-pm": ["read_file","dispatch"],
31
+ "crew-telegram": ["telegram","read_file"],
32
+ };
33
+
34
+ export function readAgentTools(agentId) {
35
+ const swarm = tryRead(path.join(os.homedir(), ".crewswarm", "crewswarm.json")) || {};
36
+ const agents = Array.isArray(swarm.agents) ? swarm.agents : [];
37
+ const agent = agents.find(a => a.id === agentId);
38
+ const exact = AGENT_TOOL_ROLE_DEFAULTS[agentId];
39
+ const roleDefaults = exact || Object.entries(AGENT_TOOL_ROLE_DEFAULTS).find(([key]) => agentId.startsWith(key))?.[1] || [];
40
+ const explicit = agent?.tools?.crewswarmAllow || agent?.tools?.alsoAllow || null;
41
+ if (explicit) {
42
+ const valid = explicit.filter(t => CREWSWARM_TOOL_NAMES.has(t));
43
+ if (valid.length) return { source: "config", tools: [...new Set([...roleDefaults, ...valid])] };
44
+ }
45
+ if (roleDefaults.length) return { source: "role-default", tools: roleDefaults };
46
+ return { source: "fallback", tools: ["read_file","write_file","mkdir","run_cmd"] };
47
+ }
48
+
49
+ export function writeAgentTools(agentId, tools) {
50
+ const valid = tools.filter(t => CREWSWARM_TOOL_NAMES.has(t));
51
+ const swarmPath = path.join(os.homedir(), ".crewswarm", "crewswarm.json");
52
+ const swarm = tryRead(swarmPath) || {};
53
+ if (!Array.isArray(swarm.agents)) swarm.agents = [];
54
+ let agent = swarm.agents.find(a => a.id === agentId);
55
+ if (!agent) {
56
+ agent = { id: agentId };
57
+ swarm.agents.push(agent);
58
+ }
59
+ if (!agent.tools) agent.tools = {};
60
+ agent.tools.crewswarmAllow = valid;
61
+ fs.writeFileSync(swarmPath, JSON.stringify(swarm, null, 2), "utf8");
62
+ return valid;
63
+ }
64
+
65
+ export function getSearchToolsConfig() {
66
+ return tryRead(path.join(os.homedir(), ".crewswarm", "search-tools.json")) || {};
67
+ }
68
+
69
+ export function getRawAgentPrompts() {
70
+ return (
71
+ tryRead(path.join(os.homedir(), ".crewswarm", "agent-prompts.json")) || {}
72
+ );
73
+ }
74
+
75
+ export function getAgentPrompts() {
76
+ const prompts = getRawAgentPrompts();
77
+ const augmented = {};
78
+ for (const [key, value] of Object.entries(prompts)) {
79
+ augmented[key] = applySharedChatPromptOverlay(value, key);
80
+ }
81
+ return augmented;
82
+ }
83
+
84
+ export function writeAgentPrompt(agentId, promptText) {
85
+ const promptsPath = path.join(os.homedir(), ".crewswarm", "agent-prompts.json");
86
+ const prompts = getRawAgentPrompts();
87
+ prompts[agentId] = promptText;
88
+ fs.writeFileSync(promptsPath, JSON.stringify(prompts, null, 2), "utf8");
89
+ return promptText;
90
+ }