autosnippet 3.0.13 → 3.1.1

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 (100) hide show
  1. package/bin/api-server.js +2 -0
  2. package/bin/cli.js +24 -19
  3. package/config/default.json +1 -1
  4. package/lib/bootstrap.js +4 -4
  5. package/lib/cli/SetupService.js +29 -29
  6. package/lib/cli/UpgradeService.js +3 -2
  7. package/lib/core/AstAnalyzer.js +1 -1
  8. package/lib/core/ast/ensure-grammars.js +1 -1
  9. package/lib/core/ast/index.js +62 -11
  10. package/lib/core/ast/lang-dart.js +27 -21
  11. package/lib/core/ast/lang-go.js +6 -20
  12. package/lib/core/ast/lang-rust.js +53 -28
  13. package/lib/core/ast/parser-init.js +9 -5
  14. package/lib/core/discovery/DartDiscoverer.js +4 -10
  15. package/lib/core/discovery/GoDiscoverer.js +45 -25
  16. package/lib/core/discovery/NodeDiscoverer.js +1 -3
  17. package/lib/core/discovery/PythonDiscoverer.js +7 -1
  18. package/lib/core/discovery/RustDiscoverer.js +111 -38
  19. package/lib/core/discovery/index.js +2 -2
  20. package/lib/core/enhancement/django-enhancement.js +10 -4
  21. package/lib/core/enhancement/fastapi-enhancement.js +16 -9
  22. package/lib/core/enhancement/go-grpc-enhancement.js +2 -1
  23. package/lib/core/enhancement/go-web-enhancement.js +3 -6
  24. package/lib/core/enhancement/ml-enhancement.js +6 -3
  25. package/lib/core/enhancement/nextjs-enhancement.js +17 -7
  26. package/lib/core/enhancement/node-server-enhancement.js +4 -2
  27. package/lib/core/enhancement/react-enhancement.js +6 -3
  28. package/lib/core/enhancement/rust-tokio-enhancement.js +6 -2
  29. package/lib/core/enhancement/rust-web-enhancement.js +13 -7
  30. package/lib/core/enhancement/vue-enhancement.js +10 -5
  31. package/lib/external/ai/AiFactory.js +3 -1
  32. package/lib/external/ai/AiProvider.js +3 -1
  33. package/lib/external/mcp/McpServer.js +2 -0
  34. package/lib/external/mcp/handlers/bootstrap/base-dimensions.js +1 -2
  35. package/lib/external/mcp/handlers/bootstrap/pipeline/checkpoint.js +7 -1
  36. package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +55 -26
  37. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +8 -8
  38. package/lib/external/mcp/handlers/bootstrap/refine.js +3 -1
  39. package/lib/external/mcp/handlers/bootstrap.js +4 -10
  40. package/lib/external/mcp/handlers/browse.js +6 -2
  41. package/lib/external/mcp/handlers/guard.js +6 -2
  42. package/lib/external/mcp/handlers/skill.js +6 -2
  43. package/lib/http/HttpServer.js +1 -1
  44. package/lib/http/routes/candidates.js +3 -1
  45. package/lib/http/routes/extract.js +4 -5
  46. package/lib/http/routes/guardRules.js +1 -1
  47. package/lib/http/routes/modules.js +9 -3
  48. package/lib/http/routes/skills.js +54 -6
  49. package/lib/http/routes/violations.js +4 -3
  50. package/lib/infrastructure/external/ClipboardManager.js +24 -7
  51. package/lib/infrastructure/external/NativeUi.js +3 -1
  52. package/lib/infrastructure/external/OpenBrowser.js +1 -0
  53. package/lib/infrastructure/external/XcodeAutomation.js +5 -5
  54. package/lib/infrastructure/vector/IndexingPipeline.js +14 -5
  55. package/lib/injection/ServiceContainer.js +34 -11
  56. package/lib/platform/ios/index.js +20 -25
  57. package/lib/platform/ios/routes/spm.js +6 -3
  58. package/lib/platform/ios/snippet/PlaceholderConverter.js +6 -2
  59. package/lib/platform/ios/snippet/XcodeCodec.js +4 -2
  60. package/lib/platform/ios/spm/SpmDiscoverer.js +1 -1
  61. package/lib/platform/ios/spm/SpmService.js +3 -1
  62. package/lib/platform/ios/xcode/XcodeIntegration.js +10 -12
  63. package/lib/platform/ios/xcode/XcodeWriteUtils.js +6 -1
  64. package/lib/service/automation/FileWatcher.js +1 -3
  65. package/lib/service/automation/handlers/CreateHandler.js +3 -5
  66. package/lib/service/automation/handlers/GuardHandler.js +11 -32
  67. package/lib/service/automation/handlers/SearchHandler.js +9 -9
  68. package/lib/service/chat/CandidateGuardrail.js +11 -6
  69. package/lib/service/chat/ChatAgent.js +31 -22
  70. package/lib/service/chat/HandoffProtocol.js +5 -2
  71. package/lib/service/chat/tools/composite.js +3 -2
  72. package/lib/service/chat/tools/index.js +60 -71
  73. package/lib/service/chat/tools/infrastructure.js +9 -4
  74. package/lib/service/chat/tools/lifecycle.js +22 -5
  75. package/lib/service/chat/tools/project-access.js +5 -9
  76. package/lib/service/chat/tools.js +1 -2
  77. package/lib/service/cursor/AgentInstructionsGenerator.js +33 -15
  78. package/lib/service/cursor/CursorDeliveryPipeline.js +2 -1
  79. package/lib/service/cursor/KnowledgeCompressor.js +16 -7
  80. package/lib/service/guard/ComplianceReporter.js +5 -2
  81. package/lib/service/guard/GuardCheckEngine.js +53 -26
  82. package/lib/service/guard/GuardCodeChecks.js +217 -188
  83. package/lib/service/guard/GuardCrossFileChecks.js +203 -184
  84. package/lib/service/guard/GuardPatternUtils.js +17 -10
  85. package/lib/service/module/ModuleService.js +180 -56
  86. package/lib/service/recipe/RecipeCandidateValidator.js +11 -8
  87. package/lib/service/snippet/SnippetFactory.js +3 -3
  88. package/lib/service/snippet/SnippetInstaller.js +35 -11
  89. package/lib/service/snippet/codecs/VSCodeCodec.js +2 -2
  90. package/lib/service/wiki/WikiGenerator.js +67 -40
  91. package/lib/service/wiki/WikiRenderers.js +105 -80
  92. package/lib/service/wiki/WikiUtils.js +217 -80
  93. package/lib/shared/LanguageService.js +111 -53
  94. package/lib/shared/PathGuard.js +0 -8
  95. package/package.json +3 -9
  96. package/scripts/bench-real-projects.mjs +29 -29
  97. package/scripts/generate-recipe-drafts.js +17 -27
  98. package/scripts/init-snippets.js +43 -24
  99. package/scripts/install-vscode-copilot.js +3 -19
  100. package/scripts/setup-mcp-config.js +0 -4
