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,98 @@
|
|
|
1
|
+
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
|
2
|
+
|
|
3
|
+
const languageContributionModules = {
|
|
4
|
+
css: () => import("monaco-editor/esm/vs/basic-languages/css/css.contribution.js"),
|
|
5
|
+
html: () => import("monaco-editor/esm/vs/basic-languages/html/html.contribution.js"),
|
|
6
|
+
javascript: () => import("monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js"),
|
|
7
|
+
markdown: () => import("monaco-editor/esm/vs/basic-languages/markdown/markdown.contribution.js"),
|
|
8
|
+
python: () => import("monaco-editor/esm/vs/basic-languages/python/python.contribution.js"),
|
|
9
|
+
typescript: () => import("monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution.js"),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const contributionIds = Object.keys(languageContributionModules).sort();
|
|
13
|
+
const registeredLanguageIds = new Set(
|
|
14
|
+
monaco.languages.getLanguages().map((language) => language.id),
|
|
15
|
+
);
|
|
16
|
+
const loadingLanguagePromises = new Map();
|
|
17
|
+
|
|
18
|
+
function syncBootstrapState() {
|
|
19
|
+
const readyLanguageIds = contributionIds
|
|
20
|
+
.filter((languageId) => registeredLanguageIds.has(languageId))
|
|
21
|
+
.sort();
|
|
22
|
+
|
|
23
|
+
window.__studioMonacoLanguageBootstrap = {
|
|
24
|
+
expectedLanguageIds: contributionIds,
|
|
25
|
+
registeredLanguageIds: readyLanguageIds,
|
|
26
|
+
assetFiles: contributionIds.map((languageId) => `${languageId}.contribution.js`),
|
|
27
|
+
hasLanguage(id) {
|
|
28
|
+
return registeredLanguageIds.has(id);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return readyLanguageIds;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function ensureLanguageRegistered(languageId) {
|
|
36
|
+
if (!languageId || registeredLanguageIds.has(languageId)) {
|
|
37
|
+
return registeredLanguageIds.has(languageId);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const load = languageContributionModules[languageId];
|
|
41
|
+
if (!load) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!loadingLanguagePromises.has(languageId)) {
|
|
46
|
+
loadingLanguagePromises.set(
|
|
47
|
+
languageId,
|
|
48
|
+
load()
|
|
49
|
+
.then(() => {
|
|
50
|
+
registeredLanguageIds.add(languageId);
|
|
51
|
+
syncBootstrapState();
|
|
52
|
+
return true;
|
|
53
|
+
})
|
|
54
|
+
.catch((error) => {
|
|
55
|
+
loadingLanguagePromises.delete(languageId);
|
|
56
|
+
throw error;
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return loadingLanguagePromises.get(languageId);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function scheduleBackgroundRegistration() {
|
|
65
|
+
const run = async () => {
|
|
66
|
+
for (const languageId of contributionIds) {
|
|
67
|
+
await ensureLanguageRegistered(languageId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const readyLanguageIds = syncBootstrapState();
|
|
71
|
+
console.info("[studio] Monaco language bootstrap ready", readyLanguageIds);
|
|
72
|
+
return readyLanguageIds;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const start = () =>
|
|
76
|
+
run().catch((error) => {
|
|
77
|
+
console.error("[studio] Monaco language bootstrap failed", error);
|
|
78
|
+
throw error;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (typeof window.requestIdleCallback === "function") {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
window.requestIdleCallback(() => {
|
|
84
|
+
start().then(resolve).catch(reject);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
window.setTimeout(() => {
|
|
91
|
+
start().then(resolve).catch(reject);
|
|
92
|
+
}, 0);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
syncBootstrapState();
|
|
97
|
+
window.__studioEnsureLanguageRegistered = ensureLanguageRegistered;
|
|
98
|
+
window.__studioLanguageRegistrationReady = scheduleBackgroundRegistration();
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const rootDir = path.resolve(__dirname, "..");
|
|
8
|
+
|
|
9
|
+
async function read(relativePath) {
|
|
10
|
+
return fs.readFile(path.join(rootDir, relativePath), "utf8");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function test(name, fn) {
|
|
14
|
+
return { name, fn };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function runTests(label, tests) {
|
|
18
|
+
let passed = 0;
|
|
19
|
+
for (const current of tests) {
|
|
20
|
+
try {
|
|
21
|
+
await current.fn();
|
|
22
|
+
passed += 1;
|
|
23
|
+
console.log(`PASS ${label}: ${current.name}`);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(`FAIL ${label}: ${current.name}`);
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
console.log(`${label} suite passed (${passed}/${tests.length})`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function runAccessibilityTests() {
|
|
33
|
+
const [html, appSource] = await Promise.all([
|
|
34
|
+
read("index.html"),
|
|
35
|
+
read("src/main.js"),
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
const tests = [
|
|
39
|
+
test("document declares language metadata", () => {
|
|
40
|
+
assert.match(html, /<html[^>]*lang="en"/i);
|
|
41
|
+
assert.match(html, /<meta name="viewport" content="width=device-width,\s*initial-scale=1\.0"/i);
|
|
42
|
+
}),
|
|
43
|
+
test("primary application shell is present", () => {
|
|
44
|
+
assert.match(html, /<div[^>]+id="app"/i);
|
|
45
|
+
}),
|
|
46
|
+
test("icon-only controls expose accessible names", () => {
|
|
47
|
+
assert.match(html, /aria-label="Toggle color theme"/);
|
|
48
|
+
assert.match(html, /aria-label="Open settings panel"/);
|
|
49
|
+
assert.match(html, /aria-label="Toggle keyboard shortcuts guide"/);
|
|
50
|
+
assert.match(html, /aria-label="Interactive terminal"/);
|
|
51
|
+
}),
|
|
52
|
+
test("overlay panels are labelled by their titles", () => {
|
|
53
|
+
assert.match(html, /id="settings-panel"[\s\S]*aria-labelledby="settings-panel-title"/);
|
|
54
|
+
assert.match(html, /id="shortcuts-panel"[\s\S]*aria-labelledby="shortcuts-panel-title"/);
|
|
55
|
+
assert.match(html, /id="diff-preview-overlay"[\s\S]*aria-labelledby="diff-preview-title"/);
|
|
56
|
+
}),
|
|
57
|
+
test("terminal panel starts hidden for assistive tech", () => {
|
|
58
|
+
assert.match(html, /id="bottom-terminal-panel"[^>]*aria-hidden="true"/);
|
|
59
|
+
}),
|
|
60
|
+
test("keyboard escape handling closes open overlays", () => {
|
|
61
|
+
assert.match(html, /if \(event\.key === "Escape" && settingsPanel\?\.classList\.contains\("visible"\)\)/);
|
|
62
|
+
assert.match(html, /setSettingsPanelOpen\(false\)/);
|
|
63
|
+
assert.match(html, /setShortcutsPanelOpen\(false\)/);
|
|
64
|
+
}),
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
await runTests("accessibility", tests);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const invokedDirectly = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
71
|
+
|
|
72
|
+
if (invokedDirectly) {
|
|
73
|
+
runAccessibilityTests().catch((error) => {
|
|
74
|
+
console.error(error.stack || error.message);
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { once } from "node:events";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { chromium } from "playwright";
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const rootDir = path.resolve(__dirname, "..");
|
|
12
|
+
const reportDir = path.join(rootDir, "output");
|
|
13
|
+
const reportPath = path.join(reportDir, "performance-audit.json");
|
|
14
|
+
const port = Number(process.env.STUDIO_AUDIT_PORT || 3345);
|
|
15
|
+
const baseUrl = `http://127.0.0.1:${port}`;
|
|
16
|
+
|
|
17
|
+
const BUDGETS = {
|
|
18
|
+
domContentLoadedMs: 2500,
|
|
19
|
+
loadMs: 4000,
|
|
20
|
+
lcpMs: 2500,
|
|
21
|
+
resourceCount: 40,
|
|
22
|
+
totalTransferBytes: 1_500_000,
|
|
23
|
+
jsHeapUsedBytes: 80 * 1024 * 1024,
|
|
24
|
+
longTasks: 3,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
async function ensureBuildOutput() {
|
|
28
|
+
await fs.access(path.join(rootDir, "dist", "index.html"));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function waitForServer(url, timeoutMs = 15_000) {
|
|
32
|
+
const deadline = Date.now() + timeoutMs;
|
|
33
|
+
let lastError = null;
|
|
34
|
+
|
|
35
|
+
while (Date.now() < deadline) {
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(url);
|
|
38
|
+
if (response.ok) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
lastError = new Error(`HTTP ${response.status}`);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
lastError = error;
|
|
44
|
+
}
|
|
45
|
+
await delay(250);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
throw lastError || new Error("Studio server did not become ready");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function startServer() {
|
|
52
|
+
const child = spawn(process.execPath, ["server.mjs"], {
|
|
53
|
+
cwd: rootDir,
|
|
54
|
+
env: {
|
|
55
|
+
...process.env,
|
|
56
|
+
STUDIO_PORT: String(port),
|
|
57
|
+
},
|
|
58
|
+
stdio: "ignore",
|
|
59
|
+
});
|
|
60
|
+
return child;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function collectMetrics() {
|
|
64
|
+
const browser = await chromium.launch({ headless: true });
|
|
65
|
+
const page = await browser.newPage();
|
|
66
|
+
const cdp = await page.context().newCDPSession(page);
|
|
67
|
+
|
|
68
|
+
await page.addInitScript(() => {
|
|
69
|
+
window.__studioPerf = {
|
|
70
|
+
lcp: 0,
|
|
71
|
+
cls: 0,
|
|
72
|
+
longTasks: 0,
|
|
73
|
+
longTaskTime: 0,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
new PerformanceObserver((list) => {
|
|
77
|
+
const entries = list.getEntries();
|
|
78
|
+
const lastEntry = entries.at(-1);
|
|
79
|
+
if (lastEntry) {
|
|
80
|
+
window.__studioPerf.lcp = lastEntry.startTime;
|
|
81
|
+
}
|
|
82
|
+
}).observe({ type: "largest-contentful-paint", buffered: true });
|
|
83
|
+
|
|
84
|
+
new PerformanceObserver((list) => {
|
|
85
|
+
for (const entry of list.getEntries()) {
|
|
86
|
+
if (!entry.hadRecentInput) {
|
|
87
|
+
window.__studioPerf.cls += entry.value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}).observe({ type: "layout-shift", buffered: true });
|
|
91
|
+
|
|
92
|
+
new PerformanceObserver((list) => {
|
|
93
|
+
for (const entry of list.getEntries()) {
|
|
94
|
+
window.__studioPerf.longTasks += 1;
|
|
95
|
+
window.__studioPerf.longTaskTime += entry.duration;
|
|
96
|
+
}
|
|
97
|
+
}).observe({ type: "longtask", buffered: true });
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await cdp.send("Performance.enable");
|
|
101
|
+
await page.goto(baseUrl, { waitUntil: "domcontentloaded", timeout: 15_000 });
|
|
102
|
+
await page.waitForLoadState("load", { timeout: 15_000 });
|
|
103
|
+
await delay(750);
|
|
104
|
+
|
|
105
|
+
const browserMetrics = await cdp.send("Performance.getMetrics");
|
|
106
|
+
const runtimeMetrics = await page.evaluate(() => {
|
|
107
|
+
const navigation = performance.getEntriesByType("navigation")[0];
|
|
108
|
+
const resources = performance.getEntriesByType("resource");
|
|
109
|
+
const totals = resources.reduce(
|
|
110
|
+
(acc, entry) => {
|
|
111
|
+
acc.transferSize += entry.transferSize || 0;
|
|
112
|
+
if (entry.initiatorType === "script") {
|
|
113
|
+
acc.scriptTransferSize += entry.transferSize || 0;
|
|
114
|
+
}
|
|
115
|
+
return acc;
|
|
116
|
+
},
|
|
117
|
+
{ transferSize: 0, scriptTransferSize: 0 },
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
domContentLoadedMs: navigation?.domContentLoadedEventEnd || 0,
|
|
122
|
+
loadMs: navigation?.loadEventEnd || 0,
|
|
123
|
+
resourceCount: resources.length,
|
|
124
|
+
totalTransferBytes: totals.transferSize,
|
|
125
|
+
scriptTransferBytes: totals.scriptTransferSize,
|
|
126
|
+
lcpMs: window.__studioPerf?.lcp || 0,
|
|
127
|
+
cls: window.__studioPerf?.cls || 0,
|
|
128
|
+
longTasks: window.__studioPerf?.longTasks || 0,
|
|
129
|
+
longTaskTimeMs: window.__studioPerf?.longTaskTime || 0,
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await browser.close();
|
|
134
|
+
|
|
135
|
+
const cdpMetricMap = Object.fromEntries(
|
|
136
|
+
browserMetrics.metrics.map((metric) => [metric.name, metric.value]),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
collectedAt: new Date().toISOString(),
|
|
141
|
+
url: baseUrl,
|
|
142
|
+
budgets: BUDGETS,
|
|
143
|
+
metrics: {
|
|
144
|
+
...runtimeMetrics,
|
|
145
|
+
jsHeapUsedBytes: cdpMetricMap.JSHeapUsedSize || 0,
|
|
146
|
+
nodes: cdpMetricMap.Nodes || 0,
|
|
147
|
+
documents: cdpMetricMap.Documents || 0,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function evaluateBudgets(report) {
|
|
153
|
+
const { metrics } = report;
|
|
154
|
+
|
|
155
|
+
const checks = [
|
|
156
|
+
["domContentLoadedMs", metrics.domContentLoadedMs <= BUDGETS.domContentLoadedMs],
|
|
157
|
+
["loadMs", metrics.loadMs <= BUDGETS.loadMs],
|
|
158
|
+
["resourceCount", metrics.resourceCount <= BUDGETS.resourceCount],
|
|
159
|
+
["totalTransferBytes", metrics.totalTransferBytes <= BUDGETS.totalTransferBytes],
|
|
160
|
+
["jsHeapUsedBytes", metrics.jsHeapUsedBytes <= BUDGETS.jsHeapUsedBytes],
|
|
161
|
+
["longTasks", metrics.longTasks <= BUDGETS.longTasks],
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
if (metrics.lcpMs > 0) {
|
|
165
|
+
checks.push(["lcpMs", metrics.lcpMs <= BUDGETS.lcpMs]);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
report.checks = checks.map(([name, pass]) => ({ name, pass }));
|
|
169
|
+
report.ok = report.checks.every((check) => check.pass);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function main() {
|
|
173
|
+
await ensureBuildOutput();
|
|
174
|
+
await fs.mkdir(reportDir, { recursive: true });
|
|
175
|
+
|
|
176
|
+
console.log("Starting Studio server for performance audit...");
|
|
177
|
+
const server = startServer();
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
console.log("Waiting for Studio server...");
|
|
181
|
+
await waitForServer(baseUrl);
|
|
182
|
+
console.log("Collecting browser metrics...");
|
|
183
|
+
const report = await collectMetrics();
|
|
184
|
+
console.log("Evaluating budgets...");
|
|
185
|
+
evaluateBudgets(report);
|
|
186
|
+
await fs.writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
187
|
+
|
|
188
|
+
console.log(`Performance audit written to ${reportPath}`);
|
|
189
|
+
report.checks.forEach((check) => {
|
|
190
|
+
console.log(`${check.pass ? "PASS" : "FAIL"} ${check.name}`);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
assert.ok(report.ok, "Studio performance audit exceeded one or more budgets");
|
|
194
|
+
} finally {
|
|
195
|
+
if (server.exitCode === null && !server.killed) {
|
|
196
|
+
server.kill("SIGTERM");
|
|
197
|
+
await Promise.race([once(server, "exit"), delay(2_000)]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
main().catch((error) => {
|
|
203
|
+
console.error(error.stack || error.message);
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const rootDir = path.resolve(__dirname, "..");
|
|
8
|
+
|
|
9
|
+
async function read(relativePath) {
|
|
10
|
+
return fs.readFile(path.join(rootDir, relativePath), "utf8");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function stat(relativePath) {
|
|
14
|
+
return fs.stat(path.join(rootDir, relativePath));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function test(name, fn) {
|
|
18
|
+
return { name, fn };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function runTests(label, tests) {
|
|
22
|
+
let passed = 0;
|
|
23
|
+
for (const current of tests) {
|
|
24
|
+
try {
|
|
25
|
+
await current.fn();
|
|
26
|
+
passed += 1;
|
|
27
|
+
console.log(`PASS ${label}: ${current.name}`);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`FAIL ${label}: ${current.name}`);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
console.log(`${label} suite passed (${passed}/${tests.length})`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function runPerformanceTests() {
|
|
37
|
+
const [html, appSource, serverSource, viteConfig] = await Promise.all([
|
|
38
|
+
read("index.html"),
|
|
39
|
+
read("src/main.js"),
|
|
40
|
+
read("server.mjs"),
|
|
41
|
+
read("vite.config.js"),
|
|
42
|
+
]);
|
|
43
|
+
const distAssets = await fs.readdir(path.join(rootDir, "dist", "assets"));
|
|
44
|
+
const jsAssets = distAssets.filter((name) => name.endsWith(".js"));
|
|
45
|
+
const cssAssets = distAssets.filter((name) => name.endsWith(".css"));
|
|
46
|
+
const indexBundle = jsAssets.find((name) => /^index-.*\.js$/.test(name));
|
|
47
|
+
const indexBundleStat = indexBundle ? await stat(path.join("dist", "assets", indexBundle)) : null;
|
|
48
|
+
|
|
49
|
+
const tests = [
|
|
50
|
+
test("build output includes JavaScript and CSS assets", () => {
|
|
51
|
+
assert.ok(jsAssets.length > 0, "expected built JavaScript assets");
|
|
52
|
+
assert.ok(cssAssets.length > 0, "expected built CSS assets");
|
|
53
|
+
}),
|
|
54
|
+
test("main bundle stays below a 3 MB guardrail", () => {
|
|
55
|
+
assert.ok(indexBundleStat, "expected a built index bundle");
|
|
56
|
+
assert.ok(indexBundleStat.size < 3 * 1024 * 1024, `bundle too large: ${indexBundleStat.size}`);
|
|
57
|
+
}),
|
|
58
|
+
test("index.html avoids external font and CDN preconnects", () => {
|
|
59
|
+
assert.match(html, /System font stack only to avoid CORS/i);
|
|
60
|
+
assert.doesNotMatch(html, /<link rel="preconnect"/i);
|
|
61
|
+
}),
|
|
62
|
+
test("Monaco is loaded lazily through dynamic imports", () => {
|
|
63
|
+
assert.match(appSource, /async function loadMonaco\(/);
|
|
64
|
+
assert.match(appSource, /import\("monaco-editor\/esm\/vs\/editor\/editor\.api"\)/);
|
|
65
|
+
}),
|
|
66
|
+
test("editor renders a lightweight placeholder before Monaco loads", () => {
|
|
67
|
+
assert.match(appSource, /function renderEditorPlaceholder\(/);
|
|
68
|
+
assert.match(appSource, /Editor loads on demand/);
|
|
69
|
+
}),
|
|
70
|
+
test("explorer hides heavy generated directories from scans", () => {
|
|
71
|
+
assert.match(appSource, /relativePath\.startsWith\("dist\/"\)/);
|
|
72
|
+
assert.match(appSource, /relativePath\.startsWith\("node_modules\/"\)/);
|
|
73
|
+
assert.match(appSource, /relativePath\.startsWith\("output\/"\)/);
|
|
74
|
+
}),
|
|
75
|
+
test("static server serves immutable cache headers for hashed assets", () => {
|
|
76
|
+
assert.match(serverSource, /return "public, max-age=31536000, immutable";/);
|
|
77
|
+
}),
|
|
78
|
+
test("static server can serve precompressed assets", () => {
|
|
79
|
+
assert.match(serverSource, /if \(acceptEncoding\.includes\("br"\)\)/);
|
|
80
|
+
assert.match(serverSource, /if \(acceptEncoding\.includes\("gzip"\)\)/);
|
|
81
|
+
}),
|
|
82
|
+
test("Vite build targets the dist assets directory explicitly", () => {
|
|
83
|
+
assert.match(viteConfig, /outDir:\s*["']dist["']/);
|
|
84
|
+
assert.match(viteConfig, /assetsDir:\s*["']assets["']/);
|
|
85
|
+
}),
|
|
86
|
+
test("workspace scans cap file enumeration to avoid runaway traversal", () => {
|
|
87
|
+
assert.match(serverSource, /const MAX_FILES = 800;/);
|
|
88
|
+
assert.match(serverSource, /if \(depth > 6 \|\| results\.length >= MAX_FILES\) return;/);
|
|
89
|
+
}),
|
|
90
|
+
test("workspace scans use a short-lived cache with targeted invalidation", () => {
|
|
91
|
+
assert.match(serverSource, /const WORKSPACE_SCAN_CACHE_TTL_MS = Number\(process\.env\.STUDIO_SCAN_CACHE_TTL_MS \|\| 1_500\);/);
|
|
92
|
+
assert.match(serverSource, /workspaceScanCache\.set\(resolvedScanDir,\s*\{/);
|
|
93
|
+
assert.match(serverSource, /invalidateWorkspaceScanCache\(resolvedPath\);/);
|
|
94
|
+
}),
|
|
95
|
+
test("audit cache is tracked and invalidated alongside workspace scans", () => {
|
|
96
|
+
assert.match(serverSource, /const auditFileCache = new Map\(\);/);
|
|
97
|
+
assert.match(serverSource, /for \(const cache of \[workspaceScanCache, auditFileCache\]\)/);
|
|
98
|
+
}),
|
|
99
|
+
test("file tree refreshes are debounced during bursty CLI updates", () => {
|
|
100
|
+
assert.match(appSource, /const FILE_TREE_REFRESH_DEBOUNCE_MS = 150;/);
|
|
101
|
+
assert.match(appSource, /function scheduleFileTreeRefresh\(/);
|
|
102
|
+
assert.match(appSource, /scheduleFileTreeRefresh\(\);/);
|
|
103
|
+
}),
|
|
104
|
+
test("terminal output is capped to avoid long-session DOM bloat", () => {
|
|
105
|
+
assert.match(appSource, /const MAX_TERMINAL_ENTRIES = 250;/);
|
|
106
|
+
assert.match(appSource, /while \(container\.children\.length > MAX_TERMINAL_ENTRIES\)/);
|
|
107
|
+
}),
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
await runTests("performance", tests);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const invokedDirectly = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
114
|
+
|
|
115
|
+
if (invokedDirectly) {
|
|
116
|
+
runPerformanceTests().catch((error) => {
|
|
117
|
+
console.error(error.stack || error.message);
|
|
118
|
+
process.exitCode = 1;
|
|
119
|
+
});
|
|
120
|
+
}
|