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.
- package/README.md +230 -324
- package/bin/api-server.js +1 -1
- package/bin/cli.js +204 -244
- package/bin/mcp-server.js +5 -3
- package/config/knowledge-base.config.js +132 -132
- package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
- package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
- package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/bootstrap.js +8 -8
- package/lib/cli/AiScanService.js +86 -40
- package/lib/cli/KnowledgeSyncService.js +113 -74
- package/lib/cli/SetupService.js +439 -277
- package/lib/cli/UpgradeService.js +63 -100
- package/lib/core/AstAnalyzer.js +276 -597
- package/lib/core/ast/ProjectGraph.js +101 -40
- package/lib/core/ast/ensure-grammars.js +232 -0
- package/lib/core/ast/index.js +115 -0
- package/lib/core/ast/lang-dart.js +661 -0
- package/lib/core/ast/lang-go.js +530 -0
- package/lib/core/ast/lang-java.js +435 -0
- package/lib/core/ast/lang-javascript.js +272 -0
- package/lib/core/ast/lang-kotlin.js +423 -0
- package/lib/core/ast/lang-objc.js +388 -0
- package/lib/core/ast/lang-python.js +371 -0
- package/lib/core/ast/lang-swift.js +337 -0
- package/lib/core/ast/lang-typescript.js +503 -0
- package/lib/core/capability/CapabilityProbe.js +18 -9
- package/lib/core/constitution/Constitution.js +2 -3
- package/lib/core/constitution/ConstitutionValidator.js +65 -24
- package/lib/core/discovery/DartDiscoverer.js +534 -0
- package/lib/core/discovery/DiscovererRegistry.js +83 -0
- package/lib/core/discovery/GenericDiscoverer.js +225 -0
- package/lib/core/discovery/GoDiscoverer.js +541 -0
- package/lib/core/discovery/JvmDiscoverer.js +506 -0
- package/lib/core/discovery/NodeDiscoverer.js +466 -0
- package/lib/core/discovery/ProjectDiscoverer.js +93 -0
- package/lib/core/discovery/PythonDiscoverer.js +338 -0
- package/lib/core/discovery/SpmDiscoverer.js +5 -0
- package/lib/core/discovery/index.js +53 -0
- package/lib/core/enhancement/EnhancementPack.js +71 -0
- package/lib/core/enhancement/EnhancementRegistry.js +47 -0
- package/lib/core/enhancement/android-enhancement.js +102 -0
- package/lib/core/enhancement/django-enhancement.js +70 -0
- package/lib/core/enhancement/fastapi-enhancement.js +63 -0
- package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
- package/lib/core/enhancement/go-web-enhancement.js +201 -0
- package/lib/core/enhancement/index.js +65 -0
- package/lib/core/enhancement/node-server-enhancement.js +88 -0
- package/lib/core/enhancement/react-enhancement.js +86 -0
- package/lib/core/enhancement/spring-enhancement.js +112 -0
- package/lib/core/enhancement/vue-enhancement.js +96 -0
- package/lib/core/gateway/Gateway.js +8 -9
- package/lib/core/gateway/GatewayActionRegistry.js +1 -1
- package/lib/core/permission/PermissionManager.js +12 -8
- package/lib/domain/index.js +13 -9
- package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
- package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
- package/lib/domain/knowledge/Lifecycle.js +22 -22
- package/lib/domain/knowledge/index.js +9 -12
- package/lib/domain/knowledge/values/Constraints.js +31 -21
- package/lib/domain/knowledge/values/Content.js +21 -13
- package/lib/domain/knowledge/values/Quality.js +31 -18
- package/lib/domain/knowledge/values/Reasoning.js +20 -12
- package/lib/domain/knowledge/values/Relations.js +37 -25
- package/lib/domain/knowledge/values/Stats.js +18 -12
- package/lib/domain/knowledge/values/index.js +4 -3
- package/lib/domain/snippet/Snippet.js +35 -10
- package/lib/external/ai/AiFactory.js +48 -16
- package/lib/external/ai/AiProvider.js +184 -90
- package/lib/external/ai/providers/ClaudeProvider.js +25 -12
- package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
- package/lib/external/ai/providers/MockProvider.js +9 -3
- package/lib/external/ai/providers/OpenAiProvider.js +51 -29
- package/lib/external/mcp/McpServer.js +66 -36
- package/lib/external/mcp/errorHandler.js +23 -11
- package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
- package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
- package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
- package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
- package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
- package/lib/external/mcp/handlers/bootstrap.js +691 -168
- package/lib/external/mcp/handlers/browse.js +66 -22
- package/lib/external/mcp/handlers/candidate.js +118 -35
- package/lib/external/mcp/handlers/consolidated.js +49 -17
- package/lib/external/mcp/handlers/guard.js +104 -39
- package/lib/external/mcp/handlers/knowledge.js +60 -36
- package/lib/external/mcp/handlers/search.js +43 -14
- package/lib/external/mcp/handlers/skill.js +120 -45
- package/lib/external/mcp/handlers/structure.js +240 -86
- package/lib/external/mcp/handlers/system.js +42 -12
- package/lib/external/mcp/handlers/wiki.js +58 -33
- package/lib/external/mcp/tools.js +306 -123
- package/lib/http/HttpServer.js +72 -47
- package/lib/http/middleware/RateLimiter.js +5 -3
- package/lib/http/middleware/errorHandler.js +6 -1
- package/lib/http/middleware/requestLogger.js +14 -3
- package/lib/http/middleware/roleResolver.js +30 -23
- package/lib/http/routes/ai.js +387 -265
- package/lib/http/routes/auth.js +81 -61
- package/lib/http/routes/candidates.js +430 -320
- package/lib/http/routes/commands.js +289 -189
- package/lib/http/routes/extract.js +158 -125
- package/lib/http/routes/guardRules.js +309 -217
- package/lib/http/routes/knowledge.js +213 -154
- package/lib/http/routes/modules.js +578 -0
- package/lib/http/routes/monitoring.js +6 -6
- package/lib/http/routes/recipes.js +104 -93
- package/lib/http/routes/search.js +361 -305
- package/lib/http/routes/skills.js +145 -98
- package/lib/http/routes/snippets.js +42 -30
- package/lib/http/routes/spm.js +3 -405
- package/lib/http/routes/violations.js +113 -93
- package/lib/http/routes/wiki.js +211 -170
- package/lib/http/utils/routeHelpers.js +3 -1
- package/lib/http/utils/sse-sessions.js +16 -6
- package/lib/http/utils/sse.js +15 -5
- package/lib/infrastructure/audit/AuditLogger.js +5 -2
- package/lib/infrastructure/audit/AuditStore.js +10 -7
- package/lib/infrastructure/cache/CacheService.js +3 -1
- package/lib/infrastructure/cache/GraphCache.js +8 -4
- package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
- package/lib/infrastructure/config/ConfigLoader.js +9 -5
- package/lib/infrastructure/config/Defaults.js +30 -10
- package/lib/infrastructure/config/Paths.js +28 -8
- package/lib/infrastructure/config/TriggerSymbol.js +22 -10
- package/lib/infrastructure/database/DatabaseConnection.js +15 -10
- package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
- package/lib/infrastructure/external/ClipboardManager.js +6 -2
- package/lib/infrastructure/external/NativeUi.js +50 -43
- package/lib/infrastructure/external/OpenBrowser.js +14 -17
- package/lib/infrastructure/external/XcodeAutomation.js +14 -258
- package/lib/infrastructure/logging/Logger.js +46 -30
- package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
- package/lib/infrastructure/paths/HeaderResolver.js +25 -9
- package/lib/infrastructure/paths/PathFinder.js +34 -12
- package/lib/infrastructure/plugin/PluginManager.js +26 -8
- package/lib/infrastructure/realtime/RealtimeService.js +2 -2
- package/lib/infrastructure/vector/Chunker.js +22 -7
- package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
- package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
- package/lib/infrastructure/vector/VectorStore.js +28 -10
- package/lib/injection/ServiceContainer.js +247 -93
- package/lib/platform/ios/index.js +63 -0
- package/lib/platform/ios/routes/spm.js +437 -0
- package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
- package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
- package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
- package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
- package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
- package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
- package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
- package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
- package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
- package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
- package/lib/repository/base/BaseRepository.js +7 -9
- package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
- package/lib/repository/token/TokenUsageStore.js +4 -2
- package/lib/service/automation/ActionPipeline.js +1 -1
- package/lib/service/automation/AutomationOrchestrator.js +8 -4
- package/lib/service/automation/ContextCollector.js +7 -5
- package/lib/service/automation/DirectiveDetector.js +23 -16
- package/lib/service/automation/FileWatcher.js +112 -56
- package/lib/service/automation/TriggerResolver.js +6 -4
- package/lib/service/automation/handlers/AlinkHandler.js +24 -12
- package/lib/service/automation/handlers/CreateHandler.js +19 -20
- package/lib/service/automation/handlers/DraftHandler.js +14 -8
- package/lib/service/automation/handlers/GuardHandler.js +93 -63
- package/lib/service/automation/handlers/HeaderHandler.js +1 -6
- package/lib/service/automation/handlers/SearchHandler.js +155 -88
- package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
- package/lib/service/candidate/SimilarityService.js +25 -9
- package/lib/service/chat/AnalystAgent.js +50 -24
- package/lib/service/chat/CandidateGuardrail.js +143 -17
- package/lib/service/chat/ChatAgent.js +759 -243
- package/lib/service/chat/ContextWindow.js +116 -71
- package/lib/service/chat/ConversationStore.js +77 -36
- package/lib/service/chat/EpisodicConsolidator.js +47 -23
- package/lib/service/chat/HandoffProtocol.js +98 -22
- package/lib/service/chat/Memory.js +34 -14
- package/lib/service/chat/ProducerAgent.js +40 -20
- package/lib/service/chat/ProjectSemanticMemory.js +109 -78
- package/lib/service/chat/ReasoningLayer.js +148 -70
- package/lib/service/chat/ReasoningTrace.js +44 -32
- package/lib/service/chat/TaskPipeline.js +39 -19
- package/lib/service/chat/ToolRegistry.js +48 -29
- package/lib/service/chat/WorkingMemory.js +44 -18
- package/lib/service/chat/tools.js +1096 -494
- package/lib/service/context/RecipeExtractor.js +132 -51
- package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
- package/lib/service/cursor/KnowledgeCompressor.js +25 -22
- package/lib/service/cursor/RulesGenerator.js +13 -7
- package/lib/service/cursor/SkillsSyncer.js +77 -27
- package/lib/service/cursor/TokenBudget.js +2 -2
- package/lib/service/cursor/TopicClassifier.js +54 -20
- package/lib/service/guard/ComplianceReporter.js +55 -43
- package/lib/service/guard/ExclusionManager.js +67 -29
- package/lib/service/guard/GuardCheckEngine.js +381 -86
- package/lib/service/guard/GuardFeedbackLoop.js +22 -10
- package/lib/service/guard/GuardService.js +29 -19
- package/lib/service/guard/RuleLearner.js +55 -23
- package/lib/service/guard/SourceFileCollector.js +27 -20
- package/lib/service/guard/ViolationsStore.js +43 -38
- package/lib/service/knowledge/CodeEntityGraph.js +147 -82
- package/lib/service/knowledge/ConfidenceRouter.js +12 -10
- package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
- package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
- package/lib/service/knowledge/KnowledgeService.js +222 -112
- package/lib/service/module/ModuleService.js +969 -0
- package/lib/service/quality/FeedbackCollector.js +27 -15
- package/lib/service/quality/QualityScorer.js +78 -24
- package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
- package/lib/service/recipe/RecipeParser.js +78 -45
- package/lib/service/search/CoarseRanker.js +43 -28
- package/lib/service/search/CrossEncoderReranker.js +32 -21
- package/lib/service/search/InvertedIndex.js +21 -7
- package/lib/service/search/MultiSignalRanker.js +90 -28
- package/lib/service/search/RetrievalFunnel.js +45 -24
- package/lib/service/search/SearchEngine.js +255 -103
- package/lib/service/skills/EventAggregator.js +32 -15
- package/lib/service/skills/SignalCollector.js +140 -64
- package/lib/service/skills/SkillAdvisor.js +79 -42
- package/lib/service/skills/SkillHooks.js +16 -14
- package/lib/service/snippet/PlaceholderConverter.js +5 -0
- package/lib/service/snippet/SnippetFactory.js +116 -99
- package/lib/service/snippet/SnippetInstaller.js +234 -62
- package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
- package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
- package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
- package/lib/service/wiki/WikiGenerator.js +637 -263
- package/lib/shared/DimensionCopyRegistry.js +472 -0
- package/lib/shared/LanguageService.js +399 -0
- package/lib/shared/PathGuard.js +45 -28
- package/lib/shared/RecipeReadinessChecker.js +72 -12
- package/lib/shared/constants.js +41 -41
- package/lib/shared/errors/BaseError.js +2 -2
- package/lib/shared/errors/index.js +4 -4
- package/lib/shared/similarity.js +25 -8
- package/lib/shared/token-utils.js +6 -2
- package/lib/shared/utils/common.js +12 -4
- package/package.json +49 -13
- package/scripts/bench-real-projects.mjs +256 -0
- package/scripts/build-native-ui.js +30 -30
- package/scripts/clear-old-vector-index.js +5 -35
- package/scripts/clear-vector-cache.js +7 -37
- package/scripts/collect-test-project-stats.mjs +160 -0
- package/scripts/diagnose-mcp.js +41 -32
- package/scripts/ensure-parse-package.js +6 -9
- package/scripts/generate-recipe-drafts.js +116 -77
- package/scripts/init-db.js +3 -20
- package/scripts/init-snippets.js +305 -0
- package/scripts/init-vector-db.js +173 -170
- package/scripts/install-cursor-skill.js +148 -104
- package/scripts/install-full.js +8 -21
- package/scripts/install-vscode-copilot.js +146 -145
- package/scripts/migrate-md-to-knowledge.mjs +139 -151
- package/scripts/postinstall-safe.js +5 -17
- package/scripts/recipe-audit.js +106 -82
- package/scripts/release.js +283 -323
- package/scripts/setup-mcp-config.js +60 -52
- package/scripts/verify-context-api.js +20 -20
- package/skills/autosnippet-analysis/SKILL.md +10 -6
- package/skills/autosnippet-candidates/SKILL.md +27 -26
- package/skills/autosnippet-coldstart/SKILL.md +555 -38
- package/skills/autosnippet-concepts/SKILL.md +349 -337
- package/skills/autosnippet-create/SKILL.md +5 -5
- package/skills/autosnippet-reference-dart/SKILL.md +543 -0
- package/skills/autosnippet-reference-go/SKILL.md +539 -0
- package/skills/autosnippet-reference-java/SKILL.md +534 -0
- package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
- package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
- package/skills/autosnippet-reference-objc/SKILL.md +29 -6
- package/skills/autosnippet-reference-python/SKILL.md +800 -0
- package/skills/autosnippet-reference-swift/SKILL.md +70 -14
- package/skills/autosnippet-structure/SKILL.md +4 -4
- package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
- package/templates/recipes-setup/README.md +2 -2
- package/templates/recipes-setup/_template.md +1 -1
- package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
- package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
- package/resources/asd-entry/main.swift +0 -159
- package/scripts/build-asd-entry.js +0 -51
- package/scripts/init-xcode-snippets.js +0 -311
- package/template.json +0 -39
|
@@ -1,259 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// 内部辅助
|
|
17
|
-
// ─────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 将行号限制为有效正整数(最小值 1)
|
|
21
|
-
* @param {number} n 原始行号
|
|
22
|
-
* @returns {number} 安全的 1-based 行号
|
|
23
|
-
*/
|
|
24
|
-
function _safeLine(n) {
|
|
25
|
-
return Number.isFinite(n) && n > 0 ? n : 1;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* 执行 osascript 并返回是否成功
|
|
30
|
-
* @param {string[]} args osascript 参数数组(每对 `-e`, `script`)
|
|
31
|
-
* @returns {boolean}
|
|
32
|
-
*/
|
|
33
|
-
function _run(args) {
|
|
34
|
-
try {
|
|
35
|
-
const res = spawnSync('osascript', args, { stdio: 'ignore', timeout: OSASCRIPT_TIMEOUT });
|
|
36
|
-
return res.status === 0;
|
|
37
|
-
} catch {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// ─────────────────────────────────────────────
|
|
43
|
-
// 状态查询
|
|
44
|
-
// ─────────────────────────────────────────────
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 检查 Xcode 是否正在运行(不会启动 Xcode)
|
|
48
|
-
*/
|
|
49
|
-
export function isXcodeRunning() {
|
|
50
|
-
if (process.platform !== 'darwin') return false;
|
|
51
|
-
try {
|
|
52
|
-
const result = execSync('pgrep -x Xcode', {
|
|
53
|
-
encoding: 'utf8',
|
|
54
|
-
timeout: 2000,
|
|
55
|
-
stdio: 'pipe',
|
|
56
|
-
});
|
|
57
|
-
return result.trim().length > 0;
|
|
58
|
-
} catch {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 检查 Xcode 是否为当前前台应用
|
|
65
|
-
*/
|
|
66
|
-
export function isXcodeFrontmost() {
|
|
67
|
-
if (!isXcodeRunning()) return false;
|
|
68
|
-
try {
|
|
69
|
-
const result = execSync(
|
|
70
|
-
'osascript -e \'tell application "System Events" to get name of first process whose frontmost is true\'',
|
|
71
|
-
{ encoding: 'utf8', timeout: OSASCRIPT_TIMEOUT, stdio: 'pipe' }
|
|
72
|
-
);
|
|
73
|
-
return result.trim() === 'Xcode';
|
|
74
|
-
} catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// ─────────────────────────────────────────────
|
|
80
|
-
// 行操作
|
|
81
|
-
// ─────────────────────────────────────────────
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 跳转到指定行
|
|
85
|
-
*
|
|
86
|
-
* 按键序列:Cmd+L → 输入行号 → Return
|
|
87
|
-
*
|
|
88
|
-
* @param {number} lineNumber 1-based 行号
|
|
89
|
-
* @returns {boolean} 是否成功
|
|
90
|
-
*/
|
|
91
|
-
export function jumpToLineInXcode(lineNumber) {
|
|
92
|
-
if (!isXcodeRunning()) return false;
|
|
93
|
-
const n = _safeLine(lineNumber);
|
|
94
|
-
return _run([
|
|
95
|
-
'-e', 'tell application "Xcode" to activate',
|
|
96
|
-
'-e', 'delay 0.2',
|
|
97
|
-
'-e', 'tell application "System Events"',
|
|
98
|
-
'-e', ' keystroke "l" using command down',
|
|
99
|
-
'-e', ' delay 0.2',
|
|
100
|
-
'-e', ` keystroke "${String(n)}"`,
|
|
101
|
-
'-e', ' delay 0.2',
|
|
102
|
-
'-e', ' key code 36',
|
|
103
|
-
'-e', 'end tell',
|
|
104
|
-
]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 剪切指定行的文本内容(不含换行符)
|
|
109
|
-
*
|
|
110
|
-
* 按键序列:Cmd+L 跳转 → Cmd+← 行首 → Cmd+Shift+→ 选到行尾 → Cmd+X 剪切
|
|
111
|
-
*
|
|
112
|
-
* @param {number} lineNumber 1-based 行号
|
|
113
|
-
* @returns {boolean} 是否成功
|
|
114
|
-
*/
|
|
115
|
-
export function cutLineInXcode(lineNumber) {
|
|
116
|
-
if (!isXcodeRunning()) return false;
|
|
117
|
-
const n = _safeLine(lineNumber);
|
|
118
|
-
return _run([
|
|
119
|
-
'-e', 'tell application "Xcode" to activate',
|
|
120
|
-
'-e', 'delay 0.5',
|
|
121
|
-
'-e', 'tell application "System Events"',
|
|
122
|
-
'-e', ' keystroke "l" using command down', // Cmd+L: Go to Line
|
|
123
|
-
'-e', ' delay 0.5',
|
|
124
|
-
'-e', ` keystroke "${String(n)}"`, // 输入行号
|
|
125
|
-
'-e', ' delay 0.5',
|
|
126
|
-
'-e', ' key code 36', // Return
|
|
127
|
-
'-e', ' delay 0.5',
|
|
128
|
-
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
129
|
-
'-e', ' delay 0.5',
|
|
130
|
-
'-e', ' key code 124 using {command down, shift down}', // Cmd+Shift+→ 选到行尾
|
|
131
|
-
'-e', ' delay 0.5',
|
|
132
|
-
'-e', ' keystroke "x" using command down', // Cmd+X
|
|
133
|
-
'-e', 'end tell',
|
|
134
|
-
]);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* 删除指定行的文本内容(保留空行,不删除行本身)
|
|
139
|
-
*
|
|
140
|
-
* 按键序列:Cmd+L 跳转 → Cmd+← 行首 → Cmd+Shift+→ 选到行尾 → Delete
|
|
141
|
-
*
|
|
142
|
-
* @param {number} lineNumber 1-based 行号
|
|
143
|
-
* @returns {boolean} 是否成功
|
|
144
|
-
*/
|
|
145
|
-
export function deleteLineContentInXcode(lineNumber) {
|
|
146
|
-
if (!isXcodeRunning()) return false;
|
|
147
|
-
const n = _safeLine(lineNumber);
|
|
148
|
-
return _run([
|
|
149
|
-
'-e', 'tell application "Xcode" to activate',
|
|
150
|
-
'-e', 'delay 0.3',
|
|
151
|
-
'-e', 'tell application "System Events"',
|
|
152
|
-
'-e', ' keystroke "l" using command down',
|
|
153
|
-
'-e', ' delay 0.3',
|
|
154
|
-
'-e', ` keystroke "${String(n)}"`,
|
|
155
|
-
'-e', ' delay 0.3',
|
|
156
|
-
'-e', ' key code 36',
|
|
157
|
-
'-e', ' delay 0.3',
|
|
158
|
-
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
159
|
-
'-e', ' delay 0.2',
|
|
160
|
-
'-e', ' key code 124 using {command down, shift down}', // Cmd+Shift+→ 选到行尾
|
|
161
|
-
'-e', ' delay 0.2',
|
|
162
|
-
'-e', ' key code 51', // Delete 键
|
|
163
|
-
'-e', ' delay 0.3',
|
|
164
|
-
'-e', 'end tell',
|
|
165
|
-
]);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ─────────────────────────────────────────────
|
|
169
|
-
// 粘贴操作
|
|
170
|
-
// ─────────────────────────────────────────────
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* 执行粘贴(Cmd+V)
|
|
174
|
-
*
|
|
175
|
-
* 调用前须确保剪贴板已写入目标内容。
|
|
176
|
-
* @returns {boolean} 是否成功
|
|
177
|
-
*/
|
|
178
|
-
export function pasteInXcode() {
|
|
179
|
-
if (!isXcodeRunning()) return false;
|
|
180
|
-
return _run([
|
|
181
|
-
'-e', 'tell application "Xcode" to activate',
|
|
182
|
-
'-e', 'delay 0.2',
|
|
183
|
-
'-e', 'tell application "System Events"',
|
|
184
|
-
'-e', ' keystroke "v" using command down',
|
|
185
|
-
'-e', 'end tell',
|
|
186
|
-
]);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 选中当前行内容后粘贴替换
|
|
191
|
-
*
|
|
192
|
-
* 假设光标已在目标行(通常由 jumpToLineInXcode 定位后调用)。
|
|
193
|
-
* 按键序列:Cmd+← 行首 → Cmd+Shift+→ 选到行尾 → Cmd+V 粘贴替换
|
|
194
|
-
*
|
|
195
|
-
* @returns {boolean} 是否成功
|
|
196
|
-
*/
|
|
197
|
-
export function selectAndPasteInXcode() {
|
|
198
|
-
if (!isXcodeRunning()) return false;
|
|
199
|
-
return _run([
|
|
200
|
-
'-e', 'tell application "Xcode" to activate',
|
|
201
|
-
'-e', 'delay 0.5',
|
|
202
|
-
'-e', 'tell application "System Events"',
|
|
203
|
-
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
204
|
-
'-e', ' delay 0.1',
|
|
205
|
-
'-e', ' key code 124 using {command down, shift down}', // Cmd+Shift+→ 选到行尾
|
|
206
|
-
'-e', ' delay 0.2',
|
|
207
|
-
'-e', ' keystroke "v" using command down', // Cmd+V 粘贴替换
|
|
208
|
-
'-e', 'end tell',
|
|
209
|
-
]);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* 跳转到指定行行首并粘贴剪贴板内容
|
|
214
|
-
*
|
|
215
|
-
* 用于在 import 区域插入新行。
|
|
216
|
-
* 按键序列:Cmd+L → 输入行号 → Return → Cmd+← 行首 → Cmd+V 粘贴
|
|
217
|
-
*
|
|
218
|
-
* @param {number} lineNumber 1-based 行号
|
|
219
|
-
* @returns {boolean} 是否成功
|
|
220
|
-
*/
|
|
221
|
-
export function insertAtLineStartInXcode(lineNumber) {
|
|
222
|
-
if (!isXcodeRunning()) return false;
|
|
223
|
-
const n = _safeLine(lineNumber);
|
|
224
|
-
return _run([
|
|
225
|
-
'-e', 'tell application "Xcode" to activate',
|
|
226
|
-
'-e', 'delay 0.3',
|
|
227
|
-
'-e', 'tell application "System Events"',
|
|
228
|
-
'-e', ' keystroke "l" using command down', // Cmd+L: Go to Line
|
|
229
|
-
'-e', ' delay 0.3',
|
|
230
|
-
'-e', ` keystroke "${String(n)}"`, // 输入行号
|
|
231
|
-
'-e', ' delay 0.3',
|
|
232
|
-
'-e', ' key code 36', // Return
|
|
233
|
-
'-e', ' delay 0.3',
|
|
234
|
-
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
235
|
-
'-e', ' delay 0.2',
|
|
236
|
-
'-e', ' keystroke "v" using command down', // Cmd+V 粘贴
|
|
237
|
-
'-e', ' delay 0.3',
|
|
238
|
-
'-e', 'end tell',
|
|
239
|
-
]);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// ─────────────────────────────────────────────
|
|
243
|
-
// 文档操作
|
|
244
|
-
// ─────────────────────────────────────────────
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* 保存 Xcode 当前活动文档(Cmd+S)
|
|
248
|
-
* @returns {boolean} 是否成功
|
|
249
|
-
*/
|
|
250
|
-
export function saveActiveDocumentInXcode() {
|
|
251
|
-
if (!isXcodeRunning()) return false;
|
|
252
|
-
return _run([
|
|
253
|
-
'-e', 'tell application "Xcode" to activate',
|
|
254
|
-
'-e', 'delay 0.1',
|
|
255
|
-
'-e', 'tell application "System Events"',
|
|
256
|
-
'-e', ' keystroke "s" using command down',
|
|
257
|
-
'-e', 'end tell',
|
|
258
|
-
]);
|
|
259
|
-
}
|
|
2
|
+
* @deprecated Moved to lib/platform/ios/xcode/XcodeAutomation.js
|
|
3
|
+
* This re-export shim maintains backward compatibility.
|
|
4
|
+
*/
|
|
5
|
+
export {
|
|
6
|
+
isXcodeRunning,
|
|
7
|
+
isXcodeFrontmost,
|
|
8
|
+
jumpToLineInXcode,
|
|
9
|
+
cutLineInXcode,
|
|
10
|
+
deleteLineContentInXcode,
|
|
11
|
+
pasteInXcode,
|
|
12
|
+
selectAndPasteInXcode,
|
|
13
|
+
insertAtLineStartInXcode,
|
|
14
|
+
saveActiveDocumentInXcode,
|
|
15
|
+
} from '../../platform/ios/xcode/XcodeAutomation.js';
|
|
@@ -1,31 +1,38 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
1
3
|
import winston from 'winston';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import fs from 'fs';
|
|
4
4
|
|
|
5
5
|
// ChatAgent 相关标签 — 终端高亮显示
|
|
6
|
-
const AGENT_TAGS = [
|
|
6
|
+
const AGENT_TAGS = [
|
|
7
|
+
'ChatAgent',
|
|
8
|
+
'ToolRegistry',
|
|
9
|
+
'SignalCollector',
|
|
10
|
+
'SkillAdvisor',
|
|
11
|
+
'CircuitBreaker',
|
|
12
|
+
'EventAggregator',
|
|
13
|
+
];
|
|
7
14
|
const MUTED_PREFIXES = ['HTTP Request', 'Tool registered:', '📊 性能统计已更新'];
|
|
8
15
|
|
|
9
16
|
// ANSI 颜色常量 — 保证深色终端可读性
|
|
10
17
|
const C = {
|
|
11
|
-
reset:
|
|
12
|
-
dim:
|
|
13
|
-
bold:
|
|
18
|
+
reset: '\x1b[0m',
|
|
19
|
+
dim: '\x1b[2m', // 真正的 dim(用于次要信息)
|
|
20
|
+
bold: '\x1b[1m',
|
|
14
21
|
// 前景色 — 使用亮色变体,深色终端更清晰
|
|
15
|
-
gray:
|
|
16
|
-
cyan:
|
|
17
|
-
green:
|
|
18
|
-
yellow:
|
|
19
|
-
red:
|
|
20
|
-
magenta: '\x1b[95m',
|
|
21
|
-
blue:
|
|
22
|
-
dimGray: '\x1b[2;37m',
|
|
22
|
+
gray: '\x1b[37m', // 白色(替代 90 暗灰)
|
|
23
|
+
cyan: '\x1b[96m', // 亮青
|
|
24
|
+
green: '\x1b[92m', // 亮绿
|
|
25
|
+
yellow: '\x1b[93m', // 亮黄
|
|
26
|
+
red: '\x1b[91m', // 亮红
|
|
27
|
+
magenta: '\x1b[95m', // 亮洋红
|
|
28
|
+
blue: '\x1b[94m', // 亮蓝
|
|
29
|
+
dimGray: '\x1b[2;37m', // dim 白色 — 比 90 在深色背景上更可读
|
|
23
30
|
};
|
|
24
31
|
|
|
25
32
|
const LEVEL_COLORS = {
|
|
26
33
|
error: C.red,
|
|
27
|
-
warn:
|
|
28
|
-
info:
|
|
34
|
+
warn: C.yellow,
|
|
35
|
+
info: C.green,
|
|
29
36
|
debug: C.blue,
|
|
30
37
|
};
|
|
31
38
|
|
|
@@ -37,23 +44,32 @@ const LEVEL_COLORS = {
|
|
|
37
44
|
* - 其他 info/debug: 一行精简格式
|
|
38
45
|
*/
|
|
39
46
|
const compactConsoleFormat = winston.format.printf(({ level, message, timestamp, ...meta }) => {
|
|
40
|
-
const ts = new Date(timestamp).toLocaleTimeString('en-US', {
|
|
47
|
+
const ts = new Date(timestamp).toLocaleTimeString('en-US', {
|
|
48
|
+
hour12: false,
|
|
49
|
+
hour: '2-digit',
|
|
50
|
+
minute: '2-digit',
|
|
51
|
+
second: '2-digit',
|
|
52
|
+
});
|
|
53
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ANSI escape sequence stripping
|
|
41
54
|
const rawLevel = level.replace(/\u001b\[\d+m/g, ''); // 去 ANSI
|
|
42
55
|
const lc = LEVEL_COLORS[rawLevel] || C.gray;
|
|
43
56
|
|
|
44
57
|
// 静音高频噪音日志
|
|
45
|
-
if (rawLevel === 'info' && MUTED_PREFIXES.some(p => message.startsWith(p))) {
|
|
58
|
+
if (rawLevel === 'info' && MUTED_PREFIXES.some((p) => message.startsWith(p))) {
|
|
46
59
|
return ''; // 返回空字符串会被 winston 跳过
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
// 判断是否为 Agent 相关日志
|
|
50
|
-
const isAgentLog = AGENT_TAGS.some(
|
|
63
|
+
const isAgentLog = AGENT_TAGS.some(
|
|
64
|
+
(tag) => message.includes(tag) || message.startsWith(`[${tag}]`)
|
|
65
|
+
);
|
|
51
66
|
|
|
52
67
|
if (isAgentLog) {
|
|
53
68
|
// ChatAgent 日志 — 高亮显示
|
|
54
|
-
const metaStr =
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
const metaStr =
|
|
70
|
+
Object.keys(meta).length > 0
|
|
71
|
+
? ` ${JSON.stringify(meta, null, 0).replace(/"/g, '').replace(/,/g, ', ')}`
|
|
72
|
+
: '';
|
|
57
73
|
return `${C.cyan}${ts}${C.reset} ${C.magenta}⚡ ${message}${C.reset}${metaStr ? `${C.dimGray}${metaStr}${C.reset}` : ''}`;
|
|
58
74
|
}
|
|
59
75
|
|
|
@@ -62,17 +78,20 @@ const compactConsoleFormat = winston.format.printf(({ level, message, timestamp,
|
|
|
62
78
|
const { method, path: reqPath, statusCode, duration } = meta;
|
|
63
79
|
const status = Number(statusCode);
|
|
64
80
|
const sc = status >= 500 ? C.red : status >= 400 ? C.yellow : C.dimGray;
|
|
65
|
-
const dur =
|
|
81
|
+
const dur =
|
|
82
|
+
parseInt(duration) > 1000
|
|
83
|
+
? `${C.yellow}${duration}${C.reset}`
|
|
84
|
+
: `${C.dimGray}${duration}${C.reset}`;
|
|
66
85
|
return `${C.dimGray}${ts}${C.reset} ${lc}${rawLevel}${C.reset} ${C.dimGray}${method}${C.reset} ${C.gray}${reqPath}${C.reset} ${sc}${statusCode}${C.reset} ${dur}`;
|
|
67
86
|
}
|
|
68
87
|
|
|
69
88
|
if (rawLevel === 'warn') {
|
|
70
|
-
const metaStr = Object.keys(meta).length > 0 ?
|
|
89
|
+
const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';
|
|
71
90
|
return `${C.gray}${ts}${C.reset} ${C.yellow}${C.bold}warn${C.reset} ${C.yellow}${message}${C.reset}${metaStr ? `${C.dimGray}${metaStr}${C.reset}` : ''}`;
|
|
72
91
|
}
|
|
73
92
|
|
|
74
93
|
if (rawLevel === 'error') {
|
|
75
|
-
const metaStr = Object.keys(meta).length > 0 ?
|
|
94
|
+
const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';
|
|
76
95
|
return `${C.gray}${ts}${C.reset} ${C.red}${C.bold}error${C.reset} ${C.red}${message}${C.reset}${metaStr ? `${C.dimGray}${metaStr}${C.reset}` : ''}`;
|
|
77
96
|
}
|
|
78
97
|
|
|
@@ -96,7 +115,7 @@ export class Logger {
|
|
|
96
115
|
static getInstance(config = {}) {
|
|
97
116
|
if (!this.instance) {
|
|
98
117
|
const logsDir = config.file?.path || './logs';
|
|
99
|
-
|
|
118
|
+
|
|
100
119
|
// 确保日志目录存在
|
|
101
120
|
if (!fs.existsSync(logsDir)) {
|
|
102
121
|
fs.mkdirSync(logsDir, { recursive: true });
|
|
@@ -111,10 +130,7 @@ export class Logger {
|
|
|
111
130
|
transports.push(
|
|
112
131
|
new winston.transports.Console({
|
|
113
132
|
stderrLevels: ['error', 'warn', 'info', 'debug'],
|
|
114
|
-
format: winston.format.combine(
|
|
115
|
-
winston.format.timestamp(),
|
|
116
|
-
compactConsoleFormat,
|
|
117
|
-
),
|
|
133
|
+
format: winston.format.combine(winston.format.timestamp(), compactConsoleFormat),
|
|
118
134
|
})
|
|
119
135
|
);
|
|
120
136
|
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* 捕获、记录和分析应用程序错误
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
6
8
|
import Logger from '../logging/Logger.js';
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
9
|
|
|
10
10
|
export class ErrorTracker {
|
|
11
11
|
constructor(options = {}) {
|
|
@@ -29,7 +29,9 @@ export class ErrorTracker {
|
|
|
29
29
|
|
|
30
30
|
// 定期生成错误报告(unref 避免阻止进程退出)
|
|
31
31
|
this.reportInterval = setInterval(() => this._generateReport(), 60000);
|
|
32
|
-
if (this.reportInterval.unref)
|
|
32
|
+
if (this.reportInterval.unref) {
|
|
33
|
+
this.reportInterval.unref();
|
|
34
|
+
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -139,10 +141,10 @@ export class ErrorTracker {
|
|
|
139
141
|
const fileName = `errors-${date}.log`;
|
|
140
142
|
const filePath = path.join(this.config.logDirectory, fileName);
|
|
141
143
|
|
|
142
|
-
const logEntry = JSON.stringify({
|
|
144
|
+
const logEntry = `${JSON.stringify({
|
|
143
145
|
...errorData,
|
|
144
146
|
_timestamp: Date.now(),
|
|
145
|
-
})
|
|
147
|
+
})}\n`;
|
|
146
148
|
|
|
147
149
|
fs.appendFileSync(filePath, logEntry, 'utf8');
|
|
148
150
|
} catch (error) {
|
|
@@ -29,7 +29,9 @@ export class PerformanceMonitor {
|
|
|
29
29
|
|
|
30
30
|
// 定期计算统计数据(unref 避免阻止进程退出)
|
|
31
31
|
this.statsInterval = setInterval(() => this.calculateStats(), 30000);
|
|
32
|
-
if (this.statsInterval.unref)
|
|
32
|
+
if (this.statsInterval.unref) {
|
|
33
|
+
this.statsInterval.unref();
|
|
34
|
+
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -79,11 +81,17 @@ export class PerformanceMonitor {
|
|
|
79
81
|
if (!this.metrics.endpoints.has(route)) {
|
|
80
82
|
if (this.metrics.endpoints.size >= 500) {
|
|
81
83
|
// 淘汰最少访问的端点
|
|
82
|
-
let minKey = null,
|
|
84
|
+
let minKey = null,
|
|
85
|
+
minCount = Infinity;
|
|
83
86
|
for (const [k, v] of this.metrics.endpoints) {
|
|
84
|
-
if (v.count < minCount) {
|
|
87
|
+
if (v.count < minCount) {
|
|
88
|
+
minCount = v.count;
|
|
89
|
+
minKey = k;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (minKey) {
|
|
93
|
+
this.metrics.endpoints.delete(minKey);
|
|
85
94
|
}
|
|
86
|
-
if (minKey) this.metrics.endpoints.delete(minKey);
|
|
87
95
|
}
|
|
88
96
|
this.metrics.endpoints.set(route, {
|
|
89
97
|
count: 0,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import * as PathFinder from './PathFinder.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -32,12 +32,18 @@ export function parseImportLine(headerStr) {
|
|
|
32
32
|
* 解析单个 import 的相对路径
|
|
33
33
|
*/
|
|
34
34
|
export async function resolveHeaderRelativePath(headerStr, targetRootDir) {
|
|
35
|
-
if (!targetRootDir)
|
|
35
|
+
if (!targetRootDir) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
36
38
|
const parsed = parseImportLine(headerStr);
|
|
37
|
-
if (!parsed)
|
|
39
|
+
if (!parsed) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
38
42
|
const { moduleName, headerName } = parsed;
|
|
39
43
|
const headerPath = await PathFinder.findSubHeaderPath(targetRootDir, headerName, moduleName);
|
|
40
|
-
if (!headerPath)
|
|
44
|
+
if (!headerPath) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
41
47
|
return path.relative(targetRootDir, headerPath);
|
|
42
48
|
}
|
|
43
49
|
|
|
@@ -48,7 +54,9 @@ export function determineModuleNameFromPath(filePath, packageInfo) {
|
|
|
48
54
|
const relativePath = path.relative(packageInfo.path, filePath);
|
|
49
55
|
const segments = relativePath.split(path.sep);
|
|
50
56
|
for (let i = segments.length - 1; i >= 0; i--) {
|
|
51
|
-
if (packageInfo.targets?.includes(segments[i]))
|
|
57
|
+
if (packageInfo.targets?.includes(segments[i])) {
|
|
58
|
+
return segments[i];
|
|
59
|
+
}
|
|
52
60
|
}
|
|
53
61
|
return packageInfo.targets?.[0] || packageInfo.name || null;
|
|
54
62
|
}
|
|
@@ -71,7 +79,7 @@ export async function resolveHeadersForText(projectRoot, relativePath, text) {
|
|
|
71
79
|
const importRegex = /^(?:#import|import)\s+.*$/gm;
|
|
72
80
|
let headers = (text.match(importRegex) || []).filter(Boolean);
|
|
73
81
|
let headerPaths = targetRootDir
|
|
74
|
-
? await Promise.all(headers.map(h => resolveHeaderRelativePath(h, targetRootDir)))
|
|
82
|
+
? await Promise.all(headers.map((h) => resolveHeaderRelativePath(h, targetRootDir)))
|
|
75
83
|
: [];
|
|
76
84
|
|
|
77
85
|
// 如果 .m/.mm 无 import,尝试推断同名 .h
|
|
@@ -80,10 +88,18 @@ export async function resolveHeadersForText(projectRoot, relativePath, text) {
|
|
|
80
88
|
const headerNameWithoutExt = path.basename(fullPath, ext);
|
|
81
89
|
const packagePath = await PathFinder.findPackageSwiftPath(fullPath);
|
|
82
90
|
const packageInfo = packagePath ? await PathFinder.parsePackageSwift(packagePath) : null;
|
|
83
|
-
if (packageInfo)
|
|
84
|
-
|
|
91
|
+
if (packageInfo) {
|
|
92
|
+
moduleName = determineModuleNameFromPath(fullPath, packageInfo);
|
|
93
|
+
}
|
|
94
|
+
const headerPath = await PathFinder.findSubHeaderPath(
|
|
95
|
+
targetRootDir,
|
|
96
|
+
headerNameWithoutExt,
|
|
97
|
+
moduleName
|
|
98
|
+
);
|
|
85
99
|
if (headerPath) {
|
|
86
|
-
headers = [
|
|
100
|
+
headers = [
|
|
101
|
+
`#import <${moduleName || path.basename(targetRootDir)}/${headerNameWithoutExt}.h>`,
|
|
102
|
+
];
|
|
87
103
|
headerPaths = [path.relative(targetRootDir, headerPath)];
|
|
88
104
|
}
|
|
89
105
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* PathFinder — 轻量级路径发现工具(V2 ESM)
|
|
@@ -21,9 +21,13 @@ export async function findTargetRootDir(filePath) {
|
|
|
21
21
|
return current;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
} catch {
|
|
24
|
+
} catch {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
25
27
|
const parent = path.dirname(current);
|
|
26
|
-
if (parent === current)
|
|
28
|
+
if (parent === current) {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
27
31
|
current = parent;
|
|
28
32
|
}
|
|
29
33
|
return null;
|
|
@@ -36,9 +40,13 @@ export async function findPackageSwiftPath(filePath) {
|
|
|
36
40
|
let current = path.dirname(path.resolve(filePath));
|
|
37
41
|
for (let i = 0; i < 15; i++) {
|
|
38
42
|
const candidate = path.join(current, 'Package.swift');
|
|
39
|
-
if (fs.existsSync(candidate))
|
|
43
|
+
if (fs.existsSync(candidate)) {
|
|
44
|
+
return candidate;
|
|
45
|
+
}
|
|
40
46
|
const parent = path.dirname(current);
|
|
41
|
-
if (parent === current)
|
|
47
|
+
if (parent === current) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
42
50
|
current = parent;
|
|
43
51
|
}
|
|
44
52
|
return null;
|
|
@@ -73,14 +81,18 @@ export async function parsePackageSwift(packagePath) {
|
|
|
73
81
|
* @returns {Promise<string|null>}
|
|
74
82
|
*/
|
|
75
83
|
export async function findSubHeaderPath(rootDir, headerName, moduleName) {
|
|
76
|
-
if (!rootDir || !headerName)
|
|
84
|
+
if (!rootDir || !headerName) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
77
87
|
const target = `${headerName}.h`;
|
|
78
88
|
|
|
79
89
|
// 优先在模块名子目录下找
|
|
80
90
|
if (moduleName) {
|
|
81
91
|
const modDir = path.join(rootDir, 'Sources', moduleName);
|
|
82
92
|
const found = _findFile(modDir, target);
|
|
83
|
-
if (found)
|
|
93
|
+
if (found) {
|
|
94
|
+
return found;
|
|
95
|
+
}
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
// 全局搜索
|
|
@@ -88,18 +100,28 @@ export async function findSubHeaderPath(rootDir, headerName, moduleName) {
|
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
function _findFile(dir, filename, maxDepth = 8, depth = 0) {
|
|
91
|
-
if (depth > maxDepth || !fs.existsSync(dir))
|
|
103
|
+
if (depth > maxDepth || !fs.existsSync(dir)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
92
106
|
try {
|
|
93
107
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
94
|
-
if (entry.name.startsWith('.'))
|
|
108
|
+
if (entry.name.startsWith('.')) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
95
111
|
const full = path.join(dir, entry.name);
|
|
96
|
-
if (entry.isFile() && entry.name === filename)
|
|
112
|
+
if (entry.isFile() && entry.name === filename) {
|
|
113
|
+
return full;
|
|
114
|
+
}
|
|
97
115
|
if (entry.isDirectory()) {
|
|
98
116
|
const found = _findFile(full, filename, maxDepth, depth + 1);
|
|
99
|
-
if (found)
|
|
117
|
+
if (found) {
|
|
118
|
+
return found;
|
|
119
|
+
}
|
|
100
120
|
}
|
|
101
121
|
}
|
|
102
|
-
} catch {
|
|
122
|
+
} catch {
|
|
123
|
+
/* ignore */
|
|
124
|
+
}
|
|
103
125
|
return null;
|
|
104
126
|
}
|
|
105
127
|
|