autosnippet 3.2.21 → 3.3.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/dashboard/dist/assets/{icons-C1dUryS-.js → icons-BofcEZ3f.js} +1 -1
- package/dashboard/dist/assets/index-SiN1GChm.js +128 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/bin/cli.d.ts +0 -1
- package/dist/bin/cli.js +0 -133
- package/dist/lib/cli/SetupService.d.ts +46 -2
- package/dist/lib/cli/SetupService.js +2 -27
- package/dist/lib/{platform/ios/spm → core/discovery}/SpmDiscoverer.d.ts +2 -5
- package/dist/lib/{platform/ios/spm → core/discovery}/SpmDiscoverer.js +159 -44
- package/dist/lib/core/discovery/index.d.ts +1 -1
- package/dist/lib/core/discovery/index.js +2 -2
- package/dist/lib/external/mcp/handlers/guard.js +6 -3
- package/dist/lib/http/HttpServer.js +0 -6
- package/dist/lib/http/routes/commands.d.ts +1 -1
- package/dist/lib/http/routes/commands.js +1 -66
- package/dist/lib/http/routes/remote.js +0 -5
- package/dist/lib/injection/ServiceMap.d.ts +0 -9
- package/dist/lib/injection/modules/AppModule.d.ts +2 -3
- package/dist/lib/injection/modules/AppModule.js +3 -30
- package/dist/lib/injection/modules/GuardModule.js +33 -1
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +13 -1
- package/dist/lib/service/guard/GuardCheckEngine.js +44 -2
- package/dist/lib/service/module/ModuleService.js +3 -13
- package/dist/lib/service/search/SearchEngine.js +1 -1
- package/dist/lib/shared/constants.d.ts +0 -15
- package/dist/lib/shared/constants.js +0 -10
- package/dist/lib/shared/schemas/config.d.ts +4 -1
- package/dist/lib/shared/schemas/config.js +8 -1
- package/dist/scripts/release.js +2 -10
- package/package.json +4 -19
- package/dashboard/dist/assets/index-DdvZE4Yd.js +0 -128
- package/dist/lib/http/routes/snippets.d.ts +0 -6
- package/dist/lib/http/routes/snippets.js +0 -49
- package/dist/lib/platform/ClipboardManager.d.ts +0 -24
- package/dist/lib/platform/ClipboardManager.js +0 -142
- package/dist/lib/platform/NativeUi.d.ts +0 -53
- package/dist/lib/platform/NativeUi.js +0 -284
- package/dist/lib/platform/ios/index.d.ts +0 -38
- package/dist/lib/platform/ios/index.js +0 -42
- package/dist/lib/platform/ios/routes/spm.d.ts +0 -9
- package/dist/lib/platform/ios/routes/spm.js +0 -371
- package/dist/lib/platform/ios/snippet/PlaceholderConverter.d.ts +0 -21
- package/dist/lib/platform/ios/snippet/PlaceholderConverter.js +0 -48
- package/dist/lib/platform/ios/snippet/XcodeCodec.d.ts +0 -23
- package/dist/lib/platform/ios/snippet/XcodeCodec.js +0 -96
- package/dist/lib/platform/ios/spm/DependencyGraph.d.ts +0 -56
- package/dist/lib/platform/ios/spm/DependencyGraph.js +0 -195
- package/dist/lib/platform/ios/spm/PackageSwiftParser.d.ts +0 -69
- package/dist/lib/platform/ios/spm/PackageSwiftParser.js +0 -231
- package/dist/lib/platform/ios/spm/PathFinder.d.ts +0 -28
- package/dist/lib/platform/ios/spm/PathFinder.js +0 -117
- package/dist/lib/platform/ios/spm/PolicyEngine.d.ts +0 -44
- package/dist/lib/platform/ios/spm/PolicyEngine.js +0 -79
- package/dist/lib/platform/ios/spm/SpmHelper.d.ts +0 -102
- package/dist/lib/platform/ios/spm/SpmHelper.js +0 -464
- package/dist/lib/platform/ios/xcode/HeaderResolver.d.ts +0 -33
- package/dist/lib/platform/ios/xcode/HeaderResolver.js +0 -90
- package/dist/lib/platform/ios/xcode/SaveEventFilter.d.ts +0 -66
- package/dist/lib/platform/ios/xcode/SaveEventFilter.js +0 -142
- package/dist/lib/platform/ios/xcode/XcodeAutomation.d.ts +0 -71
- package/dist/lib/platform/ios/xcode/XcodeAutomation.js +0 -327
- package/dist/lib/platform/ios/xcode/XcodeImportResolver.d.ts +0 -130
- package/dist/lib/platform/ios/xcode/XcodeImportResolver.js +0 -404
- package/dist/lib/platform/ios/xcode/XcodeIntegration.d.ts +0 -89
- package/dist/lib/platform/ios/xcode/XcodeIntegration.js +0 -588
- package/dist/lib/platform/ios/xcode/XcodeWriteUtils.d.ts +0 -99
- package/dist/lib/platform/ios/xcode/XcodeWriteUtils.js +0 -190
- package/dist/lib/service/automation/ActionPipeline.d.ts +0 -34
- package/dist/lib/service/automation/ActionPipeline.js +0 -53
- package/dist/lib/service/automation/AutomationOrchestrator.d.ts +0 -86
- package/dist/lib/service/automation/AutomationOrchestrator.js +0 -57
- package/dist/lib/service/automation/ContextCollector.d.ts +0 -24
- package/dist/lib/service/automation/ContextCollector.js +0 -35
- package/dist/lib/service/automation/DirectiveDetector.d.ts +0 -51
- package/dist/lib/service/automation/DirectiveDetector.js +0 -112
- package/dist/lib/service/automation/FileWatcher.d.ts +0 -51
- package/dist/lib/service/automation/FileWatcher.js +0 -366
- package/dist/lib/service/automation/TriggerResolver.d.ts +0 -36
- package/dist/lib/service/automation/TriggerResolver.js +0 -62
- package/dist/lib/service/automation/handlers/AlinkHandler.d.ts +0 -7
- package/dist/lib/service/automation/handlers/AlinkHandler.js +0 -80
- package/dist/lib/service/automation/handlers/CreateHandler.d.ts +0 -11
- package/dist/lib/service/automation/handlers/CreateHandler.js +0 -170
- package/dist/lib/service/automation/handlers/GuardHandler.d.ts +0 -17
- package/dist/lib/service/automation/handlers/GuardHandler.js +0 -218
- package/dist/lib/service/automation/handlers/HeaderHandler.d.ts +0 -2
- package/dist/lib/service/automation/handlers/HeaderHandler.js +0 -32
- package/dist/lib/service/automation/handlers/SearchHandler.d.ts +0 -11
- package/dist/lib/service/automation/handlers/SearchHandler.js +0 -278
- package/dist/lib/service/snippet/SnippetFactory.d.ts +0 -101
- package/dist/lib/service/snippet/SnippetFactory.js +0 -145
- package/dist/lib/service/snippet/SnippetInstaller.d.ts +0 -91
- package/dist/lib/service/snippet/SnippetInstaller.js +0 -276
- package/dist/lib/service/snippet/codecs/SnippetCodec.d.ts +0 -44
- package/dist/lib/service/snippet/codecs/SnippetCodec.js +0 -35
- package/dist/lib/service/snippet/codecs/VSCodeCodec.d.ts +0 -27
- package/dist/lib/service/snippet/codecs/VSCodeCodec.js +0 -82
- package/dist/scripts/build-native-ui.d.ts +0 -3
- package/dist/scripts/build-native-ui.js +0 -62
- package/dist/scripts/init-snippets.d.ts +0 -30
- package/dist/scripts/init-snippets.js +0 -298
- package/dist/scripts/install-full.d.ts +0 -7
- package/dist/scripts/install-full.js +0 -38
- package/resources/native-ui/README.md +0 -29
- package/resources/native-ui/combined-window.swift +0 -494
- package/resources/native-ui/main.swift +0 -598
- package/scripts/postinstall-safe.mjs +0 -89
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CreateHandler — 处理 // as:c 指令
|
|
3
|
-
* 从 FileWatcher 拆分,负责候选创建逻辑
|
|
4
|
-
*/
|
|
5
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
6
|
-
import { saveEventFilter } from '#platform/ios/xcode/SaveEventFilter.js';
|
|
7
|
-
import { LanguageService } from '#shared/LanguageService.js';
|
|
8
|
-
import { REGEX } from '../DirectiveDetector.js';
|
|
9
|
-
/**
|
|
10
|
-
* 处理 // as:c 指令
|
|
11
|
-
* @param createOption 'c' | 'f' | undefined
|
|
12
|
-
*/
|
|
13
|
-
export async function handleCreate(watcher, fullPath, relativePath, createOption) {
|
|
14
|
-
const XA = await import('../../../platform/ios/xcode/XcodeAutomation.js');
|
|
15
|
-
const CM = await import('../../../platform/ClipboardManager.js');
|
|
16
|
-
// 1. 读剪贴板(仅 -c 模式)
|
|
17
|
-
let textToExtract = '';
|
|
18
|
-
if (createOption === 'c') {
|
|
19
|
-
textToExtract = CM.read().trim();
|
|
20
|
-
}
|
|
21
|
-
// 2. 自动移除触发行
|
|
22
|
-
let cutSucceeded = false;
|
|
23
|
-
try {
|
|
24
|
-
const content = readFileSync(fullPath, 'utf8');
|
|
25
|
-
const lineNumber = findCreateLineNumber(content);
|
|
26
|
-
if (XA.isXcodeRunning() && lineNumber > 0) {
|
|
27
|
-
const savedClip = CM.read();
|
|
28
|
-
cutSucceeded = XA.cutLineInXcode(lineNumber);
|
|
29
|
-
if (cutSucceeded && savedClip) {
|
|
30
|
-
await _sleep(200);
|
|
31
|
-
CM.write(savedClip);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (!cutSucceeded) {
|
|
35
|
-
const newContent = content.replace(REGEX.CREATE_REMOVE, '');
|
|
36
|
-
saveEventFilter.markWrite(fullPath, newContent);
|
|
37
|
-
writeFileSync(fullPath, newContent, 'utf8');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
catch (err) {
|
|
41
|
-
console.error('[Watcher] Failed to remove as:create mark', err.message);
|
|
42
|
-
}
|
|
43
|
-
// 3. 无 -c 选项:打开 Dashboard
|
|
44
|
-
if (createOption !== 'c') {
|
|
45
|
-
const autoScan = createOption === 'f' ? '&autoScan=1' : '';
|
|
46
|
-
watcher._openDashboard(`/?action=create&path=${encodeURIComponent(relativePath)}${autoScan}`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
// 4. -c 模式:剪贴板为空则打开 Dashboard
|
|
50
|
-
if (textToExtract.length === 0) {
|
|
51
|
-
watcher._openDashboard(`/?action=create&path=${encodeURIComponent(relativePath)}`);
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
// 5. -c 模式:静默创建候选
|
|
55
|
-
try {
|
|
56
|
-
await silentCreateCandidate(watcher, textToExtract, relativePath);
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
console.warn('[Watcher] 静默创建候选失败,回退到打开浏览器:', e.message);
|
|
60
|
-
watcher._openDashboard(`/?action=create&path=${encodeURIComponent(relativePath)}&source=clipboard`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/** 静默创建候选(从剪贴板文本解析 Recipe 并提交) */
|
|
64
|
-
async function silentCreateCandidate(watcher, text, relativePath) {
|
|
65
|
-
const { RecipeParser } = await import('../../recipe/RecipeParser.js');
|
|
66
|
-
const parser = new RecipeParser();
|
|
67
|
-
const normalize = (arr) => arr.map((r) => ({
|
|
68
|
-
title: r.title,
|
|
69
|
-
summary: r.summary || r.description || '',
|
|
70
|
-
trigger: r.trigger,
|
|
71
|
-
category: r.category || 'Utility',
|
|
72
|
-
language: r.language || 'unknown',
|
|
73
|
-
code: r.code,
|
|
74
|
-
usageGuide: r.usageGuide || '',
|
|
75
|
-
headers: r.headers || [],
|
|
76
|
-
}));
|
|
77
|
-
// 先尝试批量解析(仅对 Recipe Markdown 格式有效)
|
|
78
|
-
const allRecipes = parser.parseAll(text);
|
|
79
|
-
const validRecipes = allRecipes.filter((r) => r.title?.trim());
|
|
80
|
-
if (validRecipes.length > 0) {
|
|
81
|
-
const items = normalize(validRecipes);
|
|
82
|
-
await watcher._resolveHeadersIfNeeded(items[0], relativePath, text);
|
|
83
|
-
await watcher._appendCandidates(items, 'watch-create');
|
|
84
|
-
const msg = validRecipes.length === 1
|
|
85
|
-
? `已创建候选「${validRecipes[0].title}」,请在 Dashboard Candidates 页审核`
|
|
86
|
-
: `已创建 ${validRecipes.length} 条候选,请在 Dashboard Candidates 页审核`;
|
|
87
|
-
watcher._notify(msg);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
// 尝试单条解析
|
|
91
|
-
if (parser.isCompleteRecipe(text)) {
|
|
92
|
-
const one = parser.parse(text);
|
|
93
|
-
if (one?.title?.trim()) {
|
|
94
|
-
const item = normalize([one])[0];
|
|
95
|
-
await watcher._resolveHeadersIfNeeded(item, relativePath, text);
|
|
96
|
-
await watcher._appendCandidates([item], 'watch-create');
|
|
97
|
-
watcher._notify(`已创建候选「${one.title}」,请在 Candidates 页审核`);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// -c 模式:剪贴板内容整体作为一条候选(不拆分)
|
|
102
|
-
// 先用 AI 生成标题和摘要,code 保持剪贴板原文
|
|
103
|
-
const lang = relativePath ? LanguageService.inferLang(relativePath) || 'unknown' : 'unknown';
|
|
104
|
-
const ext = LanguageService.extForLang(lang) || '.txt';
|
|
105
|
-
const fileName = relativePath
|
|
106
|
-
? (relativePath.split('/').pop() ?? `clipboard${ext}`)
|
|
107
|
-
: `clipboard${ext}`;
|
|
108
|
-
let title = fileName.replace(/\.\w+$/, '') || 'Clipboard Snippet';
|
|
109
|
-
let summary = '';
|
|
110
|
-
let usageGuide = '';
|
|
111
|
-
let category = 'Utility';
|
|
112
|
-
let headers = [];
|
|
113
|
-
let tags = [];
|
|
114
|
-
let trigger = '';
|
|
115
|
-
// 尝试用 AI 生成摘要信息(但 code 始终保持原文)
|
|
116
|
-
try {
|
|
117
|
-
const { getServiceContainer } = await import('../../../injection/ServiceContainer.js');
|
|
118
|
-
const container = getServiceContainer();
|
|
119
|
-
const agentFactory = container.get('agentFactory');
|
|
120
|
-
const aiResult = await agentFactory.scanKnowledge({
|
|
121
|
-
label: title,
|
|
122
|
-
files: [{ name: title, content: text, language: lang }],
|
|
123
|
-
task: 'summarize',
|
|
124
|
-
});
|
|
125
|
-
if (aiResult && !aiResult.error) {
|
|
126
|
-
title = aiResult.title || title;
|
|
127
|
-
summary = aiResult.summary || '';
|
|
128
|
-
usageGuide = aiResult.usageGuide || '';
|
|
129
|
-
category = aiResult.category || category;
|
|
130
|
-
headers = aiResult.headers || [];
|
|
131
|
-
tags = aiResult.tags || [];
|
|
132
|
-
trigger = aiResult.trigger || '';
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
/* AI 不可用,使用默认值 */
|
|
137
|
-
}
|
|
138
|
-
const item = {
|
|
139
|
-
title,
|
|
140
|
-
summary,
|
|
141
|
-
description: summary,
|
|
142
|
-
trigger,
|
|
143
|
-
category,
|
|
144
|
-
language: lang,
|
|
145
|
-
code: text, // 剪贴板原文整体
|
|
146
|
-
usageGuide,
|
|
147
|
-
headers,
|
|
148
|
-
tags,
|
|
149
|
-
};
|
|
150
|
-
await watcher._resolveHeadersIfNeeded(item, relativePath, text);
|
|
151
|
-
await watcher._appendCandidates([item], 'watch-create');
|
|
152
|
-
watcher._notify(`已创建候选「${title}」,请在 Candidates 页审核`);
|
|
153
|
-
}
|
|
154
|
-
/** 查找 // as:c 的行号 (1-based) */
|
|
155
|
-
export function findCreateLineNumber(content) {
|
|
156
|
-
if (!content) {
|
|
157
|
-
return -1;
|
|
158
|
-
}
|
|
159
|
-
const lines = content.split(/\r?\n/);
|
|
160
|
-
for (let i = 0; i < lines.length; i++) {
|
|
161
|
-
const t = lines[i].trim();
|
|
162
|
-
if (t.startsWith('// as:create') || t.startsWith('// as:c')) {
|
|
163
|
-
return i + 1;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return -1;
|
|
167
|
-
}
|
|
168
|
-
function _sleep(ms) {
|
|
169
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
170
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GuardHandler — 处理 // as:a (audit/guard/lint) 指令
|
|
3
|
-
*
|
|
4
|
-
* 用法:
|
|
5
|
-
* // as:a — 检查当前文件 (scope=file)
|
|
6
|
-
* // as:a file — 同上,显式 file scope
|
|
7
|
-
* // as:a target — 检查当前文件所在目录树 (scope=target)
|
|
8
|
-
* // as:a project — 检查整个项目所有源文件 (scope=project)
|
|
9
|
-
* // as:a <keyword> — 检查当前文件 + 搜索相关规范
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* @param watcher FileWatcher 实例
|
|
13
|
-
* @param fullPath 当前文件绝对路径
|
|
14
|
-
* @param code 当前文件内容
|
|
15
|
-
* @param guardLine 触发行原文
|
|
16
|
-
*/
|
|
17
|
-
export declare function handleGuard(watcher: import('../FileWatcher.js').FileWatcher, fullPath: string, code: string, guardLine: string): Promise<void>;
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GuardHandler — 处理 // as:a (audit/guard/lint) 指令
|
|
3
|
-
*
|
|
4
|
-
* 用法:
|
|
5
|
-
* // as:a — 检查当前文件 (scope=file)
|
|
6
|
-
* // as:a file — 同上,显式 file scope
|
|
7
|
-
* // as:a target — 检查当前文件所在目录树 (scope=target)
|
|
8
|
-
* // as:a project — 检查整个项目所有源文件 (scope=project)
|
|
9
|
-
* // as:a <keyword> — 检查当前文件 + 搜索相关规范
|
|
10
|
-
*/
|
|
11
|
-
import { readFile } from 'node:fs/promises';
|
|
12
|
-
import { dirname, extname, join } from 'node:path';
|
|
13
|
-
import { LanguageService } from '#shared/LanguageService.js';
|
|
14
|
-
/** 已知的 scope 关键词 */
|
|
15
|
-
const SCOPE_KEYWORDS = new Set(['file', 'target', 'project', 'all']);
|
|
16
|
-
/** 支持审计的源文件扩展名 — 委托给 LanguageService */
|
|
17
|
-
const SOURCE_EXTS = LanguageService.sourceExts;
|
|
18
|
-
/** 递归收集目录下所有源文件路径 */
|
|
19
|
-
async function collectSourceFiles(dir) {
|
|
20
|
-
const { readdir } = await import('node:fs/promises');
|
|
21
|
-
const files = [];
|
|
22
|
-
// 跳过的目录
|
|
23
|
-
const SKIP_DIRS = new Set([
|
|
24
|
-
'node_modules',
|
|
25
|
-
'.git',
|
|
26
|
-
'build',
|
|
27
|
-
'DerivedData',
|
|
28
|
-
'Pods',
|
|
29
|
-
'.build',
|
|
30
|
-
'vendor',
|
|
31
|
-
'dist',
|
|
32
|
-
'.next',
|
|
33
|
-
'Carthage',
|
|
34
|
-
'xcuserdata',
|
|
35
|
-
'__pycache__',
|
|
36
|
-
]);
|
|
37
|
-
async function walk(currentDir) {
|
|
38
|
-
let entries;
|
|
39
|
-
try {
|
|
40
|
-
entries = await readdir(currentDir, { withFileTypes: true });
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return; // 权限不足等情况跳过
|
|
44
|
-
}
|
|
45
|
-
for (const entry of entries) {
|
|
46
|
-
if (entry.name.startsWith('.') && entry.name !== '.') {
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
const fullPath = join(currentDir, entry.name);
|
|
50
|
-
if (entry.isDirectory()) {
|
|
51
|
-
if (!SKIP_DIRS.has(entry.name)) {
|
|
52
|
-
await walk(fullPath);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
else if (entry.isFile() && SOURCE_EXTS.has(extname(entry.name).toLowerCase())) {
|
|
56
|
-
files.push(fullPath);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
await walk(dir);
|
|
61
|
-
return files;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* @param watcher FileWatcher 实例
|
|
65
|
-
* @param fullPath 当前文件绝对路径
|
|
66
|
-
* @param code 当前文件内容
|
|
67
|
-
* @param guardLine 触发行原文
|
|
68
|
-
*/
|
|
69
|
-
export async function handleGuard(watcher, fullPath, code, guardLine) {
|
|
70
|
-
const rest = guardLine.replace(/^\/\/\s*as:(?:audit|a|lint|l|guard|g)\s*/, '').trim();
|
|
71
|
-
const scopeArg = rest.toLowerCase();
|
|
72
|
-
const isScope = SCOPE_KEYWORDS.has(scopeArg);
|
|
73
|
-
// 确定 scope:无参数或 'file' → file;'target' → target;'project'/'all' → project
|
|
74
|
-
const scope = !rest || scopeArg === 'file'
|
|
75
|
-
? 'file'
|
|
76
|
-
: scopeArg === 'target'
|
|
77
|
-
? 'target'
|
|
78
|
-
: scopeArg === 'project' || scopeArg === 'all'
|
|
79
|
-
? 'project'
|
|
80
|
-
: 'file'; // 非 scope 关键词回退到 file
|
|
81
|
-
try {
|
|
82
|
-
const { detectLanguage } = await import('../../guard/GuardCheckEngine.js');
|
|
83
|
-
const { ServiceContainer } = await import('../../../injection/ServiceContainer.js');
|
|
84
|
-
const container = ServiceContainer.getInstance();
|
|
85
|
-
const engine = container.get('guardCheckEngine');
|
|
86
|
-
/* ── 多文件审计 (target / project) ── */
|
|
87
|
-
if (scope === 'project' || scope === 'target') {
|
|
88
|
-
let scanRoot;
|
|
89
|
-
if (scope === 'project') {
|
|
90
|
-
scanRoot = watcher?.projectRoot;
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
// target: 扫描当前文件所在目录树
|
|
94
|
-
scanRoot = dirname(fullPath);
|
|
95
|
-
}
|
|
96
|
-
if (!scanRoot) {
|
|
97
|
-
console.warn(' ⚠️ 无法确定扫描根目录,回退到单文件检查');
|
|
98
|
-
return _auditSingleFile(watcher, engine, fullPath, code, detectLanguage, 'file');
|
|
99
|
-
}
|
|
100
|
-
const scopeLabel = scope === 'project' ? '整个项目' : '当前目录';
|
|
101
|
-
const sourcePaths = await collectSourceFiles(scanRoot);
|
|
102
|
-
if (sourcePaths.length === 0) {
|
|
103
|
-
watcher._notify?.('未找到可审计的源文件');
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
// 读取所有文件内容
|
|
107
|
-
const fileEntries = [];
|
|
108
|
-
let readErrors = 0;
|
|
109
|
-
for (const p of sourcePaths) {
|
|
110
|
-
try {
|
|
111
|
-
const content = await readFile(p, 'utf-8');
|
|
112
|
-
fileEntries.push({ path: p, content });
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
readErrors++;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (readErrors > 0) {
|
|
119
|
-
console.warn(` ⚠️ ${readErrors} 个文件读取失败,已跳过`);
|
|
120
|
-
}
|
|
121
|
-
// 批量审计(传递 scope 以启用对应维度规则)
|
|
122
|
-
const report = engine.auditFiles(fileEntries, { scope });
|
|
123
|
-
const { summary } = report;
|
|
124
|
-
if (summary.totalViolations === 0) {
|
|
125
|
-
watcher._notify?.(`${scopeLabel}审计通过 ✅ ${fileEntries.length} 个文件,无违规`);
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
watcher._notify?.(`${scopeLabel}审计: ${summary.totalViolations} 个问题 (${summary.errors ?? 0} 错误, ${summary.warnings ?? 0} 警告)`);
|
|
129
|
-
const filesWithIssues = report.files.filter((f) => f.summary.total > 0);
|
|
130
|
-
for (const file of filesWithIssues.slice(0, 10)) {
|
|
131
|
-
const _rel = String(file.filePath).replace(`${scanRoot}/`, '');
|
|
132
|
-
const errors = file.violations.filter((v) => v.severity === 'error');
|
|
133
|
-
const warnings = file.violations.filter((v) => v.severity === 'warning');
|
|
134
|
-
for (const _v of errors.slice(0, 5)) {
|
|
135
|
-
}
|
|
136
|
-
if (errors.length > 5) {
|
|
137
|
-
}
|
|
138
|
-
for (const _v of warnings.slice(0, 3)) {
|
|
139
|
-
}
|
|
140
|
-
if (warnings.length > 3) {
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (filesWithIssues.length > 10) {
|
|
144
|
-
}
|
|
145
|
-
// 跨文件问题汇总
|
|
146
|
-
if (report.crossFileViolations?.length > 0) {
|
|
147
|
-
for (const v of report.crossFileViolations.slice(0, 10)) {
|
|
148
|
-
if (v.locations) {
|
|
149
|
-
for (const loc of v.locations.slice(0, 5)) {
|
|
150
|
-
const _relLoc = loc.filePath.replace(`${scanRoot}/`, '');
|
|
151
|
-
}
|
|
152
|
-
if (v.locations.length > 5) {
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
_auditSingleFile(watcher, engine, fullPath, code, detectLanguage, scope);
|
|
161
|
-
// 如果有非 scope 关键词,也做语义搜索
|
|
162
|
-
if (rest && !isScope) {
|
|
163
|
-
try {
|
|
164
|
-
const searchEngine = container.get('searchEngine');
|
|
165
|
-
const results = await searchEngine.search(rest, { limit: 3, mode: 'keyword' });
|
|
166
|
-
const items = Array.isArray(results) ? results : results.items || [];
|
|
167
|
-
if (items.length > 0) {
|
|
168
|
-
for (const _r of items) {
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
// 搜索失败不阻塞
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
catch (err) {
|
|
178
|
-
console.warn(` ⚠️ Guard 检查失败: ${err.message}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/** 检查单个文件并打印结果 */
|
|
182
|
-
function _auditSingleFile(watcher, engine, fullPath, code, detectLanguage, scope = 'file') {
|
|
183
|
-
const language = detectLanguage(fullPath);
|
|
184
|
-
const violations = engine.checkCode(code, language, { scope });
|
|
185
|
-
if (violations.length === 0) {
|
|
186
|
-
watcher._notify?.('审计通过 ✅ 无违规');
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
const errors = violations.filter((v) => v.severity === 'error');
|
|
190
|
-
const warnings = violations.filter((v) => v.severity === 'warning');
|
|
191
|
-
watcher._notify?.(`审计: ${violations.length} 个问题 (${errors.length} 错误, ${warnings.length} 警告)`);
|
|
192
|
-
for (const v of errors) {
|
|
193
|
-
if (v.fixSuggestion) {
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
for (const v of warnings.slice(0, 5)) {
|
|
197
|
-
if (v.fixSuggestion) {
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (warnings.length > 5) {
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
// Guard ↔ Recipe 闭环:检测修复并自动确认使用(fire-and-forget)
|
|
204
|
-
import('../../../injection/ServiceContainer.js')
|
|
205
|
-
.then(({ ServiceContainer }) => {
|
|
206
|
-
try {
|
|
207
|
-
const container = ServiceContainer.getInstance();
|
|
208
|
-
const feedbackLoop = container.get('guardFeedbackLoop');
|
|
209
|
-
feedbackLoop.processFixDetection({ violations }, fullPath);
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
/* guardFeedbackLoop not available */
|
|
213
|
-
}
|
|
214
|
-
})
|
|
215
|
-
.catch(() => {
|
|
216
|
-
/* ignored */
|
|
217
|
-
});
|
|
218
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/** HeaderHandler — 处理 // as:include / // as:import 指令 */
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { basename } from 'node:path';
|
|
4
|
-
export async function handleHeader(watcher, fullPath, headerLine, importArray, isSwift) {
|
|
5
|
-
try {
|
|
6
|
-
const HeaderResolver = await import('../../../platform/ios/xcode/HeaderResolver.js');
|
|
7
|
-
const parsed = HeaderResolver.parseImportLine(headerLine);
|
|
8
|
-
if (!parsed) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
const resolved = await HeaderResolver.resolveHeadersForText(watcher.projectRoot, basename(fullPath), readFileSync(fullPath, 'utf8'));
|
|
12
|
-
if (!resolved || !resolved.headers || resolved.headers.length === 0) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const { insertHeaders } = await import('../../../platform/ios/xcode/XcodeIntegration.js');
|
|
16
|
-
const result = await insertHeaders(watcher, fullPath, resolved.headers, {
|
|
17
|
-
isSwift,
|
|
18
|
-
moduleName: resolved.moduleName || null,
|
|
19
|
-
});
|
|
20
|
-
if (result.cancelled) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (result.inserted.length === 0 && result.skipped.length > 0) {
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
catch (err) {
|
|
27
|
-
console.warn(` ⚠️ Header 处理失败: ${err.message}`);
|
|
28
|
-
if (process.env.ASD_DEBUG === '1') {
|
|
29
|
-
console.error(err.stack);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/** SearchHandler — 处理 // as:s 指令 */
|
|
2
|
-
export declare function handleSearch(watcher: import('../FileWatcher.js').FileWatcher, fullPath: string, relativePath: string, searchLine: string): Promise<void>;
|
|
3
|
-
/** 将搜索结果标准化为 NativeUI 可展示格式 */
|
|
4
|
-
export declare function normalizeSearchResults(results: unknown): {
|
|
5
|
-
title: string;
|
|
6
|
-
code: string;
|
|
7
|
-
explanation: string;
|
|
8
|
-
headers: string[];
|
|
9
|
-
moduleName: string | null;
|
|
10
|
-
trigger: string;
|
|
11
|
-
}[];
|