autosnippet 3.0.10 → 3.0.13
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/bin/cli.js +64 -1
- package/config/default.json +9 -0
- package/dashboard/dist/assets/{index-I2ySoCmF.js → index-Bnm26ulL.js} +47 -47
- package/dashboard/dist/index.html +1 -1
- package/lib/cli/SetupService.js +92 -5
- package/lib/cli/UpgradeService.js +14 -5
- package/lib/core/discovery/GenericDiscoverer.js +4 -28
- package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +246 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +80 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +275 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +600 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +125 -342
- package/lib/external/mcp/handlers/bootstrap/refine.js +362 -0
- package/lib/external/mcp/handlers/bootstrap.js +6 -590
- package/lib/external/mcp/handlers/browse.js +119 -9
- package/lib/external/mcp/handlers/guard.js +25 -6
- package/lib/external/mcp/handlers/search.js +56 -24
- package/lib/http/routes/guardRules.js +9 -17
- package/lib/injection/ServiceContainer.js +12 -3
- package/lib/platform/ios/xcode/XcodeImportResolver.js +434 -0
- package/lib/platform/ios/xcode/XcodeIntegration.js +40 -659
- package/lib/platform/ios/xcode/XcodeWriteUtils.js +220 -0
- package/lib/service/chat/ChatAgent.js +39 -418
- package/lib/service/chat/ChatAgentPrompts.js +149 -0
- package/lib/service/chat/ChatAgentTasks.js +297 -0
- package/lib/service/chat/tools/_shared.js +61 -0
- package/lib/service/chat/tools/ai-analysis.js +284 -0
- package/lib/service/chat/tools/ast-graph.js +681 -0
- package/lib/service/chat/tools/composite.js +496 -0
- package/lib/service/chat/tools/guard.js +265 -0
- package/lib/service/chat/tools/index.js +250 -0
- package/lib/service/chat/tools/infrastructure.js +222 -0
- package/lib/service/chat/tools/knowledge-graph.js +234 -0
- package/lib/service/chat/tools/lifecycle.js +469 -0
- package/lib/service/chat/tools/project-access.js +923 -0
- package/lib/service/chat/tools/query.js +264 -0
- package/lib/service/chat/tools.js +14 -3994
- package/lib/service/cursor/AgentInstructionsGenerator.js +395 -0
- package/lib/service/cursor/CursorDeliveryPipeline.js +70 -11
- package/lib/service/cursor/FileProtection.js +116 -0
- package/lib/service/cursor/KnowledgeCompressor.js +61 -11
- package/lib/service/cursor/SkillsSyncer.js +5 -3
- package/lib/service/cursor/TopicClassifier.js +19 -3
- package/lib/service/guard/ExclusionManager.js +26 -2
- package/lib/service/guard/GuardCheckEngine.js +38 -370
- package/lib/service/guard/GuardCodeChecks.js +362 -0
- package/lib/service/guard/GuardCrossFileChecks.js +307 -0
- package/lib/service/guard/GuardPatternUtils.js +180 -0
- package/lib/service/guard/GuardService.js +80 -38
- package/lib/service/module/ModuleService.js +1 -0
- package/lib/service/search/SearchEngine.js +10 -2
- package/lib/service/wiki/WikiGenerator.js +226 -1532
- package/lib/service/wiki/WikiRenderers.js +1878 -0
- package/lib/service/wiki/WikiUtils.js +907 -0
- package/lib/shared/LanguageService.js +299 -0
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>AutoSnippet Dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Bnm26ulL.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/yaml-qRaU8Ldn.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-CEnWn7aV.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/axios-C0Zqfgkc.js">
|
package/lib/cli/SetupService.js
CHANGED
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
} from 'node:fs';
|
|
54
54
|
import { dirname, join, resolve } from 'node:path';
|
|
55
55
|
import { fileURLToPath } from 'node:url';
|
|
56
|
+
import { checkWriteSafety, safeCopyFile, safeWriteFile } from '../service/cursor/FileProtection.js';
|
|
56
57
|
|
|
57
58
|
const __filename = fileURLToPath(import.meta.url);
|
|
58
59
|
const __dirname = dirname(__filename);
|
|
@@ -451,10 +452,10 @@ export class SetupService {
|
|
|
451
452
|
this._configureVSCodeMCP(mcpServerPath);
|
|
452
453
|
this._configureCursorMCP(mcpServerPath);
|
|
453
454
|
this._copyCopilotInstructions();
|
|
455
|
+
this._generateAgentInstructionFiles();
|
|
454
456
|
this._copyCursorRules();
|
|
455
457
|
this._copySkillsTemplate();
|
|
456
|
-
|
|
457
|
-
this._mirrorCursorToIDE('.trae');
|
|
458
|
+
// NOTE: .qoder/ .trae/ 不再自动创建,用户可通过 `asd mirror` 按需生成
|
|
458
459
|
|
|
459
460
|
const extResult = this._installVSCodeExtension();
|
|
460
461
|
|
|
@@ -462,10 +463,9 @@ export class SetupService {
|
|
|
462
463
|
'vscode-mcp',
|
|
463
464
|
'cursor-mcp',
|
|
464
465
|
'copilot-instructions',
|
|
466
|
+
'agent-instructions',
|
|
465
467
|
'cursor-rules',
|
|
466
468
|
'skills-template',
|
|
467
|
-
'qoder-rules',
|
|
468
|
-
'trae-rules',
|
|
469
469
|
];
|
|
470
470
|
if (extResult) {
|
|
471
471
|
configured.push(...extResult);
|
|
@@ -706,7 +706,7 @@ export class SetupService {
|
|
|
706
706
|
writeFileSync(configPath, JSON.stringify(existing, null, 2));
|
|
707
707
|
}
|
|
708
708
|
|
|
709
|
-
/** @private .github/copilot-instructions.md */
|
|
709
|
+
/** @private .github/copilot-instructions.md (static template fallback) */
|
|
710
710
|
_copyCopilotInstructions() {
|
|
711
711
|
const src = join(REPO_ROOT, 'templates', 'copilot-instructions.md');
|
|
712
712
|
if (!existsSync(src)) {
|
|
@@ -719,10 +719,97 @@ export class SetupService {
|
|
|
719
719
|
return;
|
|
720
720
|
}
|
|
721
721
|
|
|
722
|
+
// 即使 --force,也不覆盖用户原有的非 AutoSnippet 文件
|
|
723
|
+
const { canWrite, reason } = checkWriteSafety(dest);
|
|
724
|
+
if (!canWrite) {
|
|
725
|
+
console.log(` ⏭️ copilot-instructions.md — 跳过(${reason},非 AutoSnippet 生成)`);
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
|
|
722
729
|
mkdirSync(destDir, { recursive: true });
|
|
723
730
|
copyFileSync(src, dest);
|
|
724
731
|
}
|
|
725
732
|
|
|
733
|
+
/**
|
|
734
|
+
* @private 生成 AGENTS.md + CLAUDE.md 静态骨架
|
|
735
|
+
* setup 阶段没有知识库数据,所以只生成指向 MCP 的基础版本。
|
|
736
|
+
* bootstrap / delivery pipeline 完成后会用动态版本覆盖。
|
|
737
|
+
*/
|
|
738
|
+
_generateAgentInstructionFiles() {
|
|
739
|
+
const projectName = this.projectRoot.split('/').pop();
|
|
740
|
+
|
|
741
|
+
// AGENTS.md
|
|
742
|
+
const agentsPath = join(this.projectRoot, 'AGENTS.md');
|
|
743
|
+
if (!existsSync(agentsPath) || this.force) {
|
|
744
|
+
const { canWrite } = checkWriteSafety(agentsPath);
|
|
745
|
+
if (canWrite) {
|
|
746
|
+
const agentsContent = [
|
|
747
|
+
`# ${projectName} — Agent Instructions`,
|
|
748
|
+
'',
|
|
749
|
+
'> Auto-generated by AutoSnippet. Will be enriched after `asd bootstrap`.',
|
|
750
|
+
'',
|
|
751
|
+
'## Project Knowledge Base',
|
|
752
|
+
'',
|
|
753
|
+
'This project uses **AutoSnippet** for knowledge management.',
|
|
754
|
+
'Run `asd bootstrap` to populate the knowledge base, then this file will be',
|
|
755
|
+
'regenerated with coding standards, patterns, and tool references.',
|
|
756
|
+
'',
|
|
757
|
+
'## MCP Tools',
|
|
758
|
+
'',
|
|
759
|
+
'Use these MCP tools to access the full knowledge base:',
|
|
760
|
+
'- `autosnippet_search` — Search knowledge (mode: auto/context/keyword/semantic)',
|
|
761
|
+
'- `autosnippet_knowledge` — Browse/get recipes (operation: list/get/insights)',
|
|
762
|
+
'- `autosnippet_submit_knowledge` — Submit candidate (strict validation)',
|
|
763
|
+
'- `autosnippet_guard` — Code compliance check',
|
|
764
|
+
'- `autosnippet_health` — Service health & KB stats',
|
|
765
|
+
'',
|
|
766
|
+
'## Mandatory Constraints',
|
|
767
|
+
'',
|
|
768
|
+
'1. **Do NOT modify** knowledge base files directly (`AutoSnippet/`, `.autosnippet/`).',
|
|
769
|
+
'2. Create or update knowledge **only** through MCP tools.',
|
|
770
|
+
'3. **Prefer Recipes** as project standards; source code is supplementary.',
|
|
771
|
+
'',
|
|
772
|
+
].join('\n');
|
|
773
|
+
writeFileSync(agentsPath, agentsContent);
|
|
774
|
+
} else {
|
|
775
|
+
console.log(' ⏭️ AGENTS.md — 跳过(用户文件,非 AutoSnippet 生成)');
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// CLAUDE.md
|
|
780
|
+
const claudePath = join(this.projectRoot, 'CLAUDE.md');
|
|
781
|
+
if (!existsSync(claudePath) || this.force) {
|
|
782
|
+
const { canWrite } = checkWriteSafety(claudePath);
|
|
783
|
+
if (canWrite) {
|
|
784
|
+
const claudeContent = [
|
|
785
|
+
`# ${projectName} — Claude Code Instructions`,
|
|
786
|
+
'',
|
|
787
|
+
'> Auto-generated by AutoSnippet. Will be enriched after `asd bootstrap`.',
|
|
788
|
+
'',
|
|
789
|
+
'## MCP Integration',
|
|
790
|
+
'',
|
|
791
|
+
'This project has an AutoSnippet MCP server configured.',
|
|
792
|
+
'Use the following tools to access project knowledge:',
|
|
793
|
+
'- `autosnippet_search` — Search knowledge (mode: auto/context/keyword/semantic)',
|
|
794
|
+
'- `autosnippet_knowledge` — Browse/get recipes (operation: list/get/insights)',
|
|
795
|
+
'- `autosnippet_submit_knowledge` — Submit candidate (strict validation)',
|
|
796
|
+
'- `autosnippet_guard` — Code compliance check',
|
|
797
|
+
'- `autosnippet_health` — Service health & KB stats',
|
|
798
|
+
'',
|
|
799
|
+
'## Mandatory Constraints',
|
|
800
|
+
'',
|
|
801
|
+
'1. **Do NOT modify** knowledge base files directly (`AutoSnippet/`, `.autosnippet/`).',
|
|
802
|
+
'2. Create or update knowledge **only** through MCP tools.',
|
|
803
|
+
'3. **Prefer Recipes** as project standards; source code is supplementary.',
|
|
804
|
+
'',
|
|
805
|
+
].join('\n');
|
|
806
|
+
writeFileSync(claudePath, claudeContent);
|
|
807
|
+
} else {
|
|
808
|
+
console.log(' ⏭️ CLAUDE.md — 跳过(用户文件,非 AutoSnippet 生成)');
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
726
813
|
/** @private .cursor/rules/autosnippet-conventions.mdc */
|
|
727
814
|
_copyCursorRules() {
|
|
728
815
|
const src = join(REPO_ROOT, 'templates', 'cursor-rules', 'autosnippet-conventions.mdc');
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* ① MCP 配置(.cursor/mcp.json + .vscode/mcp.json)
|
|
6
6
|
* ② Cursor Skills(.cursor/skills/)
|
|
7
7
|
* ③ Cursor Rules(.cursor/rules/autosnippet-conventions.mdc + autosnippet-skills.mdc)
|
|
8
|
-
* ④
|
|
8
|
+
* ④ Agent Instructions(AGENTS.md + CLAUDE.md + .github/copilot-instructions.md — 通过 Channel F 动态生成)
|
|
9
9
|
* ⑤ Constitution(AutoSnippet/constitution.yaml)
|
|
10
10
|
* ⑥ .gitignore(升级规则 + 清理旧版本残留)
|
|
11
11
|
* ⑦ Skills 路径迁移(.autosnippet/skills/ → AutoSnippet/skills/)
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from 'node:fs';
|
|
25
25
|
import { dirname, join, resolve } from 'node:path';
|
|
26
26
|
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import { safeCopyFile } from '../service/cursor/FileProtection.js';
|
|
27
28
|
|
|
28
29
|
const __filename = fileURLToPath(import.meta.url);
|
|
29
30
|
const __dirname = dirname(__filename);
|
|
@@ -47,8 +48,7 @@ export class UpgradeService {
|
|
|
47
48
|
}
|
|
48
49
|
if (!skillsOnly && !mcpOnly) {
|
|
49
50
|
results.push(this._upgradeCursorRules());
|
|
50
|
-
|
|
51
|
-
results.push(this._upgradeMirrorIDE('.trae'));
|
|
51
|
+
// NOTE: .qoder/ .trae/ 不再自动镜像,用户可通过 `asd mirror` 按需同步
|
|
52
52
|
results.push(this._upgradeSkillsTemplate());
|
|
53
53
|
results.push(this._upgradeCopilotInstructions());
|
|
54
54
|
results.push(this._upgradeConstitution());
|
|
@@ -169,6 +169,7 @@ export class UpgradeService {
|
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
171
|
* 触发 Cursor Delivery Pipeline 动态生成
|
|
172
|
+
* 包含 Channel A-D + Channel F (AGENTS.md / CLAUDE.md / copilot-instructions)
|
|
172
173
|
* 非阻塞 — 失败不影响 upgrade 流程
|
|
173
174
|
*/
|
|
174
175
|
_triggerCursorDelivery() {
|
|
@@ -247,8 +248,13 @@ export class UpgradeService {
|
|
|
247
248
|
}
|
|
248
249
|
}
|
|
249
250
|
|
|
250
|
-
/* ═══ Copilot Instructions
|
|
251
|
+
/* ═══ Copilot Instructions (fallback static copy) ══════════════════ */
|
|
251
252
|
|
|
253
|
+
/**
|
|
254
|
+
* 静态模板回退 — 当 _triggerCursorDelivery() 无法运行时
|
|
255
|
+
* (无 DB 环境),至少保证有一份基础模板。
|
|
256
|
+
* Channel F 动态生成会覆盖此文件。
|
|
257
|
+
*/
|
|
252
258
|
_upgradeCopilotInstructions() {
|
|
253
259
|
const src = join(REPO_ROOT, 'templates', 'copilot-instructions.md');
|
|
254
260
|
if (!existsSync(src)) {
|
|
@@ -258,7 +264,10 @@ export class UpgradeService {
|
|
|
258
264
|
const destDir = join(this.projectRoot, '.github');
|
|
259
265
|
const dest = join(destDir, 'copilot-instructions.md');
|
|
260
266
|
mkdirSync(destDir, { recursive: true });
|
|
261
|
-
|
|
267
|
+
const { written } = safeCopyFile(src, dest);
|
|
268
|
+
if (!written) {
|
|
269
|
+
console.log(' ⏭️ copilot-instructions.md — 跳过(用户文件,非 AutoSnippet 生成)');
|
|
270
|
+
}
|
|
262
271
|
}
|
|
263
272
|
|
|
264
273
|
/* ═══ Constitution ══════════════════════════════════ */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { existsSync, readdirSync } from 'node:fs';
|
|
11
11
|
import { basename, extname, join, relative } from 'node:path';
|
|
12
|
-
import {
|
|
12
|
+
import { LanguageService } from '../../shared/LanguageService.js';
|
|
13
13
|
import { ProjectDiscoverer } from './ProjectDiscoverer.js';
|
|
14
14
|
|
|
15
15
|
const EXCLUDE_DIRS = new Set([
|
|
@@ -33,31 +33,7 @@ const EXCLUDE_DIRS = new Set([
|
|
|
33
33
|
'.cache',
|
|
34
34
|
]);
|
|
35
35
|
|
|
36
|
-
const SOURCE_EXTENSIONS =
|
|
37
|
-
'.ts',
|
|
38
|
-
'.tsx',
|
|
39
|
-
'.js',
|
|
40
|
-
'.jsx',
|
|
41
|
-
'.mjs',
|
|
42
|
-
'.cjs',
|
|
43
|
-
'.py',
|
|
44
|
-
'.java',
|
|
45
|
-
'.kt',
|
|
46
|
-
'.kts',
|
|
47
|
-
'.swift',
|
|
48
|
-
'.m',
|
|
49
|
-
'.h',
|
|
50
|
-
'.mm',
|
|
51
|
-
'.go',
|
|
52
|
-
'.dart',
|
|
53
|
-
'.rs',
|
|
54
|
-
'.rb',
|
|
55
|
-
'.c',
|
|
56
|
-
'.cpp',
|
|
57
|
-
'.cs',
|
|
58
|
-
'.vue',
|
|
59
|
-
'.svelte',
|
|
60
|
-
]);
|
|
36
|
+
const SOURCE_EXTENSIONS = LanguageService.sourceExts;
|
|
61
37
|
|
|
62
38
|
export class GenericDiscoverer extends ProjectDiscoverer {
|
|
63
39
|
#projectRoot = null;
|
|
@@ -178,7 +154,7 @@ export class GenericDiscoverer extends ProjectDiscoverer {
|
|
|
178
154
|
} else if (entry.isFile()) {
|
|
179
155
|
const ext = extname(entry.name);
|
|
180
156
|
if (SOURCE_EXTENSIONS.has(ext)) {
|
|
181
|
-
const lang = inferLang(entry.name) || 'unknown';
|
|
157
|
+
const lang = LanguageService.inferLang(entry.name) || 'unknown';
|
|
182
158
|
stats[lang] = (stats[lang] || 0) + 1;
|
|
183
159
|
}
|
|
184
160
|
}
|
|
@@ -208,7 +184,7 @@ export class GenericDiscoverer extends ProjectDiscoverer {
|
|
|
208
184
|
} else if (entry.isFile()) {
|
|
209
185
|
const ext = extname(entry.name);
|
|
210
186
|
if (SOURCE_EXTENSIONS.has(ext)) {
|
|
211
|
-
const lang = inferLang(entry.name) || 'unknown';
|
|
187
|
+
const lang = LanguageService.inferLang(entry.name) || 'unknown';
|
|
212
188
|
files.push({
|
|
213
189
|
name: entry.name,
|
|
214
190
|
path: fullPath,
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap 基础维度定义 + 维度条件化过滤
|
|
3
|
+
*
|
|
4
|
+
* 从 bootstrap.js 提取,包含 9+ 维度的完整定义(通用维度 + 语言条件维度)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ═══════════════════════════════════════════════════════════
|
|
8
|
+
// 基础维度定义
|
|
9
|
+
// ═══════════════════════════════════════════════════════════
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 9+ 维度定义(Phase 4 响应 + Phase 5 候选创建共用)
|
|
13
|
+
* skillWorthy 维度会在 Phase 5.5 自动生成 Project Skill(宏观叙事性知识)
|
|
14
|
+
* 注意:anti-pattern 已移除 — 代码问题由 Guard 独立处理,bootstrap 不做错误检测
|
|
15
|
+
*
|
|
16
|
+
* 执行顺序优化(v5.1):
|
|
17
|
+
* ⑧ ⑨ 提前到 ⑥ 前面执行 → deep-scan / category-scan 的中间结果
|
|
18
|
+
* 通过 PipelineContext 缓存,供 project-profile 复用,避免重复扫描
|
|
19
|
+
*/
|
|
20
|
+
export const baseDimensions = [
|
|
21
|
+
// ── 通用维度(所有语言共享)──────────────────────────────────
|
|
22
|
+
|
|
23
|
+
// ① 代码规范(Dual: Skill + Candidate)
|
|
24
|
+
{
|
|
25
|
+
id: 'code-standard',
|
|
26
|
+
label: '代码规范',
|
|
27
|
+
guide:
|
|
28
|
+
'命名约定(类名前缀/方法签名风格/API 命名)、注释风格(语言/格式/MARK 分段)、文件组织规范',
|
|
29
|
+
knowledgeTypes: ['code-standard', 'code-style'],
|
|
30
|
+
skillWorthy: true,
|
|
31
|
+
dualOutput: true,
|
|
32
|
+
skillMeta: {
|
|
33
|
+
name: 'project-code-standard',
|
|
34
|
+
description:
|
|
35
|
+
'Project coding standards and naming conventions (auto-generated by bootstrap)',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
// ② 代码模式(Candidate)
|
|
39
|
+
{
|
|
40
|
+
id: 'code-pattern',
|
|
41
|
+
label: '设计模式与代码惯例',
|
|
42
|
+
guide: '单例/委托/Category·Extension/工厂/Builder/观察者/Coordinator 模式、继承关系',
|
|
43
|
+
knowledgeTypes: ['code-pattern', 'code-relation', 'inheritance'],
|
|
44
|
+
},
|
|
45
|
+
// ③ 架构模式(Dual: Skill + Candidate)
|
|
46
|
+
{
|
|
47
|
+
id: 'architecture',
|
|
48
|
+
label: '架构模式',
|
|
49
|
+
guide: '分层架构、模块职责与边界、依赖图、导入约束规则',
|
|
50
|
+
knowledgeTypes: ['architecture', 'module-dependency', 'boundary-constraint'],
|
|
51
|
+
skillWorthy: true,
|
|
52
|
+
dualOutput: true,
|
|
53
|
+
skillMeta: {
|
|
54
|
+
name: 'project-architecture',
|
|
55
|
+
description:
|
|
56
|
+
'Project architecture layers, module boundaries and dependency graph (auto-generated by bootstrap)',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
// ④ 最佳实践(Candidate)
|
|
60
|
+
{
|
|
61
|
+
id: 'best-practice',
|
|
62
|
+
label: '最佳实践',
|
|
63
|
+
guide: '错误处理、并发安全、内存管理、日志规范、测试模式',
|
|
64
|
+
knowledgeTypes: ['best-practice'],
|
|
65
|
+
},
|
|
66
|
+
// ⑤ 事件与数据流(Candidate)
|
|
67
|
+
{
|
|
68
|
+
id: 'event-and-data-flow',
|
|
69
|
+
label: '事件与数据流',
|
|
70
|
+
guide:
|
|
71
|
+
'事件传播(Delegate/Notification/Block·Closure/Target-Action)、数据状态管理(KVO/属性观察/响应式/持久化)',
|
|
72
|
+
knowledgeTypes: ['call-chain', 'data-flow'],
|
|
73
|
+
},
|
|
74
|
+
// ⑥ 项目特征(Dual: Skill + Candidate)
|
|
75
|
+
{
|
|
76
|
+
id: 'project-profile',
|
|
77
|
+
label: '项目特征',
|
|
78
|
+
guide:
|
|
79
|
+
'技术栈、目录结构、三方依赖枚举与用途、Extension/Category 分类聚合、自定义基类层级与全局定义(宏/typealias/PCH)、系统事件 hook 与生命周期入口、基础设施服务注册表、Runtime 与语言互操作',
|
|
80
|
+
knowledgeTypes: ['architecture'],
|
|
81
|
+
skillWorthy: true,
|
|
82
|
+
dualOutput: true,
|
|
83
|
+
skillMeta: {
|
|
84
|
+
name: 'project-profile',
|
|
85
|
+
description:
|
|
86
|
+
'Project tech stack, module structure, third-party dependencies, base extensions/classes, event hooks, infrastructure services, and runtime/interop features (auto-generated by bootstrap)',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
// ⑦ Agent 开发注意事项(Skill)
|
|
90
|
+
{
|
|
91
|
+
id: 'agent-guidelines',
|
|
92
|
+
label: 'Agent开发注意事项',
|
|
93
|
+
guide:
|
|
94
|
+
'三大核心原则(严谨性/深度特征挖掘/完整性)、命名强制、线程安全、内存约束、已废弃 API 标记、架构约束注释、TODO/FIXME',
|
|
95
|
+
knowledgeTypes: ['boundary-constraint', 'code-standard'],
|
|
96
|
+
skillWorthy: true,
|
|
97
|
+
skillMeta: {
|
|
98
|
+
name: 'project-agent-guidelines',
|
|
99
|
+
description:
|
|
100
|
+
'Mandatory coding rules, deprecated APIs and agent constraints for this project (auto-generated by bootstrap)',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// ── 语言条件维度(按 conditions 过滤)──────────────────────
|
|
105
|
+
|
|
106
|
+
// ⑧ ObjC/Swift 深度扫描
|
|
107
|
+
{
|
|
108
|
+
id: 'objc-deep-scan',
|
|
109
|
+
label: '深度扫描(常量/Hook)',
|
|
110
|
+
guide:
|
|
111
|
+
'全量扫描 #define 值宏/函数宏、extern/static 常量、Method Swizzling hook 对(Agent 必须使用项目常量,修改被 hook 方法前必须查阅 hook 清单)',
|
|
112
|
+
knowledgeTypes: ['code-standard', 'code-pattern'],
|
|
113
|
+
conditions: { languages: ['objectivec', 'swift'] },
|
|
114
|
+
skillWorthy: true,
|
|
115
|
+
dualOutput: true,
|
|
116
|
+
skillMeta: {
|
|
117
|
+
name: 'project-objc-deep-scan',
|
|
118
|
+
description:
|
|
119
|
+
'Project #define macros, static constants, and Method Swizzling hooks (auto-generated by bootstrap)',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
// ⑨ Foundation/UIKit Category/Extension 专项扫描
|
|
123
|
+
{
|
|
124
|
+
id: 'category-scan',
|
|
125
|
+
label: '基础类分类方法扫描',
|
|
126
|
+
guide:
|
|
127
|
+
'Foundation/UIKit Category/Extension 逐方法清单(含完整实现代码与项目使用频次),仅扫描基础类分类、不含业务代码(Agent 遇到同等功能必须使用项目已有分类方法,禁止重复实现)',
|
|
128
|
+
knowledgeTypes: ['code-standard', 'code-pattern'],
|
|
129
|
+
conditions: { languages: ['objectivec', 'swift'] },
|
|
130
|
+
skillWorthy: true,
|
|
131
|
+
dualOutput: true,
|
|
132
|
+
skillMeta: {
|
|
133
|
+
name: 'project-category-scan',
|
|
134
|
+
description:
|
|
135
|
+
'Foundation/UIKit Category and Extension methods with implementations and usage patterns — base classes only, no business code (auto-generated by bootstrap)',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
// ⑩ TS/JS 模块导出分析
|
|
140
|
+
{
|
|
141
|
+
id: 'module-export-scan',
|
|
142
|
+
label: '模块导出分析',
|
|
143
|
+
guide: 'barrel export 结构、re-export 链路、public API surface、tree-shaking 合规性',
|
|
144
|
+
knowledgeTypes: ['code-standard', 'architecture'],
|
|
145
|
+
conditions: { languages: ['typescript', 'javascript'] },
|
|
146
|
+
skillWorthy: true,
|
|
147
|
+
dualOutput: true,
|
|
148
|
+
skillMeta: {
|
|
149
|
+
name: 'project-module-exports',
|
|
150
|
+
description: 'Module export structure and public API surface (auto-generated by bootstrap)',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
// ⑪ TS/JS 框架约定扫描
|
|
154
|
+
{
|
|
155
|
+
id: 'framework-convention-scan',
|
|
156
|
+
label: '框架约定扫描',
|
|
157
|
+
guide: '组件目录结构、状态管理约定、路由约定、样式约定、数据获取模式',
|
|
158
|
+
knowledgeTypes: ['code-standard', 'architecture'],
|
|
159
|
+
conditions: {
|
|
160
|
+
languages: ['typescript', 'javascript'],
|
|
161
|
+
frameworks: ['react', 'vue', 'angular', 'nextjs', 'nuxt'],
|
|
162
|
+
},
|
|
163
|
+
skillWorthy: true,
|
|
164
|
+
dualOutput: true,
|
|
165
|
+
skillMeta: {
|
|
166
|
+
name: 'project-framework-conventions',
|
|
167
|
+
description: 'Framework-specific conventions and patterns (auto-generated by bootstrap)',
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// ⑫ Python 包结构分析
|
|
172
|
+
{
|
|
173
|
+
id: 'python-package-scan',
|
|
174
|
+
label: 'Python 包结构分析',
|
|
175
|
+
guide:
|
|
176
|
+
'__init__.py 导出策略、相对/绝对导入风格、type hints 覆盖率、decorator 使用模式、__all__ 定义',
|
|
177
|
+
knowledgeTypes: ['code-standard', 'architecture'],
|
|
178
|
+
conditions: { languages: ['python'] },
|
|
179
|
+
skillWorthy: true,
|
|
180
|
+
dualOutput: true,
|
|
181
|
+
skillMeta: {
|
|
182
|
+
name: 'project-python-structure',
|
|
183
|
+
description:
|
|
184
|
+
'Python package structure, import patterns and type hint coverage (auto-generated by bootstrap)',
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
// ⑬ Java/Kotlin 注解扫描
|
|
189
|
+
{
|
|
190
|
+
id: 'jvm-annotation-scan',
|
|
191
|
+
label: '注解/Annotation 扫描',
|
|
192
|
+
guide:
|
|
193
|
+
'DI 注解(@Inject/@Autowired/@Component)、ORM 注解(@Entity/@Table)、API 注解(@RestController/@RequestMapping)、自定义注解、元编程模式',
|
|
194
|
+
knowledgeTypes: ['code-pattern', 'architecture'],
|
|
195
|
+
conditions: { languages: ['java', 'kotlin'] },
|
|
196
|
+
skillWorthy: true,
|
|
197
|
+
dualOutput: true,
|
|
198
|
+
skillMeta: {
|
|
199
|
+
name: 'project-jvm-annotations',
|
|
200
|
+
description:
|
|
201
|
+
'Annotation/DI usage patterns and meta-programming (auto-generated by bootstrap)',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
// ⑭ Go 模块结构分析
|
|
206
|
+
{
|
|
207
|
+
id: 'go-module-scan',
|
|
208
|
+
label: 'Go 模块结构分析',
|
|
209
|
+
guide:
|
|
210
|
+
'go.mod 依赖图、internal 包隔离边界、cmd/ 入口点枚举、build tags/constraints、interface 分布与实现关系、init() 函数清单',
|
|
211
|
+
knowledgeTypes: ['architecture', 'code-pattern'],
|
|
212
|
+
conditions: { languages: ['go'] },
|
|
213
|
+
skillWorthy: true,
|
|
214
|
+
dualOutput: true,
|
|
215
|
+
skillMeta: {
|
|
216
|
+
name: 'project-go-module-structure',
|
|
217
|
+
description:
|
|
218
|
+
'Go module structure, internal packages, build tags and interface distribution (auto-generated by bootstrap)',
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
// ═══════════════════════════════════════════════════════════
|
|
224
|
+
// 维度条件化过滤
|
|
225
|
+
// ═══════════════════════════════════════════════════════════
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 根据项目主语言和检测到的框架过滤条件维度
|
|
229
|
+
* @param {Array} allDimensions 所有维度定义(含 conditions 字段)
|
|
230
|
+
* @param {string} primaryLang 主语言
|
|
231
|
+
* @param {string[]} detectedFrameworks 检测到的框架
|
|
232
|
+
* @returns {Array} 适用的维度列表
|
|
233
|
+
*/
|
|
234
|
+
export function resolveActiveDimensions(allDimensions, primaryLang, detectedFrameworks = []) {
|
|
235
|
+
return allDimensions.filter((dim) => {
|
|
236
|
+
if (!dim.conditions) {
|
|
237
|
+
return true; // 无条件 → 通用维度
|
|
238
|
+
}
|
|
239
|
+
const langMatch = !dim.conditions.languages || dim.conditions.languages.includes(primaryLang);
|
|
240
|
+
const fwMatch =
|
|
241
|
+
!dim.conditions.frameworks ||
|
|
242
|
+
dim.conditions.frameworks.some((f) => detectedFrameworks.includes(f));
|
|
243
|
+
// languages 必须匹配;frameworks 为可选增强(有 frameworks 条件时必须至少命中一个)
|
|
244
|
+
return langMatch && (dim.conditions.frameworks ? fwMatch : true);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* checkpoint.js — Bootstrap 断点续传 (Checkpoint) 存储/恢复
|
|
3
|
+
*
|
|
4
|
+
* 在维度级粒度保存/加载/清理执行进度,支持意外中断后恢复。
|
|
5
|
+
*
|
|
6
|
+
* @module pipeline/checkpoint
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'node:fs/promises';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import Logger from '../../../../../infrastructure/logging/Logger.js';
|
|
12
|
+
|
|
13
|
+
const logger = Logger.getInstance();
|
|
14
|
+
|
|
15
|
+
const CHECKPOINT_TTL_MS = 3600_000; // 1小时内有效
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 保存维度级 checkpoint
|
|
19
|
+
* @param {string} projectRoot
|
|
20
|
+
* @param {string} sessionId
|
|
21
|
+
* @param {string} dimId
|
|
22
|
+
* @param {object} result — 维度执行结果
|
|
23
|
+
* @param {object} [digest] — DimensionDigest
|
|
24
|
+
*/
|
|
25
|
+
export async function saveDimensionCheckpoint(projectRoot, sessionId, dimId, result, digest = null) {
|
|
26
|
+
try {
|
|
27
|
+
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
28
|
+
await fs.mkdir(checkpointDir, { recursive: true });
|
|
29
|
+
await fs.writeFile(
|
|
30
|
+
path.join(checkpointDir, `${dimId}.json`),
|
|
31
|
+
JSON.stringify({ dimId, sessionId, ...result, digest, completedAt: Date.now() })
|
|
32
|
+
);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger.warn(`[Bootstrap-v3] checkpoint save failed for "${dimId}": ${err.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 加载有效的 checkpoints
|
|
40
|
+
* @param {string} projectRoot
|
|
41
|
+
* @returns {Promise<Map<string, object>>} dimId → checkpoint data
|
|
42
|
+
*/
|
|
43
|
+
export async function loadCheckpoints(projectRoot) {
|
|
44
|
+
const checkpoints = new Map();
|
|
45
|
+
try {
|
|
46
|
+
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
47
|
+
const files = await fs.readdir(checkpointDir).catch(() => []);
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
if (!file.endsWith('.json')) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const content = await fs.readFile(path.join(checkpointDir, file), 'utf-8');
|
|
55
|
+
const data = JSON.parse(content);
|
|
56
|
+
if (data.completedAt && now - data.completedAt < CHECKPOINT_TTL_MS) {
|
|
57
|
+
checkpoints.set(data.dimId, data);
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
/* skip corrupt checkpoint */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
/* checkpoint dir doesn't exist */
|
|
65
|
+
}
|
|
66
|
+
return checkpoints;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 清理 checkpoint 目录
|
|
71
|
+
* @param {string} projectRoot
|
|
72
|
+
*/
|
|
73
|
+
export async function clearCheckpoints(projectRoot) {
|
|
74
|
+
try {
|
|
75
|
+
const checkpointDir = path.join(projectRoot, '.autosnippet', 'bootstrap-checkpoint');
|
|
76
|
+
await fs.rm(checkpointDir, { recursive: true, force: true });
|
|
77
|
+
} catch {
|
|
78
|
+
/* ignore */
|
|
79
|
+
}
|
|
80
|
+
}
|