@grafema/util 0.3.0-beta

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 (324) hide show
  1. package/LICENSE +190 -0
  2. package/dist/api/GraphAPI.d.ts +87 -0
  3. package/dist/api/GraphAPI.d.ts.map +1 -0
  4. package/dist/api/GraphAPI.js +212 -0
  5. package/dist/api/GraphAPI.js.map +1 -0
  6. package/dist/api/GuaranteeAPI.d.ts +147 -0
  7. package/dist/api/GuaranteeAPI.d.ts.map +1 -0
  8. package/dist/api/GuaranteeAPI.js +290 -0
  9. package/dist/api/GuaranteeAPI.js.map +1 -0
  10. package/dist/config/ConfigLoader.d.ts +214 -0
  11. package/dist/config/ConfigLoader.d.ts.map +1 -0
  12. package/dist/config/ConfigLoader.js +441 -0
  13. package/dist/config/ConfigLoader.js.map +1 -0
  14. package/dist/config/index.d.ts +6 -0
  15. package/dist/config/index.d.ts.map +1 -0
  16. package/dist/config/index.js +5 -0
  17. package/dist/config/index.js.map +1 -0
  18. package/dist/core/CoverageAnalyzer.d.ts +65 -0
  19. package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
  20. package/dist/core/CoverageAnalyzer.js +199 -0
  21. package/dist/core/CoverageAnalyzer.js.map +1 -0
  22. package/dist/core/FileExplainer.d.ts +101 -0
  23. package/dist/core/FileExplainer.d.ts.map +1 -0
  24. package/dist/core/FileExplainer.js +140 -0
  25. package/dist/core/FileExplainer.js.map +1 -0
  26. package/dist/core/FileOverview.d.ts +124 -0
  27. package/dist/core/FileOverview.d.ts.map +1 -0
  28. package/dist/core/FileOverview.js +279 -0
  29. package/dist/core/FileOverview.js.map +1 -0
  30. package/dist/core/GrafemaUri.d.ts +66 -0
  31. package/dist/core/GrafemaUri.d.ts.map +1 -0
  32. package/dist/core/GrafemaUri.js +191 -0
  33. package/dist/core/GrafemaUri.js.map +1 -0
  34. package/dist/core/GraphBackend.d.ts +158 -0
  35. package/dist/core/GraphBackend.d.ts.map +1 -0
  36. package/dist/core/GraphBackend.js +85 -0
  37. package/dist/core/GraphBackend.js.map +1 -0
  38. package/dist/core/GraphFreshnessChecker.d.ts +33 -0
  39. package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
  40. package/dist/core/GraphFreshnessChecker.js +104 -0
  41. package/dist/core/GraphFreshnessChecker.js.map +1 -0
  42. package/dist/core/GuaranteeManager.d.ts +254 -0
  43. package/dist/core/GuaranteeManager.d.ts.map +1 -0
  44. package/dist/core/GuaranteeManager.js +447 -0
  45. package/dist/core/GuaranteeManager.js.map +1 -0
  46. package/dist/core/HashUtils.d.ts +24 -0
  47. package/dist/core/HashUtils.d.ts.map +1 -0
  48. package/dist/core/HashUtils.js +46 -0
  49. package/dist/core/HashUtils.js.map +1 -0
  50. package/dist/core/IncrementalReanalyzer.d.ts +33 -0
  51. package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
  52. package/dist/core/IncrementalReanalyzer.js +67 -0
  53. package/dist/core/IncrementalReanalyzer.js.map +1 -0
  54. package/dist/core/ResourceRegistry.d.ts +17 -0
  55. package/dist/core/ResourceRegistry.d.ts.map +1 -0
  56. package/dist/core/ResourceRegistry.js +32 -0
  57. package/dist/core/ResourceRegistry.js.map +1 -0
  58. package/dist/core/SemanticId.d.ts +159 -0
  59. package/dist/core/SemanticId.d.ts.map +1 -0
  60. package/dist/core/SemanticId.js +291 -0
  61. package/dist/core/SemanticId.js.map +1 -0
  62. package/dist/core/VersionManager.d.ts +166 -0
  63. package/dist/core/VersionManager.d.ts.map +1 -0
  64. package/dist/core/VersionManager.js +239 -0
  65. package/dist/core/VersionManager.js.map +1 -0
  66. package/dist/core/brandNodeInternal.d.ts +14 -0
  67. package/dist/core/brandNodeInternal.d.ts.map +1 -0
  68. package/dist/core/brandNodeInternal.js +4 -0
  69. package/dist/core/brandNodeInternal.js.map +1 -0
  70. package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
  71. package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
  72. package/dist/core/nodes/GuaranteeNode.js +118 -0
  73. package/dist/core/nodes/GuaranteeNode.js.map +1 -0
  74. package/dist/core/nodes/IssueNode.d.ts +73 -0
  75. package/dist/core/nodes/IssueNode.d.ts.map +1 -0
  76. package/dist/core/nodes/IssueNode.js +130 -0
  77. package/dist/core/nodes/IssueNode.js.map +1 -0
  78. package/dist/core/nodes/NodeKind.d.ts +104 -0
  79. package/dist/core/nodes/NodeKind.d.ts.map +1 -0
  80. package/dist/core/nodes/NodeKind.js +166 -0
  81. package/dist/core/nodes/NodeKind.js.map +1 -0
  82. package/dist/diagnostics/DiagnosticCollector.d.ts +103 -0
  83. package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
  84. package/dist/diagnostics/DiagnosticCollector.js +133 -0
  85. package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
  86. package/dist/diagnostics/DiagnosticReporter.d.ts +122 -0
  87. package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
  88. package/dist/diagnostics/DiagnosticReporter.js +300 -0
  89. package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
  90. package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
  91. package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
  92. package/dist/diagnostics/DiagnosticWriter.js +44 -0
  93. package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
  94. package/dist/diagnostics/categories.d.ts +57 -0
  95. package/dist/diagnostics/categories.d.ts.map +1 -0
  96. package/dist/diagnostics/categories.js +71 -0
  97. package/dist/diagnostics/categories.js.map +1 -0
  98. package/dist/diagnostics/index.d.ts +17 -0
  99. package/dist/diagnostics/index.d.ts.map +1 -0
  100. package/dist/diagnostics/index.js +15 -0
  101. package/dist/diagnostics/index.js.map +1 -0
  102. package/dist/errors/GrafemaError.d.ts +200 -0
  103. package/dist/errors/GrafemaError.d.ts.map +1 -0
  104. package/dist/errors/GrafemaError.js +209 -0
  105. package/dist/errors/GrafemaError.js.map +1 -0
  106. package/dist/index.d.ts +75 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +76 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/instructions/index.d.ts +8 -0
  111. package/dist/instructions/index.d.ts.map +1 -0
  112. package/dist/instructions/index.js +20 -0
  113. package/dist/instructions/index.js.map +1 -0
  114. package/dist/instructions/onboarding.md +133 -0
  115. package/dist/knowledge/KnowledgeBase.d.ts +113 -0
  116. package/dist/knowledge/KnowledgeBase.d.ts.map +1 -0
  117. package/dist/knowledge/KnowledgeBase.js +420 -0
  118. package/dist/knowledge/KnowledgeBase.js.map +1 -0
  119. package/dist/knowledge/SemanticAddressResolver.d.ts +59 -0
  120. package/dist/knowledge/SemanticAddressResolver.d.ts.map +1 -0
  121. package/dist/knowledge/SemanticAddressResolver.js +160 -0
  122. package/dist/knowledge/SemanticAddressResolver.js.map +1 -0
  123. package/dist/knowledge/git-ingest.d.ts +58 -0
  124. package/dist/knowledge/git-ingest.d.ts.map +1 -0
  125. package/dist/knowledge/git-ingest.js +301 -0
  126. package/dist/knowledge/git-ingest.js.map +1 -0
  127. package/dist/knowledge/git-queries.d.ts +86 -0
  128. package/dist/knowledge/git-queries.d.ts.map +1 -0
  129. package/dist/knowledge/git-queries.js +177 -0
  130. package/dist/knowledge/git-queries.js.map +1 -0
  131. package/dist/knowledge/index.d.ts +14 -0
  132. package/dist/knowledge/index.d.ts.map +1 -0
  133. package/dist/knowledge/index.js +10 -0
  134. package/dist/knowledge/index.js.map +1 -0
  135. package/dist/knowledge/parser.d.ts +39 -0
  136. package/dist/knowledge/parser.d.ts.map +1 -0
  137. package/dist/knowledge/parser.js +292 -0
  138. package/dist/knowledge/parser.js.map +1 -0
  139. package/dist/knowledge/types.d.ts +133 -0
  140. package/dist/knowledge/types.d.ts.map +1 -0
  141. package/dist/knowledge/types.js +8 -0
  142. package/dist/knowledge/types.js.map +1 -0
  143. package/dist/logging/Logger.d.ts +98 -0
  144. package/dist/logging/Logger.d.ts.map +1 -0
  145. package/dist/logging/Logger.js +274 -0
  146. package/dist/logging/Logger.js.map +1 -0
  147. package/dist/notation/archetypes.d.ts +36 -0
  148. package/dist/notation/archetypes.d.ts.map +1 -0
  149. package/dist/notation/archetypes.js +173 -0
  150. package/dist/notation/archetypes.js.map +1 -0
  151. package/dist/notation/fold.d.ts +25 -0
  152. package/dist/notation/fold.d.ts.map +1 -0
  153. package/dist/notation/fold.js +598 -0
  154. package/dist/notation/fold.js.map +1 -0
  155. package/dist/notation/index.d.ts +18 -0
  156. package/dist/notation/index.d.ts.map +1 -0
  157. package/dist/notation/index.js +16 -0
  158. package/dist/notation/index.js.map +1 -0
  159. package/dist/notation/lodExtractor.d.ts +32 -0
  160. package/dist/notation/lodExtractor.d.ts.map +1 -0
  161. package/dist/notation/lodExtractor.js +149 -0
  162. package/dist/notation/lodExtractor.js.map +1 -0
  163. package/dist/notation/nameShortener.d.ts +22 -0
  164. package/dist/notation/nameShortener.d.ts.map +1 -0
  165. package/dist/notation/nameShortener.js +24 -0
  166. package/dist/notation/nameShortener.js.map +1 -0
  167. package/dist/notation/perspectives.d.ts +11 -0
  168. package/dist/notation/perspectives.d.ts.map +1 -0
  169. package/dist/notation/perspectives.js +16 -0
  170. package/dist/notation/perspectives.js.map +1 -0
  171. package/dist/notation/renderer.d.ts +31 -0
  172. package/dist/notation/renderer.d.ts.map +1 -0
  173. package/dist/notation/renderer.js +315 -0
  174. package/dist/notation/renderer.js.map +1 -0
  175. package/dist/notation/traceRenderer.d.ts +39 -0
  176. package/dist/notation/traceRenderer.d.ts.map +1 -0
  177. package/dist/notation/traceRenderer.js +358 -0
  178. package/dist/notation/traceRenderer.js.map +1 -0
  179. package/dist/notation/types.d.ts +66 -0
  180. package/dist/notation/types.d.ts.map +1 -0
  181. package/dist/notation/types.js +10 -0
  182. package/dist/notation/types.js.map +1 -0
  183. package/dist/queries/NodeContext.d.ts +81 -0
  184. package/dist/queries/NodeContext.d.ts.map +1 -0
  185. package/dist/queries/NodeContext.js +196 -0
  186. package/dist/queries/NodeContext.js.map +1 -0
  187. package/dist/queries/findCallsInFunction.d.ts +62 -0
  188. package/dist/queries/findCallsInFunction.d.ts.map +1 -0
  189. package/dist/queries/findCallsInFunction.js +169 -0
  190. package/dist/queries/findCallsInFunction.js.map +1 -0
  191. package/dist/queries/findContainingFunction.d.ts +57 -0
  192. package/dist/queries/findContainingFunction.d.ts.map +1 -0
  193. package/dist/queries/findContainingFunction.js +91 -0
  194. package/dist/queries/findContainingFunction.js.map +1 -0
  195. package/dist/queries/index.d.ts +18 -0
  196. package/dist/queries/index.d.ts.map +1 -0
  197. package/dist/queries/index.js +14 -0
  198. package/dist/queries/index.js.map +1 -0
  199. package/dist/queries/traceDataflow.d.ts +65 -0
  200. package/dist/queries/traceDataflow.d.ts.map +1 -0
  201. package/dist/queries/traceDataflow.js +754 -0
  202. package/dist/queries/traceDataflow.js.map +1 -0
  203. package/dist/queries/traceValues.d.ts +70 -0
  204. package/dist/queries/traceValues.d.ts.map +1 -0
  205. package/dist/queries/traceValues.js +373 -0
  206. package/dist/queries/traceValues.js.map +1 -0
  207. package/dist/queries/types.d.ts +166 -0
  208. package/dist/queries/types.d.ts.map +1 -0
  209. package/dist/queries/types.js +10 -0
  210. package/dist/queries/types.js.map +1 -0
  211. package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
  212. package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
  213. package/dist/schema/GraphSchemaExtractor.js +125 -0
  214. package/dist/schema/GraphSchemaExtractor.js.map +1 -0
  215. package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
  216. package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
  217. package/dist/schema/InterfaceSchemaExtractor.js +113 -0
  218. package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
  219. package/dist/schema/index.d.ts +5 -0
  220. package/dist/schema/index.d.ts.map +1 -0
  221. package/dist/schema/index.js +3 -0
  222. package/dist/schema/index.js.map +1 -0
  223. package/dist/storage/backends/RFDBServerBackend.d.ts +356 -0
  224. package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
  225. package/dist/storage/backends/RFDBServerBackend.js +748 -0
  226. package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
  227. package/dist/storage/backends/typeValidation.d.ts +47 -0
  228. package/dist/storage/backends/typeValidation.d.ts.map +1 -0
  229. package/dist/storage/backends/typeValidation.js +141 -0
  230. package/dist/storage/backends/typeValidation.js.map +1 -0
  231. package/dist/utils/findRfdbBinary.d.ts +67 -0
  232. package/dist/utils/findRfdbBinary.d.ts.map +1 -0
  233. package/dist/utils/findRfdbBinary.js +261 -0
  234. package/dist/utils/findRfdbBinary.js.map +1 -0
  235. package/dist/utils/lazyDownload.d.ts +43 -0
  236. package/dist/utils/lazyDownload.d.ts.map +1 -0
  237. package/dist/utils/lazyDownload.js +175 -0
  238. package/dist/utils/lazyDownload.js.map +1 -0
  239. package/dist/utils/moduleResolution.d.ts +134 -0
  240. package/dist/utils/moduleResolution.d.ts.map +1 -0
  241. package/dist/utils/moduleResolution.js +189 -0
  242. package/dist/utils/moduleResolution.js.map +1 -0
  243. package/dist/utils/resolveNodeFile.d.ts +13 -0
  244. package/dist/utils/resolveNodeFile.d.ts.map +1 -0
  245. package/dist/utils/resolveNodeFile.js +18 -0
  246. package/dist/utils/resolveNodeFile.js.map +1 -0
  247. package/dist/utils/startRfdbServer.d.ts +63 -0
  248. package/dist/utils/startRfdbServer.d.ts.map +1 -0
  249. package/dist/utils/startRfdbServer.js +142 -0
  250. package/dist/utils/startRfdbServer.js.map +1 -0
  251. package/dist/validation/PathValidator.d.ts +80 -0
  252. package/dist/validation/PathValidator.d.ts.map +1 -0
  253. package/dist/validation/PathValidator.js +252 -0
  254. package/dist/validation/PathValidator.js.map +1 -0
  255. package/dist/version.d.ts +11 -0
  256. package/dist/version.d.ts.map +1 -0
  257. package/dist/version.js +26 -0
  258. package/dist/version.js.map +1 -0
  259. package/package.json +50 -0
  260. package/src/api/GraphAPI.ts +307 -0
  261. package/src/api/GuaranteeAPI.ts +402 -0
  262. package/src/config/ConfigLoader.ts +653 -0
  263. package/src/config/index.ts +13 -0
  264. package/src/core/CoverageAnalyzer.ts +243 -0
  265. package/src/core/FileExplainer.ts +179 -0
  266. package/src/core/FileOverview.ts +397 -0
  267. package/src/core/GrafemaUri.ts +216 -0
  268. package/src/core/GraphBackend.ts +266 -0
  269. package/src/core/GraphFreshnessChecker.ts +145 -0
  270. package/src/core/GuaranteeManager.ts +684 -0
  271. package/src/core/HashUtils.ts +48 -0
  272. package/src/core/IncrementalReanalyzer.ts +106 -0
  273. package/src/core/ResourceRegistry.ts +39 -0
  274. package/src/core/SemanticId.ts +423 -0
  275. package/src/core/VersionManager.ts +405 -0
  276. package/src/core/brandNodeInternal.ts +16 -0
  277. package/src/core/nodes/GuaranteeNode.ts +162 -0
  278. package/src/core/nodes/IssueNode.ts +177 -0
  279. package/src/core/nodes/NodeKind.ts +192 -0
  280. package/src/diagnostics/DiagnosticCollector.ts +170 -0
  281. package/src/diagnostics/DiagnosticReporter.ts +395 -0
  282. package/src/diagnostics/DiagnosticWriter.ts +50 -0
  283. package/src/diagnostics/categories.ts +104 -0
  284. package/src/diagnostics/index.ts +30 -0
  285. package/src/errors/GrafemaError.ts +297 -0
  286. package/src/index.ts +261 -0
  287. package/src/instructions/index.ts +21 -0
  288. package/src/instructions/onboarding.md +133 -0
  289. package/src/knowledge/KnowledgeBase.ts +486 -0
  290. package/src/knowledge/SemanticAddressResolver.ts +191 -0
  291. package/src/knowledge/git-ingest.ts +402 -0
  292. package/src/knowledge/git-queries.ts +269 -0
  293. package/src/knowledge/index.ts +29 -0
  294. package/src/knowledge/parser.ts +294 -0
  295. package/src/knowledge/types.ts +146 -0
  296. package/src/logging/Logger.ts +303 -0
  297. package/src/notation/archetypes.ts +189 -0
  298. package/src/notation/fold.ts +696 -0
  299. package/src/notation/index.ts +27 -0
  300. package/src/notation/lodExtractor.ts +177 -0
  301. package/src/notation/nameShortener.ts +24 -0
  302. package/src/notation/perspectives.ts +18 -0
  303. package/src/notation/renderer.ts +394 -0
  304. package/src/notation/traceRenderer.ts +458 -0
  305. package/src/notation/types.ts +79 -0
  306. package/src/queries/NodeContext.ts +280 -0
  307. package/src/queries/findCallsInFunction.ts +249 -0
  308. package/src/queries/findContainingFunction.ts +124 -0
  309. package/src/queries/index.ts +44 -0
  310. package/src/queries/traceDataflow.ts +838 -0
  311. package/src/queries/traceValues.ts +531 -0
  312. package/src/queries/types.ts +191 -0
  313. package/src/schema/GraphSchemaExtractor.ts +177 -0
  314. package/src/schema/InterfaceSchemaExtractor.ts +173 -0
  315. package/src/schema/index.ts +5 -0
  316. package/src/storage/backends/RFDBServerBackend.ts +895 -0
  317. package/src/storage/backends/typeValidation.ts +154 -0
  318. package/src/utils/findRfdbBinary.ts +288 -0
  319. package/src/utils/lazyDownload.ts +206 -0
  320. package/src/utils/moduleResolution.ts +271 -0
  321. package/src/utils/resolveNodeFile.ts +18 -0
  322. package/src/utils/startRfdbServer.ts +197 -0
  323. package/src/validation/PathValidator.ts +334 -0
  324. package/src/version.ts +28 -0
