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.
- package/.env.example +155 -0
- package/LICENSE +21 -0
- package/README.md +316 -0
- package/apps/dashboard/dist/assets/chat-core-BwSoInmZ.js +1 -0
- package/apps/dashboard/dist/assets/chat-core-BwSoInmZ.js.br +0 -0
- package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js +1 -0
- package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
- package/apps/dashboard/dist/assets/components-CSUb80ze.js +1 -0
- package/apps/dashboard/dist/assets/components-CSUb80ze.js.br +0 -0
- package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js +1 -0
- package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js.br +0 -0
- package/apps/dashboard/dist/assets/index-CF0aJRtC.css +1 -0
- package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
- package/apps/dashboard/dist/assets/index-Px49zu76.js +2 -0
- package/apps/dashboard/dist/assets/index-Px49zu76.js.br +0 -0
- package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js +1 -0
- package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
- package/apps/dashboard/dist/assets/setup-wizard-i3eEixlo.js +1 -0
- package/apps/dashboard/dist/assets/setup-wizard-i3eEixlo.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-agents-tab-BThdsdJY.js +1 -0
- package/apps/dashboard/dist/assets/tab-agents-tab-BThdsdJY.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-benchmarks-tab-DfCuAClu.js +1 -0
- package/apps/dashboard/dist/assets/tab-comms-tab-eHpOSBhG.js +1 -0
- package/apps/dashboard/dist/assets/tab-comms-tab-eHpOSBhG.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-contacts-tab-yEegNyO4.js +1 -0
- package/apps/dashboard/dist/assets/tab-contacts-tab-yEegNyO4.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-engines-tab-C3DYxTwy.js +1 -0
- package/apps/dashboard/dist/assets/tab-engines-tab-C3DYxTwy.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-memory-tab-C59BYFQD.js +1 -0
- package/apps/dashboard/dist/assets/tab-memory-tab-C59BYFQD.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-models-tab-9Ur7pXWA.js +1 -0
- package/apps/dashboard/dist/assets/tab-models-tab-9Ur7pXWA.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-pm-loop-tab-D7mnDelU.js +1 -0
- package/apps/dashboard/dist/assets/tab-pm-loop-tab-D7mnDelU.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-projects-tab-C6h2Mv1K.js +1 -0
- package/apps/dashboard/dist/assets/tab-projects-tab-C6h2Mv1K.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-prompts-tab-C0wZvWK3.js +1 -0
- package/apps/dashboard/dist/assets/tab-prompts-tab-C0wZvWK3.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-services-tab-DBj_w3bc.js +1 -0
- package/apps/dashboard/dist/assets/tab-services-tab-DBj_w3bc.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-settings-tab-ezeqAjZk.js +1 -0
- package/apps/dashboard/dist/assets/tab-settings-tab-ezeqAjZk.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-skills-tab-BYdU2whk.js +1 -0
- package/apps/dashboard/dist/assets/tab-skills-tab-BYdU2whk.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-spending-tab-Bg6w9t_p.js +1 -0
- package/apps/dashboard/dist/assets/tab-spending-tab-Bg6w9t_p.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BBV9HB2X.js +1 -0
- package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BBV9HB2X.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-swarm-tab-ChqLlEVs.js +1 -0
- package/apps/dashboard/dist/assets/tab-swarm-tab-ChqLlEVs.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-usage-tab-B2UWXenJ.js +1 -0
- package/apps/dashboard/dist/assets/tab-usage-tab-B2UWXenJ.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js +1 -0
- package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-workflows-tab-6QSXLJ0i.js +1 -0
- package/apps/dashboard/dist/assets/tab-workflows-tab-6QSXLJ0i.js.br +0 -0
- package/apps/dashboard/dist/favicon.png +0 -0
- package/apps/dashboard/dist/index.html +6466 -0
- package/apps/dashboard/dist/index.html.br +0 -0
- package/apps/dashboard/dist/index.html.gz +0 -0
- package/apps/dashboard/dist/signup.html +446 -0
- package/apps/dashboard/index.html +6442 -0
- package/apps/dashboard/package.json +15 -0
- package/apps/dashboard/src/app.js +2823 -0
- package/apps/dashboard/src/app.js.br +0 -0
- package/apps/dashboard/src/app.js.gz +0 -0
- package/apps/dashboard/src/chat/chat-actions.js +1847 -0
- package/apps/dashboard/src/chat/chat-actions.js.br +0 -0
- package/apps/dashboard/src/chat/unified-messages.js +327 -0
- package/apps/dashboard/src/chat/unified-messages.js.br +0 -0
- package/apps/dashboard/src/cli-process.js +208 -0
- package/apps/dashboard/src/cli-process.js.br +0 -0
- package/apps/dashboard/src/cli-process.js.gz +0 -0
- package/apps/dashboard/src/components/active-tasks-panel.js +175 -0
- package/apps/dashboard/src/components/active-tasks-panel.js.br +0 -0
- package/apps/dashboard/src/core/api.js +18 -0
- package/apps/dashboard/src/core/api.js.br +0 -0
- package/apps/dashboard/src/core/dom.js +220 -0
- package/apps/dashboard/src/core/dom.js.br +0 -0
- package/apps/dashboard/src/core/state.js +91 -0
- package/apps/dashboard/src/core/state.js.br +0 -0
- package/apps/dashboard/src/core/task-manager.js +134 -0
- package/apps/dashboard/src/core/task-manager.js.br +0 -0
- package/apps/dashboard/src/orchestration-status.js +127 -0
- package/apps/dashboard/src/orchestration-status.js.br +0 -0
- package/apps/dashboard/src/setup-wizard.js +555 -0
- package/apps/dashboard/src/setup-wizard.js.br +0 -0
- package/apps/dashboard/src/styles.css +2085 -0
- package/apps/dashboard/src/styles.css.br +0 -0
- package/apps/dashboard/src/styles.css.gz +0 -0
- package/apps/dashboard/src/tabs/agents-tab.js +2237 -0
- package/apps/dashboard/src/tabs/agents-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/benchmarks-tab.js +229 -0
- package/apps/dashboard/src/tabs/benchmarks-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/comms-tab.js +955 -0
- package/apps/dashboard/src/tabs/comms-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/contacts-tab.js +654 -0
- package/apps/dashboard/src/tabs/contacts-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/engines-tab.js +175 -0
- package/apps/dashboard/src/tabs/engines-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/memory-tab.js +182 -0
- package/apps/dashboard/src/tabs/memory-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/models-tab.js +441 -0
- package/apps/dashboard/src/tabs/models-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/pm-loop-tab.js +185 -0
- package/apps/dashboard/src/tabs/pm-loop-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/projects-tab.js +663 -0
- package/apps/dashboard/src/tabs/projects-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/projects-tab.js.gz +0 -0
- package/apps/dashboard/src/tabs/prompts-tab.js +160 -0
- package/apps/dashboard/src/tabs/prompts-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/services-tab.js +202 -0
- package/apps/dashboard/src/tabs/services-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/settings-tab.js +803 -0
- package/apps/dashboard/src/tabs/settings-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/skills-tab.js +284 -0
- package/apps/dashboard/src/tabs/skills-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/spending-tab.js +173 -0
- package/apps/dashboard/src/tabs/spending-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/swarm-chat-tab.js +660 -0
- package/apps/dashboard/src/tabs/swarm-chat-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/swarm-tab.js +538 -0
- package/apps/dashboard/src/tabs/swarm-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/usage-tab.js +390 -0
- package/apps/dashboard/src/tabs/usage-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/waves-tab.js +238 -0
- package/apps/dashboard/src/tabs/waves-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/workflows-tab.js +747 -0
- package/apps/dashboard/src/tabs/workflows-tab.js.br +0 -0
- package/apps/vibe/.crew/agent-memory/pipeline.json +249 -0
- package/apps/vibe/.crew/cost.json +17 -0
- package/apps/vibe/.crew/json-parse-metrics.jsonl +22 -0
- package/apps/vibe/.crew/pipeline-metrics.jsonl +22 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-0f90c392-2425-4ae5-850c-bd9d17b1d690.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-1c269dd9-a63f-4fba-af81-5cf08048ef06.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +1 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-2c78fd22-a657-4bd1-bc49-0679fb384409.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-3e6fe08d-3264-404a-8df3-aab7efef10e7.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-42eec610-57fe-4e09-9e7e-b315038495c2.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-4438eb4c-ae13-42b1-90e2-b043d8983be8.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-4740a9f5-86e7-44b6-a394-de433e291727.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-49e1da6a-957e-48fd-9220-415019e4f8e2.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-4c9251db-be68-427b-a3fc-a264f2b5778d.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-65e29a57-664d-4196-8109-017e364f182e.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-6aa04bc5-9593-4b1f-b58d-3bf2978cb602.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-6e1cba53-9b70-457e-99e0-59199149dd21.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-749f41cc-4dac-4204-be64-873a6080a0d2.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-74d68121-e181-4864-bd9a-c3211341dfaf.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-8509bc24-142d-4e07-b44a-a50bf99d1103.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-960339c6-07ca-43ce-9900-f6e1702b39b9.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-9c6480a9-7031-4146-b241-825b9a2d1de1.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-9fd42426-8492-4157-9d5f-e1537c060489.jsonl +2 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-ad6d40a3-2f5e-46a9-a345-47caaccc51aa.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-bc606133-8d5b-4535-8d85-f1a29cdaa981.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-c1a13ccd-634a-4d01-a4a7-1177b8a752ff.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-c7d27b42-249e-4bd4-8f26-6aa998110b8a.jsonl +5 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-cca2e9b9-4a34-4d25-a311-5c793fa7e91e.jsonl +5 -0
- package/apps/vibe/.crew/sandbox.json +7 -0
- package/apps/vibe/.crew/session.json +285 -0
- package/apps/vibe/.crew/training-data.jsonl +0 -0
- package/apps/vibe/.github/workflows/studio-quality.yml +37 -0
- package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +12 -0
- package/apps/vibe/.studio-data/project-messages/general.jsonl +54 -0
- package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +10 -0
- package/apps/vibe/ARCHITECTURE.md +3393 -0
- package/apps/vibe/QUICK-REFERENCE.md +211 -0
- package/apps/vibe/README.md +76 -0
- package/apps/vibe/ROADMAP.md +41 -0
- package/apps/vibe/STUDIO-SETUP-COMPLETE.md +35 -0
- package/apps/vibe/VISUAL-GUIDE.md +378 -0
- package/apps/vibe/capture-demo.mjs +160 -0
- package/apps/vibe/capture-vibe-assets.mjs +71 -0
- package/apps/vibe/capture-vibe-video.mjs +260 -0
- package/apps/vibe/check-buttons.js +41 -0
- package/apps/vibe/diagnose.html +106 -0
- package/apps/vibe/fix-buttons.js +103 -0
- package/apps/vibe/index.html +3401 -0
- package/apps/vibe/package-lock.json +920 -0
- package/apps/vibe/package.json +31 -0
- package/apps/vibe/public/favicon.png +0 -0
- package/apps/vibe/scripts/studio-pty-host.py +117 -0
- package/apps/vibe/server.mjs +1835 -0
- package/apps/vibe/src/main.js +2846 -0
- package/apps/vibe/src/register-all-languages.js +98 -0
- package/apps/vibe/start-studio.sh +11 -0
- package/apps/vibe/test/accessibility-tests.js +77 -0
- package/apps/vibe/test/browser-performance-audit.mjs +205 -0
- package/apps/vibe/test/performance-tests.js +120 -0
- package/apps/vibe/test/security-tests.js +213 -0
- package/apps/vibe/tests/e2e.local.mjs +54 -0
- package/apps/vibe/tests/server.smoke.mjs +106 -0
- package/apps/vibe/update_website.mjs +74 -0
- package/apps/vibe/vite.config.js +19 -0
- package/apps/vibe/watch-server.mjs +108 -0
- package/contrib/openclaw-plugin/README.md +199 -0
- package/contrib/openclaw-plugin/index.ts +306 -0
- package/contrib/openclaw-plugin/openclaw.plugin.json +41 -0
- package/contrib/openclaw-plugin/package.json +27 -0
- package/contrib/openclaw-plugin/skills/crewswarm/SKILL.md +88 -0
- package/crew-lead.mjs +649 -0
- package/engines/claude-code.json +36 -0
- package/engines/codex.json +37 -0
- package/engines/crew-cli.json +42 -0
- package/engines/cursor.json +40 -0
- package/engines/docker-sandbox.json +38 -0
- package/engines/gemini-cli.json +75 -0
- package/engines/opencode.json +31 -0
- package/gateway-bridge.mjs +1575 -0
- package/install.sh +738 -0
- package/lib/agent-registry.mjs +232 -0
- package/lib/agents/daemon.mjs +121 -0
- package/lib/agents/dispatch.mjs +225 -0
- package/lib/agents/permissions.mjs +90 -0
- package/lib/agents/platform-formatting.mjs +102 -0
- package/lib/agents/registry.mjs +81 -0
- package/lib/agents/tool-instructions.mjs +257 -0
- package/lib/agents/validation.mjs +75 -0
- package/lib/approval/policy-manager.mjs +221 -0
- package/lib/autoharness/index.mjs +391 -0
- package/lib/bridges/cli-executor.mjs +332 -0
- package/lib/bridges/gateway-ws.mjs +345 -0
- package/lib/bridges/integration.mjs +229 -0
- package/lib/bridges/rag-helper.mjs +90 -0
- package/lib/browser/opencode-passthrough-filter.js +44 -0
- package/lib/browser/passthrough-stderr.js +109 -0
- package/lib/chat/autonomous-mentions.mjs +373 -0
- package/lib/chat/history.mjs +82 -0
- package/lib/chat/mention-routing-intent.mjs +136 -0
- package/lib/chat/participants.mjs +95 -0
- package/lib/chat/project-messages-rag.mjs +265 -0
- package/lib/chat/project-messages.mjs +479 -0
- package/lib/chat/shared-chat-prompt-overlay.mjs +52 -0
- package/lib/chat/thread-binding.mjs +34 -0
- package/lib/chat/unified-history.mjs +223 -0
- package/lib/chat/unified-wrapper.mjs +41 -0
- package/lib/cli-process-tracker.mjs +228 -0
- package/lib/collections/index.mjs +433 -0
- package/lib/contacts/identity-linker.mjs +248 -0
- package/lib/contacts/index.mjs +341 -0
- package/lib/crew-judge/PROMPT.md +93 -0
- package/lib/crew-judge/judge.mjs +260 -0
- package/lib/crew-lead/agent-manager.mjs +125 -0
- package/lib/crew-lead/background.mjs +270 -0
- package/lib/crew-lead/brain.mjs +110 -0
- package/lib/crew-lead/chat-handler.mjs +2603 -0
- package/lib/crew-lead/chat-handler.mjs.bak +1274 -0
- package/lib/crew-lead/classifier.mjs +83 -0
- package/lib/crew-lead/http-server.mjs +4824 -0
- package/lib/crew-lead/intent.mjs +102 -0
- package/lib/crew-lead/interval-manager.mjs +41 -0
- package/lib/crew-lead/llm-caller.mjs +544 -0
- package/lib/crew-lead/prompts.mjs +392 -0
- package/lib/crew-lead/retry-manager.mjs +118 -0
- package/lib/crew-lead/tools.mjs +318 -0
- package/lib/crew-lead/wave-dispatcher.mjs +798 -0
- package/lib/crew-lead/waves-config.json +73 -0
- package/lib/crew-lead/waves-loader.mjs +110 -0
- package/lib/crew-lead/ws-router.mjs +428 -0
- package/lib/dispatch/parsers.mjs +299 -0
- package/lib/domain-planning/detector.mjs +196 -0
- package/lib/domain-planning/prompts/crew-pm-cli.md +96 -0
- package/lib/domain-planning/prompts/crew-pm-core.md +122 -0
- package/lib/domain-planning/prompts/crew-pm-frontend.md +111 -0
- package/lib/engines/crew-cli-sandbox.mjs +422 -0
- package/lib/engines/crew-cli.mjs +155 -0
- package/lib/engines/cursor-launcher.mjs +110 -0
- package/lib/engines/engine-registry.mjs +253 -0
- package/lib/engines/llm-direct.mjs +184 -0
- package/lib/engines/opencode.mjs +256 -0
- package/lib/engines/ouroboros.mjs +114 -0
- package/lib/engines/rt-envelope.mjs +1643 -0
- package/lib/engines/rt-envelope.mjs.backup-current +870 -0
- package/lib/engines/runners.mjs +1367 -0
- package/lib/gemini-cli-passthrough-noise.mjs +37 -0
- package/lib/integrations/code-search.mjs +259 -0
- package/lib/integrations/greptile.mjs +148 -0
- package/lib/integrations/multimodal.mjs +313 -0
- package/lib/integrations/telegram-streaming.mjs +153 -0
- package/lib/integrations/tts.mjs +312 -0
- package/lib/integrations/twitter-links.mjs +294 -0
- package/lib/memory/shared-adapter.mjs +296 -0
- package/lib/pipeline/manager.mjs +539 -0
- package/lib/preferences/extractor.mjs +347 -0
- package/lib/project-dir.mjs +20 -0
- package/lib/runtime/config.mjs +388 -0
- package/lib/runtime/dlq.mjs +170 -0
- package/lib/runtime/log-rotation.mjs +82 -0
- package/lib/runtime/logger.mjs +58 -0
- package/lib/runtime/memory.mjs +421 -0
- package/lib/runtime/paths.mjs +76 -0
- package/lib/runtime/project-dir.mjs +127 -0
- package/lib/runtime/spending.mjs +204 -0
- package/lib/runtime/startup-guard.mjs +291 -0
- package/lib/runtime/task-lease.mjs +234 -0
- package/lib/runtime/telemetry-schema.mjs +208 -0
- package/lib/runtime/telemetry.mjs +101 -0
- package/lib/runtime/utils.mjs +64 -0
- package/lib/skills/index.mjs +265 -0
- package/lib/tools/browser.mjs +135 -0
- package/lib/tools/executor.mjs +913 -0
- package/lib/types.d.ts +57 -0
- package/package.json +106 -0
- package/pm-loop.mjs +1626 -0
- package/prompts/coder-back.md +27 -0
- package/prompts/coder-front.md +27 -0
- package/prompts/coder.md +28 -0
- package/prompts/copywriter.md +17 -0
- package/prompts/fixer.md +39 -0
- package/prompts/frontend.md +23 -0
- package/prompts/github.md +24 -0
- package/prompts/main.md +39 -0
- package/prompts/pm-cli.md +95 -0
- package/prompts/pm-core.md +121 -0
- package/prompts/pm-frontend.md +110 -0
- package/prompts/pm.md +234 -0
- package/prompts/qa.md +44 -0
- package/prompts/security.md +19 -0
- package/scripts/build-crew-chat.sh +28 -0
- package/scripts/build-llms-full.mjs +52 -0
- package/scripts/chatmock-login.sh +16 -0
- package/scripts/chatmock-serve.sh +16 -0
- package/scripts/check-dashboard.mjs +88 -0
- package/scripts/crew-scribe.mjs +326 -0
- package/scripts/dashboard-helpers.mjs +391 -0
- package/scripts/dashboard-validation.mjs +198 -0
- package/scripts/dashboard.mjs +9717 -0
- package/scripts/dlq-replay.mjs +61 -0
- package/scripts/doctor.mjs +196 -0
- package/scripts/file-lock.mjs +186 -0
- package/scripts/fresh-machine-smoke.sh +323 -0
- package/scripts/generate-changelog.mjs +227 -0
- package/scripts/generate-openapi.mjs +334 -0
- package/scripts/health-check.mjs +229 -0
- package/scripts/install-docker.sh +213 -0
- package/scripts/mcp-server.mjs +1625 -0
- package/scripts/opencrew-rt-daemon.mjs +568 -0
- package/scripts/openswitchctl +646 -0
- package/scripts/refactor-configs.mjs +39 -0
- package/scripts/release-check.sh +46 -0
- package/scripts/resolve-node-bin.sh +25 -0
- package/scripts/restart-all-from-repo.sh +329 -0
- package/scripts/restart-crew-lead.sh +98 -0
- package/scripts/restart-dashboard.sh +104 -0
- package/scripts/restart-service.sh +274 -0
- package/scripts/run-accessibility-audit.mjs +356 -0
- package/scripts/run-integration-bounded.mjs +188 -0
- package/scripts/run-scheduled-pipeline.mjs +230 -0
- package/scripts/run.mjs +41 -0
- package/scripts/scan-skills.mjs +79 -0
- package/scripts/setup-firewall.sh +128 -0
- package/scripts/smoke-dispatch.mjs +149 -0
- package/scripts/smoke.sh +163 -0
- package/scripts/start-crew.mjs +328 -0
- package/scripts/start.mjs +146 -0
- package/scripts/swiftbar-restart-service.sh +19 -0
- package/scripts/sync-agents.mjs +152 -0
- package/scripts/sync-prompts.mjs +79 -0
- package/scripts/validate-config.mjs +337 -0
- package/scripts/wow.mjs +89 -0
- package/telegram-bridge.mjs +2421 -0
- package/unified-orchestrator.mjs +519 -0
- package/whatsapp-bridge.mjs +1481 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task lease + deduplication system — extracted from gateway-bridge.mjs
|
|
3
|
+
* File-based leases prevent duplicate task execution across multiple agent instances.
|
|
4
|
+
*
|
|
5
|
+
* Inject: initTaskLease({ telemetry, sleep, parseJsonSafe })
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import os from "os";
|
|
11
|
+
import crypto from "crypto";
|
|
12
|
+
|
|
13
|
+
const SHARED_MEMORY_BASE = process.env.SHARED_MEMORY_DIR || path.join(os.homedir(), ".crewswarm", "workspace", "shared-memory");
|
|
14
|
+
const SHARED_MEMORY_NAMESPACE = process.env.SHARED_MEMORY_NAMESPACE || "claw-swarm";
|
|
15
|
+
const SWARM_RUNTIME_DIR = path.join(SHARED_MEMORY_BASE, SHARED_MEMORY_NAMESPACE, "opencrew-rt", "runtime");
|
|
16
|
+
const SWARM_TASK_LEASE_DIR = path.join(SWARM_RUNTIME_DIR, "task-leases");
|
|
17
|
+
const SWARM_TASK_STATE_DIR = path.join(SWARM_RUNTIME_DIR, "task-state");
|
|
18
|
+
const SWARM_DLQ_DIR = path.join(SHARED_MEMORY_BASE, SHARED_MEMORY_NAMESPACE, "opencrew-rt", "dlq");
|
|
19
|
+
|
|
20
|
+
const CREWSWARM_RT_DISPATCH_LEASE_MS = Number(process.env.CREWSWARM_RT_DISPATCH_LEASE_MS || "45000");
|
|
21
|
+
const CREWSWARM_RT_DISPATCH_HEARTBEAT_MS = Number(process.env.CREWSWARM_RT_DISPATCH_HEARTBEAT_MS || "10000");
|
|
22
|
+
const CREWSWARM_RT_TASK_STATE_TTL_MS = Number(process.env.CREWSWARM_RT_TASK_STATE_TTL_MS || "21600000");
|
|
23
|
+
const CREWSWARM_RT_AGENT = process.env.CREWSWARM_RT_AGENT || process.env.OPENCREW_RT_AGENT || "crew-coder";
|
|
24
|
+
|
|
25
|
+
let _telemetry = () => {};
|
|
26
|
+
let _sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
27
|
+
let _parseJsonSafe = (s, def) => { try { return JSON.parse(s); } catch { return def; } };
|
|
28
|
+
|
|
29
|
+
export function initTaskLease({ telemetry, sleep, parseJsonSafe } = {}) {
|
|
30
|
+
if (telemetry) _telemetry = telemetry;
|
|
31
|
+
if (sleep) _sleep = sleep;
|
|
32
|
+
if (parseJsonSafe) _parseJsonSafe = parseJsonSafe;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function ensureSwarmRuntimeDirs() {
|
|
36
|
+
fs.mkdirSync(SWARM_RUNTIME_DIR, { recursive: true });
|
|
37
|
+
fs.mkdirSync(SWARM_TASK_LEASE_DIR, { recursive: true });
|
|
38
|
+
fs.mkdirSync(SWARM_TASK_STATE_DIR, { recursive: true });
|
|
39
|
+
fs.mkdirSync(SWARM_DLQ_DIR, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function parseTaskState(filePath) {
|
|
43
|
+
try {
|
|
44
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
45
|
+
return _parseJsonSafe(raw, null);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function taskIdentity({ envelope, payload, incomingType, prompt }) {
|
|
52
|
+
const explicit = String(payload?.idempotencyKey || payload?.idempotency_key || payload?.dedupeKey || "").trim();
|
|
53
|
+
if (explicit) return explicit;
|
|
54
|
+
const taskId = String(envelope?.taskId || "").trim();
|
|
55
|
+
if (taskId) return `${incomingType}:${taskId}`;
|
|
56
|
+
const envelopeId = String(envelope?.id || "").trim();
|
|
57
|
+
if (envelopeId) return `${incomingType}:${envelopeId}`;
|
|
58
|
+
const base = JSON.stringify({
|
|
59
|
+
incomingType,
|
|
60
|
+
from: envelope?.from || "unknown",
|
|
61
|
+
prompt: String(prompt || "").slice(0, 2000),
|
|
62
|
+
});
|
|
63
|
+
return `hash:${crypto.createHash("sha256").update(base).digest("hex")}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function taskKeyFor(identity) {
|
|
67
|
+
return crypto.createHash("sha256").update(String(identity)).digest("hex");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function leasePath(taskKey) {
|
|
71
|
+
return path.join(SWARM_TASK_LEASE_DIR, `${taskKey}.json`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function taskStatePath(taskKey) {
|
|
75
|
+
return path.join(SWARM_TASK_STATE_DIR, `${taskKey}.json`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function lockPath(taskKey) {
|
|
79
|
+
return path.join(SWARM_TASK_LEASE_DIR, `${taskKey}.lock`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function withTaskLock(taskKey, fn) {
|
|
83
|
+
ensureSwarmRuntimeDirs();
|
|
84
|
+
const file = lockPath(taskKey);
|
|
85
|
+
const deadline = Date.now() + Math.max(200, CREWSWARM_RT_DISPATCH_HEARTBEAT_MS);
|
|
86
|
+
let lastErr;
|
|
87
|
+
while (Date.now() < deadline) {
|
|
88
|
+
try {
|
|
89
|
+
const fd = fs.openSync(file, "wx");
|
|
90
|
+
try {
|
|
91
|
+
return await fn();
|
|
92
|
+
} finally {
|
|
93
|
+
try { fs.closeSync(fd); } catch {}
|
|
94
|
+
try { fs.unlinkSync(file); } catch {}
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
lastErr = err;
|
|
98
|
+
if (err?.code !== "EEXIST") throw err;
|
|
99
|
+
// Add jitter to prevent thundering herd
|
|
100
|
+
await _sleep(40 + Math.random() * 20);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
throw new Error(`task lock timeout for ${taskKey}: ${lastErr?.message || "unknown"}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function clearStaleTaskState() {
|
|
107
|
+
try {
|
|
108
|
+
ensureSwarmRuntimeDirs();
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
for (const fileName of fs.readdirSync(SWARM_TASK_STATE_DIR)) {
|
|
111
|
+
if (!fileName.endsWith(".json")) continue;
|
|
112
|
+
const fullPath = path.join(SWARM_TASK_STATE_DIR, fileName);
|
|
113
|
+
const row = parseTaskState(fullPath);
|
|
114
|
+
if (!row) continue;
|
|
115
|
+
const ts = Date.parse(String(row.completedAt || row.updatedAt || ""));
|
|
116
|
+
if (!Number.isFinite(ts)) continue;
|
|
117
|
+
if (now - ts > CREWSWARM_RT_TASK_STATE_TTL_MS) {
|
|
118
|
+
try { fs.unlinkSync(fullPath); } catch {}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch {}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function claimTaskLease({ taskKey, identity, incomingType, envelope, payload }) {
|
|
125
|
+
const nowIso = new Date().toISOString();
|
|
126
|
+
const nowMs = Date.now();
|
|
127
|
+
return withTaskLock(taskKey, async () => {
|
|
128
|
+
clearStaleTaskState();
|
|
129
|
+
const stateFile = taskStatePath(taskKey);
|
|
130
|
+
const existingState = parseTaskState(stateFile);
|
|
131
|
+
if (existingState?.status === "done") {
|
|
132
|
+
return {
|
|
133
|
+
status: "already_done",
|
|
134
|
+
owner: existingState.owner || "unknown",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const leaseFile = leasePath(taskKey);
|
|
139
|
+
const existingLease = parseTaskState(leaseFile) || {};
|
|
140
|
+
const leaseExpiresAtMs = Date.parse(String(existingLease.leaseExpiresAt || ""));
|
|
141
|
+
const leaseActive = Number.isFinite(leaseExpiresAtMs) && leaseExpiresAtMs > nowMs;
|
|
142
|
+
if (leaseActive && existingLease.owner && existingLease.owner !== CREWSWARM_RT_AGENT) {
|
|
143
|
+
return {
|
|
144
|
+
status: "claimed_by_other",
|
|
145
|
+
owner: existingLease.owner,
|
|
146
|
+
leaseExpiresAt: existingLease.leaseExpiresAt,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const previousAttempts = Number(existingLease.attempt || payload?.retryCount || 0);
|
|
151
|
+
const attempt = leaseActive && existingLease.owner === CREWSWARM_RT_AGENT
|
|
152
|
+
? Math.max(1, previousAttempts)
|
|
153
|
+
: previousAttempts + 1;
|
|
154
|
+
|
|
155
|
+
const leaseRecord = {
|
|
156
|
+
taskKey,
|
|
157
|
+
identity,
|
|
158
|
+
incomingType,
|
|
159
|
+
owner: CREWSWARM_RT_AGENT,
|
|
160
|
+
source: envelope?.from || "unknown",
|
|
161
|
+
attempt,
|
|
162
|
+
taskId: envelope?.taskId || "",
|
|
163
|
+
messageId: envelope?.id || "",
|
|
164
|
+
claimedAt: nowIso,
|
|
165
|
+
heartbeatAt: nowIso,
|
|
166
|
+
leaseExpiresAt: new Date(nowMs + CREWSWARM_RT_DISPATCH_LEASE_MS).toISOString(),
|
|
167
|
+
};
|
|
168
|
+
fs.writeFileSync(leaseFile, `${JSON.stringify(leaseRecord, null, 2)}\n`, "utf8");
|
|
169
|
+
_telemetry("realtime_task_claimed", {
|
|
170
|
+
taskKey,
|
|
171
|
+
identity,
|
|
172
|
+
attempt,
|
|
173
|
+
incomingType,
|
|
174
|
+
owner: CREWSWARM_RT_AGENT,
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
status: "claimed",
|
|
178
|
+
attempt,
|
|
179
|
+
lease: leaseRecord,
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function startTaskLeaseHeartbeat(taskKey) {
|
|
185
|
+
return setInterval(async () => {
|
|
186
|
+
try {
|
|
187
|
+
await withTaskLock(taskKey, async () => {
|
|
188
|
+
const leaseFile = leasePath(taskKey);
|
|
189
|
+
const existingLease = parseTaskState(leaseFile);
|
|
190
|
+
if (!existingLease || existingLease.owner !== CREWSWARM_RT_AGENT) return;
|
|
191
|
+
const nowMs = Date.now();
|
|
192
|
+
existingLease.heartbeatAt = new Date(nowMs).toISOString();
|
|
193
|
+
existingLease.leaseExpiresAt = new Date(nowMs + CREWSWARM_RT_DISPATCH_LEASE_MS).toISOString();
|
|
194
|
+
fs.writeFileSync(leaseFile, `${JSON.stringify(existingLease, null, 2)}\n`, "utf8");
|
|
195
|
+
});
|
|
196
|
+
} catch (err) {
|
|
197
|
+
_telemetry("realtime_task_heartbeat_error", { taskKey, message: err?.message ?? String(err) });
|
|
198
|
+
}
|
|
199
|
+
}, Math.max(1000, CREWSWARM_RT_DISPATCH_HEARTBEAT_MS));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export async function finalizeTaskState({ taskKey, identity, status, attempt, error = "", note = "" }) {
|
|
203
|
+
const completedAt = new Date().toISOString();
|
|
204
|
+
await withTaskLock(taskKey, async () => {
|
|
205
|
+
const stateFile = taskStatePath(taskKey);
|
|
206
|
+
const leaseFile = leasePath(taskKey);
|
|
207
|
+
const state = {
|
|
208
|
+
taskKey,
|
|
209
|
+
identity,
|
|
210
|
+
status,
|
|
211
|
+
owner: CREWSWARM_RT_AGENT,
|
|
212
|
+
attempt,
|
|
213
|
+
error,
|
|
214
|
+
note,
|
|
215
|
+
completedAt,
|
|
216
|
+
updatedAt: completedAt,
|
|
217
|
+
};
|
|
218
|
+
fs.writeFileSync(stateFile, `${JSON.stringify(state, null, 2)}\n`, "utf8");
|
|
219
|
+
try { fs.unlinkSync(leaseFile); } catch {}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function releaseRuntimeTaskLease(taskKey) {
|
|
224
|
+
await withTaskLock(taskKey, async () => {
|
|
225
|
+
const leaseFile = leasePath(taskKey);
|
|
226
|
+
const lease = parseTaskState(leaseFile);
|
|
227
|
+
if (!lease || lease.owner !== CREWSWARM_RT_AGENT) return;
|
|
228
|
+
lease.leaseExpiresAt = new Date(Date.now() - 1).toISOString();
|
|
229
|
+
lease.releasedAt = new Date().toISOString();
|
|
230
|
+
fs.writeFileSync(leaseFile, `${JSON.stringify(lease, null, 2)}\n`, "utf8");
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export { SWARM_RUNTIME_DIR, SWARM_TASK_LEASE_DIR, SWARM_TASK_STATE_DIR, SWARM_DLQ_DIR };
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/telemetry-schema.mjs
|
|
3
|
+
*
|
|
4
|
+
* Canonical JSON Schema definitions for crewswarm telemetry events.
|
|
5
|
+
* Matches docs/OPS-TELEMETRY-SCHEMA.md.
|
|
6
|
+
*
|
|
7
|
+
* Exported:
|
|
8
|
+
* TELEMETRY_SCHEMAS — { [eventType]: schema }
|
|
9
|
+
* ENVELOPE_REQUIRED — required envelope fields (all event types)
|
|
10
|
+
* validateTelemetryEvent — validate a parsed event object, returns { ok, errors }
|
|
11
|
+
* validateTelemetryLog — validate all lines in a JSONL file, returns summary
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
|
|
16
|
+
// ── Envelope fields shared by all event types ────────────────────────────────
|
|
17
|
+
|
|
18
|
+
const ENVELOPE_REQUIRED = ["schemaVersion", "eventType", "eventId", "occurredAt", "source", "correlationId", "data"];
|
|
19
|
+
|
|
20
|
+
const ENVELOPE_SCHEMA = {
|
|
21
|
+
type: "object",
|
|
22
|
+
required: ENVELOPE_REQUIRED,
|
|
23
|
+
properties: {
|
|
24
|
+
schemaVersion: { type: "string", pattern: "^\\d+\\.\\d+$" },
|
|
25
|
+
eventType: { type: "string", minLength: 1 },
|
|
26
|
+
eventId: { type: "string", minLength: 1 },
|
|
27
|
+
occurredAt: { type: "string", format: "date-time-ish" },
|
|
28
|
+
receivedAt: { type: "string" },
|
|
29
|
+
source: {
|
|
30
|
+
type: "object",
|
|
31
|
+
required: ["component"],
|
|
32
|
+
properties: {
|
|
33
|
+
component: { type: "string", minLength: 1 },
|
|
34
|
+
agentId: { type: "string" },
|
|
35
|
+
hostname: { type: "string" },
|
|
36
|
+
pid: { type: "number" },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
correlationId: { type: "string", minLength: 1 },
|
|
40
|
+
sessionId: { type: "string" },
|
|
41
|
+
initiator: { type: "object" },
|
|
42
|
+
tags: { type: "object" },
|
|
43
|
+
data: { type: "object" },
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// ── Event-type data schemas ───────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
const AGENT_PRESENCE_DATA_SCHEMA = {
|
|
50
|
+
type: "object",
|
|
51
|
+
required: ["status", "latencyMs", "uptimeSeconds", "heartbeatSeq", "version"],
|
|
52
|
+
properties: {
|
|
53
|
+
status: { type: "string", enum: ["online", "offline", "degraded", "draining"] },
|
|
54
|
+
latencyMs: { type: "number", minimum: 0 },
|
|
55
|
+
uptimeSeconds: { type: "number", minimum: 0 },
|
|
56
|
+
queueDepth: { type: "number", minimum: 0 },
|
|
57
|
+
lastTaskId: { type: "string" },
|
|
58
|
+
heartbeatSeq: { type: "number", minimum: 0 },
|
|
59
|
+
capabilities: { type: "array", items: { type: "string" } },
|
|
60
|
+
version: { type: "string", minLength: 1 },
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const TASK_LIFECYCLE_DATA_SCHEMA = {
|
|
65
|
+
type: "object",
|
|
66
|
+
required: ["taskId", "agentId", "taskType", "phase", "phaseOrdinal"],
|
|
67
|
+
properties: {
|
|
68
|
+
taskId: { type: "string", minLength: 1 },
|
|
69
|
+
agentId: { type: "string", minLength: 1 },
|
|
70
|
+
taskType: { type: "string", minLength: 1 },
|
|
71
|
+
phase: {
|
|
72
|
+
type: "string",
|
|
73
|
+
enum: ["dispatched","accepted","started","needs_approval","approved","rejected","awaiting_input","completed","failed","escalated","cancelled"],
|
|
74
|
+
},
|
|
75
|
+
phaseOrdinal: { type: "number", minimum: 0 },
|
|
76
|
+
durationMs: { type: "number", minimum: 0 },
|
|
77
|
+
result: { type: "object" },
|
|
78
|
+
error: { type: "object" },
|
|
79
|
+
retryStrategy:{ type: "object" },
|
|
80
|
+
dispatcher: { type: "object" },
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const ERROR_DATA_SCHEMA = {
|
|
85
|
+
type: "object",
|
|
86
|
+
required: ["component", "severity", "errorCode", "message"],
|
|
87
|
+
properties: {
|
|
88
|
+
component: { type: "string", minLength: 1 },
|
|
89
|
+
severity: { type: "string", enum: ["info", "warn", "error", "critical"] },
|
|
90
|
+
errorCode: { type: "string", minLength: 1 },
|
|
91
|
+
message: { type: "string", minLength: 1 },
|
|
92
|
+
stack: { type: "string" },
|
|
93
|
+
taskId: { type: "string" },
|
|
94
|
+
agentId: { type: "string" },
|
|
95
|
+
context: { type: "object" },
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// ── Exported schemas map ──────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
export const TELEMETRY_SCHEMAS = {
|
|
102
|
+
"agent.presence": { envelope: ENVELOPE_SCHEMA, data: AGENT_PRESENCE_DATA_SCHEMA },
|
|
103
|
+
"task.lifecycle": { envelope: ENVELOPE_SCHEMA, data: TASK_LIFECYCLE_DATA_SCHEMA },
|
|
104
|
+
"error": { envelope: ENVELOPE_SCHEMA, data: ERROR_DATA_SCHEMA },
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// ── Lightweight schema validator (no dependencies) ────────────────────────────
|
|
108
|
+
|
|
109
|
+
function validateValue(value, schema, path) {
|
|
110
|
+
const errors = [];
|
|
111
|
+
if (schema.type) {
|
|
112
|
+
const actualType = Array.isArray(value) ? "array" : typeof value;
|
|
113
|
+
if (actualType !== schema.type) {
|
|
114
|
+
errors.push(`${path}: expected ${schema.type}, got ${actualType}`);
|
|
115
|
+
return errors;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (schema.enum && !schema.enum.includes(value)) {
|
|
119
|
+
errors.push(`${path}: "${value}" not in allowed values [${schema.enum.join(", ")}]`);
|
|
120
|
+
}
|
|
121
|
+
if (schema.minLength !== undefined && typeof value === "string" && value.length < schema.minLength) {
|
|
122
|
+
errors.push(`${path}: string length ${value.length} < minimum ${schema.minLength}`);
|
|
123
|
+
}
|
|
124
|
+
if (schema.minimum !== undefined && typeof value === "number" && value < schema.minimum) {
|
|
125
|
+
errors.push(`${path}: ${value} < minimum ${schema.minimum}`);
|
|
126
|
+
}
|
|
127
|
+
if (schema.pattern && typeof value === "string" && !new RegExp(schema.pattern).test(value)) {
|
|
128
|
+
errors.push(`${path}: "${value}" does not match pattern ${schema.pattern}`);
|
|
129
|
+
}
|
|
130
|
+
if (schema.type === "object" && schema.required) {
|
|
131
|
+
for (const key of schema.required) {
|
|
132
|
+
if (value[key] === undefined || value[key] === null) {
|
|
133
|
+
errors.push(`${path}.${key}: required field missing`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (schema.type === "object" && schema.properties && typeof value === "object") {
|
|
138
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
139
|
+
if (value[key] !== undefined && value[key] !== null) {
|
|
140
|
+
errors.push(...validateValue(value[key], propSchema, `${path}.${key}`));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (schema.type === "array" && schema.items && Array.isArray(value)) {
|
|
145
|
+
value.forEach((item, i) => {
|
|
146
|
+
errors.push(...validateValue(item, schema.items, `${path}[${i}]`));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return errors;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Validate a single parsed telemetry event object.
|
|
154
|
+
* @param {object} event — parsed JSON event
|
|
155
|
+
* @returns {{ ok: boolean, errors: string[], eventType: string }}
|
|
156
|
+
*/
|
|
157
|
+
export function validateTelemetryEvent(event) {
|
|
158
|
+
if (!event || typeof event !== "object") {
|
|
159
|
+
return { ok: false, errors: ["event is not an object"], eventType: "unknown" };
|
|
160
|
+
}
|
|
161
|
+
const eventType = event.eventType || "unknown";
|
|
162
|
+
const errors = [];
|
|
163
|
+
|
|
164
|
+
// Envelope validation (common to all types)
|
|
165
|
+
errors.push(...validateValue(event, ENVELOPE_SCHEMA, "event"));
|
|
166
|
+
|
|
167
|
+
// Data validation (type-specific)
|
|
168
|
+
const typeSchema = TELEMETRY_SCHEMAS[eventType];
|
|
169
|
+
if (typeSchema && event.data && typeof event.data === "object") {
|
|
170
|
+
errors.push(...validateValue(event.data, typeSchema.data, "event.data"));
|
|
171
|
+
} else if (!typeSchema) {
|
|
172
|
+
// Unknown event type — only warn, don't fail (forward-compat)
|
|
173
|
+
errors.push(`event.eventType: unknown type "${eventType}" (not in schema — new type or typo)`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { ok: errors.length === 0, errors, eventType };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Validate all lines in a JSONL telemetry log file.
|
|
181
|
+
* @param {string} filePath
|
|
182
|
+
* @returns {{ total: number, valid: number, invalid: number, unknownType: number, issues: Array }}
|
|
183
|
+
*/
|
|
184
|
+
export function validateTelemetryLog(filePath) {
|
|
185
|
+
const summary = { total: 0, valid: 0, invalid: 0, unknownType: 0, issues: [] };
|
|
186
|
+
let raw;
|
|
187
|
+
try {
|
|
188
|
+
raw = fs.readFileSync(filePath, "utf8");
|
|
189
|
+
} catch {
|
|
190
|
+
return summary;
|
|
191
|
+
}
|
|
192
|
+
for (const line of raw.split("\n").filter(l => l.trim())) {
|
|
193
|
+
summary.total++;
|
|
194
|
+
let parsed;
|
|
195
|
+
try { parsed = JSON.parse(line); }
|
|
196
|
+
catch { summary.invalid++; summary.issues.push({ line: summary.total, error: "invalid JSON" }); continue; }
|
|
197
|
+
const result = validateTelemetryEvent(parsed);
|
|
198
|
+
if (!result.ok) {
|
|
199
|
+
const isUnknownType = result.errors.some(e => e.includes("unknown type"));
|
|
200
|
+
if (isUnknownType) summary.unknownType++;
|
|
201
|
+
else summary.invalid++;
|
|
202
|
+
summary.issues.push({ line: summary.total, eventType: result.eventType, errors: result.errors });
|
|
203
|
+
} else {
|
|
204
|
+
summary.valid++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return summary;
|
|
208
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry and ops snapshot — extracted from crew-lead.mjs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
let _broadcastSSE = () => {};
|
|
6
|
+
|
|
7
|
+
export function initTelemetry({ broadcastSSE }) {
|
|
8
|
+
if (broadcastSSE) _broadcastSSE = broadcastSSE;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const TELEMETRY_SCHEMA_VERSION = "1.1";
|
|
12
|
+
export const TELEMETRY_EVENT_LIMIT = 100;
|
|
13
|
+
export const telemetryEvents = [];
|
|
14
|
+
export const taskPhaseOrdinal = new Map();
|
|
15
|
+
|
|
16
|
+
export const OPS_EVENT_LIMIT = 200;
|
|
17
|
+
export const OPS_EVENTS = [];
|
|
18
|
+
export const OPS_COUNTERS = {
|
|
19
|
+
tasksDispatched: 0,
|
|
20
|
+
tasksCompleted: 0,
|
|
21
|
+
pipelinesStarted: 0,
|
|
22
|
+
pipelinesCompleted: 0,
|
|
23
|
+
webhooksReceived: 0,
|
|
24
|
+
skillsApproved: 0,
|
|
25
|
+
skillsRejected: 0,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function nextPhaseOrdinal(taskId) {
|
|
29
|
+
const n = (taskPhaseOrdinal.get(taskId) || 0) + 1;
|
|
30
|
+
taskPhaseOrdinal.set(taskId, n);
|
|
31
|
+
return n;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function emitTaskLifecycle(phase, data) {
|
|
35
|
+
const { taskId, agentId } = data;
|
|
36
|
+
const eventId = "evt_" + Date.now() + "_" + Math.random().toString(36).slice(2, 10);
|
|
37
|
+
const envelope = {
|
|
38
|
+
schemaVersion: TELEMETRY_SCHEMA_VERSION,
|
|
39
|
+
eventType: "task.lifecycle",
|
|
40
|
+
eventId,
|
|
41
|
+
occurredAt: new Date().toISOString(),
|
|
42
|
+
source: { component: "crew-lead" },
|
|
43
|
+
correlationId: taskId ? "task:" + taskId : "task:unknown",
|
|
44
|
+
data: {
|
|
45
|
+
taskId: taskId || "",
|
|
46
|
+
agentId: agentId || "",
|
|
47
|
+
taskType: data.taskType || "task",
|
|
48
|
+
phase,
|
|
49
|
+
phaseOrdinal: nextPhaseOrdinal(taskId || "global"),
|
|
50
|
+
...(data.durationMs != null && { durationMs: data.durationMs }),
|
|
51
|
+
...(data.result && { result: data.result }),
|
|
52
|
+
...(data.error && { error: data.error }),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
telemetryEvents.push(envelope);
|
|
56
|
+
if (telemetryEvents.length > TELEMETRY_EVENT_LIMIT) telemetryEvents.shift();
|
|
57
|
+
_broadcastSSE({ type: "telemetry", payload: envelope });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function readTelemetryEvents(limit = 25) {
|
|
61
|
+
const n = Math.min(Number(limit) || 25, TELEMETRY_EVENT_LIMIT);
|
|
62
|
+
return telemetryEvents.slice(-n);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function bumpOpsCounter(key, delta = 1) {
|
|
66
|
+
OPS_COUNTERS[key] = (OPS_COUNTERS[key] || 0) + delta;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function recordOpsEvent(type, fields = {}) {
|
|
70
|
+
const entry = { ts: Date.now(), type, ...fields };
|
|
71
|
+
OPS_EVENTS.push(entry);
|
|
72
|
+
if (OPS_EVENTS.length > OPS_EVENT_LIMIT) OPS_EVENTS.shift();
|
|
73
|
+
return entry;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function readOpsEvents(limit = 25) {
|
|
77
|
+
if (!Number.isFinite(limit) || limit <= 0) limit = 25;
|
|
78
|
+
const sliceCount = Math.min(Math.trunc(limit), OPS_EVENT_LIMIT);
|
|
79
|
+
return OPS_EVENTS.slice(sliceCount * -1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function buildTaskText(taskSpec) {
|
|
83
|
+
if (typeof taskSpec === "string") return taskSpec;
|
|
84
|
+
let text = taskSpec.task || "";
|
|
85
|
+
if (taskSpec.verify || taskSpec.done) {
|
|
86
|
+
text += "\n\n## Acceptance criteria";
|
|
87
|
+
if (taskSpec.verify) text += `\n- Verify: ${taskSpec.verify}`;
|
|
88
|
+
if (taskSpec.done) text += `\n- Done when: ${taskSpec.done}`;
|
|
89
|
+
}
|
|
90
|
+
return text;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function resolveAgentId(cfg, nameOrId) {
|
|
94
|
+
if (!nameOrId) return null;
|
|
95
|
+
const id = String(nameOrId).trim();
|
|
96
|
+
if (cfg.knownAgents && cfg.knownAgents.includes(id)) return id;
|
|
97
|
+
const roster = cfg.agentRoster || [];
|
|
98
|
+
const byName = roster.find(a => (a.name || "").toLowerCase() === id.toLowerCase());
|
|
99
|
+
if (byName) return byName.id;
|
|
100
|
+
return id;
|
|
101
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities and telemetry reader — extracted from gateway-bridge.mjs
|
|
3
|
+
* Pure functions with no external injection needed.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import os from "os";
|
|
8
|
+
import path from "path";
|
|
9
|
+
|
|
10
|
+
const LEGACY_STATE_DIR = path.join(os.homedir(), ".openclaw");
|
|
11
|
+
const TELEMETRY_DIR = path.join(LEGACY_STATE_DIR, "telemetry");
|
|
12
|
+
export const TELEMETRY_LOG = path.join(TELEMETRY_DIR, "events.log");
|
|
13
|
+
|
|
14
|
+
export function formatError(err) {
|
|
15
|
+
const msg = err?.message ?? String(err);
|
|
16
|
+
const lower = msg.toLowerCase();
|
|
17
|
+
let hint = "Hint: run --quickstart to verify connection and channel status.";
|
|
18
|
+
if (lower.includes("enoent") || lower.includes("device.json") || lower.includes("openclaw.json")) {
|
|
19
|
+
hint = `Hint: initialize config (e.g. run install) so identity/config exist under ~/.crewswarm or legacy path.`;
|
|
20
|
+
} else if (lower.includes("econnrefused") || lower.includes("connect") || lower.includes("websocket")) {
|
|
21
|
+
hint = "Hint: start the local gateway service, then re-run with --quickstart.";
|
|
22
|
+
} else if (lower.includes("timeout")) {
|
|
23
|
+
hint = "Hint: gateway may be busy; retry in a few seconds or use --status to verify responsiveness.";
|
|
24
|
+
}
|
|
25
|
+
return `❌ ${msg}\n${hint}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function formatDuration(ms) {
|
|
29
|
+
if (ms < 1000) return `${ms}ms`;
|
|
30
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function median(numbers) {
|
|
34
|
+
if (!numbers.length) return null;
|
|
35
|
+
const sorted = [...numbers].sort((a, b) => a - b);
|
|
36
|
+
const mid = Math.floor(sorted.length / 2);
|
|
37
|
+
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function percentile(numbers, p) {
|
|
41
|
+
if (!numbers.length) return null;
|
|
42
|
+
const sorted = [...numbers].sort((a, b) => a - b);
|
|
43
|
+
const idx = Math.ceil((p / 100) * sorted.length) - 1;
|
|
44
|
+
return sorted[Math.max(0, Math.min(sorted.length - 1, idx))];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function readTelemetryEvents(limit = 20000) {
|
|
48
|
+
try {
|
|
49
|
+
if (!fs.existsSync(TELEMETRY_LOG)) return [];
|
|
50
|
+
const lines = fs.readFileSync(TELEMETRY_LOG, "utf8").split("\n").filter(Boolean);
|
|
51
|
+
const tail = lines.slice(-limit);
|
|
52
|
+
const events = [];
|
|
53
|
+
for (const line of tail) {
|
|
54
|
+
try {
|
|
55
|
+
const row = JSON.parse(line);
|
|
56
|
+
if (row?.event && row?.timestamp) events.push(row);
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
return events;
|
|
60
|
+
} catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|