brainbank 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +76 -1398
  2. package/bin/brainbank +5 -1
  3. package/dist/{chunk-N2OJRXSB.js → chunk-3HVCONGF.js} +1 -1
  4. package/dist/{chunk-N2OJRXSB.js.map → chunk-3HVCONGF.js.map} +1 -1
  5. package/dist/{chunk-CCXVL56V.js → chunk-3JZIM5AU.js} +6 -3
  6. package/dist/chunk-3JZIM5AU.js.map +1 -0
  7. package/dist/{chunk-6XOXM7MI.js → chunk-5KU2PP34.js} +2 -2
  8. package/dist/{chunk-6XOXM7MI.js.map → chunk-5KU2PP34.js.map} +1 -1
  9. package/dist/chunk-7JDCHUJV.js +89 -0
  10. package/dist/chunk-7JDCHUJV.js.map +1 -0
  11. package/dist/{chunk-B77KABWH.js → chunk-7T2ZCZQA.js} +17 -15
  12. package/dist/chunk-7T2ZCZQA.js.map +1 -0
  13. package/dist/chunk-E3J37GDA.js +74 -0
  14. package/dist/chunk-E3J37GDA.js.map +1 -0
  15. package/dist/chunk-JEFWMS5Z.js +217 -0
  16. package/dist/chunk-JEFWMS5Z.js.map +1 -0
  17. package/dist/chunk-JRVYSTMP.js +3256 -0
  18. package/dist/chunk-JRVYSTMP.js.map +1 -0
  19. package/dist/chunk-OLDHLOMT.js +69 -0
  20. package/dist/chunk-OLDHLOMT.js.map +1 -0
  21. package/dist/{chunk-424UFCY7.js → chunk-QTZNB6AK.js} +6 -2
  22. package/dist/chunk-QTZNB6AK.js.map +1 -0
  23. package/dist/chunk-RFF7HMP6.js +109 -0
  24. package/dist/chunk-RFF7HMP6.js.map +1 -0
  25. package/dist/{chunk-ZNLN2VWV.js → chunk-TD3TEFI3.js} +1 -1
  26. package/dist/chunk-TD3TEFI3.js.map +1 -0
  27. package/dist/cli.js +1036 -341
  28. package/dist/cli.js.map +1 -1
  29. package/dist/haiku-expander-WOVJIVXD.js +8 -0
  30. package/dist/haiku-pruner-DB77ZQLJ.js +8 -0
  31. package/dist/http-server-GIRELCCL.js +9 -0
  32. package/dist/index.d.ts +1774 -611
  33. package/dist/index.js +282 -70
  34. package/dist/index.js.map +1 -1
  35. package/dist/{local-embedding-ZIMTK6PU.js → local-embedding-2RNCC5EU.js} +2 -2
  36. package/dist/{openai-embedding-VQZCZQYT.js → openai-embedding-Z5I4K4CN.js} +2 -2
  37. package/dist/perplexity-context-embedding-V5YUMXDR.js +9 -0
  38. package/dist/{perplexity-embedding-227WQY4R.js → perplexity-embedding-X2S72OAC.js} +2 -2
  39. package/dist/plugin-FF4Q34TI.js +32 -0
  40. package/dist/{qwen3-reranker-3MHEENT5.js → qwen3-reranker-HVIQOLKS.js} +2 -2
  41. package/dist/{resolve-CUJWY6HP.js → resolve-Q5D6HECY.js} +2 -2
  42. package/package.json +25 -52
  43. package/src/brainbank.ts +620 -0
  44. package/src/cli/commands/collection.ts +77 -0
  45. package/src/cli/commands/context.ts +171 -0
  46. package/src/cli/commands/daemon.ts +100 -0
  47. package/src/cli/commands/docs.ts +71 -0
  48. package/src/cli/commands/files.ts +69 -0
  49. package/src/cli/commands/help.ts +72 -0
  50. package/src/cli/commands/index.ts +282 -0
  51. package/src/cli/commands/kv.ts +140 -0
  52. package/src/cli/commands/mcp.ts +13 -0
  53. package/src/cli/commands/reembed.ts +30 -0
  54. package/src/cli/commands/scan.ts +365 -0
  55. package/src/cli/commands/search.ts +130 -0
  56. package/src/cli/commands/stats.ts +44 -0
  57. package/src/cli/commands/status.ts +47 -0
  58. package/src/cli/commands/watch.ts +43 -0
  59. package/src/cli/factory/brain-context.ts +43 -0
  60. package/src/cli/factory/builtin-registration.ts +123 -0
  61. package/src/cli/factory/config-loader.ts +72 -0
  62. package/src/cli/factory/index.ts +65 -0
  63. package/src/cli/factory/plugin-loader.ts +146 -0
  64. package/src/cli/index.ts +63 -0
  65. package/src/cli/server-client.ts +135 -0
  66. package/src/cli/utils.ts +121 -0
  67. package/src/config.ts +50 -0
  68. package/src/constants.ts +13 -0
  69. package/src/db/adapter.ts +112 -0
  70. package/src/db/metadata.ts +130 -0
  71. package/src/db/migrations.ts +66 -0
  72. package/src/db/sqlite-adapter.ts +208 -0
  73. package/src/db/tracker.ts +91 -0
  74. package/src/engine/index-api.ts +85 -0
  75. package/src/engine/reembed.ts +206 -0
  76. package/src/engine/search-api.ts +222 -0
  77. package/src/index.ts +159 -0
  78. package/src/lib/fts.ts +57 -0
  79. package/src/lib/languages.ts +180 -0
  80. package/src/lib/logger.ts +125 -0
  81. package/src/lib/math.ts +87 -0
  82. package/src/lib/provider-key.ts +20 -0
  83. package/src/lib/prune.ts +71 -0
  84. package/src/lib/rerank.ts +33 -0
  85. package/src/lib/rrf.ts +133 -0
  86. package/src/lib/write-lock.ts +108 -0
  87. package/src/plugin.ts +323 -0
  88. package/src/providers/embeddings/embedding-worker-thread.ts +95 -0
  89. package/src/providers/embeddings/embedding-worker.ts +141 -0
  90. package/src/providers/embeddings/local-embedding.ts +115 -0
  91. package/src/providers/embeddings/openai-embedding.ts +167 -0
  92. package/src/providers/embeddings/perplexity-context-embedding.ts +195 -0
  93. package/src/providers/embeddings/perplexity-embedding.ts +165 -0
  94. package/src/providers/embeddings/resolve.ts +34 -0
  95. package/src/providers/pruners/haiku-expander.ts +152 -0
  96. package/src/providers/pruners/haiku-pruner.ts +112 -0
  97. package/src/providers/rerankers/qwen3-reranker.ts +180 -0
  98. package/src/providers/vector/hnsw-index.ts +174 -0
  99. package/src/providers/vector/hnsw-loader.ts +129 -0
  100. package/src/search/bm25-boost.ts +61 -0
  101. package/src/search/context-builder.ts +298 -0
  102. package/src/search/keyword/composite-bm25-search.ts +62 -0
  103. package/src/search/types.ts +35 -0
  104. package/src/search/vector/composite-vector-search.ts +76 -0
  105. package/src/search/vector/mmr.ts +64 -0
  106. package/src/services/collection.ts +405 -0
  107. package/src/services/daemon.ts +87 -0
  108. package/src/services/http-server.ts +288 -0
  109. package/src/services/kv-service.ts +65 -0
  110. package/src/services/plugin-registry.ts +109 -0
  111. package/src/services/watch.ts +348 -0
  112. package/src/services/webhook-server.ts +100 -0
  113. package/src/types.ts +504 -0
  114. package/dist/base-3SNc_CeY.d.ts +0 -593
  115. package/dist/chunk-424UFCY7.js.map +0 -1
  116. package/dist/chunk-7EZR47JV.js +0 -232
  117. package/dist/chunk-7EZR47JV.js.map +0 -1
  118. package/dist/chunk-B77KABWH.js.map +0 -1
  119. package/dist/chunk-CCXVL56V.js.map +0 -1
  120. package/dist/chunk-DI3H6JVZ.js +0 -2432
  121. package/dist/chunk-DI3H6JVZ.js.map +0 -1
  122. package/dist/chunk-FGL32LUJ.js +0 -754
  123. package/dist/chunk-FGL32LUJ.js.map +0 -1
  124. package/dist/chunk-JRSKWF6K.js +0 -313
  125. package/dist/chunk-JRSKWF6K.js.map +0 -1
  126. package/dist/chunk-U2Q2XGPZ.js +0 -42
  127. package/dist/chunk-U2Q2XGPZ.js.map +0 -1
  128. package/dist/chunk-VQ27YUHH.js +0 -629
  129. package/dist/chunk-VQ27YUHH.js.map +0 -1
  130. package/dist/chunk-VVXYZIIB.js +0 -304
  131. package/dist/chunk-VVXYZIIB.js.map +0 -1
  132. package/dist/chunk-YOLKSYWK.js +0 -79
  133. package/dist/chunk-YOLKSYWK.js.map +0 -1
  134. package/dist/chunk-ZNLN2VWV.js.map +0 -1
  135. package/dist/code.d.ts +0 -33
  136. package/dist/code.js +0 -9
  137. package/dist/docs.d.ts +0 -21
  138. package/dist/docs.js +0 -9
  139. package/dist/git.d.ts +0 -33
  140. package/dist/git.js +0 -9
  141. package/dist/memory.d.ts +0 -17
  142. package/dist/memory.js +0 -9
  143. package/dist/notes.d.ts +0 -17
  144. package/dist/notes.js +0 -10
  145. package/dist/perplexity-context-embedding-KSVSZXMD.js +0 -9
  146. package/dist/resolve-CUJWY6HP.js.map +0 -1
  147. /package/dist/{code.js.map → haiku-expander-WOVJIVXD.js.map} +0 -0
  148. /package/dist/{docs.js.map → haiku-pruner-DB77ZQLJ.js.map} +0 -0
  149. /package/dist/{git.js.map → http-server-GIRELCCL.js.map} +0 -0
  150. /package/dist/{local-embedding-ZIMTK6PU.js.map → local-embedding-2RNCC5EU.js.map} +0 -0
  151. /package/dist/{memory.js.map → openai-embedding-Z5I4K4CN.js.map} +0 -0
  152. /package/dist/{notes.js.map → perplexity-context-embedding-V5YUMXDR.js.map} +0 -0
  153. /package/dist/{openai-embedding-VQZCZQYT.js.map → perplexity-embedding-X2S72OAC.js.map} +0 -0
  154. /package/dist/{perplexity-context-embedding-KSVSZXMD.js.map → plugin-FF4Q34TI.js.map} +0 -0
  155. /package/dist/{perplexity-embedding-227WQY4R.js.map → qwen3-reranker-HVIQOLKS.js.map} +0 -0
  156. /package/dist/{qwen3-reranker-3MHEENT5.js.map → resolve-Q5D6HECY.js.map} +0 -0
