@orquentra/codebuddy 2.6.0 → 2.6.2

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 (79) hide show
  1. package/CLAUDE_CODEX.md +6 -4
  2. package/WORKFLOW.md +5 -5
  3. package/dist/{chunk-UN57FKQX.js → chunk-2XDPKFUW.js} +111 -847
  4. package/dist/chunk-2XDPKFUW.js.map +1 -0
  5. package/dist/{chunk-QDBDYCM2.js → chunk-5FW3PMNP.js} +2 -2
  6. package/dist/{chunk-776EQXDV.js → chunk-5KZY6OTG.js} +82 -5
  7. package/dist/chunk-5KZY6OTG.js.map +1 -0
  8. package/dist/{chunk-UFZD3JAA.js → chunk-5MQOE4J6.js} +3 -3
  9. package/dist/chunk-5UH3BEQR.js +32 -0
  10. package/dist/chunk-5UH3BEQR.js.map +1 -0
  11. package/dist/{chunk-N34XHWBA.js → chunk-B6CO63SQ.js} +8 -7
  12. package/dist/chunk-B6CO63SQ.js.map +1 -0
  13. package/dist/chunk-CSRD5OQA.js +79 -0
  14. package/dist/chunk-CSRD5OQA.js.map +1 -0
  15. package/dist/{chunk-PYLH4MH5.js → chunk-FJOTP632.js} +1 -1
  16. package/dist/{chunk-U4HAJLIB.js → chunk-IBLJOHJL.js} +15 -2
  17. package/dist/chunk-IBLJOHJL.js.map +1 -0
  18. package/dist/chunk-IMFUYEZA.js +1607 -0
  19. package/dist/chunk-IMFUYEZA.js.map +1 -0
  20. package/dist/{chunk-SYWJG5NA.js → chunk-J2EAZ4MA.js} +20 -7
  21. package/dist/chunk-J2EAZ4MA.js.map +1 -0
  22. package/dist/{chunk-L5AYZC3F.js → chunk-NERKZSSE.js} +7 -7
  23. package/dist/{chunk-PCE4STAY.js → chunk-OWWCDRXW.js} +5 -5
  24. package/dist/{chunk-WHZSVY2L.js → chunk-QBDJXGG5.js} +2 -2
  25. package/dist/{chunk-VAKBJV26.js → chunk-R7CD6EXS.js} +307 -1822
  26. package/dist/chunk-R7CD6EXS.js.map +1 -0
  27. package/dist/{chunk-6MKEIDX5.js → chunk-RAJJSCIP.js} +2 -2
  28. package/dist/chunk-S6VEG4S2.js +991 -0
  29. package/dist/chunk-S6VEG4S2.js.map +1 -0
  30. package/dist/cli/index.js +14 -3
  31. package/dist/cli/index.js.map +1 -1
  32. package/dist/{codebuddy-DM-i0Fu5.d.ts → codebuddy-B_pCaQrV.d.ts} +22 -2
  33. package/dist/{config-KFEHLV6W.js → config-DEVHUDIU.js} +3 -3
  34. package/dist/docker-autostart-KDME7TVC.js +12 -0
  35. package/dist/index.d.ts +4 -2
  36. package/dist/index.js +19 -15
  37. package/dist/langgraph/index.d.ts +1 -1
  38. package/dist/lean-command-HTQCPH76.js +15 -0
  39. package/dist/{local-OTOY56B4.js → local-5MZURLCZ.js} +6 -2
  40. package/dist/{main-HFHLGID4.js → main-MTBQZGJV.js} +139 -171
  41. package/dist/main-MTBQZGJV.js.map +1 -0
  42. package/dist/{memory-4RGVLPKG.js → memory-KIC5FJVW.js} +4 -4
  43. package/dist/{operations-LOBAQRLO.js → operations-POCHY3WR.js} +5 -4
  44. package/dist/postgres-docker-QQZQ2ABK.js +16 -0
  45. package/dist/{pretool-command-MQQ2UNQM.js → pretool-command-AX6JXP25.js} +3 -3
  46. package/dist/{rerank-3P3C2UHN.js → rerank-5QZ3PNUW.js} +4 -4
  47. package/dist/runtime-CUBOOPZO.js +43 -0
  48. package/dist/runtime-CUBOOPZO.js.map +1 -0
  49. package/dist/stdio-HOV4P3DQ.js +12 -0
  50. package/dist/stdio-HOV4P3DQ.js.map +1 -0
  51. package/dist/{summaries-ZBV5IN7Y.js → summaries-SB5L2TSW.js} +6 -6
  52. package/dist/summaries-SB5L2TSW.js.map +1 -0
  53. package/dist/{zvec-MAPSJQSR.js → zvec-MSRKT7IV.js} +3 -3
  54. package/dist/zvec-MSRKT7IV.js.map +1 -0
  55. package/package.json +7 -10
  56. package/dist/chunk-776EQXDV.js.map +0 -1
  57. package/dist/chunk-N34XHWBA.js.map +0 -1
  58. package/dist/chunk-SYWJG5NA.js.map +0 -1
  59. package/dist/chunk-U4HAJLIB.js.map +0 -1
  60. package/dist/chunk-UN57FKQX.js.map +0 -1
  61. package/dist/chunk-VAKBJV26.js.map +0 -1
  62. package/dist/lean-command-C5YPFKHP.js +0 -15
  63. package/dist/main-HFHLGID4.js.map +0 -1
  64. /package/dist/{chunk-QDBDYCM2.js.map → chunk-5FW3PMNP.js.map} +0 -0
  65. /package/dist/{chunk-UFZD3JAA.js.map → chunk-5MQOE4J6.js.map} +0 -0
  66. /package/dist/{chunk-PYLH4MH5.js.map → chunk-FJOTP632.js.map} +0 -0
  67. /package/dist/{chunk-L5AYZC3F.js.map → chunk-NERKZSSE.js.map} +0 -0
  68. /package/dist/{chunk-PCE4STAY.js.map → chunk-OWWCDRXW.js.map} +0 -0
  69. /package/dist/{chunk-WHZSVY2L.js.map → chunk-QBDJXGG5.js.map} +0 -0
  70. /package/dist/{chunk-6MKEIDX5.js.map → chunk-RAJJSCIP.js.map} +0 -0
  71. /package/dist/{config-KFEHLV6W.js.map → config-DEVHUDIU.js.map} +0 -0
  72. /package/dist/{lean-command-C5YPFKHP.js.map → docker-autostart-KDME7TVC.js.map} +0 -0
  73. /package/dist/{local-OTOY56B4.js.map → lean-command-HTQCPH76.js.map} +0 -0
  74. /package/dist/{operations-LOBAQRLO.js.map → local-5MZURLCZ.js.map} +0 -0
  75. /package/dist/{memory-4RGVLPKG.js.map → memory-KIC5FJVW.js.map} +0 -0
  76. /package/dist/{pretool-command-MQQ2UNQM.js.map → operations-POCHY3WR.js.map} +0 -0
  77. /package/dist/{summaries-ZBV5IN7Y.js.map → postgres-docker-QQZQ2ABK.js.map} +0 -0
  78. /package/dist/{zvec-MAPSJQSR.js.map → pretool-command-AX6JXP25.js.map} +0 -0
  79. /package/dist/{rerank-3P3C2UHN.js.map → rerank-5QZ3PNUW.js.map} +0 -0