@@ -0,0 +1,748 @@
1
+ /**
2
+ * RFDBServerBackend - Graph backend using RFDB server via Unix socket
3
+ *
4
+ * Replaces ReginaFlowBackend's direct NAPI binding with socket-based
5
+ * communication to a shared RFDB server. This allows multiple processes
6
+ * (MCP server, analysis workers) to share the same graph database.
7
+ *
8
+ * Socket path defaults to `{dbPath}/../rfdb.sock` (e.g., .grafema/rfdb.sock),
9
+ * ensuring each project has its own socket and avoiding conflicts when
10
+ * multiple MCP instances run simultaneously.
11
+ *
12
+ * Usage:
13
+ * const backend = new RFDBServerBackend({
14
+ * dbPath: '/project/.grafema/graph.rfdb' // socket will be /project/.grafema/rfdb.sock
15
+ * });
16
+ * await backend.connect();
17
+ * await backend.addNodes([...]);
18
+ * await backend.flush();
19
+ */
20
+ import { RFDBClient } from '@grafema/rfdb-client';
21
+ import { join, dirname } from 'path';
22
+ import { startRfdbServer } from '../../utils/startRfdbServer.js';
23
+ import { GRAFEMA_VERSION, getSchemaVersion } from '../../version.js';
24
+ import { brandNodeInternal } from '../../core/brandNodeInternal.js';
25
+ export class RFDBServerBackend {
26
+ socketPath;
27
+ dbPath;
28
+ autoStart;
29
+ silent;
30
+ _clientName;
31
+ client;
32
+ serverProcess;
33
+ connected; // Public for compatibility
34
+ protocolVersion = 2; // Negotiated protocol version
35
+ edgeTypes;
36
+ _cachedNodeCounts;
37
+ _cachedEdgeCounts;
38
+ constructor(options = {}) {
39
+ this.dbPath = options.dbPath;
40
+ this.autoStart = options.autoStart ?? true; // Default true for backwards compat
41
+ this.silent = options.silent ?? false;
42
+ this._clientName = options.clientName ?? 'core';
43
+ // Default socket path: next to the database in .grafema folder
44
+ // This ensures each project has its own socket, avoiding conflicts
45
+ if (options.socketPath) {
46
+ this.socketPath = options.socketPath;
47
+ }
48
+ else if (this.dbPath) {
49
+ this.socketPath = join(dirname(this.dbPath), 'rfdb.sock');
50
+ }
51
+ else {
52
+ this.socketPath = '/tmp/rfdb.sock'; // fallback, not recommended
53
+ }
54
+ this.client = null;
55
+ this.serverProcess = null;
56
+ this.connected = false;
57
+ this.edgeTypes = new Set();
58
+ }
59
+ /**
60
+ * Log message if not in silent mode.
61
+ */
62
+ log(message) {
63
+ if (!this.silent) {
64
+ console.error(message);
65
+ }
66
+ }
67
+ /**
68
+ * Log error (always shown, even in silent mode).
69
+ */
70
+ logError(message, error) {
71
+ console.error(message, error ?? '');
72
+ }
73
+ /**
74
+ * Connect to RFDB server.
75
+ * If autoStart is true (default), starts the server if not running.
76
+ * If autoStart is false, requires explicit `grafema server start`.
77
+ */
78
+ async connect() {
79
+ if (this.connected)
80
+ return;
81
+ // Try to connect first
82
+ this.client = new RFDBClient(this.socketPath, this._clientName);
83
+ // Attach error handler to prevent unhandled 'error' events
84
+ // This is important for stale sockets (socket file exists but server is dead)
85
+ this.client.on('error', (err) => {
86
+ this.logError('[RFDBServerBackend] Client error:', err.message);
87
+ });
88
+ try {
89
+ await this.client.connect();
90
+ // Verify server is responsive
91
+ await this.client.ping();
92
+ this.connected = true;
93
+ await this._negotiateProtocol();
94
+ this.log(`[RFDBServerBackend] Connected to RFDB server at ${this.socketPath} (protocol v${this.protocolVersion})`);
95
+ return;
96
+ }
97
+ catch {
98
+ // Server not running or stale socket
99
+ if (!this.autoStart) {
100
+ throw new Error(`RFDB server not running at ${this.socketPath}\n` +
101
+ `Start the server first: grafema server start`);
102
+ }
103
+ this.log(`[RFDBServerBackend] RFDB server not running, starting...`);
104
+ }
105
+ // Start the server (only if autoStart is true)
106
+ await this._startServer();
107
+ // Connect again with fresh client
108
+ this.client = new RFDBClient(this.socketPath, this._clientName);
109
+ this.client.on('error', (err) => {
110
+ this.logError('[RFDBServerBackend] Client error:', err.message);
111
+ });
112
+ await this.client.connect();
113
+ await this.client.ping();
114
+ this.connected = true;
115
+ await this._negotiateProtocol();
116
+ this.log(`[RFDBServerBackend] Connected to RFDB server at ${this.socketPath} (protocol v${this.protocolVersion})`);
117
+ }
118
+ /**
119
+ * Alias for connect()
120
+ */
121
+ async initialize() {
122
+ return this.connect();
123
+ }
124
+ /**
125
+ * Start RFDB server process using shared utility.
126
+ */
127
+ async _startServer() {
128
+ if (!this.dbPath) {
129
+ throw new Error('dbPath required to start RFDB server');
130
+ }
131
+ await startRfdbServer({
132
+ dbPath: this.dbPath,
133
+ socketPath: this.socketPath,
134
+ pidPath: join(dirname(this.socketPath), 'rfdb.pid'),
135
+ waitTimeoutMs: 5000,
136
+ logger: this.silent ? undefined : { debug: (m) => this.log(m) },
137
+ });
138
+ }
139
+ /**
140
+ * Negotiate protocol version with server.
141
+ * Requests v3 (semantic IDs), falls back to v2 if server doesn't support it.
142
+ * Called after ping() confirmed connectivity, so failures here indicate
143
+ * the server doesn't support hello/v3, not network issues.
144
+ */
145
+ async _negotiateProtocol() {
146
+ if (!this.client)
147
+ return;
148
+ try {
149
+ const hello = await this.client.hello(3);
150
+ this.protocolVersion = hello.protocolVersion;
151
+ this._checkServerVersion(hello.serverVersion);
152
+ }
153
+ catch {
154
+ // Server predates hello command or doesn't support v3 — safe v2 fallback
155
+ this.protocolVersion = 2;
156
+ this.log('[RFDBServerBackend] WARNING: Server does not support version negotiation. Consider updating rfdb-server.');
157
+ }
158
+ }
159
+ /**
160
+ * Validate server version against expected client version.
161
+ * Warns on mismatch but never fails — version differences are informational.
162
+ */
163
+ _checkServerVersion(serverVersion) {
164
+ if (!serverVersion)
165
+ return;
166
+ const expected = getSchemaVersion(GRAFEMA_VERSION);
167
+ const actual = getSchemaVersion(serverVersion);
168
+ if (actual !== expected) {
169
+ this.log(`[RFDBServerBackend] WARNING: rfdb-server version mismatch — ` +
170
+ `server v${serverVersion}, expected v${GRAFEMA_VERSION}. ` +
171
+ `Update with: grafema server restart`);
172
+ }
173
+ }
174
+ /**
175
+ * Close client connection. Server continues running to serve other clients.
176
+ */
177
+ async close() {
178
+ // Request server flush before disconnecting
179
+ if (this.client) {
180
+ try {
181
+ await this.client.flush();
182
+ }
183
+ catch {
184
+ // Ignore flush errors on close - best effort
185
+ }
186
+ await this.client.close();
187
+ this.client = null;
188
+ }
189
+ this.connected = false;
190
+ // NOTE: We intentionally do NOT kill the server process.
191
+ // The server continues running to serve other clients (MCP, other CLI invocations).
192
+ // This is by design for multi-client architecture.
193
+ // Server lifecycle is managed separately (system process, or manual grafema server stop).
194
+ this.serverProcess = null;
195
+ }
196
+ /**
197
+ * Clear the database
198
+ */
199
+ async clear() {
200
+ if (!this.client)
201
+ throw new Error('Not connected');
202
+ await this.client.clear();
203
+ }
204
+ /**
205
+ * Flush data to disk
206
+ */
207
+ async flush() {
208
+ if (!this.client)
209
+ throw new Error('Not connected');
210
+ await this.client.flush();
211
+ }
212
+ /**
213
+ * Declare metadata fields for server-side indexing.
214
+ * Persisted in metadata.json — survives database reopen.
215
+ */
216
+ async declareFields(fields) {
217
+ if (!this.client)
218
+ throw new Error('Not connected');
219
+ return this.client.declareFields(fields);
220
+ }
221
+ // ===========================================================================
222
+ // Node Operations
223
+ // ===========================================================================
224
+ /**
225
+ * Add a single node
226
+ */
227
+ async addNode(node) {
228
+ return this.addNodes([node]);
229
+ }
230
+ /**
231
+ * Add multiple nodes
232
+ */
233
+ async addNodes(nodes) {
234
+ if (!this.client)
235
+ throw new Error('Not connected');
236
+ if (!nodes.length)
237
+ return;
238
+ const useV3 = this.protocolVersion >= 3;
239
+ const wireNodes = nodes.map(n => {
240
+ // Extract metadata from node
241
+ const { id, type, nodeType, node_type, name, file, exported, ...rest } = n;
242
+ const wire = {
243
+ id: String(id),
244
+ nodeType: (nodeType || node_type || type || 'UNKNOWN'),
245
+ name: name || '',
246
+ file: file || '',
247
+ exported: exported || false,
248
+ metadata: useV3
249
+ ? JSON.stringify(rest)
250
+ : JSON.stringify({ originalId: String(id), ...rest }),
251
+ };
252
+ if (useV3) {
253
+ wire.semanticId = String(id);
254
+ }
255
+ return wire;
256
+ });
257
+ await this.client.addNodes(wireNodes);
258
+ }
259
+ /**
260
+ * Add a single edge
261
+ */
262
+ async addEdge(edge) {
263
+ return this.addEdges([edge]);
264
+ }
265
+ /**
266
+ * Add multiple edges
267
+ */
268
+ async addEdges(edges, skipValidation = false) {
269
+ if (!this.client)
270
+ throw new Error('Not connected');
271
+ if (!edges.length)
272
+ return;
273
+ // Track edge types
274
+ for (const e of edges) {
275
+ const edgeType = e.edgeType || e.edge_type || e.etype || e.type;
276
+ if (typeof edgeType === 'string')
277
+ this.edgeTypes.add(edgeType);
278
+ }
279
+ const useV3 = this.protocolVersion >= 3;
280
+ const wireEdges = edges.map(e => {
281
+ const { src, dst, type, edgeType, edge_type, etype, metadata, ...rest } = e;
282
+ // Flatten metadata: spread both edge-level properties and nested metadata
283
+ const flatMetadata = useV3
284
+ ? { ...rest, ...(typeof metadata === 'object' && metadata !== null ? metadata : {}) }
285
+ : { _origSrc: String(src), _origDst: String(dst), ...rest, ...(typeof metadata === 'object' && metadata !== null ? metadata : {}) };
286
+ return {
287
+ src: String(src),
288
+ dst: String(dst),
289
+ edgeType: (edgeType || edge_type || etype || type || 'UNKNOWN'),
290
+ metadata: JSON.stringify(flatMetadata),
291
+ };
292
+ });
293
+ await this.client.addEdges(wireEdges, skipValidation);
294
+ }
295
+ /**
296
+ * Get a node by ID
297
+ */
298
+ async getNode(id) {
299
+ if (!this.client)
300
+ throw new Error('Not connected');
301
+ const node = await this.client.getNode(String(id));
302
+ if (!node)
303
+ return null;
304
+ return this._parseNode(node);
305
+ }
306
+ /**
307
+ * Check if node exists
308
+ */
309
+ async nodeExists(id) {
310
+ if (!this.client)
311
+ throw new Error('Not connected');
312
+ return this.client.nodeExists(id);
313
+ }
314
+ /**
315
+ * Delete a node
316
+ */
317
+ async deleteNode(id) {
318
+ if (!this.client)
319
+ throw new Error('Not connected');
320
+ await this.client.deleteNode(id);
321
+ }
322
+ /**
323
+ * Find nodes by attributes
324
+ */
325
+ async findByAttr(query) {
326
+ if (!this.client)
327
+ throw new Error('Not connected');
328
+ return this.client.findByAttr(query);
329
+ }
330
+ /**
331
+ * Parse a node from wire format to JS format
332
+ */
333
+ _parseNode(wireNode) {
334
+ const metadata = wireNode.metadata ? JSON.parse(wireNode.metadata) : {};
335
+ // Parse nested JSON strings
336
+ for (const [key, value] of Object.entries(metadata)) {
337
+ if (typeof value === 'string' && (value.startsWith('[') || value.startsWith('{'))) {
338
+ try {
339
+ metadata[key] = JSON.parse(value);
340
+ }
341
+ catch {
342
+ // Not JSON, keep as string
343
+ }
344
+ }
345
+ }
346
+ // Prefer metadata.semanticId (original v1 format preserved by RFDB server),
347
+ // then v3 semanticId, then v2 originalId metadata hack, then raw id
348
+ const humanId = metadata.semanticId || wireNode.semanticId || metadata.originalId || wireNode.id;
349
+ // Exclude standard fields from metadata to prevent overwriting wireNode values
350
+ // REG-325: Metadata spread was overwriting name with LITERAL node data
351
+ const { id: _id, type: _type, name: _name, file: _file, exported: _exported, nodeType: _nodeType, originalId: _originalId, // Already extracted above
352
+ semanticId: _semanticId, // Exclude from safeMetadata (used for humanId above)
353
+ ...safeMetadata } = metadata;
354
+ const parsed = {
355
+ id: humanId,
356
+ type: wireNode.nodeType,
357
+ name: wireNode.name,
358
+ file: wireNode.file,
359
+ exported: wireNode.exported,
360
+ ...safeMetadata,
361
+ };
362
+ // Re-brand nodes coming from database
363
+ return brandNodeInternal(parsed);
364
+ }
365
+ /**
366
+ * Parse an edge from wire format to EdgeRecord
367
+ */
368
+ _parseEdge(wireEdge) {
369
+ const meta = wireEdge.metadata ? JSON.parse(wireEdge.metadata) : {};
370
+ // v3: server resolves src/dst to semantic IDs, use directly
371
+ // v2: fall back to _origSrc/_origDst metadata hack
372
+ const { _origSrc, _origDst, ...rest } = meta;
373
+ const src = this.protocolVersion >= 3
374
+ ? wireEdge.src
375
+ : _origSrc || wireEdge.src;
376
+ const dst = this.protocolVersion >= 3
377
+ ? wireEdge.dst
378
+ : _origDst || wireEdge.dst;
379
+ return {
380
+ src,
381
+ dst,
382
+ type: wireEdge.edgeType,
383
+ metadata: Object.keys(rest).length > 0 ? rest : undefined,
384
+ };
385
+ }
386
+ /**
387
+ * Async generator for querying nodes
388
+ */
389
+ async *queryNodes(query) {
390
+ if (!this.client)
391
+ throw new Error('Not connected');
392
+ // Build query for server
393
+ const serverQuery = {};
394
+ if (query.nodeType)
395
+ serverQuery.nodeType = query.nodeType;
396
+ if (query.type)
397
+ serverQuery.nodeType = query.type;
398
+ if (query.name)
399
+ serverQuery.name = query.name;
400
+ if (query.file)
401
+ serverQuery.file = query.file;
402
+ if (query.substringMatch)
403
+ serverQuery.substringMatch = query.substringMatch;
404
+ // Use findByType if only nodeType specified
405
+ if (serverQuery.nodeType && Object.keys(serverQuery).length === 1) {
406
+ const ids = await this.client.findByType(serverQuery.nodeType);
407
+ for (const id of ids) {
408
+ const node = await this.getNode(id);
409
+ if (node)
410
+ yield node;
411
+ }
412
+ return;
413
+ }
414
+ // Otherwise use client's queryNodes
415
+ for await (const wireNode of this.client.queryNodes(serverQuery)) {
416
+ yield this._parseNode(wireNode);
417
+ }
418
+ }
419
+ /**
420
+ * Get ALL nodes matching query (collects from queryNodes into array)
421
+ */
422
+ async getAllNodes(query = {}) {
423
+ const nodes = [];
424
+ for await (const node of this.queryNodes(query)) {
425
+ nodes.push(node);
426
+ }
427
+ return nodes;
428
+ }
429
+ // ===========================================================================
430
+ // Edge Operations
431
+ // ===========================================================================
432
+ /**
433
+ * Delete an edge
434
+ */
435
+ async deleteEdge(src, dst, type) {
436
+ if (!this.client)
437
+ throw new Error('Not connected');
438
+ await this.client.deleteEdge(src, dst, type);
439
+ }
440
+ /**
441
+ * Get all edges
442
+ */
443
+ async getAllEdges() {
444
+ return this.getAllEdgesAsync();
445
+ }
446
+ /**
447
+ * Get all edges (async version)
448
+ */
449
+ async getAllEdgesAsync() {
450
+ if (!this.client)
451
+ throw new Error('Not connected');
452
+ const edges = await this.client.getAllEdges();
453
+ return edges.map(e => this._parseEdge(e));
454
+ }
455
+ /**
456
+ * Get outgoing edges from a node
457
+ */
458
+ async getOutgoingEdges(nodeId, edgeTypes = null) {
459
+ if (!this.client)
460
+ throw new Error('Not connected');
461
+ const edges = await this.client.getOutgoingEdges(nodeId, edgeTypes || undefined);
462
+ return edges.map(e => this._parseEdge(e));
463
+ }
464
+ /**
465
+ * Get incoming edges to a node
466
+ */
467
+ async getIncomingEdges(nodeId, edgeTypes = null) {
468
+ if (!this.client)
469
+ throw new Error('Not connected');
470
+ const edges = await this.client.getIncomingEdges(nodeId, edgeTypes || undefined);
471
+ return edges.map(e => this._parseEdge(e));
472
+ }
473
+ // ===========================================================================
474
+ // Graph Traversal
475
+ // ===========================================================================
476
+ /**
477
+ * BFS traversal
478
+ */
479
+ async bfs(startIds, maxDepth, edgeTypes) {
480
+ if (!this.client)
481
+ throw new Error('Not connected');
482
+ return this.client.bfs(startIds, maxDepth, edgeTypes);
483
+ }
484
+ /**
485
+ * DFS traversal
486
+ */
487
+ async dfs(startIds, maxDepth, edgeTypes = []) {
488
+ if (!this.client)
489
+ throw new Error('Not connected');
490
+ return this.client.dfs(startIds, maxDepth, edgeTypes);
491
+ }
492
+ /**
493
+ * Reachability query - find all nodes reachable from start nodes
494
+ */
495
+ async reachability(startIds, maxDepth, edgeTypes = [], backward = false) {
496
+ if (!this.client)
497
+ throw new Error('Not connected');
498
+ return this.client.reachability(startIds, maxDepth, edgeTypes, backward);
499
+ }
500
+ // ===========================================================================
501
+ // Statistics
502
+ // ===========================================================================
503
+ /**
504
+ * Get node count
505
+ */
506
+ async nodeCount() {
507
+ if (!this.client)
508
+ throw new Error('Not connected');
509
+ return this.client.nodeCount();
510
+ }
511
+ /**
512
+ * Get edge count
513
+ */
514
+ async edgeCount() {
515
+ if (!this.client)
516
+ throw new Error('Not connected');
517
+ return this.client.edgeCount();
518
+ }
519
+ /**
520
+ * Get statistics
521
+ */
522
+ async getStats() {
523
+ if (!this.client)
524
+ throw new Error('Not connected');
525
+ const nodeCount = await this.client.nodeCount();
526
+ const edgeCount = await this.client.edgeCount();
527
+ const nodeCounts = await this.client.countNodesByType();
528
+ const edgeCounts = await this.client.countEdgesByType();
529
+ return {
530
+ nodeCount,
531
+ edgeCount,
532
+ nodesByType: nodeCounts,
533
+ edgesByType: edgeCounts,
534
+ };
535
+ }
536
+ /**
537
+ * Get full server stats including shard diagnostics.
538
+ * Uses the GetStats wire command which returns all metrics in one call.
539
+ */
540
+ async getServerStats() {
541
+ if (!this.client)
542
+ throw new Error('Not connected');
543
+ return this.client.getStats();
544
+ }
545
+ /**
546
+ * Count nodes by type (sync, returns cached value)
547
+ */
548
+ async countNodesByType(_types = null) {
549
+ if (!this.client)
550
+ throw new Error('Not connected');
551
+ return this.client.countNodesByType();
552
+ }
553
+ /**
554
+ * Count edges by type
555
+ */
556
+ async countEdgesByType(_edgeTypes = null) {
557
+ if (!this.client)
558
+ throw new Error('Not connected');
559
+ return this.client.countEdgesByType();
560
+ }
561
+ /**
562
+ * Refresh cached counts (call after analysis)
563
+ */
564
+ async refreshCounts() {
565
+ if (!this.client)
566
+ throw new Error('Not connected');
567
+ this._cachedNodeCounts = await this.client.countNodesByType();
568
+ this._cachedEdgeCounts = await this.client.countEdgesByType();
569
+ }
570
+ async checkGuarantee(ruleSource, explain) {
571
+ if (!this.client)
572
+ throw new Error('Not connected');
573
+ if (explain) {
574
+ return await this.client.checkGuarantee(ruleSource, true);
575
+ }
576
+ const violations = await this.client.checkGuarantee(ruleSource);
577
+ // Convert bindings from {X: "value"} to [{name: "X", value: "value"}]
578
+ return violations.map(v => ({
579
+ bindings: Object.entries(v.bindings).map(([name, value]) => ({ name, value }))
580
+ }));
581
+ }
582
+ /**
583
+ * Load Datalog rules
584
+ */
585
+ async datalogLoadRules(source) {
586
+ if (!this.client)
587
+ throw new Error('Not connected');
588
+ return await this.client.datalogLoadRules(source);
589
+ }
590
+ /**
591
+ * Clear Datalog rules
592
+ */
593
+ async datalogClearRules() {
594
+ if (!this.client)
595
+ throw new Error('Not connected');
596
+ await this.client.datalogClearRules();
597
+ }
598
+ async datalogQuery(query, explain) {
599
+ if (!this.client)
600
+ throw new Error('Not connected');
601
+ if (explain) {
602
+ return await this.client.datalogQuery(query, true);
603
+ }
604
+ const results = await this.client.datalogQuery(query);
605
+ // Convert bindings from {X: "value"} to [{name: "X", value: "value"}]
606
+ return results.map(r => ({
607
+ bindings: Object.entries(r.bindings).map(([name, value]) => ({ name, value }))
608
+ }));
609
+ }
610
+ async executeDatalog(source, explain) {
611
+ if (!this.client)
612
+ throw new Error('Not connected');
613
+ if (explain) {
614
+ return await this.client.executeDatalog(source, true);
615
+ }
616
+ const results = await this.client.executeDatalog(source);
617
+ return results.map(r => ({
618
+ bindings: Object.entries(r.bindings).map(([name, value]) => ({ name, value }))
619
+ }));
620
+ }
621
+ /**
622
+ * Run a Cypher query.
623
+ */
624
+ async cypherQuery(query) {
625
+ if (!this.client)
626
+ throw new Error('Not connected');
627
+ return await this.client.cypherQuery(query);
628
+ }
629
+ // ===========================================================================
630
+ // Batch Operations (RFD-16: CommitBatch protocol)
631
+ // ===========================================================================
632
+ /**
633
+ * Begin a batch operation. While batching, addNodes/addEdges buffer locally.
634
+ * Call commitBatch() to send all buffered data atomically.
635
+ */
636
+ beginBatch() {
637
+ if (!this.client)
638
+ throw new Error('Not connected to RFDB server');
639
+ this.client.beginBatch();
640
+ }
641
+ /**
642
+ * Commit the current batch to the server atomically.
643
+ * Returns a CommitDelta describing what changed.
644
+ *
645
+ * @param tags - Optional tags for the commit
646
+ * @param deferIndex - When true, server writes data but skips index rebuild.
647
+ */
648
+ async commitBatch(tags, deferIndex, protectedTypes, changedFiles) {
649
+ if (!this.client)
650
+ throw new Error('Not connected to RFDB server');
651
+ return this.client.commitBatch(tags, deferIndex, protectedTypes, changedFiles);
652
+ }
653
+ /**
654
+ * Synchronously batch a node. Must be inside beginBatch/commitBatch.
655
+ * Bypasses async wrapper for direct batch insertion.
656
+ */
657
+ batchNode(node) {
658
+ if (!this.client)
659
+ throw new Error('Not connected');
660
+ const { id, type, nodeType, node_type, name, file, exported, ...rest } = node;
661
+ const useV3 = this.protocolVersion >= 3;
662
+ const wire = {
663
+ id: String(id),
664
+ nodeType: (nodeType || node_type || type || 'UNKNOWN'),
665
+ name: name || '',
666
+ file: file || '',
667
+ exported: exported || false,
668
+ metadata: useV3 ? JSON.stringify(rest) : JSON.stringify({ originalId: String(id), ...rest }),
669
+ };
670
+ if (useV3) {
671
+ wire.semanticId = String(id);
672
+ }
673
+ this.client.batchNode(wire);
674
+ }
675
+ /**
676
+ * Synchronously batch an edge. Must be inside beginBatch/commitBatch.
677
+ */
678
+ batchEdge(edge) {
679
+ if (!this.client)
680
+ throw new Error('Not connected');
681
+ const { src, dst, type, edgeType, edge_type, etype, metadata, ...rest } = edge;
682
+ const edgeTypeStr = edgeType || edge_type || etype || type;
683
+ if (typeof edgeTypeStr === 'string')
684
+ this.edgeTypes.add(edgeTypeStr);
685
+ const flatMetadata = { ...rest, ...(typeof metadata === 'object' && metadata !== null ? metadata : {}) };
686
+ this.client.batchEdge({
687
+ src: String(src),
688
+ dst: String(dst),
689
+ edgeType: (edgeTypeStr || 'UNKNOWN'),
690
+ metadata: JSON.stringify(flatMetadata),
691
+ });
692
+ }
693
+ /**
694
+ * Abort the current batch, discarding all buffered data.
695
+ */
696
+ abortBatch() {
697
+ if (!this.client)
698
+ throw new Error('Not connected to RFDB server');
699
+ this.client.abortBatch();
700
+ }
701
+ /**
702
+ * Rebuild all secondary indexes after deferred-index commits (REG-487).
703
+ * Call this once after a series of commitBatch(tags, true) calls.
704
+ */
705
+ async rebuildIndexes() {
706
+ if (!this.client)
707
+ throw new Error('Not connected to RFDB server');
708
+ await this.client.rebuildIndexes();
709
+ }
710
+ /**
711
+ * Create an isolated batch handle for concurrent-safe batching (REG-487).
712
+ * Each handle has its own buffers — safe for parallel workers.
713
+ */
714
+ createBatch() {
715
+ if (!this.client)
716
+ throw new Error('Not connected to RFDB server');
717
+ return this.client.createBatch();
718
+ }
719
+ // ===========================================================================
720
+ // Export/Import
721
+ // ===========================================================================
722
+ /**
723
+ * Export graph (for tests)
724
+ */
725
+ async export() {
726
+ const nodes = await this.getAllNodes();
727
+ const edges = await this.getAllEdgesAsync();
728
+ return {
729
+ nodes: nodes,
730
+ edges: edges,
731
+ };
732
+ }
733
+ /**
734
+ * Find nodes by predicate (for compatibility)
735
+ */
736
+ async findNodes(predicate) {
737
+ const allNodes = await this.getAllNodes();
738
+ return allNodes.filter(predicate);
739
+ }
740
+ // ===========================================================================
741
+ // Graph property (for compatibility)
742
+ // ===========================================================================
743
+ get graph() {
744
+ return this;
745
+ }
746
+ }
747
+ export default RFDBServerBackend;
748
+ //# sourceMappingURL=RFDBServerBackend.js.map