autosnippet 3.0.0 → 3.0.2

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 (290) hide show
  1. package/README.md +230 -324
  2. package/bin/api-server.js +1 -1
  3. package/bin/cli.js +204 -244
  4. package/bin/mcp-server.js +5 -3
  5. package/config/knowledge-base.config.js +132 -132
  6. package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
  7. package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
  8. package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
  9. package/dashboard/dist/index.html +3 -3
  10. package/lib/bootstrap.js +8 -8
  11. package/lib/cli/AiScanService.js +86 -40
  12. package/lib/cli/KnowledgeSyncService.js +113 -74
  13. package/lib/cli/SetupService.js +439 -277
  14. package/lib/cli/UpgradeService.js +63 -100
  15. package/lib/core/AstAnalyzer.js +276 -597
  16. package/lib/core/ast/ProjectGraph.js +101 -40
  17. package/lib/core/ast/ensure-grammars.js +232 -0
  18. package/lib/core/ast/index.js +115 -0
  19. package/lib/core/ast/lang-dart.js +661 -0
  20. package/lib/core/ast/lang-go.js +530 -0
  21. package/lib/core/ast/lang-java.js +435 -0
  22. package/lib/core/ast/lang-javascript.js +272 -0
  23. package/lib/core/ast/lang-kotlin.js +423 -0
  24. package/lib/core/ast/lang-objc.js +388 -0
  25. package/lib/core/ast/lang-python.js +371 -0
  26. package/lib/core/ast/lang-swift.js +337 -0
  27. package/lib/core/ast/lang-typescript.js +503 -0
  28. package/lib/core/capability/CapabilityProbe.js +18 -9
  29. package/lib/core/constitution/Constitution.js +2 -3
  30. package/lib/core/constitution/ConstitutionValidator.js +65 -24
  31. package/lib/core/discovery/DartDiscoverer.js +534 -0
  32. package/lib/core/discovery/DiscovererRegistry.js +83 -0
  33. package/lib/core/discovery/GenericDiscoverer.js +225 -0
  34. package/lib/core/discovery/GoDiscoverer.js +541 -0
  35. package/lib/core/discovery/JvmDiscoverer.js +506 -0
  36. package/lib/core/discovery/NodeDiscoverer.js +466 -0
  37. package/lib/core/discovery/ProjectDiscoverer.js +93 -0
  38. package/lib/core/discovery/PythonDiscoverer.js +338 -0
  39. package/lib/core/discovery/SpmDiscoverer.js +5 -0
  40. package/lib/core/discovery/index.js +53 -0
  41. package/lib/core/enhancement/EnhancementPack.js +71 -0
  42. package/lib/core/enhancement/EnhancementRegistry.js +47 -0
  43. package/lib/core/enhancement/android-enhancement.js +102 -0
  44. package/lib/core/enhancement/django-enhancement.js +70 -0
  45. package/lib/core/enhancement/fastapi-enhancement.js +63 -0
  46. package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
  47. package/lib/core/enhancement/go-web-enhancement.js +201 -0
  48. package/lib/core/enhancement/index.js +65 -0
  49. package/lib/core/enhancement/node-server-enhancement.js +88 -0
  50. package/lib/core/enhancement/react-enhancement.js +86 -0
  51. package/lib/core/enhancement/spring-enhancement.js +112 -0
  52. package/lib/core/enhancement/vue-enhancement.js +96 -0
  53. package/lib/core/gateway/Gateway.js +8 -9
  54. package/lib/core/gateway/GatewayActionRegistry.js +1 -1
  55. package/lib/core/permission/PermissionManager.js +12 -8
  56. package/lib/domain/index.js +13 -9
  57. package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
  58. package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
  59. package/lib/domain/knowledge/Lifecycle.js +22 -22
  60. package/lib/domain/knowledge/index.js +9 -12
  61. package/lib/domain/knowledge/values/Constraints.js +31 -21
  62. package/lib/domain/knowledge/values/Content.js +21 -13
  63. package/lib/domain/knowledge/values/Quality.js +31 -18
  64. package/lib/domain/knowledge/values/Reasoning.js +20 -12
  65. package/lib/domain/knowledge/values/Relations.js +37 -25
  66. package/lib/domain/knowledge/values/Stats.js +18 -12
  67. package/lib/domain/knowledge/values/index.js +4 -3
  68. package/lib/domain/snippet/Snippet.js +35 -10
  69. package/lib/external/ai/AiFactory.js +48 -16
  70. package/lib/external/ai/AiProvider.js +184 -90
  71. package/lib/external/ai/providers/ClaudeProvider.js +25 -12
  72. package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
  73. package/lib/external/ai/providers/MockProvider.js +9 -3
  74. package/lib/external/ai/providers/OpenAiProvider.js +51 -29
  75. package/lib/external/mcp/McpServer.js +66 -36
  76. package/lib/external/mcp/errorHandler.js +23 -11
  77. package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
  78. package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
  79. package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
  80. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
  81. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
  82. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
  83. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
  84. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
  85. package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
  86. package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
  87. package/lib/external/mcp/handlers/bootstrap.js +691 -168
  88. package/lib/external/mcp/handlers/browse.js +66 -22
  89. package/lib/external/mcp/handlers/candidate.js +118 -35
  90. package/lib/external/mcp/handlers/consolidated.js +49 -17
  91. package/lib/external/mcp/handlers/guard.js +104 -39
  92. package/lib/external/mcp/handlers/knowledge.js +60 -36
  93. package/lib/external/mcp/handlers/search.js +43 -14
  94. package/lib/external/mcp/handlers/skill.js +120 -45
  95. package/lib/external/mcp/handlers/structure.js +240 -86
  96. package/lib/external/mcp/handlers/system.js +42 -12
  97. package/lib/external/mcp/handlers/wiki.js +58 -33
  98. package/lib/external/mcp/tools.js +306 -123
  99. package/lib/http/HttpServer.js +72 -47
  100. package/lib/http/middleware/RateLimiter.js +5 -3
  101. package/lib/http/middleware/errorHandler.js +6 -1
  102. package/lib/http/middleware/requestLogger.js +14 -3
  103. package/lib/http/middleware/roleResolver.js +30 -23
  104. package/lib/http/routes/ai.js +387 -265
  105. package/lib/http/routes/auth.js +81 -61
  106. package/lib/http/routes/candidates.js +430 -320
  107. package/lib/http/routes/commands.js +289 -189
  108. package/lib/http/routes/extract.js +158 -125
  109. package/lib/http/routes/guardRules.js +309 -217
  110. package/lib/http/routes/knowledge.js +213 -154
  111. package/lib/http/routes/modules.js +578 -0
  112. package/lib/http/routes/monitoring.js +6 -6
  113. package/lib/http/routes/recipes.js +104 -93
  114. package/lib/http/routes/search.js +361 -305
  115. package/lib/http/routes/skills.js +145 -98
  116. package/lib/http/routes/snippets.js +42 -30
  117. package/lib/http/routes/spm.js +3 -405
  118. package/lib/http/routes/violations.js +113 -93
  119. package/lib/http/routes/wiki.js +211 -170
  120. package/lib/http/utils/routeHelpers.js +3 -1
  121. package/lib/http/utils/sse-sessions.js +16 -6
  122. package/lib/http/utils/sse.js +15 -5
  123. package/lib/infrastructure/audit/AuditLogger.js +5 -2
  124. package/lib/infrastructure/audit/AuditStore.js +10 -7
  125. package/lib/infrastructure/cache/CacheService.js +3 -1
  126. package/lib/infrastructure/cache/GraphCache.js +8 -4
  127. package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
  128. package/lib/infrastructure/config/ConfigLoader.js +9 -5
  129. package/lib/infrastructure/config/Defaults.js +30 -10
  130. package/lib/infrastructure/config/Paths.js +28 -8
  131. package/lib/infrastructure/config/TriggerSymbol.js +22 -10
  132. package/lib/infrastructure/database/DatabaseConnection.js +15 -10
  133. package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
  134. package/lib/infrastructure/external/ClipboardManager.js +6 -2
  135. package/lib/infrastructure/external/NativeUi.js +50 -43
  136. package/lib/infrastructure/external/OpenBrowser.js +14 -17
  137. package/lib/infrastructure/external/XcodeAutomation.js +14 -258
  138. package/lib/infrastructure/logging/Logger.js +46 -30
  139. package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
  140. package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
  141. package/lib/infrastructure/paths/HeaderResolver.js +25 -9
  142. package/lib/infrastructure/paths/PathFinder.js +34 -12
  143. package/lib/infrastructure/plugin/PluginManager.js +26 -8
  144. package/lib/infrastructure/realtime/RealtimeService.js +2 -2
  145. package/lib/infrastructure/vector/Chunker.js +22 -7
  146. package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
  147. package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
  148. package/lib/infrastructure/vector/VectorStore.js +28 -10
  149. package/lib/injection/ServiceContainer.js +247 -93
  150. package/lib/platform/ios/index.js +63 -0
  151. package/lib/platform/ios/routes/spm.js +437 -0
  152. package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
  153. package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
  154. package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
  155. package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
  156. package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
  157. package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
  158. package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
  159. package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
  160. package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
  161. package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
  162. package/lib/repository/base/BaseRepository.js +7 -9
  163. package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
  164. package/lib/repository/token/TokenUsageStore.js +4 -2
  165. package/lib/service/automation/ActionPipeline.js +1 -1
  166. package/lib/service/automation/AutomationOrchestrator.js +8 -4
  167. package/lib/service/automation/ContextCollector.js +7 -5
  168. package/lib/service/automation/DirectiveDetector.js +23 -16
  169. package/lib/service/automation/FileWatcher.js +112 -56
  170. package/lib/service/automation/TriggerResolver.js +6 -4
  171. package/lib/service/automation/handlers/AlinkHandler.js +24 -12
  172. package/lib/service/automation/handlers/CreateHandler.js +19 -20
  173. package/lib/service/automation/handlers/DraftHandler.js +14 -8
  174. package/lib/service/automation/handlers/GuardHandler.js +93 -63
  175. package/lib/service/automation/handlers/HeaderHandler.js +1 -6
  176. package/lib/service/automation/handlers/SearchHandler.js +155 -88
  177. package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
  178. package/lib/service/candidate/SimilarityService.js +25 -9
  179. package/lib/service/chat/AnalystAgent.js +50 -24
  180. package/lib/service/chat/CandidateGuardrail.js +143 -17
  181. package/lib/service/chat/ChatAgent.js +759 -243
  182. package/lib/service/chat/ContextWindow.js +116 -71
  183. package/lib/service/chat/ConversationStore.js +77 -36
  184. package/lib/service/chat/EpisodicConsolidator.js +47 -23
  185. package/lib/service/chat/HandoffProtocol.js +98 -22
  186. package/lib/service/chat/Memory.js +34 -14
  187. package/lib/service/chat/ProducerAgent.js +40 -20
  188. package/lib/service/chat/ProjectSemanticMemory.js +109 -78
  189. package/lib/service/chat/ReasoningLayer.js +148 -70
  190. package/lib/service/chat/ReasoningTrace.js +44 -32
  191. package/lib/service/chat/TaskPipeline.js +39 -19
  192. package/lib/service/chat/ToolRegistry.js +48 -29
  193. package/lib/service/chat/WorkingMemory.js +44 -18
  194. package/lib/service/chat/tools.js +1096 -494
  195. package/lib/service/context/RecipeExtractor.js +132 -51
  196. package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
  197. package/lib/service/cursor/KnowledgeCompressor.js +25 -22
  198. package/lib/service/cursor/RulesGenerator.js +13 -7
  199. package/lib/service/cursor/SkillsSyncer.js +77 -27
  200. package/lib/service/cursor/TokenBudget.js +2 -2
  201. package/lib/service/cursor/TopicClassifier.js +54 -20
  202. package/lib/service/guard/ComplianceReporter.js +55 -43
  203. package/lib/service/guard/ExclusionManager.js +67 -29
  204. package/lib/service/guard/GuardCheckEngine.js +381 -86
  205. package/lib/service/guard/GuardFeedbackLoop.js +22 -10
  206. package/lib/service/guard/GuardService.js +29 -19
  207. package/lib/service/guard/RuleLearner.js +55 -23
  208. package/lib/service/guard/SourceFileCollector.js +27 -20
  209. package/lib/service/guard/ViolationsStore.js +43 -38
  210. package/lib/service/knowledge/CodeEntityGraph.js +147 -82
  211. package/lib/service/knowledge/ConfidenceRouter.js +12 -10
  212. package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
  213. package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
  214. package/lib/service/knowledge/KnowledgeService.js +222 -112
  215. package/lib/service/module/ModuleService.js +969 -0
  216. package/lib/service/quality/FeedbackCollector.js +27 -15
  217. package/lib/service/quality/QualityScorer.js +78 -24
  218. package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
  219. package/lib/service/recipe/RecipeParser.js +78 -45
  220. package/lib/service/search/CoarseRanker.js +43 -28
  221. package/lib/service/search/CrossEncoderReranker.js +32 -21
  222. package/lib/service/search/InvertedIndex.js +21 -7
  223. package/lib/service/search/MultiSignalRanker.js +90 -28
  224. package/lib/service/search/RetrievalFunnel.js +45 -24
  225. package/lib/service/search/SearchEngine.js +255 -103
  226. package/lib/service/skills/EventAggregator.js +32 -15
  227. package/lib/service/skills/SignalCollector.js +140 -64
  228. package/lib/service/skills/SkillAdvisor.js +79 -42
  229. package/lib/service/skills/SkillHooks.js +16 -14
  230. package/lib/service/snippet/PlaceholderConverter.js +5 -0
  231. package/lib/service/snippet/SnippetFactory.js +116 -99
  232. package/lib/service/snippet/SnippetInstaller.js +234 -62
  233. package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
  234. package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
  235. package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
  236. package/lib/service/wiki/WikiGenerator.js +637 -263
  237. package/lib/shared/DimensionCopyRegistry.js +472 -0
  238. package/lib/shared/LanguageService.js +399 -0
  239. package/lib/shared/PathGuard.js +45 -28
  240. package/lib/shared/RecipeReadinessChecker.js +72 -12
  241. package/lib/shared/constants.js +41 -41
  242. package/lib/shared/errors/BaseError.js +2 -2
  243. package/lib/shared/errors/index.js +4 -4
  244. package/lib/shared/similarity.js +25 -8
  245. package/lib/shared/token-utils.js +6 -2
  246. package/lib/shared/utils/common.js +12 -4
  247. package/package.json +49 -13
  248. package/scripts/bench-real-projects.mjs +256 -0
  249. package/scripts/build-native-ui.js +30 -30
  250. package/scripts/clear-old-vector-index.js +5 -35
  251. package/scripts/clear-vector-cache.js +7 -37
  252. package/scripts/collect-test-project-stats.mjs +160 -0
  253. package/scripts/diagnose-mcp.js +41 -32
  254. package/scripts/ensure-parse-package.js +6 -9
  255. package/scripts/generate-recipe-drafts.js +116 -77
  256. package/scripts/init-db.js +3 -20
  257. package/scripts/init-snippets.js +305 -0
  258. package/scripts/init-vector-db.js +173 -170
  259. package/scripts/install-cursor-skill.js +148 -104
  260. package/scripts/install-full.js +8 -21
  261. package/scripts/install-vscode-copilot.js +146 -145
  262. package/scripts/migrate-md-to-knowledge.mjs +139 -151
  263. package/scripts/postinstall-safe.js +5 -17
  264. package/scripts/recipe-audit.js +106 -82
  265. package/scripts/release.js +283 -323
  266. package/scripts/setup-mcp-config.js +60 -52
  267. package/scripts/verify-context-api.js +20 -20
  268. package/skills/autosnippet-analysis/SKILL.md +10 -6
  269. package/skills/autosnippet-candidates/SKILL.md +27 -26
  270. package/skills/autosnippet-coldstart/SKILL.md +555 -38
  271. package/skills/autosnippet-concepts/SKILL.md +349 -337
  272. package/skills/autosnippet-create/SKILL.md +5 -5
  273. package/skills/autosnippet-reference-dart/SKILL.md +543 -0
  274. package/skills/autosnippet-reference-go/SKILL.md +539 -0
  275. package/skills/autosnippet-reference-java/SKILL.md +534 -0
  276. package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
  277. package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
  278. package/skills/autosnippet-reference-objc/SKILL.md +29 -6
  279. package/skills/autosnippet-reference-python/SKILL.md +800 -0
  280. package/skills/autosnippet-reference-swift/SKILL.md +70 -14
  281. package/skills/autosnippet-structure/SKILL.md +4 -4
  282. package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
  283. package/templates/recipes-setup/README.md +2 -2
  284. package/templates/recipes-setup/_template.md +1 -1
  285. package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
  286. package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
  287. package/resources/asd-entry/main.swift +0 -159
  288. package/scripts/build-asd-entry.js +0 -51
  289. package/scripts/init-xcode-snippets.js +0 -311
  290. package/template.json +0 -39
