bluera-knowledge 0.9.32 → 0.9.34

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 (196) hide show
  1. package/.claude/hooks/post-edit-check.sh +5 -3
  2. package/.claude/skills/atomic-commits/SKILL.md +3 -1
  3. package/.husky/pre-commit +3 -2
  4. package/.prettierrc +9 -0
  5. package/.versionrc.json +1 -1
  6. package/CHANGELOG.md +33 -0
  7. package/CLAUDE.md +6 -0
  8. package/README.md +25 -13
  9. package/bun.lock +277 -33
  10. package/dist/{chunk-L2YVNC63.js → chunk-6FHWC36B.js} +9 -1
  11. package/dist/chunk-6FHWC36B.js.map +1 -0
  12. package/dist/{chunk-RST4XGRL.js → chunk-DC7CGSGT.js} +288 -241
  13. package/dist/chunk-DC7CGSGT.js.map +1 -0
  14. package/dist/{chunk-6PBP5DVD.js → chunk-WFNPNAAP.js} +3212 -3054
  15. package/dist/chunk-WFNPNAAP.js.map +1 -0
  16. package/dist/{chunk-WT2DAEO7.js → chunk-Z2KKVH45.js} +548 -482
  17. package/dist/chunk-Z2KKVH45.js.map +1 -0
  18. package/dist/index.js +871 -758
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp/server.js +3 -3
  21. package/dist/watch.service-BJV3TI3F.js +7 -0
  22. package/dist/workers/background-worker-cli.js +46 -45
  23. package/dist/workers/background-worker-cli.js.map +1 -1
  24. package/eslint.config.js +43 -1
  25. package/package.json +18 -11
  26. package/plugin.json +8 -0
  27. package/python/requirements.txt +1 -1
  28. package/src/analysis/ast-parser.test.ts +12 -11
  29. package/src/analysis/ast-parser.ts +28 -22
  30. package/src/analysis/code-graph.test.ts +52 -62
  31. package/src/analysis/code-graph.ts +9 -13
  32. package/src/analysis/dependency-usage-analyzer.test.ts +91 -271
  33. package/src/analysis/dependency-usage-analyzer.ts +52 -24
  34. package/src/analysis/go-ast-parser.test.ts +22 -22
  35. package/src/analysis/go-ast-parser.ts +18 -25
  36. package/src/analysis/parser-factory.test.ts +9 -9
  37. package/src/analysis/parser-factory.ts +3 -3
  38. package/src/analysis/python-ast-parser.test.ts +27 -27
  39. package/src/analysis/python-ast-parser.ts +2 -2
  40. package/src/analysis/repo-url-resolver.test.ts +82 -82
  41. package/src/analysis/rust-ast-parser.test.ts +19 -19
  42. package/src/analysis/rust-ast-parser.ts +17 -27
  43. package/src/analysis/tree-sitter-parser.test.ts +3 -3
  44. package/src/analysis/tree-sitter-parser.ts +10 -16
  45. package/src/cli/commands/crawl.test.ts +40 -24
  46. package/src/cli/commands/crawl.ts +186 -166
  47. package/src/cli/commands/index-cmd.test.ts +90 -90
  48. package/src/cli/commands/index-cmd.ts +52 -36
  49. package/src/cli/commands/mcp.test.ts +6 -6
  50. package/src/cli/commands/mcp.ts +2 -2
  51. package/src/cli/commands/plugin-api.test.ts +16 -18
  52. package/src/cli/commands/plugin-api.ts +9 -6
  53. package/src/cli/commands/search.test.ts +16 -7
  54. package/src/cli/commands/search.ts +124 -87
  55. package/src/cli/commands/serve.test.ts +67 -25
  56. package/src/cli/commands/serve.ts +18 -3
  57. package/src/cli/commands/setup.test.ts +176 -101
  58. package/src/cli/commands/setup.ts +140 -117
  59. package/src/cli/commands/store.test.ts +82 -53
  60. package/src/cli/commands/store.ts +56 -37
  61. package/src/cli/program.ts +2 -2
  62. package/src/crawl/article-converter.test.ts +4 -1
  63. package/src/crawl/article-converter.ts +46 -31
  64. package/src/crawl/bridge.test.ts +240 -132
  65. package/src/crawl/bridge.ts +87 -30
  66. package/src/crawl/claude-client.test.ts +124 -56
  67. package/src/crawl/claude-client.ts +7 -15
  68. package/src/crawl/intelligent-crawler.test.ts +65 -22
  69. package/src/crawl/intelligent-crawler.ts +86 -53
  70. package/src/crawl/markdown-utils.ts +1 -4
  71. package/src/db/embeddings.ts +4 -6
  72. package/src/db/lance.test.ts +4 -4
  73. package/src/db/lance.ts +16 -12
  74. package/src/index.ts +26 -17
  75. package/src/logging/index.ts +1 -5
  76. package/src/logging/logger.ts +3 -5
  77. package/src/logging/payload.test.ts +1 -1
  78. package/src/logging/payload.ts +3 -5
  79. package/src/mcp/commands/index.ts +2 -2
  80. package/src/mcp/commands/job.commands.ts +12 -18
  81. package/src/mcp/commands/meta.commands.ts +13 -13
  82. package/src/mcp/commands/registry.ts +5 -8
  83. package/src/mcp/commands/store.commands.ts +19 -19
  84. package/src/mcp/handlers/execute.handler.test.ts +10 -10
  85. package/src/mcp/handlers/execute.handler.ts +4 -5
  86. package/src/mcp/handlers/index.ts +10 -14
  87. package/src/mcp/handlers/job.handler.test.ts +10 -10
  88. package/src/mcp/handlers/job.handler.ts +22 -25
  89. package/src/mcp/handlers/search.handler.test.ts +36 -65
  90. package/src/mcp/handlers/search.handler.ts +135 -104
  91. package/src/mcp/handlers/store.handler.test.ts +41 -52
  92. package/src/mcp/handlers/store.handler.ts +108 -88
  93. package/src/mcp/schemas/index.test.ts +73 -68
  94. package/src/mcp/schemas/index.ts +18 -12
  95. package/src/mcp/server.test.ts +1 -1
  96. package/src/mcp/server.ts +59 -46
  97. package/src/plugin/commands.test.ts +230 -95
  98. package/src/plugin/commands.ts +24 -25
  99. package/src/plugin/dependency-analyzer.test.ts +52 -52
  100. package/src/plugin/dependency-analyzer.ts +85 -22
  101. package/src/plugin/git-clone.test.ts +24 -13
  102. package/src/plugin/git-clone.ts +3 -7
  103. package/src/server/app.test.ts +109 -109
  104. package/src/server/app.ts +32 -23
  105. package/src/server/index.test.ts +64 -66
  106. package/src/services/chunking.service.test.ts +32 -32
  107. package/src/services/chunking.service.ts +16 -9
  108. package/src/services/code-graph.service.test.ts +30 -36
  109. package/src/services/code-graph.service.ts +24 -10
  110. package/src/services/code-unit.service.test.ts +55 -11
  111. package/src/services/code-unit.service.ts +85 -11
  112. package/src/services/config.service.test.ts +37 -18
  113. package/src/services/config.service.ts +30 -7
  114. package/src/services/index.service.test.ts +49 -18
  115. package/src/services/index.service.ts +98 -48
  116. package/src/services/index.ts +6 -9
  117. package/src/services/job.service.test.ts +22 -22
  118. package/src/services/job.service.ts +18 -18
  119. package/src/services/project-root.service.test.ts +1 -3
  120. package/src/services/search.service.test.ts +248 -120
  121. package/src/services/search.service.ts +286 -156
  122. package/src/services/services.test.ts +1 -1
  123. package/src/services/snippet.service.test.ts +14 -6
  124. package/src/services/snippet.service.ts +7 -5
  125. package/src/services/store.service.test.ts +68 -29
  126. package/src/services/store.service.ts +41 -12
  127. package/src/services/watch.service.test.ts +34 -14
  128. package/src/services/watch.service.ts +11 -1
  129. package/src/types/brands.test.ts +3 -1
  130. package/src/types/index.ts +2 -13
  131. package/src/types/search.ts +10 -8
  132. package/src/utils/type-guards.test.ts +20 -15
  133. package/src/utils/type-guards.ts +1 -1
  134. package/src/workers/background-worker-cli.ts +2 -2
  135. package/src/workers/background-worker.test.ts +54 -40
  136. package/src/workers/background-worker.ts +76 -60
  137. package/src/workers/spawn-worker.test.ts +22 -10
  138. package/src/workers/spawn-worker.ts +6 -6
  139. package/tests/analysis/ast-parser.test.ts +3 -3
  140. package/tests/analysis/code-graph.test.ts +5 -5
  141. package/tests/fixtures/code-snippets/api/error-handling.ts +4 -15
  142. package/tests/fixtures/code-snippets/api/rest-controller.ts +3 -9
  143. package/tests/fixtures/code-snippets/auth/jwt-auth.ts +5 -21
  144. package/tests/fixtures/code-snippets/auth/oauth-flow.ts +4 -4
  145. package/tests/fixtures/code-snippets/database/repository-pattern.ts +11 -3
  146. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +2 -2
  147. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +1 -1
  148. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +2 -2
  149. package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +2 -2
  150. package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +22 -20
  151. package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +13 -10
  152. package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +10 -7
  153. package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +2 -2
  154. package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +1 -1
  155. package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +16 -16
  156. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +2 -2
  157. package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +3 -3
  158. package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +1 -1
  159. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +2 -2
  160. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +1 -1
  161. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +7 -7
  162. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +3 -3
  163. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +1 -1
  164. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +6 -6
  165. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +3 -3
  166. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +1 -1
  167. package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +1 -1
  168. package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +1 -1
  169. package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +2 -2
  170. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +4 -4
  171. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +1 -1
  172. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +1 -1
  173. package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +166 -169
  174. package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +8 -8
  175. package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +3 -3
  176. package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +2 -2
  177. package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +2 -2
  178. package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +30 -33
  179. package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +2 -2
  180. package/tests/fixtures/test-server.ts +3 -2
  181. package/tests/helpers/performance-metrics.ts +8 -25
  182. package/tests/helpers/search-relevance.ts +14 -69
  183. package/tests/integration/cli-consistency.test.ts +5 -4
  184. package/tests/integration/python-bridge.test.ts +13 -3
  185. package/tests/mcp/server.test.ts +1 -1
  186. package/tests/services/code-unit.service.test.ts +48 -0
  187. package/tests/services/job.service.test.ts +124 -0
  188. package/tests/services/search.progressive-context.test.ts +2 -2
  189. package/.claude-plugin/plugin.json +0 -13
  190. package/dist/chunk-6PBP5DVD.js.map +0 -1
  191. package/dist/chunk-L2YVNC63.js.map +0 -1
  192. package/dist/chunk-RST4XGRL.js.map +0 -1
  193. package/dist/chunk-WT2DAEO7.js.map +0 -1
  194. package/dist/watch.service-YAIKKDCF.js +0 -7
  195. package/skills/atomic-commits/SKILL.md +0 -77
  196. /package/dist/{watch.service-YAIKKDCF.js.map → watch.service-BJV3TI3F.js.map} +0 -0
