memorydetective 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/README.md +49 -20
  3. package/USAGE.md +39 -23
  4. package/dist/cli.js +1 -1
  5. package/dist/index.js +41 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/runtime/sourcekit/client.d.ts +37 -0
  8. package/dist/runtime/sourcekit/client.js +132 -0
  9. package/dist/runtime/sourcekit/client.js.map +1 -0
  10. package/dist/runtime/sourcekit/pool.d.ts +25 -0
  11. package/dist/runtime/sourcekit/pool.js +101 -0
  12. package/dist/runtime/sourcekit/pool.js.map +1 -0
  13. package/dist/runtime/sourcekit/protocol.d.ts +37 -0
  14. package/dist/runtime/sourcekit/protocol.js +161 -0
  15. package/dist/runtime/sourcekit/protocol.js.map +1 -0
  16. package/dist/tools/swift/_helpers.d.ts +29 -0
  17. package/dist/tools/swift/_helpers.js +64 -0
  18. package/dist/tools/swift/_helpers.js.map +1 -0
  19. package/dist/tools/swift/findSymbolReferences.d.ts +30 -0
  20. package/dist/tools/swift/findSymbolReferences.js +56 -0
  21. package/dist/tools/swift/findSymbolReferences.js.map +1 -0
  22. package/dist/tools/swift/getHoverInfo.d.ts +27 -0
  23. package/dist/tools/swift/getHoverInfo.js +40 -0
  24. package/dist/tools/swift/getHoverInfo.js.map +1 -0
  25. package/dist/tools/swift/getSymbolDefinition.d.ts +46 -0
  26. package/dist/tools/swift/getSymbolDefinition.js +68 -0
  27. package/dist/tools/swift/getSymbolDefinition.js.map +1 -0
  28. package/dist/tools/swift/getSymbolsOverview.d.ts +22 -0
  29. package/dist/tools/swift/getSymbolsOverview.js +33 -0
  30. package/dist/tools/swift/getSymbolsOverview.js.map +1 -0
  31. package/dist/tools/swift/index.d.ts +14 -0
  32. package/dist/tools/swift/index.js +15 -0
  33. package/dist/tools/swift/index.js.map +1 -0
  34. package/dist/tools/swift/searchPattern.d.ts +38 -0
  35. package/dist/tools/swift/searchPattern.js +71 -0
  36. package/dist/tools/swift/searchPattern.js.map +1 -0
  37. package/package.json +3 -1
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Pool of `sourcekit-lsp` clients, keyed by project root.
3
+ *
4
+ * Why a pool: starting `sourcekit-lsp` and waiting for it to be ready costs
5
+ * ~2 seconds. Doing that on every tool call would kill the agent loop.
6
+ * Instead we keep one client alive per project root and reuse it across
7
+ * tool invocations. After an idle window we shut it down so we're not
8
+ * blocking the user's build/test pipeline.
9
+ */
10
+ import { existsSync, readdirSync, realpathSync } from "node:fs";
11
+ import { resolve as resolvePath } from "node:path";
12
+ import { createSourceKitClient, } from "./client.js";
13
+ const DEFAULT_IDLE_MS = 5 * 60_000; // 5 minutes
14
+ const pool = new Map();
15
+ /** Resolve a file path to its enclosing project root by walking up to the
16
+ * nearest `Package.swift`, `*.xcodeproj`, or `*.xcworkspace`. Falls back
17
+ * to the file's directory if nothing is found. */
18
+ export function projectRootFor(filePath) {
19
+ let dir = resolvePath(filePath);
20
+ try {
21
+ dir = realpathSync(dir);
22
+ }
23
+ catch { }
24
+ let prev = "";
25
+ while (dir !== prev) {
26
+ if (dirHas(dir, "Package.swift") ||
27
+ dirHasGlob(dir, ".xcodeproj") ||
28
+ dirHasGlob(dir, ".xcworkspace")) {
29
+ return dir;
30
+ }
31
+ prev = dir;
32
+ dir = resolvePath(dir, "..");
33
+ }
34
+ // No marker found — use the original directory.
35
+ return resolvePath(filePath, "..");
36
+ }
37
+ function dirHas(dir, name) {
38
+ try {
39
+ return existsSync(resolvePath(dir, name));
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ function dirHasGlob(dir, suffix) {
46
+ try {
47
+ return readdirSync(dir).some((entry) => entry.endsWith(suffix));
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /** Acquire an LSP client for a project root. Reuses an existing one if
54
+ * warm, spawns + initializes one otherwise. */
55
+ export async function acquireClient(projectRoot, opts = {}) {
56
+ const key = resolvePath(projectRoot);
57
+ const idleMs = opts.idleMs ?? DEFAULT_IDLE_MS;
58
+ let entry = pool.get(key);
59
+ if (!entry) {
60
+ const client = await createSourceKitClient({ projectRoot: key });
61
+ entry = { client, lastUsed: Date.now() };
62
+ pool.set(key, entry);
63
+ }
64
+ entry.lastUsed = Date.now();
65
+ if (entry.idleTimer)
66
+ clearTimeout(entry.idleTimer);
67
+ entry.idleTimer = setTimeout(() => {
68
+ void shutdownClient(key);
69
+ }, idleMs);
70
+ return entry.client;
71
+ }
72
+ /** Manually shut down the client for a given project root. */
73
+ export async function shutdownClient(projectRoot) {
74
+ const key = resolvePath(projectRoot);
75
+ const entry = pool.get(key);
76
+ if (!entry)
77
+ return;
78
+ pool.delete(key);
79
+ if (entry.idleTimer)
80
+ clearTimeout(entry.idleTimer);
81
+ await entry.client.dispose();
82
+ }
83
+ /** Shut down all pooled clients. Useful in tests + on process exit. */
84
+ export async function shutdownAll() {
85
+ const keys = Array.from(pool.keys());
86
+ for (const key of keys) {
87
+ await shutdownClient(key);
88
+ }
89
+ }
90
+ // Best-effort cleanup on process exit.
91
+ process.once("exit", () => {
92
+ // Synchronous only — async cleanups won't run here, but the OS will
93
+ // reap the subprocess.
94
+ });
95
+ process.once("SIGINT", () => {
96
+ void shutdownAll().finally(() => process.exit(0));
97
+ });
98
+ process.once("SIGTERM", () => {
99
+ void shutdownAll().finally(() => process.exit(0));
100
+ });
101
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../../src/runtime/sourcekit/pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Typed wrappers around the LSP methods we use.
3
+ *
4
+ * Imports types from `vscode-languageserver-protocol` and converts to/from
5
+ * the file:// URI format LSP servers expect. All paths in the public API
6
+ * are absolute filesystem paths; LSP URIs only show up internally.
7
+ */
8
+ import type { InitializedClient } from "./client.js";
9
+ export interface SourceLocation {
10
+ filePath: string;
11
+ line: number;
12
+ character: number;
13
+ /** Optional end position when the LSP server returns a range. */
14
+ endLine?: number;
15
+ endCharacter?: number;
16
+ }
17
+ export interface ResolvedSymbol {
18
+ name: string;
19
+ kind: string;
20
+ filePath: string;
21
+ startLine: number;
22
+ startCharacter: number;
23
+ endLine: number;
24
+ endCharacter: number;
25
+ /** Children symbols (methods inside a class, properties, etc.) when hierarchical. */
26
+ children?: ResolvedSymbol[];
27
+ }
28
+ /** LSP `textDocument/definition` — returns 0+ source locations. */
29
+ export declare function lspDefinition(client: InitializedClient, filePath: string, line: number, character: number): Promise<SourceLocation[]>;
30
+ /** LSP `textDocument/references` — returns all references in indexed projects. */
31
+ export declare function lspReferences(client: InitializedClient, filePath: string, line: number, character: number, includeDeclaration?: boolean): Promise<SourceLocation[]>;
32
+ /** LSP `textDocument/hover` — returns type info / docs at a position. */
33
+ export declare function lspHover(client: InitializedClient, filePath: string, line: number, character: number): Promise<{
34
+ contents: string;
35
+ } | null>;
36
+ /** LSP `textDocument/documentSymbol` — returns top-level + nested symbols. */
37
+ export declare function lspDocumentSymbol(client: InitializedClient, filePath: string): Promise<ResolvedSymbol[]>;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Typed wrappers around the LSP methods we use.
3
+ *
4
+ * Imports types from `vscode-languageserver-protocol` and converts to/from
5
+ * the file:// URI format LSP servers expect. All paths in the public API
6
+ * are absolute filesystem paths; LSP URIs only show up internally.
7
+ */
8
+ import { resolve as resolvePath } from "node:path";
9
+ import { pathToFileURL, fileURLToPath } from "node:url";
10
+ import { SymbolKind, } from "vscode-languageserver-protocol";
11
+ const SYMBOL_KIND_NAMES = {
12
+ [SymbolKind.File]: "file",
13
+ [SymbolKind.Module]: "module",
14
+ [SymbolKind.Namespace]: "namespace",
15
+ [SymbolKind.Package]: "package",
16
+ [SymbolKind.Class]: "class",
17
+ [SymbolKind.Method]: "method",
18
+ [SymbolKind.Property]: "property",
19
+ [SymbolKind.Field]: "field",
20
+ [SymbolKind.Constructor]: "constructor",
21
+ [SymbolKind.Enum]: "enum",
22
+ [SymbolKind.Interface]: "interface",
23
+ [SymbolKind.Function]: "function",
24
+ [SymbolKind.Variable]: "variable",
25
+ [SymbolKind.Constant]: "constant",
26
+ [SymbolKind.String]: "string",
27
+ [SymbolKind.Number]: "number",
28
+ [SymbolKind.Boolean]: "boolean",
29
+ [SymbolKind.Array]: "array",
30
+ [SymbolKind.Object]: "object",
31
+ [SymbolKind.Key]: "key",
32
+ [SymbolKind.Null]: "null",
33
+ [SymbolKind.EnumMember]: "enum-member",
34
+ [SymbolKind.Struct]: "struct",
35
+ [SymbolKind.Event]: "event",
36
+ [SymbolKind.Operator]: "operator",
37
+ [SymbolKind.TypeParameter]: "type-parameter",
38
+ };
39
+ function uriOf(filePath) {
40
+ return pathToFileURL(resolvePath(filePath)).href;
41
+ }
42
+ function pathOf(uri) {
43
+ return fileURLToPath(uri);
44
+ }
45
+ /** LSP `textDocument/definition` — returns 0+ source locations. */
46
+ export async function lspDefinition(client, filePath, line, character) {
47
+ client.didOpen(filePath);
48
+ const params = {
49
+ textDocument: { uri: uriOf(filePath) },
50
+ position: { line, character },
51
+ };
52
+ const result = await client.sendRequest("textDocument/definition", params);
53
+ return locationsToArray(result);
54
+ }
55
+ /** LSP `textDocument/references` — returns all references in indexed projects. */
56
+ export async function lspReferences(client, filePath, line, character, includeDeclaration = true) {
57
+ client.didOpen(filePath);
58
+ const params = {
59
+ textDocument: { uri: uriOf(filePath) },
60
+ position: { line, character },
61
+ context: { includeDeclaration },
62
+ };
63
+ const result = await client.sendRequest("textDocument/references", params);
64
+ return locationsToArray(result);
65
+ }
66
+ /** LSP `textDocument/hover` — returns type info / docs at a position. */
67
+ export async function lspHover(client, filePath, line, character) {
68
+ client.didOpen(filePath);
69
+ const params = {
70
+ textDocument: { uri: uriOf(filePath) },
71
+ position: { line, character },
72
+ };
73
+ const result = await client.sendRequest("textDocument/hover", params);
74
+ if (!result)
75
+ return null;
76
+ const contents = hoverContentsToString(result.contents);
77
+ return { contents };
78
+ }
79
+ /** LSP `textDocument/documentSymbol` — returns top-level + nested symbols. */
80
+ export async function lspDocumentSymbol(client, filePath) {
81
+ client.didOpen(filePath);
82
+ const params = {
83
+ textDocument: { uri: uriOf(filePath) },
84
+ };
85
+ const result = await client.sendRequest("textDocument/documentSymbol", params);
86
+ if (!result)
87
+ return [];
88
+ // Hierarchical case (DocumentSymbol[]).
89
+ if (result.length > 0 && "range" in result[0] && "children" in result[0]) {
90
+ return result.map((s) => docSymbolToResolved(s, filePath));
91
+ }
92
+ // Flat case (SymbolInformation[]).
93
+ return result.map((s) => symInfoToResolved(s));
94
+ }
95
+ function docSymbolToResolved(s, filePath) {
96
+ return {
97
+ name: s.name,
98
+ kind: SYMBOL_KIND_NAMES[s.kind] ?? `kind-${s.kind}`,
99
+ filePath,
100
+ startLine: s.range.start.line,
101
+ startCharacter: s.range.start.character,
102
+ endLine: s.range.end.line,
103
+ endCharacter: s.range.end.character,
104
+ children: s.children?.map((c) => docSymbolToResolved(c, filePath)),
105
+ };
106
+ }
107
+ function symInfoToResolved(s) {
108
+ return {
109
+ name: s.name,
110
+ kind: SYMBOL_KIND_NAMES[s.kind] ?? `kind-${s.kind}`,
111
+ filePath: pathOf(s.location.uri),
112
+ startLine: s.location.range.start.line,
113
+ startCharacter: s.location.range.start.character,
114
+ endLine: s.location.range.end.line,
115
+ endCharacter: s.location.range.end.character,
116
+ };
117
+ }
118
+ function locationsToArray(result) {
119
+ if (!result)
120
+ return [];
121
+ const arr = Array.isArray(result) ? result : [result];
122
+ const out = [];
123
+ for (const item of arr) {
124
+ if ("targetUri" in item) {
125
+ // LocationLink
126
+ out.push({
127
+ filePath: pathOf(item.targetUri),
128
+ line: item.targetSelectionRange.start.line,
129
+ character: item.targetSelectionRange.start.character,
130
+ endLine: item.targetSelectionRange.end.line,
131
+ endCharacter: item.targetSelectionRange.end.character,
132
+ });
133
+ }
134
+ else {
135
+ // Location
136
+ out.push({
137
+ filePath: pathOf(item.uri),
138
+ line: item.range.start.line,
139
+ character: item.range.start.character,
140
+ endLine: item.range.end.line,
141
+ endCharacter: item.range.end.character,
142
+ });
143
+ }
144
+ }
145
+ return out;
146
+ }
147
+ function hoverContentsToString(c) {
148
+ if (!c)
149
+ return "";
150
+ if (typeof c === "string")
151
+ return c;
152
+ if (Array.isArray(c)) {
153
+ return c
154
+ .map((part) => (typeof part === "string" ? part : part.value))
155
+ .join("\n");
156
+ }
157
+ if ("value" in c)
158
+ return c.value;
159
+ return "";
160
+ }
161
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/runtime/sourcekit/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shared utilities for the Swift source-bridging tools.
3
+ *
4
+ * Position-finding via local regex pre-scan is the load-bearing trick: we
5
+ * locate the symbol's declaration in a candidate file with a quick regex
6
+ * before sending its position to SourceKit-LSP. This avoids LSP's
7
+ * comparatively slow workspace symbol search.
8
+ */
9
+ export interface SymbolPosition {
10
+ line: number;
11
+ character: number;
12
+ matchedText: string;
13
+ }
14
+ /**
15
+ * Find the first declaration of `symbolName` in the file.
16
+ *
17
+ * Looks for the symbol after one of Swift's declaration keywords
18
+ * (`class`, `struct`, `enum`, `protocol`, `func`, `var`, `let`,
19
+ * `actor`, `extension`). Falls back to the first standalone-word
20
+ * occurrence so we still surface a position when the name is referenced
21
+ * but not declared in the file (e.g. an extension method on a type
22
+ * declared elsewhere).
23
+ *
24
+ * Returns 0-based positions matching LSP's convention.
25
+ */
26
+ export declare function findSymbolDeclaration(filePath: string, symbolName: string): SymbolPosition | null;
27
+ export declare function escapeRegex(s: string): string;
28
+ /** Extract a few lines of context around `line` for snippet display. */
29
+ export declare function snippetAt(filePath: string, line: number, padding?: number): string;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Shared utilities for the Swift source-bridging tools.
3
+ *
4
+ * Position-finding via local regex pre-scan is the load-bearing trick: we
5
+ * locate the symbol's declaration in a candidate file with a quick regex
6
+ * before sending its position to SourceKit-LSP. This avoids LSP's
7
+ * comparatively slow workspace symbol search.
8
+ */
9
+ import { readFileSync } from "node:fs";
10
+ /**
11
+ * Find the first declaration of `symbolName` in the file.
12
+ *
13
+ * Looks for the symbol after one of Swift's declaration keywords
14
+ * (`class`, `struct`, `enum`, `protocol`, `func`, `var`, `let`,
15
+ * `actor`, `extension`). Falls back to the first standalone-word
16
+ * occurrence so we still surface a position when the name is referenced
17
+ * but not declared in the file (e.g. an extension method on a type
18
+ * declared elsewhere).
19
+ *
20
+ * Returns 0-based positions matching LSP's convention.
21
+ */
22
+ export function findSymbolDeclaration(filePath, symbolName) {
23
+ const text = readFileSync(filePath, "utf8");
24
+ const lines = text.split(/\r?\n/);
25
+ const declRe = new RegExp(`\\b(?:class|struct|enum|protocol|func|var|let|actor|extension)\\s+${escapeRegex(symbolName)}\\b`);
26
+ for (let i = 0; i < lines.length; i++) {
27
+ const m = lines[i].match(declRe);
28
+ if (m) {
29
+ const ch = lines[i].indexOf(symbolName, m.index ?? 0);
30
+ if (ch >= 0) {
31
+ return { line: i, character: ch, matchedText: lines[i] };
32
+ }
33
+ }
34
+ }
35
+ const wordRe = new RegExp(`\\b${escapeRegex(symbolName)}\\b`);
36
+ for (let i = 0; i < lines.length; i++) {
37
+ const m = lines[i].match(wordRe);
38
+ if (m) {
39
+ return {
40
+ line: i,
41
+ character: m.index ?? 0,
42
+ matchedText: lines[i],
43
+ };
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ export function escapeRegex(s) {
49
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
50
+ }
51
+ /** Extract a few lines of context around `line` for snippet display. */
52
+ export function snippetAt(filePath, line, padding = 1) {
53
+ try {
54
+ const text = readFileSync(filePath, "utf8");
55
+ const lines = text.split(/\r?\n/);
56
+ const start = Math.max(0, line - padding);
57
+ const end = Math.min(lines.length - 1, line + padding);
58
+ return lines.slice(start, end + 1).join("\n");
59
+ }
60
+ catch {
61
+ return "";
62
+ }
63
+ }
64
+ //# sourceMappingURL=_helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_helpers.js","sourceRoot":"","sources":["../../../src/tools/swift/_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQvC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,UAAkB;IAElB,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,qEAAqE,WAAW,CAAC,UAAU,CAAC,KAAK,CAClG,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;YACtD,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACZ,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC;YACN,OAAO;gBACL,IAAI,EAAE,CAAC;gBACP,SAAS,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;gBACvB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;aACtB,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAY,EAAE,OAAO,GAAG,CAAC;IACnE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ import { type SourceLocation } from "../../runtime/sourcekit/protocol.js";
3
+ export declare const swiftFindSymbolReferencesSchema: z.ZodObject<{
4
+ symbolName: z.ZodString;
5
+ filePath: z.ZodString;
6
+ projectRoot: z.ZodOptional<z.ZodString>;
7
+ includeDeclaration: z.ZodDefault<z.ZodBoolean>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ symbolName: string;
10
+ filePath: string;
11
+ includeDeclaration: boolean;
12
+ projectRoot?: string | undefined;
13
+ }, {
14
+ symbolName: string;
15
+ filePath: string;
16
+ projectRoot?: string | undefined;
17
+ includeDeclaration?: boolean | undefined;
18
+ }>;
19
+ export type SwiftFindSymbolReferencesInput = z.infer<typeof swiftFindSymbolReferencesSchema>;
20
+ export interface SwiftFindSymbolReferencesResult {
21
+ ok: boolean;
22
+ symbolName: string;
23
+ totalReferences: number;
24
+ references: Array<SourceLocation & {
25
+ snippet?: string;
26
+ }>;
27
+ /** True when the IndexStoreDB was missing — references are likely incomplete. Build the index with `swift build -Xswiftc -index-store-path -Xswiftc <project>/.build/index/store`. */
28
+ needsIndex?: boolean;
29
+ }
30
+ export declare function swiftFindSymbolReferences(input: SwiftFindSymbolReferencesInput): Promise<SwiftFindSymbolReferencesResult>;
@@ -0,0 +1,56 @@
1
+ import { z } from "zod";
2
+ import { existsSync } from "node:fs";
3
+ import { resolve as resolvePath } from "node:path";
4
+ import { acquireClient, projectRootFor } from "../../runtime/sourcekit/pool.js";
5
+ import { lspReferences, } from "../../runtime/sourcekit/protocol.js";
6
+ import { findSymbolDeclaration, snippetAt } from "./_helpers.js";
7
+ export const swiftFindSymbolReferencesSchema = z.object({
8
+ symbolName: z
9
+ .string()
10
+ .min(1)
11
+ .describe("Name of the Swift symbol to find references for."),
12
+ filePath: z
13
+ .string()
14
+ .min(1)
15
+ .describe("Path to a Swift file where the symbol is declared. The LSP query needs a position; we locate it in this file via a regex pre-scan."),
16
+ projectRoot: z
17
+ .string()
18
+ .optional()
19
+ .describe("Override the project root. Default discovers the nearest Package.swift / .xcodeproj / .xcworkspace."),
20
+ includeDeclaration: z
21
+ .boolean()
22
+ .default(true)
23
+ .describe("Include the declaration site itself in the result set."),
24
+ });
25
+ export async function swiftFindSymbolReferences(input) {
26
+ const file = resolvePath(input.filePath);
27
+ if (!existsSync(file)) {
28
+ throw new Error(`File not found: ${file}`);
29
+ }
30
+ const root = input.projectRoot
31
+ ? resolvePath(input.projectRoot)
32
+ : projectRootFor(file);
33
+ const pos = findSymbolDeclaration(file, input.symbolName);
34
+ if (!pos) {
35
+ return {
36
+ ok: true,
37
+ symbolName: input.symbolName,
38
+ totalReferences: 0,
39
+ references: [],
40
+ };
41
+ }
42
+ const client = await acquireClient(root);
43
+ const refs = await lspReferences(client, file, pos.line, pos.character, input.includeDeclaration ?? true);
44
+ const refsWithSnippets = refs.map((r) => ({
45
+ ...r,
46
+ snippet: snippetAt(r.filePath, r.line),
47
+ }));
48
+ return {
49
+ ok: true,
50
+ symbolName: input.symbolName,
51
+ totalReferences: refs.length,
52
+ references: refsWithSnippets,
53
+ needsIndex: refs.length === 0 ? true : undefined,
54
+ };
55
+ }
56
+ //# sourceMappingURL=findSymbolReferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findSymbolReferences.js","sourceRoot":"","sources":["../../../src/tools/swift/findSymbolReferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EACL,aAAa,GAEd,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEjE,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC;IACtD,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,oIAAoI,CACrI;IACH,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,qGAAqG,CACtG;IACH,kBAAkB,EAAE,CAAC;SAClB,OAAO,EAAE;SACT,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,wDAAwD,CAAC;CACtE,CAAC,CAAC;AAeH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAqC;IAErC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW;QAC5B,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;QAChC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAEzB,MAAM,GAAG,GAAG,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO;YACL,EAAE,EAAE,IAAI;YACR,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,eAAe,EAAE,CAAC;YAClB,UAAU,EAAE,EAAE;SACf,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,MAAM,aAAa,CAC9B,MAAM,EACN,IAAI,EACJ,GAAG,CAAC,IAAI,EACR,GAAG,CAAC,SAAS,EACb,KAAK,CAAC,kBAAkB,IAAI,IAAI,CACjC,CAAC;IAEF,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,GAAG,CAAC;QACJ,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC;KACvC,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,EAAE,EAAE,IAAI;QACR,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,eAAe,EAAE,IAAI,CAAC,MAAM;QAC5B,UAAU,EAAE,gBAAgB;QAC5B,UAAU,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;KACjD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ export declare const swiftGetHoverInfoSchema: z.ZodObject<{
3
+ filePath: z.ZodString;
4
+ line: z.ZodNumber;
5
+ character: z.ZodNumber;
6
+ projectRoot: z.ZodOptional<z.ZodString>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ line: number;
9
+ character: number;
10
+ filePath: string;
11
+ projectRoot?: string | undefined;
12
+ }, {
13
+ line: number;
14
+ character: number;
15
+ filePath: string;
16
+ projectRoot?: string | undefined;
17
+ }>;
18
+ export type SwiftGetHoverInfoInput = z.infer<typeof swiftGetHoverInfoSchema>;
19
+ export interface SwiftGetHoverInfoResult {
20
+ ok: boolean;
21
+ filePath: string;
22
+ /** Markdown / plaintext hover content from SourceKit-LSP. */
23
+ contents: string;
24
+ /** Best-effort extracted declaration fragment (e.g. "class DetailViewModel : ObservableObject"). */
25
+ typeName?: string;
26
+ }
27
+ export declare function swiftGetHoverInfo(input: SwiftGetHoverInfoInput): Promise<SwiftGetHoverInfoResult>;
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { existsSync } from "node:fs";
3
+ import { resolve as resolvePath } from "node:path";
4
+ import { acquireClient, projectRootFor } from "../../runtime/sourcekit/pool.js";
5
+ import { lspHover } from "../../runtime/sourcekit/protocol.js";
6
+ export const swiftGetHoverInfoSchema = z.object({
7
+ filePath: z.string().min(1).describe("Absolute path to a Swift source file."),
8
+ line: z
9
+ .number()
10
+ .int()
11
+ .nonnegative()
12
+ .describe("Zero-based line number (LSP convention)."),
13
+ character: z
14
+ .number()
15
+ .int()
16
+ .nonnegative()
17
+ .describe("Zero-based UTF-16 character offset within the line."),
18
+ projectRoot: z.string().optional(),
19
+ });
20
+ export async function swiftGetHoverInfo(input) {
21
+ const file = resolvePath(input.filePath);
22
+ if (!existsSync(file)) {
23
+ throw new Error(`File not found: ${file}`);
24
+ }
25
+ const root = input.projectRoot
26
+ ? resolvePath(input.projectRoot)
27
+ : projectRootFor(file);
28
+ const client = await acquireClient(root);
29
+ const result = await lspHover(client, file, input.line, input.character);
30
+ const contents = result?.contents ?? "";
31
+ const typeName = extractTypeName(contents);
32
+ return { ok: true, filePath: file, contents, typeName };
33
+ }
34
+ function extractTypeName(hover) {
35
+ // Hover output usually leads with a code fence containing the
36
+ // declaration line (e.g. "let foo: Bar" or "class Baz : Quux").
37
+ const m = hover.match(/\b(class|struct|enum|protocol|actor|func|var|let)\s+\S+/);
38
+ return m ? m[0] : undefined;
39
+ }
40
+ //# sourceMappingURL=getHoverInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getHoverInfo.js","sourceRoot":"","sources":["../../../src/tools/swift/getHoverInfo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAE/D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IAC7E,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,WAAW,EAAE;SACb,QAAQ,CAAC,0CAA0C,CAAC;IACvD,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,EAAE;SACL,WAAW,EAAE;SACb,QAAQ,CAAC,qDAAqD,CAAC;IAClE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAaH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAA6B;IAE7B,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW;QAC5B,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;QAChC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC3C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,8DAA8D;IAC9D,gEAAgE;IAChE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CACnB,yDAAyD,CAC1D,CAAC;IACF,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ import { type SourceLocation } from "../../runtime/sourcekit/protocol.js";
3
+ export declare const swiftGetSymbolDefinitionSchema: z.ZodObject<{
4
+ symbolName: z.ZodString;
5
+ hint: z.ZodOptional<z.ZodObject<{
6
+ filePath: z.ZodOptional<z.ZodString>;
7
+ module: z.ZodOptional<z.ZodString>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ module?: string | undefined;
10
+ filePath?: string | undefined;
11
+ }, {
12
+ module?: string | undefined;
13
+ filePath?: string | undefined;
14
+ }>>;
15
+ projectRoot: z.ZodOptional<z.ZodString>;
16
+ candidatePaths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
+ }, "strip", z.ZodTypeAny, {
18
+ symbolName: string;
19
+ hint?: {
20
+ module?: string | undefined;
21
+ filePath?: string | undefined;
22
+ } | undefined;
23
+ projectRoot?: string | undefined;
24
+ candidatePaths?: string[] | undefined;
25
+ }, {
26
+ symbolName: string;
27
+ hint?: {
28
+ module?: string | undefined;
29
+ filePath?: string | undefined;
30
+ } | undefined;
31
+ projectRoot?: string | undefined;
32
+ candidatePaths?: string[] | undefined;
33
+ }>;
34
+ export type SwiftGetSymbolDefinitionInput = z.infer<typeof swiftGetSymbolDefinitionSchema>;
35
+ export interface SwiftGetSymbolDefinitionResult {
36
+ ok: boolean;
37
+ symbolName: string;
38
+ /** Definition locations returned by SourceKit-LSP (or pre-scan when LSP returns nothing). */
39
+ definitions: SourceLocation[];
40
+ /** When set, indicates we located the symbol via filename pre-scan rather than a true LSP query. */
41
+ preScanHit?: {
42
+ filePath: string;
43
+ matchedText: string;
44
+ };
45
+ }
46
+ export declare function swiftGetSymbolDefinition(input: SwiftGetSymbolDefinitionInput): Promise<SwiftGetSymbolDefinitionResult>;