k0ntext 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +623 -0
  3. package/bin/k0ntext.js +12 -0
  4. package/dist/agents/cleanup-agent.d.ts +39 -0
  5. package/dist/agents/cleanup-agent.d.ts.map +1 -0
  6. package/dist/agents/cleanup-agent.js +56 -0
  7. package/dist/agents/cleanup-agent.js.map +1 -0
  8. package/dist/agents/performance-agent.d.ts +37 -0
  9. package/dist/agents/performance-agent.d.ts.map +1 -0
  10. package/dist/agents/performance-agent.js +91 -0
  11. package/dist/agents/performance-agent.js.map +1 -0
  12. package/dist/analyzer/index.d.ts +5 -0
  13. package/dist/analyzer/index.d.ts.map +1 -0
  14. package/dist/analyzer/index.js +5 -0
  15. package/dist/analyzer/index.js.map +1 -0
  16. package/dist/analyzer/intelligent-analyzer.d.ts +111 -0
  17. package/dist/analyzer/intelligent-analyzer.d.ts.map +1 -0
  18. package/dist/analyzer/intelligent-analyzer.js +537 -0
  19. package/dist/analyzer/intelligent-analyzer.js.map +1 -0
  20. package/dist/cli/commands/cleanup.d.ts +3 -0
  21. package/dist/cli/commands/cleanup.d.ts.map +1 -0
  22. package/dist/cli/commands/cleanup.js +24 -0
  23. package/dist/cli/commands/cleanup.js.map +1 -0
  24. package/dist/cli/commands/export.d.ts +9 -0
  25. package/dist/cli/commands/export.d.ts.map +1 -0
  26. package/dist/cli/commands/export.js +72 -0
  27. package/dist/cli/commands/export.js.map +1 -0
  28. package/dist/cli/commands/import.d.ts +9 -0
  29. package/dist/cli/commands/import.d.ts.map +1 -0
  30. package/dist/cli/commands/import.js +62 -0
  31. package/dist/cli/commands/import.js.map +1 -0
  32. package/dist/cli/commands/performance.d.ts +9 -0
  33. package/dist/cli/commands/performance.d.ts.map +1 -0
  34. package/dist/cli/commands/performance.js +36 -0
  35. package/dist/cli/commands/performance.js.map +1 -0
  36. package/dist/cli/commands/validate.d.ts +9 -0
  37. package/dist/cli/commands/validate.d.ts.map +1 -0
  38. package/dist/cli/commands/validate.js +82 -0
  39. package/dist/cli/commands/validate.js.map +1 -0
  40. package/dist/cli/commands/watch.d.ts +9 -0
  41. package/dist/cli/commands/watch.d.ts.map +1 -0
  42. package/dist/cli/commands/watch.js +72 -0
  43. package/dist/cli/commands/watch.js.map +1 -0
  44. package/dist/cli/generate.d.ts +3 -0
  45. package/dist/cli/generate.d.ts.map +1 -0
  46. package/dist/cli/generate.js +194 -0
  47. package/dist/cli/generate.js.map +1 -0
  48. package/dist/cli/index.d.ts +9 -0
  49. package/dist/cli/index.d.ts.map +1 -0
  50. package/dist/cli/index.js +448 -0
  51. package/dist/cli/index.js.map +1 -0
  52. package/dist/cli/sync.d.ts +26 -0
  53. package/dist/cli/sync.d.ts.map +1 -0
  54. package/dist/cli/sync.js +163 -0
  55. package/dist/cli/sync.js.map +1 -0
  56. package/dist/config/cleanup-config.d.ts +26 -0
  57. package/dist/config/cleanup-config.d.ts.map +1 -0
  58. package/dist/config/cleanup-config.js +21 -0
  59. package/dist/config/cleanup-config.js.map +1 -0
  60. package/dist/db/client.d.ts +284 -0
  61. package/dist/db/client.d.ts.map +1 -0
  62. package/dist/db/client.js +688 -0
  63. package/dist/db/client.js.map +1 -0
  64. package/dist/db/index.d.ts +6 -0
  65. package/dist/db/index.d.ts.map +1 -0
  66. package/dist/db/index.js +6 -0
  67. package/dist/db/index.js.map +1 -0
  68. package/dist/db/schema.d.ts +41 -0
  69. package/dist/db/schema.d.ts.map +1 -0
  70. package/dist/db/schema.js +226 -0
  71. package/dist/db/schema.js.map +1 -0
  72. package/dist/embeddings/index.d.ts +5 -0
  73. package/dist/embeddings/index.d.ts.map +1 -0
  74. package/dist/embeddings/index.js +5 -0
  75. package/dist/embeddings/index.js.map +1 -0
  76. package/dist/embeddings/openrouter.d.ts +133 -0
  77. package/dist/embeddings/openrouter.d.ts.map +1 -0
  78. package/dist/embeddings/openrouter.js +455 -0
  79. package/dist/embeddings/openrouter.js.map +1 -0
  80. package/dist/index.d.ts +14 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +18 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/mcp.d.ts +29 -0
  85. package/dist/mcp.d.ts.map +1 -0
  86. package/dist/mcp.js +257 -0
  87. package/dist/mcp.js.map +1 -0
  88. package/docs/ARCHIVE/MIGRATE_TO_NEW_REPO.md +222 -0
  89. package/docs/ARCHIVE/MIGRATE_TO_UNIFIED.md +220 -0
  90. package/docs/CLEANUP.md +76 -0
  91. package/docs/MCP_QUICKSTART.md +219 -0
  92. package/docs/QUICKSTART.md +119 -0
  93. package/docs/TROUBLESHOOTING.md +611 -0
  94. package/package.json +100 -0
  95. package/skills/context-optimize/SKILL.md +86 -0
  96. package/skills/implement/SKILL.md +150 -0
  97. package/skills/plan/SKILL.md +143 -0
  98. package/skills/research/SKILL.md +103 -0
  99. package/skills/validate/SKILL.md +62 -0
  100. package/skills/verify-docs/SKILL.md +77 -0
  101. package/src/agents/cleanup-agent.ts +96 -0
  102. package/src/agents/performance-agent.ts +117 -0
  103. package/src/analyzer/index.ts +10 -0
  104. package/src/analyzer/intelligent-analyzer.ts +640 -0
  105. package/src/cli/commands/cleanup.ts +26 -0
  106. package/src/cli/commands/export.ts +82 -0
  107. package/src/cli/commands/import.ts +73 -0
  108. package/src/cli/commands/performance.ts +40 -0
  109. package/src/cli/commands/validate.ts +98 -0
  110. package/src/cli/commands/watch.ts +83 -0
  111. package/src/cli/generate.ts +219 -0
  112. package/src/cli/index.ts +510 -0
  113. package/src/cli/sync.ts +194 -0
  114. package/src/config/cleanup-config.ts +42 -0
  115. package/src/db/client.ts +949 -0
  116. package/src/db/index.ts +19 -0
  117. package/src/db/schema.ts +241 -0
  118. package/src/embeddings/index.ts +11 -0
  119. package/src/embeddings/openrouter.ts +592 -0
  120. package/src/index.ts +57 -0
  121. package/src/mcp.ts +354 -0
  122. package/templates/AI_CONTEXT.md.template +245 -0
  123. package/templates/base/README.md +260 -0
  124. package/templates/base/RPI_WORKFLOW_PLAN.md +325 -0
  125. package/templates/base/agents/api-developer.md +76 -0
  126. package/templates/base/agents/context-engineer.md +525 -0
  127. package/templates/base/agents/core-architect.md +76 -0
  128. package/templates/base/agents/database-ops.md +76 -0
  129. package/templates/base/agents/deployment-ops.md +76 -0
  130. package/templates/base/agents/integration-hub.md +76 -0
  131. package/templates/base/analytics/README.md +114 -0
  132. package/templates/base/automation/config.json +58 -0
  133. package/templates/base/automation/generators/code-mapper.js +308 -0
  134. package/templates/base/automation/generators/index-builder.js +321 -0
  135. package/templates/base/automation/hooks/post-commit.sh +83 -0
  136. package/templates/base/automation/hooks/pre-commit.sh +103 -0
  137. package/templates/base/ci-templates/README.md +108 -0
  138. package/templates/base/ci-templates/github-actions/context-check.yml +144 -0
  139. package/templates/base/ci-templates/github-actions/validate-docs.yml +105 -0
  140. package/templates/base/commands/analytics.md +238 -0
  141. package/templates/base/commands/auto-sync.md +172 -0
  142. package/templates/base/commands/collab.md +194 -0
  143. package/templates/base/commands/context-optimize.md +226 -0
  144. package/templates/base/commands/help.md +485 -0
  145. package/templates/base/commands/rpi-implement.md +164 -0
  146. package/templates/base/commands/rpi-plan.md +147 -0
  147. package/templates/base/commands/rpi-research.md +145 -0
  148. package/templates/base/commands/session-resume.md +144 -0
  149. package/templates/base/commands/session-save.md +112 -0
  150. package/templates/base/commands/validate-all.md +77 -0
  151. package/templates/base/commands/verify-docs-current.md +86 -0
  152. package/templates/base/config/base.json +57 -0
  153. package/templates/base/config/environments/development.json +13 -0
  154. package/templates/base/config/environments/production.json +17 -0
  155. package/templates/base/config/environments/staging.json +13 -0
  156. package/templates/base/config/local.json.example +21 -0
  157. package/templates/base/context/.meta/generated-at.json +18 -0
  158. package/templates/base/context/ARCHITECTURE_SNAPSHOT.md +156 -0
  159. package/templates/base/context/CODE_TO_WORKFLOW_MAP.md +94 -0
  160. package/templates/base/context/FILE_OWNERSHIP.md +57 -0
  161. package/templates/base/context/INTEGRATION_POINTS.md +92 -0
  162. package/templates/base/context/KNOWN_GOTCHAS.md +195 -0
  163. package/templates/base/context/TESTING_MAP.md +95 -0
  164. package/templates/base/context/WORKFLOW_INDEX.md +129 -0
  165. package/templates/base/context/workflows/WORKFLOW_TEMPLATE.md +294 -0
  166. package/templates/base/indexes/agents/CAPABILITY_MATRIX.md +255 -0
  167. package/templates/base/indexes/agents/CATEGORY_INDEX.md +44 -0
  168. package/templates/base/indexes/code/CATEGORY_INDEX.md +38 -0
  169. package/templates/base/indexes/routing/CATEGORY_INDEX.md +39 -0
  170. package/templates/base/indexes/search/CATEGORY_INDEX.md +39 -0
  171. package/templates/base/indexes/workflows/CATEGORY_INDEX.md +38 -0
  172. package/templates/base/knowledge/README.md +98 -0
  173. package/templates/base/knowledge/sessions/README.md +88 -0
  174. package/templates/base/knowledge/sessions/TEMPLATE.md +150 -0
  175. package/templates/base/knowledge/shared/decisions/0001-adopt-context-engineering.md +144 -0
  176. package/templates/base/knowledge/shared/decisions/README.md +49 -0
  177. package/templates/base/knowledge/shared/decisions/TEMPLATE.md +123 -0
  178. package/templates/base/knowledge/shared/patterns/README.md +62 -0
  179. package/templates/base/knowledge/shared/patterns/TEMPLATE.md +120 -0
  180. package/templates/base/plans/PLAN_TEMPLATE.md +316 -0
  181. package/templates/base/plans/active/.gitkeep +0 -0
  182. package/templates/base/plans/completed/.gitkeep +0 -0
  183. package/templates/base/research/RESEARCH_TEMPLATE.md +245 -0
  184. package/templates/base/research/active/.gitkeep +0 -0
  185. package/templates/base/research/completed/.gitkeep +0 -0
  186. package/templates/base/schemas/agent.schema.json +141 -0
  187. package/templates/base/schemas/anchors.schema.json +54 -0
  188. package/templates/base/schemas/automation.schema.json +93 -0
  189. package/templates/base/schemas/command.schema.json +134 -0
  190. package/templates/base/schemas/hashes.schema.json +40 -0
  191. package/templates/base/schemas/manifest.schema.json +117 -0
  192. package/templates/base/schemas/plan.schema.json +136 -0
  193. package/templates/base/schemas/research.schema.json +115 -0
  194. package/templates/base/schemas/roles.schema.json +34 -0
  195. package/templates/base/schemas/session.schema.json +77 -0
  196. package/templates/base/schemas/settings.schema.json +244 -0
  197. package/templates/base/schemas/staleness.schema.json +53 -0
  198. package/templates/base/schemas/team-config.schema.json +42 -0
  199. package/templates/base/schemas/workflow.schema.json +126 -0
  200. package/templates/base/session/checkpoints/.gitkeep +2 -0
  201. package/templates/base/session/current/state.json +20 -0
  202. package/templates/base/session/history/.gitkeep +2 -0
  203. package/templates/base/settings.json +3 -0
  204. package/templates/base/standards/COMPATIBILITY.md +219 -0
  205. package/templates/base/standards/EXTENSION_GUIDELINES.md +280 -0
  206. package/templates/base/standards/QUALITY_CHECKLIST.md +211 -0
  207. package/templates/base/standards/README.md +66 -0
  208. package/templates/base/sync/anchors.json +6 -0
  209. package/templates/base/sync/hashes.json +6 -0
  210. package/templates/base/sync/staleness.json +10 -0
  211. package/templates/base/team/README.md +168 -0
  212. package/templates/base/team/config.json +79 -0
  213. package/templates/base/team/roles.json +145 -0
  214. package/templates/base/tools/bin/claude-context.js +151 -0
  215. package/templates/base/tools/lib/anchor-resolver.js +276 -0
  216. package/templates/base/tools/lib/config-loader.js +363 -0
  217. package/templates/base/tools/lib/detector.js +350 -0
  218. package/templates/base/tools/lib/diagnose.js +206 -0
  219. package/templates/base/tools/lib/drift-detector.js +373 -0
  220. package/templates/base/tools/lib/errors.js +199 -0
  221. package/templates/base/tools/lib/index.js +36 -0
  222. package/templates/base/tools/lib/init.js +192 -0
  223. package/templates/base/tools/lib/logger.js +230 -0
  224. package/templates/base/tools/lib/placeholder.js +201 -0
  225. package/templates/base/tools/lib/session-manager.js +354 -0
  226. package/templates/base/tools/lib/validate.js +521 -0
  227. package/templates/base/tools/package.json +49 -0
  228. package/templates/handlebars/aider-config.hbs +146 -0
  229. package/templates/handlebars/antigravity.hbs +377 -0
  230. package/templates/handlebars/claude.hbs +183 -0
  231. package/templates/handlebars/cline.hbs +62 -0
  232. package/templates/handlebars/continue-config.hbs +116 -0
  233. package/templates/handlebars/copilot.hbs +130 -0
  234. package/templates/handlebars/partials/gotcha-list.hbs +11 -0
  235. package/templates/handlebars/partials/header.hbs +3 -0
  236. package/templates/handlebars/partials/workflow-summary.hbs +16 -0
  237. package/templates/handlebars/windsurf-rules.hbs +69 -0
  238. package/templates/hooks/post-commit.hbs +28 -0
  239. package/templates/hooks/pre-commit.hbs +46 -0
