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
@@ -1,371 +0,0 @@
1
- /**
2
- * SPM API 路由 — 向后兼容层
3
- *
4
- * 所有端点统一委派到 ModuleService(语言无关模块扫描服务)。
5
- * SPM Discoverer 作为 ModuleService 的一个 discoverer 自动匹配 Swift/SPM 项目。
6
- * 新代码应直接使用 /api/v1/modules/* 端点。
7
- */
8
- import express from 'express';
9
- import { createStreamSession, getStreamSession } from '#http/utils/sse-sessions.js';
10
- import Logger from '#infra/logging/Logger.js';
11
- import { getServiceContainer } from '#inject/ServiceContainer.js';
12
- import { ValidationError } from '#shared/errors/index.js';
13
- const router = express.Router();
14
- const logger = Logger.getInstance();
15
- /** 获取 moduleService 并确保已加载 */
16
- async function getModuleService() {
17
- const container = getServiceContainer();
18
- const moduleService = container.get('moduleService');
19
- await moduleService.load();
20
- return moduleService;
21
- }
22
- /** GET /api/v1/spm/targets */
23
- router.get('/targets', async (req, res) => {
24
- const moduleService = await getModuleService();
25
- const targets = await moduleService.listTargets();
26
- res.json({
27
- success: true,
28
- data: { targets, total: targets.length },
29
- });
30
- });
31
- /** GET /api/v1/spm/dep-graph */
32
- router.get('/dep-graph', async (req, res) => {
33
- const moduleService = await getModuleService();
34
- const level = String(req.query.level || 'package');
35
- const _graphBase = await moduleService.getDependencyGraph({ level });
36
- const graph = _graphBase;
37
- if (!graph || (!graph.nodes && !graph.packages)) {
38
- res.json({
39
- success: true,
40
- data: { nodes: [], edges: [], projectRoot: null },
41
- });
42
- return;
43
- }
44
- // 标准化为 { nodes, edges } 格式
45
- let nodes = [];
46
- let edges = [];
47
- if (graph.nodes && graph.edges) {
48
- // 已经是标准格式
49
- nodes = graph.nodes;
50
- edges = graph.edges;
51
- }
52
- else if (graph.packages) {
53
- // 从 packages 构建图
54
- if (level === 'target') {
55
- for (const [pkgName, pkgInfo] of Object.entries(graph.packages)) {
56
- const targetsInfo = pkgInfo?.targetsInfo || {};
57
- for (const [targetName, info] of Object.entries(targetsInfo)) {
58
- const id = `${pkgName}::${targetName}`;
59
- nodes.push({
60
- id,
61
- label: targetName,
62
- type: 'target',
63
- packageName: pkgName,
64
- });
65
- for (const d of info
66
- ?.dependencies || []) {
67
- if (!d?.name) {
68
- continue;
69
- }
70
- const depPkg = d?.package || pkgName;
71
- edges.push({ from: id, to: `${depPkg}::${d.name}`, source: 'base' });
72
- }
73
- }
74
- }
75
- }
76
- else {
77
- const pkgs = graph.packages;
78
- nodes = Object.keys(pkgs).map((id) => ({
79
- id,
80
- label: id,
81
- type: 'package',
82
- packageDir: pkgs[id]?.packageDir,
83
- targets: pkgs[id]?.targets,
84
- }));
85
- for (const [from, tos] of Object.entries(graph.edges || {})) {
86
- for (const to of tos || []) {
87
- edges.push({ from, to, source: 'base' });
88
- }
89
- }
90
- }
91
- }
92
- res.json({
93
- success: true,
94
- data: {
95
- nodes,
96
- edges,
97
- projectRoot: graph.projectRoot || null,
98
- generatedAt: graph.generatedAt || null,
99
- },
100
- });
101
- });
102
- /**
103
- * POST /api/v1/spm/target-files
104
- * 获取 Target 的文件列表
105
- */
106
- router.post('/target-files', async (req, res) => {
107
- const { target, targetName } = req.body;
108
- if (!target && !targetName) {
109
- throw new ValidationError('target object or targetName is required');
110
- }
111
- const moduleService = await getModuleService();
112
- let resolvedTarget = target;
113
- if (!resolvedTarget && targetName) {
114
- const targets = await moduleService.listTargets();
115
- resolvedTarget = targets.find((t) => t.name === targetName);
116
- if (!resolvedTarget) {
117
- res.status(404).json({
118
- success: false,
119
- error: { code: 'NOT_FOUND', message: `Target not found: ${targetName}` },
120
- });
121
- return;
122
- }
123
- }
124
- const files = await moduleService.getTargetFiles(resolvedTarget);
125
- res.json({
126
- success: true,
127
- data: {
128
- target: resolvedTarget.name || targetName,
129
- files,
130
- total: files.length,
131
- },
132
- });
133
- });
134
- /**
135
- * POST /api/v1/spm/scan
136
- * AI 扫描 Target,发现候选项
137
- */
138
- router.post('/scan', async (req, res) => {
139
- const { target, targetName, options = {} } = req.body;
140
- if (!target && !targetName) {
141
- throw new ValidationError('target object or targetName is required');
142
- }
143
- const moduleService = await getModuleService();
144
- let resolvedTarget = target;
145
- if (!resolvedTarget && targetName) {
146
- const targets = await moduleService.listTargets();
147
- resolvedTarget = targets.find((t) => t.name === targetName);
148
- if (!resolvedTarget) {
149
- res.status(404).json({
150
- success: false,
151
- error: { code: 'NOT_FOUND', message: `Target not found: ${targetName}` },
152
- });
153
- return;
154
- }
155
- }
156
- logger.info('Module scan started via /spm/', { target: resolvedTarget.name });
157
- const result = await moduleService.scanTarget(resolvedTarget, options);
158
- res.json({
159
- success: true,
160
- data: result,
161
- });
162
- });
163
- // ── 流式 Target 扫描(SSE Session + EventSource 架构) ─────────
164
- /**
165
- * POST /api/v1/spm/scan/stream
166
- * 创建流式扫描会话,后台异步执行 AI 扫描
167
- *
168
- * 协议事件(通过 SSE session 缓冲 + EventSource 交付):
169
- * scan:started — 扫描启动
170
- * scan:files-loaded — 文件列表就绪,含 files[] + count
171
- * scan:reading — 读取文件内容中
172
- * scan:ai-extracting — AI 提取开始(耗时阶段)
173
- * scan:enriching — 后处理阶段
174
- * scan:completed — 最终结果 {recipes, scannedFiles, recipeCount, fileCount}
175
- * scan:error — 发生错误
176
- * stream:done — 会话结束标记
177
- */
178
- router.post('/scan/stream', async (req, res) => {
179
- const { target, targetName, options = {} } = req.body;
180
- if (!target && !targetName) {
181
- throw new ValidationError('target object or targetName is required');
182
- }
183
- const moduleService = await getModuleService();
184
- let resolvedTarget = target;
185
- if (!resolvedTarget && targetName) {
186
- const targets = await moduleService.listTargets();
187
- resolvedTarget = targets.find((t) => t.name === targetName);
188
- if (!resolvedTarget) {
189
- res.status(404).json({
190
- success: false,
191
- error: { code: 'NOT_FOUND', message: `Target not found: ${targetName}` },
192
- });
193
- return;
194
- }
195
- }
196
- // 创建 SSE session
197
- const session = createStreamSession('scan');
198
- const tName = resolvedTarget.name || targetName;
199
- // 立即返回 sessionId
200
- res.json({ sessionId: session.sessionId });
201
- // 异步执行扫描,通过 session 推送进度事件
202
- setImmediate(async () => {
203
- try {
204
- logger.info('Module stream scan started via /spm/', {
205
- target: tName,
206
- sessionId: session.sessionId,
207
- });
208
- const result = await moduleService.scanTarget(resolvedTarget, {
209
- ...options,
210
- onProgress(event) {
211
- session.send(event);
212
- },
213
- });
214
- // 发送最终结果
215
- session.send({
216
- type: 'scan:result',
217
- recipes: result.recipes || [],
218
- scannedFiles: result.scannedFiles || [],
219
- message: result.message || '',
220
- recipeCount: (result.recipes || []).length,
221
- fileCount: (result.scannedFiles || []).length,
222
- });
223
- session.end();
224
- }
225
- catch (err) {
226
- const errMsg = err instanceof Error ? err.message : String(err);
227
- logger.error('Module stream scan failed via /spm/', { target: tName, error: errMsg });
228
- session.error(errMsg, 'SCAN_ERROR');
229
- }
230
- });
231
- });
232
- /**
233
- * GET /api/v1/spm/scan/events/:sessionId
234
- * EventSource SSE 端点 — 消费扫描进度事件
235
- *
236
- * 复用 chat/events 相同的 SSE 交付模式:回放缓冲 → 订阅实时 → 心跳保活
237
- */
238
- router.get('/scan/events/:sessionId', (req, res) => {
239
- const session = getStreamSession(req.params.sessionId);
240
- if (!session) {
241
- res.status(404).json({ success: false, error: 'Session not found or expired' });
242
- return;
243
- }
244
- // ─── SSE Headers ───
245
- res.setHeader('Content-Type', 'text/event-stream');
246
- res.setHeader('Cache-Control', 'no-cache');
247
- res.setHeader('Connection', 'keep-alive');
248
- res.setHeader('X-Accel-Buffering', 'no');
249
- res.flushHeaders();
250
- if (res.socket) {
251
- res.socket.setNoDelay(true);
252
- res.socket.setTimeout(0);
253
- }
254
- function writeEvent(event) {
255
- if (res.writableEnded) {
256
- return;
257
- }
258
- res.write(`data: ${JSON.stringify(event)}\n\n`);
259
- }
260
- // 1) 回放缓冲区
261
- let isDone = false;
262
- for (const event of session.buffer) {
263
- writeEvent(event);
264
- if (event.type === 'stream:done' || event.type === 'stream:error') {
265
- isDone = true;
266
- }
267
- }
268
- if (isDone || session.completed) {
269
- res.end();
270
- return;
271
- }
272
- // 2) 订阅实时事件
273
- const unsubscribe = session.on((event) => {
274
- writeEvent(event);
275
- if (event.type === 'stream:done' || event.type === 'stream:error') {
276
- unsubscribe();
277
- clearInterval(heartbeat);
278
- res.end();
279
- }
280
- });
281
- // 心跳保活 (每 15 秒)
282
- const heartbeat = setInterval(() => {
283
- if (res.writableEnded) {
284
- clearInterval(heartbeat);
285
- return;
286
- }
287
- res.write(`: ping ${Date.now()}\n\n`);
288
- }, 15_000);
289
- // 客户端断开连接时清理
290
- res.on('close', () => {
291
- unsubscribe();
292
- clearInterval(heartbeat);
293
- });
294
- });
295
- /**
296
- * POST /api/v1/spm/scan-project
297
- * 全项目扫描:AI 提取候选 + Guard 审计
298
- */
299
- router.post('/scan-project', async (req, res) => {
300
- const { options = {} } = req.body;
301
- const moduleService = await getModuleService();
302
- logger.info('Full project scan started via /spm/');
303
- const result = await moduleService.scanProject(options);
304
- res.json({
305
- success: true,
306
- data: result,
307
- });
308
- });
309
- /**
310
- * POST /api/v1/spm/bootstrap
311
- * 冷启动:快速骨架 + 异步逐维度填充(v5)
312
- *
313
- * 执行策略:
314
- * ① 同步阶段: Phase 1-4(文件收集 + AST + SPM + Guard + 骨架响应)→ 立即返回
315
- * ② 异步阶段: Phase 5/5.5(逐维度提取 + Candidate/Skill 创建)→ 后台逐一执行
316
- * ③ 进度推送: 通过 Socket.io 实时推送每个维度的完成状态
317
- *
318
- * 前端立即获得骨架 + 任务清单,每个维度完成后通过 Socket.io 推送更新。
319
- */
320
- router.post('/bootstrap', async (req, res) => {
321
- const { maxFiles, skipGuard, contentMaxLines } = req.body || {};
322
- const container = getServiceContainer();
323
- const agentFactory = container.get('agentFactory');
324
- logger.info('Bootstrap cold start initiated (v5: async fill mode)');
325
- // ── 同步阶段: 快速执行 Phase 1-4 → 返回骨架 ──
326
- const bootstrapResult = await agentFactory.bootstrapKnowledge({
327
- maxFiles: maxFiles || 500,
328
- skipGuard: skipGuard || false,
329
- contentMaxLines: contentMaxLines || 120,
330
- loadSkills: true,
331
- });
332
- // 立即返回骨架结果给前端
333
- res.json({
334
- success: true,
335
- data: {
336
- ...bootstrapResult,
337
- asyncFill: true, // 告知前端:内容正在异步填充中
338
- },
339
- });
340
- // 注意:Phase 5/5.5 异步填充已在 bootstrapKnowledge() 内部通过 setImmediate 启动
341
- // 进度通过 BootstrapTaskManager → Socket.io 推送到前端
342
- });
343
- /**
344
- * GET /api/v1/spm/bootstrap/status
345
- * 查询当前 bootstrap 异步填充进度
346
- *
347
- * 返回当前 session 的任务状态列表,供前端轮询(Socket.io 不可用时的 fallback)
348
- */
349
- router.get('/bootstrap/status', async (req, res) => {
350
- const container = getServiceContainer();
351
- // 从容器获取 BootstrapTaskManager(正式 DI 注册)
352
- let taskManager = null;
353
- try {
354
- taskManager = container.get('bootstrapTaskManager');
355
- }
356
- catch {
357
- /* not registered */
358
- }
359
- if (!taskManager) {
360
- res.json({
361
- success: true,
362
- data: { status: 'idle', message: 'No bootstrap task manager initialized' },
363
- });
364
- return;
365
- }
366
- res.json({
367
- success: true,
368
- data: taskManager.getSessionStatus(),
369
- });
370
- });
371
- export default router;
@@ -1,21 +0,0 @@
1
- /**
2
- * PlaceholderConverter — Xcode <#…#> ↔ VSCode ${N:…} 双向占位符转换
3
- *
4
- * 转换规则:
5
- * Xcode → VSCode:
6
- * <#name#> → ${1:name} (序号自动递增)
7
- * <#T##Type#> → ${1:Type} (取最后一段)
8
- * <#T##Label##Type#> → ${1:Label} (取 Label 段)
9
- *
10
- * VSCode → Xcode:
11
- * ${1:name} → <#name#>
12
- * ${1} → <#value#>
13
- * $1 → <#value#>
14
- * $0 → (移除,Xcode 无终止光标)
15
- */
16
- export declare class PlaceholderConverter {
17
- /** Xcode → VSCode 占位符转换 */
18
- static xcodeToVSCode(code: string): string;
19
- /** VSCode → Xcode 占位符转换 */
20
- static vscodeToXcode(code: string): string;
21
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * PlaceholderConverter — Xcode <#…#> ↔ VSCode ${N:…} 双向占位符转换
3
- *
4
- * 转换规则:
5
- * Xcode → VSCode:
6
- * <#name#> → ${1:name} (序号自动递增)
7
- * <#T##Type#> → ${1:Type} (取最后一段)
8
- * <#T##Label##Type#> → ${1:Label} (取 Label 段)
9
- *
10
- * VSCode → Xcode:
11
- * ${1:name} → <#name#>
12
- * ${1} → <#value#>
13
- * $1 → <#value#>
14
- * $0 → (移除,Xcode 无终止光标)
15
- */
16
- export class PlaceholderConverter {
17
- /** Xcode → VSCode 占位符转换 */
18
- static xcodeToVSCode(code) {
19
- if (!code) {
20
- return '';
21
- }
22
- let index = 0;
23
- return code.replace(/<#(.*?)#>/g, (_match, inner) => {
24
- index++;
25
- // <#T##Label##Type#> → Label (parts[1])
26
- // <#T##Type#> → Type (parts[1])
27
- // <#name#> → name (inner)
28
- const parts = inner.split('##');
29
- const label = parts.length >= 2 ? parts[1] : inner;
30
- return `\${${index}:${label}}`;
31
- });
32
- }
33
- /** VSCode → Xcode 占位符转换 */
34
- static vscodeToXcode(code) {
35
- if (!code) {
36
- return '';
37
- }
38
- return (code
39
- // ${1:name} → <#name#>
40
- .replace(/\$\{(\d+):([^}]*)}/g, (_m, _n, label) => `<#${label}#>`)
41
- // ${1} → <#value#>
42
- .replace(/\$\{(\d+)}/g, '<#value#>')
43
- // $0 → remove (Xcode has no final cursor)
44
- .replace(/\$0/g, '')
45
- // $1..$9 → <#value#>
46
- .replace(/\$([1-9]\d*)/g, '<#value#>'));
47
- }
48
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * XcodeCodec — Xcode .codesnippet (plist XML) 生成器
3
- *
4
- * 从原 SnippetFactory 提取的 Xcode 专用逻辑:
5
- * - XML plist 模板
6
- * - Xcode 语言 ID 映射
7
- * - XML 转义
8
- */
9
- import { SnippetCodec, type SnippetSpec } from '#service/snippet/codecs/SnippetCodec.js';
10
- export declare class XcodeCodec extends SnippetCodec {
11
- get id(): string;
12
- get fileExtension(): string;
13
- /** SnippetSpec → plist XML 字符串 */
14
- generate(spec: SnippetSpec): string;
15
- /** Xcode: 每个 snippet 一个文件 → 返回 Array<{ filename, content }> */
16
- generateBundle(specs: SnippetSpec[]): Array<{
17
- filename: string;
18
- content: string;
19
- }>;
20
- /** Xcode snippets 全局目录 (macOS only) */
21
- getInstallDir(_projectRoot: string | undefined): string;
22
- mapLanguage(lang: string | undefined): string;
23
- }
@@ -1,96 +0,0 @@
1
- /**
2
- * XcodeCodec — Xcode .codesnippet (plist XML) 生成器
3
- *
4
- * 从原 SnippetFactory 提取的 Xcode 专用逻辑:
5
- * - XML plist 模板
6
- * - Xcode 语言 ID 映射
7
- * - XML 转义
8
- */
9
- import { homedir } from 'node:os';
10
- import { join } from 'node:path';
11
- import { SnippetCodec } from '#service/snippet/codecs/SnippetCodec.js';
12
- const XCODE_LANGUAGE_MAP = {
13
- swift: 'Xcode.SourceCodeLanguage.Swift',
14
- 'objective-c': 'Xcode.SourceCodeLanguage.Objective-C',
15
- objc: 'Xcode.SourceCodeLanguage.Objective-C',
16
- c: 'Xcode.SourceCodeLanguage.C',
17
- 'c++': 'Xcode.SourceCodeLanguage.C-Plus-Plus',
18
- javascript: 'Xcode.SourceCodeLanguage.JavaScript',
19
- };
20
- const PLIST_TEMPLATE = `<?xml version="1.0" encoding="UTF-8"?>
21
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
22
- <plist version="1.0">
23
- <dict>
24
- \t<key>IDECodeSnippetCompletionPrefix</key>
25
- \t<string>{completion}</string>
26
- \t<key>IDECodeSnippetCompletionScopes</key>
27
- \t<array>
28
- \t\t<string>All</string>
29
- \t</array>
30
- \t<key>IDECodeSnippetContents</key>
31
- \t<string>{content}</string>
32
- \t<key>IDECodeSnippetIdentifier</key>
33
- \t<string>{identifier}</string>
34
- \t<key>IDECodeSnippetLanguage</key>
35
- \t<string>{language}</string>
36
- \t<key>IDECodeSnippetSummary</key>
37
- \t<string>{summary}</string>
38
- \t<key>IDECodeSnippetTitle</key>
39
- \t<string>{title}</string>
40
- \t<key>IDECodeSnippetUserSnippet</key>
41
- \t<true/>
42
- \t<key>IDECodeSnippetVersion</key>
43
- \t<integer>2</integer>
44
- </dict>
45
- </plist>`;
46
- export class XcodeCodec extends SnippetCodec {
47
- get id() {
48
- return 'xcode';
49
- }
50
- get fileExtension() {
51
- return '.codesnippet';
52
- }
53
- /** SnippetSpec → plist XML 字符串 */
54
- generate(spec) {
55
- if (!spec?.identifier || !spec?.code) {
56
- throw new Error('Snippet spec must have identifier and code');
57
- }
58
- const content = Array.isArray(spec.code) ? spec.code.join('\n') : spec.code;
59
- const languageKey = this.mapLanguage(spec.language);
60
- let xml = PLIST_TEMPLATE;
61
- xml = xml.replace('{identifier}', escapeXml(spec.identifier));
62
- xml = xml.replace('{title}', escapeXml(spec.title || spec.identifier));
63
- xml = xml.replace('{completion}', escapeXml(spec.completion || spec.identifier));
64
- xml = xml.replace('{summary}', escapeXml(spec.summary || ''));
65
- xml = xml.replace('{content}', escapeXml(content));
66
- xml = xml.replace('{language}', languageKey);
67
- return xml;
68
- }
69
- /** Xcode: 每个 snippet 一个文件 → 返回 Array<{ filename, content }> */
70
- generateBundle(specs) {
71
- return specs.map((spec) => ({
72
- filename: `${spec.identifier}${this.fileExtension}`,
73
- content: this.generate(spec),
74
- }));
75
- }
76
- /** Xcode snippets 全局目录 (macOS only) */
77
- getInstallDir(_projectRoot) {
78
- return join(homedir(), 'Library/Developer/Xcode/UserData/CodeSnippets');
79
- }
80
- mapLanguage(lang) {
81
- return (XCODE_LANGUAGE_MAP[lang?.toLowerCase() ?? ''] ||
82
- XCODE_LANGUAGE_MAP.swift);
83
- }
84
- }
85
- /** XML 特殊字符转义 */
86
- function escapeXml(str) {
87
- if (!str) {
88
- return '';
89
- }
90
- return String(str)
91
- .replace(/&/g, '&amp;')
92
- .replace(/</g, '&lt;')
93
- .replace(/>/g, '&gt;')
94
- .replace(/"/g, '&quot;')
95
- .replace(/'/g, '&apos;');
96
- }
@@ -1,56 +0,0 @@
1
- /**
2
- * DependencyGraph — SPM 依赖图构建与分析
3
- * 合并 V1 DepGraphService + DepGraphAnalyzer
4
- * 构建 target 级依赖 DAG,支持层级计算、拓扑排序、可达性检查
5
- */
6
- export declare class DependencyGraph {
7
- #private;
8
- constructor();
9
- /**
10
- * 从 PackageSwiftParser 的解析结果构建图
11
- * @param parsed
12
- */
13
- buildFromParsed(parsed: {
14
- targets: {
15
- name: string;
16
- dependencies: string[];
17
- }[];
18
- }): void;
19
- /** 添加节点 */
20
- addNode(name: string): void;
21
- /** 添加边: from 依赖 to */
22
- addEdge(from: string, to: string): void;
23
- /** BFS 可达性检查 */
24
- isReachable(from: string, to: string): boolean;
25
- /**
26
- * 检测循环依赖
27
- * @returns 循环路径列表
28
- */
29
- detectCycles(): string[][];
30
- /**
31
- * 拓扑排序 (Kahn's algorithm)
32
- * @returns 若有环则返回部分结果
33
- */
34
- topologicalSort(): string[];
35
- /**
36
- * 层级计算: L0 = 无依赖的节点, L1 = 只依赖 L0, etc.
37
- * @returns node → level
38
- */
39
- computeLevels(): Map<any, any>;
40
- /** 获取节点的直接依赖 */
41
- getDependencies(node: string): string[];
42
- /** 获取节点的直接依赖者 (谁依赖了这个节点) */
43
- getDependents(node: string): string[];
44
- /** 获取所有节点 */
45
- getNodes(): string[];
46
- edgeCount(): number;
47
- clear(): void;
48
- /** 导出为 JSON (可视化用) */
49
- toJSON(): {
50
- nodes: string[];
51
- edges: {
52
- from: string;
53
- to: string;
54
- }[];
55
- };
56
- }