kynjal-cli 4.0.0 → 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/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 +286 -525
- package/dist/src/appliance/gguf-engine.js.map +1 -1
- 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 +203 -403
- package/dist/src/appliance/ruvllm-bridge.js.map +1 -1
- 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 +154 -208
- package/dist/src/appliance/rvfa-builder.js.map +1 -1
- 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 +260 -423
- package/dist/src/appliance/rvfa-distribution.js.map +1 -1
- 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 +128 -200
- package/dist/src/appliance/rvfa-format.js.map +1 -1
- 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 +168 -304
- package/dist/src/appliance/rvfa-runner.js.map +1 -1
- 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 +173 -295
- package/dist/src/appliance/rvfa-signing.js.map +1 -1
- package/dist/src/benchmarks/pretrain/index.d.ts +58 -0
- package/dist/src/benchmarks/pretrain/index.d.ts.map +1 -0
- package/dist/src/benchmarks/pretrain/index.js +331 -542
- package/dist/src/benchmarks/pretrain/index.js.map +1 -1
- package/dist/src/commands/agent.js +574 -697
- package/dist/src/commands/agent.js.map +1 -1
- package/dist/src/commands/analyze.js +1218 -1548
- package/dist/src/commands/analyze.js.map +1 -1
- package/dist/src/commands/appliance-advanced.js +158 -267
- package/dist/src/commands/appliance-advanced.js.map +1 -1
- package/dist/src/commands/appliance.js +318 -493
- package/dist/src/commands/appliance.js.map +1 -1
- package/dist/src/commands/benchmark.js +372 -523
- package/dist/src/commands/benchmark.js.map +1 -1
- package/dist/src/commands/claims.js +274 -364
- package/dist/src/commands/claims.js.map +1 -1
- package/dist/src/commands/cleanup.js +113 -157
- package/dist/src/commands/cleanup.js.map +1 -1
- package/dist/src/commands/completions.js +477 -118
- package/dist/src/commands/completions.js.map +1 -1
- package/dist/src/commands/config.js +237 -303
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/daemon.js +487 -596
- package/dist/src/commands/daemon.js.map +1 -1
- package/dist/src/commands/deployment.js +194 -275
- package/dist/src/commands/deployment.js.map +1 -1
- package/dist/src/commands/doctor.js +504 -686
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/embeddings.js +1293 -1543
- package/dist/src/commands/embeddings.js.map +1 -1
- package/dist/src/commands/guidance.js +449 -596
- package/dist/src/commands/guidance.js.map +1 -1
- package/dist/src/commands/hive-mind.js +854 -938
- package/dist/src/commands/hive-mind.js.map +1 -1
- package/dist/src/commands/hooks.js +3112 -3519
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/commands/index.d.ts +115 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +126 -308
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init.js +788 -940
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/issues.js +383 -558
- package/dist/src/commands/issues.js.map +1 -1
- package/dist/src/commands/mcp.js +493 -605
- package/dist/src/commands/mcp.js.map +1 -1
- package/dist/src/commands/memory.js +833 -1026
- package/dist/src/commands/memory.js.map +1 -1
- package/dist/src/commands/migrate.js +282 -347
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/neural.js +1289 -1563
- package/dist/src/commands/neural.js.map +1 -1
- package/dist/src/commands/performance.js +497 -643
- package/dist/src/commands/performance.js.map +1 -1
- package/dist/src/commands/plugins.js +668 -841
- package/dist/src/commands/plugins.js.map +1 -1
- package/dist/src/commands/process.js +392 -447
- package/dist/src/commands/process.js.map +1 -1
- package/dist/src/commands/progress.js +162 -256
- package/dist/src/commands/progress.js.map +1 -1
- package/dist/src/commands/providers.js +150 -220
- package/dist/src/commands/providers.js.map +1 -1
- package/dist/src/commands/route.js +520 -665
- package/dist/src/commands/route.js.map +1 -1
- package/dist/src/commands/ruvector/backup.js +505 -651
- package/dist/src/commands/ruvector/backup.js.map +1 -1
- package/dist/src/commands/ruvector/benchmark.js +349 -401
- package/dist/src/commands/ruvector/benchmark.js.map +1 -1
- package/dist/src/commands/ruvector/import.js +224 -266
- package/dist/src/commands/ruvector/import.js.map +1 -1
- package/dist/src/commands/ruvector/index.js +37 -75
- package/dist/src/commands/ruvector/index.js.map +1 -1
- package/dist/src/commands/ruvector/init.js +336 -359
- package/dist/src/commands/ruvector/init.js.map +1 -1
- package/dist/src/commands/ruvector/migrate.js +335 -322
- package/dist/src/commands/ruvector/migrate.js.map +1 -1
- package/dist/src/commands/ruvector/optimize.js +375 -431
- package/dist/src/commands/ruvector/optimize.js.map +1 -1
- package/dist/src/commands/ruvector/setup.js +703 -117
- package/dist/src/commands/ruvector/setup.js.map +1 -1
- package/dist/src/commands/ruvector/status.js +364 -419
- package/dist/src/commands/ruvector/status.js.map +1 -1
- package/dist/src/commands/security.js +485 -608
- package/dist/src/commands/security.js.map +1 -1
- package/dist/src/commands/session.js +504 -626
- package/dist/src/commands/session.js.map +1 -1
- package/dist/src/commands/start.js +267 -364
- package/dist/src/commands/start.js.map +1 -1
- package/dist/src/commands/status.js +380 -486
- package/dist/src/commands/status.js.map +1 -1
- package/dist/src/commands/swarm.js +408 -488
- package/dist/src/commands/swarm.js.map +1 -1
- package/dist/src/commands/task.js +423 -538
- package/dist/src/commands/task.js.map +1 -1
- package/dist/src/commands/transfer-store.js +322 -412
- package/dist/src/commands/transfer-store.js.map +1 -1
- package/dist/src/commands/update.js +196 -291
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/workflow.js +386 -486
- package/dist/src/commands/workflow.js.map +1 -1
- package/dist/src/config-adapter.d.ts +15 -0
- package/dist/src/config-adapter.d.ts.map +1 -0
- package/dist/src/config-adapter.js +38 -39
- package/dist/src/config-adapter.js.map +1 -1
- package/dist/src/index.d.ts +77 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +309 -411
- package/dist/src/index.js.map +1 -1
- package/dist/src/infrastructure/in-memory-repositories.d.ts +68 -0
- package/dist/src/infrastructure/in-memory-repositories.d.ts.map +1 -0
- package/dist/src/infrastructure/in-memory-repositories.js +246 -507
- package/dist/src/infrastructure/in-memory-repositories.js.map +1 -1
- package/dist/src/init/claudemd-generator.d.ts +25 -0
- package/dist/src/init/claudemd-generator.d.ts.map +1 -0
- package/dist/src/init/claudemd-generator.js +368 -78
- package/dist/src/init/claudemd-generator.js.map +1 -1
- package/dist/src/init/executor.d.ts +41 -0
- package/dist/src/init/executor.d.ts.map +1 -0
- package/dist/src/init/executor.js +1307 -996
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/helpers-generator.d.ts +60 -0
- package/dist/src/init/helpers-generator.d.ts.map +1 -0
- package/dist/src/init/helpers-generator.js +657 -12
- package/dist/src/init/helpers-generator.js.map +1 -1
- package/dist/src/init/index.d.ts +1 -1
- package/dist/src/init/index.d.ts.map +1 -1
- package/dist/src/init/index.js +1 -1
- package/dist/src/init/index.js.map +1 -1
- package/dist/src/init/mcp-generator.js +33 -37
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/init/settings-generator.js +76 -77
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/init/statusline-generator.js +801 -3
- package/dist/src/init/statusline-generator.js.map +1 -1
- package/dist/src/init/types.d.ts +1 -1
- package/dist/src/init/types.d.ts.map +1 -1
- package/dist/src/init/types.js +76 -59
- package/dist/src/init/types.js.map +1 -1
- package/dist/src/mcp-client.d.ts +92 -0
- package/dist/src/mcp-client.d.ts.map +1 -0
- package/dist/src/mcp-client.js +81 -125
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-server.d.ts +161 -0
- package/dist/src/mcp-server.d.ts.map +1 -0
- package/dist/src/mcp-server.js +470 -757
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/agent-tools.js +391 -492
- package/dist/src/mcp-tools/agent-tools.js.map +1 -1
- package/dist/src/mcp-tools/agentdb-tools.js +332 -533
- package/dist/src/mcp-tools/agentdb-tools.js.map +1 -1
- package/dist/src/mcp-tools/analyze-tools.js +172 -236
- package/dist/src/mcp-tools/analyze-tools.js.map +1 -1
- package/dist/src/mcp-tools/auto-install.d.ts +83 -0
- package/dist/src/mcp-tools/auto-install.d.ts.map +1 -0
- package/dist/src/mcp-tools/auto-install.js +80 -142
- package/dist/src/mcp-tools/auto-install.js.map +1 -1
- package/dist/src/mcp-tools/browser-tools.js +252 -375
- package/dist/src/mcp-tools/browser-tools.js.map +1 -1
- package/dist/src/mcp-tools/claims-tools.js +473 -565
- package/dist/src/mcp-tools/claims-tools.js.map +1 -1
- package/dist/src/mcp-tools/config-tools.js +197 -272
- package/dist/src/mcp-tools/config-tools.js.map +1 -1
- package/dist/src/mcp-tools/coordination-tools.js +500 -572
- package/dist/src/mcp-tools/coordination-tools.js.map +1 -1
- package/dist/src/mcp-tools/daa-tools.js +286 -364
- package/dist/src/mcp-tools/daa-tools.js.map +1 -1
- package/dist/src/mcp-tools/embeddings-tools.js +582 -693
- package/dist/src/mcp-tools/embeddings-tools.js.map +1 -1
- package/dist/src/mcp-tools/github-tools.js +260 -311
- package/dist/src/mcp-tools/github-tools.js.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +573 -640
- package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.js +2215 -2648
- package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
- package/dist/src/mcp-tools/memory-tools.js +350 -505
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/mcp-tools/neural-tools.js +315 -412
- package/dist/src/mcp-tools/neural-tools.js.map +1 -1
- package/dist/src/mcp-tools/performance-tools.js +420 -480
- package/dist/src/mcp-tools/performance-tools.js.map +1 -1
- package/dist/src/mcp-tools/progress-tools.js +204 -278
- package/dist/src/mcp-tools/progress-tools.js.map +1 -1
- package/dist/src/mcp-tools/ruvllm-tools.js +163 -279
- package/dist/src/mcp-tools/ruvllm-tools.js.map +1 -1
- package/dist/src/mcp-tools/security-tools.js +297 -429
- package/dist/src/mcp-tools/security-tools.js.map +1 -1
- package/dist/src/mcp-tools/session-tools.js +185 -234
- package/dist/src/mcp-tools/session-tools.js.map +1 -1
- package/dist/src/mcp-tools/swarm-tools.js +207 -260
- package/dist/src/mcp-tools/swarm-tools.js.map +1 -1
- package/dist/src/mcp-tools/system-tools.js +276 -325
- package/dist/src/mcp-tools/system-tools.js.map +1 -1
- package/dist/src/mcp-tools/task-tools.js +270 -336
- package/dist/src/mcp-tools/task-tools.js.map +1 -1
- package/dist/src/mcp-tools/terminal-tools.js +148 -196
- package/dist/src/mcp-tools/terminal-tools.js.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.js +186 -333
- package/dist/src/mcp-tools/transfer-tools.js.map +1 -1
- package/dist/src/mcp-tools/types.d.ts +31 -0
- package/dist/src/mcp-tools/types.d.ts.map +1 -0
- package/dist/src/mcp-tools/wasm-agent-tools.js +133 -280
- package/dist/src/mcp-tools/wasm-agent-tools.js.map +1 -1
- package/dist/src/mcp-tools/workflow-tools.js +405 -450
- package/dist/src/mcp-tools/workflow-tools.js.map +1 -1
- package/dist/src/memory/ewc-consolidation.d.ts +295 -0
- package/dist/src/memory/ewc-consolidation.d.ts.map +1 -0
- package/dist/src/memory/ewc-consolidation.js +190 -303
- package/dist/src/memory/ewc-consolidation.js.map +1 -1
- package/dist/src/memory/intelligence.d.ts +338 -0
- package/dist/src/memory/intelligence.d.ts.map +1 -0
- package/dist/src/memory/intelligence.js +569 -794
- 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 +1170 -1640
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-initializer.d.ts +412 -0
- package/dist/src/memory/memory-initializer.d.ts.map +1 -0
- package/dist/src/memory/memory-initializer.js +1836 -1851
- package/dist/src/memory/memory-initializer.js.map +1 -1
- package/dist/src/memory/sona-optimizer.d.ts +227 -0
- package/dist/src/memory/sona-optimizer.d.ts.map +1 -0
- package/dist/src/memory/sona-optimizer.js +199 -329
- package/dist/src/memory/sona-optimizer.js.map +1 -1
- package/dist/src/output.d.ts +2 -2
- package/dist/src/output.d.ts.map +1 -1
- package/dist/src/output.js +242 -272
- package/dist/src/output.js.map +1 -1
- package/dist/src/parser.d.ts +51 -0
- package/dist/src/parser.d.ts.map +1 -0
- package/dist/src/parser.js +140 -187
- package/dist/src/parser.js.map +1 -1
- package/dist/src/plugins/manager.d.ts +133 -0
- package/dist/src/plugins/manager.d.ts.map +1 -0
- package/dist/src/plugins/manager.js +285 -521
- package/dist/src/plugins/manager.js.map +1 -1
- package/dist/src/plugins/store/discovery.d.ts +88 -0
- package/dist/src/plugins/store/discovery.d.ts.map +1 -0
- package/dist/src/plugins/store/discovery.js +271 -358
- package/dist/src/plugins/store/discovery.js.map +1 -1
- package/dist/src/plugins/store/index.d.ts +76 -0
- package/dist/src/plugins/store/index.d.ts.map +1 -0
- package/dist/src/plugins/store/index.js +48 -105
- package/dist/src/plugins/store/index.js.map +1 -1
- package/dist/src/plugins/store/search.d.ts +46 -0
- package/dist/src/plugins/store/search.d.ts.map +1 -0
- package/dist/src/plugins/store/search.js +69 -107
- package/dist/src/plugins/store/search.js.map +1 -1
- package/dist/src/plugins/store/types.d.ts +274 -0
- package/dist/src/plugins/store/types.d.ts.map +1 -0
- package/dist/src/plugins/tests/demo-plugin-store.js +113 -160
- package/dist/src/plugins/tests/demo-plugin-store.js.map +1 -1
- package/dist/src/plugins/tests/standalone-test.js +172 -223
- package/dist/src/plugins/tests/standalone-test.js.map +1 -1
- package/dist/src/plugins/tests/test-plugin-store.js +190 -228
- package/dist/src/plugins/tests/test-plugin-store.js.map +1 -1
- package/dist/src/production/circuit-breaker.d.ts +101 -0
- package/dist/src/production/circuit-breaker.d.ts.map +1 -0
- package/dist/src/production/circuit-breaker.js +62 -126
- package/dist/src/production/circuit-breaker.js.map +1 -1
- package/dist/src/production/error-handler.d.ts +92 -0
- package/dist/src/production/error-handler.d.ts.map +1 -0
- package/dist/src/production/error-handler.js +86 -156
- package/dist/src/production/error-handler.js.map +1 -1
- package/dist/src/production/monitoring.d.ts +161 -0
- package/dist/src/production/monitoring.d.ts.map +1 -0
- package/dist/src/production/monitoring.js +139 -220
- package/dist/src/production/monitoring.js.map +1 -1
- package/dist/src/production/rate-limiter.d.ts +80 -0
- package/dist/src/production/rate-limiter.d.ts.map +1 -0
- package/dist/src/production/rate-limiter.js +74 -93
- package/dist/src/production/rate-limiter.js.map +1 -1
- package/dist/src/production/retry.d.ts +48 -0
- package/dist/src/production/retry.d.ts.map +1 -0
- package/dist/src/production/retry.js +75 -167
- package/dist/src/production/retry.js.map +1 -1
- package/dist/src/prompt.d.ts +44 -0
- package/dist/src/prompt.d.ts.map +1 -0
- package/dist/src/prompt.js +436 -560
- package/dist/src/prompt.js.map +1 -1
- package/dist/src/runtime/headless.d.ts +60 -0
- package/dist/src/runtime/headless.d.ts.map +1 -0
- package/dist/src/runtime/headless.js +197 -286
- 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 +156 -351
- package/dist/src/ruvector/agent-wasm.js.map +1 -1
- package/dist/src/ruvector/ast-analyzer.d.ts +67 -0
- package/dist/src/ruvector/ast-analyzer.d.ts.map +1 -0
- package/dist/src/ruvector/ast-analyzer.js +145 -232
- package/dist/src/ruvector/ast-analyzer.js.map +1 -1
- package/dist/src/ruvector/coverage-router.d.ts +160 -0
- package/dist/src/ruvector/coverage-router.d.ts.map +1 -0
- package/dist/src/ruvector/coverage-router.js +287 -419
- package/dist/src/ruvector/coverage-router.js.map +1 -1
- package/dist/src/ruvector/coverage-tools.js +56 -101
- package/dist/src/ruvector/coverage-tools.js.map +1 -1
- package/dist/src/ruvector/diff-classifier.d.ts +175 -0
- package/dist/src/ruvector/diff-classifier.d.ts.map +1 -0
- package/dist/src/ruvector/diff-classifier.js +324 -451
- package/dist/src/ruvector/diff-classifier.js.map +1 -1
- package/dist/src/ruvector/enhanced-model-router.d.ts +146 -0
- package/dist/src/ruvector/enhanced-model-router.d.ts.map +1 -0
- package/dist/src/ruvector/enhanced-model-router.js +260 -336
- package/dist/src/ruvector/enhanced-model-router.js.map +1 -1
- package/dist/src/ruvector/flash-attention.d.ts +195 -0
- package/dist/src/ruvector/flash-attention.d.ts.map +1 -0
- package/dist/src/ruvector/flash-attention.js +223 -254
- package/dist/src/ruvector/flash-attention.js.map +1 -1
- package/dist/src/ruvector/graph-analyzer.d.ts +187 -0
- package/dist/src/ruvector/graph-analyzer.d.ts.map +1 -0
- package/dist/src/ruvector/graph-analyzer.js +486 -680
- package/dist/src/ruvector/graph-analyzer.js.map +1 -1
- package/dist/src/ruvector/index.d.ts +40 -0
- package/dist/src/ruvector/index.d.ts.map +1 -0
- package/dist/src/ruvector/index.js +36 -106
- package/dist/src/ruvector/index.js.map +1 -1
- package/dist/src/ruvector/lora-adapter.d.ts +218 -0
- package/dist/src/ruvector/lora-adapter.d.ts.map +1 -0
- package/dist/src/ruvector/lora-adapter.js +155 -248
- package/dist/src/ruvector/lora-adapter.js.map +1 -1
- package/dist/src/ruvector/model-router.d.ts +220 -0
- package/dist/src/ruvector/model-router.d.ts.map +1 -0
- package/dist/src/ruvector/model-router.js +175 -248
- package/dist/src/ruvector/model-router.js.map +1 -1
- package/dist/src/ruvector/moe-router.d.ts +206 -0
- package/dist/src/ruvector/moe-router.d.ts.map +1 -0
- package/dist/src/ruvector/moe-router.js +228 -286
- package/dist/src/ruvector/moe-router.js.map +1 -1
- package/dist/src/ruvector/q-learning-router.d.ts +211 -0
- package/dist/src/ruvector/q-learning-router.d.ts.map +1 -0
- package/dist/src/ruvector/q-learning-router.js +257 -338
- package/dist/src/ruvector/q-learning-router.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 +270 -434
- package/dist/src/ruvector/ruvllm-wasm.js.map +1 -1
- package/dist/src/ruvector/semantic-router.d.ts +77 -0
- package/dist/src/ruvector/semantic-router.d.ts.map +1 -0
- package/dist/src/ruvector/semantic-router.js +60 -67
- package/dist/src/ruvector/semantic-router.js.map +1 -1
- package/dist/src/ruvector/vector-db.d.ts +69 -0
- package/dist/src/ruvector/vector-db.d.ts.map +1 -0
- package/dist/src/ruvector/vector-db.js +119 -205
- package/dist/src/ruvector/vector-db.js.map +1 -1
- 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 +32 -105
- package/dist/src/services/agentic-flow-bridge.js.map +1 -1
- package/dist/src/services/claim-service.d.ts +204 -0
- package/dist/src/services/claim-service.d.ts.map +1 -0
- package/dist/src/services/claim-service.js +615 -940
- package/dist/src/services/claim-service.js.map +1 -1
- package/dist/src/services/container-worker-pool.d.ts +197 -0
- package/dist/src/services/container-worker-pool.d.ts.map +1 -0
- package/dist/src/services/container-worker-pool.js +398 -666
- package/dist/src/services/container-worker-pool.js.map +1 -1
- package/dist/src/services/headless-worker-executor.d.ts +304 -0
- package/dist/src/services/headless-worker-executor.d.ts.map +1 -0
- package/dist/src/services/headless-worker-executor.js +441 -467
- package/dist/src/services/headless-worker-executor.js.map +1 -1
- package/dist/src/services/index.d.ts +4 -4
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +4 -4
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/registry-api.d.ts +58 -0
- package/dist/src/services/registry-api.d.ts.map +1 -0
- package/dist/src/services/registry-api.js +92 -200
- package/dist/src/services/registry-api.js.map +1 -1
- package/dist/src/services/ruvector-training.d.ts +222 -0
- package/dist/src/services/ruvector-training.d.ts.map +1 -0
- package/dist/src/services/ruvector-training.js +257 -337
- package/dist/src/services/ruvector-training.js.map +1 -1
- package/dist/src/services/worker-daemon.d.ts +228 -0
- package/dist/src/services/worker-daemon.d.ts.map +1 -0
- package/dist/src/services/worker-daemon.js +591 -849
- package/dist/src/services/worker-daemon.js.map +1 -1
- package/dist/src/services/worker-queue.d.ts +194 -0
- package/dist/src/services/worker-queue.d.ts.map +1 -0
- package/dist/src/services/worker-queue.js +331 -548
- package/dist/src/services/worker-queue.js.map +1 -1
- package/dist/src/suggest.d.ts +53 -0
- package/dist/src/suggest.d.ts.map +1 -0
- package/dist/src/suggest.js +45 -55
- package/dist/src/suggest.js.map +1 -1
- package/dist/src/transfer/anonymization/index.js +29 -37
- package/dist/src/transfer/anonymization/index.js.map +1 -1
- package/dist/src/transfer/deploy-seraphine.js +128 -155
- package/dist/src/transfer/deploy-seraphine.js.map +1 -1
- package/dist/src/transfer/export.d.ts +25 -0
- package/dist/src/transfer/export.d.ts.map +1 -0
- package/dist/src/transfer/export.js +84 -142
- package/dist/src/transfer/export.js.map +1 -1
- package/dist/src/transfer/index.d.ts +1 -1
- package/dist/src/transfer/index.d.ts.map +1 -1
- package/dist/src/transfer/index.js +0 -2
- package/dist/src/transfer/index.js.map +1 -1
- package/dist/src/transfer/ipfs/client.d.ts +109 -0
- package/dist/src/transfer/ipfs/client.d.ts.map +1 -0
- package/dist/src/transfer/ipfs/client.js +187 -337
- package/dist/src/transfer/ipfs/client.js.map +1 -1
- package/dist/src/transfer/ipfs/upload.d.ts +95 -0
- package/dist/src/transfer/ipfs/upload.d.ts.map +1 -0
- package/dist/src/transfer/ipfs/upload.js +288 -434
- package/dist/src/transfer/ipfs/upload.js.map +1 -1
- package/dist/src/transfer/models/seraphine.d.ts +72 -0
- package/dist/src/transfer/models/seraphine.d.ts.map +1 -0
- package/dist/src/transfer/models/seraphine.js +55 -55
- package/dist/src/transfer/models/seraphine.js.map +1 -1
- package/dist/src/transfer/serialization/cfp.d.ts +49 -0
- package/dist/src/transfer/serialization/cfp.d.ts.map +1 -0
- package/dist/src/transfer/serialization/cfp.js +30 -31
- package/dist/src/transfer/serialization/cfp.js.map +1 -1
- package/dist/src/transfer/storage/gcs.d.ts +82 -0
- package/dist/src/transfer/storage/gcs.d.ts.map +1 -0
- package/dist/src/transfer/storage/gcs.js +165 -232
- package/dist/src/transfer/storage/gcs.js.map +1 -1
- package/dist/src/transfer/store/discovery.d.ts +84 -0
- package/dist/src/transfer/store/discovery.d.ts.map +1 -0
- package/dist/src/transfer/store/discovery.js +239 -349
- package/dist/src/transfer/store/discovery.js.map +1 -1
- package/dist/src/transfer/store/download.d.ts +70 -0
- package/dist/src/transfer/store/download.d.ts.map +1 -0
- package/dist/src/transfer/store/download.js +243 -365
- package/dist/src/transfer/store/download.js.map +1 -1
- package/dist/src/transfer/store/index.d.ts +84 -0
- package/dist/src/transfer/store/index.d.ts.map +1 -0
- package/dist/src/transfer/store/index.js +63 -130
- package/dist/src/transfer/store/index.js.map +1 -1
- package/dist/src/transfer/store/publish.d.ts +76 -0
- package/dist/src/transfer/store/publish.d.ts.map +1 -0
- package/dist/src/transfer/store/publish.js +184 -258
- package/dist/src/transfer/store/publish.js.map +1 -1
- package/dist/src/transfer/store/registry.js +50 -72
- package/dist/src/transfer/store/registry.js.map +1 -1
- package/dist/src/transfer/store/search.d.ts +54 -0
- package/dist/src/transfer/store/search.d.ts.map +1 -0
- package/dist/src/transfer/store/search.js +64 -96
- package/dist/src/transfer/store/search.js.map +1 -1
- package/dist/src/transfer/store/tests/standalone-test.js +174 -231
- package/dist/src/transfer/store/tests/standalone-test.js.map +1 -1
- package/dist/src/transfer/test-seraphine.js +95 -130
- package/dist/src/transfer/test-seraphine.js.map +1 -1
- package/dist/src/transfer/tests/test-store.js +194 -239
- package/dist/src/transfer/tests/test-store.js.map +1 -1
- package/dist/src/transfer/types.d.ts +245 -0
- package/dist/src/transfer/types.d.ts.map +1 -0
- package/dist/src/types.d.ts +198 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +26 -55
- package/dist/src/types.js.map +1 -1
- package/dist/src/update/checker.d.ts +34 -0
- package/dist/src/update/checker.d.ts.map +1 -0
- package/dist/src/update/checker.js +106 -183
- package/dist/src/update/checker.js.map +1 -1
- package/dist/src/update/executor.d.ts +32 -0
- package/dist/src/update/executor.d.ts.map +1 -0
- package/dist/src/update/executor.js +135 -198
- package/dist/src/update/executor.js.map +1 -1
- package/dist/src/update/index.d.ts +33 -0
- package/dist/src/update/index.d.ts.map +1 -0
- package/dist/src/update/index.js +38 -85
- package/dist/src/update/index.js.map +1 -1
- package/dist/src/update/rate-limiter.d.ts +20 -0
- package/dist/src/update/rate-limiter.d.ts.map +1 -0
- package/dist/src/update/rate-limiter.js +19 -31
- package/dist/src/update/rate-limiter.js.map +1 -1
- package/dist/src/update/validator.d.ts +17 -0
- package/dist/src/update/validator.d.ts.map +1 -0
- package/dist/src/update/validator.js +38 -64
- package/dist/src/update/validator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -13,53 +13,6 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Created with ruv.io
|
|
15
15
|
*/
|
|
16
|
-
var __assign = (this && this.__assign) || function () {
|
|
17
|
-
__assign = Object.assign || function(t) {
|
|
18
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
19
|
-
s = arguments[i];
|
|
20
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
21
|
-
t[p] = s[p];
|
|
22
|
-
}
|
|
23
|
-
return t;
|
|
24
|
-
};
|
|
25
|
-
return __assign.apply(this, arguments);
|
|
26
|
-
};
|
|
27
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
28
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
29
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
30
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
31
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
32
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
33
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
34
|
-
});
|
|
35
|
-
};
|
|
36
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
37
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
38
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
39
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
40
|
-
function step(op) {
|
|
41
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
42
|
-
while (_) try {
|
|
43
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
44
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
45
|
-
switch (op[0]) {
|
|
46
|
-
case 0: case 1: t = op; break;
|
|
47
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
48
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
49
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
50
|
-
default:
|
|
51
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
52
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
53
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
54
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
55
|
-
if (t[2]) _.ops.pop();
|
|
56
|
-
_.trys.pop(); continue;
|
|
57
|
-
}
|
|
58
|
-
op = body.call(thisArg, _);
|
|
59
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
60
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
16
|
import { output } from '../output.js';
|
|
64
17
|
import { callMCPTool, MCPClientError } from '../mcp-client.js';
|
|
65
18
|
import * as path from 'path';
|
|
@@ -67,43 +20,25 @@ import * as fs from 'fs/promises';
|
|
|
67
20
|
import { writeFile } from 'fs/promises';
|
|
68
21
|
import { resolve } from 'path';
|
|
69
22
|
// Dynamic import for AST analyzer
|
|
70
|
-
function getASTAnalyzer() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return [4 /*yield*/, import('../ruvector/ast-analyzer.js')];
|
|
78
|
-
case 1: return [2 /*return*/, _b.sent()];
|
|
79
|
-
case 2:
|
|
80
|
-
_a = _b.sent();
|
|
81
|
-
return [2 /*return*/, null];
|
|
82
|
-
case 3: return [2 /*return*/];
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
});
|
|
23
|
+
async function getASTAnalyzer() {
|
|
24
|
+
try {
|
|
25
|
+
return await import('../ruvector/ast-analyzer.js');
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
86
30
|
}
|
|
87
31
|
// Dynamic import for graph analyzer
|
|
88
|
-
function getGraphAnalyzer() {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return [4 /*yield*/, import('../ruvector/graph-analyzer.js')];
|
|
96
|
-
case 1: return [2 /*return*/, _b.sent()];
|
|
97
|
-
case 2:
|
|
98
|
-
_a = _b.sent();
|
|
99
|
-
return [2 /*return*/, null];
|
|
100
|
-
case 3: return [2 /*return*/];
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
});
|
|
32
|
+
async function getGraphAnalyzer() {
|
|
33
|
+
try {
|
|
34
|
+
return await import('../ruvector/graph-analyzer.js');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
104
39
|
}
|
|
105
40
|
// Diff subcommand
|
|
106
|
-
|
|
41
|
+
const diffCommand = {
|
|
107
42
|
name: 'diff',
|
|
108
43
|
description: 'Analyze git diff for change risk assessment and classification',
|
|
109
44
|
options: [
|
|
@@ -112,35 +47,35 @@ var diffCommand = {
|
|
|
112
47
|
short: 'r',
|
|
113
48
|
description: 'Show risk assessment',
|
|
114
49
|
type: 'boolean',
|
|
115
|
-
|
|
50
|
+
default: false,
|
|
116
51
|
},
|
|
117
52
|
{
|
|
118
53
|
name: 'classify',
|
|
119
54
|
short: 'c',
|
|
120
55
|
description: 'Classify change type',
|
|
121
56
|
type: 'boolean',
|
|
122
|
-
|
|
57
|
+
default: false,
|
|
123
58
|
},
|
|
124
59
|
{
|
|
125
60
|
name: 'reviewers',
|
|
126
61
|
description: 'Show recommended reviewers',
|
|
127
62
|
type: 'boolean',
|
|
128
|
-
|
|
63
|
+
default: false,
|
|
129
64
|
},
|
|
130
65
|
{
|
|
131
66
|
name: 'format',
|
|
132
67
|
short: 'f',
|
|
133
68
|
description: 'Output format: text, json, table',
|
|
134
69
|
type: 'string',
|
|
135
|
-
|
|
136
|
-
choices: ['text', 'json', 'table']
|
|
70
|
+
default: 'text',
|
|
71
|
+
choices: ['text', 'json', 'table'],
|
|
137
72
|
},
|
|
138
73
|
{
|
|
139
74
|
name: 'verbose',
|
|
140
75
|
short: 'v',
|
|
141
76
|
description: 'Show detailed file-level analysis',
|
|
142
77
|
type: 'boolean',
|
|
143
|
-
|
|
78
|
+
default: false,
|
|
144
79
|
},
|
|
145
80
|
],
|
|
146
81
|
examples: [
|
|
@@ -149,201 +84,191 @@ var diffCommand = {
|
|
|
149
84
|
{ command: 'claude-flow analyze diff main..feature --format json', description: 'Compare branches with JSON output' },
|
|
150
85
|
{ command: 'claude-flow analyze diff --reviewers', description: 'Get recommended reviewers for changes' },
|
|
151
86
|
],
|
|
152
|
-
action:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
87
|
+
action: async (ctx) => {
|
|
88
|
+
const ref = ctx.args[0] || 'HEAD';
|
|
89
|
+
const showRisk = ctx.flags.risk;
|
|
90
|
+
const showClassify = ctx.flags.classify;
|
|
91
|
+
const showReviewers = ctx.flags.reviewers;
|
|
92
|
+
const formatType = ctx.flags.format || 'text';
|
|
93
|
+
const verbose = ctx.flags.verbose;
|
|
94
|
+
// If no specific flag, show all
|
|
95
|
+
const showAll = !showRisk && !showClassify && !showReviewers;
|
|
96
|
+
output.printInfo(`Analyzing diff: ${output.highlight(ref)}`);
|
|
97
|
+
try {
|
|
98
|
+
// Call MCP tool for diff analysis
|
|
99
|
+
const result = await callMCPTool('analyze_diff', {
|
|
100
|
+
ref,
|
|
101
|
+
includeFileRisks: verbose,
|
|
102
|
+
includeReviewers: showReviewers || showAll,
|
|
103
|
+
});
|
|
104
|
+
// JSON output
|
|
105
|
+
if (formatType === 'json') {
|
|
106
|
+
output.printJson(result);
|
|
107
|
+
return { success: true, data: result };
|
|
108
|
+
}
|
|
109
|
+
output.writeln();
|
|
110
|
+
// Summary box
|
|
111
|
+
const files = result.files || [];
|
|
112
|
+
const risk = result.risk || { overall: 'unknown', score: 0, breakdown: { fileCount: 0, totalChanges: 0, highRiskFiles: [], securityConcerns: [], breakingChanges: [], testCoverage: 'unknown' } };
|
|
113
|
+
const classification = result.classification || { category: 'unknown', confidence: 0, reasoning: '' };
|
|
114
|
+
output.printBox([
|
|
115
|
+
`Ref: ${result.ref || 'HEAD'}`,
|
|
116
|
+
`Files: ${files.length}`,
|
|
117
|
+
`Risk: ${getRiskDisplay(risk.overall)} (${risk.score}/100)`,
|
|
118
|
+
`Type: ${classification.category}${classification.subcategory ? ` (${classification.subcategory})` : ''}`,
|
|
119
|
+
``,
|
|
120
|
+
result.summary || 'No summary available',
|
|
121
|
+
].join('\n'), 'Diff Analysis');
|
|
122
|
+
// Risk assessment
|
|
123
|
+
if (showRisk || showAll) {
|
|
124
|
+
output.writeln();
|
|
125
|
+
output.writeln(output.bold('Risk Assessment'));
|
|
126
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
127
|
+
output.printTable({
|
|
128
|
+
columns: [
|
|
129
|
+
{ key: 'metric', header: 'Metric', width: 25 },
|
|
130
|
+
{ key: 'value', header: 'Value', width: 30 },
|
|
131
|
+
],
|
|
132
|
+
data: [
|
|
133
|
+
{ metric: 'Overall Risk', value: getRiskDisplay(risk.overall) },
|
|
134
|
+
{ metric: 'Risk Score', value: `${risk.score}/100` },
|
|
135
|
+
{ metric: 'Files Changed', value: risk.breakdown.fileCount },
|
|
136
|
+
{ metric: 'Total Lines Changed', value: risk.breakdown.totalChanges },
|
|
137
|
+
{ metric: 'Test Coverage', value: risk.breakdown.testCoverage },
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
// Security concerns
|
|
141
|
+
if (risk.breakdown.securityConcerns.length > 0) {
|
|
180
142
|
output.writeln();
|
|
181
|
-
|
|
182
|
-
risk
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
output.writeln(output.bold('File-Level Analysis'));
|
|
265
|
-
output.writeln(output.dim('-'.repeat(50)));
|
|
266
|
-
output.printTable({
|
|
267
|
-
columns: [
|
|
268
|
-
{ key: 'path', header: 'File', width: 40 },
|
|
269
|
-
{ key: 'risk', header: 'Risk', width: 12, format: function (v) { return getRiskDisplay(String(v)); } },
|
|
270
|
-
{ key: 'score', header: 'Score', width: 8, align: 'right' },
|
|
271
|
-
{ key: 'reasons', header: 'Reasons', width: 30, format: function (v) {
|
|
272
|
-
var reasons = v;
|
|
273
|
-
return reasons.slice(0, 2).join('; ');
|
|
274
|
-
} },
|
|
275
|
-
],
|
|
276
|
-
data: result.fileRisks
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
// Files changed table
|
|
280
|
-
if (formatType === 'table' || showAll) {
|
|
281
|
-
output.writeln();
|
|
282
|
-
output.writeln(output.bold('Files Changed'));
|
|
283
|
-
output.writeln(output.dim('-'.repeat(50)));
|
|
284
|
-
output.printTable({
|
|
285
|
-
columns: [
|
|
286
|
-
{ key: 'status', header: 'Status', width: 10, format: function (v) { return getStatusDisplay(String(v)); } },
|
|
287
|
-
{ key: 'path', header: 'File', width: 45 },
|
|
288
|
-
{ key: 'additions', header: '+', width: 8, align: 'right', format: function (v) { return output.success("+" + v); } },
|
|
289
|
-
{ key: 'deletions', header: '-', width: 8, align: 'right', format: function (v) { return output.error("-" + v); } },
|
|
290
|
-
],
|
|
291
|
-
data: files.slice(0, 20)
|
|
292
|
-
});
|
|
293
|
-
if (files.length > 20) {
|
|
294
|
-
output.writeln(output.dim(" ... and " + (files.length - 20) + " more files"));
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return [2 /*return*/, { success: true, data: result }];
|
|
298
|
-
case 3:
|
|
299
|
-
error_1 = _a.sent();
|
|
300
|
-
if (error_1 instanceof MCPClientError) {
|
|
301
|
-
output.printError("Diff analysis failed: " + error_1.message);
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
304
|
-
output.printError("Unexpected error: " + String(error_1));
|
|
305
|
-
}
|
|
306
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
307
|
-
case 4: return [2 /*return*/];
|
|
143
|
+
output.writeln(output.bold(output.warning('Security Concerns')));
|
|
144
|
+
output.printList(risk.breakdown.securityConcerns.map(c => output.warning(c)));
|
|
145
|
+
}
|
|
146
|
+
// Breaking changes
|
|
147
|
+
if (risk.breakdown.breakingChanges.length > 0) {
|
|
148
|
+
output.writeln();
|
|
149
|
+
output.writeln(output.bold(output.error('Potential Breaking Changes')));
|
|
150
|
+
output.printList(risk.breakdown.breakingChanges.map(c => output.error(c)));
|
|
151
|
+
}
|
|
152
|
+
// High risk files
|
|
153
|
+
if (risk.breakdown.highRiskFiles.length > 0) {
|
|
154
|
+
output.writeln();
|
|
155
|
+
output.writeln(output.bold('High Risk Files'));
|
|
156
|
+
output.printList(risk.breakdown.highRiskFiles.map(f => output.warning(f)));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Classification
|
|
160
|
+
if (showClassify || showAll) {
|
|
161
|
+
output.writeln();
|
|
162
|
+
output.writeln(output.bold('Classification'));
|
|
163
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
164
|
+
output.printTable({
|
|
165
|
+
columns: [
|
|
166
|
+
{ key: 'field', header: 'Field', width: 15 },
|
|
167
|
+
{ key: 'value', header: 'Value', width: 40 },
|
|
168
|
+
],
|
|
169
|
+
data: [
|
|
170
|
+
{ field: 'Category', value: classification.category },
|
|
171
|
+
{ field: 'Subcategory', value: classification.subcategory || '-' },
|
|
172
|
+
{ field: 'Confidence', value: `${(classification.confidence * 100).toFixed(0)}%` },
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
output.writeln();
|
|
176
|
+
output.writeln(output.dim(`Reasoning: ${classification.reasoning}`));
|
|
177
|
+
}
|
|
178
|
+
// Reviewers
|
|
179
|
+
if (showReviewers || showAll) {
|
|
180
|
+
output.writeln();
|
|
181
|
+
output.writeln(output.bold('Recommended Reviewers'));
|
|
182
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
183
|
+
const reviewers = result.recommendedReviewers || [];
|
|
184
|
+
if (reviewers.length > 0) {
|
|
185
|
+
output.printNumberedList(reviewers.map(r => output.highlight(r)));
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
output.writeln(output.dim('No specific reviewers recommended'));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Verbose file-level details
|
|
192
|
+
if (verbose && result.fileRisks) {
|
|
193
|
+
output.writeln();
|
|
194
|
+
output.writeln(output.bold('File-Level Analysis'));
|
|
195
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
196
|
+
output.printTable({
|
|
197
|
+
columns: [
|
|
198
|
+
{ key: 'path', header: 'File', width: 40 },
|
|
199
|
+
{ key: 'risk', header: 'Risk', width: 12, format: (v) => getRiskDisplay(String(v)) },
|
|
200
|
+
{ key: 'score', header: 'Score', width: 8, align: 'right' },
|
|
201
|
+
{ key: 'reasons', header: 'Reasons', width: 30, format: (v) => {
|
|
202
|
+
const reasons = v;
|
|
203
|
+
return reasons.slice(0, 2).join('; ');
|
|
204
|
+
} },
|
|
205
|
+
],
|
|
206
|
+
data: result.fileRisks,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Files changed table
|
|
210
|
+
if (formatType === 'table' || showAll) {
|
|
211
|
+
output.writeln();
|
|
212
|
+
output.writeln(output.bold('Files Changed'));
|
|
213
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
214
|
+
output.printTable({
|
|
215
|
+
columns: [
|
|
216
|
+
{ key: 'status', header: 'Status', width: 10, format: (v) => getStatusDisplay(String(v)) },
|
|
217
|
+
{ key: 'path', header: 'File', width: 45 },
|
|
218
|
+
{ key: 'additions', header: '+', width: 8, align: 'right', format: (v) => output.success(`+${v}`) },
|
|
219
|
+
{ key: 'deletions', header: '-', width: 8, align: 'right', format: (v) => output.error(`-${v}`) },
|
|
220
|
+
],
|
|
221
|
+
data: files.slice(0, 20),
|
|
222
|
+
});
|
|
223
|
+
if (files.length > 20) {
|
|
224
|
+
output.writeln(output.dim(` ... and ${files.length - 20} more files`));
|
|
225
|
+
}
|
|
308
226
|
}
|
|
309
|
-
|
|
310
|
-
|
|
227
|
+
return { success: true, data: result };
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
if (error instanceof MCPClientError) {
|
|
231
|
+
output.printError(`Diff analysis failed: ${error.message}`);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
output.printError(`Unexpected error: ${String(error)}`);
|
|
235
|
+
}
|
|
236
|
+
return { success: false, exitCode: 1 };
|
|
237
|
+
}
|
|
238
|
+
},
|
|
311
239
|
};
|
|
312
240
|
// Code subcommand (placeholder for future code analysis)
|
|
313
|
-
|
|
241
|
+
const codeCommand = {
|
|
314
242
|
name: 'code',
|
|
315
243
|
description: 'Static code analysis and quality assessment',
|
|
316
244
|
options: [
|
|
317
|
-
{ name: 'path', short: 'p', type: 'string', description: 'Path to analyze',
|
|
318
|
-
{ name: 'type', short: 't', type: 'string', description: 'Analysis type: quality, complexity, security',
|
|
319
|
-
{ name: 'format', short: 'f', type: 'string', description: 'Output format: text, json',
|
|
245
|
+
{ name: 'path', short: 'p', type: 'string', description: 'Path to analyze', default: '.' },
|
|
246
|
+
{ name: 'type', short: 't', type: 'string', description: 'Analysis type: quality, complexity, security', default: 'quality' },
|
|
247
|
+
{ name: 'format', short: 'f', type: 'string', description: 'Output format: text, json', default: 'text' },
|
|
320
248
|
],
|
|
321
249
|
examples: [
|
|
322
250
|
{ command: 'claude-flow analyze code -p ./src', description: 'Analyze source directory' },
|
|
323
251
|
{ command: 'claude-flow analyze code --type complexity', description: 'Run complexity analysis' },
|
|
324
252
|
],
|
|
325
|
-
action:
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return [2 /*return*/, { success: true }];
|
|
345
|
-
});
|
|
346
|
-
}); }
|
|
253
|
+
action: async (ctx) => {
|
|
254
|
+
const path = ctx.flags.path || '.';
|
|
255
|
+
const analysisType = ctx.flags.type || 'quality';
|
|
256
|
+
output.writeln();
|
|
257
|
+
output.writeln(output.bold('Code Analysis'));
|
|
258
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
259
|
+
output.printInfo(`Analyzing ${path} for ${analysisType}...`);
|
|
260
|
+
output.writeln();
|
|
261
|
+
// Placeholder - would integrate with actual code analysis tools
|
|
262
|
+
output.printBox([
|
|
263
|
+
`Path: ${path}`,
|
|
264
|
+
`Type: ${analysisType}`,
|
|
265
|
+
`Status: Feature in development`,
|
|
266
|
+
``,
|
|
267
|
+
`Code analysis capabilities coming soon.`,
|
|
268
|
+
`Use 'analyze diff' for change analysis.`,
|
|
269
|
+
].join('\n'), 'Code Analysis');
|
|
270
|
+
return { success: true };
|
|
271
|
+
},
|
|
347
272
|
};
|
|
348
273
|
// ============================================================================
|
|
349
274
|
// AST Analysis Subcommands (using ruvector tree-sitter with fallback)
|
|
@@ -351,8 +276,7 @@ var codeCommand = {
|
|
|
351
276
|
/**
|
|
352
277
|
* Helper: Truncate file path for display
|
|
353
278
|
*/
|
|
354
|
-
function truncatePathAst(filePath, maxLen) {
|
|
355
|
-
if (maxLen === void 0) { maxLen = 45; }
|
|
279
|
+
function truncatePathAst(filePath, maxLen = 45) {
|
|
356
280
|
if (filePath.length <= maxLen)
|
|
357
281
|
return filePath;
|
|
358
282
|
return '...' + filePath.slice(-(maxLen - 3));
|
|
@@ -395,7 +319,7 @@ function getComplexityRatingAst(value) {
|
|
|
395
319
|
/**
|
|
396
320
|
* AST analysis subcommand
|
|
397
321
|
*/
|
|
398
|
-
|
|
322
|
+
const astCommand = {
|
|
399
323
|
name: 'ast',
|
|
400
324
|
description: 'Analyze code using AST parsing (tree-sitter via ruvector)',
|
|
401
325
|
options: [
|
|
@@ -404,35 +328,35 @@ var astCommand = {
|
|
|
404
328
|
short: 'c',
|
|
405
329
|
description: 'Include complexity metrics',
|
|
406
330
|
type: 'boolean',
|
|
407
|
-
|
|
331
|
+
default: false,
|
|
408
332
|
},
|
|
409
333
|
{
|
|
410
334
|
name: 'symbols',
|
|
411
335
|
short: 's',
|
|
412
336
|
description: 'Include symbol extraction',
|
|
413
337
|
type: 'boolean',
|
|
414
|
-
|
|
338
|
+
default: false,
|
|
415
339
|
},
|
|
416
340
|
{
|
|
417
341
|
name: 'format',
|
|
418
342
|
short: 'f',
|
|
419
343
|
description: 'Output format (text, json, table)',
|
|
420
344
|
type: 'string',
|
|
421
|
-
|
|
422
|
-
choices: ['text', 'json', 'table']
|
|
345
|
+
default: 'text',
|
|
346
|
+
choices: ['text', 'json', 'table'],
|
|
423
347
|
},
|
|
424
348
|
{
|
|
425
349
|
name: 'output',
|
|
426
350
|
short: 'o',
|
|
427
351
|
description: 'Output file path',
|
|
428
|
-
type: 'string'
|
|
352
|
+
type: 'string',
|
|
429
353
|
},
|
|
430
354
|
{
|
|
431
355
|
name: 'verbose',
|
|
432
356
|
short: 'v',
|
|
433
357
|
description: 'Show detailed analysis',
|
|
434
358
|
type: 'boolean',
|
|
435
|
-
|
|
359
|
+
default: false,
|
|
436
360
|
},
|
|
437
361
|
],
|
|
438
362
|
examples: [
|
|
@@ -441,223 +365,193 @@ var astCommand = {
|
|
|
441
365
|
{ command: 'claude-flow analyze ast . --format json', description: 'JSON output' },
|
|
442
366
|
{ command: 'claude-flow analyze ast src/ --symbols', description: 'Extract symbols' },
|
|
443
367
|
],
|
|
444
|
-
action:
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (!(_i < _a.length)) return [3 /*break*/, 10];
|
|
487
|
-
file = _a[_i];
|
|
488
|
-
_o.label = 6;
|
|
489
|
-
case 6:
|
|
490
|
-
_o.trys.push([6, 8, , 9]);
|
|
491
|
-
return [4 /*yield*/, fs.readFile(file, 'utf-8')];
|
|
492
|
-
case 7:
|
|
493
|
-
content = _o.sent();
|
|
494
|
-
if (astModule) {
|
|
495
|
-
analyzer = astModule.createASTAnalyzer();
|
|
496
|
-
analysis = analyzer.analyze(content, file);
|
|
497
|
-
results.push(analysis);
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
// Fallback analysis
|
|
501
|
-
results.push(fallbackAnalyze(content, file));
|
|
502
|
-
}
|
|
503
|
-
return [3 /*break*/, 9];
|
|
504
|
-
case 8:
|
|
505
|
-
_b = _o.sent();
|
|
506
|
-
return [3 /*break*/, 9];
|
|
507
|
-
case 9:
|
|
508
|
-
_i++;
|
|
509
|
-
return [3 /*break*/, 5];
|
|
510
|
-
case 10: return [3 /*break*/, 13];
|
|
511
|
-
case 11: return [4 /*yield*/, fs.readFile(resolvedPath, 'utf-8')];
|
|
512
|
-
case 12:
|
|
513
|
-
content = _o.sent();
|
|
514
|
-
if (astModule) {
|
|
515
|
-
analyzer = astModule.createASTAnalyzer();
|
|
516
|
-
analysis = analyzer.analyze(content, resolvedPath);
|
|
517
|
-
results.push(analysis);
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
results.push(fallbackAnalyze(content, resolvedPath));
|
|
368
|
+
action: async (ctx) => {
|
|
369
|
+
const targetPath = ctx.args[0] || ctx.cwd;
|
|
370
|
+
const showComplexity = ctx.flags.complexity;
|
|
371
|
+
const showSymbols = ctx.flags.symbols;
|
|
372
|
+
const formatType = ctx.flags.format || 'text';
|
|
373
|
+
const outputFile = ctx.flags.output;
|
|
374
|
+
const verbose = ctx.flags.verbose;
|
|
375
|
+
// If no specific flags, show summary
|
|
376
|
+
const showAll = !showComplexity && !showSymbols;
|
|
377
|
+
output.printInfo(`Analyzing: ${output.highlight(targetPath)}`);
|
|
378
|
+
output.writeln();
|
|
379
|
+
const spinner = output.createSpinner({ text: 'Parsing AST...', spinner: 'dots' });
|
|
380
|
+
spinner.start();
|
|
381
|
+
try {
|
|
382
|
+
const astModule = await getASTAnalyzer();
|
|
383
|
+
if (!astModule) {
|
|
384
|
+
spinner.stop();
|
|
385
|
+
output.printWarning('AST analyzer not available, using regex fallback');
|
|
386
|
+
}
|
|
387
|
+
// Resolve path and check if file or directory
|
|
388
|
+
const resolvedPath = resolve(targetPath);
|
|
389
|
+
const stat = await fs.stat(resolvedPath);
|
|
390
|
+
const isDirectory = stat.isDirectory();
|
|
391
|
+
let results = [];
|
|
392
|
+
if (isDirectory) {
|
|
393
|
+
// Scan directory for source files
|
|
394
|
+
const files = await scanSourceFiles(resolvedPath);
|
|
395
|
+
spinner.stop();
|
|
396
|
+
output.printInfo(`Found ${files.length} source files`);
|
|
397
|
+
spinner.start();
|
|
398
|
+
for (const file of files.slice(0, 100)) {
|
|
399
|
+
try {
|
|
400
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
401
|
+
if (astModule) {
|
|
402
|
+
const analyzer = astModule.createASTAnalyzer();
|
|
403
|
+
const analysis = analyzer.analyze(content, file);
|
|
404
|
+
results.push(analysis);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// Fallback analysis
|
|
408
|
+
results.push(fallbackAnalyze(content, file));
|
|
409
|
+
}
|
|
521
410
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
spinner.stop();
|
|
525
|
-
if (results.length === 0) {
|
|
526
|
-
output.printWarning('No files analyzed');
|
|
527
|
-
return [2 /*return*/, { success: true }];
|
|
411
|
+
catch {
|
|
412
|
+
// Skip files that can't be analyzed
|
|
528
413
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
// Single file
|
|
418
|
+
const content = await fs.readFile(resolvedPath, 'utf-8');
|
|
419
|
+
if (astModule) {
|
|
420
|
+
const analyzer = astModule.createASTAnalyzer();
|
|
421
|
+
const analysis = analyzer.analyze(content, resolvedPath);
|
|
422
|
+
results.push(analysis);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
results.push(fallbackAnalyze(content, resolvedPath));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
spinner.stop();
|
|
429
|
+
if (results.length === 0) {
|
|
430
|
+
output.printWarning('No files analyzed');
|
|
431
|
+
return { success: true };
|
|
432
|
+
}
|
|
433
|
+
// Calculate totals
|
|
434
|
+
const totals = {
|
|
435
|
+
files: results.length,
|
|
436
|
+
functions: results.reduce((sum, r) => sum + r.functions.length, 0),
|
|
437
|
+
classes: results.reduce((sum, r) => sum + r.classes.length, 0),
|
|
438
|
+
imports: results.reduce((sum, r) => sum + r.imports.length, 0),
|
|
439
|
+
avgComplexity: results.reduce((sum, r) => sum + r.complexity.cyclomatic, 0) / results.length,
|
|
440
|
+
totalLoc: results.reduce((sum, r) => sum + r.complexity.loc, 0),
|
|
441
|
+
};
|
|
442
|
+
// JSON output
|
|
443
|
+
if (formatType === 'json') {
|
|
444
|
+
const jsonOutput = { files: results, totals };
|
|
445
|
+
if (outputFile) {
|
|
446
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
447
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
546
450
|
output.printJson(jsonOutput);
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
451
|
+
}
|
|
452
|
+
return { success: true, data: jsonOutput };
|
|
453
|
+
}
|
|
454
|
+
// Summary box
|
|
455
|
+
output.printBox([
|
|
456
|
+
`Files analyzed: ${totals.files}`,
|
|
457
|
+
`Functions: ${totals.functions}`,
|
|
458
|
+
`Classes: ${totals.classes}`,
|
|
459
|
+
`Total LOC: ${totals.totalLoc}`,
|
|
460
|
+
`Avg Complexity: ${formatComplexityValueAst(Math.round(totals.avgComplexity))}`,
|
|
461
|
+
].join('\n'), 'AST Analysis Summary');
|
|
462
|
+
// Complexity view
|
|
463
|
+
if (showComplexity || showAll) {
|
|
464
|
+
output.writeln();
|
|
465
|
+
output.writeln(output.bold('Complexity by File'));
|
|
466
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
467
|
+
const complexityData = results
|
|
468
|
+
.map(r => ({
|
|
469
|
+
file: truncatePathAst(r.filePath),
|
|
470
|
+
cyclomatic: r.complexity.cyclomatic,
|
|
471
|
+
cognitive: r.complexity.cognitive,
|
|
472
|
+
loc: r.complexity.loc,
|
|
473
|
+
rating: getComplexityRatingAst(r.complexity.cyclomatic),
|
|
474
|
+
}))
|
|
475
|
+
.sort((a, b) => b.cyclomatic - a.cyclomatic)
|
|
476
|
+
.slice(0, 15);
|
|
477
|
+
output.printTable({
|
|
478
|
+
columns: [
|
|
479
|
+
{ key: 'file', header: 'File', width: 40 },
|
|
480
|
+
{ key: 'cyclomatic', header: 'Cyclo', width: 8, align: 'right', format: (v) => formatComplexityValueAst(v) },
|
|
481
|
+
{ key: 'cognitive', header: 'Cogni', width: 8, align: 'right' },
|
|
482
|
+
{ key: 'loc', header: 'LOC', width: 8, align: 'right' },
|
|
483
|
+
{ key: 'rating', header: 'Rating', width: 15 },
|
|
484
|
+
],
|
|
485
|
+
data: complexityData,
|
|
486
|
+
});
|
|
487
|
+
if (results.length > 15) {
|
|
488
|
+
output.writeln(output.dim(` ... and ${results.length - 15} more files`));
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
// Symbols view
|
|
492
|
+
if (showSymbols || showAll) {
|
|
493
|
+
output.writeln();
|
|
494
|
+
output.writeln(output.bold('Extracted Symbols'));
|
|
495
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
496
|
+
const allSymbols = [];
|
|
497
|
+
for (const r of results) {
|
|
498
|
+
for (const fn of r.functions) {
|
|
499
|
+
allSymbols.push({ name: fn.name, type: 'function', file: truncatePathAst(r.filePath, 30), line: fn.startLine });
|
|
586
500
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
output.writeln();
|
|
590
|
-
output.writeln(output.bold('Extracted Symbols'));
|
|
591
|
-
output.writeln(output.dim('-'.repeat(60)));
|
|
592
|
-
allSymbols = [];
|
|
593
|
-
for (_c = 0, results_1 = results; _c < results_1.length; _c++) {
|
|
594
|
-
r = results_1[_c];
|
|
595
|
-
for (_d = 0, _e = r.functions; _d < _e.length; _d++) {
|
|
596
|
-
fn = _e[_d];
|
|
597
|
-
allSymbols.push({ name: fn.name, type: 'function', file: truncatePathAst(r.filePath, 30), line: fn.startLine });
|
|
598
|
-
}
|
|
599
|
-
for (_f = 0, _g = r.classes; _f < _g.length; _f++) {
|
|
600
|
-
cls = _g[_f];
|
|
601
|
-
allSymbols.push({ name: cls.name, type: 'class', file: truncatePathAst(r.filePath, 30), line: cls.startLine });
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
displaySymbols = allSymbols.slice(0, 20);
|
|
605
|
-
output.printTable({
|
|
606
|
-
columns: [
|
|
607
|
-
{ key: 'type', header: 'Type', width: 8, format: function (v) { return getTypeMarkerAst(v); } },
|
|
608
|
-
{ key: 'name', header: 'Symbol', width: 30 },
|
|
609
|
-
{ key: 'file', header: 'File', width: 35 },
|
|
610
|
-
{ key: 'line', header: 'Line', width: 8, align: 'right' },
|
|
611
|
-
],
|
|
612
|
-
data: displaySymbols
|
|
613
|
-
});
|
|
614
|
-
if (allSymbols.length > 20) {
|
|
615
|
-
output.writeln(output.dim(" ... and " + (allSymbols.length - 20) + " more symbols"));
|
|
616
|
-
}
|
|
501
|
+
for (const cls of r.classes) {
|
|
502
|
+
allSymbols.push({ name: cls.name, type: 'class', file: truncatePathAst(r.filePath, 30), line: cls.startLine });
|
|
617
503
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
504
|
+
}
|
|
505
|
+
const displaySymbols = allSymbols.slice(0, 20);
|
|
506
|
+
output.printTable({
|
|
507
|
+
columns: [
|
|
508
|
+
{ key: 'type', header: 'Type', width: 8, format: (v) => getTypeMarkerAst(v) },
|
|
509
|
+
{ key: 'name', header: 'Symbol', width: 30 },
|
|
510
|
+
{ key: 'file', header: 'File', width: 35 },
|
|
511
|
+
{ key: 'line', header: 'Line', width: 8, align: 'right' },
|
|
512
|
+
],
|
|
513
|
+
data: displaySymbols,
|
|
514
|
+
});
|
|
515
|
+
if (allSymbols.length > 20) {
|
|
516
|
+
output.writeln(output.dim(` ... and ${allSymbols.length - 20} more symbols`));
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
// Verbose output
|
|
520
|
+
if (verbose) {
|
|
521
|
+
output.writeln();
|
|
522
|
+
output.writeln(output.bold('Import Analysis'));
|
|
523
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
524
|
+
const importCounts = new Map();
|
|
525
|
+
for (const r of results) {
|
|
526
|
+
for (const imp of r.imports) {
|
|
527
|
+
importCounts.set(imp, (importCounts.get(imp) || 0) + 1);
|
|
638
528
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
output.printError("AST analysis failed: " + message);
|
|
651
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
652
|
-
case 21: return [2 /*return*/];
|
|
529
|
+
}
|
|
530
|
+
const topImports = Array.from(importCounts.entries())
|
|
531
|
+
.sort((a, b) => b[1] - a[1])
|
|
532
|
+
.slice(0, 10);
|
|
533
|
+
for (const [imp, count] of topImports) {
|
|
534
|
+
output.writeln(` ${output.highlight(count.toString().padStart(3))} ${imp}`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (outputFile) {
|
|
538
|
+
await writeFile(outputFile, JSON.stringify({ files: results, totals }, null, 2));
|
|
539
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
653
540
|
}
|
|
654
|
-
|
|
655
|
-
|
|
541
|
+
return { success: true, data: { files: results, totals } };
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
spinner.stop();
|
|
545
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
546
|
+
output.printError(`AST analysis failed: ${message}`);
|
|
547
|
+
return { success: false, exitCode: 1 };
|
|
548
|
+
}
|
|
549
|
+
},
|
|
656
550
|
};
|
|
657
551
|
/**
|
|
658
552
|
* Complexity analysis subcommand
|
|
659
553
|
*/
|
|
660
|
-
|
|
554
|
+
const complexityAstCommand = {
|
|
661
555
|
name: 'complexity',
|
|
662
556
|
aliases: ['cx'],
|
|
663
557
|
description: 'Analyze code complexity metrics',
|
|
@@ -667,82 +561,55 @@ var complexityAstCommand = {
|
|
|
667
561
|
short: 't',
|
|
668
562
|
description: 'Complexity threshold to flag (default: 10)',
|
|
669
563
|
type: 'number',
|
|
670
|
-
|
|
564
|
+
default: 10,
|
|
671
565
|
},
|
|
672
566
|
{
|
|
673
567
|
name: 'format',
|
|
674
568
|
short: 'f',
|
|
675
569
|
description: 'Output format (text, json)',
|
|
676
570
|
type: 'string',
|
|
677
|
-
|
|
678
|
-
choices: ['text', 'json']
|
|
571
|
+
default: 'text',
|
|
572
|
+
choices: ['text', 'json'],
|
|
679
573
|
},
|
|
680
574
|
{
|
|
681
575
|
name: 'output',
|
|
682
576
|
short: 'o',
|
|
683
577
|
description: 'Output file path',
|
|
684
|
-
type: 'string'
|
|
578
|
+
type: 'string',
|
|
685
579
|
},
|
|
686
580
|
],
|
|
687
581
|
examples: [
|
|
688
582
|
{ command: 'claude-flow analyze complexity src/', description: 'Analyze complexity' },
|
|
689
583
|
{ command: 'claude-flow analyze complexity src/ --threshold 15', description: 'Flag high complexity' },
|
|
690
584
|
],
|
|
691
|
-
action:
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
resolvedPath = resolve(targetPath);
|
|
711
|
-
return [4 /*yield*/, fs.stat(resolvedPath)];
|
|
712
|
-
case 3:
|
|
713
|
-
stat = _d.sent();
|
|
714
|
-
if (!stat.isDirectory()) return [3 /*break*/, 5];
|
|
715
|
-
return [4 /*yield*/, scanSourceFiles(resolvedPath)];
|
|
716
|
-
case 4:
|
|
717
|
-
_a = _d.sent();
|
|
718
|
-
return [3 /*break*/, 6];
|
|
719
|
-
case 5:
|
|
720
|
-
_a = [resolvedPath];
|
|
721
|
-
_d.label = 6;
|
|
722
|
-
case 6:
|
|
723
|
-
files = _a;
|
|
724
|
-
results = [];
|
|
725
|
-
_i = 0, _b = files.slice(0, 100);
|
|
726
|
-
_d.label = 7;
|
|
727
|
-
case 7:
|
|
728
|
-
if (!(_i < _b.length)) return [3 /*break*/, 12];
|
|
729
|
-
file = _b[_i];
|
|
730
|
-
_d.label = 8;
|
|
731
|
-
case 8:
|
|
732
|
-
_d.trys.push([8, 10, , 11]);
|
|
733
|
-
return [4 /*yield*/, fs.readFile(file, 'utf-8')];
|
|
734
|
-
case 9:
|
|
735
|
-
content = _d.sent();
|
|
736
|
-
analysis = void 0;
|
|
585
|
+
action: async (ctx) => {
|
|
586
|
+
const targetPath = ctx.args[0] || ctx.cwd;
|
|
587
|
+
const threshold = ctx.flags.threshold || 10;
|
|
588
|
+
const formatType = ctx.flags.format || 'text';
|
|
589
|
+
const outputFile = ctx.flags.output;
|
|
590
|
+
output.printInfo(`Analyzing complexity: ${output.highlight(targetPath)}`);
|
|
591
|
+
output.writeln();
|
|
592
|
+
const spinner = output.createSpinner({ text: 'Calculating complexity...', spinner: 'dots' });
|
|
593
|
+
spinner.start();
|
|
594
|
+
try {
|
|
595
|
+
const astModule = await getASTAnalyzer();
|
|
596
|
+
const resolvedPath = resolve(targetPath);
|
|
597
|
+
const stat = await fs.stat(resolvedPath);
|
|
598
|
+
const files = stat.isDirectory() ? await scanSourceFiles(resolvedPath) : [resolvedPath];
|
|
599
|
+
const results = [];
|
|
600
|
+
for (const file of files.slice(0, 100)) {
|
|
601
|
+
try {
|
|
602
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
603
|
+
let analysis;
|
|
737
604
|
if (astModule) {
|
|
738
|
-
analyzer = astModule.createASTAnalyzer();
|
|
605
|
+
const analyzer = astModule.createASTAnalyzer();
|
|
739
606
|
analysis = analyzer.analyze(content, file);
|
|
740
607
|
}
|
|
741
608
|
else {
|
|
742
609
|
analysis = fallbackAnalyze(content, file);
|
|
743
610
|
}
|
|
744
|
-
flagged = analysis.complexity.cyclomatic > threshold;
|
|
745
|
-
rating = analysis.complexity.cyclomatic <= 5 ? 'Simple' :
|
|
611
|
+
const flagged = analysis.complexity.cyclomatic > threshold;
|
|
612
|
+
const rating = analysis.complexity.cyclomatic <= 5 ? 'Simple' :
|
|
746
613
|
analysis.complexity.cyclomatic <= 10 ? 'Moderate' :
|
|
747
614
|
analysis.complexity.cyclomatic <= 20 ? 'Complex' : 'Very Complex';
|
|
748
615
|
results.push({
|
|
@@ -751,100 +618,91 @@ var complexityAstCommand = {
|
|
|
751
618
|
cognitive: analysis.complexity.cognitive,
|
|
752
619
|
loc: analysis.complexity.loc,
|
|
753
620
|
commentDensity: analysis.complexity.commentDensity,
|
|
754
|
-
rating
|
|
755
|
-
flagged
|
|
621
|
+
rating,
|
|
622
|
+
flagged,
|
|
756
623
|
});
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
case 13:
|
|
777
|
-
_d.sent();
|
|
778
|
-
output.printSuccess("Results written to " + outputFile);
|
|
779
|
-
return [3 /*break*/, 15];
|
|
780
|
-
case 14:
|
|
624
|
+
}
|
|
625
|
+
catch {
|
|
626
|
+
// Skip files that can't be analyzed
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
spinner.stop();
|
|
630
|
+
// Sort by complexity descending
|
|
631
|
+
results.sort((a, b) => b.cyclomatic - a.cyclomatic);
|
|
632
|
+
const flaggedCount = results.filter(r => r.flagged).length;
|
|
633
|
+
const avgComplexity = results.length > 0
|
|
634
|
+
? results.reduce((sum, r) => sum + r.cyclomatic, 0) / results.length
|
|
635
|
+
: 0;
|
|
636
|
+
if (formatType === 'json') {
|
|
637
|
+
const jsonOutput = { files: results, summary: { total: results.length, flagged: flaggedCount, avgComplexity, threshold } };
|
|
638
|
+
if (outputFile) {
|
|
639
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
640
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
781
643
|
output.printJson(jsonOutput);
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
// Show all files in table format
|
|
810
|
-
output.writeln();
|
|
811
|
-
output.writeln(output.bold('All Files'));
|
|
812
|
-
output.writeln(output.dim('-'.repeat(60)));
|
|
813
|
-
displayFiles = results.slice(0, 15);
|
|
814
|
-
output.printTable({
|
|
815
|
-
columns: [
|
|
816
|
-
{ key: 'file', header: 'File', width: 40, format: function (v) { return truncatePathAst(v); } },
|
|
817
|
-
{ key: 'cyclomatic', header: 'Cyclo', width: 8, align: 'right', format: function (v) { return formatComplexityValueAst(v); } },
|
|
818
|
-
{ key: 'cognitive', header: 'Cogni', width: 8, align: 'right' },
|
|
819
|
-
{ key: 'loc', header: 'LOC', width: 8, align: 'right' },
|
|
820
|
-
],
|
|
821
|
-
data: displayFiles
|
|
822
|
-
});
|
|
823
|
-
if (results.length > 15) {
|
|
824
|
-
output.writeln(output.dim(" ... and " + (results.length - 15) + " more files"));
|
|
825
|
-
}
|
|
826
|
-
if (!outputFile) return [3 /*break*/, 18];
|
|
827
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify({ files: results, summary: { total: results.length, flagged: flaggedCount, avgComplexity: avgComplexity, threshold: threshold } }, null, 2))];
|
|
828
|
-
case 17:
|
|
829
|
-
_d.sent();
|
|
830
|
-
output.printSuccess("Results written to " + outputFile);
|
|
831
|
-
_d.label = 18;
|
|
832
|
-
case 18: return [2 /*return*/, { success: true, data: { files: results, flaggedCount: flaggedCount } }];
|
|
833
|
-
case 19:
|
|
834
|
-
error_3 = _d.sent();
|
|
835
|
-
spinner.stop();
|
|
836
|
-
message = error_3 instanceof Error ? error_3.message : String(error_3);
|
|
837
|
-
output.printError("Complexity analysis failed: " + message);
|
|
838
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
839
|
-
case 20: return [2 /*return*/];
|
|
644
|
+
}
|
|
645
|
+
return { success: true, data: jsonOutput };
|
|
646
|
+
}
|
|
647
|
+
// Summary
|
|
648
|
+
output.printBox([
|
|
649
|
+
`Files analyzed: ${results.length}`,
|
|
650
|
+
`Threshold: ${threshold}`,
|
|
651
|
+
`Flagged files: ${flaggedCount > 0 ? output.error(String(flaggedCount)) : output.success('0')}`,
|
|
652
|
+
`Average complexity: ${formatComplexityValueAst(Math.round(avgComplexity))}`,
|
|
653
|
+
].join('\n'), 'Complexity Analysis');
|
|
654
|
+
// Show flagged files first
|
|
655
|
+
if (flaggedCount > 0) {
|
|
656
|
+
output.writeln();
|
|
657
|
+
output.writeln(output.bold(output.warning(`High Complexity Files (>${threshold})`)));
|
|
658
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
659
|
+
const flaggedFiles = results.filter(r => r.flagged).slice(0, 10);
|
|
660
|
+
output.printTable({
|
|
661
|
+
columns: [
|
|
662
|
+
{ key: 'file', header: 'File', width: 40, format: (v) => truncatePathAst(v) },
|
|
663
|
+
{ key: 'cyclomatic', header: 'Cyclo', width: 8, align: 'right', format: (v) => output.error(String(v)) },
|
|
664
|
+
{ key: 'cognitive', header: 'Cogni', width: 8, align: 'right' },
|
|
665
|
+
{ key: 'loc', header: 'LOC', width: 8, align: 'right' },
|
|
666
|
+
{ key: 'rating', header: 'Rating', width: 15 },
|
|
667
|
+
],
|
|
668
|
+
data: flaggedFiles,
|
|
669
|
+
});
|
|
840
670
|
}
|
|
841
|
-
|
|
842
|
-
|
|
671
|
+
// Show all files in table format
|
|
672
|
+
output.writeln();
|
|
673
|
+
output.writeln(output.bold('All Files'));
|
|
674
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
675
|
+
const displayFiles = results.slice(0, 15);
|
|
676
|
+
output.printTable({
|
|
677
|
+
columns: [
|
|
678
|
+
{ key: 'file', header: 'File', width: 40, format: (v) => truncatePathAst(v) },
|
|
679
|
+
{ key: 'cyclomatic', header: 'Cyclo', width: 8, align: 'right', format: (v) => formatComplexityValueAst(v) },
|
|
680
|
+
{ key: 'cognitive', header: 'Cogni', width: 8, align: 'right' },
|
|
681
|
+
{ key: 'loc', header: 'LOC', width: 8, align: 'right' },
|
|
682
|
+
],
|
|
683
|
+
data: displayFiles,
|
|
684
|
+
});
|
|
685
|
+
if (results.length > 15) {
|
|
686
|
+
output.writeln(output.dim(` ... and ${results.length - 15} more files`));
|
|
687
|
+
}
|
|
688
|
+
if (outputFile) {
|
|
689
|
+
await writeFile(outputFile, JSON.stringify({ files: results, summary: { total: results.length, flagged: flaggedCount, avgComplexity, threshold } }, null, 2));
|
|
690
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
691
|
+
}
|
|
692
|
+
return { success: true, data: { files: results, flaggedCount } };
|
|
693
|
+
}
|
|
694
|
+
catch (error) {
|
|
695
|
+
spinner.stop();
|
|
696
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
697
|
+
output.printError(`Complexity analysis failed: ${message}`);
|
|
698
|
+
return { success: false, exitCode: 1 };
|
|
699
|
+
}
|
|
700
|
+
},
|
|
843
701
|
};
|
|
844
702
|
/**
|
|
845
703
|
* Symbol extraction subcommand
|
|
846
704
|
*/
|
|
847
|
-
|
|
705
|
+
const symbolsCommand = {
|
|
848
706
|
name: 'symbols',
|
|
849
707
|
aliases: ['sym'],
|
|
850
708
|
description: 'Extract and list code symbols (functions, classes, types)',
|
|
@@ -854,22 +712,22 @@ var symbolsCommand = {
|
|
|
854
712
|
short: 't',
|
|
855
713
|
description: 'Filter by symbol type (function, class, all)',
|
|
856
714
|
type: 'string',
|
|
857
|
-
|
|
858
|
-
choices: ['function', 'class', 'all']
|
|
715
|
+
default: 'all',
|
|
716
|
+
choices: ['function', 'class', 'all'],
|
|
859
717
|
},
|
|
860
718
|
{
|
|
861
719
|
name: 'format',
|
|
862
720
|
short: 'f',
|
|
863
721
|
description: 'Output format (text, json)',
|
|
864
722
|
type: 'string',
|
|
865
|
-
|
|
866
|
-
choices: ['text', 'json']
|
|
723
|
+
default: 'text',
|
|
724
|
+
choices: ['text', 'json'],
|
|
867
725
|
},
|
|
868
726
|
{
|
|
869
727
|
name: 'output',
|
|
870
728
|
short: 'o',
|
|
871
729
|
description: 'Output file path',
|
|
872
|
-
type: 'string'
|
|
730
|
+
type: 'string',
|
|
873
731
|
},
|
|
874
732
|
],
|
|
875
733
|
examples: [
|
|
@@ -877,152 +735,115 @@ var symbolsCommand = {
|
|
|
877
735
|
{ command: 'claude-flow analyze symbols src/ --type function', description: 'Only functions' },
|
|
878
736
|
{ command: 'claude-flow analyze symbols src/ --format json', description: 'JSON output' },
|
|
879
737
|
],
|
|
880
|
-
action:
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
resolvedPath = resolve(targetPath);
|
|
900
|
-
return [4 /*yield*/, fs.stat(resolvedPath)];
|
|
901
|
-
case 3:
|
|
902
|
-
stat = _h.sent();
|
|
903
|
-
if (!stat.isDirectory()) return [3 /*break*/, 5];
|
|
904
|
-
return [4 /*yield*/, scanSourceFiles(resolvedPath)];
|
|
905
|
-
case 4:
|
|
906
|
-
_a = _h.sent();
|
|
907
|
-
return [3 /*break*/, 6];
|
|
908
|
-
case 5:
|
|
909
|
-
_a = [resolvedPath];
|
|
910
|
-
_h.label = 6;
|
|
911
|
-
case 6:
|
|
912
|
-
files = _a;
|
|
913
|
-
symbols = [];
|
|
914
|
-
_i = 0, _b = files.slice(0, 100);
|
|
915
|
-
_h.label = 7;
|
|
916
|
-
case 7:
|
|
917
|
-
if (!(_i < _b.length)) return [3 /*break*/, 12];
|
|
918
|
-
file = _b[_i];
|
|
919
|
-
_h.label = 8;
|
|
920
|
-
case 8:
|
|
921
|
-
_h.trys.push([8, 10, , 11]);
|
|
922
|
-
return [4 /*yield*/, fs.readFile(file, 'utf-8')];
|
|
923
|
-
case 9:
|
|
924
|
-
content = _h.sent();
|
|
925
|
-
analysis = void 0;
|
|
738
|
+
action: async (ctx) => {
|
|
739
|
+
const targetPath = ctx.args[0] || ctx.cwd;
|
|
740
|
+
const symbolType = ctx.flags.type || 'all';
|
|
741
|
+
const formatType = ctx.flags.format || 'text';
|
|
742
|
+
const outputFile = ctx.flags.output;
|
|
743
|
+
output.printInfo(`Extracting symbols: ${output.highlight(targetPath)}`);
|
|
744
|
+
output.writeln();
|
|
745
|
+
const spinner = output.createSpinner({ text: 'Parsing code...', spinner: 'dots' });
|
|
746
|
+
spinner.start();
|
|
747
|
+
try {
|
|
748
|
+
const astModule = await getASTAnalyzer();
|
|
749
|
+
const resolvedPath = resolve(targetPath);
|
|
750
|
+
const stat = await fs.stat(resolvedPath);
|
|
751
|
+
const files = stat.isDirectory() ? await scanSourceFiles(resolvedPath) : [resolvedPath];
|
|
752
|
+
const symbols = [];
|
|
753
|
+
for (const file of files.slice(0, 100)) {
|
|
754
|
+
try {
|
|
755
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
756
|
+
let analysis;
|
|
926
757
|
if (astModule) {
|
|
927
|
-
analyzer = astModule.createASTAnalyzer();
|
|
758
|
+
const analyzer = astModule.createASTAnalyzer();
|
|
928
759
|
analysis = analyzer.analyze(content, file);
|
|
929
760
|
}
|
|
930
761
|
else {
|
|
931
762
|
analysis = fallbackAnalyze(content, file);
|
|
932
763
|
}
|
|
933
764
|
if (symbolType === 'all' || symbolType === 'function') {
|
|
934
|
-
for (
|
|
935
|
-
fn = _d[_c];
|
|
765
|
+
for (const fn of analysis.functions) {
|
|
936
766
|
symbols.push({
|
|
937
767
|
name: fn.name,
|
|
938
768
|
type: 'function',
|
|
939
|
-
file
|
|
769
|
+
file,
|
|
940
770
|
startLine: fn.startLine,
|
|
941
|
-
endLine: fn.endLine
|
|
771
|
+
endLine: fn.endLine,
|
|
942
772
|
});
|
|
943
773
|
}
|
|
944
774
|
}
|
|
945
775
|
if (symbolType === 'all' || symbolType === 'class') {
|
|
946
|
-
for (
|
|
947
|
-
cls = _f[_e];
|
|
776
|
+
for (const cls of analysis.classes) {
|
|
948
777
|
symbols.push({
|
|
949
778
|
name: cls.name,
|
|
950
779
|
type: 'class',
|
|
951
|
-
file
|
|
780
|
+
file,
|
|
952
781
|
startLine: cls.startLine,
|
|
953
|
-
endLine: cls.endLine
|
|
782
|
+
endLine: cls.endLine,
|
|
954
783
|
});
|
|
955
784
|
}
|
|
956
785
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
case 13:
|
|
972
|
-
_h.sent();
|
|
973
|
-
output.printSuccess("Results written to " + outputFile);
|
|
974
|
-
return [3 /*break*/, 15];
|
|
975
|
-
case 14:
|
|
786
|
+
}
|
|
787
|
+
catch {
|
|
788
|
+
// Skip files that can't be parsed
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
spinner.stop();
|
|
792
|
+
// Sort by file then name
|
|
793
|
+
symbols.sort((a, b) => a.file.localeCompare(b.file) || a.name.localeCompare(b.name));
|
|
794
|
+
if (formatType === 'json') {
|
|
795
|
+
if (outputFile) {
|
|
796
|
+
await writeFile(outputFile, JSON.stringify(symbols, null, 2));
|
|
797
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
976
800
|
output.printJson(symbols);
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
if (!outputFile) return [3 /*break*/, 18];
|
|
1005
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify(symbols, null, 2))];
|
|
1006
|
-
case 17:
|
|
1007
|
-
_h.sent();
|
|
1008
|
-
output.printSuccess("Results written to " + outputFile);
|
|
1009
|
-
_h.label = 18;
|
|
1010
|
-
case 18: return [2 /*return*/, { success: true, data: symbols }];
|
|
1011
|
-
case 19:
|
|
1012
|
-
error_4 = _h.sent();
|
|
1013
|
-
spinner.stop();
|
|
1014
|
-
message = error_4 instanceof Error ? error_4.message : String(error_4);
|
|
1015
|
-
output.printError("Symbol extraction failed: " + message);
|
|
1016
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
1017
|
-
case 20: return [2 /*return*/];
|
|
801
|
+
}
|
|
802
|
+
return { success: true, data: symbols };
|
|
803
|
+
}
|
|
804
|
+
// Summary
|
|
805
|
+
const functionCount = symbols.filter(s => s.type === 'function').length;
|
|
806
|
+
const classCount = symbols.filter(s => s.type === 'class').length;
|
|
807
|
+
output.printBox([
|
|
808
|
+
`Total symbols: ${symbols.length}`,
|
|
809
|
+
`Functions: ${functionCount}`,
|
|
810
|
+
`Classes: ${classCount}`,
|
|
811
|
+
`Files: ${files.length}`,
|
|
812
|
+
].join('\n'), 'Symbol Extraction');
|
|
813
|
+
output.writeln();
|
|
814
|
+
output.writeln(output.bold('Symbols'));
|
|
815
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
816
|
+
const displaySymbols = symbols.slice(0, 30);
|
|
817
|
+
output.printTable({
|
|
818
|
+
columns: [
|
|
819
|
+
{ key: 'type', header: 'Type', width: 10, format: (v) => getTypeMarkerAst(v) },
|
|
820
|
+
{ key: 'name', header: 'Name', width: 30 },
|
|
821
|
+
{ key: 'file', header: 'File', width: 35, format: (v) => truncatePathAst(v, 33) },
|
|
822
|
+
{ key: 'startLine', header: 'Line', width: 8, align: 'right' },
|
|
823
|
+
],
|
|
824
|
+
data: displaySymbols,
|
|
825
|
+
});
|
|
826
|
+
if (symbols.length > 30) {
|
|
827
|
+
output.writeln(output.dim(` ... and ${symbols.length - 30} more symbols`));
|
|
1018
828
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
829
|
+
if (outputFile) {
|
|
830
|
+
await writeFile(outputFile, JSON.stringify(symbols, null, 2));
|
|
831
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
832
|
+
}
|
|
833
|
+
return { success: true, data: symbols };
|
|
834
|
+
}
|
|
835
|
+
catch (error) {
|
|
836
|
+
spinner.stop();
|
|
837
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
838
|
+
output.printError(`Symbol extraction failed: ${message}`);
|
|
839
|
+
return { success: false, exitCode: 1 };
|
|
840
|
+
}
|
|
841
|
+
},
|
|
1021
842
|
};
|
|
1022
843
|
/**
|
|
1023
844
|
* Imports analysis subcommand
|
|
1024
845
|
*/
|
|
1025
|
-
|
|
846
|
+
const importsCommand = {
|
|
1026
847
|
name: 'imports',
|
|
1027
848
|
aliases: ['imp'],
|
|
1028
849
|
description: 'Analyze import dependencies across files',
|
|
@@ -1032,357 +853,275 @@ var importsCommand = {
|
|
|
1032
853
|
short: 'f',
|
|
1033
854
|
description: 'Output format (text, json)',
|
|
1034
855
|
type: 'string',
|
|
1035
|
-
|
|
1036
|
-
choices: ['text', 'json']
|
|
856
|
+
default: 'text',
|
|
857
|
+
choices: ['text', 'json'],
|
|
1037
858
|
},
|
|
1038
859
|
{
|
|
1039
860
|
name: 'output',
|
|
1040
861
|
short: 'o',
|
|
1041
862
|
description: 'Output file path',
|
|
1042
|
-
type: 'string'
|
|
863
|
+
type: 'string',
|
|
1043
864
|
},
|
|
1044
865
|
{
|
|
1045
866
|
name: 'external',
|
|
1046
867
|
short: 'e',
|
|
1047
868
|
description: 'Show only external (npm) imports',
|
|
1048
869
|
type: 'boolean',
|
|
1049
|
-
|
|
870
|
+
default: false,
|
|
1050
871
|
},
|
|
1051
872
|
],
|
|
1052
873
|
examples: [
|
|
1053
874
|
{ command: 'claude-flow analyze imports src/', description: 'Analyze all imports' },
|
|
1054
875
|
{ command: 'claude-flow analyze imports src/ --external', description: 'Only npm packages' },
|
|
1055
876
|
],
|
|
1056
|
-
action:
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
return [4 /*yield*/, fs.stat(resolvedPath)];
|
|
1077
|
-
case 3:
|
|
1078
|
-
stat = _e.sent();
|
|
1079
|
-
if (!stat.isDirectory()) return [3 /*break*/, 5];
|
|
1080
|
-
return [4 /*yield*/, scanSourceFiles(resolvedPath)];
|
|
1081
|
-
case 4:
|
|
1082
|
-
_a = _e.sent();
|
|
1083
|
-
return [3 /*break*/, 6];
|
|
1084
|
-
case 5:
|
|
1085
|
-
_a = [resolvedPath];
|
|
1086
|
-
_e.label = 6;
|
|
1087
|
-
case 6:
|
|
1088
|
-
files = _a;
|
|
1089
|
-
importCounts = new Map();
|
|
1090
|
-
fileImports = new Map();
|
|
1091
|
-
_i = 0, _b = files.slice(0, 100);
|
|
1092
|
-
_e.label = 7;
|
|
1093
|
-
case 7:
|
|
1094
|
-
if (!(_i < _b.length)) return [3 /*break*/, 12];
|
|
1095
|
-
file = _b[_i];
|
|
1096
|
-
_e.label = 8;
|
|
1097
|
-
case 8:
|
|
1098
|
-
_e.trys.push([8, 10, , 11]);
|
|
1099
|
-
return [4 /*yield*/, fs.readFile(file, 'utf-8')];
|
|
1100
|
-
case 9:
|
|
1101
|
-
content = _e.sent();
|
|
1102
|
-
analysis = void 0;
|
|
877
|
+
action: async (ctx) => {
|
|
878
|
+
const targetPath = ctx.args[0] || ctx.cwd;
|
|
879
|
+
const formatType = ctx.flags.format || 'text';
|
|
880
|
+
const outputFile = ctx.flags.output;
|
|
881
|
+
const externalOnly = ctx.flags.external;
|
|
882
|
+
output.printInfo(`Analyzing imports: ${output.highlight(targetPath)}`);
|
|
883
|
+
output.writeln();
|
|
884
|
+
const spinner = output.createSpinner({ text: 'Scanning imports...', spinner: 'dots' });
|
|
885
|
+
spinner.start();
|
|
886
|
+
try {
|
|
887
|
+
const astModule = await getASTAnalyzer();
|
|
888
|
+
const resolvedPath = resolve(targetPath);
|
|
889
|
+
const stat = await fs.stat(resolvedPath);
|
|
890
|
+
const files = stat.isDirectory() ? await scanSourceFiles(resolvedPath) : [resolvedPath];
|
|
891
|
+
const importCounts = new Map();
|
|
892
|
+
const fileImports = new Map();
|
|
893
|
+
for (const file of files.slice(0, 100)) {
|
|
894
|
+
try {
|
|
895
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
896
|
+
let analysis;
|
|
1103
897
|
if (astModule) {
|
|
1104
|
-
analyzer = astModule.createASTAnalyzer();
|
|
898
|
+
const analyzer = astModule.createASTAnalyzer();
|
|
1105
899
|
analysis = analyzer.analyze(content, file);
|
|
1106
900
|
}
|
|
1107
901
|
else {
|
|
1108
902
|
analysis = fallbackAnalyze(content, file);
|
|
1109
903
|
}
|
|
1110
|
-
imports = analysis.imports.filter(
|
|
904
|
+
const imports = analysis.imports.filter(imp => {
|
|
1111
905
|
if (externalOnly) {
|
|
1112
906
|
return !imp.startsWith('.') && !imp.startsWith('/');
|
|
1113
907
|
}
|
|
1114
908
|
return true;
|
|
1115
909
|
});
|
|
1116
910
|
fileImports.set(file, imports);
|
|
1117
|
-
for (
|
|
1118
|
-
|
|
1119
|
-
existing = importCounts.get(imp) || { count: 0, files: [] };
|
|
911
|
+
for (const imp of imports) {
|
|
912
|
+
const existing = importCounts.get(imp) || { count: 0, files: [] };
|
|
1120
913
|
existing.count++;
|
|
1121
914
|
existing.files.push(file);
|
|
1122
915
|
importCounts.set(imp, existing);
|
|
1123
916
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
_e.sent();
|
|
1144
|
-
output.printSuccess("Results written to " + outputFile);
|
|
1145
|
-
return [3 /*break*/, 15];
|
|
1146
|
-
case 14:
|
|
917
|
+
}
|
|
918
|
+
catch {
|
|
919
|
+
// Skip files that can't be parsed
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
spinner.stop();
|
|
923
|
+
// Sort by count
|
|
924
|
+
const sortedImports = Array.from(importCounts.entries())
|
|
925
|
+
.sort((a, b) => b[1].count - a[1].count);
|
|
926
|
+
if (formatType === 'json') {
|
|
927
|
+
const jsonOutput = {
|
|
928
|
+
imports: Object.fromEntries(sortedImports),
|
|
929
|
+
fileImports: Object.fromEntries(fileImports),
|
|
930
|
+
};
|
|
931
|
+
if (outputFile) {
|
|
932
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
933
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
1147
936
|
output.printJson(jsonOutput);
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
case 16:
|
|
1151
|
-
externalImports = sortedImports.filter(function (_a) {
|
|
1152
|
-
var imp = _a[0];
|
|
1153
|
-
return !imp.startsWith('.') && !imp.startsWith('/');
|
|
1154
|
-
});
|
|
1155
|
-
localImports = sortedImports.filter(function (_a) {
|
|
1156
|
-
var imp = _a[0];
|
|
1157
|
-
return imp.startsWith('.') || imp.startsWith('/');
|
|
1158
|
-
});
|
|
1159
|
-
output.printBox([
|
|
1160
|
-
"Total unique imports: " + sortedImports.length,
|
|
1161
|
-
"External (npm): " + externalImports.length,
|
|
1162
|
-
"Local (relative): " + localImports.length,
|
|
1163
|
-
"Files scanned: " + files.length,
|
|
1164
|
-
].join('\n'), 'Import Analysis');
|
|
1165
|
-
// Most used imports
|
|
1166
|
-
output.writeln();
|
|
1167
|
-
output.writeln(output.bold('Most Used Imports'));
|
|
1168
|
-
output.writeln(output.dim('-'.repeat(60)));
|
|
1169
|
-
topImports = sortedImports.slice(0, 20);
|
|
1170
|
-
output.printTable({
|
|
1171
|
-
columns: [
|
|
1172
|
-
{ key: 'count', header: 'Uses', width: 8, align: 'right' },
|
|
1173
|
-
{ key: 'import', header: 'Import', width: 50 },
|
|
1174
|
-
{ key: 'type', header: 'Type', width: 10 },
|
|
1175
|
-
],
|
|
1176
|
-
data: topImports.map(function (_a) {
|
|
1177
|
-
var imp = _a[0], data = _a[1];
|
|
1178
|
-
return ({
|
|
1179
|
-
count: data.count,
|
|
1180
|
-
"import": imp,
|
|
1181
|
-
type: imp.startsWith('.') || imp.startsWith('/') ? output.dim('local') : output.highlight('npm')
|
|
1182
|
-
});
|
|
1183
|
-
})
|
|
1184
|
-
});
|
|
1185
|
-
if (sortedImports.length > 20) {
|
|
1186
|
-
output.writeln(output.dim(" ... and " + (sortedImports.length - 20) + " more imports"));
|
|
1187
|
-
}
|
|
1188
|
-
if (!outputFile) return [3 /*break*/, 18];
|
|
1189
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify({
|
|
1190
|
-
imports: Object.fromEntries(sortedImports),
|
|
1191
|
-
fileImports: Object.fromEntries(fileImports)
|
|
1192
|
-
}, null, 2))];
|
|
1193
|
-
case 17:
|
|
1194
|
-
_e.sent();
|
|
1195
|
-
output.printSuccess("Results written to " + outputFile);
|
|
1196
|
-
_e.label = 18;
|
|
1197
|
-
case 18: return [2 /*return*/, { success: true, data: { imports: sortedImports } }];
|
|
1198
|
-
case 19:
|
|
1199
|
-
error_5 = _e.sent();
|
|
1200
|
-
spinner.stop();
|
|
1201
|
-
message = error_5 instanceof Error ? error_5.message : String(error_5);
|
|
1202
|
-
output.printError("Import analysis failed: " + message);
|
|
1203
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
1204
|
-
case 20: return [2 /*return*/];
|
|
937
|
+
}
|
|
938
|
+
return { success: true, data: jsonOutput };
|
|
1205
939
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
940
|
+
// Summary
|
|
941
|
+
const externalImports = sortedImports.filter(([imp]) => !imp.startsWith('.') && !imp.startsWith('/'));
|
|
942
|
+
const localImports = sortedImports.filter(([imp]) => imp.startsWith('.') || imp.startsWith('/'));
|
|
943
|
+
output.printBox([
|
|
944
|
+
`Total unique imports: ${sortedImports.length}`,
|
|
945
|
+
`External (npm): ${externalImports.length}`,
|
|
946
|
+
`Local (relative): ${localImports.length}`,
|
|
947
|
+
`Files scanned: ${files.length}`,
|
|
948
|
+
].join('\n'), 'Import Analysis');
|
|
949
|
+
// Most used imports
|
|
950
|
+
output.writeln();
|
|
951
|
+
output.writeln(output.bold('Most Used Imports'));
|
|
952
|
+
output.writeln(output.dim('-'.repeat(60)));
|
|
953
|
+
const topImports = sortedImports.slice(0, 20);
|
|
954
|
+
output.printTable({
|
|
955
|
+
columns: [
|
|
956
|
+
{ key: 'count', header: 'Uses', width: 8, align: 'right' },
|
|
957
|
+
{ key: 'import', header: 'Import', width: 50 },
|
|
958
|
+
{ key: 'type', header: 'Type', width: 10 },
|
|
959
|
+
],
|
|
960
|
+
data: topImports.map(([imp, data]) => ({
|
|
961
|
+
count: data.count,
|
|
962
|
+
import: imp,
|
|
963
|
+
type: imp.startsWith('.') || imp.startsWith('/') ? output.dim('local') : output.highlight('npm'),
|
|
964
|
+
})),
|
|
965
|
+
});
|
|
966
|
+
if (sortedImports.length > 20) {
|
|
967
|
+
output.writeln(output.dim(` ... and ${sortedImports.length - 20} more imports`));
|
|
968
|
+
}
|
|
969
|
+
if (outputFile) {
|
|
970
|
+
await writeFile(outputFile, JSON.stringify({
|
|
971
|
+
imports: Object.fromEntries(sortedImports),
|
|
972
|
+
fileImports: Object.fromEntries(fileImports),
|
|
973
|
+
}, null, 2));
|
|
974
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
975
|
+
}
|
|
976
|
+
return { success: true, data: { imports: sortedImports } };
|
|
977
|
+
}
|
|
978
|
+
catch (error) {
|
|
979
|
+
spinner.stop();
|
|
980
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
981
|
+
output.printError(`Import analysis failed: ${message}`);
|
|
982
|
+
return { success: false, exitCode: 1 };
|
|
983
|
+
}
|
|
984
|
+
},
|
|
1208
985
|
};
|
|
1209
986
|
/**
|
|
1210
987
|
* Helper: Scan directory for source files
|
|
1211
988
|
*/
|
|
1212
|
-
function scanSourceFiles(dir, maxDepth) {
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
return [4 /*yield*/, fs.readdir(currentDir, { withFileTypes: true })];
|
|
1227
|
-
case 2:
|
|
1228
|
-
entries = _b.sent();
|
|
1229
|
-
_i = 0, entries_1 = entries;
|
|
1230
|
-
_b.label = 3;
|
|
1231
|
-
case 3:
|
|
1232
|
-
if (!(_i < entries_1.length)) return [3 /*break*/, 8];
|
|
1233
|
-
entry = entries_1[_i];
|
|
1234
|
-
fullPath = path.join(currentDir, entry.name);
|
|
1235
|
-
if (!entry.isDirectory()) return [3 /*break*/, 6];
|
|
1236
|
-
if (!!excludeDirs.includes(entry.name)) return [3 /*break*/, 5];
|
|
1237
|
-
return [4 /*yield*/, scan(fullPath, depth + 1)];
|
|
1238
|
-
case 4:
|
|
1239
|
-
_b.sent();
|
|
1240
|
-
_b.label = 5;
|
|
1241
|
-
case 5: return [3 /*break*/, 7];
|
|
1242
|
-
case 6:
|
|
1243
|
-
if (entry.isFile()) {
|
|
1244
|
-
ext = path.extname(entry.name);
|
|
1245
|
-
if (extensions.includes(ext)) {
|
|
1246
|
-
files.push(fullPath);
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
_b.label = 7;
|
|
1250
|
-
case 7:
|
|
1251
|
-
_i++;
|
|
1252
|
-
return [3 /*break*/, 3];
|
|
1253
|
-
case 8: return [3 /*break*/, 10];
|
|
1254
|
-
case 9:
|
|
1255
|
-
_a = _b.sent();
|
|
1256
|
-
return [3 /*break*/, 10];
|
|
1257
|
-
case 10: return [2 /*return*/];
|
|
989
|
+
async function scanSourceFiles(dir, maxDepth = 10) {
|
|
990
|
+
const files = [];
|
|
991
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
992
|
+
const excludeDirs = ['node_modules', 'dist', 'build', '.git', 'coverage', '__pycache__'];
|
|
993
|
+
async function scan(currentDir, depth) {
|
|
994
|
+
if (depth > maxDepth)
|
|
995
|
+
return;
|
|
996
|
+
try {
|
|
997
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
998
|
+
for (const entry of entries) {
|
|
999
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
1000
|
+
if (entry.isDirectory()) {
|
|
1001
|
+
if (!excludeDirs.includes(entry.name)) {
|
|
1002
|
+
await scan(fullPath, depth + 1);
|
|
1258
1003
|
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
files = [];
|
|
1267
|
-
extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
1268
|
-
excludeDirs = ['node_modules', 'dist', 'build', '.git', 'coverage', '__pycache__'];
|
|
1269
|
-
return [4 /*yield*/, scan(dir, 0)];
|
|
1270
|
-
case 1:
|
|
1271
|
-
_a.sent();
|
|
1272
|
-
return [2 /*return*/, files];
|
|
1004
|
+
}
|
|
1005
|
+
else if (entry.isFile()) {
|
|
1006
|
+
const ext = path.extname(entry.name);
|
|
1007
|
+
if (extensions.includes(ext)) {
|
|
1008
|
+
files.push(fullPath);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1273
1011
|
}
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1012
|
+
}
|
|
1013
|
+
catch {
|
|
1014
|
+
// Skip directories we can't read
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
await scan(dir, 0);
|
|
1018
|
+
return files;
|
|
1276
1019
|
}
|
|
1277
1020
|
/**
|
|
1278
1021
|
* Fallback analysis when ruvector is not available
|
|
1279
1022
|
*/
|
|
1280
1023
|
function fallbackAnalyze(code, filePath) {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1024
|
+
const lines = code.split('\n');
|
|
1025
|
+
const functions = [];
|
|
1026
|
+
const classes = [];
|
|
1027
|
+
const imports = [];
|
|
1028
|
+
const exports = [];
|
|
1286
1029
|
// Extract functions
|
|
1287
|
-
|
|
1288
|
-
|
|
1030
|
+
const funcPattern = /(?:export\s+)?(?:async\s+)?function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*=>|^\s*(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{/gm;
|
|
1031
|
+
let match;
|
|
1289
1032
|
while ((match = funcPattern.exec(code)) !== null) {
|
|
1290
|
-
|
|
1033
|
+
const name = match[1] || match[2] || match[3];
|
|
1291
1034
|
if (name && !['if', 'while', 'for', 'switch'].includes(name)) {
|
|
1292
|
-
|
|
1293
|
-
functions.push({ name
|
|
1035
|
+
const lineNum = code.substring(0, match.index).split('\n').length;
|
|
1036
|
+
functions.push({ name, startLine: lineNum, endLine: lineNum + 10 });
|
|
1294
1037
|
}
|
|
1295
1038
|
}
|
|
1296
1039
|
// Extract classes
|
|
1297
|
-
|
|
1040
|
+
const classPattern = /(?:export\s+)?class\s+(\w+)/gm;
|
|
1298
1041
|
while ((match = classPattern.exec(code)) !== null) {
|
|
1299
|
-
|
|
1042
|
+
const lineNum = code.substring(0, match.index).split('\n').length;
|
|
1300
1043
|
classes.push({ name: match[1], startLine: lineNum, endLine: lineNum + 20 });
|
|
1301
1044
|
}
|
|
1302
1045
|
// Extract imports
|
|
1303
|
-
|
|
1046
|
+
const importPattern = /import\s+(?:.*\s+from\s+)?['"]([^'"]+)['"]/gm;
|
|
1304
1047
|
while ((match = importPattern.exec(code)) !== null) {
|
|
1305
1048
|
imports.push(match[1]);
|
|
1306
1049
|
}
|
|
1307
|
-
|
|
1050
|
+
const requirePattern = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/gm;
|
|
1308
1051
|
while ((match = requirePattern.exec(code)) !== null) {
|
|
1309
1052
|
imports.push(match[1]);
|
|
1310
1053
|
}
|
|
1311
1054
|
// Extract exports
|
|
1312
|
-
|
|
1055
|
+
const exportPattern = /export\s+(?:default\s+)?(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/gm;
|
|
1313
1056
|
while ((match = exportPattern.exec(code)) !== null) {
|
|
1314
1057
|
exports.push(match[1]);
|
|
1315
1058
|
}
|
|
1316
1059
|
// Calculate complexity
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
for (
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
var closes = (line.match(/\}/g) || []).length;
|
|
1060
|
+
const nonEmptyLines = lines.filter(l => l.trim().length > 0).length;
|
|
1061
|
+
const commentLines = lines.filter(l => /^\s*(\/\/|\/\*|\*|#)/.test(l)).length;
|
|
1062
|
+
const decisionPoints = (code.match(/\b(if|else|for|while|switch|case|catch|&&|\|\||\?)\b/g) || []).length;
|
|
1063
|
+
let cognitive = 0;
|
|
1064
|
+
let nestingLevel = 0;
|
|
1065
|
+
for (const line of lines) {
|
|
1066
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
1067
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
1326
1068
|
if (/\b(if|for|while|switch)\b/.test(line)) {
|
|
1327
1069
|
cognitive += 1 + nestingLevel;
|
|
1328
1070
|
}
|
|
1329
1071
|
nestingLevel = Math.max(0, nestingLevel + opens - closes);
|
|
1330
1072
|
}
|
|
1331
1073
|
// Detect language
|
|
1332
|
-
|
|
1333
|
-
|
|
1074
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
1075
|
+
const language = ext === '.ts' || ext === '.tsx' ? 'typescript' :
|
|
1334
1076
|
ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs' ? 'javascript' :
|
|
1335
1077
|
ext === '.py' ? 'python' : 'unknown';
|
|
1336
1078
|
return {
|
|
1337
|
-
filePath
|
|
1338
|
-
language
|
|
1339
|
-
functions
|
|
1340
|
-
classes
|
|
1341
|
-
imports
|
|
1342
|
-
exports
|
|
1079
|
+
filePath,
|
|
1080
|
+
language,
|
|
1081
|
+
functions,
|
|
1082
|
+
classes,
|
|
1083
|
+
imports,
|
|
1084
|
+
exports,
|
|
1343
1085
|
complexity: {
|
|
1344
1086
|
cyclomatic: decisionPoints + 1,
|
|
1345
|
-
cognitive
|
|
1087
|
+
cognitive,
|
|
1346
1088
|
loc: nonEmptyLines,
|
|
1347
|
-
commentDensity: lines.length > 0 ? commentLines / lines.length : 0
|
|
1348
|
-
}
|
|
1089
|
+
commentDensity: lines.length > 0 ? commentLines / lines.length : 0,
|
|
1090
|
+
},
|
|
1349
1091
|
};
|
|
1350
1092
|
}
|
|
1351
1093
|
// Dependencies subcommand
|
|
1352
|
-
|
|
1094
|
+
const depsCommand = {
|
|
1353
1095
|
name: 'deps',
|
|
1354
1096
|
description: 'Analyze project dependencies',
|
|
1355
1097
|
options: [
|
|
1356
1098
|
{ name: 'outdated', short: 'o', type: 'boolean', description: 'Show only outdated dependencies' },
|
|
1357
1099
|
{ name: 'security', short: 's', type: 'boolean', description: 'Check for security vulnerabilities' },
|
|
1358
|
-
{ name: 'format', short: 'f', type: 'string', description: 'Output format: text, json',
|
|
1100
|
+
{ name: 'format', short: 'f', type: 'string', description: 'Output format: text, json', default: 'text' },
|
|
1359
1101
|
],
|
|
1360
1102
|
examples: [
|
|
1361
1103
|
{ command: 'claude-flow analyze deps --outdated', description: 'Show outdated dependencies' },
|
|
1362
1104
|
{ command: 'claude-flow analyze deps --security', description: 'Check for vulnerabilities' },
|
|
1363
1105
|
],
|
|
1364
|
-
action:
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
return [2 /*return*/, { success: true }];
|
|
1384
|
-
});
|
|
1385
|
-
}); }
|
|
1106
|
+
action: async (ctx) => {
|
|
1107
|
+
const showOutdated = ctx.flags.outdated;
|
|
1108
|
+
const checkSecurity = ctx.flags.security;
|
|
1109
|
+
output.writeln();
|
|
1110
|
+
output.writeln(output.bold('Dependency Analysis'));
|
|
1111
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
1112
|
+
output.printInfo('Analyzing dependencies...');
|
|
1113
|
+
output.writeln();
|
|
1114
|
+
// Placeholder - would integrate with npm/yarn audit
|
|
1115
|
+
output.printBox([
|
|
1116
|
+
`Outdated Check: ${showOutdated ? 'Enabled' : 'Disabled'}`,
|
|
1117
|
+
`Security Check: ${checkSecurity ? 'Enabled' : 'Disabled'}`,
|
|
1118
|
+
`Status: Feature in development`,
|
|
1119
|
+
``,
|
|
1120
|
+
`Dependency analysis capabilities coming soon.`,
|
|
1121
|
+
`Use 'security scan --type deps' for security scanning.`,
|
|
1122
|
+
].join('\n'), 'Dependency Analysis');
|
|
1123
|
+
return { success: true };
|
|
1124
|
+
},
|
|
1386
1125
|
};
|
|
1387
1126
|
// ============================================================================
|
|
1388
1127
|
// Graph Analysis Subcommands (MinCut, Louvain, Circular Dependencies)
|
|
@@ -1390,7 +1129,7 @@ var depsCommand = {
|
|
|
1390
1129
|
/**
|
|
1391
1130
|
* Analyze code boundaries using MinCut algorithm
|
|
1392
1131
|
*/
|
|
1393
|
-
|
|
1132
|
+
const boundariesCommand = {
|
|
1394
1133
|
name: 'boundaries',
|
|
1395
1134
|
aliases: ['boundary', 'mincut'],
|
|
1396
1135
|
description: 'Find natural code boundaries using MinCut algorithm',
|
|
@@ -1400,21 +1139,21 @@ var boundariesCommand = {
|
|
|
1400
1139
|
short: 'p',
|
|
1401
1140
|
description: 'Number of partitions to find',
|
|
1402
1141
|
type: 'number',
|
|
1403
|
-
|
|
1142
|
+
default: 2,
|
|
1404
1143
|
},
|
|
1405
1144
|
{
|
|
1406
1145
|
name: 'output',
|
|
1407
1146
|
short: 'o',
|
|
1408
1147
|
description: 'Output file path',
|
|
1409
|
-
type: 'string'
|
|
1148
|
+
type: 'string',
|
|
1410
1149
|
},
|
|
1411
1150
|
{
|
|
1412
1151
|
name: 'format',
|
|
1413
1152
|
short: 'f',
|
|
1414
1153
|
description: 'Output format (text, json, dot)',
|
|
1415
1154
|
type: 'string',
|
|
1416
|
-
|
|
1417
|
-
choices: ['text', 'json', 'dot']
|
|
1155
|
+
default: 'text',
|
|
1156
|
+
choices: ['text', 'json', 'dot'],
|
|
1418
1157
|
},
|
|
1419
1158
|
],
|
|
1420
1159
|
examples: [
|
|
@@ -1422,145 +1161,127 @@ var boundariesCommand = {
|
|
|
1422
1161
|
{ command: 'claude-flow analyze boundaries -p 3 src/', description: 'Find 3 partitions' },
|
|
1423
1162
|
{ command: 'claude-flow analyze boundaries -f dot -o graph.dot src/', description: 'Export to DOT format' },
|
|
1424
1163
|
],
|
|
1425
|
-
action:
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
boundaries: result.boundaries,
|
|
1460
|
-
statistics: result.statistics,
|
|
1461
|
-
circularDependencies: result.circularDependencies
|
|
1462
|
-
};
|
|
1463
|
-
if (!outputFile) return [3 /*break*/, 5];
|
|
1464
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify(jsonOutput, null, 2))];
|
|
1465
|
-
case 4:
|
|
1466
|
-
_b.sent();
|
|
1467
|
-
output.printSuccess("Results written to " + outputFile);
|
|
1468
|
-
return [3 /*break*/, 6];
|
|
1469
|
-
case 5:
|
|
1164
|
+
action: async (ctx) => {
|
|
1165
|
+
const targetDir = ctx.args[0] || ctx.cwd;
|
|
1166
|
+
const numPartitions = ctx.flags.partitions || 2;
|
|
1167
|
+
const outputFile = ctx.flags.output;
|
|
1168
|
+
const format = ctx.flags.format || 'text';
|
|
1169
|
+
output.printInfo(`Analyzing code boundaries in: ${output.highlight(targetDir)}`);
|
|
1170
|
+
output.writeln();
|
|
1171
|
+
const spinner = output.createSpinner({ text: 'Building dependency graph...', spinner: 'dots' });
|
|
1172
|
+
spinner.start();
|
|
1173
|
+
try {
|
|
1174
|
+
const analyzer = await getGraphAnalyzer();
|
|
1175
|
+
if (!analyzer) {
|
|
1176
|
+
spinner.stop();
|
|
1177
|
+
output.printError('Graph analyzer module not available');
|
|
1178
|
+
return { success: false, exitCode: 1 };
|
|
1179
|
+
}
|
|
1180
|
+
const result = await analyzer.analyzeGraph(resolve(targetDir), {
|
|
1181
|
+
includeBoundaries: true,
|
|
1182
|
+
includeModules: false,
|
|
1183
|
+
numPartitions,
|
|
1184
|
+
});
|
|
1185
|
+
spinner.stop();
|
|
1186
|
+
// Handle different output formats
|
|
1187
|
+
if (format === 'json') {
|
|
1188
|
+
const jsonOutput = {
|
|
1189
|
+
boundaries: result.boundaries,
|
|
1190
|
+
statistics: result.statistics,
|
|
1191
|
+
circularDependencies: result.circularDependencies,
|
|
1192
|
+
};
|
|
1193
|
+
if (outputFile) {
|
|
1194
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
1195
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1470
1198
|
output.printJson(jsonOutput);
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
_b.sent();
|
|
1483
|
-
output.printSuccess("DOT graph written to " + outputFile);
|
|
1199
|
+
}
|
|
1200
|
+
return { success: true, data: jsonOutput };
|
|
1201
|
+
}
|
|
1202
|
+
if (format === 'dot') {
|
|
1203
|
+
const dotOutput = analyzer.exportToDot(result, {
|
|
1204
|
+
includeLabels: true,
|
|
1205
|
+
highlightCycles: true,
|
|
1206
|
+
});
|
|
1207
|
+
if (outputFile) {
|
|
1208
|
+
await writeFile(outputFile, dotOutput);
|
|
1209
|
+
output.printSuccess(`DOT graph written to ${outputFile}`);
|
|
1484
1210
|
output.writeln(output.dim('Visualize with: dot -Tpng -o graph.png ' + outputFile));
|
|
1485
|
-
|
|
1486
|
-
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1487
1213
|
output.writeln(dotOutput);
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
}
|
|
1513
|
-
output.writeln();
|
|
1514
|
-
output.writeln(output.dim('Partition 2:'));
|
|
1515
|
-
p2Display = boundary.partition2.slice(0, 10);
|
|
1516
|
-
output.printList(p2Display);
|
|
1517
|
-
if (boundary.partition2.length > 10) {
|
|
1518
|
-
output.writeln(output.dim(" ... and " + (boundary.partition2.length - 10) + " more files"));
|
|
1519
|
-
}
|
|
1520
|
-
output.writeln();
|
|
1521
|
-
output.writeln(output.success('Suggestion:'));
|
|
1522
|
-
output.writeln(" " + boundary.suggestion);
|
|
1523
|
-
output.writeln();
|
|
1524
|
-
}
|
|
1214
|
+
}
|
|
1215
|
+
return { success: true };
|
|
1216
|
+
}
|
|
1217
|
+
// Text format (default)
|
|
1218
|
+
output.printBox([
|
|
1219
|
+
`Files analyzed: ${result.statistics.nodeCount}`,
|
|
1220
|
+
`Dependencies: ${result.statistics.edgeCount}`,
|
|
1221
|
+
`Avg degree: ${result.statistics.avgDegree.toFixed(2)}`,
|
|
1222
|
+
`Density: ${(result.statistics.density * 100).toFixed(2)}%`,
|
|
1223
|
+
`Components: ${result.statistics.componentCount}`,
|
|
1224
|
+
].join('\n'), 'Graph Statistics');
|
|
1225
|
+
if (result.boundaries && result.boundaries.length > 0) {
|
|
1226
|
+
output.writeln();
|
|
1227
|
+
output.writeln(output.bold('MinCut Boundaries'));
|
|
1228
|
+
output.writeln();
|
|
1229
|
+
for (let i = 0; i < result.boundaries.length; i++) {
|
|
1230
|
+
const boundary = result.boundaries[i];
|
|
1231
|
+
output.writeln(output.bold(`Boundary ${i + 1} (cut value: ${boundary.cutValue})`));
|
|
1232
|
+
output.writeln();
|
|
1233
|
+
output.writeln(output.dim('Partition 1:'));
|
|
1234
|
+
const p1Display = boundary.partition1.slice(0, 10);
|
|
1235
|
+
output.printList(p1Display);
|
|
1236
|
+
if (boundary.partition1.length > 10) {
|
|
1237
|
+
output.writeln(output.dim(` ... and ${boundary.partition1.length - 10} more files`));
|
|
1525
1238
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
cycle = _a[_i];
|
|
1533
|
-
severityColor = cycle.severity === 'high' ? output.error : cycle.severity === 'medium' ? output.warning : output.dim;
|
|
1534
|
-
output.writeln(severityColor("[" + cycle.severity.toUpperCase() + "]") + " " + cycle.cycle.join(' -> '));
|
|
1535
|
-
output.writeln(output.dim(" " + cycle.suggestion));
|
|
1536
|
-
output.writeln();
|
|
1537
|
-
}
|
|
1538
|
-
if (result.circularDependencies.length > 5) {
|
|
1539
|
-
output.writeln(output.dim("... and " + (result.circularDependencies.length - 5) + " more cycles"));
|
|
1540
|
-
}
|
|
1239
|
+
output.writeln();
|
|
1240
|
+
output.writeln(output.dim('Partition 2:'));
|
|
1241
|
+
const p2Display = boundary.partition2.slice(0, 10);
|
|
1242
|
+
output.printList(p2Display);
|
|
1243
|
+
if (boundary.partition2.length > 10) {
|
|
1244
|
+
output.writeln(output.dim(` ... and ${boundary.partition2.length - 10} more files`));
|
|
1541
1245
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
_b.label = 13;
|
|
1548
|
-
case 13: return [2 /*return*/, { success: true, data: result }];
|
|
1549
|
-
case 14:
|
|
1550
|
-
error_6 = _b.sent();
|
|
1551
|
-
spinner.stop();
|
|
1552
|
-
message = error_6 instanceof Error ? error_6.message : String(error_6);
|
|
1553
|
-
output.printError("Analysis failed: " + message);
|
|
1554
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
1555
|
-
case 15: return [2 /*return*/];
|
|
1246
|
+
output.writeln();
|
|
1247
|
+
output.writeln(output.success('Suggestion:'));
|
|
1248
|
+
output.writeln(` ${boundary.suggestion}`);
|
|
1249
|
+
output.writeln();
|
|
1250
|
+
}
|
|
1556
1251
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1252
|
+
// Show circular dependencies
|
|
1253
|
+
if (result.circularDependencies.length > 0) {
|
|
1254
|
+
output.writeln();
|
|
1255
|
+
output.writeln(output.bold(output.warning('Circular Dependencies Detected')));
|
|
1256
|
+
output.writeln();
|
|
1257
|
+
for (const cycle of result.circularDependencies.slice(0, 5)) {
|
|
1258
|
+
const severityColor = cycle.severity === 'high' ? output.error : cycle.severity === 'medium' ? output.warning : output.dim;
|
|
1259
|
+
output.writeln(`${severityColor(`[${cycle.severity.toUpperCase()}]`)} ${cycle.cycle.join(' -> ')}`);
|
|
1260
|
+
output.writeln(output.dim(` ${cycle.suggestion}`));
|
|
1261
|
+
output.writeln();
|
|
1262
|
+
}
|
|
1263
|
+
if (result.circularDependencies.length > 5) {
|
|
1264
|
+
output.writeln(output.dim(`... and ${result.circularDependencies.length - 5} more cycles`));
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (outputFile) {
|
|
1268
|
+
await writeFile(outputFile, JSON.stringify(result, null, 2));
|
|
1269
|
+
output.printSuccess(`Full results written to ${outputFile}`);
|
|
1270
|
+
}
|
|
1271
|
+
return { success: true, data: result };
|
|
1272
|
+
}
|
|
1273
|
+
catch (error) {
|
|
1274
|
+
spinner.stop();
|
|
1275
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1276
|
+
output.printError(`Analysis failed: ${message}`);
|
|
1277
|
+
return { success: false, exitCode: 1 };
|
|
1278
|
+
}
|
|
1279
|
+
},
|
|
1559
1280
|
};
|
|
1560
1281
|
/**
|
|
1561
1282
|
* Analyze modules/communities using Louvain algorithm
|
|
1562
1283
|
*/
|
|
1563
|
-
|
|
1284
|
+
const modulesCommand = {
|
|
1564
1285
|
name: 'modules',
|
|
1565
1286
|
aliases: ['communities', 'louvain'],
|
|
1566
1287
|
description: 'Detect module communities using Louvain algorithm',
|
|
@@ -1569,22 +1290,22 @@ var modulesCommand = {
|
|
|
1569
1290
|
name: 'output',
|
|
1570
1291
|
short: 'o',
|
|
1571
1292
|
description: 'Output file path',
|
|
1572
|
-
type: 'string'
|
|
1293
|
+
type: 'string',
|
|
1573
1294
|
},
|
|
1574
1295
|
{
|
|
1575
1296
|
name: 'format',
|
|
1576
1297
|
short: 'f',
|
|
1577
1298
|
description: 'Output format (text, json, dot)',
|
|
1578
1299
|
type: 'string',
|
|
1579
|
-
|
|
1580
|
-
choices: ['text', 'json', 'dot']
|
|
1300
|
+
default: 'text',
|
|
1301
|
+
choices: ['text', 'json', 'dot'],
|
|
1581
1302
|
},
|
|
1582
1303
|
{
|
|
1583
1304
|
name: 'min-size',
|
|
1584
1305
|
short: 'm',
|
|
1585
1306
|
description: 'Minimum community size to display',
|
|
1586
1307
|
type: 'number',
|
|
1587
|
-
|
|
1308
|
+
default: 2,
|
|
1588
1309
|
},
|
|
1589
1310
|
],
|
|
1590
1311
|
examples: [
|
|
@@ -1592,128 +1313,109 @@ var modulesCommand = {
|
|
|
1592
1313
|
{ command: 'claude-flow analyze modules -f dot -o modules.dot src/', description: 'Export colored DOT graph' },
|
|
1593
1314
|
{ command: 'claude-flow analyze modules -m 3 src/', description: 'Only show communities with 3+ files' },
|
|
1594
1315
|
],
|
|
1595
|
-
action:
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
jsonOutput = {
|
|
1630
|
-
communities: communities,
|
|
1631
|
-
statistics: result.statistics
|
|
1632
|
-
};
|
|
1633
|
-
if (!outputFile) return [3 /*break*/, 5];
|
|
1634
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify(jsonOutput, null, 2))];
|
|
1635
|
-
case 4:
|
|
1636
|
-
_e.sent();
|
|
1637
|
-
output.printSuccess("Results written to " + outputFile);
|
|
1638
|
-
return [3 /*break*/, 6];
|
|
1639
|
-
case 5:
|
|
1316
|
+
action: async (ctx) => {
|
|
1317
|
+
const targetDir = ctx.args[0] || ctx.cwd;
|
|
1318
|
+
const outputFile = ctx.flags.output;
|
|
1319
|
+
const format = ctx.flags.format || 'text';
|
|
1320
|
+
const minSize = ctx.flags['min-size'] || 2;
|
|
1321
|
+
output.printInfo(`Detecting module communities in: ${output.highlight(targetDir)}`);
|
|
1322
|
+
output.writeln();
|
|
1323
|
+
const spinner = output.createSpinner({ text: 'Building dependency graph...', spinner: 'dots' });
|
|
1324
|
+
spinner.start();
|
|
1325
|
+
try {
|
|
1326
|
+
const analyzer = await getGraphAnalyzer();
|
|
1327
|
+
if (!analyzer) {
|
|
1328
|
+
spinner.stop();
|
|
1329
|
+
output.printError('Graph analyzer module not available');
|
|
1330
|
+
return { success: false, exitCode: 1 };
|
|
1331
|
+
}
|
|
1332
|
+
const result = await analyzer.analyzeGraph(resolve(targetDir), {
|
|
1333
|
+
includeBoundaries: false,
|
|
1334
|
+
includeModules: true,
|
|
1335
|
+
});
|
|
1336
|
+
spinner.stop();
|
|
1337
|
+
// Filter communities by size
|
|
1338
|
+
const communities = result.communities?.filter(c => c.members.length >= minSize) || [];
|
|
1339
|
+
// Handle different output formats
|
|
1340
|
+
if (format === 'json') {
|
|
1341
|
+
const jsonOutput = {
|
|
1342
|
+
communities,
|
|
1343
|
+
statistics: result.statistics,
|
|
1344
|
+
};
|
|
1345
|
+
if (outputFile) {
|
|
1346
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
1347
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
1348
|
+
}
|
|
1349
|
+
else {
|
|
1640
1350
|
output.printJson(jsonOutput);
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
_e.sent();
|
|
1654
|
-
output.printSuccess("DOT graph written to " + outputFile);
|
|
1351
|
+
}
|
|
1352
|
+
return { success: true, data: jsonOutput };
|
|
1353
|
+
}
|
|
1354
|
+
if (format === 'dot') {
|
|
1355
|
+
const dotOutput = analyzer.exportToDot(result, {
|
|
1356
|
+
includeLabels: true,
|
|
1357
|
+
colorByCommunity: true,
|
|
1358
|
+
highlightCycles: true,
|
|
1359
|
+
});
|
|
1360
|
+
if (outputFile) {
|
|
1361
|
+
await writeFile(outputFile, dotOutput);
|
|
1362
|
+
output.printSuccess(`DOT graph written to ${outputFile}`);
|
|
1655
1363
|
output.writeln(output.dim('Visualize with: dot -Tpng -o modules.png ' + outputFile));
|
|
1656
|
-
|
|
1657
|
-
|
|
1364
|
+
}
|
|
1365
|
+
else {
|
|
1658
1366
|
output.writeln(dotOutput);
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
if (community.members.length > 5) {
|
|
1687
|
-
output.writeln(output.dim(" ... and " + (community.members.length - 5) + " more"));
|
|
1688
|
-
}
|
|
1689
|
-
output.writeln();
|
|
1690
|
-
}
|
|
1691
|
-
if (communities.length > 10) {
|
|
1692
|
-
output.writeln(output.dim("... and " + (communities.length - 10) + " more communities"));
|
|
1693
|
-
}
|
|
1367
|
+
}
|
|
1368
|
+
return { success: true };
|
|
1369
|
+
}
|
|
1370
|
+
// Text format (default)
|
|
1371
|
+
output.printBox([
|
|
1372
|
+
`Files analyzed: ${result.statistics.nodeCount}`,
|
|
1373
|
+
`Dependencies: ${result.statistics.edgeCount}`,
|
|
1374
|
+
`Communities found: ${result.communities?.length || 0}`,
|
|
1375
|
+
`Showing: ${communities.length} (min size: ${minSize})`,
|
|
1376
|
+
].join('\n'), 'Module Detection Results');
|
|
1377
|
+
if (communities.length > 0) {
|
|
1378
|
+
output.writeln();
|
|
1379
|
+
output.writeln(output.bold('Detected Communities'));
|
|
1380
|
+
output.writeln();
|
|
1381
|
+
for (const community of communities.slice(0, 10)) {
|
|
1382
|
+
const cohesionIndicator = community.cohesion > 0.5 ? output.success('High') :
|
|
1383
|
+
community.cohesion > 0.2 ? output.warning('Medium') : output.dim('Low');
|
|
1384
|
+
output.writeln(output.bold(`Community ${community.id}: ${community.suggestedName || 'unnamed'}`));
|
|
1385
|
+
output.writeln(` ${output.dim('Cohesion:')} ${cohesionIndicator} (${(community.cohesion * 100).toFixed(1)}%)`);
|
|
1386
|
+
output.writeln(` ${output.dim('Central node:')} ${community.centralNode || 'none'}`);
|
|
1387
|
+
output.writeln(` ${output.dim('Members:')} ${community.members.length} files`);
|
|
1388
|
+
const displayMembers = community.members.slice(0, 5);
|
|
1389
|
+
for (const member of displayMembers) {
|
|
1390
|
+
output.writeln(` - ${member}`);
|
|
1391
|
+
}
|
|
1392
|
+
if (community.members.length > 5) {
|
|
1393
|
+
output.writeln(output.dim(` ... and ${community.members.length - 5} more`));
|
|
1694
1394
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
spinner.stop();
|
|
1705
|
-
message = error_7 instanceof Error ? error_7.message : String(error_7);
|
|
1706
|
-
output.printError("Analysis failed: " + message);
|
|
1707
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
1708
|
-
case 15: return [2 /*return*/];
|
|
1395
|
+
output.writeln();
|
|
1396
|
+
}
|
|
1397
|
+
if (communities.length > 10) {
|
|
1398
|
+
output.writeln(output.dim(`... and ${communities.length - 10} more communities`));
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
if (outputFile) {
|
|
1402
|
+
await writeFile(outputFile, JSON.stringify(result, null, 2));
|
|
1403
|
+
output.printSuccess(`Full results written to ${outputFile}`);
|
|
1709
1404
|
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1405
|
+
return { success: true, data: result };
|
|
1406
|
+
}
|
|
1407
|
+
catch (error) {
|
|
1408
|
+
spinner.stop();
|
|
1409
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1410
|
+
output.printError(`Analysis failed: ${message}`);
|
|
1411
|
+
return { success: false, exitCode: 1 };
|
|
1412
|
+
}
|
|
1413
|
+
},
|
|
1712
1414
|
};
|
|
1713
1415
|
/**
|
|
1714
1416
|
* Build and export dependency graph
|
|
1715
1417
|
*/
|
|
1716
|
-
|
|
1418
|
+
const dependenciesCommand = {
|
|
1717
1419
|
name: 'dependencies',
|
|
1718
1420
|
aliases: ['graph'],
|
|
1719
1421
|
description: 'Build and export full dependency graph',
|
|
@@ -1722,36 +1424,36 @@ var dependenciesCommand = {
|
|
|
1722
1424
|
name: 'output',
|
|
1723
1425
|
short: 'o',
|
|
1724
1426
|
description: 'Output file path',
|
|
1725
|
-
type: 'string'
|
|
1427
|
+
type: 'string',
|
|
1726
1428
|
},
|
|
1727
1429
|
{
|
|
1728
1430
|
name: 'format',
|
|
1729
1431
|
short: 'f',
|
|
1730
1432
|
description: 'Output format (text, json, dot)',
|
|
1731
1433
|
type: 'string',
|
|
1732
|
-
|
|
1733
|
-
choices: ['text', 'json', 'dot']
|
|
1434
|
+
default: 'text',
|
|
1435
|
+
choices: ['text', 'json', 'dot'],
|
|
1734
1436
|
},
|
|
1735
1437
|
{
|
|
1736
1438
|
name: 'include',
|
|
1737
1439
|
short: 'i',
|
|
1738
1440
|
description: 'File extensions to include (comma-separated)',
|
|
1739
1441
|
type: 'string',
|
|
1740
|
-
|
|
1442
|
+
default: '.ts,.tsx,.js,.jsx,.mjs,.cjs',
|
|
1741
1443
|
},
|
|
1742
1444
|
{
|
|
1743
1445
|
name: 'exclude',
|
|
1744
1446
|
short: 'e',
|
|
1745
1447
|
description: 'Patterns to exclude (comma-separated)',
|
|
1746
1448
|
type: 'string',
|
|
1747
|
-
|
|
1449
|
+
default: 'node_modules,dist,build,.git',
|
|
1748
1450
|
},
|
|
1749
1451
|
{
|
|
1750
1452
|
name: 'depth',
|
|
1751
1453
|
short: 'd',
|
|
1752
1454
|
description: 'Maximum directory depth',
|
|
1753
1455
|
type: 'number',
|
|
1754
|
-
|
|
1456
|
+
default: 10,
|
|
1755
1457
|
},
|
|
1756
1458
|
],
|
|
1757
1459
|
examples: [
|
|
@@ -1759,152 +1461,138 @@ var dependenciesCommand = {
|
|
|
1759
1461
|
{ command: 'claude-flow analyze dependencies -f dot -o deps.dot src/', description: 'Export to DOT' },
|
|
1760
1462
|
{ command: 'claude-flow analyze dependencies -i .ts,.tsx src/', description: 'Only TypeScript files' },
|
|
1761
1463
|
],
|
|
1762
|
-
action:
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
metadata: graph_1.metadata,
|
|
1802
|
-
circularDependencies: circularDeps
|
|
1803
|
-
};
|
|
1804
|
-
if (!outputFile) return [3 /*break*/, 5];
|
|
1805
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify(jsonOutput, null, 2))];
|
|
1806
|
-
case 4:
|
|
1807
|
-
_b.sent();
|
|
1808
|
-
output.printSuccess("Graph written to " + outputFile);
|
|
1809
|
-
return [3 /*break*/, 6];
|
|
1810
|
-
case 5:
|
|
1464
|
+
action: async (ctx) => {
|
|
1465
|
+
const targetDir = ctx.args[0] || ctx.cwd;
|
|
1466
|
+
const outputFile = ctx.flags.output;
|
|
1467
|
+
const format = ctx.flags.format || 'text';
|
|
1468
|
+
const include = (ctx.flags.include || '.ts,.tsx,.js,.jsx,.mjs,.cjs').split(',');
|
|
1469
|
+
const exclude = (ctx.flags.exclude || 'node_modules,dist,build,.git').split(',');
|
|
1470
|
+
const maxDepth = ctx.flags.depth || 10;
|
|
1471
|
+
output.printInfo(`Building dependency graph for: ${output.highlight(targetDir)}`);
|
|
1472
|
+
output.writeln();
|
|
1473
|
+
const spinner = output.createSpinner({ text: 'Scanning files...', spinner: 'dots' });
|
|
1474
|
+
spinner.start();
|
|
1475
|
+
try {
|
|
1476
|
+
const analyzer = await getGraphAnalyzer();
|
|
1477
|
+
if (!analyzer) {
|
|
1478
|
+
spinner.stop();
|
|
1479
|
+
output.printError('Graph analyzer module not available');
|
|
1480
|
+
return { success: false, exitCode: 1 };
|
|
1481
|
+
}
|
|
1482
|
+
const graph = await analyzer.buildDependencyGraph(resolve(targetDir), {
|
|
1483
|
+
include,
|
|
1484
|
+
exclude,
|
|
1485
|
+
maxDepth,
|
|
1486
|
+
});
|
|
1487
|
+
spinner.stop();
|
|
1488
|
+
// Detect circular dependencies
|
|
1489
|
+
const circularDeps = analyzer.detectCircularDependencies(graph);
|
|
1490
|
+
// Handle different output formats
|
|
1491
|
+
if (format === 'json') {
|
|
1492
|
+
const jsonOutput = {
|
|
1493
|
+
nodes: Array.from(graph.nodes.values()),
|
|
1494
|
+
edges: graph.edges,
|
|
1495
|
+
metadata: graph.metadata,
|
|
1496
|
+
circularDependencies: circularDeps,
|
|
1497
|
+
};
|
|
1498
|
+
if (outputFile) {
|
|
1499
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
1500
|
+
output.printSuccess(`Graph written to ${outputFile}`);
|
|
1501
|
+
}
|
|
1502
|
+
else {
|
|
1811
1503
|
output.printJson(jsonOutput);
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
_b.sent();
|
|
1832
|
-
output.printSuccess("DOT graph written to " + outputFile);
|
|
1504
|
+
}
|
|
1505
|
+
return { success: true, data: jsonOutput };
|
|
1506
|
+
}
|
|
1507
|
+
if (format === 'dot') {
|
|
1508
|
+
const result = { graph, circularDependencies: circularDeps, statistics: {
|
|
1509
|
+
nodeCount: graph.nodes.size,
|
|
1510
|
+
edgeCount: graph.edges.length,
|
|
1511
|
+
avgDegree: 0,
|
|
1512
|
+
maxDegree: 0,
|
|
1513
|
+
density: 0,
|
|
1514
|
+
componentCount: 0,
|
|
1515
|
+
} };
|
|
1516
|
+
const dotOutput = analyzer.exportToDot(result, {
|
|
1517
|
+
includeLabels: true,
|
|
1518
|
+
highlightCycles: true,
|
|
1519
|
+
});
|
|
1520
|
+
if (outputFile) {
|
|
1521
|
+
await writeFile(outputFile, dotOutput);
|
|
1522
|
+
output.printSuccess(`DOT graph written to ${outputFile}`);
|
|
1833
1523
|
output.writeln(output.dim('Visualize with: dot -Tpng -o deps.png ' + outputFile));
|
|
1834
|
-
|
|
1835
|
-
|
|
1524
|
+
}
|
|
1525
|
+
else {
|
|
1836
1526
|
output.writeln(dotOutput);
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
_b.label = 13;
|
|
1892
|
-
case 13: return [2 /*return*/, { success: true }];
|
|
1893
|
-
case 14:
|
|
1894
|
-
error_8 = _b.sent();
|
|
1895
|
-
spinner.stop();
|
|
1896
|
-
message = error_8 instanceof Error ? error_8.message : String(error_8);
|
|
1897
|
-
output.printError("Analysis failed: " + message);
|
|
1898
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
1899
|
-
case 15: return [2 /*return*/];
|
|
1527
|
+
}
|
|
1528
|
+
return { success: true };
|
|
1529
|
+
}
|
|
1530
|
+
// Text format (default)
|
|
1531
|
+
output.printBox([
|
|
1532
|
+
`Files: ${graph.metadata.totalFiles}`,
|
|
1533
|
+
`Dependencies: ${graph.metadata.totalEdges}`,
|
|
1534
|
+
`Build time: ${graph.metadata.buildTime}ms`,
|
|
1535
|
+
`Root: ${graph.metadata.rootDir}`,
|
|
1536
|
+
].join('\n'), 'Dependency Graph');
|
|
1537
|
+
// Show top files by imports
|
|
1538
|
+
output.writeln();
|
|
1539
|
+
output.writeln(output.bold('Most Connected Files'));
|
|
1540
|
+
output.writeln();
|
|
1541
|
+
const nodesByDegree = Array.from(graph.nodes.values())
|
|
1542
|
+
.map(n => ({
|
|
1543
|
+
...n,
|
|
1544
|
+
degree: graph.edges.filter(e => e.source === n.id || e.target === n.id).length,
|
|
1545
|
+
}))
|
|
1546
|
+
.sort((a, b) => b.degree - a.degree)
|
|
1547
|
+
.slice(0, 10);
|
|
1548
|
+
output.printTable({
|
|
1549
|
+
columns: [
|
|
1550
|
+
{ key: 'path', header: 'File', width: 50 },
|
|
1551
|
+
{ key: 'degree', header: 'Connections', width: 12, align: 'right' },
|
|
1552
|
+
{ key: 'complexity', header: 'Complexity', width: 12, align: 'right' },
|
|
1553
|
+
],
|
|
1554
|
+
data: nodesByDegree.map(n => ({
|
|
1555
|
+
path: n.path.length > 48 ? '...' + n.path.slice(-45) : n.path,
|
|
1556
|
+
degree: n.degree,
|
|
1557
|
+
complexity: n.complexity || 0,
|
|
1558
|
+
})),
|
|
1559
|
+
});
|
|
1560
|
+
// Show circular dependencies
|
|
1561
|
+
if (circularDeps.length > 0) {
|
|
1562
|
+
output.writeln();
|
|
1563
|
+
output.writeln(output.bold(output.warning(`Circular Dependencies: ${circularDeps.length}`)));
|
|
1564
|
+
output.writeln();
|
|
1565
|
+
for (const cycle of circularDeps.slice(0, 3)) {
|
|
1566
|
+
output.writeln(` ${cycle.cycle.join(' -> ')}`);
|
|
1567
|
+
}
|
|
1568
|
+
if (circularDeps.length > 3) {
|
|
1569
|
+
output.writeln(output.dim(` ... and ${circularDeps.length - 3} more`));
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
if (outputFile) {
|
|
1573
|
+
const fullOutput = {
|
|
1574
|
+
nodes: Array.from(graph.nodes.values()),
|
|
1575
|
+
edges: graph.edges,
|
|
1576
|
+
metadata: graph.metadata,
|
|
1577
|
+
circularDependencies: circularDeps,
|
|
1578
|
+
};
|
|
1579
|
+
await writeFile(outputFile, JSON.stringify(fullOutput, null, 2));
|
|
1580
|
+
output.printSuccess(`Full results written to ${outputFile}`);
|
|
1900
1581
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1582
|
+
return { success: true };
|
|
1583
|
+
}
|
|
1584
|
+
catch (error) {
|
|
1585
|
+
spinner.stop();
|
|
1586
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1587
|
+
output.printError(`Analysis failed: ${message}`);
|
|
1588
|
+
return { success: false, exitCode: 1 };
|
|
1589
|
+
}
|
|
1590
|
+
},
|
|
1903
1591
|
};
|
|
1904
1592
|
/**
|
|
1905
1593
|
* Detect circular dependencies
|
|
1906
1594
|
*/
|
|
1907
|
-
|
|
1595
|
+
const circularCommand = {
|
|
1908
1596
|
name: 'circular',
|
|
1909
1597
|
aliases: ['cycles'],
|
|
1910
1598
|
description: 'Detect circular dependencies in codebase',
|
|
@@ -1913,127 +1601,111 @@ var circularCommand = {
|
|
|
1913
1601
|
name: 'output',
|
|
1914
1602
|
short: 'o',
|
|
1915
1603
|
description: 'Output file path',
|
|
1916
|
-
type: 'string'
|
|
1604
|
+
type: 'string',
|
|
1917
1605
|
},
|
|
1918
1606
|
{
|
|
1919
1607
|
name: 'format',
|
|
1920
1608
|
short: 'f',
|
|
1921
1609
|
description: 'Output format (text, json)',
|
|
1922
1610
|
type: 'string',
|
|
1923
|
-
|
|
1924
|
-
choices: ['text', 'json']
|
|
1611
|
+
default: 'text',
|
|
1612
|
+
choices: ['text', 'json'],
|
|
1925
1613
|
},
|
|
1926
1614
|
{
|
|
1927
1615
|
name: 'severity',
|
|
1928
1616
|
short: 's',
|
|
1929
1617
|
description: 'Minimum severity to show (low, medium, high)',
|
|
1930
1618
|
type: 'string',
|
|
1931
|
-
|
|
1932
|
-
choices: ['low', 'medium', 'high']
|
|
1619
|
+
default: 'low',
|
|
1620
|
+
choices: ['low', 'medium', 'high'],
|
|
1933
1621
|
},
|
|
1934
1622
|
],
|
|
1935
1623
|
examples: [
|
|
1936
1624
|
{ command: 'claude-flow analyze circular src/', description: 'Find circular dependencies' },
|
|
1937
1625
|
{ command: 'claude-flow analyze circular -s high src/', description: 'Only high severity cycles' },
|
|
1938
1626
|
],
|
|
1939
|
-
action:
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
minLevel_1 = severityOrder_1[minSeverity] || 0;
|
|
1970
|
-
filtered = cycles.filter(function (c) { return severityOrder_1[c.severity] >= minLevel_1; });
|
|
1971
|
-
if (!(format === 'json')) return [3 /*break*/, 7];
|
|
1972
|
-
jsonOutput = { cycles: filtered, total: cycles.length, filtered: filtered.length };
|
|
1973
|
-
if (!outputFile) return [3 /*break*/, 5];
|
|
1974
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify(jsonOutput, null, 2))];
|
|
1975
|
-
case 4:
|
|
1976
|
-
_e.sent();
|
|
1977
|
-
output.printSuccess("Results written to " + outputFile);
|
|
1978
|
-
return [3 /*break*/, 6];
|
|
1979
|
-
case 5:
|
|
1627
|
+
action: async (ctx) => {
|
|
1628
|
+
const targetDir = ctx.args[0] || ctx.cwd;
|
|
1629
|
+
const outputFile = ctx.flags.output;
|
|
1630
|
+
const format = ctx.flags.format || 'text';
|
|
1631
|
+
const minSeverity = ctx.flags.severity || 'low';
|
|
1632
|
+
output.printInfo(`Detecting circular dependencies in: ${output.highlight(targetDir)}`);
|
|
1633
|
+
output.writeln();
|
|
1634
|
+
const spinner = output.createSpinner({ text: 'Analyzing dependencies...', spinner: 'dots' });
|
|
1635
|
+
spinner.start();
|
|
1636
|
+
try {
|
|
1637
|
+
const analyzer = await getGraphAnalyzer();
|
|
1638
|
+
if (!analyzer) {
|
|
1639
|
+
spinner.stop();
|
|
1640
|
+
output.printError('Graph analyzer module not available');
|
|
1641
|
+
return { success: false, exitCode: 1 };
|
|
1642
|
+
}
|
|
1643
|
+
const graph = await analyzer.buildDependencyGraph(resolve(targetDir));
|
|
1644
|
+
const cycles = analyzer.detectCircularDependencies(graph);
|
|
1645
|
+
spinner.stop();
|
|
1646
|
+
// Filter by severity
|
|
1647
|
+
const severityOrder = { low: 0, medium: 1, high: 2 };
|
|
1648
|
+
const minLevel = severityOrder[minSeverity] || 0;
|
|
1649
|
+
const filtered = cycles.filter(c => severityOrder[c.severity] >= minLevel);
|
|
1650
|
+
if (format === 'json') {
|
|
1651
|
+
const jsonOutput = { cycles: filtered, total: cycles.length, filtered: filtered.length };
|
|
1652
|
+
if (outputFile) {
|
|
1653
|
+
await writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
|
|
1654
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
1655
|
+
}
|
|
1656
|
+
else {
|
|
1980
1657
|
output.printJson(jsonOutput);
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1658
|
+
}
|
|
1659
|
+
return { success: true, data: jsonOutput };
|
|
1660
|
+
}
|
|
1661
|
+
// Text format
|
|
1662
|
+
if (filtered.length === 0) {
|
|
1663
|
+
output.printSuccess('No circular dependencies found!');
|
|
1664
|
+
return { success: true };
|
|
1665
|
+
}
|
|
1666
|
+
output.printBox([
|
|
1667
|
+
`Total cycles: ${cycles.length}`,
|
|
1668
|
+
`Shown (${minSeverity}+): ${filtered.length}`,
|
|
1669
|
+
`High severity: ${cycles.filter(c => c.severity === 'high').length}`,
|
|
1670
|
+
`Medium severity: ${cycles.filter(c => c.severity === 'medium').length}`,
|
|
1671
|
+
`Low severity: ${cycles.filter(c => c.severity === 'low').length}`,
|
|
1672
|
+
].join('\n'), 'Circular Dependencies');
|
|
1673
|
+
output.writeln();
|
|
1674
|
+
// Group by severity
|
|
1675
|
+
const grouped = {
|
|
1676
|
+
high: filtered.filter(c => c.severity === 'high'),
|
|
1677
|
+
medium: filtered.filter(c => c.severity === 'medium'),
|
|
1678
|
+
low: filtered.filter(c => c.severity === 'low'),
|
|
1679
|
+
};
|
|
1680
|
+
for (const [severity, items] of Object.entries(grouped)) {
|
|
1681
|
+
if (items.length === 0)
|
|
1682
|
+
continue;
|
|
1683
|
+
const color = severity === 'high' ? output.error : severity === 'medium' ? output.warning : output.dim;
|
|
1684
|
+
output.writeln(color(output.bold(`${severity.toUpperCase()} SEVERITY (${items.length})`)));
|
|
1685
|
+
output.writeln();
|
|
1686
|
+
for (const cycle of items.slice(0, 5)) {
|
|
1687
|
+
output.writeln(` ${cycle.cycle.join(' -> ')}`);
|
|
1688
|
+
output.writeln(output.dim(` Fix: ${cycle.suggestion}`));
|
|
1996
1689
|
output.writeln();
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
color = severity === 'high' ? output.error : severity === 'medium' ? output.warning : output.dim;
|
|
2007
|
-
output.writeln(color(output.bold(severity.toUpperCase() + " SEVERITY (" + items.length + ")")));
|
|
2008
|
-
output.writeln();
|
|
2009
|
-
for (_c = 0, _d = items.slice(0, 5); _c < _d.length; _c++) {
|
|
2010
|
-
cycle = _d[_c];
|
|
2011
|
-
output.writeln(" " + cycle.cycle.join(' -> '));
|
|
2012
|
-
output.writeln(output.dim(" Fix: " + cycle.suggestion));
|
|
2013
|
-
output.writeln();
|
|
2014
|
-
}
|
|
2015
|
-
if (items.length > 5) {
|
|
2016
|
-
output.writeln(output.dim(" ... and " + (items.length - 5) + " more " + severity + " cycles"));
|
|
2017
|
-
output.writeln();
|
|
2018
|
-
}
|
|
2019
|
-
}
|
|
2020
|
-
if (!outputFile) return [3 /*break*/, 9];
|
|
2021
|
-
return [4 /*yield*/, writeFile(outputFile, JSON.stringify({ cycles: filtered }, null, 2))];
|
|
2022
|
-
case 8:
|
|
2023
|
-
_e.sent();
|
|
2024
|
-
output.printSuccess("Results written to " + outputFile);
|
|
2025
|
-
_e.label = 9;
|
|
2026
|
-
case 9: return [2 /*return*/, { success: true, data: { cycles: filtered } }];
|
|
2027
|
-
case 10:
|
|
2028
|
-
error_9 = _e.sent();
|
|
2029
|
-
spinner.stop();
|
|
2030
|
-
message = error_9 instanceof Error ? error_9.message : String(error_9);
|
|
2031
|
-
output.printError("Analysis failed: " + message);
|
|
2032
|
-
return [2 /*return*/, { success: false, exitCode: 1 }];
|
|
2033
|
-
case 11: return [2 /*return*/];
|
|
1690
|
+
}
|
|
1691
|
+
if (items.length > 5) {
|
|
1692
|
+
output.writeln(output.dim(` ... and ${items.length - 5} more ${severity} cycles`));
|
|
1693
|
+
output.writeln();
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (outputFile) {
|
|
1697
|
+
await writeFile(outputFile, JSON.stringify({ cycles: filtered }, null, 2));
|
|
1698
|
+
output.printSuccess(`Results written to ${outputFile}`);
|
|
2034
1699
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
1700
|
+
return { success: true, data: { cycles: filtered } };
|
|
1701
|
+
}
|
|
1702
|
+
catch (error) {
|
|
1703
|
+
spinner.stop();
|
|
1704
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1705
|
+
output.printError(`Analysis failed: ${message}`);
|
|
1706
|
+
return { success: false, exitCode: 1 };
|
|
1707
|
+
}
|
|
1708
|
+
},
|
|
2037
1709
|
};
|
|
2038
1710
|
// Helper functions
|
|
2039
1711
|
function getRiskDisplay(risk) {
|
|
@@ -2065,7 +1737,7 @@ function getStatusDisplay(status) {
|
|
|
2065
1737
|
}
|
|
2066
1738
|
}
|
|
2067
1739
|
// Main analyze command
|
|
2068
|
-
export
|
|
1740
|
+
export const analyzeCommand = {
|
|
2069
1741
|
name: 'analyze',
|
|
2070
1742
|
description: 'Code analysis, diff classification, graph boundaries, and change risk assessment',
|
|
2071
1743
|
aliases: ['an'],
|
|
@@ -2088,7 +1760,7 @@ export var analyzeCommand = {
|
|
|
2088
1760
|
short: 'f',
|
|
2089
1761
|
description: 'Output format: text, json, table',
|
|
2090
1762
|
type: 'string',
|
|
2091
|
-
|
|
1763
|
+
default: 'text',
|
|
2092
1764
|
},
|
|
2093
1765
|
],
|
|
2094
1766
|
examples: [
|
|
@@ -2103,51 +1775,49 @@ export var analyzeCommand = {
|
|
|
2103
1775
|
{ command: 'claude-flow analyze circular src/', description: 'Find circular dependencies' },
|
|
2104
1776
|
{ command: 'claude-flow analyze deps --security', description: 'Check dependency vulnerabilities' },
|
|
2105
1777
|
],
|
|
2106
|
-
action:
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
});
|
|
2150
|
-
}); }
|
|
1778
|
+
action: async (ctx) => {
|
|
1779
|
+
// If no subcommand, show help
|
|
1780
|
+
output.writeln();
|
|
1781
|
+
output.writeln(output.bold('Analyze Commands'));
|
|
1782
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
1783
|
+
output.writeln();
|
|
1784
|
+
output.writeln(output.bold('Available subcommands:'));
|
|
1785
|
+
output.writeln();
|
|
1786
|
+
output.writeln(` ${output.highlight('diff')} Analyze git diff for change risk and classification`);
|
|
1787
|
+
output.writeln(` ${output.highlight('code')} Static code analysis and quality assessment`);
|
|
1788
|
+
output.writeln(` ${output.highlight('deps')} Analyze project dependencies`);
|
|
1789
|
+
output.writeln(` ${output.highlight('ast')} AST analysis with symbol extraction and complexity`);
|
|
1790
|
+
output.writeln(` ${output.highlight('complexity')} Analyze cyclomatic and cognitive complexity`);
|
|
1791
|
+
output.writeln(` ${output.highlight('symbols')} Extract functions, classes, and types`);
|
|
1792
|
+
output.writeln(` ${output.highlight('imports')} Analyze import dependencies`);
|
|
1793
|
+
output.writeln(` ${output.highlight('boundaries')} Find code boundaries using MinCut algorithm`);
|
|
1794
|
+
output.writeln(` ${output.highlight('modules')} Detect module communities using Louvain algorithm`);
|
|
1795
|
+
output.writeln(` ${output.highlight('dependencies')} Build and export full dependency graph`);
|
|
1796
|
+
output.writeln(` ${output.highlight('circular')} Detect circular dependencies in codebase`);
|
|
1797
|
+
output.writeln();
|
|
1798
|
+
output.writeln(output.bold('AST Analysis Examples:'));
|
|
1799
|
+
output.writeln();
|
|
1800
|
+
output.writeln(` ${output.dim('claude-flow analyze ast src/')} # Full AST analysis`);
|
|
1801
|
+
output.writeln(` ${output.dim('claude-flow analyze ast src/index.ts -c')} # Include complexity`);
|
|
1802
|
+
output.writeln(` ${output.dim('claude-flow analyze complexity src/ -t 15')} # Flag high complexity`);
|
|
1803
|
+
output.writeln(` ${output.dim('claude-flow analyze symbols src/ --type fn')} # Extract functions`);
|
|
1804
|
+
output.writeln(` ${output.dim('claude-flow analyze imports src/ --external')} # Only npm imports`);
|
|
1805
|
+
output.writeln();
|
|
1806
|
+
output.writeln(output.bold('Graph Analysis Examples:'));
|
|
1807
|
+
output.writeln();
|
|
1808
|
+
output.writeln(` ${output.dim('claude-flow analyze boundaries src/')} # Find natural code boundaries`);
|
|
1809
|
+
output.writeln(` ${output.dim('claude-flow analyze modules src/')} # Detect module communities`);
|
|
1810
|
+
output.writeln(` ${output.dim('claude-flow analyze dependencies -f dot src/')} # Export to DOT format`);
|
|
1811
|
+
output.writeln(` ${output.dim('claude-flow analyze circular src/')} # Find circular deps`);
|
|
1812
|
+
output.writeln();
|
|
1813
|
+
output.writeln(output.bold('Diff Analysis Examples:'));
|
|
1814
|
+
output.writeln();
|
|
1815
|
+
output.writeln(` ${output.dim('claude-flow analyze diff --risk')} # Risk assessment`);
|
|
1816
|
+
output.writeln(` ${output.dim('claude-flow analyze diff HEAD~1 --classify')} # Classify changes`);
|
|
1817
|
+
output.writeln(` ${output.dim('claude-flow analyze diff main..feature')} # Compare branches`);
|
|
1818
|
+
output.writeln();
|
|
1819
|
+
return { success: true };
|
|
1820
|
+
},
|
|
2151
1821
|
};
|
|
2152
1822
|
export default analyzeCommand;
|
|
2153
1823
|
//# sourceMappingURL=analyze.js.map
|