@mycodemap/mycodemap 0.4.1 → 0.4.2
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/CHANGELOG.md +11 -0
- package/README.md +214 -221
- package/dist/cli/commands/analyze-options.d.ts +36 -0
- package/dist/cli/commands/analyze-options.d.ts.map +1 -0
- package/dist/cli/commands/analyze-options.js +147 -0
- package/dist/cli/commands/analyze-options.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +93 -4
- package/dist/cli/commands/analyze.d.ts.map +1 -1
- package/dist/cli/commands/analyze.js +592 -176
- package/dist/cli/commands/analyze.js.map +1 -1
- package/dist/cli/commands/ci.d.ts +47 -1
- package/dist/cli/commands/ci.d.ts.map +1 -1
- package/dist/cli/commands/ci.js +208 -1
- package/dist/cli/commands/ci.js.map +1 -1
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +2 -2
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/generate.d.ts +8 -2
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +151 -22
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +2 -13
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/ship/checker.d.ts.map +1 -1
- package/dist/cli/commands/ship/checker.js +0 -3
- package/dist/cli/commands/ship/checker.js.map +1 -1
- package/dist/cli/commands/ship/rules/quality-rules.d.ts +0 -1
- package/dist/cli/commands/ship/rules/quality-rules.d.ts.map +1 -1
- package/dist/cli/commands/ship/rules/quality-rules.js +4 -76
- package/dist/cli/commands/ship/rules/quality-rules.js.map +1 -1
- package/dist/cli/commands/workflow.js +4 -4
- package/dist/cli/commands/workflow.js.map +1 -1
- package/dist/cli/config-loader.d.ts +31 -0
- package/dist/cli/config-loader.d.ts.map +1 -0
- package/dist/cli/config-loader.js +235 -0
- package/dist/cli/config-loader.js.map +1 -0
- package/dist/cli/index.js +18 -63
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/removed-commands.d.ts +9 -0
- package/dist/cli/removed-commands.d.ts.map +1 -0
- package/dist/cli/removed-commands.js +48 -0
- package/dist/cli/removed-commands.js.map +1 -0
- package/dist/cli/storage-runtime.d.ts +8 -0
- package/dist/cli/storage-runtime.d.ts.map +1 -0
- package/dist/cli/storage-runtime.js +14 -0
- package/dist/cli/storage-runtime.js.map +1 -0
- package/dist/cli/tree-sitter-check.d.ts.map +1 -1
- package/dist/cli/tree-sitter-check.js +0 -1
- package/dist/cli/tree-sitter-check.js.map +1 -1
- package/dist/cli-new/commands/export.d.ts.map +1 -1
- package/dist/cli-new/commands/export.js +2 -2
- package/dist/cli-new/commands/export.js.map +1 -1
- package/dist/cli-new/commands/query.d.ts.map +1 -1
- package/dist/cli-new/commands/query.js +5 -4
- package/dist/cli-new/commands/query.js.map +1 -1
- package/dist/cli-new/index.d.ts.map +1 -1
- package/dist/cli-new/index.js +0 -2
- package/dist/cli-new/index.js.map +1 -1
- package/dist/core/analyzer.d.ts.map +1 -1
- package/dist/core/analyzer.js +7 -39
- package/dist/core/analyzer.js.map +1 -1
- package/dist/core/file-discovery.d.ts +17 -0
- package/dist/core/file-discovery.d.ts.map +1 -0
- package/dist/core/file-discovery.js +75 -0
- package/dist/core/file-discovery.js.map +1 -0
- package/dist/core/global-index.d.ts +5 -0
- package/dist/core/global-index.d.ts.map +1 -1
- package/dist/core/global-index.js +71 -21
- package/dist/core/global-index.js.map +1 -1
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +8 -0
- package/dist/generator/index.js.map +1 -1
- package/dist/infrastructure/parser/implementations/GoParser.d.ts +2 -5
- package/dist/infrastructure/parser/implementations/GoParser.d.ts.map +1 -1
- package/dist/infrastructure/parser/implementations/GoParser.js +2 -5
- package/dist/infrastructure/parser/implementations/GoParser.js.map +1 -1
- package/dist/infrastructure/parser/implementations/PythonParser.d.ts +1 -5
- package/dist/infrastructure/parser/implementations/PythonParser.d.ts.map +1 -1
- package/dist/infrastructure/parser/implementations/PythonParser.js +1 -5
- package/dist/infrastructure/parser/implementations/PythonParser.js.map +1 -1
- package/dist/infrastructure/parser/implementations/TypeScriptParser.d.ts +1 -5
- package/dist/infrastructure/parser/implementations/TypeScriptParser.d.ts.map +1 -1
- package/dist/infrastructure/parser/implementations/TypeScriptParser.js +1 -5
- package/dist/infrastructure/parser/implementations/TypeScriptParser.js.map +1 -1
- package/dist/infrastructure/storage/StorageFactory.d.ts +0 -1
- package/dist/infrastructure/storage/StorageFactory.d.ts.map +1 -1
- package/dist/infrastructure/storage/StorageFactory.js +4 -29
- package/dist/infrastructure/storage/StorageFactory.js.map +1 -1
- package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts.map +1 -1
- package/dist/infrastructure/storage/adapters/FileSystemStorage.js +24 -137
- package/dist/infrastructure/storage/adapters/FileSystemStorage.js.map +1 -1
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts +10 -18
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts.map +1 -1
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.js +103 -146
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.js.map +1 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts +0 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts.map +1 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.js +16 -136
- package/dist/infrastructure/storage/adapters/MemoryStorage.js.map +1 -1
- package/dist/infrastructure/storage/graph-helpers.d.ts +16 -0
- package/dist/infrastructure/storage/graph-helpers.d.ts.map +1 -0
- package/dist/infrastructure/storage/graph-helpers.js +161 -0
- package/dist/infrastructure/storage/graph-helpers.js.map +1 -0
- package/dist/infrastructure/storage/index.d.ts.map +1 -1
- package/dist/interface/config/index.d.ts +10 -1
- package/dist/interface/config/index.d.ts.map +1 -1
- package/dist/interface/types/index.d.ts +13 -0
- package/dist/interface/types/index.d.ts.map +1 -1
- package/dist/interface/types/storage.d.ts +1 -4
- package/dist/interface/types/storage.d.ts.map +1 -1
- package/dist/orchestrator/confidence.d.ts +9 -9
- package/dist/orchestrator/confidence.d.ts.map +1 -1
- package/dist/orchestrator/confidence.js +44 -67
- package/dist/orchestrator/confidence.js.map +1 -1
- package/dist/orchestrator/file-header-scanner.d.ts.map +1 -1
- package/dist/orchestrator/file-header-scanner.js +22 -31
- package/dist/orchestrator/file-header-scanner.js.map +1 -1
- package/dist/orchestrator/intent-router.d.ts +2 -11
- package/dist/orchestrator/intent-router.d.ts.map +1 -1
- package/dist/orchestrator/intent-router.js +58 -49
- package/dist/orchestrator/intent-router.js.map +1 -1
- package/dist/orchestrator/tool-orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/tool-orchestrator.js +6 -4
- package/dist/orchestrator/tool-orchestrator.js.map +1 -1
- package/dist/orchestrator/types.d.ts +113 -2
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/orchestrator/types.js +29 -0
- package/dist/orchestrator/types.js.map +1 -1
- package/dist/orchestrator/workflow/config.d.ts +4 -12
- package/dist/orchestrator/workflow/config.d.ts.map +1 -1
- package/dist/orchestrator/workflow/config.js +4 -6
- package/dist/orchestrator/workflow/config.js.map +1 -1
- package/dist/orchestrator/workflow/git-analyzer.d.ts.map +1 -1
- package/dist/orchestrator/workflow/git-analyzer.js +9 -19
- package/dist/orchestrator/workflow/git-analyzer.js.map +1 -1
- package/dist/orchestrator/workflow/phase-inheritance.d.ts.map +1 -1
- package/dist/orchestrator/workflow/phase-inheritance.js +14 -23
- package/dist/orchestrator/workflow/phase-inheritance.js.map +1 -1
- package/dist/orchestrator/workflow/result-fusion.d.ts.map +1 -1
- package/dist/orchestrator/workflow/result-fusion.js +9 -11
- package/dist/orchestrator/workflow/result-fusion.js.map +1 -1
- package/dist/orchestrator/workflow/templates.d.ts +4 -1
- package/dist/orchestrator/workflow/templates.d.ts.map +1 -1
- package/dist/orchestrator/workflow/templates.js +49 -207
- package/dist/orchestrator/workflow/templates.js.map +1 -1
- package/dist/orchestrator/workflow/test-linker.d.ts.map +1 -1
- package/dist/orchestrator/workflow/test-linker.js +12 -24
- package/dist/orchestrator/workflow/test-linker.js.map +1 -1
- package/dist/orchestrator/workflow/types.d.ts +11 -8
- package/dist/orchestrator/workflow/types.d.ts.map +1 -1
- package/dist/orchestrator/workflow/types.js +8 -1
- package/dist/orchestrator/workflow/types.js.map +1 -1
- package/dist/orchestrator/workflow/visualizer.d.ts.map +1 -1
- package/dist/orchestrator/workflow/visualizer.js +7 -9
- package/dist/orchestrator/workflow/visualizer.js.map +1 -1
- package/dist/orchestrator/workflow/workflow-context.d.ts.map +1 -1
- package/dist/orchestrator/workflow/workflow-context.js +3 -5
- package/dist/orchestrator/workflow/workflow-context.js.map +1 -1
- package/dist/orchestrator/workflow/workflow-orchestrator.d.ts +0 -4
- package/dist/orchestrator/workflow/workflow-orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/workflow/workflow-orchestrator.js +7 -99
- package/dist/orchestrator/workflow/workflow-orchestrator.js.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +2 -2
- package/dist/parser/index.js.map +1 -1
- package/dist/plugins/index.d.ts +5 -3
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +19 -8
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin-loader.d.ts +21 -6
- package/dist/plugins/plugin-loader.d.ts.map +1 -1
- package/dist/plugins/plugin-loader.js +170 -54
- package/dist/plugins/plugin-loader.js.map +1 -1
- package/dist/plugins/plugin-registry.d.ts +7 -4
- package/dist/plugins/plugin-registry.d.ts.map +1 -1
- package/dist/plugins/plugin-registry.js +62 -14
- package/dist/plugins/plugin-registry.js.map +1 -1
- package/dist/plugins/types.d.ts +16 -6
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -1
- package/dist/server/handlers/AnalysisHandler.d.ts +16 -2
- package/dist/server/handlers/AnalysisHandler.d.ts.map +1 -1
- package/dist/server/handlers/AnalysisHandler.js +31 -47
- package/dist/server/handlers/AnalysisHandler.js.map +1 -1
- package/dist/server/routes/api.d.ts.map +1 -1
- package/dist/server/routes/api.js +31 -12
- package/dist/server/routes/api.js.map +1 -1
- package/docs/AI_ASSISTANT_SETUP.md +3 -1
- package/docs/SETUP_GUIDE.md +41 -17
- package/docs/ai-guide/COMMANDS.md +106 -102
- package/docs/ai-guide/INTEGRATION.md +23 -21
- package/docs/ai-guide/OUTPUT.md +206 -10
- package/docs/ai-guide/PATTERNS.md +64 -15
- package/docs/ai-guide/PROMPTS.md +12 -12
- package/docs/ai-guide/QUICKSTART.md +35 -19
- package/docs/ai-guide/README.md +22 -4
- package/docs/product-specs/MVP3-ARCHITECTURE-COMPARISON.md +159 -434
- package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-PRD.md +169 -261
- package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-TECH-PRD.md +201 -1259
- package/docs/product-specs/README.md +8 -1
- package/docs/rules/architecture-guardrails.md +1 -2
- package/docs/rules/engineering-with-codex-openai.md +15 -9
- package/docs/rules/validation.md +26 -4
- package/mycodemap.config.schema.json +76 -5
- package/package.json +1 -1
- package/scripts/sync-analyze-docs.js +500 -0
- package/scripts/validate-ai-docs.js +54 -1
- package/scripts/validate-docs.js +746 -26
- package/dist/cli/commands/server.d.ts +0 -9
- package/dist/cli/commands/server.d.ts.map +0 -1
- package/dist/cli/commands/server.js +0 -68
- package/dist/cli/commands/server.js.map +0 -1
- package/dist/cli-new/commands/server.d.ts +0 -13
- package/dist/cli-new/commands/server.d.ts.map +0 -1
- package/dist/cli-new/commands/server.js +0 -94
- package/dist/cli-new/commands/server.js.map +0 -1
- package/dist/infrastructure/storage/adapters/Neo4jStorage.d.ts +0 -49
- package/dist/infrastructure/storage/adapters/Neo4jStorage.d.ts.map +0 -1
- package/dist/infrastructure/storage/adapters/Neo4jStorage.js +0 -222
- package/dist/infrastructure/storage/adapters/Neo4jStorage.js.map +0 -1
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
* [META] AnalyzeCommand - 统一分析入口
|
|
3
3
|
* [WHY] 为 CI 与人工调用提供统一分析输出,支持 machine/json 契约
|
|
4
4
|
*/
|
|
5
|
+
import { readFile } from 'node:fs/promises';
|
|
6
|
+
import path from 'node:path';
|
|
5
7
|
import { parseArgs } from 'node:util';
|
|
6
8
|
import chalk from 'chalk';
|
|
7
9
|
import { ImpactCommand } from './impact.js';
|
|
8
10
|
import { DepsCommand } from './deps.js';
|
|
9
11
|
import { ComplexityCommand } from './complexity.js';
|
|
12
|
+
import { ANALYZE_PARSE_OPTIONS, getAnalyzeHelpText } from './analyze-options.js';
|
|
13
|
+
import { PUBLIC_INTENTS, calculateConfidenceLevel } from '../../orchestrator/types.js';
|
|
10
14
|
import { resolveTestFile } from '../../orchestrator/test-linker.js';
|
|
11
15
|
import { ToolOrchestrator } from '../../orchestrator/tool-orchestrator.js';
|
|
12
16
|
import { ResultFusion } from '../../orchestrator/result-fusion.js';
|
|
13
17
|
import { CodemapAdapter } from '../../orchestrator/adapters/codemap-adapter.js';
|
|
14
18
|
import { AstGrepAdapter } from '../../orchestrator/adapters/ast-grep-adapter.js';
|
|
15
19
|
import { IntentRouter } from '../../orchestrator/intent-router.js';
|
|
16
|
-
import { resolveOutputDir } from '../paths.js';
|
|
20
|
+
import { resolveDataPath, resolveOutputDir } from '../paths.js';
|
|
17
21
|
/**
|
|
18
22
|
* 错误码定义
|
|
19
23
|
*/
|
|
@@ -47,14 +51,7 @@ export const ERROR_MESSAGES = {
|
|
|
47
51
|
* 支持的 intent 列表
|
|
48
52
|
*/
|
|
49
53
|
export const VALID_INTENTS = [
|
|
50
|
-
|
|
51
|
-
'dependency',
|
|
52
|
-
'search',
|
|
53
|
-
'documentation',
|
|
54
|
-
'complexity',
|
|
55
|
-
'overview',
|
|
56
|
-
'refactor',
|
|
57
|
-
'reference',
|
|
54
|
+
...PUBLIC_INTENTS,
|
|
58
55
|
];
|
|
59
56
|
/**
|
|
60
57
|
* AnalyzeCommand 分析命令类
|
|
@@ -73,12 +70,30 @@ export class AnalyzeCommand {
|
|
|
73
70
|
* @throws AnalyzeError 当参数无效时
|
|
74
71
|
*/
|
|
75
72
|
validate() {
|
|
73
|
+
if (!this.args.intent) {
|
|
74
|
+
throw this.createError(AnalyzeErrorCode.E0002_MISSING_REQUIRED_PARAM, '缺少必要参数: intent');
|
|
75
|
+
}
|
|
76
|
+
const intentRouter = new IntentRouter();
|
|
76
77
|
// 验证 intent
|
|
77
|
-
if (
|
|
78
|
+
if (!intentRouter.isValidIntent(this.args.intent)) {
|
|
78
79
|
throw this.createError(AnalyzeErrorCode.E0001_INVALID_INTENT, `无效的 intent: ${this.args.intent}。支持的选项: ${VALID_INTENTS.join(', ')}`);
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
const routedIntent = intentRouter.route(this.args);
|
|
82
|
+
const normalizedIntent = routedIntent.intent;
|
|
83
|
+
const hasTargets = Boolean(this.args.targets && this.args.targets.length > 0);
|
|
84
|
+
const hasKeywords = Boolean(this.args.keywords && this.args.keywords.length > 0);
|
|
85
|
+
if (normalizedIntent === 'find') {
|
|
86
|
+
if (!hasTargets && !hasKeywords) {
|
|
87
|
+
throw this.createError(AnalyzeErrorCode.E0002_MISSING_REQUIRED_PARAM, '缺少必要参数: targets 或 keywords');
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (normalizedIntent === 'link' &&
|
|
92
|
+
routedIntent.compatibility?.normalizedFrom === 'reference' &&
|
|
93
|
+
hasKeywords) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!hasTargets) {
|
|
82
97
|
throw this.createError(AnalyzeErrorCode.E0002_MISSING_REQUIRED_PARAM, '缺少必要参数: targets');
|
|
83
98
|
}
|
|
84
99
|
}
|
|
@@ -95,33 +110,39 @@ export class AnalyzeCommand {
|
|
|
95
110
|
*/
|
|
96
111
|
async execute() {
|
|
97
112
|
this.validate();
|
|
98
|
-
const
|
|
99
|
-
const
|
|
113
|
+
const intentRouter = new IntentRouter();
|
|
114
|
+
const intentObj = intentRouter.route(this.args);
|
|
115
|
+
const scope = intentObj.scope;
|
|
100
116
|
const topK = this.args.topK || 8;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
switch (intent) {
|
|
111
|
-
case 'impact':
|
|
112
|
-
return this.executeImpact(scope, topK);
|
|
113
|
-
case 'dependency':
|
|
114
|
-
return this.executeDeps(topK);
|
|
115
|
-
case 'complexity':
|
|
116
|
-
return this.executeComplexity(topK);
|
|
117
|
+
switch (intentObj.intent) {
|
|
118
|
+
case 'read':
|
|
119
|
+
return this.executeRead(intentObj, scope, topK);
|
|
120
|
+
case 'link':
|
|
121
|
+
return this.executeLink(intentObj, topK);
|
|
122
|
+
case 'show':
|
|
123
|
+
return this.executeShow(intentObj, topK);
|
|
124
|
+
case 'find':
|
|
125
|
+
return this.executeFindWithFallback(intentObj, topK);
|
|
117
126
|
default:
|
|
118
|
-
|
|
127
|
+
throw this.createError(AnalyzeErrorCode.E0001_INVALID_INTENT, `无效的 intent: ${intentObj.intent}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* `find` 优先走 orchestrator,失败时回退到 AstGrep 搜索
|
|
132
|
+
*/
|
|
133
|
+
async executeFindWithFallback(intentObj, topK) {
|
|
134
|
+
try {
|
|
135
|
+
return this.withCompatibility(await this.executeWithOrchestrator(intentObj, topK), intentObj.compatibility);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
console.warn('[Analyze] Orchestrator not available, falling back to AstGrep search');
|
|
139
|
+
return this.executeFind(intentObj, topK);
|
|
119
140
|
}
|
|
120
141
|
}
|
|
121
142
|
/**
|
|
122
143
|
* 使用编排器执行分析
|
|
123
144
|
*/
|
|
124
|
-
async executeWithOrchestrator(
|
|
145
|
+
async executeWithOrchestrator(intentObj, topK) {
|
|
125
146
|
const orchestrator = new ToolOrchestrator();
|
|
126
147
|
// 注册适配器
|
|
127
148
|
const codemapAdapter = new CodemapAdapter({ codemapPath: resolveOutputDir().outputDir });
|
|
@@ -129,13 +150,7 @@ export class AnalyzeCommand {
|
|
|
129
150
|
orchestrator.registerAdapter(codemapAdapter);
|
|
130
151
|
orchestrator.registerAdapter(astGrepAdapter);
|
|
131
152
|
const fusion = new ResultFusion();
|
|
132
|
-
const
|
|
133
|
-
// 构建意图对象
|
|
134
|
-
const intentObj = intentRouter.route({
|
|
135
|
-
...this.args,
|
|
136
|
-
intent: intent,
|
|
137
|
-
scope: scope,
|
|
138
|
-
});
|
|
153
|
+
const effectiveIntent = intentObj.executionIntent ?? intentObj.intent;
|
|
139
154
|
let orchestratedResults = [];
|
|
140
155
|
let confidence;
|
|
141
156
|
if (intentObj.secondary) {
|
|
@@ -143,7 +158,7 @@ export class AnalyzeCommand {
|
|
|
143
158
|
const resultsByTool = await orchestrator.executeParallel(intentObj, tools);
|
|
144
159
|
orchestratedResults = fusion.fuse(resultsByTool, {
|
|
145
160
|
topK,
|
|
146
|
-
intent:
|
|
161
|
+
intent: effectiveIntent,
|
|
147
162
|
keywordWeights: {},
|
|
148
163
|
maxTokens: 160,
|
|
149
164
|
});
|
|
@@ -165,17 +180,525 @@ export class AnalyzeCommand {
|
|
|
165
180
|
const resultsWithLocation = this.enrichWithLocation(orchestratedResults);
|
|
166
181
|
return {
|
|
167
182
|
schemaVersion: 'v1.0.0',
|
|
168
|
-
intent: intent,
|
|
183
|
+
intent: intentObj.intent,
|
|
169
184
|
tool: 'codemap-orchestrated',
|
|
170
185
|
confidence,
|
|
171
186
|
results: resultsWithLocation,
|
|
172
187
|
metadata: {
|
|
173
188
|
total: orchestratedResults.length,
|
|
174
|
-
scope,
|
|
189
|
+
scope: intentObj.scope,
|
|
175
190
|
resultCount: orchestratedResults.length,
|
|
176
191
|
},
|
|
177
192
|
};
|
|
178
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* 为输出添加兼容期 warning
|
|
196
|
+
*/
|
|
197
|
+
withCompatibility(output, compatibility) {
|
|
198
|
+
const warnings = this.buildCompatibilityWarnings(compatibility);
|
|
199
|
+
if (warnings.length === 0) {
|
|
200
|
+
return output;
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
...output,
|
|
204
|
+
warnings
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* 生成结构化兼容 warning
|
|
209
|
+
*/
|
|
210
|
+
buildCompatibilityWarnings(compatibility) {
|
|
211
|
+
if (!compatibility?.isDeprecated || !compatibility.normalizedFrom) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
const replacementIntent = compatibility.normalizedFrom === 'search'
|
|
215
|
+
? 'find'
|
|
216
|
+
: compatibility.normalizedFrom === 'impact' || compatibility.normalizedFrom === 'complexity'
|
|
217
|
+
? 'read'
|
|
218
|
+
: compatibility.normalizedFrom === 'dependency' || compatibility.normalizedFrom === 'reference'
|
|
219
|
+
? 'link'
|
|
220
|
+
: 'show';
|
|
221
|
+
return [{
|
|
222
|
+
code: 'deprecated-intent',
|
|
223
|
+
severity: 'warning',
|
|
224
|
+
message: `legacy intent "${compatibility.normalizedFrom}" 已弃用,请改用 "${replacementIntent}"`,
|
|
225
|
+
deprecatedIntent: compatibility.normalizedFrom,
|
|
226
|
+
replacementIntent,
|
|
227
|
+
sunsetPolicy: '2-minor-window'
|
|
228
|
+
}];
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* find fallback
|
|
232
|
+
*/
|
|
233
|
+
async executeFind(intentObj, topK) {
|
|
234
|
+
const searchTerms = intentObj.keywords.length > 0 ? intentObj.keywords : intentObj.targets;
|
|
235
|
+
const adapter = new AstGrepAdapter({ includeTests: this.args.includeTests ?? true });
|
|
236
|
+
const rawResults = await adapter.execute(searchTerms, {
|
|
237
|
+
topK,
|
|
238
|
+
includeTests: this.args.includeTests,
|
|
239
|
+
keywords: searchTerms
|
|
240
|
+
});
|
|
241
|
+
const results = this.enrichWithLocation(rawResults).slice(0, topK);
|
|
242
|
+
const confidence = this.buildConfidence(this.calculateConfidence(results));
|
|
243
|
+
return this.withCompatibility({
|
|
244
|
+
schemaVersion: 'v1.0.0',
|
|
245
|
+
intent: 'find',
|
|
246
|
+
tool: 'ast-grep-find',
|
|
247
|
+
confidence,
|
|
248
|
+
results,
|
|
249
|
+
metadata: {
|
|
250
|
+
total: results.length,
|
|
251
|
+
resultCount: results.length,
|
|
252
|
+
scope: intentObj.scope
|
|
253
|
+
}
|
|
254
|
+
}, intentObj.compatibility);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* 执行 read 聚合
|
|
258
|
+
*/
|
|
259
|
+
async executeRead(intentObj, scope, topK) {
|
|
260
|
+
const [impactOutput, complexityOutput] = await Promise.all([
|
|
261
|
+
this.executeImpact(scope, topK),
|
|
262
|
+
this.executeComplexity(topK)
|
|
263
|
+
]);
|
|
264
|
+
const mergedResults = this.mergeUnifiedResults(impactOutput.results, complexityOutput.results);
|
|
265
|
+
const results = mergedResults.slice(0, topK);
|
|
266
|
+
const analysis = {
|
|
267
|
+
intent: 'read',
|
|
268
|
+
impact: impactOutput.results
|
|
269
|
+
.filter(result => result.content.startsWith('被 '))
|
|
270
|
+
.map(result => ({
|
|
271
|
+
file: result.file,
|
|
272
|
+
location: result.location,
|
|
273
|
+
changedFiles: [result.file],
|
|
274
|
+
transitiveDependencies: result.metadata?.dependencies ?? [],
|
|
275
|
+
impactCount: result.metadata?.impactCount ?? 0,
|
|
276
|
+
risk: result.metadata?.riskLevel ?? 'low'
|
|
277
|
+
})),
|
|
278
|
+
complexity: complexityOutput.results
|
|
279
|
+
.filter(result => Boolean(result.metadata?.complexityMetrics))
|
|
280
|
+
.map(result => ({
|
|
281
|
+
file: result.file,
|
|
282
|
+
location: result.location,
|
|
283
|
+
metrics: result.metadata?.complexityMetrics ?? {
|
|
284
|
+
cyclomatic: 0,
|
|
285
|
+
cognitive: 0,
|
|
286
|
+
maintainability: 0
|
|
287
|
+
},
|
|
288
|
+
risk: result.metadata?.riskLevel ?? 'low'
|
|
289
|
+
}))
|
|
290
|
+
};
|
|
291
|
+
return this.withCompatibility({
|
|
292
|
+
schemaVersion: 'v1.0.0',
|
|
293
|
+
intent: 'read',
|
|
294
|
+
tool: 'codemap-read',
|
|
295
|
+
confidence: this.combineConfidence([impactOutput.confidence, complexityOutput.confidence], results),
|
|
296
|
+
results,
|
|
297
|
+
analysis,
|
|
298
|
+
metadata: {
|
|
299
|
+
total: mergedResults.length,
|
|
300
|
+
resultCount: results.length,
|
|
301
|
+
scope
|
|
302
|
+
}
|
|
303
|
+
}, intentObj.compatibility);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 执行 link 聚合
|
|
307
|
+
*/
|
|
308
|
+
async executeLink(intentObj, topK) {
|
|
309
|
+
const dependencyOutput = intentObj.targets.length > 0
|
|
310
|
+
? await this.executeDeps(Math.max(topK, intentObj.targets.length))
|
|
311
|
+
: this.createEmptyOutput('link', 'codemap-link', intentObj.scope);
|
|
312
|
+
const codeMap = await this.loadCodeMap();
|
|
313
|
+
const dependency = codeMap
|
|
314
|
+
? this.buildLinkDependencyAnalysis(codeMap, intentObj.targets)
|
|
315
|
+
: [];
|
|
316
|
+
const reference = codeMap
|
|
317
|
+
? this.buildLinkReferenceAnalysis(codeMap, intentObj.targets, intentObj.keywords)
|
|
318
|
+
: [];
|
|
319
|
+
const referenceResults = this.buildReferenceResults(reference);
|
|
320
|
+
const mergedResults = this.mergeUnifiedResults(dependencyOutput.results, referenceResults);
|
|
321
|
+
const results = mergedResults.slice(0, topK);
|
|
322
|
+
const confidence = this.combineConfidence([
|
|
323
|
+
dependencyOutput.confidence,
|
|
324
|
+
this.buildConfidence(this.calculateConfidence(referenceResults))
|
|
325
|
+
], results);
|
|
326
|
+
const analysis = {
|
|
327
|
+
intent: 'link',
|
|
328
|
+
...(reference.length > 0 ? { reference } : {}),
|
|
329
|
+
...(dependency.length > 0 ? { dependency } : {})
|
|
330
|
+
};
|
|
331
|
+
return this.withCompatibility({
|
|
332
|
+
schemaVersion: 'v1.0.0',
|
|
333
|
+
intent: 'link',
|
|
334
|
+
tool: 'codemap-link',
|
|
335
|
+
confidence,
|
|
336
|
+
results,
|
|
337
|
+
analysis,
|
|
338
|
+
metadata: {
|
|
339
|
+
total: mergedResults.length,
|
|
340
|
+
resultCount: results.length,
|
|
341
|
+
scope: intentObj.scope
|
|
342
|
+
}
|
|
343
|
+
}, intentObj.compatibility);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* 执行 show 聚合
|
|
347
|
+
*/
|
|
348
|
+
async executeShow(intentObj, topK) {
|
|
349
|
+
const codeMap = await this.loadCodeMap();
|
|
350
|
+
const modules = codeMap ? this.findMatchingModules(codeMap, intentObj.targets) : [];
|
|
351
|
+
const analysis = {
|
|
352
|
+
intent: 'show',
|
|
353
|
+
overview: modules.map(module => ({
|
|
354
|
+
title: path.basename(module.absolutePath),
|
|
355
|
+
file: this.toRelativePath(codeMap, module.absolutePath),
|
|
356
|
+
overview: module.overview ?? `模块 ${this.toRelativePath(codeMap, module.absolutePath)},导出 ${module.exports.length} 个符号,依赖 ${module.dependencies.length} 个模块`,
|
|
357
|
+
exports: module.exports.map(exp => exp.name)
|
|
358
|
+
})),
|
|
359
|
+
documentation: modules.map(module => ({
|
|
360
|
+
title: path.basename(module.absolutePath),
|
|
361
|
+
file: this.toRelativePath(codeMap, module.absolutePath),
|
|
362
|
+
content: module.overview
|
|
363
|
+
?? `类型: ${module.type}; 代码行: ${module.stats.codeLines}; 导出: ${module.exports.map(exp => exp.name).join(', ') || '无'}`
|
|
364
|
+
}))
|
|
365
|
+
};
|
|
366
|
+
const results = this.buildShowResults(analysis).slice(0, topK);
|
|
367
|
+
return this.withCompatibility({
|
|
368
|
+
schemaVersion: 'v1.0.0',
|
|
369
|
+
intent: 'show',
|
|
370
|
+
tool: 'codemap-show',
|
|
371
|
+
confidence: this.buildConfidence(this.calculateConfidence(results)),
|
|
372
|
+
results,
|
|
373
|
+
analysis,
|
|
374
|
+
metadata: {
|
|
375
|
+
total: results.length,
|
|
376
|
+
resultCount: results.length,
|
|
377
|
+
scope: intentObj.scope
|
|
378
|
+
}
|
|
379
|
+
}, intentObj.compatibility);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* 创建空输出
|
|
383
|
+
*/
|
|
384
|
+
createEmptyOutput(intent, tool, scope) {
|
|
385
|
+
return {
|
|
386
|
+
schemaVersion: 'v1.0.0',
|
|
387
|
+
intent,
|
|
388
|
+
tool,
|
|
389
|
+
confidence: this.buildConfidence(0),
|
|
390
|
+
results: [],
|
|
391
|
+
metadata: {
|
|
392
|
+
total: 0,
|
|
393
|
+
resultCount: 0,
|
|
394
|
+
scope
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* 聚合多个 Confidence
|
|
400
|
+
*/
|
|
401
|
+
combineConfidence(confidences, results) {
|
|
402
|
+
const effective = confidences.filter(confidence => Number.isFinite(confidence.score));
|
|
403
|
+
if (effective.length === 0) {
|
|
404
|
+
return this.buildConfidence(this.calculateConfidence(results));
|
|
405
|
+
}
|
|
406
|
+
const score = Math.round((effective.reduce((sum, confidence) => sum + confidence.score, 0) / effective.length) * 100) / 100;
|
|
407
|
+
return this.buildConfidence(score);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* 构建 Confidence
|
|
411
|
+
*/
|
|
412
|
+
buildConfidence(score) {
|
|
413
|
+
const normalizedScore = Math.round(Math.max(0, Math.min(score, 1)) * 100) / 100;
|
|
414
|
+
return {
|
|
415
|
+
score: normalizedScore,
|
|
416
|
+
level: calculateConfidenceLevel(normalizedScore)
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* 合并 UnifiedResult
|
|
421
|
+
*/
|
|
422
|
+
mergeUnifiedResults(...collections) {
|
|
423
|
+
const merged = new Map();
|
|
424
|
+
for (const results of collections) {
|
|
425
|
+
for (const result of results) {
|
|
426
|
+
const key = `${result.file}:${result.location?.line ?? result.line ?? 1}`;
|
|
427
|
+
const existing = merged.get(key);
|
|
428
|
+
if (!existing || result.relevance > existing.relevance) {
|
|
429
|
+
merged.set(key, result);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return Array.from(merged.values()).sort((left, right) => right.relevance - left.relevance);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* 加载 CodeMap 数据
|
|
437
|
+
*/
|
|
438
|
+
async loadCodeMap() {
|
|
439
|
+
try {
|
|
440
|
+
const dataPath = resolveDataPath();
|
|
441
|
+
const raw = await readFile(dataPath, 'utf-8');
|
|
442
|
+
return JSON.parse(raw);
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* 查找目标模块
|
|
450
|
+
*/
|
|
451
|
+
findMatchingModules(codeMap, targets) {
|
|
452
|
+
const seen = new Set();
|
|
453
|
+
const modules = [];
|
|
454
|
+
for (const target of targets) {
|
|
455
|
+
const module = this.findMatchingModule(codeMap, target);
|
|
456
|
+
if (module && !seen.has(module.id)) {
|
|
457
|
+
seen.add(module.id);
|
|
458
|
+
modules.push(module);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return modules;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* 查找单个匹配模块
|
|
465
|
+
*/
|
|
466
|
+
findMatchingModule(codeMap, target) {
|
|
467
|
+
return codeMap.modules.find(module => {
|
|
468
|
+
const relativePath = this.toRelativePath(codeMap, module.absolutePath);
|
|
469
|
+
return module.absolutePath.includes(target) || relativePath.includes(target);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* 构建 link dependency analysis
|
|
474
|
+
*/
|
|
475
|
+
buildLinkDependencyAnalysis(codeMap, targets) {
|
|
476
|
+
return this.findMatchingModules(codeMap, targets).map(module => ({
|
|
477
|
+
file: this.toRelativePath(codeMap, module.absolutePath),
|
|
478
|
+
location: {
|
|
479
|
+
file: this.toRelativePath(codeMap, module.absolutePath),
|
|
480
|
+
line: 1,
|
|
481
|
+
column: 1
|
|
482
|
+
},
|
|
483
|
+
imports: module.dependencies,
|
|
484
|
+
importedBy: module.dependents.map(id => {
|
|
485
|
+
const dependent = codeMap.modules.find(candidate => candidate.id === id);
|
|
486
|
+
return dependent ? this.toRelativePath(codeMap, dependent.absolutePath) : id;
|
|
487
|
+
}),
|
|
488
|
+
cycles: []
|
|
489
|
+
}));
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* 构建 link reference analysis
|
|
493
|
+
*/
|
|
494
|
+
buildLinkReferenceAnalysis(codeMap, targets, keywords) {
|
|
495
|
+
const items = [];
|
|
496
|
+
for (const module of this.findMatchingModules(codeMap, targets)) {
|
|
497
|
+
items.push(this.buildModuleReferenceItem(codeMap, module));
|
|
498
|
+
}
|
|
499
|
+
for (const keyword of keywords) {
|
|
500
|
+
items.push(this.buildKeywordReferenceItem(codeMap, keyword));
|
|
501
|
+
}
|
|
502
|
+
const merged = new Map();
|
|
503
|
+
for (const item of items) {
|
|
504
|
+
const existing = merged.get(item.target);
|
|
505
|
+
if (!existing) {
|
|
506
|
+
merged.set(item.target, item);
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
merged.set(item.target, {
|
|
510
|
+
target: item.target,
|
|
511
|
+
callers: Array.from(new Set([...existing.callers, ...item.callers])),
|
|
512
|
+
callees: Array.from(new Set([...existing.callees, ...item.callees])),
|
|
513
|
+
matches: [...existing.matches, ...item.matches]
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return Array.from(merged.values());
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* 基于模块构建 reference item
|
|
520
|
+
*/
|
|
521
|
+
buildModuleReferenceItem(codeMap, module) {
|
|
522
|
+
const relativePath = this.toRelativePath(codeMap, module.absolutePath);
|
|
523
|
+
const exportedSymbols = new Set(module.exports.map(exp => exp.name));
|
|
524
|
+
const matchTokens = new Set([
|
|
525
|
+
relativePath,
|
|
526
|
+
this.stripModuleExtension(relativePath),
|
|
527
|
+
path.basename(relativePath),
|
|
528
|
+
this.stripModuleExtension(path.basename(relativePath)),
|
|
529
|
+
module.id
|
|
530
|
+
]);
|
|
531
|
+
const callers = new Set();
|
|
532
|
+
const matches = [];
|
|
533
|
+
for (const candidate of codeMap.modules) {
|
|
534
|
+
if (candidate.id === module.id) {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
const candidatePath = this.toRelativePath(codeMap, candidate.absolutePath);
|
|
538
|
+
for (const entry of candidate.imports) {
|
|
539
|
+
const sourceMatched = this.matchesModuleSource(entry.source, matchTokens);
|
|
540
|
+
const symbolMatched = entry.specifiers.some(specifier => exportedSymbols.has(specifier.name));
|
|
541
|
+
if (!sourceMatched && !symbolMatched) {
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
callers.add(candidatePath);
|
|
545
|
+
matches.push({
|
|
546
|
+
file: candidatePath,
|
|
547
|
+
line: 1,
|
|
548
|
+
snippet: entry.source
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return {
|
|
553
|
+
target: relativePath,
|
|
554
|
+
callers: Array.from(callers),
|
|
555
|
+
callees: module.dependencies,
|
|
556
|
+
matches
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* 基于关键词构建 reference item
|
|
561
|
+
*/
|
|
562
|
+
buildKeywordReferenceItem(codeMap, keyword) {
|
|
563
|
+
const callers = new Set();
|
|
564
|
+
const callees = new Set();
|
|
565
|
+
const matches = [];
|
|
566
|
+
for (const module of codeMap.modules) {
|
|
567
|
+
const relativePath = this.toRelativePath(codeMap, module.absolutePath);
|
|
568
|
+
const definesKeyword = module.exports.some(exp => exp.name === keyword)
|
|
569
|
+
|| module.symbols.some(symbol => symbol.name === keyword);
|
|
570
|
+
if (definesKeyword) {
|
|
571
|
+
callees.add(relativePath);
|
|
572
|
+
}
|
|
573
|
+
for (const entry of module.imports) {
|
|
574
|
+
const sourceMatched = entry.source.toLowerCase().includes(keyword.toLowerCase());
|
|
575
|
+
const specifierMatched = entry.specifiers.some(specifier => specifier.name === keyword || specifier.alias === keyword);
|
|
576
|
+
if (!sourceMatched && !specifierMatched) {
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
callers.add(relativePath);
|
|
580
|
+
matches.push({
|
|
581
|
+
file: relativePath,
|
|
582
|
+
line: 1,
|
|
583
|
+
snippet: entry.source
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
target: keyword,
|
|
589
|
+
callers: Array.from(callers),
|
|
590
|
+
callees: Array.from(callees),
|
|
591
|
+
matches
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* 将 reference analysis 转为 results
|
|
596
|
+
*/
|
|
597
|
+
buildReferenceResults(items) {
|
|
598
|
+
return items.map(item => ({
|
|
599
|
+
id: `reference-${item.target}`,
|
|
600
|
+
source: 'codemap',
|
|
601
|
+
toolScore: 0.8,
|
|
602
|
+
type: 'symbol',
|
|
603
|
+
file: item.matches[0]?.file ?? item.callees[0] ?? item.target,
|
|
604
|
+
line: item.matches[0]?.line ?? 1,
|
|
605
|
+
location: {
|
|
606
|
+
file: item.matches[0]?.file ?? item.callees[0] ?? item.target,
|
|
607
|
+
line: item.matches[0]?.line ?? 1,
|
|
608
|
+
column: 1
|
|
609
|
+
},
|
|
610
|
+
content: `发现 ${item.callers.length} 个引用方,${item.callees.length} 个关联目标`,
|
|
611
|
+
relevance: Math.min(0.4 + item.callers.length * 0.1, 0.95),
|
|
612
|
+
keywords: [item.target],
|
|
613
|
+
metadata: {
|
|
614
|
+
dependencies: item.callees,
|
|
615
|
+
impactCount: item.callers.length,
|
|
616
|
+
stability: true,
|
|
617
|
+
riskLevel: item.callers.length > 10 ? 'high' : item.callers.length > 3 ? 'medium' : 'low'
|
|
618
|
+
}
|
|
619
|
+
}));
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* 构建 show 结果
|
|
623
|
+
*/
|
|
624
|
+
buildShowResults(analysis) {
|
|
625
|
+
const results = [];
|
|
626
|
+
for (const section of analysis.overview ?? []) {
|
|
627
|
+
results.push({
|
|
628
|
+
id: `show-overview-${section.file}`,
|
|
629
|
+
source: 'codemap',
|
|
630
|
+
toolScore: 0.75,
|
|
631
|
+
type: 'documentation',
|
|
632
|
+
file: section.file,
|
|
633
|
+
line: 1,
|
|
634
|
+
location: {
|
|
635
|
+
file: section.file,
|
|
636
|
+
line: 1,
|
|
637
|
+
column: 1
|
|
638
|
+
},
|
|
639
|
+
content: section.overview,
|
|
640
|
+
relevance: 0.75,
|
|
641
|
+
keywords: section.exports,
|
|
642
|
+
metadata: {
|
|
643
|
+
stability: true,
|
|
644
|
+
riskLevel: 'low'
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
for (const section of analysis.documentation ?? []) {
|
|
649
|
+
results.push({
|
|
650
|
+
id: `show-documentation-${section.file}`,
|
|
651
|
+
source: 'codemap',
|
|
652
|
+
toolScore: 0.7,
|
|
653
|
+
type: 'documentation',
|
|
654
|
+
file: section.file,
|
|
655
|
+
line: 1,
|
|
656
|
+
location: {
|
|
657
|
+
file: section.file,
|
|
658
|
+
line: 1,
|
|
659
|
+
column: 1
|
|
660
|
+
},
|
|
661
|
+
content: section.content,
|
|
662
|
+
relevance: 0.7,
|
|
663
|
+
keywords: [],
|
|
664
|
+
metadata: {
|
|
665
|
+
stability: true,
|
|
666
|
+
riskLevel: 'low'
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return this.mergeUnifiedResults(results);
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* 转为相对路径
|
|
674
|
+
*/
|
|
675
|
+
toRelativePath(codeMap, filePath) {
|
|
676
|
+
return path.relative(codeMap.project.rootDir, filePath).replace(/\\/g, '/');
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* 去除模块扩展名
|
|
680
|
+
*/
|
|
681
|
+
stripModuleExtension(value) {
|
|
682
|
+
return value.replace(/\.[cm]?[jt]sx?$/i, '');
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* 判断 import source 是否引用目标模块
|
|
686
|
+
*/
|
|
687
|
+
matchesModuleSource(source, tokens) {
|
|
688
|
+
const normalizedSource = this.stripModuleExtension(source).replace(/\\/g, '/').toLowerCase();
|
|
689
|
+
for (const token of tokens) {
|
|
690
|
+
const normalizedToken = this.stripModuleExtension(token).replace(/\\/g, '/').toLowerCase();
|
|
691
|
+
if (!normalizedToken) {
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
if (normalizedSource === normalizedToken
|
|
695
|
+
|| normalizedSource.endsWith(normalizedToken)
|
|
696
|
+
|| normalizedSource.includes(normalizedToken)) {
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
179
702
|
/**
|
|
180
703
|
* 为 UnifiedResult 添加 location 字段
|
|
181
704
|
*/
|
|
@@ -220,33 +743,16 @@ export class AnalyzeCommand {
|
|
|
220
743
|
// 添加 location 字段
|
|
221
744
|
const resultsWithLocation = this.enrichWithLocation(resultsWithTests);
|
|
222
745
|
const typedResults = resultsWithLocation;
|
|
223
|
-
// 输出格式处理
|
|
224
|
-
if (this.args.outputMode === 'machine' || this.args.json) {
|
|
225
|
-
return {
|
|
226
|
-
schemaVersion: 'v1.0.0',
|
|
227
|
-
intent: 'impact',
|
|
228
|
-
tool: 'codemap-impact',
|
|
229
|
-
confidence,
|
|
230
|
-
results: typedResults.slice(0, topK),
|
|
231
|
-
metadata: {
|
|
232
|
-
total: resultsWithTests.length,
|
|
233
|
-
scope,
|
|
234
|
-
resultCount: resultsWithTests.length,
|
|
235
|
-
},
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
// 人类可读输出
|
|
239
|
-
this.printHumanOutput(resultsWithTests, 'impact');
|
|
240
746
|
return {
|
|
241
747
|
schemaVersion: 'v1.0.0',
|
|
242
|
-
intent: '
|
|
748
|
+
intent: 'read',
|
|
243
749
|
tool: 'codemap-impact',
|
|
244
750
|
confidence,
|
|
245
|
-
results: typedResults,
|
|
751
|
+
results: typedResults.slice(0, topK),
|
|
246
752
|
metadata: {
|
|
247
753
|
total: resultsWithTests.length,
|
|
248
754
|
scope,
|
|
249
|
-
resultCount:
|
|
755
|
+
resultCount: typedResults.slice(0, topK).length,
|
|
250
756
|
},
|
|
251
757
|
};
|
|
252
758
|
}
|
|
@@ -284,31 +790,15 @@ export class AnalyzeCommand {
|
|
|
284
790
|
// 添加 location 字段
|
|
285
791
|
const resultsWithLocation = this.enrichWithLocation(resultsWithTests);
|
|
286
792
|
const typedResults = resultsWithLocation;
|
|
287
|
-
// 输出格式处理
|
|
288
|
-
if (this.args.outputMode === 'machine' || this.args.json) {
|
|
289
|
-
return {
|
|
290
|
-
schemaVersion: 'v1.0.0',
|
|
291
|
-
intent: 'dependency',
|
|
292
|
-
tool: 'codemap-deps',
|
|
293
|
-
confidence,
|
|
294
|
-
results: typedResults.slice(0, topK),
|
|
295
|
-
metadata: {
|
|
296
|
-
total: resultsWithTests.length,
|
|
297
|
-
resultCount: resultsWithTests.length,
|
|
298
|
-
},
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
// 人类可读输出
|
|
302
|
-
this.printHumanOutput(resultsWithTests, 'dependency');
|
|
303
793
|
return {
|
|
304
794
|
schemaVersion: 'v1.0.0',
|
|
305
|
-
intent: '
|
|
795
|
+
intent: 'link',
|
|
306
796
|
tool: 'codemap-deps',
|
|
307
797
|
confidence,
|
|
308
|
-
results: typedResults,
|
|
798
|
+
results: typedResults.slice(0, topK),
|
|
309
799
|
metadata: {
|
|
310
800
|
total: resultsWithTests.length,
|
|
311
|
-
resultCount:
|
|
801
|
+
resultCount: typedResults.slice(0, topK).length,
|
|
312
802
|
},
|
|
313
803
|
};
|
|
314
804
|
}
|
|
@@ -332,31 +822,15 @@ export class AnalyzeCommand {
|
|
|
332
822
|
// 添加 location 字段
|
|
333
823
|
const resultsWithLocation = this.enrichWithLocation(resultsWithTests);
|
|
334
824
|
const typedResults = resultsWithLocation;
|
|
335
|
-
// 输出格式处理
|
|
336
|
-
if (this.args.outputMode === 'machine' || this.args.json) {
|
|
337
|
-
return {
|
|
338
|
-
schemaVersion: 'v1.0.0',
|
|
339
|
-
intent: 'complexity',
|
|
340
|
-
tool: 'codemap-complexity',
|
|
341
|
-
confidence,
|
|
342
|
-
results: typedResults.slice(0, topK),
|
|
343
|
-
metadata: {
|
|
344
|
-
total: resultsWithTests.length,
|
|
345
|
-
resultCount: resultsWithTests.length,
|
|
346
|
-
},
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
// 人类可读输出
|
|
350
|
-
this.printHumanOutput(resultsWithTests, 'complexity');
|
|
351
825
|
return {
|
|
352
826
|
schemaVersion: 'v1.0.0',
|
|
353
|
-
intent: '
|
|
827
|
+
intent: 'read',
|
|
354
828
|
tool: 'codemap-complexity',
|
|
355
829
|
confidence,
|
|
356
|
-
results: typedResults,
|
|
830
|
+
results: typedResults.slice(0, topK),
|
|
357
831
|
metadata: {
|
|
358
832
|
total: resultsWithTests.length,
|
|
359
|
-
resultCount:
|
|
833
|
+
resultCount: typedResults.slice(0, topK).length,
|
|
360
834
|
},
|
|
361
835
|
};
|
|
362
836
|
}
|
|
@@ -400,68 +874,31 @@ export class AnalyzeCommand {
|
|
|
400
874
|
/**
|
|
401
875
|
* 解析 CLI 参数
|
|
402
876
|
*/
|
|
877
|
+
function normalizeStringArray(value) {
|
|
878
|
+
if (typeof value === 'string') {
|
|
879
|
+
return [value];
|
|
880
|
+
}
|
|
881
|
+
if (Array.isArray(value)) {
|
|
882
|
+
return value.filter((item) => typeof item === 'string');
|
|
883
|
+
}
|
|
884
|
+
return [];
|
|
885
|
+
}
|
|
403
886
|
export function parseAnalyzeArgs(argv) {
|
|
404
887
|
try {
|
|
405
888
|
const { values, positionals } = parseArgs({
|
|
406
|
-
argv,
|
|
889
|
+
args: argv,
|
|
407
890
|
allowPositionals: true,
|
|
408
|
-
options:
|
|
409
|
-
intent: {
|
|
410
|
-
type: 'string',
|
|
411
|
-
short: 'i',
|
|
412
|
-
},
|
|
413
|
-
targets: {
|
|
414
|
-
type: 'string',
|
|
415
|
-
multiple: true,
|
|
416
|
-
short: 't',
|
|
417
|
-
},
|
|
418
|
-
keywords: {
|
|
419
|
-
type: 'string',
|
|
420
|
-
multiple: true,
|
|
421
|
-
short: 'k',
|
|
422
|
-
},
|
|
423
|
-
scope: {
|
|
424
|
-
type: 'string',
|
|
425
|
-
short: 's',
|
|
426
|
-
},
|
|
427
|
-
topK: {
|
|
428
|
-
type: 'string',
|
|
429
|
-
short: 'n',
|
|
430
|
-
},
|
|
431
|
-
'include-tests': {
|
|
432
|
-
type: 'boolean',
|
|
433
|
-
default: false,
|
|
434
|
-
},
|
|
435
|
-
'include-git-history': {
|
|
436
|
-
type: 'boolean',
|
|
437
|
-
default: false,
|
|
438
|
-
},
|
|
439
|
-
json: {
|
|
440
|
-
type: 'boolean',
|
|
441
|
-
default: false,
|
|
442
|
-
},
|
|
443
|
-
structured: {
|
|
444
|
-
type: 'boolean',
|
|
445
|
-
default: false,
|
|
446
|
-
},
|
|
447
|
-
'output-mode': {
|
|
448
|
-
type: 'string',
|
|
449
|
-
},
|
|
450
|
-
help: {
|
|
451
|
-
type: 'boolean',
|
|
452
|
-
short: 'h',
|
|
453
|
-
default: false,
|
|
454
|
-
},
|
|
455
|
-
},
|
|
891
|
+
options: ANALYZE_PARSE_OPTIONS,
|
|
456
892
|
});
|
|
457
893
|
// 合并位置参数和 --targets 参数作为 targets
|
|
458
894
|
const positionalTargets = positionals?.filter(p => !p.startsWith('-')) || [];
|
|
459
|
-
const explicitTargets =
|
|
895
|
+
const explicitTargets = normalizeStringArray(values.targets);
|
|
460
896
|
const allTargets = [...explicitTargets, ...positionalTargets];
|
|
897
|
+
const keywords = normalizeStringArray(values.keywords);
|
|
461
898
|
return {
|
|
462
899
|
intent: values.intent,
|
|
463
900
|
targets: allTargets.length > 0 ? allTargets : undefined,
|
|
464
|
-
keywords:
|
|
901
|
+
keywords: keywords.length > 0 ? keywords : undefined,
|
|
465
902
|
scope: values.scope,
|
|
466
903
|
topK: values.topK ? parseInt(values.topK, 10) : undefined,
|
|
467
904
|
includeTests: values['include-tests'],
|
|
@@ -510,6 +947,9 @@ export async function analyzeCommand(argv) {
|
|
|
510
947
|
else {
|
|
511
948
|
// human 模式:打印格式化输出
|
|
512
949
|
const typedOutput = output;
|
|
950
|
+
for (const warning of typedOutput.warnings || []) {
|
|
951
|
+
console.warn(chalk.yellow(`⚠️ ${warning.message}`));
|
|
952
|
+
}
|
|
513
953
|
console.log(chalk.bold(`\n📊 ${typedOutput.intent?.toUpperCase() || 'ANALYSIS'} 分析结果\n`));
|
|
514
954
|
for (const result of typedOutput.results || []) {
|
|
515
955
|
const lineInfo = result.location?.line ? `:${result.location.line}` : '';
|
|
@@ -538,30 +978,6 @@ export async function analyzeCommand(argv) {
|
|
|
538
978
|
* 打印帮助信息
|
|
539
979
|
*/
|
|
540
980
|
function printHelp() {
|
|
541
|
-
console.log(
|
|
542
|
-
${chalk.bold('codemap analyze')} - 统一分析入口
|
|
543
|
-
|
|
544
|
-
${chalk.bold('用法:')}
|
|
545
|
-
codemap analyze [选项]
|
|
546
|
-
|
|
547
|
-
${chalk.bold('选项:')}
|
|
548
|
-
-i, --intent <type> 分析类型 (impact|dependency|search|documentation|complexity|overview|refactor|reference)
|
|
549
|
-
-t, --targets <paths> 目标文件/模块路径 (多个)
|
|
550
|
-
-k, --keywords <words> 搜索关键词 (多个)
|
|
551
|
-
-s, --scope <scope> 范围 (direct|transitive)
|
|
552
|
-
-n, --topK <number> 返回结果数量 (默认 8, 最大 100)
|
|
553
|
-
--include-tests 包含测试文件
|
|
554
|
-
--include-git-history 包含 Git 历史
|
|
555
|
-
--json JSON 格式输出
|
|
556
|
-
--structured 输出完全结构化的 JSON(移除自然语言字符串)
|
|
557
|
-
--output-mode <mode> 输出模式 (machine|human)
|
|
558
|
-
-h, --help 显示帮助
|
|
559
|
-
|
|
560
|
-
${chalk.bold('示例:')}
|
|
561
|
-
codemap analyze -i impact -t src/index.ts
|
|
562
|
-
codemap analyze -i dependency -t src/utils --scope transitive --json
|
|
563
|
-
codemap analyze -i complexity -t src/ --include-tests
|
|
564
|
-
codemap analyze -i search -k "SourceLocation" --json --structured
|
|
565
|
-
`);
|
|
981
|
+
console.log(getAnalyzeHelpText());
|
|
566
982
|
}
|
|
567
983
|
//# sourceMappingURL=analyze.js.map
|