@@ -1,15 +1,30 @@
1
- import { readFile, readdir } from 'node:fs/promises';
2
1
  import { existsSync } from 'node:fs';
2
+ import { readFile, readdir } from 'node:fs/promises';
3
3
  import { join, extname } from 'node:path';
4
4
  import { ASTParser } from './ast-parser.js';
5
- import type { Result } from '../types/result.js';
6
5
  import { ok, err } from '../types/result.js';
7
6
  import type { SupportedLanguage } from './repo-url-resolver.js';
7
+ import type { Result } from '../types/result.js';
8
8
 
9
9
  const TEXT_EXTENSIONS = new Set([
10
- '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
11
- '.py', '.rb', '.go', '.java', '.rs', '.php',
12
- '.md', '.txt', '.json', '.yml', '.yaml', '.toml'
10
+ '.ts',
11
+ '.tsx',
12
+ '.js',
13
+ '.jsx',
14
+ '.mjs',
15
+ '.cjs',
16
+ '.py',
17
+ '.rb',
18
+ '.go',
19
+ '.java',
20
+ '.rs',
21
+ '.php',
22
+ '.md',
23
+ '.txt',
24
+ '.json',
25
+ '.yml',
26
+ '.yaml',
27
+ '.toml',
13
28
  ]);
14
29
 
