crewswarm 0.9.2 → 0.9.4
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/README.md +22 -9
- package/apps/dashboard/dist/assets/chat-core-uXb_C0GM.js +1 -0
- package/apps/dashboard/dist/assets/chat-core-uXb_C0GM.js.br +0 -0
- package/apps/dashboard/dist/assets/cli-process-CNZ_UBCt.js +1 -0
- package/apps/dashboard/dist/assets/cli-process-CNZ_UBCt.js.br +0 -0
- package/apps/dashboard/dist/assets/index-BeVllEj_.js +2 -0
- package/apps/dashboard/dist/assets/index-BeVllEj_.js.br +0 -0
- package/apps/dashboard/dist/assets/{index-CF0aJRtC.css → index-D-sRshvg.css} +1 -1
- package/apps/dashboard/dist/assets/index-D-sRshvg.css.br +0 -0
- package/apps/dashboard/dist/assets/tab-benchmarks-tab-BHjKCPm3.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-models-tab-dNRgsTOO.js +1 -0
- package/apps/dashboard/dist/assets/tab-models-tab-dNRgsTOO.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-pm-loop-tab-Bfd449B4.js → tab-pm-loop-tab-DiAPTJXu.js} +1 -1
- package/apps/dashboard/dist/assets/tab-pm-loop-tab-DiAPTJXu.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-projects-tab-DhNWnlzt.js → tab-projects-tab-SFH4E--a.js} +1 -1
- package/apps/dashboard/dist/assets/tab-projects-tab-SFH4E--a.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-settings-tab-CuvH_Fj_.js +1 -0
- package/apps/dashboard/dist/assets/tab-settings-tab-CuvH_Fj_.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-skills-tab-DR7PJ7NB.js +1 -0
- package/apps/dashboard/dist/assets/tab-skills-tab-DR7PJ7NB.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-testing-tab-CezZOZcJ.js +1 -0
- package/apps/dashboard/dist/assets/tab-testing-tab-CezZOZcJ.js.br +0 -0
- package/apps/dashboard/dist/index.html +135 -15
- package/apps/dashboard/dist/index.html.br +0 -0
- package/apps/dashboard/dist/index.html.gz +0 -0
- package/apps/vibe/README.md +2 -2
- package/apps/vibe/package.json +1 -1
- package/apps/vibe/server.mjs +101 -56
- package/crew-lead.mjs +34 -4
- package/lib/bridges/cli-executor.mjs +1 -1
- package/lib/bridges/gateway-ws.mjs +4 -0
- package/lib/browser/passthrough-stderr.js +1 -0
- package/lib/chat/project-messages.mjs +3 -5
- package/lib/cli-process-tracker.mjs +3 -2
- package/lib/contacts/identity-linker.mjs +1 -0
- package/lib/crew-judge/judge.mjs +19 -18
- package/lib/crew-lead/agent-manager.mjs +1 -1
- package/lib/crew-lead/background.mjs +14 -1
- package/lib/crew-lead/chat-handler.mjs +38 -1
- package/lib/crew-lead/http-server.mjs +106 -57
- package/lib/crew-lead/llm-caller.mjs +24 -8
- package/lib/crew-lead/prompts.mjs +14 -1
- package/lib/crew-lead/tools.mjs +3 -2
- package/lib/crew-lead/wave-dispatcher.mjs +19 -5
- package/lib/crew-lead/ws-router.mjs +219 -27
- package/lib/engines/crew-cli.mjs +1 -1
- package/lib/engines/engine-registry.mjs +14 -3
- package/lib/engines/rt-envelope.mjs +1 -0
- package/lib/engines/runners.mjs +28 -4
- package/lib/gemini-cli-passthrough-noise.mjs +1 -1
- package/lib/integrations/code-search.mjs +4 -3
- package/lib/memory/shared-adapter.mjs +23 -10
- package/lib/pipeline/manager.mjs +2 -1
- package/lib/runtime/config.mjs +1 -1
- package/lib/runtime/paths.mjs +12 -8
- package/lib/runtime/spending.mjs +2 -1
- package/package.json +42 -14
- package/scripts/capture-build-flow.mjs +118 -0
- package/scripts/coverage-report.mjs +209 -0
- package/scripts/coverage-summary.mjs +47 -0
- package/scripts/dashboard-validation.mjs +76 -0
- package/scripts/dashboard.mjs +1667 -551
- package/scripts/generate-openapi.mjs +683 -277
- package/scripts/live-bridge-matrix.mjs +79 -0
- package/scripts/live-cli-matrix.mjs +166 -0
- package/scripts/live-crewchat-check.mjs +42 -0
- package/scripts/live-engine-matrix.mjs +50 -0
- package/scripts/live-provider-failover-matrix.mjs +107 -0
- package/scripts/live-provider-matrix.mjs +228 -0
- package/scripts/restart-all-from-repo.sh +4 -4
- package/scripts/restart-service.sh +12 -9
- package/scripts/smoke-dispatch.mjs +4 -1
- package/scripts/test-blast-radius.mjs +204 -0
- package/scripts/test-report-summary.mjs +88 -0
- package/scripts/test-reporter.mjs +651 -0
- package/scripts/test-rerun.mjs +136 -0
- package/scripts/tmux-bridge +130 -0
- package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js +0 -1
- package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js.br +0 -0
- package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js +0 -1
- package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
- package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
- package/apps/dashboard/dist/assets/index-DnClJ1ee.js +0 -2
- package/apps/dashboard/dist/assets/index-DnClJ1ee.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js +0 -1
- package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-pm-loop-tab-Bfd449B4.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-projects-tab-DhNWnlzt.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js +0 -1
- package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js +0 -1
- package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js.br +0 -0
- package/apps/dashboard/index.html +0 -6529
- package/apps/dashboard/package.json +0 -15
- package/apps/dashboard/src/app.js +0 -2828
- 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 +0 -1847
- package/apps/dashboard/src/chat/chat-actions.js.br +0 -0
- package/apps/dashboard/src/chat/unified-messages.js +0 -327
- package/apps/dashboard/src/chat/unified-messages.js.br +0 -0
- package/apps/dashboard/src/cli-process.js +0 -208
- 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 +0 -175
- package/apps/dashboard/src/components/active-tasks-panel.js.br +0 -0
- package/apps/dashboard/src/core/api.js +0 -18
- package/apps/dashboard/src/core/api.js.br +0 -0
- package/apps/dashboard/src/core/dom.js +0 -228
- package/apps/dashboard/src/core/dom.js.br +0 -0
- package/apps/dashboard/src/core/state.js +0 -91
- package/apps/dashboard/src/core/state.js.br +0 -0
- package/apps/dashboard/src/core/task-manager.js +0 -134
- package/apps/dashboard/src/core/task-manager.js.br +0 -0
- package/apps/dashboard/src/orchestration-status.js +0 -127
- package/apps/dashboard/src/orchestration-status.js.br +0 -0
- package/apps/dashboard/src/setup-wizard.js +0 -562
- package/apps/dashboard/src/setup-wizard.js.br +0 -0
- package/apps/dashboard/src/styles.css +0 -2085
- 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 +0 -2237
- package/apps/dashboard/src/tabs/agents-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/benchmarks-tab.js +0 -229
- package/apps/dashboard/src/tabs/benchmarks-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/comms-tab.js +0 -955
- package/apps/dashboard/src/tabs/comms-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/contacts-tab.js +0 -654
- package/apps/dashboard/src/tabs/contacts-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/engines-tab.js +0 -175
- package/apps/dashboard/src/tabs/engines-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/memory-tab.js +0 -182
- package/apps/dashboard/src/tabs/memory-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/models-tab.js +0 -450
- package/apps/dashboard/src/tabs/models-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/pm-loop-tab.js +0 -185
- package/apps/dashboard/src/tabs/pm-loop-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/projects-tab.js +0 -663
- 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 +0 -160
- package/apps/dashboard/src/tabs/prompts-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/services-tab.js +0 -202
- package/apps/dashboard/src/tabs/services-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/settings-tab.js +0 -861
- package/apps/dashboard/src/tabs/settings-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/skills-tab.js +0 -284
- package/apps/dashboard/src/tabs/skills-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/spending-tab.js +0 -173
- package/apps/dashboard/src/tabs/spending-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/swarm-chat-tab.js +0 -660
- package/apps/dashboard/src/tabs/swarm-chat-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/swarm-tab.js +0 -538
- package/apps/dashboard/src/tabs/swarm-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/usage-tab.js +0 -390
- package/apps/dashboard/src/tabs/usage-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/waves-tab.js +0 -238
- package/apps/dashboard/src/tabs/waves-tab.js.br +0 -0
- package/apps/dashboard/src/tabs/workflows-tab.js +0 -747
- package/apps/dashboard/src/tabs/workflows-tab.js.br +0 -0
- package/apps/vibe/.crew/agent-memory/pipeline.json +0 -304
- package/apps/vibe/.crew/cost.json +0 -17
- package/apps/vibe/.crew/json-parse-metrics.jsonl +0 -27
- package/apps/vibe/.crew/pipeline-metrics.jsonl +0 -27
- package/apps/vibe/.crew/pipeline-runs/pipeline-0f90c392-2425-4ae5-850c-bd9d17b1d690.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-1c269dd9-a63f-4fba-af81-5cf08048ef06.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-2c78fd22-a657-4bd1-bc49-0679fb384409.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-3da23550-22ed-4904-9a0a-8e79c1f3024c.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-3e6fe08d-3264-404a-8df3-aab7efef10e7.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-42eec610-57fe-4e09-9e7e-b315038495c2.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-4438eb4c-ae13-42b1-90e2-b043d8983be8.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-4740a9f5-86e7-44b6-a394-de433e291727.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-49e1da6a-957e-48fd-9220-415019e4f8e2.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-4c9251db-be68-427b-a3fc-a264f2b5778d.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-6413fa33-a802-4b57-a8c0-a9056ad67842.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-65e29a57-664d-4196-8109-017e364f182e.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-6aa04bc5-9593-4b1f-b58d-3bf2978cb602.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-6e1cba53-9b70-457e-99e0-59199149dd21.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-749f41cc-4dac-4204-be64-873a6080a0d2.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-74d68121-e181-4864-bd9a-c3211341dfaf.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-8509bc24-142d-4e07-b44a-a50bf99d1103.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-960339c6-07ca-43ce-9900-f6e1702b39b9.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-9bef2dd2-6122-42e5-b3d9-19f4d80f9e40.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-9c6480a9-7031-4146-b241-825b9a2d1de1.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-9fd42426-8492-4157-9d5f-e1537c060489.jsonl +0 -2
- package/apps/vibe/.crew/pipeline-runs/pipeline-ad6d40a3-2f5e-46a9-a345-47caaccc51aa.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-bc606133-8d5b-4535-8d85-f1a29cdaa981.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-c1418f4e-b773-4ca1-84a3-216acf36e2f2.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-c1a13ccd-634a-4d01-a4a7-1177b8a752ff.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-c7d27b42-249e-4bd4-8f26-6aa998110b8a.jsonl +0 -5
- package/apps/vibe/.crew/pipeline-runs/pipeline-cca2e9b9-4a34-4d25-a311-5c793fa7e91e.jsonl +0 -5
- package/apps/vibe/.crew/sandbox.json +0 -7
- package/apps/vibe/.crew/session.json +0 -330
- package/apps/vibe/.crew/training-data.jsonl +0 -0
- package/apps/vibe/.github/workflows/studio-quality.yml +0 -37
- package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +0 -18
- package/apps/vibe/.studio-data/project-messages/general.jsonl +0 -81
- package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +0 -18
- package/apps/vibe/ARCHITECTURE.md +0 -3393
- package/apps/vibe/QUICK-REFERENCE.md +0 -211
- package/apps/vibe/ROADMAP.md +0 -41
- package/apps/vibe/STUDIO-SETUP-COMPLETE.md +0 -35
- package/apps/vibe/VISUAL-GUIDE.md +0 -378
- package/apps/vibe/capture-demo.mjs +0 -160
- package/apps/vibe/capture-full-demo.mjs +0 -255
- package/apps/vibe/capture-quickstart.mjs +0 -256
- package/apps/vibe/capture-vibe-assets.mjs +0 -71
- package/apps/vibe/capture-vibe-video.mjs +0 -260
- package/apps/vibe/check-buttons.js +0 -41
- package/apps/vibe/diagnose.html +0 -106
- package/apps/vibe/fix-buttons.js +0 -103
- package/apps/vibe/index.html +0 -3404
- package/apps/vibe/package-lock.json +0 -920
- package/apps/vibe/scripts/studio-pty-host.py +0 -117
- package/apps/vibe/src/main.js +0 -2940
- package/apps/vibe/src/register-all-languages.js +0 -98
- package/apps/vibe/start-studio.sh +0 -11
- package/apps/vibe/test/accessibility-tests.js +0 -77
- package/apps/vibe/test/browser-performance-audit.mjs +0 -205
- package/apps/vibe/test/performance-tests.js +0 -120
- package/apps/vibe/test/security-tests.js +0 -213
- package/apps/vibe/tests/e2e.local.mjs +0 -54
- package/apps/vibe/tests/server.smoke.mjs +0 -106
- package/apps/vibe/update_website.mjs +0 -74
- package/apps/vibe/vite.config.js +0 -19
- package/lib/crew-lead/chat-handler.mjs.bak +0 -1274
- package/lib/engines/rt-envelope.mjs.backup-current +0 -870
package/lib/runtime/paths.mjs
CHANGED
|
@@ -21,14 +21,16 @@ let _stateDir = null;
|
|
|
21
21
|
*/
|
|
22
22
|
export function getConfigDir() {
|
|
23
23
|
if (_configDir) return _configDir;
|
|
24
|
-
|
|
25
|
-
if (process.env.
|
|
24
|
+
|
|
25
|
+
if (process.env.CREWSWARM_CONFIG_DIR) {
|
|
26
|
+
_configDir = process.env.CREWSWARM_CONFIG_DIR;
|
|
27
|
+
} else if (process.env.CREWSWARM_TEST_MODE === "true") {
|
|
26
28
|
// Use a consistent temp dir for the entire test process (not per-call)
|
|
27
29
|
_configDir = path.join(os.tmpdir(), `crewswarm-test-${process.pid}`);
|
|
28
30
|
} else {
|
|
29
|
-
_configDir =
|
|
31
|
+
_configDir = path.join(os.homedir(), ".crewswarm");
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
|
|
32
34
|
fs.mkdirSync(_configDir, { recursive: true });
|
|
33
35
|
return _configDir;
|
|
34
36
|
}
|
|
@@ -39,14 +41,16 @@ export function getConfigDir() {
|
|
|
39
41
|
*/
|
|
40
42
|
export function getStateDir() {
|
|
41
43
|
if (_stateDir) return _stateDir;
|
|
42
|
-
|
|
43
|
-
if (process.env.
|
|
44
|
+
|
|
45
|
+
if (process.env.CREWSWARM_STATE_DIR) {
|
|
46
|
+
_stateDir = process.env.CREWSWARM_STATE_DIR;
|
|
47
|
+
} else if (process.env.CREWSWARM_TEST_MODE === "true") {
|
|
44
48
|
// Use a consistent temp dir for the entire test process (not per-call)
|
|
45
49
|
_stateDir = path.join(os.tmpdir(), `crewswarm-test-${process.pid}`);
|
|
46
50
|
} else {
|
|
47
|
-
_stateDir =
|
|
51
|
+
_stateDir = path.join(os.homedir(), ".crewswarm");
|
|
48
52
|
}
|
|
49
|
-
|
|
53
|
+
|
|
50
54
|
fs.mkdirSync(_stateDir, { recursive: true });
|
|
51
55
|
return _stateDir;
|
|
52
56
|
}
|
package/lib/runtime/spending.mjs
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import fs from "fs";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import os from "os";
|
|
9
|
+
import { getConfigPath } from "./paths.mjs";
|
|
9
10
|
|
|
10
11
|
const SPENDING_FILE = path.join(os.homedir(), ".crewswarm", "spending.json");
|
|
11
12
|
const TOKEN_USAGE_FILE = path.join(os.homedir(), ".crewswarm", "token-usage.json");
|
|
@@ -86,7 +87,7 @@ export function addAgentSpend(agentId, tokens, costUSD) {
|
|
|
86
87
|
|
|
87
88
|
export function checkSpendingCap(agentId, providerKey) {
|
|
88
89
|
try {
|
|
89
|
-
const csw = JSON.parse(fs.readFileSync(
|
|
90
|
+
const csw = JSON.parse(fs.readFileSync(getConfigPath("crewswarm.json"), "utf8"));
|
|
90
91
|
const s = loadSpending();
|
|
91
92
|
const gl = csw.globalSpendingCaps || {};
|
|
92
93
|
if (gl.dailyTokenLimit && s.global.tokens >= gl.dailyTokenLimit)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crewswarm",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "Local-first multi-agent orchestration platform — coordinate AI coding agents, LLMs, and tools from a single dashboard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,10 +29,11 @@
|
|
|
29
29
|
"engines/",
|
|
30
30
|
"prompts/",
|
|
31
31
|
"apps/dashboard/dist/",
|
|
32
|
-
"apps/
|
|
33
|
-
"apps/
|
|
34
|
-
"apps/
|
|
35
|
-
"apps/vibe/",
|
|
32
|
+
"apps/vibe/dist/",
|
|
33
|
+
"apps/vibe/package.json",
|
|
34
|
+
"apps/vibe/public/",
|
|
35
|
+
"apps/vibe/server.mjs",
|
|
36
|
+
"apps/vibe/watch-server.mjs",
|
|
36
37
|
"contrib/openclaw-plugin/",
|
|
37
38
|
"crew-lead.mjs",
|
|
38
39
|
"gateway-bridge.mjs",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"playwright": "^1.58.2",
|
|
56
57
|
"qrcode-terminal": "^0.12.0",
|
|
57
58
|
"ws": "^8.16.0",
|
|
59
|
+
"xxhash-wasm": "^1.1.0",
|
|
58
60
|
"zod": "^4.3.6"
|
|
59
61
|
},
|
|
60
62
|
"optionalDependencies": {
|
|
@@ -63,18 +65,36 @@
|
|
|
63
65
|
"scripts": {
|
|
64
66
|
"postinstall": "node -e \"try{require('child_process').execSync('git --version',{stdio:'pipe'})}catch{console.log('\\n⚠️ git not found. Install git for full functionality (WhatsApp bridge, crew-cli git tools).\\n macOS: xcode-select --install\\n Ubuntu: sudo apt install git\\n Alpine: apk add git\\n')}\"",
|
|
65
67
|
"start": "node scripts/start.mjs",
|
|
66
|
-
"test": "node --test test/unit/*.test.mjs test/mention-participants.test.mjs test/project-messages-chat-protocol.test.mjs && npm --prefix crew-cli test",
|
|
67
|
-
"test:unit": "node --test test/unit/*.test.mjs",
|
|
68
|
-
"test:integration": "PM_LOOP_TEST_MODE=1 node --test test/
|
|
68
|
+
"test": "node --test --test-reporter=./scripts/test-reporter.mjs test/unit/*.test.mjs test/mention-participants.test.mjs test/project-messages-chat-protocol.test.mjs && npm --prefix crew-cli test",
|
|
69
|
+
"test:unit": "node --test --test-reporter=./scripts/test-reporter.mjs test/unit/*.test.mjs",
|
|
70
|
+
"test:integration": "for f in test/integration/*.test.mjs; do PM_LOOP_TEST_MODE=1 node --test --test-force-exit --test-reporter=./scripts/test-reporter.mjs \"$f\"; done",
|
|
69
71
|
"test:integration:bounded": "node scripts/run-integration-bounded.mjs",
|
|
70
|
-
"test:e2e": "
|
|
71
|
-
"test:
|
|
72
|
+
"test:e2e": "npm run test:e2e:passthrough; npm run test:e2e:dashboard; npm run test:e2e:dispatch; npm run test:e2e:pipeline; npm run test:e2e:build; npm run test:e2e:bridge",
|
|
73
|
+
"test:e2e:passthrough": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/chat-passthrough-engines.test.mjs",
|
|
74
|
+
"test:e2e:dashboard": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/dashboard-lifecycle.test.mjs; node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/dashboard-tabs.test.mjs; node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/dashboard-chat-tabs.test.mjs",
|
|
75
|
+
"test:e2e:dispatch": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/live-dispatch.test.mjs; node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/surfaces-dispatch-live.test.mjs; node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/multi-engine-dispatch.test.mjs",
|
|
76
|
+
"test:e2e:pipeline": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/pipeline-waves-live.test.mjs; node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/pm-loop-live.test.mjs; node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/pm-loop-multi-engine.test.mjs",
|
|
77
|
+
"test:e2e:build": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/dashboard-build-planner-live.test.mjs",
|
|
78
|
+
"test:e2e:bridge": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/telegram-roundtrip.test.mjs test/e2e/whatsapp-roundtrip.test.mjs",
|
|
79
|
+
"test:e2e:stress": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/load-stress.test.mjs test/e2e/cron-workflow-live.test.mjs",
|
|
80
|
+
"test:all": "npm run test:unit; npm run test:integration; npm run test:e2e; npm --prefix crew-cli test",
|
|
81
|
+
"test:coverage:root": "node --test --experimental-test-coverage test/unit/*.test.mjs",
|
|
82
|
+
"test:coverage": "node scripts/coverage-report.mjs",
|
|
83
|
+
"test:coverage:summary": "node scripts/coverage-summary.mjs",
|
|
84
|
+
"test:live:providers": "node scripts/live-provider-failover-matrix.mjs",
|
|
85
|
+
"test:live:providers:matrix": "node scripts/live-provider-matrix.mjs",
|
|
86
|
+
"test:live:providers:smoke": "node scripts/live-provider-matrix.mjs --smoke",
|
|
87
|
+
"test:live:clis": "node scripts/live-cli-matrix.mjs",
|
|
88
|
+
"test:live:clis:smoke": "node scripts/live-cli-matrix.mjs --smoke",
|
|
89
|
+
"test:live:bridges": "node scripts/live-bridge-matrix.mjs",
|
|
90
|
+
"test:live:crewchat": "node scripts/live-crewchat-check.mjs",
|
|
91
|
+
"test:live": "node scripts/live-provider-failover-matrix.mjs && node scripts/live-bridge-matrix.mjs && node scripts/live-crewchat-check.mjs",
|
|
72
92
|
"docs:api": "node scripts/generate-api-docs.mjs",
|
|
73
93
|
"changelog:generate": "node scripts/generate-changelog.mjs",
|
|
74
94
|
"changelog:release": "node scripts/generate-changelog.mjs --release",
|
|
75
95
|
"accessibility:audit": "node scripts/run-accessibility-audit.mjs",
|
|
76
|
-
"load:test": "node
|
|
77
|
-
"perf:load": "node
|
|
96
|
+
"load:test": "node --test test/e2e/load-stress.test.mjs",
|
|
97
|
+
"perf:load": "node --test test/e2e/load-stress.test.mjs",
|
|
78
98
|
"perf:analyze": "python3 scripts/bench/performance_optimization.py --url http://127.0.0.1:4319/api/health --profile all",
|
|
79
99
|
"perf:analyze:offline": "python3 scripts/bench/performance_optimization.py --url http://127.0.0.1:4319/api/health --profile all --force-synthetic",
|
|
80
100
|
"test:performance:tooling": "node test/performance-tooling.test.mjs",
|
|
@@ -86,7 +106,12 @@
|
|
|
86
106
|
"stop-crew": "node scripts/start-crew.mjs --stop",
|
|
87
107
|
"dashboard": "node scripts/dashboard.mjs",
|
|
88
108
|
"vibe": "node apps/vibe/server.mjs",
|
|
89
|
-
"vibe:
|
|
109
|
+
"vibe:build": "cd apps/vibe && npm run build",
|
|
110
|
+
"vibe:start": "cd apps/vibe && NODE_DISABLE_COMPILE_CACHE=1 npm start",
|
|
111
|
+
"vibe:watch": "NODE_DISABLE_COMPILE_CACHE=1 node apps/vibe/watch-server.mjs",
|
|
112
|
+
"vibe:full": "bash scripts/start-studio-full.sh",
|
|
113
|
+
"test:e2e:vibe": "node node_modules/playwright/cli.js test --config=playwright.config.js",
|
|
114
|
+
"test:e2e:vibe:headed": "node node_modules/playwright/cli.js test --config=playwright.config.js --headed",
|
|
90
115
|
"crew-lead": "node crew-lead.mjs",
|
|
91
116
|
"mcp": "node scripts/mcp-server.mjs",
|
|
92
117
|
"studio": "cd apps/vibe && npm run dev",
|
|
@@ -100,7 +125,10 @@
|
|
|
100
125
|
"smoke:static": "bash scripts/smoke.sh",
|
|
101
126
|
"health": "node scripts/health-check.mjs",
|
|
102
127
|
"doctor": "node scripts/doctor.mjs",
|
|
103
|
-
"release:check": "bash scripts/release-check.sh"
|
|
128
|
+
"release:check": "bash scripts/release-check.sh",
|
|
129
|
+
"test:report": "node scripts/test-report-summary.mjs",
|
|
130
|
+
"test:rerun": "node scripts/test-rerun.mjs",
|
|
131
|
+
"test:stale": "node scripts/test-rerun.mjs --stale"
|
|
104
132
|
},
|
|
105
133
|
"devDependencies": {
|
|
106
134
|
"@playwright/test": "^1.58.2",
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* capture-build-flow.mjs — Puppeteer script that captures dashboard
|
|
4
|
+
* screenshots during a build flow for documentation / demo purposes.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node scripts/capture-build-flow.mjs
|
|
7
|
+
* Requires: dashboard running at http://127.0.0.1:4319
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { mkdir } from "node:fs/promises";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { dirname, resolve } from "node:path";
|
|
13
|
+
import puppeteer from "puppeteer-core";
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const ROOT = resolve(__dirname, "..");
|
|
17
|
+
const OUT_DIR = resolve(ROOT, "website/screenshots/flow");
|
|
18
|
+
const BASE_URL = "http://127.0.0.1:4319";
|
|
19
|
+
|
|
20
|
+
const STEPS = [
|
|
21
|
+
{ name: "step1-build-tab", hash: "build", waitMs: 2000 },
|
|
22
|
+
{ name: "step2-requirement", action: "type" },
|
|
23
|
+
{ name: "step3-plan", action: "plan", waitMs: 20000 },
|
|
24
|
+
{ name: "step4-chat", hash: "chat", waitMs: 3000 },
|
|
25
|
+
{ name: "step5-agents", hash: "swarm", waitMs: 2000 },
|
|
26
|
+
{ name: "step6-rt-messages", hash: "rt", waitMs: 2000 },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
async function screenshot(page, name) {
|
|
30
|
+
const path = resolve(OUT_DIR, `${name}.webp`);
|
|
31
|
+
await page.screenshot({ path, type: "webp", quality: 85 });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function sleep(ms) {
|
|
35
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function main() {
|
|
39
|
+
await mkdir(OUT_DIR, { recursive: true });
|
|
40
|
+
|
|
41
|
+
const browser = await puppeteer.launch({
|
|
42
|
+
headless: true,
|
|
43
|
+
executablePath:
|
|
44
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
45
|
+
args: ["--no-sandbox"],
|
|
46
|
+
defaultViewport: { width: 1440, height: 960 },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const page = await browser.newPage();
|
|
50
|
+
|
|
51
|
+
// Step 1 — navigate to #build
|
|
52
|
+
await page.goto(`${BASE_URL}/#build`, { waitUntil: "domcontentloaded" });
|
|
53
|
+
await sleep(2000);
|
|
54
|
+
await screenshot(page, "step1-build-tab");
|
|
55
|
+
|
|
56
|
+
// Step 2 — type requirement
|
|
57
|
+
const REQUIREMENT = "Create a simple hello world HTML page";
|
|
58
|
+
// Try a few selectors for the requirement input
|
|
59
|
+
const textareaSelector = await page
|
|
60
|
+
.waitForSelector("textarea, #requirement, .requirement-input", {
|
|
61
|
+
timeout: 5000,
|
|
62
|
+
})
|
|
63
|
+
.catch(() => null);
|
|
64
|
+
|
|
65
|
+
if (textareaSelector) {
|
|
66
|
+
await textareaSelector.click();
|
|
67
|
+
await textareaSelector.type(REQUIREMENT, { delay: 30 });
|
|
68
|
+
}
|
|
69
|
+
await screenshot(page, "step2-requirement");
|
|
70
|
+
|
|
71
|
+
// Step 3 — click Plan and wait for result
|
|
72
|
+
await page.evaluate(() => {
|
|
73
|
+
const buttons = [...document.querySelectorAll("button")];
|
|
74
|
+
const planBtn = buttons.find((b) => /plan/i.test(b.textContent));
|
|
75
|
+
if (planBtn) planBtn.click();
|
|
76
|
+
});
|
|
77
|
+
await sleep(20000);
|
|
78
|
+
await screenshot(page, "step3-plan");
|
|
79
|
+
|
|
80
|
+
// Step 4 — Chat tab
|
|
81
|
+
await page.goto(`${BASE_URL}/#chat`, { waitUntil: "domcontentloaded" });
|
|
82
|
+
await sleep(3000);
|
|
83
|
+
await screenshot(page, "step4-chat");
|
|
84
|
+
|
|
85
|
+
// Step 5 — Swarm / agents tab
|
|
86
|
+
await page.goto(`${BASE_URL}/#swarm`, { waitUntil: "domcontentloaded" });
|
|
87
|
+
await sleep(2000);
|
|
88
|
+
await screenshot(page, "step5-agents");
|
|
89
|
+
|
|
90
|
+
// Step 6 — RT messages tab
|
|
91
|
+
await page.goto(`${BASE_URL}/#rt`, { waitUntil: "domcontentloaded" });
|
|
92
|
+
await sleep(2000);
|
|
93
|
+
await screenshot(page, "step6-rt-messages");
|
|
94
|
+
|
|
95
|
+
await browser.close();
|
|
96
|
+
|
|
97
|
+
const files = [
|
|
98
|
+
"step1-build-tab.webp",
|
|
99
|
+
"step2-requirement.webp",
|
|
100
|
+
"step3-plan.webp",
|
|
101
|
+
"step4-chat.webp",
|
|
102
|
+
"step5-agents.webp",
|
|
103
|
+
"step6-rt-messages.webp",
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
console.log(`\nCaptured ${files.length} build flow frames:`);
|
|
107
|
+
for (const f of files) {
|
|
108
|
+
console.log(` website/screenshots/flow/${f}`);
|
|
109
|
+
}
|
|
110
|
+
console.log(
|
|
111
|
+
`\nTo create animated webp: convert -delay 200 website/screenshots/flow/*.webp website/screenshots/build-flow.webp`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
main().catch((err) => {
|
|
116
|
+
console.error("Build flow capture failed:", err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
|
|
7
|
+
const ROOT = process.cwd();
|
|
8
|
+
const OUT_DIR = path.join(ROOT, "coverage");
|
|
9
|
+
fs.mkdirSync(OUT_DIR, { recursive: true });
|
|
10
|
+
|
|
11
|
+
function runStep(name, command, cwd = ROOT, allowFailure = false) {
|
|
12
|
+
console.log(`\n== ${name} ==`);
|
|
13
|
+
const result = spawnSync(command, {
|
|
14
|
+
cwd,
|
|
15
|
+
shell: true,
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
env: process.env,
|
|
18
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
19
|
+
});
|
|
20
|
+
const combined = `${result.stdout || ""}${result.stderr || ""}`;
|
|
21
|
+
fs.writeFileSync(path.join(OUT_DIR, `${name}.log`), combined);
|
|
22
|
+
if (combined.trim()) process.stdout.write(combined);
|
|
23
|
+
if (result.status !== 0 && !allowFailure) {
|
|
24
|
+
throw new Error(`${name} failed with exit code ${result.status}`);
|
|
25
|
+
}
|
|
26
|
+
return { output: combined, status: result.status ?? 0 };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function extractCoverageTail(output) {
|
|
30
|
+
const lines = output.split("\n");
|
|
31
|
+
const start = lines.findIndex((line) => /^\s*file\s*\|/i.test(line) || /^\s*all files\s*\|/i.test(line));
|
|
32
|
+
if (start === -1) return "Coverage summary not found in command output.";
|
|
33
|
+
return lines.slice(start).join("\n").trim();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Parse the "all files" summary line from Node's --experimental-test-coverage output.
|
|
38
|
+
* Format: `ℹ all files | <line%> | <branch%> | <funcs%> |`
|
|
39
|
+
* Returns { lines, branches, functions } or null if not found.
|
|
40
|
+
*/
|
|
41
|
+
function parseCoverageSummary(output) {
|
|
42
|
+
const lines = output.split("\n");
|
|
43
|
+
for (const line of lines) {
|
|
44
|
+
const match = line.match(/all files\s*\|\s*([\d.]+)\s*\|\s*([\d.]+)\s*\|\s*([\d.]+)/);
|
|
45
|
+
if (match) {
|
|
46
|
+
return {
|
|
47
|
+
lines: parseFloat(match[1]),
|
|
48
|
+
branches: parseFloat(match[2]),
|
|
49
|
+
functions: parseFloat(match[3]),
|
|
50
|
+
// Node's built-in coverage reports line% (which is effectively statements)
|
|
51
|
+
statements: parseFloat(match[1]),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Compute a weighted average of two metric objects.
|
|
60
|
+
* Uses a simple average (equal weight) since we don't have file counts per suite.
|
|
61
|
+
*/
|
|
62
|
+
function averageMetrics(a, b) {
|
|
63
|
+
if (!a && !b) return { statements: 0, branches: 0, functions: 0, lines: 0 };
|
|
64
|
+
if (!a) return b;
|
|
65
|
+
if (!b) return a;
|
|
66
|
+
const round1 = (n) => Math.round(n * 10) / 10;
|
|
67
|
+
return {
|
|
68
|
+
statements: round1((a.statements + b.statements) / 2),
|
|
69
|
+
branches: round1((a.branches + b.branches) / 2),
|
|
70
|
+
functions: round1((a.functions + b.functions) / 2),
|
|
71
|
+
lines: round1((a.lines + b.lines) / 2),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const rootCoverage = runStep(
|
|
77
|
+
"root-unit-coverage",
|
|
78
|
+
"node --test --experimental-test-coverage test/unit/*.test.mjs"
|
|
79
|
+
);
|
|
80
|
+
const rootIntegration = runStep(
|
|
81
|
+
"root-integration-bounded",
|
|
82
|
+
"node scripts/run-integration-bounded.mjs",
|
|
83
|
+
ROOT,
|
|
84
|
+
true
|
|
85
|
+
);
|
|
86
|
+
const crewCliCoverage = runStep(
|
|
87
|
+
"crew-cli-coverage",
|
|
88
|
+
"npm run test:coverage",
|
|
89
|
+
path.join(ROOT, "crew-cli")
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Parse metrics from each suite
|
|
93
|
+
const rootMetrics = parseCoverageSummary(rootCoverage.output);
|
|
94
|
+
const crewCliMetrics = parseCoverageSummary(crewCliCoverage.output);
|
|
95
|
+
const overallMetrics = averageMetrics(rootMetrics, crewCliMetrics);
|
|
96
|
+
|
|
97
|
+
// Build machine-readable summary JSON
|
|
98
|
+
const summaryJson = {
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
root: rootMetrics
|
|
101
|
+
? { statements: rootMetrics.statements, branches: rootMetrics.branches, functions: rootMetrics.functions, lines: rootMetrics.lines }
|
|
102
|
+
: null,
|
|
103
|
+
crewCli: crewCliMetrics
|
|
104
|
+
? { statements: crewCliMetrics.statements, branches: crewCliMetrics.branches, functions: crewCliMetrics.functions, lines: crewCliMetrics.lines }
|
|
105
|
+
: null,
|
|
106
|
+
overall: overallMetrics
|
|
107
|
+
? { statements: overallMetrics.statements, branches: overallMetrics.branches, functions: overallMetrics.functions, lines: overallMetrics.lines }
|
|
108
|
+
: null,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const summaryPath = path.join(OUT_DIR, "coverage-summary.json");
|
|
112
|
+
fs.writeFileSync(summaryPath, JSON.stringify(summaryJson, null, 2) + "\n");
|
|
113
|
+
|
|
114
|
+
// Build markdown report
|
|
115
|
+
function metricsTable(metrics) {
|
|
116
|
+
if (!metrics) return "Coverage metrics could not be parsed.";
|
|
117
|
+
return `| Metric | Value |
|
|
118
|
+
|------------|---------|
|
|
119
|
+
| Statements | ${metrics.statements.toFixed(1)}% |
|
|
120
|
+
| Branches | ${metrics.branches.toFixed(1)}% |
|
|
121
|
+
| Functions | ${metrics.functions.toFixed(1)}% |
|
|
122
|
+
| Lines | ${metrics.lines.toFixed(1)}% |`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const report = `# Repo Coverage Report
|
|
126
|
+
|
|
127
|
+
Generated: ${summaryJson.timestamp}
|
|
128
|
+
|
|
129
|
+
## Root unit coverage
|
|
130
|
+
|
|
131
|
+
${metricsTable(rootMetrics)}
|
|
132
|
+
|
|
133
|
+
<details><summary>Full file-by-file report</summary>
|
|
134
|
+
|
|
135
|
+
\`\`\`
|
|
136
|
+
${extractCoverageTail(rootCoverage.output)}
|
|
137
|
+
\`\`\`
|
|
138
|
+
|
|
139
|
+
</details>
|
|
140
|
+
|
|
141
|
+
## Root integration verification
|
|
142
|
+
|
|
143
|
+
Exit code: ${rootIntegration.status}
|
|
144
|
+
|
|
145
|
+
<details><summary>Output</summary>
|
|
146
|
+
|
|
147
|
+
\`\`\`
|
|
148
|
+
${rootIntegration.output.trim() || "No output."}
|
|
149
|
+
\`\`\`
|
|
150
|
+
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
## crew-cli coverage
|
|
154
|
+
|
|
155
|
+
${metricsTable(crewCliMetrics)}
|
|
156
|
+
|
|
157
|
+
<details><summary>Full file-by-file report</summary>
|
|
158
|
+
|
|
159
|
+
\`\`\`
|
|
160
|
+
${extractCoverageTail(crewCliCoverage.output)}
|
|
161
|
+
\`\`\`
|
|
162
|
+
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
## Overall (average across suites)
|
|
166
|
+
|
|
167
|
+
${metricsTable(overallMetrics)}
|
|
168
|
+
|
|
169
|
+
## Notes
|
|
170
|
+
|
|
171
|
+
- Root coverage currently reports hermetic unit coverage only.
|
|
172
|
+
- Integration and E2E surfaces are reported separately because many depend on running services or external credentials.
|
|
173
|
+
- Use \`docs/CANONICAL/COVERAGE-MATRIX.md\` for feature-by-feature status.
|
|
174
|
+
- Machine-readable metrics: \`coverage/coverage-summary.json\`
|
|
175
|
+
|
|
176
|
+
## Logs
|
|
177
|
+
|
|
178
|
+
- coverage/root-unit-coverage.log
|
|
179
|
+
- coverage/root-integration-bounded.log
|
|
180
|
+
- coverage/crew-cli-coverage.log
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
const reportPath = path.join(OUT_DIR, "coverage-report.md");
|
|
184
|
+
fs.writeFileSync(reportPath, report);
|
|
185
|
+
|
|
186
|
+
// Print summary to stdout
|
|
187
|
+
console.log("\n========================================");
|
|
188
|
+
console.log(" Coverage Summary");
|
|
189
|
+
console.log("========================================");
|
|
190
|
+
if (rootMetrics) {
|
|
191
|
+
console.log(` Root: ${rootMetrics.lines.toFixed(1)}% lines | ${rootMetrics.branches.toFixed(1)}% branches | ${rootMetrics.functions.toFixed(1)}% funcs`);
|
|
192
|
+
} else {
|
|
193
|
+
console.log(" Root: (metrics not available)");
|
|
194
|
+
}
|
|
195
|
+
if (crewCliMetrics) {
|
|
196
|
+
console.log(` crew-cli: ${crewCliMetrics.lines.toFixed(1)}% lines | ${crewCliMetrics.branches.toFixed(1)}% branches | ${crewCliMetrics.functions.toFixed(1)}% funcs`);
|
|
197
|
+
} else {
|
|
198
|
+
console.log(" crew-cli: (metrics not available)");
|
|
199
|
+
}
|
|
200
|
+
if (overallMetrics) {
|
|
201
|
+
console.log(` Overall: ${overallMetrics.lines.toFixed(1)}% lines | ${overallMetrics.branches.toFixed(1)}% branches | ${overallMetrics.functions.toFixed(1)}% funcs`);
|
|
202
|
+
}
|
|
203
|
+
console.log("========================================");
|
|
204
|
+
console.log(`\nWrote ${path.relative(ROOT, reportPath)}`);
|
|
205
|
+
console.log(`Wrote ${path.relative(ROOT, summaryPath)}`);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error(`\nCoverage report failed: ${error.message}`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Prints the most recent coverage summary from coverage/coverage-summary.json
|
|
5
|
+
* without re-running any tests.
|
|
6
|
+
*
|
|
7
|
+
* Usage: node scripts/coverage-summary.mjs
|
|
8
|
+
* or: npm run test:coverage:summary
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
|
|
14
|
+
const ROOT = process.cwd();
|
|
15
|
+
const summaryPath = path.join(ROOT, "coverage", "coverage-summary.json");
|
|
16
|
+
|
|
17
|
+
if (!fs.existsSync(summaryPath)) {
|
|
18
|
+
console.error(
|
|
19
|
+
`No coverage summary found at ${summaryPath}\n` +
|
|
20
|
+
`Run "npm run test:coverage" first to generate coverage data.`
|
|
21
|
+
);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let data;
|
|
26
|
+
try {
|
|
27
|
+
data = JSON.parse(fs.readFileSync(summaryPath, "utf8"));
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.error(`Failed to parse ${summaryPath}: ${err.message}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function fmtRow(label, metrics) {
|
|
34
|
+
if (!metrics) return ` ${label.padEnd(12)} (no data)`;
|
|
35
|
+
return ` ${label.padEnd(12)} ${String(metrics.lines.toFixed(1) + "%").padStart(7)} lines | ${String(metrics.branches.toFixed(1) + "%").padStart(7)} branches | ${String(metrics.functions.toFixed(1) + "%").padStart(7)} funcs`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log("========================================");
|
|
39
|
+
console.log(" Coverage Summary");
|
|
40
|
+
console.log(` Generated: ${data.timestamp}`);
|
|
41
|
+
console.log("========================================");
|
|
42
|
+
console.log(fmtRow("Root", data.root));
|
|
43
|
+
console.log(fmtRow("crew-cli", data.crewCli));
|
|
44
|
+
console.log(fmtRow("Overall", data.overall));
|
|
45
|
+
console.log("========================================");
|
|
46
|
+
console.log(`\nFull report: coverage/coverage-report.md`);
|
|
47
|
+
console.log(`JSON data: coverage/coverage-summary.json`);
|
|
@@ -88,6 +88,13 @@ export const StartBuildSchema = z.object({
|
|
|
88
88
|
projectId: ProjectIdSchema.optional(),
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
export const EnhancePromptSchema = z.object({
|
|
92
|
+
text: z.string().min(1).max(10000),
|
|
93
|
+
projectId: ProjectIdSchema.optional(),
|
|
94
|
+
engine: z.enum(['claude', 'codex', 'cursor', 'gemini', 'gemini-cli', 'opencode', 'crew-cli']).optional(),
|
|
95
|
+
model: z.string().max(200).optional(),
|
|
96
|
+
});
|
|
97
|
+
|
|
91
98
|
export const StopBuildSchema = z.object({
|
|
92
99
|
projectId: ProjectIdSchema.optional(),
|
|
93
100
|
});
|
|
@@ -149,6 +156,8 @@ export const ServiceActionSchema = z.object({
|
|
|
149
156
|
'mcp',
|
|
150
157
|
'openclaw-gateway',
|
|
151
158
|
'dashboard',
|
|
159
|
+
'studio',
|
|
160
|
+
'studio-watch',
|
|
152
161
|
]),
|
|
153
162
|
});
|
|
154
163
|
|
|
@@ -187,6 +196,73 @@ export const UpdateConfigSchema = z.object({
|
|
|
187
196
|
geminiCliModel: z.string().optional(),
|
|
188
197
|
});
|
|
189
198
|
|
|
199
|
+
// ── Agent Config (create / delete / reset) ───────────────────────────────
|
|
200
|
+
export const AgentConfigCreateSchema = z.object({
|
|
201
|
+
id: z.string().min(1).max(50),
|
|
202
|
+
model: ModelNameSchema.optional(),
|
|
203
|
+
name: z.string().max(100).optional(),
|
|
204
|
+
emoji: z.string().max(10).optional(),
|
|
205
|
+
theme: z.string().max(200).optional(),
|
|
206
|
+
systemPrompt: z.string().max(50000).optional(),
|
|
207
|
+
alsoAllow: z.array(z.string()).optional(),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
export const AgentConfigDeleteSchema = z.object({
|
|
211
|
+
agentId: z.string().min(1).max(50),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
export const AgentResetSessionSchema = z.object({
|
|
215
|
+
agentId: z.string().min(1).max(50),
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// ── Providers ────────────────────────────────────────────────────────────
|
|
219
|
+
export const ProviderAddSchema = z.object({
|
|
220
|
+
id: z.string().min(1).max(100),
|
|
221
|
+
baseUrl: z.string().min(1).max(1000),
|
|
222
|
+
apiKey: z.string().optional(),
|
|
223
|
+
api: z.string().max(100).optional(),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
export const ProviderSaveSchema = z.object({
|
|
227
|
+
providerId: z.string().min(1).max(100),
|
|
228
|
+
apiKey: z.string().min(1),
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
export const ProviderTestSchema = z.object({
|
|
232
|
+
providerId: z.string().min(1).max(100),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
export const ProviderBuiltinTestSchema = z.object({
|
|
236
|
+
providerId: z.string().min(1).max(100),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// ── Continuous Build ─────────────────────────────────────────────────────
|
|
240
|
+
export const ContinuousBuildSchema = z.object({
|
|
241
|
+
requirement: z.string().min(1).max(10000),
|
|
242
|
+
projectId: ProjectIdSchema.optional(),
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// ── Roadmap ──────────────────────────────────────────────────────────────
|
|
246
|
+
export const RoadmapWriteSchema = z.object({
|
|
247
|
+
roadmapFile: z.string().min(1).max(500),
|
|
248
|
+
content: z.string(),
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
export const RoadmapRetryFailedSchema = z.object({
|
|
252
|
+
roadmapFile: z.string().min(1).max(500),
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// ── Contacts ─────────────────────────────────────────────────────────────
|
|
256
|
+
export const ContactDeleteSchema = z.object({
|
|
257
|
+
contactId: z.string().min(1).max(200),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
export const ContactSendSchema = z.object({
|
|
261
|
+
contactId: z.string().min(1).max(200),
|
|
262
|
+
message: z.string().min(1).max(10000),
|
|
263
|
+
platform: z.string().max(50).optional(),
|
|
264
|
+
});
|
|
265
|
+
|
|
190
266
|
// ── Validation Helper ─────────────────────────────────────────────────────
|
|
191
267
|
export function validate(schema, data) {
|
|
192
268
|
try {
|