@vpxa/aikit 0.1.108 → 0.1.110

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.
@@ -253,15 +253,26 @@ declare class LanceStore implements IKnowledgeStore {
253
253
  //#endregion
254
254
  //#region packages/store/src/sqlite-adapter.d.ts
255
255
  /**
256
- * SQLite adapter abstraction backed by sql.js (WASM).
256
+ * SQLite adapter selects between native better-sqlite3 (preferred) and
257
+ * sql.js (WASM fallback). The fallback exists because better-sqlite3 is a
258
+ * native module whose prebuilt binary is not available in every environment
259
+ * (Codespaces, restricted CI, mismatched Node ABI).
257
260
  *
258
- * The database stays memory-resident while open and is exported back to disk
259
- * on flush/close so callers keep the same single-file persistence model.
261
+ * better-sqlite3 also lets us load the sqlite-vec extension, which sql.js
262
+ * (running inside a WASM sandbox) cannot dlopen. When we fall back, vector
263
+ * search is unavailable and the consumer (SqliteVecStore) downgrades to
264
+ * FTS-only mode loudly.
260
265
  */
261
- type SqliteAdapterType = 'sql.js';
266
+ type SqliteAdapterType = 'better-sqlite3' | 'sql.js';
262
267
  interface ISqliteAdapter {
263
268
  /** Which adapter implementation is active */
264
269
  readonly type: SqliteAdapterType;
270
+ /**
271
+ * True when the underlying engine can execute vector-search queries
272
+ * (better-sqlite3 with the sqlite-vec extension loaded). False on sql.js
273
+ * or when extension loading failed.
274
+ */
275
+ readonly vectorCapable: boolean;
265
276
  /** Open or create the database at the given file path */
266
277
  open(dbPath: string): Promise<void>;
267
278
  /** Execute DDL or multi-statement SQL (CREATE TABLE, BEGIN, COMMIT, etc.) */
@@ -277,16 +288,41 @@ interface ISqliteAdapter {
277
288
  /** Close the database connection */
278
289
  close(): void;
279
290
  }
280
- /** Create the project's SQLite adapter. */
291
+ /**
292
+ * Create the project's SQLite adapter.
293
+ *
294
+ * Prefers better-sqlite3 (native, mmap-backed, supports sqlite-vec). Falls
295
+ * back to sql.js (WASM, vector search disabled) if the native binary cannot
296
+ * be loaded — typically because the platform has no prebuild and the native
297
+ * compile failed during install. In that case the consumer should disable
298
+ * vector-dependent code paths via `adapter.vectorCapable`.
299
+ */
281
300
  declare function createSqliteAdapter(dbPath: string): Promise<ISqliteAdapter>;
301
+ /**
302
+ * Force-create a sql.js adapter (used by tests that need to assert fallback
303
+ * behavior without monkey-patching `require`).
304
+ */
305
+ declare function createSqlJsAdapter(dbPath: string): Promise<ISqliteAdapter>;
282
306
  //#endregion
283
307
  //#region packages/store/src/sqlite-graph-store.d.ts
284
308
  declare class SqliteGraphStore implements IGraphStore {
285
309
  private adapter;
286
310
  private reopenPromise;
287
311
  private readonly dbPath;
312
+ private readonly externalAdapter;
313
+ /**
314
+ * Create a graph store backed by SQLite.
315
+ *
316
+ * Two construction modes:
317
+ * - `{ path }` — creates and owns its own adapter at `<path>/graph.db`.
318
+ * Used standalone (legacy).
319
+ * - `{ adapter }` — uses an externally-managed adapter that is shared with
320
+ * other stores (e.g. `SqliteVecStore`). The caller owns the adapter
321
+ * lifecycle and must have already configured pragmas.
322
+ */
288
323
  constructor(options?: {
289
324
  path?: string;
325
+ adapter?: ISqliteAdapter;
290
326
  });
291
327
  initialize(): Promise<void>;
292
328
  private configureAdapter;
@@ -336,13 +372,83 @@ declare class SqliteGraphStore implements IGraphStore {
336
372
  close(): Promise<void>;
337
373
  }
338
374
  //#endregion
375
+ //#region packages/store/src/sqlite-vec-store.d.ts
376
+ interface SqliteVecStoreOptions {
377
+ /** Path to the .db file (file is created if missing) */
378
+ path?: string;
379
+ /** Embedding dimension — must match the embedder configuration */
380
+ embeddingDim?: number;
381
+ /** Externally-managed adapter (shared with graph store). When omitted, the store creates its own. */
382
+ adapter?: ISqliteAdapter;
383
+ }
384
+ declare class SqliteVecStore implements IKnowledgeStore {
385
+ private adapter;
386
+ private readonly externalAdapter;
387
+ private readonly dbPath;
388
+ private readonly embeddingDim;
389
+ private vectorEnabled;
390
+ private warnedVectorDisabled;
391
+ private _draining;
392
+ private _priorityQueue;
393
+ private _normalQueue;
394
+ constructor(options?: SqliteVecStoreOptions);
395
+ initialize(): Promise<void>;
396
+ /**
397
+ * Diagnostics for the status tool. Returns runtime info about the underlying
398
+ * adapter and DB file (read-only; safe to call after initialize()).
399
+ */
400
+ getDiagnostics(): {
401
+ adapterType: string;
402
+ vectorSearchEnabled: boolean;
403
+ degradedMode: boolean;
404
+ dbPath: string;
405
+ dbSizeBytes: number | null;
406
+ embeddingDim: number;
407
+ };
408
+ private createKnowledgeTable;
409
+ private createFtsTable;
410
+ private ensureVecTable;
411
+ private enqueueWrite;
412
+ private _drain;
413
+ upsert(records: KnowledgeRecord[], vectors: Float32Array[]): Promise<void>;
414
+ upsertInteractive(records: KnowledgeRecord[], vectors: Float32Array[]): Promise<void>;
415
+ private _upsertImpl;
416
+ search(queryVector: Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
417
+ ftsSearch(query: string, options?: SearchOptions): Promise<SearchResult[]>;
418
+ getById(id: string): Promise<KnowledgeRecord | null>;
419
+ deleteBySourcePath(sourcePath: string): Promise<number>;
420
+ private _deleteBySourcePathImpl;
421
+ deleteById(id: string): Promise<boolean>;
422
+ deleteByIdInteractive(id: string): Promise<boolean>;
423
+ private _deleteByIdImpl;
424
+ getBySourcePath(sourcePath: string): Promise<KnowledgeRecord[]>;
425
+ getStats(): Promise<IndexStats>;
426
+ listSourcePaths(): Promise<string[]>;
427
+ createFtsIndex(): Promise<void>;
428
+ dropTable(): Promise<void>;
429
+ private _dropTableImpl;
430
+ close(): Promise<void>;
431
+ private getAdapter;
432
+ /**
433
+ * Build a SQL filter suffix from SearchOptions.
434
+ * @param whereOnly when true the caller already has a WHERE clause and we emit `AND ...`
435
+ * otherwise we emit `WHERE ...`.
436
+ */
437
+ private buildFilterSqlSuffix;
438
+ private fromRow;
439
+ }
440
+ //#endregion
339
441
  //#region packages/store/src/store-factory.d.ts
340
442
  type StoreBackend = 'lancedb' | 'sqlite-vec';
341
443
  interface StoreConfig {
342
444
  backend: StoreBackend;
343
445
  path: string;
344
446
  options?: Record<string, unknown>;
447
+ /** Optional shared adapter (only used by the sqlite-vec backend) */
448
+ adapter?: ISqliteAdapter;
449
+ /** Embedding dimension (only used by the sqlite-vec backend) */
450
+ embeddingDim?: number;
345
451
  }
346
452
  declare function createStore(config: StoreConfig): Promise<IKnowledgeStore>;
347
453
  //#endregion
348
- export { type DepthGroupedResult, type GraphEdge, type GraphNode, type GraphStats, type GraphTraversalOptions, type GraphTraversalResult, type GraphValidationResult, type IGraphStore, type IKnowledgeStore, type ISqliteAdapter, LanceStore, type ProcessInfo, type SearchOptions, type SqliteAdapterType, SqliteGraphStore, type StoreBackend, type StoreConfig, type Symbol360, createSqliteAdapter, createStore };
454
+ export { type DepthGroupedResult, type GraphEdge, type GraphNode, type GraphStats, type GraphTraversalOptions, type GraphTraversalResult, type GraphValidationResult, type IGraphStore, type IKnowledgeStore, type ISqliteAdapter, LanceStore, type ProcessInfo, type SearchOptions, type SqliteAdapterType, SqliteGraphStore, SqliteVecStore, type SqliteVecStoreOptions, type StoreBackend, type StoreConfig, type Symbol360, createSqlJsAdapter, createSqliteAdapter, createStore };
@@ -1,4 +1,4 @@
1
- import{t as e}from"./lance-store-CQkljFy3.js";import{createRequire as t}from"node:module";import{AIKIT_PATHS as n}from"../../core/dist/index.js";import{existsSync as r,mkdirSync as i,readFileSync as a,renameSync as o,unlinkSync as s,writeFileSync as c}from"node:fs";import{dirname as l,join as u}from"node:path";const d=t(import.meta.url);function f(e){return d.resolve(`sql.js/dist/${e}`)}var p=class{type=`sql.js`;db=null;dbPath=``;dirty=!1;inTransaction=!1;async open(e){this.dbPath=e;let t=(await import(`sql.js`)).default,n=await t({locateFile:e=>f(e)});if(r(e)){let t=a(e);this.db=new n.Database(t)}else this.db=new n.Database}exec(e){let t=e.trimStart().toUpperCase();this.getDb().run(e),t.startsWith(`BEGIN`)?this.inTransaction=!0:(t.startsWith(`COMMIT`)||t.startsWith(`ROLLBACK`))&&(this.inTransaction=!1),this.dirty=!0}pragma(e){this.getDb().exec(`PRAGMA ${e}`)}queryAll(e,t=[]){let n=this.getDb().prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}}run(e,t=[]){let n=this.getDb(),r=e.trimStart().toUpperCase(),i=!this.inTransaction&&(r.startsWith(`INSERT`)||r.startsWith(`UPDATE`));i&&n.run(`SAVEPOINT fk_check`);try{if(t.length>0){let r=n.prepare(e);try{r.bind(t),r.step()}finally{r.free()}}else n.run(e);if(i){if(n.exec(`PRAGMA foreign_key_check`).length>0)throw n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`),Error(`FOREIGN KEY constraint failed`);n.run(`RELEASE fk_check`)}}catch(e){if(i)try{n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`)}catch{}throw e}this.dirty=!0}flush(){if(!this.dirty||!this.db)return;let e=this.db.export(),t=`${this.dbPath}.tmp`;c(t,Buffer.from(e)),o(t,this.dbPath),this.dirty=!1}close(){if(this.db){let e=this.db,t;try{this.flush()}catch(e){t=e;try{s(`${this.dbPath}.tmp`)}catch{}}try{e.close()}finally{this.db=null}if(t)throw t}}getDb(){if(!this.db)throw Error(`SqlJsAdapter: database not opened`);return this.db}};async function m(e){let t=new p;try{return await t.open(e),t}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`[aikit] SQLite adapter "sql.js" failed to load: ${t}`)}}var h=class{adapter=null;reopenPromise=null;dbPath;constructor(e){let t=e?.path??n.data;this.dbPath=u(t,`graph.db`)}async initialize(){let e=l(this.dbPath);r(e)||i(e,{recursive:!0}),this.adapter=await m(this.dbPath),this.configureAdapter(this.adapter),this.createTables(this.adapter),this.migrateSchema(this.adapter),this.adapter.flush()}configureAdapter(e){e.pragma(`journal_mode = WAL`),e.pragma(`foreign_keys = ON`)}createTables(e){e.exec(`
1
+ import{t as e}from"./lance-store-BRoi-4qY.js";import{i as t,r as n,t as r}from"./sqlite-vec-store-CfcO7e_I.js";import{AIKIT_PATHS as i}from"../../core/dist/index.js";import{existsSync as a,mkdirSync as o}from"node:fs";import{dirname as s,join as c}from"node:path";var l=class{adapter=null;reopenPromise=null;dbPath;externalAdapter;constructor(e={}){if(e.adapter)this.adapter=e.adapter,this.externalAdapter=!0,this.dbPath=``;else{let t=e.path??i.data;this.dbPath=c(t,`graph.db`),this.externalAdapter=!1}}async initialize(){if(this.externalAdapter){let e=this.getAdapter();this.createTables(e),this.migrateSchema(e),e.flush();return}let e=s(this.dbPath);a(e)||o(e,{recursive:!0}),this.adapter=await t(this.dbPath),this.configureAdapter(this.adapter),this.createTables(this.adapter),this.migrateSchema(this.adapter),this.adapter.flush()}configureAdapter(e){e.pragma(`journal_mode = WAL`),e.pragma(`foreign_keys = ON`)}createTables(e){e.exec(`
2
2
  CREATE TABLE IF NOT EXISTS nodes (
3
3
  id TEXT PRIMARY KEY,
4
4
  type TEXT NOT NULL,
@@ -39,7 +39,7 @@ import{t as e}from"./lance-store-CQkljFy3.js";import{createRequire as t}from"nod
39
39
  FOREIGN KEY (process_id) REFERENCES processes(id) ON DELETE CASCADE,
40
40
  FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE
41
41
  )
42
- `),e.exec(`CREATE INDEX IF NOT EXISTS idx_process_steps_node ON process_steps(node_id)`)}migrateSchema(e){for(let t of[`ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0`,`ALTER TABLE nodes ADD COLUMN community TEXT`])try{e.exec(t)}catch{}e.exec(`CREATE INDEX IF NOT EXISTS idx_nodes_community ON nodes(community)`)}getAdapter(){if(!this.adapter)throw Error(`SqliteGraphStore not initialized — call initialize() first`);return this.adapter}async ensureOpen(){if(this.adapter)return;if(this.reopenPromise)return this.reopenPromise;let e=this.reopenAdapter();this.reopenPromise=e;try{await e}finally{this.reopenPromise===e&&(this.reopenPromise=null)}}async reopenAdapter(){let e=await m(this.dbPath);this.configureAdapter(e),this.adapter=e}query(e,t=[]){return this.getAdapter().queryAll(e,t)}run(e,t=[]){this.getAdapter().run(e,t)}async upsertNode(e){await this.ensureOpen(),this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at, community)
42
+ `),e.exec(`CREATE INDEX IF NOT EXISTS idx_process_steps_node ON process_steps(node_id)`)}migrateSchema(e){for(let t of[`ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0`,`ALTER TABLE nodes ADD COLUMN community TEXT`])try{e.exec(t)}catch{}e.exec(`CREATE INDEX IF NOT EXISTS idx_nodes_community ON nodes(community)`)}getAdapter(){if(!this.adapter)throw Error(`SqliteGraphStore not initialized — call initialize() first`);return this.adapter}async ensureOpen(){if(this.adapter)return;if(this.externalAdapter)throw Error(`SqliteGraphStore: external adapter has been closed by its owner; cannot reopen`);if(this.reopenPromise)return this.reopenPromise;let e=this.reopenAdapter();this.reopenPromise=e;try{await e}finally{this.reopenPromise===e&&(this.reopenPromise=null)}}async reopenAdapter(){let e=await t(this.dbPath);this.configureAdapter(e),this.adapter=e}query(e,t=[]){return this.getAdapter().queryAll(e,t)}run(e,t=[]){this.getAdapter().run(e,t)}async upsertNode(e){await this.ensureOpen(),this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at, community)
43
43
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
44
44
  ON CONFLICT(id) DO UPDATE SET
45
45
  type = excluded.type, name = excluded.name, properties = excluded.properties,
@@ -57,19 +57,19 @@ import{t as e}from"./lance-store-CQkljFy3.js";import{createRequire as t}from"nod
57
57
  VALUES (?, ?, ?, ?, ?, ?, ?)
58
58
  ON CONFLICT(id) DO UPDATE SET
59
59
  from_id = excluded.from_id, to_id = excluded.to_id,
60
- type = excluded.type, weight = excluded.weight, confidence = excluded.confidence, properties = excluded.properties`,[t.id,t.fromId,t.toId,t.type,t.weight??1,t.confidence??1,JSON.stringify(t.properties??{})]);t.exec(`COMMIT`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}finally{t.pragma(`foreign_keys = ON`)}}async getNode(e){await this.ensureOpen();let t=this.query(`SELECT * FROM nodes WHERE id = ?`,[e]);return t.length>0?_(t[0]):null}async getNeighbors(e,t){await this.ensureOpen();let n=t?.direction??`both`,r=t?.edgeType,i=t?.limit??50,a=[],o=[],s=new Set;if(n===`outgoing`||n===`both`){let t=`
60
+ type = excluded.type, weight = excluded.weight, confidence = excluded.confidence, properties = excluded.properties`,[t.id,t.fromId,t.toId,t.type,t.weight??1,t.confidence??1,JSON.stringify(t.properties??{})]);t.exec(`COMMIT`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}finally{t.pragma(`foreign_keys = ON`)}}async getNode(e){await this.ensureOpen();let t=this.query(`SELECT * FROM nodes WHERE id = ?`,[e]);return t.length>0?d(t[0]):null}async getNeighbors(e,t){await this.ensureOpen();let n=t?.direction??`both`,r=t?.edgeType,i=t?.limit??50,a=[],o=[],s=new Set;if(n===`outgoing`||n===`both`){let t=`
61
61
  SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight,
62
62
  e.confidence AS edge_confidence, e.properties AS edge_props,
63
63
  n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
64
64
  n.source_record_id AS node_src_rec, n.source_path AS node_src_path,
65
65
  n.created_at AS node_created, n.community AS node_community
66
- FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(y(e)),s.has(e.node_id)||(s.add(e.node_id),a.push(b(e)))}if(n===`incoming`||n===`both`){let t=`
66
+ FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(p(e)),s.has(e.node_id)||(s.add(e.node_id),a.push(m(e)))}if(n===`incoming`||n===`both`){let t=`
67
67
  SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight,
68
68
  e.confidence AS edge_confidence, e.properties AS edge_props,
69
69
  n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
70
70
  n.source_record_id AS node_src_rec, n.source_path AS node_src_path,
71
71
  n.created_at AS node_created, n.community AS node_community
72
- FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(y(e)),s.has(e.node_id)||(s.add(e.node_id),a.push(b(e)))}return{nodes:a,edges:o}}async traverse(e,t){await this.ensureOpen();let n=t?.maxDepth??2,r=t?.direction??`both`,i=t?.edgeType,a=t?.limit??50,o=new Map,s=new Map,c=new Set,l=[{nodeId:e,depth:0}];for(;l.length>0&&o.size<a;){let e=l.shift();if(!e||c.has(e.nodeId)||e.depth>n)continue;c.add(e.nodeId);let t=await this.getNeighbors(e.nodeId,{direction:r,edgeType:i,limit:a-o.size});for(let r of t.nodes)o.has(r.id)||(o.set(r.id,r),e.depth+1<n&&l.push({nodeId:r.id,depth:e.depth+1}));for(let e of t.edges)s.set(e.id,e)}return{nodes:[...o.values()],edges:[...s.values()]}}async findNodes(e){await this.ensureOpen();let t=[],n=[];e.type&&(t.push(`type = ?`),n.push(e.type)),e.namePattern&&(t.push(`name LIKE ?`),n.push(`%${e.namePattern}%`)),e.sourcePath&&(t.push(`source_path = ?`),n.push(e.sourcePath));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit??100;return this.query(`SELECT * FROM nodes ${r} LIMIT ?`,[...n,i]).map(e=>_(e))}async findEdges(e){await this.ensureOpen();let t=[],n=[];e.type&&(t.push(`type = ?`),n.push(e.type)),e.fromId&&(t.push(`from_id = ?`),n.push(e.fromId)),e.toId&&(t.push(`to_id = ?`),n.push(e.toId));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit??100;return this.query(`SELECT * FROM edges ${r} LIMIT ?`,[...n,i]).map(e=>v(e))}async deleteNode(e){await this.ensureOpen();let t=this.getAdapter();t.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM edges WHERE from_id = ? OR to_id = ?`,[e,e]),this.run(`DELETE FROM nodes WHERE id = ?`,[e]),t.exec(`COMMIT`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}}async deleteBySourcePath(e){await this.ensureOpen();let t=this.query(`SELECT id FROM nodes WHERE source_path = ?`,[e]);if(t.length===0)return 0;let n=this.getAdapter();n.exec(`BEGIN TRANSACTION`);try{for(let e of t)this.run(`DELETE FROM edges WHERE from_id = ? OR to_id = ?`,[e.id,e.id]);this.run(`DELETE FROM nodes WHERE source_path = ?`,[e]),n.exec(`COMMIT`),n.flush()}catch(e){throw n.exec(`ROLLBACK`),e}return t.length}async clear(){await this.ensureOpen();let e=this.getAdapter();e.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM process_steps`),this.run(`DELETE FROM processes`),this.run(`DELETE FROM edges`),this.run(`DELETE FROM nodes`),e.exec(`COMMIT`)}catch(t){throw e.exec(`ROLLBACK`),t}e.flush()}async getStats(){await this.ensureOpen();let e=this.query(`SELECT COUNT(*) as count FROM nodes`)[0]?.count??0,t=this.query(`SELECT COUNT(*) as count FROM edges`)[0]?.count??0,n=this.query(`SELECT type, COUNT(*) as count FROM nodes GROUP BY type`),r={};for(let e of n)r[e.type]=e.count;let i=this.query(`SELECT type, COUNT(*) as count FROM edges GROUP BY type`),a={};for(let e of i)a[e.type]=e.count;return{nodeCount:e,edgeCount:t,nodeTypes:r,edgeTypes:a}}async validate(){await this.ensureOpen();let e=await this.getStats(),t=this.query(`SELECT e.id AS edgeId,
72
+ FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(p(e)),s.has(e.node_id)||(s.add(e.node_id),a.push(m(e)))}return{nodes:a,edges:o}}async traverse(e,t){await this.ensureOpen();let n=t?.maxDepth??2,r=t?.direction??`both`,i=t?.edgeType,a=t?.limit??50,o=new Map,s=new Map,c=new Set,l=[{nodeId:e,depth:0}];for(;l.length>0&&o.size<a;){let e=l.shift();if(!e||c.has(e.nodeId)||e.depth>n)continue;c.add(e.nodeId);let t=await this.getNeighbors(e.nodeId,{direction:r,edgeType:i,limit:a-o.size});for(let r of t.nodes)o.has(r.id)||(o.set(r.id,r),e.depth+1<n&&l.push({nodeId:r.id,depth:e.depth+1}));for(let e of t.edges)s.set(e.id,e)}return{nodes:[...o.values()],edges:[...s.values()]}}async findNodes(e){await this.ensureOpen();let t=[],n=[];e.type&&(t.push(`type = ?`),n.push(e.type)),e.namePattern&&(t.push(`name LIKE ?`),n.push(`%${e.namePattern}%`)),e.sourcePath&&(t.push(`source_path = ?`),n.push(e.sourcePath));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit??100;return this.query(`SELECT * FROM nodes ${r} LIMIT ?`,[...n,i]).map(e=>d(e))}async findEdges(e){await this.ensureOpen();let t=[],n=[];e.type&&(t.push(`type = ?`),n.push(e.type)),e.fromId&&(t.push(`from_id = ?`),n.push(e.fromId)),e.toId&&(t.push(`to_id = ?`),n.push(e.toId));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit??100;return this.query(`SELECT * FROM edges ${r} LIMIT ?`,[...n,i]).map(e=>f(e))}async deleteNode(e){await this.ensureOpen();let t=this.getAdapter();t.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM edges WHERE from_id = ? OR to_id = ?`,[e,e]),this.run(`DELETE FROM nodes WHERE id = ?`,[e]),t.exec(`COMMIT`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}}async deleteBySourcePath(e){await this.ensureOpen();let t=this.query(`SELECT id FROM nodes WHERE source_path = ?`,[e]);if(t.length===0)return 0;let n=this.getAdapter();n.exec(`BEGIN TRANSACTION`);try{for(let e of t)this.run(`DELETE FROM edges WHERE from_id = ? OR to_id = ?`,[e.id,e.id]);this.run(`DELETE FROM nodes WHERE source_path = ?`,[e]),n.exec(`COMMIT`),n.flush()}catch(e){throw n.exec(`ROLLBACK`),e}return t.length}async clear(){await this.ensureOpen();let e=this.getAdapter();e.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM process_steps`),this.run(`DELETE FROM processes`),this.run(`DELETE FROM edges`),this.run(`DELETE FROM nodes`),e.exec(`COMMIT`)}catch(t){throw e.exec(`ROLLBACK`),t}e.flush()}async getStats(){await this.ensureOpen();let e=this.query(`SELECT COUNT(*) as count FROM nodes`)[0]?.count??0,t=this.query(`SELECT COUNT(*) as count FROM edges`)[0]?.count??0,n=this.query(`SELECT type, COUNT(*) as count FROM nodes GROUP BY type`),r={};for(let e of n)r[e.type]=e.count;let i=this.query(`SELECT type, COUNT(*) as count FROM edges GROUP BY type`),a={};for(let e of i)a[e.type]=e.count;return{nodeCount:e,edgeCount:t,nodeTypes:r,edgeTypes:a}}async validate(){await this.ensureOpen();let e=await this.getStats(),t=this.query(`SELECT e.id AS edgeId,
73
73
  CASE
74
74
  WHEN n1.id IS NULL THEN e.from_id
75
75
  WHEN n2.id IS NULL THEN e.to_id
@@ -87,4 +87,4 @@ import{t as e}from"./lance-store-CQkljFy3.js";import{createRequire as t}from"nod
87
87
  VALUES (?, ?, ?, '{}', ?)`,[a,e,t,o]);for(let e=0;e<n.length;e++)this.run(`INSERT INTO process_steps (process_id, node_id, step_order) VALUES (?, ?, ?)`,[a,n[e],e]);s.exec(`COMMIT`),s.flush()}catch(e){throw s.exec(`ROLLBACK`),e}return{id:a,entryNodeId:e,label:t,properties:{},steps:n,createdAt:o}}async getProcesses(e){await this.ensureOpen();let t;t=e?this.query(`SELECT DISTINCT p.id, p.entry_node_id, p.label, p.properties, p.created_at
88
88
  FROM processes p
89
89
  JOIN process_steps ps ON p.id = ps.process_id
90
- WHERE ps.node_id = ?`,[e]):this.query(`SELECT * FROM processes`);let n=[];for(let e of t){let t=this.query(`SELECT node_id FROM process_steps WHERE process_id = ? ORDER BY step_order`,[e.id]);n.push({id:e.id,entryNodeId:e.entry_node_id,label:e.label,properties:g(e.properties),steps:t.map(e=>e.node_id),createdAt:e.created_at})}return n}async deleteProcess(e){await this.ensureOpen();let t=this.getAdapter();t.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM process_steps WHERE process_id = ?`,[e]),this.run(`DELETE FROM processes WHERE id = ?`,[e]),t.exec(`COMMIT`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}}async depthGroupedTraversal(e,t=3,n){await this.ensureOpen();let r=n?.direction??`both`,i=n?.edgeType,a=n?.limit??100,o={},s=new Set;s.add(e);let c=[e];for(let e=1;e<=t;e++){let t=[],n=[];for(let e of c){let o=await this.getNeighbors(e,{direction:r,edgeType:i,limit:a});for(let e of o.nodes)s.has(e.id)||(s.add(e.id),t.push(e.id),n.push(e))}if(n.length>0&&(o[e]=n),c=t,c.length===0||s.size>=a)break}return o}async getCohesionScore(e){await this.ensureOpen();let t=this.query(`SELECT id FROM nodes WHERE community = ?`,[e]);if(t.length===0)return 0;let n=new Set(t.map(e=>e.id)),r=t.map(()=>`?`).join(`,`),i=t.map(e=>e.id),a=this.query(`SELECT from_id, to_id FROM edges WHERE from_id IN (${r}) OR to_id IN (${r})`,[...i,...i]);if(a.length===0)return 0;let o=0;for(let e of a)n.has(e.from_id)&&n.has(e.to_id)&&o++;return o/a.length}async getSymbol360(e){let t=await this.getNode(e);if(!t)throw Error(`Node '${e}' not found`);let n=await this.findEdges({toId:e}),r=await this.findEdges({fromId:e}),i=await this.getProcesses(e);return{node:t,incoming:n,outgoing:r,community:t.community??null,processes:i}}async close(){this.adapter&&=(this.adapter.close(),null)}};function g(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function _(e){return{id:e.id,type:e.type,name:e.name,properties:g(e.properties),sourceRecordId:e.source_record_id??void 0,sourcePath:e.source_path??void 0,createdAt:e.created_at,community:e.community??void 0}}function v(e){return{id:e.id,fromId:e.from_id,toId:e.to_id,type:e.type,weight:e.weight??1,confidence:e.confidence??1,properties:g(e.properties)}}function y(e){return{id:e.edge_id,fromId:e.from_id,toId:e.to_id,type:e.edge_type,weight:e.weight??1,confidence:e.edge_confidence??1,properties:g(e.edge_props??`{}`)}}function b(e){return{id:e.node_id,type:e.node_type,name:e.node_name,properties:g(e.node_props??`{}`),sourceRecordId:e.node_src_rec??void 0,sourcePath:e.node_src_path??void 0,createdAt:e.node_created,community:e.node_community??void 0}}async function x(e){switch(e.backend){case`lancedb`:{let{LanceStore:t}=await import(`./lance-store-CQkljFy3.js`).then(e=>e.n);return new t({path:e.path})}default:throw Error(`Unknown store backend: "${e.backend}". Supported: lancedb`)}}export{e as LanceStore,h as SqliteGraphStore,m as createSqliteAdapter,x as createStore};
90
+ WHERE ps.node_id = ?`,[e]):this.query(`SELECT * FROM processes`);let n=[];for(let e of t){let t=this.query(`SELECT node_id FROM process_steps WHERE process_id = ? ORDER BY step_order`,[e.id]);n.push({id:e.id,entryNodeId:e.entry_node_id,label:e.label,properties:u(e.properties),steps:t.map(e=>e.node_id),createdAt:e.created_at})}return n}async deleteProcess(e){await this.ensureOpen();let t=this.getAdapter();t.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM process_steps WHERE process_id = ?`,[e]),this.run(`DELETE FROM processes WHERE id = ?`,[e]),t.exec(`COMMIT`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}}async depthGroupedTraversal(e,t=3,n){await this.ensureOpen();let r=n?.direction??`both`,i=n?.edgeType,a=n?.limit??100,o={},s=new Set;s.add(e);let c=[e];for(let e=1;e<=t;e++){let t=[],n=[];for(let e of c){let o=await this.getNeighbors(e,{direction:r,edgeType:i,limit:a});for(let e of o.nodes)s.has(e.id)||(s.add(e.id),t.push(e.id),n.push(e))}if(n.length>0&&(o[e]=n),c=t,c.length===0||s.size>=a)break}return o}async getCohesionScore(e){await this.ensureOpen();let t=this.query(`SELECT id FROM nodes WHERE community = ?`,[e]);if(t.length===0)return 0;let n=new Set(t.map(e=>e.id)),r=t.map(()=>`?`).join(`,`),i=t.map(e=>e.id),a=this.query(`SELECT from_id, to_id FROM edges WHERE from_id IN (${r}) OR to_id IN (${r})`,[...i,...i]);if(a.length===0)return 0;let o=0;for(let e of a)n.has(e.from_id)&&n.has(e.to_id)&&o++;return o/a.length}async getSymbol360(e){let t=await this.getNode(e);if(!t)throw Error(`Node '${e}' not found`);let n=await this.findEdges({toId:e}),r=await this.findEdges({fromId:e}),i=await this.getProcesses(e);return{node:t,incoming:n,outgoing:r,community:t.community??null,processes:i}}async close(){this.adapter&&=(this.externalAdapter||this.adapter.close(),null)}};function u(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function d(e){return{id:e.id,type:e.type,name:e.name,properties:u(e.properties),sourceRecordId:e.source_record_id??void 0,sourcePath:e.source_path??void 0,createdAt:e.created_at,community:e.community??void 0}}function f(e){return{id:e.id,fromId:e.from_id,toId:e.to_id,type:e.type,weight:e.weight??1,confidence:e.confidence??1,properties:u(e.properties)}}function p(e){return{id:e.edge_id,fromId:e.from_id,toId:e.to_id,type:e.edge_type,weight:e.weight??1,confidence:e.edge_confidence??1,properties:u(e.edge_props??`{}`)}}function m(e){return{id:e.node_id,type:e.node_type,name:e.node_name,properties:u(e.node_props??`{}`),sourceRecordId:e.node_src_rec??void 0,sourcePath:e.node_src_path??void 0,createdAt:e.node_created,community:e.node_community??void 0}}async function h(e){switch(e.backend){case`lancedb`:{let{LanceStore:t}=await import(`./lance-store-BRoi-4qY.js`).then(e=>e.n);return new t({path:e.path})}case`sqlite-vec`:{let{SqliteVecStore:t}=await import(`./sqlite-vec-store-CfcO7e_I.js`).then(e=>e.n);return new t({path:e.path,adapter:e.adapter,embeddingDim:e.embeddingDim})}default:{let t=e.backend;throw Error(`Unknown store backend: "${t}". Supported: lancedb, sqlite-vec`)}}}export{e as LanceStore,l as SqliteGraphStore,r as SqliteVecStore,n as createSqlJsAdapter,t as createSqliteAdapter,h as createStore};
@@ -0,0 +1 @@
1
+ import{t as e}from"./rolldown-runtime-BynbHzcv.js";import{EMBEDDING_DEFAULTS as t,SEARCH_DEFAULTS as n,STORE_DEFAULTS as r,createLogger as i,serializeError as a,sourceTypeContentTypes as o}from"../../core/dist/index.js";import{Index as s,connect as c}from"@lancedb/lancedb";var l=e({LanceStore:()=>m});function u(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}const d=/^[\w.\-/ ]+$/,f=i(`store`);function p(e,t){if(!d.test(e))throw Error(`Invalid ${t} filter value: contains disallowed characters`);return e.replace(/'/g,`''`)}var m=class e{db=null;table=null;dbPath;tableName;_draining=!1;_priorityQueue=[];_normalQueue=[];_ftsReady=!1;_ftsRecoveryAttemptAt=0;static FTS_RECOVERY_COOLDOWN_MS=300*1e3;enqueueWrite(e,t=!1){return new Promise((n,r)=>{let i=async()=>{try{n(await e())}catch(e){r(e)}};t?this._priorityQueue.push(i):this._normalQueue.push(i),this._drain()})}async _drain(){if(!this._draining){this._draining=!0;try{for(;this._priorityQueue.length>0||this._normalQueue.length>0;){let e=this._priorityQueue.shift()??this._normalQueue.shift();e&&await e()}}finally{this._draining=!1}}}constructor(e){this.dbPath=e?.path??r.path,this.tableName=e?.tableName??r.tableName}async initialize(){this.db=await c(this.dbPath),(await this.db.tableNames()).includes(this.tableName)&&(this.table=await this.db.openTable(this.tableName),await this.createFtsIndex())}async upsert(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t))}}async upsertInteractive(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t),!0)}}async _upsertImpl(e,t){let n=e.map((e,n)=>({id:e.id,vector:Array.from(t[n]),content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath??``,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:JSON.stringify(e.tags),category:e.category??``,version:e.version}));if(this.table){let t=[...new Set(e.map(e=>e.sourcePath))];for(let e of t)try{await this.table.delete(`sourcePath = '${p(e,`sourcePath`)}'`)}catch{}await this.table.add(n)}else try{this.table=await this.db?.createTable(this.tableName,n)??null}catch(e){if(String(e).includes(`already exists`)&&this.db)this.table=await this.db.openTable(this.tableName),await this.table.add(n);else throw e}}async search(e,t){if(!this.table)return[];let r=t?.limit??n.maxResults,i=t?.minScore??n.minScore,a=this.table.search(e).limit(r*2),o=this.buildFilterString(t);return o&&(a=a.where(o)),(await a.toArray()).map(e=>({record:this.fromLanceRecord(e),score:1-(e._distance??1)})).filter(e=>e.score>=i).slice(0,r)}async createFtsIndex(){return this.enqueueWrite(()=>this._createFtsIndexImpl())}async _createFtsIndexImpl(){if(this.table)try{await this.table.createIndex(`content`,{config:s.fts({withPosition:!0}),replace:!0}),this._ftsReady=!0,this._ftsRecoveryAttemptAt=0,f.info(`FTS index created/updated`,{column:`content`})}catch(e){f.warn(`FTS index creation failed`,a(e))}}async ftsSearch(t,r){if(!this.table)return[];if(!this._ftsReady){let t=Date.now();if(t-this._ftsRecoveryAttemptAt<e.FTS_RECOVERY_COOLDOWN_MS)return[];this._ftsRecoveryAttemptAt=t;try{await this.createFtsIndex()}catch{return[]}if(!this._ftsReady)return[]}let i=r?.limit??n.maxResults;try{let e=this.table.search(t).limit(i*2),n=this.buildFilterString(r);return n&&(e=e.where(n)),(await e.toArray()).map(e=>({record:this.fromLanceRecord(e),score:e._score??e._relevance_score??0}))}catch(e){return(e instanceof Error?e.message:String(e)).includes(`INVERTED index`)?(f.debug(`FTS search skipped — index not yet available`),this._ftsReady=!1):f.warn(`FTS search failed`,a(e)),[]}}async getById(e){if(!this.table)return null;let t=await this.table.query().where(`id = '${p(e,`id`)}'`).limit(1).toArray();return t.length===0?null:this.fromLanceRecord(t[0])}async deleteBySourcePath(e){return this.enqueueWrite(()=>this._deleteBySourcePathImpl(e))}async _deleteBySourcePathImpl(e){if(!this.table)return 0;let t=await this.getBySourcePath(e);return t.length===0?0:(await this.table.delete(`sourcePath = '${p(e,`sourcePath`)}'`),t.length)}async deleteById(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e))}async deleteByIdInteractive(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e),!0)}async _deleteByIdImpl(e){return!this.table||!await this.getById(e)?!1:(await this.table.delete(`id = '${p(e,`id`)}'`),!0)}async getBySourcePath(e){return this.table?(await this.table.query().where(`sourcePath = '${p(e,`sourcePath`)}'`).limit(1e3).toArray()).map(e=>this.fromLanceRecord(e)):[]}async getStats(){if(!this.table)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:`lancedb`,embeddingModel:t.model};let e=await this.table.countRows(),n=await this.table.query().select([`sourcePath`,`contentType`,`indexedAt`]).limit(1e5).toArray(),r={},i=new Set,a=null;for(let e of n){let t=e;r[t.contentType]=(r[t.contentType]??0)+1,i.add(t.sourcePath),(!a||t.indexedAt>a)&&(a=t.indexedAt)}return{totalRecords:e,totalFiles:i.size,contentTypeBreakdown:r,lastIndexedAt:a,storeBackend:`lancedb`,embeddingModel:t.model}}async listSourcePaths(){if(!this.table)return[];let e=await this.table.query().select([`sourcePath`]).limit(1e5).toArray();return[...new Set(e.map(e=>e.sourcePath))]}async dropTable(){return this.enqueueWrite(()=>this._dropTableImpl())}async _dropTableImpl(){if(this.db&&(await this.db.tableNames()).includes(this.tableName))for(let e=1;e<=3;e++)try{await this.db.dropTable(this.tableName);break}catch(t){if(e===3)throw t;let n=e*500;f.warn(`dropTable attempt failed, retrying`,{attempt:e,delayMs:n}),await new Promise(e=>setTimeout(e,n))}this.table=null}async close(){try{this.db&&typeof this.db.close==`function`&&await this.db.close()}catch{}this.table=null,this.db=null}buildFilterString(e){let t=[];if(e?.contentType&&t.push(`contentType = '${p(e.contentType,`contentType`)}'`),e?.sourceType){let n=o(e.sourceType);if(n.length>0){let e=n.map(e=>`'${p(e,`sourceType`)}'`).join(`, `);t.push(`contentType IN (${e})`)}}if(e?.origin&&t.push(`origin = '${p(e.origin,`origin`)}'`),e?.category&&t.push(`category = '${p(e.category,`category`)}'`),e?.tags&&e.tags.length>0){let n=e.tags.map(e=>`tags LIKE '%${p(e,`tag`)}%'`);t.push(`(${n.join(` OR `)})`)}return t.length>0?t.join(` AND `):null}fromLanceRecord(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:u(e.tags),category:e.category||void 0,version:e.version}}};export{l as n,m as t};
@@ -0,0 +1 @@
1
+ import{createRequire as e}from"node:module";var t=Object.defineProperty,n=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},r=e(import.meta.url);export{r as n,n as t};
@@ -0,0 +1,68 @@
1
+ import{n as e,t}from"./rolldown-runtime-BynbHzcv.js";import{createRequire as n}from"node:module";import{EMBEDDING_DEFAULTS as r,SEARCH_DEFAULTS as i,STORE_DEFAULTS as a,createLogger as o,serializeError as s,sourceTypeContentTypes as c}from"../../core/dist/index.js";import{existsSync as l,mkdirSync as u,readFileSync as d,renameSync as f,unlinkSync as p,writeFileSync as m}from"node:fs";import{dirname as h}from"node:path";const g=o(`sqlite-adapter`),_=n(import.meta.url);var v=class{type=`better-sqlite3`;vectorCapable=!1;db=null;stmtCache=new Map;async open(e){let t;try{t=_(`better-sqlite3`)}catch(e){throw Error(`better-sqlite3 native binding unavailable: ${e instanceof Error?e.message:String(e)}`)}this.db=new t(e),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`foreign_keys = ON`),this.db.pragma(`synchronous = NORMAL`);try{_(`sqlite-vec`).load(this.db),this.vectorCapable=!0,g.info(`sqlite-vec extension loaded`)}catch(e){this.vectorCapable=!1,g.warn(`sqlite-vec extension failed to load; vector search disabled`,s(e))}}exec(e){this.getDb().exec(e)}pragma(e){this.getDb().pragma(e)}queryAll(e,t=[]){let n=this.prepareCached(e);return t.length>0?n.all(...t):n.all()}run(e,t=[]){let n=this.prepareCached(e);t.length>0?n.run(...t):n.run()}flush(){}close(){this.db&&=(this.stmtCache.clear(),this.db.close(),null)}getDb(){if(!this.db)throw Error(`BetterSqlite3Adapter: database not opened`);return this.db}prepareCached(e){let t=this.stmtCache.get(e);if(t)return t;let n=this.getDb().prepare(e);return this.stmtCache.set(e,n),n}};function y(e){return _.resolve(`sql.js/dist/${e}`)}var b=class{type=`sql.js`;vectorCapable=!1;db=null;dbPath=``;dirty=!1;inTransaction=!1;async open(e){this.dbPath=e;let t=(await import(`sql.js`)).default,n=await t({locateFile:e=>y(e)});if(l(e)){let t=d(e);this.db=new n.Database(t)}else this.db=new n.Database}exec(e){let t=e.trimStart().toUpperCase();this.getDb().run(e),t.startsWith(`BEGIN`)?this.inTransaction=!0:(t.startsWith(`COMMIT`)||t.startsWith(`ROLLBACK`))&&(this.inTransaction=!1),this.dirty=!0}pragma(e){this.getDb().exec(`PRAGMA ${e}`)}queryAll(e,t=[]){let n=this.getDb().prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}}run(e,t=[]){let n=this.getDb(),r=e.trimStart().toUpperCase(),i=!this.inTransaction&&(r.startsWith(`INSERT`)||r.startsWith(`UPDATE`));i&&n.run(`SAVEPOINT fk_check`);try{if(t.length>0){let r=n.prepare(e);try{r.bind(t),r.step()}finally{r.free()}}else n.run(e);if(i){if(n.exec(`PRAGMA foreign_key_check`).length>0)throw n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`),Error(`FOREIGN KEY constraint failed`);n.run(`RELEASE fk_check`)}}catch(e){if(i)try{n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`)}catch{}throw e}this.dirty=!0}flush(){if(!this.dirty||!this.db)return;let e=this.db.export(),t=`${this.dbPath}.tmp`;m(t,Buffer.from(e)),f(t,this.dbPath),this.dirty=!1}close(){if(this.db){let e=this.db,t;try{this.flush()}catch(e){t=e;try{p(`${this.dbPath}.tmp`)}catch{}}try{e.close()}finally{this.db=null}if(t)throw t}}getDb(){if(!this.db)throw Error(`SqlJsAdapter: database not opened`);return this.db}};let x=!1;async function S(e){let t=new v;try{return await t.open(e),t}catch(e){x||(x=!0,g.warn(`[aikit] better-sqlite3 unavailable — falling back to sql.js (vector search disabled). Reinstall with prebuild support or rebuild from source to enable vector search.`,s(e)))}let n=new b;try{return await n.open(e),n}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`[aikit] SQLite adapter "sql.js" failed to load: ${t}`)}}async function C(e){let t=new b;return await t.open(e),t}var w=t({SqliteVecStore:()=>A});const T=/^[\w.\-/ ]+$/,E=o(`sqlite-vec-store`);function D(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function O(e,t){if(!T.test(e))throw Error(`Invalid ${t} filter value: contains disallowed characters`);return e}function k(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}var A=class{adapter=null;externalAdapter;dbPath;embeddingDim;vectorEnabled=!1;warnedVectorDisabled=!1;_draining=!1;_priorityQueue=[];_normalQueue=[];constructor(e={}){this.embeddingDim=e.embeddingDim??r.dimensions,e.adapter?(this.adapter=e.adapter,this.externalAdapter=!0,this.dbPath=``):(this.dbPath=e.path??`${a.path}/aikit.db`,this.externalAdapter=!1)}async initialize(){if(!this.adapter){let e=h(this.dbPath);l(e)||u(e,{recursive:!0}),this.adapter=await S(this.dbPath)}this.vectorEnabled=this.adapter.vectorCapable,this.createKnowledgeTable(),this.createFtsTable(),this.vectorEnabled?this.ensureVecTable():this.warnedVectorDisabled||(this.warnedVectorDisabled=!0,E.warn(`SqliteVecStore: vector search disabled (sqlite-vec extension not loaded). Hybrid search will return FTS-only results.`))}getDiagnostics(){let t=this.adapter,n=t?t.constructor.name:`unknown`,r=null,i=this.externalAdapter?``:this.dbPath;if(i)try{let{statSync:t}=e(`node:fs`);r=t(i).size}catch{r=null}return{adapterType:n,vectorSearchEnabled:this.vectorEnabled,degradedMode:!this.vectorEnabled,dbPath:i,dbSizeBytes:r,embeddingDim:this.embeddingDim}}createKnowledgeTable(){let e=this.getAdapter();e.exec(`
2
+ CREATE TABLE IF NOT EXISTS knowledge (
3
+ id TEXT PRIMARY KEY,
4
+ content TEXT NOT NULL,
5
+ sourcePath TEXT NOT NULL,
6
+ contentType TEXT NOT NULL,
7
+ headingPath TEXT NOT NULL DEFAULT '',
8
+ chunkIndex INTEGER NOT NULL DEFAULT 0,
9
+ totalChunks INTEGER NOT NULL DEFAULT 1,
10
+ startLine INTEGER NOT NULL DEFAULT 0,
11
+ endLine INTEGER NOT NULL DEFAULT 0,
12
+ fileHash TEXT NOT NULL DEFAULT '',
13
+ indexedAt TEXT NOT NULL,
14
+ origin TEXT NOT NULL DEFAULT 'indexed',
15
+ tags TEXT NOT NULL DEFAULT '[]',
16
+ category TEXT NOT NULL DEFAULT '',
17
+ version INTEGER NOT NULL DEFAULT 1
18
+ )
19
+ `),e.exec(`CREATE INDEX IF NOT EXISTS idx_knowledge_sourcePath ON knowledge(sourcePath)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_knowledge_contentType ON knowledge(contentType)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_knowledge_origin ON knowledge(origin)`)}createFtsTable(){this.getAdapter().exec(`
20
+ CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_fts USING fts5(
21
+ id UNINDEXED,
22
+ content,
23
+ tokenize = 'unicode61 remove_diacritics 2'
24
+ )
25
+ `)}ensureVecTable(){let e=this.getAdapter(),t=e.queryAll(`SELECT name, sql FROM sqlite_master WHERE type='table' AND name='vec_knowledge'`);if(t.length>0){let n=(t[0].sql??``).match(/float\[(\d+)\]/i),r=n?Number(n[1]):null;r!==null&&r!==this.embeddingDim&&(E.warn(`Embedding dim changed — dropping vec table`,{existingDim:r,newDim:this.embeddingDim}),e.exec(`DROP TABLE vec_knowledge`))}e.exec(`
26
+ CREATE VIRTUAL TABLE IF NOT EXISTS vec_knowledge USING vec0(
27
+ embedding float[${this.embeddingDim}] distance_metric=cosine,
28
+ +knowledge_id TEXT
29
+ )
30
+ `)}enqueueWrite(e,t=!1){return new Promise((n,r)=>{let i=async()=>{try{n(await e())}catch(e){r(e)}};t?this._priorityQueue.push(i):this._normalQueue.push(i),this._drain()})}async _drain(){if(!this._draining){this._draining=!0;try{for(;this._priorityQueue.length>0||this._normalQueue.length>0;){let e=this._priorityQueue.shift()??this._normalQueue.shift();e&&await e()}}finally{this._draining=!1}}}async upsert(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t))}}async upsertInteractive(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t),!0)}}async _upsertImpl(e,t){let n=this.getAdapter();n.exec(`BEGIN`);try{for(let r=0;r<e.length;r++){let i=e[r];n.run(`INSERT INTO knowledge (id, content, sourcePath, contentType, headingPath, chunkIndex,
31
+ totalChunks, startLine, endLine, fileHash, indexedAt, origin, tags, category, version)
32
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
33
+ ON CONFLICT(id) DO UPDATE SET
34
+ content = excluded.content,
35
+ sourcePath = excluded.sourcePath,
36
+ contentType = excluded.contentType,
37
+ headingPath = excluded.headingPath,
38
+ chunkIndex = excluded.chunkIndex,
39
+ totalChunks = excluded.totalChunks,
40
+ startLine = excluded.startLine,
41
+ endLine = excluded.endLine,
42
+ fileHash = excluded.fileHash,
43
+ indexedAt = excluded.indexedAt,
44
+ origin = excluded.origin,
45
+ tags = excluded.tags,
46
+ category = excluded.category,
47
+ version = excluded.version`,[i.id,i.content,i.sourcePath,i.contentType,i.headingPath??``,i.chunkIndex,i.totalChunks,i.startLine,i.endLine,i.fileHash,i.indexedAt,i.origin,JSON.stringify(i.tags??[]),i.category??``,i.version]),n.run(`DELETE FROM knowledge_fts WHERE id = ?`,[i.id]),n.run(`INSERT INTO knowledge_fts (id, content) VALUES (?, ?)`,[i.id,i.content]),this.vectorEnabled&&(n.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[i.id]),n.run(`INSERT INTO vec_knowledge (embedding, knowledge_id) VALUES (?, ?)`,[k(t[r]),i.id]))}n.exec(`COMMIT`)}catch(e){try{n.exec(`ROLLBACK`)}catch{}throw e}n.flush()}async search(e,t){if(!this.vectorEnabled)return this.warnedVectorDisabled||(this.warnedVectorDisabled=!0,E.warn(`search() called but vector backend is disabled — returning []`)),[];let n=this.getAdapter(),r=t?.limit??i.maxResults,a=t?.minScore??i.minScore,o=r*4,c=`
48
+ SELECT k.*, v.distance AS _distance
49
+ FROM (
50
+ SELECT knowledge_id, distance
51
+ FROM vec_knowledge
52
+ WHERE embedding MATCH ?
53
+ ORDER BY distance
54
+ LIMIT ?
55
+ ) v
56
+ JOIN knowledge k ON k.id = v.knowledge_id
57
+ ${this.buildFilterSqlSuffix(t)}
58
+ ORDER BY v.distance ASC
59
+ LIMIT ?
60
+ `,l;try{l=n.queryAll(c,[k(e),o,r])}catch(e){return E.warn(`vector search failed`,s(e)),[]}return l.map(e=>({record:this.fromRow(e),score:1-(e._distance??1)})).filter(e=>e.score>=a).slice(0,r)}async ftsSearch(e,t){if(!e||e.trim().length===0)return[];let n=this.getAdapter(),r=t?.limit??i.maxResults,a=`
61
+ SELECT k.*, bm25(knowledge_fts) AS _bm25
62
+ FROM knowledge_fts
63
+ JOIN knowledge k ON k.id = knowledge_fts.id
64
+ WHERE knowledge_fts MATCH ?
65
+ ${this.buildFilterSqlSuffix(t,!0)}
66
+ ORDER BY _bm25 ASC
67
+ LIMIT ?
68
+ `,o;try{let t=j(e);o=n.queryAll(a,[t,r])}catch(e){return E.warn(`fts search failed`,s(e)),[]}return o.map(e=>({record:this.fromRow(e),score:M(e._bm25)}))}async getById(e){let t=this.getAdapter().queryAll(`SELECT * FROM knowledge WHERE id = ? LIMIT 1`,[e]);return t.length===0?null:this.fromRow(t[0])}async deleteBySourcePath(e){return this.enqueueWrite(()=>this._deleteBySourcePathImpl(e))}async _deleteBySourcePathImpl(e){let t=this.getAdapter(),n=t.queryAll(`SELECT id FROM knowledge WHERE sourcePath = ?`,[e]);if(n.length===0)return 0;t.exec(`BEGIN`);try{for(let{id:e}of n)this.vectorEnabled&&t.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[e]),t.run(`DELETE FROM knowledge_fts WHERE id = ?`,[e]);t.run(`DELETE FROM knowledge WHERE sourcePath = ?`,[e]),t.exec(`COMMIT`)}catch(e){try{t.exec(`ROLLBACK`)}catch{}throw e}return t.flush(),n.length}async deleteById(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e))}async deleteByIdInteractive(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e),!0)}async _deleteByIdImpl(e){let t=this.getAdapter();if(t.queryAll(`SELECT id FROM knowledge WHERE id = ? LIMIT 1`,[e]).length===0)return!1;t.exec(`BEGIN`);try{this.vectorEnabled&&t.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[e]),t.run(`DELETE FROM knowledge_fts WHERE id = ?`,[e]),t.run(`DELETE FROM knowledge WHERE id = ?`,[e]),t.exec(`COMMIT`)}catch(e){try{t.exec(`ROLLBACK`)}catch{}throw e}return t.flush(),!0}async getBySourcePath(e){return this.getAdapter().queryAll(`SELECT * FROM knowledge WHERE sourcePath = ? ORDER BY chunkIndex ASC`,[e]).map(e=>this.fromRow(e))}async getStats(){let e=this.getAdapter(),t=e.queryAll(`SELECT COUNT(*) AS n FROM knowledge`)[0]?.n??0;if(t===0)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:`sqlite-vec`,embeddingModel:r.model};let n=e.queryAll(`SELECT COUNT(DISTINCT sourcePath) AS n FROM knowledge`),i=e.queryAll(`SELECT contentType, COUNT(*) AS n FROM knowledge GROUP BY contentType`),a=e.queryAll(`SELECT MAX(indexedAt) AS ts FROM knowledge`),o={};for(let e of i)o[e.contentType]=e.n;return{totalRecords:t,totalFiles:n[0]?.n??0,contentTypeBreakdown:o,lastIndexedAt:a[0]?.ts??null,storeBackend:`sqlite-vec`,embeddingModel:r.model}}async listSourcePaths(){return this.getAdapter().queryAll(`SELECT DISTINCT sourcePath FROM knowledge ORDER BY sourcePath`).map(e=>e.sourcePath)}async createFtsIndex(){this.createFtsTable()}async dropTable(){return this.enqueueWrite(()=>this._dropTableImpl())}async _dropTableImpl(){let e=this.getAdapter();e.exec(`DROP TABLE IF EXISTS knowledge_fts`),this.vectorEnabled&&e.exec(`DROP TABLE IF EXISTS vec_knowledge`),e.exec(`DROP TABLE IF EXISTS knowledge`),e.flush(),this.createKnowledgeTable(),this.createFtsTable(),this.vectorEnabled&&this.ensureVecTable()}async close(){for(;this._priorityQueue.length>0||this._normalQueue.length>0||this._draining;)await new Promise(e=>setTimeout(e,5));this.adapter&&!this.externalAdapter&&this.adapter.close(),this.adapter=null}getAdapter(){if(!this.adapter)throw Error(`SqliteVecStore: not initialized — call initialize() first`);return this.adapter}buildFilterSqlSuffix(e,t=!1){if(!e)return``;let n=[];if(e.contentType&&n.push(`k.contentType = '${O(e.contentType,`contentType`)}'`),e.sourceType){let t=c(e.sourceType);if(t.length>0){let e=t.map(e=>`'${O(e,`sourceType`)}'`).join(`, `);n.push(`k.contentType IN (${e})`)}}if(e.origin&&n.push(`k.origin = '${O(e.origin,`origin`)}'`),e.category&&n.push(`k.category = '${O(e.category,`category`)}'`),e.tags&&e.tags.length>0){let t=e.tags.map(e=>`k.tags LIKE '%' || '${O(e,`tag`)}' || '%'`);n.push(`(${t.join(` OR `)})`)}if(n.length===0)return``;let r=n.join(` AND `);return t?`AND ${r}`:`WHERE ${r}`}fromRow(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:D(e.tags),category:e.category||void 0,version:e.version}}};function j(e){let t=e.replace(/["'()*:^-]/g,` `).trim();return t?t.split(/\s+/).filter(e=>e.length>0).map(e=>`"${e}"`).join(` OR `):`""`}function M(e){return e==null||Number.isNaN(e)?0:1-Math.exp(-Math.abs(e)/5)}export{S as i,w as n,C as r,A as t};
@@ -205,6 +205,7 @@ they added. Protocol files (`_shared/*.md`) are fully replaced.
205
205
 
206
206
  | Mistake | Why it's wrong | What to do instead |
207
207
  |---------|---------------|-------------------|
208
+ | Editing deployed files directly (e.g. `~/.copilot/skills/`, `~/.github/agents/`) | These are **deploy targets**, not source. Changes will be overwritten on next `aikit init` or `generate.mjs` run | Always edit in `scaffold/definitions/` -> run `generate.mjs` -> then `aikit init` to deploy |
208
209
  | Editing `.agent.md` in `general/agents/` | Will be overwritten by `generate.mjs` | Edit `bodies.mjs` for agent bodies |
209
210
  | Editing `_shared/*.md` in `general/agents/` | Will be overwritten by `generate.mjs` | Edit `protocols.mjs` PROTOCOLS constant |
210
211
  | Editing flow step content in `_preview/flows/` | Will be overwritten by `generate.mjs` | Edit `definitions/flows.mjs` |
@@ -894,16 +894,7 @@ The Orchestrator uses **multi-model decision analysis** to resolve non-trivial t
894
894
 
895
895
  ### Phase 1 — Independent Research (parallel)
896
896
 
897
- Launch ALL available Researcher variants **in parallel**
898
- with the same
899
- question.Each;
900
- returns;
901
- an;
902
- independent;
903
- recommendation;
904
- grounded in their;
905
- thinking;
906
- style:
897
+ Dispatch ALL available Researcher variants **in parallel** via \`runSubagent\` — one call per variant, same question, simultaneous. Each returns an independent recommendation grounded in their thinking style:
907
898
 
908
899
  | Variant | Thinking Style | Lens |
909
900
  |---------|---------------|------|
@@ -914,18 +905,7 @@ style:
914
905
 
915
906
  ### Phase 2 — Peer Review (parallel)
916
907
 
917
- After all researchers
918
- return, **anonymize** their
919
- responses as Perspective
920
- A / B / C / D (strip agent names). Then
921
- launch;
922
- a ** second;
923
- parallel;
924
- batch ** of;
925
- 4;
926
- review;
927
- sub - agents;
928
- :
908
+ After all researchers return, **anonymize** their responses as Perspective A / B / C / D (strip agent names). Then dispatch a **second parallel batch** of 4 review sub-agents via \`runSubagent\`:
929
909
 
930
910
  **Peer Review Prompt Template:**
931
911
  \`\`\`
@@ -990,6 +970,7 @@ Trigger the decision protocol when there is an **unresolved non-trivial technica
990
970
 
991
971
  ## Key Rules
992
972
 
973
+ - **\`runSubagent\` is ALWAYS available** — it is a core tool in every environment (VS Code, CLI, Copilot Chat). NEVER claim it is unavailable. NEVER simulate researchers inline by "applying lenses yourself." If you cannot call \`runSubagent\`, you have a tool-loading issue — retry or escalate, do NOT degrade to single-agent inline simulation.
993
974
  - Always launch in **parallel**, minimum 4 variants
994
975
  - Use exact case-sensitive agent names — never rename or alias
995
976
  - **Anonymize** researcher outputs before peer review (A/B/C/D, not agent names)