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.
Files changed (107) hide show
  1. package/dashboard/dist/assets/{icons-C1dUryS-.js → icons-BofcEZ3f.js} +1 -1
  2. package/dashboard/dist/assets/index-SiN1GChm.js +128 -0
  3. package/dashboard/dist/index.html +2 -2
  4. package/dist/bin/cli.d.ts +0 -1
  5. package/dist/bin/cli.js +0 -133
  6. package/dist/lib/cli/SetupService.d.ts +46 -2
  7. package/dist/lib/cli/SetupService.js +2 -27
  8. package/dist/lib/{platform/ios/spm → core/discovery}/SpmDiscoverer.d.ts +2 -5
  9. package/dist/lib/{platform/ios/spm → core/discovery}/SpmDiscoverer.js +159 -44
  10. package/dist/lib/core/discovery/index.d.ts +1 -1
  11. package/dist/lib/core/discovery/index.js +2 -2
  12. package/dist/lib/external/mcp/handlers/guard.js +6 -3
  13. package/dist/lib/http/HttpServer.js +0 -6
  14. package/dist/lib/http/routes/commands.d.ts +1 -1
  15. package/dist/lib/http/routes/commands.js +1 -66
  16. package/dist/lib/http/routes/remote.js +0 -5
  17. package/dist/lib/injection/ServiceMap.d.ts +0 -9
  18. package/dist/lib/injection/modules/AppModule.d.ts +2 -3
  19. package/dist/lib/injection/modules/AppModule.js +3 -30
  20. package/dist/lib/injection/modules/GuardModule.js +33 -1
  21. package/dist/lib/service/guard/GuardCheckEngine.d.ts +13 -1
  22. package/dist/lib/service/guard/GuardCheckEngine.js +44 -2
  23. package/dist/lib/service/module/ModuleService.js +3 -13
  24. package/dist/lib/service/search/SearchEngine.js +1 -1
  25. package/dist/lib/shared/constants.d.ts +0 -15
  26. package/dist/lib/shared/constants.js +0 -10
  27. package/dist/lib/shared/schemas/config.d.ts +4 -1
  28. package/dist/lib/shared/schemas/config.js +8 -1
  29. package/dist/scripts/release.js +2 -10
  30. package/package.json +4 -19
  31. package/dashboard/dist/assets/index-DdvZE4Yd.js +0 -128
  32. package/dist/lib/http/routes/snippets.d.ts +0 -6
  33. package/dist/lib/http/routes/snippets.js +0 -49
  34. package/dist/lib/platform/ClipboardManager.d.ts +0 -24
  35. package/dist/lib/platform/ClipboardManager.js +0 -142
  36. package/dist/lib/platform/NativeUi.d.ts +0 -53
  37. package/dist/lib/platform/NativeUi.js +0 -284
  38. package/dist/lib/platform/ios/index.d.ts +0 -38
  39. package/dist/lib/platform/ios/index.js +0 -42
  40. package/dist/lib/platform/ios/routes/spm.d.ts +0 -9
  41. package/dist/lib/platform/ios/routes/spm.js +0 -371
  42. package/dist/lib/platform/ios/snippet/PlaceholderConverter.d.ts +0 -21
  43. package/dist/lib/platform/ios/snippet/PlaceholderConverter.js +0 -48
  44. package/dist/lib/platform/ios/snippet/XcodeCodec.d.ts +0 -23
  45. package/dist/lib/platform/ios/snippet/XcodeCodec.js +0 -96
  46. package/dist/lib/platform/ios/spm/DependencyGraph.d.ts +0 -56
  47. package/dist/lib/platform/ios/spm/DependencyGraph.js +0 -195
  48. package/dist/lib/platform/ios/spm/PackageSwiftParser.d.ts +0 -69
  49. package/dist/lib/platform/ios/spm/PackageSwiftParser.js +0 -231
  50. package/dist/lib/platform/ios/spm/PathFinder.d.ts +0 -28
  51. package/dist/lib/platform/ios/spm/PathFinder.js +0 -117
  52. package/dist/lib/platform/ios/spm/PolicyEngine.d.ts +0 -44
  53. package/dist/lib/platform/ios/spm/PolicyEngine.js +0 -79
  54. package/dist/lib/platform/ios/spm/SpmHelper.d.ts +0 -102
  55. package/dist/lib/platform/ios/spm/SpmHelper.js +0 -464
  56. package/dist/lib/platform/ios/xcode/HeaderResolver.d.ts +0 -33
  57. package/dist/lib/platform/ios/xcode/HeaderResolver.js +0 -90
  58. package/dist/lib/platform/ios/xcode/SaveEventFilter.d.ts +0 -66
  59. package/dist/lib/platform/ios/xcode/SaveEventFilter.js +0 -142
  60. package/dist/lib/platform/ios/xcode/XcodeAutomation.d.ts +0 -71
  61. package/dist/lib/platform/ios/xcode/XcodeAutomation.js +0 -327
  62. package/dist/lib/platform/ios/xcode/XcodeImportResolver.d.ts +0 -130
  63. package/dist/lib/platform/ios/xcode/XcodeImportResolver.js +0 -404
  64. package/dist/lib/platform/ios/xcode/XcodeIntegration.d.ts +0 -89
  65. package/dist/lib/platform/ios/xcode/XcodeIntegration.js +0 -588
  66. package/dist/lib/platform/ios/xcode/XcodeWriteUtils.d.ts +0 -99
  67. package/dist/lib/platform/ios/xcode/XcodeWriteUtils.js +0 -190
  68. package/dist/lib/service/automation/ActionPipeline.d.ts +0 -34
  69. package/dist/lib/service/automation/ActionPipeline.js +0 -53
  70. package/dist/lib/service/automation/AutomationOrchestrator.d.ts +0 -86
  71. package/dist/lib/service/automation/AutomationOrchestrator.js +0 -57
  72. package/dist/lib/service/automation/ContextCollector.d.ts +0 -24
  73. package/dist/lib/service/automation/ContextCollector.js +0 -35
  74. package/dist/lib/service/automation/DirectiveDetector.d.ts +0 -51
  75. package/dist/lib/service/automation/DirectiveDetector.js +0 -112
  76. package/dist/lib/service/automation/FileWatcher.d.ts +0 -51
  77. package/dist/lib/service/automation/FileWatcher.js +0 -366
  78. package/dist/lib/service/automation/TriggerResolver.d.ts +0 -36
  79. package/dist/lib/service/automation/TriggerResolver.js +0 -62
  80. package/dist/lib/service/automation/handlers/AlinkHandler.d.ts +0 -7
  81. package/dist/lib/service/automation/handlers/AlinkHandler.js +0 -80
  82. package/dist/lib/service/automation/handlers/CreateHandler.d.ts +0 -11
  83. package/dist/lib/service/automation/handlers/CreateHandler.js +0 -170
  84. package/dist/lib/service/automation/handlers/GuardHandler.d.ts +0 -17
  85. package/dist/lib/service/automation/handlers/GuardHandler.js +0 -218
  86. package/dist/lib/service/automation/handlers/HeaderHandler.d.ts +0 -2
  87. package/dist/lib/service/automation/handlers/HeaderHandler.js +0 -32
  88. package/dist/lib/service/automation/handlers/SearchHandler.d.ts +0 -11
  89. package/dist/lib/service/automation/handlers/SearchHandler.js +0 -278
  90. package/dist/lib/service/snippet/SnippetFactory.d.ts +0 -101
  91. package/dist/lib/service/snippet/SnippetFactory.js +0 -145
  92. package/dist/lib/service/snippet/SnippetInstaller.d.ts +0 -91
  93. package/dist/lib/service/snippet/SnippetInstaller.js +0 -276
  94. package/dist/lib/service/snippet/codecs/SnippetCodec.d.ts +0 -44
  95. package/dist/lib/service/snippet/codecs/SnippetCodec.js +0 -35
  96. package/dist/lib/service/snippet/codecs/VSCodeCodec.d.ts +0 -27
  97. package/dist/lib/service/snippet/codecs/VSCodeCodec.js +0 -82
  98. package/dist/scripts/build-native-ui.d.ts +0 -3
  99. package/dist/scripts/build-native-ui.js +0 -62
  100. package/dist/scripts/init-snippets.d.ts +0 -30
  101. package/dist/scripts/init-snippets.js +0 -298
  102. package/dist/scripts/install-full.d.ts +0 -7
  103. package/dist/scripts/install-full.js +0 -38
  104. package/resources/native-ui/README.md +0 -29
  105. package/resources/native-ui/combined-window.swift +0 -494
  106. package/resources/native-ui/main.swift +0 -598
  107. 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
