kynjal-cli 3.1.4 → 4.0.1
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/.claude/agents/core/coder.md +1 -1
- package/.claude/agents/core/planner.md +2 -2
- package/.claude/agents/core/researcher.md +1 -1
- package/.claude/agents/core/reviewer.md +1 -1
- package/.claude/agents/core/tester.md +1 -1
- package/.claude/agents/data/data-ml-model.md +4 -4
- package/.claude/agents/development/dev-backend-api.md +4 -4
- package/.claude/agents/documentation/docs-api-openapi.md +4 -4
- package/.claude/agents/github/code-review-swarm.md +2 -2
- package/.claude/agents/github/issue-tracker.md +2 -2
- package/.claude/agents/github/pr-manager.md +2 -2
- package/.claude/agents/github/release-manager.md +2 -2
- package/.claude/agents/github/workflow-automation.md +2 -2
- package/.claude/agents/sparc/architecture.md +3 -3
- package/.claude/agents/sparc/pseudocode.md +2 -2
- package/.claude/agents/sparc/refinement.md +3 -3
- package/.claude/agents/sparc/specification.md +2 -2
- package/.claude/agents/swarm/adaptive-coordinator.md +1 -1
- package/.claude/agents/swarm/hierarchical-coordinator.md +1 -1
- package/.claude/agents/swarm/mesh-coordinator.md +1 -1
- package/.claude/agents/templates/base-template-generator.md +25 -4
- package/.claude/agents/templates/sparc-coordinator.md +3 -3
- package/.claude/helpers/auto-commit.sh +1 -1
- package/.claude/helpers/auto-memory-hook.mjs +27 -9
- package/.claude/helpers/hook-handler.cjs +58 -18
- package/.claude/helpers/statusline.cjs +420 -613
- package/.claude/helpers/statusline.js +3 -3
- package/.claude/settings.json +9 -9
- package/.claude/skills/reasoningbank-intelligence/SKILL.md +2 -2
- package/.claude/skills/swarm-orchestration/SKILL.md +1 -1
- package/README.md +383 -170
- package/bin/cli.js +6 -6
- package/bin/mcp-server.js +1 -1
- package/bin/preinstall.cjs +2 -0
- package/dist/src/appliance/gguf-engine.d.ts +91 -0
- package/dist/src/appliance/gguf-engine.d.ts.map +1 -0
- package/dist/src/appliance/gguf-engine.js +425 -0
- package/dist/src/appliance/gguf-engine.js.map +1 -0
- package/dist/src/appliance/ruvllm-bridge.d.ts +102 -0
- package/dist/src/appliance/ruvllm-bridge.d.ts.map +1 -0
- package/dist/src/appliance/ruvllm-bridge.js +292 -0
- package/dist/src/appliance/ruvllm-bridge.js.map +1 -0
- package/dist/src/appliance/rvfa-builder.d.ts +44 -0
- package/dist/src/appliance/rvfa-builder.d.ts.map +1 -0
- package/dist/src/appliance/rvfa-builder.js +329 -0
- package/dist/src/appliance/rvfa-builder.js.map +1 -0
- package/dist/src/appliance/rvfa-distribution.d.ts +97 -0
- package/dist/src/appliance/rvfa-distribution.d.ts.map +1 -0
- package/dist/src/appliance/rvfa-distribution.js +370 -0
- package/dist/src/appliance/rvfa-distribution.js.map +1 -0
- package/dist/src/appliance/rvfa-format.d.ts +111 -0
- package/dist/src/appliance/rvfa-format.d.ts.map +1 -0
- package/dist/src/appliance/rvfa-format.js +393 -0
- package/dist/src/appliance/rvfa-format.js.map +1 -0
- package/dist/src/appliance/rvfa-runner.d.ts +69 -0
- package/dist/src/appliance/rvfa-runner.d.ts.map +1 -0
- package/dist/src/appliance/rvfa-runner.js +237 -0
- package/dist/src/appliance/rvfa-runner.js.map +1 -0
- package/dist/src/appliance/rvfa-signing.d.ts +123 -0
- package/dist/src/appliance/rvfa-signing.d.ts.map +1 -0
- package/dist/src/appliance/rvfa-signing.js +347 -0
- package/dist/src/appliance/rvfa-signing.js.map +1 -0
- package/dist/src/commands/agent.d.ts.map +1 -1
- package/dist/src/commands/agent.js +121 -21
- package/dist/src/commands/agent.js.map +1 -1
- package/dist/src/commands/appliance-advanced.d.ts +9 -0
- package/dist/src/commands/appliance-advanced.d.ts.map +1 -0
- package/dist/src/commands/appliance-advanced.js +215 -0
- package/dist/src/commands/appliance-advanced.js.map +1 -0
- package/dist/src/commands/appliance.d.ts +8 -0
- package/dist/src/commands/appliance.d.ts.map +1 -0
- package/dist/src/commands/appliance.js +406 -0
- package/dist/src/commands/appliance.js.map +1 -0
- package/dist/src/commands/benchmark.js +2 -2
- package/dist/src/commands/benchmark.js.map +1 -1
- package/dist/src/commands/claims.js +1 -1
- package/dist/src/commands/claims.js.map +1 -1
- package/dist/src/commands/cleanup.d.ts +13 -0
- package/dist/src/commands/cleanup.d.ts.map +1 -0
- package/dist/src/commands/cleanup.js +218 -0
- package/dist/src/commands/cleanup.js.map +1 -0
- package/dist/src/commands/config.js +1 -1
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/daemon.d.ts.map +1 -1
- package/dist/src/commands/daemon.js +81 -18
- package/dist/src/commands/daemon.js.map +1 -1
- package/dist/src/commands/deployment.js +1 -1
- package/dist/src/commands/deployment.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +99 -51
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/embeddings.js +1 -1
- package/dist/src/commands/embeddings.js.map +1 -1
- package/dist/src/commands/hive-mind.js +26 -26
- package/dist/src/commands/hive-mind.js.map +1 -1
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/hooks.js +800 -100
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/commands/index.d.ts +9 -2
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +20 -2
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init.d.ts +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +22 -18
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/mcp.d.ts.map +1 -1
- package/dist/src/commands/mcp.js +23 -5
- package/dist/src/commands/mcp.js.map +1 -1
- package/dist/src/commands/memory.d.ts.map +1 -1
- package/dist/src/commands/memory.js +24 -0
- package/dist/src/commands/memory.js.map +1 -1
- package/dist/src/commands/neural.d.ts.map +1 -1
- package/dist/src/commands/neural.js +13 -7
- package/dist/src/commands/neural.js.map +1 -1
- package/dist/src/commands/performance.js +1 -1
- package/dist/src/commands/performance.js.map +1 -1
- package/dist/src/commands/plugins.js +1 -1
- package/dist/src/commands/plugins.js.map +1 -1
- package/dist/src/commands/providers.js +1 -1
- package/dist/src/commands/providers.js.map +1 -1
- package/dist/src/commands/ruvector/import.js +2 -2
- package/dist/src/commands/ruvector/import.js.map +1 -1
- package/dist/src/commands/ruvector/index.js +1 -1
- package/dist/src/commands/ruvector/index.js.map +1 -1
- package/dist/src/commands/ruvector/setup.js +6 -6
- package/dist/src/commands/security.d.ts.map +1 -1
- package/dist/src/commands/security.js +47 -16
- package/dist/src/commands/security.js.map +1 -1
- package/dist/src/commands/session.d.ts +1 -1
- package/dist/src/commands/session.js +1 -1
- package/dist/src/commands/start.d.ts +1 -1
- package/dist/src/commands/start.js +12 -12
- package/dist/src/commands/start.js.map +1 -1
- package/dist/src/commands/status.d.ts +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/status.js +13 -6
- package/dist/src/commands/status.js.map +1 -1
- package/dist/src/commands/swarm.js +2 -2
- package/dist/src/commands/swarm.js.map +1 -1
- package/dist/src/commands/task.d.ts +1 -1
- package/dist/src/commands/task.js +1 -1
- package/dist/src/commands/transfer-store.js +1 -1
- package/dist/src/commands/transfer-store.js.map +1 -1
- package/dist/src/config-adapter.js +1 -1
- package/dist/src/config-adapter.js.map +1 -1
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/init/claudemd-generator.js +30 -30
- package/dist/src/init/claudemd-generator.js.map +1 -1
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +86 -101
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/helpers-generator.d.ts.map +1 -1
- package/dist/src/init/helpers-generator.js +96 -26
- package/dist/src/init/helpers-generator.js.map +1 -1
- package/dist/src/init/mcp-generator.d.ts +0 -1
- package/dist/src/init/mcp-generator.d.ts.map +1 -1
- package/dist/src/init/mcp-generator.js +34 -18
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/init/settings-generator.d.ts.map +1 -1
- package/dist/src/init/settings-generator.js +107 -41
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/init/statusline-generator.d.ts +16 -8
- package/dist/src/init/statusline-generator.d.ts.map +1 -1
- package/dist/src/init/statusline-generator.js +537 -1019
- package/dist/src/init/statusline-generator.js.map +1 -1
- package/dist/src/init/types.d.ts +14 -4
- package/dist/src/init/types.d.ts.map +1 -1
- package/dist/src/init/types.js +9 -2
- package/dist/src/init/types.js.map +1 -1
- package/dist/src/mcp-client.d.ts.map +1 -1
- package/dist/src/mcp-client.js +10 -0
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +30 -4
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/agentdb-tools.d.ts +30 -0
- package/dist/src/mcp-tools/agentdb-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/agentdb-tools.js +557 -0
- package/dist/src/mcp-tools/agentdb-tools.js.map +1 -0
- package/dist/src/mcp-tools/browser-tools.js +2 -2
- package/dist/src/mcp-tools/browser-tools.js.map +1 -1
- package/dist/src/mcp-tools/config-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/config-tools.js +21 -2
- package/dist/src/mcp-tools/config-tools.js.map +1 -1
- package/dist/src/mcp-tools/coordination-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/coordination-tools.js +192 -13
- package/dist/src/mcp-tools/coordination-tools.js.map +1 -1
- package/dist/src/mcp-tools/daa-tools.js +5 -5
- package/dist/src/mcp-tools/daa-tools.js.map +1 -1
- package/dist/src/mcp-tools/github-tools.js +2 -2
- package/dist/src/mcp-tools/github-tools.js.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +263 -35
- package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.js +355 -40
- package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +2 -0
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +2 -0
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/memory-tools.js +31 -1
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/mcp-tools/neural-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/neural-tools.js +32 -27
- package/dist/src/mcp-tools/neural-tools.js.map +1 -1
- package/dist/src/mcp-tools/performance-tools.js +1 -1
- package/dist/src/mcp-tools/performance-tools.js.map +1 -1
- package/dist/src/mcp-tools/ruvllm-tools.d.ts +9 -0
- package/dist/src/mcp-tools/ruvllm-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/ruvllm-tools.js +283 -0
- package/dist/src/mcp-tools/ruvllm-tools.js.map +1 -0
- package/dist/src/mcp-tools/swarm-tools.d.ts +2 -1
- package/dist/src/mcp-tools/swarm-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/swarm-tools.js +216 -30
- package/dist/src/mcp-tools/swarm-tools.js.map +1 -1
- package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/system-tools.js +109 -6
- package/dist/src/mcp-tools/system-tools.js.map +1 -1
- package/dist/src/mcp-tools/task-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/task-tools.js +102 -0
- package/dist/src/mcp-tools/task-tools.js.map +1 -1
- package/dist/src/mcp-tools/wasm-agent-tools.d.ts +9 -0
- package/dist/src/mcp-tools/wasm-agent-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/wasm-agent-tools.js +230 -0
- package/dist/src/mcp-tools/wasm-agent-tools.js.map +1 -0
- package/dist/src/mcp-tools/workflow-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/workflow-tools.js +91 -0
- package/dist/src/mcp-tools/workflow-tools.js.map +1 -1
- package/dist/src/memory/ewc-consolidation.d.ts +24 -0
- package/dist/src/memory/ewc-consolidation.d.ts.map +1 -1
- package/dist/src/memory/ewc-consolidation.js +59 -0
- package/dist/src/memory/ewc-consolidation.js.map +1 -1
- package/dist/src/memory/intelligence.d.ts +53 -0
- package/dist/src/memory/intelligence.d.ts.map +1 -1
- package/dist/src/memory/intelligence.js +264 -7
- package/dist/src/memory/intelligence.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts +407 -0
- package/dist/src/memory/memory-bridge.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge.js +1494 -0
- package/dist/src/memory/memory-bridge.js.map +1 -0
- package/dist/src/memory/memory-initializer.d.ts +17 -1
- package/dist/src/memory/memory-initializer.d.ts.map +1 -1
- package/dist/src/memory/memory-initializer.js +320 -42
- package/dist/src/memory/memory-initializer.js.map +1 -1
- package/dist/src/output.d.ts.map +1 -1
- package/dist/src/output.js +1 -0
- package/dist/src/output.js.map +1 -1
- package/dist/src/parser.d.ts +10 -0
- package/dist/src/parser.d.ts.map +1 -1
- package/dist/src/parser.js +49 -3
- package/dist/src/parser.js.map +1 -1
- package/dist/src/plugins/manager.d.ts.map +1 -1
- package/dist/src/plugins/manager.js +31 -14
- package/dist/src/plugins/manager.js.map +1 -1
- package/dist/src/plugins/store/discovery.js +5 -5
- package/dist/src/plugins/store/discovery.js.map +1 -1
- package/dist/src/plugins/tests/standalone-test.js +4 -4
- package/dist/src/plugins/tests/standalone-test.js.map +1 -1
- package/dist/src/production/error-handler.js +1 -1
- package/dist/src/production/error-handler.js.map +1 -1
- package/dist/src/runtime/headless.d.ts +3 -3
- package/dist/src/runtime/headless.js +6 -6
- package/dist/src/runtime/headless.js.map +1 -1
- package/dist/src/ruvector/agent-wasm.d.ts +182 -0
- package/dist/src/ruvector/agent-wasm.d.ts.map +1 -0
- package/dist/src/ruvector/agent-wasm.js +316 -0
- package/dist/src/ruvector/agent-wasm.js.map +1 -0
- package/dist/src/ruvector/enhanced-model-router.d.ts.map +1 -1
- package/dist/src/ruvector/enhanced-model-router.js +25 -15
- package/dist/src/ruvector/enhanced-model-router.js.map +1 -1
- package/dist/src/ruvector/index.d.ts +7 -1
- package/dist/src/ruvector/index.d.ts.map +1 -1
- package/dist/src/ruvector/index.js +17 -1
- package/dist/src/ruvector/index.js.map +1 -1
- package/dist/src/ruvector/ruvllm-wasm.d.ts +179 -0
- package/dist/src/ruvector/ruvllm-wasm.d.ts.map +1 -0
- package/dist/src/ruvector/ruvllm-wasm.js +363 -0
- package/dist/src/ruvector/ruvllm-wasm.js.map +1 -0
- package/dist/src/services/agentic-flow-bridge.d.ts +50 -0
- package/dist/src/services/agentic-flow-bridge.d.ts.map +1 -0
- package/dist/src/services/agentic-flow-bridge.js +95 -0
- package/dist/src/services/agentic-flow-bridge.js.map +1 -0
- package/dist/src/services/claim-service.js +1 -1
- package/dist/src/services/claim-service.js.map +1 -1
- package/dist/src/services/container-worker-pool.d.ts.map +1 -1
- package/dist/src/services/container-worker-pool.js +3 -1
- package/dist/src/services/container-worker-pool.js.map +1 -1
- package/dist/src/services/index.d.ts +1 -1
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/registry-api.d.ts +1 -1
- package/dist/src/services/registry-api.js +1 -1
- package/dist/src/services/ruvector-training.d.ts +11 -2
- package/dist/src/services/ruvector-training.d.ts.map +1 -1
- package/dist/src/services/ruvector-training.js +233 -43
- package/dist/src/services/ruvector-training.js.map +1 -1
- package/dist/src/services/worker-daemon.d.ts +28 -3
- package/dist/src/services/worker-daemon.d.ts.map +1 -1
- package/dist/src/services/worker-daemon.js +156 -17
- package/dist/src/services/worker-daemon.js.map +1 -1
- package/dist/src/services/worker-queue.d.ts.map +1 -1
- package/dist/src/services/worker-queue.js +2 -0
- package/dist/src/services/worker-queue.js.map +1 -1
- package/dist/src/transfer/deploy-seraphine.d.ts +1 -1
- package/dist/src/transfer/deploy-seraphine.js +4 -4
- package/dist/src/transfer/deploy-seraphine.js.map +1 -1
- package/dist/src/transfer/ipfs/client.d.ts.map +1 -1
- package/dist/src/transfer/ipfs/client.js +8 -0
- package/dist/src/transfer/ipfs/client.js.map +1 -1
- package/dist/src/transfer/ipfs/upload.d.ts.map +1 -1
- package/dist/src/transfer/ipfs/upload.js +0 -2
- package/dist/src/transfer/ipfs/upload.js.map +1 -1
- package/dist/src/transfer/models/seraphine.d.ts +1 -1
- package/dist/src/transfer/models/seraphine.js +5 -5
- package/dist/src/transfer/models/seraphine.js.map +1 -1
- package/dist/src/transfer/serialization/cfp.d.ts +1 -1
- package/dist/src/transfer/serialization/cfp.d.ts.map +1 -1
- package/dist/src/transfer/serialization/cfp.js +9 -6
- package/dist/src/transfer/serialization/cfp.js.map +1 -1
- package/dist/src/transfer/storage/gcs.d.ts.map +1 -1
- package/dist/src/transfer/storage/gcs.js +71 -29
- package/dist/src/transfer/storage/gcs.js.map +1 -1
- package/dist/src/transfer/store/discovery.js +4 -4
- package/dist/src/transfer/store/discovery.js.map +1 -1
- package/dist/src/transfer/store/registry.js +1 -1
- package/dist/src/transfer/store/registry.js.map +1 -1
- package/dist/src/transfer/store/tests/standalone-test.js +4 -4
- package/dist/src/transfer/store/tests/standalone-test.js.map +1 -1
- package/dist/src/transfer/types.d.ts +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.js +1 -1
- package/dist/src/update/validator.js +1 -1
- package/dist/src/update/validator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -10
- package/.claude/agents/custom/accessibility-auditor.yaml +0 -56
- package/.claude/agents/custom/design-architect.yaml +0 -48
- package/.claude/agents/custom/ui-developer.yaml +0 -46
- package/.claude/agents/custom/ux-researcher.yaml +0 -60
|
@@ -1,48 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Statusline Configuration Generator
|
|
3
|
-
* Creates statusline
|
|
2
|
+
* Statusline Configuration Generator (Optimized)
|
|
3
|
+
* Creates fast, reliable statusline for V3 progress display
|
|
4
|
+
*
|
|
5
|
+
* Performance:
|
|
6
|
+
* - Single combined git execSync call (not 8+ separate ones)
|
|
7
|
+
* - process.memoryUsage() instead of ps aux
|
|
8
|
+
* - No recursive test file content reading
|
|
9
|
+
* - Shared settings cache
|
|
10
|
+
* - Strict 2s timeouts on all shell calls
|
|
4
11
|
*/
|
|
5
12
|
/**
|
|
6
|
-
* Generate statusline
|
|
7
|
-
*
|
|
8
|
-
* ▊
|
|
13
|
+
* Generate optimized statusline script
|
|
14
|
+
* Output format:
|
|
15
|
+
* ▊ RuFlo V3.5 ● user │ ⎇ branch │ Opus 4.6 (1M context)
|
|
9
16
|
* ─────────────────────────────────────────────────────
|
|
10
|
-
* 🏗️ DDD Domains [
|
|
11
|
-
* 🤖 Swarm ◉ [
|
|
12
|
-
* 🔧 Architecture
|
|
17
|
+
* 🏗️ DDD Domains [●●○○○] 2/5 ⚡ HNSW 150x
|
|
18
|
+
* 🤖 Swarm ◉ [ 5/15] 👥 2 🪝 10/17 🟢 CVE 3/3 💾 4MB 🧠 63%
|
|
19
|
+
* 🔧 Architecture ADRs ●71% │ DDD ● 13% │ Security ●CLEAN
|
|
20
|
+
* 📊 AgentDB Vectors ●3104⚡ │ Size 216KB │ Tests ●6 (~24 cases) │ MCP ●1/1
|
|
13
21
|
*/
|
|
14
22
|
export function generateStatuslineScript(options) {
|
|
15
|
-
const
|
|
16
|
-
// Generate CommonJS script - use .cjs extension for ES module project compatibility
|
|
23
|
+
const maxAgents = options.runtime.maxAgents;
|
|
17
24
|
return `#!/usr/bin/env node
|
|
18
25
|
/**
|
|
19
|
-
*
|
|
26
|
+
* RuFlo V3 Statusline Generator (Optimized)
|
|
20
27
|
* Displays real-time V3 implementation progress and system status
|
|
21
28
|
*
|
|
22
29
|
* Usage: node statusline.cjs [--json] [--compact]
|
|
23
30
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
31
|
+
* Performance notes:
|
|
32
|
+
* - Single git execSync call (combines branch + status + upstream)
|
|
33
|
+
* - No recursive file reading (only stat/readdir, never read test contents)
|
|
34
|
+
* - No ps aux calls (uses process.memoryUsage() + file-based metrics)
|
|
35
|
+
* - Strict 2s timeout on all execSync calls
|
|
36
|
+
* - Shared settings cache across functions
|
|
26
37
|
*/
|
|
27
38
|
|
|
28
39
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
29
40
|
const fs = require('fs');
|
|
30
41
|
const path = require('path');
|
|
31
42
|
const { execSync } = require('child_process');
|
|
43
|
+
const os = require('os');
|
|
32
44
|
|
|
33
45
|
// Configuration
|
|
34
46
|
const CONFIG = {
|
|
35
|
-
|
|
36
|
-
showProgress: ${config.showProgress},
|
|
37
|
-
showSecurity: ${config.showSecurity},
|
|
38
|
-
showSwarm: ${config.showSwarm},
|
|
39
|
-
showHooks: ${config.showHooks},
|
|
40
|
-
showPerformance: ${config.showPerformance},
|
|
41
|
-
refreshInterval: ${config.refreshInterval},
|
|
42
|
-
maxAgents: ${options.runtime.maxAgents},
|
|
43
|
-
topology: '${options.runtime.topology}',
|
|
47
|
+
maxAgents: ${maxAgents},
|
|
44
48
|
};
|
|
45
49
|
|
|
50
|
+
const CWD = process.cwd();
|
|
51
|
+
|
|
46
52
|
// ANSI colors
|
|
47
53
|
const c = {
|
|
48
54
|
reset: '\\x1b[0m',
|
|
@@ -63,225 +69,178 @@ const c = {
|
|
|
63
69
|
brightWhite: '\\x1b[1;37m',
|
|
64
70
|
};
|
|
65
71
|
|
|
66
|
-
//
|
|
67
|
-
function
|
|
68
|
-
let name = 'user';
|
|
69
|
-
let gitBranch = '';
|
|
70
|
-
let modelName = '🤖 Claude Code';
|
|
71
|
-
|
|
72
|
+
// Safe execSync with strict timeout (returns empty string on failure)
|
|
73
|
+
function safeExec(cmd, timeoutMs = 2000) {
|
|
72
74
|
try {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
return execSync(cmd, {
|
|
76
|
+
encoding: 'utf-8',
|
|
77
|
+
timeout: timeoutMs,
|
|
78
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
79
|
+
}).trim();
|
|
80
|
+
} catch {
|
|
81
|
+
return '';
|
|
77
82
|
}
|
|
83
|
+
}
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
// Safe JSON file reader (returns null on failure)
|
|
86
|
+
function readJSON(filePath) {
|
|
80
87
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (fs.existsSync(claudeConfigPath)) {
|
|
84
|
-
const claudeConfig = JSON.parse(fs.readFileSync(claudeConfigPath, 'utf-8'));
|
|
85
|
-
// Try to find lastModelUsage - check current dir and parent dirs
|
|
86
|
-
let lastModelUsage = null;
|
|
87
|
-
const cwd = process.cwd();
|
|
88
|
-
if (claudeConfig.projects) {
|
|
89
|
-
// Try exact match first, then check if cwd starts with any project path
|
|
90
|
-
for (const [projectPath, projectConfig] of Object.entries(claudeConfig.projects)) {
|
|
91
|
-
if (cwd === projectPath || cwd.startsWith(projectPath + '/')) {
|
|
92
|
-
lastModelUsage = projectConfig.lastModelUsage;
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (lastModelUsage) {
|
|
98
|
-
const modelIds = Object.keys(lastModelUsage);
|
|
99
|
-
if (modelIds.length > 0) {
|
|
100
|
-
// Find the most recently used model by checking lastUsedAt timestamps
|
|
101
|
-
// or fall back to the last key in the object (preserves insertion order in modern JS)
|
|
102
|
-
let modelId = modelIds[modelIds.length - 1];
|
|
103
|
-
let latestTimestamp = 0;
|
|
104
|
-
|
|
105
|
-
for (const id of modelIds) {
|
|
106
|
-
const usage = lastModelUsage[id];
|
|
107
|
-
// Check for lastUsedAt timestamp (if available)
|
|
108
|
-
if (usage.lastUsedAt) {
|
|
109
|
-
const ts = new Date(usage.lastUsedAt).getTime();
|
|
110
|
-
if (ts > latestTimestamp) {
|
|
111
|
-
latestTimestamp = ts;
|
|
112
|
-
modelId = id;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Parse model ID to human-readable name
|
|
118
|
-
if (modelId.includes('opus-4-6') || modelId.includes('opus-4.6')) modelName = 'Opus 4.6';
|
|
119
|
-
else if (modelId.includes('opus')) modelName = 'Opus 4.5';
|
|
120
|
-
else if (modelId.includes('sonnet-4-6') || modelId.includes('sonnet-4.6')) modelName = 'Sonnet 4.6';
|
|
121
|
-
else if (modelId.includes('sonnet')) modelName = 'Sonnet 4';
|
|
122
|
-
else if (modelId.includes('haiku')) modelName = 'Haiku 4.5';
|
|
123
|
-
else modelName = modelId.split('-').slice(1, 3).join(' ');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
88
|
+
if (fs.existsSync(filePath)) {
|
|
89
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
126
90
|
}
|
|
127
|
-
} catch
|
|
128
|
-
|
|
129
|
-
|
|
91
|
+
} catch { /* ignore */ }
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
130
94
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (settings.model.includes('opus-4-6') || settings.model.includes('opus-4.6')) modelName = 'Opus 4.6';
|
|
139
|
-
else if (settings.model.includes('opus')) modelName = 'Opus 4.5';
|
|
140
|
-
else if (settings.model.includes('sonnet-4-6') || settings.model.includes('sonnet-4.6')) modelName = 'Sonnet 4.6';
|
|
141
|
-
else if (settings.model.includes('sonnet')) modelName = 'Sonnet 4';
|
|
142
|
-
else if (settings.model.includes('haiku')) modelName = 'Haiku 4.5';
|
|
143
|
-
else modelName = settings.model.split('-').slice(1, 3).join(' ');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} catch (e) {
|
|
147
|
-
// Keep Unknown
|
|
148
|
-
}
|
|
149
|
-
}
|
|
95
|
+
// Safe file stat (returns null on failure)
|
|
96
|
+
function safeStat(filePath) {
|
|
97
|
+
try {
|
|
98
|
+
return fs.statSync(filePath);
|
|
99
|
+
} catch { /* ignore */ }
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
150
102
|
|
|
151
|
-
|
|
103
|
+
// Shared settings cache — read once, used by multiple functions
|
|
104
|
+
let _settingsCache = undefined;
|
|
105
|
+
function getSettings() {
|
|
106
|
+
if (_settingsCache !== undefined) return _settingsCache;
|
|
107
|
+
_settingsCache = readJSON(path.join(CWD, '.claude', 'settings.json'))
|
|
108
|
+
|| readJSON(path.join(CWD, '.claude', 'settings.local.json'))
|
|
109
|
+
|| null;
|
|
110
|
+
return _settingsCache;
|
|
152
111
|
}
|
|
153
112
|
|
|
154
|
-
//
|
|
155
|
-
function getLearningStats() {
|
|
156
|
-
let patterns = 0;
|
|
157
|
-
let sessions = 0;
|
|
158
|
-
let trajectories = 0;
|
|
159
|
-
let edges = 0;
|
|
160
|
-
let confidenceMean = 0;
|
|
161
|
-
let accessedCount = 0;
|
|
162
|
-
let trend = 'STABLE';
|
|
163
|
-
|
|
164
|
-
// PRIMARY: Read from intelligence loop data files
|
|
165
|
-
const dataDir = path.join(process.cwd(), '.claude-flow', 'data');
|
|
166
|
-
|
|
167
|
-
// 1. graph-state.json — authoritative node/edge counts
|
|
168
|
-
const graphPath = path.join(dataDir, 'graph-state.json');
|
|
169
|
-
if (fs.existsSync(graphPath)) {
|
|
170
|
-
try {
|
|
171
|
-
const graph = JSON.parse(fs.readFileSync(graphPath, 'utf-8'));
|
|
172
|
-
patterns = graph.nodes ? Object.keys(graph.nodes).length : 0;
|
|
173
|
-
edges = Array.isArray(graph.edges) ? graph.edges.length : 0;
|
|
174
|
-
} catch (e) { /* ignore */ }
|
|
175
|
-
}
|
|
113
|
+
// ─── Data Collection (all pure-Node.js or single-exec) ──────────
|
|
176
114
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
patterns = Math.max(patterns, ranked.entries.length);
|
|
184
|
-
let confSum = 0;
|
|
185
|
-
let accCount = 0;
|
|
186
|
-
for (let i = 0; i < ranked.entries.length; i++) {
|
|
187
|
-
confSum += (ranked.entries[i].confidence || 0);
|
|
188
|
-
if ((ranked.entries[i].accessCount || 0) > 0) accCount++;
|
|
189
|
-
}
|
|
190
|
-
confidenceMean = confSum / ranked.entries.length;
|
|
191
|
-
accessedCount = accCount;
|
|
192
|
-
}
|
|
193
|
-
} catch (e) { /* ignore */ }
|
|
194
|
-
}
|
|
115
|
+
// Get all git info in ONE shell call
|
|
116
|
+
function getGitInfo() {
|
|
117
|
+
const result = {
|
|
118
|
+
name: 'user', gitBranch: '', modified: 0, untracked: 0,
|
|
119
|
+
staged: 0, ahead: 0, behind: 0,
|
|
120
|
+
};
|
|
195
121
|
|
|
196
|
-
//
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
122
|
+
// Single shell: get user.name, branch, porcelain status, and upstream diff
|
|
123
|
+
const script = [
|
|
124
|
+
'git config user.name 2>/dev/null || echo user',
|
|
125
|
+
'echo "---SEP---"',
|
|
126
|
+
'git branch --show-current 2>/dev/null',
|
|
127
|
+
'echo "---SEP---"',
|
|
128
|
+
'git status --porcelain 2>/dev/null',
|
|
129
|
+
'echo "---SEP---"',
|
|
130
|
+
'git rev-list --left-right --count HEAD...@{upstream} 2>/dev/null || echo "0 0"',
|
|
131
|
+
].join('; ');
|
|
132
|
+
|
|
133
|
+
const raw = safeExec("sh -c '" + script + "'", 3000);
|
|
134
|
+
if (!raw) return result;
|
|
135
|
+
|
|
136
|
+
const parts = raw.split('---SEP---').map(s => s.trim());
|
|
137
|
+
if (parts.length >= 4) {
|
|
138
|
+
result.name = parts[0] || 'user';
|
|
139
|
+
result.gitBranch = parts[1] || '';
|
|
140
|
+
|
|
141
|
+
// Parse porcelain status
|
|
142
|
+
if (parts[2]) {
|
|
143
|
+
for (const line of parts[2].split('\\n')) {
|
|
144
|
+
if (!line || line.length < 2) continue;
|
|
145
|
+
const x = line[0], y = line[1];
|
|
146
|
+
if (x === '?' && y === '?') { result.untracked++; continue; }
|
|
147
|
+
if (x !== ' ' && x !== '?') result.staged++;
|
|
148
|
+
if (y !== ' ' && y !== '?') result.modified++;
|
|
207
149
|
}
|
|
208
|
-
} catch (e) { /* ignore */ }
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// 4. auto-memory-store.json — fallback entry count
|
|
212
|
-
if (patterns === 0) {
|
|
213
|
-
const autoMemPath = path.join(dataDir, 'auto-memory-store.json');
|
|
214
|
-
if (fs.existsSync(autoMemPath)) {
|
|
215
|
-
try {
|
|
216
|
-
const data = JSON.parse(fs.readFileSync(autoMemPath, 'utf-8'));
|
|
217
|
-
patterns = Array.isArray(data) ? data.length : (data.entries ? data.entries.length : 0);
|
|
218
|
-
} catch (e) { /* ignore */ }
|
|
219
150
|
}
|
|
151
|
+
|
|
152
|
+
// Parse ahead/behind
|
|
153
|
+
const ab = (parts[3] || '0 0').split(/\\s+/);
|
|
154
|
+
result.ahead = parseInt(ab[0]) || 0;
|
|
155
|
+
result.behind = parseInt(ab[1]) || 0;
|
|
220
156
|
}
|
|
221
157
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Detect model name from Claude config (pure file reads, no exec)
|
|
162
|
+
function getModelName() {
|
|
163
|
+
try {
|
|
164
|
+
const claudeConfig = readJSON(path.join(os.homedir(), '.claude.json'));
|
|
165
|
+
if (claudeConfig && claudeConfig.projects) {
|
|
166
|
+
for (const [projectPath, projectConfig] of Object.entries(claudeConfig.projects)) {
|
|
167
|
+
if (CWD === projectPath || CWD.startsWith(projectPath + '/')) {
|
|
168
|
+
const usage = projectConfig.lastModelUsage;
|
|
169
|
+
if (usage) {
|
|
170
|
+
const ids = Object.keys(usage);
|
|
171
|
+
if (ids.length > 0) {
|
|
172
|
+
let modelId = ids[ids.length - 1];
|
|
173
|
+
let latest = 0;
|
|
174
|
+
for (const id of ids) {
|
|
175
|
+
const ts = usage[id] && usage[id].lastUsedAt ? new Date(usage[id].lastUsedAt).getTime() : 0;
|
|
176
|
+
if (ts > latest) { latest = ts; modelId = id; }
|
|
177
|
+
}
|
|
178
|
+
if (modelId.includes('opus')) return 'Opus 4.6 (1M context)';
|
|
179
|
+
if (modelId.includes('sonnet')) return 'Sonnet 4.6';
|
|
180
|
+
if (modelId.includes('haiku')) return 'Haiku 4.5';
|
|
181
|
+
return modelId.split('-').slice(1, 3).join(' ');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
237
184
|
break;
|
|
238
|
-
}
|
|
185
|
+
}
|
|
239
186
|
}
|
|
240
187
|
}
|
|
188
|
+
} catch { /* ignore */ }
|
|
189
|
+
|
|
190
|
+
// Fallback: settings.json model field
|
|
191
|
+
const settings = getSettings();
|
|
192
|
+
if (settings && settings.model) {
|
|
193
|
+
const m = settings.model;
|
|
194
|
+
if (m.includes('opus')) return 'Opus 4.6 (1M context)';
|
|
195
|
+
if (m.includes('sonnet')) return 'Sonnet 4.6';
|
|
196
|
+
if (m.includes('haiku')) return 'Haiku 4.5';
|
|
241
197
|
}
|
|
198
|
+
return 'Claude Code';
|
|
199
|
+
}
|
|
242
200
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
201
|
+
// Get learning stats from memory database (pure stat calls)
|
|
202
|
+
function getLearningStats() {
|
|
203
|
+
const memoryPaths = [
|
|
204
|
+
path.join(CWD, '.swarm', 'memory.db'),
|
|
205
|
+
path.join(CWD, '.claude-flow', 'memory.db'),
|
|
206
|
+
path.join(CWD, '.claude', 'memory.db'),
|
|
207
|
+
path.join(CWD, 'data', 'memory.db'),
|
|
208
|
+
path.join(CWD, '.agentdb', 'memory.db'),
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
for (const dbPath of memoryPaths) {
|
|
212
|
+
const stat = safeStat(dbPath);
|
|
213
|
+
if (stat) {
|
|
214
|
+
const sizeKB = stat.size / 1024;
|
|
215
|
+
const patterns = Math.floor(sizeKB / 2);
|
|
216
|
+
return {
|
|
217
|
+
patterns,
|
|
218
|
+
sessions: Math.max(1, Math.floor(patterns / 10)),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
250
221
|
}
|
|
251
222
|
|
|
252
|
-
|
|
223
|
+
// Check session files count
|
|
224
|
+
let sessions = 0;
|
|
225
|
+
try {
|
|
226
|
+
const sessDir = path.join(CWD, '.claude', 'sessions');
|
|
227
|
+
if (fs.existsSync(sessDir)) {
|
|
228
|
+
sessions = fs.readdirSync(sessDir).filter(f => f.endsWith('.json')).length;
|
|
229
|
+
}
|
|
230
|
+
} catch { /* ignore */ }
|
|
253
231
|
|
|
254
|
-
return { patterns, sessions
|
|
232
|
+
return { patterns: 0, sessions };
|
|
255
233
|
}
|
|
256
234
|
|
|
257
|
-
//
|
|
235
|
+
// V3 progress from metrics files (pure file reads)
|
|
258
236
|
function getV3Progress() {
|
|
259
237
|
const learning = getLearningStats();
|
|
260
238
|
const totalDomains = 5;
|
|
261
239
|
|
|
262
|
-
|
|
263
|
-
let
|
|
264
|
-
let dddMaxScore = 100;
|
|
265
|
-
let moduleCount = 0;
|
|
266
|
-
|
|
267
|
-
// Check ddd-progress.json for REAL DDD analysis
|
|
268
|
-
const dddPath = path.join(process.cwd(), '.claude-flow', 'metrics', 'ddd-progress.json');
|
|
269
|
-
if (fs.existsSync(dddPath)) {
|
|
270
|
-
try {
|
|
271
|
-
const data = JSON.parse(fs.readFileSync(dddPath, 'utf-8'));
|
|
272
|
-
dddProgress = data.progress || 0;
|
|
273
|
-
dddScore = data.score || 0;
|
|
274
|
-
dddMaxScore = data.maxScore || 100;
|
|
275
|
-
moduleCount = data.modules ? Object.keys(data.modules).length : 0;
|
|
276
|
-
} catch (e) {
|
|
277
|
-
// Ignore - use fallback
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Calculate domains completed from DDD progress (each 20% = 1 domain)
|
|
240
|
+
const dddData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'ddd-progress.json'));
|
|
241
|
+
let dddProgress = dddData ? (dddData.progress || 0) : 0;
|
|
282
242
|
let domainsCompleted = Math.min(5, Math.floor(dddProgress / 20));
|
|
283
243
|
|
|
284
|
-
// Fallback: if no DDD data, use pattern-based calculation
|
|
285
244
|
if (dddProgress === 0 && learning.patterns > 0) {
|
|
286
245
|
if (learning.patterns >= 500) domainsCompleted = 5;
|
|
287
246
|
else if (learning.patterns >= 200) domainsCompleted = 4;
|
|
@@ -292,820 +251,336 @@ function getV3Progress() {
|
|
|
292
251
|
}
|
|
293
252
|
|
|
294
253
|
return {
|
|
295
|
-
domainsCompleted,
|
|
296
|
-
totalDomains,
|
|
297
|
-
dddProgress,
|
|
298
|
-
dddScore,
|
|
299
|
-
dddMaxScore,
|
|
300
|
-
moduleCount,
|
|
254
|
+
domainsCompleted, totalDomains, dddProgress,
|
|
301
255
|
patternsLearned: learning.patterns,
|
|
302
|
-
sessionsCompleted: learning.sessions
|
|
256
|
+
sessionsCompleted: learning.sessions,
|
|
303
257
|
};
|
|
304
258
|
}
|
|
305
259
|
|
|
306
|
-
//
|
|
260
|
+
// Security status (pure file reads)
|
|
307
261
|
function getSecurityStatus() {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (fs.existsSync(scanResultsPath)) {
|
|
329
|
-
try {
|
|
330
|
-
const scans = fs.readdirSync(scanResultsPath).filter(f => f.endsWith('.json'));
|
|
331
|
-
// Each successful scan file = 1 CVE addressed
|
|
332
|
-
cvesFixed = Math.min(totalCves, scans.length);
|
|
333
|
-
} catch (e) {
|
|
334
|
-
// Ignore
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Also check .swarm/security for audit results
|
|
339
|
-
const swarmAuditPath = path.join(process.cwd(), '.swarm', 'security');
|
|
340
|
-
if (fs.existsSync(swarmAuditPath)) {
|
|
341
|
-
try {
|
|
342
|
-
const audits = fs.readdirSync(swarmAuditPath).filter(f => f.includes('audit'));
|
|
343
|
-
cvesFixed = Math.min(totalCves, Math.max(cvesFixed, audits.length));
|
|
344
|
-
} catch (e) {
|
|
345
|
-
// Ignore
|
|
262
|
+
const auditData = readJSON(path.join(CWD, '.claude-flow', 'security', 'audit-status.json'));
|
|
263
|
+
if (auditData) {
|
|
264
|
+
const auditDate = auditData.lastAudit || auditData.lastScan;
|
|
265
|
+
if (!auditDate) {
|
|
266
|
+
return { status: 'PENDING', cvesFixed: 0, totalCves: 0 };
|
|
267
|
+
}
|
|
268
|
+
const auditAge = Date.now() - new Date(auditDate).getTime();
|
|
269
|
+
const isStale = auditAge > 7 * 24 * 60 * 60 * 1000;
|
|
270
|
+
return {
|
|
271
|
+
status: isStale ? 'STALE' : (auditData.status || 'PENDING'),
|
|
272
|
+
cvesFixed: auditData.cvesFixed || 0,
|
|
273
|
+
totalCves: auditData.totalCves || 0,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let scanCount = 0;
|
|
278
|
+
try {
|
|
279
|
+
const scanDir = path.join(CWD, '.claude', 'security-scans');
|
|
280
|
+
if (fs.existsSync(scanDir)) {
|
|
281
|
+
scanCount = fs.readdirSync(scanDir).filter(f => f.endsWith('.json')).length;
|
|
346
282
|
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const status = cvesFixed >= totalCves ? 'CLEAN' : cvesFixed > 0 ? 'IN_PROGRESS' : 'PENDING';
|
|
283
|
+
} catch { /* ignore */ }
|
|
350
284
|
|
|
351
285
|
return {
|
|
352
|
-
status,
|
|
353
|
-
cvesFixed,
|
|
354
|
-
totalCves,
|
|
286
|
+
status: scanCount > 0 ? 'SCANNED' : 'NONE',
|
|
287
|
+
cvesFixed: 0,
|
|
288
|
+
totalCves: 0,
|
|
355
289
|
};
|
|
356
290
|
}
|
|
357
291
|
|
|
358
|
-
//
|
|
292
|
+
// Swarm status (pure file reads, NO ps aux)
|
|
359
293
|
function getSwarmStatus() {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
} catch (e) {
|
|
376
|
-
// Fall through to v3-progress.json check
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Also check v3-progress.json for swarm data (secondary source)
|
|
381
|
-
const progressPath = path.join(process.cwd(), '.claude-flow', 'metrics', 'v3-progress.json');
|
|
382
|
-
if (fs.existsSync(progressPath)) {
|
|
383
|
-
try {
|
|
384
|
-
const data = JSON.parse(fs.readFileSync(progressPath, 'utf-8'));
|
|
385
|
-
if (data.swarm) {
|
|
386
|
-
return {
|
|
387
|
-
activeAgents: data.swarm.activeAgents || data.swarm.agent_count || 0,
|
|
388
|
-
maxAgents: data.swarm.totalAgents || CONFIG.maxAgents,
|
|
389
|
-
coordinationActive: data.swarm.active || (data.swarm.activeAgents > 0),
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
} catch (e) {
|
|
393
|
-
// Fall through to process detection
|
|
294
|
+
const staleThresholdMs = 5 * 60 * 1000;
|
|
295
|
+
const now = Date.now();
|
|
296
|
+
|
|
297
|
+
const swarmStatePath = path.join(CWD, '.claude-flow', 'swarm', 'swarm-state.json');
|
|
298
|
+
const swarmState = readJSON(swarmStatePath);
|
|
299
|
+
if (swarmState) {
|
|
300
|
+
const updatedAt = swarmState.updatedAt || swarmState.startedAt;
|
|
301
|
+
const age = updatedAt ? now - new Date(updatedAt).getTime() : Infinity;
|
|
302
|
+
if (age < staleThresholdMs) {
|
|
303
|
+
return {
|
|
304
|
+
activeAgents: (swarmState.agents && swarmState.agents.length) || swarmState.agentCount || 0,
|
|
305
|
+
maxAgents: swarmState.maxAgents || CONFIG.maxAgents,
|
|
306
|
+
coordinationActive: true,
|
|
307
|
+
};
|
|
394
308
|
}
|
|
395
309
|
}
|
|
396
310
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
// Unix: use ps - check for various agent process patterns
|
|
408
|
-
try {
|
|
409
|
-
const ps = execSync('ps aux 2>/dev/null | grep -E "(agentic-flow|claude-flow|mcp.*server)" | grep -v grep | wc -l', { encoding: 'utf-8' });
|
|
410
|
-
activeAgents = Math.max(0, parseInt(ps.trim()));
|
|
411
|
-
coordinationActive = activeAgents > 0;
|
|
412
|
-
} catch (e) {
|
|
413
|
-
// Fallback to simple agentic-flow check
|
|
414
|
-
const ps = execSync('ps aux 2>/dev/null | grep -c agentic-flow || echo "0"', { encoding: 'utf-8' });
|
|
415
|
-
activeAgents = Math.max(0, parseInt(ps.trim()) - 1);
|
|
416
|
-
coordinationActive = activeAgents > 0;
|
|
417
|
-
}
|
|
311
|
+
const activityData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'swarm-activity.json'));
|
|
312
|
+
if (activityData && activityData.swarm) {
|
|
313
|
+
const updatedAt = activityData.timestamp || (activityData.swarm && activityData.swarm.timestamp);
|
|
314
|
+
const age = updatedAt ? now - new Date(updatedAt).getTime() : Infinity;
|
|
315
|
+
if (age < staleThresholdMs) {
|
|
316
|
+
return {
|
|
317
|
+
activeAgents: activityData.swarm.agent_count || 0,
|
|
318
|
+
maxAgents: CONFIG.maxAgents,
|
|
319
|
+
coordinationActive: activityData.swarm.coordination_active || activityData.swarm.active || false,
|
|
320
|
+
};
|
|
418
321
|
}
|
|
419
|
-
} catch (e) {
|
|
420
|
-
// Ignore errors - return defaults
|
|
421
322
|
}
|
|
422
323
|
|
|
423
|
-
return {
|
|
424
|
-
activeAgents,
|
|
425
|
-
maxAgents: CONFIG.maxAgents,
|
|
426
|
-
coordinationActive,
|
|
427
|
-
};
|
|
324
|
+
return { activeAgents: 0, maxAgents: CONFIG.maxAgents, coordinationActive: false };
|
|
428
325
|
}
|
|
429
326
|
|
|
430
|
-
//
|
|
327
|
+
// System metrics (uses process.memoryUsage() — no shell spawn)
|
|
431
328
|
function getSystemMetrics() {
|
|
432
|
-
|
|
433
|
-
let subAgents = 0;
|
|
434
|
-
|
|
435
|
-
// Check learning.json first for REAL intelligence metrics
|
|
436
|
-
const learningMetricsPath = path.join(process.cwd(), '.claude-flow', 'metrics', 'learning.json');
|
|
437
|
-
let intelligenceFromFile = null;
|
|
438
|
-
let contextFromFile = null;
|
|
439
|
-
if (fs.existsSync(learningMetricsPath)) {
|
|
440
|
-
try {
|
|
441
|
-
const data = JSON.parse(fs.readFileSync(learningMetricsPath, 'utf-8'));
|
|
442
|
-
// Use intelligence.score (the REAL metric) instead of routing.accuracy
|
|
443
|
-
if (data.intelligence?.score !== undefined) {
|
|
444
|
-
intelligenceFromFile = Math.min(100, Math.floor(data.intelligence.score));
|
|
445
|
-
}
|
|
446
|
-
if (data.sessions?.total !== undefined) {
|
|
447
|
-
contextFromFile = Math.min(100, data.sessions.total * 5);
|
|
448
|
-
}
|
|
449
|
-
} catch (e) {
|
|
450
|
-
// Fall through
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Platform-specific memory detection
|
|
455
|
-
const isWindows = process.platform === 'win32';
|
|
456
|
-
try {
|
|
457
|
-
if (isWindows) {
|
|
458
|
-
// Windows: use process.memoryUsage() (most reliable cross-platform)
|
|
459
|
-
memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
460
|
-
} else {
|
|
461
|
-
// Unix: try ps command, fallback to process.memoryUsage()
|
|
462
|
-
try {
|
|
463
|
-
const mem = execSync('ps aux | grep -E "(node|agentic|claude)" | grep -v grep | awk \\'{sum += \\$6} END {print int(sum/1024)}\\'', { encoding: 'utf-8' });
|
|
464
|
-
memoryMB = parseInt(mem.trim()) || 0;
|
|
465
|
-
} catch (e) {
|
|
466
|
-
memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
} catch (e) {
|
|
470
|
-
// Fallback to Node.js memory API
|
|
471
|
-
memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Get learning stats for intelligence %
|
|
329
|
+
const memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
475
330
|
const learning = getLearningStats();
|
|
331
|
+
const agentdb = getAgentDBStats();
|
|
476
332
|
|
|
477
|
-
//
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
// Intelligence % — priority chain (ADR-050):
|
|
481
|
-
// 1. Intelligence loop data (confidenceMean + accessRatio + density)
|
|
482
|
-
// 2. learning.json file metric
|
|
483
|
-
// 3. Pattern count / vector count fallback
|
|
484
|
-
// 4. Project maturity fallback (below)
|
|
333
|
+
// Intelligence from learning.json
|
|
334
|
+
const learningData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'learning.json'));
|
|
485
335
|
let intelligencePct = 0;
|
|
336
|
+
let contextPct = 0;
|
|
486
337
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
const densityScore = Math.min(100, Math.floor(learning.patterns / 5));
|
|
493
|
-
intelligencePct = Math.floor(confScore * 0.4 + accessScore * 0.3 + densityScore * 0.3);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Priority 2: learning.json file metric
|
|
497
|
-
if (intelligencePct === 0 && intelligenceFromFile !== null) {
|
|
498
|
-
intelligencePct = intelligenceFromFile;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// Priority 3: Pattern/vector count fallback
|
|
502
|
-
if (intelligencePct === 0) {
|
|
503
|
-
const fromPatterns = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 10)) : 0;
|
|
504
|
-
const fromVectors = agentdbStats.vectorCount > 0 ? Math.min(100, Math.floor(agentdbStats.vectorCount / 100)) : 0;
|
|
338
|
+
if (learningData && learningData.intelligence && learningData.intelligence.score !== undefined) {
|
|
339
|
+
intelligencePct = Math.min(100, Math.floor(learningData.intelligence.score));
|
|
340
|
+
} else {
|
|
341
|
+
const fromPatterns = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 20)) : 0;
|
|
342
|
+
const fromVectors = agentdb.vectorCount > 0 ? Math.min(100, Math.floor(agentdb.vectorCount / 20)) : 0;
|
|
505
343
|
intelligencePct = Math.max(fromPatterns, fromVectors);
|
|
506
344
|
}
|
|
507
345
|
|
|
508
|
-
//
|
|
346
|
+
// Maturity fallback (pure fs checks, no git exec)
|
|
509
347
|
if (intelligencePct === 0) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (fs.existsSync(sessPath)) {
|
|
526
|
-
try {
|
|
527
|
-
const sessions = fs.readdirSync(sessPath).filter(f => f.endsWith('.json')).length;
|
|
528
|
-
maturityScore += Math.min(20, sessions * 2); // Max 20% from sessions
|
|
529
|
-
break;
|
|
530
|
-
} catch (e) { /* ignore */ }
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// Check for source files (indicates codebase size)
|
|
535
|
-
try {
|
|
536
|
-
const srcDirs = ['src', 'lib', 'app', 'packages'];
|
|
537
|
-
for (const dir of srcDirs) {
|
|
538
|
-
const dirPath = path.join(process.cwd(), dir);
|
|
539
|
-
if (fs.existsSync(dirPath)) {
|
|
540
|
-
maturityScore += 15; // Base score for having source dir
|
|
541
|
-
break;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
} catch (e) { /* ignore */ }
|
|
545
|
-
|
|
546
|
-
// Check for test files
|
|
547
|
-
try {
|
|
548
|
-
const testDirs = ['tests', 'test', '__tests__', 'spec'];
|
|
549
|
-
for (const dir of testDirs) {
|
|
550
|
-
const dirPath = path.join(process.cwd(), dir);
|
|
551
|
-
if (fs.existsSync(dirPath)) {
|
|
552
|
-
maturityScore += 10; // Bonus for having tests
|
|
553
|
-
break;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
} catch (e) { /* ignore */ }
|
|
557
|
-
|
|
558
|
-
// Check for .claude directory (Claude Code usage)
|
|
559
|
-
if (fs.existsSync(path.join(process.cwd(), '.claude'))) {
|
|
560
|
-
maturityScore += 15; // Bonus for Claude Code integration
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Check for config files (project maturity)
|
|
564
|
-
const configFiles = ['package.json', 'tsconfig.json', 'pyproject.toml', 'Cargo.toml', 'go.mod'];
|
|
565
|
-
for (const cfg of configFiles) {
|
|
566
|
-
if (fs.existsSync(path.join(process.cwd(), cfg))) {
|
|
567
|
-
maturityScore += 5;
|
|
568
|
-
break;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
intelligencePct = Math.min(100, maturityScore);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// Context % based on session history (0 sessions = 0%, grows with usage)
|
|
576
|
-
const contextPct = contextFromFile !== null
|
|
577
|
-
? contextFromFile
|
|
578
|
-
: Math.min(100, Math.floor(learning.sessions * 5));
|
|
579
|
-
|
|
580
|
-
// Count active sub-agents (cross-platform via metrics file)
|
|
581
|
-
const activityPath = path.join(process.cwd(), '.claude-flow', 'metrics', 'swarm-activity.json');
|
|
582
|
-
if (fs.existsSync(activityPath)) {
|
|
583
|
-
try {
|
|
584
|
-
const data = JSON.parse(fs.readFileSync(activityPath, 'utf-8'));
|
|
585
|
-
subAgents = data.processes?.estimated_agents || 0;
|
|
586
|
-
} catch (e) {
|
|
587
|
-
// Ignore
|
|
588
|
-
}
|
|
348
|
+
let score = 0;
|
|
349
|
+
if (fs.existsSync(path.join(CWD, '.claude'))) score += 15;
|
|
350
|
+
const srcDirs = ['src', 'lib', 'app', 'packages', 'v3'];
|
|
351
|
+
for (const d of srcDirs) { if (fs.existsSync(path.join(CWD, d))) { score += 15; break; } }
|
|
352
|
+
const testDirs = ['tests', 'test', '__tests__', 'spec'];
|
|
353
|
+
for (const d of testDirs) { if (fs.existsSync(path.join(CWD, d))) { score += 10; break; } }
|
|
354
|
+
const cfgFiles = ['package.json', 'tsconfig.json', 'pyproject.toml', 'Cargo.toml', 'go.mod'];
|
|
355
|
+
for (const f of cfgFiles) { if (fs.existsSync(path.join(CWD, f))) { score += 5; break; } }
|
|
356
|
+
intelligencePct = Math.min(100, score);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (learningData && learningData.sessions && learningData.sessions.total !== undefined) {
|
|
360
|
+
contextPct = Math.min(100, learningData.sessions.total * 5);
|
|
361
|
+
} else {
|
|
362
|
+
contextPct = Math.min(100, Math.floor(learning.sessions * 5));
|
|
589
363
|
}
|
|
590
364
|
|
|
591
|
-
//
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
} catch (e) {
|
|
597
|
-
// Ignore
|
|
598
|
-
}
|
|
365
|
+
// Sub-agents from file metrics (no ps aux)
|
|
366
|
+
let subAgents = 0;
|
|
367
|
+
const activityData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'swarm-activity.json'));
|
|
368
|
+
if (activityData && activityData.processes && activityData.processes.estimated_agents) {
|
|
369
|
+
subAgents = activityData.processes.estimated_agents;
|
|
599
370
|
}
|
|
600
371
|
|
|
601
|
-
return {
|
|
602
|
-
memoryMB,
|
|
603
|
-
contextPct,
|
|
604
|
-
intelligencePct,
|
|
605
|
-
subAgents,
|
|
606
|
-
};
|
|
372
|
+
return { memoryMB, contextPct, intelligencePct, subAgents };
|
|
607
373
|
}
|
|
608
374
|
|
|
609
|
-
//
|
|
375
|
+
// ADR status (count files only — don't read contents)
|
|
610
376
|
function getADRStatus() {
|
|
611
|
-
|
|
612
|
-
let totalChecks = 0;
|
|
613
|
-
let compliantChecks = 0;
|
|
614
|
-
let checks = {};
|
|
615
|
-
|
|
616
|
-
// Check adr-compliance.json for REAL compliance data
|
|
617
|
-
const compliancePath = path.join(process.cwd(), '.claude-flow', 'metrics', 'adr-compliance.json');
|
|
618
|
-
if (fs.existsSync(compliancePath)) {
|
|
619
|
-
try {
|
|
620
|
-
const data = JSON.parse(fs.readFileSync(compliancePath, 'utf-8'));
|
|
621
|
-
compliance = data.compliance || 0;
|
|
622
|
-
checks = data.checks || {};
|
|
623
|
-
totalChecks = Object.keys(checks).length;
|
|
624
|
-
compliantChecks = Object.values(checks).filter(c => c.compliant).length;
|
|
625
|
-
return { count: totalChecks, implemented: compliantChecks, compliance };
|
|
626
|
-
} catch (e) {
|
|
627
|
-
// Fall through to file-based detection
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// Fallback: count ADR files directly
|
|
377
|
+
// Count actual ADR files first — compliance JSON may be stale
|
|
632
378
|
const adrPaths = [
|
|
633
|
-
path.join(
|
|
634
|
-
path.join(
|
|
635
|
-
path.join(
|
|
636
|
-
path.join(process.cwd(), 'ADR'),
|
|
637
|
-
path.join(process.cwd(), '.claude-flow', 'adrs'),
|
|
638
|
-
path.join(process.cwd(), 'v3', 'implementation', 'adrs'),
|
|
639
|
-
path.join(process.cwd(), 'implementation', 'adrs'),
|
|
379
|
+
path.join(CWD, 'v3', 'implementation', 'adrs'),
|
|
380
|
+
path.join(CWD, 'docs', 'adrs'),
|
|
381
|
+
path.join(CWD, '.claude-flow', 'adrs'),
|
|
640
382
|
];
|
|
641
383
|
|
|
642
|
-
let count = 0;
|
|
643
|
-
let implemented = 0;
|
|
644
|
-
|
|
645
384
|
for (const adrPath of adrPaths) {
|
|
646
|
-
|
|
647
|
-
|
|
385
|
+
try {
|
|
386
|
+
if (fs.existsSync(adrPath)) {
|
|
648
387
|
const files = fs.readdirSync(adrPath).filter(f =>
|
|
649
388
|
f.endsWith('.md') && (f.startsWith('ADR-') || f.startsWith('adr-') || /^\\d{4}-/.test(f))
|
|
650
389
|
);
|
|
651
|
-
count
|
|
652
|
-
|
|
653
|
-
for (const file of files) {
|
|
654
|
-
try {
|
|
655
|
-
const content = fs.readFileSync(path.join(adrPath, file), 'utf-8');
|
|
656
|
-
if (content.includes('Status: Implemented') || content.includes('status: implemented') ||
|
|
657
|
-
content.includes('Status: Accepted') || content.includes('status: accepted')) {
|
|
658
|
-
implemented++;
|
|
659
|
-
}
|
|
660
|
-
} catch (e) {
|
|
661
|
-
// Skip unreadable files
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
break;
|
|
665
|
-
} catch (e) {
|
|
666
|
-
// Ignore
|
|
390
|
+
return { count: files.length, implemented: files.length, compliance: 0 };
|
|
667
391
|
}
|
|
668
|
-
}
|
|
392
|
+
} catch { /* ignore */ }
|
|
669
393
|
}
|
|
670
394
|
|
|
671
|
-
|
|
672
|
-
return { count, implemented, compliance };
|
|
395
|
+
return { count: 0, implemented: 0, compliance: 0 };
|
|
673
396
|
}
|
|
674
397
|
|
|
675
|
-
//
|
|
398
|
+
// Hooks status (shared settings cache)
|
|
676
399
|
function getHooksStatus() {
|
|
677
400
|
let enabled = 0;
|
|
678
|
-
let total =
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
if (settings.hooks) {
|
|
691
|
-
// Claude Code native hooks format: PreToolUse, PostToolUse, SessionStart, etc.
|
|
692
|
-
const hookCategories = Object.keys(settings.hooks);
|
|
693
|
-
for (const category of hookCategories) {
|
|
694
|
-
const categoryHooks = settings.hooks[category];
|
|
695
|
-
if (Array.isArray(categoryHooks) && categoryHooks.length > 0) {
|
|
696
|
-
// Count categories with at least one hook defined
|
|
697
|
-
enabled++;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
401
|
+
let total = 0;
|
|
402
|
+
const settings = getSettings();
|
|
403
|
+
|
|
404
|
+
if (settings && settings.hooks) {
|
|
405
|
+
for (const category of Object.keys(settings.hooks)) {
|
|
406
|
+
const matchers = settings.hooks[category];
|
|
407
|
+
if (!Array.isArray(matchers)) continue;
|
|
408
|
+
for (const matcher of matchers) {
|
|
409
|
+
const hooks = matcher && matcher.hooks;
|
|
410
|
+
if (Array.isArray(hooks)) {
|
|
411
|
+
total += hooks.length;
|
|
412
|
+
enabled += hooks.length;
|
|
700
413
|
}
|
|
701
|
-
break;
|
|
702
|
-
} catch (e) {
|
|
703
|
-
// Ignore parse errors
|
|
704
414
|
}
|
|
705
415
|
}
|
|
706
416
|
}
|
|
707
417
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
enabled = Math.max(enabled, hookFiles
|
|
714
|
-
} catch (e) {
|
|
715
|
-
// Ignore
|
|
418
|
+
try {
|
|
419
|
+
const hooksDir = path.join(CWD, '.claude', 'hooks');
|
|
420
|
+
if (fs.existsSync(hooksDir)) {
|
|
421
|
+
const hookFiles = fs.readdirSync(hooksDir).filter(f => f.endsWith('.js') || f.endsWith('.sh')).length;
|
|
422
|
+
total = Math.max(total, hookFiles);
|
|
423
|
+
enabled = Math.max(enabled, hookFiles);
|
|
716
424
|
}
|
|
717
|
-
}
|
|
425
|
+
} catch { /* ignore */ }
|
|
718
426
|
|
|
719
427
|
return { enabled, total };
|
|
720
428
|
}
|
|
721
429
|
|
|
722
|
-
//
|
|
430
|
+
// AgentDB stats — count real entries, not file-size heuristics
|
|
723
431
|
function getAgentDBStats() {
|
|
724
432
|
let vectorCount = 0;
|
|
725
433
|
let dbSizeKB = 0;
|
|
726
434
|
let namespaces = 0;
|
|
727
435
|
let hasHnsw = false;
|
|
728
436
|
|
|
729
|
-
//
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
path.join(process.cwd(), '.swarm', 'memory.db'),
|
|
741
|
-
path.join(process.cwd(), '.claude-flow', 'memory.db'),
|
|
742
|
-
path.join(process.cwd(), '.claude', 'memory.db'),
|
|
743
|
-
path.join(process.cwd(), 'data', 'memory.db'),
|
|
744
|
-
path.join(process.cwd(), 'memory.db'),
|
|
745
|
-
];
|
|
437
|
+
// 1. Count real entries from auto-memory-store.json
|
|
438
|
+
const storePath = path.join(CWD, '.claude-flow', 'data', 'auto-memory-store.json');
|
|
439
|
+
const storeStat = safeStat(storePath);
|
|
440
|
+
if (storeStat) {
|
|
441
|
+
dbSizeKB += storeStat.size / 1024;
|
|
442
|
+
try {
|
|
443
|
+
const store = JSON.parse(fs.readFileSync(storePath, 'utf-8'));
|
|
444
|
+
if (Array.isArray(store)) vectorCount += store.length;
|
|
445
|
+
else if (store && store.entries) vectorCount += store.entries.length;
|
|
446
|
+
} catch { /* fall back */ }
|
|
447
|
+
}
|
|
746
448
|
|
|
747
|
-
//
|
|
748
|
-
|
|
749
|
-
path.join(
|
|
750
|
-
|
|
751
|
-
|
|
449
|
+
// 2. Count entries from ranked-context.json
|
|
450
|
+
try {
|
|
451
|
+
const ranked = readJSON(path.join(CWD, '.claude-flow', 'data', 'ranked-context.json'));
|
|
452
|
+
if (ranked && ranked.entries && ranked.entries.length > vectorCount) vectorCount = ranked.entries.length;
|
|
453
|
+
} catch { /* ignore */ }
|
|
454
|
+
|
|
455
|
+
// 3. Add DB file sizes
|
|
456
|
+
const dbFiles = [
|
|
457
|
+
path.join(CWD, 'data', 'memory.db'),
|
|
458
|
+
path.join(CWD, '.claude-flow', 'memory.db'),
|
|
459
|
+
path.join(CWD, '.swarm', 'memory.db'),
|
|
752
460
|
];
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
const stats = fs.statSync(dbFile);
|
|
759
|
-
dbSizeKB = stats.size / 1024;
|
|
760
|
-
// Estimate vectors: ~2KB per vector for SQLite with embeddings
|
|
761
|
-
vectorCount = Math.floor(dbSizeKB / 2);
|
|
762
|
-
namespaces = 1;
|
|
763
|
-
break;
|
|
764
|
-
} catch (e) {
|
|
765
|
-
// Ignore
|
|
766
|
-
}
|
|
461
|
+
for (const f of dbFiles) {
|
|
462
|
+
const stat = safeStat(f);
|
|
463
|
+
if (stat) {
|
|
464
|
+
dbSizeKB += stat.size / 1024;
|
|
465
|
+
namespaces++;
|
|
767
466
|
}
|
|
768
467
|
}
|
|
769
468
|
|
|
770
|
-
//
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
if (fs.existsSync(dbPath)) {
|
|
774
|
-
try {
|
|
775
|
-
const stats = fs.statSync(dbPath);
|
|
776
|
-
if (stats.isDirectory()) {
|
|
777
|
-
const files = fs.readdirSync(dbPath);
|
|
778
|
-
namespaces = files.filter(f => f.endsWith('.db') || f.endsWith('.sqlite')).length;
|
|
779
|
-
|
|
780
|
-
for (const file of files) {
|
|
781
|
-
const filePath = path.join(dbPath, file);
|
|
782
|
-
const fileStat = fs.statSync(filePath);
|
|
783
|
-
if (fileStat.isFile()) {
|
|
784
|
-
dbSizeKB += fileStat.size / 1024;
|
|
785
|
-
}
|
|
786
|
-
}
|
|
469
|
+
// 4. Graph data size
|
|
470
|
+
const graphStat = safeStat(path.join(CWD, 'data', 'memory.graph'));
|
|
471
|
+
if (graphStat) dbSizeKB += graphStat.size / 1024;
|
|
787
472
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// Check for HNSW index (indicates vector search capability)
|
|
799
|
-
for (const hnswPath of hnswPaths) {
|
|
800
|
-
if (fs.existsSync(hnswPath)) {
|
|
801
|
-
hasHnsw = true;
|
|
802
|
-
try {
|
|
803
|
-
const stats = fs.statSync(hnswPath);
|
|
804
|
-
// HNSW index: ~0.5KB per vector
|
|
805
|
-
const hnswVectors = Math.floor(stats.size / 1024 / 0.5);
|
|
806
|
-
vectorCount = Math.max(vectorCount, hnswVectors);
|
|
807
|
-
} catch (e) {
|
|
808
|
-
// Ignore
|
|
809
|
-
}
|
|
810
|
-
break;
|
|
811
|
-
}
|
|
473
|
+
// 5. HNSW index or memory package
|
|
474
|
+
const hnswPaths = [
|
|
475
|
+
path.join(CWD, '.swarm', 'hnsw.index'),
|
|
476
|
+
path.join(CWD, '.claude-flow', 'hnsw.index'),
|
|
477
|
+
];
|
|
478
|
+
for (const p of hnswPaths) {
|
|
479
|
+
if (safeStat(p)) { hasHnsw = true; break; }
|
|
812
480
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
if (
|
|
820
|
-
vectorCount = data.length;
|
|
821
|
-
} else if (data.vectors) {
|
|
822
|
-
vectorCount = Object.keys(data.vectors).length;
|
|
823
|
-
}
|
|
824
|
-
} catch (e) {
|
|
825
|
-
// Ignore
|
|
481
|
+
if (!hasHnsw) {
|
|
482
|
+
const memPkgPaths = [
|
|
483
|
+
path.join(CWD, 'v3', '@claude-flow', 'memory', 'dist'),
|
|
484
|
+
path.join(CWD, 'node_modules', '@claude-flow', 'memory'),
|
|
485
|
+
];
|
|
486
|
+
for (const p of memPkgPaths) {
|
|
487
|
+
if (fs.existsSync(p)) { hasHnsw = true; break; }
|
|
826
488
|
}
|
|
827
489
|
}
|
|
828
490
|
|
|
829
491
|
return { vectorCount, dbSizeKB: Math.floor(dbSizeKB), namespaces, hasHnsw };
|
|
830
492
|
}
|
|
831
493
|
|
|
832
|
-
//
|
|
494
|
+
// Test stats (count files only — NO reading file contents)
|
|
833
495
|
function getTestStats() {
|
|
834
496
|
let testFiles = 0;
|
|
835
|
-
let testCases = 0;
|
|
836
|
-
|
|
837
|
-
const testDirs = [
|
|
838
|
-
path.join(process.cwd(), 'tests'),
|
|
839
|
-
path.join(process.cwd(), 'test'),
|
|
840
|
-
path.join(process.cwd(), '__tests__'),
|
|
841
|
-
path.join(process.cwd(), 'src', '__tests__'),
|
|
842
|
-
path.join(process.cwd(), 'v3', '__tests__'),
|
|
843
|
-
];
|
|
844
|
-
|
|
845
|
-
// Recursively count test files
|
|
846
|
-
function countTestFiles(dir, depth = 0) {
|
|
847
|
-
if (depth > 3) return; // Limit recursion
|
|
848
|
-
if (!fs.existsSync(dir)) return;
|
|
849
497
|
|
|
498
|
+
function countTestFiles(dir, depth) {
|
|
499
|
+
if (depth === undefined) depth = 0;
|
|
500
|
+
if (depth > 6) return;
|
|
850
501
|
try {
|
|
502
|
+
if (!fs.existsSync(dir)) return;
|
|
851
503
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
852
504
|
for (const entry of entries) {
|
|
853
505
|
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
|
|
854
506
|
countTestFiles(path.join(dir, entry.name), depth + 1);
|
|
855
507
|
} else if (entry.isFile()) {
|
|
856
|
-
const
|
|
857
|
-
if (
|
|
858
|
-
name.includes('_test.') || name.includes('_spec.') ||
|
|
859
|
-
name.startsWith('test_') || name.startsWith('spec_')) {
|
|
508
|
+
const n = entry.name;
|
|
509
|
+
if (n.includes('.test.') || n.includes('.spec.') || n.includes('_test.') || n.includes('_spec.')) {
|
|
860
510
|
testFiles++;
|
|
861
|
-
|
|
862
|
-
// Try to estimate test cases from file
|
|
863
|
-
try {
|
|
864
|
-
const content = fs.readFileSync(path.join(dir, name), 'utf-8');
|
|
865
|
-
// Count it(), test(), describe() patterns
|
|
866
|
-
const itMatches = (content.match(/\\bit\\s*\\(/g) || []).length;
|
|
867
|
-
const testMatches = (content.match(/\\btest\\s*\\(/g) || []).length;
|
|
868
|
-
testCases += itMatches + testMatches;
|
|
869
|
-
} catch (e) {
|
|
870
|
-
// Estimate 3 tests per file if can't read
|
|
871
|
-
testCases += 3;
|
|
872
|
-
}
|
|
873
511
|
}
|
|
874
512
|
}
|
|
875
513
|
}
|
|
876
|
-
} catch
|
|
877
|
-
// Ignore
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
for (const dir of testDirs) {
|
|
882
|
-
countTestFiles(dir);
|
|
514
|
+
} catch { /* ignore */ }
|
|
883
515
|
}
|
|
884
516
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
countTestFiles(srcDir);
|
|
517
|
+
var testDirNames = ['tests', 'test', '__tests__', 'src', 'v3'];
|
|
518
|
+
for (var i = 0; i < testDirNames.length; i++) {
|
|
519
|
+
countTestFiles(path.join(CWD, testDirNames[i]));
|
|
889
520
|
}
|
|
890
521
|
|
|
891
|
-
return { testFiles, testCases };
|
|
522
|
+
return { testFiles, testCases: testFiles * 4 };
|
|
892
523
|
}
|
|
893
524
|
|
|
894
|
-
//
|
|
525
|
+
// Integration status (shared settings + file checks)
|
|
895
526
|
function getIntegrationStatus() {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
let hasCache = false;
|
|
899
|
-
let hasApi = false;
|
|
900
|
-
|
|
901
|
-
// Check for MCP servers in settings
|
|
902
|
-
const settingsPaths = [
|
|
903
|
-
path.join(process.cwd(), '.claude', 'settings.json'),
|
|
904
|
-
path.join(process.cwd(), '.claude', 'settings.local.json'),
|
|
905
|
-
];
|
|
527
|
+
const mcpServers = { total: 0, enabled: 0 };
|
|
528
|
+
const settings = getSettings();
|
|
906
529
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
if (settings.mcpServers && typeof settings.mcpServers === 'object') {
|
|
914
|
-
const servers = Object.keys(settings.mcpServers);
|
|
915
|
-
mcpServers.total = servers.length;
|
|
916
|
-
mcpServers.names = servers;
|
|
917
|
-
|
|
918
|
-
// Check enabledMcpjsonServers for enabled count
|
|
919
|
-
if (settings.enabledMcpjsonServers && Array.isArray(settings.enabledMcpjsonServers)) {
|
|
920
|
-
mcpServers.enabled = settings.enabledMcpjsonServers.filter(s => servers.includes(s)).length;
|
|
921
|
-
} else {
|
|
922
|
-
mcpServers.enabled = mcpServers.total; // Assume all enabled if not specified
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
break;
|
|
926
|
-
} catch (e) { /* ignore */ }
|
|
927
|
-
}
|
|
530
|
+
if (settings && settings.mcpServers && typeof settings.mcpServers === 'object') {
|
|
531
|
+
const servers = Object.keys(settings.mcpServers);
|
|
532
|
+
mcpServers.total = servers.length;
|
|
533
|
+
mcpServers.enabled = settings.enabledMcpjsonServers
|
|
534
|
+
? settings.enabledMcpjsonServers.filter(s => servers.includes(s)).length
|
|
535
|
+
: servers.length;
|
|
928
536
|
}
|
|
929
537
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
for (const mcpPath of mcpConfigPaths) {
|
|
938
|
-
if (fs.existsSync(mcpPath) && mcpServers.total === 0) {
|
|
939
|
-
try {
|
|
940
|
-
const config = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
|
|
941
|
-
if (config.mcpServers) {
|
|
942
|
-
const servers = Object.keys(config.mcpServers);
|
|
943
|
-
mcpServers.total = servers.length;
|
|
944
|
-
mcpServers.names = servers;
|
|
945
|
-
mcpServers.enabled = servers.length;
|
|
946
|
-
}
|
|
947
|
-
} catch (e) { /* ignore */ }
|
|
538
|
+
if (mcpServers.total === 0) {
|
|
539
|
+
const mcpConfig = readJSON(path.join(CWD, '.mcp.json'))
|
|
540
|
+
|| readJSON(path.join(os.homedir(), '.claude', 'mcp.json'));
|
|
541
|
+
if (mcpConfig && mcpConfig.mcpServers) {
|
|
542
|
+
const s = Object.keys(mcpConfig.mcpServers);
|
|
543
|
+
mcpServers.total = s.length;
|
|
544
|
+
mcpServers.enabled = s.length;
|
|
948
545
|
}
|
|
949
546
|
}
|
|
950
547
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
path.join(process.cwd(), '.claude-flow', 'memory.db'),
|
|
955
|
-
path.join(process.cwd(), 'data', 'memory.db'),
|
|
956
|
-
];
|
|
957
|
-
hasDatabase = dbPaths.some(p => fs.existsSync(p));
|
|
548
|
+
const hasDatabase = ['.swarm/memory.db', '.claude-flow/memory.db', 'data/memory.db']
|
|
549
|
+
.some(p => fs.existsSync(path.join(CWD, p)));
|
|
550
|
+
const hasApi = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY);
|
|
958
551
|
|
|
959
|
-
|
|
960
|
-
const cachePaths = [
|
|
961
|
-
path.join(process.cwd(), '.claude-flow', 'cache'),
|
|
962
|
-
path.join(process.cwd(), '.cache'),
|
|
963
|
-
path.join(process.cwd(), 'node_modules', '.cache'),
|
|
964
|
-
];
|
|
965
|
-
hasCache = cachePaths.some(p => fs.existsSync(p));
|
|
966
|
-
|
|
967
|
-
// Check for API configuration (env vars or config)
|
|
968
|
-
try {
|
|
969
|
-
hasApi = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY);
|
|
970
|
-
} catch (e) { /* ignore */ }
|
|
971
|
-
|
|
972
|
-
return { mcpServers, hasDatabase, hasCache, hasApi };
|
|
552
|
+
return { mcpServers, hasDatabase, hasApi };
|
|
973
553
|
}
|
|
974
554
|
|
|
975
|
-
//
|
|
976
|
-
function getGitStatus() {
|
|
977
|
-
let modified = 0;
|
|
978
|
-
let untracked = 0;
|
|
979
|
-
let staged = 0;
|
|
980
|
-
let ahead = 0;
|
|
981
|
-
let behind = 0;
|
|
982
|
-
const isWindows = process.platform === 'win32';
|
|
983
|
-
|
|
984
|
-
try {
|
|
985
|
-
// Get modified and staged counts - works on all platforms
|
|
986
|
-
const status = execSync('git status --porcelain', {
|
|
987
|
-
encoding: 'utf-8',
|
|
988
|
-
stdio: ['pipe', 'pipe', 'pipe'], // Suppress stderr
|
|
989
|
-
timeout: 5000,
|
|
990
|
-
});
|
|
991
|
-
const lines = status.trim().split('\\n').filter(l => l);
|
|
992
|
-
for (const line of lines) {
|
|
993
|
-
const code = line.substring(0, 2);
|
|
994
|
-
if (code.includes('M') || code.includes('D') || code.includes('R')) {
|
|
995
|
-
if (code[0] !== ' ') staged++;
|
|
996
|
-
if (code[1] !== ' ') modified++;
|
|
997
|
-
}
|
|
998
|
-
if (code.includes('?')) untracked++;
|
|
999
|
-
if (code.includes('A')) staged++;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
// Get ahead/behind - may fail if no upstream
|
|
1003
|
-
try {
|
|
1004
|
-
const abStatus = execSync('git rev-list --left-right --count HEAD...@{upstream}', {
|
|
1005
|
-
encoding: 'utf-8',
|
|
1006
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1007
|
-
timeout: 5000,
|
|
1008
|
-
});
|
|
1009
|
-
const parts = abStatus.trim().split(/\\s+/);
|
|
1010
|
-
ahead = parseInt(parts[0]) || 0;
|
|
1011
|
-
behind = parseInt(parts[1]) || 0;
|
|
1012
|
-
} catch (e) { /* no upstream or error - that's ok */ }
|
|
1013
|
-
|
|
1014
|
-
} catch (e) {
|
|
1015
|
-
// Not a git repo or git not installed - return zeros
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
return { modified, untracked, staged, ahead, behind };
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// Get session statistics
|
|
555
|
+
// Session stats (pure file reads)
|
|
1022
556
|
function getSessionStats() {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
path.join(process.cwd(), '.claude', 'session.json'),
|
|
1032
|
-
];
|
|
1033
|
-
|
|
1034
|
-
for (const sessPath of sessionPaths) {
|
|
1035
|
-
if (fs.existsSync(sessPath)) {
|
|
1036
|
-
try {
|
|
1037
|
-
const data = JSON.parse(fs.readFileSync(sessPath, 'utf-8'));
|
|
1038
|
-
if (data.startTime) {
|
|
1039
|
-
sessionStart = new Date(data.startTime);
|
|
1040
|
-
const now = new Date();
|
|
1041
|
-
const diffMs = now.getTime() - sessionStart.getTime();
|
|
1042
|
-
const diffMins = Math.floor(diffMs / 60000);
|
|
1043
|
-
if (diffMins < 60) {
|
|
1044
|
-
duration = \`\${diffMins}m\`;
|
|
1045
|
-
} else {
|
|
1046
|
-
const hours = Math.floor(diffMins / 60);
|
|
1047
|
-
const mins = diffMins % 60;
|
|
1048
|
-
duration = \`\${hours}h\${mins}m\`;
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
if (data.lastActivity) {
|
|
1052
|
-
const last = new Date(data.lastActivity);
|
|
1053
|
-
const now = new Date();
|
|
1054
|
-
const diffMs = now.getTime() - last.getTime();
|
|
1055
|
-
const diffMins = Math.floor(diffMs / 60000);
|
|
1056
|
-
if (diffMins < 1) lastActivity = 'now';
|
|
1057
|
-
else if (diffMins < 60) lastActivity = \`\${diffMins}m ago\`;
|
|
1058
|
-
else lastActivity = \`\${Math.floor(diffMins / 60)}h ago\`;
|
|
1059
|
-
}
|
|
1060
|
-
operationsCount = data.operationsCount || data.commandCount || 0;
|
|
1061
|
-
break;
|
|
1062
|
-
} catch (e) { /* ignore */ }
|
|
557
|
+
var sessionPaths = ['.claude-flow/session.json', '.claude/session.json'];
|
|
558
|
+
for (var i = 0; i < sessionPaths.length; i++) {
|
|
559
|
+
const data = readJSON(path.join(CWD, sessionPaths[i]));
|
|
560
|
+
if (data && data.startTime) {
|
|
561
|
+
const diffMs = Date.now() - new Date(data.startTime).getTime();
|
|
562
|
+
const mins = Math.floor(diffMs / 60000);
|
|
563
|
+
const duration = mins < 60 ? mins + 'm' : Math.floor(mins / 60) + 'h' + (mins % 60) + 'm';
|
|
564
|
+
return { duration: duration };
|
|
1063
565
|
}
|
|
1064
566
|
}
|
|
1065
|
-
|
|
1066
|
-
// Fallback: check metrics for activity
|
|
1067
|
-
if (!duration) {
|
|
1068
|
-
const metricsPath = path.join(process.cwd(), '.claude-flow', 'metrics', 'activity.json');
|
|
1069
|
-
if (fs.existsSync(metricsPath)) {
|
|
1070
|
-
try {
|
|
1071
|
-
const data = JSON.parse(fs.readFileSync(metricsPath, 'utf-8'));
|
|
1072
|
-
operationsCount = data.totalOperations || 0;
|
|
1073
|
-
} catch (e) { /* ignore */ }
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
return { duration, lastActivity, operationsCount };
|
|
567
|
+
return { duration: '' };
|
|
1078
568
|
}
|
|
1079
569
|
|
|
1080
|
-
//
|
|
1081
|
-
function getTrend(current, previous) {
|
|
1082
|
-
if (previous === null || previous === undefined) return '';
|
|
1083
|
-
if (current > previous) return \`\${c.brightGreen}↑\${c.reset}\`;
|
|
1084
|
-
if (current < previous) return \`\${c.brightRed}↓\${c.reset}\`;
|
|
1085
|
-
return \`\${c.dim}→\${c.reset}\`;
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// Store previous values for trends (persisted between calls)
|
|
1089
|
-
let prevIntelligence = null;
|
|
1090
|
-
try {
|
|
1091
|
-
const trendPath = path.join(process.cwd(), '.claude-flow', '.trend-cache.json');
|
|
1092
|
-
if (fs.existsSync(trendPath)) {
|
|
1093
|
-
const data = JSON.parse(fs.readFileSync(trendPath, 'utf-8'));
|
|
1094
|
-
prevIntelligence = data.intelligence;
|
|
1095
|
-
}
|
|
1096
|
-
} catch (e) { /* ignore */ }
|
|
570
|
+
// ─── Rendering ──────────────────────────────────────────────────
|
|
1097
571
|
|
|
1098
|
-
// Generate progress bar
|
|
1099
572
|
function progressBar(current, total) {
|
|
1100
573
|
const width = 5;
|
|
1101
574
|
const filled = Math.round((current / total) * width);
|
|
1102
|
-
|
|
1103
|
-
return '[' + '\\u25CF'.repeat(filled) + '\\u25CB'.repeat(empty) + ']';
|
|
575
|
+
return '[' + '\\u25CF'.repeat(filled) + '\\u25CB'.repeat(width - filled) + ']';
|
|
1104
576
|
}
|
|
1105
577
|
|
|
1106
|
-
// Generate full statusline
|
|
1107
578
|
function generateStatusline() {
|
|
1108
|
-
const
|
|
579
|
+
const git = getGitInfo();
|
|
580
|
+
// Prefer model name from Claude Code stdin data, fallback to file-based detection
|
|
581
|
+
const modelName = getModelFromStdin() || getModelName();
|
|
582
|
+
const ctxInfo = getContextFromStdin();
|
|
583
|
+
const costInfo = getCostFromStdin();
|
|
1109
584
|
const progress = getV3Progress();
|
|
1110
585
|
const security = getSecurityStatus();
|
|
1111
586
|
const swarm = getSwarmStatus();
|
|
@@ -1114,147 +589,122 @@ function generateStatusline() {
|
|
|
1114
589
|
const hooks = getHooksStatus();
|
|
1115
590
|
const agentdb = getAgentDBStats();
|
|
1116
591
|
const tests = getTestStats();
|
|
1117
|
-
const git = getGitStatus();
|
|
1118
592
|
const session = getSessionStats();
|
|
1119
593
|
const integration = getIntegrationStatus();
|
|
1120
594
|
const lines = [];
|
|
1121
595
|
|
|
1122
|
-
//
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
const
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
if (git.behind > 0) header += \` \${c.brightRed}↓\${git.behind}\${c.reset}\`;
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
header += \` \${c.dim}│\${c.reset} \${c.purple}\${user.modelName}\${c.reset}\`;
|
|
1154
|
-
// Add session duration if available
|
|
1155
|
-
if (session.duration) {
|
|
1156
|
-
header += \` \${c.dim}│\${c.reset} \${c.cyan}⏱ \${session.duration}\${c.reset}\`;
|
|
596
|
+
// Header
|
|
597
|
+
let header = c.bold + c.brightPurple + '\\u258A RuFlo V3.5 ' + c.reset;
|
|
598
|
+
header += (swarm.coordinationActive ? c.brightCyan : c.dim) + '\\u25CF ' + c.brightCyan + git.name + c.reset;
|
|
599
|
+
if (git.gitBranch) {
|
|
600
|
+
header += ' ' + c.dim + '\\u2502' + c.reset + ' ' + c.brightBlue + '\\u23C7 ' + git.gitBranch + c.reset;
|
|
601
|
+
const changes = git.modified + git.staged + git.untracked;
|
|
602
|
+
if (changes > 0) {
|
|
603
|
+
let ind = '';
|
|
604
|
+
if (git.staged > 0) ind += c.brightGreen + '+' + git.staged + c.reset;
|
|
605
|
+
if (git.modified > 0) ind += c.brightYellow + '~' + git.modified + c.reset;
|
|
606
|
+
if (git.untracked > 0) ind += c.dim + '?' + git.untracked + c.reset;
|
|
607
|
+
header += ' ' + ind;
|
|
608
|
+
}
|
|
609
|
+
if (git.ahead > 0) header += ' ' + c.brightGreen + '\\u2191' + git.ahead + c.reset;
|
|
610
|
+
if (git.behind > 0) header += ' ' + c.brightRed + '\\u2193' + git.behind + c.reset;
|
|
611
|
+
}
|
|
612
|
+
header += ' ' + c.dim + '\\u2502' + c.reset + ' ' + c.purple + modelName + c.reset;
|
|
613
|
+
// Show session duration from Claude Code stdin if available, else from local files
|
|
614
|
+
const duration = costInfo ? costInfo.duration : session.duration;
|
|
615
|
+
if (duration) header += ' ' + c.dim + '\\u2502' + c.reset + ' ' + c.cyan + '\\u23F1 ' + duration + c.reset;
|
|
616
|
+
// Show context usage from Claude Code stdin if available
|
|
617
|
+
if (ctxInfo && ctxInfo.usedPct > 0) {
|
|
618
|
+
const ctxColor = ctxInfo.usedPct >= 90 ? c.brightRed : ctxInfo.usedPct >= 70 ? c.brightYellow : c.brightGreen;
|
|
619
|
+
header += ' ' + c.dim + '\\u2502' + c.reset + ' ' + ctxColor + '\\u25CF ' + ctxInfo.usedPct + '% ctx' + c.reset;
|
|
620
|
+
}
|
|
621
|
+
// Show cost from Claude Code stdin if available
|
|
622
|
+
if (costInfo && costInfo.costUsd > 0) {
|
|
623
|
+
header += ' ' + c.dim + '\\u2502' + c.reset + ' ' + c.brightYellow + '$' + costInfo.costUsd.toFixed(2) + c.reset;
|
|
1157
624
|
}
|
|
1158
625
|
lines.push(header);
|
|
1159
626
|
|
|
1160
627
|
// Separator
|
|
1161
|
-
lines.push(
|
|
628
|
+
lines.push(c.dim + '\\u2500'.repeat(53) + c.reset);
|
|
1162
629
|
|
|
1163
|
-
// Line 1: DDD
|
|
630
|
+
// Line 1: DDD Domains
|
|
1164
631
|
const domainsColor = progress.domainsCompleted >= 3 ? c.brightGreen : progress.domainsCompleted > 0 ? c.yellow : c.red;
|
|
1165
|
-
|
|
1166
|
-
let perfIndicator = '';
|
|
632
|
+
let perfIndicator;
|
|
1167
633
|
if (agentdb.hasHnsw && agentdb.vectorCount > 0) {
|
|
1168
|
-
// HNSW enabled: show estimated speedup (150x-12500x based on vector count)
|
|
1169
634
|
const speedup = agentdb.vectorCount > 10000 ? '12500x' : agentdb.vectorCount > 1000 ? '150x' : '10x';
|
|
1170
|
-
perfIndicator =
|
|
635
|
+
perfIndicator = c.brightGreen + '\\u26A1 HNSW ' + speedup + c.reset;
|
|
1171
636
|
} else if (progress.patternsLearned > 0) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
? \`\${(progress.patternsLearned / 1000).toFixed(1)}k\`
|
|
1175
|
-
: String(progress.patternsLearned);
|
|
1176
|
-
perfIndicator = \`\${c.brightYellow}📚 \${patternsK} patterns\${c.reset}\`;
|
|
637
|
+
const pk = progress.patternsLearned >= 1000 ? (progress.patternsLearned / 1000).toFixed(1) + 'k' : String(progress.patternsLearned);
|
|
638
|
+
perfIndicator = c.brightYellow + '\\uD83D\\uDCDA ' + pk + ' patterns' + c.reset;
|
|
1177
639
|
} else {
|
|
1178
|
-
|
|
1179
|
-
perfIndicator = \`\${c.dim}⚡ target: 150x-12500x\${c.reset}\`;
|
|
640
|
+
perfIndicator = c.dim + '\\u26A1 target: 150x-12500x' + c.reset;
|
|
1180
641
|
}
|
|
1181
642
|
lines.push(
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
perfIndicator
|
|
643
|
+
c.brightCyan + '\\uD83C\\uDFD7\\uFE0F DDD Domains' + c.reset + ' ' + progressBar(progress.domainsCompleted, progress.totalDomains) + ' ' +
|
|
644
|
+
domainsColor + progress.domainsCompleted + c.reset + '/' + c.brightWhite + progress.totalDomains + c.reset + ' ' + perfIndicator
|
|
1185
645
|
);
|
|
1186
646
|
|
|
1187
|
-
// Line 2: Swarm + Hooks + CVE + Memory +
|
|
1188
|
-
const
|
|
647
|
+
// Line 2: Swarm + Hooks + CVE + Memory + Intelligence
|
|
648
|
+
const swarmInd = swarm.coordinationActive ? c.brightGreen + '\\u25C9' + c.reset : c.dim + '\\u25CB' + c.reset;
|
|
1189
649
|
const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.red;
|
|
1190
|
-
|
|
1191
|
-
|
|
650
|
+
const secIcon = security.status === 'CLEAN' ? '\\uD83D\\uDFE2' : (security.status === 'IN_PROGRESS' || security.status === 'STALE') ? '\\uD83D\\uDFE1' : (security.status === 'NONE' ? '\\u26AA' : '\\uD83D\\uDD34');
|
|
651
|
+
const secColor = security.status === 'CLEAN' ? c.brightGreen : (security.status === 'IN_PROGRESS' || security.status === 'STALE') ? c.brightYellow : (security.status === 'NONE' ? c.dim : c.brightRed);
|
|
1192
652
|
const hooksColor = hooks.enabled > 0 ? c.brightGreen : c.dim;
|
|
653
|
+
const intellColor = system.intelligencePct >= 80 ? c.brightGreen : system.intelligencePct >= 40 ? c.brightYellow : c.dim;
|
|
1193
654
|
|
|
1194
655
|
lines.push(
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
656
|
+
c.brightYellow + '\\uD83E\\uDD16 Swarm' + c.reset + ' ' + swarmInd + ' [' + agentsColor + String(swarm.activeAgents).padStart(2) + c.reset + '/' + c.brightWhite + swarm.maxAgents + c.reset + '] ' +
|
|
657
|
+
c.brightPurple + '\\uD83D\\uDC65 ' + system.subAgents + c.reset + ' ' +
|
|
658
|
+
c.brightBlue + '\\uD83E\\uDE9D ' + hooksColor + hooks.enabled + c.reset + '/' + c.brightWhite + hooks.total + c.reset + ' ' +
|
|
659
|
+
secIcon + ' ' + secColor + 'CVE ' + security.cvesFixed + c.reset + '/' + c.brightWhite + security.totalCves + c.reset + ' ' +
|
|
660
|
+
c.brightCyan + '\\uD83D\\uDCBE ' + system.memoryMB + 'MB' + c.reset + ' ' +
|
|
661
|
+
intellColor + '\\uD83E\\uDDE0 ' + String(system.intelligencePct).padStart(3) + '%' + c.reset
|
|
1201
662
|
);
|
|
1202
663
|
|
|
1203
|
-
// Line 3: Architecture
|
|
664
|
+
// Line 3: Architecture
|
|
1204
665
|
const dddColor = progress.dddProgress >= 50 ? c.brightGreen : progress.dddProgress > 0 ? c.yellow : c.red;
|
|
1205
666
|
const adrColor = adrs.count > 0 ? (adrs.implemented === adrs.count ? c.brightGreen : c.yellow) : c.dim;
|
|
1206
|
-
const
|
|
1207
|
-
const testColor = tests.testFiles > 0 ? c.brightGreen : c.dim;
|
|
1208
|
-
|
|
1209
|
-
// Show ADR compliance % if from real data, otherwise show count
|
|
1210
|
-
const adrDisplay = adrs.compliance > 0
|
|
1211
|
-
? \`\${adrColor}●\${adrs.compliance}%\${c.reset}\`
|
|
1212
|
-
: \`\${adrColor}●\${adrs.implemented}/\${adrs.count}\${c.reset}\`;
|
|
667
|
+
const adrDisplay = adrs.compliance > 0 ? adrColor + '\\u25CF' + adrs.compliance + '%' + c.reset : adrColor + '\\u25CF' + adrs.implemented + '/' + adrs.count + c.reset;
|
|
1213
668
|
|
|
1214
669
|
lines.push(
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
670
|
+
c.brightPurple + '\\uD83D\\uDD27 Architecture' + c.reset + ' ' +
|
|
671
|
+
c.cyan + 'ADRs' + c.reset + ' ' + adrDisplay + ' ' + c.dim + '\\u2502' + c.reset + ' ' +
|
|
672
|
+
c.cyan + 'DDD' + c.reset + ' ' + dddColor + '\\u25CF' + String(progress.dddProgress).padStart(3) + '%' + c.reset + ' ' + c.dim + '\\u2502' + c.reset + ' ' +
|
|
673
|
+
c.cyan + 'Security' + c.reset + ' ' + secColor + '\\u25CF' + security.status + c.reset
|
|
1219
674
|
);
|
|
1220
675
|
|
|
1221
|
-
// Line 4:
|
|
1222
|
-
const
|
|
1223
|
-
const
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
let
|
|
676
|
+
// Line 4: AgentDB, Tests, Integration
|
|
677
|
+
const hnswInd = agentdb.hasHnsw ? c.brightGreen + '\\u26A1' + c.reset : '';
|
|
678
|
+
const sizeDisp = agentdb.dbSizeKB >= 1024 ? (agentdb.dbSizeKB / 1024).toFixed(1) + 'MB' : agentdb.dbSizeKB + 'KB';
|
|
679
|
+
const vectorColor = agentdb.vectorCount > 0 ? c.brightGreen : c.dim;
|
|
680
|
+
const testColor = tests.testFiles > 0 ? c.brightGreen : c.dim;
|
|
681
|
+
|
|
682
|
+
let integStr = '';
|
|
1228
683
|
if (integration.mcpServers.total > 0) {
|
|
1229
|
-
const
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
}
|
|
1233
|
-
if (integration.hasDatabase) {
|
|
1234
|
-
integrationStr += (integrationStr ? ' ' : '') + \`\${c.brightGreen}◆\${c.reset}DB\`;
|
|
1235
|
-
}
|
|
1236
|
-
if (integration.hasApi) {
|
|
1237
|
-
integrationStr += (integrationStr ? ' ' : '') + \`\${c.brightGreen}◆\${c.reset}API\`;
|
|
1238
|
-
}
|
|
1239
|
-
if (!integrationStr) {
|
|
1240
|
-
integrationStr = \`\${c.dim}●none\${c.reset}\`;
|
|
684
|
+
const mcpCol = integration.mcpServers.enabled === integration.mcpServers.total ? c.brightGreen :
|
|
685
|
+
integration.mcpServers.enabled > 0 ? c.brightYellow : c.red;
|
|
686
|
+
integStr += c.cyan + 'MCP' + c.reset + ' ' + mcpCol + '\\u25CF' + integration.mcpServers.enabled + '/' + integration.mcpServers.total + c.reset;
|
|
1241
687
|
}
|
|
688
|
+
if (integration.hasDatabase) integStr += (integStr ? ' ' : '') + c.brightGreen + '\\u25C6' + c.reset + 'DB';
|
|
689
|
+
if (integration.hasApi) integStr += (integStr ? ' ' : '') + c.brightGreen + '\\u25C6' + c.reset + 'API';
|
|
690
|
+
if (!integStr) integStr = c.dim + '\\u25CF none' + c.reset;
|
|
1242
691
|
|
|
1243
692
|
lines.push(
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
693
|
+
c.brightCyan + '\\uD83D\\uDCCA AgentDB' + c.reset + ' ' +
|
|
694
|
+
c.cyan + 'Vectors' + c.reset + ' ' + vectorColor + '\\u25CF' + agentdb.vectorCount + hnswInd + c.reset + ' ' + c.dim + '\\u2502' + c.reset + ' ' +
|
|
695
|
+
c.cyan + 'Size' + c.reset + ' ' + c.brightWhite + sizeDisp + c.reset + ' ' + c.dim + '\\u2502' + c.reset + ' ' +
|
|
696
|
+
c.cyan + 'Tests' + c.reset + ' ' + testColor + '\\u25CF' + tests.testFiles + c.reset + ' ' + c.dim + '(~' + tests.testCases + ' cases)' + c.reset + ' ' + c.dim + '\\u2502' + c.reset + ' ' +
|
|
697
|
+
integStr
|
|
1249
698
|
);
|
|
1250
699
|
|
|
1251
700
|
return lines.join('\\n');
|
|
1252
701
|
}
|
|
1253
702
|
|
|
1254
|
-
//
|
|
703
|
+
// JSON output
|
|
1255
704
|
function generateJSON() {
|
|
705
|
+
const git = getGitInfo();
|
|
1256
706
|
return {
|
|
1257
|
-
user:
|
|
707
|
+
user: { name: git.name, gitBranch: git.gitBranch, modelName: getModelName() },
|
|
1258
708
|
v3Progress: getV3Progress(),
|
|
1259
709
|
security: getSecurityStatus(),
|
|
1260
710
|
swarm: getSwarmStatus(),
|
|
@@ -1263,16 +713,81 @@ function generateJSON() {
|
|
|
1263
713
|
hooks: getHooksStatus(),
|
|
1264
714
|
agentdb: getAgentDBStats(),
|
|
1265
715
|
tests: getTestStats(),
|
|
1266
|
-
|
|
1267
|
-
flashAttentionTarget: '2.49x-7.47x',
|
|
1268
|
-
searchImprovement: '150x-12,500x',
|
|
1269
|
-
memoryReduction: '50-75%',
|
|
1270
|
-
},
|
|
716
|
+
git: { modified: git.modified, untracked: git.untracked, staged: git.staged, ahead: git.ahead, behind: git.behind },
|
|
1271
717
|
lastUpdated: new Date().toISOString(),
|
|
1272
718
|
};
|
|
1273
719
|
}
|
|
1274
720
|
|
|
1275
|
-
//
|
|
721
|
+
// ─── Stdin reader (Claude Code pipes session JSON) ──────────────
|
|
722
|
+
|
|
723
|
+
// Claude Code sends session JSON via stdin (model, context, cost, etc.)
|
|
724
|
+
// Read it synchronously so the script works both:
|
|
725
|
+
// 1. When invoked by Claude Code (stdin has JSON)
|
|
726
|
+
// 2. When invoked manually from terminal (stdin is empty/tty)
|
|
727
|
+
let _stdinData = null;
|
|
728
|
+
function getStdinData() {
|
|
729
|
+
if (_stdinData !== undefined && _stdinData !== null) return _stdinData;
|
|
730
|
+
try {
|
|
731
|
+
// Check if stdin is a TTY (manual run) — skip reading
|
|
732
|
+
if (process.stdin.isTTY) { _stdinData = null; return null; }
|
|
733
|
+
// Read stdin synchronously via fd 0
|
|
734
|
+
const chunks = [];
|
|
735
|
+
const buf = Buffer.alloc(4096);
|
|
736
|
+
let bytesRead;
|
|
737
|
+
try {
|
|
738
|
+
while ((bytesRead = fs.readSync(0, buf, 0, buf.length, null)) > 0) {
|
|
739
|
+
chunks.push(buf.slice(0, bytesRead));
|
|
740
|
+
}
|
|
741
|
+
} catch { /* EOF or read error */ }
|
|
742
|
+
const raw = Buffer.concat(chunks).toString('utf-8').trim();
|
|
743
|
+
if (raw && raw.startsWith('{')) {
|
|
744
|
+
_stdinData = JSON.parse(raw);
|
|
745
|
+
} else {
|
|
746
|
+
_stdinData = null;
|
|
747
|
+
}
|
|
748
|
+
} catch {
|
|
749
|
+
_stdinData = null;
|
|
750
|
+
}
|
|
751
|
+
return _stdinData;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Override model detection to prefer stdin data from Claude Code
|
|
755
|
+
function getModelFromStdin() {
|
|
756
|
+
const data = getStdinData();
|
|
757
|
+
if (data && data.model && data.model.display_name) return data.model.display_name;
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Get context window info from Claude Code session
|
|
762
|
+
function getContextFromStdin() {
|
|
763
|
+
const data = getStdinData();
|
|
764
|
+
if (data && data.context_window) {
|
|
765
|
+
return {
|
|
766
|
+
usedPct: Math.floor(data.context_window.used_percentage || 0),
|
|
767
|
+
remainingPct: Math.floor(data.context_window.remaining_percentage || 100),
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
return null;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Get cost info from Claude Code session
|
|
774
|
+
function getCostFromStdin() {
|
|
775
|
+
const data = getStdinData();
|
|
776
|
+
if (data && data.cost) {
|
|
777
|
+
const durationMs = data.cost.total_duration_ms || 0;
|
|
778
|
+
const mins = Math.floor(durationMs / 60000);
|
|
779
|
+
const secs = Math.floor((durationMs % 60000) / 1000);
|
|
780
|
+
return {
|
|
781
|
+
costUsd: data.cost.total_cost_usd || 0,
|
|
782
|
+
duration: mins > 0 ? mins + 'm' + secs + 's' : secs + 's',
|
|
783
|
+
linesAdded: data.cost.total_lines_added || 0,
|
|
784
|
+
linesRemoved: data.cost.total_lines_removed || 0,
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// ─── Main ───────────────────────────────────────────────────────
|
|
1276
791
|
if (process.argv.includes('--json')) {
|
|
1277
792
|
console.log(JSON.stringify(generateJSON(), null, 2));
|
|
1278
793
|
} else if (process.argv.includes('--compact')) {
|
|
@@ -1287,10 +802,11 @@ if (process.argv.includes('--json')) {
|
|
|
1287
802
|
*/
|
|
1288
803
|
export function generateStatuslineHook(options) {
|
|
1289
804
|
if (!options.statusline.enabled) {
|
|
1290
|
-
return '# Statusline disabled';
|
|
805
|
+
return '#!/bin/bash\n# Statusline disabled\n';
|
|
1291
806
|
}
|
|
1292
|
-
return
|
|
1293
|
-
#
|
|
807
|
+
return `#!/bin/bash
|
|
808
|
+
# RuFlo V3 Statusline Hook
|
|
809
|
+
# Source this in your .bashrc/.zshrc for terminal statusline
|
|
1294
810
|
|
|
1295
811
|
# Function to get statusline
|
|
1296
812
|
claude_flow_statusline() {
|
|
@@ -1300,16 +816,18 @@ claude_flow_statusline() {
|
|
|
1300
816
|
fi
|
|
1301
817
|
}
|
|
1302
818
|
|
|
1303
|
-
#
|
|
819
|
+
# Bash: Add to PS1
|
|
1304
820
|
# export PS1='$(claude_flow_statusline) \\n\\$ '
|
|
1305
821
|
|
|
1306
|
-
#
|
|
822
|
+
# Zsh: Add to RPROMPT
|
|
1307
823
|
# export RPROMPT='$(claude_flow_statusline)'
|
|
1308
824
|
|
|
1309
|
-
#
|
|
1310
|
-
#
|
|
1311
|
-
# command
|
|
1312
|
-
#
|
|
825
|
+
# Claude Code: Add to .claude/settings.json
|
|
826
|
+
# "statusLine": {
|
|
827
|
+
# "type": "command",
|
|
828
|
+
# "command": "node .claude/helpers/statusline.cjs 2>/dev/null"
|
|
829
|
+
# "when": "test -f .claude/helpers/statusline.cjs"
|
|
830
|
+
# }
|
|
1313
831
|
`;
|
|
1314
832
|
}
|
|
1315
833
|
//# sourceMappingURL=statusline-generator.js.map
|