march-cli 0.1.21 → 0.1.22

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 (242) hide show
  1. package/bin/march.mjs +13 -13
  2. package/package.json +43 -43
  3. package/src/agent/command-exec-tool.mjs +172 -168
  4. package/src/agent/context-stats-tool.mjs +57 -57
  5. package/src/agent/editing/diff-apply.mjs +28 -28
  6. package/src/agent/editing/diff-format.mjs +57 -57
  7. package/src/agent/editing/lsp-report.mjs +69 -69
  8. package/src/agent/file-edit-tool.mjs +262 -262
  9. package/src/agent/file-tools/read-file-tool.mjs +112 -112
  10. package/src/agent/file-tools/read-image-tool.mjs +76 -76
  11. package/src/agent/model-payload-dumper.mjs +208 -208
  12. package/src/agent/pi-session/pi-session-sidecar-failure.mjs +10 -10
  13. package/src/agent/provider/payload-messages.mjs +138 -138
  14. package/src/agent/runner/codex-large-context-guard.mjs +87 -87
  15. package/src/agent/runner/codex-transport-compression.mjs +180 -180
  16. package/src/agent/runner/codex-transport-debug.mjs +113 -113
  17. package/src/agent/runner/codex-websocket-event-debug.mjs +130 -130
  18. package/src/agent/runner/fast-model.mjs +36 -36
  19. package/src/agent/runner/runner-cleanup.mjs +12 -12
  20. package/src/agent/runner/runner-init.mjs +15 -15
  21. package/src/agent/runner/runner-session-state.mjs +40 -40
  22. package/src/agent/runner/runner-utils.mjs +24 -24
  23. package/src/agent/runner.mjs +299 -299
  24. package/src/agent/runtime/ipc/ipc-peer.mjs +99 -99
  25. package/src/agent/runtime/ipc/process-ipc-transport.mjs +16 -16
  26. package/src/agent/runtime/remote-runner-client.mjs +73 -73
  27. package/src/agent/runtime/remote-ui-client.mjs +20 -20
  28. package/src/agent/runtime/runner-ipc-target.mjs +125 -125
  29. package/src/agent/runtime/runner-process-client.mjs +47 -47
  30. package/src/agent/runtime/runner-process-entry.mjs +11 -11
  31. package/src/agent/runtime/runner-process-factory.mjs +108 -108
  32. package/src/agent/runtime/runner-runtime-host.mjs +79 -79
  33. package/src/agent/runtime/runtime-factory.mjs +42 -42
  34. package/src/agent/runtime/runtime-host.mjs +34 -34
  35. package/src/agent/runtime/ui-event-bridge.mjs +95 -95
  36. package/src/agent/screen-tools/list-windows-tool.mjs +39 -39
  37. package/src/agent/screen-tools/screen-tool.mjs +49 -49
  38. package/src/agent/screen-tools/windows-screen.mjs +133 -133
  39. package/src/agent/session/session-auto-name.mjs +41 -41
  40. package/src/agent/session/session-binding.mjs +12 -12
  41. package/src/agent/session/session-options.mjs +47 -47
  42. package/src/agent/tool-names.mjs +1 -1
  43. package/src/agent/tool-result.mjs +3 -3
  44. package/src/agent/tool-summary.mjs +112 -112
  45. package/src/agent/tools.mjs +58 -58
  46. package/src/agent/turn/turn-events.mjs +111 -111
  47. package/src/agent/turn/turn-logging.mjs +30 -30
  48. package/src/agent/turn/turn-runner.mjs +196 -196
  49. package/src/agent/vision-capability.mjs +14 -14
  50. package/src/auth/login-command.mjs +90 -90
  51. package/src/auth/storage.mjs +34 -34
  52. package/src/cli/args.mjs +79 -79
  53. package/src/cli/commands/copy-command.mjs +87 -87
  54. package/src/cli/commands/export-command.mjs +206 -206
  55. package/src/cli/commands/extensions-command.mjs +53 -53
  56. package/src/cli/commands/help-command.mjs +7 -7
  57. package/src/cli/commands/model-command.mjs +141 -141
  58. package/src/cli/commands/paste-image-command.mjs +43 -43
  59. package/src/cli/commands/provider-command.mjs +59 -59
  60. package/src/cli/commands/status-command.mjs +194 -194
  61. package/src/cli/commands/thinking-command.mjs +87 -87
  62. package/src/cli/fallback-ui.mjs +156 -156
  63. package/src/cli/input/attachment-tokens.mjs +20 -20
  64. package/src/cli/input/autocomplete.mjs +74 -106
  65. package/src/cli/input/external-editor.mjs +39 -39
  66. package/src/cli/input/file-search/index.mjs +160 -0
  67. package/src/cli/input/history-store.mjs +35 -35
  68. package/src/cli/input/image-clipboard.mjs +55 -55
  69. package/src/cli/input/keybinding-dispatch.mjs +76 -76
  70. package/src/cli/input/keybindings.mjs +96 -96
  71. package/src/cli/input/mode-state.mjs +43 -43
  72. package/src/cli/input/prompt-templates.mjs +84 -84
  73. package/src/cli/input/select-with-keyboard.mjs +86 -86
  74. package/src/cli/permissions.mjs +103 -103
  75. package/src/cli/repl-commands.mjs +86 -86
  76. package/src/cli/repl-loop.mjs +183 -183
  77. package/src/cli/selector-list.mjs +21 -21
  78. package/src/cli/session/pi-session-switch-command.mjs +41 -41
  79. package/src/cli/session/session-command.mjs +23 -23
  80. package/src/cli/session/session-list-command.mjs +68 -68
  81. package/src/cli/session/session-name-command.mjs +26 -26
  82. package/src/cli/session/session-source-command.mjs +89 -89
  83. package/src/cli/session/session-switch-command.mjs +1 -1
  84. package/src/cli/shell/shell-command.mjs +55 -55
  85. package/src/cli/shell/shell-drawer-controls.mjs +33 -33
  86. package/src/cli/shell/shell-drawer.mjs +192 -192
  87. package/src/cli/shell/shell-split-layout.mjs +70 -70
  88. package/src/cli/slash-commands.mjs +192 -192
  89. package/src/cli/startup/create-runtime-runner.mjs +61 -61
  90. package/src/cli/startup/runtime-close.mjs +23 -23
  91. package/src/cli/startup/startup-banner.mjs +71 -71
  92. package/src/cli/startup/startup-session.mjs +51 -51
  93. package/src/cli/status-line-updater.mjs +75 -75
  94. package/src/cli/tool-output.mjs +9 -9
  95. package/src/cli/tui/editor/external-editor-runner.mjs +24 -24
  96. package/src/cli/tui/input/mouse-selection-controller.mjs +91 -91
  97. package/src/cli/tui/input/mouse-tracking.mjs +20 -20
  98. package/src/cli/tui/layout/main-pane-layout.mjs +47 -47
  99. package/src/cli/tui/layout/safe-render-boundary.mjs +46 -46
  100. package/src/cli/tui/markdown-renderer.mjs +285 -285
  101. package/src/cli/tui/output/scroll-state.mjs +79 -79
  102. package/src/cli/tui/output/text-line-renderer.mjs +50 -50
  103. package/src/cli/tui/output/tool-card-renderer.mjs +59 -59
  104. package/src/cli/tui/output/visible-lines.mjs +8 -8
  105. package/src/cli/tui/output-buffer.mjs +293 -293
  106. package/src/cli/tui/permission-request-ui.mjs +18 -18
  107. package/src/cli/tui/recall-rendering.mjs +25 -25
  108. package/src/cli/tui/render/render-scheduler.mjs +26 -26
  109. package/src/cli/tui/render/stream-delta-buffer.mjs +46 -46
  110. package/src/cli/tui/select/editor-select-list.mjs +111 -111
  111. package/src/cli/tui/selection-screen.mjs +269 -269
  112. package/src/cli/tui/status/retry-status.mjs +72 -72
  113. package/src/cli/tui/status/spinner-status.mjs +42 -42
  114. package/src/cli/tui/status/status-bar.mjs +225 -225
  115. package/src/cli/tui/syntax/highlighting.mjs +260 -260
  116. package/src/cli/tui/syntax/languages.mjs +91 -91
  117. package/src/cli/tui/syntax/tree-sitter/bash.highlights.scm +261 -261
  118. package/src/cli/tui/syntax/tree-sitter/c.highlights.scm +341 -341
  119. package/src/cli/tui/syntax/tree-sitter/cpp.highlights.scm +268 -268
  120. package/src/cli/tui/syntax/tree-sitter/csharp.highlights.scm +577 -577
  121. package/src/cli/tui/syntax/tree-sitter/css.highlights.scm +109 -109
  122. package/src/cli/tui/syntax/tree-sitter/diff.highlights.scm +49 -49
  123. package/src/cli/tui/syntax/tree-sitter/go.highlights.scm +254 -254
  124. package/src/cli/tui/syntax/tree-sitter/html.highlights.scm +13 -13
  125. package/src/cli/tui/syntax/tree-sitter/java.highlights.scm +330 -330
  126. package/src/cli/tui/syntax/tree-sitter/json.highlights.scm +38 -38
  127. package/src/cli/tui/syntax/tree-sitter/php.highlights.scm +203 -203
  128. package/src/cli/tui/syntax/tree-sitter/python.highlights.scm +137 -137
  129. package/src/cli/tui/syntax/tree-sitter/ruby.highlights.scm +309 -309
  130. package/src/cli/tui/syntax/tree-sitter/rust.highlights.scm +531 -531
  131. package/src/cli/tui/syntax/tree-sitter/toml.highlights.scm +39 -39
  132. package/src/cli/tui/syntax/tree-sitter/tsx.highlights.scm +35 -35
  133. package/src/cli/tui/syntax/tree-sitter/typescript.highlights.scm +35 -35
  134. package/src/cli/tui/syntax/tree-sitter/yaml.highlights.scm +99 -99
  135. package/src/cli/tui/tool-rendering.mjs +87 -87
  136. package/src/cli/tui/tui-diff-rendering.mjs +157 -157
  137. package/src/cli/tui/tui-handlers.mjs +111 -111
  138. package/src/cli/tui/tui-input-controller.mjs +61 -61
  139. package/src/cli/tui/ui-theme.mjs +157 -157
  140. package/src/cli/ui.mjs +297 -297
  141. package/src/config/config-json.mjs +84 -84
  142. package/src/config/dotenv.mjs +20 -20
  143. package/src/config/features.mjs +75 -75
  144. package/src/config/loader.mjs +143 -143
  145. package/src/config/settings-command.mjs +97 -97
  146. package/src/context/engine.mjs +198 -198
  147. package/src/context/injections.mjs +26 -26
  148. package/src/context/profiles.mjs +39 -39
  149. package/src/context/project-context.mjs +20 -20
  150. package/src/context/session-status.mjs +17 -17
  151. package/src/context/shell-layers.mjs +23 -23
  152. package/src/context/system-core/base.md +65 -65
  153. package/src/context/system-core/prompts/deepseek-v4-pro.md +3 -3
  154. package/src/context/system-core/prompts/default.md +3 -3
  155. package/src/context/system-core.mjs +35 -35
  156. package/src/debug/logger.mjs +141 -141
  157. package/src/debug/model-context-dumper.mjs +52 -52
  158. package/src/extensions/discovery.mjs +40 -40
  159. package/src/extensions/lifecycle-adapter.mjs +210 -210
  160. package/src/extensions/lifecycle-manifest.mjs +69 -69
  161. package/src/image-gen/index.mjs +7 -7
  162. package/src/image-gen/provider.mjs +231 -231
  163. package/src/image-gen/tool.mjs +84 -84
  164. package/src/lsp/client.mjs +257 -257
  165. package/src/lsp/diagnostic-store.mjs +42 -42
  166. package/src/lsp/diagnostics-format.mjs +72 -72
  167. package/src/lsp/managed-node-server.mjs +99 -99
  168. package/src/lsp/path-match.mjs +10 -10
  169. package/src/lsp/server-definitions.mjs +188 -188
  170. package/src/lsp/servers.mjs +165 -165
  171. package/src/lsp/service.mjs +110 -110
  172. package/src/lsp/status-message.mjs +9 -9
  173. package/src/lsp/typescript-project-resolver.mjs +186 -186
  174. package/src/main.mjs +299 -299
  175. package/src/mcp/client.mjs +195 -195
  176. package/src/mcp/config.mjs +130 -130
  177. package/src/mcp/index.mjs +48 -48
  178. package/src/mcp/tools.mjs +98 -98
  179. package/src/memory/database.mjs +219 -219
  180. package/src/memory/glossary.mjs +124 -124
  181. package/src/memory/graph/graph-cascades.mjs +109 -109
  182. package/src/memory/graph/graph-diagnostics.mjs +73 -73
  183. package/src/memory/graph/graph-path-removal.mjs +50 -50
  184. package/src/memory/graph/graph-path-utils.mjs +17 -17
  185. package/src/memory/graph/graph-primitives.mjs +103 -103
  186. package/src/memory/graph/graph-read.mjs +159 -159
  187. package/src/memory/graph.mjs +282 -282
  188. package/src/memory/markdown/markdown-delete.mjs +23 -23
  189. package/src/memory/markdown/markdown-format.mjs +128 -128
  190. package/src/memory/markdown/markdown-recall.mjs +28 -28
  191. package/src/memory/markdown/ripgrep.mjs +16 -16
  192. package/src/memory/markdown/sqlite-index.mjs +87 -87
  193. package/src/memory/markdown-store.mjs +286 -286
  194. package/src/memory/markdown-tools.mjs +103 -103
  195. package/src/memory/search.mjs +142 -142
  196. package/src/memory/snapshot.mjs +86 -86
  197. package/src/memory/system-views.mjs +120 -120
  198. package/src/memory/tools.mjs +282 -282
  199. package/src/network/environment.mjs +131 -131
  200. package/src/notification/desktop-notifier.mjs +262 -262
  201. package/src/platform/open-file.mjs +28 -28
  202. package/src/platform/spawn-command.mjs +27 -27
  203. package/src/provider/accept-command.mjs +89 -89
  204. package/src/provider/command.mjs +21 -21
  205. package/src/provider/config-command.mjs +129 -129
  206. package/src/provider/custom-provider.mjs +113 -113
  207. package/src/provider/hosted-tools.mjs +111 -111
  208. package/src/provider/presets.mjs +72 -72
  209. package/src/provider/share-command.mjs +79 -79
  210. package/src/provider/share-payload.mjs +52 -52
  211. package/src/session/attachment-display.mjs +16 -16
  212. package/src/session/attachment-references.mjs +65 -65
  213. package/src/session/attachments.mjs +140 -140
  214. package/src/session/persist.mjs +1 -1
  215. package/src/session/pi-manager.mjs +34 -34
  216. package/src/session/session-utils.mjs +16 -16
  217. package/src/session/sidecar-sync.mjs +19 -19
  218. package/src/session/sidecar.mjs +69 -69
  219. package/src/session/transcript.mjs +83 -83
  220. package/src/session/tree.mjs +42 -42
  221. package/src/shell/cli-runtime.mjs +11 -11
  222. package/src/shell/hints.mjs +12 -12
  223. package/src/shell/node-pty-adapter.mjs +81 -81
  224. package/src/shell/runtime-state.mjs +126 -126
  225. package/src/shell/runtime.mjs +252 -252
  226. package/src/shell/screen-buffer.mjs +136 -136
  227. package/src/shell/tool-read.mjs +74 -74
  228. package/src/shell/tools.mjs +299 -299
  229. package/src/supergrok/actions/image-generate.mjs +60 -60
  230. package/src/supergrok/actions/search.mjs +78 -78
  231. package/src/supergrok/auth.mjs +36 -36
  232. package/src/supergrok/constants.mjs +18 -18
  233. package/src/supergrok/oauth-provider.mjs +278 -278
  234. package/src/supergrok/provider.mjs +35 -35
  235. package/src/supergrok/response.mjs +76 -76
  236. package/src/supergrok/tool.mjs +61 -61
  237. package/src/text/ansi.mjs +3 -3
  238. package/src/web/config-command.mjs +43 -43
  239. package/src/web/fetch.mjs +78 -78
  240. package/src/web/presets.mjs +16 -16
  241. package/src/web/search.mjs +83 -83
  242. package/src/web/tools.mjs +107 -107
