musubi-sdd 5.1.0 → 5.6.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/README.ja.md +106 -48
- package/README.md +110 -32
- package/bin/musubi-analyze.js +74 -67
- package/bin/musubi-browser.js +27 -26
- package/bin/musubi-change.js +48 -47
- package/bin/musubi-checkpoint.js +10 -7
- package/bin/musubi-convert.js +25 -25
- package/bin/musubi-costs.js +27 -10
- package/bin/musubi-gui.js +52 -46
- package/bin/musubi-init.js +1952 -10
- package/bin/musubi-orchestrate.js +327 -239
- package/bin/musubi-remember.js +69 -56
- package/bin/musubi-resolve.js +53 -45
- package/bin/musubi-trace.js +51 -22
- package/bin/musubi-validate.js +39 -30
- package/bin/musubi-workflow.js +33 -34
- package/bin/musubi.js +39 -2
- package/package.json +1 -1
- package/src/agents/agent-loop.js +94 -95
- package/src/agents/agentic/code-generator.js +119 -109
- package/src/agents/agentic/code-reviewer.js +105 -108
- package/src/agents/agentic/index.js +4 -4
- package/src/agents/browser/action-executor.js +13 -13
- package/src/agents/browser/ai-comparator.js +11 -10
- package/src/agents/browser/context-manager.js +6 -6
- package/src/agents/browser/index.js +5 -5
- package/src/agents/browser/nl-parser.js +31 -46
- package/src/agents/browser/screenshot.js +2 -2
- package/src/agents/browser/test-generator.js +6 -4
- package/src/agents/function-tool.js +71 -65
- package/src/agents/index.js +7 -7
- package/src/agents/schema-generator.js +98 -94
- package/src/analyzers/ast-extractor.js +158 -146
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +241 -126
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +77 -81
- package/src/analyzers/security-analyzer.js +19 -11
- package/src/analyzers/stuck-detector.js +19 -17
- package/src/converters/index.js +78 -57
- package/src/converters/ir/types.js +12 -12
- package/src/converters/parsers/musubi-parser.js +134 -126
- package/src/converters/parsers/openapi-parser.js +70 -53
- package/src/converters/parsers/speckit-parser.js +239 -175
- package/src/converters/writers/musubi-writer.js +123 -118
- package/src/converters/writers/speckit-writer.js +124 -113
- package/src/generators/rust-migration-generator.js +512 -0
- package/src/gui/public/index.html +1365 -1211
- package/src/gui/server.js +41 -40
- package/src/gui/services/file-watcher.js +23 -8
- package/src/gui/services/project-scanner.js +26 -20
- package/src/gui/services/replanning-service.js +27 -23
- package/src/gui/services/traceability-service.js +8 -8
- package/src/gui/services/workflow-service.js +14 -7
- package/src/index.js +151 -0
- package/src/integrations/cicd.js +90 -104
- package/src/integrations/codegraph-mcp.js +643 -0
- package/src/integrations/documentation.js +142 -103
- package/src/integrations/examples.js +95 -80
- package/src/integrations/github-client.js +17 -17
- package/src/integrations/index.js +5 -5
- package/src/integrations/mcp/index.js +21 -21
- package/src/integrations/mcp/mcp-context-provider.js +76 -78
- package/src/integrations/mcp/mcp-discovery.js +74 -72
- package/src/integrations/mcp/mcp-tool-registry.js +99 -94
- package/src/integrations/mcp-connector.js +70 -66
- package/src/integrations/platforms.js +50 -49
- package/src/integrations/tool-discovery.js +37 -31
- package/src/llm-providers/anthropic-provider.js +11 -11
- package/src/llm-providers/base-provider.js +16 -18
- package/src/llm-providers/copilot-provider.js +22 -19
- package/src/llm-providers/index.js +26 -25
- package/src/llm-providers/ollama-provider.js +11 -11
- package/src/llm-providers/openai-provider.js +12 -12
- package/src/managers/agent-memory.js +36 -24
- package/src/managers/checkpoint-manager.js +4 -8
- package/src/managers/delta-spec.js +19 -19
- package/src/managers/index.js +13 -4
- package/src/managers/memory-condenser.js +35 -45
- package/src/managers/repo-skill-manager.js +57 -31
- package/src/managers/skill-loader.js +25 -22
- package/src/managers/skill-tools.js +36 -72
- package/src/managers/workflow.js +30 -22
- package/src/monitoring/cost-tracker.js +48 -46
- package/src/monitoring/incident-manager.js +116 -106
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +75 -62
- package/src/monitoring/quality-dashboard.js +45 -41
- package/src/monitoring/release-manager.js +63 -53
- package/src/orchestration/agent-skill-binding.js +39 -47
- package/src/orchestration/error-handler.js +65 -107
- package/src/orchestration/guardrails/base-guardrail.js +26 -24
- package/src/orchestration/guardrails/guardrail-rules.js +50 -64
- package/src/orchestration/guardrails/index.js +5 -5
- package/src/orchestration/guardrails/input-guardrail.js +58 -45
- package/src/orchestration/guardrails/output-guardrail.js +104 -81
- package/src/orchestration/guardrails/safety-check.js +79 -79
- package/src/orchestration/index.js +38 -55
- package/src/orchestration/mcp-tool-adapters.js +96 -99
- package/src/orchestration/orchestration-engine.js +21 -21
- package/src/orchestration/pattern-registry.js +60 -45
- package/src/orchestration/patterns/auto.js +34 -47
- package/src/orchestration/patterns/group-chat.js +59 -65
- package/src/orchestration/patterns/handoff.js +67 -65
- package/src/orchestration/patterns/human-in-loop.js +51 -72
- package/src/orchestration/patterns/nested.js +25 -40
- package/src/orchestration/patterns/sequential.js +35 -34
- package/src/orchestration/patterns/swarm.js +63 -56
- package/src/orchestration/patterns/triage.js +150 -109
- package/src/orchestration/reasoning/index.js +9 -9
- package/src/orchestration/reasoning/planning-engine.js +143 -140
- package/src/orchestration/reasoning/reasoning-engine.js +206 -144
- package/src/orchestration/reasoning/self-correction.js +121 -128
- package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
- package/src/orchestration/replanning/alternative-generator.js +37 -42
- package/src/orchestration/replanning/config.js +63 -59
- package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
- package/src/orchestration/replanning/index.js +24 -20
- package/src/orchestration/replanning/plan-evaluator.js +49 -50
- package/src/orchestration/replanning/plan-monitor.js +32 -28
- package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
- package/src/orchestration/replanning/replan-history.js +33 -26
- package/src/orchestration/replanning/replanning-engine.js +106 -108
- package/src/orchestration/skill-executor.js +107 -109
- package/src/orchestration/skill-registry.js +85 -89
- package/src/orchestration/workflow-examples.js +228 -231
- package/src/orchestration/workflow-executor.js +65 -68
- package/src/orchestration/workflow-orchestrator.js +72 -73
- package/src/phase4-integration.js +47 -40
- package/src/phase5-integration.js +89 -30
- package/src/reporters/coverage-report.js +82 -30
- package/src/reporters/hierarchical-reporter.js +498 -0
- package/src/reporters/traceability-matrix-report.js +29 -20
- package/src/resolvers/issue-resolver.js +43 -31
- package/src/steering/advanced-validation.js +133 -124
- package/src/steering/auto-updater.js +60 -73
- package/src/steering/index.js +6 -6
- package/src/steering/quality-metrics.js +41 -35
- package/src/steering/steering-auto-update.js +83 -86
- package/src/steering/steering-validator.js +98 -106
- package/src/steering/template-constraints.js +53 -54
- package/src/templates/agents/claude-code/CLAUDE.md +32 -32
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
- package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
- package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
- package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
- package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
- package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
- package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
- package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
- package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
- package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
- package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
- package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
- package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
- package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
- package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
- package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
- package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
- package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
- package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
- package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
- package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
- package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
- package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
- package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
- package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
- package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
- package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
- package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
- package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
- package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
- package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
- package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
- package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
- package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
- package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
- package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
- package/src/templates/agents/codex/AGENTS.md +74 -42
- package/src/templates/agents/cursor/AGENTS.md +74 -42
- package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
- package/src/templates/agents/github-copilot/AGENTS.md +83 -51
- package/src/templates/agents/qwen-code/QWEN.md +74 -42
- package/src/templates/agents/windsurf/AGENTS.md +74 -42
- package/src/templates/architectures/README.md +41 -0
- package/src/templates/architectures/clean-architecture/README.md +113 -0
- package/src/templates/architectures/event-driven/README.md +162 -0
- package/src/templates/architectures/hexagonal/README.md +130 -0
- package/src/templates/index.js +6 -1
- package/src/templates/locale-manager.js +16 -16
- package/src/templates/shared/delta-spec-template.md +20 -13
- package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
- package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
- package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
- package/src/templates/shared/steering/structure.md +95 -0
- package/src/templates/skills/browser-agent.md +21 -16
- package/src/templates/skills/web-gui.md +8 -0
- package/src/templates/template-constraints.js +50 -53
- package/src/validators/advanced-validation.js +30 -36
- package/src/validators/constitutional-validator.js +77 -73
- package/src/validators/critic-system.js +49 -59
- package/src/validators/delta-format.js +59 -55
- package/src/validators/traceability-validator.js +7 -11
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MUSUBI CodeGraph MCP Integration
|
|
3
|
+
*
|
|
4
|
+
* Deep integration with CodeGraph MCP for:
|
|
5
|
+
* - Function call graph analysis
|
|
6
|
+
* - Impact analysis for changes
|
|
7
|
+
* - Dependency chain tracking
|
|
8
|
+
* - Community detection
|
|
9
|
+
*
|
|
10
|
+
* Based on analysis of GCC codebase with 1,436,920 relations
|
|
11
|
+
*
|
|
12
|
+
* @version 5.5.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs-extra');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { spawn, execSync } = require('child_process');
|
|
18
|
+
const Database = require('better-sqlite3');
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// CodeGraph Integration
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
class CodeGraphIntegration {
|
|
25
|
+
constructor(repoPath, options = {}) {
|
|
26
|
+
this.repoPath = repoPath;
|
|
27
|
+
this.dbPath = path.join(repoPath, '.codegraph', 'graph.db');
|
|
28
|
+
this.options = {
|
|
29
|
+
fullIndex: false,
|
|
30
|
+
noCommunity: false,
|
|
31
|
+
...options,
|
|
32
|
+
};
|
|
33
|
+
this.db = null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if CodeGraph MCP is installed
|
|
38
|
+
*/
|
|
39
|
+
static isInstalled() {
|
|
40
|
+
try {
|
|
41
|
+
execSync('which codegraph-mcp', { encoding: 'utf8', stdio: 'pipe' });
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if index exists
|
|
50
|
+
*/
|
|
51
|
+
hasIndex() {
|
|
52
|
+
return fs.existsSync(this.dbPath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initialize or update CodeGraph index
|
|
57
|
+
*/
|
|
58
|
+
async indexRepository(options = {}) {
|
|
59
|
+
const args = ['index', this.repoPath];
|
|
60
|
+
|
|
61
|
+
if (options.full || this.options.fullIndex) {
|
|
62
|
+
args.push('--full');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (options.noCommunity || this.options.noCommunity) {
|
|
66
|
+
args.push('--no-community');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
console.log(`📊 Indexing repository: ${this.repoPath}`);
|
|
71
|
+
const proc = spawn('codegraph-mcp', args, {
|
|
72
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
let stdout = '';
|
|
76
|
+
let stderr = '';
|
|
77
|
+
|
|
78
|
+
proc.stdout.on('data', data => {
|
|
79
|
+
stdout += data.toString();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
proc.stderr.on('data', data => {
|
|
83
|
+
stderr += data.toString();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
proc.on('close', code => {
|
|
87
|
+
if (code === 0) {
|
|
88
|
+
resolve({ success: true, output: stdout });
|
|
89
|
+
} else {
|
|
90
|
+
reject(new Error(`CodeGraph indexing failed: ${stderr}`));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
proc.on('error', error => {
|
|
95
|
+
reject(error);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Open database connection
|
|
102
|
+
*/
|
|
103
|
+
open() {
|
|
104
|
+
if (!this.hasIndex()) {
|
|
105
|
+
throw new Error(`CodeGraph index not found at ${this.dbPath}. Run indexRepository() first.`);
|
|
106
|
+
}
|
|
107
|
+
this.db = new Database(this.dbPath, { readonly: true });
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Close database connection
|
|
113
|
+
*/
|
|
114
|
+
close() {
|
|
115
|
+
if (this.db) {
|
|
116
|
+
this.db.close();
|
|
117
|
+
this.db = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get repository statistics
|
|
123
|
+
*/
|
|
124
|
+
getStats() {
|
|
125
|
+
this.ensureOpen();
|
|
126
|
+
|
|
127
|
+
const entityCount = this.db.prepare('SELECT COUNT(*) as count FROM entities').get().count;
|
|
128
|
+
const fileCount = this.db
|
|
129
|
+
.prepare("SELECT COUNT(*) as count FROM entities WHERE type = 'module'")
|
|
130
|
+
.get().count;
|
|
131
|
+
const relationCount = this.db.prepare('SELECT COUNT(*) as count FROM relations').get().count;
|
|
132
|
+
|
|
133
|
+
const entityTypes = this.db
|
|
134
|
+
.prepare(
|
|
135
|
+
`
|
|
136
|
+
SELECT type, COUNT(*) as count
|
|
137
|
+
FROM entities
|
|
138
|
+
GROUP BY type
|
|
139
|
+
ORDER BY count DESC
|
|
140
|
+
`
|
|
141
|
+
)
|
|
142
|
+
.all();
|
|
143
|
+
|
|
144
|
+
const relationTypes = this.db
|
|
145
|
+
.prepare(
|
|
146
|
+
`
|
|
147
|
+
SELECT type, COUNT(*) as count
|
|
148
|
+
FROM relations
|
|
149
|
+
GROUP BY type
|
|
150
|
+
ORDER BY count DESC
|
|
151
|
+
`
|
|
152
|
+
)
|
|
153
|
+
.all();
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
entities: entityCount,
|
|
157
|
+
files: fileCount,
|
|
158
|
+
relations: relationCount,
|
|
159
|
+
entityTypes,
|
|
160
|
+
relationTypes,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get call graph for a function
|
|
166
|
+
*/
|
|
167
|
+
getCallGraph(functionName, options = {}) {
|
|
168
|
+
this.ensureOpen();
|
|
169
|
+
|
|
170
|
+
const depth = options.depth || 3;
|
|
171
|
+
const direction = options.direction || 'both'; // 'callers', 'callees', 'both'
|
|
172
|
+
|
|
173
|
+
const result = {
|
|
174
|
+
function: functionName,
|
|
175
|
+
callers: [],
|
|
176
|
+
callees: [],
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Get function entity
|
|
180
|
+
const entity = this.db
|
|
181
|
+
.prepare(
|
|
182
|
+
`
|
|
183
|
+
SELECT id, name, file, start_line, end_line
|
|
184
|
+
FROM entities
|
|
185
|
+
WHERE name = ? AND type = 'function'
|
|
186
|
+
LIMIT 1
|
|
187
|
+
`
|
|
188
|
+
)
|
|
189
|
+
.get(functionName);
|
|
190
|
+
|
|
191
|
+
if (!entity) {
|
|
192
|
+
return { error: `Function "${functionName}" not found` };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
result.entity = entity;
|
|
196
|
+
|
|
197
|
+
// Get callees (functions this function calls)
|
|
198
|
+
if (direction === 'callees' || direction === 'both') {
|
|
199
|
+
result.callees = this.getCallees(entity.id, depth);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Get callers (functions that call this function)
|
|
203
|
+
if (direction === 'callers' || direction === 'both') {
|
|
204
|
+
result.callers = this.getCallers(entity.id, depth);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get functions called by given function (recursive)
|
|
212
|
+
*/
|
|
213
|
+
getCallees(entityId, depth, visited = new Set()) {
|
|
214
|
+
if (depth <= 0 || visited.has(entityId)) return [];
|
|
215
|
+
visited.add(entityId);
|
|
216
|
+
|
|
217
|
+
const callees = this.db
|
|
218
|
+
.prepare(
|
|
219
|
+
`
|
|
220
|
+
SELECT e.id, e.name, e.file, e.start_line, r.type as relation_type
|
|
221
|
+
FROM relations r
|
|
222
|
+
JOIN entities e ON r.target_id = e.id
|
|
223
|
+
WHERE r.source_id = ?
|
|
224
|
+
AND r.type IN ('calls', 'invokes', 'references')
|
|
225
|
+
AND e.type = 'function'
|
|
226
|
+
`
|
|
227
|
+
)
|
|
228
|
+
.all(entityId);
|
|
229
|
+
|
|
230
|
+
return callees.map(callee => ({
|
|
231
|
+
...callee,
|
|
232
|
+
callees: depth > 1 ? this.getCallees(callee.id, depth - 1, visited) : [],
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get functions that call given function (recursive)
|
|
238
|
+
*/
|
|
239
|
+
getCallers(entityId, depth, visited = new Set()) {
|
|
240
|
+
if (depth <= 0 || visited.has(entityId)) return [];
|
|
241
|
+
visited.add(entityId);
|
|
242
|
+
|
|
243
|
+
const callers = this.db
|
|
244
|
+
.prepare(
|
|
245
|
+
`
|
|
246
|
+
SELECT e.id, e.name, e.file, e.start_line, r.type as relation_type
|
|
247
|
+
FROM relations r
|
|
248
|
+
JOIN entities e ON r.source_id = e.id
|
|
249
|
+
WHERE r.target_id = ?
|
|
250
|
+
AND r.type IN ('calls', 'invokes', 'references')
|
|
251
|
+
AND e.type = 'function'
|
|
252
|
+
`
|
|
253
|
+
)
|
|
254
|
+
.all(entityId);
|
|
255
|
+
|
|
256
|
+
return callers.map(caller => ({
|
|
257
|
+
...caller,
|
|
258
|
+
callers: depth > 1 ? this.getCallers(caller.id, depth - 1, visited) : [],
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Analyze impact of changes to specified files
|
|
264
|
+
*/
|
|
265
|
+
async analyzeImpact(changedFiles) {
|
|
266
|
+
this.ensureOpen();
|
|
267
|
+
|
|
268
|
+
const impact = {
|
|
269
|
+
changedFiles,
|
|
270
|
+
directlyAffected: new Set(),
|
|
271
|
+
transitivelyAffected: new Set(),
|
|
272
|
+
affectedTests: [],
|
|
273
|
+
affectedDocs: [],
|
|
274
|
+
riskLevel: 'low',
|
|
275
|
+
summary: {},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
for (const file of changedFiles) {
|
|
279
|
+
// Get all entities in changed file
|
|
280
|
+
const entities = this.db
|
|
281
|
+
.prepare(
|
|
282
|
+
`
|
|
283
|
+
SELECT id, name, type
|
|
284
|
+
FROM entities
|
|
285
|
+
WHERE file LIKE ?
|
|
286
|
+
`
|
|
287
|
+
)
|
|
288
|
+
.all(`%${file}%`);
|
|
289
|
+
|
|
290
|
+
for (const entity of entities) {
|
|
291
|
+
// Find all entities that depend on changed entities
|
|
292
|
+
const dependents = this.db
|
|
293
|
+
.prepare(
|
|
294
|
+
`
|
|
295
|
+
SELECT DISTINCT e.file, e.name, e.type
|
|
296
|
+
FROM relations r
|
|
297
|
+
JOIN entities e ON r.source_id = e.id
|
|
298
|
+
WHERE r.target_id = ?
|
|
299
|
+
`
|
|
300
|
+
)
|
|
301
|
+
.all(entity.id);
|
|
302
|
+
|
|
303
|
+
for (const dep of dependents) {
|
|
304
|
+
if (!changedFiles.includes(dep.file)) {
|
|
305
|
+
impact.directlyAffected.add(dep.file);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Convert Sets to arrays
|
|
312
|
+
impact.directlyAffected = [...impact.directlyAffected];
|
|
313
|
+
|
|
314
|
+
// Find transitive dependencies
|
|
315
|
+
const toCheck = [...impact.directlyAffected];
|
|
316
|
+
const checked = new Set(changedFiles);
|
|
317
|
+
|
|
318
|
+
while (toCheck.length > 0) {
|
|
319
|
+
const file = toCheck.pop();
|
|
320
|
+
if (checked.has(file)) continue;
|
|
321
|
+
checked.add(file);
|
|
322
|
+
|
|
323
|
+
const entities = this.db
|
|
324
|
+
.prepare(
|
|
325
|
+
`
|
|
326
|
+
SELECT id FROM entities WHERE file LIKE ?
|
|
327
|
+
`
|
|
328
|
+
)
|
|
329
|
+
.all(`%${file}%`);
|
|
330
|
+
|
|
331
|
+
for (const entity of entities) {
|
|
332
|
+
const dependents = this.db
|
|
333
|
+
.prepare(
|
|
334
|
+
`
|
|
335
|
+
SELECT DISTINCT e.file
|
|
336
|
+
FROM relations r
|
|
337
|
+
JOIN entities e ON r.source_id = e.id
|
|
338
|
+
WHERE r.target_id = ?
|
|
339
|
+
`
|
|
340
|
+
)
|
|
341
|
+
.all(entity.id);
|
|
342
|
+
|
|
343
|
+
for (const dep of dependents) {
|
|
344
|
+
if (!checked.has(dep.file) && !changedFiles.includes(dep.file)) {
|
|
345
|
+
impact.transitivelyAffected.add(dep.file);
|
|
346
|
+
toCheck.push(dep.file);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
impact.transitivelyAffected = [...impact.transitivelyAffected];
|
|
353
|
+
|
|
354
|
+
// Find affected tests
|
|
355
|
+
const allAffected = [...impact.directlyAffected, ...impact.transitivelyAffected];
|
|
356
|
+
impact.affectedTests = allAffected.filter(
|
|
357
|
+
f => f.includes('test') || f.includes('spec') || f.includes('__tests__')
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
// Calculate risk level
|
|
361
|
+
const totalAffected = allAffected.length;
|
|
362
|
+
if (totalAffected > 100) {
|
|
363
|
+
impact.riskLevel = 'critical';
|
|
364
|
+
} else if (totalAffected > 50) {
|
|
365
|
+
impact.riskLevel = 'high';
|
|
366
|
+
} else if (totalAffected > 20) {
|
|
367
|
+
impact.riskLevel = 'medium';
|
|
368
|
+
} else {
|
|
369
|
+
impact.riskLevel = 'low';
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Summary
|
|
373
|
+
impact.summary = {
|
|
374
|
+
changedFiles: changedFiles.length,
|
|
375
|
+
directlyAffected: impact.directlyAffected.length,
|
|
376
|
+
transitivelyAffected: impact.transitivelyAffected.length,
|
|
377
|
+
affectedTests: impact.affectedTests.length,
|
|
378
|
+
totalImpact: totalAffected,
|
|
379
|
+
riskLevel: impact.riskLevel,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
return impact;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get largest functions in the codebase
|
|
387
|
+
*/
|
|
388
|
+
getLargestFunctions(limit = 50) {
|
|
389
|
+
this.ensureOpen();
|
|
390
|
+
|
|
391
|
+
return this.db
|
|
392
|
+
.prepare(
|
|
393
|
+
`
|
|
394
|
+
SELECT
|
|
395
|
+
name,
|
|
396
|
+
file,
|
|
397
|
+
start_line,
|
|
398
|
+
end_line,
|
|
399
|
+
(end_line - start_line) as lines
|
|
400
|
+
FROM entities
|
|
401
|
+
WHERE type = 'function'
|
|
402
|
+
AND end_line > start_line
|
|
403
|
+
ORDER BY (end_line - start_line) DESC
|
|
404
|
+
LIMIT ?
|
|
405
|
+
`
|
|
406
|
+
)
|
|
407
|
+
.all(limit);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Get most connected entities (potential refactoring candidates)
|
|
412
|
+
*/
|
|
413
|
+
getMostConnected(limit = 50) {
|
|
414
|
+
this.ensureOpen();
|
|
415
|
+
|
|
416
|
+
return this.db
|
|
417
|
+
.prepare(
|
|
418
|
+
`
|
|
419
|
+
SELECT
|
|
420
|
+
e.name,
|
|
421
|
+
e.file,
|
|
422
|
+
e.type,
|
|
423
|
+
COUNT(DISTINCT r1.source_id) as incoming,
|
|
424
|
+
COUNT(DISTINCT r2.target_id) as outgoing,
|
|
425
|
+
COUNT(DISTINCT r1.source_id) + COUNT(DISTINCT r2.target_id) as total_connections
|
|
426
|
+
FROM entities e
|
|
427
|
+
LEFT JOIN relations r1 ON e.id = r1.target_id
|
|
428
|
+
LEFT JOIN relations r2 ON e.id = r2.source_id
|
|
429
|
+
GROUP BY e.id
|
|
430
|
+
ORDER BY total_connections DESC
|
|
431
|
+
LIMIT ?
|
|
432
|
+
`
|
|
433
|
+
)
|
|
434
|
+
.all(limit);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Find circular dependencies
|
|
439
|
+
*/
|
|
440
|
+
findCircularDependencies(maxDepth = 5) {
|
|
441
|
+
this.ensureOpen();
|
|
442
|
+
|
|
443
|
+
const cycles = [];
|
|
444
|
+
const visited = new Set();
|
|
445
|
+
|
|
446
|
+
// Get all modules
|
|
447
|
+
const modules = this.db
|
|
448
|
+
.prepare(
|
|
449
|
+
`
|
|
450
|
+
SELECT id, name, file FROM entities WHERE type = 'module' LIMIT 1000
|
|
451
|
+
`
|
|
452
|
+
)
|
|
453
|
+
.all();
|
|
454
|
+
|
|
455
|
+
for (const module of modules) {
|
|
456
|
+
const path = [module.file];
|
|
457
|
+
this.findCycles(module.id, path, visited, cycles, maxDepth);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return cycles;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Helper to find cycles (DFS)
|
|
465
|
+
*/
|
|
466
|
+
findCycles(entityId, path, visited, cycles, depth) {
|
|
467
|
+
if (depth <= 0) return;
|
|
468
|
+
if (visited.has(entityId)) return;
|
|
469
|
+
|
|
470
|
+
const deps = this.db
|
|
471
|
+
.prepare(
|
|
472
|
+
`
|
|
473
|
+
SELECT DISTINCT e.id, e.file
|
|
474
|
+
FROM relations r
|
|
475
|
+
JOIN entities e ON r.target_id = e.id
|
|
476
|
+
WHERE r.source_id = ?
|
|
477
|
+
AND e.type = 'module'
|
|
478
|
+
AND r.type IN ('imports', 'includes', 'requires')
|
|
479
|
+
`
|
|
480
|
+
)
|
|
481
|
+
.all(entityId);
|
|
482
|
+
|
|
483
|
+
for (const dep of deps) {
|
|
484
|
+
if (path.includes(dep.file)) {
|
|
485
|
+
const cycleStart = path.indexOf(dep.file);
|
|
486
|
+
cycles.push([...path.slice(cycleStart), dep.file]);
|
|
487
|
+
} else {
|
|
488
|
+
this.findCycles(dep.id, [...path, dep.file], visited, cycles, depth - 1);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
visited.add(entityId);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Get file dependencies
|
|
497
|
+
*/
|
|
498
|
+
getFileDependencies(filePath) {
|
|
499
|
+
this.ensureOpen();
|
|
500
|
+
|
|
501
|
+
const imports = this.db
|
|
502
|
+
.prepare(
|
|
503
|
+
`
|
|
504
|
+
SELECT DISTINCT
|
|
505
|
+
target.file as imported_file,
|
|
506
|
+
target.name as imported_name,
|
|
507
|
+
r.type as relation_type
|
|
508
|
+
FROM entities source
|
|
509
|
+
JOIN relations r ON source.id = r.source_id
|
|
510
|
+
JOIN entities target ON r.target_id = target.id
|
|
511
|
+
WHERE source.file LIKE ?
|
|
512
|
+
AND r.type IN ('imports', 'includes', 'requires', 'references')
|
|
513
|
+
AND target.type = 'module'
|
|
514
|
+
`
|
|
515
|
+
)
|
|
516
|
+
.all(`%${filePath}%`);
|
|
517
|
+
|
|
518
|
+
const exports = this.db
|
|
519
|
+
.prepare(
|
|
520
|
+
`
|
|
521
|
+
SELECT DISTINCT
|
|
522
|
+
source.file as importing_file,
|
|
523
|
+
source.name as importing_name,
|
|
524
|
+
r.type as relation_type
|
|
525
|
+
FROM entities target
|
|
526
|
+
JOIN relations r ON target.id = r.target_id
|
|
527
|
+
JOIN entities source ON r.source_id = source.id
|
|
528
|
+
WHERE target.file LIKE ?
|
|
529
|
+
AND r.type IN ('imports', 'includes', 'requires', 'references')
|
|
530
|
+
AND source.type = 'module'
|
|
531
|
+
`
|
|
532
|
+
)
|
|
533
|
+
.all(`%${filePath}%`);
|
|
534
|
+
|
|
535
|
+
return { imports, exports };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Search entities by pattern
|
|
540
|
+
*/
|
|
541
|
+
searchEntities(pattern, options = {}) {
|
|
542
|
+
this.ensureOpen();
|
|
543
|
+
|
|
544
|
+
const type = options.type || null;
|
|
545
|
+
const limit = options.limit || 100;
|
|
546
|
+
|
|
547
|
+
let query = `
|
|
548
|
+
SELECT id, name, type, file, start_line, end_line
|
|
549
|
+
FROM entities
|
|
550
|
+
WHERE name LIKE ?
|
|
551
|
+
`;
|
|
552
|
+
|
|
553
|
+
const params = [`%${pattern}%`];
|
|
554
|
+
|
|
555
|
+
if (type) {
|
|
556
|
+
query += ' AND type = ?';
|
|
557
|
+
params.push(type);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
query += ' ORDER BY name LIMIT ?';
|
|
561
|
+
params.push(limit);
|
|
562
|
+
|
|
563
|
+
return this.db.prepare(query).all(...params);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Get community information (if available)
|
|
568
|
+
*/
|
|
569
|
+
getCommunities() {
|
|
570
|
+
this.ensureOpen();
|
|
571
|
+
|
|
572
|
+
try {
|
|
573
|
+
return this.db
|
|
574
|
+
.prepare(
|
|
575
|
+
`
|
|
576
|
+
SELECT
|
|
577
|
+
community_id,
|
|
578
|
+
COUNT(*) as member_count,
|
|
579
|
+
GROUP_CONCAT(name, ', ') as members
|
|
580
|
+
FROM entities
|
|
581
|
+
WHERE community_id IS NOT NULL
|
|
582
|
+
GROUP BY community_id
|
|
583
|
+
ORDER BY member_count DESC
|
|
584
|
+
LIMIT 50
|
|
585
|
+
`
|
|
586
|
+
)
|
|
587
|
+
.all();
|
|
588
|
+
} catch (error) {
|
|
589
|
+
return { error: 'Community data not available. Re-index without --no-community flag.' };
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Ensure database is open
|
|
595
|
+
*/
|
|
596
|
+
ensureOpen() {
|
|
597
|
+
if (!this.db) {
|
|
598
|
+
this.open();
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Generate markdown report
|
|
604
|
+
*/
|
|
605
|
+
generateReport() {
|
|
606
|
+
const stats = this.getStats();
|
|
607
|
+
const largestFunctions = this.getLargestFunctions(20);
|
|
608
|
+
const mostConnected = this.getMostConnected(20);
|
|
609
|
+
|
|
610
|
+
let report = '# CodeGraph Analysis Report\n\n';
|
|
611
|
+
report += `**Generated**: ${new Date().toISOString()}\n`;
|
|
612
|
+
report += `**Repository**: ${this.repoPath}\n\n`;
|
|
613
|
+
|
|
614
|
+
report += '## Statistics\n\n';
|
|
615
|
+
report += `- Total Entities: ${stats.entities.toLocaleString()}\n`;
|
|
616
|
+
report += `- Total Files: ${stats.files.toLocaleString()}\n`;
|
|
617
|
+
report += `- Total Relations: ${stats.relations.toLocaleString()}\n\n`;
|
|
618
|
+
|
|
619
|
+
report += '### Entity Types\n\n';
|
|
620
|
+
report += '| Type | Count |\n|------|-------|\n';
|
|
621
|
+
for (const { type, count } of stats.entityTypes) {
|
|
622
|
+
report += `| ${type} | ${count.toLocaleString()} |\n`;
|
|
623
|
+
}
|
|
624
|
+
report += '\n';
|
|
625
|
+
|
|
626
|
+
report += '## Largest Functions (Refactoring Candidates)\n\n';
|
|
627
|
+
report += '| Function | File | Lines |\n|----------|------|-------|\n';
|
|
628
|
+
for (const func of largestFunctions) {
|
|
629
|
+
report += `| ${func.name} | ${func.file} | ${func.lines} |\n`;
|
|
630
|
+
}
|
|
631
|
+
report += '\n';
|
|
632
|
+
|
|
633
|
+
report += '## Most Connected Entities (High Coupling)\n\n';
|
|
634
|
+
report += '| Entity | Type | Connections |\n|--------|------|-------------|\n';
|
|
635
|
+
for (const entity of mostConnected) {
|
|
636
|
+
report += `| ${entity.name} | ${entity.type} | ${entity.total_connections} |\n`;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return report;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
module.exports = { CodeGraphIntegration };
|