bluera-knowledge 0.9.31 → 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 (200) hide show
  1. package/.claude/commands/code-review.md +15 -0
  2. package/.claude/hooks/post-edit-check.sh +5 -3
  3. package/.claude/skills/atomic-commits/SKILL.md +3 -1
  4. package/.claude/skills/code-review-repo/skill.md +62 -0
  5. package/.husky/pre-commit +3 -2
  6. package/.prettierrc +9 -0
  7. package/.versionrc.json +1 -1
  8. package/CHANGELOG.md +35 -0
  9. package/CLAUDE.md +6 -0
  10. package/README.md +25 -13
  11. package/bun.lock +277 -33
  12. package/dist/{chunk-L2YVNC63.js → chunk-6FHWC36B.js} +9 -1
  13. package/dist/chunk-6FHWC36B.js.map +1 -0
  14. package/dist/{chunk-2SJHNRXD.js → chunk-DC7CGSGT.js} +288 -241
  15. package/dist/chunk-DC7CGSGT.js.map +1 -0
  16. package/dist/{chunk-RWSXP3PQ.js → chunk-WFNPNAAP.js} +3194 -3024
  17. package/dist/chunk-WFNPNAAP.js.map +1 -0
  18. package/dist/{chunk-OGEY66FZ.js → chunk-Z2KKVH45.js} +548 -482
  19. package/dist/chunk-Z2KKVH45.js.map +1 -0
  20. package/dist/index.js +871 -754
  21. package/dist/index.js.map +1 -1
  22. package/dist/mcp/server.js +3 -3
  23. package/dist/watch.service-BJV3TI3F.js +7 -0
  24. package/dist/workers/background-worker-cli.js +46 -45
  25. package/dist/workers/background-worker-cli.js.map +1 -1
  26. package/eslint.config.js +43 -1
  27. package/package.json +18 -11
  28. package/plugin.json +8 -0
  29. package/python/requirements.txt +1 -1
  30. package/src/analysis/ast-parser.test.ts +12 -11
  31. package/src/analysis/ast-parser.ts +28 -22
  32. package/src/analysis/code-graph.test.ts +52 -62
  33. package/src/analysis/code-graph.ts +9 -13
  34. package/src/analysis/dependency-usage-analyzer.test.ts +91 -271
  35. package/src/analysis/dependency-usage-analyzer.ts +52 -24
  36. package/src/analysis/go-ast-parser.test.ts +22 -22
  37. package/src/analysis/go-ast-parser.ts +18 -25
  38. package/src/analysis/parser-factory.test.ts +9 -9
  39. package/src/analysis/parser-factory.ts +3 -3
  40. package/src/analysis/python-ast-parser.test.ts +27 -27
  41. package/src/analysis/python-ast-parser.ts +2 -2
  42. package/src/analysis/repo-url-resolver.test.ts +82 -82
  43. package/src/analysis/rust-ast-parser.test.ts +19 -19
  44. package/src/analysis/rust-ast-parser.ts +17 -27
  45. package/src/analysis/tree-sitter-parser.test.ts +3 -3
  46. package/src/analysis/tree-sitter-parser.ts +10 -16
  47. package/src/cli/commands/crawl.test.ts +40 -24
  48. package/src/cli/commands/crawl.ts +186 -161
  49. package/src/cli/commands/index-cmd.test.ts +90 -90
  50. package/src/cli/commands/index-cmd.ts +52 -36
  51. package/src/cli/commands/mcp.test.ts +6 -6
  52. package/src/cli/commands/mcp.ts +2 -2
  53. package/src/cli/commands/plugin-api.test.ts +16 -18
  54. package/src/cli/commands/plugin-api.ts +9 -6
  55. package/src/cli/commands/search.test.ts +16 -7
  56. package/src/cli/commands/search.ts +124 -87
  57. package/src/cli/commands/serve.test.ts +67 -25
  58. package/src/cli/commands/serve.ts +18 -3
  59. package/src/cli/commands/setup.test.ts +176 -101
  60. package/src/cli/commands/setup.ts +140 -117
  61. package/src/cli/commands/store.test.ts +82 -53
  62. package/src/cli/commands/store.ts +56 -37
  63. package/src/cli/program.ts +2 -2
  64. package/src/crawl/article-converter.test.ts +4 -1
  65. package/src/crawl/article-converter.ts +46 -31
  66. package/src/crawl/bridge.test.ts +240 -132
  67. package/src/crawl/bridge.ts +87 -30
  68. package/src/crawl/claude-client.test.ts +124 -56
  69. package/src/crawl/claude-client.ts +7 -15
  70. package/src/crawl/intelligent-crawler.test.ts +65 -22
  71. package/src/crawl/intelligent-crawler.ts +86 -53
  72. package/src/crawl/markdown-utils.ts +1 -4
  73. package/src/db/embeddings.ts +4 -6
  74. package/src/db/lance.test.ts +63 -4
  75. package/src/db/lance.ts +31 -12
  76. package/src/index.ts +26 -17
  77. package/src/logging/index.ts +1 -5
  78. package/src/logging/logger.ts +3 -5
  79. package/src/logging/payload.test.ts +1 -1
  80. package/src/logging/payload.ts +3 -5
  81. package/src/mcp/commands/index.ts +2 -2
  82. package/src/mcp/commands/job.commands.ts +12 -18
  83. package/src/mcp/commands/meta.commands.ts +13 -13
  84. package/src/mcp/commands/registry.ts +5 -8
  85. package/src/mcp/commands/store.commands.ts +19 -19
  86. package/src/mcp/handlers/execute.handler.test.ts +10 -10
  87. package/src/mcp/handlers/execute.handler.ts +4 -5
  88. package/src/mcp/handlers/index.ts +10 -14
  89. package/src/mcp/handlers/job.handler.test.ts +10 -10
  90. package/src/mcp/handlers/job.handler.ts +22 -25
  91. package/src/mcp/handlers/search.handler.test.ts +36 -65
  92. package/src/mcp/handlers/search.handler.ts +135 -104
  93. package/src/mcp/handlers/store.handler.test.ts +41 -52
  94. package/src/mcp/handlers/store.handler.ts +108 -88
  95. package/src/mcp/schemas/index.test.ts +73 -68
  96. package/src/mcp/schemas/index.ts +18 -12
  97. package/src/mcp/server.test.ts +1 -1
  98. package/src/mcp/server.ts +59 -46
  99. package/src/plugin/commands.test.ts +230 -95
  100. package/src/plugin/commands.ts +24 -25
  101. package/src/plugin/dependency-analyzer.test.ts +52 -52
  102. package/src/plugin/dependency-analyzer.ts +85 -22
  103. package/src/plugin/git-clone.test.ts +24 -13
  104. package/src/plugin/git-clone.ts +3 -7
  105. package/src/server/app.test.ts +109 -109
  106. package/src/server/app.ts +32 -23
  107. package/src/server/index.test.ts +64 -66
  108. package/src/services/chunking.service.test.ts +32 -32
  109. package/src/services/chunking.service.ts +16 -9
  110. package/src/services/code-graph.service.test.ts +30 -36
  111. package/src/services/code-graph.service.ts +24 -10
  112. package/src/services/code-unit.service.test.ts +55 -11
  113. package/src/services/code-unit.service.ts +85 -11
  114. package/src/services/config.service.test.ts +37 -18
  115. package/src/services/config.service.ts +30 -7
  116. package/src/services/index.service.test.ts +49 -18
  117. package/src/services/index.service.ts +98 -48
  118. package/src/services/index.ts +8 -10
  119. package/src/services/job.service.test.ts +22 -22
  120. package/src/services/job.service.ts +18 -18
  121. package/src/services/project-root.service.test.ts +1 -3
  122. package/src/services/search.service.test.ts +248 -120
  123. package/src/services/search.service.ts +286 -156
  124. package/src/services/services.test.ts +36 -0
  125. package/src/services/snippet.service.test.ts +14 -6
  126. package/src/services/snippet.service.ts +7 -5
  127. package/src/services/store.service.test.ts +68 -29
  128. package/src/services/store.service.ts +41 -12
  129. package/src/services/watch.service.test.ts +34 -14
  130. package/src/services/watch.service.ts +11 -1
  131. package/src/types/brands.test.ts +3 -1
  132. package/src/types/index.ts +2 -13
  133. package/src/types/search.ts +10 -8
  134. package/src/utils/type-guards.test.ts +20 -15
  135. package/src/utils/type-guards.ts +1 -1
  136. package/src/workers/background-worker-cli.ts +2 -2
  137. package/src/workers/background-worker.test.ts +54 -40
  138. package/src/workers/background-worker.ts +76 -60
  139. package/src/workers/spawn-worker.test.ts +22 -10
  140. package/src/workers/spawn-worker.ts +6 -6
  141. package/tests/analysis/ast-parser.test.ts +3 -3
  142. package/tests/analysis/code-graph.test.ts +5 -5
  143. package/tests/fixtures/code-snippets/api/error-handling.ts +4 -15
  144. package/tests/fixtures/code-snippets/api/rest-controller.ts +3 -9
  145. package/tests/fixtures/code-snippets/auth/jwt-auth.ts +5 -21
  146. package/tests/fixtures/code-snippets/auth/oauth-flow.ts +4 -4
  147. package/tests/fixtures/code-snippets/database/repository-pattern.ts +11 -3
  148. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +2 -2
  149. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +1 -1
  150. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +2 -2
  151. package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +2 -2
  152. package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +22 -20
  153. package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +13 -10
  154. package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +10 -7
  155. package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +2 -2
  156. package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +1 -1
  157. package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +16 -16
  158. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +2 -2
  159. package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +3 -3
  160. package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +1 -1
  161. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +2 -2
  162. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +1 -1
  163. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +7 -7
  164. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +3 -3
  165. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +1 -1
  166. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +6 -6
  167. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +3 -3
  168. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +1 -1
  169. package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +1 -1
  170. package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +1 -1
  171. package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +2 -2
  172. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +4 -4
  173. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +1 -1
  174. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +1 -1
  175. package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +166 -169
  176. package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +8 -8
  177. package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +3 -3
  178. package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +2 -2
  179. package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +2 -2
  180. package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +30 -33
  181. package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +2 -2
  182. package/tests/fixtures/test-server.ts +3 -2
  183. package/tests/helpers/performance-metrics.ts +8 -25
  184. package/tests/helpers/search-relevance.ts +14 -69
  185. package/tests/integration/cli-consistency.test.ts +5 -4
  186. package/tests/integration/e2e-workflow.test.ts +2 -0
  187. package/tests/integration/python-bridge.test.ts +13 -3
  188. package/tests/mcp/server.test.ts +1 -1
  189. package/tests/services/code-unit.service.test.ts +48 -0
  190. package/tests/services/job.service.test.ts +124 -0
  191. package/tests/services/search.progressive-context.test.ts +2 -2
  192. package/.claude-plugin/plugin.json +0 -13
  193. package/BUGS-FOUND.md +0 -71
  194. package/dist/chunk-2SJHNRXD.js.map +0 -1
  195. package/dist/chunk-L2YVNC63.js.map +0 -1
  196. package/dist/chunk-OGEY66FZ.js.map +0 -1
  197. package/dist/chunk-RWSXP3PQ.js.map +0 -1
  198. package/dist/watch.service-YAIKKDCF.js +0 -7
  199. package/skills/atomic-commits/SKILL.md +0 -77
  200. /package/dist/{watch.service-YAIKKDCF.js.map → watch.service-BJV3TI3F.js.map} +0 -0
