@lsctech/polaris 0.1.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 (316) hide show
  1. package/README.md +87 -0
  2. package/dist/__mocks__/tool-server-linear.js +34 -0
  3. package/dist/cli/adopt-approve.js +60 -0
  4. package/dist/cli/adopt-cognition.js +199 -0
  5. package/dist/cli/adopt-instructions.js +143 -0
  6. package/dist/cli/adopt-rules.js +169 -0
  7. package/dist/cli/adopt-scan.js +25 -0
  8. package/dist/cli/adopt-smartdocs.js +192 -0
  9. package/dist/cli/adoption-inventory.js +350 -0
  10. package/dist/cli/adoption-plan.js +222 -0
  11. package/dist/cli/args.js +28 -0
  12. package/dist/cli/args.test.js +30 -0
  13. package/dist/cli/branding.js +41 -0
  14. package/dist/cli/graph.js +358 -0
  15. package/dist/cli/index.js +127 -0
  16. package/dist/cli/index.test.js +162 -0
  17. package/dist/cli/init-detect.js +61 -0
  18. package/dist/cli/init.js +492 -0
  19. package/dist/cli/init.test.js +259 -0
  20. package/dist/cli/librarian.js +32 -0
  21. package/dist/cli/medic.js +96 -0
  22. package/dist/cli/startup.test.js +23 -0
  23. package/dist/cli/tracker.js +130 -0
  24. package/dist/cli/tracker.test.js +126 -0
  25. package/dist/cli/version.js +10 -0
  26. package/dist/cli/version.test.js +11 -0
  27. package/dist/cli/worker.js +287 -0
  28. package/dist/cluster-state/fixtures/test-clusters.json +19 -0
  29. package/dist/cluster-state/store.js +302 -0
  30. package/dist/cluster-state/store.test.js +145 -0
  31. package/dist/cluster-state/types.js +2 -0
  32. package/dist/cognition/archive.js +158 -0
  33. package/dist/cognition/closeout-librarian-types.js +161 -0
  34. package/dist/cognition/cognition.test.js +623 -0
  35. package/dist/cognition/index.js +41 -0
  36. package/dist/cognition/librarian-dispatch.js +391 -0
  37. package/dist/cognition/librarian-dispatch.test.js +247 -0
  38. package/dist/cognition/librarian-packet.js +313 -0
  39. package/dist/cognition/librarian-types.js +57 -0
  40. package/dist/cognition/route-cognition-delta.js +350 -0
  41. package/dist/cognition/summary-delta.js +279 -0
  42. package/dist/cognition/validate.js +162 -0
  43. package/dist/config/defaults.js +98 -0
  44. package/dist/config/doctor.js +273 -0
  45. package/dist/config/index.js +14 -0
  46. package/dist/config/loader.js +58 -0
  47. package/dist/config/provider-detect.js +60 -0
  48. package/dist/config/provider-detect.test.js +119 -0
  49. package/dist/config/schema.js +2 -0
  50. package/dist/config/show.js +44 -0
  51. package/dist/config/show.test.js +42 -0
  52. package/dist/config/validator.js +675 -0
  53. package/dist/config/validator.test.js +77 -0
  54. package/dist/docs/canon-check.js +334 -0
  55. package/dist/docs/canon-check.test.js +207 -0
  56. package/dist/docs/doctrine.js +133 -0
  57. package/dist/docs/doctrine.test.js +139 -0
  58. package/dist/docs/index.js +168 -0
  59. package/dist/docs/index.test.js +83 -0
  60. package/dist/docs/ingest.js +295 -0
  61. package/dist/docs/ingest.test.js +71 -0
  62. package/dist/docs/migrate.js +165 -0
  63. package/dist/docs/migrate.test.js +136 -0
  64. package/dist/docs/seed-instructions.js +147 -0
  65. package/dist/docs/seed-instructions.test.js +137 -0
  66. package/dist/docs/validate-instructions.js +267 -0
  67. package/dist/docs/validate-instructions.test.js +238 -0
  68. package/dist/finalize/artifact-policy.js +214 -0
  69. package/dist/finalize/artifact-policy.test.js +84 -0
  70. package/dist/finalize/delivery-integrity.js +141 -0
  71. package/dist/finalize/finalize.test.js +210 -0
  72. package/dist/finalize/github.js +41 -0
  73. package/dist/finalize/index.js +474 -0
  74. package/dist/finalize/linear.js +213 -0
  75. package/dist/finalize/run-report.js +47 -0
  76. package/dist/finalize/steps/01-map-update.js +11 -0
  77. package/dist/finalize/steps/02-map-validate.js +11 -0
  78. package/dist/finalize/steps/03-schema-validate.js +11 -0
  79. package/dist/finalize/steps/04-run-checks.js +118 -0
  80. package/dist/finalize/steps/05-generate-report.js +14 -0
  81. package/dist/finalize/steps/06-commit.js +39 -0
  82. package/dist/finalize/steps/07-push.js +10 -0
  83. package/dist/finalize/steps/08-create-pr.js +9 -0
  84. package/dist/finalize/steps/09-update-state.js +9 -0
  85. package/dist/finalize/steps/10-append-jsonl.js +23 -0
  86. package/dist/finalize/steps/11-update-linear.js +22 -0
  87. package/dist/finalize/steps/12-archive.js +21 -0
  88. package/dist/graph/adapter/c/adapter.js +45 -0
  89. package/dist/graph/adapter/c/extract.js +135 -0
  90. package/dist/graph/adapter/c/index.js +10 -0
  91. package/dist/graph/adapter/c/runtime.js +67 -0
  92. package/dist/graph/adapter/cpp/adapter.js +45 -0
  93. package/dist/graph/adapter/cpp/extract.js +159 -0
  94. package/dist/graph/adapter/cpp/index.js +10 -0
  95. package/dist/graph/adapter/cpp/runtime.js +61 -0
  96. package/dist/graph/adapter/csharp/adapter.js +45 -0
  97. package/dist/graph/adapter/csharp/extract.js +127 -0
  98. package/dist/graph/adapter/csharp/index.js +10 -0
  99. package/dist/graph/adapter/csharp/runtime.js +61 -0
  100. package/dist/graph/adapter/dart/adapter.js +56 -0
  101. package/dist/graph/adapter/dart/extract.js +130 -0
  102. package/dist/graph/adapter/dart/index.js +10 -0
  103. package/dist/graph/adapter/dart/runtime.js +61 -0
  104. package/dist/graph/adapter/go/adapter.js +45 -0
  105. package/dist/graph/adapter/go/extract.js +112 -0
  106. package/dist/graph/adapter/go/index.js +10 -0
  107. package/dist/graph/adapter/go/runtime.js +58 -0
  108. package/dist/graph/adapter/kotlin-java/extract-common.js +83 -0
  109. package/dist/graph/adapter/kotlin-java/index.js +15 -0
  110. package/dist/graph/adapter/kotlin-java/java-adapter.js +45 -0
  111. package/dist/graph/adapter/kotlin-java/java-extract.js +42 -0
  112. package/dist/graph/adapter/kotlin-java/kotlin-adapter.js +48 -0
  113. package/dist/graph/adapter/kotlin-java/kotlin-extract.js +58 -0
  114. package/dist/graph/adapter/kotlin-java/runtime.js +75 -0
  115. package/dist/graph/adapter/python/adapter.js +45 -0
  116. package/dist/graph/adapter/python/extract.js +121 -0
  117. package/dist/graph/adapter/python/index.js +10 -0
  118. package/dist/graph/adapter/python/runtime.js +70 -0
  119. package/dist/graph/adapter/registry.js +82 -0
  120. package/dist/graph/adapter/rust/adapter.js +45 -0
  121. package/dist/graph/adapter/rust/extract.js +110 -0
  122. package/dist/graph/adapter/rust/index.js +10 -0
  123. package/dist/graph/adapter/rust/runtime.js +74 -0
  124. package/dist/graph/adapter/shell/adapter.js +34 -0
  125. package/dist/graph/adapter/shell/extract.js +98 -0
  126. package/dist/graph/adapter/shell/index.js +8 -0
  127. package/dist/graph/adapter/svelte/adapter.js +91 -0
  128. package/dist/graph/adapter/svelte/extract.js +41 -0
  129. package/dist/graph/adapter/svelte/index.js +8 -0
  130. package/dist/graph/adapter/swift/adapter.js +45 -0
  131. package/dist/graph/adapter/swift/extract.js +120 -0
  132. package/dist/graph/adapter/swift/index.js +10 -0
  133. package/dist/graph/adapter/swift/runtime.js +70 -0
  134. package/dist/graph/adapter/types.js +2 -0
  135. package/dist/graph/adapter/typescript-javascript/adapter.js +72 -0
  136. package/dist/graph/adapter/typescript-javascript/extract.js +115 -0
  137. package/dist/graph/adapter/typescript-javascript/index.js +10 -0
  138. package/dist/graph/adapter/typescript-javascript/runtime.js +97 -0
  139. package/dist/graph/capability/index.js +105 -0
  140. package/dist/graph/governance.js +104 -0
  141. package/dist/graph/parser/extract.js +5 -0
  142. package/dist/graph/parser/loader.js +2 -0
  143. package/dist/graph/parser/pipeline.js +194 -0
  144. package/dist/graph/query/index.js +277 -0
  145. package/dist/graph/query/types.js +5 -0
  146. package/dist/graph/resolver/build-edges.js +211 -0
  147. package/dist/graph/resolver/index.js +23 -0
  148. package/dist/graph/resolver/resolve-imports.js +168 -0
  149. package/dist/graph/store/adapter.js +132 -0
  150. package/dist/graph/store/queries.js +124 -0
  151. package/dist/graph/store/types.js +4 -0
  152. package/dist/ignore/defaults.js +41 -0
  153. package/dist/ignore/parser.js +39 -0
  154. package/dist/lint/map-reference-validator.js +72 -0
  155. package/dist/loop/abort.js +188 -0
  156. package/dist/loop/abort.test.js +151 -0
  157. package/dist/loop/adapters/__tests__/terminal-cli.test.js +92 -0
  158. package/dist/loop/adapters/agent-subtask.js +137 -0
  159. package/dist/loop/adapters/agent-subtask.test.js +151 -0
  160. package/dist/loop/adapters/cli-subtask-bridge.js +108 -0
  161. package/dist/loop/adapters/index.js +9 -0
  162. package/dist/loop/adapters/registry.js +17 -0
  163. package/dist/loop/adapters/terminal-cli.js +403 -0
  164. package/dist/loop/adapters/types.js +2 -0
  165. package/dist/loop/adapters/worker-instructions.js +85 -0
  166. package/dist/loop/body-parser.js +226 -0
  167. package/dist/loop/bootstrap-packet.js +97 -0
  168. package/dist/loop/bootstrap-packet.test.js +171 -0
  169. package/dist/loop/branch-governance.js +54 -0
  170. package/dist/loop/budget.js +63 -0
  171. package/dist/loop/budget.test.js +163 -0
  172. package/dist/loop/checkpoint.js +325 -0
  173. package/dist/loop/compact-return.js +59 -0
  174. package/dist/loop/continue.js +645 -0
  175. package/dist/loop/continue.test.js +337 -0
  176. package/dist/loop/dispatch-boundary.js +335 -0
  177. package/dist/loop/dispatch-state.js +223 -0
  178. package/dist/loop/dispatch-state.test.js +186 -0
  179. package/dist/loop/dispatch.js +1236 -0
  180. package/dist/loop/dispatch.test.js +499 -0
  181. package/dist/loop/ephemeral-smoke.test.js +160 -0
  182. package/dist/loop/evidence-backfill.js +216 -0
  183. package/dist/loop/execution-adapter.js +141 -0
  184. package/dist/loop/execution-adapter.test.js +66 -0
  185. package/dist/loop/finalize-evidence.js +169 -0
  186. package/dist/loop/git-custody.js +250 -0
  187. package/dist/loop/impl-packet-input.js +38 -0
  188. package/dist/loop/index.js +270 -0
  189. package/dist/loop/ledger.js +49 -0
  190. package/dist/loop/ledger.test.js +127 -0
  191. package/dist/loop/lifecycle-dispatch.js +348 -0
  192. package/dist/loop/lifecycle-dispatch.test.js +318 -0
  193. package/dist/loop/lifecycle.js +93 -0
  194. package/dist/loop/lifecycle.test.js +150 -0
  195. package/dist/loop/orphan-recovery.js +276 -0
  196. package/dist/loop/orphan-recovery.test.js +236 -0
  197. package/dist/loop/parent.js +1566 -0
  198. package/dist/loop/parent.test.js +738 -0
  199. package/dist/loop/provider-sealed-packet.test.js +164 -0
  200. package/dist/loop/resume.js +295 -0
  201. package/dist/loop/resume.test.js +172 -0
  202. package/dist/loop/run-bootstrap.js +234 -0
  203. package/dist/loop/run-preflight.js +203 -0
  204. package/dist/loop/status.js +665 -0
  205. package/dist/loop/status.test.js +235 -0
  206. package/dist/loop/wait.js +86 -0
  207. package/dist/loop/worker-packet.js +406 -0
  208. package/dist/loop/worker-packet.test.js +243 -0
  209. package/dist/loop/worker-prompt.js +260 -0
  210. package/dist/loop/worker-prompt.test.js +247 -0
  211. package/dist/loop/worker.js +498 -0
  212. package/dist/loop/worker.test.js +372 -0
  213. package/dist/map/atlas.js +77 -0
  214. package/dist/map/backfill.js +171 -0
  215. package/dist/map/backfill.test.js +120 -0
  216. package/dist/map/index.js +255 -0
  217. package/dist/map/inference.js +73 -0
  218. package/dist/map/inference.test.js +35 -0
  219. package/dist/map/query.js +157 -0
  220. package/dist/map/query.test.js +174 -0
  221. package/dist/map/update.js +355 -0
  222. package/dist/map/update.test.js +67 -0
  223. package/dist/map/validate.js +153 -0
  224. package/dist/map/validate.test.js +90 -0
  225. package/dist/map/welfare.js +86 -0
  226. package/dist/mcp/lib/invoke.js +35 -0
  227. package/dist/mcp/lib/redact.js +24 -0
  228. package/dist/mcp/lib/redact.test.js +112 -0
  229. package/dist/mcp/lib/root.js +41 -0
  230. package/dist/mcp/lib/root.test.js +114 -0
  231. package/dist/mcp/server.js +15 -0
  232. package/dist/mcp/tools/claim-child.js +119 -0
  233. package/dist/mcp/tools/claim-child.test.js +69 -0
  234. package/dist/mcp/tools/current-state.js +73 -0
  235. package/dist/mcp/tools/current-state.test.js +114 -0
  236. package/dist/mcp/tools/dispatch-result.js +186 -0
  237. package/dist/mcp/tools/dispatch-result.test.js +109 -0
  238. package/dist/mcp/tools/index.js +222 -0
  239. package/dist/mcp/tools/index.test.js +172 -0
  240. package/dist/mcp/tools/linear.js +74 -0
  241. package/dist/mcp/tools/loop-continue.js +159 -0
  242. package/dist/mcp/tools/loop-continue.test.js +186 -0
  243. package/dist/mcp/tools/loop-dry-run.js +15 -0
  244. package/dist/mcp/tools/status.js +65 -0
  245. package/dist/medic/chart-id.js +75 -0
  246. package/dist/medic/chart-schema.js +139 -0
  247. package/dist/runs/index.js +119 -0
  248. package/dist/runs/index.test.js +184 -0
  249. package/dist/runs/ledger-tail.js +15 -0
  250. package/dist/runs/list.js +29 -0
  251. package/dist/runs/reconcile.js +74 -0
  252. package/dist/runs/show.js +10 -0
  253. package/dist/runtime/audit/logger.js +15 -0
  254. package/dist/runtime/audit/reader.js +42 -0
  255. package/dist/runtime/checkpoint.js +89 -0
  256. package/dist/runtime/continuation/confirmed.js +225 -0
  257. package/dist/runtime/continuation/confirmed.test.js +421 -0
  258. package/dist/runtime/continuation/dry-run.js +74 -0
  259. package/dist/runtime/execution-window.js +106 -0
  260. package/dist/runtime/scheduling/child-selector.js +16 -0
  261. package/dist/runtime/state.js +43 -0
  262. package/dist/runtime/status.js +46 -0
  263. package/dist/runtime/verification/envelope.js +80 -0
  264. package/dist/runtime/verification/fingerprint.js +26 -0
  265. package/dist/skill-packet/cli.test.js +105 -0
  266. package/dist/skill-packet/generator.js +225 -0
  267. package/dist/skill-packet/generator.test.js +159 -0
  268. package/dist/skill-packet/index.js +49 -0
  269. package/dist/skill-packet/types.js +2 -0
  270. package/dist/smartdocs-engine/audit.js +194 -0
  271. package/dist/smartdocs-engine/audit.test.js +122 -0
  272. package/dist/smartdocs-engine/canon-check.js +340 -0
  273. package/dist/smartdocs-engine/canon-check.test.js +234 -0
  274. package/dist/smartdocs-engine/doctrine.js +633 -0
  275. package/dist/smartdocs-engine/doctrine.test.js +374 -0
  276. package/dist/smartdocs-engine/index.js +456 -0
  277. package/dist/smartdocs-engine/index.test.js +82 -0
  278. package/dist/smartdocs-engine/ingest.js +495 -0
  279. package/dist/smartdocs-engine/ingest.test.js +163 -0
  280. package/dist/smartdocs-engine/migrate.js +217 -0
  281. package/dist/smartdocs-engine/migrate.test.js +200 -0
  282. package/dist/smartdocs-engine/seed-instructions.js +335 -0
  283. package/dist/smartdocs-engine/seed-instructions.test.js +275 -0
  284. package/dist/smartdocs-engine/smartdoc-ignore.js +258 -0
  285. package/dist/smartdocs-engine/smartdoc-ignore.test.js +146 -0
  286. package/dist/smartdocs-engine/validate-instructions.js +366 -0
  287. package/dist/smartdocs-engine/validate-instructions.test.js +283 -0
  288. package/dist/tracker/adapters/github/index.js +305 -0
  289. package/dist/tracker/adapters/jira/index.js +293 -0
  290. package/dist/tracker/adapters/linear/http-errors.test.js +51 -0
  291. package/dist/tracker/adapters/linear/index.js +621 -0
  292. package/dist/tracker/adapters/linear/index.test.js +238 -0
  293. package/dist/tracker/adapters/linear.js +50 -0
  294. package/dist/tracker/adapters/local/index.js +10 -0
  295. package/dist/tracker/adapters/local-file/index.js +159 -0
  296. package/dist/tracker/adapters/mcp-bridge.js +158 -0
  297. package/dist/tracker/adapters/mcp-bridge.test.js +12 -0
  298. package/dist/tracker/adapters/spec/index.js +146 -0
  299. package/dist/tracker/capabilities.js +2 -0
  300. package/dist/tracker/index.js +49 -0
  301. package/dist/tracker/lifecycle-policy.js +139 -0
  302. package/dist/tracker/lifecycle-transition.js +164 -0
  303. package/dist/tracker/local-graph.js +98 -0
  304. package/dist/tracker/migration.js +56 -0
  305. package/dist/tracker/schema.js +86 -0
  306. package/dist/tracker/sync/index.js +404 -0
  307. package/dist/tracker/sync/queue-store.js +95 -0
  308. package/dist/tracker/sync/queue-store.test.js +104 -0
  309. package/dist/tracker/types.js +11 -0
  310. package/dist/types/linear.js +3 -0
  311. package/dist/types/result-packet.js +12 -0
  312. package/dist/types/runtime-state.js +2 -0
  313. package/dist/types/work-contract.js +2 -0
  314. package/dist/utils/monotonic-timestamp.js +13 -0
  315. package/dist/utils/monotonic-timestamp.test.js +19 -0
  316. package/package.json +64 -0
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runExtractionPipeline = runExtractionPipeline;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_crypto_1 = require("node:crypto");
6
+ const node_path_1 = require("node:path");
7
+ const registry_js_1 = require("../adapter/registry.js");
8
+ const index_js_1 = require("../capability/index.js");
9
+ const queries_js_1 = require("../store/queries.js");
10
+ async function runExtractionPipeline(filePaths, options) {
11
+ const adapterRegistry = options.adapterRegistry ?? (0, registry_js_1.getDefaultAdapterRegistry)();
12
+ const db = options.graphStore.getDatabase();
13
+ const warningMessages = [];
14
+ const sortedPaths = Array.from(new Set(filePaths)).sort((left, right) => left.localeCompare(right));
15
+ const capabilityRegistry = new index_js_1.GraphCapabilityRegistry(adapterRegistry.getAll().map((adapter) => adapter.languageId));
16
+ let succeededFiles = 0;
17
+ let failedFiles = 0;
18
+ let persistedNodes = 0;
19
+ let persistedSymbols = 0;
20
+ const fallbackFiles = [];
21
+ for (const filePath of sortedPaths) {
22
+ const ext = (0, node_path_1.extname)(filePath).toLowerCase();
23
+ const adapter = adapterRegistry.getForExtension(ext);
24
+ const languageId = adapter?.languageId ?? index_js_1.GraphCapabilityRegistry.unsupportedLanguageId(ext);
25
+ try {
26
+ if (!adapter) {
27
+ const fileId = makeDeterministicId("file", filePath);
28
+ persistUnsupportedFile(db, filePath, languageId, fileId);
29
+ fallbackFiles.push({ path: filePath, ext });
30
+ succeededFiles += 1;
31
+ persistedNodes += 1;
32
+ const warning = `Falling back to file node for unsupported file type: ${filePath}`;
33
+ warningMessages.push(warning);
34
+ capabilityRegistry.noteUnsupportedExtension(ext);
35
+ capabilityRegistry.recordFileLevel(languageId, [warning]);
36
+ options.logger?.warn(warning);
37
+ continue;
38
+ }
39
+ const source = (0, node_fs_1.readFileSync)(filePath, "utf-8");
40
+ const extracted = await adapter.extractSymbols(filePath, source);
41
+ const fileId = makeDeterministicId("file", filePath);
42
+ const symbols = extracted.symbols.map((entry, index) => toPersistableSymbol(fileId, filePath, entry, index));
43
+ persistFileSymbols(db, filePath, extracted.language, fileId, symbols);
44
+ succeededFiles += 1;
45
+ persistedNodes += symbols.length;
46
+ persistedSymbols += symbols.length;
47
+ capabilityRegistry.recordSymbolLevel(adapter.languageId, symbols.length);
48
+ }
49
+ catch (error) {
50
+ failedFiles += 1;
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ const warning = `Extraction failed for ${filePath}: ${message}`;
53
+ warningMessages.push(warning);
54
+ if (!adapter) {
55
+ capabilityRegistry.noteUnsupportedExtension(ext);
56
+ }
57
+ capabilityRegistry.recordFailure(languageId, warning);
58
+ options.logger?.warn(warning);
59
+ }
60
+ }
61
+ return {
62
+ processedFiles: sortedPaths.length,
63
+ succeededFiles,
64
+ failedFiles,
65
+ persistedNodes,
66
+ persistedSymbols,
67
+ fallbackFiles,
68
+ warnings: warningMessages,
69
+ capability: capabilityRegistry.buildReport(),
70
+ };
71
+ }
72
+ function toPersistableSymbol(fileId, filePath, entry, index) {
73
+ const symbolIdSeed = [
74
+ filePath,
75
+ entry.kind,
76
+ entry.name,
77
+ entry.startLine,
78
+ entry.startColumn,
79
+ entry.endLine,
80
+ entry.endColumn,
81
+ index,
82
+ ].join(":");
83
+ const symbolId = makeDeterministicId("symbol", symbolIdSeed);
84
+ const nodeId = makeDeterministicId("node", symbolIdSeed);
85
+ const node = {
86
+ id: nodeId,
87
+ type: mapKindToNodeType(entry.kind),
88
+ fileId,
89
+ name: entry.name,
90
+ startLine: entry.startLine,
91
+ startColumn: entry.startColumn,
92
+ endLine: entry.endLine,
93
+ endColumn: entry.endColumn,
94
+ };
95
+ const symbol = {
96
+ id: symbolId,
97
+ nodeId,
98
+ fileId,
99
+ name: entry.name,
100
+ kind: entry.kind,
101
+ signature: entry.signature,
102
+ exported: entry.exported,
103
+ };
104
+ return { node, symbol };
105
+ }
106
+ function persistFileSymbols(db, filePath, language, fileId, symbols) {
107
+ db.exec("BEGIN IMMEDIATE TRANSACTION");
108
+ try {
109
+ db.prepare(`
110
+ INSERT INTO files (id, path, language)
111
+ VALUES (?1, ?2, ?3)
112
+ ON CONFLICT(path) DO UPDATE SET
113
+ id = excluded.id,
114
+ language = excluded.language
115
+ `).run(fileId, filePath, normalizeLanguage(language, filePath));
116
+ db.prepare("DELETE FROM symbols WHERE file_id = ?1").run(fileId);
117
+ db.prepare("DELETE FROM nodes WHERE file_id = ?1").run(fileId);
118
+ for (const item of symbols) {
119
+ (0, queries_js_1.insertNode)(db, item.node);
120
+ db.prepare(`
121
+ INSERT INTO symbols (id, node_id, file_id, name, kind, signature, exported)
122
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
123
+ ON CONFLICT(id) DO UPDATE SET
124
+ node_id = excluded.node_id,
125
+ file_id = excluded.file_id,
126
+ name = excluded.name,
127
+ kind = excluded.kind,
128
+ signature = excluded.signature,
129
+ exported = excluded.exported
130
+ `).run(item.symbol.id, item.symbol.nodeId, item.symbol.fileId, item.symbol.name, item.symbol.kind, item.symbol.signature ?? null, item.symbol.exported ? 1 : 0);
131
+ }
132
+ db.exec("COMMIT");
133
+ }
134
+ catch (error) {
135
+ db.exec("ROLLBACK");
136
+ throw error;
137
+ }
138
+ }
139
+ function persistUnsupportedFile(db, filePath, language, fileId) {
140
+ db.exec("BEGIN IMMEDIATE TRANSACTION");
141
+ try {
142
+ db.prepare(`
143
+ INSERT INTO files (id, path, language)
144
+ VALUES (?1, ?2, ?3)
145
+ ON CONFLICT(path) DO UPDATE SET
146
+ id = excluded.id,
147
+ language = excluded.language
148
+ `).run(fileId, filePath, normalizeLanguage(language, filePath));
149
+ db.prepare("DELETE FROM symbols WHERE file_id = ?1").run(fileId);
150
+ db.prepare("DELETE FROM nodes WHERE file_id = ?1").run(fileId);
151
+ (0, queries_js_1.insertNode)(db, {
152
+ id: fileId,
153
+ type: "FILE",
154
+ fileId,
155
+ });
156
+ db.exec("COMMIT");
157
+ }
158
+ catch (error) {
159
+ db.exec("ROLLBACK");
160
+ throw error;
161
+ }
162
+ }
163
+ function normalizeLanguage(language, filePath) {
164
+ const extension = (0, node_path_1.extname)(filePath).toLowerCase();
165
+ if (language === "typescript" || extension === ".ts" || extension === ".tsx") {
166
+ return "ts";
167
+ }
168
+ if (language === "javascript" ||
169
+ extension === ".js" ||
170
+ extension === ".jsx" ||
171
+ extension === ".mjs" ||
172
+ extension === ".cjs") {
173
+ return "js";
174
+ }
175
+ return language;
176
+ }
177
+ function mapKindToNodeType(kind) {
178
+ switch (kind) {
179
+ case "function":
180
+ return "FUNCTION";
181
+ case "class":
182
+ return "CLASS";
183
+ case "method":
184
+ return "METHOD";
185
+ case "import":
186
+ return "IMPORT";
187
+ default:
188
+ return "SYMBOL";
189
+ }
190
+ }
191
+ function makeDeterministicId(prefix, input) {
192
+ const digest = (0, node_crypto_1.createHash)("sha256").update(input).digest("hex").slice(0, 24);
193
+ return `${prefix}-${digest}`;
194
+ }
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureGraphQuery = configureGraphQuery;
4
+ exports.lookupSymbol = lookupSymbol;
5
+ exports.getCallers = getCallers;
6
+ exports.getCallees = getCallees;
7
+ exports.getImpactedFiles = getImpactedFiles;
8
+ exports.getGraphStats = getGraphStats;
9
+ const types_js_1 = require("./types.js");
10
+ const FILE_NODE_PREFIX = "node-file-";
11
+ const queryState = {
12
+ defaultStore: null,
13
+ overrideStore: null,
14
+ };
15
+ function configureGraphQuery(options) {
16
+ queryState.overrideStore = options.graphStore ?? null;
17
+ }
18
+ function lookupSymbol(name, file) {
19
+ const db = getDatabase();
20
+ const row = db
21
+ .prepare(`
22
+ SELECT
23
+ s.id,
24
+ s.node_id AS nodeId,
25
+ s.name,
26
+ s.kind,
27
+ s.signature,
28
+ s.exported,
29
+ s.file_id AS fileId,
30
+ f.path AS filePath
31
+ FROM symbols s
32
+ JOIN files f ON f.id = s.file_id
33
+ WHERE s.name = ?1
34
+ AND (?2 IS NULL OR f.path = ?2)
35
+ ORDER BY s.id
36
+ LIMIT 1
37
+ `)
38
+ .get(name, file ?? null);
39
+ if (!row) {
40
+ return null;
41
+ }
42
+ return toGraphSymbol(row);
43
+ }
44
+ function getCallers(symbolId) {
45
+ const db = getDatabase();
46
+ return lookupRelatedSymbols(db, symbolId, "CALLS", "to_node_id", "from_node_id");
47
+ }
48
+ function getCallees(symbolId) {
49
+ const db = getDatabase();
50
+ return lookupRelatedSymbols(db, symbolId, "CALLS", "from_node_id", "to_node_id");
51
+ }
52
+ function getImpactedFiles(symbolId) {
53
+ const db = getDatabase();
54
+ const root = lookupSymbolRowById(db, symbolId);
55
+ if (!root) {
56
+ return [];
57
+ }
58
+ const impactedFiles = new Map();
59
+ const visitedSymbolNodes = new Set();
60
+ const visitedFileNodes = new Set();
61
+ const queue = [];
62
+ addImpactedFile(impactedFiles, {
63
+ fileId: root.fileId,
64
+ path: root.filePath,
65
+ language: lookupLanguageByFileId(db, root.fileId),
66
+ });
67
+ queue.push({ kind: "symbol", nodeId: root.nodeId, depth: 0 });
68
+ while (queue.length > 0) {
69
+ const current = queue.shift();
70
+ if (!current) {
71
+ continue;
72
+ }
73
+ if (current.depth > types_js_1.DEFAULT_IMPACT_MAX_DEPTH) {
74
+ continue;
75
+ }
76
+ if (current.kind === "symbol") {
77
+ if (visitedSymbolNodes.has(current.nodeId)) {
78
+ continue;
79
+ }
80
+ visitedSymbolNodes.add(current.nodeId);
81
+ const symbolFile = lookupFileBySymbolNodeId(db, current.nodeId);
82
+ if (symbolFile) {
83
+ addImpactedFile(impactedFiles, symbolFile);
84
+ queue.push({
85
+ kind: "file",
86
+ nodeId: `${FILE_NODE_PREFIX}${symbolFile.fileId}`,
87
+ depth: current.depth + 1,
88
+ });
89
+ }
90
+ const outgoingCalls = db
91
+ .prepare(`
92
+ SELECT e.to_node_id AS nodeId
93
+ FROM edges e
94
+ WHERE e.type = 'CALLS'
95
+ AND e.from_node_id = ?1
96
+ ORDER BY e.to_node_id
97
+ `)
98
+ .all(current.nodeId);
99
+ for (const edge of outgoingCalls) {
100
+ queue.push({ kind: "symbol", nodeId: edge.nodeId, depth: current.depth + 1 });
101
+ }
102
+ continue;
103
+ }
104
+ if (visitedFileNodes.has(current.nodeId)) {
105
+ continue;
106
+ }
107
+ visitedFileNodes.add(current.nodeId);
108
+ const fileByNode = lookupFileByFileNodeId(db, current.nodeId);
109
+ if (fileByNode) {
110
+ addImpactedFile(impactedFiles, fileByNode);
111
+ }
112
+ const importedFiles = db
113
+ .prepare(`
114
+ SELECT e.to_node_id AS fileNodeId
115
+ FROM edges e
116
+ WHERE e.type = 'IMPORTS'
117
+ AND e.from_node_id = ?1
118
+ ORDER BY e.to_node_id
119
+ `)
120
+ .all(current.nodeId);
121
+ for (const imported of importedFiles) {
122
+ const importedFile = lookupFileByFileNodeId(db, imported.fileNodeId);
123
+ if (importedFile) {
124
+ addImpactedFile(impactedFiles, importedFile);
125
+ }
126
+ queue.push({ kind: "file", nodeId: imported.fileNodeId, depth: current.depth + 1 });
127
+ }
128
+ const symbolsInFile = db
129
+ .prepare(`
130
+ SELECT e.from_node_id AS symbolNodeId
131
+ FROM edges e
132
+ WHERE e.type = 'DEFINED_IN'
133
+ AND e.to_node_id = ?1
134
+ ORDER BY e.from_node_id
135
+ `)
136
+ .all(current.nodeId);
137
+ for (const symbol of symbolsInFile) {
138
+ queue.push({ kind: "symbol", nodeId: symbol.symbolNodeId, depth: current.depth + 1 });
139
+ }
140
+ }
141
+ return Array.from(impactedFiles.values()).sort((left, right) => left.path.localeCompare(right.path));
142
+ }
143
+ function getGraphStats() {
144
+ const db = getDatabase();
145
+ const row = db
146
+ .prepare(`
147
+ SELECT
148
+ (SELECT COUNT(*) FROM nodes) AS nodeCount,
149
+ (SELECT COUNT(*) FROM edges) AS edgeCount,
150
+ (SELECT COUNT(*) FROM files) AS fileCount,
151
+ (SELECT COUNT(*) FROM symbols) AS symbolCount
152
+ `)
153
+ .get();
154
+ return {
155
+ version: types_js_1.GRAPH_QUERY_RESPONSE_VERSION,
156
+ nodeCount: row.nodeCount,
157
+ edgeCount: row.edgeCount,
158
+ fileCount: row.fileCount,
159
+ symbolCount: row.symbolCount,
160
+ };
161
+ }
162
+ function getDatabase() {
163
+ const activeStore = queryState.overrideStore ?? getDefaultStore();
164
+ return activeStore.getDatabase();
165
+ }
166
+ function getDefaultStore() {
167
+ if (queryState.defaultStore) {
168
+ return queryState.defaultStore;
169
+ }
170
+ throw new Error("No graph store configured. Call configureGraphQuery() before using the query API.");
171
+ }
172
+ function lookupRelatedSymbols(db, symbolId, edgeType, sourceColumn, targetColumn) {
173
+ const source = lookupSymbolRowById(db, symbolId);
174
+ if (!source) {
175
+ return [];
176
+ }
177
+ const rows = db
178
+ .prepare(`
179
+ SELECT DISTINCT
180
+ s.id,
181
+ s.node_id AS nodeId,
182
+ s.name,
183
+ s.kind,
184
+ s.signature,
185
+ s.exported,
186
+ s.file_id AS fileId,
187
+ f.path AS filePath
188
+ FROM edges e
189
+ JOIN symbols s ON s.node_id = e.${targetColumn}
190
+ JOIN files f ON f.id = s.file_id
191
+ WHERE e.type = ?1
192
+ AND e.${sourceColumn} = ?2
193
+ ORDER BY s.id
194
+ `)
195
+ .all(edgeType, source.nodeId);
196
+ return rows.map((row) => toGraphSymbol(row));
197
+ }
198
+ function lookupSymbolRowById(db, symbolId) {
199
+ const row = db
200
+ .prepare(`
201
+ SELECT
202
+ s.id,
203
+ s.node_id AS nodeId,
204
+ s.name,
205
+ s.kind,
206
+ s.signature,
207
+ s.exported,
208
+ s.file_id AS fileId,
209
+ f.path AS filePath
210
+ FROM symbols s
211
+ JOIN files f ON f.id = s.file_id
212
+ WHERE s.id = ?1
213
+ LIMIT 1
214
+ `)
215
+ .get(symbolId);
216
+ return row ?? null;
217
+ }
218
+ function lookupFileBySymbolNodeId(db, symbolNodeId) {
219
+ const row = db
220
+ .prepare(`
221
+ SELECT DISTINCT
222
+ f.id AS fileId,
223
+ f.path,
224
+ f.language
225
+ FROM symbols s
226
+ JOIN files f ON f.id = s.file_id
227
+ WHERE s.node_id = ?1
228
+ LIMIT 1
229
+ `)
230
+ .get(symbolNodeId);
231
+ return row ?? null;
232
+ }
233
+ function lookupFileByFileNodeId(db, fileNodeId) {
234
+ const row = db
235
+ .prepare(`
236
+ SELECT
237
+ f.id AS fileId,
238
+ f.path,
239
+ f.language
240
+ FROM nodes n
241
+ JOIN files f ON f.id = n.file_id
242
+ WHERE n.id = ?1
243
+ AND n.type = 'FILE'
244
+ LIMIT 1
245
+ `)
246
+ .get(fileNodeId);
247
+ return row ?? null;
248
+ }
249
+ function lookupLanguageByFileId(db, fileId) {
250
+ const row = db
251
+ .prepare(`
252
+ SELECT language
253
+ FROM files
254
+ WHERE id = ?1
255
+ LIMIT 1
256
+ `)
257
+ .get(fileId);
258
+ return row?.language ?? "unknown";
259
+ }
260
+ function addImpactedFile(target, file) {
261
+ target.set(file.path, {
262
+ version: types_js_1.GRAPH_QUERY_RESPONSE_VERSION,
263
+ path: file.path,
264
+ language: file.language,
265
+ });
266
+ }
267
+ function toGraphSymbol(row) {
268
+ return {
269
+ version: types_js_1.GRAPH_QUERY_RESPONSE_VERSION,
270
+ id: row.id,
271
+ name: row.name,
272
+ kind: row.kind,
273
+ signature: row.signature,
274
+ exported: row.exported === 1,
275
+ filePath: row.filePath,
276
+ };
277
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_IMPACT_MAX_DEPTH = exports.GRAPH_QUERY_RESPONSE_VERSION = void 0;
4
+ exports.GRAPH_QUERY_RESPONSE_VERSION = 1;
5
+ exports.DEFAULT_IMPACT_MAX_DEPTH = 8;
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildEdges = buildEdges;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const queries_js_1 = require("../store/queries.js");
6
+ const FILE_NODE_PREFIX = "node-file-";
7
+ const UNRESOLVED_NODE_PREFIX = "node-unresolved-call-";
8
+ const UNRESOLVED_SYMBOL_PREFIX = "symbol-unresolved-call-";
9
+ const UNRESOLVED_SIGNATURE = "__UNRESOLVED__";
10
+ function buildEdges(db, resolvedImports) {
11
+ const files = db
12
+ .prepare(`
13
+ SELECT id, path
14
+ FROM files
15
+ `)
16
+ .all();
17
+ for (const file of files) {
18
+ upsertFileNode(db, file.id, file.path);
19
+ }
20
+ const symbols = db
21
+ .prepare(`
22
+ SELECT id, node_id AS nodeId, file_id AS fileId, name, kind, signature
23
+ FROM symbols
24
+ `)
25
+ .all();
26
+ const symbolById = new Map();
27
+ const symbolsByName = new Map();
28
+ for (const symbol of symbols) {
29
+ symbolById.set(symbol.id, symbol);
30
+ if (symbol.kind === "import") {
31
+ continue;
32
+ }
33
+ const existing = symbolsByName.get(symbol.name) ?? [];
34
+ existing.push(symbol);
35
+ symbolsByName.set(symbol.name, existing);
36
+ }
37
+ for (const list of symbolsByName.values()) {
38
+ list.sort((left, right) => left.id.localeCompare(right.id));
39
+ }
40
+ let importsEdges = 0;
41
+ let unresolvedImports = 0;
42
+ for (const resolvedImport of resolvedImports) {
43
+ const fromFileNodeId = toFileNodeId(resolvedImport.importerFileId);
44
+ const targetFileNodeId = toFileNodeId(resolvedImport.resolvedFileId);
45
+ const importEdge = {
46
+ id: makeEdgeId("imports", fromFileNodeId, targetFileNodeId, resolvedImport.importSpecifier),
47
+ type: "IMPORTS",
48
+ fromNodeId: fromFileNodeId,
49
+ toNodeId: targetFileNodeId,
50
+ metadata: JSON.stringify({
51
+ importSpecifier: resolvedImport.importSpecifier,
52
+ resolvedSymbolIds: resolvedImport.resolvedSymbolIds,
53
+ UNRESOLVED: resolvedImport.unresolved,
54
+ }),
55
+ };
56
+ (0, queries_js_1.insertEdge)(db, importEdge);
57
+ importsEdges += 1;
58
+ if (resolvedImport.unresolved) {
59
+ unresolvedImports += 1;
60
+ }
61
+ }
62
+ let definedInEdges = 0;
63
+ for (const symbol of symbols) {
64
+ const edge = {
65
+ id: makeEdgeId("defined-in", symbol.nodeId, toFileNodeId(symbol.fileId), symbol.id),
66
+ type: "DEFINED_IN",
67
+ fromNodeId: symbol.nodeId,
68
+ toNodeId: toFileNodeId(symbol.fileId),
69
+ metadata: null,
70
+ };
71
+ (0, queries_js_1.insertEdge)(db, edge);
72
+ definedInEdges += 1;
73
+ }
74
+ let callsEdges = 0;
75
+ let unresolvedCalls = 0;
76
+ for (const symbol of symbols) {
77
+ if ((symbol.kind !== "function" && symbol.kind !== "method") || !symbol.signature) {
78
+ continue;
79
+ }
80
+ const callees = extractCallNames(symbol.signature);
81
+ for (const calleeName of callees) {
82
+ if (calleeName === symbol.name) {
83
+ continue;
84
+ }
85
+ const resolvedCallee = resolveCalleeSymbol(calleeName, symbol.fileId, symbolsByName);
86
+ if (resolvedCallee) {
87
+ const edge = {
88
+ id: makeEdgeId("calls", symbol.nodeId, resolvedCallee.nodeId, calleeName),
89
+ type: "CALLS",
90
+ fromNodeId: symbol.nodeId,
91
+ toNodeId: resolvedCallee.nodeId,
92
+ metadata: JSON.stringify({
93
+ calleeName,
94
+ UNRESOLVED: false,
95
+ }),
96
+ };
97
+ (0, queries_js_1.insertEdge)(db, edge);
98
+ callsEdges += 1;
99
+ continue;
100
+ }
101
+ const unresolved = upsertUnresolvedCallStub(db, symbol.fileId, calleeName);
102
+ const unresolvedDefinedIn = {
103
+ id: makeEdgeId("defined-in", unresolved.nodeId, toFileNodeId(symbol.fileId), unresolved.nodeId),
104
+ type: "DEFINED_IN",
105
+ fromNodeId: unresolved.nodeId,
106
+ toNodeId: toFileNodeId(symbol.fileId),
107
+ metadata: JSON.stringify({
108
+ UNRESOLVED: true,
109
+ }),
110
+ };
111
+ (0, queries_js_1.insertEdge)(db, unresolvedDefinedIn);
112
+ definedInEdges += 1;
113
+ const edge = {
114
+ id: makeEdgeId("calls", symbol.nodeId, unresolved.nodeId, calleeName),
115
+ type: "CALLS",
116
+ fromNodeId: symbol.nodeId,
117
+ toNodeId: unresolved.nodeId,
118
+ metadata: JSON.stringify({
119
+ calleeName,
120
+ UNRESOLVED: true,
121
+ }),
122
+ };
123
+ (0, queries_js_1.insertEdge)(db, edge);
124
+ callsEdges += 1;
125
+ unresolvedCalls += 1;
126
+ }
127
+ }
128
+ return {
129
+ callsEdges,
130
+ importsEdges,
131
+ definedInEdges,
132
+ unresolvedImports,
133
+ unresolvedCalls,
134
+ };
135
+ }
136
+ function upsertFileNode(db, fileId, filePath) {
137
+ const node = {
138
+ id: toFileNodeId(fileId),
139
+ type: "FILE",
140
+ fileId,
141
+ name: filePath,
142
+ };
143
+ (0, queries_js_1.insertNode)(db, node);
144
+ }
145
+ function upsertUnresolvedCallStub(db, callerFileId, calleeName) {
146
+ const digest = makeDigest(`${callerFileId}:${calleeName}`);
147
+ const nodeId = `${UNRESOLVED_NODE_PREFIX}${digest}`;
148
+ const symbolId = `${UNRESOLVED_SYMBOL_PREFIX}${digest}`;
149
+ const node = {
150
+ id: nodeId,
151
+ type: "SYMBOL",
152
+ fileId: callerFileId,
153
+ name: `UNRESOLVED:${calleeName}`,
154
+ };
155
+ (0, queries_js_1.insertNode)(db, node);
156
+ db.prepare(`
157
+ INSERT INTO symbols (id, node_id, file_id, name, kind, signature, exported)
158
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, 0)
159
+ ON CONFLICT(id) DO UPDATE SET
160
+ node_id = excluded.node_id,
161
+ file_id = excluded.file_id,
162
+ name = excluded.name,
163
+ kind = excluded.kind,
164
+ signature = excluded.signature,
165
+ exported = excluded.exported
166
+ `).run(symbolId, nodeId, callerFileId, calleeName, "unknown", UNRESOLVED_SIGNATURE);
167
+ return { nodeId };
168
+ }
169
+ function resolveCalleeSymbol(calleeName, callerFileId, symbolsByName) {
170
+ const candidates = symbolsByName.get(calleeName);
171
+ if (!candidates || candidates.length === 0) {
172
+ return null;
173
+ }
174
+ const local = candidates.find((entry) => entry.fileId === callerFileId);
175
+ return local ?? candidates[0] ?? null;
176
+ }
177
+ function extractCallNames(signature) {
178
+ const matches = new Set();
179
+ for (const match of signature.matchAll(/\b([A-Za-z_$][A-Za-z0-9_$]*)\s*\(/g)) {
180
+ const name = match[1];
181
+ if (!name || RESERVED_CALL_TOKENS.has(name)) {
182
+ continue;
183
+ }
184
+ matches.add(name);
185
+ }
186
+ return Array.from(matches.values()).sort((left, right) => left.localeCompare(right));
187
+ }
188
+ function makeEdgeId(prefix, fromNodeId, toNodeId, suffix) {
189
+ return `${prefix}-${makeDigest(`${fromNodeId}:${toNodeId}:${suffix}`)}`;
190
+ }
191
+ function toFileNodeId(fileId) {
192
+ return `${FILE_NODE_PREFIX}${fileId}`;
193
+ }
194
+ function makeDigest(input) {
195
+ return (0, node_crypto_1.createHash)("sha256").update(input).digest("hex").slice(0, 24);
196
+ }
197
+ const RESERVED_CALL_TOKENS = new Set([
198
+ "if",
199
+ "for",
200
+ "while",
201
+ "switch",
202
+ "catch",
203
+ "function",
204
+ "return",
205
+ "new",
206
+ "typeof",
207
+ "await",
208
+ "import",
209
+ "super",
210
+ "console",
211
+ ]);