@@ -26,6 +26,7 @@ const TRIGGER_SNIPPETS = [
26
26
  title: 'AutoSnippet: Search (Long)',
27
27
  summary: 'Search and insert Recipe/Snippet from knowledge base',
28
28
  xcodeContent: '// as:search <#keyword#>',
29
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: VSCode snippet placeholder syntax
29
30
  vscodeBody: ['// as:search ${1:keyword}'],
30
31
  },
31
32
  {
@@ -34,6 +35,7 @@ const TRIGGER_SNIPPETS = [
34
35
  title: 'AutoSnippet: Create Recipe',
35
36
  summary: 'Create new Recipe (Dashboard or clipboard/file)',
36
37
  xcodeContent: '// as:create <#-c or -f#>',
38
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: VSCode snippet placeholder syntax
37
39
  vscodeBody: ['// as:create ${1:-c or -f}'],
38
40
  },
39
41
  {
@@ -42,6 +44,7 @@ const TRIGGER_SNIPPETS = [
42
44
  title: 'AutoSnippet: Audit Code',
43
45
  summary: 'AI code review against knowledge base',
44
46
  xcodeContent: '// as:audit <#keyword or scope (file/target/project)#>',
47
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: VSCode snippet placeholder syntax
45
48
  vscodeBody: ['// as:audit ${1:keyword or scope (file/target/project)}'],
46
49
  },
47
50
  ];
@@ -54,7 +57,9 @@ class XcodeInitializer {
54
57
  }
55
58
 
56
59
  isAvailable() {
57
- if (process.platform !== 'darwin') return false;
60
+ if (process.platform !== 'darwin') {
61
+ return false;
62
+ }
58
63
  try {
59
64
  execSync('xcode-select -p', { stdio: 'ignore' });
60
65
  return true;
@@ -76,7 +81,7 @@ class XcodeInitializer {
76
81
  }
77
82
 
78
83
  generatePlist(snippet) {
79
- const escape = (s) =>
84
+ const escapeXml = (s) =>
80
85
  String(s || '')
81
86
  .replace(/&/g, '&amp;')
82
87
  .replace(/</g, '&lt;')
@@ -89,21 +94,21 @@ class XcodeInitializer {
89
94
  <plist version="1.0">
90
95
  <dict>
91
96
  <key>IDECodeSnippetCompletionPrefix</key>
92
- <string>${escape(snippet.shortcut)}</string>
97
+ <string>${escapeXml(snippet.shortcut)}</string>
93
98
  <key>IDECodeSnippetCompletionScopes</key>
94
99
  <array>
95
100
  <string>All</string>
96
101
  </array>
97
102
  <key>IDECodeSnippetContents</key>
98
- <string>${escape(snippet.xcodeContent)}</string>
103
+ <string>${escapeXml(snippet.xcodeContent)}</string>
99
104
  <key>IDECodeSnippetIdentifier</key>
100
- <string>${escape(snippet.id)}</string>
105
+ <string>${escapeXml(snippet.id)}</string>
101
106
  <key>IDECodeSnippetLanguage</key>
102
107
  <string>Xcode.SourceCodeLanguage.Generic</string>
103
108
  <key>IDECodeSnippetSummary</key>
104
- <string>${escape(snippet.summary)}</string>
109
+ <string>${escapeXml(snippet.summary)}</string>
105
110
  <key>IDECodeSnippetTitle</key>
106
- <string>${escape(snippet.title)}</string>
111
+ <string>${escapeXml(snippet.title)}</string>
107
112
  <key>IDECodeSnippetUserSnippet</key>
108
113
  <true/>
109
114
  <key>IDECodeSnippetVersion</key>
@@ -113,8 +118,12 @@ class XcodeInitializer {
113
118
  }
114
119
 
115
120
  init() {
116
- if (!this.isAvailable()) return { skipped: true, reason: 'Xcode not available' };
117
- if (!this.ensureDir()) return { skipped: true, reason: 'Cannot create snippets dir' };
121
+ if (!this.isAvailable()) {
122
+ return { skipped: true, reason: 'Xcode not available' };
123
+ }
124
+ if (!this.ensureDir()) {
125
+ return { skipped: true, reason: 'Cannot create snippets dir' };
126
+ }
118
127
 
119
128
  let count = 0;
120
129
  for (const snippet of TRIGGER_SNIPPETS) {
@@ -126,7 +135,9 @@ class XcodeInitializer {
126
135
  }
127
136
 
128
137
  list() {
129
- if (!fs.existsSync(this.snippetsDir)) return [];
138
+ if (!fs.existsSync(this.snippetsDir)) {
139
+ return [];
140
+ }
130
141
  return fs
131
142
  .readdirSync(this.snippetsDir)
132
143
  .filter((f) => f.startsWith('com.autosnippet') && f.endsWith('.codesnippet'));
@@ -174,7 +185,9 @@ class VSCodeInitializer {
174
185
  }
175
186
 
176
187
  init() {
177
- if (!this.ensureDir()) return { skipped: true, reason: 'Cannot create .vscode dir' };
188
+ if (!this.ensureDir()) {
189
+ return { skipped: true, reason: 'Cannot create .vscode dir' };
190
+ }
178
191
 
179
192
  const bundle = {};
180
193
  for (const snippet of TRIGGER_SNIPPETS) {
@@ -186,13 +199,15 @@ class VSCodeInitializer {
186
199
  }
187
200
 
188
201
  const filePath = path.join(this.vscodeDir, this.filename);
189
- fs.writeFileSync(filePath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
202
+ fs.writeFileSync(filePath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
190
203
  return { success: true, count: TRIGGER_SNIPPETS.length, path: filePath };
191
204
  }
192
205
 
193
206
  list() {
194
207
  const filePath = path.join(this.vscodeDir, this.filename);
195
- if (!fs.existsSync(filePath)) return [];
208
+ if (!fs.existsSync(filePath)) {
209
+ return [];
210
+ }
196
211
  try {
197
212
  const content = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
198
213
  return Object.keys(content);
@@ -239,15 +254,23 @@ export class SnippetInitializer {
239
254
 
240
255
  list(target = 'all') {
241
256
  const result = {};
242
- if (target === 'all' || target === 'xcode') result.xcode = this.xcode.list();
243
- if (target === 'all' || target === 'vscode') result.vscode = this.vscode.list();
257
+ if (target === 'all' || target === 'xcode') {
258
+ result.xcode = this.xcode.list();
259
+ }
260
+ if (target === 'all' || target === 'vscode') {
261
+ result.vscode = this.vscode.list();
262
+ }
244
263
  return result;
245
264
  }
246
265
 
247
266
  remove(target = 'all') {
248
267
  const result = {};
249
- if (target === 'all' || target === 'xcode') result.xcode = this.xcode.remove();
250
- if (target === 'all' || target === 'vscode') result.vscode = this.vscode.remove();
268
+ if (target === 'all' || target === 'xcode') {
269
+ result.xcode = this.xcode.remove();
270
+ }
271
+ if (target === 'all' || target === 'vscode') {
272
+ result.vscode = this.vscode.remove();
273
+ }
251
274
  return result;
252
275
  }
253
276
  }
@@ -273,22 +296,18 @@ async function main() {
273
296
 
274
297
  switch (command) {
275
298
  case 'init': {
276
- const result = await init.initialize(target);
277
- console.log('✅ Snippets initialized:', JSON.stringify(result, null, 2));
299
+ const _result = await init.initialize(target);
278
300
  break;
279
301
  }
280
302
  case 'list': {
281
- const result = init.list(target);
282
- console.log('📋 Installed snippets:', JSON.stringify(result, null, 2));
303
+ const _result = init.list(target);
283
304
  break;
284
305
  }
285
306
  case 'remove': {
286
- const result = init.remove(target);
287
- console.log('🗑️ Snippets removed:', JSON.stringify(result, null, 2));
307
+ const _result = init.remove(target);
288
308
  break;
289
309
  }
290
310
  case 'help':
291
- console.log(`Usage: init-snippets.js [init|list|remove] [--target=xcode|vscode|all]`);
292
311
  break;
293
312
  default:
294
313
  console.error(`Unknown command: ${command}`);
@@ -30,7 +30,6 @@ const __dirname = dirname(__filename);
30
30
 
31
31
  import fs from 'node:fs';
32
32
  import { createRequire } from 'node:module';
33
- import os from 'node:os';
34
33
  import path from 'node:path';
35
34
 
36
35
  const require = createRequire(import.meta.url);
@@ -46,7 +45,6 @@ const isAutoSnippetRepo =
46
45
 
47
46
  // 默认只做工作区配置,不做全局配置
48
47
  // 如果在 AutoSnippet 仓库内执行且未明确指定 --path,跳过所有配置
49
- const configGlobal = args.global && !isAutoSnippetRepo;
50
48
  const configWorkspace = !args.global && !isAutoSnippetRepo && (args.path || !isAutoSnippetRepo);
51
49
  const skipVerify = args['skip-verify'];
52
50
  const isQuiet = args.quiet || process.env.ASD_QUIET === 'true';
@@ -71,22 +69,6 @@ function error(msg) {
71
69
 
72
70
  // ============ 助手函数 ============
73
71
 
74
- function getVSCodeSettingsPath(isGlobal = true) {
75
- const platform = os.platform();
76
-
77
- if (isGlobal) {
78
- if (platform === 'darwin') {
79
- return path.join(os.homedir(), 'Library/Application Support/Code/User/settings.json');
80
- } else if (platform === 'win32') {
81
- return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Code/User/settings.json');
82
- } else {
83
- return path.join(os.homedir(), '.config/Code/User/settings.json');
84
- }
85
- } else {
86
- return path.join(projectPath, '.vscode/settings.json');
87
- }
88
- }
89
-
90
72
  function readJsonFile(filePath, defaultValue = {}) {
91
73
  if (!fs.existsSync(filePath)) {
92
74
  return defaultValue;
@@ -154,7 +136,9 @@ function configureVSCodeSettings() {
154
136
  if (fs.existsSync(mcpConfigPath)) {
155
137
  try {
156
138
  config = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
157
- } catch { /* ignore */ }
139
+ } catch {
140
+ /* ignore */
141
+ }
158
142
  }
159
143
 
160
144
  if (!config.servers) {
@@ -10,7 +10,6 @@
10
10
 
11
11
  import fs from 'node:fs';
12
12
  import { createRequire } from 'node:module';
13
- import os from 'node:os';
14
13
  import path from 'node:path';
15
14
 
16
15
  const require = createRequire(import.meta.url);
@@ -50,8 +49,6 @@ if (!fs.existsSync(mcpServerPath)) {
50
49
 
51
50
  // ============ 编辑器配置 ============
52
51
 
53
- let settingsPath; // 全局声明,供后面使用
54
-
55
52
  if (isVSCode) {
56
53
  configureVSCode();
57
54
  } else if (isCursor) {
@@ -105,7 +102,6 @@ function configureVSCode() {
105
102
  }
106
103
  process.exit(1);
107
104
  }
108
-
109
105
  }
110
106
 
111
107
  function configureCursor() {