package/src/server/app.ts CHANGED
@@ -1,30 +1,38 @@
1
1
  import { Hono } from 'hono';
2
2
  import { cors } from 'hono/cors';
3
3
  import { z } from 'zod';
4
+ import { createStoreId } from '../types/brands.js';
4
5
  import type { ServiceContainer } from '../services/index.js';
5
6
  import type { SearchQuery } from '../types/search.js';
6
- import { createStoreId } from '../types/brands.js';
7
7
 
8
8
  // HTTP API validation schemas (consistent with MCP schemas)
9
- const CreateStoreBodySchema = z.object({
10
- name: z.string().min(1, 'Store name must be a non-empty string'),
11
- type: z.enum(['file', 'repo', 'web']),
12
- path: z.string().min(1).optional(),
13
- url: z.string().min(1).optional(),
14
- description: z.string().optional(),
15
- tags: z.array(z.string()).optional(),
16
- branch: z.string().optional(),
17
- depth: z.number().int().positive().optional(),
18
- }).refine(
19
- (data) => {
20
- switch (data.type) {
21
- case 'file': return data.path !== undefined;
22
- case 'web': return data.url !== undefined;
23
- case 'repo': return data.path !== undefined || data.url !== undefined;
9
+ const CreateStoreBodySchema = z
10
+ .object({
11
+ name: z.string().min(1, 'Store name must be a non-empty string'),
12
+ type: z.enum(['file', 'repo', 'web']),
13
+ path: z.string().min(1).optional(),
14
+ url: z.string().min(1).optional(),
15
+ description: z.string().optional(),
16
+ tags: z.array(z.string()).optional(),
17
+ branch: z.string().optional(),
18
+ depth: z.number().int().positive().optional(),
19
+ })
20
+ .refine(
21
+ (data) => {
22
+ switch (data.type) {
23
+ case 'file':
24
+ return data.path !== undefined;
25
+ case 'web':
26
+ return data.url !== undefined;
27
+ case 'repo':
28
+ return data.path !== undefined || data.url !== undefined;
29
+ }
30
+ },
31
+ {
32
+ message:
33
+ 'Missing required field: file stores need path, web stores need url, repo stores need path or url',
24
34
  }
25
- },
26
- { message: 'Missing required field: file stores need path, web stores need url, repo stores need path or url' }
27
- );
35
+ );
28
36
 
29
37
  const SearchBodySchema = z.object({
30
38
  query: z.string().min(1, 'Query must be a non-empty string'),
@@ -82,16 +90,17 @@ export function createApp(services: ServiceContainer): Hono {
82
90
  return c.json({ error: parseResult.error.issues[0]?.message ?? 'Invalid request body' }, 400);
83
91
  }
84
92
 
85
- const storeIds = (await services.store.list()).map(s => s.id);
93
+ const storeIds = (await services.store.list()).map((s) => s.id);
86
94
 
87
95
  for (const id of storeIds) {
88
96
  await services.lance.initialize(id);
89
97
  }
90
98
 
91
99
  // Convert user-provided store strings to StoreIds, or use all stores
92
- const requestedStores = parseResult.data.stores !== undefined
93
- ? parseResult.data.stores.map(s => createStoreId(s))
94
- : storeIds;
100
+ const requestedStores =
101
+ parseResult.data.stores !== undefined
102
+ ? parseResult.data.stores.map((s) => createStoreId(s))
103
+ : storeIds;
95
104
 
96
105
  const query: SearchQuery = {
97
106
  query: parseResult.data.query,
@@ -13,17 +13,17 @@ describe('Server Integration - Full App Creation', () => {
13
13
  list: vi.fn(),
14
14
  getByIdOrName: vi.fn(),
15
15
  create: vi.fn(),
16
- delete: vi.fn()
16
+ delete: vi.fn(),
17
17
  },
18
18
  lance: {
19
- initialize: vi.fn()
19
+ initialize: vi.fn(),
20
20
  },
21
21
  search: {
22
- search: vi.fn()
22
+ search: vi.fn(),
23
23
  },
24
24
  index: {
25
- indexStore: vi.fn()
26
- }
25
+ indexStore: vi.fn(),
26
+ },
27
27
  } as unknown as ServiceContainer;
28
28
  });
29
29
 
@@ -62,17 +62,17 @@ describe('Server Integration - Store CRUD Flow', () => {
62
62
  list: vi.fn(),
63
63
  getByIdOrName: vi.fn(),
64
64
  create: vi.fn(),
65
- delete: vi.fn()
65
+ delete: vi.fn(),
66
66
  },
67
67
  lance: {
68
- initialize: vi.fn()
68
+ initialize: vi.fn(),
69
69
  },
70
70
  search: {
71
- search: vi.fn()
71
+ search: vi.fn(),
72
72
  },
73
73
  index: {
74
- indexStore: vi.fn()
75
- }
74
+ indexStore: vi.fn(),
75
+ },
76
76
  } as unknown as ServiceContainer;