@@ -0,0 +1,217 @@
1
+ import {
2
+ DEFAULT_PORT,
3
+ removePid,
4
+ writePid
5
+ } from "./chunk-OLDHLOMT.js";
6
+ import {
7
+ __name
8
+ } from "./chunk-7QVYU63E.js";
9
+
10
+ // src/services/http-server.ts
11
+ import * as http from "http";
12
+ var SimplePool = class _SimplePool {
13
+ static {
14
+ __name(this, "SimplePool");
15
+ }
16
+ _pool = /* @__PURE__ */ new Map();
17
+ _factory;
18
+ _onError;
19
+ _timer;
20
+ static TTL_MS = 30 * 60 * 1e3;
21
+ // 30 minutes
22
+ static EVICT_INTERVAL_MS = 5 * 60 * 1e3;
23
+ // 5 minutes
24
+ constructor(options) {
25
+ this._factory = options.factory;
26
+ this._onError = options.onError;
27
+ this._timer = setInterval(() => this._evictStale(), _SimplePool.EVICT_INTERVAL_MS);
28
+ if (this._timer.unref) this._timer.unref();
29
+ }
30
+ async get(repoPath) {
31
+ const key = repoPath.replace(/\/+$/, "");
32
+ const existing = this._pool.get(key);
33
+ if (existing) {
34
+ existing.lastAccess = Date.now();
35
+ try {
36
+ await existing.brain.ensureFresh();
37
+ } catch {
38
+ }
39
+ return existing.brain;
40
+ }
41
+ const brain = await this._factory(key);
42
+ this._pool.set(key, { brain, lastAccess: Date.now() });
43
+ return brain;
44
+ }
45
+ close() {
46
+ clearInterval(this._timer);
47
+ for (const [key, entry] of this._pool) {
48
+ try {
49
+ entry.brain.close();
50
+ } catch (err) {
51
+ this._onError?.(key, err);
52
+ }
53
+ }
54
+ this._pool.clear();
55
+ }
56
+ get size() {
57
+ return this._pool.size;
58
+ }
59
+ _evictStale() {
60
+ const cutoff = Date.now() - _SimplePool.TTL_MS;
61
+ for (const [key, entry] of this._pool) {
62
+ if (entry.lastAccess < cutoff) {
63
+ try {
64
+ entry.brain.close();
65
+ } catch (err) {
66
+ this._onError?.(key, err);
67
+ }
68
+ this._pool.delete(key);
69
+ }
70
+ }
71
+ }
72
+ };
73
+ var HttpServer = class {
74
+ static {
75
+ __name(this, "HttpServer");
76
+ }
77
+ _server = null;
78
+ _pool;
79
+ _port;
80
+ _defaultRepo;
81
+ _startTime = 0;
82
+ _log;
83
+ constructor(options) {
84
+ this._port = options.port ?? DEFAULT_PORT;
85
+ this._defaultRepo = options.defaultRepo ?? process.cwd();
86
+ this._log = options.onLog ?? console.log;
87
+ this._pool = new SimplePool({
88
+ factory: options.factory,
89
+ onError: options.onError
90
+ });
91
+ }
92
+ /** Start listening. Writes PID file for daemon detection. */
93
+ start() {
94
+ return new Promise((resolve, reject) => {
95
+ this._server = http.createServer((req, res) => {
96
+ this._handleRequest(req, res).catch((err) => {
97
+ const msg = err instanceof Error ? err.message : String(err);
98
+ this._log(`Request error: ${msg}`);
99
+ if (!res.headersSent) {
100
+ res.writeHead(500, { "Content-Type": "application/json" });
101
+ res.end(JSON.stringify({ error: "Internal server error" }));
102
+ }
103
+ });
104
+ });
105
+ this._server.on("error", (err) => {
106
+ if (err.code === "EADDRINUSE") {
107
+ reject(new Error(`Port ${this._port} already in use. Is another server running?`));
108
+ } else {
109
+ reject(err);
110
+ }
111
+ });
112
+ this._server.listen(this._port, "127.0.0.1", () => {
113
+ this._startTime = Date.now();
114
+ writePid(process.pid, this._port);
115
+ this._log(`BrainBank HTTP server listening on http://localhost:${this._port}`);
116
+ resolve();
117
+ });
118
+ });
119
+ }
120
+ /** Stop the server and clean up. */
121
+ close() {
122
+ this._pool.close();
123
+ this._server?.close();
124
+ this._server = null;
125
+ removePid();
126
+ }
127
+ get port() {
128
+ return this._port;
129
+ }
130
+ // ── Request Router ──────────────────────────────────
131
+ async _handleRequest(req, res) {
132
+ res.setHeader("Content-Type", "application/json");
133
+ if (req.method === "GET" && req.url === "/health") {
134
+ return this._handleHealth(res);
135
+ }
136
+ if (req.method !== "POST") {
137
+ res.writeHead(405);
138
+ res.end(JSON.stringify({ error: "Method not allowed" }));
139
+ return;
140
+ }
141
+ const body = await this._readBody(req);
142
+ switch (req.url) {
143
+ case "/context":
144
+ return this._handleContext(body, res);
145
+ case "/index":
146
+ return this._handleIndex(body, res);
147
+ default:
148
+ res.writeHead(404);
149
+ res.end(JSON.stringify({ error: "Not found" }));
150
+ }
151
+ }
152
+ // ── Handlers ────────────────────────────────────────
153
+ _handleHealth(res) {
154
+ const uptime = Math.round((Date.now() - this._startTime) / 1e3);
155
+ res.writeHead(200);
156
+ res.end(JSON.stringify({
157
+ ok: true,
158
+ pid: process.pid,
159
+ port: this._port,
160
+ uptime,
161
+ workspaces: this._pool.size
162
+ }));
163
+ }
164
+ async _handleContext(body, res) {
165
+ const req = body;
166
+ if (!req.task) {
167
+ res.writeHead(400);
168
+ res.end(JSON.stringify({ error: "Missing required field: task" }));
169
+ return;
170
+ }
171
+ const repoPath = req.repo ?? this._defaultRepo;
172
+ const brain = await this._pool.get(repoPath);
173
+ const base = {
174
+ code: req.codeResults ?? 20,
175
+ git: req.gitResults ?? 5
176
+ };
177
+ if (req.docsResults !== void 0) base.docs = req.docsResults;
178
+ const resolvedSources = req.sources ? { ...base, ...req.sources } : base;
179
+ const context = await brain.getContext(req.task, {
180
+ affectedFiles: req.affectedFiles,
181
+ sources: resolvedSources,
182
+ pathPrefix: req.pathPrefix,
183
+ source: "daemon"
184
+ });
185
+ res.writeHead(200);
186
+ res.end(JSON.stringify({ context }));
187
+ }
188
+ async _handleIndex(body, res) {
189
+ const req = body;
190
+ const repoPath = req.repo ?? this._defaultRepo;
191
+ const brain = await this._pool.get(repoPath);
192
+ const result = await brain.index({ forceReindex: req.forceReindex });
193
+ res.writeHead(200);
194
+ res.end(JSON.stringify({ result }));
195
+ }
196
+ // ── Helpers ─────────────────────────────────────────
197
+ _readBody(req) {
198
+ return new Promise((resolve, reject) => {
199
+ const chunks = [];
200
+ req.on("data", (chunk) => chunks.push(chunk));
201
+ req.on("error", reject);
202
+ req.on("end", () => {
203
+ try {
204
+ const raw = Buffer.concat(chunks).toString("utf8");
205
+ resolve(raw ? JSON.parse(raw) : {});
206
+ } catch {
207
+ resolve({});
208
+ }
209
+ });
210
+ });
211
+ }
212
+ };
213
+
214
+ export {
215
+ HttpServer
216
+ };
217
+ //# sourceMappingURL=chunk-JEFWMS5Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/http-server.ts"],"sourcesContent":["/**\n * HttpServer — Lightweight JSON API for BrainBank.\n *\n * Exposes BrainBank operations over HTTP so CLI commands can delegate\n * to a running server instead of cold-loading models each time.\n *\n * Routes:\n * POST /context → brain.getContext()\n * POST /index → brain.index()\n * GET /health → { ok, pid, uptime, port }\n *\n * Multi-repo: a single server handles all repos via WorkspacePool.\n * Each request includes a `repo` field to select the workspace.\n */\n\nimport type { BrainBank } from '@/brainbank.ts';\n\nimport * as http from 'node:http';\n\nimport { DEFAULT_PORT, writePid, removePid } from './daemon.ts';\n\n// ── Types ─────────────────────────────────────────────\n\ninterface ContextRequest {\n task: string;\n repo?: string;\n sources?: Record<string, number>;\n pathPrefix?: string;\n affectedFiles?: string[];\n codeResults?: number;\n gitResults?: number;\n docsResults?: number;\n}\n\ninterface IndexRequest {\n repo?: string;\n forceReindex?: boolean;\n}\n\ninterface PoolOptions {\n /** Factory function to create a BrainBank for a repo path. */\n factory: (repoPath: string) => Promise<BrainBank>;\n /** Called when an error occurs. */\n onError?: (repo: string, err: unknown) => void;\n}\n\n// ── Simple Workspace Pool ─────────────────────────────\n\n/**\n * Minimal in-memory pool for multi-repo support.\n * Creates BrainBank instances on demand and caches them.\n * Eviction by TTL (30 min inactivity).\n */\nclass SimplePool {\n private _pool = new Map<string, { brain: BrainBank; lastAccess: number }>();\n private _factory: (repoPath: string) => Promise<BrainBank>;\n private _onError?: (repo: string, err: unknown) => void;\n private _timer: ReturnType<typeof setInterval>;\n\n private static readonly TTL_MS = 30 * 60 * 1000; // 30 minutes\n private static readonly EVICT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n constructor(options: PoolOptions) {\n this._factory = options.factory;\n this._onError = options.onError;\n this._timer = setInterval(() => this._evictStale(), SimplePool.EVICT_INTERVAL_MS);\n if (this._timer.unref) this._timer.unref();\n }\n\n async get(repoPath: string): Promise<BrainBank> {\n const key = repoPath.replace(/\\/+$/, '');\n const existing = this._pool.get(key);\n if (existing) {\n existing.lastAccess = Date.now();\n try { await existing.brain.ensureFresh(); } catch { /* stale is better than nothing */ }\n return existing.brain;\n }\n\n const brain = await this._factory(key);\n this._pool.set(key, { brain, lastAccess: Date.now() });\n return brain;\n }\n\n close(): void {\n clearInterval(this._timer);\n for (const [key, entry] of this._pool) {\n try { entry.brain.close(); } catch (err: unknown) {\n this._onError?.(key, err);\n }\n }\n this._pool.clear();\n }\n\n get size(): number {\n return this._pool.size;\n }\n\n private _evictStale(): void {\n const cutoff = Date.now() - SimplePool.TTL_MS;\n for (const [key, entry] of this._pool) {\n if (entry.lastAccess < cutoff) {\n try { entry.brain.close(); } catch (err: unknown) {\n this._onError?.(key, err);\n }\n this._pool.delete(key);\n }\n }\n }\n}\n\n// ── HTTP Server ───────────────────────────────────────\n\nexport interface HttpServerOptions {\n port?: number;\n /** Factory to create a BrainBank instance for a given repo path. */\n factory: (repoPath: string) => Promise<BrainBank>;\n /** Default repo path when request doesn't specify one. */\n defaultRepo?: string;\n /** Called when an error occurs during pool operations. */\n onError?: (repo: string, err: unknown) => void;\n /** Called on server lifecycle events. */\n onLog?: (msg: string) => void;\n}\n\nexport class HttpServer {\n private _server: http.Server | null = null;\n private _pool: SimplePool;\n private _port: number;\n private _defaultRepo: string;\n private _startTime = 0;\n private _log: (msg: string) => void;\n\n constructor(options: HttpServerOptions) {\n this._port = options.port ?? DEFAULT_PORT;\n this._defaultRepo = options.defaultRepo ?? process.cwd();\n this._log = options.onLog ?? console.log;\n this._pool = new SimplePool({\n factory: options.factory,\n onError: options.onError,\n });\n }\n\n /** Start listening. Writes PID file for daemon detection. */\n start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this._server = http.createServer((req, res) => {\n this._handleRequest(req, res).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n this._log(`Request error: ${msg}`);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Internal server error' }));\n }\n });\n });\n\n this._server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n reject(new Error(`Port ${this._port} already in use. Is another server running?`));\n } else {\n reject(err);\n }\n });\n\n this._server.listen(this._port, '127.0.0.1', () => {\n this._startTime = Date.now();\n writePid(process.pid, this._port);\n this._log(`BrainBank HTTP server listening on http://localhost:${this._port}`);\n resolve();\n });\n });\n }\n\n /** Stop the server and clean up. */\n close(): void {\n this._pool.close();\n this._server?.close();\n this._server = null;\n removePid();\n }\n\n get port(): number {\n return this._port;\n }\n\n // ── Request Router ──────────────────────────────────\n\n private async _handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n // CORS + content type\n res.setHeader('Content-Type', 'application/json');\n\n // Health check — no body parsing needed\n if (req.method === 'GET' && req.url === '/health') {\n return this._handleHealth(res);\n }\n\n if (req.method !== 'POST') {\n res.writeHead(405);\n res.end(JSON.stringify({ error: 'Method not allowed' }));\n return;\n }\n\n const body = await this._readBody(req);\n\n switch (req.url) {\n case '/context':\n return this._handleContext(body, res);\n case '/index':\n return this._handleIndex(body, res);\n default:\n res.writeHead(404);\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n }\n\n // ── Handlers ────────────────────────────────────────\n\n private _handleHealth(res: http.ServerResponse): void {\n const uptime = Math.round((Date.now() - this._startTime) / 1000);\n res.writeHead(200);\n res.end(JSON.stringify({\n ok: true,\n pid: process.pid,\n port: this._port,\n uptime,\n workspaces: this._pool.size,\n }));\n }\n\n private async _handleContext(body: unknown, res: http.ServerResponse): Promise<void> {\n const req = body as ContextRequest;\n if (!req.task) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: 'Missing required field: task' }));\n return;\n }\n\n const repoPath = req.repo ?? this._defaultRepo;\n const brain = await this._pool.get(repoPath);\n\n // Build sources from explicit params, then let `sources` override\n const base: Record<string, number> = {\n code: req.codeResults ?? 20,\n git: req.gitResults ?? 5,\n };\n if (req.docsResults !== undefined) base.docs = req.docsResults;\n const resolvedSources = req.sources ? { ...base, ...req.sources } : base;\n\n const context = await brain.getContext(req.task, {\n affectedFiles: req.affectedFiles,\n sources: resolvedSources,\n pathPrefix: req.pathPrefix,\n source: 'daemon',\n });\n\n res.writeHead(200);\n res.end(JSON.stringify({ context }));\n }\n\n private async _handleIndex(body: unknown, res: http.ServerResponse): Promise<void> {\n const req = body as IndexRequest;\n const repoPath = req.repo ?? this._defaultRepo;\n const brain = await this._pool.get(repoPath);\n\n const result = await brain.index({ forceReindex: req.forceReindex });\n\n res.writeHead(200);\n res.end(JSON.stringify({ result }));\n }\n\n // ── Helpers ─────────────────────────────────────────\n\n private _readBody(req: http.IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('error', reject);\n req.on('end', () => {\n try {\n const raw = Buffer.concat(chunks).toString('utf8');\n resolve(raw ? JSON.parse(raw) as unknown : {});\n } catch {\n resolve({});\n }\n });\n });\n }\n}\n"],"mappings":"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","names":[]}