kmp-api-lookup-mcp 0.1.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 (38) hide show
  1. package/README.md +219 -0
  2. package/dist/config/index.d.ts +4 -0
  3. package/dist/config/index.js +33 -0
  4. package/dist/config/index.js.map +1 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +29 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/indexer/index.d.ts +12 -0
  9. package/dist/indexer/index.js +245 -0
  10. package/dist/indexer/index.js.map +1 -0
  11. package/dist/search-utils.d.ts +10 -0
  12. package/dist/search-utils.js +81 -0
  13. package/dist/search-utils.js.map +1 -0
  14. package/dist/server/createServer.d.ts +11 -0
  15. package/dist/server/createServer.js +30 -0
  16. package/dist/server/createServer.js.map +1 -0
  17. package/dist/server/index.d.ts +2 -0
  18. package/dist/server/index.js +3 -0
  19. package/dist/server/index.js.map +1 -0
  20. package/dist/server/lookupDetail.d.ts +3 -0
  21. package/dist/server/lookupDetail.js +295 -0
  22. package/dist/server/lookupDetail.js.map +1 -0
  23. package/dist/server/lookupService.d.ts +34 -0
  24. package/dist/server/lookupService.js +822 -0
  25. package/dist/server/lookupService.js.map +1 -0
  26. package/dist/server/metadataInspector.d.ts +14 -0
  27. package/dist/server/metadataInspector.js +288 -0
  28. package/dist/server/metadataInspector.js.map +1 -0
  29. package/dist/storage/index.d.ts +58 -0
  30. package/dist/storage/index.js +554 -0
  31. package/dist/storage/index.js.map +1 -0
  32. package/dist/tools/index.d.ts +3 -0
  33. package/dist/tools/index.js +488 -0
  34. package/dist/tools/index.js.map +1 -0
  35. package/dist/types.d.ts +287 -0
  36. package/dist/types.js +2 -0
  37. package/dist/types.js.map +1 -0
  38. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # kmp-api-lookup-mcp
