@rangerchaz/aimem 0.2.0 → 0.2.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 (182) hide show
  1. package/README.md +10 -11
  2. package/dist/cli/commands/git.d.ts +0 -0
  3. package/dist/cli/commands/git.d.ts.map +0 -0
  4. package/dist/cli/commands/git.js +0 -0
  5. package/dist/cli/commands/git.js.map +0 -0
  6. package/dist/cli/commands/guardrails.d.ts.map +1 -1
  7. package/dist/cli/commands/guardrails.js +90 -1
  8. package/dist/cli/commands/guardrails.js.map +1 -1
  9. package/dist/cli/commands/import.d.ts +0 -0
  10. package/dist/cli/commands/import.d.ts.map +0 -0
  11. package/dist/cli/commands/import.js +0 -0
  12. package/dist/cli/commands/import.js.map +0 -0
  13. package/dist/cli/commands/init.d.ts +0 -0
  14. package/dist/cli/commands/init.d.ts.map +0 -0
  15. package/dist/cli/commands/init.js +0 -0
  16. package/dist/cli/commands/init.js.map +0 -0
  17. package/dist/cli/commands/mcp-serve.d.ts +0 -0
  18. package/dist/cli/commands/mcp-serve.d.ts.map +0 -0
  19. package/dist/cli/commands/mcp-serve.js +0 -0
  20. package/dist/cli/commands/mcp-serve.js.map +0 -0
  21. package/dist/cli/commands/query.d.ts +0 -0
  22. package/dist/cli/commands/query.d.ts.map +0 -0
  23. package/dist/cli/commands/query.js +0 -0
  24. package/dist/cli/commands/query.js.map +0 -0
  25. package/dist/cli/commands/reindex.js +4 -4
  26. package/dist/cli/commands/setup.d.ts +0 -0
  27. package/dist/cli/commands/setup.d.ts.map +0 -0
  28. package/dist/cli/commands/setup.js +0 -0
  29. package/dist/cli/commands/setup.js.map +0 -0
  30. package/dist/cli/commands/start.d.ts +0 -0
  31. package/dist/cli/commands/start.d.ts.map +0 -0
  32. package/dist/cli/commands/start.js +0 -0
  33. package/dist/cli/commands/start.js.map +0 -0
  34. package/dist/cli/commands/status.d.ts +0 -0
  35. package/dist/cli/commands/status.d.ts.map +0 -0
  36. package/dist/cli/commands/status.js +0 -0
  37. package/dist/cli/commands/status.js.map +0 -0
  38. package/dist/cli/commands/stop.d.ts +0 -0
  39. package/dist/cli/commands/stop.d.ts.map +0 -0
  40. package/dist/cli/commands/stop.js +0 -0
  41. package/dist/cli/commands/stop.js.map +0 -0
  42. package/dist/cli/commands/visualize.d.ts +0 -0
  43. package/dist/cli/commands/visualize.d.ts.map +0 -0
  44. package/dist/cli/commands/visualize.js +0 -0
  45. package/dist/cli/commands/visualize.js.map +0 -0
  46. package/dist/cli/index.d.ts +0 -0
  47. package/dist/cli/index.d.ts.map +0 -0
  48. package/dist/cli/index.js +0 -0
  49. package/dist/cli/index.js.map +0 -0
  50. package/dist/db/index.d.ts +16 -1
  51. package/dist/db/index.d.ts.map +1 -1
  52. package/dist/db/index.js +325 -196
  53. package/dist/db/index.js.map +1 -1
  54. package/dist/db/schema.d.ts +0 -0
  55. package/dist/db/schema.d.ts.map +1 -1
  56. package/dist/db/schema.js +247 -238
  57. package/dist/db/schema.js.map +1 -1
  58. package/dist/extractor/index.d.ts +0 -0
  59. package/dist/extractor/index.d.ts.map +0 -0
  60. package/dist/extractor/index.js +0 -0
  61. package/dist/extractor/index.js.map +0 -0
  62. package/dist/git/extractor.d.ts +0 -0
  63. package/dist/git/extractor.d.ts.map +0 -0
  64. package/dist/git/extractor.js +0 -0
  65. package/dist/git/extractor.js.map +0 -0
  66. package/dist/git/hooks.d.ts +0 -0
  67. package/dist/git/hooks.d.ts.map +0 -0
  68. package/dist/git/hooks.js +0 -0
  69. package/dist/git/hooks.js.map +0 -0
  70. package/dist/git/index.d.ts +0 -0
  71. package/dist/git/index.d.ts.map +0 -0
  72. package/dist/git/index.js +0 -0
  73. package/dist/git/index.js.map +0 -0
  74. package/dist/guardrails/enforcer.d.ts +3 -2
  75. package/dist/guardrails/enforcer.d.ts.map +1 -1
  76. package/dist/guardrails/enforcer.js +30 -3
  77. package/dist/guardrails/enforcer.js.map +1 -1
  78. package/dist/guardrails/index.d.ts +2 -0
  79. package/dist/guardrails/index.d.ts.map +1 -1
  80. package/dist/guardrails/index.js +4 -0
  81. package/dist/guardrails/index.js.map +1 -1
  82. package/dist/guardrails/vindication-checker.d.ts +24 -0
  83. package/dist/guardrails/vindication-checker.d.ts.map +1 -0
  84. package/dist/guardrails/vindication-checker.js +209 -0
  85. package/dist/guardrails/vindication-checker.js.map +1 -0
  86. package/dist/guardrails/vindication-queue.d.ts +63 -0
  87. package/dist/guardrails/vindication-queue.d.ts.map +1 -0
  88. package/dist/guardrails/vindication-queue.js +98 -0
  89. package/dist/guardrails/vindication-queue.js.map +1 -0
  90. package/dist/indexer/index.d.ts +0 -0
  91. package/dist/indexer/index.d.ts.map +0 -0
  92. package/dist/indexer/index.js +0 -0
  93. package/dist/indexer/index.js.map +0 -0
  94. package/dist/indexer/parsers/base.d.ts +0 -0
  95. package/dist/indexer/parsers/base.d.ts.map +0 -0
  96. package/dist/indexer/parsers/base.js +0 -0
  97. package/dist/indexer/parsers/base.js.map +0 -0
  98. package/dist/indexer/parsers/cpp.d.ts +0 -0
  99. package/dist/indexer/parsers/cpp.d.ts.map +0 -0
  100. package/dist/indexer/parsers/cpp.js +0 -0
  101. package/dist/indexer/parsers/cpp.js.map +0 -0
  102. package/dist/indexer/parsers/go.d.ts +0 -0
  103. package/dist/indexer/parsers/go.d.ts.map +0 -0
  104. package/dist/indexer/parsers/go.js +0 -0
  105. package/dist/indexer/parsers/go.js.map +0 -0
  106. package/dist/indexer/parsers/java.d.ts +0 -0
  107. package/dist/indexer/parsers/java.d.ts.map +0 -0
  108. package/dist/indexer/parsers/java.js +0 -0
  109. package/dist/indexer/parsers/java.js.map +0 -0
  110. package/dist/indexer/parsers/javascript.d.ts +0 -0
  111. package/dist/indexer/parsers/javascript.d.ts.map +0 -0
  112. package/dist/indexer/parsers/javascript.js +0 -0
  113. package/dist/indexer/parsers/javascript.js.map +0 -0
  114. package/dist/indexer/parsers/kotlin.d.ts +0 -0
  115. package/dist/indexer/parsers/kotlin.d.ts.map +0 -0
  116. package/dist/indexer/parsers/kotlin.js +0 -0
  117. package/dist/indexer/parsers/kotlin.js.map +0 -0
  118. package/dist/indexer/parsers/php.d.ts +0 -0
  119. package/dist/indexer/parsers/php.d.ts.map +0 -0
  120. package/dist/indexer/parsers/php.js +0 -0
  121. package/dist/indexer/parsers/php.js.map +0 -0
  122. package/dist/indexer/parsers/python.d.ts +0 -0
  123. package/dist/indexer/parsers/python.d.ts.map +0 -0
  124. package/dist/indexer/parsers/python.js +0 -0
  125. package/dist/indexer/parsers/python.js.map +0 -0
  126. package/dist/indexer/parsers/ruby.d.ts +0 -0
  127. package/dist/indexer/parsers/ruby.d.ts.map +0 -0
  128. package/dist/indexer/parsers/ruby.js +0 -0
  129. package/dist/indexer/parsers/ruby.js.map +0 -0
  130. package/dist/indexer/parsers/rust.d.ts +0 -0
  131. package/dist/indexer/parsers/rust.d.ts.map +0 -0
  132. package/dist/indexer/parsers/rust.js +0 -0
  133. package/dist/indexer/parsers/rust.js.map +0 -0
  134. package/dist/indexer/watcher-daemon.d.ts +0 -0
  135. package/dist/indexer/watcher-daemon.d.ts.map +0 -0
  136. package/dist/indexer/watcher-daemon.js +10 -0
  137. package/dist/indexer/watcher-daemon.js.map +1 -1
  138. package/dist/indexer/watcher.d.ts +2 -0
  139. package/dist/indexer/watcher.d.ts.map +1 -1
  140. package/dist/indexer/watcher.js +8 -0
  141. package/dist/indexer/watcher.js.map +1 -1
  142. package/dist/mcp/server.d.ts +0 -0
  143. package/dist/mcp/server.d.ts.map +1 -1
  144. package/dist/mcp/server.js +176 -274
  145. package/dist/mcp/server.js.map +1 -1
  146. package/dist/proxy/interceptor-mockttp.d.ts +0 -0
  147. package/dist/proxy/interceptor-mockttp.d.ts.map +1 -1
  148. package/dist/proxy/interceptor-mockttp.js +4 -2
  149. package/dist/proxy/interceptor-mockttp.js.map +1 -1
  150. package/dist/proxy/proxy-daemon.d.ts +0 -0
  151. package/dist/proxy/proxy-daemon.d.ts.map +0 -0
  152. package/dist/proxy/proxy-daemon.js +0 -0
  153. package/dist/proxy/proxy-daemon.js.map +0 -0
  154. package/dist/query/index.d.ts +0 -0
  155. package/dist/query/index.d.ts.map +0 -0
  156. package/dist/query/index.js +0 -0
  157. package/dist/query/index.js.map +0 -0
  158. package/dist/types/index.d.ts +38 -0
  159. package/dist/types/index.d.ts.map +1 -1
  160. package/dist/types/index.js +0 -0
  161. package/dist/types/index.js.map +0 -0
  162. package/dist/visualize/index.d.ts +0 -0
  163. package/dist/visualize/index.d.ts.map +0 -0
  164. package/dist/visualize/index.js +0 -0
  165. package/dist/visualize/index.js.map +0 -0
  166. package/dist/visualize/server.d.ts +0 -0
  167. package/dist/visualize/server.d.ts.map +0 -0
  168. package/dist/visualize/server.js +0 -0
  169. package/dist/visualize/server.js.map +0 -0
  170. package/dist/visualize/template.d.ts +0 -0
  171. package/dist/visualize/template.d.ts.map +0 -0
  172. package/dist/visualize/template.js +0 -0
  173. package/dist/visualize/template.js.map +0 -0
  174. package/package.json +16 -5
  175. package/dist/cli/commands/hook-session-end.d.ts +0 -7
  176. package/dist/cli/commands/hook-session-end.d.ts.map +0 -1
  177. package/dist/cli/commands/hook-session-end.js +0 -109
  178. package/dist/cli/commands/hook-session-end.js.map +0 -1
  179. package/dist/cli/commands/hook-session-start.d.ts +0 -7
  180. package/dist/cli/commands/hook-session-start.d.ts.map +0 -1
  181. package/dist/cli/commands/hook-session-start.js +0 -116
  182. package/dist/cli/commands/hook-session-start.js.map +0 -1
