spec-gen-cli 1.0.0
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/LICENSE +21 -0
- package/README.md +1078 -0
- package/dist/api/analyze.d.ts +17 -0
- package/dist/api/analyze.d.ts.map +1 -0
- package/dist/api/analyze.js +109 -0
- package/dist/api/analyze.js.map +1 -0
- package/dist/api/drift.d.ts +21 -0
- package/dist/api/drift.d.ts.map +1 -0
- package/dist/api/drift.js +145 -0
- package/dist/api/drift.js.map +1 -0
- package/dist/api/generate.d.ts +18 -0
- package/dist/api/generate.d.ts.map +1 -0
- package/dist/api/generate.js +251 -0
- package/dist/api/generate.js.map +1 -0
- package/dist/api/index.d.ts +39 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +32 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/init.d.ts +18 -0
- package/dist/api/init.d.ts.map +1 -0
- package/dist/api/init.js +82 -0
- package/dist/api/init.js.map +1 -0
- package/dist/api/run.d.ts +19 -0
- package/dist/api/run.d.ts.map +1 -0
- package/dist/api/run.js +291 -0
- package/dist/api/run.js.map +1 -0
- package/dist/api/specs.d.ts +49 -0
- package/dist/api/specs.d.ts.map +1 -0
- package/dist/api/specs.js +136 -0
- package/dist/api/specs.js.map +1 -0
- package/dist/api/types.d.ts +176 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +9 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/verify.d.ts +20 -0
- package/dist/api/verify.d.ts.map +1 -0
- package/dist/api/verify.js +117 -0
- package/dist/api/verify.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +27 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +485 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/drift.d.ts +9 -0
- package/dist/cli/commands/drift.d.ts.map +1 -0
- package/dist/cli/commands/drift.js +540 -0
- package/dist/cli/commands/drift.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +9 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +633 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +171 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +638 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +574 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/run.d.ts +24 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +546 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/verify.d.ts +9 -0
- package/dist/cli/commands/verify.d.ts.map +1 -0
- package/dist/cli/commands/verify.js +417 -0
- package/dist/cli/commands/verify.js.map +1 -0
- package/dist/cli/commands/view.d.ts +9 -0
- package/dist/cli/commands/view.d.ts.map +1 -0
- package/dist/cli/commands/view.js +511 -0
- package/dist/cli/commands/view.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +83 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/analyzer/architecture-writer.d.ts +67 -0
- package/dist/core/analyzer/architecture-writer.d.ts.map +1 -0
- package/dist/core/analyzer/architecture-writer.js +209 -0
- package/dist/core/analyzer/architecture-writer.js.map +1 -0
- package/dist/core/analyzer/artifact-generator.d.ts +222 -0
- package/dist/core/analyzer/artifact-generator.d.ts.map +1 -0
- package/dist/core/analyzer/artifact-generator.js +726 -0
- package/dist/core/analyzer/artifact-generator.js.map +1 -0
- package/dist/core/analyzer/call-graph.d.ts +83 -0
- package/dist/core/analyzer/call-graph.d.ts.map +1 -0
- package/dist/core/analyzer/call-graph.js +827 -0
- package/dist/core/analyzer/call-graph.js.map +1 -0
- package/dist/core/analyzer/code-shaper.d.ts +33 -0
- package/dist/core/analyzer/code-shaper.d.ts.map +1 -0
- package/dist/core/analyzer/code-shaper.js +149 -0
- package/dist/core/analyzer/code-shaper.js.map +1 -0
- package/dist/core/analyzer/dependency-graph.d.ts +179 -0
- package/dist/core/analyzer/dependency-graph.d.ts.map +1 -0
- package/dist/core/analyzer/dependency-graph.js +574 -0
- package/dist/core/analyzer/dependency-graph.js.map +1 -0
- package/dist/core/analyzer/duplicate-detector.d.ts +52 -0
- package/dist/core/analyzer/duplicate-detector.d.ts.map +1 -0
- package/dist/core/analyzer/duplicate-detector.js +279 -0
- package/dist/core/analyzer/duplicate-detector.js.map +1 -0
- package/dist/core/analyzer/embedding-service.d.ts +50 -0
- package/dist/core/analyzer/embedding-service.d.ts.map +1 -0
- package/dist/core/analyzer/embedding-service.js +104 -0
- package/dist/core/analyzer/embedding-service.js.map +1 -0
- package/dist/core/analyzer/file-walker.d.ts +78 -0
- package/dist/core/analyzer/file-walker.d.ts.map +1 -0
- package/dist/core/analyzer/file-walker.js +531 -0
- package/dist/core/analyzer/file-walker.js.map +1 -0
- package/dist/core/analyzer/import-parser.d.ts +91 -0
- package/dist/core/analyzer/import-parser.d.ts.map +1 -0
- package/dist/core/analyzer/import-parser.js +720 -0
- package/dist/core/analyzer/import-parser.js.map +1 -0
- package/dist/core/analyzer/index.d.ts +10 -0
- package/dist/core/analyzer/index.d.ts.map +1 -0
- package/dist/core/analyzer/index.js +10 -0
- package/dist/core/analyzer/index.js.map +1 -0
- package/dist/core/analyzer/refactor-analyzer.d.ts +80 -0
- package/dist/core/analyzer/refactor-analyzer.d.ts.map +1 -0
- package/dist/core/analyzer/refactor-analyzer.js +339 -0
- package/dist/core/analyzer/refactor-analyzer.js.map +1 -0
- package/dist/core/analyzer/repository-mapper.d.ts +150 -0
- package/dist/core/analyzer/repository-mapper.d.ts.map +1 -0
- package/dist/core/analyzer/repository-mapper.js +731 -0
- package/dist/core/analyzer/repository-mapper.js.map +1 -0
- package/dist/core/analyzer/signature-extractor.d.ts +31 -0
- package/dist/core/analyzer/signature-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/signature-extractor.js +387 -0
- package/dist/core/analyzer/signature-extractor.js.map +1 -0
- package/dist/core/analyzer/significance-scorer.d.ts +79 -0
- package/dist/core/analyzer/significance-scorer.d.ts.map +1 -0
- package/dist/core/analyzer/significance-scorer.js +407 -0
- package/dist/core/analyzer/significance-scorer.js.map +1 -0
- package/dist/core/analyzer/subgraph-extractor.d.ts +43 -0
- package/dist/core/analyzer/subgraph-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/subgraph-extractor.js +129 -0
- package/dist/core/analyzer/subgraph-extractor.js.map +1 -0
- package/dist/core/analyzer/vector-index.d.ts +63 -0
- package/dist/core/analyzer/vector-index.d.ts.map +1 -0
- package/dist/core/analyzer/vector-index.js +169 -0
- package/dist/core/analyzer/vector-index.js.map +1 -0
- package/dist/core/drift/drift-detector.d.ts +102 -0
- package/dist/core/drift/drift-detector.d.ts.map +1 -0
- package/dist/core/drift/drift-detector.js +597 -0
- package/dist/core/drift/drift-detector.js.map +1 -0
- package/dist/core/drift/git-diff.d.ts +55 -0
- package/dist/core/drift/git-diff.d.ts.map +1 -0
- package/dist/core/drift/git-diff.js +356 -0
- package/dist/core/drift/git-diff.js.map +1 -0
- package/dist/core/drift/index.d.ts +12 -0
- package/dist/core/drift/index.d.ts.map +1 -0
- package/dist/core/drift/index.js +9 -0
- package/dist/core/drift/index.js.map +1 -0
- package/dist/core/drift/spec-mapper.d.ts +73 -0
- package/dist/core/drift/spec-mapper.d.ts.map +1 -0
- package/dist/core/drift/spec-mapper.js +353 -0
- package/dist/core/drift/spec-mapper.js.map +1 -0
- package/dist/core/generator/adr-generator.d.ts +32 -0
- package/dist/core/generator/adr-generator.d.ts.map +1 -0
- package/dist/core/generator/adr-generator.js +192 -0
- package/dist/core/generator/adr-generator.js.map +1 -0
- package/dist/core/generator/index.d.ts +9 -0
- package/dist/core/generator/index.d.ts.map +1 -0
- package/dist/core/generator/index.js +12 -0
- package/dist/core/generator/index.js.map +1 -0
- package/dist/core/generator/mapping-generator.d.ts +54 -0
- package/dist/core/generator/mapping-generator.d.ts.map +1 -0
- package/dist/core/generator/mapping-generator.js +239 -0
- package/dist/core/generator/mapping-generator.js.map +1 -0
- package/dist/core/generator/openspec-compat.d.ts +160 -0
- package/dist/core/generator/openspec-compat.d.ts.map +1 -0
- package/dist/core/generator/openspec-compat.js +523 -0
- package/dist/core/generator/openspec-compat.js.map +1 -0
- package/dist/core/generator/openspec-format-generator.d.ts +111 -0
- package/dist/core/generator/openspec-format-generator.d.ts.map +1 -0
- package/dist/core/generator/openspec-format-generator.js +817 -0
- package/dist/core/generator/openspec-format-generator.js.map +1 -0
- package/dist/core/generator/openspec-writer.d.ts +131 -0
- package/dist/core/generator/openspec-writer.d.ts.map +1 -0
- package/dist/core/generator/openspec-writer.js +379 -0
- package/dist/core/generator/openspec-writer.js.map +1 -0
- package/dist/core/generator/prompts.d.ts +35 -0
- package/dist/core/generator/prompts.d.ts.map +1 -0
- package/dist/core/generator/prompts.js +212 -0
- package/dist/core/generator/prompts.js.map +1 -0
- package/dist/core/generator/spec-pipeline.d.ts +94 -0
- package/dist/core/generator/spec-pipeline.d.ts.map +1 -0
- package/dist/core/generator/spec-pipeline.js +474 -0
- package/dist/core/generator/spec-pipeline.js.map +1 -0
- package/dist/core/generator/stages/stage1-survey.d.ts +19 -0
- package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -0
- package/dist/core/generator/stages/stage1-survey.js +105 -0
- package/dist/core/generator/stages/stage1-survey.js.map +1 -0
- package/dist/core/generator/stages/stage2-entities.d.ts +11 -0
- package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -0
- package/dist/core/generator/stages/stage2-entities.js +67 -0
- package/dist/core/generator/stages/stage2-entities.js.map +1 -0
- package/dist/core/generator/stages/stage3-services.d.ts +11 -0
- package/dist/core/generator/stages/stage3-services.d.ts.map +1 -0
- package/dist/core/generator/stages/stage3-services.js +75 -0
- package/dist/core/generator/stages/stage3-services.js.map +1 -0
- package/dist/core/generator/stages/stage4-api.d.ts +11 -0
- package/dist/core/generator/stages/stage4-api.d.ts.map +1 -0
- package/dist/core/generator/stages/stage4-api.js +65 -0
- package/dist/core/generator/stages/stage4-api.js.map +1 -0
- package/dist/core/generator/stages/stage5-architecture.d.ts +10 -0
- package/dist/core/generator/stages/stage5-architecture.d.ts.map +1 -0
- package/dist/core/generator/stages/stage5-architecture.js +62 -0
- package/dist/core/generator/stages/stage5-architecture.js.map +1 -0
- package/dist/core/generator/stages/stage6-adr.d.ts +8 -0
- package/dist/core/generator/stages/stage6-adr.d.ts.map +1 -0
- package/dist/core/generator/stages/stage6-adr.js +41 -0
- package/dist/core/generator/stages/stage6-adr.js.map +1 -0
- package/dist/core/services/chat-agent.d.ts +45 -0
- package/dist/core/services/chat-agent.d.ts.map +1 -0
- package/dist/core/services/chat-agent.js +310 -0
- package/dist/core/services/chat-agent.js.map +1 -0
- package/dist/core/services/chat-tools.d.ts +32 -0
- package/dist/core/services/chat-tools.d.ts.map +1 -0
- package/dist/core/services/chat-tools.js +270 -0
- package/dist/core/services/chat-tools.js.map +1 -0
- package/dist/core/services/config-manager.d.ts +61 -0
- package/dist/core/services/config-manager.d.ts.map +1 -0
- package/dist/core/services/config-manager.js +143 -0
- package/dist/core/services/config-manager.js.map +1 -0
- package/dist/core/services/gitignore-manager.d.ts +29 -0
- package/dist/core/services/gitignore-manager.d.ts.map +1 -0
- package/dist/core/services/gitignore-manager.js +106 -0
- package/dist/core/services/gitignore-manager.js.map +1 -0
- package/dist/core/services/index.d.ts +8 -0
- package/dist/core/services/index.d.ts.map +1 -0
- package/dist/core/services/index.js +8 -0
- package/dist/core/services/index.js.map +1 -0
- package/dist/core/services/llm-service.d.ts +336 -0
- package/dist/core/services/llm-service.d.ts.map +1 -0
- package/dist/core/services/llm-service.js +1155 -0
- package/dist/core/services/llm-service.js.map +1 -0
- package/dist/core/services/mcp-handlers/analysis.d.ts +42 -0
- package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/analysis.js +300 -0
- package/dist/core/services/mcp-handlers/analysis.js.map +1 -0
- package/dist/core/services/mcp-handlers/graph.d.ts +65 -0
- package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/graph.js +509 -0
- package/dist/core/services/mcp-handlers/graph.js.map +1 -0
- package/dist/core/services/mcp-handlers/semantic.d.ts +38 -0
- package/dist/core/services/mcp-handlers/semantic.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/semantic.js +172 -0
- package/dist/core/services/mcp-handlers/semantic.js.map +1 -0
- package/dist/core/services/mcp-handlers/utils.d.ts +21 -0
- package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/utils.js +62 -0
- package/dist/core/services/mcp-handlers/utils.js.map +1 -0
- package/dist/core/services/project-detector.d.ts +32 -0
- package/dist/core/services/project-detector.d.ts.map +1 -0
- package/dist/core/services/project-detector.js +111 -0
- package/dist/core/services/project-detector.js.map +1 -0
- package/dist/core/verifier/index.d.ts +5 -0
- package/dist/core/verifier/index.d.ts.map +1 -0
- package/dist/core/verifier/index.js +5 -0
- package/dist/core/verifier/index.js.map +1 -0
- package/dist/core/verifier/verification-engine.d.ts +226 -0
- package/dist/core/verifier/verification-engine.d.ts.map +1 -0
- package/dist/core/verifier/verification-engine.js +681 -0
- package/dist/core/verifier/verification-engine.js.map +1 -0
- package/dist/types/index.d.ts +252 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/pipeline.d.ts +148 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +5 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/utils/errors.d.ts +51 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +128 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +149 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +331 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/progress.d.ts +142 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +280 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/prompts.d.ts +53 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +199 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/shutdown.d.ts +89 -0
- package/dist/utils/shutdown.d.ts.map +1 -0
- package/dist/utils/shutdown.js +237 -0
- package/dist/utils/shutdown.js.map +1 -0
- package/package.json +114 -0
- package/src/viewer/InteractiveGraphViewer.jsx +1486 -0
- package/src/viewer/app/index.html +17 -0
- package/src/viewer/app/main.jsx +13 -0
- package/src/viewer/components/ArchitectureView.jsx +177 -0
- package/src/viewer/components/ChatPanel.jsx +448 -0
- package/src/viewer/components/ClusterGraph.jsx +441 -0
- package/src/viewer/components/FilterBar.jsx +179 -0
- package/src/viewer/components/FlatGraph.jsx +275 -0
- package/src/viewer/components/MicroComponents.jsx +83 -0
- package/src/viewer/hooks/usePanZoom.js +79 -0
- package/src/viewer/utils/constants.js +47 -0
- package/src/viewer/utils/graph-helpers.js +291 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool handlers for semantic search and feature insertion:
|
|
3
|
+
* search_code, suggest_insertion_points.
|
|
4
|
+
*/
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { validateDirectory } from './utils.js';
|
|
7
|
+
import { readSpecGenConfig } from '../config-manager.js';
|
|
8
|
+
export function classifyRole(fanIn, fanOut, isHub, isEntryPoint) {
|
|
9
|
+
if (isEntryPoint)
|
|
10
|
+
return 'entry_point';
|
|
11
|
+
if (isHub)
|
|
12
|
+
return 'hub';
|
|
13
|
+
if (fanOut >= 5)
|
|
14
|
+
return 'orchestrator';
|
|
15
|
+
if (fanIn <= 1)
|
|
16
|
+
return 'utility';
|
|
17
|
+
return 'internal';
|
|
18
|
+
}
|
|
19
|
+
export function deriveStrategy(role) {
|
|
20
|
+
switch (role) {
|
|
21
|
+
case 'entry_point': return 'extend_entry_point';
|
|
22
|
+
case 'orchestrator': return 'add_orchestration_step';
|
|
23
|
+
case 'hub': return 'cross_cutting_hook';
|
|
24
|
+
case 'utility': return 'extract_shared_logic';
|
|
25
|
+
default: return 'call_alongside';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function buildReason(name, role, strategy, fanIn, fanOut) {
|
|
29
|
+
switch (strategy) {
|
|
30
|
+
case 'extend_entry_point':
|
|
31
|
+
return `${name} is an entry point (no internal callers). Add your feature here or create a sibling entry point that delegates to it.`;
|
|
32
|
+
case 'add_orchestration_step':
|
|
33
|
+
return `${name} orchestrates ${fanOut} downstream calls. Insert your feature as a new step in this pipeline.`;
|
|
34
|
+
case 'cross_cutting_hook':
|
|
35
|
+
return `${name} is called by ${fanIn} functions — adding logic here affects the entire callsite surface.`;
|
|
36
|
+
case 'extract_shared_logic':
|
|
37
|
+
return `${name} is a low-traffic utility. Shared logic for your feature can live here or be extracted alongside it.`;
|
|
38
|
+
default:
|
|
39
|
+
return `${name} is semantically close to your feature and operates in the same domain. Extend or call alongside it.`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Composite score = (1 - semanticDistance) * 0.6 + structuralBonus * 0.4 */
|
|
43
|
+
export function compositeScore(semanticDistance, role) {
|
|
44
|
+
const semantic = Math.max(0, 1 - semanticDistance);
|
|
45
|
+
const structuralBonus = {
|
|
46
|
+
entry_point: 1.0,
|
|
47
|
+
orchestrator: 0.8,
|
|
48
|
+
hub: 0.6,
|
|
49
|
+
internal: 0.4,
|
|
50
|
+
utility: 0.3,
|
|
51
|
+
};
|
|
52
|
+
return semantic * 0.6 + structuralBonus[role] * 0.4;
|
|
53
|
+
}
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// HANDLERS
|
|
56
|
+
// ============================================================================
|
|
57
|
+
/**
|
|
58
|
+
* Semantic search over the vector index built by "spec-gen analyze --embed".
|
|
59
|
+
*/
|
|
60
|
+
export async function handleSearchCode(directory, query, limit = 10, language, minFanIn) {
|
|
61
|
+
const absDir = await validateDirectory(directory);
|
|
62
|
+
const outputDir = join(absDir, '.spec-gen', 'analysis');
|
|
63
|
+
const { VectorIndex } = await import('../../analyzer/vector-index.js');
|
|
64
|
+
const { EmbeddingService } = await import('../../analyzer/embedding-service.js');
|
|
65
|
+
if (!VectorIndex.exists(outputDir)) {
|
|
66
|
+
return {
|
|
67
|
+
error: 'No vector index found. Run "spec-gen analyze --embed" first, ' +
|
|
68
|
+
'then configure EMBED_BASE_URL and EMBED_MODEL.',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
let embedSvc;
|
|
72
|
+
try {
|
|
73
|
+
embedSvc = EmbeddingService.fromEnv();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
const cfg = await readSpecGenConfig(absDir);
|
|
77
|
+
if (!cfg) {
|
|
78
|
+
return { error: 'No embedding configuration found. Set EMBED_BASE_URL and EMBED_MODEL env vars, or add an "embedding" section to .spec-gen/config.json.' };
|
|
79
|
+
}
|
|
80
|
+
const svcFromConfig = EmbeddingService.fromConfig(cfg);
|
|
81
|
+
if (!svcFromConfig) {
|
|
82
|
+
return { error: 'No embedding configuration found. Set EMBED_BASE_URL and EMBED_MODEL env vars, or add an "embedding" section to .spec-gen/config.json.' };
|
|
83
|
+
}
|
|
84
|
+
embedSvc = svcFromConfig;
|
|
85
|
+
}
|
|
86
|
+
limit = Math.max(1, Math.min(limit, 100));
|
|
87
|
+
const results = await VectorIndex.search(outputDir, query, embedSvc, { limit, language, minFanIn });
|
|
88
|
+
return {
|
|
89
|
+
query,
|
|
90
|
+
count: results.length,
|
|
91
|
+
results: results.map(r => ({
|
|
92
|
+
score: r.score,
|
|
93
|
+
name: r.record.name,
|
|
94
|
+
filePath: r.record.filePath,
|
|
95
|
+
className: r.record.className || undefined,
|
|
96
|
+
language: r.record.language,
|
|
97
|
+
signature: r.record.signature || undefined,
|
|
98
|
+
docstring: r.record.docstring || undefined,
|
|
99
|
+
fanIn: r.record.fanIn,
|
|
100
|
+
fanOut: r.record.fanOut,
|
|
101
|
+
isHub: r.record.isHub,
|
|
102
|
+
isEntryPoint: r.record.isEntryPoint,
|
|
103
|
+
})),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Find the best places in the codebase to implement a new feature.
|
|
108
|
+
*/
|
|
109
|
+
export async function handleSuggestInsertionPoints(directory, description, limit = 5, language) {
|
|
110
|
+
const absDir = await validateDirectory(directory);
|
|
111
|
+
const outputDir = join(absDir, '.spec-gen', 'analysis');
|
|
112
|
+
const { VectorIndex } = await import('../../analyzer/vector-index.js');
|
|
113
|
+
const { EmbeddingService } = await import('../../analyzer/embedding-service.js');
|
|
114
|
+
if (!VectorIndex.exists(outputDir)) {
|
|
115
|
+
return {
|
|
116
|
+
error: 'No vector index found. Run "spec-gen analyze --embed" first, ' +
|
|
117
|
+
'then configure EMBED_BASE_URL and EMBED_MODEL.',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
let embedSvc;
|
|
121
|
+
try {
|
|
122
|
+
embedSvc = EmbeddingService.fromEnv();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
const cfg = await readSpecGenConfig(absDir);
|
|
126
|
+
if (!cfg) {
|
|
127
|
+
return { error: 'No embedding configuration found. Set EMBED_BASE_URL and EMBED_MODEL env vars, or add an "embedding" section to .spec-gen/config.json.' };
|
|
128
|
+
}
|
|
129
|
+
const svcFromConfig = EmbeddingService.fromConfig(cfg);
|
|
130
|
+
if (!svcFromConfig) {
|
|
131
|
+
return { error: 'No embedding configuration found. Set EMBED_BASE_URL and EMBED_MODEL env vars, or add an "embedding" section to .spec-gen/config.json.' };
|
|
132
|
+
}
|
|
133
|
+
embedSvc = svcFromConfig;
|
|
134
|
+
}
|
|
135
|
+
limit = Math.max(1, Math.min(limit, 20));
|
|
136
|
+
const rawResults = await VectorIndex.search(outputDir, description, embedSvc, { limit: limit * 4, language });
|
|
137
|
+
const candidates = rawResults.map(r => {
|
|
138
|
+
const role = classifyRole(r.record.fanIn, r.record.fanOut, r.record.isHub, r.record.isEntryPoint);
|
|
139
|
+
const strategy = deriveStrategy(role);
|
|
140
|
+
const score = compositeScore(r.score, role);
|
|
141
|
+
return {
|
|
142
|
+
rank: 0,
|
|
143
|
+
score,
|
|
144
|
+
semanticDistance: r.score,
|
|
145
|
+
name: r.record.name,
|
|
146
|
+
filePath: r.record.filePath,
|
|
147
|
+
className: r.record.className || undefined,
|
|
148
|
+
language: r.record.language,
|
|
149
|
+
signature: r.record.signature || undefined,
|
|
150
|
+
docstring: r.record.docstring || undefined,
|
|
151
|
+
role, insertionStrategy: strategy,
|
|
152
|
+
reason: buildReason(r.record.name, role, strategy, r.record.fanIn, r.record.fanOut),
|
|
153
|
+
fanIn: r.record.fanIn, fanOut: r.record.fanOut,
|
|
154
|
+
isHub: r.record.isHub, isEntryPoint: r.record.isEntryPoint,
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
158
|
+
const top = candidates.slice(0, limit).map((c, i) => ({ ...c, rank: i + 1 }));
|
|
159
|
+
return {
|
|
160
|
+
description,
|
|
161
|
+
count: top.length,
|
|
162
|
+
candidates: top,
|
|
163
|
+
nextSteps: top.length > 0
|
|
164
|
+
? [
|
|
165
|
+
`Run get_function_skeleton on "${top[0].filePath}" to see the internal structure of ${top[0].name}`,
|
|
166
|
+
`Run get_subgraph on "${top[0].name}" to understand its call neighborhood`,
|
|
167
|
+
`After implementing, run check_spec_drift to verify the code matches the spec`,
|
|
168
|
+
]
|
|
169
|
+
: ['No candidates found. Try a broader description or run "spec-gen analyze --embed" to build the index.'],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=semantic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.js","sourceRoot":"","sources":["../../../../src/core/services/mcp-handlers/semantic.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAiCzD,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,MAAc,EAAE,KAAc,EAAE,YAAqB;IAC/F,IAAI,YAAY;QAAE,OAAO,aAAa,CAAC;IACvC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,cAAc,CAAC;IACvC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACjC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAmB;IAChD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,aAAa,CAAC,CAAE,OAAO,oBAAoB,CAAC;QACjD,KAAK,cAAc,CAAC,CAAC,OAAO,wBAAwB,CAAC;QACrD,KAAK,KAAK,CAAC,CAAU,OAAO,oBAAoB,CAAC;QACjD,KAAK,SAAS,CAAC,CAAM,OAAO,sBAAsB,CAAC;QACnD,OAAO,CAAC,CAAa,OAAO,gBAAgB,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,IAAmB,EACnB,QAA2B,EAC3B,KAAa,EACb,MAAc;IAEd,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,oBAAoB;YACvB,OAAO,GAAG,IAAI,uHAAuH,CAAC;QACxI,KAAK,wBAAwB;YAC3B,OAAO,GAAG,IAAI,iBAAiB,MAAM,wEAAwE,CAAC;QAChH,KAAK,oBAAoB;YACvB,OAAO,GAAG,IAAI,iBAAiB,KAAK,qEAAqE,CAAC;QAC5G,KAAK,sBAAsB;YACzB,OAAO,GAAG,IAAI,sGAAsG,CAAC;QACvH;YACE,OAAO,GAAG,IAAI,sGAAsG,CAAC;IACzH,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,gBAAwB,EAAE,IAAmB;IAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACnD,MAAM,eAAe,GAAkC;QACrD,WAAW,EAAG,GAAG;QACjB,YAAY,EAAE,GAAG;QACjB,GAAG,EAAW,GAAG;QACjB,QAAQ,EAAM,GAAG;QACjB,OAAO,EAAO,GAAG;KAClB,CAAC;IACF,OAAO,QAAQ,GAAG,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;AACtD,CAAC;AAED,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,KAAa,EACb,KAAK,GAAG,EAAE,EACV,QAAiB,EACjB,QAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IAExD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;IACvE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,qCAAqC,CAAC,CAAC;IAEjF,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,OAAO;YACL,KAAK,EACH,+DAA+D;gBAC/D,gDAAgD;SACnD,CAAC;IACJ,CAAC;IAED,IAAI,QAA+C,CAAC;IACpD,IAAI,CAAC;QACH,QAAQ,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,EAAE,KAAK,EAAE,wIAAwI,EAAE,CAAC;QAC7J,CAAC;QACD,MAAM,aAAa,GAAG,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,EAAE,KAAK,EAAE,wIAAwI,EAAE,CAAC;QAC7J,CAAC;QACD,QAAQ,GAAG,aAAa,CAAC;IAC3B,CAAC;IAED,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEpG,OAAO;QACL,KAAK;QACL,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI;YACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ;YAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,SAAS;YAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ;YAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,SAAS;YAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,SAAS;YAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;YACrB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;YACvB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;YACrB,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY;SACpC,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,SAAiB,EACjB,WAAmB,EACnB,KAAK,GAAG,CAAC,EACT,QAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IAExD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;IACvE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,qCAAqC,CAAC,CAAC;IAEjF,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,OAAO;YACL,KAAK,EACH,+DAA+D;gBAC/D,gDAAgD;SACnD,CAAC;IACJ,CAAC;IAED,IAAI,QAA+C,CAAC;IACpD,IAAI,CAAC;QACH,QAAQ,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,EAAE,KAAK,EAAE,wIAAwI,EAAE,CAAC;QAC7J,CAAC;QACD,MAAM,aAAa,GAAG,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,EAAE,KAAK,EAAE,wIAAwI,EAAE,CAAC;QAC7J,CAAC;QACD,QAAQ,GAAG,aAAa,CAAC;IAC3B,CAAC;IAED,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE9G,MAAM,UAAU,GAAyB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QAC1D,MAAM,IAAI,GAAO,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACtG,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,KAAK,GAAM,cAAc,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC/C,OAAO;YACL,IAAI,EAAE,CAAC;YACP,KAAK;YACL,gBAAgB,EAAE,CAAC,CAAC,KAAK;YACzB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI;YACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ;YAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,SAAS;YAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ;YAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,SAAS;YAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,SAAS;YAC1C,IAAI,EAAE,iBAAiB,EAAE,QAAQ;YACjC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;YACnF,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;YAC9C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY;SAC3D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAE9E,OAAO;QACL,WAAW;QACX,KAAK,EAAE,GAAG,CAAC,MAAM;QACjB,UAAU,EAAE,GAAG;QACf,SAAS,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC;YACvB,CAAC,CAAC;gBACE,iCAAiC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,sCAAsC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBACnG,wBAAwB,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,uCAAuC;gBAC1E,8EAA8E;aAC/E;YACH,CAAC,CAAC,CAAC,sGAAsG,CAAC;KAC7G,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for MCP tool handlers.
|
|
3
|
+
*/
|
|
4
|
+
import type { LLMContext } from '../../analyzer/artifact-generator.js';
|
|
5
|
+
/**
|
|
6
|
+
* Resolve and validate a user-supplied directory path.
|
|
7
|
+
*
|
|
8
|
+
* Ensures the path resolves to an existing directory, which prevents path
|
|
9
|
+
* traversal attacks where a client supplies `"../../../../etc"` or a plain
|
|
10
|
+
* file path instead of a project directory.
|
|
11
|
+
*/
|
|
12
|
+
export declare function validateDirectory(directory: string): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Strip common API key and token patterns from an error message before
|
|
15
|
+
* returning it to MCP clients, to prevent secret leakage via error responses.
|
|
16
|
+
*/
|
|
17
|
+
export declare function sanitizeMcpError(err: unknown): string;
|
|
18
|
+
export declare function readCachedContext(directory: string): Promise<LLMContext | null>;
|
|
19
|
+
/** Returns true if the cached analysis is present and less than 1 hour old. */
|
|
20
|
+
export declare function isCacheFresh(directory: string): Promise<boolean>;
|
|
21
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/core/services/mcp-handlers/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAEvE;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAe1E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAQrD;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAUrF;AAED,+EAA+E;AAC/E,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOtE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for MCP tool handlers.
|
|
3
|
+
*/
|
|
4
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
/**
|
|
7
|
+
* Resolve and validate a user-supplied directory path.
|
|
8
|
+
*
|
|
9
|
+
* Ensures the path resolves to an existing directory, which prevents path
|
|
10
|
+
* traversal attacks where a client supplies `"../../../../etc"` or a plain
|
|
11
|
+
* file path instead of a project directory.
|
|
12
|
+
*/
|
|
13
|
+
export async function validateDirectory(directory) {
|
|
14
|
+
if (!directory || typeof directory !== 'string') {
|
|
15
|
+
throw new Error('directory parameter is required and must be a string');
|
|
16
|
+
}
|
|
17
|
+
const absDir = resolve(directory);
|
|
18
|
+
let s;
|
|
19
|
+
try {
|
|
20
|
+
s = await stat(absDir);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error(`Directory not found: ${absDir}`);
|
|
24
|
+
}
|
|
25
|
+
if (!s.isDirectory()) {
|
|
26
|
+
throw new Error(`Not a directory: ${absDir}`);
|
|
27
|
+
}
|
|
28
|
+
return absDir;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Strip common API key and token patterns from an error message before
|
|
32
|
+
* returning it to MCP clients, to prevent secret leakage via error responses.
|
|
33
|
+
*/
|
|
34
|
+
export function sanitizeMcpError(err) {
|
|
35
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
36
|
+
return msg
|
|
37
|
+
.replace(/sk-ant-[A-Za-z0-9\-_]{10,}/g, '[REDACTED]')
|
|
38
|
+
.replace(/sk-[A-Za-z0-9\-_]{20,}/g, '[REDACTED]')
|
|
39
|
+
.replace(/Bearer\s+\S{10,}/g, 'Bearer [REDACTED]')
|
|
40
|
+
.replace(/Authorization:\s*\S+/gi, 'Authorization: [REDACTED]')
|
|
41
|
+
.replace(/api[_-]?key[=:]\s*\S{8,}/gi, 'api_key=[REDACTED]');
|
|
42
|
+
}
|
|
43
|
+
export async function readCachedContext(directory) {
|
|
44
|
+
try {
|
|
45
|
+
const raw = await readFile(join(directory, '.spec-gen', 'analysis', 'llm-context.json'), 'utf-8');
|
|
46
|
+
return JSON.parse(raw);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Returns true if the cached analysis is present and less than 1 hour old. */
|
|
53
|
+
export async function isCacheFresh(directory) {
|
|
54
|
+
try {
|
|
55
|
+
const s = await stat(join(directory, '.spec-gen', 'analysis', 'llm-context.json'));
|
|
56
|
+
return Date.now() - s.mtimeMs < 60 * 60 * 1000;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/core/services/mcp-handlers/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,CAAmC,CAAC;IACxC,IAAI,CAAC;QACH,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO,GAAG;SACP,OAAO,CAAC,6BAA6B,EAAE,YAAY,CAAC;SACpD,OAAO,CAAC,yBAAyB,EAAE,YAAY,CAAC;SAChD,OAAO,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;SACjD,OAAO,CAAC,wBAAwB,EAAE,2BAA2B,CAAC;SAC9D,OAAO,CAAC,4BAA4B,EAAE,oBAAoB,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CACxB,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,CAAC,EAC5D,OAAO,CACR,CAAC;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB;IAClD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACnF,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project type detection service
|
|
3
|
+
*
|
|
4
|
+
* Detects the project type by checking for language-specific manifest files.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProjectType } from '../../types/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Project detection result
|
|
9
|
+
*/
|
|
10
|
+
export interface ProjectDetectionResult {
|
|
11
|
+
projectType: ProjectType;
|
|
12
|
+
manifestFile: string | null;
|
|
13
|
+
hasGit: boolean;
|
|
14
|
+
confidence: 'high' | 'medium' | 'low';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detect if the directory is a git repository
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectGitRepository(rootPath: string): Promise<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Detect the project type based on manifest files
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectProjectType(rootPath: string): Promise<ProjectDetectionResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Get a human-readable project type name
|
|
26
|
+
*/
|
|
27
|
+
export declare function getProjectTypeName(type: ProjectType): string;
|
|
28
|
+
/**
|
|
29
|
+
* Read and parse package.json if it exists
|
|
30
|
+
*/
|
|
31
|
+
export declare function readPackageJson(rootPath: string): Promise<Record<string, unknown> | null>;
|
|
32
|
+
//# sourceMappingURL=project-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-detector.d.ts","sourceRoot":"","sources":["../../../src/core/services/project-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACvC;AA+BD;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE5E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA0CzF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAY5D;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAQzC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project type detection service
|
|
3
|
+
*
|
|
4
|
+
* Detects the project type by checking for language-specific manifest files.
|
|
5
|
+
*/
|
|
6
|
+
import { access, readFile } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
/**
|
|
9
|
+
* Manifest file to project type mapping
|
|
10
|
+
*/
|
|
11
|
+
const MANIFEST_MAP = [
|
|
12
|
+
{ file: 'package.json', type: 'nodejs', priority: 1 },
|
|
13
|
+
{ file: 'pyproject.toml', type: 'python', priority: 1 },
|
|
14
|
+
{ file: 'setup.py', type: 'python', priority: 2 },
|
|
15
|
+
{ file: 'requirements.txt', type: 'python', priority: 3 },
|
|
16
|
+
{ file: 'Cargo.toml', type: 'rust', priority: 1 },
|
|
17
|
+
{ file: 'go.mod', type: 'go', priority: 1 },
|
|
18
|
+
{ file: 'pom.xml', type: 'java', priority: 1 },
|
|
19
|
+
{ file: 'build.gradle', type: 'java', priority: 2 },
|
|
20
|
+
{ file: 'build.gradle.kts', type: 'java', priority: 2 },
|
|
21
|
+
{ file: 'Gemfile', type: 'ruby', priority: 1 },
|
|
22
|
+
{ file: 'composer.json', type: 'php', priority: 1 },
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Check if a file exists
|
|
26
|
+
*/
|
|
27
|
+
async function fileExists(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
await access(filePath);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Detect if the directory is a git repository
|
|
38
|
+
*/
|
|
39
|
+
export async function detectGitRepository(rootPath) {
|
|
40
|
+
return fileExists(join(rootPath, '.git'));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Detect the project type based on manifest files
|
|
44
|
+
*/
|
|
45
|
+
export async function detectProjectType(rootPath) {
|
|
46
|
+
const hasGit = await detectGitRepository(rootPath);
|
|
47
|
+
// Check each manifest file
|
|
48
|
+
const detectedManifests = [];
|
|
49
|
+
for (const manifest of MANIFEST_MAP) {
|
|
50
|
+
if (await fileExists(join(rootPath, manifest.file))) {
|
|
51
|
+
detectedManifests.push(manifest);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// No manifests found
|
|
55
|
+
if (detectedManifests.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
projectType: 'unknown',
|
|
58
|
+
manifestFile: null,
|
|
59
|
+
hasGit,
|
|
60
|
+
confidence: 'low',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Sort by priority (lower is better) and pick the first
|
|
64
|
+
detectedManifests.sort((a, b) => a.priority - b.priority);
|
|
65
|
+
const primary = detectedManifests[0];
|
|
66
|
+
// Determine confidence based on detection
|
|
67
|
+
let confidence = 'high';
|
|
68
|
+
if (detectedManifests.length > 1) {
|
|
69
|
+
// Multiple project types detected
|
|
70
|
+
const uniqueTypes = new Set(detectedManifests.map((m) => m.type));
|
|
71
|
+
if (uniqueTypes.size > 1) {
|
|
72
|
+
confidence = 'medium';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
projectType: primary.type,
|
|
77
|
+
manifestFile: primary.file,
|
|
78
|
+
hasGit,
|
|
79
|
+
confidence,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get a human-readable project type name
|
|
84
|
+
*/
|
|
85
|
+
export function getProjectTypeName(type) {
|
|
86
|
+
const names = {
|
|
87
|
+
nodejs: 'Node.js/TypeScript',
|
|
88
|
+
python: 'Python',
|
|
89
|
+
rust: 'Rust',
|
|
90
|
+
go: 'Go',
|
|
91
|
+
java: 'Java',
|
|
92
|
+
ruby: 'Ruby',
|
|
93
|
+
php: 'PHP',
|
|
94
|
+
unknown: 'Unknown',
|
|
95
|
+
};
|
|
96
|
+
return names[type];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Read and parse package.json if it exists
|
|
100
|
+
*/
|
|
101
|
+
export async function readPackageJson(rootPath) {
|
|
102
|
+
const packagePath = join(rootPath, 'package.json');
|
|
103
|
+
try {
|
|
104
|
+
const content = await readFile(packagePath, 'utf-8');
|
|
105
|
+
return JSON.parse(content);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=project-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-detector.js","sourceRoot":"","sources":["../../../src/core/services/project-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/verifier/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,0BAA0B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/verifier/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,0BAA0B,CAAC"}
|