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
@@ -21,16 +21,10 @@ describe('DependencyUsageAnalyzer', () => {
21
21
  describe('Package name extraction', () => {
22
22
  it('extracts regular package name', async () => {
23
23
  const packageJson = {
24
- dependencies: { 'lodash': '^4.0.0' }
24
+ dependencies: { lodash: '^4.0.0' },
25
25
  };
26
- await writeFile(
27
- join(tempDir, 'package.json'),
28
- JSON.stringify(packageJson)
29
- );
30
- await writeFile(
31
- join(tempDir, 'index.ts'),
32
- 'import { map } from "lodash";'
33
- );
26
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
27
+ await writeFile(join(tempDir, 'index.ts'), 'import { map } from "lodash";');
34
28
 
35
29
  const result = await analyzer.analyze(tempDir);
36
30
 
@@ -43,16 +37,10 @@ describe('DependencyUsageAnalyzer', () => {
43
37
 
44
38
  it('extracts scoped package name', async () => {
45
39
  const packageJson = {
46
- dependencies: { '@org/package': '^1.0.0' }
40
+ dependencies: { '@org/package': '^1.0.0' },
47
41
  };
48
- await writeFile(
49
- join(tempDir, 'package.json'),
50
- JSON.stringify(packageJson)
51
- );
52
- await writeFile(
53
- join(tempDir, 'index.ts'),
54
- 'import { foo } from "@org/package";'
55
- );
42
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
43
+ await writeFile(join(tempDir, 'index.ts'), 'import { foo } from "@org/package";');
56
44
 
57
45
  const result = await analyzer.analyze(tempDir);
58
46
 
@@ -64,16 +52,10 @@ describe('DependencyUsageAnalyzer', () => {
64
52
 
65
53
  it('extracts package from deep import path', async () => {
66
54
  const packageJson = {
67
- dependencies: { 'lodash': '^4.0.0' }
55
+ dependencies: { lodash: '^4.0.0' },
68
56
  };
69
- await writeFile(
70
- join(tempDir, 'package.json'),
71
- JSON.stringify(packageJson)
72
- );
73
- await writeFile(
74
- join(tempDir, 'index.ts'),
75
- 'import map from "lodash/map";'
76
- );
57
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
58
+ await writeFile(join(tempDir, 'index.ts'), 'import map from "lodash/map";');
77
59
 
78
60
  const result = await analyzer.analyze(tempDir);
79
61
 
@@ -85,14 +67,8 @@ describe('DependencyUsageAnalyzer', () => {
85
67
 
86
68
  it('ignores relative imports', async () => {
87
69
  const packageJson = { dependencies: {} };
88
- await writeFile(
89
- join(tempDir, 'package.json'),
90
- JSON.stringify(packageJson)
91
- );
92
- await writeFile(
93
- join(tempDir, 'index.ts'),
94
- 'import { helper } from "./utils";'
95
- );
70
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
71
+ await writeFile(join(tempDir, 'index.ts'), 'import { helper } from "./utils";');
96
72
 
97
73
  const result = await analyzer.analyze(tempDir);
98
74
 
@@ -104,14 +80,8 @@ describe('DependencyUsageAnalyzer', () => {
104
80
 
105
81
  it('ignores node built-ins', async () => {
106
82
  const packageJson = { dependencies: {} };
107
- await writeFile(
108
- join(tempDir, 'package.json'),
109
- JSON.stringify(packageJson)
110
- );
111
- await writeFile(
112
- join(tempDir, 'index.ts'),
113
- 'import { readFile } from "node:fs/promises";'
114
- );
83
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
84
+ await writeFile(join(tempDir, 'index.ts'), 'import { readFile } from "node:fs/promises";');
115
85
 
116
86
  const result = await analyzer.analyze(tempDir);
117
87
 
@@ -123,14 +93,8 @@ describe('DependencyUsageAnalyzer', () => {
123
93
 
124
94
  it('ignores absolute paths', async () => {
125
95
  const packageJson = { dependencies: {} };
126
- await writeFile(
127
- join(tempDir, 'package.json'),
128
- JSON.stringify(packageJson)
129
- );
130
- await writeFile(
131
- join(tempDir, 'index.ts'),
132
- 'import { util } from "/absolute/path";'
133
- );
96
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
97
+ await writeFile(join(tempDir, 'index.ts'), 'import { util } from "/absolute/path";');
134
98
 
135
99
  const result = await analyzer.analyze(tempDir);
136
100
 
@@ -145,14 +109,11 @@ describe('DependencyUsageAnalyzer', () => {
145
109
  it('reads dependencies from package.json', async () => {
146
110
  const packageJson = {
147
111
  dependencies: {
148
- 'react': '^18.0.0',
149
- 'lodash': '^4.0.0'
150
- }
112
+ react: '^18.0.0',
113
+ lodash: '^4.0.0',
114
+ },
151
115
  };
152
- await writeFile(
153
- join(tempDir, 'package.json'),
154
- JSON.stringify(packageJson)
155
- );
116
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
156
117
  await writeFile(
157
118
  join(tempDir, 'index.ts'),
158
119
  'import React from "react"; import _ from "lodash";'
@@ -169,17 +130,11 @@ describe('DependencyUsageAnalyzer', () => {
169
130
  it('identifies dev dependencies', async () => {
170
131
  const packageJson = {
171
132
  devDependencies: {
172
- 'vitest': '^1.0.0'
173
- }
133
+ vitest: '^1.0.0',
134
+ },
174
135
  };
175
- await writeFile(
176
- join(tempDir, 'package.json'),
177
- JSON.stringify(packageJson)
178
- );
179
- await writeFile(
180
- join(tempDir, 'test.ts'),
181
- 'import { describe } from "vitest";'
182
- );
136
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
137
+ await writeFile(join(tempDir, 'test.ts'), 'import { describe } from "vitest";');
183
138
 
184
139
  const result = await analyzer.analyze(tempDir);
185
140
 
@@ -191,10 +146,7 @@ describe('DependencyUsageAnalyzer', () => {
191
146
 
192
147
  it('handles project with no dependencies', async () => {
193
148
  const packageJson = {};
194
- await writeFile(
195
- join(tempDir, 'package.json'),
196
- JSON.stringify(packageJson)
197
- );
149
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
198
150
 
199
151
  const result = await analyzer.analyze(tempDir);
200
152
 
@@ -215,14 +167,8 @@ describe('DependencyUsageAnalyzer', () => {
215
167
  });
216
168
 
217
169
  it('reads Python dependencies from requirements.txt', async () => {
218
- await writeFile(
219
- join(tempDir, 'requirements.txt'),
220
- 'requests==2.28.0\nnumpy>=1.20.0'
221
- );
222
- await writeFile(
223
- join(tempDir, 'script.py'),
224
- 'import requests\nimport numpy'
225
- );
170
+ await writeFile(join(tempDir, 'requirements.txt'), 'requests==2.28.0\nnumpy>=1.20.0');
171
+ await writeFile(join(tempDir, 'script.py'), 'import requests\nimport numpy');
226
172
 
227
173
  const result = await analyzer.analyze(tempDir);
228
174
 
@@ -233,10 +179,7 @@ describe('DependencyUsageAnalyzer', () => {
233
179
  });
234
180
 
235
181
  it('handles malformed package.json gracefully', async () => {
236
- await writeFile(
237
- join(tempDir, 'package.json'),
238
- '{ invalid json'
239
- );
182
+ await writeFile(join(tempDir, 'package.json'), '{ invalid json');
240
183
 
241
184
  const result = await analyzer.analyze(tempDir);
242
185
 
@@ -250,16 +193,10 @@ describe('DependencyUsageAnalyzer', () => {
250
193
  describe('File scanning', () => {
251
194
  it('scans JavaScript files', async () => {
252
195
  const packageJson = {
253
- dependencies: { 'package': '^1.0.0' }
196
+ dependencies: { package: '^1.0.0' },
254
197
  };
255
- await writeFile(
256
- join(tempDir, 'package.json'),
257
- JSON.stringify(packageJson)
258
- );
259
- await writeFile(
260
- join(tempDir, 'index.js'),
261
- 'import { foo } from "package";'
262
- );
198
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
199
+ await writeFile(join(tempDir, 'index.js'), 'import { foo } from "package";');
263
200
 
264
201
  const result = await analyzer.analyze(tempDir);
265
202
 
@@ -271,16 +208,10 @@ describe('DependencyUsageAnalyzer', () => {
271
208
 
272
209
  it('scans TypeScript files', async () => {
273
210
  const packageJson = {
274
- dependencies: { 'package': '^1.0.0' }
211
+ dependencies: { package: '^1.0.0' },
275
212
  };
276
- await writeFile(
277
- join(tempDir, 'package.json'),
278
- JSON.stringify(packageJson)
279
- );
280
- await writeFile(
281
- join(tempDir, 'index.ts'),
282
- 'import { foo } from "package";'
283
- );
213
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
214
+ await writeFile(join(tempDir, 'index.ts'), 'import { foo } from "package";');
284
215
 
285
216
  const result = await analyzer.analyze(tempDir);
286
217
 
@@ -292,18 +223,12 @@ describe('DependencyUsageAnalyzer', () => {
292
223
 
293
224
  it('scans nested directories', async () => {
294
225
  const packageJson = {
295
- dependencies: { 'pkg': '^1.0.0' }
226
+ dependencies: { pkg: '^1.0.0' },
296
227
  };
297
- await writeFile(
298
- join(tempDir, 'package.json'),
299
- JSON.stringify(packageJson)
300
- );
228
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
301
229
 
302
230
  await mkdir(join(tempDir, 'src'), { recursive: true });
303
- await writeFile(
304
- join(tempDir, 'src/app.ts'),
305
- 'import { x } from "pkg";'
306
- );
231
+ await writeFile(join(tempDir, 'src/app.ts'), 'import { x } from "pkg";');
307
232
 
308
233
  const result = await analyzer.analyze(tempDir);
309
234
 
@@ -315,18 +240,12 @@ describe('DependencyUsageAnalyzer', () => {
315
240
 
316
241
  it('ignores node_modules directory', async () => {
317
242
  const packageJson = {
318
- dependencies: { 'pkg': '^1.0.0' }
243
+ dependencies: { pkg: '^1.0.0' },
319
244
  };
320
- await writeFile(
321
- join(tempDir, 'package.json'),
322
- JSON.stringify(packageJson)
323
- );
245
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
324
246
 
325
247
  await mkdir(join(tempDir, 'node_modules'), { recursive: true });
326
- await writeFile(
327
- join(tempDir, 'node_modules/file.js'),
328
- 'import { x } from "pkg";'
329
- );
248
+ await writeFile(join(tempDir, 'node_modules/file.js'), 'import { x } from "pkg";');
330
249
 
331
250
  const result = await analyzer.analyze(tempDir);
332
251
 
@@ -339,12 +258,9 @@ describe('DependencyUsageAnalyzer', () => {
339
258
 
340
259
  it('ignores dist and build directories', async () => {
341
260
  const packageJson = {
342
- dependencies: { 'pkg': '^1.0.0' }
261
+ dependencies: { pkg: '^1.0.0' },
343
262
  };
344
- await writeFile(
345
- join(tempDir, 'package.json'),
346
- JSON.stringify(packageJson)
347
- );
263
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
348
264
 
349
265
  await mkdir(join(tempDir, 'dist'), { recursive: true });
350
266
  await mkdir(join(tempDir, 'build'), { recursive: true });
@@ -362,16 +278,10 @@ describe('DependencyUsageAnalyzer', () => {
362
278
 
363
279
  it('handles unreadable files gracefully', async () => {
364
280
  const packageJson = {
365
- dependencies: { 'pkg': '^1.0.0' }
281
+ dependencies: { pkg: '^1.0.0' },
366
282
  };
367
- await writeFile(
368
- join(tempDir, 'package.json'),
369
- JSON.stringify(packageJson)
370
- );
371
- await writeFile(
372
- join(tempDir, 'good.ts'),
373
- 'import { x } from "pkg";'
374
- );
283
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
284
+ await writeFile(join(tempDir, 'good.ts'), 'import { x } from "pkg";');
375
285
 
376
286
  const result = await analyzer.analyze(tempDir);
377
287
 
@@ -385,12 +295,9 @@ describe('DependencyUsageAnalyzer', () => {
385
295
  describe('Usage counting', () => {
386
296
  it('counts import occurrences', async () => {
387
297
  const packageJson = {
388
- dependencies: { 'lodash': '^4.0.0' }
298
+ dependencies: { lodash: '^4.0.0' },
389
299
  };
390
- await writeFile(
391
- join(tempDir, 'package.json'),
392
- JSON.stringify(packageJson)
393
- );
300
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
394
301
  await writeFile(
395
302
  join(tempDir, 'file1.ts'),
396
303
  'import { map } from "lodash";\nimport { filter } from "lodash";'
@@ -407,20 +314,11 @@ describe('DependencyUsageAnalyzer', () => {
407
314
 
408
315
  it('counts files using a package', async () => {
409
316
  const packageJson = {
410
- dependencies: { 'pkg': '^1.0.0' }
317
+ dependencies: { pkg: '^1.0.0' },
411
318
  };
412
- await writeFile(
413
- join(tempDir, 'package.json'),
414
- JSON.stringify(packageJson)
415
- );
416
- await writeFile(
417
- join(tempDir, 'file1.ts'),
418
- 'import { x } from "pkg";'
419
- );
420
- await writeFile(
421
- join(tempDir, 'file2.ts'),
422
- 'import { y } from "pkg";'
423
- );
319
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
320
+ await writeFile(join(tempDir, 'file1.ts'), 'import { x } from "pkg";');
321
+ await writeFile(join(tempDir, 'file2.ts'), 'import { y } from "pkg";');
424
322
 
425
323
  const result = await analyzer.analyze(tempDir);
426
324
 
@@ -433,16 +331,10 @@ describe('DependencyUsageAnalyzer', () => {
433
331
 
434
332
  it('tracks which files use each package', async () => {
435
333
  const packageJson = {
436
- dependencies: { 'pkg': '^1.0.0' }
334
+ dependencies: { pkg: '^1.0.0' },
437
335
  };
438
- await writeFile(
439
- join(tempDir, 'package.json'),
440
- JSON.stringify(packageJson)
441
- );
442
- await writeFile(
443
- join(tempDir, 'app.ts'),
444
- 'import { x } from "pkg";'
445
- );
336
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
337
+ await writeFile(join(tempDir, 'app.ts'), 'import { x } from "pkg";');
446
338
 
447
339
  const result = await analyzer.analyze(tempDir);
448
340
 
@@ -455,14 +347,11 @@ describe('DependencyUsageAnalyzer', () => {
455
347
  it('sorts results by import count', async () => {
456
348
  const packageJson = {
457
349
  dependencies: {
458
- 'pkg1': '^1.0.0',
459
- 'pkg2': '^1.0.0'
460
- }
350
+ pkg1: '^1.0.0',
351
+ pkg2: '^1.0.0',
352
+ },
461
353
  };
462
- await writeFile(
463
- join(tempDir, 'package.json'),
464
- JSON.stringify(packageJson)
465
- );
354
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
466
355
  await writeFile(
467
356
  join(tempDir, 'file.ts'),
468
357
  'import { a } from "pkg1";\nimport { b } from "pkg1";\nimport { c } from "pkg2";'
@@ -481,19 +370,13 @@ describe('DependencyUsageAnalyzer', () => {
481
370
  describe('Progress reporting', () => {
482
371
  it('calls progress callback during analysis', async () => {
483
372
  const packageJson = {
484
- dependencies: { 'pkg': '^1.0.0' }
373
+ dependencies: { pkg: '^1.0.0' },
485
374
  };
486
- await writeFile(
487
- join(tempDir, 'package.json'),
488
- JSON.stringify(packageJson)
489
- );
375
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
490
376
 
491
377
  // Create multiple files to trigger progress (fires every 10 files)
492
378
  for (let i = 0; i < 25; i++) {
493
- await writeFile(
494
- join(tempDir, `file${i}.ts`),
495
- 'import { x } from "pkg";'
496
- );
379
+ await writeFile(join(tempDir, `file${i}.ts`), 'import { x } from "pkg";');
497
380
  }
498
381
 
499
382
  const progressCalls: Array<{ current: number; total: number; message: string }> = [];
@@ -512,75 +395,51 @@ describe('DependencyUsageAnalyzer', () => {
512
395
  describe('Import detection methods', () => {
513
396
  it('uses ESM imports as primary detection method', async () => {
514
397
  const packageJson = {
515
- dependencies: { 'pkg': '^1.0.0' }
398
+ dependencies: { pkg: '^1.0.0' },
516
399
  };
517
- await writeFile(
518
- join(tempDir, 'package.json'),
519
- JSON.stringify(packageJson)
520
- );
521
- await writeFile(
522
- join(tempDir, 'file.js'),
523
- 'import { foo } from "pkg";'
524
- );
400
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
401
+ await writeFile(join(tempDir, 'file.js'), 'import { foo } from "pkg";');
525
402
 
526
403
  const result = await analyzer.analyze(tempDir);
527
404
 
528
405
  expect(result.success).toBe(true);
529
406
  if (result.success) {
530
- const pkgUsage = result.data.usages.find(u => u.packageName === 'pkg');
407
+ const pkgUsage = result.data.usages.find((u) => u.packageName === 'pkg');
531
408
  expect(pkgUsage).toBeDefined();
532
409
  expect(pkgUsage?.packageName).toBe('pkg');
533
410
  }
534
411
  });
535
412
 
536
413
  it('detects Python import statements', async () => {
537
- await writeFile(
538
- join(tempDir, 'requirements.txt'),
539
- 'requests==2.28.0'
540
- );
541
- await writeFile(
542
- join(tempDir, 'script.py'),
543
- 'import requests'
544
- );
414
+ await writeFile(join(tempDir, 'requirements.txt'), 'requests==2.28.0');
415
+ await writeFile(join(tempDir, 'script.py'), 'import requests');
545
416
 
546
417
  const result = await analyzer.analyze(tempDir);
547
418
 
548
419
  expect(result.success).toBe(true);
549
420
  if (result.success) {
550
- expect(result.data.usages.some(u => u.packageName === 'requests')).toBe(true);
421
+ expect(result.data.usages.some((u) => u.packageName === 'requests')).toBe(true);
551
422
  }
552
423
  });
553
424
 
554
425
  it('detects Python from...import statements', async () => {
555
- await writeFile(
556
- join(tempDir, 'requirements.txt'),
557
- 'numpy>=1.20.0'
558
- );
559
- await writeFile(
560
- join(tempDir, 'script.py'),
561
- 'from numpy import array'
562
- );
426
+ await writeFile(join(tempDir, 'requirements.txt'), 'numpy>=1.20.0');
427
+ await writeFile(join(tempDir, 'script.py'), 'from numpy import array');
563
428
 
564
429
  const result = await analyzer.analyze(tempDir);
565
430
 
566
431
  expect(result.success).toBe(true);
567
432
  if (result.success) {
568
- expect(result.data.usages.some(u => u.packageName === 'numpy')).toBe(true);
433
+ expect(result.data.usages.some((u) => u.packageName === 'numpy')).toBe(true);
569
434
  }
570
435
  });
571
436
 
572
437
  it('handles malformed code gracefully', async () => {
573
438
  const packageJson = {
574
- dependencies: { 'pkg': '^1.0.0' }
439
+ dependencies: { pkg: '^1.0.0' },
575
440
  };
576
- await writeFile(
577
- join(tempDir, 'package.json'),
578
- JSON.stringify(packageJson)
579
- );
580
- await writeFile(
581
- join(tempDir, 'broken.ts'),
582
- 'import { incomplete from "pkg"'
583
- );
441
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
442
+ await writeFile(join(tempDir, 'broken.ts'), 'import { incomplete from "pkg"');
584
443
 
585
444
  const result = await analyzer.analyze(tempDir);
586
445
 
@@ -594,10 +453,7 @@ describe('DependencyUsageAnalyzer', () => {
594
453
  describe('Analysis metadata', () => {
595
454
  it('includes analysis time', async () => {
596
455
  const packageJson = { dependencies: {} };
597
- await writeFile(
598
- join(tempDir, 'package.json'),
599
- JSON.stringify(packageJson)
600
- );
456
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
601
457
 
602
458
  const result = await analyzer.analyze(tempDir);
603
459
 
@@ -609,16 +465,10 @@ describe('DependencyUsageAnalyzer', () => {
609
465
 
610
466
  it('counts skipped files', async () => {
611
467
  const packageJson = {
612
- dependencies: { 'pkg': '^1.0.0' }
468
+ dependencies: { pkg: '^1.0.0' },
613
469
  };
614
- await writeFile(
615
- join(tempDir, 'package.json'),
616
- JSON.stringify(packageJson)
617
- );
618
- await writeFile(
619
- join(tempDir, 'good.ts'),
620
- 'import { x } from "pkg";'
621
- );
470
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
471
+ await writeFile(join(tempDir, 'good.ts'), 'import { x } from "pkg";');
622
472
 
623
473
  const result = await analyzer.analyze(tempDir);
624
474
 
@@ -632,16 +482,10 @@ describe('DependencyUsageAnalyzer', () => {
632
482
  describe('Language detection', () => {
633
483
  it('sets language to javascript for package.json dependencies', async () => {
634
484
  const packageJson = {
635
- dependencies: { 'lodash': '^4.0.0' }
485
+ dependencies: { lodash: '^4.0.0' },
636
486
  };
637
- await writeFile(
638
- join(tempDir, 'package.json'),
639
- JSON.stringify(packageJson)
640
- );
641
- await writeFile(
642
- join(tempDir, 'index.ts'),
643
- 'import { map } from "lodash";'
644
- );
487
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
488
+ await writeFile(join(tempDir, 'index.ts'), 'import { map } from "lodash";');
645
489
 
646
490
  const result = await analyzer.analyze(tempDir);
647
491
 
@@ -652,14 +496,8 @@ describe('DependencyUsageAnalyzer', () => {
652
496
  });
653
497
 
654
498
  it('sets language to python for requirements.txt dependencies', async () => {
655
- await writeFile(
656
- join(tempDir, 'requirements.txt'),
657
- 'requests==2.28.0'
658
- );
659
- await writeFile(
660
- join(tempDir, 'script.py'),
661
- 'import requests'
662
- );
499
+ await writeFile(join(tempDir, 'requirements.txt'), 'requests==2.28.0');
500
+ await writeFile(join(tempDir, 'script.py'), 'import requests');
663
501
 
664
502
  const result = await analyzer.analyze(tempDir);
665
503
 
@@ -704,10 +542,7 @@ serde = "1.0"
704
542
  tokio = { version = "1.0" }
705
543
  `
706
544
  );
707
- await writeFile(
708
- join(tempDir, 'main.rs'),
709
- 'use serde::Serialize;'
710
- );
545
+ await writeFile(join(tempDir, 'main.rs'), 'use serde::Serialize;');
711
546
 
712
547
  const result = await analyzer.analyze(tempDir);
713
548
 
@@ -729,10 +564,7 @@ require (
729
564
  )
730
565
  `
731
566
  );
732
- await writeFile(
733
- join(tempDir, 'main.go'),
734
- 'import "github.com/gorilla/mux"'
735
- );
567
+ await writeFile(join(tempDir, 'main.go'), 'import "github.com/gorilla/mux"');
736
568
 
737
569
  const result = await analyzer.analyze(tempDir);
738
570
 
@@ -763,33 +595,21 @@ require (
763
595
  it('handles mixed language projects', async () => {
764
596
  // JavaScript
765
597
  const packageJson = {
766
- dependencies: { 'express': '^4.0.0' }
598
+ dependencies: { express: '^4.0.0' },
767
599
  };
768
- await writeFile(
769
- join(tempDir, 'package.json'),
770
- JSON.stringify(packageJson)
771
- );
772
- await writeFile(
773
- join(tempDir, 'server.js'),
774
- 'import express from "express";'
775
- );
600
+ await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
601
+ await writeFile(join(tempDir, 'server.js'), 'import express from "express";');
776
602
 
777
603
  // Python
778
- await writeFile(
779
- join(tempDir, 'requirements.txt'),
780
- 'flask==2.0.0'
781
- );
782
- await writeFile(
783
- join(tempDir, 'app.py'),
784
- 'import flask'
785
- );
604
+ await writeFile(join(tempDir, 'requirements.txt'), 'flask==2.0.0');
605
+ await writeFile(join(tempDir, 'app.py'), 'import flask');
786
606
 
787
607
  const result = await analyzer.analyze(tempDir);
788
608
 
789
609
  expect(result.success).toBe(true);
790
610
  if (result.success) {
791
- const jsUsage = result.data.usages.find(u => u.packageName === 'express');
792
- const pyUsage = result.data.usages.find(u => u.packageName === 'flask');
611
+ const jsUsage = result.data.usages.find((u) => u.packageName === 'express');
612
+ const pyUsage = result.data.usages.find((u) => u.packageName === 'flask');
793
613
 
794
614
  expect(jsUsage?.language).toBe('javascript');
795
615
  expect(pyUsage?.language).toBe('python');