@mycodemap/mycodemap 0.5.0 → 0.5.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 (199) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +77 -9
  3. package/dist/cli/commands/analyze.d.ts +18 -0
  4. package/dist/cli/commands/analyze.d.ts.map +1 -1
  5. package/dist/cli/commands/analyze.js +239 -6
  6. package/dist/cli/commands/analyze.js.map +1 -1
  7. package/dist/cli/commands/check.d.ts +22 -0
  8. package/dist/cli/commands/check.d.ts.map +1 -0
  9. package/dist/cli/commands/check.js +168 -0
  10. package/dist/cli/commands/check.js.map +1 -0
  11. package/dist/cli/commands/ci.d.ts +25 -0
  12. package/dist/cli/commands/ci.d.ts.map +1 -1
  13. package/dist/cli/commands/ci.js +139 -36
  14. package/dist/cli/commands/ci.js.map +1 -1
  15. package/dist/cli/commands/complexity.d.ts.map +1 -1
  16. package/dist/cli/commands/complexity.js +6 -0
  17. package/dist/cli/commands/complexity.js.map +1 -1
  18. package/dist/cli/commands/design.d.ts +5 -0
  19. package/dist/cli/commands/design.d.ts.map +1 -1
  20. package/dist/cli/commands/design.js +6 -0
  21. package/dist/cli/commands/design.js.map +1 -1
  22. package/dist/cli/commands/generate.d.ts +1 -0
  23. package/dist/cli/commands/generate.d.ts.map +1 -1
  24. package/dist/cli/commands/generate.js +121 -8
  25. package/dist/cli/commands/generate.js.map +1 -1
  26. package/dist/cli/commands/history.d.ts +26 -0
  27. package/dist/cli/commands/history.d.ts.map +1 -0
  28. package/dist/cli/commands/history.js +92 -0
  29. package/dist/cli/commands/history.js.map +1 -0
  30. package/dist/cli/commands/mcp.d.ts +13 -0
  31. package/dist/cli/commands/mcp.d.ts.map +1 -0
  32. package/dist/cli/commands/mcp.js +108 -0
  33. package/dist/cli/commands/mcp.js.map +1 -0
  34. package/dist/cli/commands/workflow.d.ts.map +1 -1
  35. package/dist/cli/commands/workflow.js +22 -2
  36. package/dist/cli/commands/workflow.js.map +1 -1
  37. package/dist/cli/config-loader.d.ts.map +1 -1
  38. package/dist/cli/config-loader.js +3 -2
  39. package/dist/cli/config-loader.js.map +1 -1
  40. package/dist/cli/contract-checker.d.ts +33 -0
  41. package/dist/cli/contract-checker.d.ts.map +1 -0
  42. package/dist/cli/contract-checker.js +719 -0
  43. package/dist/cli/contract-checker.js.map +1 -0
  44. package/dist/cli/contract-diff-scope.d.ts +14 -0
  45. package/dist/cli/contract-diff-scope.d.ts.map +1 -0
  46. package/dist/cli/contract-diff-scope.js +127 -0
  47. package/dist/cli/contract-diff-scope.js.map +1 -0
  48. package/dist/cli/contract-gate-thresholds.d.ts +14 -0
  49. package/dist/cli/contract-gate-thresholds.d.ts.map +1 -0
  50. package/dist/cli/contract-gate-thresholds.js +19 -0
  51. package/dist/cli/contract-gate-thresholds.js.map +1 -0
  52. package/dist/cli/design-contract-loader.d.ts.map +1 -1
  53. package/dist/cli/design-contract-loader.js +355 -3
  54. package/dist/cli/design-contract-loader.js.map +1 -1
  55. package/dist/cli/design-scope-resolver.d.ts.map +1 -1
  56. package/dist/cli/design-scope-resolver.js +89 -41
  57. package/dist/cli/design-scope-resolver.js.map +1 -1
  58. package/dist/cli/index.js +18 -6
  59. package/dist/cli/index.js.map +1 -1
  60. package/dist/cli/paths.d.ts.map +1 -1
  61. package/dist/cli/paths.js +30 -7
  62. package/dist/cli/paths.js.map +1 -1
  63. package/dist/core/analyzer.d.ts.map +1 -1
  64. package/dist/core/analyzer.js +16 -0
  65. package/dist/core/analyzer.js.map +1 -1
  66. package/dist/domain/entities/CodeGraph.d.ts +5 -1
  67. package/dist/domain/entities/CodeGraph.d.ts.map +1 -1
  68. package/dist/domain/entities/CodeGraph.js +29 -12
  69. package/dist/domain/entities/CodeGraph.js.map +1 -1
  70. package/dist/domain/entities/Dependency.d.ts +8 -1
  71. package/dist/domain/entities/Dependency.d.ts.map +1 -1
  72. package/dist/domain/entities/Dependency.js +19 -4
  73. package/dist/domain/entities/Dependency.js.map +1 -1
  74. package/dist/domain/entities/Symbol.d.ts +2 -1
  75. package/dist/domain/entities/Symbol.d.ts.map +1 -1
  76. package/dist/domain/entities/Symbol.js +6 -3
  77. package/dist/domain/entities/Symbol.js.map +1 -1
  78. package/dist/infrastructure/storage/StorageFactory.d.ts +1 -0
  79. package/dist/infrastructure/storage/StorageFactory.d.ts.map +1 -1
  80. package/dist/infrastructure/storage/StorageFactory.js +7 -2
  81. package/dist/infrastructure/storage/StorageFactory.js.map +1 -1
  82. package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts +3 -1
  83. package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts.map +1 -1
  84. package/dist/infrastructure/storage/adapters/FileSystemStorage.js +10 -2
  85. package/dist/infrastructure/storage/adapters/FileSystemStorage.js.map +1 -1
  86. package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts +3 -1
  87. package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts.map +1 -1
  88. package/dist/infrastructure/storage/adapters/KuzuDBStorage.js +9 -1
  89. package/dist/infrastructure/storage/adapters/KuzuDBStorage.js.map +1 -1
  90. package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts +3 -1
  91. package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts.map +1 -1
  92. package/dist/infrastructure/storage/adapters/MemoryStorage.js +9 -1
  93. package/dist/infrastructure/storage/adapters/MemoryStorage.js.map +1 -1
  94. package/dist/infrastructure/storage/adapters/SQLiteStorage.d.ts +53 -0
  95. package/dist/infrastructure/storage/adapters/SQLiteStorage.d.ts.map +1 -0
  96. package/dist/infrastructure/storage/adapters/SQLiteStorage.js +879 -0
  97. package/dist/infrastructure/storage/adapters/SQLiteStorage.js.map +1 -0
  98. package/dist/infrastructure/storage/graph-helpers.d.ts +3 -1
  99. package/dist/infrastructure/storage/graph-helpers.d.ts.map +1 -1
  100. package/dist/infrastructure/storage/graph-helpers.js +90 -0
  101. package/dist/infrastructure/storage/graph-helpers.js.map +1 -1
  102. package/dist/infrastructure/storage/index.d.ts +1 -1
  103. package/dist/infrastructure/storage/index.d.ts.map +1 -1
  104. package/dist/infrastructure/storage/interfaces/StorageBase.d.ts +3 -1
  105. package/dist/infrastructure/storage/interfaces/StorageBase.d.ts.map +1 -1
  106. package/dist/infrastructure/storage/interfaces/StorageBase.js.map +1 -1
  107. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.d.ts +27 -0
  108. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.d.ts.map +1 -0
  109. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.js +246 -0
  110. package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.js.map +1 -0
  111. package/dist/infrastructure/storage/sqlite/perf-thresholds.d.ts +25 -0
  112. package/dist/infrastructure/storage/sqlite/perf-thresholds.d.ts.map +1 -0
  113. package/dist/infrastructure/storage/sqlite/perf-thresholds.js +25 -0
  114. package/dist/infrastructure/storage/sqlite/perf-thresholds.js.map +1 -0
  115. package/dist/infrastructure/storage/sqlite/schema.d.ts +4 -0
  116. package/dist/infrastructure/storage/sqlite/schema.d.ts.map +1 -0
  117. package/dist/infrastructure/storage/sqlite/schema.js +111 -0
  118. package/dist/infrastructure/storage/sqlite/schema.js.map +1 -0
  119. package/dist/interface/types/design-check.d.ts +73 -0
  120. package/dist/interface/types/design-check.d.ts.map +1 -0
  121. package/dist/interface/types/design-check.js +4 -0
  122. package/dist/interface/types/design-check.js.map +1 -0
  123. package/dist/interface/types/design-contract.d.ts +56 -1
  124. package/dist/interface/types/design-contract.d.ts.map +1 -1
  125. package/dist/interface/types/history-risk.d.ts +90 -0
  126. package/dist/interface/types/history-risk.d.ts.map +1 -0
  127. package/dist/interface/types/history-risk.js +4 -0
  128. package/dist/interface/types/history-risk.js.map +1 -0
  129. package/dist/interface/types/index.d.ts +17 -2
  130. package/dist/interface/types/index.d.ts.map +1 -1
  131. package/dist/interface/types/storage.d.ts +28 -1
  132. package/dist/interface/types/storage.d.ts.map +1 -1
  133. package/dist/orchestrator/adapters/ast-grep-adapter.d.ts +10 -0
  134. package/dist/orchestrator/adapters/ast-grep-adapter.d.ts.map +1 -1
  135. package/dist/orchestrator/adapters/ast-grep-adapter.js +46 -17
  136. package/dist/orchestrator/adapters/ast-grep-adapter.js.map +1 -1
  137. package/dist/orchestrator/adapters/codemap-adapter.d.ts.map +1 -1
  138. package/dist/orchestrator/adapters/codemap-adapter.js +2 -22
  139. package/dist/orchestrator/adapters/codemap-adapter.js.map +1 -1
  140. package/dist/orchestrator/history-risk-service.d.ts +55 -0
  141. package/dist/orchestrator/history-risk-service.d.ts.map +1 -0
  142. package/dist/orchestrator/history-risk-service.js +680 -0
  143. package/dist/orchestrator/history-risk-service.js.map +1 -0
  144. package/dist/orchestrator/types.d.ts +19 -1
  145. package/dist/orchestrator/types.d.ts.map +1 -1
  146. package/dist/orchestrator/types.js +19 -0
  147. package/dist/orchestrator/types.js.map +1 -1
  148. package/dist/server/mcp/index.d.ts +4 -0
  149. package/dist/server/mcp/index.d.ts.map +1 -0
  150. package/dist/server/mcp/index.js +5 -0
  151. package/dist/server/mcp/index.js.map +1 -0
  152. package/dist/server/mcp/server.d.ts +17 -0
  153. package/dist/server/mcp/server.d.ts.map +1 -0
  154. package/dist/server/mcp/server.js +84 -0
  155. package/dist/server/mcp/server.js.map +1 -0
  156. package/dist/server/mcp/service.d.ts +22 -0
  157. package/dist/server/mcp/service.d.ts.map +1 -0
  158. package/dist/server/mcp/service.js +177 -0
  159. package/dist/server/mcp/service.js.map +1 -0
  160. package/dist/server/mcp/types.d.ts +56 -0
  161. package/dist/server/mcp/types.d.ts.map +1 -0
  162. package/dist/server/mcp/types.js +4 -0
  163. package/dist/server/mcp/types.js.map +1 -0
  164. package/docs/AI_ASSISTANT_SETUP.md +1 -1
  165. package/docs/SETUP_GUIDE.md +6 -6
  166. package/docs/ai-guide/COMMANDS.md +98 -4
  167. package/docs/ai-guide/INTEGRATION.md +137 -433
  168. package/docs/ai-guide/OUTPUT.md +476 -6
  169. package/docs/ai-guide/PATTERNS.md +41 -11
  170. package/docs/ai-guide/PROMPTS.md +11 -6
  171. package/docs/backlog.md +177 -0
  172. package/docs/eatdogfood-reports/2026-04-17-eatdogfood-agent-experience.md +231 -0
  173. package/docs/exec-plans/completed/2026-04-17-eatdogfood-codemap-cli.md +103 -0
  174. package/docs/ideation/2026-04-15-executable-architecture-constitution-ideation.md +102 -0
  175. package/docs/product-specs/DESIGN_CONTRACT_TEMPLATE.md +47 -0
  176. package/docs/product-specs/MVP3-ARCHITECTURE-COMPARISON.md +11 -10
  177. package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-PRD.md +10 -10
  178. package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-TECH-PRD.md +17 -12
  179. package/docs/rules/README.md +16 -11
  180. package/docs/rules/architecture-guardrails.md +24 -336
  181. package/docs/rules/code-quality-redlines.md +25 -311
  182. package/docs/rules/engineering-with-codex-openai.md +14 -1
  183. package/docs/rules/validation.md +90 -40
  184. package/mycodemap.config.schema.json +3 -3
  185. package/package.json +7 -2
  186. package/scripts/benchmark-governance-graph.mjs +132 -0
  187. package/scripts/calibrate-contract-gate.mjs +221 -0
  188. package/scripts/capability-report.py +255 -0
  189. package/scripts/qa-rule-control.sh +254 -0
  190. package/scripts/report-high-risk-files.mjs +395 -0
  191. package/scripts/rule-context.mjs +155 -0
  192. package/scripts/smoke-sqlite-impact.mjs +85 -0
  193. package/scripts/sync-analyze-docs.js +1 -0
  194. package/scripts/tests/test_capability_report.py +89 -0
  195. package/scripts/tests/test_rule_control_workflow.py +51 -0
  196. package/scripts/tests/test_validate_rules.py +81 -0
  197. package/scripts/validate-ai-docs.js +283 -1
  198. package/scripts/validate-docs.js +249 -42
  199. package/scripts/validate-rules.py +254 -0
