@trench-craft/sds 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/README.en.md +522 -0
- package/README.md +566 -0
- package/dist/bin/sds.d.ts +3 -0
- package/dist/bin/sds.d.ts.map +1 -0
- package/dist/bin/sds.js +50 -0
- package/dist/bin/sds.js.map +1 -0
- package/dist/src/__tests__/cli.test.d.ts +2 -0
- package/dist/src/__tests__/cli.test.d.ts.map +1 -0
- package/dist/src/__tests__/cli.test.js +37 -0
- package/dist/src/__tests__/cli.test.js.map +1 -0
- package/dist/src/__tests__/e2e.test.d.ts +5 -0
- package/dist/src/__tests__/e2e.test.d.ts.map +1 -0
- package/dist/src/__tests__/e2e.test.js +143 -0
- package/dist/src/__tests__/e2e.test.js.map +1 -0
- package/dist/src/__tests__/graph.test.d.ts +5 -0
- package/dist/src/__tests__/graph.test.d.ts.map +1 -0
- package/dist/src/__tests__/graph.test.js +423 -0
- package/dist/src/__tests__/graph.test.js.map +1 -0
- package/dist/src/__tests__/openspec.test.d.ts +5 -0
- package/dist/src/__tests__/openspec.test.d.ts.map +1 -0
- package/dist/src/__tests__/openspec.test.js +172 -0
- package/dist/src/__tests__/openspec.test.js.map +1 -0
- package/dist/src/commands/apply.d.ts +4 -0
- package/dist/src/commands/apply.d.ts.map +1 -0
- package/dist/src/commands/apply.js +14 -0
- package/dist/src/commands/apply.js.map +1 -0
- package/dist/src/commands/archive.d.ts +4 -0
- package/dist/src/commands/archive.d.ts.map +1 -0
- package/dist/src/commands/archive.js +20 -0
- package/dist/src/commands/archive.js.map +1 -0
- package/dist/src/commands/cache.d.ts +4 -0
- package/dist/src/commands/cache.d.ts.map +1 -0
- package/dist/src/commands/cache.js +31 -0
- package/dist/src/commands/cache.js.map +1 -0
- package/dist/src/commands/config.d.ts +4 -0
- package/dist/src/commands/config.d.ts.map +1 -0
- package/dist/src/commands/config.js +29 -0
- package/dist/src/commands/config.js.map +1 -0
- package/dist/src/commands/e2e.d.ts +4 -0
- package/dist/src/commands/e2e.d.ts.map +1 -0
- package/dist/src/commands/e2e.js +65 -0
- package/dist/src/commands/e2e.js.map +1 -0
- package/dist/src/commands/graph.d.ts +4 -0
- package/dist/src/commands/graph.d.ts.map +1 -0
- package/dist/src/commands/graph.js +783 -0
- package/dist/src/commands/graph.js.map +1 -0
- package/dist/src/commands/init.d.ts +4 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +15 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/project.d.ts +4 -0
- package/dist/src/commands/project.d.ts.map +1 -0
- package/dist/src/commands/project.js +6 -0
- package/dist/src/commands/project.js.map +1 -0
- package/dist/src/commands/propose.d.ts +4 -0
- package/dist/src/commands/propose.d.ts.map +1 -0
- package/dist/src/commands/propose.js +26 -0
- package/dist/src/commands/propose.js.map +1 -0
- package/dist/src/commands/registry.d.ts +4 -0
- package/dist/src/commands/registry.d.ts.map +1 -0
- package/dist/src/commands/registry.js +6 -0
- package/dist/src/commands/registry.js.map +1 -0
- package/dist/src/commands/skills-install.d.ts +4 -0
- package/dist/src/commands/skills-install.d.ts.map +1 -0
- package/dist/src/commands/skills-install.js +158 -0
- package/dist/src/commands/skills-install.js.map +1 -0
- package/dist/src/commands/skills.d.ts +4 -0
- package/dist/src/commands/skills.d.ts.map +1 -0
- package/dist/src/commands/skills.js +19 -0
- package/dist/src/commands/skills.js.map +1 -0
- package/dist/src/commands/verify.d.ts +4 -0
- package/dist/src/commands/verify.d.ts.map +1 -0
- package/dist/src/commands/verify.js +31 -0
- package/dist/src/commands/verify.js.map +1 -0
- package/dist/src/core/engine.d.ts +33 -0
- package/dist/src/core/engine.d.ts.map +1 -0
- package/dist/src/core/engine.js +87 -0
- package/dist/src/core/engine.js.map +1 -0
- package/dist/src/core/engine.test.d.ts +2 -0
- package/dist/src/core/engine.test.d.ts.map +1 -0
- package/dist/src/core/engine.test.js +13 -0
- package/dist/src/core/engine.test.js.map +1 -0
- package/dist/src/core/session-state.d.ts +18 -0
- package/dist/src/core/session-state.d.ts.map +1 -0
- package/dist/src/core/session-state.js +55 -0
- package/dist/src/core/session-state.js.map +1 -0
- package/dist/src/core/session-state.test.d.ts +2 -0
- package/dist/src/core/session-state.test.d.ts.map +1 -0
- package/dist/src/core/session-state.test.js +90 -0
- package/dist/src/core/session-state.test.js.map +1 -0
- package/dist/src/core/subagent-timeout.d.ts +18 -0
- package/dist/src/core/subagent-timeout.d.ts.map +1 -0
- package/dist/src/core/subagent-timeout.js +61 -0
- package/dist/src/core/subagent-timeout.js.map +1 -0
- package/dist/src/core/subagent-timeout.test.d.ts +2 -0
- package/dist/src/core/subagent-timeout.test.d.ts.map +1 -0
- package/dist/src/core/subagent-timeout.test.js +57 -0
- package/dist/src/core/subagent-timeout.test.js.map +1 -0
- package/dist/src/core/task-sync.d.ts +19 -0
- package/dist/src/core/task-sync.d.ts.map +1 -0
- package/dist/src/core/task-sync.js +62 -0
- package/dist/src/core/task-sync.js.map +1 -0
- package/dist/src/core/task-sync.test.d.ts +2 -0
- package/dist/src/core/task-sync.test.d.ts.map +1 -0
- package/dist/src/core/task-sync.test.js +84 -0
- package/dist/src/core/task-sync.test.js.map +1 -0
- package/dist/src/graph/advanced-performance.d.ts +137 -0
- package/dist/src/graph/advanced-performance.d.ts.map +1 -0
- package/dist/src/graph/advanced-performance.js +375 -0
- package/dist/src/graph/advanced-performance.js.map +1 -0
- package/dist/src/graph/database.d.ts +79 -0
- package/dist/src/graph/database.d.ts.map +1 -0
- package/dist/src/graph/database.js +305 -0
- package/dist/src/graph/database.js.map +1 -0
- package/dist/src/graph/engine.d.ts +43 -0
- package/dist/src/graph/engine.d.ts.map +1 -0
- package/dist/src/graph/engine.js +334 -0
- package/dist/src/graph/engine.js.map +1 -0
- package/dist/src/graph/exporter.d.ts +56 -0
- package/dist/src/graph/exporter.d.ts.map +1 -0
- package/dist/src/graph/exporter.js +273 -0
- package/dist/src/graph/exporter.js.map +1 -0
- package/dist/src/graph/index.d.ts +21 -0
- package/dist/src/graph/index.d.ts.map +1 -0
- package/dist/src/graph/index.js +14 -0
- package/dist/src/graph/index.js.map +1 -0
- package/dist/src/graph/layouts.d.ts +77 -0
- package/dist/src/graph/layouts.d.ts.map +1 -0
- package/dist/src/graph/layouts.js +368 -0
- package/dist/src/graph/layouts.js.map +1 -0
- package/dist/src/graph/parser.d.ts +47 -0
- package/dist/src/graph/parser.d.ts.map +1 -0
- package/dist/src/graph/parser.js +228 -0
- package/dist/src/graph/parser.js.map +1 -0
- package/dist/src/graph/performance.d.ts +90 -0
- package/dist/src/graph/performance.d.ts.map +1 -0
- package/dist/src/graph/performance.js +275 -0
- package/dist/src/graph/performance.js.map +1 -0
- package/dist/src/graph/semantic.d.ts +151 -0
- package/dist/src/graph/semantic.d.ts.map +1 -0
- package/dist/src/graph/semantic.js +402 -0
- package/dist/src/graph/semantic.js.map +1 -0
- package/dist/src/graph/types.d.ts +114 -0
- package/dist/src/graph/types.d.ts.map +1 -0
- package/dist/src/graph/types.js +5 -0
- package/dist/src/graph/types.js.map +1 -0
- package/dist/src/graph/visualizer.d.ts +50 -0
- package/dist/src/graph/visualizer.d.ts.map +1 -0
- package/dist/src/graph/visualizer.js +869 -0
- package/dist/src/graph/visualizer.js.map +1 -0
- package/dist/src/openspec/apply.d.ts +16 -0
- package/dist/src/openspec/apply.d.ts.map +1 -0
- package/dist/src/openspec/apply.js +140 -0
- package/dist/src/openspec/apply.js.map +1 -0
- package/dist/src/openspec/archive.d.ts +3 -0
- package/dist/src/openspec/archive.d.ts.map +1 -0
- package/dist/src/openspec/archive.js +17 -0
- package/dist/src/openspec/archive.js.map +1 -0
- package/dist/src/openspec/e2e-generate.d.ts +39 -0
- package/dist/src/openspec/e2e-generate.d.ts.map +1 -0
- package/dist/src/openspec/e2e-generate.js +315 -0
- package/dist/src/openspec/e2e-generate.js.map +1 -0
- package/dist/src/openspec/e2e-runner.d.ts +32 -0
- package/dist/src/openspec/e2e-runner.d.ts.map +1 -0
- package/dist/src/openspec/e2e-runner.js +208 -0
- package/dist/src/openspec/e2e-runner.js.map +1 -0
- package/dist/src/openspec/explore.d.ts +3 -0
- package/dist/src/openspec/explore.d.ts.map +1 -0
- package/dist/src/openspec/explore.js +20 -0
- package/dist/src/openspec/explore.js.map +1 -0
- package/dist/src/openspec/propose.d.ts +8 -0
- package/dist/src/openspec/propose.d.ts.map +1 -0
- package/dist/src/openspec/propose.js +124 -0
- package/dist/src/openspec/propose.js.map +1 -0
- package/dist/src/openspec/verify.d.ts +13 -0
- package/dist/src/openspec/verify.d.ts.map +1 -0
- package/dist/src/openspec/verify.js +156 -0
- package/dist/src/openspec/verify.js.map +1 -0
- package/dist/src/platform/claudecode.d.ts +2 -0
- package/dist/src/platform/claudecode.d.ts.map +1 -0
- package/dist/src/platform/claudecode.js +7 -0
- package/dist/src/platform/claudecode.js.map +1 -0
- package/dist/src/platform/codex.d.ts +2 -0
- package/dist/src/platform/codex.d.ts.map +1 -0
- package/dist/src/platform/codex.js +7 -0
- package/dist/src/platform/codex.js.map +1 -0
- package/dist/src/platform/opencode.d.ts +2 -0
- package/dist/src/platform/opencode.d.ts.map +1 -0
- package/dist/src/platform/opencode.js +7 -0
- package/dist/src/platform/opencode.js.map +1 -0
- package/dist/src/platform/router.d.ts +13 -0
- package/dist/src/platform/router.d.ts.map +1 -0
- package/dist/src/platform/router.js +57 -0
- package/dist/src/platform/router.js.map +1 -0
- package/dist/src/skills/cache.d.ts +16 -0
- package/dist/src/skills/cache.d.ts.map +1 -0
- package/dist/src/skills/cache.js +53 -0
- package/dist/src/skills/cache.js.map +1 -0
- package/dist/src/skills/discovery.d.ts +12 -0
- package/dist/src/skills/discovery.d.ts.map +1 -0
- package/dist/src/skills/discovery.js +61 -0
- package/dist/src/skills/discovery.js.map +1 -0
- package/dist/src/skills/loader.d.ts +12 -0
- package/dist/src/skills/loader.d.ts.map +1 -0
- package/dist/src/skills/loader.js +69 -0
- package/dist/src/skills/loader.js.map +1 -0
- package/dist/src/skills/registry.d.ts +23 -0
- package/dist/src/skills/registry.d.ts.map +1 -0
- package/dist/src/skills/registry.js +68 -0
- package/dist/src/skills/registry.js.map +1 -0
- package/dist/src/utils/fs.d.ts +5 -0
- package/dist/src/utils/fs.d.ts.map +1 -0
- package/dist/src/utils/fs.js +23 -0
- package/dist/src/utils/fs.js.map +1 -0
- package/dist/src/utils/logger.d.ts +7 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +8 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/yaml.d.ts +3 -0
- package/dist/src/utils/yaml.d.ts.map +1 -0
- package/dist/src/utils/yaml.js +8 -0
- package/dist/src/utils/yaml.js.map +1 -0
- package/package.json +62 -0
- package/registry/skills-registry.yaml +218 -0
- package/skills/core/brainstorming/SKILL.md +259 -0
- package/skills/core/brainstorming/scripts/frame-template.html +214 -0
- package/skills/core/brainstorming/scripts/helper.js +88 -0
- package/skills/core/brainstorming/scripts/server.cjs +338 -0
- package/skills/core/brainstorming/scripts/start-server.sh +153 -0
- package/skills/core/brainstorming/scripts/stop-server.sh +55 -0
- package/skills/core/brainstorming/skill.yaml +12 -0
- package/skills/core/brainstorming/spec-document-reviewer-prompt.md +48 -0
- package/skills/core/brainstorming/visual-companion.md +286 -0
- package/skills/core/claude-code-core/SKILL.md +164 -0
- package/skills/core/claude-code-core/skill.yaml +14 -0
- package/skills/core/claude-code-prompt/SKILL.md +283 -0
- package/skills/core/claude-code-prompt/skill.yaml +14 -0
- package/skills/core/claude-code-subagent/SKILL.md +168 -0
- package/skills/core/claude-code-subagent/skill.yaml +14 -0
- package/skills/core/e2e-generate/SKILL.md +147 -0
- package/skills/core/e2e-generate/skill.yaml +12 -0
- package/skills/core/ecc-agents-md-router/SKILL.md +90 -0
- package/skills/core/ecc-agents-md-router/skill.yaml +12 -0
- package/skills/core/ecc-context-injector/SKILL.md +69 -0
- package/skills/core/ecc-context-injector/skill.yaml +12 -0
- package/skills/core/existing-code-caveman/SKILL.md +340 -0
- package/skills/core/existing-code-caveman/skill.yaml +12 -0
- package/skills/core/opsx-apply/SKILL.md +121 -0
- package/skills/core/opsx-apply/skill.yaml +12 -0
- package/skills/core/opsx-archive/SKILL.md +83 -0
- package/skills/core/opsx-archive/skill.yaml +12 -0
- package/skills/core/opsx-explore/SKILL.md +101 -0
- package/skills/core/opsx-explore/skill.yaml +12 -0
- package/skills/core/opsx-propose/SKILL.md +131 -0
- package/skills/core/opsx-propose/skill.yaml +16 -0
- package/skills/core/opsx-verify/SKILL.md +109 -0
- package/skills/core/opsx-verify/skill.yaml +12 -0
- package/skills/core/subagent-driven-development/SKILL.md +157 -0
- package/skills/core/subagent-driven-development/code-quality-reviewer-prompt.md +64 -0
- package/skills/core/subagent-driven-development/implementer-prompt.md +122 -0
- package/skills/core/subagent-driven-development/skill.yaml +12 -0
- package/skills/core/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/core/writing-plans/SKILL.md +268 -0
- package/skills/core/writing-plans/plan-document-reviewer-prompt.md +63 -0
- package/skills/core/writing-plans/skill.yaml +12 -0
- package/skills/locale/chinese-code-review/SKILL.md +17 -0
- package/skills/locale/chinese-code-review/skill.yaml +16 -0
- package/skills/locale/chinese-commit-conventions/SKILL.md +17 -0
- package/skills/locale/chinese-commit-conventions/skill.yaml +16 -0
- package/skills/locale/chinese-documentation/SKILL.md +17 -0
- package/skills/locale/chinese-documentation/skill.yaml +16 -0
- package/skills/locale/chinese-git-workflow/SKILL.md +17 -0
- package/skills/locale/chinese-git-workflow/skill.yaml +16 -0
- package/templates/agents-md.md +42 -0
- package/templates/claude-md.md +44 -0
- package/templates/codex-md.md +49 -0
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
5
|
+
import { GraphEngine } from '../graph/index.js';
|
|
6
|
+
import yaml from 'yaml';
|
|
7
|
+
const graph = new Command('graph')
|
|
8
|
+
.description('代码图谱管理(结构索引 + 语义增强)');
|
|
9
|
+
// sds graph init
|
|
10
|
+
graph
|
|
11
|
+
.command('init')
|
|
12
|
+
.description('初始化图谱数据库,检测项目语言')
|
|
13
|
+
.option('--lang <lang>', '强制指定语言(ts / python / go / rust / java)', 'auto')
|
|
14
|
+
.option('--db-path <path>', '图谱数据库路径', '.sds/codegraph.db')
|
|
15
|
+
.option('--include <dirs>', '额外包含目录(逗号分隔)')
|
|
16
|
+
.option('--exclude <dirs>', '排除目录(逗号分隔)', 'node_modules,dist,.git')
|
|
17
|
+
.option('--platform <platform>', '目标平台(claude-code / opencode / codex)', 'auto')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const projectDir = process.cwd();
|
|
20
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
21
|
+
console.log('\n sds graph init — 初始化图谱数据库\n');
|
|
22
|
+
console.log(` 项目目录: ${projectDir}\n`);
|
|
23
|
+
// 检测项目语言
|
|
24
|
+
let lang = options.lang;
|
|
25
|
+
if (lang === 'auto') {
|
|
26
|
+
lang = detectProjectLanguage(projectDir);
|
|
27
|
+
console.log(` 检测到语言: ${lang}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(` 指定语言: ${lang}`);
|
|
31
|
+
}
|
|
32
|
+
// 检测平台
|
|
33
|
+
let platform = options.platform;
|
|
34
|
+
if (platform === 'auto') {
|
|
35
|
+
if (existsSync(resolve(projectDir, '.codex'))) {
|
|
36
|
+
platform = 'codex';
|
|
37
|
+
}
|
|
38
|
+
else if (existsSync(resolve(projectDir, '.opencode'))) {
|
|
39
|
+
platform = 'opencode';
|
|
40
|
+
}
|
|
41
|
+
else if (existsSync(resolve(projectDir, '.claude'))) {
|
|
42
|
+
platform = 'claude-code';
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
platform = 'claude-code'; // 默认
|
|
46
|
+
}
|
|
47
|
+
console.log(` 检测到平台: ${platform}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log(` 指定平台: ${platform}`);
|
|
51
|
+
}
|
|
52
|
+
// 解析 include/exclude
|
|
53
|
+
const include = options.include
|
|
54
|
+
? options.include.split(',').map((s) => s.trim())
|
|
55
|
+
: ['src', 'lib'];
|
|
56
|
+
const exclude = options.exclude
|
|
57
|
+
? options.exclude.split(',').map((s) => s.trim())
|
|
58
|
+
: ['node_modules', 'dist', '.git', 'build', 'coverage'];
|
|
59
|
+
// 生成配置
|
|
60
|
+
const config = {
|
|
61
|
+
project: {
|
|
62
|
+
name: getProjectName(projectDir),
|
|
63
|
+
lang,
|
|
64
|
+
root: '.'
|
|
65
|
+
},
|
|
66
|
+
graph: {
|
|
67
|
+
db_path: options.dbPath,
|
|
68
|
+
semantic_path: '.sds/semantic-graph.json',
|
|
69
|
+
include,
|
|
70
|
+
exclude
|
|
71
|
+
},
|
|
72
|
+
enhance: {
|
|
73
|
+
enabled: 'auto',
|
|
74
|
+
provider: 'openai',
|
|
75
|
+
model: 'gpt-4o',
|
|
76
|
+
depth: 'standard',
|
|
77
|
+
max_files: 50,
|
|
78
|
+
budget_tokens: 100000
|
|
79
|
+
},
|
|
80
|
+
cache: {
|
|
81
|
+
l1_ttl: 3600,
|
|
82
|
+
l2_path: '~/.sds/graph-cache/'
|
|
83
|
+
},
|
|
84
|
+
platform: {
|
|
85
|
+
target: platform
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
// 确保 .sds 目录存在
|
|
89
|
+
const sdsDir = resolve(projectDir, '.sds');
|
|
90
|
+
if (!existsSync(sdsDir)) {
|
|
91
|
+
mkdirSync(sdsDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
// 写入配置文件
|
|
94
|
+
writeFileSync(configPath, yaml.stringify(config), 'utf-8');
|
|
95
|
+
console.log(`\n ✅ 配置文件已生成: .sds/graph.config.yaml`);
|
|
96
|
+
// 初始化数据库
|
|
97
|
+
const dbPath = resolve(projectDir, options.dbPath);
|
|
98
|
+
const engine = new GraphEngine(projectDir, {
|
|
99
|
+
graph: {
|
|
100
|
+
dbPath: options.dbPath,
|
|
101
|
+
semanticPath: '.sds/semantic-graph.json',
|
|
102
|
+
include,
|
|
103
|
+
exclude
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
await engine.init();
|
|
107
|
+
engine.close();
|
|
108
|
+
console.log(` ✅ 数据库已初始化: ${options.dbPath}`);
|
|
109
|
+
console.log(`\n 下一步: 运行 'sds graph index' 进行全量索引\n`);
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* 检测项目语言
|
|
113
|
+
*/
|
|
114
|
+
function detectProjectLanguage(projectDir) {
|
|
115
|
+
// 检查常见配置文件
|
|
116
|
+
const langIndicators = {
|
|
117
|
+
'typescript': ['tsconfig.json', 'package.json'],
|
|
118
|
+
'python': ['pyproject.toml', 'setup.py', 'requirements.txt', 'Pipfile'],
|
|
119
|
+
'go': ['go.mod', 'go.sum'],
|
|
120
|
+
'rust': ['Cargo.toml', 'Cargo.lock'],
|
|
121
|
+
'java': ['pom.xml', 'build.gradle', 'build.gradle.kts'],
|
|
122
|
+
'ruby': ['Gemfile', 'Rakefile'],
|
|
123
|
+
'php': ['composer.json'],
|
|
124
|
+
'c': ['Makefile', 'CMakeLists.txt'],
|
|
125
|
+
'cpp': ['Makefile', 'CMakeLists.txt'],
|
|
126
|
+
};
|
|
127
|
+
for (const [lang, files] of Object.entries(langIndicators)) {
|
|
128
|
+
for (const file of files) {
|
|
129
|
+
if (existsSync(resolve(projectDir, file))) {
|
|
130
|
+
// 对于 package.json,进一步检查是否是 TypeScript
|
|
131
|
+
if (file === 'package.json') {
|
|
132
|
+
if (existsSync(resolve(projectDir, 'tsconfig.json'))) {
|
|
133
|
+
return 'typescript';
|
|
134
|
+
}
|
|
135
|
+
return 'javascript';
|
|
136
|
+
}
|
|
137
|
+
return lang;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return 'unknown';
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 获取项目名称
|
|
145
|
+
*/
|
|
146
|
+
function getProjectName(projectDir) {
|
|
147
|
+
const packageJsonPath = resolve(projectDir, 'package.json');
|
|
148
|
+
if (existsSync(packageJsonPath)) {
|
|
149
|
+
try {
|
|
150
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
151
|
+
return packageJson.name || 'unknown';
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// ignore
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const pyprojectPath = resolve(projectDir, 'pyproject.toml');
|
|
158
|
+
if (existsSync(pyprojectPath)) {
|
|
159
|
+
try {
|
|
160
|
+
const content = readFileSync(pyprojectPath, 'utf-8');
|
|
161
|
+
const nameMatch = content.match(/name\s*=\s*"([^"]+)"/);
|
|
162
|
+
if (nameMatch)
|
|
163
|
+
return nameMatch[1];
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// ignore
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const cargoPath = resolve(projectDir, 'Cargo.toml');
|
|
170
|
+
if (existsSync(cargoPath)) {
|
|
171
|
+
try {
|
|
172
|
+
const content = readFileSync(cargoPath, 'utf-8');
|
|
173
|
+
const nameMatch = content.match(/name\s*=\s*"([^"]+)"/);
|
|
174
|
+
if (nameMatch)
|
|
175
|
+
return nameMatch[1];
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// ignore
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// 使用目录名
|
|
182
|
+
return projectDir.split(/[/\\]/).pop() || 'unknown';
|
|
183
|
+
}
|
|
184
|
+
// sds graph index
|
|
185
|
+
graph
|
|
186
|
+
.command('index')
|
|
187
|
+
.description('全量索引(CodeGraph Tree-sitter)')
|
|
188
|
+
.option('--incremental', '增量模式(对比上次索引的 hash)', false)
|
|
189
|
+
.option('--tiered', '分层索引(大型项目优化)', false)
|
|
190
|
+
.option('--workers <number>', '并行 Worker 数', String(os.cpus().length))
|
|
191
|
+
.option('--output-format <format>', '输出格式(sqlite / json / mcp)', 'sqlite')
|
|
192
|
+
.option('--verbose', '显示详细进度', false)
|
|
193
|
+
.action(async (options) => {
|
|
194
|
+
const projectDir = process.cwd();
|
|
195
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
196
|
+
// 检查配置文件
|
|
197
|
+
if (!existsSync(configPath)) {
|
|
198
|
+
console.error('\n ❌ 未找到配置文件,请先运行: sds graph init\n');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
// 读取配置
|
|
202
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
203
|
+
const config = yaml.parse(configContent);
|
|
204
|
+
console.log('\n sds graph index — 全量索引\n');
|
|
205
|
+
console.log(` 项目目录: ${projectDir}`);
|
|
206
|
+
console.log(` 增量模式: ${options.incremental ? '是' : '否'}`);
|
|
207
|
+
console.log(` 分层索引: ${options.tiered ? '是' : '否'}\n`);
|
|
208
|
+
// 创建引擎
|
|
209
|
+
const engine = new GraphEngine(projectDir, {
|
|
210
|
+
graph: {
|
|
211
|
+
dbPath: config.graph.db_path,
|
|
212
|
+
semanticPath: config.graph.semantic_path,
|
|
213
|
+
include: config.graph.include,
|
|
214
|
+
exclude: config.graph.exclude
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
await engine.init();
|
|
218
|
+
// 执行索引
|
|
219
|
+
const startTime = Date.now();
|
|
220
|
+
let stats;
|
|
221
|
+
if (options.tiered) {
|
|
222
|
+
// 分层索引
|
|
223
|
+
console.log(' 使用分层索引策略...\n');
|
|
224
|
+
const progressCallback = (progress) => {
|
|
225
|
+
if (options.verbose) {
|
|
226
|
+
const bar = '█'.repeat(Math.floor(progress.percentage / 5)) + '░'.repeat(20 - Math.floor(progress.percentage / 5));
|
|
227
|
+
process.stdout.write(`\r ${bar} ${progress.percentage}% | ${progress.phase} | ${progress.current}/${progress.total} | ${progress.speed.toFixed(1)} 文件/秒`);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
stats = await engine.tieredIndex(progressCallback);
|
|
231
|
+
if (options.verbose) {
|
|
232
|
+
process.stdout.write('\n');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// 普通索引
|
|
237
|
+
stats = await engine.index({
|
|
238
|
+
incremental: options.incremental,
|
|
239
|
+
verbose: options.verbose
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const durationMs = Date.now() - startTime;
|
|
243
|
+
// 输出统计
|
|
244
|
+
console.log('\n 索引完成!\n');
|
|
245
|
+
console.log(` 文件数: ${stats.filesIndexed}`);
|
|
246
|
+
console.log(` 函数: ${stats.functions}`);
|
|
247
|
+
console.log(` 类: ${stats.classes}`);
|
|
248
|
+
console.log(` 接口: ${stats.interfaces}`);
|
|
249
|
+
console.log(` 类型: ${stats.types}`);
|
|
250
|
+
console.log(` 变量: ${stats.variables}`);
|
|
251
|
+
console.log(` 调用关系: ${stats.callEdges}`);
|
|
252
|
+
console.log(` 导入关系: ${stats.importEdges}`);
|
|
253
|
+
console.log(` 耗时: ${durationMs}ms`);
|
|
254
|
+
console.log(` 缓存命中: ${stats.cacheHit ? '是' : '否'}\n`);
|
|
255
|
+
engine.close();
|
|
256
|
+
});
|
|
257
|
+
// sds graph enhance
|
|
258
|
+
graph
|
|
259
|
+
.command('enhance')
|
|
260
|
+
.description('语义增强(Understand Anything LLM)')
|
|
261
|
+
.option('--files <files>', '指定文件路径(逗号分隔),不传则自动采样')
|
|
262
|
+
.option('--depth <depth>', 'lite / standard / deep', 'standard')
|
|
263
|
+
.option('--model <model>', '覆盖模型')
|
|
264
|
+
.option('--output <path>', '语义图谱输出路径', '.sds/semantic-graph.json')
|
|
265
|
+
.option('--dry-run', '预览将分析哪些文件,不实际调用 LLM', false)
|
|
266
|
+
.action(async (options) => {
|
|
267
|
+
const projectDir = process.cwd();
|
|
268
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
269
|
+
// 检查配置文件
|
|
270
|
+
if (!existsSync(configPath)) {
|
|
271
|
+
console.error('\n ❌ 未找到配置文件,请先运行: sds graph init\n');
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
// 读取配置
|
|
275
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
276
|
+
const config = yaml.parse(configContent);
|
|
277
|
+
console.log('\n sds graph enhance — 语义增强\n');
|
|
278
|
+
// 创建引擎
|
|
279
|
+
const engine = new GraphEngine(projectDir, {
|
|
280
|
+
graph: {
|
|
281
|
+
dbPath: config.graph.db_path,
|
|
282
|
+
semanticPath: config.graph.semantic_path,
|
|
283
|
+
include: config.graph.include,
|
|
284
|
+
exclude: config.graph.exclude
|
|
285
|
+
},
|
|
286
|
+
enhance: {
|
|
287
|
+
enabled: config.enhance.enabled,
|
|
288
|
+
provider: config.enhance.provider,
|
|
289
|
+
model: config.enhance.model,
|
|
290
|
+
depth: options.depth,
|
|
291
|
+
maxFiles: config.enhance.max_files,
|
|
292
|
+
budgetTokens: config.enhance.budget_tokens
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
await engine.init();
|
|
296
|
+
// 检查是否可用
|
|
297
|
+
if (!engine.isSemanticAvailable()) {
|
|
298
|
+
console.log(' ⚠️ 语义增强不可用\n');
|
|
299
|
+
console.log(' 请设置环境变量:');
|
|
300
|
+
console.log(' - OPENAI_API_KEY (for OpenAI)');
|
|
301
|
+
console.log(' - ANTHROPIC_API_KEY (for Anthropic)\n');
|
|
302
|
+
engine.close();
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
// 解析文件列表
|
|
306
|
+
const files = options.files ? options.files.split(',').map((s) => s.trim()) : undefined;
|
|
307
|
+
// 构建选项
|
|
308
|
+
const enhanceOptions = {
|
|
309
|
+
files,
|
|
310
|
+
depth: options.depth,
|
|
311
|
+
model: options.model,
|
|
312
|
+
budgetTokens: config.enhance.budget_tokens,
|
|
313
|
+
dryRun: options.dryRun
|
|
314
|
+
};
|
|
315
|
+
// 预览采样
|
|
316
|
+
const preview = engine.previewEnhance(enhanceOptions);
|
|
317
|
+
console.log(` 采样文件数: ${preview.files.length}`);
|
|
318
|
+
console.log(` 预估 Token: ${preview.estimatedTokens}`);
|
|
319
|
+
console.log(` 预估成本: $${preview.estimatedCost.toFixed(4)}`);
|
|
320
|
+
console.log('');
|
|
321
|
+
if (options.dryRun) {
|
|
322
|
+
console.log(' 预览模式,不执行实际分析\n');
|
|
323
|
+
console.log(' 采样文件:');
|
|
324
|
+
for (const file of preview.files) {
|
|
325
|
+
console.log(` - ${file.path} (${file.lines} 行)`);
|
|
326
|
+
}
|
|
327
|
+
console.log('');
|
|
328
|
+
engine.close();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// 执行增强
|
|
332
|
+
console.log(' 开始语义分析...\n');
|
|
333
|
+
const result = await engine.enhance(enhanceOptions);
|
|
334
|
+
if (result.status === 'completed') {
|
|
335
|
+
console.log(' ✅ 语义增强完成!\n');
|
|
336
|
+
console.log(` 分析文件数: ${result.filesAnalyzed}`);
|
|
337
|
+
console.log(` Token 消耗: ${result.tokensUsed}`);
|
|
338
|
+
console.log(` 耗时: ${result.durationMs}ms`);
|
|
339
|
+
console.log(` 输出路径: ${result.outputPath}\n`);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
console.error(' ❌ 语义增强失败\n');
|
|
343
|
+
for (const error of result.errors) {
|
|
344
|
+
console.error(` - ${error}`);
|
|
345
|
+
}
|
|
346
|
+
console.log('');
|
|
347
|
+
}
|
|
348
|
+
engine.close();
|
|
349
|
+
});
|
|
350
|
+
// sds graph query
|
|
351
|
+
graph
|
|
352
|
+
.command('query')
|
|
353
|
+
.description('查询图谱(SQL / 自然语言)')
|
|
354
|
+
.option('--sql <query>', 'SQL 查询语句')
|
|
355
|
+
.option('--nl <query>', '自然语言查询')
|
|
356
|
+
.option('--template <template>', '预定义查询模板(dead-code / circular-deps / entry-points)')
|
|
357
|
+
.action(async (options) => {
|
|
358
|
+
const projectDir = process.cwd();
|
|
359
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
360
|
+
// 检查配置文件
|
|
361
|
+
if (!existsSync(configPath)) {
|
|
362
|
+
console.error('\n ❌ 未找到配置文件,请先运行: sds graph init\n');
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
// 读取配置
|
|
366
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
367
|
+
const config = yaml.parse(configContent);
|
|
368
|
+
// 创建引擎
|
|
369
|
+
const engine = new GraphEngine(projectDir, {
|
|
370
|
+
graph: {
|
|
371
|
+
dbPath: config.graph.db_path,
|
|
372
|
+
semanticPath: config.graph.semantic_path,
|
|
373
|
+
include: config.graph.include,
|
|
374
|
+
exclude: config.graph.exclude
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
await engine.init();
|
|
378
|
+
let sql = options.sql;
|
|
379
|
+
// 处理模板查询
|
|
380
|
+
if (options.template) {
|
|
381
|
+
sql = getTemplateQuery(options.template);
|
|
382
|
+
if (!sql) {
|
|
383
|
+
console.error(`\n ❌ 未知模板: ${options.template}`);
|
|
384
|
+
console.error(' 可用模板: dead-code, circular-deps, entry-points\n');
|
|
385
|
+
engine.close();
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// 处理自然语言查询(简化实现,后续可集成 LLM)
|
|
390
|
+
if (options.nl) {
|
|
391
|
+
console.log('\n ⚠️ 自然语言查询暂未实现,请使用 --sql 或 --template\n');
|
|
392
|
+
engine.close();
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
if (!sql) {
|
|
396
|
+
console.error('\n ❌ 请指定查询: --sql, --nl, 或 --template\n');
|
|
397
|
+
engine.close();
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
console.log('\n sds graph query\n');
|
|
401
|
+
console.log(` SQL: ${sql}\n`);
|
|
402
|
+
try {
|
|
403
|
+
const result = engine.query(sql);
|
|
404
|
+
// 输出结果
|
|
405
|
+
if (result.rows.length === 0) {
|
|
406
|
+
console.log(' 没有结果\n');
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// 格式化输出
|
|
410
|
+
const maxColWidths = {};
|
|
411
|
+
// 计算列宽
|
|
412
|
+
for (const col of result.columns) {
|
|
413
|
+
maxColWidths[col] = col.length;
|
|
414
|
+
}
|
|
415
|
+
for (const row of result.rows) {
|
|
416
|
+
for (const col of result.columns) {
|
|
417
|
+
const val = String(row[col] ?? '');
|
|
418
|
+
maxColWidths[col] = Math.max(maxColWidths[col], val.length);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// 输出表头
|
|
422
|
+
const header = result.columns.map(col => col.padEnd(maxColWidths[col])).join(' | ');
|
|
423
|
+
const separator = result.columns.map(col => '-'.repeat(maxColWidths[col])).join('-+-');
|
|
424
|
+
console.log(` ${header}`);
|
|
425
|
+
console.log(` ${separator}`);
|
|
426
|
+
// 输出行
|
|
427
|
+
for (const row of result.rows) {
|
|
428
|
+
const line = result.columns.map(col => {
|
|
429
|
+
const val = String(row[col] ?? '');
|
|
430
|
+
return val.padEnd(maxColWidths[col]);
|
|
431
|
+
}).join(' | ');
|
|
432
|
+
console.log(` ${line}`);
|
|
433
|
+
}
|
|
434
|
+
console.log(`\n ${result.rowCount} 行结果,耗时 ${result.durationMs}ms\n`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
console.error(`\n ❌ 查询失败: ${error.message}\n`);
|
|
439
|
+
}
|
|
440
|
+
engine.close();
|
|
441
|
+
});
|
|
442
|
+
/**
|
|
443
|
+
* 获取预定义查询模板
|
|
444
|
+
*/
|
|
445
|
+
function getTemplateQuery(template) {
|
|
446
|
+
const templates = {
|
|
447
|
+
'dead-code': `
|
|
448
|
+
SELECT f.path, s.name, s.type
|
|
449
|
+
FROM symbols s
|
|
450
|
+
JOIN files f ON s.file_id = f.id
|
|
451
|
+
WHERE s.id NOT IN (
|
|
452
|
+
SELECT DISTINCT callee_symbol_id FROM call_graph WHERE callee_symbol_id > 0
|
|
453
|
+
)
|
|
454
|
+
AND s.type IN ('function', 'class')
|
|
455
|
+
ORDER BY f.path, s.name
|
|
456
|
+
`,
|
|
457
|
+
'circular-deps': `
|
|
458
|
+
SELECT
|
|
459
|
+
f1.path as file1,
|
|
460
|
+
f2.path as file2,
|
|
461
|
+
COUNT(*) as dep_count
|
|
462
|
+
FROM call_graph cg
|
|
463
|
+
JOIN files f1 ON cg.caller_file_id = f1.id
|
|
464
|
+
JOIN files f2 ON cg.callee_file_id = f2.id
|
|
465
|
+
WHERE cg.relation_type = 'import'
|
|
466
|
+
AND EXISTS (
|
|
467
|
+
SELECT 1 FROM call_graph cg2
|
|
468
|
+
WHERE cg2.caller_file_id = f2.id
|
|
469
|
+
AND cg2.callee_file_id = f1.id
|
|
470
|
+
AND cg2.relation_type = 'import'
|
|
471
|
+
)
|
|
472
|
+
GROUP BY f1.path, f2.path
|
|
473
|
+
ORDER BY dep_count DESC
|
|
474
|
+
`,
|
|
475
|
+
'entry-points': `
|
|
476
|
+
SELECT f.path, f.lang, f.lines
|
|
477
|
+
FROM files f
|
|
478
|
+
WHERE f.id NOT IN (
|
|
479
|
+
SELECT DISTINCT callee_file_id FROM call_graph WHERE callee_file_id > 0
|
|
480
|
+
)
|
|
481
|
+
OR f.path LIKE '%main%'
|
|
482
|
+
OR f.path LIKE '%index%'
|
|
483
|
+
OR f.path LIKE '%app%'
|
|
484
|
+
ORDER BY f.path
|
|
485
|
+
`
|
|
486
|
+
};
|
|
487
|
+
return templates[template] || null;
|
|
488
|
+
}
|
|
489
|
+
// sds graph diff
|
|
490
|
+
graph
|
|
491
|
+
.command('diff')
|
|
492
|
+
.description('增量更新(基于 Git Diff)')
|
|
493
|
+
.action(async () => {
|
|
494
|
+
const projectDir = process.cwd();
|
|
495
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
496
|
+
// 检查配置文件
|
|
497
|
+
if (!existsSync(configPath)) {
|
|
498
|
+
console.error('\n ❌ 未找到配置文件,请先运行: sds graph init\n');
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
// 读取配置
|
|
502
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
503
|
+
const config = yaml.parse(configContent);
|
|
504
|
+
console.log('\n sds graph diff — 增量更新\n');
|
|
505
|
+
// 创建引擎
|
|
506
|
+
const engine = new GraphEngine(projectDir, {
|
|
507
|
+
graph: {
|
|
508
|
+
dbPath: config.graph.db_path,
|
|
509
|
+
semanticPath: config.graph.semantic_path,
|
|
510
|
+
include: config.graph.include,
|
|
511
|
+
exclude: config.graph.exclude
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
await engine.init();
|
|
515
|
+
// 执行增量更新
|
|
516
|
+
const result = await engine.diff();
|
|
517
|
+
if (result.status === 'no_changes') {
|
|
518
|
+
console.log(' 没有检测到变更文件\n');
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
console.log(` 变更文件数: ${result.changedFiles}`);
|
|
522
|
+
console.log(` 重新索引节点: ${result.reindexedNodes}`);
|
|
523
|
+
console.log(` 重新索引关系: ${result.reindexedEdges}`);
|
|
524
|
+
if (result.semanticInvalidated.length > 0) {
|
|
525
|
+
console.log(`\n 语义失效文件:`);
|
|
526
|
+
for (const file of result.semanticInvalidated) {
|
|
527
|
+
console.log(` - ${file}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (result.suggestion) {
|
|
531
|
+
console.log(`\n 建议: ${result.suggestion}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
console.log('');
|
|
535
|
+
engine.close();
|
|
536
|
+
});
|
|
537
|
+
// sds graph export
|
|
538
|
+
graph
|
|
539
|
+
.command('export')
|
|
540
|
+
.description('导出为 AI 助手引导文件片段')
|
|
541
|
+
.option('--format <format>', '导出格式(claude-md / agents-md / json)', 'claude-md')
|
|
542
|
+
.option('--output <path>', '输出路径')
|
|
543
|
+
.action(async (options) => {
|
|
544
|
+
const projectDir = process.cwd();
|
|
545
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
546
|
+
// 检查配置文件
|
|
547
|
+
if (!existsSync(configPath)) {
|
|
548
|
+
console.error('\n ❌ 未找到配置文件,请先运行: sds graph init\n');
|
|
549
|
+
process.exit(1);
|
|
550
|
+
}
|
|
551
|
+
// 读取配置
|
|
552
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
553
|
+
const config = yaml.parse(configContent);
|
|
554
|
+
console.log('\n sds graph export — 导出图谱\n');
|
|
555
|
+
// 创建引擎
|
|
556
|
+
const engine = new GraphEngine(projectDir, {
|
|
557
|
+
graph: {
|
|
558
|
+
dbPath: config.graph.db_path,
|
|
559
|
+
semanticPath: config.graph.semantic_path,
|
|
560
|
+
include: config.graph.include,
|
|
561
|
+
exclude: config.graph.exclude
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
await engine.init();
|
|
565
|
+
// 导出图谱
|
|
566
|
+
const result = await engine.exportGraph({
|
|
567
|
+
format: options.format,
|
|
568
|
+
outputPath: options.output
|
|
569
|
+
});
|
|
570
|
+
if (result.status === 'completed') {
|
|
571
|
+
console.log(' ✅ 导出完成!\n');
|
|
572
|
+
console.log(` 格式: ${result.format}`);
|
|
573
|
+
console.log(` 输出路径: ${result.outputPath}`);
|
|
574
|
+
console.log(` 耗时: ${result.durationMs}ms\n`);
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
console.error(' ❌ 导出失败\n');
|
|
578
|
+
for (const error of result.errors) {
|
|
579
|
+
console.error(` - ${error}`);
|
|
580
|
+
}
|
|
581
|
+
console.log('');
|
|
582
|
+
}
|
|
583
|
+
engine.close();
|
|
584
|
+
});
|
|
585
|
+
// sds graph status
|
|
586
|
+
graph
|
|
587
|
+
.command('status')
|
|
588
|
+
.description('查看索引状态、覆盖率、最后更新')
|
|
589
|
+
.action(async () => {
|
|
590
|
+
const projectDir = process.cwd();
|
|
591
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
592
|
+
console.log('\n sds graph status\n');
|
|
593
|
+
// 检查配置文件
|
|
594
|
+
if (!existsSync(configPath)) {
|
|
595
|
+
console.log(' 状态: 未初始化\n');
|
|
596
|
+
console.log(' 运行 \'sds graph init\' 初始化图谱数据库\n');
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
// 读取配置
|
|
600
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
601
|
+
const config = yaml.parse(configContent);
|
|
602
|
+
// 创建引擎
|
|
603
|
+
const engine = new GraphEngine(projectDir, {
|
|
604
|
+
graph: {
|
|
605
|
+
dbPath: config.graph.db_path,
|
|
606
|
+
semanticPath: config.graph.semantic_path,
|
|
607
|
+
include: config.graph.include,
|
|
608
|
+
exclude: config.graph.exclude
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
await engine.init();
|
|
612
|
+
// 获取状态
|
|
613
|
+
const status = await engine.getStatus();
|
|
614
|
+
if (!status.exists) {
|
|
615
|
+
console.log(' 状态: 数据库不存在\n');
|
|
616
|
+
console.log(' 运行 \'sds graph index\' 进行索引\n');
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
console.log(' 状态: 已初始化\n');
|
|
620
|
+
console.log(` 数据库路径: ${status.dbPath}`);
|
|
621
|
+
console.log(` 文件数: ${status.filesCount}`);
|
|
622
|
+
console.log(` 符号数: ${status.symbolsCount}`);
|
|
623
|
+
console.log(` 关系数: ${status.edgesCount}`);
|
|
624
|
+
console.log(` 覆盖率: ${status.coveragePercent}%`);
|
|
625
|
+
if (status.lastUpdated) {
|
|
626
|
+
console.log(` 最后更新: ${status.lastUpdated}`);
|
|
627
|
+
}
|
|
628
|
+
if (status.semanticEnabled) {
|
|
629
|
+
console.log(` 语义增强: 已启用`);
|
|
630
|
+
if (status.semanticLastUpdated) {
|
|
631
|
+
console.log(` 语义更新: ${status.semanticLastUpdated}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
console.log(` 语义增强: 未启用`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
console.log('');
|
|
639
|
+
engine.close();
|
|
640
|
+
});
|
|
641
|
+
// sds graph cache
|
|
642
|
+
graph
|
|
643
|
+
.command('cache')
|
|
644
|
+
.description('管理 L1/L2 缓存')
|
|
645
|
+
.option('--clear', '清除所有缓存', false)
|
|
646
|
+
.option('--info', '显示缓存信息', false)
|
|
647
|
+
.action(async (options) => {
|
|
648
|
+
const projectDir = process.cwd();
|
|
649
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
650
|
+
console.log('\n sds graph cache — 缓存管理\n');
|
|
651
|
+
// 检查配置文件
|
|
652
|
+
if (!existsSync(configPath)) {
|
|
653
|
+
console.log(' 状态: 未初始化\n');
|
|
654
|
+
console.log(' 运行 \'sds graph init\' 初始化图谱数据库\n');
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
// 读取配置
|
|
658
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
659
|
+
const config = yaml.parse(configContent);
|
|
660
|
+
const dbPath = resolve(projectDir, config.graph.db_path);
|
|
661
|
+
const semanticPath = resolve(projectDir, config.graph.semantic_path);
|
|
662
|
+
const l2Path = resolve(projectDir, config.cache.l2_path);
|
|
663
|
+
if (options.clear) {
|
|
664
|
+
// 清除缓存
|
|
665
|
+
console.log(' 清除缓存...\n');
|
|
666
|
+
// 清除 L1 内存缓存(重新加载即可)
|
|
667
|
+
console.log(' ✅ L1 内存缓存已清除');
|
|
668
|
+
// 清除 L2 磁盘缓存
|
|
669
|
+
if (existsSync(l2Path)) {
|
|
670
|
+
const { rmSync } = await import('fs');
|
|
671
|
+
rmSync(l2Path, { recursive: true, force: true });
|
|
672
|
+
console.log(' ✅ L2 磁盘缓存已清除');
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
console.log(' ℹ️ L2 磁盘缓存不存在');
|
|
676
|
+
}
|
|
677
|
+
console.log('');
|
|
678
|
+
}
|
|
679
|
+
else if (options.info) {
|
|
680
|
+
// 显示缓存信息
|
|
681
|
+
console.log(' 缓存信息:\n');
|
|
682
|
+
// L1 内存缓存
|
|
683
|
+
console.log(' L1 内存缓存:');
|
|
684
|
+
console.log(' - 状态: 活跃(进程级)');
|
|
685
|
+
console.log(' - TTL: 配置值');
|
|
686
|
+
// L2 磁盘缓存
|
|
687
|
+
console.log('\n L2 磁盘缓存:');
|
|
688
|
+
console.log(` - 路径: ${l2Path}`);
|
|
689
|
+
if (existsSync(l2Path)) {
|
|
690
|
+
const { statSync } = await import('fs');
|
|
691
|
+
const stat = statSync(l2Path);
|
|
692
|
+
console.log(` - 状态: 存在`);
|
|
693
|
+
console.log(` - 最后修改: ${stat.mtime.toISOString()}`);
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
console.log(' - 状态: 不存在');
|
|
697
|
+
}
|
|
698
|
+
// L3 项目本地
|
|
699
|
+
console.log('\n L3 项目本地:');
|
|
700
|
+
console.log(` - 数据库: ${dbPath}`);
|
|
701
|
+
console.log(` - 语义图谱: ${semanticPath}`);
|
|
702
|
+
if (existsSync(dbPath)) {
|
|
703
|
+
const { statSync } = await import('fs');
|
|
704
|
+
const stat = statSync(dbPath);
|
|
705
|
+
console.log(` - 数据库大小: ${(stat.size / 1024).toFixed(2)} KB`);
|
|
706
|
+
}
|
|
707
|
+
if (existsSync(semanticPath)) {
|
|
708
|
+
const { statSync } = await import('fs');
|
|
709
|
+
const stat = statSync(semanticPath);
|
|
710
|
+
console.log(` - 语义图谱大小: ${(stat.size / 1024).toFixed(2)} KB`);
|
|
711
|
+
}
|
|
712
|
+
console.log('');
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
console.log(' 请指定操作:\n');
|
|
716
|
+
console.log(' --clear 清除所有缓存');
|
|
717
|
+
console.log(' --info 显示缓存信息\n');
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
// sds graph viz
|
|
721
|
+
graph
|
|
722
|
+
.command('viz')
|
|
723
|
+
.description('生成 HTML 交互图谱')
|
|
724
|
+
.option('--format <format>', '输出格式(html / svg)', 'html')
|
|
725
|
+
.option('--output <path>', '输出路径')
|
|
726
|
+
.option('--max-nodes <number>', '最大节点数', '100')
|
|
727
|
+
.option('--max-edges <number>', '最大边数', '500')
|
|
728
|
+
.option('--theme <theme>', '主题(light / dark)', 'light')
|
|
729
|
+
.option('--layout <layout>', '布局算法(hierarchical / circular / force-directed / grid / tree)', 'force-directed')
|
|
730
|
+
.action(async (options) => {
|
|
731
|
+
const projectDir = process.cwd();
|
|
732
|
+
const configPath = resolve(projectDir, '.sds/graph.config.yaml');
|
|
733
|
+
// 检查配置文件
|
|
734
|
+
if (!existsSync(configPath)) {
|
|
735
|
+
console.error('\n ❌ 未找到配置文件,请先运行: sds graph init\n');
|
|
736
|
+
process.exit(1);
|
|
737
|
+
}
|
|
738
|
+
// 读取配置
|
|
739
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
740
|
+
const config = yaml.parse(configContent);
|
|
741
|
+
console.log('\n sds graph viz — 生成交互图谱\n');
|
|
742
|
+
// 创建引擎
|
|
743
|
+
const engine = new GraphEngine(projectDir, {
|
|
744
|
+
graph: {
|
|
745
|
+
dbPath: config.graph.db_path,
|
|
746
|
+
semanticPath: config.graph.semantic_path,
|
|
747
|
+
include: config.graph.include,
|
|
748
|
+
exclude: config.graph.exclude
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
await engine.init();
|
|
752
|
+
// 生成可视化
|
|
753
|
+
const result = await engine.visualize({
|
|
754
|
+
format: options.format,
|
|
755
|
+
outputPath: options.output,
|
|
756
|
+
includeCode: false,
|
|
757
|
+
maxNodes: parseInt(options.maxNodes),
|
|
758
|
+
maxEdges: parseInt(options.maxEdges),
|
|
759
|
+
theme: options.theme,
|
|
760
|
+
layout: options.layout,
|
|
761
|
+
});
|
|
762
|
+
if (result.status === 'completed') {
|
|
763
|
+
console.log(' ✅ 图谱生成完成!\n');
|
|
764
|
+
console.log(` 格式: ${result.format}`);
|
|
765
|
+
console.log(` 节点数: ${result.nodesCount}`);
|
|
766
|
+
console.log(` 边数: ${result.edgesCount}`);
|
|
767
|
+
console.log(` 输出路径: ${result.outputPath}`);
|
|
768
|
+
console.log(` 耗时: ${result.durationMs}ms\n`);
|
|
769
|
+
if (result.format === 'html') {
|
|
770
|
+
console.log(' 在浏览器中打开 HTML 文件查看交互图谱\n');
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
console.error(' ❌ 图谱生成失败\n');
|
|
775
|
+
for (const error of result.errors) {
|
|
776
|
+
console.error(` - ${error}`);
|
|
777
|
+
}
|
|
778
|
+
console.log('');
|
|
779
|
+
}
|
|
780
|
+
engine.close();
|
|
781
|
+
});
|
|
782
|
+
export default graph;
|
|
783
|
+
//# sourceMappingURL=graph.js.map
|