77
77
  });
78
78
 
@@ -93,12 +93,12 @@ describe('Server Integration - Store CRUD Flow', () => {
93
93
  type: 'file',
94
94
  path: '/tmp/test',
95
95
  createdAt: new Date(),
96
- updatedAt: new Date()
96
+ updatedAt: new Date(),
97
97
  };
98
98
 
99
99
  vi.mocked(mockServices.store.create).mockResolvedValue({
100
100
  success: true,
101
- data: newStore
101
+ data: newStore,
102
102
  });
103
103
 
104
104
  res = await app.request('/api/stores', {
@@ -107,8 +107,8 @@ describe('Server Integration - Store CRUD Flow', () => {
107
107
  body: JSON.stringify({
108
108
  name: 'test-store',
109
109
  type: 'file',
110
- path: '/tmp/test'
111
- })
110
+ path: '/tmp/test',
111
+ }),
112
112
  });
113
113
 
114
114
  expect(res.status).toBe(201);
@@ -123,11 +123,11 @@ describe('Server Integration - Store CRUD Flow', () => {
123
123
  // 4. Delete store
124
124
  vi.mocked(mockServices.store.delete).mockResolvedValue({
125
125
  success: true,
126
- data: undefined
126
+ data: undefined,
127
127
  });
128
128
 
129
129
  res = await app.request('/api/stores/new-store', {
130
- method: 'DELETE'
130
+ method: 'DELETE',
131
131
  });
132
132
 
133
133
  expect(res.status).toBe(200);
@@ -140,14 +140,14 @@ describe('Server Integration - Search Flow', () => {
140
140
  beforeEach(() => {
141
141
  mockServices = {
142
142
  store: {
143
- list: vi.fn()
143
+ list: vi.fn(),
144
144
  },
145
145
  lance: {
146
- initialize: vi.fn()
146
+ initialize: vi.fn(),
147
147
  },
148
148
  search: {
149
- search: vi.fn()
150
- }
149
+ search: vi.fn(),
150
+ },
151
151
  } as unknown as ServiceContainer;
152
152
  });
153
153
 
@@ -161,7 +161,7 @@ describe('Server Integration - Search Flow', () => {
161
161
  type: 'file',
162
162
  path: '/tmp/1',
163
163
  createdAt: new Date(),
164
- updatedAt: new Date()
164
+ updatedAt: new Date(),
165
165
  },
166
166
  {
167
167
  id: createStoreId('store-2'),
@@ -169,22 +169,20 @@ describe('Server Integration - Search Flow', () => {
169
169
  type: 'file',
170
170
  path: '/tmp/2',
171
171
  createdAt: new Date(),
172
- updatedAt: new Date()
173
- }
172
+ updatedAt: new Date(),
173
+ },
174
174
  ];
175
175
 
176
176
  vi.mocked(mockServices.store.list).mockResolvedValue(stores);
177
177
  vi.mocked(mockServices.search.search).mockResolvedValue({
178
- results: [
179
- { score: 0.9, summary: { location: 'file1.ts', purpose: 'Test' } }
180
- ],
181
- totalResults: 1
178
+ results: [{ score: 0.9, summary: { location: 'file1.ts', purpose: 'Test' } }],
179
+ totalResults: 1,
182
180
  });
183
181
 
184
182
  const res = await app.request('/api/search', {
185
183
  method: 'POST',
186
184
  headers: { 'Content-Type': 'application/json' },
187
- body: JSON.stringify({ query: 'test query' })
185
+ body: JSON.stringify({ query: 'test query' }),
188
186
  });
189
187
 
190
188
  expect(res.status).toBe(200);
@@ -199,14 +197,14 @@ describe('Server Integration - Index Flow', () => {
199
197
  beforeEach(() => {
200
198
  mockServices = {
201
199
  store: {
202
- getByIdOrName: vi.fn()
200
+ getByIdOrName: vi.fn(),
203
201
  },
204
202
  lance: {
205
- initialize: vi.fn()
203
+ initialize: vi.fn(),
206
204
  },
207
205
  index: {
208
- indexStore: vi.fn()
209
- }
206
+ indexStore: vi.fn(),
207
+ },
210
208
  } as unknown as ServiceContainer;
211
209
  });
212
210
 
@@ -219,7 +217,7 @@ describe('Server Integration - Index Flow', () => {
219
217
  type: 'file',
220
218
  path: '/tmp/test',
221
219
  createdAt: new Date(),
222
- updatedAt: new Date()
220
+ updatedAt: new Date(),
223
221
  };
224
222
 
225
223
  vi.mocked(mockServices.store.getByIdOrName).mockResolvedValue(store);
@@ -228,12 +226,12 @@ describe('Server Integration - Index Flow', () => {
228
226
  data: {
229
227
  documentsIndexed: 5,
230
228
  chunksCreated: 25,
231
- timeMs: 500
232
- }
229
+ timeMs: 500,
230
+ },
233
231
  });
234
232
 
235
233
  const res = await app.request('/api/stores/store-1/index', {
236
- method: 'POST'
234
+ method: 'POST',
237
235
  });
238
236
 
239
237
  expect(res.status).toBe(200);
@@ -250,14 +248,14 @@ describe('Server Integration - Error Handling', () => {
250
248
  store: {
251
249
  create: vi.fn(),
252
250
  getByIdOrName: vi.fn(),
253
- delete: vi.fn()
251
+ delete: vi.fn(),
254
252
  },
255
253
  index: {
256
- indexStore: vi.fn()
254
+ indexStore: vi.fn(),
257
255
  },
258
256
  lance: {
259
- initialize: vi.fn()
260
- }
257
+ initialize: vi.fn(),
258
+ },
261
259
  } as unknown as ServiceContainer;
262
260
  });
263
261
 
@@ -266,7 +264,7 @@ describe('Server Integration - Error Handling', () => {
266
264
 
267
265
  vi.mocked(mockServices.store.create).mockResolvedValue({
268
266
  success: false,
269
- error: new Error('Service error')
267
+ error: new Error('Service error'),
270
268
  });
271
269
 
272
270
  const res = await app.request('/api/stores', {
@@ -275,8 +273,8 @@ describe('Server Integration - Error Handling', () => {
275
273
  body: JSON.stringify({
276
274
  name: 'test',
277
275
  type: 'file',
278
- path: '/tmp/test'
279
- })
276
+ path: '/tmp/test',
277
+ }),
280
278
  });
281
279
 
282
280
  expect(res.status).toBe(400);
@@ -301,14 +299,14 @@ describe('Server Integration - Content Negotiation', () => {
301
299
  beforeEach(() => {
302
300
  mockServices = {
303
301
  store: {
304
- list: vi.fn()
302
+ list: vi.fn(),
305
303
  },
306
304
  lance: {
307
- initialize: vi.fn()
305
+ initialize: vi.fn(),
308
306
  },
309
307
  search: {
310
- search: vi.fn()
311
- }
308
+ search: vi.fn(),
309
+ },
312
310
  } as unknown as ServiceContainer;
313
311
  });
314
312
 
@@ -328,13 +326,13 @@ describe('Server Integration - Content Negotiation', () => {
328
326
  vi.mocked(mockServices.store.list).mockResolvedValue([]);
329
327
  vi.mocked(mockServices.search.search).mockResolvedValue({
330
328
  results: [],
331
- totalResults: 0
329
+ totalResults: 0,
332
330
  });
333
331
 
334
332
  const res = await app.request('/api/search', {
335
333
  method: 'POST',
336
334
  headers: { 'Content-Type': 'application/json' },
337
- body: JSON.stringify({ query: 'test' })
335
+ body: JSON.stringify({ query: 'test' }),
338
336
  });
339
337
 
340
338
  expect(res.status).toBe(200);
@@ -347,14 +345,14 @@ describe('Server Integration - Route Parameters', () => {
347
345
  beforeEach(() => {
348
346
  mockServices = {
349
347
  store: {
350
- getByIdOrName: vi.fn()
348
+ getByIdOrName: vi.fn(),
351
349
  },
352
350
  lance: {
353
- initialize: vi.fn()
351
+ initialize: vi.fn(),
354
352
  },
355
353
  index: {
356
- indexStore: vi.fn()
357
- }
354
+ indexStore: vi.fn(),
355
+ },
358
356
  } as unknown as ServiceContainer;
359
357
  });
360
358
 
@@ -367,7 +365,7 @@ describe('Server Integration - Route Parameters', () => {
367
365
  type: 'file',
368
366
  path: '/tmp/test',
369
367
  createdAt: new Date(),
370
- updatedAt: new Date()
368
+ updatedAt: new Date(),
371
369
  };
372
370
 
373
371
  vi.mocked(mockServices.store.getByIdOrName).mockResolvedValue(store);
@@ -386,7 +384,7 @@ describe('Server Integration - Route Parameters', () => {
386
384
  type: 'file',
387
385
  path: '/tmp/test',
388
386
  createdAt: new Date(),
389
- updatedAt: new Date()
387
+ updatedAt: new Date(),
390
388
  };
391
389
 
392
390
  vi.mocked(mockServices.store.getByIdOrName).mockResolvedValue(store);
@@ -406,17 +404,17 @@ describe('Server Integration - HTTP Methods', () => {
406
404
  list: vi.fn(),
407
405
  getByIdOrName: vi.fn(),
408
406
  create: vi.fn(),
409
- delete: vi.fn()
407
+ delete: vi.fn(),
410
408
  },
411
409
  lance: {
412
- initialize: vi.fn()
410
+ initialize: vi.fn(),
413
411
  },
414
412
  search: {
415
- search: vi.fn()
413
+ search: vi.fn(),
416
414
  },
417
415
  index: {
418
- indexStore: vi.fn()
419
- }
416
+ indexStore: vi.fn(),
417
+ },
420
418
  } as unknown as ServiceContainer;
421
419
  });
422
420
 
@@ -426,7 +424,7 @@ describe('Server Integration - HTTP Methods', () => {
426
424
  vi.mocked(mockServices.store.list).mockResolvedValue([]);
427
425
 
428
426
  const res = await app.request('/api/stores', {
429
- method: 'GET'
427
+ method: 'GET',
430
428
  });
431
429
 
432
430
  expect(res.status).toBe(200);
@@ -438,13 +436,13 @@ describe('Server Integration - HTTP Methods', () => {
438
436
  vi.mocked(mockServices.store.list).mockResolvedValue([]);
439
437
  vi.mocked(mockServices.search.search).mockResolvedValue({
440
438
  results: [],
441
- totalResults: 0
439
+ totalResults: 0,
442
440
  });
443
441
 
444
442
  const res = await app.request('/api/search', {
445
443
  method: 'POST',
446
444
  headers: { 'Content-Type': 'application/json' },
447
- body: JSON.stringify({ query: 'test' })
445
+ body: JSON.stringify({ query: 'test' }),
448
446
  });
449
447
 
450
448
  expect(res.status).toBe(200);
@@ -459,17 +457,17 @@ describe('Server Integration - HTTP Methods', () => {
459
457
  type: 'file',
460
458
  path: '/tmp/test',
461
459
  createdAt: new Date(),
462
- updatedAt: new Date()
460
+ updatedAt: new Date(),
463
461
  };
464
462
 
465
463
  vi.mocked(mockServices.store.getByIdOrName).mockResolvedValue(store);
466
464
  vi.mocked(mockServices.store.delete).mockResolvedValue({
467
465
  success: true,
468
- data: undefined
466
+ data: undefined,
469
467
  });
470
468
 
471
469
  const res = await app.request('/api/stores/store-1', {
472
- method: 'DELETE'
470
+ method: 'DELETE',
473
471
  });
474
472
 
475
473
  expect(res.status).toBe(200);
@@ -9,7 +9,7 @@ describe('ChunkingService', () => {
9
9
  const text = 'A'.repeat(250);
10
10
  const chunks = chunker.chunk(text);
11
11
  expect(chunks.length).toBeGreaterThan(1);
12
- expect(chunks.every(c => c.content.length <= 100)).toBe(true);
12
+ expect(chunks.every((c) => c.content.length <= 100)).toBe(true);
13
13
  });
14
14
 
15
15
  it('preserves overlap between chunks', () => {
@@ -34,7 +34,7 @@ describe('ChunkingService', () => {
34
34
  const chunks = chunker.chunk(text);
35
35
  expect(chunks[0]!.chunkIndex).toBe(0);
36
36
  expect(chunks[1]!.chunkIndex).toBe(1);
37
- expect(chunks.every(c => c.totalChunks === chunks.length)).toBe(true);
37
+ expect(chunks.every((c) => c.totalChunks === chunks.length)).toBe(true);
38
38
  });
39
39
 
40
40
  it('handles empty text', () => {
@@ -66,9 +66,9 @@ Content for section 3`;
66
66
 
67
67
  const chunks = chunker.chunk(markdown, 'test.md');
68
68
  expect(chunks.length).toBeGreaterThan(0);
69
- expect(chunks.some(c => c.sectionHeader === 'Header 1')).toBe(true);
70
- expect(chunks.some(c => c.sectionHeader === 'Header 2')).toBe(true);
71
- expect(chunks.some(c => c.sectionHeader === 'Header 3')).toBe(true);
69
+ expect(chunks.some((c) => c.sectionHeader === 'Header 1')).toBe(true);
70
+ expect(chunks.some((c) => c.sectionHeader === 'Header 2')).toBe(true);
71
+ expect(chunks.some((c) => c.sectionHeader === 'Header 3')).toBe(true);
72
72
  });
73
73
 
74
74
  it('handles markdown with no headers', () => {
@@ -91,7 +91,7 @@ Content for section 3`;
91
91
  const chunks = chunker.chunk(markdown, 'test.md');
92
92
  // Large section should be split
93
93
  expect(chunks.length).toBeGreaterThan(2);
94
- expect(chunks.filter(c => c.sectionHeader === 'Header 1').length).toBeGreaterThan(1);
94
+ expect(chunks.filter((c) => c.sectionHeader === 'Header 1').length).toBeGreaterThan(1);
95
95
  });
96
96
 
97
97
  it('preserves markdown section headers in metadata', () => {
@@ -121,9 +121,9 @@ Content 3
121
121
  Content 2`;
122
122
 
123
123
  const chunks = chunker.chunk(markdown, 'test.md');
124
- expect(chunks.some(c => c.sectionHeader === 'H1')).toBe(true);
125
- expect(chunks.some(c => c.sectionHeader === 'H3')).toBe(true);
126
- expect(chunks.some(c => c.sectionHeader === 'H2')).toBe(true);
124
+ expect(chunks.some((c) => c.sectionHeader === 'H1')).toBe(true);
125
+ expect(chunks.some((c) => c.sectionHeader === 'H3')).toBe(true);
126
+ expect(chunks.some((c) => c.sectionHeader === 'H2')).toBe(true);
127
127
  });
128
128
  });
129
129
 
@@ -139,8 +139,8 @@ function bar() {
139
139
 
140
140
  const chunks = chunker.chunk(code, 'test.ts');
141
141
  expect(chunks.length).toBeGreaterThan(0);
142
- expect(chunks.some(c => c.functionName === 'foo')).toBe(true);
143
- expect(chunks.some(c => c.functionName === 'bar')).toBe(true);
142
+ expect(chunks.some((c) => c.functionName === 'foo')).toBe(true);
143
+ expect(chunks.some((c) => c.functionName === 'bar')).toBe(true);
144
144
  });
145
145
 
146
146
  it('handles class declarations', () => {
@@ -153,8 +153,8 @@ class AnotherClass {
153
153
  }`;
154
154
 
155
155
  const chunks = chunker.chunk(code, 'test.ts');
156
- expect(chunks.some(c => c.functionName === 'MyClass')).toBe(true);
157
- expect(chunks.some(c => c.functionName === 'AnotherClass')).toBe(true);
156
+ expect(chunks.some((c) => c.functionName === 'MyClass')).toBe(true);
157
+ expect(chunks.some((c) => c.functionName === 'AnotherClass')).toBe(true);
158
158
  });
159
159
 
160
160
  it('handles exported declarations', () => {
@@ -165,8 +165,8 @@ class AnotherClass {
165
165
  export class ExportedClass {}`;
166
166
 
167
167
  const chunks = chunker.chunk(code, 'test.ts');
168
- expect(chunks.some(c => c.functionName === 'exportedFn')).toBe(true);
169
- expect(chunks.some(c => c.functionName === 'ExportedClass')).toBe(true);
168
+ expect(chunks.some((c) => c.functionName === 'exportedFn')).toBe(true);
169
+ expect(chunks.some((c) => c.functionName === 'ExportedClass')).toBe(true);
170
170
  });
171
171
 
172
172
  it('handles async functions', () => {
@@ -175,7 +175,7 @@ export class ExportedClass {}`;
175
175
  }`;
176
176
 
177
177
  const chunks = chunker.chunk(code, 'test.ts');
178
- expect(chunks.some(c => c.functionName === 'asyncFn')).toBe(true);
178
+ expect(chunks.some((c) => c.functionName === 'asyncFn')).toBe(true);
179
179
  });
180
180
 
181
181
  it('handles const/let/var declarations', () => {
@@ -186,9 +186,9 @@ let myLet = 'test';
186
186
  var myVar = true;`;
187
187
 
188
188
  const chunks = chunker.chunk(code, 'test.ts');
189
- expect(chunks.some(c => c.functionName === 'myConst')).toBe(true);
190
- expect(chunks.some(c => c.functionName === 'myLet')).toBe(true);
191
- expect(chunks.some(c => c.functionName === 'myVar')).toBe(true);
189
+ expect(chunks.some((c) => c.functionName === 'myConst')).toBe(true);
190
+ expect(chunks.some((c) => c.functionName === 'myLet')).toBe(true);
191
+ expect(chunks.some((c) => c.functionName === 'myVar')).toBe(true);
192
192
  });
193
193
 
194
194
  it('handles interface and type declarations', () => {
@@ -201,8 +201,8 @@ type MyType = {
201
201
  }`;
202
202
 
203
203
  const chunks = chunker.chunk(code, 'test.ts');
204
- expect(chunks.some(c => c.functionName === 'MyInterface')).toBe(true);
205
- expect(chunks.some(c => c.functionName === 'MyType')).toBe(true);
204
+ expect(chunks.some((c) => c.functionName === 'MyInterface')).toBe(true);
205
+ expect(chunks.some((c) => c.functionName === 'MyType')).toBe(true);
206
206
  });
207
207
 
208
208
  it('handles enum declarations', () => {
@@ -213,7 +213,7 @@ type MyType = {
213
213
  }`;
214
214
 
215
215
  const chunks = chunker.chunk(code, 'test.ts');
216
- expect(chunks.some(c => c.functionName === 'Color')).toBe(true);
216
+ expect(chunks.some((c) => c.functionName === 'Color')).toBe(true);
217
217
  });
218
218
 
219
219
  it('handles code with no declarations', () => {
@@ -252,7 +252,7 @@ function smallFn() {
252
252
  }`;
253
253
 
254
254
  const chunks = chunker.chunk(code, 'test.ts');
255
- expect(chunks.some(c => c.functionName === 'withNested')).toBe(true);
255
+ expect(chunks.some((c) => c.functionName === 'withNested')).toBe(true);
256
256
  });
257
257
 
258
258
  it('exposes brace counting bug - braces in strings', () => {
@@ -269,8 +269,8 @@ function nextFn() {
269
269
  }`;
270
270
 
271
271
  const chunks = chunker.chunk(code, 'test.ts');
272
- expect(chunks.some(c => c.functionName === 'withString')).toBe(true);
273
- expect(chunks.some(c => c.functionName === 'nextFn')).toBe(true);
272
+ expect(chunks.some((c) => c.functionName === 'withString')).toBe(true);
273
+ expect(chunks.some((c) => c.functionName === 'nextFn')).toBe(true);
274
274
  // The bug: braces in strings should be ignored for boundary detection
275
275
  });
276
276
 
@@ -290,8 +290,8 @@ function nextFn() {
290
290
  }`;
291
291
 
292
292
  const chunks = chunker.chunk(code, 'test.ts');
293
- expect(chunks.some(c => c.functionName === 'withComments')).toBe(true);
294
- expect(chunks.some(c => c.functionName === 'nextFn')).toBe(true);
293
+ expect(chunks.some((c) => c.functionName === 'withComments')).toBe(true);
294
+ expect(chunks.some((c) => c.functionName === 'nextFn')).toBe(true);
295
295
  // The bug: braces in comments should be ignored for boundary detection
296
296
  });
297
297
 
@@ -305,7 +305,7 @@ function myFn() {
305
305
  }`;
306
306
 
307
307
  const chunks = chunker.chunk(code, 'test.ts');
308
- expect(chunks.some(c => c.functionName === 'myFn')).toBe(true);
308
+ expect(chunks.some((c) => c.functionName === 'myFn')).toBe(true);
309
309
  expect(chunks[0]!.content).toContain('Documentation');
310
310
  });
311
311
  });
@@ -326,25 +326,25 @@ function myFn() {
326
326
  it('uses code chunking for .ts files', () => {
327
327
  const code = 'function test() {}\nfunction test2() {}';
328
328
  const chunks = chunker.chunk(code, 'file.ts');
329
- expect(chunks.some(c => c.functionName === 'test')).toBe(true);
329
+ expect(chunks.some((c) => c.functionName === 'test')).toBe(true);
330
330
  });
331
331
 
332
332
  it('uses code chunking for .tsx files', () => {
333
333
  const code = 'function Component() {}\nfunction Other() {}';
334
334
  const chunks = chunker.chunk(code, 'component.tsx');
335
- expect(chunks.some(c => c.functionName === 'Component')).toBe(true);
335
+ expect(chunks.some((c) => c.functionName === 'Component')).toBe(true);
336
336
  });
337
337
 
338
338
  it('uses code chunking for .js files', () => {
339
339
  const code = 'function test() {}\nfunction test2() {}';
340
340
  const chunks = chunker.chunk(code, 'file.js');
341
- expect(chunks.some(c => c.functionName === 'test')).toBe(true);
341
+ expect(chunks.some((c) => c.functionName === 'test')).toBe(true);
342
342
  });
343
343
 
344
344
  it('uses code chunking for .jsx files', () => {
345
345
  const code = 'function Component() {}\nfunction Other() {}';
346
346
  const chunks = chunker.chunk(code, 'component.jsx');
347
- expect(chunks.some(c => c.functionName === 'Component')).toBe(true);
347
+ expect(chunks.some((c) => c.functionName === 'Component')).toBe(true);
348
348
  });
349
349
 
350
350
  it('uses sliding window for unknown file types', () => {
@@ -154,7 +154,8 @@ export class ChunkingService {
154
154
  */
155
155
  private chunkCode(text: string): Chunk[] {
156
156
  // Match top-level declarations with optional JSDoc/comments before them
157
- const declarationRegex = /^(?:\/\*\*[\s\S]*?\*\/\s*)?(?:export\s+)?(?:async\s+)?(?:function|class|interface|type|const|let|var|enum)\s+(\w+)/gm;
157
+ const declarationRegex =
158
+ /^(?:\/\*\*[\s\S]*?\*\/\s*)?(?:export\s+)?(?:async\s+)?(?:function|class|interface|type|const|let|var|enum)\s+(\w+)/gm;
158
159
  const declarations: Array<{ startOffset: number; endOffset: number; name?: string }> = [];
159
160
 
160
161
  let match: RegExpExecArray | null;
@@ -184,7 +185,11 @@ export class ChunkingService {
184
185
  // For declarations that likely have braces (functions, classes, enums)
185
186
  // use smart boundary detection
186
187
  const declText = text.slice(currentDecl.startOffset);
187
- if (/^(?:\/\*\*[\s\S]*?\*\/\s*)?(?:export\s+)?(?:async\s+)?(?:function|class|enum)\s+/m.test(declText)) {
188
+ if (
189
+ /^(?:\/\*\*[\s\S]*?\*\/\s*)?(?:export\s+)?(?:async\s+)?(?:function|class|enum)\s+/m.test(
190
+ declText
191
+ )
192
+ ) {
188
193
  const boundary = this.findDeclarationEnd(declText);
189
194
  if (boundary > 0) {
190
195
  currentDecl.endOffset = currentDecl.startOffset + boundary;
@@ -337,13 +342,15 @@ export class ChunkingService {
337
342
  */
338
343
  private chunkSlidingWindow(text: string): Chunk[] {
339
344
  if (text.length <= this.chunkSize) {
340
- return [{
341
- content: text,
342
- chunkIndex: 0,
343
- totalChunks: 1,
344
- startOffset: 0,
345
- endOffset: text.length,
346
- }];
345
+ return [
346
+ {
347
+ content: text,
348
+ chunkIndex: 0,
349
+ totalChunks: 1,
350
+ startOffset: 0,
351
+ endOffset: text.length,
352
+ },
353
+ ];
347
354
  }
348
355
 
349
356
  const chunks: Chunk[] = [];