15
30
  export interface PackageUsage {
@@ -60,7 +75,7 @@ export class DependencyUsageAnalyzer {
60
75
  usages: [],
61
76
  totalFilesScanned: 0,
62
77
  skippedFiles: 0,
63
- analysisTimeMs: Date.now() - startTime
78
+ analysisTimeMs: Date.now() - startTime,
64
79
  });
65
80
  }
66
81
 
@@ -72,7 +87,7 @@ export class DependencyUsageAnalyzer {
72
87
  usages: [],
73
88
  totalFilesScanned: 0,
74
89
  skippedFiles: 0,
75
- analysisTimeMs: Date.now() - startTime
90
+ analysisTimeMs: Date.now() - startTime,
76
91
  });
77
92
  }
78
93
 
@@ -92,20 +107,18 @@ export class DependencyUsageAnalyzer {
92
107
  if (packageName !== null && declaredDeps.has(packageName)) {
93
108
  const dep = declaredDeps.get(packageName);
94
109
  if (dep !== undefined) {
95
- this.incrementUsage(
96
- usageMap,
97
- packageName,
98
- filePath,
99
- dep.isDev,
100
- dep.language
101
- );
110
+ this.incrementUsage(usageMap, packageName, filePath, dep.isDev, dep.language);
102
111
  }
103
112
  }
104
113
  }
105
114
 
106
115
  processedCount++;
107
116
  if (onProgress !== undefined && processedCount % 10 === 0) {
108
- onProgress(processedCount, files.length, `Analyzed ${String(processedCount)}/${String(files.length)} files`);
117
+ onProgress(
118
+ processedCount,
119
+ files.length,
120
+ `Analyzed ${String(processedCount)}/${String(files.length)} files`
121
+ );
109
122
  }