- // 优先使用 ModuleService(多语言统一入口),回退到 SpmHelper
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
- const { SpmHelper } = await import('#platform/ios/spm/SpmHelper.js');
425
- service = new SpmHelper(projectRoot);
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
- * 执行 Install (同步 Snippet 到 IDE)、SPM Map 刷新、Embed (重建索引) 等命令
3
+ * 执行 Module Map 刷新、Embed (重建索引) 等命令
4
4
  */
5
5
  declare const router: import("express-serve-static-core").Router;
6
6
  export default router;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Commands API 路由
3
- * 执行 Install (同步 Snippet 到 IDE)、SPM Map 刷新、Embed (重建索引) 等命令
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, snippetFactory, snippetInstaller
5
+ * - recipeParser, recipeCandidateValidator
6
6
  * - qualityScorer, feedbackCollector, tokenUsageStore, recipeExtractor
7
- * - spmService, automationOrchestrator, moduleService
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, snippetFactory, snippetInstaller
5
+ * - recipeParser, recipeCandidateValidator
6
6
  * - qualityScorer, feedbackCollector, tokenUsageStore, recipeExtractor
7
- * - spmService, automationOrchestrator, moduleService
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
- // ═══ Snippet ═══
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
- return new GuardCheckEngine(ct.get('database'), { guardConfig: config.guard || {} });
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: this._guardConfig.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 Header 路径解析 + moduleName 注入
370
- try {
371
- const PathFinder = await import('../../platform/ios/spm/PathFinder.js');
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 });
@@ -416,7 +416,7 @@ export class SearchEngine {
416
416
  qualityScore: meta.qualityScore || 0,
417
417
  };
418
418
  });
419
- // 为每个结果补充 content(NativeUI 预览需要)— 批量 IN 查询替代 N+1
419
+ // 为每个结果补充 content(预览需要)— 批量 IN 查询替代 N+1
420
420
  this._supplementDetails(items);
421
421
  return items;
422
422
  }
@@ -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(), z.number().int().min(0)).default({}),
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),
@@ -4,7 +4,7 @@
4
4
  * 用途:自动化发布前检查和发布流程
5
5
  * 使用:node scripts/release.js [patch|minor|major]
6
6
  */
7
- import { DASHBOARD_DIR, PACKAGE_ROOT, RESOURCES_DIR } from '../lib/shared/package-root.js';
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
- const nativeUI = path.join(RESOURCES_DIR, 'native-ui/native-ui');
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() {