@@ -1,219 +1,219 @@
1
- import { DatabaseSync } from "node:sqlite";
2
- import { mkdirSync } from "node:fs";
3
- import { dirname } from "node:path";
4
-
5
- export const ROOT_NODE_UUID = "00000000-0000-0000-0000-000000000000";
6
-
7
- const SCHEMA = `
8
- CREATE TABLE IF NOT EXISTS nodes (
9
- uuid TEXT PRIMARY KEY,
10
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
11
- last_accessed_at TEXT
12
- );
13
-
14
- CREATE TABLE IF NOT EXISTS memories (
15
- id INTEGER PRIMARY KEY AUTOINCREMENT,
16
- node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
17
- content TEXT NOT NULL,
18
- deprecated INTEGER NOT NULL DEFAULT 0,
19
- migrated_to INTEGER REFERENCES memories(id),
20
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
21
- );
22
-
23
- CREATE TABLE IF NOT EXISTS edges (
24
- id INTEGER PRIMARY KEY AUTOINCREMENT,
25
- parent_uuid TEXT NOT NULL REFERENCES nodes(uuid),
26
- child_uuid TEXT NOT NULL REFERENCES nodes(uuid),
27
- name TEXT NOT NULL,
28
- priority INTEGER NOT NULL DEFAULT 0,
29
- disclosure TEXT
30
- );
31
-
32
- CREATE TABLE IF NOT EXISTS paths (
33
- namespace TEXT NOT NULL DEFAULT '',
34
- domain TEXT NOT NULL DEFAULT 'core',
35
- path TEXT NOT NULL,
36
- edge_id INTEGER NOT NULL REFERENCES edges(id),
37
- node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
38
- PRIMARY KEY (namespace, domain, path)
39
- );
40
-
41
- CREATE TABLE IF NOT EXISTS glossary_keywords (
42
- id INTEGER PRIMARY KEY AUTOINCREMENT,
43
- keyword TEXT NOT NULL,
44
- node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
45
- namespace TEXT NOT NULL DEFAULT ''
46
- );
47
-
48
- CREATE TABLE IF NOT EXISTS search_documents (
49
- node_uuid TEXT NOT NULL,
50
- namespace TEXT NOT NULL DEFAULT '',
51
- content TEXT NOT NULL,
52
- PRIMARY KEY (node_uuid, namespace)
53
- );
54
-
55
- CREATE TABLE IF NOT EXISTS memory_access_log (
56
- id INTEGER PRIMARY KEY AUTOINCREMENT,
57
- node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
58
- namespace TEXT NOT NULL DEFAULT '',
59
- context TEXT,
60
- accessed_at TEXT NOT NULL DEFAULT (datetime('now'))
61
- );
62
-
63
- CREATE INDEX IF NOT EXISTS idx_memories_node ON memories(node_uuid, deprecated);
64
- CREATE INDEX IF NOT EXISTS idx_memories_migrated ON memories(migrated_to);
65
- CREATE INDEX IF NOT EXISTS idx_edges_parent ON edges(parent_uuid);
66
- CREATE INDEX IF NOT EXISTS idx_edges_child ON edges(child_uuid);
67
- CREATE INDEX IF NOT EXISTS idx_paths_node ON paths(node_uuid);
68
- CREATE INDEX IF NOT EXISTS idx_paths_edge ON paths(edge_id);
69
- CREATE INDEX IF NOT EXISTS idx_glossary_node ON glossary_keywords(node_uuid);
70
- CREATE INDEX IF NOT EXISTS idx_glossary_keyword ON glossary_keywords(keyword);
71
- `;
72
-
73
- export function openDatabase(dbPath) {
74
- mkdirSync(dirname(dbPath), { recursive: true });
75
- const db = new DatabaseSync(dbPath);
76
- db.exec("PRAGMA journal_mode = WAL");
77
- db.exec("PRAGMA foreign_keys = ON");
78
- db.exec(SCHEMA);
79
- ensureRootNode(db);
80
- return db;
81
- }
82
-
83
- function ensureRootNode(db) {
84
- const row = db.prepare("SELECT uuid FROM nodes WHERE uuid = ?").get(ROOT_NODE_UUID);
85
- if (!row) {
86
- db.prepare("INSERT INTO nodes (uuid) VALUES (?)").run(ROOT_NODE_UUID);
87
- db.prepare("INSERT INTO memories (node_uuid, content, deprecated) VALUES (?, ?, 0)").run(ROOT_NODE_UUID, "Root node");
88
- }
89
- }
90
-
91
- // ── Node operations ────────────────────────────────────────────────────
92
-
93
- export function createNode(db, uuid) {
94
- db.prepare("INSERT OR IGNORE INTO nodes (uuid) VALUES (?)").run(uuid);
95
- return { uuid };
96
- }
97
-
98
- export function getNode(db, uuid) {
99
- return db.prepare("SELECT * FROM nodes WHERE uuid = ?").get(uuid);
100
- }
101
-
102
- function touchNode(db, uuid) {
103
- db.prepare("UPDATE nodes SET last_accessed_at = datetime('now') WHERE uuid = ?").run(uuid);
104
- }
105
-
106
- // ── Memory operations ───────────────────────────────────────────────────
107
-
108
- export function createMemory(db, nodeUuid, content) {
109
- const result = db.prepare("INSERT INTO memories (node_uuid, content) VALUES (?, ?)").run(nodeUuid, content);
110
- touchNode(db, nodeUuid);
111
- return { id: Number(result.lastInsertRowid), node_uuid: nodeUuid, content };
112
- }
113
-
114
- export function getCurrentMemory(db, nodeUuid) {
115
- return db.prepare("SELECT * FROM memories WHERE node_uuid = ? AND deprecated = 0 ORDER BY id DESC LIMIT 1").get(nodeUuid);
116
- }
117
-
118
- export function getMemoryHistory(db, nodeUuid) {
119
- return db.prepare("SELECT * FROM memories WHERE node_uuid = ? ORDER BY id DESC").all(nodeUuid);
120
- }
121
-
122
- export function updateMemory(db, nodeUuid, newContent) {
123
- const current = getCurrentMemory(db, nodeUuid);
124
- if (!current) return null;
125
- db.prepare("UPDATE memories SET deprecated = 1 WHERE id = ?").run(current.id);
126
- const result = db.prepare("INSERT INTO memories (node_uuid, content) VALUES (?, ?)").run(nodeUuid, newContent);
127
- db.prepare("UPDATE memories SET migrated_to = ? WHERE id = ?").run(Number(result.lastInsertRowid), current.id);
128
- touchNode(db, nodeUuid);
129
- return { id: Number(result.lastInsertRowid), node_uuid: nodeUuid, content: newContent, previous_id: current.id };
130
- }
131
-
132
- export function deleteMemory(db, nodeUuid) {
133
- const pathRows = db.prepare("SELECT edge_id FROM paths WHERE node_uuid = ?").all(nodeUuid);
134
- db.prepare("DELETE FROM paths WHERE node_uuid = ?").run(nodeUuid);
135
- for (const row of pathRows) {
136
- try { db.prepare("DELETE FROM edges WHERE id = ?").run(row.edge_id); } catch {}
137
- }
138
- db.prepare("DELETE FROM edges WHERE parent_uuid = ? OR child_uuid = ?").run(nodeUuid, nodeUuid);
139
- db.prepare("DELETE FROM glossary_keywords WHERE node_uuid = ?").run(nodeUuid);
140
- db.prepare("DELETE FROM search_documents WHERE node_uuid = ?").run(nodeUuid);
141
- db.prepare("DELETE FROM memory_access_log WHERE node_uuid = ?").run(nodeUuid);
142
- db.prepare("DELETE FROM memories WHERE node_uuid = ?").run(nodeUuid);
143
- const result = db.prepare("DELETE FROM nodes WHERE uuid = ? AND uuid != ?").run(nodeUuid, ROOT_NODE_UUID);
144
- return result.changes > 0;
145
- }
146
-
147
- // ── Edge operations ─────────────────────────────────────────────────────
148
-
149
- export function createEdge(db, parentUuid, childUuid, { name = "related", priority = 0, disclosure = null } = {}) {
150
- const result = db.prepare(
151
- "INSERT INTO edges (parent_uuid, child_uuid, name, priority, disclosure) VALUES (?, ?, ?, ?, ?)",
152
- ).run(parentUuid, childUuid, name, priority, disclosure);
153
- return { id: Number(result.lastInsertRowid), parent_uuid: parentUuid, child_uuid: childUuid, name };
154
- }
155
-
156
- export function getEdges(db, nodeUuid, { direction = "both" } = {}) {
157
- if (direction === "children") return db.prepare("SELECT * FROM edges WHERE parent_uuid = ? ORDER BY priority DESC").all(nodeUuid);
158
- if (direction === "parents") return db.prepare("SELECT * FROM edges WHERE child_uuid = ? ORDER BY priority DESC").all(nodeUuid);
159
- return db.prepare("SELECT * FROM edges WHERE parent_uuid = ? OR child_uuid = ? ORDER BY priority DESC").all(nodeUuid, nodeUuid);
160
- }
161
-
162
- export function deleteEdge(db, edgeId) {
163
- db.prepare("DELETE FROM paths WHERE edge_id = ?").run(edgeId);
164
- return db.prepare("DELETE FROM edges WHERE id = ?").run(edgeId).changes > 0;
165
- }
166
-
167
- // ── Path operations ─────────────────────────────────────────────────────
168
-
169
- export function createPath(db, { namespace = "", domain = "core", path, edgeId, nodeUuid }) {
170
- db.prepare("INSERT OR REPLACE INTO paths (namespace, domain, path, edge_id, node_uuid) VALUES (?, ?, ?, ?, ?)").run(namespace, domain, path, edgeId, nodeUuid);
171
- return { namespace, domain, path, edge_id: edgeId, node_uuid: nodeUuid };
172
- }
173
-
174
- export function getPath(db, namespace, domain, path) {
175
- return db.prepare("SELECT * FROM paths WHERE namespace = ? AND domain = ? AND path = ?").get(namespace, domain, path);
176
- }
177
-
178
- export function getPathsForNode(db, nodeUuid) {
179
- return db.prepare("SELECT * FROM paths WHERE node_uuid = ?").all(nodeUuid);
180
- }
181
-
182
- export function listPaths(db, namespace = "", domain = "core", parentPath = "") {
183
- const prefix = parentPath ? `${parentPath}/` : "";
184
- return db.prepare("SELECT * FROM paths WHERE namespace = ? AND domain = ? AND path LIKE ? ORDER BY path").all(namespace, domain, `${prefix}%`);
185
- }
186
-
187
- // ── Glossary operations ─────────────────────────────────────────────────
188
-
189
- export function addGlossaryKeyword(db, keyword, nodeUuid, namespace = "") {
190
- db.prepare("INSERT OR IGNORE INTO glossary_keywords (keyword, node_uuid, namespace) VALUES (?, ?, ?)").run(keyword, nodeUuid, namespace);
191
- }
192
-
193
- export function findNodeByKeyword(db, keyword, namespace = "") {
194
- return db.prepare("SELECT * FROM glossary_keywords WHERE keyword = ? AND (namespace = ? OR namespace = '')").get(keyword, namespace);
195
- }
196
-
197
- export function getGlossaryKeywords(db, namespace = "") {
198
- return db.prepare("SELECT * FROM glossary_keywords WHERE namespace = ? OR namespace = '' ORDER BY keyword").all(namespace);
199
- }
200
-
201
- // ── Search operations ───────────────────────────────────────────────────
202
-
203
- export function indexSearchDocument(db, nodeUuid, content, namespace = "") {
204
- db.prepare("INSERT OR REPLACE INTO search_documents (node_uuid, namespace, content) VALUES (?, ?, ?)").run(nodeUuid, namespace, content);
205
- }
206
-
207
- export function searchByContent(db, query, namespace = "") {
208
- return db.prepare("SELECT * FROM search_documents WHERE (namespace = ? OR namespace = '') AND content LIKE ?").all(namespace, `%${query}%`);
209
- }
210
-
211
- // ── Access log ──────────────────────────────────────────────────────────
212
-
213
- export function logAccess(db, nodeUuid, context = null, namespace = "") {
214
- db.prepare("INSERT INTO memory_access_log (node_uuid, namespace, context) VALUES (?, ?, ?)").run(nodeUuid, namespace, context);
215
- }
216
-
217
- export function getRecentAccesses(db, limit = 20) {
218
- return db.prepare("SELECT * FROM memory_access_log ORDER BY accessed_at DESC LIMIT ?").all(limit);
219
- }
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+
5
+ export const ROOT_NODE_UUID = "00000000-0000-0000-0000-000000000000";
6
+
7
+ const SCHEMA = `
8
+ CREATE TABLE IF NOT EXISTS nodes (
9
+ uuid TEXT PRIMARY KEY,
10
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
11
+ last_accessed_at TEXT
12
+ );
13
+
14
+ CREATE TABLE IF NOT EXISTS memories (
15
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
16
+ node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
17
+ content TEXT NOT NULL,
18
+ deprecated INTEGER NOT NULL DEFAULT 0,
19
+ migrated_to INTEGER REFERENCES memories(id),
20
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
21
+ );
22
+
23
+ CREATE TABLE IF NOT EXISTS edges (
24
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
25
+ parent_uuid TEXT NOT NULL REFERENCES nodes(uuid),
26
+ child_uuid TEXT NOT NULL REFERENCES nodes(uuid),
27
+ name TEXT NOT NULL,
28
+ priority INTEGER NOT NULL DEFAULT 0,
29
+ disclosure TEXT
30
+ );
31
+
32
+ CREATE TABLE IF NOT EXISTS paths (
33
+ namespace TEXT NOT NULL DEFAULT '',
34
+ domain TEXT NOT NULL DEFAULT 'core',
35
+ path TEXT NOT NULL,
36
+ edge_id INTEGER NOT NULL REFERENCES edges(id),
37
+ node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
38
+ PRIMARY KEY (namespace, domain, path)
39
+ );
40
+
41
+ CREATE TABLE IF NOT EXISTS glossary_keywords (
42
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43
+ keyword TEXT NOT NULL,
44
+ node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
45
+ namespace TEXT NOT NULL DEFAULT ''
46
+ );
47
+
48
+ CREATE TABLE IF NOT EXISTS search_documents (
49
+ node_uuid TEXT NOT NULL,
50
+ namespace TEXT NOT NULL DEFAULT '',
51
+ content TEXT NOT NULL,
52
+ PRIMARY KEY (node_uuid, namespace)
53
+ );
54
+
55
+ CREATE TABLE IF NOT EXISTS memory_access_log (
56
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
57
+ node_uuid TEXT NOT NULL REFERENCES nodes(uuid),
58
+ namespace TEXT NOT NULL DEFAULT '',
59
+ context TEXT,
60
+ accessed_at TEXT NOT NULL DEFAULT (datetime('now'))
61
+ );
62
+
63
+ CREATE INDEX IF NOT EXISTS idx_memories_node ON memories(node_uuid, deprecated);
64
+ CREATE INDEX IF NOT EXISTS idx_memories_migrated ON memories(migrated_to);
65
+ CREATE INDEX IF NOT EXISTS idx_edges_parent ON edges(parent_uuid);
66
+ CREATE INDEX IF NOT EXISTS idx_edges_child ON edges(child_uuid);
67
+ CREATE INDEX IF NOT EXISTS idx_paths_node ON paths(node_uuid);
68
+ CREATE INDEX IF NOT EXISTS idx_paths_edge ON paths(edge_id);
69
+ CREATE INDEX IF NOT EXISTS idx_glossary_node ON glossary_keywords(node_uuid);
70
+ CREATE INDEX IF NOT EXISTS idx_glossary_keyword ON glossary_keywords(keyword);
71
+ `;
72
+
73
+ export function openDatabase(dbPath) {
74
+ mkdirSync(dirname(dbPath), { recursive: true });
75
+ const db = new DatabaseSync(dbPath);
76
+ db.exec("PRAGMA journal_mode = WAL");
77
+ db.exec("PRAGMA foreign_keys = ON");
78
+ db.exec(SCHEMA);
79
+ ensureRootNode(db);
80
+ return db;
81
+ }
82
+
83
+ function ensureRootNode(db) {
84
+ const row = db.prepare("SELECT uuid FROM nodes WHERE uuid = ?").get(ROOT_NODE_UUID);
85
+ if (!row) {
86
+ db.prepare("INSERT INTO nodes (uuid) VALUES (?)").run(ROOT_NODE_UUID);
87
+ db.prepare("INSERT INTO memories (node_uuid, content, deprecated) VALUES (?, ?, 0)").run(ROOT_NODE_UUID, "Root node");
88
+ }
89
+ }
90
+
91
+ // ── Node operations ────────────────────────────────────────────────────
92
+
93
+ export function createNode(db, uuid) {
94
+ db.prepare("INSERT OR IGNORE INTO nodes (uuid) VALUES (?)").run(uuid);
95
+ return { uuid };
96
+ }
97
+
98
+ export function getNode(db, uuid) {
99
+ return db.prepare("SELECT * FROM nodes WHERE uuid = ?").get(uuid);
100
+ }
101
+
102
+ function touchNode(db, uuid) {
103
+ db.prepare("UPDATE nodes SET last_accessed_at = datetime('now') WHERE uuid = ?").run(uuid);
104
+ }
105
+
106
+ // ── Memory operations ───────────────────────────────────────────────────
107
+
108
+ export function createMemory(db, nodeUuid, content) {
109
+ const result = db.prepare("INSERT INTO memories (node_uuid, content) VALUES (?, ?)").run(nodeUuid, content);
110
+ touchNode(db, nodeUuid);
111
+ return { id: Number(result.lastInsertRowid), node_uuid: nodeUuid, content };
112
+ }
113
+
114
+ export function getCurrentMemory(db, nodeUuid) {
115
+ return db.prepare("SELECT * FROM memories WHERE node_uuid = ? AND deprecated = 0 ORDER BY id DESC LIMIT 1").get(nodeUuid);
116
+ }
117
+
118
+ export function getMemoryHistory(db, nodeUuid) {
119
+ return db.prepare("SELECT * FROM memories WHERE node_uuid = ? ORDER BY id DESC").all(nodeUuid);
120
+ }
121
+
122
+ export function updateMemory(db, nodeUuid, newContent) {
123
+ const current = getCurrentMemory(db, nodeUuid);
124
+ if (!current) return null;
125
+ db.prepare("UPDATE memories SET deprecated = 1 WHERE id = ?").run(current.id);
126
+ const result = db.prepare("INSERT INTO memories (node_uuid, content) VALUES (?, ?)").run(nodeUuid, newContent);
127
+ db.prepare("UPDATE memories SET migrated_to = ? WHERE id = ?").run(Number(result.lastInsertRowid), current.id);
128
+ touchNode(db, nodeUuid);
129
+ return { id: Number(result.lastInsertRowid), node_uuid: nodeUuid, content: newContent, previous_id: current.id };
130
+ }
131
+
132
+ export function deleteMemory(db, nodeUuid) {
133
+ const pathRows = db.prepare("SELECT edge_id FROM paths WHERE node_uuid = ?").all(nodeUuid);
134
+ db.prepare("DELETE FROM paths WHERE node_uuid = ?").run(nodeUuid);
135
+ for (const row of pathRows) {
136
+ try { db.prepare("DELETE FROM edges WHERE id = ?").run(row.edge_id); } catch {}
137
+ }
138
+ db.prepare("DELETE FROM edges WHERE parent_uuid = ? OR child_uuid = ?").run(nodeUuid, nodeUuid);
139
+ db.prepare("DELETE FROM glossary_keywords WHERE node_uuid = ?").run(nodeUuid);
140
+ db.prepare("DELETE FROM search_documents WHERE node_uuid = ?").run(nodeUuid);
141
+ db.prepare("DELETE FROM memory_access_log WHERE node_uuid = ?").run(nodeUuid);
142
+ db.prepare("DELETE FROM memories WHERE node_uuid = ?").run(nodeUuid);
143
+ const result = db.prepare("DELETE FROM nodes WHERE uuid = ? AND uuid != ?").run(nodeUuid, ROOT_NODE_UUID);
144
+ return result.changes > 0;
145
+ }
146
+
147
+ // ── Edge operations ─────────────────────────────────────────────────────
148
+
149
+ export function createEdge(db, parentUuid, childUuid, { name = "related", priority = 0, disclosure = null } = {}) {
150
+ const result = db.prepare(
151
+ "INSERT INTO edges (parent_uuid, child_uuid, name, priority, disclosure) VALUES (?, ?, ?, ?, ?)",
152
+ ).run(parentUuid, childUuid, name, priority, disclosure);
153
+ return { id: Number(result.lastInsertRowid), parent_uuid: parentUuid, child_uuid: childUuid, name };
154
+ }
155
+
156
+ export function getEdges(db, nodeUuid, { direction = "both" } = {}) {
157
+ if (direction === "children") return db.prepare("SELECT * FROM edges WHERE parent_uuid = ? ORDER BY priority DESC").all(nodeUuid);
158
+ if (direction === "parents") return db.prepare("SELECT * FROM edges WHERE child_uuid = ? ORDER BY priority DESC").all(nodeUuid);
159
+ return db.prepare("SELECT * FROM edges WHERE parent_uuid = ? OR child_uuid = ? ORDER BY priority DESC").all(nodeUuid, nodeUuid);
160
+ }
161
+
162
+ export function deleteEdge(db, edgeId) {
163
+ db.prepare("DELETE FROM paths WHERE edge_id = ?").run(edgeId);
164
+ return db.prepare("DELETE FROM edges WHERE id = ?").run(edgeId).changes > 0;
165
+ }
166
+
167
+ // ── Path operations ─────────────────────────────────────────────────────
168
+
169
+ export function createPath(db, { namespace = "", domain = "core", path, edgeId, nodeUuid }) {
170
+ db.prepare("INSERT OR REPLACE INTO paths (namespace, domain, path, edge_id, node_uuid) VALUES (?, ?, ?, ?, ?)").run(namespace, domain, path, edgeId, nodeUuid);
171
+ return { namespace, domain, path, edge_id: edgeId, node_uuid: nodeUuid };
172
+ }
173
+
174
+ export function getPath(db, namespace, domain, path) {
175
+ return db.prepare("SELECT * FROM paths WHERE namespace = ? AND domain = ? AND path = ?").get(namespace, domain, path);
176
+ }
177
+
178
+ export function getPathsForNode(db, nodeUuid) {
179
+ return db.prepare("SELECT * FROM paths WHERE node_uuid = ?").all(nodeUuid);
180
+ }
181
+
182
+ export function listPaths(db, namespace = "", domain = "core", parentPath = "") {
183
+ const prefix = parentPath ? `${parentPath}/` : "";
184
+ return db.prepare("SELECT * FROM paths WHERE namespace = ? AND domain = ? AND path LIKE ? ORDER BY path").all(namespace, domain, `${prefix}%`);
185
+ }
186
+
187
+ // ── Glossary operations ─────────────────────────────────────────────────
188
+
189
+ export function addGlossaryKeyword(db, keyword, nodeUuid, namespace = "") {
190
+ db.prepare("INSERT OR IGNORE INTO glossary_keywords (keyword, node_uuid, namespace) VALUES (?, ?, ?)").run(keyword, nodeUuid, namespace);
191
+ }
192
+
193
+ export function findNodeByKeyword(db, keyword, namespace = "") {
194
+ return db.prepare("SELECT * FROM glossary_keywords WHERE keyword = ? AND (namespace = ? OR namespace = '')").get(keyword, namespace);
195
+ }
196
+
197
+ export function getGlossaryKeywords(db, namespace = "") {
198
+ return db.prepare("SELECT * FROM glossary_keywords WHERE namespace = ? OR namespace = '' ORDER BY keyword").all(namespace);
199
+ }
200
+
201
+ // ── Search operations ───────────────────────────────────────────────────
202
+
203
+ export function indexSearchDocument(db, nodeUuid, content, namespace = "") {
204
+ db.prepare("INSERT OR REPLACE INTO search_documents (node_uuid, namespace, content) VALUES (?, ?, ?)").run(nodeUuid, namespace, content);
205
+ }
206
+
207
+ export function searchByContent(db, query, namespace = "") {
208
+ return db.prepare("SELECT * FROM search_documents WHERE (namespace = ? OR namespace = '') AND content LIKE ?").all(namespace, `%${query}%`);
209
+ }
210
+
211
+ // ── Access log ──────────────────────────────────────────────────────────
212
+
213
+ export function logAccess(db, nodeUuid, context = null, namespace = "") {
214
+ db.prepare("INSERT INTO memory_access_log (node_uuid, namespace, context) VALUES (?, ?, ?)").run(nodeUuid, namespace, context);
215
+ }
216
+
217
+ export function getRecentAccesses(db, limit = 20) {
218
+ return db.prepare("SELECT * FROM memory_access_log ORDER BY accessed_at DESC LIMIT ?").all(limit);
219
+ }