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,58 @@
1
+ /**
2
+ * logger.mjs — structured log utility for crewswarm
3
+ *
4
+ * By default emits human-readable prefixed lines.
5
+ * Set LOG_FORMAT=json to emit newline-delimited JSON (machine-parseable).
6
+ *
7
+ * Usage:
8
+ * import { log } from "../lib/runtime/logger.mjs";
9
+ * log("info", "crew-lead", "RT connected", { port: 18889 });
10
+ * log("warn", "wave-dispatcher", "queue full", { depth: 50, agent: "crew-coder" });
11
+ * log("error", "pipeline-state", "save failed", { pipelineId, error: e.message });
12
+ */
13
+
14
+ const JSON_MODE = process.env.LOG_FORMAT === "json";
15
+
16
+ const LEVEL_PREFIX = {
17
+ info: "",
18
+ warn: "⚠️ ",
19
+ error: "❌ ",
20
+ debug: "🔍 ",
21
+ };
22
+
23
+ /**
24
+ * @param {"info"|"warn"|"error"|"debug"} level
25
+ * @param {string} component e.g. "crew-lead", "wave-dispatcher", "pipeline-state"
26
+ * @param {string} msg Human-readable message
27
+ * @param {object} [data] Optional structured fields (correlationId, agent, taskId, …)
28
+ */
29
+ export function log(level, component, msg, data = {}) {
30
+ if (JSON_MODE) {
31
+ const entry = {
32
+ ts: new Date().toISOString(),
33
+ level,
34
+ component,
35
+ msg,
36
+ ...data,
37
+ };
38
+ process.stdout.write(JSON.stringify(entry) + "\n");
39
+ } else {
40
+ const prefix = LEVEL_PREFIX[level] ?? "";
41
+ const extras = Object.keys(data).length
42
+ ? " " + Object.entries(data).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" ")
43
+ : "";
44
+ const line = `[${component}] ${prefix}${msg}${extras}`;
45
+ if (level === "error") console.error(line);
46
+ else console.log(line);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Convenience wrappers
52
+ */
53
+ export const logger = {
54
+ info: (component, msg, data) => log("info", component, msg, data),
55
+ warn: (component, msg, data) => log("warn", component, msg, data),
56
+ error: (component, msg, data) => log("error", component, msg, data),
57
+ debug: (component, msg, data) => log("debug", component, msg, data),
58
+ };
@@ -0,0 +1,421 @@
1
+ /**
2
+ * lib/runtime/memory.mjs
3
+ * Shared memory bundle loading, agent prompt loading, and task prompt assembly.
4
+ * Extracted from gateway-bridge.mjs.
5
+ */
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import os from "node:os";
9
+ import { CREWSWARM_REPO_ROOT } from "./config.mjs";
10
+ import {
11
+ applySharedChatPromptOverlay,
12
+ getSharedChatPromptOverlay,
13
+ } from "../chat/shared-chat-prompt-overlay.mjs";
14
+ import { loadProjectMessages } from "../chat/project-messages.mjs";
15
+
16
+ // ── Constants ────────────────────────────────────────────────────────────────
17
+
18
+ export const SHARED_MEMORY_DIR = path.join(CREWSWARM_REPO_ROOT, "memory");
19
+ export const SHARED_MEMORY_MAX_FILE_CHARS = 8000;
20
+ export const SHARED_MEMORY_MAX_TOTAL_CHARS = 40000;
21
+ export const SHARED_MEMORY_FILES = [
22
+ "law.md", // Crew laws — no harm, no unauthorized access, don't break machine, create value
23
+ "current-state.md", // System overview — what crewswarm is, CRITICAL task guidance
24
+ "agent-handoff.md", // Current status, last completed work, agent rules
25
+ "orchestration-protocol.md", // Agent roster, tool permissions, dispatch syntax
26
+ "brain.md", // Accumulated project knowledge — read this to avoid repeating mistakes
27
+ // "decisions.md" // Architectural decisions — only load when needed
28
+ // "telegram-context.md" // Telegram chat history — too noisy for code tasks
29
+ ];
30
+
31
+ // Extra memory files injected for specific agents (static) + dynamic agents by _role
32
+ export const _AGENT_EXTRA_MEMORY_STATIC = {
33
+ "crew-fixer": ["lessons.md"],
34
+ "crew-coder": ["lessons.md"],
35
+ "crew-coder-front": ["lessons.md"],
36
+ "crew-coder-back": ["lessons.md"],
37
+ };
38
+ export const _EXTRA_MEMORY_BY_ROLE = {
39
+ coder: ["lessons.md"],
40
+ ops: ["lessons.md"],
41
+ };
42
+
43
+ // ── Injected dependencies ────────────────────────────────────────────────────
44
+
45
+ let _telemetry = () => {};
46
+ let _ensureSharedMemoryFiles = () => ({ created: [], error: null });
47
+ let _loadAgentList = () => [];
48
+ let _loadAgentToolPermissions = () => new Set();
49
+ let _buildToolInstructions = () => "";
50
+ let _getOpencodeProjectDir = () => "";
51
+
52
+ export function initMemory({
53
+ telemetry,
54
+ ensureSharedMemoryFiles,
55
+ loadAgentList,
56
+ loadAgentToolPermissions,
57
+ buildToolInstructions,
58
+ getOpencodeProjectDir,
59
+ }) {
60
+ if (telemetry) _telemetry = telemetry;
61
+ if (ensureSharedMemoryFiles)
62
+ _ensureSharedMemoryFiles = ensureSharedMemoryFiles;
63
+ if (loadAgentList) _loadAgentList = loadAgentList;
64
+ if (loadAgentToolPermissions)
65
+ _loadAgentToolPermissions = loadAgentToolPermissions;
66
+ if (buildToolInstructions) _buildToolInstructions = buildToolInstructions;
67
+ if (getOpencodeProjectDir) _getOpencodeProjectDir = getOpencodeProjectDir;
68
+ }
69
+
70
+ // ── Functions ────────────────────────────────────────────────────────────────
71
+
72
+ export function getAgentExtraMemory(agentId) {
73
+ const bareId = agentId.startsWith("crew-")
74
+ ? `crew-${agentId.slice(5)}`
75
+ : agentId;
76
+ if (_AGENT_EXTRA_MEMORY_STATIC[agentId])
77
+ return _AGENT_EXTRA_MEMORY_STATIC[agentId];
78
+ if (_AGENT_EXTRA_MEMORY_STATIC[bareId])
79
+ return _AGENT_EXTRA_MEMORY_STATIC[bareId];
80
+ try {
81
+ const agents = _loadAgentList();
82
+ const cfg = agents.find((a) => a.id === agentId);
83
+ if (cfg?._role && _EXTRA_MEMORY_BY_ROLE[cfg._role])
84
+ return _EXTRA_MEMORY_BY_ROLE[cfg._role];
85
+ } catch {}
86
+ return [];
87
+ }
88
+
89
+ export function loadSharedMemoryBundle() {
90
+ try {
91
+ const ensureResult = _ensureSharedMemoryFiles();
92
+ if (ensureResult.error) {
93
+ return {
94
+ text: "",
95
+ missing: SHARED_MEMORY_FILES,
96
+ included: [],
97
+ files: {},
98
+ bytes: 0,
99
+ loadFailed: true,
100
+ bootstrapCreated: ensureResult.created,
101
+ };
102
+ }
103
+
104
+ if (!fs.existsSync(SHARED_MEMORY_DIR)) {
105
+ return {
106
+ text: "",
107
+ missing: SHARED_MEMORY_FILES,
108
+ included: [],
109
+ files: {},
110
+ bytes: 0,
111
+ loadFailed: true,
112
+ bootstrapCreated: ensureResult.created,
113
+ };
114
+ }
115
+
116
+ const included = [];
117
+ const missing = [];
118
+ const files = {};
119
+ const sections = [];
120
+ let totalChars = 0;
121
+
122
+ for (const fileName of SHARED_MEMORY_FILES) {
123
+ const fullPath = path.join(SHARED_MEMORY_DIR, fileName);
124
+ if (!fs.existsSync(fullPath)) {
125
+ missing.push(fileName);
126
+ continue;
127
+ }
128
+
129
+ let content = fs.readFileSync(fullPath, "utf8");
130
+ if (content.length > SHARED_MEMORY_MAX_FILE_CHARS) {
131
+ // For append-only files keep the TAIL (newest entries); for others keep the HEAD
132
+ const TAIL_FIRST_FILES = new Set([
133
+ "brain.md",
134
+ "session-log.md",
135
+ "telegram-context.md",
136
+ ]);
137
+ if (TAIL_FIRST_FILES.has(fileName)) {
138
+ content = `[…older entries trimmed]\n\n${content.slice(-SHARED_MEMORY_MAX_FILE_CHARS)}`;
139
+ } else {
140
+ content = `${content.slice(0, SHARED_MEMORY_MAX_FILE_CHARS)}\n\n[truncated]`;
141
+ }
142
+ }
143
+
144
+ files[fileName] = content;
145
+ const section = `### ${fileName}\n${content}`;
146
+ if (totalChars + section.length > SHARED_MEMORY_MAX_TOTAL_CHARS) break;
147
+
148
+ sections.push(section);
149
+ included.push(fileName);
150
+ totalChars += section.length;
151
+ }
152
+
153
+ if (!sections.length) {
154
+ return {
155
+ text: "",
156
+ missing,
157
+ included,
158
+ files,
159
+ bytes: 0,
160
+ loadFailed: false,
161
+ bootstrapCreated: ensureResult.created,
162
+ };
163
+ }
164
+
165
+ const text = [
166
+ "Persistent shared memory (load this before answering):",
167
+ ...sections,
168
+ "End persistent memory.",
169
+ ].join("\n\n");
170
+ return {
171
+ text,
172
+ missing,
173
+ included,
174
+ files,
175
+ bytes: Buffer.byteLength(text, "utf8"),
176
+ loadFailed: false,
177
+ bootstrapCreated: ensureResult.created,
178
+ };
179
+ } catch (err) {
180
+ _telemetry("shared_memory_load_error", {
181
+ message: err?.message ?? String(err),
182
+ });
183
+ return {
184
+ text: "",
185
+ missing: SHARED_MEMORY_FILES,
186
+ included: [],
187
+ files: {},
188
+ bytes: 0,
189
+ loadFailed: true,
190
+ bootstrapCreated: [],
191
+ };
192
+ }
193
+ }
194
+
195
+ export function getLastHandoffTimestamp(sharedMemory) {
196
+ const handoff = sharedMemory?.files?.["agent-handoff.md"] || "";
197
+ const match = handoff.match(/^Last updated:\s*(.+)$/m);
198
+ return match ? match[1].trim() : "unknown";
199
+ }
200
+
201
+ export function loadAgentPrompts() {
202
+ const candidates = [
203
+ path.join(os.homedir(), ".crewswarm", "agent-prompts.json"),
204
+ path.join(os.homedir(), ".openclaw", "agent-prompts.json"),
205
+ ];
206
+ for (const p of candidates) {
207
+ try {
208
+ const prompts = JSON.parse(fs.readFileSync(p, "utf8"));
209
+ if (Object.keys(prompts).length > 0) {
210
+ const augmented = {};
211
+ for (const [key, value] of Object.entries(prompts)) {
212
+ augmented[key] = applySharedChatPromptOverlay(value, key);
213
+ }
214
+ return augmented;
215
+ }
216
+ } catch {}
217
+ }
218
+ return {};
219
+ }
220
+
221
+ function buildExecutionGuardrails(agentId = "") {
222
+ if (!agentId || agentId === "crew-lead") return "";
223
+
224
+ const isPM = agentId.startsWith("crew-pm");
225
+ const isQA = agentId === "crew-qa";
226
+ const isCoder =
227
+ agentId === "crew-coder" ||
228
+ agentId === "crew-coder-front" ||
229
+ agentId === "crew-coder-back" ||
230
+ agentId === "crew-fixer" ||
231
+ agentId === "crew-frontend";
232
+
233
+ const lines = [
234
+ "## Execution Guardrails",
235
+ "",
236
+ "OPERATING PRINCIPLES:",
237
+ "- Read before acting: @@READ_FILE any file before modifying or claiming its contents. Never guess what's in a file.",
238
+ "- Simplest approach first: do what was asked. Don't refactor surrounding code, add features, or over-engineer beyond the task.",
239
+ "- Match the request: a bug fix is just a bug fix. Don't clean up adjacent code, add docstrings to unchanged functions, or suggest a rewrite.",
240
+ "- Own mistakes: if something fails or you got it wrong, say so briefly and try a different approach. Don't repeat the same failing action.",
241
+ "",
242
+ "QUALITY:",
243
+ "- Retrieval-first: before a long or technical answer, gather real context from files/tool output first; do not rely on recollection.",
244
+ "- No stale claims: never assert runtime/model/service status unless verified in this turn by tool output or injected snapshot.",
245
+ "- Anti-loop: if the same failure pattern repeats twice, switch strategy (different tool path / narrower scope / fallback) and state the switch briefly.",
246
+ "- Never fabricate file contents, command output, or tool results. If you don't have data, use a tool to get it.",
247
+ "",
248
+ "STYLE:",
249
+ "- Lead with the answer or action, not the reasoning. Skip preamble and filler.",
250
+ "- Concise execution-first output (max 5 lines) unless the user or task asks for detail.",
251
+ ];
252
+
253
+ if (isPM) {
254
+ lines.push(
255
+ "- PM has two modes:",
256
+ " - Conversational mode (research/ideation): personality and exploratory reasoning are encouraged.",
257
+ " - Execution mode (artifact-producing): strict, structured output required.",
258
+ "- Enter PM execution mode when task includes concrete delivery signals (e.g. file paths, `@@WRITE_FILE`, roadmap/spec updates, explicit acceptance criteria, 'deliver/finalize/write').",
259
+ "- PM execution mode contract: end with `Deliverables:` (exact file paths) and `Acceptance Criteria:` (testable bullets).",
260
+ );
261
+ }
262
+ if (isQA) {
263
+ lines.push(
264
+ "- QA output contract: findings must include Severity, Repro steps, and concrete fix suggestion.",
265
+ );
266
+ }
267
+ if (isCoder) {
268
+ lines.push(
269
+ "- Coding output contract: include changed file paths and verification command output (`@@RUN_CMD` result) before completion.",
270
+ );
271
+ }
272
+
273
+ return lines.join("\n");
274
+ }
275
+
276
+ export function buildTaskPrompt(taskText, sourceLabel, agentId, options = {}) {
277
+ const { projectDir: taskProjectDir, projectId: taskProjectId } = options;
278
+ const sharedMemory = loadSharedMemoryBundle();
279
+ if (sharedMemory.loadFailed) {
280
+ return { finalPrompt: "MEMORY_LOAD_FAILED", sharedMemory };
281
+ }
282
+ const lastHandoffTimestamp = getLastHandoffTimestamp(sharedMemory);
283
+
284
+ const contextNote = `[Shared memory loaded — UTC: ${new Date().toISOString().slice(0, 16).replace("T", " ")} | Last handoff: ${lastHandoffTimestamp.slice(0, 16) || "none"}]`;
285
+
286
+ // Inject agent-specific system prompt if one exists
287
+ const agentPrompts = loadAgentPrompts();
288
+ const bareId = agentId ? agentId.replace(/^crew-/, "") : null;
289
+ const agentSystemPrompt =
290
+ (agentId && agentPrompts[agentId]) ||
291
+ (bareId && agentPrompts[bareId]) ||
292
+ (agentId ? getSharedChatPromptOverlay(agentId) : null);
293
+
294
+ const agentAllowed = _loadAgentToolPermissions(agentId || "crew-main");
295
+ const toolInstructions = _buildToolInstructions(agentAllowed);
296
+
297
+ // Load global rules — injected into every agent if the file exists
298
+ const globalRulesPath = path.join(
299
+ os.homedir(),
300
+ ".crewswarm",
301
+ "global-rules.md",
302
+ );
303
+ const globalRules = (() => {
304
+ try {
305
+ const txt = fs.readFileSync(globalRulesPath, "utf8").trim();
306
+ return txt ? `## Global Rules (apply to all agents)\n${txt}` : "";
307
+ } catch {
308
+ return "";
309
+ }
310
+ })();
311
+
312
+ // Load agent-specific extra memory (e.g. lessons.md for coders + fixer)
313
+ const extraMemoryFiles = getAgentExtraMemory(agentId);
314
+ const extraMemorySections = [];
315
+ for (const fileName of extraMemoryFiles) {
316
+ const fullPath = path.join(SHARED_MEMORY_DIR, fileName);
317
+ if (!fs.existsSync(fullPath)) continue;
318
+ try {
319
+ let content = fs.readFileSync(fullPath, "utf8").trim();
320
+ if (content.length > 6000) content = content.slice(-6000); // tail-trim
321
+ if (content) extraMemorySections.push(`### ${fileName}\n${content}`);
322
+ } catch {}
323
+ }
324
+
325
+ // Inject agent identity — name, model, and ID so every agent knows who it is
326
+ let identityHeader = "";
327
+ if (agentId) {
328
+ const agentList = _loadAgentList();
329
+ const agentCfg = agentList.find((a) => a.id === agentId);
330
+ if (agentCfg) {
331
+ const displayName = agentCfg.identity?.name || agentCfg.name || agentId;
332
+ const emoji = agentCfg.identity?.emoji || agentCfg.emoji || "";
333
+ const role = agentCfg.identity?.theme || "";
334
+ const model = agentCfg.model || "unknown model";
335
+ identityHeader = `You are ${emoji ? emoji + " " : ""}${displayName} (agent ID: ${agentId}${role ? ", role: " + role : ""}, model: ${model}).`;
336
+ }
337
+ }
338
+
339
+ // Fixer: when a path in the task doesn't exist, discover it by searching the project (so wrong paths like src/api/routers/main.py → find src/api/main.py)
340
+ const projectRoot =
341
+ taskProjectDir ||
342
+ (agentId === "crew-fixer" ? _getOpencodeProjectDir() : null);
343
+ const desktopProjectsHint = path.join(
344
+ os.homedir(),
345
+ "Desktop",
346
+ "<project-name>",
347
+ );
348
+ let projectDiscoveryRule = "";
349
+ if (agentId === "crew-fixer") {
350
+ if (projectRoot) {
351
+ projectDiscoveryRule = `## Project discovery (apply when a path in the task is missing or wrong)\nProject root: ${projectRoot}\n- If a path in the task does not exist, search the project first: use @@RUN_CMD find "${projectRoot}" -name '<filename>' (e.g. main.py) or ls to locate the file. Do not report "file not found" until you have tried to resolve the path within this project.`;
352
+ } else {
353
+ projectDiscoveryRule = `## Project discovery (external projects)\n- External projects (e.g. polymarket-ai-strat) are NOT inside the crewswarm repo. Their root is typically ${desktopProjectsHint}. If a path contains "crewswarm/<project-name>/", replace that with "${path.join(os.homedir(), "Desktop")}/<project-name>/". Example: polymarket-ai-strat main.py is at ${path.join(os.homedir(), "Desktop", "polymarket-ai-strat", "src/api/main.py")} (not under crewswarm, and not src/api/routers/main.py). Use @@RUN_CMD find to locate files if unsure.`;
354
+ }
355
+ }
356
+
357
+ // Load per-project memory from <projectDir>/.crewswarm/context.md and brain.md
358
+ // context.md = static facts (GitHub, tech stack, danger zones) — human-authored
359
+ // brain.md = accumulated knowledge — agents append via @@BRAIN when project selected
360
+ const projectMemorySections = [];
361
+ if (taskProjectDir) {
362
+ const projectMemoryDir = path.join(taskProjectDir, ".crewswarm");
363
+ for (const fname of ["context.md", "brain.md"]) {
364
+ const fpath = path.join(projectMemoryDir, fname);
365
+ try {
366
+ let content = fs.readFileSync(fpath, "utf8").trim();
367
+ if (content.length > 8000) content = content.slice(-8000);
368
+ if (content)
369
+ projectMemorySections.push(
370
+ `### Project ${fname} (${taskProjectDir})\n${content}`,
371
+ );
372
+ } catch {
373
+ /* file doesn't exist — skip silently */
374
+ }
375
+ }
376
+ }
377
+
378
+ const executionGuardrails = buildExecutionGuardrails(agentId);
379
+
380
+ const parts = [];
381
+ if (identityHeader) parts.push(identityHeader);
382
+ if (agentSystemPrompt) parts.push(agentSystemPrompt);
383
+ if (globalRules) parts.push(globalRules);
384
+ if (toolInstructions) parts.push(toolInstructions);
385
+ if (executionGuardrails) parts.push(executionGuardrails);
386
+ if (projectDiscoveryRule) parts.push(projectDiscoveryRule);
387
+ if (sharedMemory.text) parts.push(sharedMemory.text);
388
+ if (extraMemorySections.length > 0)
389
+ parts.push(extraMemorySections.join("\n\n"));
390
+ if (projectMemorySections.length > 0)
391
+ parts.push(projectMemorySections.join("\n\n"));
392
+
393
+ // Inject recent project conversation history so agents have context
394
+ if (taskProjectId) {
395
+ try {
396
+ const recentMessages = loadProjectMessages(taskProjectId, { limit: 20 });
397
+ if (recentMessages.length > 0) {
398
+ const historyLines = recentMessages.map((msg) => {
399
+ const who = msg.agent ? `[${msg.agent}]` : msg.role === "user" ? "[user]" : "[assistant]";
400
+ const text = String(msg.content || "").slice(0, 500);
401
+ return `${who} ${text}`;
402
+ });
403
+ // Cap total history to ~4000 chars to avoid blowing context
404
+ let historyText = historyLines.join("\n");
405
+ if (historyText.length > 4000) {
406
+ historyText = historyText.slice(-4000);
407
+ }
408
+ parts.push(`## Recent conversation history (project: ${taskProjectId})\n${historyText}`);
409
+ }
410
+ } catch {
411
+ /* project messages unavailable — skip silently */
412
+ }
413
+ }
414
+
415
+ parts.push(contextNote);
416
+ parts.push(taskText);
417
+
418
+ const finalPrompt = parts.join("\n\n");
419
+
420
+ return { finalPrompt, sharedMemory };
421
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Centralized path resolution for crewswarm config and state directories.
3
+ * Supports test mode via environment variables for hermetic testing.
4
+ *
5
+ * Environment variables:
6
+ * - CREWSWARM_CONFIG_DIR: Override config directory (default: ~/.crewswarm)
7
+ * - CREWSWARM_STATE_DIR: Override state directory (default: ~/.crewswarm)
8
+ * - CREWSWARM_TEST_MODE: Set to "true" to automatically use temp directories
9
+ */
10
+
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import os from "os";
14
+
15
+ let _configDir = null;
16
+ let _stateDir = null;
17
+
18
+ /**
19
+ * Get the crewswarm configuration directory.
20
+ * Used for: crewswarm.json, config.json, etc.
21
+ */
22
+ export function getConfigDir() {
23
+ if (_configDir) return _configDir;
24
+
25
+ if (process.env.CREWSWARM_TEST_MODE === "true") {
26
+ // Use a consistent temp dir for the entire test process (not per-call)
27
+ _configDir = path.join(os.tmpdir(), `crewswarm-test-${process.pid}`);
28
+ } else {
29
+ _configDir = process.env.CREWSWARM_CONFIG_DIR || path.join(os.homedir(), ".crewswarm");
30
+ }
31
+
32
+ fs.mkdirSync(_configDir, { recursive: true });
33
+ return _configDir;
34
+ }
35
+
36
+ /**
37
+ * Get the crewswarm state directory.
38
+ * Used for: chat-history, spending.json, token-usage.json, logs, etc.
39
+ */
40
+ export function getStateDir() {
41
+ if (_stateDir) return _stateDir;
42
+
43
+ if (process.env.CREWSWARM_TEST_MODE === "true") {
44
+ // Use a consistent temp dir for the entire test process (not per-call)
45
+ _stateDir = path.join(os.tmpdir(), `crewswarm-test-${process.pid}`);
46
+ } else {
47
+ _stateDir = process.env.CREWSWARM_STATE_DIR || path.join(os.homedir(), ".crewswarm");
48
+ }
49
+
50
+ fs.mkdirSync(_stateDir, { recursive: true });
51
+ return _stateDir;
52
+ }
53
+
54
+ /**
55
+ * Get a path within the config directory.
56
+ * @param {...string} parts - Path components to join
57
+ */
58
+ export function getConfigPath(...parts) {
59
+ return path.join(getConfigDir(), ...parts);
60
+ }
61
+
62
+ /**
63
+ * Get a path within the state directory.
64
+ * @param {...string} parts - Path components to join
65
+ */
66
+ export function getStatePath(...parts) {
67
+ return path.join(getStateDir(), ...parts);
68
+ }
69
+
70
+ /**
71
+ * Reset cached paths (useful for testing).
72
+ */
73
+ export function resetPaths() {
74
+ _configDir = null;
75
+ _stateDir = null;
76
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Normalize user-supplied project / output directory paths.
3
+ * Fixes common dashboard typos (e.g. ~Desktop/foo instead of ~/Desktop/foo).
4
+ */
5
+
6
+ import path from "node:path";
7
+ import os from "node:os";
8
+
9
+ /**
10
+ * @param {string|null|undefined} raw
11
+ * @returns {string|null} Absolute normalized path, or null if empty/invalid
12
+ */
13
+ export function normalizeProjectDir(raw) {
14
+ if (raw == null) return null;
15
+ let s = String(raw).trim();
16
+ if (!s) return null;
17
+
18
+ const home = os.homedir();
19
+
20
+ // Typo: "~/Desktop/foo" pasted without slash → "~Desktop/foo"
21
+ if (/^~Desktop\//i.test(s)) {
22
+ s = path.join(home, "Desktop", s.replace(/^~Desktop\//i, ""));
23
+ } else if (/^~desktop$/i.test(s)) {
24
+ s = path.join(home, "Desktop");
25
+ }
26
+
27
+ // Standard tilde expansion
28
+ if (s === "~") {
29
+ s = home;
30
+ } else if (s.startsWith("~/") || s.startsWith("~\\")) {
31
+ s = path.join(home, s.slice(2));
32
+ }
33
+
34
+ try {
35
+ if (path.isAbsolute(s)) {
36
+ return path.normalize(s);
37
+ }
38
+ // Relative paths: resolve from cwd (last resort)
39
+ return path.normalize(path.resolve(process.cwd(), s));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * LLMs / sandboxes often embed the mistaken path `…/<repo>/~Desktop/<project>/` (missing `/` after `~`).
47
+ * Planning files land there while builds use the real `~/Desktop/<project>/`. Rewrite task text to the
48
+ * canonical project directory so @@READ_FILE paths resolve.
49
+ *
50
+ * @param {string} text
51
+ * @param {string} canonicalDir absolute project root (e.g. /Users/you/Desktop/stinky-1)
52
+ * @returns {string}
53
+ */
54
+ export function rewriteWrongDesktopMirrorPaths(text, canonicalDir) {
55
+ if (!text || typeof text !== "string" || !canonicalDir) return text;
56
+ const canon = path.resolve(String(canonicalDir).trim()).replace(/\\/g, "/");
57
+ const base = path.basename(canon);
58
+ if (!base || base === "." || base === "..") return text;
59
+
60
+ const wrongUnderCwd = path
61
+ .join(process.cwd(), "~Desktop", base)
62
+ .replace(/\\/g, "/");
63
+ const wrongUnderCwdNorm = path
64
+ .normalize(path.join(process.cwd(), "~Desktop", base))
65
+ .replace(/\\/g, "/");
66
+
67
+ let out = text;
68
+ const pairs = [
69
+ [wrongUnderCwd, canon],
70
+ [wrongUnderCwdNorm, canon],
71
+ ];
72
+ for (const [w, c] of pairs) {
73
+ if (w && w !== c && out.includes(w)) out = out.split(w).join(c);
74
+ }
75
+
76
+ // Any absolute path segment `.../~Desktop/<basename>` (typo) → canon (keep suffix after basename)
77
+ const escapedBase = base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
78
+ const re = new RegExp(
79
+ String.raw`([A-Za-z]:)?(?:/[^/\s"']*)*/\~Desktop/` + escapedBase + String.raw`(?=/|\s|"|'|$)`,
80
+ "gi",
81
+ );
82
+ out = out.replace(re, () => canon);
83
+
84
+ return out;
85
+ }
86
+
87
+ /**
88
+ * OpenCode (and similar sandboxes) treat absolute paths outside the active session root as
89
+ * `external_directory` and auto-reject in non-interactive mode. When cwd/projectDir is already
90
+ * the project root, rewrite obvious absolute/~/ paths to ./ so tools stay in-workspace.
91
+ *
92
+ * @param {string} taskText
93
+ * @param {string} projectDir
94
+ * @returns {string}
95
+ */
96
+ export function rewriteTaskPathsRelativeToProjectRoot(taskText, projectDir) {
97
+ if (!taskText || typeof taskText !== "string" || !projectDir) return taskText;
98
+ let canon;
99
+ try {
100
+ canon = path.resolve(String(projectDir).trim()).replace(/\\/g, "/");
101
+ } catch {
102
+ return taskText;
103
+ }
104
+ const noTrail = canon.replace(/\/+$/, "");
105
+ const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
106
+ let out = taskText;
107
+ out = out.replace(new RegExp(esc(noTrail) + "/", "g"), "./");
108
+ const base = path.basename(noTrail);
109
+ if (base && base !== "." && base !== "..") {
110
+ const homeDesk = path.join(os.homedir(), "Desktop", base).replace(/\\/g, "/");
111
+ if (homeDesk === noTrail) {
112
+ out = out.replace(
113
+ new RegExp(`~\\/Desktop\\/${esc(base)}\\/`, "g"),
114
+ "./",
115
+ );
116
+ out = out.replace(
117
+ new RegExp(`~/Desktop/${esc(base)}/`, "g"),
118
+ "./",
119
+ );
120
+ out = out.replace(
121
+ new RegExp(`~/Desktop/${esc(base)}(?=[/\\s"'\\)\\]>|$])`, "g"),
122
+ ".",
123
+ );
124
+ }
125
+ }
126
+ return out;
127
+ }