march-cli 0.1.20 → 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.
- package/bin/march.mjs +13 -13
- package/package.json +43 -42
- package/src/agent/command-exec-tool.mjs +172 -168
- package/src/agent/context-stats-tool.mjs +57 -57
- package/src/agent/editing/diff-apply.mjs +28 -28
- package/src/agent/editing/diff-format.mjs +57 -57
- package/src/agent/editing/lsp-report.mjs +69 -69
- package/src/agent/file-edit-tool.mjs +262 -262
- package/src/agent/file-tools/read-file-tool.mjs +112 -112
- package/src/agent/file-tools/read-image-tool.mjs +76 -76
- package/src/agent/model-payload-dumper.mjs +208 -208
- package/src/agent/pi-session/pi-session-sidecar-failure.mjs +10 -10
- package/src/agent/provider/payload-messages.mjs +138 -138
- package/src/agent/runner/codex-large-context-guard.mjs +87 -0
- package/src/agent/runner/codex-transport-compression.mjs +180 -0
- package/src/agent/runner/codex-transport-debug.mjs +113 -110
- package/src/agent/runner/codex-websocket-event-debug.mjs +130 -130
- package/src/agent/runner/fast-model.mjs +36 -36
- package/src/agent/runner/runner-cleanup.mjs +12 -12
- package/src/agent/runner/runner-init.mjs +15 -15
- package/src/agent/runner/runner-session-state.mjs +40 -40
- package/src/agent/runner/runner-utils.mjs +24 -24
- package/src/agent/runner.mjs +299 -295
- package/src/agent/runtime/ipc/ipc-peer.mjs +99 -99
- package/src/agent/runtime/ipc/process-ipc-transport.mjs +16 -16
- package/src/agent/runtime/remote-runner-client.mjs +73 -73
- package/src/agent/runtime/remote-ui-client.mjs +20 -20
- package/src/agent/runtime/runner-ipc-target.mjs +125 -125
- package/src/agent/runtime/runner-process-client.mjs +47 -47
- package/src/agent/runtime/runner-process-entry.mjs +11 -11
- package/src/agent/runtime/runner-process-factory.mjs +108 -108
- package/src/agent/runtime/runner-runtime-host.mjs +79 -79
- package/src/agent/runtime/runtime-factory.mjs +42 -42
- package/src/agent/runtime/runtime-host.mjs +34 -34
- package/src/agent/runtime/ui-event-bridge.mjs +95 -95
- package/src/agent/screen-tools/list-windows-tool.mjs +39 -39
- package/src/agent/screen-tools/screen-tool.mjs +49 -49
- package/src/agent/screen-tools/windows-screen.mjs +133 -133
- package/src/agent/session/session-auto-name.mjs +41 -41
- package/src/agent/session/session-binding.mjs +12 -12
- package/src/agent/session/session-options.mjs +47 -47
- package/src/agent/tool-names.mjs +1 -1
- package/src/agent/tool-result.mjs +3 -3
- package/src/agent/tool-summary.mjs +112 -112
- package/src/agent/tools.mjs +58 -58
- package/src/agent/turn/turn-events.mjs +111 -111
- package/src/agent/turn/turn-logging.mjs +30 -30
- package/src/agent/turn/turn-runner.mjs +196 -196
- package/src/agent/vision-capability.mjs +14 -14
- package/src/auth/login-command.mjs +90 -90
- package/src/auth/storage.mjs +34 -34
- package/src/cli/args.mjs +79 -79
- package/src/cli/commands/copy-command.mjs +87 -87
- package/src/cli/commands/export-command.mjs +206 -206
- package/src/cli/commands/extensions-command.mjs +53 -53
- package/src/cli/commands/help-command.mjs +7 -7
- package/src/cli/commands/model-command.mjs +141 -141
- package/src/cli/commands/paste-image-command.mjs +43 -43
- package/src/cli/commands/provider-command.mjs +59 -59
- package/src/cli/commands/status-command.mjs +194 -194
- package/src/cli/commands/thinking-command.mjs +87 -87
- package/src/cli/fallback-ui.mjs +156 -156
- package/src/cli/input/attachment-tokens.mjs +20 -20
- package/src/cli/input/autocomplete.mjs +74 -106
- package/src/cli/input/external-editor.mjs +39 -39
- package/src/cli/input/file-search/index.mjs +160 -0
- package/src/cli/input/history-store.mjs +35 -35
- package/src/cli/input/image-clipboard.mjs +55 -55
- package/src/cli/input/keybinding-dispatch.mjs +76 -76
- package/src/cli/input/keybindings.mjs +96 -96
- package/src/cli/input/mode-state.mjs +43 -43
- package/src/cli/input/prompt-templates.mjs +84 -84
- package/src/cli/input/select-with-keyboard.mjs +86 -86
- package/src/cli/permissions.mjs +103 -103
- package/src/cli/repl-commands.mjs +86 -86
- package/src/cli/repl-loop.mjs +183 -183
- package/src/cli/selector-list.mjs +21 -21
- package/src/cli/session/pi-session-switch-command.mjs +41 -41
- package/src/cli/session/session-command.mjs +23 -23
- package/src/cli/session/session-list-command.mjs +68 -68
- package/src/cli/session/session-name-command.mjs +26 -26
- package/src/cli/session/session-source-command.mjs +89 -89
- package/src/cli/session/session-switch-command.mjs +1 -1
- package/src/cli/shell/shell-command.mjs +55 -55
- package/src/cli/shell/shell-drawer-controls.mjs +33 -33
- package/src/cli/shell/shell-drawer.mjs +192 -192
- package/src/cli/shell/shell-split-layout.mjs +70 -70
- package/src/cli/slash-commands.mjs +192 -192
- package/src/cli/startup/create-runtime-runner.mjs +61 -61
- package/src/cli/startup/runtime-close.mjs +23 -23
- package/src/cli/startup/startup-banner.mjs +71 -71
- package/src/cli/startup/startup-session.mjs +51 -51
- package/src/cli/status-line-updater.mjs +75 -75
- package/src/cli/tool-output.mjs +9 -9
- package/src/cli/tui/editor/external-editor-runner.mjs +24 -24
- package/src/cli/tui/input/mouse-selection-controller.mjs +91 -91
- package/src/cli/tui/input/mouse-tracking.mjs +20 -20
- package/src/cli/tui/layout/main-pane-layout.mjs +47 -47
- package/src/cli/tui/layout/safe-render-boundary.mjs +46 -46
- package/src/cli/tui/markdown-renderer.mjs +285 -285
- package/src/cli/tui/output/scroll-state.mjs +79 -79
- package/src/cli/tui/output/text-line-renderer.mjs +50 -50
- package/src/cli/tui/output/tool-card-renderer.mjs +59 -59
- package/src/cli/tui/output/visible-lines.mjs +8 -8
- package/src/cli/tui/output-buffer.mjs +293 -293
- package/src/cli/tui/permission-request-ui.mjs +18 -18
- package/src/cli/tui/recall-rendering.mjs +25 -25
- package/src/cli/tui/render/render-scheduler.mjs +26 -26
- package/src/cli/tui/render/stream-delta-buffer.mjs +46 -46
- package/src/cli/tui/select/editor-select-list.mjs +111 -111
- package/src/cli/tui/selection-screen.mjs +269 -269
- package/src/cli/tui/status/retry-status.mjs +72 -72
- package/src/cli/tui/status/spinner-status.mjs +42 -42
- package/src/cli/tui/status/status-bar.mjs +225 -225
- package/src/cli/tui/syntax/highlighting.mjs +260 -260
- package/src/cli/tui/syntax/languages.mjs +91 -91
- package/src/cli/tui/syntax/tree-sitter/bash.highlights.scm +261 -261
- package/src/cli/tui/syntax/tree-sitter/c.highlights.scm +341 -341
- package/src/cli/tui/syntax/tree-sitter/cpp.highlights.scm +268 -268
- package/src/cli/tui/syntax/tree-sitter/csharp.highlights.scm +577 -577
- package/src/cli/tui/syntax/tree-sitter/css.highlights.scm +109 -109
- package/src/cli/tui/syntax/tree-sitter/diff.highlights.scm +49 -49
- package/src/cli/tui/syntax/tree-sitter/go.highlights.scm +254 -254
- package/src/cli/tui/syntax/tree-sitter/html.highlights.scm +13 -13
- package/src/cli/tui/syntax/tree-sitter/java.highlights.scm +330 -330
- package/src/cli/tui/syntax/tree-sitter/json.highlights.scm +38 -38
- package/src/cli/tui/syntax/tree-sitter/php.highlights.scm +203 -203
- package/src/cli/tui/syntax/tree-sitter/python.highlights.scm +137 -137
- package/src/cli/tui/syntax/tree-sitter/ruby.highlights.scm +309 -309
- package/src/cli/tui/syntax/tree-sitter/rust.highlights.scm +531 -531
- package/src/cli/tui/syntax/tree-sitter/toml.highlights.scm +39 -39
- package/src/cli/tui/syntax/tree-sitter/tsx.highlights.scm +35 -35
- package/src/cli/tui/syntax/tree-sitter/typescript.highlights.scm +35 -35
- package/src/cli/tui/syntax/tree-sitter/yaml.highlights.scm +99 -99
- package/src/cli/tui/tool-rendering.mjs +87 -87
- package/src/cli/tui/tui-diff-rendering.mjs +157 -157
- package/src/cli/tui/tui-handlers.mjs +111 -111
- package/src/cli/tui/tui-input-controller.mjs +61 -61
- package/src/cli/tui/ui-theme.mjs +157 -157
- package/src/cli/ui.mjs +297 -297
- package/src/config/config-json.mjs +84 -84
- package/src/config/dotenv.mjs +20 -20
- package/src/config/features.mjs +75 -75
- package/src/config/loader.mjs +143 -143
- package/src/config/settings-command.mjs +97 -97
- package/src/context/engine.mjs +198 -198
- package/src/context/injections.mjs +26 -26
- package/src/context/profiles.mjs +39 -39
- package/src/context/project-context.mjs +20 -20
- package/src/context/session-status.mjs +17 -17
- package/src/context/shell-layers.mjs +23 -23
- package/src/context/system-core/base.md +65 -65
- package/src/context/system-core/prompts/deepseek-v4-pro.md +3 -3
- package/src/context/system-core/prompts/default.md +3 -3
- package/src/context/system-core.mjs +35 -35
- package/src/debug/logger.mjs +141 -141
- package/src/debug/model-context-dumper.mjs +52 -52
- package/src/extensions/discovery.mjs +40 -40
- package/src/extensions/lifecycle-adapter.mjs +210 -210
- package/src/extensions/lifecycle-manifest.mjs +69 -69
- package/src/image-gen/index.mjs +7 -7
- package/src/image-gen/provider.mjs +231 -231
- package/src/image-gen/tool.mjs +84 -84
- package/src/lsp/client.mjs +257 -257
- package/src/lsp/diagnostic-store.mjs +42 -42
- package/src/lsp/diagnostics-format.mjs +72 -72
- package/src/lsp/managed-node-server.mjs +99 -99
- package/src/lsp/path-match.mjs +10 -10
- package/src/lsp/server-definitions.mjs +188 -188
- package/src/lsp/servers.mjs +165 -165
- package/src/lsp/service.mjs +110 -110
- package/src/lsp/status-message.mjs +9 -9
- package/src/lsp/typescript-project-resolver.mjs +186 -186
- package/src/main.mjs +299 -299
- package/src/mcp/client.mjs +195 -195
- package/src/mcp/config.mjs +130 -130
- package/src/mcp/index.mjs +48 -48
- package/src/mcp/tools.mjs +98 -98
- package/src/memory/database.mjs +219 -219
- package/src/memory/glossary.mjs +124 -124
- package/src/memory/graph/graph-cascades.mjs +109 -109
- package/src/memory/graph/graph-diagnostics.mjs +73 -73
- package/src/memory/graph/graph-path-removal.mjs +50 -50
- package/src/memory/graph/graph-path-utils.mjs +17 -17
- package/src/memory/graph/graph-primitives.mjs +103 -103
- package/src/memory/graph/graph-read.mjs +159 -159
- package/src/memory/graph.mjs +282 -282
- package/src/memory/markdown/markdown-delete.mjs +23 -23
- package/src/memory/markdown/markdown-format.mjs +128 -128
- package/src/memory/markdown/markdown-recall.mjs +28 -28
- package/src/memory/markdown/ripgrep.mjs +16 -16
- package/src/memory/markdown/sqlite-index.mjs +87 -87
- package/src/memory/markdown-store.mjs +286 -286
- package/src/memory/markdown-tools.mjs +103 -103
- package/src/memory/search.mjs +142 -142
- package/src/memory/snapshot.mjs +86 -86
- package/src/memory/system-views.mjs +120 -120
- package/src/memory/tools.mjs +282 -282
- package/src/network/environment.mjs +131 -131
- package/src/notification/desktop-notifier.mjs +262 -262
- package/src/platform/open-file.mjs +28 -28
- package/src/platform/spawn-command.mjs +27 -27
- package/src/provider/accept-command.mjs +89 -89
- package/src/provider/command.mjs +21 -21
- package/src/provider/config-command.mjs +129 -129
- package/src/provider/custom-provider.mjs +113 -113
- package/src/provider/hosted-tools.mjs +111 -111
- package/src/provider/presets.mjs +72 -72
- package/src/provider/share-command.mjs +79 -79
- package/src/provider/share-payload.mjs +52 -52
- package/src/session/attachment-display.mjs +16 -16
- package/src/session/attachment-references.mjs +65 -65
- package/src/session/attachments.mjs +140 -140
- package/src/session/persist.mjs +1 -1
- package/src/session/pi-manager.mjs +34 -34
- package/src/session/session-utils.mjs +16 -16
- package/src/session/sidecar-sync.mjs +19 -19
- package/src/session/sidecar.mjs +69 -69
- package/src/session/transcript.mjs +83 -83
- package/src/session/tree.mjs +42 -42
- package/src/shell/cli-runtime.mjs +11 -11
- package/src/shell/hints.mjs +12 -12
- package/src/shell/node-pty-adapter.mjs +81 -81
- package/src/shell/runtime-state.mjs +126 -126
- package/src/shell/runtime.mjs +252 -252
- package/src/shell/screen-buffer.mjs +136 -136
- package/src/shell/tool-read.mjs +74 -74
- package/src/shell/tools.mjs +299 -299
- package/src/supergrok/actions/image-generate.mjs +60 -60
- package/src/supergrok/actions/search.mjs +78 -78
- package/src/supergrok/auth.mjs +36 -36
- package/src/supergrok/constants.mjs +18 -18
- package/src/supergrok/oauth-provider.mjs +278 -278
- package/src/supergrok/provider.mjs +35 -35
- package/src/supergrok/response.mjs +76 -76
- package/src/supergrok/tool.mjs +61 -61
- package/src/text/ansi.mjs +3 -3
- package/src/web/config-command.mjs +43 -43
- package/src/web/fetch.mjs +78 -78
- package/src/web/presets.mjs +16 -16
- package/src/web/search.mjs +83 -83
- package/src/web/tools.mjs +107 -107
package/src/memory/database.mjs
CHANGED
|
@@ -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
|
+
}
|