110
123
  } catch {
111
124
  // Skip files that can't be read or parsed
@@ -114,14 +127,15 @@ export class DependencyUsageAnalyzer {
114
127
  }
115
128
 
116
129
  // 4. Sort by usage frequency
117
- const sortedUsages = Array.from(usageMap.values())
118
- .sort((a, b) => b.importCount - a.importCount);
130
+ const sortedUsages = Array.from(usageMap.values()).sort(
131
+ (a, b) => b.importCount - a.importCount
132
+ );
119
133
 
120
134
  return ok({
121
135
  usages: sortedUsages,
122
136
  totalFilesScanned: processedCount,
123
137
  skippedFiles: skippedCount,
124
- analysisTimeMs: Date.now() - startTime
138
+ analysisTimeMs: Date.now() - startTime,
125
139
  });
126
140
  } catch (error) {
127
141
  const errorObj = new Error(
@@ -178,7 +192,10 @@ export class DependencyUsageAnalyzer {
178
192
  return [];
179
193
  }
180
194
 
181
- private extractImportsRegex(content: string, language: 'javascript' | 'python'): Array<{ source: string }> {
195
+ private extractImportsRegex(
196
+ content: string,
197
+ language: 'javascript' | 'python'
198
+ ): Array<{ source: string }> {
182
199
  const imports: Array<{ source: string }> = [];
183
200
 
184
201
  if (language === 'javascript') {
@@ -234,7 +251,7 @@ export class DependencyUsageAnalyzer {
234
251
  fileCount: 1,
235
252
  files: [filePath],
236
253
  isDevDependency,
237
- language
254
+ language,
238
255
  });
239
256
  }
240
257
  }
@@ -250,7 +267,18 @@ export class DependencyUsageAnalyzer {
250
267
 
251
268
  if (entry.isDirectory()) {
252
269
  // Skip common ignored directories
253
- if (!['node_modules', '.git', 'dist', 'build', 'coverage', '__pycache__', '.venv', 'venv'].includes(entry.name)) {
270
+ if (
271
+ ![
272
+ 'node_modules',
273
+ '.git',
274
+ 'dist',
275
+ 'build',
276
+ 'coverage',
277
+ '__pycache__',
278
+ '.venv',
279
+ 'venv',
280
+ ].includes(entry.name)
281
+ ) {
254
282
  files.push(...(await this.scanDirectory(fullPath)));
255
283
  }
256
284
  } else if (entry.isFile()) {
@@ -312,7 +340,7 @@ export class DependencyUsageAnalyzer {
312
340
 
313
341
  // Parse package name (before ==, >=, etc.)
314
342
  const match = /^([a-zA-Z0-9_-]+)/.exec(trimmed);
315
- if (match !== null && match[1] !== undefined) {
343
+ if (match?.[1] !== undefined) {
316
344
  const name = match[1].toLowerCase();
317
345
  deps.set(name, { name, isDev: false, language: 'python' });
318
346
  }
@@ -350,7 +378,7 @@ export class DependencyUsageAnalyzer {
350
378
  // or serde = { version = "1.0", features = [...] }
351
379
  const inDepsSection = /\[dependencies\]([\s\S]*?)(?=\n\[|$)/;
352
380
  const depsMatch = inDepsSection.exec(content);
353
- if (depsMatch !== null && depsMatch[1] !== undefined) {
381
+ if (depsMatch?.[1] !== undefined) {
354
382
  const depsSection = depsMatch[1];
355
383
  // Match crate names at start of lines
356
384
  const cratePattern = /^([a-zA-Z0-9_-]+)\s*=/gm;
@@ -364,7 +392,7 @@ export class DependencyUsageAnalyzer {
364
392
  // Also check [dev-dependencies]
365
393
  const inDevDepsSection = /\[dev-dependencies\]([\s\S]*?)(?=\n\[|$)/;
366
394
  const devDepsMatch = inDevDepsSection.exec(content);
367
- if (devDepsMatch !== null && devDepsMatch[1] !== undefined) {
395
+ if (devDepsMatch?.[1] !== undefined) {
368
396
  const devDepsSection = devDepsMatch[1];
369
397
  const cratePattern = /^([a-zA-Z0-9_-]+)\s*=/gm;
370
398
  for (const match of devDepsSection.matchAll(cratePattern)) {
@@ -14,7 +14,7 @@ describe('GoASTParser', () => {
14
14
  type: 'function',
15
15
  name: 'hello',
16
16
  exported: false,
17
- async: false
17
+ async: false,
18
18
  });
19
19
  });
20
20
 
@@ -68,9 +68,9 @@ func Third() int { return 3 }
68
68
  `.trim();
69
69
  const nodes = parser.parse(code, 'test.go');
70
70
 
71
- const functions = nodes.filter(n => n.type === 'function');
71
+ const functions = nodes.filter((n) => n.type === 'function');
72
72
  expect(functions).toHaveLength(3);
73
- expect(functions.map(f => f.name)).toEqual(['first', 'second', 'Third']);
73
+ expect(functions.map((f) => f.name)).toEqual(['first', 'second', 'Third']);
74
74
  expect(functions[2]?.exported).toBe(true);
75
75
  });
76
76
  });
@@ -84,7 +84,7 @@ func Third() int { return 3 }
84
84
  expect(nodes[0]).toMatchObject({
85
85
  type: 'class',
86
86
  name: 'user',
87
- exported: false
87
+ exported: false,
88
88
  });
89
89
  });
90
90
 
@@ -139,7 +139,7 @@ type Data struct {
139
139
  expect(nodes[0]).toMatchObject({
140
140
  type: 'interface',
141
141
  name: 'drawable',
142
- exported: false
142
+ exported: false,
143
143
  });
144
144
  expect(nodes[0]?.methods).toBeDefined();
145
145
  });
@@ -195,7 +195,7 @@ type Animal interface {
195
195
  expect(nodes[0]).toMatchObject({
196
196
  type: 'type',
197
197
  name: 'myInt',
198
- exported: false
198
+ exported: false,
199
199
  });
200
200
  });
201
201
 
@@ -224,7 +224,7 @@ type Animal interface {
224
224
  expect(nodes[0]).toMatchObject({
225
225
  type: 'const',
226
226
  name: 'maxSize',
227
- exported: false
227
+ exported: false,
228
228
  });
229
229
  });
230
230
 
@@ -254,9 +254,9 @@ const (
254
254
  `.trim();
255
255
  const nodes = parser.parse(code, 'test.go');
256
256
 
257
- const constants = nodes.filter(n => n.type === 'const');
257
+ const constants = nodes.filter((n) => n.type === 'const');
258
258
  expect(constants).toHaveLength(3);
259
- expect(constants.map(c => c.name)).toEqual(['Red', 'Green', 'Blue']);
259
+ expect(constants.map((c) => c.name)).toEqual(['Red', 'Green', 'Blue']);
260
260
  });
261
261
 
262
262
  it('parses var declaration', () => {
@@ -265,7 +265,7 @@ const (
265
265
 
266
266
  expect(nodes[0]).toMatchObject({
267
267
  type: 'const',
268
- name: 'counter'
268
+ name: 'counter',
269
269
  });
270
270
  });
271
271
  });
@@ -281,7 +281,7 @@ func (u User) GetName() string {
281
281
  `.trim();
282
282
  const nodes = parser.parse(code, 'test.go');
283
283
 
284
- const userStruct = nodes.find(n => n.name === 'User');
284
+ const userStruct = nodes.find((n) => n.name === 'User');
285
285
  expect(userStruct).toBeDefined();
286
286
  expect(userStruct?.methods).toHaveLength(1);
287
287
  expect(userStruct?.methods?.[0]?.name).toBe('GetName');
@@ -297,7 +297,7 @@ func (c *Counter) Increment() {
297
297
  `.trim();
298
298
  const nodes = parser.parse(code, 'test.go');
299
299
 
300
- const counter = nodes.find(n => n.name === 'Counter');
300
+ const counter = nodes.find((n) => n.name === 'Counter');
301
301
  expect(counter?.methods).toHaveLength(1);
302
302
  expect(counter?.methods?.[0]?.name).toBe('Increment');
303
303
  });
@@ -318,9 +318,9 @@ func (s *Stack) Pop() int {
318
318
  `.trim();
319
319
  const nodes = parser.parse(code, 'test.go');
320
320
 
321
- const stack = nodes.find(n => n.name === 'Stack');
321
+ const stack = nodes.find((n) => n.name === 'Stack');
322
322
  expect(stack?.methods).toHaveLength(2);
323
- expect(stack?.methods?.map(m => m.name)).toEqual(['Push', 'Pop']);
323
+ expect(stack?.methods?.map((m) => m.name)).toEqual(['Push', 'Pop']);
324
324
  });
325
325
 
326
326
  it('does not count methods as standalone functions', () => {
@@ -332,7 +332,7 @@ func standalone() {}
332
332
  `.trim();
333
333
  const nodes = parser.parse(code, 'test.go');
334
334
 
335
- const functions = nodes.filter(n => n.type === 'function');
335
+ const functions = nodes.filter((n) => n.type === 'function');
336
336
  expect(functions).toHaveLength(1);
337
337
  expect(functions[0]?.name).toBe('standalone');
338
338
  });
@@ -347,7 +347,7 @@ func standalone() {}
347
347
  expect(imports[0]).toMatchObject({
348
348
  source: 'fmt',
349
349
  specifiers: [],
350
- isType: false
350
+ isType: false,
351
351
  });
352
352
  });
353
353
 
@@ -376,7 +376,7 @@ import (
376
376
  const imports = parser.extractImports(code);
377
377
 
378
378
  expect(imports).toHaveLength(3);
379
- expect(imports.map(i => i.source)).toEqual(['fmt', 'os', 'net/http']);
379
+ expect(imports.map((i) => i.source)).toEqual(['fmt', 'os', 'net/http']);
380
380
  });
381
381
 
382
382
  it('extracts aliased import', () => {
@@ -470,10 +470,10 @@ type Handler interface {
470
470
 
471
471
  expect(nodes.length).toBeGreaterThan(0);
472
472
 
473
- const structs = nodes.filter(n => n.type === 'class');
474
- const functions = nodes.filter(n => n.type === 'function');
475
- const interfaces = nodes.filter(n => n.type === 'interface');
476
- const constants = nodes.filter(n => n.type === 'const');
473
+ const structs = nodes.filter((n) => n.type === 'class');
474
+ const functions = nodes.filter((n) => n.type === 'function');
475
+ const interfaces = nodes.filter((n) => n.type === 'interface');
476
+ const constants = nodes.filter((n) => n.type === 'const');
477
477
 
478
478
  expect(structs).toHaveLength(1);
479
479
  expect(functions).toHaveLength(1); // Only main, not the method
@@ -521,7 +521,7 @@ func (t Test) method() {
521
521
  `.trim();
522
522
  const nodes = parser.parse(code, 'test.go');
523
523
 
524
- const test = nodes.find(n => n.name === 'Test');
524
+ const test = nodes.find((n) => n.name === 'Test');
525
525
  const method = test?.methods?.[0];
526
526
 
527
527
  expect(method?.startLine).toBe(3);
@@ -1,4 +1,3 @@
1
- import type { CodeNode, ImportInfo } from './ast-parser.js';
2
1
  import {
3
2
  parseGoCode,
4
3
  queryNodesByType,
@@ -7,8 +6,9 @@ import {
7
6
  getFunctionSignature,
8
7
  getFirstChildOfType,
9
8
  type TreeSitterNode,
10
- type TreeSitterTree
9
+ type TreeSitterTree,
11
10
  } from './tree-sitter-parser.js';
11
+ import type { CodeNode, ImportInfo } from './ast-parser.js';
12
12
 
13
13
  /**
14
14
  * Parser for Go code using tree-sitter
@@ -87,13 +87,14 @@ export class GoASTParser {
87
87
 
88
88
  // Extract string content from interpreted_string_literal
89
89
  const stringContent = pathNode.descendantsOfType('interpreted_string_literal_content')[0];
90
- const path = stringContent !== undefined ? stringContent.text : pathNode.text.replace(/"/g, '');
90
+ const path =
91
+ stringContent !== undefined ? stringContent.text : pathNode.text.replace(/"/g, '');
91
92
 
92
93
  if (path !== '') {
93
94
  imports.push({
94
95
  source: path,
95
96
  specifiers: [],
96
- isType: false
97
+ isType: false,
97
98
  });
98
99
  }
99
100
  }
@@ -131,7 +132,7 @@ export class GoASTParser {
131
132
  async: false,
132
133
  startLine,
133
134
  endLine,
134
- signature
135
+ signature,
135
136
  });
136
137
  }
137
138
 
@@ -176,7 +177,7 @@ export class GoASTParser {
176
177
  startLine,
177
178
  endLine,
178
179
  signature: name,
179
- methods: []
180
+ methods: [],
180
181
  });
181
182
  }
182
183
 
@@ -223,7 +224,7 @@ export class GoASTParser {
223
224
  startLine,
224
225
  endLine,
225
226
  signature: name,
226
- methods
227
+ methods,
227
228
  });
228
229
  }
229
230
 
@@ -267,7 +268,7 @@ export class GoASTParser {
267
268
  exported,
268
269
  startLine,
269
270
  endLine,
270
- signature
271
+ signature,
271
272
  });
272
273
  }
273
274
 
@@ -296,9 +297,7 @@ export class GoASTParser {
296
297
  const endLine = positionToLineNumber(spec.endPosition);
297
298
 
298
299
  const typeNode = getChildByFieldName(spec, 'type');
299
- const signature = typeNode !== null
300
- ? `${name}: ${typeNode.text}`
301
- : name;
300
+ const signature = typeNode !== null ? `${name}: ${typeNode.text}` : name;
302
301
 
303
302
  nodes.push({
304
303
  type: 'const',
@@ -306,7 +305,7 @@ export class GoASTParser {
306
305
  exported,
307
306
  startLine,
308
307
  endLine,
309
- signature
308
+ signature,
310
309
  });
311
310
  }
312
311
  }
@@ -327,9 +326,7 @@ export class GoASTParser {
327
326
  const endLine = positionToLineNumber(spec.endPosition);
328
327
 
329
328
  const typeNode = getChildByFieldName(spec, 'type');
330
- const signature = typeNode !== null
331
- ? `${name}: ${typeNode.text}`
332
- : name;
329
+ const signature = typeNode !== null ? `${name}: ${typeNode.text}` : name;
333
330
 
334
331
  nodes.push({
335
332
  type: 'const',
@@ -337,7 +334,7 @@ export class GoASTParser {
337
334
  exported,
338
335
  startLine,
339
336
  endLine,
340
- signature
337
+ signature,
341
338
  });
342
339
  }
343
340
  }
@@ -368,17 +365,15 @@ export class GoASTParser {
368
365
  const endLine = positionToLineNumber(methodNode.endPosition);
369
366
 
370
367
  // Find the corresponding struct and attach method
371
- const structNode = nodes.find(
372
- node => node.type === 'class' && node.name === receiverType
373
- );
368
+ const structNode = nodes.find((node) => node.type === 'class' && node.name === receiverType);
374
369
 
375
- if (structNode !== undefined && structNode.methods !== undefined) {
370
+ if (structNode?.methods !== undefined) {
376
371
  structNode.methods.push({
377
372
  name,
378
373
  async: false,
379
374
  signature,
380
375
  startLine,
381
- endLine
376
+ endLine,
382
377
  });
383
378
  }
384
379
  }
@@ -420,7 +415,7 @@ export class GoASTParser {
420
415
  async: false,
421
416
  signature,
422
417
  startLine,
423
- endLine
418
+ endLine,
424
419
  });
425
420
  }
426
421
 
@@ -448,9 +443,7 @@ export class GoASTParser {
448
443
 
449
444
  // Handle pointer receivers (*Type)
450
445
  if (typeNode.type === 'pointer_type') {
451
- const innerType = typeNode.children.find(
452
- child => child.type === 'type_identifier'
453
- );
446
+ const innerType = typeNode.children.find((child) => child.type === 'type_identifier');
454
447
  return innerType !== undefined ? innerType.text : null;
455
448
  }
456
449
 
@@ -13,7 +13,7 @@ describe('ParserFactory', () => {
13
13
  expect(nodes[0]).toMatchObject({
14
14
  type: 'function',
15
15
  name: 'hello',
16
- exported: true
16
+ exported: true,
17
17
  });
18
18
  });
19
19
 
@@ -35,7 +35,7 @@ describe('ParserFactory', () => {
35
35
  expect(nodes[0]).toMatchObject({
36
36
  type: 'function',
37
37
  name: 'add',
38
- exported: true
38
+ exported: true,
39
39
  });
40
40
  });
41
41
 
@@ -57,13 +57,13 @@ describe('ParserFactory', () => {
57
57
  exported: true,
58
58
  startLine: 1,
59
59
  endLine: 2,
60
- signature: 'def greet(name: str) -> str'
61
- }
62
- ]
60
+ signature: 'def greet(name: str) -> str',
61
+ },
62
+ ],
63
63
  };
64
64
 
65
65
  const mockBridge = {
66
- parsePython: vi.fn().mockResolvedValue(mockResult)
66
+ parsePython: vi.fn().mockResolvedValue(mockResult),
67
67
  } as unknown as PythonBridge;
68
68
 
69
69
  const factory = new ParserFactory(mockBridge);
@@ -75,7 +75,7 @@ describe('ParserFactory', () => {
75
75
  expect(nodes[0]).toMatchObject({
76
76
  type: 'function',
77
77
  name: 'greet',
78
- exported: true
78
+ exported: true,
79
79
  });
80
80
  });
81
81
 
@@ -97,7 +97,7 @@ describe('ParserFactory', () => {
97
97
  expect(nodes[0]).toMatchObject({
98
98
  type: 'function',
99
99
  name: 'calculate',
100
- exported: true
100
+ exported: true,
101
101
  });
102
102
  });
103
103
 
@@ -110,7 +110,7 @@ describe('ParserFactory', () => {
110
110
  expect(nodes[0]).toMatchObject({
111
111
  type: 'function',
112
112
  name: 'Add',
113
- exported: true
113
+ exported: true,
114
114
  });
115
115
  });
116
116
 
@@ -1,9 +1,9 @@
1
1
  import path from 'node:path';
2
- import type { PythonBridge } from '../crawl/bridge.js';
3
2
  import { ASTParser, type CodeNode } from './ast-parser.js';
3
+ import { GoASTParser } from './go-ast-parser.js';
4
4
  import { PythonASTParser } from './python-ast-parser.js';
5
5
  import { RustASTParser } from './rust-ast-parser.js';
6
- import { GoASTParser } from './go-ast-parser.js';
6
+ import type { PythonBridge } from '../crawl/bridge.js';
7
7
 
8
8
  export class ParserFactory {
9
9
  constructor(private readonly pythonBridge?: PythonBridge) {}
@@ -26,7 +26,7 @@ export class ParserFactory {
26
26
  throw new Error('Python bridge not available for parsing Python files');
27
27
  }
28
28
  const parser = new PythonASTParser(this.pythonBridge);
29
- return await parser.parse(code, filePath);
29
+ return parser.parse(code, filePath);
30
30
  }
31
31
 
32
32
  if (ext === '.rs') {
@@ -4,7 +4,7 @@ import type { PythonBridge, ParsePythonResult } from '../crawl/bridge.js';
4
4
 
5
5
  function createMockBridge(result: ParsePythonResult): PythonBridge {
6
6
  return {
7
- parsePython: vi.fn().mockResolvedValue(result)
7
+ parsePython: vi.fn().mockResolvedValue(result),
8
8
  } as unknown as PythonBridge;
9
9
  }
10
10
 
@@ -18,10 +18,10 @@ describe('PythonASTParser', () => {
18
18
  name: 'hello',
19
19
  exported: true,
20
20
  startLine: 1,
21
- endLine: 2
22
- }
21
+ endLine: 2,
22
+ },
23
23
  ],
24
- imports: []
24
+ imports: [],
25
25
  };
26
26
 
27
27
  const bridge = createMockBridge(mockResult);
@@ -35,7 +35,7 @@ describe('PythonASTParser', () => {
35
35
  name: 'hello',
36
36
  exported: true,
37
37
  startLine: 1,
38
- endLine: 2
38
+ endLine: 2,
39
39
  });
40
40
  });
41
41
 
@@ -48,10 +48,10 @@ describe('PythonASTParser', () => {
48
48
  exported: true,
49
49
  startLine: 1,
50
50
  endLine: 3,
51
- async: true
52
- }
51
+ async: true,
52
+ },
53
53
  ],
54
- imports: []
54
+ imports: [],
55
55
  };
56
56
 
57
57
  const bridge = createMockBridge(mockResult);
@@ -71,10 +71,10 @@ describe('PythonASTParser', () => {
71
71
  exported: true,
72
72
  startLine: 1,
73
73
  endLine: 2,
74
- signature: 'def greet(name: str) -> str'
75
- }
74
+ signature: 'def greet(name: str) -> str',
75
+ },
76
76
  ],
77
- imports: []
77
+ imports: [],
78
78
  };
79
79
 
80
80
  const bridge = createMockBridge(mockResult);
@@ -100,7 +100,7 @@ describe('PythonASTParser', () => {
100
100
  signature: 'def add(self, a: int, b: int) -> int',
101
101
  startLine: 2,
102
102
  endLine: 3,
103
- calls: []
103
+ calls: [],
104
104
  },
105
105
  {
106
106
  name: 'subtract',
@@ -108,12 +108,12 @@ describe('PythonASTParser', () => {
108
108
  signature: 'def subtract(self, a: int, b: int) -> int',
109
109
  startLine: 4,
110
110
  endLine: 5,
111
- calls: []
112
- }
113
- ]
114
- }
111
+ calls: [],
112
+ },
113
+ ],
114
+ },
115
115
  ],
116
- imports: []
116
+ imports: [],
117
117
  };
118
118
 
119
119
  const bridge = createMockBridge(mockResult);
@@ -134,11 +134,11 @@ describe('PythonASTParser', () => {
134
134
  name: 'simple',
135
135
  exported: false,
136
136
  startLine: 1,
137
- endLine: 1
137
+ endLine: 1,
138
138
  // No async, signature, or methods
139
- }
139
+ },
140
140
  ],
141
- imports: []
141
+ imports: [],
142
142
  };
143
143
 
144
144
  const bridge = createMockBridge(mockResult);
@@ -148,7 +148,7 @@ describe('PythonASTParser', () => {
148
148
  expect(nodes[0]).toMatchObject({
149
149
  type: 'function',
150
150
  name: 'simple',
151
- exported: false
151
+ exported: false,
152
152
  });
153
153
  // Optional fields should not be present
154
154
  expect(nodes[0]?.async).toBeUndefined();
@@ -164,24 +164,24 @@ describe('PythonASTParser', () => {
164
164
  name: 'func1',
165
165
  exported: true,
166
166
  startLine: 1,
167
- endLine: 2
167
+ endLine: 2,
168
168
  },
169
169
  {
170
170
  type: 'class',
171
171
  name: 'MyClass',
172
172
  exported: true,
173
173
  startLine: 3,
174
- endLine: 10
174
+ endLine: 10,
175
175
  },
176
176
  {
177
177
  type: 'function',
178
178
  name: 'func2',
179
179
  exported: false,
180
180
  startLine: 11,
181
- endLine: 12
182
- }
181
+ endLine: 12,
182
+ },
183
183
  ],
184
- imports: []
184
+ imports: [],
185
185
  };
186
186
 
187
187
  const bridge = createMockBridge(mockResult);
@@ -197,7 +197,7 @@ describe('PythonASTParser', () => {
197
197
  it('returns empty array when no nodes found', async () => {
198
198
  const mockResult: ParsePythonResult = {
199
199
  nodes: [],
200
- imports: []
200
+ imports: [],
201
201
  };
202
202
 
203
203
  const bridge = createMockBridge(mockResult);