chronicle-ai 0.0.1

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 (155) hide show
  1. package/README.md +132 -0
  2. package/package.json +86 -0
  3. package/packages/README.md +139 -0
  4. package/packages/cli/README.md +92 -0
  5. package/packages/cli/bin/chronicle.js +2 -0
  6. package/packages/cli/dist/commands/add.d.ts +2 -0
  7. package/packages/cli/dist/commands/add.d.ts.map +1 -0
  8. package/packages/cli/dist/commands/add.js +82 -0
  9. package/packages/cli/dist/commands/add.js.map +1 -0
  10. package/packages/cli/dist/commands/diff.d.ts +11 -0
  11. package/packages/cli/dist/commands/diff.d.ts.map +1 -0
  12. package/packages/cli/dist/commands/diff.js +164 -0
  13. package/packages/cli/dist/commands/diff.js.map +1 -0
  14. package/packages/cli/dist/commands/init.d.ts +2 -0
  15. package/packages/cli/dist/commands/init.d.ts.map +1 -0
  16. package/packages/cli/dist/commands/init.js +54 -0
  17. package/packages/cli/dist/commands/init.js.map +1 -0
  18. package/packages/cli/dist/commands/list.d.ts +2 -0
  19. package/packages/cli/dist/commands/list.d.ts.map +1 -0
  20. package/packages/cli/dist/commands/list.js +62 -0
  21. package/packages/cli/dist/commands/list.js.map +1 -0
  22. package/packages/cli/dist/commands/log.d.ts +4 -0
  23. package/packages/cli/dist/commands/log.d.ts.map +1 -0
  24. package/packages/cli/dist/commands/log.js +223 -0
  25. package/packages/cli/dist/commands/log.js.map +1 -0
  26. package/packages/cli/dist/commands/pause.d.ts +3 -0
  27. package/packages/cli/dist/commands/pause.d.ts.map +1 -0
  28. package/packages/cli/dist/commands/pause.js +49 -0
  29. package/packages/cli/dist/commands/pause.js.map +1 -0
  30. package/packages/cli/dist/commands/queue.d.ts +2 -0
  31. package/packages/cli/dist/commands/queue.d.ts.map +1 -0
  32. package/packages/cli/dist/commands/queue.js +96 -0
  33. package/packages/cli/dist/commands/queue.js.map +1 -0
  34. package/packages/cli/dist/commands/remove.d.ts +2 -0
  35. package/packages/cli/dist/commands/remove.d.ts.map +1 -0
  36. package/packages/cli/dist/commands/remove.js +80 -0
  37. package/packages/cli/dist/commands/remove.js.map +1 -0
  38. package/packages/cli/dist/commands/reset.d.ts +5 -0
  39. package/packages/cli/dist/commands/reset.d.ts.map +1 -0
  40. package/packages/cli/dist/commands/reset.js +90 -0
  41. package/packages/cli/dist/commands/reset.js.map +1 -0
  42. package/packages/cli/dist/commands/restart.d.ts +2 -0
  43. package/packages/cli/dist/commands/restart.d.ts.map +1 -0
  44. package/packages/cli/dist/commands/restart.js +72 -0
  45. package/packages/cli/dist/commands/restart.js.map +1 -0
  46. package/packages/cli/dist/commands/start.d.ts +2 -0
  47. package/packages/cli/dist/commands/start.d.ts.map +1 -0
  48. package/packages/cli/dist/commands/start.js +127 -0
  49. package/packages/cli/dist/commands/start.js.map +1 -0
  50. package/packages/cli/dist/commands/status.d.ts +2 -0
  51. package/packages/cli/dist/commands/status.d.ts.map +1 -0
  52. package/packages/cli/dist/commands/status.js +181 -0
  53. package/packages/cli/dist/commands/status.js.map +1 -0
  54. package/packages/cli/dist/commands/stop.d.ts +2 -0
  55. package/packages/cli/dist/commands/stop.d.ts.map +1 -0
  56. package/packages/cli/dist/commands/stop.js +64 -0
  57. package/packages/cli/dist/commands/stop.js.map +1 -0
  58. package/packages/cli/dist/index.d.ts +2 -0
  59. package/packages/cli/dist/index.d.ts.map +1 -0
  60. package/packages/cli/dist/index.js +85 -0
  61. package/packages/cli/dist/index.js.map +1 -0
  62. package/packages/cli/dist/utils/paths.d.ts +26 -0
  63. package/packages/cli/dist/utils/paths.d.ts.map +1 -0
  64. package/packages/cli/dist/utils/paths.js +183 -0
  65. package/packages/cli/dist/utils/paths.js.map +1 -0
  66. package/packages/cli/package.json +25 -0
  67. package/packages/daemon/README.md +83 -0
  68. package/packages/daemon/dist/ai_test.d.ts +2 -0
  69. package/packages/daemon/dist/ai_test.d.ts.map +1 -0
  70. package/packages/daemon/dist/ai_test.js +4 -0
  71. package/packages/daemon/dist/ai_test.js.map +1 -0
  72. package/packages/daemon/dist/index.d.ts +2 -0
  73. package/packages/daemon/dist/index.d.ts.map +1 -0
  74. package/packages/daemon/dist/index.js +147 -0
  75. package/packages/daemon/dist/index.js.map +1 -0
  76. package/packages/daemon/dist/jobs/AIProcessor.d.ts +6 -0
  77. package/packages/daemon/dist/jobs/AIProcessor.d.ts.map +1 -0
  78. package/packages/daemon/dist/jobs/AIProcessor.js +58 -0
  79. package/packages/daemon/dist/jobs/AIProcessor.js.map +1 -0
  80. package/packages/daemon/dist/jobs/DocProcessor.d.ts +8 -0
  81. package/packages/daemon/dist/jobs/DocProcessor.d.ts.map +1 -0
  82. package/packages/daemon/dist/jobs/DocProcessor.js +336 -0
  83. package/packages/daemon/dist/jobs/DocProcessor.js.map +1 -0
  84. package/packages/daemon/dist/jobs/FileProcessor.d.ts +7 -0
  85. package/packages/daemon/dist/jobs/FileProcessor.d.ts.map +1 -0
  86. package/packages/daemon/dist/jobs/FileProcessor.js +29 -0
  87. package/packages/daemon/dist/jobs/FileProcessor.js.map +1 -0
  88. package/packages/daemon/dist/jobs/SystemProcessor.d.ts +13 -0
  89. package/packages/daemon/dist/jobs/SystemProcessor.d.ts.map +1 -0
  90. package/packages/daemon/dist/jobs/SystemProcessor.js +38 -0
  91. package/packages/daemon/dist/jobs/SystemProcessor.js.map +1 -0
  92. package/packages/daemon/dist/jobs/UpdateProcessor.d.ts +21 -0
  93. package/packages/daemon/dist/jobs/UpdateProcessor.d.ts.map +1 -0
  94. package/packages/daemon/dist/jobs/UpdateProcessor.js +222 -0
  95. package/packages/daemon/dist/jobs/UpdateProcessor.js.map +1 -0
  96. package/packages/daemon/dist/services/AIService.d.ts +90 -0
  97. package/packages/daemon/dist/services/AIService.d.ts.map +1 -0
  98. package/packages/daemon/dist/services/AIService.js +451 -0
  99. package/packages/daemon/dist/services/AIService.js.map +1 -0
  100. package/packages/daemon/dist/services/ConfigService.d.ts +30 -0
  101. package/packages/daemon/dist/services/ConfigService.d.ts.map +1 -0
  102. package/packages/daemon/dist/services/ConfigService.js +69 -0
  103. package/packages/daemon/dist/services/ConfigService.js.map +1 -0
  104. package/packages/daemon/dist/services/DatabaseService.d.ts +204 -0
  105. package/packages/daemon/dist/services/DatabaseService.d.ts.map +1 -0
  106. package/packages/daemon/dist/services/DatabaseService.js +692 -0
  107. package/packages/daemon/dist/services/DatabaseService.js.map +1 -0
  108. package/packages/daemon/dist/services/GitService.d.ts +12 -0
  109. package/packages/daemon/dist/services/GitService.d.ts.map +1 -0
  110. package/packages/daemon/dist/services/GitService.js +68 -0
  111. package/packages/daemon/dist/services/GitService.js.map +1 -0
  112. package/packages/daemon/dist/services/QueueService.d.ts +16 -0
  113. package/packages/daemon/dist/services/QueueService.d.ts.map +1 -0
  114. package/packages/daemon/dist/services/QueueService.js +87 -0
  115. package/packages/daemon/dist/services/QueueService.js.map +1 -0
  116. package/packages/daemon/dist/services/TriggerService.d.ts +37 -0
  117. package/packages/daemon/dist/services/TriggerService.d.ts.map +1 -0
  118. package/packages/daemon/dist/services/TriggerService.js +150 -0
  119. package/packages/daemon/dist/services/TriggerService.js.map +1 -0
  120. package/packages/daemon/dist/services/WatcherService.d.ts +12 -0
  121. package/packages/daemon/dist/services/WatcherService.d.ts.map +1 -0
  122. package/packages/daemon/dist/services/WatcherService.js +77 -0
  123. package/packages/daemon/dist/services/WatcherService.js.map +1 -0
  124. package/packages/daemon/dist/services/index.d.ts +2 -0
  125. package/packages/daemon/dist/services/index.d.ts.map +1 -0
  126. package/packages/daemon/dist/services/index.js +18 -0
  127. package/packages/daemon/dist/services/index.js.map +1 -0
  128. package/packages/daemon/dist/test-ignore.js +0 -0
  129. package/packages/daemon/package.json +28 -0
  130. package/packages/ui/app/actions.ts +73 -0
  131. package/packages/ui/app/api/ai-activity/route.ts +14 -0
  132. package/packages/ui/app/globals.css +98 -0
  133. package/packages/ui/app/layout.tsx +29 -0
  134. package/packages/ui/app/page.tsx +109 -0
  135. package/packages/ui/components/AutoRefresh.tsx +18 -0
  136. package/packages/ui/components/DocumentationViewer.tsx +276 -0
  137. package/packages/ui/components/FileList.tsx +69 -0
  138. package/packages/ui/components/HeaderWithThinking.tsx +102 -0
  139. package/packages/ui/components/JobQueue.tsx +194 -0
  140. package/packages/ui/components/JobQueueWrapper.tsx +31 -0
  141. package/packages/ui/components/MermaidInit.tsx +24 -0
  142. package/packages/ui/components/ProjectContentArea.tsx +186 -0
  143. package/packages/ui/components/ProjectList.tsx +136 -0
  144. package/packages/ui/components/ThinkingDrawer.tsx +377 -0
  145. package/packages/ui/components/ThinkingPanel.tsx +63 -0
  146. package/packages/ui/components/TriggerSettings.tsx +185 -0
  147. package/packages/ui/components/VersionSelector.tsx +132 -0
  148. package/packages/ui/lib/db.ts +521 -0
  149. package/packages/ui/next-env.d.ts +5 -0
  150. package/packages/ui/next.config.js +4 -0
  151. package/packages/ui/package.json +32 -0
  152. package/packages/ui/postcss.config.js +6 -0
  153. package/packages/ui/public/logo.png +0 -0
  154. package/packages/ui/tailwind.config.ts +32 -0
  155. package/packages/ui/tsconfig.json +40 -0
