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
|
@@ -11,62 +11,6 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module @claude-flow/cli/ruvector/graph-analyzer
|
|
13
13
|
*/
|
|
14
|
-
var __assign = (this && this.__assign) || function () {
|
|
15
|
-
__assign = Object.assign || function(t) {
|
|
16
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
17
|
-
s = arguments[i];
|
|
18
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
19
|
-
t[p] = s[p];
|
|
20
|
-
}
|
|
21
|
-
return t;
|
|
22
|
-
};
|
|
23
|
-
return __assign.apply(this, arguments);
|
|
24
|
-
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
35
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
36
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
37
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
38
|
-
function step(op) {
|
|
39
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
40
|
-
while (_) try {
|
|
41
|
-
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;
|
|
42
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
43
|
-
switch (op[0]) {
|
|
44
|
-
case 0: case 1: t = op; break;
|
|
45
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
46
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
47
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
48
|
-
default:
|
|
49
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
50
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
51
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
52
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
53
|
-
if (t[2]) _.ops.pop();
|
|
54
|
-
_.trys.pop(); continue;
|
|
55
|
-
}
|
|
56
|
-
op = body.call(thisArg, _);
|
|
57
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
58
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
62
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
63
|
-
if (ar || !(i in from)) {
|
|
64
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
65
|
-
ar[i] = from[i];
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
69
|
-
};
|
|
70
14
|
import { readFile, readdir, stat } from 'fs/promises';
|
|
71
15
|
import { join, relative, extname, dirname, basename } from 'path';
|
|
72
16
|
// ============================================================================
|
|
@@ -75,13 +19,13 @@ import { join, relative, extname, dirname, basename } from 'path';
|
|
|
75
19
|
/**
|
|
76
20
|
* Cache for dependency graphs (5 minute TTL)
|
|
77
21
|
*/
|
|
78
|
-
|
|
79
|
-
|
|
22
|
+
const graphCache = new Map();
|
|
23
|
+
const GRAPH_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
80
24
|
/**
|
|
81
25
|
* Cache for analysis results (2 minute TTL)
|
|
82
26
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
27
|
+
const analysisResultCache = new Map();
|
|
28
|
+
const ANALYSIS_CACHE_TTL_MS = 2 * 60 * 1000; // 2 minutes
|
|
85
29
|
/**
|
|
86
30
|
* Clear all graph caches
|
|
87
31
|
*/
|
|
@@ -95,64 +39,53 @@ export function clearGraphCaches() {
|
|
|
95
39
|
export function getGraphCacheStats() {
|
|
96
40
|
return {
|
|
97
41
|
graphCacheSize: graphCache.size,
|
|
98
|
-
analysisCacheSize: analysisResultCache.size
|
|
42
|
+
analysisCacheSize: analysisResultCache.size,
|
|
99
43
|
};
|
|
100
44
|
}
|
|
101
|
-
|
|
102
|
-
|
|
45
|
+
let ruVectorGraph = null;
|
|
46
|
+
let ruVectorLoadAttempted = false;
|
|
103
47
|
/**
|
|
104
48
|
* Attempt to load ruvector graph algorithms
|
|
105
49
|
*/
|
|
106
|
-
function loadRuVector() {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
wasm = _c.sent();
|
|
139
|
-
if (wasm && wasm.GraphAnalyzer) {
|
|
140
|
-
analyzer_1 = new wasm.GraphAnalyzer();
|
|
141
|
-
ruVectorGraph = {
|
|
142
|
-
mincut: function (nodes, edges) { return analyzer_1.mincut(nodes, edges); },
|
|
143
|
-
louvain: function (nodes, edges) { return analyzer_1.louvain(nodes, edges); }
|
|
144
|
-
};
|
|
145
|
-
return [2 /*return*/, ruVectorGraph];
|
|
146
|
-
}
|
|
147
|
-
return [3 /*break*/, 7];
|
|
148
|
-
case 6:
|
|
149
|
-
_b = _c.sent();
|
|
150
|
-
return [3 /*break*/, 7];
|
|
151
|
-
case 7: return [3 /*break*/, 8];
|
|
152
|
-
case 8: return [2 /*return*/, null];
|
|
50
|
+
async function loadRuVector() {
|
|
51
|
+
if (ruVectorLoadAttempted)
|
|
52
|
+
return ruVectorGraph;
|
|
53
|
+
ruVectorLoadAttempted = true;
|
|
54
|
+
// Use dynamic module names to bypass TypeScript static analysis
|
|
55
|
+
// These modules are optional and may not be installed
|
|
56
|
+
const ruvectorModule = 'ruvector';
|
|
57
|
+
const wasmModule = '@ruvector/wasm';
|
|
58
|
+
try {
|
|
59
|
+
// Try to load ruvector's graph module
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
+
const ruvector = await import(/* webpackIgnore: true */ ruvectorModule).catch(() => null);
|
|
62
|
+
if (ruvector && typeof ruvector.hooks_graph_mincut === 'function' && typeof ruvector.hooks_graph_cluster === 'function') {
|
|
63
|
+
ruVectorGraph = {
|
|
64
|
+
mincut: (nodes, edges) => ruvector.hooks_graph_mincut(nodes, edges),
|
|
65
|
+
louvain: (nodes, edges) => ruvector.hooks_graph_cluster(nodes, edges),
|
|
66
|
+
};
|
|
67
|
+
return ruVectorGraph;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Try alternative import paths
|
|
72
|
+
try {
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
+
const wasm = await import(/* webpackIgnore: true */ wasmModule).catch(() => null);
|
|
75
|
+
if (wasm && wasm.GraphAnalyzer) {
|
|
76
|
+
const analyzer = new wasm.GraphAnalyzer();
|
|
77
|
+
ruVectorGraph = {
|
|
78
|
+
mincut: (nodes, edges) => analyzer.mincut(nodes, edges),
|
|
79
|
+
louvain: (nodes, edges) => analyzer.louvain(nodes, edges),
|
|
80
|
+
};
|
|
81
|
+
return ruVectorGraph;
|
|
153
82
|
}
|
|
154
|
-
}
|
|
155
|
-
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Fallback will be used
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
156
89
|
}
|
|
157
90
|
// ============================================================================
|
|
158
91
|
// Import/Require Parser
|
|
@@ -161,30 +94,30 @@ function loadRuVector() {
|
|
|
161
94
|
* Extract imports from TypeScript/JavaScript file
|
|
162
95
|
*/
|
|
163
96
|
function extractImports(content, _filePath) {
|
|
164
|
-
|
|
97
|
+
const imports = [];
|
|
165
98
|
// ES6 import statements
|
|
166
|
-
|
|
167
|
-
|
|
99
|
+
const esImportRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s*,?\s*)*\s*from\s*['"]([^'"]+)['"]/g;
|
|
100
|
+
let match;
|
|
168
101
|
while ((match = esImportRegex.exec(content)) !== null) {
|
|
169
102
|
imports.push({ path: match[1], type: 'import' });
|
|
170
103
|
}
|
|
171
104
|
// Side-effect imports: import 'module'
|
|
172
|
-
|
|
105
|
+
const sideEffectRegex = /import\s+['"]([^'"]+)['"]/g;
|
|
173
106
|
while ((match = sideEffectRegex.exec(content)) !== null) {
|
|
174
107
|
imports.push({ path: match[1], type: 'import' });
|
|
175
108
|
}
|
|
176
109
|
// CommonJS require
|
|
177
|
-
|
|
110
|
+
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
178
111
|
while ((match = requireRegex.exec(content)) !== null) {
|
|
179
112
|
imports.push({ path: match[1], type: 'require' });
|
|
180
113
|
}
|
|
181
114
|
// Dynamic imports
|
|
182
|
-
|
|
115
|
+
const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
183
116
|
while ((match = dynamicImportRegex.exec(content)) !== null) {
|
|
184
117
|
imports.push({ path: match[1], type: 'dynamic' });
|
|
185
118
|
}
|
|
186
119
|
// Re-exports: export * from 'module'
|
|
187
|
-
|
|
120
|
+
const reExportRegex = /export\s+(?:\*|\{[^}]*\})\s+from\s*['"]([^'"]+)['"]/g;
|
|
188
121
|
while ((match = reExportRegex.exec(content)) !== null) {
|
|
189
122
|
imports.push({ path: match[1], type: 're-export' });
|
|
190
123
|
}
|
|
@@ -194,18 +127,18 @@ function extractImports(content, _filePath) {
|
|
|
194
127
|
* Extract exports from TypeScript/JavaScript file
|
|
195
128
|
*/
|
|
196
129
|
function extractExports(content) {
|
|
197
|
-
|
|
130
|
+
const exports = [];
|
|
198
131
|
// Named exports
|
|
199
|
-
|
|
200
|
-
|
|
132
|
+
const namedExportRegex = /export\s+(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/g;
|
|
133
|
+
let match;
|
|
201
134
|
while ((match = namedExportRegex.exec(content)) !== null) {
|
|
202
135
|
exports.push(match[1]);
|
|
203
136
|
}
|
|
204
137
|
// Export list: export { a, b, c }
|
|
205
|
-
|
|
138
|
+
const exportListRegex = /export\s+\{([^}]+)\}/g;
|
|
206
139
|
while ((match = exportListRegex.exec(content)) !== null) {
|
|
207
|
-
|
|
208
|
-
exports.push
|
|
140
|
+
const names = match[1].split(',').map(n => n.trim().split(/\s+as\s+/)[0].trim());
|
|
141
|
+
exports.push(...names.filter(n => n));
|
|
209
142
|
}
|
|
210
143
|
// Default export
|
|
211
144
|
if (/export\s+default/.test(content)) {
|
|
@@ -221,8 +154,8 @@ function resolveImportPath(importPath, fromFile, rootDir) {
|
|
|
221
154
|
if (!importPath.startsWith('.') && !importPath.startsWith('/')) {
|
|
222
155
|
return null;
|
|
223
156
|
}
|
|
224
|
-
|
|
225
|
-
|
|
157
|
+
const fromDir = dirname(fromFile);
|
|
158
|
+
let resolved;
|
|
226
159
|
if (importPath.startsWith('/')) {
|
|
227
160
|
resolved = join(rootDir, importPath);
|
|
228
161
|
}
|
|
@@ -230,13 +163,12 @@ function resolveImportPath(importPath, fromFile, rootDir) {
|
|
|
230
163
|
resolved = join(fromDir, importPath);
|
|
231
164
|
}
|
|
232
165
|
// Handle extension-less imports
|
|
233
|
-
|
|
166
|
+
const ext = extname(resolved);
|
|
234
167
|
if (!ext) {
|
|
235
168
|
// Try common extensions
|
|
236
|
-
|
|
237
|
-
for (
|
|
238
|
-
|
|
239
|
-
var tryPath = resolved + tryExt;
|
|
169
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
170
|
+
for (const tryExt of extensions) {
|
|
171
|
+
const tryPath = resolved + tryExt;
|
|
240
172
|
return tryPath; // Return normalized, existence check done later
|
|
241
173
|
}
|
|
242
174
|
// Could be index file
|
|
@@ -250,209 +182,161 @@ function resolveImportPath(importPath, fromFile, rootDir) {
|
|
|
250
182
|
/**
|
|
251
183
|
* Build dependency graph from source directory (with caching)
|
|
252
184
|
*/
|
|
253
|
-
export function buildDependencyGraph(rootDir, options) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
function shouldExclude(path) {
|
|
261
|
-
var name = basename(path);
|
|
262
|
-
return exclude.some(function (pattern) {
|
|
263
|
-
if (pattern.includes('*')) {
|
|
264
|
-
var regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
|
|
265
|
-
return regex.test(name);
|
|
266
|
-
}
|
|
267
|
-
return name === pattern || path.includes("/" + pattern + "/");
|
|
268
|
-
});
|
|
185
|
+
export async function buildDependencyGraph(rootDir, options = {}) {
|
|
186
|
+
// Check cache first
|
|
187
|
+
const cacheKey = `${rootDir}:${JSON.stringify(options)}`;
|
|
188
|
+
if (!options.skipCache) {
|
|
189
|
+
const cached = graphCache.get(cacheKey);
|
|
190
|
+
if (cached && Date.now() - cached.timestamp < GRAPH_CACHE_TTL_MS) {
|
|
191
|
+
return cached.graph;
|
|
269
192
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
_i++;
|
|
311
|
-
return [3 /*break*/, 3];
|
|
312
|
-
case 8: return [3 /*break*/, 10];
|
|
313
|
-
case 9:
|
|
314
|
-
_a = _b.sent();
|
|
315
|
-
return [3 /*break*/, 10];
|
|
316
|
-
case 10: return [2 /*return*/];
|
|
193
|
+
}
|
|
194
|
+
const startTime = Date.now();
|
|
195
|
+
const nodes = new Map();
|
|
196
|
+
const edges = [];
|
|
197
|
+
const include = options.include || ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
198
|
+
const exclude = options.exclude || ['node_modules', 'dist', 'build', '.git', '__tests__', '*.test.*', '*.spec.*'];
|
|
199
|
+
const maxDepth = options.maxDepth ?? 10;
|
|
200
|
+
/**
|
|
201
|
+
* Check if path should be excluded
|
|
202
|
+
*/
|
|
203
|
+
function shouldExclude(path) {
|
|
204
|
+
const name = basename(path);
|
|
205
|
+
return exclude.some(pattern => {
|
|
206
|
+
if (pattern.includes('*')) {
|
|
207
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
|
|
208
|
+
return regex.test(name);
|
|
209
|
+
}
|
|
210
|
+
return name === pattern || path.includes(`/${pattern}/`);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Recursively scan directory for source files
|
|
215
|
+
*/
|
|
216
|
+
async function scanDir(dir, depth) {
|
|
217
|
+
if (depth > maxDepth)
|
|
218
|
+
return;
|
|
219
|
+
try {
|
|
220
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
221
|
+
for (const entry of entries) {
|
|
222
|
+
const fullPath = join(dir, entry.name);
|
|
223
|
+
const relPath = relative(rootDir, fullPath);
|
|
224
|
+
if (shouldExclude(fullPath))
|
|
225
|
+
continue;
|
|
226
|
+
if (entry.isDirectory()) {
|
|
227
|
+
await scanDir(fullPath, depth + 1);
|
|
228
|
+
}
|
|
229
|
+
else if (entry.isFile()) {
|
|
230
|
+
const ext = extname(entry.name);
|
|
231
|
+
if (include.includes(ext)) {
|
|
232
|
+
await processFile(fullPath, relPath);
|
|
317
233
|
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
320
236
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
*/
|
|
324
|
-
function processFile(fullPath, relPath) {
|
|
325
|
-
return __awaiter(this, void 0, Promise, function () {
|
|
326
|
-
var content, fileStats, imports, exportsList, node, _i, imports_1, imp, resolved, targetRel, _a;
|
|
327
|
-
return __generator(this, function (_b) {
|
|
328
|
-
switch (_b.label) {
|
|
329
|
-
case 0:
|
|
330
|
-
_b.trys.push([0, 3, , 4]);
|
|
331
|
-
return [4 /*yield*/, readFile(fullPath, 'utf-8')];
|
|
332
|
-
case 1:
|
|
333
|
-
content = _b.sent();
|
|
334
|
-
return [4 /*yield*/, stat(fullPath)];
|
|
335
|
-
case 2:
|
|
336
|
-
fileStats = _b.sent();
|
|
337
|
-
imports = extractImports(content, fullPath);
|
|
338
|
-
exportsList = extractExports(content);
|
|
339
|
-
node = {
|
|
340
|
-
id: relPath,
|
|
341
|
-
path: relPath,
|
|
342
|
-
name: basename(relPath, extname(relPath)),
|
|
343
|
-
type: 'file',
|
|
344
|
-
imports: imports.map(function (i) { return i.path; }),
|
|
345
|
-
exports: exportsList,
|
|
346
|
-
size: fileStats.size,
|
|
347
|
-
complexity: estimateComplexity(content)
|
|
348
|
-
};
|
|
349
|
-
nodes.set(relPath, node);
|
|
350
|
-
// Create edges for imports
|
|
351
|
-
for (_i = 0, imports_1 = imports; _i < imports_1.length; _i++) {
|
|
352
|
-
imp = imports_1[_i];
|
|
353
|
-
resolved = resolveImportPath(imp.path, fullPath, rootDir);
|
|
354
|
-
if (resolved) {
|
|
355
|
-
targetRel = relative(rootDir, resolved);
|
|
356
|
-
edges.push({
|
|
357
|
-
source: relPath,
|
|
358
|
-
target: targetRel,
|
|
359
|
-
type: imp.type,
|
|
360
|
-
weight: imp.type === 're-export' ? 2 : 1
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
return [3 /*break*/, 4];
|
|
365
|
-
case 3:
|
|
366
|
-
_a = _b.sent();
|
|
367
|
-
return [3 /*break*/, 4];
|
|
368
|
-
case 4: return [2 /*return*/];
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
});
|
|
237
|
+
catch {
|
|
238
|
+
// Directory not readable, skip
|
|
372
239
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
// Try index files
|
|
409
|
-
if (nodes.has(join(baseTarget, 'index' + ext))) {
|
|
410
|
-
targetKey = join(baseTarget, 'index' + ext);
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
if (nodes.has(targetKey)) {
|
|
416
|
-
normalizedEdges.push(__assign(__assign({}, edge), { target: targetKey }));
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
graph = {
|
|
420
|
-
nodes: nodes,
|
|
421
|
-
edges: normalizedEdges,
|
|
422
|
-
metadata: {
|
|
423
|
-
rootDir: rootDir,
|
|
424
|
-
totalFiles: nodes.size,
|
|
425
|
-
totalEdges: normalizedEdges.length,
|
|
426
|
-
buildTime: Date.now() - startTime
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
// Cache the result
|
|
430
|
-
graphCache.set(cacheKey, { graph: graph, timestamp: Date.now() });
|
|
431
|
-
return [2 /*return*/, graph];
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Process a single source file
|
|
243
|
+
*/
|
|
244
|
+
async function processFile(fullPath, relPath) {
|
|
245
|
+
try {
|
|
246
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
247
|
+
const fileStats = await stat(fullPath);
|
|
248
|
+
const imports = extractImports(content, fullPath);
|
|
249
|
+
const exportsList = extractExports(content);
|
|
250
|
+
// Create node
|
|
251
|
+
const node = {
|
|
252
|
+
id: relPath,
|
|
253
|
+
path: relPath,
|
|
254
|
+
name: basename(relPath, extname(relPath)),
|
|
255
|
+
type: 'file',
|
|
256
|
+
imports: imports.map(i => i.path),
|
|
257
|
+
exports: exportsList,
|
|
258
|
+
size: fileStats.size,
|
|
259
|
+
complexity: estimateComplexity(content),
|
|
260
|
+
};
|
|
261
|
+
nodes.set(relPath, node);
|
|
262
|
+
// Create edges for imports
|
|
263
|
+
for (const imp of imports) {
|
|
264
|
+
const resolved = resolveImportPath(imp.path, fullPath, rootDir);
|
|
265
|
+
if (resolved) {
|
|
266
|
+
const targetRel = relative(rootDir, resolved);
|
|
267
|
+
edges.push({
|
|
268
|
+
source: relPath,
|
|
269
|
+
target: targetRel,
|
|
270
|
+
type: imp.type,
|
|
271
|
+
weight: imp.type === 're-export' ? 2 : 1,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
432
274
|
}
|
|
433
|
-
}
|
|
434
|
-
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// File not readable, skip
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Build the graph
|
|
281
|
+
await scanDir(rootDir, 0);
|
|
282
|
+
// Normalize edges - ensure targets exist (with extension variations)
|
|
283
|
+
const normalizedEdges = [];
|
|
284
|
+
for (const edge of edges) {
|
|
285
|
+
// Try to find matching node
|
|
286
|
+
let targetKey = edge.target;
|
|
287
|
+
if (!nodes.has(targetKey)) {
|
|
288
|
+
// Try with different extensions
|
|
289
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
290
|
+
const baseTarget = targetKey.replace(/\.[^.]+$/, '');
|
|
291
|
+
for (const ext of extensions) {
|
|
292
|
+
if (nodes.has(baseTarget + ext)) {
|
|
293
|
+
targetKey = baseTarget + ext;
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
// Try index files
|
|
297
|
+
if (nodes.has(join(baseTarget, 'index' + ext))) {
|
|
298
|
+
targetKey = join(baseTarget, 'index' + ext);
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (nodes.has(targetKey)) {
|
|
304
|
+
normalizedEdges.push({ ...edge, target: targetKey });
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const graph = {
|
|
308
|
+
nodes,
|
|
309
|
+
edges: normalizedEdges,
|
|
310
|
+
metadata: {
|
|
311
|
+
rootDir,
|
|
312
|
+
totalFiles: nodes.size,
|
|
313
|
+
totalEdges: normalizedEdges.length,
|
|
314
|
+
buildTime: Date.now() - startTime,
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
// Cache the result
|
|
318
|
+
graphCache.set(cacheKey, { graph, timestamp: Date.now() });
|
|
319
|
+
return graph;
|
|
435
320
|
}
|
|
436
321
|
/**
|
|
437
322
|
* Estimate cyclomatic complexity from code
|
|
438
323
|
*/
|
|
439
324
|
function estimateComplexity(content) {
|
|
440
|
-
|
|
325
|
+
let complexity = 1;
|
|
441
326
|
// Count branching statements
|
|
442
|
-
|
|
327
|
+
const patterns = [
|
|
443
328
|
/\bif\s*\(/g,
|
|
444
329
|
/\belse\s+if\s*\(/g,
|
|
445
330
|
/\bfor\s*\(/g,
|
|
446
331
|
/\bwhile\s*\(/g,
|
|
447
332
|
/\bcase\s+/g,
|
|
448
333
|
/\bcatch\s*\(/g,
|
|
449
|
-
/\?\s*[^:]+:/g,
|
|
334
|
+
/\?\s*[^:]+:/g, // Ternary operator
|
|
450
335
|
/&&/g,
|
|
451
336
|
/\|\|/g,
|
|
452
337
|
];
|
|
453
|
-
for (
|
|
454
|
-
|
|
455
|
-
var matches = content.match(pattern);
|
|
338
|
+
for (const pattern of patterns) {
|
|
339
|
+
const matches = content.match(pattern);
|
|
456
340
|
if (matches)
|
|
457
341
|
complexity += matches.length;
|
|
458
342
|
}
|
|
@@ -466,49 +350,44 @@ function estimateComplexity(content) {
|
|
|
466
350
|
* Finds minimum cut with deterministic result
|
|
467
351
|
*/
|
|
468
352
|
function fallbackMinCut(nodes, edges) {
|
|
469
|
-
var _a, _b;
|
|
470
353
|
if (nodes.length < 2) {
|
|
471
354
|
return {
|
|
472
355
|
cutValue: 0,
|
|
473
356
|
partition1: nodes,
|
|
474
357
|
partition2: [],
|
|
475
|
-
cutEdges: []
|
|
358
|
+
cutEdges: [],
|
|
476
359
|
};
|
|
477
360
|
}
|
|
478
361
|
// Build adjacency map with weights
|
|
479
|
-
|
|
480
|
-
for (
|
|
481
|
-
var node = nodes_1[_i];
|
|
362
|
+
const adj = new Map();
|
|
363
|
+
for (const node of nodes) {
|
|
482
364
|
adj.set(node, new Map());
|
|
483
365
|
}
|
|
484
|
-
for (
|
|
485
|
-
var _d = edges_2[_c], u = _d[0], v = _d[1], w = _d[2];
|
|
366
|
+
for (const [u, v, w] of edges) {
|
|
486
367
|
if (adj.has(u) && adj.has(v)) {
|
|
487
368
|
adj.get(u).set(v, (adj.get(u).get(v) || 0) + w);
|
|
488
369
|
adj.get(v).set(u, (adj.get(v).get(u) || 0) + w);
|
|
489
370
|
}
|
|
490
371
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
372
|
+
let bestCut = Infinity;
|
|
373
|
+
let bestPartition1 = [];
|
|
374
|
+
let bestPartition2 = [];
|
|
375
|
+
let bestCutEdges = [];
|
|
495
376
|
// Run multiple iterations for better results
|
|
496
|
-
|
|
497
|
-
|
|
377
|
+
const iterations = Math.min(nodes.length * 2, 20);
|
|
378
|
+
for (let iter = 0; iter < iterations; iter++) {
|
|
498
379
|
// Start from different nodes
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
380
|
+
const startNode = nodes[iter % nodes.length];
|
|
381
|
+
const inSet = new Set([startNode]);
|
|
382
|
+
const remaining = new Set(nodes.filter(n => n !== startNode));
|
|
502
383
|
while (remaining.size > 1) {
|
|
503
384
|
// Find node with maximum connectivity to current set
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
for (
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
var inNode = _k[_j];
|
|
511
|
-
conn += ((_a = adj.get(node)) === null || _a === void 0 ? void 0 : _a.get(inNode)) || 0;
|
|
385
|
+
let maxNode = '';
|
|
386
|
+
let maxConn = -1;
|
|
387
|
+
for (const node of Array.from(remaining)) {
|
|
388
|
+
let conn = 0;
|
|
389
|
+
for (const inNode of Array.from(inSet)) {
|
|
390
|
+
conn += adj.get(node)?.get(inNode) || 0;
|
|
512
391
|
}
|
|
513
392
|
if (conn > maxConn) {
|
|
514
393
|
maxConn = conn;
|
|
@@ -517,16 +396,15 @@ function fallbackMinCut(nodes, edges) {
|
|
|
517
396
|
}
|
|
518
397
|
if (!maxNode)
|
|
519
398
|
break;
|
|
520
|
-
remaining
|
|
399
|
+
remaining.delete(maxNode);
|
|
521
400
|
inSet.add(maxNode);
|
|
522
401
|
}
|
|
523
402
|
if (remaining.size === 1) {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
for (
|
|
528
|
-
|
|
529
|
-
var weight = ((_b = adj.get(lastNode)) === null || _b === void 0 ? void 0 : _b.get(inNode)) || 0;
|
|
403
|
+
const lastNode = Array.from(remaining)[0];
|
|
404
|
+
let cutValue = 0;
|
|
405
|
+
const cutEdges = [];
|
|
406
|
+
for (const inNode of Array.from(inSet)) {
|
|
407
|
+
const weight = adj.get(lastNode)?.get(inNode) || 0;
|
|
530
408
|
if (weight > 0) {
|
|
531
409
|
cutValue += weight;
|
|
532
410
|
cutEdges.push([lastNode, inNode]);
|
|
@@ -539,21 +417,17 @@ function fallbackMinCut(nodes, edges) {
|
|
|
539
417
|
bestCutEdges = cutEdges;
|
|
540
418
|
}
|
|
541
419
|
}
|
|
542
|
-
};
|
|
543
|
-
for (var iter = 0; iter < iterations; iter++) {
|
|
544
|
-
_loop_1(iter);
|
|
545
420
|
}
|
|
546
421
|
// If we didn't find a good cut, split roughly in half
|
|
547
422
|
if (bestCut === Infinity) {
|
|
548
|
-
|
|
423
|
+
const mid = Math.floor(nodes.length / 2);
|
|
549
424
|
bestPartition1 = nodes.slice(0, mid);
|
|
550
425
|
bestPartition2 = nodes.slice(mid);
|
|
551
426
|
bestCut = 0;
|
|
552
427
|
bestCutEdges = [];
|
|
553
|
-
for (
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
var vIn1 = bestPartition1.includes(v);
|
|
428
|
+
for (const [u, v, w] of edges) {
|
|
429
|
+
const uIn1 = bestPartition1.includes(u);
|
|
430
|
+
const vIn1 = bestPartition1.includes(v);
|
|
557
431
|
if (uIn1 !== vIn1) {
|
|
558
432
|
bestCut += w;
|
|
559
433
|
bestCutEdges.push([u, v]);
|
|
@@ -564,7 +438,7 @@ function fallbackMinCut(nodes, edges) {
|
|
|
564
438
|
cutValue: bestCut,
|
|
565
439
|
partition1: bestPartition1,
|
|
566
440
|
partition2: bestPartition2,
|
|
567
|
-
cutEdges: bestCutEdges
|
|
441
|
+
cutEdges: bestCutEdges,
|
|
568
442
|
};
|
|
569
443
|
}
|
|
570
444
|
// ============================================================================
|
|
@@ -579,14 +453,12 @@ function fallbackLouvain(nodes, edges) {
|
|
|
579
453
|
return { communities: [], modularity: 0 };
|
|
580
454
|
}
|
|
581
455
|
// Build adjacency map
|
|
582
|
-
|
|
583
|
-
for (
|
|
584
|
-
var node = nodes_2[_i];
|
|
456
|
+
const adj = new Map();
|
|
457
|
+
for (const node of nodes) {
|
|
585
458
|
adj.set(node, new Map());
|
|
586
459
|
}
|
|
587
|
-
|
|
588
|
-
for (
|
|
589
|
-
var _b = edges_4[_a], u = _b[0], v = _b[1], w = _b[2];
|
|
460
|
+
let totalWeight = 0;
|
|
461
|
+
for (const [u, v, w] of edges) {
|
|
590
462
|
if (adj.has(u) && adj.has(v)) {
|
|
591
463
|
adj.get(u).set(v, (adj.get(u).get(v) || 0) + w);
|
|
592
464
|
adj.get(v).set(u, (adj.get(v).get(u) || 0) + w);
|
|
@@ -596,64 +468,57 @@ function fallbackLouvain(nodes, edges) {
|
|
|
596
468
|
if (totalWeight === 0) {
|
|
597
469
|
// No edges, each node is its own community
|
|
598
470
|
return {
|
|
599
|
-
communities: nodes.map(
|
|
600
|
-
modularity: 0
|
|
471
|
+
communities: nodes.map((n, i) => ({ id: i, members: [n] })),
|
|
472
|
+
modularity: 0,
|
|
601
473
|
};
|
|
602
474
|
}
|
|
603
475
|
// Initialize: each node in its own community
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
for (
|
|
607
|
-
var node = nodes_3[_c];
|
|
476
|
+
const community = new Map();
|
|
477
|
+
let nextCommunityId = 0;
|
|
478
|
+
for (const node of nodes) {
|
|
608
479
|
community.set(node, nextCommunityId++);
|
|
609
480
|
}
|
|
610
481
|
// Calculate node degree
|
|
611
|
-
|
|
612
|
-
for (
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
for (var _e = 0, _f = Array.from(adj.get(node).entries()); _e < _f.length; _e++) {
|
|
616
|
-
var _g = _f[_e], w = _g[1];
|
|
482
|
+
const degree = new Map();
|
|
483
|
+
for (const node of nodes) {
|
|
484
|
+
let d = 0;
|
|
485
|
+
for (const [, w] of Array.from(adj.get(node).entries())) {
|
|
617
486
|
d += w;
|
|
618
487
|
}
|
|
619
488
|
degree.set(node, d);
|
|
620
489
|
}
|
|
621
490
|
// Louvain phase 1: local moving
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
491
|
+
let improved = true;
|
|
492
|
+
const maxIterations = 10;
|
|
493
|
+
let iteration = 0;
|
|
625
494
|
while (improved && iteration < maxIterations) {
|
|
626
495
|
improved = false;
|
|
627
496
|
iteration++;
|
|
628
|
-
for (
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
var nodeDegree = degree.get(node);
|
|
497
|
+
for (const node of nodes) {
|
|
498
|
+
const currentCommunity = community.get(node);
|
|
499
|
+
const nodeAdj = adj.get(node);
|
|
500
|
+
const nodeDegree = degree.get(node);
|
|
633
501
|
// Calculate modularity gain for moving to each neighbor's community
|
|
634
|
-
|
|
635
|
-
for (
|
|
636
|
-
|
|
637
|
-
var neighborCommunity = community.get(neighbor);
|
|
502
|
+
const communityWeights = new Map();
|
|
503
|
+
for (const [neighbor, weight] of Array.from(nodeAdj.entries())) {
|
|
504
|
+
const neighborCommunity = community.get(neighbor);
|
|
638
505
|
communityWeights.set(neighborCommunity, (communityWeights.get(neighborCommunity) || 0) + weight);
|
|
639
506
|
}
|
|
640
507
|
// Calculate community totals
|
|
641
|
-
|
|
642
|
-
for (
|
|
643
|
-
var _p = _o[_m], n = _p[0], c = _p[1];
|
|
508
|
+
const communityTotal = new Map();
|
|
509
|
+
for (const [n, c] of Array.from(community.entries())) {
|
|
644
510
|
communityTotal.set(c, (communityTotal.get(c) || 0) + (degree.get(n) || 0));
|
|
645
511
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
for (
|
|
649
|
-
var _s = _r[_q], targetCommunity = _s[0], edgeWeight = _s[1];
|
|
512
|
+
let bestCommunity = currentCommunity;
|
|
513
|
+
let bestGain = 0;
|
|
514
|
+
for (const [targetCommunity, edgeWeight] of Array.from(communityWeights.entries())) {
|
|
650
515
|
if (targetCommunity === currentCommunity)
|
|
651
516
|
continue;
|
|
652
517
|
// Calculate modularity gain
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
518
|
+
const currentTotal = communityTotal.get(currentCommunity) || 0;
|
|
519
|
+
const targetTotal = communityTotal.get(targetCommunity) || 0;
|
|
520
|
+
const currentEdges = communityWeights.get(currentCommunity) || 0;
|
|
521
|
+
const gain = (edgeWeight - currentEdges) / totalWeight -
|
|
657
522
|
(nodeDegree * (targetTotal - currentTotal + nodeDegree)) / (totalWeight * totalWeight);
|
|
658
523
|
if (gain > bestGain) {
|
|
659
524
|
bestGain = gain;
|
|
@@ -667,35 +532,32 @@ function fallbackLouvain(nodes, edges) {
|
|
|
667
532
|
}
|
|
668
533
|
}
|
|
669
534
|
// Collect communities
|
|
670
|
-
|
|
671
|
-
for (
|
|
672
|
-
var _v = _u[_t], node = _v[0], comm = _v[1];
|
|
535
|
+
const communityMembers = new Map();
|
|
536
|
+
for (const [node, comm] of Array.from(community.entries())) {
|
|
673
537
|
if (!communityMembers.has(comm)) {
|
|
674
538
|
communityMembers.set(comm, []);
|
|
675
539
|
}
|
|
676
540
|
communityMembers.get(comm).push(node);
|
|
677
541
|
}
|
|
678
542
|
// Renumber communities
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
for (
|
|
682
|
-
|
|
683
|
-
communities.push({ id: id++, members: members });
|
|
543
|
+
const communities = [];
|
|
544
|
+
let id = 0;
|
|
545
|
+
for (const members of Array.from(communityMembers.values())) {
|
|
546
|
+
communities.push({ id: id++, members });
|
|
684
547
|
}
|
|
685
548
|
// Calculate modularity
|
|
686
|
-
|
|
687
|
-
for (
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
var cv = community.get(v);
|
|
549
|
+
let modularity = 0;
|
|
550
|
+
for (const [u, v, w] of edges) {
|
|
551
|
+
const cu = community.get(u);
|
|
552
|
+
const cv = community.get(v);
|
|
691
553
|
if (cu === cv) {
|
|
692
|
-
|
|
693
|
-
|
|
554
|
+
const du = degree.get(u);
|
|
555
|
+
const dv = degree.get(v);
|
|
694
556
|
modularity += w - (du * dv) / totalWeight;
|
|
695
557
|
}
|
|
696
558
|
}
|
|
697
559
|
modularity /= totalWeight;
|
|
698
|
-
return { communities
|
|
560
|
+
return { communities, modularity };
|
|
699
561
|
}
|
|
700
562
|
// ============================================================================
|
|
701
563
|
// Circular Dependency Detection
|
|
@@ -704,19 +566,17 @@ function fallbackLouvain(nodes, edges) {
|
|
|
704
566
|
* Detect circular dependencies using DFS
|
|
705
567
|
*/
|
|
706
568
|
export function detectCircularDependencies(graph) {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
569
|
+
const cycles = [];
|
|
570
|
+
const visited = new Set();
|
|
571
|
+
const recursionStack = new Set();
|
|
572
|
+
const path = [];
|
|
711
573
|
// Build adjacency list
|
|
712
|
-
|
|
713
|
-
for (
|
|
714
|
-
var node = _a[_i];
|
|
574
|
+
const adjList = new Map();
|
|
575
|
+
for (const node of Array.from(graph.nodes.keys())) {
|
|
715
576
|
adjList.set(node, []);
|
|
716
577
|
}
|
|
717
|
-
for (
|
|
718
|
-
|
|
719
|
-
var list = adjList.get(edge.source);
|
|
578
|
+
for (const edge of graph.edges) {
|
|
579
|
+
const list = adjList.get(edge.source);
|
|
720
580
|
if (list) {
|
|
721
581
|
list.push(edge.target);
|
|
722
582
|
}
|
|
@@ -725,30 +585,28 @@ export function detectCircularDependencies(graph) {
|
|
|
725
585
|
visited.add(node);
|
|
726
586
|
recursionStack.add(node);
|
|
727
587
|
path.push(node);
|
|
728
|
-
|
|
729
|
-
for (
|
|
730
|
-
var neighbor = neighbors_1[_i];
|
|
588
|
+
const neighbors = adjList.get(node) || [];
|
|
589
|
+
for (const neighbor of neighbors) {
|
|
731
590
|
if (!visited.has(neighbor)) {
|
|
732
591
|
dfs(neighbor);
|
|
733
592
|
}
|
|
734
593
|
else if (recursionStack.has(neighbor)) {
|
|
735
594
|
// Found cycle
|
|
736
|
-
|
|
737
|
-
|
|
595
|
+
const cycleStart = path.indexOf(neighbor);
|
|
596
|
+
const cycle = path.slice(cycleStart);
|
|
738
597
|
cycle.push(neighbor); // Complete the cycle
|
|
739
|
-
|
|
598
|
+
const severity = getCycleSeverity(cycle, graph);
|
|
740
599
|
cycles.push({
|
|
741
|
-
cycle
|
|
742
|
-
severity
|
|
743
|
-
suggestion: getCycleSuggestion(cycle, graph)
|
|
600
|
+
cycle,
|
|
601
|
+
severity,
|
|
602
|
+
suggestion: getCycleSuggestion(cycle, graph),
|
|
744
603
|
});
|
|
745
604
|
}
|
|
746
605
|
}
|
|
747
|
-
recursionStack
|
|
606
|
+
recursionStack.delete(node);
|
|
748
607
|
path.pop();
|
|
749
608
|
}
|
|
750
|
-
for (
|
|
751
|
-
var node = _e[_d];
|
|
609
|
+
for (const node of Array.from(graph.nodes.keys())) {
|
|
752
610
|
if (!visited.has(node)) {
|
|
753
611
|
dfs(node);
|
|
754
612
|
}
|
|
@@ -759,7 +617,7 @@ function getCycleSeverity(cycle, _graph) {
|
|
|
759
617
|
// High severity if cycle involves many files or core modules
|
|
760
618
|
if (cycle.length > 5)
|
|
761
619
|
return 'high';
|
|
762
|
-
if (cycle.some(
|
|
620
|
+
if (cycle.some(n => n.includes('index') || n.includes('core')))
|
|
763
621
|
return 'high';
|
|
764
622
|
if (cycle.length > 3)
|
|
765
623
|
return 'medium';
|
|
@@ -767,21 +625,21 @@ function getCycleSeverity(cycle, _graph) {
|
|
|
767
625
|
}
|
|
768
626
|
function getCycleSuggestion(cycle, graph) {
|
|
769
627
|
if (cycle.length === 2) {
|
|
770
|
-
return
|
|
628
|
+
return `Consider extracting shared code into a separate module to break the cycle between ${cycle[0]} and ${cycle[1]}`;
|
|
771
629
|
}
|
|
772
630
|
// Find the weakest link (least important edge)
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
for (
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
631
|
+
let weakestEdge = '';
|
|
632
|
+
let minImports = Infinity;
|
|
633
|
+
for (let i = 0; i < cycle.length - 1; i++) {
|
|
634
|
+
const from = cycle[i];
|
|
635
|
+
const to = cycle[i + 1];
|
|
636
|
+
const fromNode = graph.nodes.get(from);
|
|
779
637
|
if (fromNode && fromNode.imports.length < minImports) {
|
|
780
638
|
minImports = fromNode.imports.length;
|
|
781
|
-
weakestEdge = from
|
|
639
|
+
weakestEdge = `${from} -> ${to}`;
|
|
782
640
|
}
|
|
783
641
|
}
|
|
784
|
-
return
|
|
642
|
+
return `Break the cycle by refactoring the dependency: ${weakestEdge}. Consider dependency injection or extracting interfaces.`;
|
|
785
643
|
}
|
|
786
644
|
// ============================================================================
|
|
787
645
|
// Main Analysis Functions
|
|
@@ -789,131 +647,103 @@ function getCycleSuggestion(cycle, graph) {
|
|
|
789
647
|
/**
|
|
790
648
|
* Analyze graph boundaries using MinCut algorithm
|
|
791
649
|
*/
|
|
792
|
-
export function analyzeMinCutBoundaries(graph, numPartitions) {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
cutEdges: result.cutEdges.map(function (_a) {
|
|
816
|
-
var s = _a[0], t = _a[1];
|
|
817
|
-
var edge = graph.edges.find(function (e) { return e.source === s && e.target === t; });
|
|
818
|
-
return edge || { source: s, target: t, type: 'import', weight: 1 };
|
|
819
|
-
}),
|
|
820
|
-
suggestion: generateBoundarySuggestion(result.partition1, result.partition2, graph)
|
|
821
|
-
});
|
|
822
|
-
// Recursively partition if needed
|
|
823
|
-
if (numPartitions > 2 && result.partition1.length > 2) {
|
|
824
|
-
subEdges = edges.filter(function (_a) {
|
|
825
|
-
var u = _a[0], v = _a[1];
|
|
826
|
-
return result.partition1.includes(u) && result.partition1.includes(v);
|
|
827
|
-
});
|
|
828
|
-
subResult = ruVector
|
|
829
|
-
? ruVector.mincut(result.partition1, subEdges)
|
|
830
|
-
: fallbackMinCut(result.partition1, subEdges);
|
|
831
|
-
if (subResult.cutValue > 0) {
|
|
832
|
-
boundaries.push({
|
|
833
|
-
cutValue: subResult.cutValue,
|
|
834
|
-
partition1: subResult.partition1,
|
|
835
|
-
partition2: subResult.partition2,
|
|
836
|
-
cutEdges: subResult.cutEdges.map(function (_a) {
|
|
837
|
-
var s = _a[0], t = _a[1];
|
|
838
|
-
var edge = graph.edges.find(function (e) { return e.source === s && e.target === t; });
|
|
839
|
-
return edge || { source: s, target: t, type: 'import', weight: 1 };
|
|
840
|
-
}),
|
|
841
|
-
suggestion: generateBoundarySuggestion(subResult.partition1, subResult.partition2, graph)
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
return [2 /*return*/, boundaries];
|
|
846
|
-
}
|
|
847
|
-
});
|
|
650
|
+
export async function analyzeMinCutBoundaries(graph, numPartitions = 2) {
|
|
651
|
+
const nodes = Array.from(graph.nodes.keys());
|
|
652
|
+
const edges = graph.edges.map(e => [e.source, e.target, e.weight]);
|
|
653
|
+
const boundaries = [];
|
|
654
|
+
// Try to use ruvector, fallback to built-in
|
|
655
|
+
const ruVector = await loadRuVector();
|
|
656
|
+
// Get initial partition
|
|
657
|
+
let result;
|
|
658
|
+
if (ruVector) {
|
|
659
|
+
result = ruVector.mincut(nodes, edges);
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
result = fallbackMinCut(nodes, edges);
|
|
663
|
+
}
|
|
664
|
+
boundaries.push({
|
|
665
|
+
cutValue: result.cutValue,
|
|
666
|
+
partition1: result.partition1,
|
|
667
|
+
partition2: result.partition2,
|
|
668
|
+
cutEdges: result.cutEdges.map(([s, t]) => {
|
|
669
|
+
const edge = graph.edges.find(e => e.source === s && e.target === t);
|
|
670
|
+
return edge || { source: s, target: t, type: 'import', weight: 1 };
|
|
671
|
+
}),
|
|
672
|
+
suggestion: generateBoundarySuggestion(result.partition1, result.partition2, graph),
|
|
848
673
|
});
|
|
674
|
+
// Recursively partition if needed
|
|
675
|
+
if (numPartitions > 2 && result.partition1.length > 2) {
|
|
676
|
+
const subEdges = edges.filter(([u, v]) => result.partition1.includes(u) && result.partition1.includes(v));
|
|
677
|
+
const subResult = ruVector
|
|
678
|
+
? ruVector.mincut(result.partition1, subEdges)
|
|
679
|
+
: fallbackMinCut(result.partition1, subEdges);
|
|
680
|
+
if (subResult.cutValue > 0) {
|
|
681
|
+
boundaries.push({
|
|
682
|
+
cutValue: subResult.cutValue,
|
|
683
|
+
partition1: subResult.partition1,
|
|
684
|
+
partition2: subResult.partition2,
|
|
685
|
+
cutEdges: subResult.cutEdges.map(([s, t]) => {
|
|
686
|
+
const edge = graph.edges.find(e => e.source === s && e.target === t);
|
|
687
|
+
return edge || { source: s, target: t, type: 'import', weight: 1 };
|
|
688
|
+
}),
|
|
689
|
+
suggestion: generateBoundarySuggestion(subResult.partition1, subResult.partition2, graph),
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return boundaries;
|
|
849
694
|
}
|
|
850
695
|
function generateBoundarySuggestion(partition1, partition2, _graph) {
|
|
851
696
|
// Analyze the partitions to suggest organization
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
697
|
+
const p1Dirs = partition1.map(p => dirname(p)).filter(d => d !== '.');
|
|
698
|
+
const p2Dirs = partition2.map(p => dirname(p)).filter(d => d !== '.');
|
|
699
|
+
const p1DirsSet = new Set(p1Dirs);
|
|
700
|
+
const p2DirsSet = new Set(p2Dirs);
|
|
856
701
|
if (p1DirsSet.size === 1 && p2DirsSet.size === 1) {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
return
|
|
702
|
+
const dir1 = p1Dirs[0];
|
|
703
|
+
const dir2 = p2Dirs[0];
|
|
704
|
+
return `Natural boundary detected between ${dir1}/ and ${dir2}/. These could be separate packages.`;
|
|
860
705
|
}
|
|
861
706
|
if (partition1.length > partition2.length * 3) {
|
|
862
|
-
return
|
|
707
|
+
return `Consider extracting ${partition2.length} files into a separate module. They have minimal coupling to the rest.`;
|
|
863
708
|
}
|
|
864
|
-
return
|
|
709
|
+
return `Found ${partition1.length} and ${partition2.length} file groups with minimal coupling. Consider organizing into separate modules.`;
|
|
865
710
|
}
|
|
866
711
|
/**
|
|
867
712
|
* Analyze module communities using Louvain algorithm
|
|
868
713
|
*/
|
|
869
|
-
export function analyzeModuleCommunities(graph) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
var _loop_2 = function (member) {
|
|
886
|
-
var connections = graph.edges.filter(function (e) {
|
|
887
|
-
return (e.source === member && comm.members.includes(e.target)) ||
|
|
888
|
-
(e.target === member && comm.members.includes(e.source));
|
|
889
|
-
}).length;
|
|
890
|
-
if (connections > maxConnections) {
|
|
891
|
-
maxConnections = connections;
|
|
892
|
-
centralNode = member;
|
|
893
|
-
}
|
|
894
|
-
};
|
|
895
|
-
for (var _i = 0, _a = comm.members; _i < _a.length; _i++) {
|
|
896
|
-
var member = _a[_i];
|
|
897
|
-
_loop_2(member);
|
|
898
|
-
}
|
|
899
|
-
// Calculate cohesion (internal edges / total possible edges)
|
|
900
|
-
var internalEdges = graph.edges.filter(function (e) { return comm.members.includes(e.source) && comm.members.includes(e.target); }).length;
|
|
901
|
-
var possibleEdges = (comm.members.length * (comm.members.length - 1)) / 2;
|
|
902
|
-
var cohesion = possibleEdges > 0 ? internalEdges / possibleEdges : 1;
|
|
903
|
-
// Suggest name based on common directory
|
|
904
|
-
var dirs = comm.members.map(function (m) { return dirname(m); });
|
|
905
|
-
var commonDir = findCommonPrefix(dirs);
|
|
906
|
-
var suggestedName = commonDir || basename(centralNode, extname(centralNode));
|
|
907
|
-
return {
|
|
908
|
-
id: comm.id,
|
|
909
|
-
members: comm.members,
|
|
910
|
-
cohesion: cohesion,
|
|
911
|
-
centralNode: centralNode,
|
|
912
|
-
suggestedName: suggestedName
|
|
913
|
-
};
|
|
914
|
-
})];
|
|
714
|
+
export async function analyzeModuleCommunities(graph) {
|
|
715
|
+
const nodes = Array.from(graph.nodes.keys());
|
|
716
|
+
const edges = graph.edges.map(e => [e.source, e.target, e.weight]);
|
|
717
|
+
// Try to use ruvector, fallback to built-in
|
|
718
|
+
const ruVector = await loadRuVector();
|
|
719
|
+
const result = ruVector ? ruVector.louvain(nodes, edges) : fallbackLouvain(nodes, edges);
|
|
720
|
+
return result.communities.map(comm => {
|
|
721
|
+
// Find the most connected node as central
|
|
722
|
+
let maxConnections = 0;
|
|
723
|
+
let centralNode = comm.members[0];
|
|
724
|
+
for (const member of comm.members) {
|
|
725
|
+
const connections = graph.edges.filter(e => (e.source === member && comm.members.includes(e.target)) ||
|
|
726
|
+
(e.target === member && comm.members.includes(e.source))).length;
|
|
727
|
+
if (connections > maxConnections) {
|
|
728
|
+
maxConnections = connections;
|
|
729
|
+
centralNode = member;
|
|
915
730
|
}
|
|
916
|
-
}
|
|
731
|
+
}
|
|
732
|
+
// Calculate cohesion (internal edges / total possible edges)
|
|
733
|
+
const internalEdges = graph.edges.filter(e => comm.members.includes(e.source) && comm.members.includes(e.target)).length;
|
|
734
|
+
const possibleEdges = (comm.members.length * (comm.members.length - 1)) / 2;
|
|
735
|
+
const cohesion = possibleEdges > 0 ? internalEdges / possibleEdges : 1;
|
|
736
|
+
// Suggest name based on common directory
|
|
737
|
+
const dirs = comm.members.map(m => dirname(m));
|
|
738
|
+
const commonDir = findCommonPrefix(dirs);
|
|
739
|
+
const suggestedName = commonDir || basename(centralNode, extname(centralNode));
|
|
740
|
+
return {
|
|
741
|
+
id: comm.id,
|
|
742
|
+
members: comm.members,
|
|
743
|
+
cohesion,
|
|
744
|
+
centralNode,
|
|
745
|
+
suggestedName,
|
|
746
|
+
};
|
|
917
747
|
});
|
|
918
748
|
}
|
|
919
749
|
function findCommonPrefix(strings) {
|
|
@@ -921,108 +751,94 @@ function findCommonPrefix(strings) {
|
|
|
921
751
|
return '';
|
|
922
752
|
if (strings.length === 1)
|
|
923
753
|
return strings[0];
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
754
|
+
const sorted = [...strings].sort();
|
|
755
|
+
const first = sorted[0];
|
|
756
|
+
const last = sorted[sorted.length - 1];
|
|
757
|
+
let i = 0;
|
|
928
758
|
while (i < first.length && first[i] === last[i]) {
|
|
929
759
|
i++;
|
|
930
760
|
}
|
|
931
|
-
|
|
761
|
+
const prefix = first.slice(0, i);
|
|
932
762
|
// Return the last complete directory segment
|
|
933
|
-
|
|
763
|
+
const lastSlash = prefix.lastIndexOf('/');
|
|
934
764
|
return lastSlash > 0 ? prefix.slice(0, lastSlash) : '';
|
|
935
765
|
}
|
|
936
766
|
/**
|
|
937
767
|
* Full graph analysis (with caching)
|
|
938
768
|
*/
|
|
939
|
-
export function analyzeGraph(rootDir, options) {
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
if (edge.source === node && !visited.has(edge.target)) {
|
|
947
|
-
dfs(edge.target);
|
|
948
|
-
}
|
|
949
|
-
if (edge.target === node && !visited.has(edge.source)) {
|
|
950
|
-
dfs(edge.source);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
769
|
+
export async function analyzeGraph(rootDir, options = {}) {
|
|
770
|
+
// Check cache first
|
|
771
|
+
const cacheKey = `analysis:${rootDir}:${JSON.stringify(options)}`;
|
|
772
|
+
if (!options.skipCache) {
|
|
773
|
+
const cached = analysisResultCache.get(cacheKey);
|
|
774
|
+
if (cached && Date.now() - cached.timestamp < ANALYSIS_CACHE_TTL_MS) {
|
|
775
|
+
return cached.result;
|
|
953
776
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
}
|
|
980
|
-
degreeValues = Array.from(degrees.values());
|
|
981
|
-
avgDegree = degreeValues.length > 0 ? degreeValues.reduce(function (a, b) { return a + b; }, 0) / degreeValues.length : 0;
|
|
982
|
-
maxDegree = degreeValues.length > 0 ? Math.max.apply(Math, degreeValues) : 0;
|
|
983
|
-
density = nodeCount > 1 ? (2 * edgeCount) / (nodeCount * (nodeCount - 1)) : 0;
|
|
984
|
-
visited = new Set();
|
|
985
|
-
componentCount = 0;
|
|
986
|
-
for (_d = 0, _e = Array.from(graph.nodes.keys()); _d < _e.length; _d++) {
|
|
987
|
-
node = _e[_d];
|
|
988
|
-
if (!visited.has(node)) {
|
|
989
|
-
componentCount++;
|
|
990
|
-
dfs(node);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
circularDependencies = detectCircularDependencies(graph);
|
|
994
|
-
if (!(options.includeBoundaries !== false)) return [3 /*break*/, 3];
|
|
995
|
-
return [4 /*yield*/, analyzeMinCutBoundaries(graph, options.numPartitions)];
|
|
996
|
-
case 2:
|
|
997
|
-
boundaries = _f.sent();
|
|
998
|
-
_f.label = 3;
|
|
999
|
-
case 3:
|
|
1000
|
-
if (!(options.includeModules !== false)) return [3 /*break*/, 5];
|
|
1001
|
-
return [4 /*yield*/, analyzeModuleCommunities(graph)];
|
|
1002
|
-
case 4:
|
|
1003
|
-
communities = _f.sent();
|
|
1004
|
-
_f.label = 5;
|
|
1005
|
-
case 5:
|
|
1006
|
-
result = {
|
|
1007
|
-
graph: graph,
|
|
1008
|
-
boundaries: boundaries,
|
|
1009
|
-
communities: communities,
|
|
1010
|
-
circularDependencies: circularDependencies,
|
|
1011
|
-
statistics: {
|
|
1012
|
-
nodeCount: nodeCount,
|
|
1013
|
-
edgeCount: edgeCount,
|
|
1014
|
-
avgDegree: avgDegree,
|
|
1015
|
-
maxDegree: maxDegree,
|
|
1016
|
-
density: density,
|
|
1017
|
-
componentCount: componentCount
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
// Cache the result
|
|
1021
|
-
analysisResultCache.set(cacheKey, { result: result, timestamp: Date.now() });
|
|
1022
|
-
return [2 /*return*/, result];
|
|
777
|
+
}
|
|
778
|
+
const graph = await buildDependencyGraph(rootDir, { skipCache: options.skipCache });
|
|
779
|
+
// Calculate statistics
|
|
780
|
+
const nodeCount = graph.nodes.size;
|
|
781
|
+
const edgeCount = graph.edges.length;
|
|
782
|
+
const degrees = new Map();
|
|
783
|
+
for (const node of Array.from(graph.nodes.keys())) {
|
|
784
|
+
degrees.set(node, 0);
|
|
785
|
+
}
|
|
786
|
+
for (const edge of graph.edges) {
|
|
787
|
+
degrees.set(edge.source, (degrees.get(edge.source) || 0) + 1);
|
|
788
|
+
degrees.set(edge.target, (degrees.get(edge.target) || 0) + 1);
|
|
789
|
+
}
|
|
790
|
+
const degreeValues = Array.from(degrees.values());
|
|
791
|
+
const avgDegree = degreeValues.length > 0 ? degreeValues.reduce((a, b) => a + b, 0) / degreeValues.length : 0;
|
|
792
|
+
const maxDegree = degreeValues.length > 0 ? Math.max(...degreeValues) : 0;
|
|
793
|
+
const density = nodeCount > 1 ? (2 * edgeCount) / (nodeCount * (nodeCount - 1)) : 0;
|
|
794
|
+
// Count connected components
|
|
795
|
+
const visited = new Set();
|
|
796
|
+
let componentCount = 0;
|
|
797
|
+
function dfs(node) {
|
|
798
|
+
visited.add(node);
|
|
799
|
+
for (const edge of graph.edges) {
|
|
800
|
+
if (edge.source === node && !visited.has(edge.target)) {
|
|
801
|
+
dfs(edge.target);
|
|
1023
802
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
803
|
+
if (edge.target === node && !visited.has(edge.source)) {
|
|
804
|
+
dfs(edge.source);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
for (const node of Array.from(graph.nodes.keys())) {
|
|
809
|
+
if (!visited.has(node)) {
|
|
810
|
+
componentCount++;
|
|
811
|
+
dfs(node);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
// Detect circular dependencies
|
|
815
|
+
const circularDependencies = detectCircularDependencies(graph);
|
|
816
|
+
// Analyze boundaries and communities if requested
|
|
817
|
+
let boundaries;
|
|
818
|
+
let communities;
|
|
819
|
+
if (options.includeBoundaries !== false) {
|
|
820
|
+
boundaries = await analyzeMinCutBoundaries(graph, options.numPartitions);
|
|
821
|
+
}
|
|
822
|
+
if (options.includeModules !== false) {
|
|
823
|
+
communities = await analyzeModuleCommunities(graph);
|
|
824
|
+
}
|
|
825
|
+
const result = {
|
|
826
|
+
graph,
|
|
827
|
+
boundaries,
|
|
828
|
+
communities,
|
|
829
|
+
circularDependencies,
|
|
830
|
+
statistics: {
|
|
831
|
+
nodeCount,
|
|
832
|
+
edgeCount,
|
|
833
|
+
avgDegree,
|
|
834
|
+
maxDegree,
|
|
835
|
+
density,
|
|
836
|
+
componentCount,
|
|
837
|
+
},
|
|
838
|
+
};
|
|
839
|
+
// Cache the result
|
|
840
|
+
analysisResultCache.set(cacheKey, { result, timestamp: Date.now() });
|
|
841
|
+
return result;
|
|
1026
842
|
}
|
|
1027
843
|
// ============================================================================
|
|
1028
844
|
// DOT Format Export
|
|
@@ -1030,62 +846,56 @@ export function analyzeGraph(rootDir, options) {
|
|
|
1030
846
|
/**
|
|
1031
847
|
* Export graph to DOT format for visualization
|
|
1032
848
|
*/
|
|
1033
|
-
export function exportToDot(result, options) {
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
var lines = ['digraph DependencyGraph {'];
|
|
849
|
+
export function exportToDot(result, options = {}) {
|
|
850
|
+
const { graph, communities, circularDependencies } = result;
|
|
851
|
+
const lines = ['digraph DependencyGraph {'];
|
|
1037
852
|
lines.push(' rankdir=LR;');
|
|
1038
853
|
lines.push(' node [shape=box, style=rounded];');
|
|
1039
854
|
lines.push('');
|
|
1040
855
|
// Generate colors for communities
|
|
1041
|
-
|
|
856
|
+
const communityColors = new Map();
|
|
1042
857
|
if (options.colorByCommunity && communities) {
|
|
1043
|
-
|
|
858
|
+
const colors = [
|
|
1044
859
|
'#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231',
|
|
1045
860
|
'#911eb4', '#42d4f4', '#f032e6', '#bfef45', '#fabed4',
|
|
1046
861
|
];
|
|
1047
|
-
for (
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
for (var _a = 0, _b = comm.members; _a < _b.length; _a++) {
|
|
1051
|
-
var member = _b[_a];
|
|
862
|
+
for (const comm of communities) {
|
|
863
|
+
const color = colors[comm.id % colors.length];
|
|
864
|
+
for (const member of comm.members) {
|
|
1052
865
|
communityColors.set(member, color);
|
|
1053
866
|
}
|
|
1054
867
|
}
|
|
1055
868
|
}
|
|
1056
869
|
// Find nodes in cycles
|
|
1057
|
-
|
|
870
|
+
const nodesInCycles = new Set();
|
|
1058
871
|
if (options.highlightCycles && circularDependencies) {
|
|
1059
|
-
for (
|
|
1060
|
-
|
|
1061
|
-
for (var _d = 0, _e = cycle.cycle; _d < _e.length; _d++) {
|
|
1062
|
-
var node = _e[_d];
|
|
872
|
+
for (const cycle of circularDependencies) {
|
|
873
|
+
for (const node of cycle.cycle) {
|
|
1063
874
|
nodesInCycles.add(node);
|
|
1064
875
|
}
|
|
1065
876
|
}
|
|
1066
877
|
}
|
|
1067
878
|
// Output nodes
|
|
1068
879
|
lines.push(' // Nodes');
|
|
1069
|
-
for (
|
|
1070
|
-
|
|
1071
|
-
var attrs = [];
|
|
880
|
+
for (const [id, node] of Array.from(graph.nodes.entries())) {
|
|
881
|
+
const attrs = [];
|
|
1072
882
|
if (options.includeLabels !== false) {
|
|
1073
|
-
attrs.push(
|
|
883
|
+
attrs.push(`label="${node.name}"`);
|
|
1074
884
|
}
|
|
1075
885
|
if (communityColors.has(id)) {
|
|
1076
|
-
attrs.push(
|
|
886
|
+
attrs.push(`fillcolor="${communityColors.get(id)}"`, 'style="filled,rounded"');
|
|
1077
887
|
}
|
|
1078
888
|
if (nodesInCycles.has(id)) {
|
|
1079
889
|
attrs.push('color=red', 'penwidth=2');
|
|
1080
890
|
}
|
|
1081
|
-
|
|
1082
|
-
lines.push(
|
|
891
|
+
const attrStr = attrs.length > 0 ? ` [${attrs.join(', ')}]` : '';
|
|
892
|
+
lines.push(` "${id}"${attrStr};`);
|
|
1083
893
|
}
|
|
1084
894
|
lines.push('');
|
|
1085
895
|
// Output edges
|
|
1086
896
|
lines.push(' // Edges');
|
|
1087
|
-
|
|
1088
|
-
|
|
897
|
+
for (const edge of graph.edges) {
|
|
898
|
+
const attrs = [];
|
|
1089
899
|
if (edge.type === 'dynamic') {
|
|
1090
900
|
attrs.push('style=dashed');
|
|
1091
901
|
}
|
|
@@ -1094,8 +904,8 @@ export function exportToDot(result, options) {
|
|
|
1094
904
|
}
|
|
1095
905
|
// Check if edge is part of a cycle
|
|
1096
906
|
if (options.highlightCycles) {
|
|
1097
|
-
|
|
1098
|
-
for (
|
|
907
|
+
const isCycleEdge = circularDependencies.some(cd => {
|
|
908
|
+
for (let i = 0; i < cd.cycle.length - 1; i++) {
|
|
1099
909
|
if (cd.cycle[i] === edge.source && cd.cycle[i + 1] === edge.target) {
|
|
1100
910
|
return true;
|
|
1101
911
|
}
|
|
@@ -1106,12 +916,8 @@ export function exportToDot(result, options) {
|
|
|
1106
916
|
attrs.push('color=red', 'penwidth=2');
|
|
1107
917
|
}
|
|
1108
918
|
}
|
|
1109
|
-
|
|
1110
|
-
lines.push(
|
|
1111
|
-
};
|
|
1112
|
-
for (var _j = 0, _k = graph.edges; _j < _k.length; _j++) {
|
|
1113
|
-
var edge = _k[_j];
|
|
1114
|
-
_loop_3(edge);
|
|
919
|
+
const attrStr = attrs.length > 0 ? ` [${attrs.join(', ')}]` : '';
|
|
920
|
+
lines.push(` "${edge.source}" -> "${edge.target}"${attrStr};`);
|
|
1115
921
|
}
|
|
1116
922
|
lines.push('}');
|
|
1117
923
|
return lines.join('\n');
|