package/dist/db/index.js CHANGED
@@ -71,13 +71,13 @@ export function getAllProjects() {
71
71
  // File operations
72
72
  export function upsertFile(projectId, path, hash) {
73
73
  const db = getDb();
74
- const stmt = db.prepare(`
75
- INSERT INTO files (project_id, path, hash, last_indexed)
76
- VALUES (?, ?, ?, datetime('now'))
77
- ON CONFLICT(project_id, path) DO UPDATE SET
78
- hash = excluded.hash,
79
- last_indexed = datetime('now')
80
- RETURNING *
74
+ const stmt = db.prepare(`
75
+ INSERT INTO files (project_id, path, hash, last_indexed)
76
+ VALUES (?, ?, ?, datetime('now'))
77
+ ON CONFLICT(project_id, path) DO UPDATE SET
78
+ hash = excluded.hash,
79
+ last_indexed = datetime('now')
80
+ RETURNING *
81
81
  `);
82
82
  return stmt.get(projectId, path, hash);
83
83
  }
@@ -100,10 +100,10 @@ export function getProjectFiles(projectId) {
100
100
  // Structure operations
101
101
  export function insertStructure(fileId, type, name, lineStart, lineEnd, signature, rawContent, metadata = {}) {
102
102
  const db = getDb();
103
- const stmt = db.prepare(`
104
- INSERT INTO structures (file_id, type, name, line_start, line_end, signature, raw_content, metadata)
105
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
106
- RETURNING *
103
+ const stmt = db.prepare(`
104
+ INSERT INTO structures (file_id, type, name, line_start, line_end, signature, raw_content, metadata)
105
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
106
+ RETURNING *
107
107
  `);
108
108
  return stmt.get(fileId, type, name, lineStart, lineEnd, signature, rawContent, JSON.stringify(metadata));
109
109
  }
@@ -114,30 +114,30 @@ export function deleteFileStructures(fileId) {
114
114
  export function searchStructures(query, limit = 20, projectId) {
115
115
  const db = getDb();
116
116
  if (projectId) {
117
- return db.prepare(`
118
- SELECT s.* FROM structures s
119
- JOIN structures_fts fts ON s.id = fts.rowid
120
- JOIN files f ON s.file_id = f.id
121
- WHERE structures_fts MATCH ? AND f.project_id = ?
122
- ORDER BY rank
123
- LIMIT ?
117
+ return db.prepare(`
118
+ SELECT s.* FROM structures s
119
+ JOIN structures_fts fts ON s.id = fts.rowid
120
+ JOIN files f ON s.file_id = f.id
121
+ WHERE structures_fts MATCH ? AND f.project_id = ?
122
+ ORDER BY rank
123
+ LIMIT ?
124
124
  `).all(query, projectId, limit);
125
125
  }
126
- return db.prepare(`
127
- SELECT s.* FROM structures s
128
- JOIN structures_fts fts ON s.id = fts.rowid
129
- WHERE structures_fts MATCH ?
130
- ORDER BY rank
131
- LIMIT ?
126
+ return db.prepare(`
127
+ SELECT s.* FROM structures s
128
+ JOIN structures_fts fts ON s.id = fts.rowid
129
+ WHERE structures_fts MATCH ?
130
+ ORDER BY rank
131
+ LIMIT ?
132
132
  `).all(query, limit);
133
133
  }
134
134
  export function getStructuresByName(name, projectId) {
135
135
  const db = getDb();
136
136
  if (projectId) {
137
- return db.prepare(`
138
- SELECT s.* FROM structures s
139
- JOIN files f ON s.file_id = f.id
140
- WHERE s.name = ? AND f.project_id = ?
137
+ return db.prepare(`
138
+ SELECT s.* FROM structures s
139
+ JOIN files f ON s.file_id = f.id
140
+ WHERE s.name = ? AND f.project_id = ?
141
141
  `).all(name, projectId);
142
142
  }
143
143
  return db.prepare('SELECT * FROM structures WHERE name = ?').all(name);
@@ -157,39 +157,39 @@ export function findProjectForPath(targetPath) {
157
157
  // Conversation operations
158
158
  export function insertConversation(rawContent, projectId = null, model = null, tool = null, summary = null) {
159
159
  const db = getDb();
160
- const stmt = db.prepare(`
161
- INSERT INTO conversations (project_id, model, tool, summary, raw_content)
162
- VALUES (?, ?, ?, ?, ?)
163
- RETURNING *
160
+ const stmt = db.prepare(`
161
+ INSERT INTO conversations (project_id, model, tool, summary, raw_content)
162
+ VALUES (?, ?, ?, ?, ?)
163
+ RETURNING *
164
164
  `);
165
165
  return stmt.get(projectId, model, tool, summary, rawContent);
166
166
  }
167
167
  export function searchConversations(query, limit = 20, projectId) {
168
168
  const db = getDb();
169
169
  if (projectId) {
170
- return db.prepare(`
171
- SELECT c.* FROM conversations c
172
- JOIN conversations_fts fts ON c.id = fts.rowid
173
- WHERE conversations_fts MATCH ? AND c.project_id = ?
174
- ORDER BY rank
175
- LIMIT ?
170
+ return db.prepare(`
171
+ SELECT c.* FROM conversations c
172
+ JOIN conversations_fts fts ON c.id = fts.rowid
173
+ WHERE conversations_fts MATCH ? AND c.project_id = ?
174
+ ORDER BY rank
175
+ LIMIT ?
176
176
  `).all(query, projectId, limit);
177
177
  }
178
- return db.prepare(`
179
- SELECT c.* FROM conversations c
180
- JOIN conversations_fts fts ON c.id = fts.rowid
181
- WHERE conversations_fts MATCH ?
182
- ORDER BY rank
183
- LIMIT ?
178
+ return db.prepare(`
179
+ SELECT c.* FROM conversations c
180
+ JOIN conversations_fts fts ON c.id = fts.rowid
181
+ WHERE conversations_fts MATCH ?
182
+ ORDER BY rank
183
+ LIMIT ?
184
184
  `).all(query, limit);
185
185
  }
186
186
  // Link operations
187
187
  export function createLink(sourceType, sourceId, targetType, targetId, linkType) {
188
188
  const db = getDb();
189
- const stmt = db.prepare(`
190
- INSERT OR IGNORE INTO links (source_type, source_id, target_type, target_id, link_type)
191
- VALUES (?, ?, ?, ?, ?)
192
- RETURNING *
189
+ const stmt = db.prepare(`
190
+ INSERT OR IGNORE INTO links (source_type, source_id, target_type, target_id, link_type)
191
+ VALUES (?, ?, ?, ?, ?)
192
+ RETURNING *
193
193
  `);
194
194
  return stmt.get(sourceType, sourceId, targetType, targetId, linkType);
195
195
  }
@@ -204,10 +204,10 @@ export function getLinksTo(targetType, targetId) {
204
204
  // Extraction operations
205
205
  export function insertExtraction(conversationId, type, content, metadata = {}) {
206
206
  const db = getDb();
207
- const stmt = db.prepare(`
208
- INSERT INTO extractions (conversation_id, type, content, metadata)
209
- VALUES (?, ?, ?, ?)
210
- RETURNING *
207
+ const stmt = db.prepare(`
208
+ INSERT INTO extractions (conversation_id, type, content, metadata)
209
+ VALUES (?, ?, ?, ?)
210
+ RETURNING *
211
211
  `);
212
212
  return stmt.get(conversationId, type, content, JSON.stringify(metadata));
213
213
  }
@@ -223,30 +223,30 @@ export function searchExtractions(query, limit = 20, projectId) {
223
223
  const db = getDb();
224
224
  const searchTerm = `%${query}%`;
225
225
  if (projectId) {
226
- return db.prepare(`
227
- SELECT e.* FROM extractions e
228
- JOIN conversations c ON e.conversation_id = c.id
229
- WHERE e.content LIKE ? AND c.project_id = ?
230
- ORDER BY e.id DESC
231
- LIMIT ?
226
+ return db.prepare(`
227
+ SELECT e.* FROM extractions e
228
+ JOIN conversations c ON e.conversation_id = c.id
229
+ WHERE e.content LIKE ? AND c.project_id = ?
230
+ ORDER BY e.id DESC
231
+ LIMIT ?
232
232
  `).all(searchTerm, projectId, limit);
233
233
  }
234
- return db.prepare(`
235
- SELECT * FROM extractions
236
- WHERE content LIKE ?
237
- ORDER BY id DESC
238
- LIMIT ?
234
+ return db.prepare(`
235
+ SELECT * FROM extractions
236
+ WHERE content LIKE ?
237
+ ORDER BY id DESC
238
+ LIMIT ?
239
239
  `).all(searchTerm, limit);
240
240
  }
241
241
  export function isDuplicateExtraction(content, projectId, windowSeconds = 300) {
242
242
  const db = getDb();
243
243
  // Check for duplicate extraction content within the last N seconds
244
- const stmt = db.prepare(`
245
- SELECT COUNT(*) as count FROM extractions e
246
- JOIN conversations c ON e.conversation_id = c.id
247
- WHERE e.content = ?
248
- AND (c.project_id = ? OR (c.project_id IS NULL AND ? IS NULL))
249
- AND datetime(c.timestamp) > datetime('now', '-' || ? || ' seconds')
244
+ const stmt = db.prepare(`
245
+ SELECT COUNT(*) as count FROM extractions e
246
+ JOIN conversations c ON e.conversation_id = c.id
247
+ WHERE e.content = ?
248
+ AND (c.project_id = ? OR (c.project_id IS NULL AND ? IS NULL))
249
+ AND datetime(c.timestamp) > datetime('now', '-' || ? || ' seconds')
250
250
  `);
251
251
  const result = stmt.get(content.trim(), projectId, projectId, windowSeconds);
252
252
  return result.count > 0;
@@ -280,97 +280,97 @@ export function getConversationById(id) {
280
280
  // Get full conversations for a project (for long-term memory)
281
281
  export function getFullConversations(projectId, limit = 50, offset = 0) {
282
282
  const db = getDb();
283
- return db.prepare(`
284
- SELECT * FROM conversations
285
- WHERE project_id = ?
286
- ORDER BY timestamp DESC
287
- LIMIT ? OFFSET ?
283
+ return db.prepare(`
284
+ SELECT * FROM conversations
285
+ WHERE project_id = ?
286
+ ORDER BY timestamp DESC
287
+ LIMIT ? OFFSET ?
288
288
  `).all(projectId, limit, offset);
289
289
  }
290
290
  // Get recent conversations (optionally scoped to project)
291
291
  export function getRecentConversations(limit = 10, projectId) {
292
292
  const db = getDb();
293
293
  if (projectId) {
294
- return db.prepare(`
295
- SELECT * FROM conversations
296
- WHERE project_id = ?
297
- ORDER BY timestamp DESC
298
- LIMIT ?
294
+ return db.prepare(`
295
+ SELECT * FROM conversations
296
+ WHERE project_id = ?
297
+ ORDER BY timestamp DESC
298
+ LIMIT ?
299
299
  `).all(projectId, limit);
300
300
  }
301
- return db.prepare(`
302
- SELECT * FROM conversations
303
- ORDER BY timestamp DESC
304
- LIMIT ?
301
+ return db.prepare(`
302
+ SELECT * FROM conversations
303
+ ORDER BY timestamp DESC
304
+ LIMIT ?
305
305
  `).all(limit);
306
306
  }
307
307
  // Search conversations and return full content
308
308
  export function searchFullConversations(query, limit = 20, projectId) {
309
309
  const db = getDb();
310
310
  if (projectId) {
311
- return db.prepare(`
312
- SELECT c.* FROM conversations c
313
- JOIN conversations_fts fts ON c.id = fts.rowid
314
- WHERE conversations_fts MATCH ? AND c.project_id = ?
315
- ORDER BY rank
316
- LIMIT ?
311
+ return db.prepare(`
312
+ SELECT c.* FROM conversations c
313
+ JOIN conversations_fts fts ON c.id = fts.rowid
314
+ WHERE conversations_fts MATCH ? AND c.project_id = ?
315
+ ORDER BY rank
316
+ LIMIT ?
317
317
  `).all(query, projectId, limit);
318
318
  }
319
- return db.prepare(`
320
- SELECT c.* FROM conversations c
321
- JOIN conversations_fts fts ON c.id = fts.rowid
322
- WHERE conversations_fts MATCH ?
323
- ORDER BY rank
324
- LIMIT ?
319
+ return db.prepare(`
320
+ SELECT c.* FROM conversations c
321
+ JOIN conversations_fts fts ON c.id = fts.rowid
322
+ WHERE conversations_fts MATCH ?
323
+ ORDER BY rank
324
+ LIMIT ?
325
325
  `).all(query, limit);
326
326
  }
327
327
  // Get all structures for a project with file paths
328
328
  export function getAllProjectStructures(projectId) {
329
329
  const db = getDb();
330
- return db.prepare(`
331
- SELECT s.*, f.path as file_path
332
- FROM structures s
333
- JOIN files f ON s.file_id = f.id
334
- WHERE f.project_id = ?
335
- ORDER BY f.path, s.line_start
330
+ return db.prepare(`
331
+ SELECT s.*, f.path as file_path
332
+ FROM structures s
333
+ JOIN files f ON s.file_id = f.id
334
+ WHERE f.project_id = ?
335
+ ORDER BY f.path, s.line_start
336
336
  `).all(projectId);
337
337
  }
338
338
  // Get all links for a project
339
339
  export function getAllProjectLinks(projectId) {
340
340
  const db = getDb();
341
- return db.prepare(`
342
- SELECT DISTINCT l.* FROM links l
343
- LEFT JOIN structures s ON l.source_type = 'structure' AND l.source_id = s.id
344
- LEFT JOIN files f ON s.file_id = f.id
345
- LEFT JOIN conversations c ON l.source_type = 'conversation' AND l.source_id = c.id
346
- WHERE f.project_id = ? OR c.project_id = ?
341
+ return db.prepare(`
342
+ SELECT DISTINCT l.* FROM links l
343
+ LEFT JOIN structures s ON l.source_type = 'structure' AND l.source_id = s.id
344
+ LEFT JOIN files f ON s.file_id = f.id
345
+ LEFT JOIN conversations c ON l.source_type = 'conversation' AND l.source_id = c.id
346
+ WHERE f.project_id = ? OR c.project_id = ?
347
347
  `).all(projectId, projectId);
348
348
  }
349
349
  // Get all extractions for a project
350
350
  export function getAllProjectExtractions(projectId) {
351
351
  const db = getDb();
352
- return db.prepare(`
353
- SELECT e.* FROM extractions e
354
- JOIN conversations c ON e.conversation_id = c.id
355
- WHERE c.project_id = ?
356
- ORDER BY c.timestamp DESC
352
+ return db.prepare(`
353
+ SELECT e.* FROM extractions e
354
+ JOIN conversations c ON e.conversation_id = c.id
355
+ WHERE c.project_id = ?
356
+ ORDER BY c.timestamp DESC
357
357
  `).all(projectId);
358
358
  }
359
359
  // ============ Git Operations ============
360
360
  // Commit operations
361
361
  export function upsertCommit(projectId, hash, shortHash, authorName, authorEmail, timestamp, subject, body, parentHashes = []) {
362
362
  const db = getDb();
363
- const stmt = db.prepare(`
364
- INSERT INTO commits (project_id, hash, short_hash, author_name, author_email, timestamp, subject, body, parent_hashes)
365
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
366
- ON CONFLICT(project_id, hash) DO UPDATE SET
367
- short_hash = excluded.short_hash,
368
- author_name = excluded.author_name,
369
- author_email = excluded.author_email,
370
- subject = excluded.subject,
371
- body = excluded.body,
372
- parent_hashes = excluded.parent_hashes
373
- RETURNING *
363
+ const stmt = db.prepare(`
364
+ INSERT INTO commits (project_id, hash, short_hash, author_name, author_email, timestamp, subject, body, parent_hashes)
365
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
366
+ ON CONFLICT(project_id, hash) DO UPDATE SET
367
+ short_hash = excluded.short_hash,
368
+ author_name = excluded.author_name,
369
+ author_email = excluded.author_email,
370
+ subject = excluded.subject,
371
+ body = excluded.body,
372
+ parent_hashes = excluded.parent_hashes
373
+ RETURNING *
374
374
  `);
375
375
  return stmt.get(projectId, hash, shortHash, authorName, authorEmail, timestamp, subject, body, JSON.stringify(parentHashes));
376
376
  }
@@ -385,36 +385,36 @@ export function getCommitById(id) {
385
385
  export function searchCommits(query, limit = 20, projectId) {
386
386
  const db = getDb();
387
387
  if (projectId) {
388
- return db.prepare(`
389
- SELECT c.* FROM commits c
390
- JOIN commits_fts fts ON c.id = fts.rowid
391
- WHERE commits_fts MATCH ? AND c.project_id = ?
392
- ORDER BY rank
393
- LIMIT ?
388
+ return db.prepare(`
389
+ SELECT c.* FROM commits c
390
+ JOIN commits_fts fts ON c.id = fts.rowid
391
+ WHERE commits_fts MATCH ? AND c.project_id = ?
392
+ ORDER BY rank
393
+ LIMIT ?
394
394
  `).all(query, projectId, limit);
395
395
  }
396
- return db.prepare(`
397
- SELECT c.* FROM commits c
398
- JOIN commits_fts fts ON c.id = fts.rowid
399
- WHERE commits_fts MATCH ?
400
- ORDER BY rank
401
- LIMIT ?
396
+ return db.prepare(`
397
+ SELECT c.* FROM commits c
398
+ JOIN commits_fts fts ON c.id = fts.rowid
399
+ WHERE commits_fts MATCH ?
400
+ ORDER BY rank
401
+ LIMIT ?
402
402
  `).all(query, limit);
403
403
  }
404
404
  export function getRecentCommits(projectId, limit = 50) {
405
405
  const db = getDb();
406
- return db.prepare(`
407
- SELECT * FROM commits WHERE project_id = ?
408
- ORDER BY timestamp DESC LIMIT ?
406
+ return db.prepare(`
407
+ SELECT * FROM commits WHERE project_id = ?
408
+ ORDER BY timestamp DESC LIMIT ?
409
409
  `).all(projectId, limit);
410
410
  }
411
411
  // Commit link operations
412
412
  export function createCommitLink(commitId, targetType, targetId, linkType) {
413
413
  const db = getDb();
414
- const stmt = db.prepare(`
415
- INSERT OR IGNORE INTO commit_links (commit_id, target_type, target_id, link_type)
416
- VALUES (?, ?, ?, ?)
417
- RETURNING *
414
+ const stmt = db.prepare(`
415
+ INSERT OR IGNORE INTO commit_links (commit_id, target_type, target_id, link_type)
416
+ VALUES (?, ?, ?, ?)
417
+ RETURNING *
418
418
  `);
419
419
  return stmt.get(commitId, targetType, targetId, linkType);
420
420
  }
@@ -428,31 +428,31 @@ export function getLinksToCommit(targetType, targetId) {
428
428
  }
429
429
  export function getCommitsForStructure(structureId) {
430
430
  const db = getDb();
431
- return db.prepare(`
432
- SELECT c.* FROM commits c
433
- JOIN commit_links cl ON c.id = cl.commit_id
434
- WHERE cl.target_type = 'structure' AND cl.target_id = ?
435
- ORDER BY c.timestamp DESC
431
+ return db.prepare(`
432
+ SELECT c.* FROM commits c
433
+ JOIN commit_links cl ON c.id = cl.commit_id
434
+ WHERE cl.target_type = 'structure' AND cl.target_id = ?
435
+ ORDER BY c.timestamp DESC
436
436
  `).all(structureId);
437
437
  }
438
438
  export function getCommitsForExtraction(extractionId) {
439
439
  const db = getDb();
440
- return db.prepare(`
441
- SELECT c.* FROM commits c
442
- JOIN commit_links cl ON c.id = cl.commit_id
443
- WHERE cl.target_type = 'extraction' AND cl.target_id = ?
444
- ORDER BY c.timestamp DESC
440
+ return db.prepare(`
441
+ SELECT c.* FROM commits c
442
+ JOIN commit_links cl ON c.id = cl.commit_id
443
+ WHERE cl.target_type = 'extraction' AND cl.target_id = ?
444
+ ORDER BY c.timestamp DESC
445
445
  `).all(extractionId);
446
446
  }
447
447
  // Update structure authorship
448
448
  export function updateStructureAuthorship(structureId, author, authorEmail, commitHash) {
449
449
  const db = getDb();
450
- db.prepare(`
451
- UPDATE structures SET
452
- last_author = ?,
453
- last_author_email = ?,
454
- last_commit_hash = ?
455
- WHERE id = ?
450
+ db.prepare(`
451
+ UPDATE structures SET
452
+ last_author = ?,
453
+ last_author_email = ?,
454
+ last_commit_hash = ?
455
+ WHERE id = ?
456
456
  `).run(author, authorEmail, commitHash, structureId);
457
457
  }
458
458
  // Get uncommitted decisions (extractions created since last commit)
@@ -460,38 +460,38 @@ export function getUncommittedExtractions(projectId, sinceCommitHash) {
460
460
  const db = getDb();
461
461
  if (sinceCommitHash) {
462
462
  // Get extractions created after the specified commit's timestamp
463
- return db.prepare(`
464
- SELECT e.* FROM extractions e
465
- JOIN conversations c ON e.conversation_id = c.id
466
- WHERE c.project_id = ?
467
- AND c.timestamp > (
468
- SELECT timestamp FROM commits WHERE project_id = ? AND hash = ?
469
- )
470
- AND e.id NOT IN (
471
- SELECT target_id FROM commit_links WHERE target_type = 'extraction'
472
- )
473
- ORDER BY c.timestamp DESC
463
+ return db.prepare(`
464
+ SELECT e.* FROM extractions e
465
+ JOIN conversations c ON e.conversation_id = c.id
466
+ WHERE c.project_id = ?
467
+ AND c.timestamp > (
468
+ SELECT timestamp FROM commits WHERE project_id = ? AND hash = ?
469
+ )
470
+ AND e.id NOT IN (
471
+ SELECT target_id FROM commit_links WHERE target_type = 'extraction'
472
+ )
473
+ ORDER BY c.timestamp DESC
474
474
  `).all(projectId, projectId, sinceCommitHash);
475
475
  }
476
476
  // Get all extractions not linked to any commit
477
- return db.prepare(`
478
- SELECT e.* FROM extractions e
479
- JOIN conversations c ON e.conversation_id = c.id
480
- WHERE c.project_id = ?
481
- AND e.id NOT IN (
482
- SELECT target_id FROM commit_links WHERE target_type = 'extraction'
483
- )
484
- ORDER BY c.timestamp DESC
477
+ return db.prepare(`
478
+ SELECT e.* FROM extractions e
479
+ JOIN conversations c ON e.conversation_id = c.id
480
+ WHERE c.project_id = ?
481
+ AND e.id NOT IN (
482
+ SELECT target_id FROM commit_links WHERE target_type = 'extraction'
483
+ )
484
+ ORDER BY c.timestamp DESC
485
485
  `).all(projectId);
486
486
  }
487
487
  // ============ Guardrails Operations (DIK) ============
488
488
  // Guardrail CRUD
489
489
  export function insertGuardrail(projectId, category, rule, rationale = null, severity = 'warn', source = 'explicit', sourceFile = null) {
490
490
  const db = getDb();
491
- const stmt = db.prepare(`
492
- INSERT INTO guardrails (project_id, category, rule, rationale, severity, source, source_file)
493
- VALUES (?, ?, ?, ?, ?, ?, ?)
494
- RETURNING *
491
+ const stmt = db.prepare(`
492
+ INSERT INTO guardrails (project_id, category, rule, rationale, severity, source, source_file)
493
+ VALUES (?, ?, ?, ?, ?, ?, ?)
494
+ RETURNING *
495
495
  `);
496
496
  return stmt.get(projectId, category, rule, rationale, severity, source, sourceFile);
497
497
  }
@@ -535,10 +535,10 @@ export function deleteGuardrail(id) {
535
535
  // Guardrail events
536
536
  export function insertGuardrailEvent(guardrailId, eventType, context = null, response = null, dikLevel = null) {
537
537
  const db = getDb();
538
- const stmt = db.prepare(`
539
- INSERT INTO guardrail_events (guardrail_id, event_type, context, response, dik_level)
540
- VALUES (?, ?, ?, ?, ?)
541
- RETURNING *
538
+ const stmt = db.prepare(`
539
+ INSERT INTO guardrail_events (guardrail_id, event_type, context, response, dik_level)
540
+ VALUES (?, ?, ?, ?, ?)
541
+ RETURNING *
542
542
  `);
543
543
  return stmt.get(guardrailId, eventType, context, response, dikLevel);
544
544
  }
@@ -552,11 +552,11 @@ export function getGuardrailEvent(id) {
552
552
  }
553
553
  export function getOverrideEvents(projectId) {
554
554
  const db = getDb();
555
- return db.prepare(`
556
- SELECT e.* FROM guardrail_events e
557
- JOIN guardrails g ON e.guardrail_id = g.id
558
- WHERE g.project_id = ? AND e.event_type = 'overridden'
559
- ORDER BY e.timestamp DESC
555
+ return db.prepare(`
556
+ SELECT e.* FROM guardrail_events e
557
+ JOIN guardrails g ON e.guardrail_id = g.id
558
+ WHERE g.project_id = ? AND e.event_type = 'overridden'
559
+ ORDER BY e.timestamp DESC
560
560
  `).all(projectId);
561
561
  }
562
562
  // Project DIK
@@ -564,8 +564,8 @@ export function getOrCreateProjectDik(projectId) {
564
564
  const db = getDb();
565
565
  let dik = db.prepare('SELECT * FROM project_dik WHERE project_id = ?').get(projectId);
566
566
  if (!dik) {
567
- dik = db.prepare(`
568
- INSERT INTO project_dik (project_id) VALUES (?) RETURNING *
567
+ dik = db.prepare(`
568
+ INSERT INTO project_dik (project_id) VALUES (?) RETURNING *
569
569
  `).get(projectId);
570
570
  }
571
571
  return dik;
@@ -613,10 +613,10 @@ export function incrementDikCounter(projectId, counter) {
613
613
  // Get guardrail history for a specific rule (for response generation)
614
614
  export function getGuardrailHistory(guardrailId) {
615
615
  const db = getDb();
616
- const events = db.prepare(`
617
- SELECT event_type, COUNT(*) as count FROM guardrail_events
618
- WHERE guardrail_id = ?
619
- GROUP BY event_type
616
+ const events = db.prepare(`
617
+ SELECT event_type, COUNT(*) as count FROM guardrail_events
618
+ WHERE guardrail_id = ?
619
+ GROUP BY event_type
620
620
  `).all(guardrailId);
621
621
  let overrides = 0;
622
622
  let vindicated = false;
@@ -656,4 +656,133 @@ export function isDikManuallySet(projectId) {
656
656
  // If level is non-default but stats are zero, it's manually set
657
657
  return dik.level !== 2 && dik.rules_confirmed === 0 && dik.corrections_made === 0 && dik.overrides_regretted === 0 && dik.conversations === 0;
658
658
  }
659
+ // ============ Vindication Operations ============
660
+ // Insert guardrail event with vindication context (enhanced version)
661
+ export function insertGuardrailEventWithContext(guardrailId, eventType, context = null, response = null, dikLevel = null, vindicationContext) {
662
+ const db = getDb();
663
+ if (vindicationContext && eventType === 'overridden') {
664
+ const stmt = db.prepare(`
665
+ INSERT INTO guardrail_events (
666
+ guardrail_id, event_type, context, response, dik_level,
667
+ suggestion, code_context, file_path, line_start, line_end, content_hash, vindication_pending
668
+ )
669
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)
670
+ RETURNING *
671
+ `);
672
+ return stmt.get(guardrailId, eventType, context, response, dikLevel, vindicationContext.suggestion || null, vindicationContext.codeContext || null, vindicationContext.filePath || null, vindicationContext.lineStart || null, vindicationContext.lineEnd || null, vindicationContext.contentHash || null);
673
+ }
674
+ // Fall back to regular insert for non-override events
675
+ return insertGuardrailEvent(guardrailId, eventType, context, response, dikLevel);
676
+ }
677
+ // Get pending vindications for a project
678
+ export function getPendingVindications(projectId) {
679
+ const db = getDb();
680
+ const rows = db.prepare(`
681
+ SELECT
682
+ e.id as eventId,
683
+ e.guardrail_id as guardrailId,
684
+ g.project_id as projectId,
685
+ e.suggestion,
686
+ e.file_path as filePath,
687
+ e.line_start as lineStart,
688
+ e.line_end as lineEnd,
689
+ e.code_context as originalCode,
690
+ e.content_hash as contentHash,
691
+ e.context as reason,
692
+ e.timestamp
693
+ FROM guardrail_events e
694
+ JOIN guardrails g ON e.guardrail_id = g.id
695
+ WHERE g.project_id = ?
696
+ AND e.event_type = 'overridden'
697
+ AND e.vindication_pending = 1
698
+ AND e.suggestion IS NOT NULL
699
+ AND e.file_path IS NOT NULL
700
+ ORDER BY e.timestamp DESC
701
+ `).all(projectId);
702
+ return rows;
703
+ }
704
+ // Get pending vindications for specific files
705
+ export function getPendingVindicationsForFile(projectId, filePath) {
706
+ const db = getDb();
707
+ const rows = db.prepare(`
708
+ SELECT
709
+ e.id as eventId,
710
+ e.guardrail_id as guardrailId,
711
+ g.project_id as projectId,
712
+ e.suggestion,
713
+ e.file_path as filePath,
714
+ e.line_start as lineStart,
715
+ e.line_end as lineEnd,
716
+ e.code_context as originalCode,
717
+ e.content_hash as contentHash,
718
+ e.context as reason,
719
+ e.timestamp
720
+ FROM guardrail_events e
721
+ JOIN guardrails g ON e.guardrail_id = g.id
722
+ WHERE g.project_id = ?
723
+ AND e.file_path = ?
724
+ AND e.event_type = 'overridden'
725
+ AND e.vindication_pending = 1
726
+ AND e.suggestion IS NOT NULL
727
+ ORDER BY e.timestamp DESC
728
+ `).all(projectId, filePath);
729
+ return rows;
730
+ }
731
+ // Mark a vindication as checked (not vindicated)
732
+ export function markVindicationChecked(eventId) {
733
+ const db = getDb();
734
+ db.prepare(`
735
+ UPDATE guardrail_events
736
+ SET vindication_pending = 0, checked_at = datetime('now')
737
+ WHERE id = ?
738
+ `).run(eventId);
739
+ }
740
+ // Mark a vindication as complete (vindicated)
741
+ export function markVindicated(eventId) {
742
+ const db = getDb();
743
+ db.prepare(`
744
+ UPDATE guardrail_events
745
+ SET vindication_pending = 0, checked_at = datetime('now')
746
+ WHERE id = ?
747
+ `).run(eventId);
748
+ }
749
+ // Expire old pending vindications
750
+ export function expireOldVindications(projectId, maxAgeDays = 30) {
751
+ const db = getDb();
752
+ const result = db.prepare(`
753
+ UPDATE guardrail_events
754
+ SET vindication_pending = 0, checked_at = datetime('now')
755
+ WHERE id IN (
756
+ SELECT e.id FROM guardrail_events e
757
+ JOIN guardrails g ON e.guardrail_id = g.id
758
+ WHERE g.project_id = ?
759
+ AND e.vindication_pending = 1
760
+ AND datetime(e.timestamp) < datetime('now', '-' || ? || ' days')
761
+ )
762
+ `).run(projectId, maxAgeDays);
763
+ return result.changes;
764
+ }
765
+ // Get all vindicated events for a project (for CLI display)
766
+ export function getVindicatedEvents(projectId) {
767
+ const db = getDb();
768
+ return db.prepare(`
769
+ SELECT e.* FROM guardrail_events e
770
+ JOIN guardrails g ON e.guardrail_id = g.id
771
+ WHERE g.project_id = ? AND e.event_type = 'vindicated'
772
+ ORDER BY e.timestamp DESC
773
+ `).all(projectId);
774
+ }
775
+ export function getOverrideEventsWithRules(projectId, pendingOnly = false) {
776
+ const db = getDb();
777
+ let sql = `
778
+ SELECT e.*, g.rule, g.category FROM guardrail_events e
779
+ JOIN guardrails g ON e.guardrail_id = g.id
780
+ WHERE g.project_id = ? AND e.event_type = 'overridden'
781
+ `;
782
+ if (pendingOnly) {
783
+ sql += ' AND e.vindication_pending = 1';
784
+ }
785
+ sql += ' ORDER BY e.timestamp DESC';
786
+ return db.prepare(sql).all(projectId);
787
+ }
659
788
  //# sourceMappingURL=index.js.map