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
|
@@ -414,15 +414,18 @@ export async function scanProject(ctx, args) {
|
|
|
414
414
|
const includeContent = args.includeContent || false;
|
|
415
415
|
const contentMaxLines = args.contentMaxLines || 100;
|
|
416
416
|
const projectRoot = resolveProjectRoot(ctx.container);
|
|
417
|
-
//
|
|
417
|
+
// 使用 ModuleService(多语言统一入口)
|
|
418
418
|
let service;
|
|
419
419
|
try {
|
|
420
420
|
const { ModuleService } = await import('#service/module/ModuleService.js');
|
|
421
421
|
service = new ModuleService(projectRoot);
|
|
422
422
|
}
|
|
423
423
|
catch {
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
return envelope({
|
|
425
|
+
success: false,
|
|
426
|
+
data: { targets: [], files: [], guardAudit: null, message: 'ModuleService not available' },
|
|
427
|
+
meta: { tool: 'autosnippet_bootstrap' },
|
|
428
|
+
});
|
|
426
429
|
}
|
|
427
430
|
await service.load();
|
|
428
431
|
const allTargets = await service.listTargets();
|
|
@@ -15,7 +15,6 @@ import { initErrorTracker } from '../infrastructure/monitoring/ErrorTracker.js';
|
|
|
15
15
|
import { initPerformanceMonitor } from '../infrastructure/monitoring/PerformanceMonitor.js';
|
|
16
16
|
import { initRealtimeService } from '../infrastructure/realtime/RealtimeService.js';
|
|
17
17
|
import { getServiceContainer } from '../injection/ServiceContainer.js';
|
|
18
|
-
import spmRouter from '../platform/ios/routes/spm.js';
|
|
19
18
|
import apiSpec from './api-spec.js';
|
|
20
19
|
import { errorHandler } from './middleware/errorHandler.js';
|
|
21
20
|
import { gatewayMiddleware } from './middleware/gatewayMiddleware.js';
|
|
@@ -36,7 +35,6 @@ import recipesRouter from './routes/recipes.js';
|
|
|
36
35
|
import remoteRouter from './routes/remote.js';
|
|
37
36
|
import searchRouter from './routes/search.js';
|
|
38
37
|
import skillsRouter from './routes/skills.js';
|
|
39
|
-
import snippetRouter from './routes/snippets.js';
|
|
40
38
|
import taskRouter from './routes/task.js';
|
|
41
39
|
import violationsRouter from './routes/violations.js';
|
|
42
40
|
import wikiRouter from './routes/wiki.js';
|
|
@@ -231,8 +229,6 @@ export class HttpServer {
|
|
|
231
229
|
this.app.use(`${apiPrefix}/task`, taskRouter);
|
|
232
230
|
// 搜索路由
|
|
233
231
|
this.app.use(`${apiPrefix}/search`, searchRouter);
|
|
234
|
-
// Snippet 路由
|
|
235
|
-
this.app.use(`${apiPrefix}/snippets`, snippetRouter);
|
|
236
232
|
// AI 路由
|
|
237
233
|
this.app.use(`${apiPrefix}/ai`, aiRouter);
|
|
238
234
|
// 提取路由
|
|
@@ -243,8 +239,6 @@ export class HttpServer {
|
|
|
243
239
|
this.app.use(`${apiPrefix}/skills`, skillsRouter);
|
|
244
240
|
// Candidates 路由(AI 补齐/润色)
|
|
245
241
|
this.app.use(`${apiPrefix}/candidates`, candidatesRouter);
|
|
246
|
-
// SPM 路由(向后兼容保留)
|
|
247
|
-
this.app.use(`${apiPrefix}/spm`, spmRouter);
|
|
248
242
|
// Modules 路由(v3.2 统一多语言模块扫描)
|
|
249
243
|
this.app.use(`${apiPrefix}/modules`, modulesRouter);
|
|
250
244
|
// 违规记录路由
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Commands API 路由
|
|
3
|
-
* 执行
|
|
3
|
+
* 执行 Module Map 刷新、Embed (重建索引) 等命令
|
|
4
4
|
*/
|
|
5
5
|
import express from 'express';
|
|
6
6
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
@@ -9,56 +9,6 @@ import { FileReadQuery, FileSaveBody } from '../../shared/schemas/http-requests.
|
|
|
9
9
|
import { validate, validateQuery } from '../middleware/validate.js';
|
|
10
10
|
const router = express.Router();
|
|
11
11
|
const logger = Logger.getInstance();
|
|
12
|
-
/**
|
|
13
|
-
* POST /api/v1/commands/install
|
|
14
|
-
* 从 Recipe 生成并同步 Snippet 到 IDE
|
|
15
|
-
* Body: { target?: 'xcode' | 'vscode' | 'all' }
|
|
16
|
-
*/
|
|
17
|
-
router.post('/install', async (req, res) => {
|
|
18
|
-
const container = getServiceContainer();
|
|
19
|
-
const knowledgeRepository = container.get('knowledgeRepository');
|
|
20
|
-
const target = req.body?.target || 'all';
|
|
21
|
-
// 获取所有活跃 Recipe(V3: lifecycle='active' 即 Recipe)
|
|
22
|
-
const result = await knowledgeRepository.findWithPagination({ lifecycle: 'active' }, { page: 1, pageSize: 9999 });
|
|
23
|
-
const recipes = (result?.data ??
|
|
24
|
-
result?.items ??
|
|
25
|
-
[])
|
|
26
|
-
.map((r) => ({
|
|
27
|
-
id: r.id,
|
|
28
|
-
title: r.title,
|
|
29
|
-
trigger: r.trigger,
|
|
30
|
-
code: r.content?.pattern || '',
|
|
31
|
-
description: r.description || r.summaryCn || '',
|
|
32
|
-
language: r.language || 'unknown',
|
|
33
|
-
}))
|
|
34
|
-
.filter((r) => String(r.code).trim().length > 0);
|
|
35
|
-
const installResults = {};
|
|
36
|
-
// Xcode
|
|
37
|
-
if ((target === 'all' || target === 'xcode') && process.platform === 'darwin') {
|
|
38
|
-
try {
|
|
39
|
-
const xcodeInstaller = container.get('snippetInstaller');
|
|
40
|
-
installResults.xcode = xcodeInstaller.installFromRecipes(recipes);
|
|
41
|
-
}
|
|
42
|
-
catch (e) {
|
|
43
|
-
installResults.xcode = { success: false, error: e.message };
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// VSCode
|
|
47
|
-
if (target === 'all' || target === 'vscode') {
|
|
48
|
-
try {
|
|
49
|
-
const vscodeInstaller = container.get('vscodeSnippetInstaller');
|
|
50
|
-
installResults.vscode = vscodeInstaller.installFromRecipes(recipes);
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
installResults.vscode = { success: false, error: e.message };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
logger.info('Snippets installed via dashboard', { target, results: installResults });
|
|
57
|
-
res.json({
|
|
58
|
-
success: true,
|
|
59
|
-
data: installResults,
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
12
|
/**
|
|
63
13
|
* POST /api/v1/commands/spm-map
|
|
64
14
|
* 执行 SPM 依赖映射刷新(向后兼容)
|
|
@@ -126,24 +76,9 @@ router.post('/embed', async (req, res) => {
|
|
|
126
76
|
router.get('/status', async (req, res) => {
|
|
127
77
|
const container = getServiceContainer();
|
|
128
78
|
const status = {
|
|
129
|
-
snippets: { xcode: { synced: false }, vscode: { synced: false } },
|
|
130
79
|
index: { ready: false },
|
|
131
80
|
spmMap: { available: false },
|
|
132
81
|
};
|
|
133
|
-
try {
|
|
134
|
-
const snippetInstaller = container.get('snippetInstaller');
|
|
135
|
-
status.snippets.xcode.synced = (await snippetInstaller.listInstalled?.())?.length > 0;
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
/* ignore */
|
|
139
|
-
}
|
|
140
|
-
try {
|
|
141
|
-
const vscodeInstaller = container.get('vscodeSnippetInstaller');
|
|
142
|
-
status.snippets.vscode.synced = (await vscodeInstaller.listInstalled?.())?.length > 0;
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
/* ignore */
|
|
146
|
-
}
|
|
147
82
|
try {
|
|
148
83
|
const indexingPipeline = container.get('indexingPipeline');
|
|
149
84
|
status.index.ready = true; // IndexingPipeline is available
|
|
@@ -715,16 +715,12 @@ async function replyLark(messageId, text) {
|
|
|
715
715
|
/**
|
|
716
716
|
* 截取 IDE 窗口截图(通过 ScreenCaptureKit 原生 API,息屏时可用)
|
|
717
717
|
* @param [opts.windowTitle] 窗口标题关键词(默认 "Code")
|
|
718
|
-
* @returns >}
|
|
719
718
|
*/
|
|
720
719
|
async function captureIDEScreenshot(opts = {}) {
|
|
721
720
|
try {
|
|
722
721
|
const { screenshot } = await import('../../platform/ScreenCaptureService.js');
|
|
723
|
-
// 统一使用窗口截取(desktopIndependentWindow,亮屏/息屏均可用)
|
|
724
|
-
// 优先截取 IDE 窗口
|
|
725
722
|
const windowTitle = opts.windowTitle || 'Code';
|
|
726
723
|
let result = await screenshot({ windowTitle, format: 'png' });
|
|
727
|
-
// IDE 窗口未找到 → 尝试常见 IDE 名称
|
|
728
724
|
if (!result.success) {
|
|
729
725
|
for (const alt of ['Visual Studio', 'Cursor', 'Xcode', 'IntelliJ', 'WebStorm']) {
|
|
730
726
|
if (alt.toLowerCase() === windowTitle.toLowerCase()) {
|
|
@@ -736,7 +732,6 @@ async function captureIDEScreenshot(opts = {}) {
|
|
|
736
732
|
}
|
|
737
733
|
}
|
|
738
734
|
}
|
|
739
|
-
// 仍未找到 → 不指定窗口名,Swift 工具会自动选最大窗口
|
|
740
735
|
if (!result.success) {
|
|
741
736
|
logger.info(`[Remote/Screenshot] IDE window not found, capturing largest available window`);
|
|
742
737
|
result = await screenshot({ format: 'png' });
|
|
@@ -21,11 +21,9 @@ import type { EventBus } from '../infrastructure/event/EventBus.js';
|
|
|
21
21
|
import type Logger from '../infrastructure/logging/Logger.js';
|
|
22
22
|
import type { IndexingPipeline } from '../infrastructure/vector/IndexingPipeline.js';
|
|
23
23
|
import type { VectorStore } from '../infrastructure/vector/VectorStore.js';
|
|
24
|
-
import type { SpmHelper } from '../platform/ios/spm/SpmHelper.js';
|
|
25
24
|
import type { KnowledgeRepositoryImpl } from '../repository/knowledge/KnowledgeRepository.impl.js';
|
|
26
25
|
import type { TaskRepositoryImpl } from '../repository/task/TaskRepository.impl.js';
|
|
27
26
|
import type { TokenUsageStore } from '../repository/token/TokenUsageStore.js';
|
|
28
|
-
import type { AutomationOrchestrator } from '../service/automation/AutomationOrchestrator.js';
|
|
29
27
|
import type { BootstrapTaskManager } from '../service/bootstrap/BootstrapTaskManager.js';
|
|
30
28
|
import type DimensionCopy from '../service/bootstrap/DimensionCopyRegistry.js';
|
|
31
29
|
import type { CursorDeliveryPipeline } from '../service/delivery/CursorDeliveryPipeline.js';
|
|
@@ -50,8 +48,6 @@ import type { RecipeParser } from '../service/recipe/RecipeParser.js';
|
|
|
50
48
|
import type { HybridRetriever } from '../service/search/HybridRetriever.js';
|
|
51
49
|
import type SearchEngine from '../service/search/SearchEngine.js';
|
|
52
50
|
import type { SkillHooks } from '../service/skills/SkillHooks.js';
|
|
53
|
-
import type { SnippetFactory } from '../service/snippet/SnippetFactory.js';
|
|
54
|
-
import type { SnippetInstaller } from '../service/snippet/SnippetInstaller.js';
|
|
55
51
|
import type { TaskGraphService } from '../service/task/TaskGraphService.js';
|
|
56
52
|
import type { TaskKnowledgeBridge } from '../service/task/TaskKnowledgeBridge.js';
|
|
57
53
|
import type { TaskReadyEngine } from '../service/task/TaskReadyEngine.js';
|
|
@@ -82,11 +78,6 @@ export interface ServiceMap {
|
|
|
82
78
|
recipeExtractor: RecipeExtractor | null;
|
|
83
79
|
feedbackCollector: FeedbackCollector;
|
|
84
80
|
tokenUsageStore: TokenUsageStore;
|
|
85
|
-
snippetFactory: SnippetFactory;
|
|
86
|
-
snippetInstaller: SnippetInstaller;
|
|
87
|
-
vscodeSnippetInstaller: SnippetInstaller;
|
|
88
|
-
spmService: SpmHelper;
|
|
89
|
-
automationOrchestrator: AutomationOrchestrator;
|
|
90
81
|
moduleService: ModuleService;
|
|
91
82
|
cursorDeliveryPipeline: CursorDeliveryPipeline;
|
|
92
83
|
taskIdGenerator: TaskIdGenerator;
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* AppModule — 应用层杂项服务注册
|
|
3
3
|
*
|
|
4
4
|
* 负责注册:
|
|
5
|
-
* - recipeParser, recipeCandidateValidator
|
|
5
|
+
* - recipeParser, recipeCandidateValidator
|
|
6
6
|
* - qualityScorer, feedbackCollector, tokenUsageStore, recipeExtractor
|
|
7
|
-
* -
|
|
8
|
-
* - cursorDeliveryPipeline
|
|
7
|
+
* - moduleService, cursorDeliveryPipeline
|
|
9
8
|
* - taskIdGenerator, taskReadyEngine, taskKnowledgeBridge, taskGraphService
|
|
10
9
|
*/
|
|
11
10
|
import type { ServiceContainer } from '../ServiceContainer.js';
|
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
* AppModule — 应用层杂项服务注册
|
|
3
3
|
*
|
|
4
4
|
* 负责注册:
|
|
5
|
-
* - recipeParser, recipeCandidateValidator
|
|
5
|
+
* - recipeParser, recipeCandidateValidator
|
|
6
6
|
* - qualityScorer, feedbackCollector, tokenUsageStore, recipeExtractor
|
|
7
|
-
* -
|
|
8
|
-
* - cursorDeliveryPipeline
|
|
7
|
+
* - moduleService, cursorDeliveryPipeline
|
|
9
8
|
* - taskIdGenerator, taskReadyEngine, taskKnowledgeBridge, taskGraphService
|
|
10
9
|
*/
|
|
11
10
|
import { resolveProjectRoot } from '#shared/resolveProjectRoot.js';
|
|
12
11
|
import { TaskIdGenerator } from '../../domain/task/TaskIdGenerator.js';
|
|
13
|
-
import { XcodeCodec } from '../../platform/ios/snippet/XcodeCodec.js';
|
|
14
|
-
import { SpmHelper } from '../../platform/ios/spm/SpmHelper.js';
|
|
15
12
|
import { TokenUsageStore } from '../../repository/token/TokenUsageStore.js';
|
|
16
|
-
import { AutomationOrchestrator } from '../../service/automation/AutomationOrchestrator.js';
|
|
17
13
|
import { CursorDeliveryPipeline } from '../../service/delivery/CursorDeliveryPipeline.js';
|
|
18
14
|
import { RecipeExtractor } from '../../service/knowledge/RecipeExtractor.js';
|
|
19
15
|
import { ModuleService } from '../../service/module/ModuleService.js';
|
|
@@ -21,9 +17,6 @@ import { FeedbackCollector } from '../../service/quality/FeedbackCollector.js';
|
|
|
21
17
|
import { QualityScorer } from '../../service/quality/QualityScorer.js';
|
|
22
18
|
import { RecipeCandidateValidator } from '../../service/recipe/RecipeCandidateValidator.js';
|
|
23
19
|
import { RecipeParser } from '../../service/recipe/RecipeParser.js';
|
|
24
|
-
import { VSCodeCodec } from '../../service/snippet/codecs/VSCodeCodec.js';
|
|
25
|
-
import { SnippetFactory } from '../../service/snippet/SnippetFactory.js';
|
|
26
|
-
import { SnippetInstaller } from '../../service/snippet/SnippetInstaller.js';
|
|
27
20
|
import { TaskGraphService } from '../../service/task/TaskGraphService.js';
|
|
28
21
|
import { TaskKnowledgeBridge } from '../../service/task/TaskKnowledgeBridge.js';
|
|
29
22
|
import { TaskReadyEngine } from '../../service/task/TaskReadyEngine.js';
|
|
@@ -41,27 +34,7 @@ export function register(c) {
|
|
|
41
34
|
const db = ct.get('database');
|
|
42
35
|
return new TokenUsageStore(db.getDb(), db.getDrizzle());
|
|
43
36
|
});
|
|
44
|
-
// ═══
|
|
45
|
-
c.singleton('snippetFactory', (ct) => {
|
|
46
|
-
const factory = new SnippetFactory(ct.get('knowledgeRepository'));
|
|
47
|
-
factory.registerCodec(new XcodeCodec());
|
|
48
|
-
factory.registerCodec(new VSCodeCodec());
|
|
49
|
-
return factory;
|
|
50
|
-
});
|
|
51
|
-
c.singleton('snippetInstaller', (ct) => {
|
|
52
|
-
const factory = ct.get('snippetFactory');
|
|
53
|
-
return new SnippetInstaller({ codec: factory.getCodec('xcode'), snippetFactory: factory });
|
|
54
|
-
});
|
|
55
|
-
c.singleton('vscodeSnippetInstaller', (ct) => {
|
|
56
|
-
const factory = ct.get('snippetFactory');
|
|
57
|
-
return new SnippetInstaller({ codec: factory.getCodec('vscode'), snippetFactory: factory });
|
|
58
|
-
});
|
|
59
|
-
// ═══ Platform + Automation ═══
|
|
60
|
-
c.singleton('spmService', (ct) => {
|
|
61
|
-
const projectRoot = resolveProjectRoot(ct);
|
|
62
|
-
return new SpmHelper(projectRoot);
|
|
63
|
-
});
|
|
64
|
-
c.singleton('automationOrchestrator', () => new AutomationOrchestrator());
|
|
37
|
+
// ═══ Module ═══
|
|
65
38
|
c.singleton('moduleService', (ct) => {
|
|
66
39
|
const projectRoot = resolveProjectRoot(ct);
|
|
67
40
|
return new ModuleService(projectRoot, {
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* - exclusionManager, ruleLearner, violationsStore
|
|
7
7
|
* - complianceReporter, guardFeedbackLoop
|
|
8
8
|
*/
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
9
11
|
import { resolveProjectRoot } from '#shared/resolveProjectRoot.js';
|
|
10
12
|
import { ComplianceReporter } from '../../service/guard/ComplianceReporter.js';
|
|
11
13
|
import { ExclusionManager } from '../../service/guard/ExclusionManager.js';
|
|
@@ -29,7 +31,37 @@ export function register(c) {
|
|
|
29
31
|
});
|
|
30
32
|
c.singleton('guardCheckEngine', (ct) => {
|
|
31
33
|
const config = ct.singletons._config || {};
|
|
32
|
-
|
|
34
|
+
// 基础配置(AutoSnippet 自身 config/default.json)
|
|
35
|
+
const baseGuard = config.guard || {};
|
|
36
|
+
// 项目级覆盖(.autosnippet/config.json 的 guard 段)
|
|
37
|
+
let projectGuard = {};
|
|
38
|
+
try {
|
|
39
|
+
const projectRoot = resolveProjectRoot(ct);
|
|
40
|
+
const projConfigPath = path.join(projectRoot, '.autosnippet', 'config.json');
|
|
41
|
+
if (fs.existsSync(projConfigPath)) {
|
|
42
|
+
const raw = JSON.parse(fs.readFileSync(projConfigPath, 'utf-8'));
|
|
43
|
+
if (raw.guard && typeof raw.guard === 'object') {
|
|
44
|
+
projectGuard = raw.guard;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* 项目配置读取失败不阻塞 */
|
|
50
|
+
}
|
|
51
|
+
// 合并:项目级覆盖基础配置
|
|
52
|
+
const merged = { ...baseGuard, ...projectGuard };
|
|
53
|
+
if (baseGuard.codeLevelThresholds || projectGuard.codeLevelThresholds) {
|
|
54
|
+
merged.codeLevelThresholds = {
|
|
55
|
+
...(baseGuard.codeLevelThresholds || {}),
|
|
56
|
+
...(projectGuard.codeLevelThresholds || {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (baseGuard.disabledRules || projectGuard.disabledRules) {
|
|
60
|
+
const base = Array.isArray(baseGuard.disabledRules) ? baseGuard.disabledRules : [];
|
|
61
|
+
const proj = Array.isArray(projectGuard.disabledRules) ? projectGuard.disabledRules : [];
|
|
62
|
+
merged.disabledRules = [...new Set([...base, ...proj])];
|
|
63
|
+
}
|
|
64
|
+
return new GuardCheckEngine(ct.get('database'), { guardConfig: merged });
|
|
33
65
|
});
|
|
34
66
|
c.singleton('exclusionManager', (ct) => {
|
|
35
67
|
const projectRoot = resolveProjectRoot(ct);
|
|
@@ -24,6 +24,7 @@ interface BuiltInRule {
|
|
|
24
24
|
category?: string;
|
|
25
25
|
fixSuggestion?: string;
|
|
26
26
|
excludePaths?: RegExp;
|
|
27
|
+
excludeLinePatterns?: string[];
|
|
27
28
|
skipComments?: boolean;
|
|
28
29
|
skipTestBlocks?: boolean;
|
|
29
30
|
}
|
|
@@ -40,6 +41,7 @@ interface GuardRule {
|
|
|
40
41
|
type?: string;
|
|
41
42
|
fixSuggestion?: string | null;
|
|
42
43
|
excludePaths?: RegExp | string;
|
|
44
|
+
excludeLinePatterns?: string[];
|
|
43
45
|
skipComments?: boolean;
|
|
44
46
|
skipTestBlocks?: boolean;
|
|
45
47
|
astQuery?: {
|
|
@@ -62,9 +64,14 @@ interface GuardViolation {
|
|
|
62
64
|
suggestedFix: string | null;
|
|
63
65
|
};
|
|
64
66
|
}
|
|
67
|
+
/** 每条规则的覆盖配置(支持数字阈值或富对象) */
|
|
68
|
+
interface RuleOverride {
|
|
69
|
+
severity?: string;
|
|
70
|
+
exclude?: string[];
|
|
71
|
+
}
|
|
65
72
|
interface GuardConfig {
|
|
66
73
|
disabledRules?: string[];
|
|
67
|
-
codeLevelThresholds?: Record<string, number>;
|
|
74
|
+
codeLevelThresholds?: Record<string, number | RuleOverride>;
|
|
68
75
|
}
|
|
69
76
|
interface GuardCheckEngineOptions {
|
|
70
77
|
cacheTTL?: number;
|
|
@@ -157,6 +164,11 @@ export declare class GuardCheckEngine {
|
|
|
157
164
|
_runAstRuleChecks(code: string, language: string): GuardViolation[];
|
|
158
165
|
/** 获取 AstAnalyzer 模块(静态 import,带可用性检测) */
|
|
159
166
|
_getAstAnalyzer(): typeof AstAnalyzerModule;
|
|
167
|
+
/**
|
|
168
|
+
* 合并内置 + 配置级行排除模式,编译为 RegExp 数组
|
|
169
|
+
* 配置来自 guardConfig.codeLevelThresholds[ruleId].exclude
|
|
170
|
+
*/
|
|
171
|
+
_getExcludeLineRegexes(ruleId: string, builtIn?: string[]): RegExp[];
|
|
160
172
|
/**
|
|
161
173
|
* 将 Guard 命中计数回写到对应 Recipe 的 guard_hit_count
|
|
162
174
|
* @param violations
|
|
@@ -75,6 +75,13 @@ const BUILT_IN_RULES = {
|
|
|
75
75
|
dimension: 'file',
|
|
76
76
|
category: 'safety',
|
|
77
77
|
fixSuggestion: '使用 as? 配合 guard let / if let 进行安全转换',
|
|
78
|
+
// UIKit 框架契约保证安全的 as! 场景
|
|
79
|
+
excludeLinePatterns: [
|
|
80
|
+
'dequeueReusableCell.*as\\s*!',
|
|
81
|
+
'dequeueReusableSupplementaryView.*as\\s*!',
|
|
82
|
+
'dequeueReusableHeaderFooterView.*as\\s*!',
|
|
83
|
+
'layerClass.*layer\\s+as\\s*!',
|
|
84
|
+
],
|
|
78
85
|
},
|
|
79
86
|
'swift-force-try': {
|
|
80
87
|
message: 'try! 在异常时崩溃,建议 do-catch 或 try?',
|
|
@@ -689,6 +696,9 @@ export class GuardCheckEngine {
|
|
|
689
696
|
}
|
|
690
697
|
const shouldSkipComments = !!rule.skipComments;
|
|
691
698
|
const shouldSkipTestBlocks = !!rule.skipTestBlocks;
|
|
699
|
+
// 合并内置 + 配置级排除行模式
|
|
700
|
+
const ruleId = rule.id || rule.name;
|
|
701
|
+
const excludeLineRegexes = this._getExcludeLineRegexes(ruleId, rule.excludeLinePatterns);
|
|
692
702
|
for (let i = 0; i < lines.length; i++) {
|
|
693
703
|
// skipComments: 跳过注释行(doc comments / 行注释 / 块注释内)
|
|
694
704
|
if (shouldSkipComments && commentLines[i]) {
|
|
@@ -699,6 +709,10 @@ export class GuardCheckEngine {
|
|
|
699
709
|
continue;
|
|
700
710
|
}
|
|
701
711
|
if (re.test(lines[i])) {
|
|
712
|
+
// excludeLinePatterns: 跳过匹配排除模式的行(UIKit 框架契约安全等场景)
|
|
713
|
+
if (excludeLineRegexes.length > 0 && excludeLineRegexes.some((ep) => ep.test(lines[i]))) {
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
702
716
|
violations.push({
|
|
703
717
|
ruleId: rule.id || rule.name,
|
|
704
718
|
message: rule.message,
|
|
@@ -711,10 +725,16 @@ export class GuardCheckEngine {
|
|
|
711
725
|
}
|
|
712
726
|
}
|
|
713
727
|
}
|
|
714
|
-
// Code-level
|
|
728
|
+
// Code-level 检查(不依赖正则)— 仅传递数字类型阈值
|
|
729
|
+
const numericThresholds = {};
|
|
730
|
+
for (const [k, v] of Object.entries(this._guardConfig.codeLevelThresholds || {})) {
|
|
731
|
+
if (typeof v === 'number') {
|
|
732
|
+
numericThresholds[k] = v;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
715
735
|
violations.push(...runCodeLevelChecks(code, language, lines, {
|
|
716
736
|
disabledRules: this._guardConfig.disabledRules,
|
|
717
|
-
codeLevelThresholds:
|
|
737
|
+
codeLevelThresholds: numericThresholds,
|
|
718
738
|
}));
|
|
719
739
|
// AST 语义规则检查
|
|
720
740
|
violations.push(...this._runAstRuleChecks(code, language));
|
|
@@ -853,6 +873,28 @@ export class GuardCheckEngine {
|
|
|
853
873
|
_getAstAnalyzer() {
|
|
854
874
|
return AstAnalyzerModule;
|
|
855
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* 合并内置 + 配置级行排除模式,编译为 RegExp 数组
|
|
878
|
+
* 配置来自 guardConfig.codeLevelThresholds[ruleId].exclude
|
|
879
|
+
*/
|
|
880
|
+
_getExcludeLineRegexes(ruleId, builtIn) {
|
|
881
|
+
const patterns = [...(builtIn || [])];
|
|
882
|
+
// 合并项目配置中的 exclude
|
|
883
|
+
const override = this._guardConfig.codeLevelThresholds?.[ruleId];
|
|
884
|
+
if (override && typeof override === 'object' && Array.isArray(override.exclude)) {
|
|
885
|
+
patterns.push(...override.exclude);
|
|
886
|
+
}
|
|
887
|
+
const regexes = [];
|
|
888
|
+
for (const p of patterns) {
|
|
889
|
+
try {
|
|
890
|
+
regexes.push(new RegExp(p));
|
|
891
|
+
}
|
|
892
|
+
catch {
|
|
893
|
+
this.logger.debug(`Invalid excludeLinePattern in rule ${ruleId}: ${p}`);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return regexes;
|
|
897
|
+
}
|
|
856
898
|
/**
|
|
857
899
|
* 将 Guard 命中计数回写到对应 Recipe 的 guard_hit_count
|
|
858
900
|
* @param violations
|
|
@@ -366,19 +366,9 @@ export class ModuleService {
|
|
|
366
366
|
if (!Array.isArray(recipes)) {
|
|
367
367
|
recipes = [];
|
|
368
368
|
}
|
|
369
|
-
// 3.5
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const HeaderResolver = await import('../../platform/ios/xcode/HeaderResolver.js');
|
|
373
|
-
const targetRootDir = await PathFinder.findTargetRootDir(files[0].path);
|
|
374
|
-
for (const recipe of recipes) {
|
|
375
|
-
const headerList = (recipe.headers || []);
|
|
376
|
-
recipe.headerPaths = await Promise.all(headerList.map((h) => HeaderResolver.resolveHeaderRelativePath(h, targetRootDir)));
|
|
377
|
-
recipe.moduleName = targetName;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
catch (err) {
|
|
381
|
-
this.#logger.warn(`[ModuleService] Header resolution failed: ${err.message}`);
|
|
369
|
+
// 3.5 moduleName 注入
|
|
370
|
+
for (const recipe of recipes) {
|
|
371
|
+
recipe.moduleName = targetName;
|
|
382
372
|
}
|
|
383
373
|
// 4. 工具增强
|
|
384
374
|
onProgress?.({ type: 'scan:enriching', recipeCount: recipes.length });
|
|
@@ -78,14 +78,6 @@ export declare const SEARCH: Readonly<{
|
|
|
78
78
|
DEFAULT_LIMIT: 10;
|
|
79
79
|
MAX_RESULTS: 100;
|
|
80
80
|
}>;
|
|
81
|
-
/** FileWatcher 配置 */
|
|
82
|
-
export declare const FILE_WATCHER: Readonly<{
|
|
83
|
-
DEBOUNCE_DELAY_MS: 300;
|
|
84
|
-
STABILITY_THRESHOLD_MS: 500;
|
|
85
|
-
POLL_INTERVAL_MS: 100;
|
|
86
|
-
BINARY_INTERVAL_MS: 300;
|
|
87
|
-
MAX_FILE_SIZE_BYTES: number;
|
|
88
|
-
}>;
|
|
89
81
|
/** AiProvider 熔断配置 */
|
|
90
82
|
export declare const AI_CIRCUIT_BREAKER: Readonly<{
|
|
91
83
|
FAILURE_THRESHOLD: 5;
|
|
@@ -176,13 +168,6 @@ declare const _default: {
|
|
|
176
168
|
DEFAULT_LIMIT: 10;
|
|
177
169
|
MAX_RESULTS: 100;
|
|
178
170
|
}>;
|
|
179
|
-
FILE_WATCHER: Readonly<{
|
|
180
|
-
DEBOUNCE_DELAY_MS: 300;
|
|
181
|
-
STABILITY_THRESHOLD_MS: 500;
|
|
182
|
-
POLL_INTERVAL_MS: 100;
|
|
183
|
-
BINARY_INTERVAL_MS: 300;
|
|
184
|
-
MAX_FILE_SIZE_BYTES: number;
|
|
185
|
-
}>;
|
|
186
171
|
AI_CIRCUIT_BREAKER: Readonly<{
|
|
187
172
|
FAILURE_THRESHOLD: 5;
|
|
188
173
|
}>;
|
|
@@ -83,15 +83,6 @@ export const SEARCH = Object.freeze({
|
|
|
83
83
|
DEFAULT_LIMIT: 10,
|
|
84
84
|
MAX_RESULTS: 100,
|
|
85
85
|
});
|
|
86
|
-
// ─── 文件监听器 ──────────────────────────────────────────
|
|
87
|
-
/** FileWatcher 配置 */
|
|
88
|
-
export const FILE_WATCHER = Object.freeze({
|
|
89
|
-
DEBOUNCE_DELAY_MS: 300,
|
|
90
|
-
STABILITY_THRESHOLD_MS: 500,
|
|
91
|
-
POLL_INTERVAL_MS: 100,
|
|
92
|
-
BINARY_INTERVAL_MS: 300,
|
|
93
|
-
MAX_FILE_SIZE_BYTES: 1024 * 1024,
|
|
94
|
-
});
|
|
95
86
|
// ─── AI Provider ─────────────────────────────────────────
|
|
96
87
|
/** AiProvider 熔断配置 */
|
|
97
88
|
export const AI_CIRCUIT_BREAKER = Object.freeze({
|
|
@@ -129,7 +120,6 @@ export default {
|
|
|
129
120
|
COMPLIANCE_SCORING,
|
|
130
121
|
KNOWLEDGE_CONFIDENCE,
|
|
131
122
|
SEARCH,
|
|
132
|
-
FILE_WATCHER,
|
|
133
123
|
AI_CIRCUIT_BREAKER,
|
|
134
124
|
CACHE,
|
|
135
125
|
MONITORING,
|
|
@@ -103,7 +103,10 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
103
103
|
}, z.core.$strip>>;
|
|
104
104
|
guard: z.ZodOptional<z.ZodObject<{
|
|
105
105
|
disabledRules: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
106
|
-
codeLevelThresholds: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber
|
|
106
|
+
codeLevelThresholds: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodObject<{
|
|
107
|
+
severity: z.ZodOptional<z.ZodString>;
|
|
108
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
109
|
+
}, z.core.$strip>]>>>;
|
|
107
110
|
}, z.core.$strip>>;
|
|
108
111
|
taskGraph: z.ZodOptional<z.ZodObject<{
|
|
109
112
|
decision: z.ZodOptional<z.ZodObject<{
|
|
@@ -81,9 +81,16 @@ const QualityGateConfig = z.object({
|
|
|
81
81
|
maxWarnings: z.number().int().min(0).default(20),
|
|
82
82
|
minScore: z.number().int().min(0).max(100).default(70),
|
|
83
83
|
});
|
|
84
|
+
const RuleOverrideConfig = z.union([
|
|
85
|
+
z.number().int().min(0),
|
|
86
|
+
z.object({
|
|
87
|
+
severity: z.string().optional(),
|
|
88
|
+
exclude: z.array(z.string()).optional(),
|
|
89
|
+
}),
|
|
90
|
+
]);
|
|
84
91
|
const GuardConfig = z.object({
|
|
85
92
|
disabledRules: z.array(z.string()).default([]),
|
|
86
|
-
codeLevelThresholds: z.record(z.string(),
|
|
93
|
+
codeLevelThresholds: z.record(z.string(), RuleOverrideConfig).default({}),
|
|
87
94
|
});
|
|
88
95
|
const TaskDecisionConfig = z.object({
|
|
89
96
|
staleDays: z.number().int().min(1).default(30),
|
package/dist/scripts/release.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 用途:自动化发布前检查和发布流程
|
|
5
5
|
* 使用:node scripts/release.js [patch|minor|major]
|
|
6
6
|
*/
|
|
7
|
-
import { DASHBOARD_DIR, PACKAGE_ROOT
|
|
7
|
+
import { DASHBOARD_DIR, PACKAGE_ROOT } from '../lib/shared/package-root.js';
|
|
8
8
|
const __dirname = import.meta.dirname;
|
|
9
9
|
import { execSync } from 'node:child_process';
|
|
10
10
|
import fs from 'node:fs';
|
|
@@ -196,15 +196,7 @@ class ReleaseChecker {
|
|
|
196
196
|
// 检查其他构建产物
|
|
197
197
|
checkBuildArtifacts() {
|
|
198
198
|
header('其他构建产物检查');
|
|
199
|
-
|
|
200
|
-
if (!fs.existsSync(nativeUI)) {
|
|
201
|
-
this.warnings.push('Native UI 未构建 (执行 npm run build:native-ui)');
|
|
202
|
-
warning('Native UI: 未构建');
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
const stat = fs.statSync(nativeUI);
|
|
206
|
-
success(`Native UI: 已构建 (${new Date(stat.mtime).toLocaleString()})`);
|
|
207
|
-
}
|
|
199
|
+
success('No platform-specific binaries to check');
|
|
208
200
|
}
|
|
209
201
|
// 运行测试
|
|
210
202
|
runTests() {
|