2
+
3
+ MCP server for fast lookup of Kotlin/Native iOS klib APIs.
4
+
5
+ The server indexes local Kotlin/Native platform klibs into a persistent SQLite database and exposes a compact MCP API for symbol lookup and index maintenance.
6
+
7
+ ## Current Scope
8
+
9
+ - TypeScript npm ESM MCP server over stdio
10
+ - Persistent SQLite cache in the user cache directory
11
+ - Discovery of Kotlin/Native prebuilt installations via `KONAN_HOME`, `~/.konan`, or an explicit path
12
+ - Manual index rebuild from `klib dump-metadata-signatures`
13
+ - On-demand enrichment from `klib dump-metadata` for full Kotlin signatures, class hierarchy, and imports
14
+ - Structured JSON MCP responses with short text summaries
15
+
16
+ ## Implemented Tools
17
+
18
+ ### `lookup_symbol`
19
+
20
+ Resolve a Kotlin/Native Apple platform class, member, or top-level platform alias/constant into a compact development card.
21
+
22
+ Input:
23
+
24
+ ```json
25
+ {
26
+ "query": "AVPlayer",
27
+ "frameworks": ["AVFoundation"],
28
+ "detail": "compact",
29
+ "queryKind": "auto"
30
+ }
31
+ ```
32
+
33
+ Behavior:
34
+
35
+ - A class query like `AVPlayer` returns one class card with:
36
+ - full Kotlin class signature
37
+ - superclass and implemented interfaces
38
+ - all constructors, instance methods, and class methods when `detail` is omitted or set to `compact`, grouped by member name to reduce output size
39
+ - a separate `properties` list in compact mode with explicit `accessors.getter` and `accessors.setter` flags when matching getter/setter methods exist for that property
40
+ - compact mode removes only duplicated property accessor methods; it does not trim unrelated methods from the class surface
41
+ - the full direct member set, ObjC bridge extension members, and `Meta` class members when `detail` is set to `full`
42
+ - `requiredImports` for code generation
43
+ - A member query like `AVPlayer.play` or `play` returns a compact grouped card with overload signatures and imports.
44
+ - Exact top-level platform aliases and constants like `AVPlayerStatus`, `AVLayerVideoGravity`, or `AVPlayerItemDidPlayToEndTimeNotification` resolve to package-scoped member cards instead of degrading into fuzzy class matches.
45
+ - If the query is ambiguous, the tool returns a short alternatives list instead of dumping raw search rows.
46
+ - Output intentionally omits noisy fields like DB paths, internal IDs, raw metadata dumps, match stages, and installation paths.
47
+ - `detail` defaults to `compact`. Use `"detail": "full"` only when you really need the entire class surface.
48
+
49
+ ### `get_klib_index_status`
50
+
51
+ Return a compact index summary.
52
+
53
+ Input:
54
+
55
+ ```json
56
+ {}
57
+ ```
58
+
59
+ Output includes:
60
+
61
+ - `ready`
62
+ - discovered Kotlin/Native versions and targets
63
+ - indexed datasets with counts
64
+ - aggregate symbol counts
65
+ - `lastRebuildAt`
66
+
67
+ ### `rebuild_klib_index`
68
+
69
+ Build or refresh the SQLite index from local klibs.
70
+
71
+ Input:
72
+
73
+ ```json
74
+ {
75
+ "kotlinVersion": "2.2.21",
76
+ "target": "ios_simulator_arm64",
77
+ "frameworks": ["Foundation", "UIKit"],
78
+ "force": false,
79
+ "dryRun": false,
80
+ "cleanBefore": true
81
+ }
82
+ ```
83
+
84
+ Rules:
85
+
86
+ - `kotlinVersion` and `konanHome` are optional, but you may provide at most one of them.
87
+ - If both are omitted, the latest discovered local Kotlin/Native installation is used.
88
+ - If `target` is omitted, the server prefers `ios_simulator_arm64`, then `ios_arm64`, then `ios_x64`.
89
+ - If `frameworks` is omitted, the rebuild covers all frameworks for the selected target.
90
+ - `dryRun=true` computes the rebuild plan without writing to SQLite.
91
+ - `force=true` ignores freshness checks.
92
+ - `cleanBefore=true` removes existing rows for the affected frameworks before writing fresh records.
93
+
94
+ ## Storage Layout
95
+
96
+ The server stores data outside the repository.
97
+
98
+ - SQLite DB: user cache dir + `klib-index.sqlite`
99
+ - Service metadata: user cache dir + `state.json`
100
+
101
+ Typical cache locations:
102
+
103
+ - macOS: `~/Library/Caches/kmp-api-lookup-mcp/`
104
+ - Linux: `${XDG_CACHE_HOME:-~/.cache}/kmp-api-lookup-mcp/`
105
+ - Windows: `%LOCALAPPDATA%/kmp-api-lookup-mcp/`
106
+
107
+ ## Discovery Rules
108
+
109
+ Installations are discovered in this order:
110
+
111
+ 1. Explicit `konanHome` argument when a tool provides it
112
+ 2. `KONAN_HOME`
113
+ 3. `~/.konan/kotlin-native-prebuilt-*`
114
+
115
+ Each installation is validated by checking for:
116
+
117
+ - `bin/klib`
118
+ - `klib/platform/`
119
+
120
+ ## MCP Configuration
121
+
122
+ ### Run From Source
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "kmp-api-lookup": {
128
+ "command": "node",
129
+ "args": ["/absolute/path/to/kmp-api-lookup-mcp/dist/index.js"]
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ Optional environment override:
136
+
137
+ ```json
138
+ {
139
+ "mcpServers": {
140
+ "kmp-api-lookup": {
141
+ "command": "node",
142
+ "args": ["/absolute/path/to/kmp-api-lookup-mcp/dist/index.js"],
143
+ "env": {
144
+ "KONAN_HOME": "/Users/you/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.21"
145
+ }
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ ### Run As Installed Binary
152
+
153
+ ```json
154
+ {
155
+ "mcpServers": {
156
+ "kmp-api-lookup": {
157
+ "command": "kmp-api-lookup-mcp"
158
+ }
159
+ }
160
+ }
161
+ ```
162
+
163
+ ## Development
164
+
165
+ ### Scripts
166
+
167
+ - `npm run dev` starts the server from TypeScript sources
168
+ - `npm run build` compiles to `dist/`
169
+ - `npm start` runs the compiled server
170
+ - `npm run typecheck` runs TypeScript type checking
171
+ - `npm test` runs Vitest
172
+ - `npm run test:watch` starts Vitest in watch mode
173
+
174
+ ### Local Workflow
175
+
176
+ ```bash
177
+ npm install
178
+ npm run typecheck
179
+ npm run build
180
+ npm test
181
+ ```
182
+
183
+ ## Publishing
184
+
185
+ npm publication is handled by GitHub Actions.
186
+
187
+ - Push a tag in the form `vX.Y.Z` where `X.Y.Z` matches the `version` in `package.json`.
188
+ - The `Publish Package` workflow validates the package and publishes it to npm.
189
+ - The npm package must be configured for trusted publishing from the `SuLG-ik/kmp-api-lookup-mcp` GitHub repository.
190
+ - See [PUBLISHING.md](./PUBLISHING.md) for the one-time npm setup and the exact release steps.
191
+
192
+ ## Test Coverage
193
+
194
+ The current test suite covers:
195
+
196
+ - MCP tool registration
197
+ - `dump-metadata-signatures` line parsing
198
+ - SQLite storage and search behavior on synthetic fixtures
199
+ - server runtime creation
200
+
201
+ ## Project Structure
202
+
203
+ ```text
204
+ .
205
+ ├── src/
206
+ │ ├── index.ts
207
+ │ ├── config/
208
+ │ ├── indexer/
209
+ │ ├── server/
210
+ │ ├── storage/
211
+ │ ├── tools/
212
+ │ ├── search-utils.ts
213
+ │ └── types.ts
214
+ ├── test/
215
+ ├── package.json
216
+ ├── tsconfig.json
217
+ ├── tsconfig.build.json
218
+ └── vitest.config.ts
219
+ ```
@@ -0,0 +1,4 @@
1
+ import type { ServerConfigSummary } from '../types.js';
2
+ export interface AppConfig extends ServerConfigSummary {
3
+ }
4
+ export declare function loadAppConfig(overrides?: Partial<AppConfig>): AppConfig;
@@ -0,0 +1,33 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ export function loadAppConfig(overrides = {}) {
4
+ const cacheDir = overrides.cacheDir ?? path.join(resolveBaseCacheDir(), 'kmp-api-lookup-mcp');
5
+ return {
6
+ serverName: overrides.serverName ?? 'kmp-api-lookup-mcp',
7
+ version: overrides.version ?? '0.1.0',
8
+ cacheDir,
9
+ dbPath: overrides.dbPath ?? path.join(cacheDir, 'klib-index.sqlite'),
10
+ metadataPath: overrides.metadataPath ?? path.join(cacheDir, 'state.json'),
11
+ konanScanRoot: overrides.konanScanRoot ?? path.join(os.homedir(), '.konan'),
12
+ defaultSearchLimit: overrides.defaultSearchLimit ?? 20,
13
+ defaultMatchMode: overrides.defaultMatchMode ?? 'auto',
14
+ defaultIncludeMetaClasses: overrides.defaultIncludeMetaClasses ?? false,
15
+ defaultIncludeRawSignature: overrides.defaultIncludeRawSignature ?? false,
16
+ storageDriver: overrides.storageDriver ?? 'better-sqlite3',
17
+ freshnessStrategy: overrides.freshnessStrategy
18
+ ?? 'version + target + selected frameworks + source directory mtime',
19
+ autoIndexing: overrides.autoIndexing ?? 'manual-error',
20
+ searchTargetFallback: overrides.searchTargetFallback ?? 'all-indexed-targets',
21
+ searchVersionFallback: overrides.searchVersionFallback ?? 'latest-indexed-version',
22
+ };
23
+ }
24
+ function resolveBaseCacheDir() {
25
+ if (process.platform === 'darwin') {
26
+ return path.join(os.homedir(), 'Library', 'Caches');
27
+ }
28
+ if (process.platform === 'win32') {
29
+ return process.env.LOCALAPPDATA ?? path.join(os.homedir(), 'AppData', 'Local');
30
+ }
31
+ return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), '.cache');
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,MAAM,UAAU,aAAa,CAAC,YAAgC,EAAE;IAC9D,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAE9F,OAAO;QACL,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,oBAAoB;QACxD,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,OAAO;QACrC,QAAQ;QACR,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC;QACpE,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC;QACzE,aAAa,EAAE,SAAS,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC;QAC3E,kBAAkB,EAAE,SAAS,CAAC,kBAAkB,IAAI,EAAE;QACtD,gBAAgB,EAAE,SAAS,CAAC,gBAAgB,IAAI,MAAM;QACtD,yBAAyB,EAAE,SAAS,CAAC,yBAAyB,IAAI,KAAK;QACvE,0BAA0B,EAAE,SAAS,CAAC,0BAA0B,IAAI,KAAK;QACzE,aAAa,EAAE,SAAS,CAAC,aAAa,IAAI,gBAAgB;QAC1D,iBAAiB,EACf,SAAS,CAAC,iBAAiB;eACxB,iEAAiE;QACtE,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,cAAc;QACtD,oBAAoB,EAAE,SAAS,CAAC,oBAAoB,IAAI,qBAAqB;QAC7E,qBAAqB,EAAE,SAAS,CAAC,qBAAqB,IAAI,wBAAwB;KACnF,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB;IAC1B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACjF,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/server';
3
+ import { createServerRuntime } from './server/index.js';
4
+ async function main() {
5
+ const runtime = createServerRuntime();
6
+ const transport = new StdioServerTransport();
7
+ let isShuttingDown = false;
8
+ const shutdown = async (signal) => {
9
+ if (isShuttingDown) {
10
+ return;
11
+ }
12
+ isShuttingDown = true;
13
+ console.error(`Received ${signal}, shutting down kmp-api-lookup-mcp...`);
14
+ await runtime.close();
15
+ };
16
+ process.on('SIGINT', () => {
17
+ void shutdown('SIGINT').finally(() => process.exit(0));
18
+ });
19
+ process.on('SIGTERM', () => {
20
+ void shutdown('SIGTERM').finally(() => process.exit(0));
21
+ });
22
+ await runtime.server.connect(transport);
23
+ console.error('kmp-api-lookup-mcp server running on stdio');
24
+ }
25
+ await main().catch((error) => {
26
+ console.error('Fatal error while starting kmp-api-lookup-mcp:', error);
27
+ process.exit(1);
28
+ });
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,cAAc,GAAG,IAAI,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,YAAY,MAAM,uCAAuC,CAAC,CAAC;QACzE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACpC,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AppConfig } from '../config/index.js';
2
+ import type { DiscoveredInstallation, FrameworkSource, ParsedSignatureRecord } from '../types.js';
3
+ export declare function discoverKotlinNativeInstallations(config: AppConfig, explicitKonanHome?: string, options?: {
4
+ onlyExplicit?: boolean;
5
+ }): Promise<DiscoveredInstallation[]>;
6
+ export declare function listFrameworkSources(installation: DiscoveredInstallation, target: string, requestedFrameworks?: string[]): Promise<FrameworkSource[]>;
7
+ export declare function parseSignatureLine(line: string): ParsedSignatureRecord | null;
8
+ export declare function dumpFrameworkSignatures(installation: DiscoveredInstallation, framework: FrameworkSource): Promise<{
9
+ lineCount: number;
10
+ records: ParsedSignatureRecord[];
11
+ }>;
12
+ export declare function dumpFrameworkMetadata(installation: DiscoveredInstallation, framework: FrameworkSource): Promise<string[]>;
@@ -0,0 +1,245 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { access, readdir, realpath, stat } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { promisify } from 'node:util';
5
+ import { compactSelector, compareVersionStrings, normalizeSelector, uniqueSorted } from '../search-utils.js';
6
+ const execFileAsync = promisify(execFile);
7
+ const FRAMEWORK_PREFIX = 'org.jetbrains.kotlin.native.platform.';
8
+ export async function discoverKotlinNativeInstallations(config, explicitKonanHome, options = {}) {
9
+ const candidates = new Map();
10
+ const installations = new Map();
11
+ const addCandidate = (candidatePath, source) => {
12
+ const resolvedPath = path.resolve(candidatePath);
13
+ const sources = candidates.get(resolvedPath) ?? new Set();
14
+ sources.add(source);
15
+ candidates.set(resolvedPath, sources);
16
+ };
17
+ if (explicitKonanHome) {
18
+ addCandidate(explicitKonanHome, 'explicit');
19
+ }
20
+ if (!options.onlyExplicit) {
21
+ if (process.env.KONAN_HOME) {
22
+ addCandidate(process.env.KONAN_HOME, 'env');
23
+ }
24
+ try {
25
+ const scanEntries = await readdir(config.konanScanRoot, { withFileTypes: true });
26
+ for (const entry of scanEntries) {
27
+ if (entry.isDirectory() && entry.name.startsWith('kotlin-native-prebuilt-')) {
28
+ addCandidate(path.join(config.konanScanRoot, entry.name), 'scan');
29
+ }
30
+ }
31
+ }
32
+ catch {
33
+ // Ignore missing ~/.konan roots.
34
+ }
35
+ }
36
+ for (const [candidatePath, sources] of candidates.entries()) {
37
+ const installation = await inspectKonanHome(candidatePath, [...sources]);
38
+ if (!installation) {
39
+ continue;
40
+ }
41
+ const existing = installations.get(installation.konanHome);
42
+ if (existing) {
43
+ installations.set(installation.konanHome, {
44
+ ...existing,
45
+ sources: uniqueSorted([...existing.sources, ...installation.sources]),
46
+ });
47
+ }
48
+ else {
49
+ installations.set(installation.konanHome, installation);
50
+ }
51
+ }
52
+ return [...installations.values()].sort((left, right) => {
53
+ const versionOrder = compareVersionStrings(right.kotlinVersion, left.kotlinVersion);
54
+ if (versionOrder !== 0) {
55
+ return versionOrder;
56
+ }
57
+ return left.konanHome.localeCompare(right.konanHome);
58
+ });
59
+ }
60
+ export async function listFrameworkSources(installation, target, requestedFrameworks) {
61
+ const targetRoot = path.join(installation.platformRootPath, target);
62
+ const entries = await readdir(targetRoot, { withFileTypes: true });
63
+ const availableFrameworks = new Map();
64
+ for (const entry of entries) {
65
+ if (!entry.isDirectory() || !entry.name.startsWith(FRAMEWORK_PREFIX)) {
66
+ continue;
67
+ }
68
+ const frameworkName = entry.name.slice(FRAMEWORK_PREFIX.length);
69
+ availableFrameworks.set(frameworkName, path.join(targetRoot, entry.name));
70
+ }
71
+ const selectedFrameworks = requestedFrameworks ?? [...availableFrameworks.keys()];
72
+ const missingFrameworks = selectedFrameworks.filter((framework) => !availableFrameworks.has(framework));
73
+ if (missingFrameworks.length > 0) {
74
+ throw new Error(`Frameworks not found for target ${target}: ${missingFrameworks.join(', ')}`);
75
+ }
76
+ const frameworkSources = [];
77
+ for (const frameworkName of uniqueSorted(selectedFrameworks)) {
78
+ const directoryPath = availableFrameworks.get(frameworkName);
79
+ if (!directoryPath) {
80
+ continue;
81
+ }
82
+ const frameworkStat = await stat(directoryPath);
83
+ frameworkSources.push({
84
+ name: frameworkName,
85
+ directoryPath,
86
+ sourceMtimeMs: frameworkStat.mtimeMs,
87
+ });
88
+ }
89
+ return frameworkSources;
90
+ }
91
+ export function parseSignatureLine(line) {
92
+ const trimmedLine = line.trim();
93
+ if (!trimmedLine) {
94
+ return null;
95
+ }
96
+ const classMatch = trimmedLine.match(/^(?<container>[^|]+)\|null\[(?<version>\d+)\]$/);
97
+ if (classMatch?.groups) {
98
+ const [packageName, symbolPath] = classMatch.groups.container.split('/', 2);
99
+ if (!packageName || !symbolPath) {
100
+ return null;
101
+ }
102
+ const framework = packageName.startsWith('platform.')
103
+ ? packageName.slice('platform.'.length)
104
+ : packageName;
105
+ const memberName = symbolPath.includes('.') ? symbolPath.slice(symbolPath.lastIndexOf('.') + 1) : symbolPath;
106
+ return {
107
+ framework,
108
+ packageName,
109
+ className: symbolPath,
110
+ memberName,
111
+ memberSearchName: memberName,
112
+ memberKind: 'class',
113
+ declarationForm: 'class',
114
+ objcSelector: null,
115
+ objcSelectorNormalized: null,
116
+ objcSelectorCompact: null,
117
+ rawSignature: trimmedLine,
118
+ isMetaClass: symbolPath.endsWith('Meta'),
119
+ };
120
+ }
121
+ const propertyMatch = trimmedLine.match(/^(?<container>[^|]+)\|\{\}(?<property>[^\[]+)\[(?<version>\d+)\]$/);
122
+ if (propertyMatch?.groups) {
123
+ const [packageName, symbolPath] = propertyMatch.groups.container.split('/', 2);
124
+ if (!packageName || !symbolPath) {
125
+ return null;
126
+ }
127
+ const dotIndex = symbolPath.lastIndexOf('.');
128
+ const className = dotIndex >= 0 ? symbolPath.slice(0, dotIndex) : null;
129
+ const memberName = propertyMatch.groups.property;
130
+ if (memberName.startsWith('<get-') || memberName.startsWith('<set-')) {
131
+ return null;
132
+ }
133
+ const framework = packageName.startsWith('platform.')
134
+ ? packageName.slice('platform.'.length)
135
+ : packageName;
136
+ return {
137
+ framework,
138
+ packageName,
139
+ className,
140
+ memberName,
141
+ memberSearchName: memberName,
142
+ memberKind: 'member',
143
+ declarationForm: 'direct_member',
144
+ objcSelector: null,
145
+ objcSelectorNormalized: null,
146
+ objcSelectorCompact: null,
147
+ rawSignature: trimmedLine,
148
+ isMetaClass: className?.endsWith('Meta') ?? false,
149
+ };
150
+ }
151
+ const lineMatch = trimmedLine.match(/^(?<container>[^|]+)\|(?:(?<receiver>.+)\.)?objc:(?<selector>[^\[]+)\[(?<version>\d+)\]$/);
152
+ if (!lineMatch?.groups) {
153
+ return null;
154
+ }
155
+ const [packageName, symbolPath] = lineMatch.groups.container.split('/', 2);
156
+ if (!packageName || !symbolPath) {
157
+ return null;
158
+ }
159
+ const dotIndex = symbolPath.lastIndexOf('.');
160
+ const className = lineMatch.groups.receiver ?? (dotIndex >= 0 ? symbolPath.slice(0, dotIndex) : null);
161
+ const memberName = dotIndex >= 0 ? symbolPath.slice(dotIndex + 1) : symbolPath;
162
+ if (memberName.startsWith('<get-') || memberName.startsWith('<set-')) {
163
+ return null;
164
+ }
165
+ const normalizedSelector = lineMatch.groups.selector.replace(/#Constructor$/, '');
166
+ const framework = packageName.startsWith('platform.')
167
+ ? packageName.slice('platform.'.length)
168
+ : packageName;
169
+ return {
170
+ framework,
171
+ packageName,
172
+ className,
173
+ memberName,
174
+ memberSearchName: memberName === '<init>' ? 'init' : memberName,
175
+ memberKind: memberName === '<init>' ? 'constructor' : 'member',
176
+ declarationForm: lineMatch.groups.receiver ? 'objc_bridge_extension' : 'direct_member',
177
+ objcSelector: normalizedSelector,
178
+ objcSelectorNormalized: normalizeSelector(normalizedSelector),
179
+ objcSelectorCompact: compactSelector(normalizedSelector),
180
+ rawSignature: trimmedLine,
181
+ isMetaClass: className?.endsWith('Meta') ?? false,
182
+ };
183
+ }
184
+ export async function dumpFrameworkSignatures(installation, framework) {
185
+ try {
186
+ const { stdout } = await execFileAsync(installation.klibBinaryPath, ['dump-metadata-signatures', framework.directoryPath], {
187
+ encoding: 'utf8',
188
+ maxBuffer: 64 * 1024 * 1024,
189
+ });
190
+ const lines = stdout.split(/\r?\n/).filter(Boolean);
191
+ return {
192
+ lineCount: lines.length,
193
+ records: lines
194
+ .map((line) => parseSignatureLine(line))
195
+ .filter((record) => record !== null),
196
+ };
197
+ }
198
+ catch (error) {
199
+ const message = error instanceof Error ? error.message : String(error);
200
+ throw new Error(`Failed to dump metadata signatures for ${framework.name}: ${message}`);
201
+ }
202
+ }
203
+ export async function dumpFrameworkMetadata(installation, framework) {
204
+ try {
205
+ const { stdout } = await execFileAsync(installation.klibBinaryPath, ['dump-metadata', framework.directoryPath, '-print-signatures', 'true'], {
206
+ encoding: 'utf8',
207
+ maxBuffer: 64 * 1024 * 1024,
208
+ });
209
+ return stdout.split(/\r?\n/);
210
+ }
211
+ catch (error) {
212
+ const message = error instanceof Error ? error.message : String(error);
213
+ throw new Error(`Failed to dump metadata for ${framework.name}: ${message}`);
214
+ }
215
+ }
216
+ async function inspectKonanHome(konanHome, sources) {
217
+ try {
218
+ const resolvedKonanHome = await realpath(konanHome);
219
+ const klibBinaryPath = path.join(resolvedKonanHome, 'bin', 'klib');
220
+ const platformRootPath = path.join(resolvedKonanHome, 'klib', 'platform');
221
+ await access(klibBinaryPath);
222
+ await access(platformRootPath);
223
+ const targetEntries = await readdir(platformRootPath, { withFileTypes: true });
224
+ return {
225
+ kotlinVersion: parseVersionFromKonanHome(resolvedKonanHome),
226
+ konanHome: resolvedKonanHome,
227
+ klibBinaryPath,
228
+ platformRootPath,
229
+ availableTargets: uniqueSorted(targetEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name)),
230
+ sources: uniqueSorted(sources),
231
+ };
232
+ }
233
+ catch {
234
+ return null;
235
+ }
236
+ }
237
+ function parseVersionFromKonanHome(konanHome) {
238
+ const baseName = path.basename(konanHome);
239
+ const versionMatch = baseName.match(/-(\d+\.\d+\.\d+(?:[-A-Za-z0-9.]+)?)$/);
240
+ if (versionMatch) {
241
+ return versionMatch[1];
242
+ }
243
+ return baseName.replace(/^kotlin-native-prebuilt-/, '');
244
+ }
245
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare function normalizeText(value: string): string;
2
+ export declare function normalizeSelector(value: string | null | undefined): string | null;
3
+ export declare function compactSelector(value: string | null | undefined): string | null;
4
+ export declare function tokenizeSearchText(value: string): string[];
5
+ export declare function buildFtsQuery(value: string): string | null;
6
+ export declare function escapeLikePattern(value: string): string;
7
+ export declare function uniqueSorted(values: readonly string[]): string[];
8
+ export declare function compareVersionStrings(left: string, right: string): number;
9
+ export declare function pickLatestVersion(values: readonly string[]): string | null;
10
+ export declare function toIsoNow(): string;
@@ -0,0 +1,81 @@
1
+ export function normalizeText(value) {
2
+ return value.trim().toLowerCase();
3
+ }
4
+ export function normalizeSelector(value) {
5
+ if (!value) {
6
+ return null;
7
+ }
8
+ return normalizeText(value);
9
+ }
10
+ export function compactSelector(value) {
11
+ if (!value) {
12
+ return null;
13
+ }
14
+ return normalizeText(value).replace(/:/g, '');
15
+ }
16
+ export function tokenizeSearchText(value) {
17
+ const withCamelCaseSplit = value.replace(/([a-z0-9])([A-Z])/g, '$1 $2');
18
+ const normalized = withCamelCaseSplit
19
+ .toLowerCase()
20
+ .replace(/[^a-z0-9]+/g, ' ')
21
+ .trim();
22
+ if (!normalized) {
23
+ return [];
24
+ }
25
+ return [...new Set(normalized.split(/\s+/).filter(Boolean))];
26
+ }
27
+ export function buildFtsQuery(value) {
28
+ const tokens = tokenizeSearchText(value);
29
+ if (tokens.length === 0) {
30
+ return null;
31
+ }
32
+ return tokens.map((token) => `${token}*`).join(' OR ');
33
+ }
34
+ export function escapeLikePattern(value) {
35
+ return value.replace(/[\\%_]/g, '\\$&');
36
+ }
37
+ export function uniqueSorted(values) {
38
+ return [...new Set(values)].sort((left, right) => left.localeCompare(right));
39
+ }
40
+ export function compareVersionStrings(left, right) {
41
+ const leftParts = splitVersion(left);
42
+ const rightParts = splitVersion(right);
43
+ const maxLength = Math.max(leftParts.numbers.length, rightParts.numbers.length);
44
+ for (let index = 0; index < maxLength; index += 1) {
45
+ const leftNumber = leftParts.numbers[index] ?? 0;
46
+ const rightNumber = rightParts.numbers[index] ?? 0;
47
+ if (leftNumber !== rightNumber) {
48
+ return leftNumber - rightNumber;
49
+ }
50
+ }
51
+ if (!leftParts.suffix && rightParts.suffix) {
52
+ return 1;
53
+ }
54
+ if (leftParts.suffix && !rightParts.suffix) {
55
+ return -1;
56
+ }
57
+ return leftParts.suffix.localeCompare(rightParts.suffix);
58
+ }
59
+ export function pickLatestVersion(values) {
60
+ if (values.length === 0) {
61
+ return null;
62
+ }
63
+ return [...values].sort((left, right) => compareVersionStrings(right, left))[0] ?? null;
64
+ }
65
+ export function toIsoNow() {
66
+ return new Date().toISOString();
67
+ }
68
+ function splitVersion(value) {
69
+ const match = value.match(/(\d+(?:\.\d+)*)(.*)/);
70
+ if (!match) {
71
+ return {
72
+ numbers: [],
73
+ suffix: value.toLowerCase(),
74
+ };
75
+ }
76
+ return {
77
+ numbers: match[1].split('.').map((part) => Number.parseInt(part, 10)),
78
+ suffix: match[2].replace(/^[^a-z0-9]+/i, '').toLowerCase(),
79
+ };
80
+ }
81
+ //# sourceMappingURL=search-utils.js.map