@@ -1,3 +1,19 @@
1
+ import {
2
+ MemoryFileStore,
3
+ auditLog,
4
+ candidateLimit,
5
+ embeddings,
6
+ facts,
7
+ interactions,
8
+ isEligibleMemory,
9
+ lexicalTerms,
10
+ modelCalls,
11
+ namespaces,
12
+ schema_exports,
13
+ sessionSummaries,
14
+ shares,
15
+ validSearchVector
16
+ } from "./chunk-S6VEG4S2.js";
1
17
  import {
2
18
  REDACTED,
3
19
  redactPersisted
@@ -15,7 +31,7 @@ import {
15
31
  } from "./chunk-JFDRBPYF.js";
16
32
  import {
17
33
  LocalModelProvider
18
- } from "./chunk-U4HAJLIB.js";
34
+ } from "./chunk-IBLJOHJL.js";
19
35
  import {
20
36
  DEFAULT_CLOUD_EMBEDDING_MODELS,
21
37
  DEFAULT_EMBEDDING_MODELS,
@@ -26,325 +42,21 @@ import {
26
42
  } from "./chunk-JPHJBCZB.js";
27
43
  import {
28
44
  MISSING_DATABASE_URL,
29
- assertNoSymlinkBetween,
30
45
  checkConfigPermissions,
31
46
  checkProjectScaffold,
32
- composeMarkdown,
33
47
  defaultNamespaceForCwd,
34
48
  loadRuntimeConfig,
35
- parseFrontMatter,
49
+ migrateLegacyNamespace,
36
50
  readConfigFile,
37
- redactSecrets,
38
- writeAtomic
39
- } from "./chunk-776EQXDV.js";
40
- import {
41
- __export
42
- } from "./chunk-PZ5AY32C.js";
43
-
44
- // src/db/schema.ts
45
- var schema_exports = {};
46
- __export(schema_exports, {
47
- HNSW_EF_CONSTRUCTION: () => HNSW_EF_CONSTRUCTION,
48
- HNSW_M: () => HNSW_M,
49
- VECTOR_DIMENSIONS: () => VECTOR_DIMENSIONS,
50
- auditActionEnum: () => auditActionEnum,
51
- auditLog: () => auditLog,
52
- checkpoints: () => checkpoints,
53
- embeddingOwnerTypeEnum: () => embeddingOwnerTypeEnum,
54
- embeddingStatusEnum: () => embeddingStatusEnum,
55
- embeddings: () => embeddings,
56
- facts: () => facts,
57
- interactionRoleEnum: () => interactionRoleEnum,
58
- interactions: () => interactions,
59
- memoryTypeEnum: () => memoryTypeEnum,
60
- modelCallStatusEnum: () => modelCallStatusEnum,
61
- modelCallTypeEnum: () => modelCallTypeEnum,
62
- modelCalls: () => modelCalls,
63
- namespaces: () => namespaces,
64
- sessionSummaries: () => sessionSummaries,
65
- shareModeEnum: () => shareModeEnum,
66
- shares: () => shares
67
- });
68
- import { sql } from "drizzle-orm";
69
- import {
70
- boolean,
71
- customType,
72
- index,
73
- integer,
74
- jsonb,
75
- numeric,
76
- pgEnum,
77
- pgTable,
78
- text,
79
- timestamp,
80
- uniqueIndex
81
- } from "drizzle-orm/pg-core";
82
- var VECTOR_DIMENSIONS = 384;
83
- var HNSW_M = 16;
84
- var HNSW_EF_CONSTRUCTION = 64;
85
- var vector = customType({
86
- dataType() {
87
- return `vector(${VECTOR_DIMENSIONS})`;
88
- }
89
- });
90
- var memoryTypeEnum = pgEnum("memory_type", ["interaction", "fact", "summary"]);
91
- var interactionRoleEnum = pgEnum("interaction_role", ["user", "assistant", "system"]);
92
- var embeddingOwnerTypeEnum = pgEnum("embedding_owner_type", [
93
- "interaction",
94
- "fact",
95
- "summary"
96
- ]);
97
- var embeddingStatusEnum = pgEnum("embedding_status", [
98
- "pending",
99
- "processing",
100
- "ready",
101
- "failed"
102
- ]);
103
- var shareModeEnum = pgEnum("share_mode", ["reference", "snapshot"]);
104
- var modelCallTypeEnum = pgEnum("model_call_type", ["embedding", "llm"]);
105
- var modelCallStatusEnum = pgEnum("model_call_status", [
106
- "success",
107
- "failed",
108
- "timeout",
109
- "rate_limited",
110
- "gated",
111
- "fallback"
112
- ]);
113
- var auditActionEnum = pgEnum("audit_action", [
114
- "remember",
115
- "remember_batch",
116
- "share",
117
- "forget",
118
- "config"
119
- ]);
120
- var createdAt = timestamp("created_at", { withTimezone: true }).notNull().defaultNow();
121
- var updatedAt = timestamp("updated_at", { withTimezone: true }).notNull().defaultNow();
122
- var namespaces = pgTable(
123
- "namespaces",
124
- {
125
- id: text("id").primaryKey(),
126
- name: text("name").notNull(),
127
- createdAt,
128
- updatedAt
129
- },
130
- (table) => ({
131
- nameUnique: uniqueIndex("namespaces_name_unique").on(table.name)
132
- })
133
- );
134
- var interactions = pgTable(
135
- "interactions",
136
- {
137
- id: text("id").primaryKey(),
138
- namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
139
- sessionId: text("session_id").notNull(),
140
- role: interactionRoleEnum("role").notNull().default("user"),
141
- content: text("content").notNull(),
142
- contentHash: text("content_hash").notNull(),
143
- tokenCount: integer("token_count").notNull().default(0),
144
- createdByAgent: text("created_by_agent"),
145
- createdAt
146
- },
147
- (table) => ({
148
- namespaceContentHashUnique: uniqueIndex("interactions_namespace_content_hash_unique").on(
149
- table.namespaceId,
150
- table.contentHash
151
- ),
152
- namespaceSessionCreatedIdx: index("interactions_namespace_session_created_idx").on(
153
- table.namespaceId,
154
- table.sessionId,
155
- table.createdAt
156
- )
157
- })
158
- );
159
- var sessionSummaries = pgTable(
160
- "session_summaries",
161
- {
162
- id: text("id").primaryKey(),
163
- namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
164
- sessionId: text("session_id").notNull(),
165
- content: text("content").notNull(),
166
- version: integer("version").notNull().default(1),
167
- tokenCount: integer("token_count").notNull().default(0),
168
- createdByAgent: text("created_by_agent"),
169
- /** See facts.fileBacked. */
170
- fileBacked: boolean("file_backed").notNull().default(false),
171
- createdAt
172
- },
173
- (table) => ({
174
- namespaceSessionVersionIdx: index("session_summaries_namespace_session_version_idx").on(
175
- table.namespaceId,
176
- table.sessionId,
177
- table.version
178
- )
179
- })
180
- );
181
- var facts = pgTable(
182
- "facts",
183
- {
184
- id: text("id").primaryKey(),
185
- namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
186
- subject: text("subject").notNull(),
187
- predicate: text("predicate").notNull(),
188
- object: text("object").notNull(),
189
- propositionKey: text("proposition_key"),
190
- content: text("content").notNull(),
191
- contentHash: text("content_hash").notNull(),
192
- confidence: numeric("confidence", { precision: 5, scale: 4 }).notNull().default("1"),
193
- /**
194
- * Historical provenance only — deliberately not a foreign key. Interactions
195
- * are ephemeral DB rows; Markdown facts must re-import after a rebuild that
196
- * lost them, and the ID must survive so `sourceDeleted` can be tracked.
197
- */
198
- sourceInteractionId: text("source_interaction_id"),
199
- sourceDeleted: boolean("source_deleted").notNull().default(false),
200
- supersededBy: text("superseded_by"),
201
- /**
202
- * True once a reindex imported this row from its Markdown file. Only such
203
- * rows are deleted when the file disappears; DB-only legacy rows are kept.
204
- */
205
- fileBacked: boolean("file_backed").notNull().default(false),
206
- embeddingModel: text("embedding_model"),
207
- createdByAgent: text("created_by_agent"),
208
- createdAt,
209
- updatedAt
210
- },
211
- (table) => ({
212
- namespaceContentHashUnique: uniqueIndex("facts_namespace_content_hash_unique").on(
213
- table.namespaceId,
214
- table.contentHash
215
- ),
216
- namespaceSubjectIdx: index("facts_namespace_subject_idx").on(table.namespaceId, table.subject),
217
- sourceInteractionIdx: index("facts_source_interaction_idx").on(table.sourceInteractionId)
218
- })
219
- );
220
- var embeddings = pgTable(
221
- "embeddings",
222
- {
223
- id: text("id").primaryKey(),
224
- namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
225
- ownerType: embeddingOwnerTypeEnum("owner_type").notNull(),
226
- ownerId: text("owner_id").notNull(),
227
- vector: vector("vector").notNull(),
228
- embeddingModel: text("embedding_model").notNull(),
229
- embeddingSpace: text("embedding_space"),
230
- status: embeddingStatusEnum("status").notNull().default("pending"),
231
- attempts: integer("attempts").notNull().default(0),
232
- lastError: text("last_error"),
233
- /** Lease deadline while status='processing'; null otherwise. */
234
- leaseUntil: timestamp("lease_until", { withTimezone: true }),
235
- leaseToken: text("lease_token"),
236
- createdAt,
237
- updatedAt
238
- },
239
- (table) => ({
240
- ownerUnique: uniqueIndex("embeddings_owner_unique").on(table.ownerType, table.ownerId),
241
- namespaceModelStatusIdx: index("embeddings_namespace_model_status_idx").on(
242
- table.namespaceId,
243
- table.embeddingModel,
244
- table.status
245
- ),
246
- namespaceSpaceStatusIdx: index("embeddings_namespace_space_status_idx").on(
247
- table.namespaceId,
248
- table.embeddingSpace,
249
- table.status
250
- ),
251
- vectorHnswIdx: index("embeddings_vector_hnsw_idx").using(
252
- "hnsw",
253
- sql`${table.vector} vector_cosine_ops`
254
- )
255
- })
256
- );
257
- var shares = pgTable(
258
- "shares",
259
- {
260
- id: text("id").primaryKey(),
261
- fromNamespaceId: text("from_namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
262
- toNamespaceId: text("to_namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
263
- sourceFactId: text("source_fact_id").notNull().references(() => facts.id, { onDelete: "cascade" }),
264
- snapshotFactId: text("snapshot_fact_id").references(() => facts.id, { onDelete: "set null" }),
265
- mode: shareModeEnum("mode").notNull().default("reference"),
266
- tombstoned: boolean("tombstoned").notNull().default(false),
267
- createdByAgent: text("created_by_agent"),
268
- createdAt
269
- },
270
- (table) => ({
271
- shareUnique: uniqueIndex("shares_target_source_unique").on(
272
- table.toNamespaceId,
273
- table.sourceFactId,
274
- table.mode
275
- ),
276
- fromNamespaceIdx: index("shares_from_namespace_idx").on(table.fromNamespaceId)
277
- })
278
- );
279
- var checkpoints = pgTable(
280
- "checkpoints",
281
- {
282
- id: text("id").primaryKey(),
283
- namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
284
- threadId: text("thread_id").notNull(),
285
- checkpointId: text("checkpoint_id").notNull(),
286
- parentId: text("parent_id"),
287
- channelValues: jsonb("channel_values").notNull().default(sql`'{}'::jsonb`),
288
- metadata: jsonb("metadata").notNull().default(sql`'{}'::jsonb`),
289
- createdAt
290
- },
291
- (table) => ({
292
- checkpointUnique: uniqueIndex("checkpoints_thread_checkpoint_unique").on(
293
- table.namespaceId,
294
- table.threadId,
295
- table.checkpointId
296
- )
297
- })
298
- );
299
- var modelCalls = pgTable(
300
- "model_calls",
301
- {
302
- id: text("id").primaryKey(),
303
- namespaceId: text("namespace_id").references(() => namespaces.id, { onDelete: "set null" }),
304
- model: text("model").notNull(),
305
- type: modelCallTypeEnum("type").notNull(),
306
- latencyMs: integer("latency_ms"),
307
- tokens: integer("tokens"),
308
- status: modelCallStatusEnum("status").notNull(),
309
- error: text("error"),
310
- metadata: jsonb("metadata").notNull().default(sql`'{}'::jsonb`),
311
- createdAt
312
- },
313
- (table) => ({
314
- modelCreatedIdx: index("model_calls_model_created_idx").on(table.model, table.createdAt),
315
- namespaceCreatedIdx: index("model_calls_namespace_created_idx").on(
316
- table.namespaceId,
317
- table.createdAt
318
- )
319
- })
320
- );
321
- var auditLog = pgTable(
322
- "audit_log",
323
- {
324
- id: text("id").primaryKey(),
325
- namespaceId: text("namespace_id").references(() => namespaces.id, { onDelete: "set null" }),
326
- action: auditActionEnum("action").notNull(),
327
- entityType: text("entity_type").notNull(),
328
- entityId: text("entity_id"),
329
- createdByAgent: text("created_by_agent"),
330
- metadata: jsonb("metadata").notNull().default(sql`'{}'::jsonb`),
331
- createdAt
332
- },
333
- (table) => ({
334
- namespaceActionCreatedIdx: index("audit_log_namespace_action_created_idx").on(
335
- table.namespaceId,
336
- table.action,
337
- table.createdAt
338
- )
339
- })
340
- );
51
+ redactSecrets
52
+ } from "./chunk-5KZY6OTG.js";
341
53
 
342
54
  // src/db/bootstrap.ts
343
- async function enablePgvector(sql3) {
344
- await sql3`create extension if not exists vector`;
55
+ async function enablePgvector(sql2) {
56
+ await sql2`create extension if not exists vector`;
345
57
  }
346
- async function checkPgvector(sql3) {
347
- const result = await sql3`
58
+ async function checkPgvector(sql2) {
59
+ const result = await sql2`
348
60
  select extversion from pg_extension where extname = 'vector'
349
61
  `;
350
62
  return {
@@ -352,16 +64,30 @@ async function checkPgvector(sql3) {
352
64
  installedVersion: result[0]?.extversion ?? null
353
65
  };
354
66
  }
355
- async function bootstrapDatabase(sql3) {
356
- await enablePgvector(sql3);
357
- return checkPgvector(sql3);
67
+ async function bootstrapDatabase(sql2) {
68
+ await withSchemaLock(sql2, () => enablePgvector(sql2));
69
+ return checkPgvector(sql2);
70
+ }
71
+ var SCHEMA_LOCK = 7310250421;
72
+ async function withSchemaLock(sql2, work) {
73
+ const reserved = await sql2.reserve();
74
+ try {
75
+ await reserved`select pg_advisory_lock(${SCHEMA_LOCK}::bigint)`;
76
+ try {
77
+ return await work();
78
+ } finally {
79
+ await reserved`select pg_advisory_unlock(${SCHEMA_LOCK}::bigint)`;
80
+ }
81
+ } finally {
82
+ reserved.release();
83
+ }
358
84
  }
359
85
 
360
86
  // src/db/client.ts
361
87
  import { drizzle } from "drizzle-orm/postgres-js";
362
88
  import postgres from "postgres";
363
89
  function createDatabaseClient(config) {
364
- const sql3 = postgres(config.postgresUrl, {
90
+ const sql2 = postgres(config.postgresUrl, {
365
91
  max: config.maxConnections ?? 10,
366
92
  ...config.connectTimeoutSeconds !== void 0 ? { connect_timeout: config.connectTimeoutSeconds } : {},
367
93
  // postgres.js logs NOTICE messages (e.g. "extension already exists,
@@ -375,10 +101,10 @@ function createDatabaseClient(config) {
375
101
  }
376
102
  });
377
103
  return {
378
- sql: sql3,
379
- db: drizzle(sql3, { schema: schema_exports }),
104
+ sql: sql2,
105
+ db: drizzle(sql2, { schema: schema_exports }),
380
106
  async close() {
381
- await sql3.end();
107
+ await sql2.end({ timeout: 2 });
382
108
  }
383
109
  };
384
110
  }
@@ -416,165 +142,13 @@ If this is an npm-installed package, make sure src/db/migrations was included in
416
142
  }
417
143
  async function runMigrations(client) {
418
144
  const migrationsFolder = resolveMigrationsFolder();
419
- await migrate(client.db, { migrationsFolder });
145
+ await withSchemaLock(client.sql, () => migrate(client.db, { migrationsFolder }));
420
146
  }
421
147
 
422
148
  // src/db/repository.ts
423
149
  import { AsyncLocalStorage } from "async_hooks";
424
150
  import { createHash } from "crypto";
425
- import { and, desc, eq, inArray, isNull, lt, ne, or, sql as sql2 } from "drizzle-orm";
426
-
427
- // src/core/memory-search.ts
428
- function candidateLimit(limit) {
429
- if (!Number.isFinite(limit)) return 256;
430
- return Math.max(1, Math.min(1024, Math.trunc(limit)));
431
- }
432
- function validSearchVector(vector2) {
433
- return vector2.length === VECTOR_DIMENSIONS && vector2.every((value) => Number.isFinite(Math.fround(value))) && vector2.some((value) => value !== 0);
434
- }
435
- var QUERY_STOPWORDS = /* @__PURE__ */ new Set([
436
- "a",
437
- "about",
438
- "after",
439
- "again",
440
- "all",
441
- "also",
442
- "always",
443
- "an",
444
- "and",
445
- "any",
446
- "are",
447
- "as",
448
- "at",
449
- "back",
450
- "be",
451
- "been",
452
- "before",
453
- "being",
454
- "but",
455
- "by",
456
- "can",
457
- "could",
458
- "did",
459
- "do",
460
- "does",
461
- "done",
462
- "each",
463
- "even",
464
- "ever",
465
- "for",
466
- "from",
467
- "get",
468
- "gets",
469
- "got",
470
- "had",
471
- "has",
472
- "have",
473
- "here",
474
- "how",
475
- "i",
476
- "if",
477
- "in",
478
- "into",
479
- "is",
480
- "it",
481
- "its",
482
- "just",
483
- "like",
484
- "make",
485
- "me",
486
- "more",
487
- "most",
488
- "my",
489
- "never",
490
- "no",
491
- "not",
492
- "now",
493
- "of",
494
- "on",
495
- "only",
496
- "or",
497
- "other",
498
- "our",
499
- "out",
500
- "over",
501
- "please",
502
- "really",
503
- "same",
504
- "should",
505
- "so",
506
- "some",
507
- "sometimes",
508
- "still",
509
- "such",
510
- "than",
511
- "that",
512
- "the",
513
- "their",
514
- "them",
515
- "then",
516
- "there",
517
- "these",
518
- "they",
519
- "this",
520
- "those",
521
- "through",
522
- "to",
523
- "too",
524
- "under",
525
- "up",
526
- "us",
527
- "very",
528
- "was",
529
- "we",
530
- "were",
531
- "what",
532
- "when",
533
- "where",
534
- "which",
535
- "while",
536
- "who",
537
- "why",
538
- "will",
539
- "with",
540
- "would",
541
- "yet",
542
- "you",
543
- "your"
544
- ]);
545
- function lexicalTerms(query) {
546
- return [
547
- ...new Set(
548
- query.slice(0, 4096).toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? []
549
- )
550
- ].filter((term) => !QUERY_STOPWORDS.has(term)).slice(0, 32).map((term) => term.slice(0, 64));
551
- }
552
- var CLAIM_BOILERPLATE = /* @__PURE__ */ new Set([
553
- "decided",
554
- "decide",
555
- "decision",
556
- "made",
557
- "use",
558
- "uses",
559
- "used",
560
- "using",
561
- "now",
562
- "going",
563
- "will"
564
- ]);
565
- function termOverlap(a, b) {
566
- const terms = (text2) => new Set(
567
- (text2.toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? []).filter(
568
- (term) => !QUERY_STOPWORDS.has(term) && !CLAIM_BOILERPLATE.has(term)
569
- )
570
- );
571
- const left = terms(a);
572
- const right = terms(b);
573
- if (left.size === 0 || right.size === 0) return 0;
574
- let shared = 0;
575
- for (const term of left) if (right.has(term)) shared += 1;
576
- return shared / (left.size + right.size - shared);
577
- }
151
+ import { and, desc, eq, inArray, isNull, lt, ne, or, sql } from "drizzle-orm";
578
152
 
579
153
  // src/providers/embedding-space.ts
580
154
  function embeddingSpace(response) {
@@ -592,12 +166,12 @@ function embeddingSpace(response) {
592
166
  function embeddingSpaceKey(space) {
593
167
  return JSON.stringify([space.model, space.revision, space.schema, space.dimensions]);
594
168
  }
595
- function validEmbeddingVector(vector2, dimensions) {
596
- return dimensions > 0 && vector2.length === dimensions && vector2.every(Number.isFinite);
169
+ function validEmbeddingVector(vector, dimensions) {
170
+ return dimensions > 0 && vector.length === dimensions && vector.every(Number.isFinite);
597
171
  }
598
172
  function validateEmbeddingResponse(response, count) {
599
173
  embeddingSpace(response);
600
- if (response.vectors.length !== count || response.vectors.some((vector2) => !validEmbeddingVector(vector2, response.dimensions))) {
174
+ if (response.vectors.length !== count || response.vectors.some((vector) => !validEmbeddingVector(vector, response.dimensions))) {
601
175
  throw new Error("Provider returned invalid embedding dimensions, values, or batch size.");
602
176
  }
603
177
  }
@@ -628,7 +202,7 @@ var PostgresMemoryRepository = class {
628
202
  async withSessionLock(namespaceId, sessionId, fn) {
629
203
  const [k1, k2] = advisoryLockKeys(namespaceId, sessionId);
630
204
  return this.client.db.transaction(async (tx) => {
631
- await tx.execute(sql2`select pg_advisory_xact_lock(${k1}, ${k2})`);
205
+ await tx.execute(sql`select pg_advisory_xact_lock(${k1}, ${k2})`);
632
206
  return this.sessionTransaction.run(tx, fn);
633
207
  });
634
208
  }
@@ -809,7 +383,7 @@ var PostgresMemoryRepository = class {
809
383
  const contentChanged = existing.content !== fact.content;
810
384
  const metadataChanged = existing.subject !== values.subject || existing.predicate !== values.predicate || existing.object !== values.object || Number(existing.confidence) !== Number(fact.confidence.toFixed(4)) || existing.sourceInteractionId !== values.sourceInteractionId || existing.sourceDeleted !== values.sourceDeleted || existing.supersededBy !== values.supersededBy || existing.propositionKey !== values.propositionKey || existing.createdByAgent !== values.createdByAgent || existing.createdAt.getTime() !== values.createdAt.getTime();
811
385
  if (contentChanged || metadataChanged || !existing.fileBacked) {
812
- await tx.update(facts).set({ ...values, updatedAt: sql2`now()` }).where(and(eq(facts.namespaceId, fact.namespaceId), eq(facts.id, fact.id)));
386
+ await tx.update(facts).set({ ...values, updatedAt: sql`now()` }).where(and(eq(facts.namespaceId, fact.namespaceId), eq(facts.id, fact.id)));
813
387
  }
814
388
  await upsertPendingEmbedding(tx, input.embedding, contentChanged);
815
389
  if (!contentChanged && !metadataChanged) return { status: "unchanged" };
@@ -878,12 +452,13 @@ var PostgresMemoryRepository = class {
878
452
  * item twice. Expired leases are re-claimable, so a crashed worker's work is
879
453
  * picked up again instead of being stuck forever.
880
454
  */
881
- async claimPendingEmbeddings(limit) {
455
+ async claimPendingEmbeddings(limit, namespaceId) {
882
456
  const rows = await this.client.sql`
883
457
  with claimed as (
884
458
  select id from embeddings
885
- where status = 'pending'
886
- or (status = 'processing' and (lease_until is null or lease_until < now()))
459
+ where (status = 'pending'
460
+ or (status = 'processing' and (lease_until is null or lease_until < now())))
461
+ and (${namespaceId ?? null}::text is null or namespace_id = ${namespaceId ?? null})
887
462
  order by created_at asc
888
463
  for update skip locked
889
464
  limit ${limit}
@@ -922,33 +497,33 @@ var PostgresMemoryRepository = class {
922
497
  }));
923
498
  }
924
499
  async renewEmbeddingLease(id, leaseToken) {
925
- const rows = await this.db.update(embeddings).set({ leaseUntil: sql2`now() + interval '120 seconds'` }).where(
500
+ const rows = await this.db.update(embeddings).set({ leaseUntil: sql`now() + interval '120 seconds'` }).where(
926
501
  and(
927
502
  eq(embeddings.id, id),
928
503
  eq(embeddings.leaseToken, leaseToken),
929
504
  eq(embeddings.status, "processing"),
930
- sql2`${embeddings.leaseUntil} > now()`
505
+ sql`${embeddings.leaseUntil} > now()`
931
506
  )
932
507
  ).returning({ id: embeddings.id });
933
508
  return rows.length > 0;
934
509
  }
935
- async markEmbeddingReady(id, leaseToken, vector2, model, space) {
936
- const literal = `[${vector2.join(",")}]`;
510
+ async markEmbeddingReady(id, leaseToken, vector, model, space) {
511
+ const literal = `[${vector.join(",")}]`;
937
512
  const rows = await this.db.update(embeddings).set({
938
513
  status: "ready",
939
514
  vector: literal,
940
515
  embeddingModel: model,
941
- embeddingSpace: space ?? embeddingSpaceKey(embeddingSpace({ model, dimensions: vector2.length })),
516
+ embeddingSpace: space ?? embeddingSpaceKey(embeddingSpace({ model, dimensions: vector.length })),
942
517
  lastError: null,
943
518
  leaseUntil: null,
944
519
  leaseToken: null,
945
- updatedAt: sql2`now()`
520
+ updatedAt: sql`now()`
946
521
  }).where(
947
522
  and(
948
523
  eq(embeddings.id, id),
949
524
  eq(embeddings.leaseToken, leaseToken),
950
525
  eq(embeddings.status, "processing"),
951
- sql2`${embeddings.leaseUntil} > now()`
526
+ sql`${embeddings.leaseUntil} > now()`
952
527
  )
953
528
  ).returning({ id: embeddings.id });
954
529
  return rows.length > 0;
@@ -964,18 +539,18 @@ var PostgresMemoryRepository = class {
964
539
  const maxAttempts = options?.maxAttempts ?? 5;
965
540
  const backoffSeconds = Math.min(60, 2 ** Math.max(0, attempts - 1));
966
541
  const rows = await this.db.update(embeddings).set({
967
- status: sql2`case when ${attempts} >= ${maxAttempts} then 'failed'::embedding_status else 'processing'::embedding_status end`,
968
- leaseUntil: sql2`case when ${attempts} >= ${maxAttempts} then null else now() + (${backoffSeconds} || ' seconds')::interval end`,
542
+ status: sql`case when ${attempts} >= ${maxAttempts} then 'failed'::embedding_status else 'processing'::embedding_status end`,
543
+ leaseUntil: sql`case when ${attempts} >= ${maxAttempts} then null else now() + (${backoffSeconds} || ' seconds')::interval end`,
969
544
  leaseToken: null,
970
545
  attempts,
971
546
  lastError: error,
972
- updatedAt: sql2`now()`
547
+ updatedAt: sql`now()`
973
548
  }).where(
974
549
  and(
975
550
  eq(embeddings.id, id),
976
551
  eq(embeddings.leaseToken, leaseToken),
977
552
  eq(embeddings.status, "processing"),
978
- sql2`${embeddings.leaseUntil} > now()`
553
+ sql`${embeddings.leaseUntil} > now()`
979
554
  )
980
555
  ).returning({ id: embeddings.id });
981
556
  return rows.length > 0;
@@ -1192,12 +767,12 @@ var PostgresMemoryRepository = class {
1192
767
  lastError: null,
1193
768
  leaseUntil: null,
1194
769
  leaseToken: null,
1195
- updatedAt: sql2`now()`
770
+ updatedAt: sql`now()`
1196
771
  }).where(
1197
772
  and(
1198
773
  eq(embeddings.namespaceId, namespaceId),
1199
774
  inArray(embeddings.status, ["ready", "failed"]),
1200
- sql2`${embeddings.embeddingSpace} is distinct from ${space}`
775
+ sql`${embeddings.embeddingSpace} is distinct from ${space}`
1201
776
  )
1202
777
  ).returning({ id: embeddings.id });
1203
778
  return rows.length;
@@ -1205,7 +780,7 @@ var PostgresMemoryRepository = class {
1205
780
  async searchSimilarEmbeddings(input) {
1206
781
  if (!validSearchVector(input.vector))
1207
782
  return { method: "exact_pgvector", candidates: [], compatibleReady: 0 };
1208
- const rows = await this.db.execute(sql2`
783
+ const rows = await this.db.execute(sql`
1209
784
  with compatible as materialized (
1210
785
  select id, owner_type, owner_id, embedding_model, embedding_space, vector
1211
786
  from embeddings
@@ -1214,7 +789,7 @@ var PostgresMemoryRepository = class {
1214
789
  namespace_id = ${input.namespaceId}
1215
790
  or (
1216
791
  owner_type = 'fact'
1217
- and ${liveReference(input.namespaceId, sql2`embeddings.namespace_id`, sql2`embeddings.owner_id`)}
792
+ and ${liveReference(input.namespaceId, sql`embeddings.namespace_id`, sql`embeddings.owner_id`)}
1218
793
  )
1219
794
  )
1220
795
  and embedding_space = ${input.embeddingSpace}
@@ -1250,7 +825,7 @@ var PostgresMemoryRepository = class {
1250
825
  async searchFactsLexically(namespaceId, query, limit) {
1251
826
  const terms = lexicalTerms(query);
1252
827
  if (!terms.length) return { candidates: [], matchedFacts: 0 };
1253
- const rows = await this.db.execute(sql2`
828
+ const rows = await this.db.execute(sql`
1254
829
  with scored as materialized (
1255
830
  select id, content, subject, predicate, object, proposition_key, confidence,
1256
831
  created_by_agent, created_at,
@@ -1264,7 +839,7 @@ var PostgresMemoryRepository = class {
1264
839
  where not source_deleted and superseded_by is null
1265
840
  and (
1266
841
  namespace_id = ${namespaceId}
1267
- or ${liveReference(namespaceId, sql2`facts.namespace_id`, sql2`facts.id`)}
842
+ or ${liveReference(namespaceId, sql`facts.namespace_id`, sql`facts.id`)}
1268
843
  )
1269
844
  )
1270
845
  select *, count(*) over () as total from scored where score > 0
@@ -1343,7 +918,7 @@ var PostgresMemoryRepository = class {
1343
918
  isNull(facts.supersededBy),
1344
919
  or(
1345
920
  eq(facts.namespaceId, namespaceId),
1346
- liveReference(namespaceId, sql2`${facts.namespaceId}`, sql2`${facts.id}`)
921
+ liveReference(namespaceId, sql`${facts.namespaceId}`, sql`${facts.id}`)
1347
922
  )
1348
923
  )
1349
924
  );
@@ -1602,11 +1177,11 @@ var PostgresMemoryRepository = class {
1602
1177
  limit 1
1603
1178
  `;
1604
1179
  const vectorCount = Number(countRows[0]?.count ?? 0);
1605
- const index2 = indexRows[0];
1180
+ const index = indexRows[0];
1606
1181
  return {
1607
1182
  vectorCount,
1608
- indexName: index2?.indexname ?? null,
1609
- indexDefinition: index2?.indexdef ?? null,
1183
+ indexName: index?.indexname ?? null,
1184
+ indexDefinition: index?.indexdef ?? null,
1610
1185
  needsTuning: vectorCount >= 1e5
1611
1186
  };
1612
1187
  }
@@ -1650,7 +1225,7 @@ async function upsertPendingEmbedding(tx, embedding, reset) {
1650
1225
  lastError: null,
1651
1226
  leaseUntil: null,
1652
1227
  leaseToken: null,
1653
- updatedAt: sql2`now()`
1228
+ updatedAt: sql`now()`
1654
1229
  }
1655
1230
  });
1656
1231
  }
@@ -1682,7 +1257,7 @@ var recentFactColumns = {
1682
1257
  createdAt: facts.createdAt
1683
1258
  };
1684
1259
  function liveReference(namespaceId, ownerNamespace, factId) {
1685
- return sql2`exists (
1260
+ return sql`exists (
1686
1261
  select 1 from shares s
1687
1262
  where s.to_namespace_id = ${namespaceId}
1688
1263
  and s.from_namespace_id = ${ownerNamespace}
@@ -1695,14 +1270,6 @@ function liveReference(namespaceId, ownerNamespace, factId) {
1695
1270
  // src/core/codebuddy.ts
1696
1271
  import pTimeout2 from "p-timeout";
1697
1272
 
1698
- // src/core/memory-lifecycle.ts
1699
- function isEligibleMemory(fact, options = {}) {
1700
- if (options.namespace && fact.namespace !== options.namespace) return false;
1701
- if (fact.sourceDeleted || fact.supersededBy) return false;
1702
- if (fact.category === "incident" && fact.resolvedBy && !options.includeResolved) return false;
1703
- return true;
1704
- }
1705
-
1706
1273
  // src/planner/default-policy.ts
1707
1274
  var DefaultPolicy = class {
1708
1275
  recencyFloorSize;
@@ -2108,8 +1675,8 @@ var HuggingFaceResilience = class {
2108
1675
  async execute(input) {
2109
1676
  const models = [input.model, ...input.fallbackModels ?? []];
2110
1677
  let lastError;
2111
- for (const [index2, model] of models.entries()) {
2112
- const fallbackTriggered = index2 > 0;
1678
+ for (const [index, model] of models.entries()) {
1679
+ const fallbackTriggered = index > 0;
2113
1680
  try {
2114
1681
  return await this.executeForModel(model, input, fallbackTriggered);
2115
1682
  } catch (error) {
@@ -2176,8 +1743,7 @@ var HuggingFaceResilience = class {
2176
1743
  retries = error.attemptNumber;
2177
1744
  }
2178
1745
  }
2179
- ),
2180
- { throwOnTimeout: true }
1746
+ )
2181
1747
  );
2182
1748
  this.markWarm(model);
2183
1749
  status = fallbackTriggered ? "fallback" : "success";
@@ -2310,7 +1876,7 @@ function readRetryAfterMs(error) {
2310
1876
  return Number.isFinite(retryAfterSeconds) ? retryAfterSeconds * 1e3 : void 0;
2311
1877
  }
2312
1878
  function sleep(ms) {
2313
- return new Promise((resolve3) => setTimeout(resolve3, ms));
1879
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
2314
1880
  }
2315
1881
 
2316
1882
  // src/providers/huggingface.ts
@@ -2415,7 +1981,7 @@ function normalizeEmbeddingResponse(response) {
2415
1981
  return [response];
2416
1982
  }
2417
1983
  if (response.every(
2418
- (vector2) => Array.isArray(vector2) && vector2.every((value) => typeof value === "number")
1984
+ (vector) => Array.isArray(vector) && vector.every((value) => typeof value === "number")
2419
1985
  )) {
2420
1986
  return response;
2421
1987
  }
@@ -2505,308 +2071,6 @@ function validateConfig(config) {
2505
2071
  return codeBuddyConfigSchema.parse(config);
2506
2072
  }
2507
2073
 
2508
- // src/core/memory-file-store.ts
2509
- import { mkdir, readdir, readFile, rm } from "fs/promises";
2510
- import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "path";
2511
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
2512
- import { z as z2 } from "zod";
2513
- var FACT_CATEGORIES = ["general", "incident"];
2514
- var INCIDENT_SEVERITIES = ["low", "medium", "high", "critical"];
2515
- var factFrontMatterSchema = z2.object({
2516
- schemaVersion: z2.literal(1),
2517
- id: z2.string().regex(/^fact_[a-z0-9]+$/),
2518
- namespace: z2.string().min(1),
2519
- type: z2.literal("fact"),
2520
- subject: z2.string(),
2521
- predicate: z2.string(),
2522
- object: z2.string(),
2523
- /** Explicit single-valued claim identity; facts sharing it are rival assertions. */
2524
- propositionKey: z2.string().min(1).nullable().default(null),
2525
- confidence: z2.number().min(0).max(1),
2526
- createdAt: z2.preprocess(
2527
- (value) => value instanceof Date ? value.toISOString() : value,
2528
- z2.string().datetime()
2529
- ),
2530
- createdByAgent: z2.string().nullable(),
2531
- sourceInteractionId: z2.string().nullable(),
2532
- sourceDeleted: z2.boolean(),
2533
- category: z2.enum(FACT_CATEGORIES).default("general"),
2534
- paths: z2.array(z2.string().min(1)).default([]),
2535
- severity: z2.enum(INCIDENT_SEVERITIES).nullable().default(null),
2536
- introducedBy: z2.string().nullable().default(null),
2537
- resolvedBy: z2.string().nullable().default(null),
2538
- fingerprint: z2.string().regex(/^[a-f0-9]{64}$/).nullable().default(null),
2539
- sourcePlanId: z2.string().nullable().default(null),
2540
- sourceSessionId: z2.string().nullable().default(null),
2541
- verification: z2.array(z2.string()).default([]),
2542
- supersededBy: z2.string().nullable().default(null),
2543
- /** Namespaces granted a live reference to this fact (durable form of reference shares). */
2544
- sharedWith: z2.array(z2.string().min(1)).default([])
2545
- });
2546
- var summaryFrontMatterSchema = z2.object({
2547
- schemaVersion: z2.literal(1),
2548
- id: z2.string().regex(/^sum_[a-z0-9]+$/),
2549
- namespace: z2.string().min(1),
2550
- type: z2.literal("summary"),
2551
- sessionId: z2.string().min(1),
2552
- version: z2.number().int().positive(),
2553
- tokenCount: z2.number().int().nonnegative(),
2554
- createdAt: z2.preprocess(
2555
- (value) => value instanceof Date ? value.toISOString() : value,
2556
- z2.string().datetime()
2557
- ),
2558
- createdByAgent: z2.string().nullable()
2559
- });
2560
- var MemoryFileStore = class {
2561
- repositoryRoot;
2562
- factsDirectory;
2563
- summariesDirectory;
2564
- constructor(repositoryRoot = process.cwd()) {
2565
- this.repositoryRoot = resolve2(repositoryRoot);
2566
- this.factsDirectory = join(this.repositoryRoot, ".codebuddy", "memory", "facts");
2567
- this.summariesDirectory = join(this.repositoryRoot, ".codebuddy", "memory", "summaries");
2568
- }
2569
- async writeFact(raw) {
2570
- const input = redactPersisted(raw);
2571
- const path = this.factPath(input.id);
2572
- await this.prepareDirectory(this.factsDirectory);
2573
- await assertNoSymlinkBetween(this.repositoryRoot, dirname2(path));
2574
- const metadata = {
2575
- schemaVersion: 1,
2576
- id: input.id,
2577
- namespace: input.namespace,
2578
- type: "fact",
2579
- subject: input.subject,
2580
- predicate: input.predicate,
2581
- object: input.object,
2582
- propositionKey: input.propositionKey,
2583
- confidence: input.confidence,
2584
- createdAt: input.createdAt,
2585
- createdByAgent: input.createdByAgent,
2586
- sourceInteractionId: input.sourceInteractionId,
2587
- sourceDeleted: input.sourceDeleted,
2588
- category: input.category,
2589
- paths: input.paths,
2590
- severity: input.severity,
2591
- introducedBy: input.introducedBy,
2592
- resolvedBy: input.resolvedBy,
2593
- fingerprint: input.fingerprint,
2594
- sourcePlanId: input.sourcePlanId,
2595
- sourceSessionId: input.sourceSessionId,
2596
- verification: input.verification,
2597
- supersededBy: input.supersededBy,
2598
- sharedWith: input.sharedWith
2599
- };
2600
- const frontMatter = stringifyYaml(stripUndefinedAndDefaultIncidentFields(metadata));
2601
- await writeAtomic(path, composeMarkdown(frontMatter, input.content));
2602
- return path;
2603
- }
2604
- async writeSummary(input) {
2605
- const path = this.summaryPath(input.id);
2606
- await this.prepareDirectory(this.summariesDirectory);
2607
- await assertNoSymlinkBetween(this.repositoryRoot, dirname2(path));
2608
- const metadata = stringifyYaml({
2609
- schemaVersion: 1,
2610
- id: input.id,
2611
- namespace: input.namespace,
2612
- type: "summary",
2613
- sessionId: input.sessionId,
2614
- version: input.version,
2615
- tokenCount: input.tokenCount,
2616
- createdAt: input.createdAt,
2617
- createdByAgent: input.createdByAgent
2618
- });
2619
- await writeAtomic(path, composeMarkdown(metadata, input.content));
2620
- return path;
2621
- }
2622
- async readFact(pathOrId) {
2623
- const path = pathOrId.endsWith(".md") ? this.safePath(pathOrId) : this.factPath(pathOrId);
2624
- await assertNoSymlinkBetween(this.repositoryRoot, path);
2625
- const parsed = parseFrontMatter(await readFile(path, "utf8"));
2626
- const metadata = factFrontMatterSchema.parse(parseYaml(parsed.frontMatter));
2627
- return {
2628
- ...metadata,
2629
- content: parsed.content.trim(),
2630
- path
2631
- };
2632
- }
2633
- async listFacts() {
2634
- return (await this.scanFacts()).facts;
2635
- }
2636
- /**
2637
- * Parse every managed fact file. Hand-written markdown is ignored, and a
2638
- * schema-invalid/corrupt fact is reported in `invalid` (not thrown) so one
2639
- * bad file can't break recall, capture or reindexing for the whole project.
2640
- * Invalid files stay on disk for manual repair.
2641
- */
2642
- async scanFacts() {
2643
- const scan = await this.scan(
2644
- this.factsDirectory,
2645
- /^fact_[a-z0-9]+\.md$/,
2646
- (path) => this.readFact(path)
2647
- );
2648
- return { facts: scan.items, invalid: scan.invalid };
2649
- }
2650
- /**
2651
- * List incident facts for the namespace, ranked by severity then recency.
2652
- * Unlike {@link findIncidentFactsForPaths} this does not filter by path, so
2653
- * callers (e.g. the context engine's project bootstrap) can surface the
2654
- * repository's incident hotspots before any specific edit target is known.
2655
- */
2656
- async listIncidentFacts(input = {}) {
2657
- const incidents = (await this.listFacts()).filter(
2658
- (fact) => fact.category === "incident" && Boolean(fact.severity) && isEligibleMemory(fact, input)
2659
- );
2660
- return incidents.sort((left, right) => {
2661
- const severity = severityRank(right.severity) - severityRank(left.severity);
2662
- if (severity !== 0) return severity;
2663
- return right.createdAt.localeCompare(left.createdAt);
2664
- });
2665
- }
2666
- async findIncidentFactsForPaths(input) {
2667
- const wanted = new Set(input.paths.map(normalizeMemoryPath));
2668
- if (wanted.size === 0) return [];
2669
- return (await this.listIncidentFacts({
2670
- ...input.namespace !== void 0 ? { namespace: input.namespace } : {},
2671
- ...input.includeResolved !== void 0 ? { includeResolved: input.includeResolved } : {}
2672
- })).filter((fact) => fact.paths.map(normalizeMemoryPath).some((path) => wanted.has(path)));
2673
- }
2674
- async readSummary(pathOrId) {
2675
- const path = pathOrId.endsWith(".md") ? this.safePath(pathOrId) : this.summaryPath(pathOrId);
2676
- await assertNoSymlinkBetween(this.repositoryRoot, path);
2677
- const parsed = parseFrontMatter(await readFile(path, "utf8"));
2678
- return {
2679
- ...summaryFrontMatterSchema.parse(parseYaml(parsed.frontMatter)),
2680
- content: parsed.content.trim(),
2681
- path
2682
- };
2683
- }
2684
- async listSummaries() {
2685
- return (await this.scanSummaries()).summaries;
2686
- }
2687
- async scanSummaries() {
2688
- const scan = await this.scan(
2689
- this.summariesDirectory,
2690
- /^sum_[a-z0-9]+\.md$/,
2691
- (path) => this.readSummary(path)
2692
- );
2693
- return { summaries: scan.items, invalid: scan.invalid };
2694
- }
2695
- async scan(directory, managedName, read) {
2696
- try {
2697
- await this.prepareDirectory(directory);
2698
- const entries = await readdir(directory, { withFileTypes: true });
2699
- const result = { items: [], invalid: [] };
2700
- for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
2701
- if (!entry.isFile() || !managedName.test(entry.name)) continue;
2702
- const path = join(directory, entry.name);
2703
- try {
2704
- const item = await read(path);
2705
- const id = entry.name.slice(0, -".md".length);
2706
- if (item.id !== id)
2707
- throw new Error(`file ID ${id} differs from front matter ID ${item.id}`);
2708
- result.items.push(item);
2709
- } catch (error) {
2710
- result.invalid.push({
2711
- id: entry.name.slice(0, -".md".length),
2712
- path,
2713
- error: error.message.split("\n")[0]?.slice(0, 300) ?? "unreadable"
2714
- });
2715
- }
2716
- }
2717
- return result;
2718
- } catch (error) {
2719
- if (error.code === "ENOENT") return { items: [], invalid: [] };
2720
- throw error;
2721
- }
2722
- }
2723
- async deleteFact(id) {
2724
- await rm(this.factPath(id), { force: true });
2725
- }
2726
- async markIncidentResolved(id, resolvedBy) {
2727
- const fact = await this.readFact(id);
2728
- await this.writeFact(copyFact(fact, { resolvedBy }));
2729
- }
2730
- async markFactSuperseded(id, supersededBy) {
2731
- const fact = await this.readFact(id);
2732
- await this.writeFact(copyFact(fact, { supersededBy }));
2733
- }
2734
- async setFactSharedWith(id, sharedWith) {
2735
- const fact = await this.readFact(id);
2736
- await this.writeFact(copyFact(fact, { sharedWith: [...new Set(sharedWith)].sort() }));
2737
- }
2738
- /** Persist interaction deletion in Markdown before the derived DB is updated. */
2739
- async markSourceInteractionDeleted(namespace, sourceInteractionId) {
2740
- const { facts: facts2 } = await this.scanFacts();
2741
- for (const fact of facts2) {
2742
- if (fact.namespace !== namespace || fact.sourceInteractionId !== sourceInteractionId)
2743
- continue;
2744
- if (fact.sourceDeleted) continue;
2745
- await this.writeFact(copyFact(fact, { sourceDeleted: true }));
2746
- }
2747
- }
2748
- /** Persist that a fact's source interaction was forgotten, keeping its provenance id. */
2749
- async markFactSourceDeleted(id) {
2750
- const fact = await this.readFact(id);
2751
- await this.writeFact(copyFact(fact, { sourceDeleted: true }));
2752
- }
2753
- factPath(id) {
2754
- if (!/^fact_[a-z0-9]+$/.test(id)) {
2755
- throw new Error(`Invalid fact id: ${id}`);
2756
- }
2757
- return this.safePath(join(this.factsDirectory, `${id}.md`));
2758
- }
2759
- summaryPath(id) {
2760
- if (!/^sum_[a-z0-9]+$/.test(id)) throw new Error(`Invalid summary id: ${id}`);
2761
- return this.safePath(join(this.summariesDirectory, `${id}.md`));
2762
- }
2763
- safePath(path) {
2764
- const absolute = resolve2(path);
2765
- const relativePath = relative(this.repositoryRoot, absolute);
2766
- if (relativePath === ".." || relativePath.startsWith(`..${sep}`) || relativePath === "") {
2767
- throw new Error(`Memory path escapes repository root: ${path}`);
2768
- }
2769
- return absolute;
2770
- }
2771
- async prepareDirectory(directory) {
2772
- await assertNoSymlinkBetween(this.repositoryRoot, dirname2(directory));
2773
- await mkdir(directory, { recursive: true, mode: 448 });
2774
- }
2775
- };
2776
- function copyFact(fact, patch) {
2777
- const { path: _path, schemaVersion: _schemaVersion, type: _type, ...write } = fact;
2778
- return { ...write, ...patch };
2779
- }
2780
- function stripUndefinedAndDefaultIncidentFields(metadata) {
2781
- return Object.fromEntries(
2782
- Object.entries(metadata).filter(([key, value]) => {
2783
- if (value === void 0) return false;
2784
- if (key === "category" && value === "general") return false;
2785
- if ((key === "paths" || key === "sharedWith") && Array.isArray(value) && value.length === 0)
2786
- return false;
2787
- if (["severity", "introducedBy", "resolvedBy", "propositionKey"].includes(key) && (value === null || value === void 0)) {
2788
- return false;
2789
- }
2790
- return true;
2791
- })
2792
- );
2793
- }
2794
- function normalizeMemoryPath(path) {
2795
- return path.replace(/\\/g, "/").replace(/^\.\//, "");
2796
- }
2797
- function severityRank(severity) {
2798
- switch (severity) {
2799
- case "critical":
2800
- return 4;
2801
- case "high":
2802
- return 3;
2803
- case "medium":
2804
- return 2;
2805
- case "low":
2806
- return 1;
2807
- }
2808
- }
2809
-
2810
2074
  // src/core/worker.ts
2811
2075
  var DEFAULT_POLL_MS = 250;
2812
2076
  var DEFAULT_BATCH_SIZE = 8;
@@ -2819,6 +2083,7 @@ var EmbeddingWorker = class {
2819
2083
  batchSize;
2820
2084
  maxAttempts;
2821
2085
  onDiagnostic;
2086
+ namespaceId;
2822
2087
  state = "idle";
2823
2088
  loopPromise = null;
2824
2089
  wake = null;
@@ -2831,6 +2096,7 @@ var EmbeddingWorker = class {
2831
2096
  this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
2832
2097
  this.maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
2833
2098
  this.onDiagnostic = options.onDiagnostic;
2099
+ this.namespaceId = options.namespaceId;
2834
2100
  }
2835
2101
  getState() {
2836
2102
  return this.state;
@@ -2860,8 +2126,8 @@ var EmbeddingWorker = class {
2860
2126
  * wait out anymore.
2861
2127
  */
2862
2128
  async drain() {
2863
- await new Promise((resolve3) => {
2864
- this.idleResolvers.push(resolve3);
2129
+ await new Promise((resolve2) => {
2130
+ this.idleResolvers.push(resolve2);
2865
2131
  this.notify();
2866
2132
  });
2867
2133
  }
@@ -2887,13 +2153,13 @@ var EmbeddingWorker = class {
2887
2153
  while (this.state === "running") {
2888
2154
  let jobs;
2889
2155
  try {
2890
- jobs = await this.repo.claimPendingEmbeddings(this.batchSize);
2156
+ jobs = await this.repo.claimPendingEmbeddings(this.batchSize, this.namespaceId?.());
2891
2157
  } catch (error) {
2892
2158
  console.error(
2893
2159
  `[worker] claimPendingEmbeddings failed: ${error instanceof Error ? error.message : String(error)}; retrying`
2894
2160
  );
2895
2161
  if (this.state !== "running") break;
2896
- await new Promise((resolve3) => setTimeout(resolve3, ERROR_BACKOFF_MS));
2162
+ await new Promise((resolve2) => setTimeout(resolve2, ERROR_BACKOFF_MS));
2897
2163
  continue;
2898
2164
  }
2899
2165
  if (jobs.length === 0) {
@@ -2920,7 +2186,7 @@ var EmbeddingWorker = class {
2920
2186
  if (this.inFlight > 0) return;
2921
2187
  const resolvers = this.idleResolvers;
2922
2188
  this.idleResolvers = [];
2923
- for (const resolve3 of resolvers) resolve3();
2189
+ for (const resolve2 of resolvers) resolve2();
2924
2190
  }
2925
2191
  async processJob(job) {
2926
2192
  let leaseLost = false;
@@ -2940,14 +2206,14 @@ var EmbeddingWorker = class {
2940
2206
  model: job.embeddingModel
2941
2207
  });
2942
2208
  validateEmbeddingResponse(response, 1);
2943
- const vector2 = response.vectors[0];
2944
- if (!vector2 || vector2.length === 0) {
2209
+ const vector = response.vectors[0];
2210
+ if (!vector || vector.length === 0) {
2945
2211
  throw new Error("Provider returned no embedding vector.");
2946
2212
  }
2947
2213
  if (leaseLost || !await this.repo.markEmbeddingReady(
2948
2214
  job.id,
2949
2215
  job.leaseToken,
2950
- vector2,
2216
+ vector,
2951
2217
  response.model,
2952
2218
  embeddingSpaceKey(embeddingSpace(response))
2953
2219
  ))
@@ -3005,14 +2271,14 @@ var EmbeddingWorker = class {
3005
2271
  });
3006
2272
  }
3007
2273
  sleep(ms) {
3008
- return new Promise((resolve3) => {
2274
+ return new Promise((resolve2) => {
3009
2275
  const timer = setTimeout(() => {
3010
2276
  this.wake = null;
3011
- resolve3();
2277
+ resolve2();
3012
2278
  }, ms ?? this.pollIntervalMs);
3013
2279
  this.wake = () => {
3014
2280
  clearTimeout(timer);
3015
- resolve3();
2281
+ resolve2();
3016
2282
  };
3017
2283
  });
3018
2284
  }
@@ -3043,6 +2309,7 @@ var CodeBuddy = class {
3043
2309
  this.worker = deps.worker ?? new EmbeddingWorker({
3044
2310
  repository: this.repo,
3045
2311
  provider: this.provider,
2312
+ namespaceId: () => this.namespaceId ?? void 0,
3046
2313
  ...this.config.worker?.pollIntervalMs !== void 0 ? { pollIntervalMs: this.config.worker.pollIntervalMs } : {},
3047
2314
  ...this.config.worker?.batchSize !== void 0 ? { batchSize: this.config.worker.batchSize } : {},
3048
2315
  ...this.config.worker?.maxAttempts !== void 0 ? { maxAttempts: this.config.worker.maxAttempts } : {}
@@ -3186,8 +2453,8 @@ var CodeBuddy = class {
3186
2453
  })
3187
2454
  );
3188
2455
  validateEmbeddingResponse(response, 1);
3189
- const vector2 = response.vectors[0];
3190
- return vector2 ? { vector: vector2, space: embeddingSpace(response) } : null;
2456
+ const vector = response.vectors[0];
2457
+ return vector ? { vector, space: embeddingSpace(response) } : null;
3191
2458
  } catch {
3192
2459
  return null;
3193
2460
  }
@@ -3369,9 +2636,10 @@ var CodeBuddy = class {
3369
2636
  };
3370
2637
  const factResult = await this.repo.withSessionLock(namespaceId, REINDEX_LOCK_KEY, async () => {
3371
2638
  const result = await this.repo.forgetFact(namespaceId, id, factAudit);
3372
- if (result.found) {
3373
- const file = await this.memoryFileStore?.readFact(id).catch(() => null);
3374
- if (file?.namespace === this.config.namespace) await this.memoryFileStore?.deleteFact(id);
2639
+ const file = await this.memoryFileStore?.readFact(id).catch(() => null);
2640
+ if (file?.namespace === this.config.namespace) {
2641
+ await this.memoryFileStore?.deleteFact(id);
2642
+ return { ...result, found: true };
3375
2643
  }
3376
2644
  return result;
3377
2645
  });
@@ -3387,7 +2655,7 @@ var CodeBuddy = class {
3387
2655
  * file is applied independently: malformed or conflicting files are reported
3388
2656
  * in `failures` and never abort healthy imports (nor count as deletions).
3389
2657
  */
3390
- async reindexMemory() {
2658
+ async reindexMemory(options = {}) {
3391
2659
  const namespaceId = this.requireNamespaceId();
3392
2660
  const store = this.memoryFileStore;
3393
2661
  if (!store) {
@@ -3467,7 +2735,7 @@ var CodeBuddy = class {
3467
2735
  failures: failures.slice(0, MAX_REPORTED_FAILURES)
3468
2736
  };
3469
2737
  });
3470
- const space = this.provider.space;
2738
+ const space = options.respace === false ? void 0 : this.provider.space;
3471
2739
  const canEmbed = space !== void 0 && await this.provider.embed({ input: "codebuddy" }).then(
3472
2740
  () => true,
3473
2741
  () => false
@@ -3813,8 +3081,8 @@ function decodeFactCursor(cursor) {
3813
3081
  if (!Array.isArray(parsed) || parsed.length !== 2 || typeof parsed[0] !== "string" || typeof parsed[1] !== "string" || Number.isNaN(Date.parse(parsed[0]))) {
3814
3082
  throw new Error("Invalid cursor: expected a base64url-encoded [createdAt, id] pair.");
3815
3083
  }
3816
- const [createdAt2, id] = parsed;
3817
- return { createdAt: new Date(createdAt2), id };
3084
+ const [createdAt, id] = parsed;
3085
+ return { createdAt: new Date(createdAt), id };
3818
3086
  }
3819
3087
  async function listFactsPage(memory, repository, input) {
3820
3088
  const namespace = await repository.ensureNamespace(memory.config.namespace);
@@ -3850,6 +3118,7 @@ async function inspectNamespace(repository, namespace) {
3850
3118
  };
3851
3119
  }
3852
3120
  async function runDoctor(options = {}) {
3121
+ const migrated = await migrateLegacyNamespace();
3853
3122
  const fileConfig = await readConfigFile();
3854
3123
  const scaffold = await checkProjectScaffold();
3855
3124
  const configPermissions = await checkConfigPermissions();
@@ -3859,6 +3128,7 @@ async function runDoctor(options = {}) {
3859
3128
  expectedDefault: expectedDefaultNamespace,
3860
3129
  configured: fileConfig.namespace ?? null,
3861
3130
  runtime: runtimeNamespace,
3131
+ ...migrated ? { migrated } : {},
3862
3132
  ok: !fileConfig.namespace || fileConfig.namespace === expectedDefaultNamespace || process.env.CODEBUDDY_NAMESPACE !== void 0,
3863
3133
  ...!fileConfig.namespace || fileConfig.namespace === expectedDefaultNamespace || process.env.CODEBUDDY_NAMESPACE !== void 0 ? {} : {
3864
3134
  warning: `Configured namespace "${fileConfig.namespace}" differs from this folder's default "${expectedDefaultNamespace}". Confirm your MCP entries point at the intended namespace.`
@@ -4003,18 +3273,12 @@ async function checkModels(provider, skip = false) {
4003
3273
  }
4004
3274
 
4005
3275
  export {
4006
- isEligibleMemory,
4007
- lexicalTerms,
4008
- termOverlap,
4009
3276
  embeddingSpaceKey,
4010
3277
  DefaultPolicy,
4011
3278
  HuggingFaceProvider,
4012
3279
  isLangSmithTracingEnabled,
4013
3280
  createTracer,
4014
3281
  codeBuddyConfigSchema,
4015
- FACT_CATEGORIES,
4016
- INCIDENT_SEVERITIES,
4017
- MemoryFileStore,
4018
3282
  EmbeddingWorker,
4019
3283
  CodeBuddy,
4020
3284
  buildProviderFromConfig,
@@ -4030,4 +3294,4 @@ export {
4030
3294
  inspectNamespace,
4031
3295
  runDoctor
4032
3296
  };
4033
- //# sourceMappingURL=chunk-UN57FKQX.js.map
3297
+ //# sourceMappingURL=chunk-2XDPKFUW.js.map