@@ -0,0 +1,879 @@
1
+ // [META] since:2026-04 | owner:architecture-team | stable:false
2
+ // [WHY] SQLite storage adapter - normalized governance truth source for Phase 26
3
+ // ============================================
4
+ // SQLite 存储适配器 - Phase 26 的规范化治理真相源
5
+ // ============================================
6
+ import { mkdir } from 'node:fs/promises';
7
+ import { dirname, join } from 'node:path';
8
+ import { StorageBase, StorageError } from '../interfaces/StorageBase.js';
9
+ import { calculateImpactInGraph, cloneCodeGraph, createEmptyCodeGraph, deserializeCodeGraphSnapshot, detectCyclesInGraph, getProjectStatisticsFromGraph, serializeCodeGraphSnapshot, upsertModuleInGraph, } from '../graph-helpers.js';
10
+ import { CURRENT_SQLITE_SCHEMA_VERSION, SQLITE_GOVERNANCE_SCHEMA_SQL, SQLITE_SCHEMA_VERSION_UPSERT_SQL, } from '../sqlite/schema.js';
11
+ import { GovernanceGraphCache, readGovernanceGraphFromSQLite, } from '../sqlite/GovernanceGraphCache.js';
12
+ import { DEFAULT_GOVERNANCE_GRAPH_PERF_THRESHOLDS, } from '../sqlite/perf-thresholds.js';
13
+ const GRAPH_STATUS_METADATA_KEY = 'graph_status';
14
+ const FAILED_FILE_COUNT_METADATA_KEY = 'failed_file_count';
15
+ const PARSE_FAILURE_FILES_METADATA_KEY = 'parse_failure_files_json';
16
+ const LAST_GRAPH_SYNC_AT_METADATA_KEY = 'last_graph_sync_at';
17
+ async function loadSQLiteModule() {
18
+ const sqliteModule = await import('better-sqlite3');
19
+ return sqliteModule.default;
20
+ }
21
+ function toStringValue(value, fallback = '') {
22
+ return typeof value === 'string' ? value : fallback;
23
+ }
24
+ function toNumberValue(value, fallback = 0) {
25
+ return typeof value === 'number' ? value : Number(value ?? fallback);
26
+ }
27
+ function toOptionalNumberValue(value) {
28
+ if (typeof value === 'number') {
29
+ return value;
30
+ }
31
+ if (value === null || value === undefined) {
32
+ return undefined;
33
+ }
34
+ const parsed = Number(value);
35
+ return Number.isNaN(parsed) ? undefined : parsed;
36
+ }
37
+ function parseJsonValue(value) {
38
+ if (typeof value !== 'string' || value.length === 0) {
39
+ return null;
40
+ }
41
+ try {
42
+ return JSON.parse(value);
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ function toGraphStatus(value) {
49
+ return toStringValue(value) === 'partial' ? 'partial' : 'complete';
50
+ }
51
+ function normalizeParseFailureFiles(value) {
52
+ const parsedValue = parseJsonValue(value);
53
+ if (!Array.isArray(parsedValue)) {
54
+ return [];
55
+ }
56
+ return parsedValue.filter((item) => typeof item === 'string');
57
+ }
58
+ function readGraphIntegrityMetadata(database) {
59
+ const metadataRows = database.prepare(`
60
+ SELECT key, value
61
+ FROM metadata
62
+ WHERE key IN (?, ?, ?)
63
+ `).all(GRAPH_STATUS_METADATA_KEY, FAILED_FILE_COUNT_METADATA_KEY, PARSE_FAILURE_FILES_METADATA_KEY);
64
+ const metadataMap = new Map(metadataRows.map(row => [toStringValue(row.key), row.value]));
65
+ const parseFailureFiles = normalizeParseFailureFiles(metadataMap.get(PARSE_FAILURE_FILES_METADATA_KEY));
66
+ return {
67
+ graphStatus: toGraphStatus(metadataMap.get(GRAPH_STATUS_METADATA_KEY)),
68
+ failedFileCount: toNumberValue(metadataMap.get(FAILED_FILE_COUNT_METADATA_KEY), parseFailureFiles.length),
69
+ parseFailureFiles,
70
+ };
71
+ }
72
+ function readGraphMetadata(database) {
73
+ const countsRow = database
74
+ .prepare(`
75
+ SELECT
76
+ (SELECT COUNT(*) FROM modules) AS module_count,
77
+ (SELECT COUNT(*) FROM symbols) AS symbol_count
78
+ `)
79
+ .get();
80
+ const metadataRows = database
81
+ .prepare(`
82
+ SELECT key, value
83
+ FROM metadata
84
+ WHERE key IN (?, ?, ?, ?)
85
+ `)
86
+ .all(GRAPH_STATUS_METADATA_KEY, FAILED_FILE_COUNT_METADATA_KEY, PARSE_FAILURE_FILES_METADATA_KEY, LAST_GRAPH_SYNC_AT_METADATA_KEY);
87
+ const metadataMap = new Map(metadataRows.map(row => [toStringValue(row.key), row.value]));
88
+ const parseFailureFiles = normalizeParseFailureFiles(metadataMap.get(PARSE_FAILURE_FILES_METADATA_KEY));
89
+ const moduleCount = toNumberValue(countsRow?.module_count);
90
+ const symbolCount = toNumberValue(countsRow?.symbol_count);
91
+ const hasMaterializedGraph = moduleCount > 0 || symbolCount > 0;
92
+ return {
93
+ generatedAt: hasMaterializedGraph
94
+ ? toStringValue(metadataMap.get(LAST_GRAPH_SYNC_AT_METADATA_KEY)) || null
95
+ : null,
96
+ graphStatus: toGraphStatus(metadataMap.get(GRAPH_STATUS_METADATA_KEY)),
97
+ failedFileCount: toNumberValue(metadataMap.get(FAILED_FILE_COUNT_METADATA_KEY), parseFailureFiles.length),
98
+ parseFailureFiles,
99
+ moduleCount,
100
+ symbolCount,
101
+ };
102
+ }
103
+ function createHistorySnapshotId(recordedAt) {
104
+ const compactTimestamp = recordedAt.replace(/[^0-9]/g, '');
105
+ const entropy = Math.random().toString(16).slice(2, 10);
106
+ return `history-${compactTimestamp}-${entropy}`;
107
+ }
108
+ function inferEntityType(entityId, symbolIds) {
109
+ return symbolIds.has(entityId) ? 'symbol' : 'module';
110
+ }
111
+ function resolveEntityType(entityType, entityId, symbolIds) {
112
+ return entityType ?? inferEntityType(entityId, symbolIds);
113
+ }
114
+ function hasColumn(database, tableName, columnName) {
115
+ const rows = database.prepare(`PRAGMA table_info(${tableName})`).all();
116
+ return rows.some((row) => toStringValue(row.name) === columnName);
117
+ }
118
+ function addColumnIfMissing(database, tableName, columnName, definition) {
119
+ if (!hasColumn(database, tableName, columnName)) {
120
+ database.exec(`ALTER TABLE ${tableName} ADD COLUMN ${definition}`);
121
+ }
122
+ }
123
+ function createUnavailableHistoryDiagnostics(reason) {
124
+ return {
125
+ status: 'unavailable',
126
+ confidence: 'unavailable',
127
+ freshness: 'unknown',
128
+ source: 'unavailable',
129
+ reasons: [reason],
130
+ analyzedAt: null,
131
+ scopeMode: 'partial',
132
+ requestedFiles: 0,
133
+ analyzedFiles: 0,
134
+ requiresPrecompute: false,
135
+ };
136
+ }
137
+ function createUnavailableSymbolHistoryResult(query, reason) {
138
+ return {
139
+ query,
140
+ candidates: [],
141
+ symbol: null,
142
+ files: [],
143
+ timeline: [],
144
+ risk: {
145
+ level: 'unavailable',
146
+ score: null,
147
+ gravity: null,
148
+ heat: null,
149
+ impact: null,
150
+ riskFactors: [reason],
151
+ },
152
+ diagnostics: createUnavailableHistoryDiagnostics(reason),
153
+ };
154
+ }
155
+ function removeModuleAndOwnedRelations(graph, moduleId) {
156
+ const nextGraph = cloneCodeGraph(graph);
157
+ const removedSymbolIds = new Set(nextGraph.symbols
158
+ .filter(symbol => symbol.moduleId === moduleId)
159
+ .map(symbol => symbol.id));
160
+ nextGraph.modules = nextGraph.modules.filter(module => module.id !== moduleId);
161
+ nextGraph.symbols = nextGraph.symbols.filter(symbol => symbol.moduleId !== moduleId);
162
+ nextGraph.dependencies = nextGraph.dependencies.filter(dependency => dependency.sourceId !== moduleId
163
+ && dependency.targetId !== moduleId
164
+ && !removedSymbolIds.has(dependency.sourceId)
165
+ && !removedSymbolIds.has(dependency.targetId));
166
+ return nextGraph;
167
+ }
168
+ export class SQLiteStorage extends StorageBase {
169
+ type = 'sqlite';
170
+ database = null;
171
+ storageConfig;
172
+ runtimeOptions;
173
+ governanceGraphCache = null;
174
+ constructor(config, runtimeOptions = {}) {
175
+ super();
176
+ this.storageConfig = config;
177
+ this.runtimeOptions = runtimeOptions;
178
+ }
179
+ async doInitialize() {
180
+ if (!this.projectPath) {
181
+ throw new StorageError('Project path not set', 'PROJECT_PATH_NOT_SET');
182
+ }
183
+ try {
184
+ const databasePath = this.storageConfig.databasePath
185
+ ? join(this.projectPath, this.storageConfig.databasePath)
186
+ : join(this.projectPath, '.codemap', 'governance.sqlite');
187
+ await mkdir(dirname(databasePath), { recursive: true });
188
+ const Database = await loadSQLiteModule();
189
+ this.database = new Database(databasePath);
190
+ this.database.pragma?.('journal_mode = WAL');
191
+ this.database.pragma?.('foreign_keys = ON');
192
+ this.database.exec(SQLITE_GOVERNANCE_SCHEMA_SQL);
193
+ this.ensureSchemaColumns(this.database);
194
+ this.database
195
+ .prepare(SQLITE_SCHEMA_VERSION_UPSERT_SQL)
196
+ .run('schema_version', CURRENT_SQLITE_SCHEMA_VERSION);
197
+ this.backfillLegacySnapshotIfNeeded(this.database);
198
+ this.refreshGovernanceGraphCache(this.database);
199
+ }
200
+ catch (error) {
201
+ throw new StorageError('Failed to initialize SQLite storage', 'SQLITE_INIT_FAILED', error);
202
+ }
203
+ }
204
+ async doClose() {
205
+ if (this.database) {
206
+ this.database.close();
207
+ this.database = null;
208
+ }
209
+ this.governanceGraphCache = null;
210
+ }
211
+ async saveCodeGraph(graph) {
212
+ const database = this.getDatabase();
213
+ this.replaceCurrentGraph(database, graph, 'save-code-graph');
214
+ }
215
+ async loadCodeGraph() {
216
+ return this.readCodeGraph(this.getDatabase());
217
+ }
218
+ async loadGraphMetadata() {
219
+ return readGraphMetadata(this.getDatabase());
220
+ }
221
+ async deleteProject() {
222
+ const database = this.getDatabase();
223
+ this.runInTransaction(database, () => {
224
+ database.prepare('DELETE FROM history_relations').run();
225
+ database.prepare('DELETE FROM history_snapshots').run();
226
+ database.prepare('DELETE FROM dependencies').run();
227
+ database.prepare('DELETE FROM symbols').run();
228
+ database.prepare('DELETE FROM modules').run();
229
+ database.prepare('DELETE FROM projects').run();
230
+ database.prepare('DELETE FROM snapshots').run();
231
+ });
232
+ this.refreshGovernanceGraphCache(database);
233
+ }
234
+ async updateModule(module) {
235
+ const currentGraph = await this.loadCodeGraph();
236
+ await this.saveCodeGraph(upsertModuleInGraph(currentGraph, module));
237
+ }
238
+ async deleteModule(moduleId) {
239
+ const currentGraph = await this.loadCodeGraph();
240
+ await this.saveCodeGraph(removeModuleAndOwnedRelations(currentGraph, moduleId));
241
+ }
242
+ async findModuleById(id) {
243
+ const row = this.getDatabase()
244
+ .prepare(`
245
+ SELECT id, project_id, path, language, lines, code_lines, comment_lines, blank_lines
246
+ FROM modules
247
+ WHERE id = ?
248
+ LIMIT 1
249
+ `)
250
+ .get(id);
251
+ return row ? this.mapModuleRow(row) : null;
252
+ }
253
+ async findModulesByPath(path) {
254
+ const rows = this.getDatabase()
255
+ .prepare(`
256
+ SELECT id, project_id, path, language, lines, code_lines, comment_lines, blank_lines
257
+ FROM modules
258
+ WHERE instr(path, ?) > 0
259
+ ORDER BY path, id
260
+ `)
261
+ .all(path);
262
+ return rows.map(row => this.mapModuleRow(row));
263
+ }
264
+ async findSymbolByName(name) {
265
+ const rows = this.getDatabase()
266
+ .prepare(`
267
+ SELECT id, module_id, name, kind, signature, file_path, line, column_number, end_line, end_column, visibility
268
+ FROM symbols
269
+ WHERE instr(name, ?) > 0
270
+ ORDER BY name, id
271
+ `)
272
+ .all(name);
273
+ return rows.map(row => this.mapSymbolRow(row));
274
+ }
275
+ async findSymbolById(id) {
276
+ const row = this.getDatabase()
277
+ .prepare(`
278
+ SELECT id, module_id, name, kind, signature, file_path, line, column_number, end_line, end_column, visibility
279
+ FROM symbols
280
+ WHERE id = ?
281
+ LIMIT 1
282
+ `)
283
+ .get(id);
284
+ return row ? this.mapSymbolRow(row) : null;
285
+ }
286
+ async findDependencies(moduleId) {
287
+ const cachedDependencies = this.governanceGraphCache?.findDependencies(moduleId);
288
+ if (cachedDependencies) {
289
+ return cachedDependencies;
290
+ }
291
+ const rows = this.getDatabase()
292
+ .prepare(`
293
+ SELECT id, source_id, source_entity_type, target_id, target_entity_type, dependency_type, file_path, line, confidence
294
+ FROM dependencies
295
+ WHERE source_id = ?
296
+ ORDER BY id
297
+ `)
298
+ .all(moduleId);
299
+ return rows.map(row => this.mapDependencyRow(row));
300
+ }
301
+ async findDependents(moduleId) {
302
+ const cachedDependents = this.governanceGraphCache?.findDependents(moduleId);
303
+ if (cachedDependents) {
304
+ return cachedDependents;
305
+ }
306
+ const rows = this.getDatabase()
307
+ .prepare(`
308
+ SELECT id, source_id, source_entity_type, target_id, target_entity_type, dependency_type, file_path, line, confidence
309
+ FROM dependencies
310
+ WHERE target_id = ?
311
+ ORDER BY id
312
+ `)
313
+ .all(moduleId);
314
+ return rows.map(row => this.mapDependencyRow(row));
315
+ }
316
+ async findCallers(functionId) {
317
+ const rows = this.getDatabase()
318
+ .prepare(`
319
+ SELECT s.id, s.module_id, s.name, s.kind, s.signature, s.file_path, s.line, s.column_number, s.end_line, s.end_column, s.visibility
320
+ FROM dependencies d
321
+ INNER JOIN symbols s ON s.id = d.source_id
322
+ WHERE d.target_id = ?
323
+ AND d.dependency_type = 'call'
324
+ ORDER BY s.id
325
+ `)
326
+ .all(functionId);
327
+ return rows.map(row => this.mapSymbolRow(row));
328
+ }
329
+ async findCallees(functionId) {
330
+ const rows = this.getDatabase()
331
+ .prepare(`
332
+ SELECT s.id, s.module_id, s.name, s.kind, s.signature, s.file_path, s.line, s.column_number, s.end_line, s.end_column, s.visibility
333
+ FROM dependencies d
334
+ INNER JOIN symbols s ON s.id = d.target_id
335
+ WHERE d.source_id = ?
336
+ AND d.dependency_type = 'call'
337
+ ORDER BY s.id
338
+ `)
339
+ .all(functionId);
340
+ return rows.map(row => this.mapSymbolRow(row));
341
+ }
342
+ async detectCycles() {
343
+ const cachedCycles = this.governanceGraphCache?.detectCycles();
344
+ if (cachedCycles) {
345
+ return cachedCycles;
346
+ }
347
+ return detectCyclesInGraph(this.readGovernanceGraphForAnalysis(this.getDatabase()));
348
+ }
349
+ async calculateImpact(moduleId, depth) {
350
+ const cachedImpact = this.governanceGraphCache?.calculateImpact(moduleId, depth);
351
+ if (cachedImpact) {
352
+ return cachedImpact;
353
+ }
354
+ return calculateImpactInGraph(this.readGovernanceGraphForAnalysis(this.getDatabase()), moduleId, depth);
355
+ }
356
+ async calculateSymbolImpact(symbolId, depth, limit) {
357
+ const database = this.getDatabase();
358
+ const rootSymbol = await this.findSymbolById(symbolId);
359
+ if (!rootSymbol) {
360
+ throw new StorageError(`Symbol ${symbolId} not found`, 'SYMBOL_NOT_FOUND');
361
+ }
362
+ const selectCallers = database.prepare(`
363
+ SELECT s.id, s.module_id, s.name, s.kind, s.signature, s.file_path, s.line, s.column_number, s.end_line, s.end_column, s.visibility
364
+ FROM dependencies d
365
+ INNER JOIN symbols s ON s.id = d.source_id
366
+ WHERE d.target_id = ?
367
+ AND d.dependency_type = 'call'
368
+ ORDER BY d.id, s.id
369
+ `);
370
+ const affectedSymbols = [];
371
+ const visited = new Set([symbolId]);
372
+ const queue = [{
373
+ id: symbolId,
374
+ level: 0,
375
+ path: [symbolId],
376
+ }];
377
+ let truncated = false;
378
+ while (queue.length > 0) {
379
+ const current = queue.shift();
380
+ if (!current) {
381
+ continue;
382
+ }
383
+ if (current.level >= depth) {
384
+ continue;
385
+ }
386
+ const callerRows = selectCallers.all(current.id);
387
+ for (const row of callerRows) {
388
+ if (affectedSymbols.length >= limit) {
389
+ truncated = true;
390
+ queue.length = 0;
391
+ break;
392
+ }
393
+ const callerId = toStringValue(row.id);
394
+ if (visited.has(callerId)) {
395
+ continue;
396
+ }
397
+ visited.add(callerId);
398
+ const callerSymbol = this.mapSymbolRow(row);
399
+ const nextLevel = current.level + 1;
400
+ const nextPath = [...current.path, callerId];
401
+ affectedSymbols.push({
402
+ symbol: callerSymbol,
403
+ depth: nextLevel,
404
+ path: nextPath,
405
+ });
406
+ queue.push({
407
+ id: callerId,
408
+ level: nextLevel,
409
+ path: nextPath,
410
+ });
411
+ }
412
+ }
413
+ return {
414
+ rootSymbol,
415
+ affectedSymbols,
416
+ depth,
417
+ limit,
418
+ truncated,
419
+ };
420
+ }
421
+ async getStatistics() {
422
+ const database = this.getDatabase();
423
+ const row = database
424
+ .prepare(`
425
+ SELECT
426
+ (SELECT COUNT(*) FROM modules) AS total_modules,
427
+ (SELECT COUNT(*) FROM symbols) AS total_symbols,
428
+ (SELECT COUNT(*) FROM dependencies) AS total_dependencies,
429
+ (SELECT COALESCE(SUM(lines), 0) FROM modules) AS total_lines
430
+ `)
431
+ .get();
432
+ if (!row) {
433
+ return getProjectStatisticsFromGraph(createEmptyCodeGraph(this.projectPath ?? ''));
434
+ }
435
+ return {
436
+ totalModules: toNumberValue(row.total_modules),
437
+ totalSymbols: toNumberValue(row.total_symbols),
438
+ totalDependencies: toNumberValue(row.total_dependencies),
439
+ totalLines: toNumberValue(row.total_lines),
440
+ averageComplexity: 0,
441
+ };
442
+ }
443
+ async saveHistoryRiskSnapshot(payload) {
444
+ const database = this.getDatabase();
445
+ const recordedAt = payload.recordedAt ?? new Date().toISOString();
446
+ const snapshotId = createHistorySnapshotId(recordedAt);
447
+ const projectId = toStringValue(database.prepare('SELECT id FROM projects LIMIT 1').get()?.id, 'history-risk-project');
448
+ const fileSignals = payload.fileSignals ?? [];
449
+ const symbolSignals = payload.symbolSignals ?? [];
450
+ const relationCount = fileSignals.reduce((sum, signal) => sum + signal.timeline.length + 1, 0)
451
+ + symbolSignals.reduce((sum, signal) => sum + signal.timeline.length + 1, 0);
452
+ const insertSnapshot = database.prepare(`
453
+ INSERT INTO history_snapshots (
454
+ id, project_id, recorded_at, snapshot_source, module_count, symbol_count, dependency_count
455
+ )
456
+ VALUES (?, ?, ?, ?, ?, ?, ?)
457
+ `);
458
+ const insertRelation = database.prepare(`
459
+ INSERT INTO history_relations (
460
+ id, snapshot_id, relation_type, source_id, source_entity_type, target_id, target_entity_type, observed_at, metadata_json
461
+ )
462
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
463
+ `);
464
+ this.runInTransaction(database, () => {
465
+ insertSnapshot.run(snapshotId, projectId, recordedAt, payload.source, fileSignals.length, symbolSignals.length, relationCount);
466
+ for (const signal of fileSignals) {
467
+ insertRelation.run(`${snapshotId}:file-signal:${signal.file}`, snapshotId, 'file_history_signal', signal.file, 'module', null, null, recordedAt, JSON.stringify({
468
+ file: signal.file,
469
+ risk: signal.risk,
470
+ diagnostics: signal.diagnostics,
471
+ }));
472
+ for (const entry of signal.timeline) {
473
+ insertRelation.run(`${snapshotId}:file-commit:${signal.file}:${entry.hash}`, snapshotId, 'file_history_commit', signal.file, 'module', entry.hash, 'commit', entry.date, JSON.stringify(entry));
474
+ }
475
+ }
476
+ for (const signal of symbolSignals) {
477
+ const symbolId = signal.symbol?.symbolId;
478
+ if (!symbolId) {
479
+ continue;
480
+ }
481
+ insertRelation.run(`${snapshotId}:symbol-signal:${symbolId}`, snapshotId, 'symbol_history_signal', symbolId, 'symbol', signal.symbol?.moduleId ?? null, signal.symbol ? 'module' : null, recordedAt, JSON.stringify({
482
+ query: signal.query,
483
+ candidates: signal.candidates,
484
+ symbol: signal.symbol,
485
+ files: signal.files,
486
+ risk: signal.risk,
487
+ diagnostics: signal.diagnostics,
488
+ }));
489
+ for (const entry of signal.timeline) {
490
+ insertRelation.run(`${snapshotId}:symbol-commit:${symbolId}:${entry.hash}`, snapshotId, 'symbol_history_commit', symbolId, 'symbol', entry.hash, 'commit', entry.date, JSON.stringify(entry));
491
+ }
492
+ }
493
+ database
494
+ .prepare(SQLITE_SCHEMA_VERSION_UPSERT_SQL)
495
+ .run('last_history_risk_sync_at', recordedAt);
496
+ });
497
+ return {
498
+ snapshotId,
499
+ recordedAt,
500
+ source: payload.source,
501
+ };
502
+ }
503
+ async loadLatestFileHistorySignal(file) {
504
+ const database = this.getDatabase();
505
+ const row = database
506
+ .prepare(`
507
+ SELECT snapshot_id, metadata_json
508
+ FROM history_relations
509
+ WHERE relation_type = 'file_history_signal'
510
+ AND source_id = ?
511
+ ORDER BY observed_at DESC
512
+ LIMIT 1
513
+ `)
514
+ .get(file);
515
+ if (!row) {
516
+ return null;
517
+ }
518
+ const metadata = parseJsonValue(row.metadata_json);
519
+ if (!metadata) {
520
+ return {
521
+ file,
522
+ risk: {
523
+ level: 'unavailable',
524
+ score: null,
525
+ gravity: null,
526
+ heat: null,
527
+ impact: null,
528
+ riskFactors: ['stored file history metadata is invalid'],
529
+ },
530
+ timeline: [],
531
+ diagnostics: createUnavailableHistoryDiagnostics('stored file history metadata is invalid'),
532
+ };
533
+ }
534
+ const timelineRows = database
535
+ .prepare(`
536
+ SELECT metadata_json
537
+ FROM history_relations
538
+ WHERE relation_type = 'file_history_commit'
539
+ AND source_id = ?
540
+ AND snapshot_id = ?
541
+ ORDER BY observed_at DESC, target_id DESC
542
+ `)
543
+ .all(file, toStringValue(row.snapshot_id));
544
+ const timeline = timelineRows
545
+ .map((timelineRow) => parseJsonValue(timelineRow.metadata_json))
546
+ .filter((entry) => entry !== null)
547
+ .sort((left, right) => right.date.localeCompare(left.date));
548
+ return {
549
+ file: metadata.file,
550
+ risk: metadata.risk,
551
+ timeline,
552
+ diagnostics: metadata.diagnostics,
553
+ };
554
+ }
555
+ async loadLatestSymbolHistoryResult(symbolId, query = symbolId) {
556
+ const database = this.getDatabase();
557
+ const row = database
558
+ .prepare(`
559
+ SELECT snapshot_id, metadata_json
560
+ FROM history_relations
561
+ WHERE relation_type = 'symbol_history_signal'
562
+ AND source_id = ?
563
+ ORDER BY observed_at DESC
564
+ LIMIT 1
565
+ `)
566
+ .get(symbolId);
567
+ if (!row) {
568
+ return createUnavailableSymbolHistoryResult(query, 'no materialized history snapshot found for symbol');
569
+ }
570
+ const metadata = parseJsonValue(row.metadata_json);
571
+ if (!metadata) {
572
+ return createUnavailableSymbolHistoryResult(query, 'stored symbol history metadata is invalid');
573
+ }
574
+ const timelineRows = database
575
+ .prepare(`
576
+ SELECT metadata_json
577
+ FROM history_relations
578
+ WHERE relation_type = 'symbol_history_commit'
579
+ AND source_id = ?
580
+ AND snapshot_id = ?
581
+ ORDER BY observed_at DESC, target_id DESC
582
+ `)
583
+ .all(symbolId, toStringValue(row.snapshot_id));
584
+ const timeline = timelineRows
585
+ .map((timelineRow) => parseJsonValue(timelineRow.metadata_json))
586
+ .filter((entry) => entry !== null)
587
+ .sort((left, right) => right.date.localeCompare(left.date));
588
+ return {
589
+ query: metadata.query || query,
590
+ candidates: metadata.candidates,
591
+ symbol: metadata.symbol,
592
+ files: metadata.files,
593
+ timeline,
594
+ risk: metadata.risk,
595
+ diagnostics: metadata.diagnostics,
596
+ };
597
+ }
598
+ getGovernanceGraphRuntimeStats() {
599
+ return this.governanceGraphCache?.getStats() ?? {
600
+ cacheMode: 'sqlite-direct',
601
+ thresholds: this.runtimeOptions.governanceGraphThresholds ?? DEFAULT_GOVERNANCE_GRAPH_PERF_THRESHOLDS,
602
+ moduleCount: 0,
603
+ dependencyCount: 0,
604
+ loadMs: 0,
605
+ rssDeltaMb: 0,
606
+ warning: 'governance graph cache not initialized',
607
+ };
608
+ }
609
+ ensureSchemaColumns(database) {
610
+ addColumnIfMissing(database, 'symbols', 'signature', 'signature TEXT');
611
+ addColumnIfMissing(database, 'dependencies', 'file_path', 'file_path TEXT');
612
+ addColumnIfMissing(database, 'dependencies', 'line', 'line INTEGER');
613
+ addColumnIfMissing(database, 'dependencies', 'confidence', 'confidence TEXT');
614
+ }
615
+ backfillLegacySnapshotIfNeeded(database) {
616
+ const hasCurrentProject = toNumberValue(database.prepare('SELECT COUNT(*) AS count FROM projects').get()?.count) > 0;
617
+ if (hasCurrentProject) {
618
+ return;
619
+ }
620
+ const legacySnapshot = database
621
+ .prepare(`
622
+ SELECT graph_json, updated_at
623
+ FROM snapshots
624
+ ORDER BY updated_at DESC
625
+ LIMIT 1
626
+ `)
627
+ .get();
628
+ const snapshotJson = toStringValue(legacySnapshot?.graph_json);
629
+ if (!snapshotJson) {
630
+ return;
631
+ }
632
+ const recordedAt = toStringValue(legacySnapshot?.updated_at, new Date().toISOString());
633
+ const graph = deserializeCodeGraphSnapshot(snapshotJson, this.projectPath ?? '');
634
+ this.replaceCurrentGraph(database, graph, 'legacy-snapshot-backfill', recordedAt);
635
+ database
636
+ .prepare(SQLITE_SCHEMA_VERSION_UPSERT_SQL)
637
+ .run('legacy_snapshot_backfilled_at', recordedAt);
638
+ }
639
+ replaceCurrentGraph(database, graph, historySource, recordedAt = new Date().toISOString()) {
640
+ const normalizedGraph = this.normalizeGraph(graph);
641
+ const symbolIds = new Set(normalizedGraph.symbols.map(symbol => symbol.id));
642
+ const upsertMetadata = database.prepare(SQLITE_SCHEMA_VERSION_UPSERT_SQL);
643
+ const insertProject = database.prepare(`
644
+ INSERT INTO projects (id, name, root_path, created_at, updated_at)
645
+ VALUES (?, ?, ?, ?, ?)
646
+ `);
647
+ const insertModule = database.prepare(`
648
+ INSERT INTO modules (
649
+ id, project_id, path, language, lines, code_lines, comment_lines, blank_lines
650
+ )
651
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
652
+ `);
653
+ const insertSymbol = database.prepare(`
654
+ INSERT INTO symbols (
655
+ id, module_id, name, kind, signature, file_path, line, column_number, end_line, end_column, visibility
656
+ )
657
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
658
+ `);
659
+ const insertDependency = database.prepare(`
660
+ INSERT INTO dependencies (
661
+ id, source_id, source_entity_type, target_id, target_entity_type, dependency_type, file_path, line, confidence
662
+ )
663
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
664
+ `);
665
+ const insertSnapshotMirror = database.prepare(`
666
+ INSERT INTO snapshots (id, project_id, graph_json, updated_at)
667
+ VALUES (?, ?, ?, ?)
668
+ `);
669
+ const insertHistorySnapshot = database.prepare(`
670
+ INSERT INTO history_snapshots (
671
+ id, project_id, recorded_at, snapshot_source, module_count, symbol_count, dependency_count
672
+ )
673
+ VALUES (?, ?, ?, ?, ?, ?, ?)
674
+ `);
675
+ const insertHistoryRelation = database.prepare(`
676
+ INSERT INTO history_relations (
677
+ id, snapshot_id, relation_type, source_id, source_entity_type, target_id, target_entity_type, observed_at, metadata_json
678
+ )
679
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
680
+ `);
681
+ const snapshotId = createHistorySnapshotId(recordedAt);
682
+ this.runInTransaction(database, () => {
683
+ database.prepare('DELETE FROM dependencies').run();
684
+ database.prepare('DELETE FROM symbols').run();
685
+ database.prepare('DELETE FROM modules').run();
686
+ database.prepare('DELETE FROM projects').run();
687
+ database.prepare('DELETE FROM snapshots').run();
688
+ insertProject.run(normalizedGraph.project.id, normalizedGraph.project.name, normalizedGraph.project.rootPath, normalizedGraph.project.createdAt.toISOString(), normalizedGraph.project.updatedAt.toISOString());
689
+ for (const module of normalizedGraph.modules) {
690
+ insertModule.run(module.id, module.projectId, module.path, module.language, module.stats.lines, module.stats.codeLines, module.stats.commentLines, module.stats.blankLines);
691
+ }
692
+ for (const symbol of normalizedGraph.symbols) {
693
+ insertSymbol.run(symbol.id, symbol.moduleId, symbol.name, symbol.kind, symbol.signature ?? null, symbol.location.file, symbol.location.line, symbol.location.column, symbol.location.endLine ?? null, symbol.location.endColumn ?? null, symbol.visibility);
694
+ }
695
+ for (const dependency of normalizedGraph.dependencies) {
696
+ const sourceEntityType = resolveEntityType(dependency.sourceEntityType, dependency.sourceId, symbolIds);
697
+ const targetEntityType = resolveEntityType(dependency.targetEntityType, dependency.targetId, symbolIds);
698
+ insertDependency.run(dependency.id, dependency.sourceId, sourceEntityType, dependency.targetId, targetEntityType, dependency.type, dependency.filePath ?? null, dependency.line ?? null, dependency.confidence ?? null);
699
+ }
700
+ insertSnapshotMirror.run('codemap-snapshot', normalizedGraph.project.id, serializeCodeGraphSnapshot(normalizedGraph), recordedAt);
701
+ insertHistorySnapshot.run(snapshotId, normalizedGraph.project.id, recordedAt, historySource, normalizedGraph.modules.length, normalizedGraph.symbols.length, normalizedGraph.dependencies.length);
702
+ for (const module of normalizedGraph.modules) {
703
+ insertHistoryRelation.run(`${snapshotId}:module:${module.id}`, snapshotId, 'module_snapshot', module.id, 'module', null, null, recordedAt, JSON.stringify({
704
+ path: module.path,
705
+ language: module.language,
706
+ }));
707
+ }
708
+ for (const symbol of normalizedGraph.symbols) {
709
+ insertHistoryRelation.run(`${snapshotId}:symbol:${symbol.id}`, snapshotId, 'symbol_snapshot', symbol.id, 'symbol', symbol.moduleId, 'module', recordedAt, JSON.stringify({
710
+ name: symbol.name,
711
+ kind: symbol.kind,
712
+ signature: symbol.signature ?? null,
713
+ }));
714
+ }
715
+ for (const dependency of normalizedGraph.dependencies) {
716
+ const sourceEntityType = resolveEntityType(dependency.sourceEntityType, dependency.sourceId, symbolIds);
717
+ const targetEntityType = resolveEntityType(dependency.targetEntityType, dependency.targetId, symbolIds);
718
+ insertHistoryRelation.run(`${snapshotId}:dependency:${dependency.id}`, snapshotId, 'dependency_snapshot', dependency.sourceId, sourceEntityType, dependency.targetId, targetEntityType, recordedAt, JSON.stringify({
719
+ dependencyId: dependency.id,
720
+ dependencyType: dependency.type,
721
+ confidence: dependency.confidence ?? null,
722
+ filePath: dependency.filePath ?? null,
723
+ line: dependency.line ?? null,
724
+ }));
725
+ }
726
+ upsertMetadata.run(GRAPH_STATUS_METADATA_KEY, normalizedGraph.graphStatus ?? 'complete');
727
+ upsertMetadata.run(FAILED_FILE_COUNT_METADATA_KEY, String(normalizedGraph.failedFileCount ?? 0));
728
+ upsertMetadata.run(PARSE_FAILURE_FILES_METADATA_KEY, JSON.stringify(normalizedGraph.parseFailureFiles ?? []));
729
+ upsertMetadata.run(LAST_GRAPH_SYNC_AT_METADATA_KEY, recordedAt);
730
+ });
731
+ this.refreshGovernanceGraphCache(database);
732
+ }
733
+ normalizeGraph(graph) {
734
+ const projectRootPath = graph.project.rootPath || this.projectPath || '';
735
+ return {
736
+ project: {
737
+ ...graph.project,
738
+ rootPath: projectRootPath,
739
+ createdAt: new Date(graph.project.createdAt),
740
+ updatedAt: new Date(graph.project.updatedAt),
741
+ },
742
+ modules: graph.modules.map(module => ({
743
+ ...module,
744
+ stats: { ...module.stats },
745
+ })),
746
+ symbols: graph.symbols.map(symbol => ({
747
+ ...symbol,
748
+ location: { ...symbol.location },
749
+ })),
750
+ dependencies: graph.dependencies.map(dependency => ({ ...dependency })),
751
+ graphStatus: graph.graphStatus ?? 'complete',
752
+ failedFileCount: graph.failedFileCount ?? 0,
753
+ parseFailureFiles: [...(graph.parseFailureFiles ?? [])],
754
+ };
755
+ }
756
+ readCodeGraph(database) {
757
+ const projectRow = database
758
+ .prepare(`
759
+ SELECT id, name, root_path, created_at, updated_at
760
+ FROM projects
761
+ LIMIT 1
762
+ `)
763
+ .get();
764
+ if (!projectRow) {
765
+ return createEmptyCodeGraph(this.projectPath ?? '');
766
+ }
767
+ const modules = database
768
+ .prepare(`
769
+ SELECT id, project_id, path, language, lines, code_lines, comment_lines, blank_lines
770
+ FROM modules
771
+ ORDER BY path, id
772
+ `)
773
+ .all()
774
+ .map(row => this.mapModuleRow(row));
775
+ const symbols = database
776
+ .prepare(`
777
+ SELECT id, module_id, name, kind, signature, file_path, line, column_number, end_line, end_column, visibility
778
+ FROM symbols
779
+ ORDER BY file_path, line, column_number, id
780
+ `)
781
+ .all()
782
+ .map(row => this.mapSymbolRow(row));
783
+ const dependencies = database
784
+ .prepare(`
785
+ SELECT id, source_id, source_entity_type, target_id, target_entity_type, dependency_type, file_path, line, confidence
786
+ FROM dependencies
787
+ ORDER BY id
788
+ `)
789
+ .all()
790
+ .map(row => this.mapDependencyRow(row));
791
+ const graphIntegrity = readGraphIntegrityMetadata(database);
792
+ return {
793
+ project: {
794
+ id: toStringValue(projectRow.id),
795
+ name: toStringValue(projectRow.name),
796
+ rootPath: toStringValue(projectRow.root_path, this.projectPath ?? ''),
797
+ createdAt: new Date(toStringValue(projectRow.created_at)),
798
+ updatedAt: new Date(toStringValue(projectRow.updated_at)),
799
+ },
800
+ modules,
801
+ symbols,
802
+ dependencies,
803
+ graphStatus: graphIntegrity.graphStatus,
804
+ failedFileCount: graphIntegrity.failedFileCount,
805
+ parseFailureFiles: graphIntegrity.parseFailureFiles,
806
+ };
807
+ }
808
+ mapModuleRow(row) {
809
+ return {
810
+ id: toStringValue(row.id),
811
+ projectId: toStringValue(row.project_id),
812
+ path: toStringValue(row.path),
813
+ language: toStringValue(row.language),
814
+ stats: {
815
+ lines: toNumberValue(row.lines),
816
+ codeLines: toNumberValue(row.code_lines),
817
+ commentLines: toNumberValue(row.comment_lines),
818
+ blankLines: toNumberValue(row.blank_lines),
819
+ },
820
+ };
821
+ }
822
+ mapSymbolRow(row) {
823
+ return {
824
+ id: toStringValue(row.id),
825
+ moduleId: toStringValue(row.module_id),
826
+ name: toStringValue(row.name),
827
+ kind: toStringValue(row.kind),
828
+ signature: toStringValue(row.signature) || undefined,
829
+ location: {
830
+ file: toStringValue(row.file_path),
831
+ line: toNumberValue(row.line),
832
+ column: toNumberValue(row.column_number),
833
+ endLine: toOptionalNumberValue(row.end_line),
834
+ endColumn: toOptionalNumberValue(row.end_column),
835
+ },
836
+ visibility: toStringValue(row.visibility),
837
+ };
838
+ }
839
+ mapDependencyRow(row) {
840
+ return {
841
+ id: toStringValue(row.id),
842
+ sourceId: toStringValue(row.source_id),
843
+ sourceEntityType: toStringValue(row.source_entity_type, 'module'),
844
+ targetId: toStringValue(row.target_id),
845
+ targetEntityType: toStringValue(row.target_entity_type, 'module'),
846
+ type: toStringValue(row.dependency_type),
847
+ filePath: toStringValue(row.file_path) || undefined,
848
+ line: toOptionalNumberValue(row.line),
849
+ confidence: toStringValue(row.confidence) === '' ? undefined : toStringValue(row.confidence),
850
+ };
851
+ }
852
+ runInTransaction(database, callback) {
853
+ database.exec('BEGIN');
854
+ try {
855
+ callback();
856
+ database.exec('COMMIT');
857
+ }
858
+ catch (error) {
859
+ database.exec('ROLLBACK');
860
+ throw error;
861
+ }
862
+ }
863
+ getDatabase() {
864
+ this.ensureInitialized();
865
+ if (!this.database) {
866
+ throw new StorageError('SQLite connection not initialized', 'SQLITE_CONNECTION_NOT_READY');
867
+ }
868
+ return this.database;
869
+ }
870
+ readGovernanceGraphForAnalysis(database) {
871
+ return readGovernanceGraphFromSQLite(database, this.projectPath ?? '');
872
+ }
873
+ refreshGovernanceGraphCache(database) {
874
+ const cache = new GovernanceGraphCache(database, this.projectPath ?? '', this.runtimeOptions.governanceGraphThresholds ?? DEFAULT_GOVERNANCE_GRAPH_PERF_THRESHOLDS);
875
+ cache.hydrate();
876
+ this.governanceGraphCache = cache;
877
+ }
878
+ }
879
+ //# sourceMappingURL=SQLiteStorage.js.map