@@ -0,0 +1,688 @@
1
+ /**
2
+ * Database Client
3
+ *
4
+ * SQLite database operations for AI context storage.
5
+ * Handles CRUD operations, queries, and vector search.
6
+ */
7
+ import Database from 'better-sqlite3';
8
+ import * as sqliteVec from 'sqlite-vec';
9
+ import { createHash } from 'crypto';
10
+ import path from 'path';
11
+ import fs from 'fs';
12
+ import { SCHEMA_SQL, VECTOR_SCHEMA_SQL, SCHEMA_VERSION } from './schema.js';
13
+ /**
14
+ * Database client for AI context storage
15
+ */
16
+ export class DatabaseClient {
17
+ db;
18
+ dbPath;
19
+ constructor(projectRoot, dbFileName = '.k0ntext.db') {
20
+ this.dbPath = path.join(projectRoot, dbFileName);
21
+ // Ensure directory exists
22
+ const dbDir = path.dirname(this.dbPath);
23
+ if (!fs.existsSync(dbDir)) {
24
+ fs.mkdirSync(dbDir, { recursive: true });
25
+ }
26
+ this.db = new Database(this.dbPath);
27
+ // Enable foreign keys
28
+ this.db.pragma('foreign_keys = ON');
29
+ // Load sqlite-vec extension
30
+ sqliteVec.load(this.db);
31
+ // Initialize schema
32
+ this.initSchema();
33
+ }
34
+ /**
35
+ * Migrate legacy database
36
+ */
37
+ migrateLegacyDatabase() {
38
+ const legacyPath = path.join(process.cwd(), '.ai-context.db');
39
+ const newPath = this.dbPath;
40
+ if (fs.existsSync(legacyPath) && !fs.existsSync(newPath)) {
41
+ fs.copyFileSync(legacyPath, newPath);
42
+ console.log(`✓ Migrated .ai-context.db to .k0ntext.db`);
43
+ }
44
+ }
45
+ /**
46
+ * Initialize database schema
47
+ */
48
+ initSchema() {
49
+ // Migrate legacy database first
50
+ this.migrateLegacyDatabase();
51
+ // Create core tables
52
+ this.db.exec(SCHEMA_SQL);
53
+ // Create vector table
54
+ this.db.exec(VECTOR_SCHEMA_SQL);
55
+ // Record schema version
56
+ const stmt = this.db.prepare(`
57
+ INSERT OR REPLACE INTO schema_version (version, applied_at)
58
+ VALUES (?, datetime('now'))
59
+ `);
60
+ stmt.run(SCHEMA_VERSION);
61
+ }
62
+ /**
63
+ * Execute callback within a transaction (implementation)
64
+ */
65
+ transaction(callback) {
66
+ // Detect if callback is async by checking if it returns a Promise
67
+ const result = callback();
68
+ if (result instanceof Promise) {
69
+ // For async, use manual transaction control
70
+ return (async () => {
71
+ this.db.exec('BEGIN TRANSACTION');
72
+ try {
73
+ const value = await result;
74
+ this.db.exec('COMMIT');
75
+ return value;
76
+ }
77
+ catch (error) {
78
+ this.db.exec('ROLLBACK');
79
+ throw error;
80
+ }
81
+ })();
82
+ }
83
+ else {
84
+ // For sync, use better-sqlite3 transaction helper
85
+ const txn = this.db.transaction(callback);
86
+ return txn();
87
+ }
88
+ }
89
+ /**
90
+ * Begin a manual transaction (returns rollback/commit functions)
91
+ */
92
+ beginTransaction() {
93
+ this.db.exec('BEGIN TRANSACTION');
94
+ return {
95
+ rollback: () => this.db.exec('ROLLBACK'),
96
+ commit: () => this.db.exec('COMMIT')
97
+ };
98
+ }
99
+ /**
100
+ * Check database connection health
101
+ */
102
+ healthCheck() {
103
+ try {
104
+ this.db.prepare('SELECT 1').get();
105
+ return { healthy: true };
106
+ }
107
+ catch (error) {
108
+ return {
109
+ healthy: false,
110
+ error: error instanceof Error ? error.message : String(error)
111
+ };
112
+ }
113
+ }
114
+ /**
115
+ * Generate content hash for deduplication
116
+ */
117
+ hashContent(content) {
118
+ return createHash('sha256').update(content).digest('hex').slice(0, 16);
119
+ }
120
+ /**
121
+ * Generate a unique ID for a context item
122
+ */
123
+ generateId(type, name) {
124
+ return `${type}:${name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
125
+ }
126
+ // ==================== Context Items ====================
127
+ /**
128
+ * Insert or update a context item
129
+ */
130
+ upsertItem(item) {
131
+ const id = this.generateId(item.type, item.name);
132
+ const contentHash = this.hashContent(item.content);
133
+ const stmt = this.db.prepare(`
134
+ INSERT INTO context_items (id, type, name, content, metadata, file_path, content_hash, updated_at)
135
+ VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
136
+ ON CONFLICT(id) DO UPDATE SET
137
+ content = excluded.content,
138
+ metadata = excluded.metadata,
139
+ file_path = excluded.file_path,
140
+ content_hash = excluded.content_hash,
141
+ updated_at = datetime('now')
142
+ RETURNING *
143
+ `);
144
+ const row = stmt.get(id, item.type, item.name, item.content, item.metadata ? JSON.stringify(item.metadata) : null, item.filePath || null, contentHash);
145
+ return this.rowToItem(row);
146
+ }
147
+ /**
148
+ * Get a context item by ID
149
+ */
150
+ getItem(id) {
151
+ const stmt = this.db.prepare('SELECT * FROM context_items WHERE id = ?');
152
+ const row = stmt.get(id);
153
+ return row ? this.rowToItem(row) : null;
154
+ }
155
+ /**
156
+ * Get items by type
157
+ */
158
+ getItemsByType(type) {
159
+ const stmt = this.db.prepare('SELECT * FROM context_items WHERE type = ? ORDER BY name');
160
+ const rows = stmt.all(type);
161
+ return rows.map(row => this.rowToItem(row));
162
+ }
163
+ /**
164
+ * Get all items
165
+ */
166
+ getAllItems() {
167
+ const stmt = this.db.prepare('SELECT * FROM context_items ORDER BY type, name');
168
+ const rows = stmt.all();
169
+ return rows.map(row => this.rowToItem(row));
170
+ }
171
+ /**
172
+ * Delete a context item
173
+ */
174
+ deleteItem(id) {
175
+ const stmt = this.db.prepare('DELETE FROM context_items WHERE id = ?');
176
+ const result = stmt.run(id);
177
+ return result.changes > 0;
178
+ }
179
+ /**
180
+ * Delete items older than specified days
181
+ */
182
+ deleteStaleItems(daysOld, type) {
183
+ const stmt = this.db.prepare(`
184
+ DELETE FROM context_items
185
+ WHERE datetime(updated_at) < datetime('now', '-' || ? || ' days')
186
+ ${type ? 'AND type = ?' : ''}
187
+ `);
188
+ const result = stmt.run(...(type ? [daysOld, type] : [daysOld]));
189
+ return result.changes;
190
+ }
191
+ /**
192
+ * Search items by text (full-text grep-style)
193
+ */
194
+ searchText(query, type) {
195
+ const pattern = `%${query}%`;
196
+ let sql = 'SELECT * FROM context_items WHERE (content LIKE ? OR name LIKE ?)';
197
+ const params = [pattern, pattern];
198
+ if (type) {
199
+ sql += ' AND type = ?';
200
+ params.push(type);
201
+ }
202
+ sql += ' ORDER BY name LIMIT 50';
203
+ const stmt = this.db.prepare(sql);
204
+ const rows = stmt.all(...params);
205
+ return rows.map(row => this.rowToItem(row));
206
+ }
207
+ /**
208
+ * Convert database row to ContextItem
209
+ */
210
+ rowToItem(row) {
211
+ return {
212
+ id: row.id,
213
+ type: row.type,
214
+ name: row.name,
215
+ content: row.content,
216
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
217
+ filePath: row.file_path,
218
+ contentHash: row.content_hash,
219
+ createdAt: row.created_at,
220
+ updatedAt: row.updated_at
221
+ };
222
+ }
223
+ /**
224
+ * Calculate relevance score for a search result
225
+ */
226
+ calculateRelevance(item, query, baseScore) {
227
+ let score = baseScore;
228
+ // Boost score for exact name matches
229
+ if (item.name.toLowerCase().includes(query.toLowerCase())) {
230
+ score *= 1.5;
231
+ }
232
+ // Boost score for recently updated items
233
+ if (item.updatedAt) {
234
+ const daysSinceUpdate = (Date.now() - new Date(item.updatedAt).getTime()) / (1000 * 60 * 60 * 24);
235
+ if (daysSinceUpdate < 7) {
236
+ score *= 1.2; // 20% boost for items updated within a week
237
+ }
238
+ }
239
+ // Boost score for certain types
240
+ if (item.type === 'workflow' || item.type === 'agent') {
241
+ score *= 1.1;
242
+ }
243
+ return score;
244
+ }
245
+ // ==================== AI Tool Configs ====================
246
+ /**
247
+ * Upsert an AI tool configuration
248
+ */
249
+ upsertToolConfig(config) {
250
+ const contentHash = this.hashContent(config.content);
251
+ const stmt = this.db.prepare(`
252
+ INSERT INTO ai_tool_configs (id, tool_name, config_path, content, content_hash, last_sync, status, metadata)
253
+ VALUES (?, ?, ?, ?, ?, datetime('now'), ?, ?)
254
+ ON CONFLICT(id) DO UPDATE SET
255
+ content = excluded.content,
256
+ content_hash = excluded.content_hash,
257
+ last_sync = datetime('now'),
258
+ status = excluded.status,
259
+ metadata = excluded.metadata
260
+ RETURNING *
261
+ `);
262
+ const row = stmt.get(config.id, config.toolName, config.configPath, config.content, contentHash, config.status, config.metadata ? JSON.stringify(config.metadata) : null);
263
+ return {
264
+ id: row.id,
265
+ toolName: row.tool_name,
266
+ configPath: row.config_path,
267
+ content: row.content,
268
+ contentHash: row.content_hash,
269
+ lastSync: row.last_sync,
270
+ status: row.status,
271
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
272
+ };
273
+ }
274
+ /**
275
+ * Get tool configs by tool name
276
+ */
277
+ getToolConfigs(toolName) {
278
+ const stmt = this.db.prepare('SELECT * FROM ai_tool_configs WHERE tool_name = ?');
279
+ const rows = stmt.all(toolName);
280
+ return rows.map(row => ({
281
+ id: row.id,
282
+ toolName: row.tool_name,
283
+ configPath: row.config_path,
284
+ content: row.content,
285
+ contentHash: row.content_hash,
286
+ lastSync: row.last_sync,
287
+ status: row.status,
288
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
289
+ }));
290
+ }
291
+ /**
292
+ * Get all tool configs
293
+ */
294
+ getAllToolConfigs() {
295
+ const stmt = this.db.prepare('SELECT * FROM ai_tool_configs ORDER BY tool_name');
296
+ const rows = stmt.all();
297
+ return rows.map(row => ({
298
+ id: row.id,
299
+ toolName: row.tool_name,
300
+ configPath: row.config_path,
301
+ content: row.content,
302
+ contentHash: row.content_hash,
303
+ lastSync: row.last_sync,
304
+ status: row.status,
305
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
306
+ }));
307
+ }
308
+ // ==================== Knowledge Graph ====================
309
+ /**
310
+ * Add a relationship to the knowledge graph
311
+ */
312
+ addRelation(edge) {
313
+ const stmt = this.db.prepare(`
314
+ INSERT INTO knowledge_graph (source_id, target_id, relation_type, weight, metadata)
315
+ VALUES (?, ?, ?, ?, ?)
316
+ ON CONFLICT(source_id, target_id, relation_type) DO UPDATE SET
317
+ weight = excluded.weight,
318
+ metadata = excluded.metadata
319
+ RETURNING *
320
+ `);
321
+ const row = stmt.get(edge.sourceId, edge.targetId, edge.relationType, edge.weight ?? 1.0, edge.metadata ? JSON.stringify(edge.metadata) : null);
322
+ return {
323
+ id: row.id,
324
+ sourceId: row.source_id,
325
+ targetId: row.target_id,
326
+ relationType: row.relation_type,
327
+ weight: row.weight,
328
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
329
+ };
330
+ }
331
+ /**
332
+ * Get relations from a source item
333
+ */
334
+ getRelationsFrom(sourceId, relationType) {
335
+ let sql = `
336
+ SELECT kg.*, ci.name as target_name
337
+ FROM knowledge_graph kg
338
+ JOIN context_items ci ON kg.target_id = ci.id
339
+ WHERE kg.source_id = ?
340
+ `;
341
+ const params = [sourceId];
342
+ if (relationType) {
343
+ sql += ' AND kg.relation_type = ?';
344
+ params.push(relationType);
345
+ }
346
+ sql += ' ORDER BY kg.weight DESC';
347
+ const stmt = this.db.prepare(sql);
348
+ const rows = stmt.all(...params);
349
+ return rows.map(row => ({
350
+ id: row.id,
351
+ sourceId: row.source_id,
352
+ targetId: row.target_id,
353
+ relationType: row.relation_type,
354
+ weight: row.weight,
355
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
356
+ }));
357
+ }
358
+ /**
359
+ * Get relations to a target item
360
+ */
361
+ getRelationsTo(targetId, relationType) {
362
+ let sql = `
363
+ SELECT kg.*, ci.name as source_name
364
+ FROM knowledge_graph kg
365
+ JOIN context_items ci ON kg.source_id = ci.id
366
+ WHERE kg.target_id = ?
367
+ `;
368
+ const params = [targetId];
369
+ if (relationType) {
370
+ sql += ' AND kg.relation_type = ?';
371
+ params.push(relationType);
372
+ }
373
+ sql += ' ORDER BY kg.weight DESC';
374
+ const stmt = this.db.prepare(sql);
375
+ const rows = stmt.all(...params);
376
+ return rows.map(row => ({
377
+ id: row.id,
378
+ sourceId: row.source_id,
379
+ targetId: row.target_id,
380
+ relationType: row.relation_type,
381
+ weight: row.weight,
382
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
383
+ }));
384
+ }
385
+ /**
386
+ * Traverse the graph from a starting point
387
+ */
388
+ traverseGraph(startId, maxDepth = 3) {
389
+ const visited = new Map();
390
+ const queue = [{ id: startId, depth: 0 }];
391
+ while (queue.length > 0) {
392
+ const { id, depth } = queue.shift();
393
+ if (visited.has(id) || depth > maxDepth)
394
+ continue;
395
+ const item = this.getItem(id);
396
+ if (!item)
397
+ continue;
398
+ visited.set(id, { item, depth });
399
+ // Get all outgoing relations
400
+ const relations = this.getRelationsFrom(id);
401
+ for (const rel of relations) {
402
+ if (!visited.has(rel.targetId)) {
403
+ queue.push({ id: rel.targetId, depth: depth + 1 });
404
+ }
405
+ }
406
+ }
407
+ return visited;
408
+ }
409
+ // ==================== Git Commits ====================
410
+ /**
411
+ * Insert or update a git commit
412
+ */
413
+ upsertCommit(commit) {
414
+ const stmt = this.db.prepare(`
415
+ INSERT INTO git_commits (sha, message, author_name, author_email, timestamp, files_changed, stats)
416
+ VALUES (?, ?, ?, ?, ?, ?, ?)
417
+ ON CONFLICT(sha) DO UPDATE SET
418
+ message = excluded.message,
419
+ files_changed = excluded.files_changed,
420
+ stats = excluded.stats
421
+ `);
422
+ stmt.run(commit.sha, commit.message, commit.authorName || null, commit.authorEmail || null, commit.timestamp, commit.filesChanged ? JSON.stringify(commit.filesChanged) : null, commit.stats ? JSON.stringify(commit.stats) : null);
423
+ }
424
+ /**
425
+ * Get recent commits
426
+ */
427
+ getRecentCommits(limit = 50) {
428
+ const stmt = this.db.prepare(`
429
+ SELECT * FROM git_commits
430
+ ORDER BY timestamp DESC
431
+ LIMIT ?
432
+ `);
433
+ const rows = stmt.all(limit);
434
+ return rows.map(row => ({
435
+ sha: row.sha,
436
+ message: row.message,
437
+ authorName: row.author_name,
438
+ authorEmail: row.author_email,
439
+ timestamp: row.timestamp,
440
+ filesChanged: row.files_changed ? JSON.parse(row.files_changed) : undefined,
441
+ stats: row.stats ? JSON.parse(row.stats) : undefined
442
+ }));
443
+ }
444
+ // ==================== Sync State ====================
445
+ /**
446
+ * Update sync state for a tool
447
+ */
448
+ updateSyncState(state) {
449
+ const stmt = this.db.prepare(`
450
+ INSERT INTO sync_state (id, tool, content_hash, last_sync, file_path, status, metadata)
451
+ VALUES (?, ?, ?, datetime('now'), ?, ?, ?)
452
+ ON CONFLICT(id) DO UPDATE SET
453
+ content_hash = excluded.content_hash,
454
+ last_sync = datetime('now'),
455
+ status = excluded.status,
456
+ metadata = excluded.metadata
457
+ `);
458
+ stmt.run(state.id, state.tool, state.contentHash || null, state.filePath || null, state.status, state.metadata ? JSON.stringify(state.metadata) : null);
459
+ }
460
+ /**
461
+ * Get sync state for a tool
462
+ */
463
+ getSyncState(tool) {
464
+ const stmt = this.db.prepare('SELECT * FROM sync_state WHERE tool = ?');
465
+ const rows = stmt.all(tool);
466
+ return rows.map(row => ({
467
+ id: row.id,
468
+ tool: row.tool,
469
+ contentHash: row.content_hash,
470
+ lastSync: row.last_sync,
471
+ filePath: row.file_path,
472
+ status: row.status,
473
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
474
+ }));
475
+ }
476
+ // ==================== Embeddings ====================
477
+ /**
478
+ * Store an embedding
479
+ */
480
+ storeEmbedding(contextId, embedding) {
481
+ const stmt = this.db.prepare(`
482
+ INSERT INTO embeddings (context_id, embedding)
483
+ VALUES (?, ?)
484
+ ON CONFLICT(context_id) DO UPDATE SET
485
+ embedding = excluded.embedding
486
+ `);
487
+ // Convert to blob for sqlite-vec
488
+ const buffer = new Float32Array(embedding);
489
+ stmt.run(contextId, Buffer.from(buffer.buffer));
490
+ }
491
+ /**
492
+ * Search by embedding similarity
493
+ */
494
+ searchByEmbedding(queryEmbedding, limit = 10) {
495
+ const buffer = new Float32Array(queryEmbedding);
496
+ const stmt = this.db.prepare(`
497
+ SELECT
498
+ e.context_id,
499
+ e.embedding,
500
+ ci.*,
501
+ vec_distance_cosine(e.embedding, ?) as distance
502
+ FROM embeddings e
503
+ JOIN context_items ci ON e.context_id = ci.id
504
+ ORDER BY distance
505
+ LIMIT ?
506
+ `);
507
+ const rows = stmt.all(Buffer.from(buffer.buffer), limit);
508
+ return rows.map(row => ({
509
+ item: this.rowToItem(row),
510
+ similarity: 1 - (row.distance || 0) // Convert distance to similarity
511
+ }));
512
+ }
513
+ /**
514
+ * Hybrid search combining vector and text search
515
+ */
516
+ hybridSearch(query, queryEmbedding, options = {}) {
517
+ const { limit = 10, type, vectorWeight = 0.7 } = options;
518
+ const textResults = this.searchText(query, type);
519
+ const semanticResults = queryEmbedding ? this.searchByEmbedding(queryEmbedding, limit * 2) : [];
520
+ // Combine and score
521
+ const combinedScores = new Map();
522
+ // Score text results (inverse of position)
523
+ for (let i = 0; i < textResults.length; i++) {
524
+ const score = (1 - i / textResults.length) * (1 - vectorWeight);
525
+ combinedScores.set(textResults[i].id, (combinedScores.get(textResults[i].id) || 0) + score);
526
+ }
527
+ // Score semantic results
528
+ for (const result of semanticResults) {
529
+ const score = result.similarity * vectorWeight;
530
+ combinedScores.set(result.item.id, (combinedScores.get(result.item.id) || 0) + score);
531
+ }
532
+ // Sort by combined score
533
+ const results = Array.from(combinedScores.entries())
534
+ .sort((a, b) => b[1] - a[1])
535
+ .slice(0, limit)
536
+ .map(([id]) => this.getItem(id))
537
+ .filter(item => item !== null);
538
+ return results.map(item => ({
539
+ item,
540
+ similarity: combinedScores.get(item.id) || 0
541
+ }));
542
+ }
543
+ /**
544
+ * Delete an embedding
545
+ */
546
+ deleteEmbedding(contextId) {
547
+ const stmt = this.db.prepare('DELETE FROM embeddings WHERE context_id = ?');
548
+ const result = stmt.run(contextId);
549
+ return result.changes > 0;
550
+ }
551
+ /**
552
+ * Insert or update an embedding for a file by path
553
+ */
554
+ insertEmbedding(filePath, embedding) {
555
+ const itemId = this.getItemIdByPath(filePath);
556
+ if (!itemId) {
557
+ throw new Error(`Cannot insert embedding: no item found for path ${filePath}`);
558
+ }
559
+ this.storeEmbedding(itemId, embedding);
560
+ }
561
+ /**
562
+ * Get item ID by file path
563
+ */
564
+ getItemIdByPath(filePath) {
565
+ const stmt = this.db.prepare('SELECT id FROM context_items WHERE file_path = ? LIMIT 1');
566
+ const row = stmt.get(filePath);
567
+ return row?.id || null;
568
+ }
569
+ // ==================== Analytics ====================
570
+ /**
571
+ * Log a usage event
572
+ */
573
+ logUsage(toolName, query, resultCount, latencyMs) {
574
+ const stmt = this.db.prepare(`
575
+ INSERT INTO usage_analytics (tool_name, query, result_count, latency_ms)
576
+ VALUES (?, ?, ?, ?)
577
+ `);
578
+ stmt.run(toolName, query || null, resultCount ?? null, latencyMs ?? null);
579
+ }
580
+ /**
581
+ * Get usage statistics
582
+ */
583
+ getUsageStats(days = 30) {
584
+ const stmt = this.db.prepare(`
585
+ SELECT
586
+ tool_name,
587
+ COUNT(*) as count,
588
+ AVG(latency_ms) as avg_latency
589
+ FROM usage_analytics
590
+ WHERE timestamp > datetime('now', '-' || ? || ' days')
591
+ GROUP BY tool_name
592
+ ORDER BY count DESC
593
+ `);
594
+ const rows = stmt.all(days);
595
+ return rows.map(row => ({
596
+ toolName: row.tool_name,
597
+ count: row.count,
598
+ avgLatency: row.avg_latency
599
+ }));
600
+ }
601
+ // ==================== Utility ====================
602
+ /**
603
+ * Get database path
604
+ */
605
+ getPath() {
606
+ return this.dbPath;
607
+ }
608
+ /**
609
+ * Get database statistics
610
+ */
611
+ getStats() {
612
+ const itemCount = this.db.prepare('SELECT COUNT(*) as count FROM context_items').get().count;
613
+ const relationCount = this.db.prepare('SELECT COUNT(*) as count FROM knowledge_graph').get().count;
614
+ const commitCount = this.db.prepare('SELECT COUNT(*) as count FROM git_commits').get().count;
615
+ const toolConfigCount = this.db.prepare('SELECT COUNT(*) as count FROM ai_tool_configs').get().count;
616
+ let embeddingCount = 0;
617
+ try {
618
+ embeddingCount = this.db.prepare('SELECT COUNT(*) as count FROM embeddings').get().count;
619
+ }
620
+ catch {
621
+ // Vector table might not exist yet
622
+ }
623
+ return {
624
+ items: itemCount,
625
+ relations: relationCount,
626
+ commits: commitCount,
627
+ embeddings: embeddingCount,
628
+ toolConfigs: toolConfigCount
629
+ };
630
+ }
631
+ /**
632
+ * Get raw database instance (for advanced operations)
633
+ */
634
+ getRawDb() {
635
+ return this.db;
636
+ }
637
+ /**
638
+ * Vacuum database to reclaim space
639
+ */
640
+ vacuum() {
641
+ this.db.exec('VACUUM');
642
+ }
643
+ /**
644
+ * Reindex database for optimization
645
+ */
646
+ reindex() {
647
+ this.db.exec('REINDEX');
648
+ }
649
+ /**
650
+ * Backup database to specified path
651
+ */
652
+ backup(backupPath) {
653
+ try {
654
+ // Ensure backup directory exists
655
+ const backupDir = path.dirname(backupPath);
656
+ if (!fs.existsSync(backupDir)) {
657
+ fs.mkdirSync(backupDir, { recursive: true });
658
+ }
659
+ // Close the database before copying to ensure consistency
660
+ this.db.close();
661
+ fs.copyFileSync(this.dbPath, backupPath);
662
+ // Reopen the database
663
+ this.db = new Database(this.dbPath);
664
+ this.db.pragma('foreign_keys = ON');
665
+ sqliteVec.load(this.db);
666
+ console.log(`Database backed up to: ${backupPath}`);
667
+ }
668
+ catch (error) {
669
+ // Try to reopen database if copy failed
670
+ try {
671
+ this.db = new Database(this.dbPath);
672
+ this.db.pragma('foreign_keys = ON');
673
+ sqliteVec.load(this.db);
674
+ }
675
+ catch {
676
+ // Ignore reopen errors
677
+ }
678
+ throw new Error(`Failed to backup database: ${error instanceof Error ? error.message : error}`);
679
+ }
680
+ }
681
+ /**
682
+ * Close database connection
683
+ */
684
+ close() {
685
+ this.db.close();
686
+ }
687
+ }
688
+ //# sourceMappingURL=client.js.map