@@ -0,0 +1,692 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.DatabaseService = void 0;
40
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const fs_1 = __importDefault(require("fs"));
43
+ const sqliteVec = __importStar(require("sqlite-vec"));
44
+ class DatabaseService {
45
+ dataDir;
46
+ db;
47
+ constructor(dataDir = '.chronicle') {
48
+ this.dataDir = dataDir;
49
+ if (!fs_1.default.existsSync(dataDir)) {
50
+ fs_1.default.mkdirSync(dataDir, { recursive: true });
51
+ }
52
+ const dbPath = path_1.default.join(dataDir, 'db.sqlite');
53
+ this.db = new better_sqlite3_1.default(dbPath);
54
+ // Load sqlite-vec extension
55
+ try {
56
+ this.db.loadExtension(sqliteVec.getLoadablePath());
57
+ }
58
+ catch (e) {
59
+ console.warn('⚠️ Could not load sqlite-vec extension. Vector search will be disabled.', e);
60
+ }
61
+ this.initSchema();
62
+ }
63
+ initSchema() {
64
+ this.db.pragma('journal_mode = WAL');
65
+ // Structural Memory: Files
66
+ this.db.exec(`
67
+ CREATE TABLE IF NOT EXISTS files (
68
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
69
+ path TEXT UNIQUE NOT NULL,
70
+ hash TEXT,
71
+ last_modified INTEGER,
72
+ last_indexed INTEGER
73
+ );
74
+ `);
75
+ // Events: What happened
76
+ this.db.exec(`
77
+ CREATE TABLE IF NOT EXISTS events (
78
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
79
+ type TEXT NOT NULL,
80
+ payload TEXT,
81
+ created_at INTEGER DEFAULT (unixepoch())
82
+ );
83
+ `);
84
+ // Jobs: Persistent Queue
85
+ this.db.exec(`
86
+ CREATE TABLE IF NOT EXISTS jobs (
87
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
88
+ name TEXT NOT NULL,
89
+ data TEXT NOT NULL,
90
+ status TEXT DEFAULT 'pending', -- pending, processing, completed, failed
91
+ error TEXT,
92
+ created_at INTEGER DEFAULT (unixepoch()),
93
+ updated_at INTEGER DEFAULT (unixepoch())
94
+ );
95
+ `);
96
+ // Projects: Monitored Repositories
97
+ this.db.exec(`
98
+ CREATE TABLE IF NOT EXISTS projects (
99
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
100
+ path TEXT UNIQUE NOT NULL,
101
+ name TEXT,
102
+ type TEXT,
103
+ created_at INTEGER,
104
+ is_paused INTEGER DEFAULT 0
105
+ );
106
+ `);
107
+ // Migration: Add is_paused if missing
108
+ try {
109
+ this.db.exec('ALTER TABLE projects ADD COLUMN is_paused INTEGER DEFAULT 0');
110
+ }
111
+ catch (e) {
112
+ // Ignore if column exists
113
+ }
114
+ // Migration: Fix NULL timestamps in jobs table
115
+ try {
116
+ this.db.exec(`
117
+ UPDATE jobs SET created_at = unixepoch() WHERE created_at IS NULL OR created_at = 0;
118
+ UPDATE jobs SET updated_at = unixepoch() WHERE updated_at IS NULL OR updated_at = 0;
119
+ `);
120
+ }
121
+ catch (e) {
122
+ // Ignore errors
123
+ }
124
+ // Embeddings: Vector Store
125
+ try {
126
+ // 768 dimensions for Gemini Embeddings
127
+ this.db.exec(`
128
+ CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(
129
+ file_id INTEGER,
130
+ chunk_index INTEGER,
131
+ embedding FLOAT[768]
132
+ );
133
+ `);
134
+ }
135
+ catch (error) {
136
+ console.error('Failed to create embeddings table (sqlite-vec might be missing):', error);
137
+ }
138
+ // Doc Stages: Track multi-stage documentation progress
139
+ this.db.exec(`
140
+ CREATE TABLE IF NOT EXISTS doc_stages (
141
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
142
+ project_id INTEGER NOT NULL UNIQUE,
143
+ current_stage INTEGER DEFAULT 0,
144
+ total_stages INTEGER DEFAULT 4,
145
+ coverage_plan TEXT,
146
+ last_updated INTEGER DEFAULT (unixepoch()),
147
+ FOREIGN KEY (project_id) REFERENCES projects(id)
148
+ );
149
+ `);
150
+ // ===== Phase 1.5: Versioning Tables =====
151
+ // Doc Versions: Each generation run creates a version
152
+ this.db.exec(`
153
+ CREATE TABLE IF NOT EXISTS doc_versions (
154
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
155
+ project_id INTEGER NOT NULL,
156
+ version_number INTEGER NOT NULL,
157
+ trigger_type TEXT, -- 'init', 'on_change', 'on_commit', 'schedule', 'manual'
158
+ commit_hash TEXT,
159
+ status TEXT DEFAULT 'draft', -- draft, pending_review, active, archived
160
+ created_at INTEGER DEFAULT (unixepoch()),
161
+ FOREIGN KEY (project_id) REFERENCES projects(id)
162
+ );
163
+ `);
164
+ // Doc Files: Stores content for each version
165
+ this.db.exec(`
166
+ CREATE TABLE IF NOT EXISTS doc_files (
167
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
168
+ version_id INTEGER NOT NULL,
169
+ path TEXT NOT NULL,
170
+ content TEXT,
171
+ content_hash TEXT,
172
+ created_at INTEGER DEFAULT (unixepoch()),
173
+ FOREIGN KEY (version_id) REFERENCES doc_versions(id)
174
+ );
175
+ `);
176
+ // Thought Logs: Chain-of-thought for each doc file
177
+ this.db.exec(`
178
+ CREATE TABLE IF NOT EXISTS thought_logs (
179
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
180
+ version_id INTEGER NOT NULL,
181
+ doc_path TEXT,
182
+ thinking_summary TEXT,
183
+ created_at INTEGER DEFAULT (unixepoch()),
184
+ FOREIGN KEY (version_id) REFERENCES doc_versions(id)
185
+ );
186
+ `);
187
+ // Assumptions: Claims made in docs that need verification
188
+ this.db.exec(`
189
+ CREATE TABLE IF NOT EXISTS assumptions (
190
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
191
+ doc_file_id INTEGER NOT NULL,
192
+ claim TEXT NOT NULL,
193
+ verified INTEGER DEFAULT 0, -- 0 = unverified, 1 = verified, -1 = rejected
194
+ verification_method TEXT,
195
+ verified_at INTEGER,
196
+ FOREIGN KEY (doc_file_id) REFERENCES doc_files(id)
197
+ );
198
+ `);
199
+ // ===== Phase 1.6: AI Activity Logging =====
200
+ // AI Activity: Central log of all AI calls for the thinking platform
201
+ this.db.exec(`
202
+ CREATE TABLE IF NOT EXISTS ai_activity (
203
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
204
+ project_id INTEGER,
205
+ version_id INTEGER,
206
+ activity_type TEXT NOT NULL, -- 'analyze', 'generate', 'plan', 'embed', 'other'
207
+ prompt_summary TEXT,
208
+ response_preview TEXT,
209
+ thinking_summary TEXT,
210
+ tokens_used INTEGER,
211
+ duration_ms INTEGER,
212
+ status TEXT DEFAULT 'completed', -- 'running', 'completed', 'error'
213
+ created_at INTEGER DEFAULT (unixepoch() * 1000), -- Milliseconds for UI
214
+ FOREIGN KEY (project_id) REFERENCES projects(id),
215
+ FOREIGN KEY (version_id) REFERENCES doc_versions(id)
216
+ );
217
+ `);
218
+ // Create index for fast AI activity queries
219
+ this.db.exec(`
220
+ CREATE INDEX IF NOT EXISTS idx_ai_activity_created
221
+ ON ai_activity(created_at DESC);
222
+ `);
223
+ console.log('📦 Database initialized.');
224
+ }
225
+ init() {
226
+ // Public init for external use if needed
227
+ }
228
+ addProject(pathStr) {
229
+ const name = path_1.default.basename(pathStr);
230
+ return this.db.prepare(`
231
+ INSERT INTO projects (path, name, created_at)
232
+ VALUES (?, ?, unixepoch())
233
+ ON CONFLICT(path) DO NOTHING
234
+ `).run(pathStr, name);
235
+ }
236
+ removeProject(pathToRemove) {
237
+ // Normalize path - remove trailing slashes and resolve to absolute
238
+ let normalizedPath = pathToRemove.trim();
239
+ if (normalizedPath.endsWith('/') || normalizedPath.endsWith('\\')) {
240
+ normalizedPath = normalizedPath.slice(0, -1);
241
+ }
242
+ // Resolve to absolute path if not already absolute
243
+ if (!path_1.default.isAbsolute(normalizedPath)) {
244
+ normalizedPath = path_1.default.resolve(normalizedPath);
245
+ }
246
+ else {
247
+ normalizedPath = path_1.default.resolve(normalizedPath);
248
+ }
249
+ // Try exact match first
250
+ let result = this.db.prepare(`
251
+ DELETE FROM projects WHERE path = ?
252
+ `).run(normalizedPath);
253
+ // If no match, try to find by normalizing stored paths
254
+ if (result.changes === 0) {
255
+ const projects = this.getProjects();
256
+ for (const project of projects) {
257
+ let storedPath = project.path.trim();
258
+ if (storedPath.endsWith('/') || storedPath.endsWith('\\')) {
259
+ storedPath = storedPath.slice(0, -1);
260
+ }
261
+ storedPath = path_1.default.resolve(storedPath);
262
+ if (storedPath === normalizedPath) {
263
+ result = this.db.prepare(`
264
+ DELETE FROM projects WHERE id = ?
265
+ `).run(project.id);
266
+ console.log(`✅ Removed project by ID: ${project.id} (path matched after normalization)`);
267
+ break;
268
+ }
269
+ }
270
+ }
271
+ return result;
272
+ }
273
+ toggleProjectPaused(path, paused) {
274
+ return this.db.prepare(`
275
+ UPDATE projects SET is_paused = ? WHERE path = ?
276
+ `).run(paused ? 1 : 0, path);
277
+ }
278
+ getProjects() {
279
+ return this.db.prepare('SELECT * FROM projects').all();
280
+ }
281
+ getProjectByPath(path) {
282
+ return this.db.prepare('SELECT * FROM projects WHERE path = ?').get(path);
283
+ }
284
+ getFile(path) {
285
+ return this.db.prepare('SELECT * FROM files WHERE path = ?').get(path);
286
+ }
287
+ upsertFile(path, hash, mtime) {
288
+ return this.db.prepare(`
289
+ INSERT INTO files (path, hash, last_modified, last_indexed)
290
+ VALUES (?, ?, ?, unixepoch())
291
+ ON CONFLICT(path) DO UPDATE SET
292
+ hash = excluded.hash,
293
+ last_modified = excluded.last_modified,
294
+ last_indexed = unixepoch()
295
+ `).run(path, hash, mtime);
296
+ }
297
+ logEvent(type, payload) {
298
+ return this.db.prepare(`
299
+ INSERT INTO events (type, payload)
300
+ VALUES (?, ?)
301
+ `).run(type, JSON.stringify(payload));
302
+ }
303
+ raw() {
304
+ return this.db;
305
+ }
306
+ findSimilarSegments(vector, limit = 5) {
307
+ // vec0 search syntax:
308
+ // SELECT rowid, distance FROM embeddings WHERE embedding MATCH ? ORDER BY distance LIMIT ?
309
+ // Note: 'embedding' column in WHERE clause, standard pattern for virtual tables.
310
+ // Ensure vector is Float32Array
311
+ const floatVector = new Float32Array(vector);
312
+ const results = this.db.prepare(`
313
+ SELECT
314
+ e.file_id,
315
+ e.chunk_index,
316
+ distance
317
+ FROM embeddings e
318
+ WHERE embedding MATCH ?
319
+ ORDER BY distance
320
+ LIMIT ?
321
+ `).all(floatVector, limit);
322
+ // Hydrate with file info
323
+ return results.map(r => {
324
+ const file = this.db.prepare('SELECT path FROM files WHERE id = ?').get(r.file_id);
325
+ return {
326
+ filePath: file ? file.path : 'unknown',
327
+ score: r.distance, // lower is better in Euclidean? check sqlite-vec config. Default L2.
328
+ ...r
329
+ };
330
+ });
331
+ }
332
+ // --- Job Queue Methods ---
333
+ enqueueJob(name, data) {
334
+ return this.db.prepare(`
335
+ INSERT INTO jobs (name, data, status)
336
+ VALUES (?, ?, 'pending')
337
+ `).run(name, JSON.stringify(data));
338
+ }
339
+ getNextPendingJob() {
340
+ // Simple FIFO: get oldest pending job
341
+ const job = this.db.prepare(`
342
+ SELECT * FROM jobs
343
+ WHERE status = 'pending'
344
+ ORDER BY created_at ASC
345
+ LIMIT 1
346
+ `).get();
347
+ return job ? { ...job, data: JSON.parse(job.data) } : null;
348
+ }
349
+ updateJobStatus(id, status, error) {
350
+ return this.db.prepare(`
351
+ UPDATE jobs
352
+ SET status = ?, error = ?, updated_at = unixepoch()
353
+ WHERE id = ?
354
+ `).run(status, error || null, id);
355
+ }
356
+ resetProcessingJobs() {
357
+ // On startup, reset 'processing' jobs to 'pending' so they aren't lost
358
+ return this.db.prepare(`
359
+ UPDATE jobs
360
+ SET status = 'pending'
361
+ WHERE status = 'processing'
362
+ `).run();
363
+ }
364
+ /**
365
+ * Clears all pending jobs from the queue.
366
+ */
367
+ clearPendingJobs() {
368
+ return this.db.prepare(`
369
+ DELETE FROM jobs WHERE status = 'pending'
370
+ `).run();
371
+ }
372
+ /**
373
+ * Cancels (marks as failed) the currently processing job.
374
+ */
375
+ cancelCurrentJob() {
376
+ return this.db.prepare(`
377
+ UPDATE jobs
378
+ SET status = 'failed', error = 'Cancelled by user', updated_at = unixepoch()
379
+ WHERE status = 'processing'
380
+ `).run();
381
+ }
382
+ /**
383
+ * Clears the entire queue (pending jobs) and cancels current job.
384
+ */
385
+ clearQueue() {
386
+ this.cancelCurrentJob();
387
+ return this.clearPendingJobs();
388
+ }
389
+ /**
390
+ * Gets count of pending jobs.
391
+ */
392
+ getPendingJobCount() {
393
+ const result = this.db.prepare(`SELECT COUNT(*) as count FROM jobs WHERE status = 'pending'`).get();
394
+ return result.count;
395
+ }
396
+ // ===== Doc Stage Management =====
397
+ /**
398
+ * Gets the documentation stage for a project.
399
+ */
400
+ getDocStage(projectId) {
401
+ const result = this.db.prepare(`
402
+ SELECT current_stage, total_stages, coverage_plan FROM doc_stages WHERE project_id = ?
403
+ `).get(projectId);
404
+ if (!result)
405
+ return null;
406
+ return {
407
+ currentStage: result.current_stage,
408
+ totalStages: result.total_stages,
409
+ coveragePlan: result.coverage_plan
410
+ };
411
+ }
412
+ /**
413
+ * Creates or resets doc stage for a project.
414
+ */
415
+ setDocStage(projectId, coveragePlan, totalStages = 4) {
416
+ this.db.prepare(`
417
+ INSERT INTO doc_stages (project_id, current_stage, total_stages, coverage_plan, last_updated)
418
+ VALUES (?, 0, ?, ?, unixepoch())
419
+ ON CONFLICT(project_id) DO UPDATE SET
420
+ current_stage = 0,
421
+ total_stages = excluded.total_stages,
422
+ coverage_plan = excluded.coverage_plan,
423
+ last_updated = unixepoch()
424
+ `).run(projectId, totalStages, coveragePlan);
425
+ }
426
+ /**
427
+ * Updates the current stage for a project.
428
+ */
429
+ updateDocStage(projectId, stage) {
430
+ this.db.prepare(`
431
+ UPDATE doc_stages SET current_stage = ?, last_updated = unixepoch() WHERE project_id = ?
432
+ `).run(stage, projectId);
433
+ }
434
+ /**
435
+ * Resets the doc stage to 0 (hides the stage counter in UI).
436
+ */
437
+ resetDocStage(projectId) {
438
+ this.db.prepare(`
439
+ UPDATE doc_stages SET current_stage = 0, last_updated = unixepoch() WHERE project_id = ?
440
+ `).run(projectId);
441
+ }
442
+ /**
443
+ * Gets coverage plan JSON for a project.
444
+ */
445
+ getDocCoveragePlan(projectId) {
446
+ const result = this.db.prepare(`
447
+ SELECT coverage_plan FROM doc_stages WHERE project_id = ?
448
+ `).get(projectId);
449
+ if (!result || !result.coverage_plan)
450
+ return null;
451
+ try {
452
+ return JSON.parse(result.coverage_plan);
453
+ }
454
+ catch {
455
+ return null;
456
+ }
457
+ }
458
+ // ===== Doc Version Management =====
459
+ /**
460
+ * Creates a new doc version for a project.
461
+ */
462
+ createDocVersion(projectId, triggerType, commitHash) {
463
+ // Get next version number
464
+ const latest = this.db.prepare(`
465
+ SELECT MAX(version_number) as max_version FROM doc_versions WHERE project_id = ?
466
+ `).get(projectId);
467
+ const nextVersion = (latest?.max_version ?? 0) + 1;
468
+ const result = this.db.prepare(`
469
+ INSERT INTO doc_versions (project_id, version_number, trigger_type, commit_hash, status)
470
+ VALUES (?, ?, ?, ?, 'draft')
471
+ `).run(projectId, nextVersion, triggerType, commitHash || null);
472
+ return Number(result.lastInsertRowid);
473
+ }
474
+ /**
475
+ * Adds a doc file to a version.
476
+ */
477
+ addDocFile(versionId, path, content) {
478
+ const hash = require('crypto').createHash('md5').update(content).digest('hex');
479
+ const result = this.db.prepare(`
480
+ INSERT INTO doc_files (version_id, path, content, content_hash)
481
+ VALUES (?, ?, ?, ?)
482
+ `).run(versionId, path, content, hash);
483
+ return Number(result.lastInsertRowid);
484
+ }
485
+ /**
486
+ * Adds a thought log entry for a version.
487
+ */
488
+ addThoughtLog(versionId, docPath, thinkingSummary) {
489
+ this.db.prepare(`
490
+ INSERT INTO thought_logs (version_id, doc_path, thinking_summary)
491
+ VALUES (?, ?, ?)
492
+ `).run(versionId, docPath, thinkingSummary);
493
+ }
494
+ /**
495
+ * Adds an assumption to a doc file.
496
+ */
497
+ addAssumption(docFileId, claim) {
498
+ const result = this.db.prepare(`
499
+ INSERT INTO assumptions (doc_file_id, claim, verified)
500
+ VALUES (?, ?, 0)
501
+ `).run(docFileId, claim);
502
+ return Number(result.lastInsertRowid);
503
+ }
504
+ /**
505
+ * Updates assumption verification status.
506
+ */
507
+ verifyAssumption(assumptionId, verified, method) {
508
+ this.db.prepare(`
509
+ UPDATE assumptions
510
+ SET verified = ?, verification_method = ?, verified_at = unixepoch()
511
+ WHERE id = ?
512
+ `).run(verified ? 1 : -1, method || null, assumptionId);
513
+ }
514
+ /**
515
+ * Gets all versions for a project.
516
+ */
517
+ getDocVersions(projectId) {
518
+ return this.db.prepare(`
519
+ SELECT id, version_number, trigger_type, status, created_at
520
+ FROM doc_versions
521
+ WHERE project_id = ?
522
+ ORDER BY version_number DESC
523
+ `).all(projectId);
524
+ }
525
+ /**
526
+ * Gets the active version for a project.
527
+ */
528
+ getActiveDocVersion(projectId) {
529
+ return this.db.prepare(`
530
+ SELECT id, version_number FROM doc_versions
531
+ WHERE project_id = ? AND status = 'active'
532
+ `).get(projectId) || null;
533
+ }
534
+ /**
535
+ * Activates a version (sets it as current, archives others).
536
+ */
537
+ activateDocVersion(versionId, projectId) {
538
+ // Archive current active
539
+ this.db.prepare(`
540
+ UPDATE doc_versions SET status = 'archived'
541
+ WHERE project_id = ? AND status = 'active'
542
+ `).run(projectId);
543
+ // Activate new version
544
+ this.db.prepare(`
545
+ UPDATE doc_versions SET status = 'active' WHERE id = ?
546
+ `).run(versionId);
547
+ }
548
+ /**
549
+ * Updates version status.
550
+ */
551
+ updateDocVersionStatus(versionId, status) {
552
+ this.db.prepare(`
553
+ UPDATE doc_versions SET status = ? WHERE id = ?
554
+ `).run(status, versionId);
555
+ }
556
+ /**
557
+ * Gets doc files for a version.
558
+ */
559
+ getDocFiles(versionId) {
560
+ return this.db.prepare(`
561
+ SELECT id, path, content FROM doc_files WHERE version_id = ?
562
+ `).all(versionId);
563
+ }
564
+ /**
565
+ * Gets thought logs for a version.
566
+ */
567
+ getThoughtLogs(versionId) {
568
+ return this.db.prepare(`
569
+ SELECT doc_path, thinking_summary FROM thought_logs WHERE version_id = ?
570
+ `).all(versionId);
571
+ }
572
+ /**
573
+ * Gets assumptions for a doc file.
574
+ */
575
+ getAssumptions(docFileId) {
576
+ return this.db.prepare(`
577
+ SELECT id, claim, verified FROM assumptions WHERE doc_file_id = ?
578
+ `).all(docFileId);
579
+ }
580
+ /**
581
+ * Gets unverified assumptions for a version.
582
+ */
583
+ getUnverifiedAssumptions(versionId) {
584
+ return this.db.prepare(`
585
+ SELECT a.id, a.claim, df.path as doc_path
586
+ FROM assumptions a
587
+ JOIN doc_files df ON a.doc_file_id = df.id
588
+ WHERE df.version_id = ? AND a.verified = 0
589
+ `).all(versionId);
590
+ }
591
+ // ===== AI Activity Methods (Phase 1.6) =====
592
+ /**
593
+ * Logs an AI activity for the central thinking platform.
594
+ */
595
+ logAIActivity(data) {
596
+ const stmt = this.db.prepare(`
597
+ INSERT INTO ai_activity (
598
+ project_id, version_id, activity_type, prompt_summary,
599
+ response_preview, thinking_summary, tokens_used, duration_ms, status, created_at
600
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
601
+ `);
602
+ const result = stmt.run(data.projectId || null, data.versionId || null, data.activityType, data.promptSummary?.slice(0, 200) || null, // Truncate for storage
603
+ data.responsePreview?.slice(0, 500) || null, data.thinkingSummary || null, data.tokensUsed || null, data.durationMs || null, data.status || 'completed', Date.now() // Use JS timestamp (milliseconds)
604
+ );
605
+ return result.lastInsertRowid;
606
+ }
607
+ /**
608
+ * Updates an existing AI activity (e.g., when it completes).
609
+ */
610
+ updateAIActivity(id, data) {
611
+ const updates = [];
612
+ const values = [];
613
+ if (data.responsePreview !== undefined) {
614
+ updates.push('response_preview = ?');
615
+ values.push(data.responsePreview.slice(0, 500));
616
+ }
617
+ if (data.thinkingSummary !== undefined) {
618
+ updates.push('thinking_summary = ?');
619
+ values.push(data.thinkingSummary);
620
+ }
621
+ if (data.tokensUsed !== undefined) {
622
+ updates.push('tokens_used = ?');
623
+ values.push(data.tokensUsed);
624
+ }
625
+ if (data.durationMs !== undefined) {
626
+ updates.push('duration_ms = ?');
627
+ values.push(data.durationMs);
628
+ }
629
+ if (data.status !== undefined) {
630
+ updates.push('status = ?');
631
+ values.push(data.status);
632
+ }
633
+ if (updates.length > 0) {
634
+ values.push(id);
635
+ this.db.prepare(`UPDATE ai_activity SET ${updates.join(', ')} WHERE id = ?`).run(...values);
636
+ }
637
+ }
638
+ /**
639
+ * Gets recent AI activity (for live thinking panel).
640
+ */
641
+ getRecentAIActivity(limit = 20) {
642
+ return this.db.prepare(`
643
+ SELECT
644
+ a.*,
645
+ p.path as project_path
646
+ FROM ai_activity a
647
+ LEFT JOIN projects p ON a.project_id = p.id
648
+ ORDER BY a.created_at DESC
649
+ LIMIT ?
650
+ `).all(limit);
651
+ }
652
+ /**
653
+ * Gets AI activity for a specific version.
654
+ */
655
+ getActivityForVersion(versionId) {
656
+ return this.db.prepare(`
657
+ SELECT * FROM ai_activity
658
+ WHERE version_id = ?
659
+ ORDER BY created_at ASC
660
+ `).all(versionId);
661
+ }
662
+ /**
663
+ * Updates assumption status.
664
+ * verified: 0=unverified, 1=verified, -1=rejected
665
+ */
666
+ updateAssumptionStatus(id, verified, method) {
667
+ this.db.prepare(`
668
+ UPDATE assumptions
669
+ SET verified = ?, verification_method = ?, verified_at = (unixepoch() * 1000)
670
+ WHERE id = ?
671
+ `).run(verified, method, id);
672
+ }
673
+ /**
674
+ * Gets doc file ID by version and path.
675
+ */
676
+ getDocFileId(versionId, docPath) {
677
+ const result = this.db.prepare(`
678
+ SELECT id FROM doc_files WHERE version_id = ? AND path = ?
679
+ `).get(versionId, docPath);
680
+ return result?.id || null;
681
+ }
682
+ /**
683
+ * Updates doc file content (correction).
684
+ */
685
+ updateDocFileContent(id, content) {
686
+ this.db.prepare(`
687
+ UPDATE doc_files SET content = ? WHERE id = ?
688
+ `).run(content, id);
689
+ }
690
+ }
691
+ exports.DatabaseService = DatabaseService;
692
+ //# sourceMappingURL=DatabaseService.js.map