@@ -9,9 +9,9 @@
9
9
  * 缓存位置: {projectRoot}/.autosnippet/cache/
10
10
  */
11
11
 
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
13
- import { join, relative } from 'node:path';
14
12
  import { createHash } from 'node:crypto';
13
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
14
+ import { join, relative } from 'node:path';
15
15
  import Logger from '../logging/Logger.js';
16
16
 
17
17
  export class GraphCache {
@@ -59,7 +59,9 @@ export class GraphCache {
59
59
  load(key) {
60
60
  try {
61
61
  const filePath = join(this.#cacheDir, `${key}.json`);
62
- if (!existsSync(filePath)) return null;
62
+ if (!existsSync(filePath)) {
63
+ return null;
64
+ }
63
65
  const raw = readFileSync(filePath, 'utf-8');
64
66
  return JSON.parse(raw);
65
67
  } catch (err) {
@@ -76,7 +78,9 @@ export class GraphCache {
76
78
  */
77
79
  isValid(key, currentHash) {
78
80
  const cached = this.load(key);
79
- if (!cached) return false;
81
+ if (!cached) {
82
+ return false;
83
+ }
80
84
  return cached.contentHash === currentHash;
81
85
  }
82
86
 
@@ -3,8 +3,8 @@
3
3
  * 内存缓存模式
4
4
  */
5
5
 
6
- import { cacheService as memoryCacheService } from './CacheService.js';
7
6
  import Logger from '../logging/Logger.js';
7
+ import { cacheService as memoryCacheService } from './CacheService.js';
8
8
 
9
9
  export class UnifiedCacheAdapter {
10
10
  constructor() {
@@ -1,6 +1,6 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
4
 
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
@@ -49,8 +49,12 @@ export class ConfigLoader {
49
49
  const output = { ...target };
50
50
  for (const key of Object.keys(source)) {
51
51
  if (
52
- source[key] && typeof source[key] === 'object' && !Array.isArray(source[key]) &&
53
- target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])
52
+ source[key] &&
53
+ typeof source[key] === 'object' &&
54
+ !Array.isArray(source[key]) &&
55
+ target[key] &&
56
+ typeof target[key] === 'object' &&
57
+ !Array.isArray(target[key])
54
58
  ) {
55
59
  output[key] = this._deepMerge(target[key], source[key]);
56
60
  } else {
@@ -52,21 +52,41 @@ export const DEFAULT_CATEGORY = 'general';
52
52
  */
53
53
  export function inferCategory(relPath, content) {
54
54
  const frontMatch = (content || '').match(/^---[\s\S]*?category:\s*["']?([\w-]+)["']?/m);
55
- if (frontMatch) return frontMatch[1];
55
+ if (frontMatch) {
56
+ return frontMatch[1];
57
+ }
56
58
  const lower = (relPath || '').toLowerCase();
57
59
  for (const { pattern, category } of CATEGORY_RULES) {
58
- if (pattern.test(lower)) return category;
60
+ if (pattern.test(lower)) {
61
+ return category;
62
+ }
59
63
  }
60
64
  return DEFAULT_CATEGORY;
61
65
  }
62
66
 
63
67
  export default {
64
- SPEC_FILENAME, KNOWLEDGE_BASE_DIR, RECIPES_DIR, CANDIDATES_DIR, RECIPES_INDEX,
65
- SPMMAP_FILENAME, SPMMAP_PATH,
66
- DEFAULT_STORAGE_ADAPTER, STORAGE_ADAPTERS,
67
- SOURCE_TYPES, SOURCE_TYPE_RECIPE, SOURCE_TYPE_TARGET_README,
68
- DEFAULT_SOURCES, DEFAULT_CHUNKING, CHUNKING_STRATEGIES,
69
- DEFAULT_MAX_CHUNK_TOKENS, DEFAULT_OVERLAP_TOKENS, CHARS_PER_TOKEN,
70
- README_NAMES, DEFAULT_ASD_UI_URL, GUARD_CONTEXT_EXCERPT_LIMIT,
71
- CATEGORY_RULES, DEFAULT_CATEGORY, inferCategory,
68
+ SPEC_FILENAME,
69
+ KNOWLEDGE_BASE_DIR,
70
+ RECIPES_DIR,
71
+ CANDIDATES_DIR,
72
+ RECIPES_INDEX,
73
+ SPMMAP_FILENAME,
74
+ SPMMAP_PATH,
75
+ DEFAULT_STORAGE_ADAPTER,
76
+ STORAGE_ADAPTERS,
77
+ SOURCE_TYPES,
78
+ SOURCE_TYPE_RECIPE,
79
+ SOURCE_TYPE_TARGET_README,
80
+ DEFAULT_SOURCES,
81
+ DEFAULT_CHUNKING,
82
+ CHUNKING_STRATEGIES,
83
+ DEFAULT_MAX_CHUNK_TOKENS,
84
+ DEFAULT_OVERLAP_TOKENS,
85
+ CHARS_PER_TOKEN,
86
+ README_NAMES,
87
+ DEFAULT_ASD_UI_URL,
88
+ GUARD_CONTEXT_EXCERPT_LIMIT,
89
+ CATEGORY_RULES,
90
+ DEFAULT_CATEGORY,
91
+ inferCategory,
72
92
  };
@@ -1,10 +1,10 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs';
2
+ import path from 'node:path';
3
3
  import pathGuard from '../../shared/PathGuard.js';
4
4
 
5
5
  /**
6
6
  * Paths — 项目路径解析工具
7
- * 提供 Xcode snippets 目录、缓存目录、知识库目录等路径计算能力。
7
+ * 提供 Snippet 安装目录、缓存目录、知识库目录等路径计算能力。
8
8
  * 所有路径均自动确保目录存在。
9
9
  */
10
10
 
@@ -20,25 +20,40 @@ function ensureDir(dirPath) {
20
20
  if (!fs.existsSync(dirPath)) {
21
21
  fs.mkdirSync(dirPath, { recursive: true });
22
22
  }
23
- } catch { /* ignore */ }
23
+ } catch {
24
+ /* ignore */
25
+ }
24
26
  return dirPath;
25
27
  }
26
28
 
27
29
  /**
28
- * Xcode CodeSnippets 输出目录
30
+ * Xcode CodeSnippets 输出目录 (macOS only)
29
31
  * 可通过 ASD_SNIPPETS_PATH 环境变量覆盖
30
32
  */
31
33
  export function getSnippetsPath() {
32
- if (process.env.ASD_SNIPPETS_PATH) return process.env.ASD_SNIPPETS_PATH;
34
+ if (process.env.ASD_SNIPPETS_PATH) {
35
+ return process.env.ASD_SNIPPETS_PATH;
36
+ }
33
37
  return ensureDir(path.join(USER_HOME, 'Library/Developer/Xcode/UserData/CodeSnippets'));
34
38
  }
35
39
 
40
+ /**
41
+ * VSCode 项目级 Snippets 目录 = projectRoot/.vscode/
42
+ * @param {string} projectRoot
43
+ * @returns {string}
44
+ */
45
+ export function getVSCodeSnippetsPath(projectRoot) {
46
+ return ensureDir(path.join(projectRoot, '.vscode'));
47
+ }
48
+
36
49
  /**
37
50
  * AutoSnippet 全局缓存目录 ~/.autosnippet/cache
38
51
  * 可通过 ASD_CACHE_PATH 环境变量覆盖
39
52
  */
40
53
  export function getCachePath() {
41
- if (process.env.ASD_CACHE_PATH) return process.env.ASD_CACHE_PATH;
54
+ if (process.env.ASD_CACHE_PATH) {
55
+ return process.env.ASD_CACHE_PATH;
56
+ }
42
57
  return ensureDir(path.join(USER_HOME, '.autosnippet', 'cache'));
43
58
  }
44
59
 
@@ -58,7 +73,9 @@ export function getKnowledgeBaseDirName(projectRoot) {
58
73
  }
59
74
  }
60
75
  }
61
- } catch { /* ignore */ }
76
+ } catch {
77
+ /* ignore */
78
+ }
62
79
  return 'AutoSnippet';
63
80
  }
64
81
 
@@ -113,13 +130,16 @@ export function getProjectSkillsPath(projectRoot) {
113
130
  */
114
131
  export function getProjectRecipesPath(projectRoot, rootSpec) {
115
132
  const dir = rootSpec?.recipes?.dir || rootSpec?.skills?.dir || null;
116
- if (dir) return path.join(projectRoot, dir);
133
+ if (dir) {
134
+ return path.join(projectRoot, dir);
135
+ }
117
136
  return path.join(getProjectKnowledgePath(projectRoot), 'recipes');
118
137
  }
119
138
 
120
139
  export default {
121
140
  SPEC_FILENAME,
122
141
  getSnippetsPath,
142
+ getVSCodeSnippetsPath,
123
143
  getCachePath,
124
144
  getKnowledgeBaseDirName,
125
145
  getProjectKnowledgePath,
@@ -9,7 +9,9 @@ const DEFAULT_SYMBOL = '@';
9
9
 
10
10
  function fromEnv() {
11
11
  const raw = process.env.ASD_TRIGGER_SYMBOL;
12
- if (raw != null && String(raw).length === 1) return String(raw);
12
+ if (raw != null && String(raw).length === 1) {
13
+ return String(raw);
14
+ }
13
15
  return DEFAULT_SYMBOL;
14
16
  }
15
17
 
@@ -24,20 +26,22 @@ export const TRIGGER_SYMBOL = fromEnv();
24
26
  export const TRIGGER_SYMBOLS = [TRIGGER_SYMBOL];
25
27
 
26
28
  /** 用于按触发符拆分的正则 */
27
- export const TRIGGER_SPLIT_REGEX = new RegExp(
28
- '[' + TRIGGER_SYMBOLS.map(escapeRegExp).join('') + ']'
29
- );
29
+ export const TRIGGER_SPLIT_REGEX = new RegExp(`[${TRIGGER_SYMBOLS.map(escapeRegExp).join('')}]`);
30
30
 
31
31
  /** str 是否以触发符开头 */
32
32
  export function hasTriggerPrefix(str) {
33
- if (!str || typeof str !== 'string') return false;
33
+ if (!str || typeof str !== 'string') {
34
+ return false;
35
+ }
34
36
  const s = String(str).trim();
35
37
  return TRIGGER_SYMBOLS.some((sym) => s.startsWith(sym));
36
38
  }
37
39
 
38
40
  /** 去掉 str 开头的连续触发符 */
39
41
  export function stripTriggerPrefix(str) {
40
- if (!str || typeof str !== 'string') return String(str);
42
+ if (!str || typeof str !== 'string') {
43
+ return String(str);
44
+ }
41
45
  let s = String(str).trim();
42
46
  while (s.length && TRIGGER_SYMBOLS.some((sym) => s.startsWith(sym))) {
43
47
  s = s.slice(1).trimStart();
@@ -47,18 +51,26 @@ export function stripTriggerPrefix(str) {
47
51
 
48
52
  /** 若 str 不以触发符开头,则加上默认触发符 */
49
53
  export function ensureTriggerPrefix(str) {
50
- if (!str || typeof str !== 'string') return str;
54
+ if (!str || typeof str !== 'string') {
55
+ return str;
56
+ }
51
57
  const s = String(str).trim();
52
- if (!s) return s;
58
+ if (!s) {
59
+ return s;
60
+ }
53
61
  return hasTriggerPrefix(s) ? s : TRIGGER_SYMBOL + s;
54
62
  }
55
63
 
56
64
  /** 获取 str 已带的触发符,否则返回默认触发符 */
57
65
  export function getPrefixFromTrigger(str) {
58
- if (!str || typeof str !== 'string') return TRIGGER_SYMBOL;
66
+ if (!str || typeof str !== 'string') {
67
+ return TRIGGER_SYMBOL;
68
+ }
59
69
  const s = String(str).trim();
60
70
  for (const sym of TRIGGER_SYMBOLS) {
61
- if (s.startsWith(sym)) return sym;
71
+ if (s.startsWith(sym)) {
72
+ return sym;
73
+ }
62
74
  }
63
75
  return TRIGGER_SYMBOL;
64
76
  }
@@ -1,7 +1,7 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import Database from 'better-sqlite3';
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
5
5
  import pathGuard from '../../shared/PathGuard.js';
6
6
 
7
7
  const __filename = fileURLToPath(import.meta.url);
@@ -28,13 +28,14 @@ export class DatabaseConnection {
28
28
  // 使用 projectRoot(PathGuard 已配置)优先解析相对路径,
29
29
  // 而非 path.resolve()(依赖 cwd,MCP 场景下 cwd 可能是用户主目录)
30
30
  const projectRoot = pathGuard.projectRoot;
31
- const resolvedDbPath = (projectRoot && !path.isAbsolute(dbPath))
32
- ? path.resolve(projectRoot, dbPath)
33
- : path.resolve(dbPath);
31
+ const resolvedDbPath =
32
+ projectRoot && !path.isAbsolute(dbPath)
33
+ ? path.resolve(projectRoot, dbPath)
34
+ : path.resolve(dbPath);
34
35
 
35
36
  // 路径安全检查 — 防止 DB 文件创建到项目允许范围外
36
37
  pathGuard.assertProjectWriteSafe(resolvedDbPath);
37
-
38
+
38
39
  // 确保数据目录存在
39
40
  const dbDir = path.dirname(resolvedDbPath);
40
41
  if (!fs.existsSync(dbDir)) {
@@ -72,7 +73,7 @@ export class DatabaseConnection {
72
73
 
73
74
  for (const file of migrationFiles) {
74
75
  const version = file.replace(/\.(sql|js)$/, '');
75
-
76
+
76
77
  // 检查是否已应用
77
78
  const applied = this.db
78
79
  .prepare('SELECT version FROM schema_migrations WHERE version = ?')
@@ -88,7 +89,9 @@ export class DatabaseConnection {
88
89
  const runMigration = this.db.transaction(() => {
89
90
  migrate(this.db);
90
91
  this.db
91
- .prepare('INSERT OR IGNORE INTO schema_migrations (version, applied_at) VALUES (?, ?)')
92
+ .prepare(
93
+ 'INSERT OR IGNORE INTO schema_migrations (version, applied_at) VALUES (?, ?)'
94
+ )
92
95
  .run(version, new Date().toISOString());
93
96
  });
94
97
  runMigration();
@@ -97,7 +100,9 @@ export class DatabaseConnection {
97
100
  const runMigration = this.db.transaction(() => {
98
101
  this.db.exec(sql);
99
102
  this.db
100
- .prepare('INSERT OR IGNORE INTO schema_migrations (version, applied_at) VALUES (?, ?)')
103
+ .prepare(
104
+ 'INSERT OR IGNORE INTO schema_migrations (version, applied_at) VALUES (?, ?)'
105
+ )
101
106
  .run(version, new Date().toISOString());
102
107
  });
103
108
  runMigration();
@@ -17,7 +17,6 @@
17
17
  * 10. code_entities — 代码实体节点 (AST 解析)
18
18
  */
19
19
  export default function migrate(db) {
20
-
21
20
  // ═══════════════════════════════════════════════════════════════
22
21
  // 1. knowledge_entries — 核心知识条目
23
22
  // ═══════════════════════════════════════════════════════════════
@@ -14,7 +14,9 @@ const TIMEOUT = 3000;
14
14
  * @returns {string} 剪贴板文本,失败返回空字符串
15
15
  */
16
16
  export function read() {
17
- if (process.platform !== 'darwin') return '';
17
+ if (process.platform !== 'darwin') {
18
+ return '';
19
+ }
18
20
  try {
19
21
  return execSync('pbpaste', { encoding: 'utf8', timeout: TIMEOUT });
20
22
  } catch {
@@ -28,7 +30,9 @@ export function read() {
28
30
  * @returns {boolean}
29
31
  */
30
32
  export function write(text) {
31
- if (process.platform !== 'darwin') return false;
33
+ if (process.platform !== 'darwin') {
34
+ return false;
35
+ }
32
36
  try {
33
37
  execSync('pbcopy', { input: text, timeout: TIMEOUT, stdio: ['pipe', 'ignore', 'ignore'] });
34
38
  return true;
@@ -9,9 +9,9 @@
9
9
  * V2 ESM 版本,对应 V1 NativeUi.js
10
10
  */
11
11
 
12
- import { execSync, execFileSync } from 'node:child_process';
12
+ import { execFileSync, execSync } from 'node:child_process';
13
13
  import { existsSync } from 'node:fs';
14
- import { join, dirname } from 'node:path';
14
+ import { dirname, join } from 'node:path';
15
15
  import { fileURLToPath } from 'node:url';
16
16
 
17
17
  const __filename = fileURLToPath(import.meta.url);
@@ -23,7 +23,9 @@ const NATIVE_UI_PATH = join(__dirname, '../../../resources/native-ui/native-ui')
23
23
  * 检查 Swift Helper 是否可用
24
24
  */
25
25
  export function isNativeUiAvailable() {
26
- if (process.platform !== 'darwin') return false;
26
+ if (process.platform !== 'darwin') {
27
+ return false;
28
+ }
27
29
  try {
28
30
  return existsSync(NATIVE_UI_PATH);
29
31
  } catch {
@@ -39,7 +41,9 @@ export function isNativeUiAvailable() {
39
41
  * @returns {number} 选中的索引(0-based),-1 表示取消
40
42
  */
41
43
  export function showCombinedWindow(items, keyword = '') {
42
- if (!items || items.length === 0) return -1;
44
+ if (!items || items.length === 0) {
45
+ return -1;
46
+ }
43
47
 
44
48
  // 1. 尝试 Swift Helper
45
49
  if (isNativeUiAvailable()) {
@@ -47,16 +51,17 @@ export function showCombinedWindow(items, keyword = '') {
47
51
  const safeKeyword = keyword.replace(/'/g, "'\\''");
48
52
  const json = JSON.stringify(items);
49
53
  const safeJson = json.replace(/'/g, "'\\''");
50
- const result = execFileSync(
51
- NATIVE_UI_PATH,
52
- ['combined', safeKeyword, safeJson],
53
- { encoding: 'utf8', timeout: 60000 }
54
- ).trim();
54
+ const result = execFileSync(NATIVE_UI_PATH, ['combined', safeKeyword, safeJson], {
55
+ encoding: 'utf8',
56
+ timeout: 60000,
57
+ }).trim();
55
58
  const index = parseInt(result, 10);
56
- return isNaN(index) ? -1 : index;
59
+ return Number.isNaN(index) ? -1 : index;
57
60
  } catch (err) {
58
61
  // exit(1) = 用户取消,直接返回 -1,不降级
59
- if (err.status === 1) return -1;
62
+ if (err.status === 1) {
63
+ return -1;
64
+ }
60
65
  // 其他错误(崩溃等)才降级到 AppleScript
61
66
  }
62
67
  }
@@ -83,7 +88,9 @@ export function showCombinedWindow(items, keyword = '') {
83
88
  * @returns {number} 选中索引(0-based),-1 取消
84
89
  */
85
90
  export function showListSelection(items, title = 'AutoSnippet', prompt = '请选择:') {
86
- if (!items || items.length === 0) return -1;
91
+ if (!items || items.length === 0) {
92
+ return -1;
93
+ }
87
94
 
88
95
  // 1. Swift Helper
89
96
  if (isNativeUiAvailable()) {
@@ -94,10 +101,12 @@ export function showListSelection(items, title = 'AutoSnippet', prompt = '请选
94
101
  timeout: 60000,
95
102
  }).trim();
96
103
  const index = parseInt(result, 10);
97
- return isNaN(index) ? -1 : index;
104
+ return Number.isNaN(index) ? -1 : index;
98
105
  } catch (err) {
99
106
  // exit(1) = 用户取消,直接返回
100
- if (err.status === 1) return -1;
107
+ if (err.status === 1) {
108
+ return -1;
109
+ }
101
110
  // 其他错误才降级
102
111
  }
103
112
  }
@@ -105,10 +114,15 @@ export function showListSelection(items, title = 'AutoSnippet', prompt = '请选
105
114
  // 2. AppleScript
106
115
  if (process.platform === 'darwin') {
107
116
  try {
108
- const listStr = items.map(i => `"${i.replace(/"/g, '\\"')}"`).join(', ');
117
+ const listStr = items.map((i) => `"${i.replace(/"/g, '\\"')}"`).join(', ');
109
118
  const script = `choose from list {${listStr}} with title "${_escAS(title)}" with prompt "${_escAS(prompt)}" default items {"${_escAS(items[0])}"}`;
110
- const result = execSync(`osascript -e '${script}'`, { encoding: 'utf8', timeout: 30000 }).trim();
111
- if (result === 'false') return -1;
119
+ const result = execSync(`osascript -e '${script}'`, {
120
+ encoding: 'utf8',
121
+ timeout: 30000,
122
+ }).trim();
123
+ if (result === 'false') {
124
+ return -1;
125
+ }
112
126
  return items.indexOf(result);
113
127
  } catch {
114
128
  return -1;
@@ -129,11 +143,10 @@ export function showPreviewConfirm(title, code) {
129
143
  // 1. Swift Helper
130
144
  if (isNativeUiAvailable()) {
131
145
  try {
132
- const result = execFileSync(
133
- NATIVE_UI_PATH,
134
- ['preview', title, code],
135
- { encoding: 'utf8', timeout: 60000 }
136
- );
146
+ const _result = execFileSync(NATIVE_UI_PATH, ['preview', title, code], {
147
+ encoding: 'utf8',
148
+ timeout: 60000,
149
+ });
137
150
  return true; // exit 0 = confirmed
138
151
  } catch {
139
152
  return false;
@@ -143,7 +156,7 @@ export function showPreviewConfirm(title, code) {
143
156
  // 2. AppleScript
144
157
  if (process.platform === 'darwin') {
145
158
  try {
146
- const preview = code.length > 300 ? code.substring(0, 297) + '...' : code;
159
+ const preview = code.length > 300 ? `${code.substring(0, 297)}...` : code;
147
160
  const script = `display dialog "${_escAS(title)}\\n\\n${_escAS(preview)}" with title "AutoSnippet" buttons {"取消", "确认"} default button "确认"`;
148
161
  const result = execSync(`osascript -e '${script}'`, { encoding: 'utf8', timeout: 30000 });
149
162
  return result.includes('确认');
@@ -162,19 +175,16 @@ export function showPreviewConfirm(title, code) {
162
175
  */
163
176
  export function notify(message, title = 'AutoSnippet') {
164
177
  if (process.platform !== 'darwin') {
165
- console.log(`[${title}] ${message}`);
166
178
  return;
167
179
  }
168
180
  try {
169
181
  const safeMsg = message.replace(/"/g, '\\"').replace(/\n/g, '\\n');
170
182
  const safeTitle = title.replace(/"/g, '\\"');
171
- execSync(
172
- `osascript -e 'display notification "${safeMsg}" with title "${safeTitle}"'`,
173
- { timeout: 5000, stdio: 'ignore' }
174
- );
175
- } catch {
176
- console.log(`[${title}] ${message}`);
177
- }
183
+ execSync(`osascript -e 'display notification "${safeMsg}" with title "${safeTitle}"'`, {
184
+ timeout: 5000,
185
+ stdio: 'ignore',
186
+ });
187
+ } catch {}
178
188
  }
179
189
 
180
190
  /**
@@ -185,9 +195,11 @@ export function notify(message, title = 'AutoSnippet') {
185
195
  * @returns {string|null} 点击的按钮名,或 null 表示取消
186
196
  */
187
197
  export function promptWithButtons(message, buttons = ['确认', '取消'], title = 'AutoSnippet') {
188
- if (process.platform !== 'darwin') return null;
198
+ if (process.platform !== 'darwin') {
199
+ return null;
200
+ }
189
201
  try {
190
- const btnStr = buttons.map(b => `"${_escAS(b)}"`).join(', ');
202
+ const btnStr = buttons.map((b) => `"${_escAS(b)}"`).join(', ');
191
203
  const script = `display dialog "${_escAS(message)}" with title "${_escAS(title)}" buttons {${btnStr}} default button "${_escAS(buttons[0])}"`;
192
204
  const result = execSync(`osascript -e '${script}'`, { encoding: 'utf8', timeout: 30000 });
193
205
  const match = result.match(/button returned:(.+)/);
@@ -210,21 +222,16 @@ function _appleScriptCombinedWindow(items, keyword) {
210
222
  // 两步:先选择,再预览确认
211
223
  const titles = items.map((it, i) => `${i + 1}. ${it.title || 'Recipe'}`);
212
224
  const idx = showListSelection(titles, 'AutoSnippet Search', `搜索: ${keyword}`);
213
- if (idx < 0 || idx >= items.length) return -1;
225
+ if (idx < 0 || idx >= items.length) {
226
+ return -1;
227
+ }
214
228
 
215
229
  const item = items[idx];
216
- const confirmed = showPreviewConfirm(
217
- item.title || 'Recipe',
218
- item.code || item.explanation || ''
219
- );
230
+ const confirmed = showPreviewConfirm(item.title || 'Recipe', item.code || item.explanation || '');
220
231
  return confirmed ? idx : -1;
221
232
  }
222
233
 
223
234
  function _consoleFallback(items, keyword) {
224
- console.log(`\n📋 搜索结果 (${keyword}):`);
225
- items.forEach((item, i) => {
226
- console.log(` ${i + 1}. ${item.title || 'Recipe'}${item.groupSize > 1 ? ` (${item.groupSize} variants)` : ''}`);
227
- });
228
- console.log(` 使用 NativeUI (npm run build:native-ui) 可获得交互式选择体验`);
235
+ items.forEach((item, i) => {});
229
236
  return -1;
230
237
  }
@@ -4,17 +4,19 @@
4
4
  * V2 ESM 版本,对应 V1 OpenBrowser.js
5
5
  */
6
6
 
7
- import { execSync, execFileSync } from 'node:child_process';
7
+ import { execFileSync, execSync } from 'node:child_process';
8
8
  import { existsSync } from 'node:fs';
9
- import { dirname, join } from 'node:path';
10
9
  import { homedir } from 'node:os';
10
+ import { dirname, join } from 'node:path';
11
11
  import { fileURLToPath } from 'node:url';
12
12
 
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = dirname(__filename);
15
15
 
16
16
  function isAppInstalled(appName) {
17
- if (process.platform !== 'darwin') return false;
17
+ if (process.platform !== 'darwin') {
18
+ return false;
19
+ }
18
20
  const candidates = [
19
21
  `/Applications/${appName}.app`,
20
22
  `${homedir()}/Applications/${appName}.app`,
@@ -27,7 +29,9 @@ function isAppInstalled(appName) {
27
29
  * 检测当前进程是否已有控制 Chromium 系浏览器的权限
28
30
  */
29
31
  export function hasMacOSBrowserControlGranted() {
30
- if (process.platform !== 'darwin') return false;
32
+ if (process.platform !== 'darwin') {
33
+ return false;
34
+ }
31
35
  const chromiumBrowsers = [
32
36
  'Google Chrome Canary',
33
37
  'Google Chrome',
@@ -37,7 +41,9 @@ export function hasMacOSBrowserControlGranted() {
37
41
  'Chromium',
38
42
  ];
39
43
  for (const browser of chromiumBrowsers) {
40
- if (!isAppInstalled(browser)) continue;
44
+ if (!isAppInstalled(browser)) {
45
+ continue;
46
+ }
41
47
  try {
42
48
  execSync(`osascript -e 'tell application "${browser}" to get name'`, {
43
49
  stdio: 'ignore',
@@ -58,8 +64,7 @@ export function hasMacOSBrowserControlGranted() {
58
64
  */
59
65
  export function openBrowserReuseTab(url, baseUrlForLookup) {
60
66
  const skipReuse =
61
- process.env.ASD_UI_NO_REUSE_TAB === '1' ||
62
- process.env.ASD_UI_OPEN_REUSE === '0';
67
+ process.env.ASD_UI_NO_REUSE_TAB === '1' || process.env.ASD_UI_OPEN_REUSE === '0';
63
68
 
64
69
  if (skipReuse) {
65
70
  _fallbackOpen(url);
@@ -84,27 +89,21 @@ export function openBrowserReuseTab(url, baseUrlForLookup) {
84
89
  }
85
90
 
86
91
  if (!hasMacOSBrowserControlGranted()) {
87
- console.log(
88
- '💡 若已打开该页将复用标签;若系统弹出「辅助功能」权限请求,允许即可;未授权则自动新开标签。'
89
- );
90
92
  }
91
93
 
92
94
  const lookupUrl = baseUrlForLookup || url;
93
95
  for (const browser of availableChromium) {
94
96
  try {
95
97
  const args =
96
- lookupUrl !== url
97
- ? [scriptPath, lookupUrl, url, browser]
98
- : [scriptPath, url, browser];
98
+ lookupUrl !== url ? [scriptPath, lookupUrl, url, browser] : [scriptPath, url, browser];
99
99
  execFileSync('osascript', args, {
100
100
  cwd: dirname(scriptPath),
101
101
  stdio: 'pipe',
102
102
  timeout: 3000,
103
103
  });
104
104
  return;
105
- } catch (err) {
105
+ } catch (_err) {
106
106
  if (process.env.ASD_DEBUG === '1') {
107
- console.log(`[Debug] ${browser} 打开失败: ${err.message}`);
108
107
  }
109
108
  }
110
109
  }
@@ -122,10 +121,8 @@ async function _fallbackOpen(url) {
122
121
  const open = (await import('open')).default;
123
122
  open(url).catch((err) => {
124
123
  console.error(`⚠️ 打开浏览器失败: ${err.message}`);
125
- console.log(`💡 请手动访问: ${url}`);
126
124
  });
127
125
  } catch (err) {
128
126
  console.error(`⚠️ 打开浏览器失败: ${err.message}`);
129
- console.log(`💡 请手动访问: ${url}`);
130
127
  }
131
128
  }