clawvault 2.5.1 → 2.5.3
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/README.md +159 -199
- package/bin/clawvault.js +111 -111
- package/bin/command-registration.test.js +166 -165
- package/bin/command-runtime.js +93 -77
- package/bin/command-runtime.test.js +154 -102
- package/bin/help-contract.test.js +39 -28
- package/bin/register-config-commands.js +153 -153
- package/bin/register-config-route-commands.test.js +121 -121
- package/bin/register-core-commands.js +237 -237
- package/bin/register-kanban-commands.js +56 -56
- package/bin/register-kanban-commands.test.js +83 -83
- package/bin/register-maintenance-commands.js +282 -248
- package/bin/register-project-commands.js +209 -209
- package/bin/register-project-commands.test.js +206 -201
- package/bin/register-query-commands.js +317 -312
- package/bin/register-query-commands.test.js +65 -0
- package/bin/register-resilience-commands.js +182 -182
- package/bin/register-resilience-commands.test.js +81 -81
- package/bin/register-route-commands.js +114 -114
- package/bin/register-session-lifecycle-commands.js +206 -206
- package/bin/register-tailscale-commands.js +106 -106
- package/bin/register-task-commands.js +348 -348
- package/bin/register-task-commands.test.js +69 -69
- package/bin/register-template-commands.js +72 -72
- package/bin/register-vault-operations-commands.js +300 -300
- package/bin/test-helpers/cli-command-fixtures.js +119 -119
- package/dashboard/lib/graph-diff.js +104 -104
- package/dashboard/lib/graph-diff.test.js +75 -75
- package/dashboard/lib/vault-parser.js +556 -556
- package/dashboard/lib/vault-parser.test.js +254 -254
- package/dashboard/public/app.js +796 -796
- package/dashboard/public/index.html +52 -52
- package/dashboard/public/styles.css +221 -221
- package/dashboard/server.js +374 -374
- package/dist/{chunk-G3OQJ2NQ.js → chunk-2YDBJS7M.js} +1 -1
- package/dist/chunk-3FP5BJ42.js +88 -0
- package/dist/{chunk-C3PF7WBA.js → chunk-4IV3R2F5.js} +2 -2
- package/dist/{chunk-7OHQFMJK.js → chunk-AY4PGUVL.js} +5 -4
- package/dist/chunk-FG6RJMCN.js +33 -0
- package/dist/{chunk-WIICLBNF.js → chunk-GFJ3LIIB.js} +1 -1
- package/dist/chunk-IZEY5S74.js +541 -0
- package/dist/chunk-LMEMZGUV.js +332 -0
- package/dist/{chunk-6RQPD7X6.js → chunk-M25QVSJM.js} +4 -3
- package/dist/{chunk-6B3JWM7J.js → chunk-O7XHXF7F.js} +34 -7
- package/dist/chunk-OSMS7QIG.js +406 -0
- package/dist/{chunk-PAYUH64O.js → chunk-QVMXF7FY.js} +11 -1
- package/dist/{chunk-TMZMN7OS.js → chunk-S2IG7VNM.js} +24 -12
- package/dist/{chunk-LMCC5OC7.js → chunk-TPDH3JPP.js} +1 -1
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +31 -0
- package/dist/commands/canvas.js +3 -3
- package/dist/commands/compat.js +1 -1
- package/dist/commands/context.js +4 -4
- package/dist/commands/doctor.js +16 -309
- package/dist/commands/embed.d.ts +17 -0
- package/dist/commands/embed.js +10 -0
- package/dist/commands/migrate-observations.js +2 -2
- package/dist/commands/observe.d.ts +1 -0
- package/dist/commands/observe.js +7 -6
- package/dist/commands/rebuild.js +5 -5
- package/dist/commands/reflect.js +3 -3
- package/dist/commands/replay.js +7 -7
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +2 -2
- package/dist/commands/sleep.d.ts +2 -1
- package/dist/commands/sleep.js +15 -15
- package/dist/commands/status.d.ts +9 -1
- package/dist/commands/status.js +33 -8
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +6 -6
- package/dist/index.d.ts +82 -5
- package/dist/index.js +127 -105
- package/dist/{types-jjuYN2Xn.d.ts → types-C74wgGL1.d.ts} +2 -0
- package/hooks/clawvault/HOOK.md +83 -74
- package/hooks/clawvault/handler.js +816 -812
- package/hooks/clawvault/handler.test.js +263 -263
- package/package.json +94 -125
- package/templates/checkpoint.md +19 -19
- package/templates/daily-note.md +19 -19
- package/templates/daily.md +19 -19
- package/templates/decision.md +17 -17
- package/templates/handoff.md +19 -19
- package/templates/lesson.md +16 -16
- package/templates/person.md +19 -19
- package/templates/project.md +23 -23
- package/dist/chunk-2RK2AG32.js +0 -743
- package/dist/{chunk-FW465EEA.js → chunk-VXEOHTSL.js} +3 -3
- package/dist/{chunk-KCCHROBR.js → chunk-YOSEUUNB.js} +4 -4
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatAge
|
|
3
|
+
} from "./chunk-7ZRP733D.js";
|
|
4
|
+
import {
|
|
5
|
+
scanVaultLinks
|
|
6
|
+
} from "./chunk-4VQTUVH7.js";
|
|
7
|
+
import {
|
|
8
|
+
getObserverStaleness
|
|
9
|
+
} from "./chunk-IZEY5S74.js";
|
|
10
|
+
import {
|
|
11
|
+
ClawVault,
|
|
12
|
+
findVault
|
|
13
|
+
} from "./chunk-AY4PGUVL.js";
|
|
14
|
+
import {
|
|
15
|
+
hasQmd
|
|
16
|
+
} from "./chunk-O7XHXF7F.js";
|
|
17
|
+
import {
|
|
18
|
+
loadMemoryGraphIndex
|
|
19
|
+
} from "./chunk-ZZA73MFY.js";
|
|
20
|
+
import {
|
|
21
|
+
checkOpenClawCompatibility
|
|
22
|
+
} from "./chunk-QVMXF7FY.js";
|
|
23
|
+
|
|
24
|
+
// src/commands/doctor.ts
|
|
25
|
+
import * as fs from "fs";
|
|
26
|
+
import * as os from "os";
|
|
27
|
+
import * as path from "path";
|
|
28
|
+
var CLAWVAULT_DIR = ".clawvault";
|
|
29
|
+
var CHECKPOINT_FILE = "last-checkpoint.json";
|
|
30
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
31
|
+
var ACTIVE_USE_DAYS = 7;
|
|
32
|
+
function daysSince(date, now = Date.now()) {
|
|
33
|
+
return Math.max(0, Math.floor((now - date.getTime()) / DAY_MS));
|
|
34
|
+
}
|
|
35
|
+
function describeAge(date, now = Date.now()) {
|
|
36
|
+
return formatAge(now - date.getTime());
|
|
37
|
+
}
|
|
38
|
+
function loadCheckpointTimestamp(vaultPath) {
|
|
39
|
+
const checkpointPath = path.join(vaultPath, CLAWVAULT_DIR, CHECKPOINT_FILE);
|
|
40
|
+
if (!fs.existsSync(checkpointPath)) {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const data = JSON.parse(fs.readFileSync(checkpointPath, "utf-8"));
|
|
45
|
+
return { timestamp: data.timestamp };
|
|
46
|
+
} catch (err) {
|
|
47
|
+
return { error: err?.message || "Failed to parse checkpoint" };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function getShellConfigPaths(shellPath) {
|
|
51
|
+
const home = os.homedir();
|
|
52
|
+
const shellName = shellPath ? path.basename(shellPath) : "bash";
|
|
53
|
+
if (shellName === "zsh") {
|
|
54
|
+
return [path.join(home, ".zshrc"), path.join(home, ".zprofile")];
|
|
55
|
+
}
|
|
56
|
+
if (shellName === "fish") {
|
|
57
|
+
return [path.join(home, ".config", "fish", "config.fish")];
|
|
58
|
+
}
|
|
59
|
+
return [path.join(home, ".bashrc"), path.join(home, ".bash_profile"), path.join(home, ".profile")];
|
|
60
|
+
}
|
|
61
|
+
function hasClawvaultPathConfig(paths) {
|
|
62
|
+
for (const filePath of paths) {
|
|
63
|
+
if (!fs.existsSync(filePath)) continue;
|
|
64
|
+
try {
|
|
65
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
66
|
+
if (/CLAWVAULT_PATH\s*=/.test(content)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
async function resolveVault(vaultPath) {
|
|
75
|
+
if (vaultPath) {
|
|
76
|
+
const vault = new ClawVault(path.resolve(vaultPath));
|
|
77
|
+
await vault.load();
|
|
78
|
+
return vault;
|
|
79
|
+
}
|
|
80
|
+
const envPath = process.env.CLAWVAULT_PATH;
|
|
81
|
+
if (envPath) {
|
|
82
|
+
const vault = new ClawVault(path.resolve(envPath));
|
|
83
|
+
await vault.load();
|
|
84
|
+
return vault;
|
|
85
|
+
}
|
|
86
|
+
const found = await findVault();
|
|
87
|
+
if (!found) {
|
|
88
|
+
throw new Error("No ClawVault found. Run `clawvault init` first.");
|
|
89
|
+
}
|
|
90
|
+
return found;
|
|
91
|
+
}
|
|
92
|
+
async function doctor(vaultPath) {
|
|
93
|
+
const checks = [];
|
|
94
|
+
let warnings = 0;
|
|
95
|
+
let errors = 0;
|
|
96
|
+
const compatReport = checkOpenClawCompatibility();
|
|
97
|
+
if (compatReport.errors > 0) {
|
|
98
|
+
checks.push({
|
|
99
|
+
label: "OpenClaw compatibility",
|
|
100
|
+
status: "error",
|
|
101
|
+
detail: `${compatReport.errors} error(s), ${compatReport.warnings} warning(s)`,
|
|
102
|
+
hint: "Run `clawvault compat` for full compatibility diagnostics."
|
|
103
|
+
});
|
|
104
|
+
errors++;
|
|
105
|
+
} else if (compatReport.warnings > 0) {
|
|
106
|
+
checks.push({
|
|
107
|
+
label: "OpenClaw compatibility",
|
|
108
|
+
status: "warn",
|
|
109
|
+
detail: `${compatReport.warnings} warning(s)`,
|
|
110
|
+
hint: "Run `clawvault compat` for full compatibility diagnostics."
|
|
111
|
+
});
|
|
112
|
+
warnings++;
|
|
113
|
+
} else {
|
|
114
|
+
checks.push({
|
|
115
|
+
label: "OpenClaw compatibility",
|
|
116
|
+
status: "ok"
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (hasQmd()) {
|
|
120
|
+
checks.push({ label: "qmd installed", status: "ok" });
|
|
121
|
+
} else {
|
|
122
|
+
checks.push({
|
|
123
|
+
label: "qmd installed",
|
|
124
|
+
status: "error",
|
|
125
|
+
hint: "Install qmd to enable ClawVault commands."
|
|
126
|
+
});
|
|
127
|
+
errors++;
|
|
128
|
+
}
|
|
129
|
+
const shellConfigs = getShellConfigPaths(process.env.SHELL).filter(fs.existsSync);
|
|
130
|
+
if (hasClawvaultPathConfig(shellConfigs)) {
|
|
131
|
+
checks.push({
|
|
132
|
+
label: "CLAWVAULT_PATH in shell config",
|
|
133
|
+
status: "ok",
|
|
134
|
+
detail: shellConfigs.map((p) => path.basename(p)).join(", ")
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
checks.push({
|
|
138
|
+
label: "CLAWVAULT_PATH in shell config",
|
|
139
|
+
status: "warn",
|
|
140
|
+
hint: "Run `clawvault shell-init` and add it to your shell rc."
|
|
141
|
+
});
|
|
142
|
+
warnings++;
|
|
143
|
+
}
|
|
144
|
+
if (!hasQmd()) {
|
|
145
|
+
return { vaultPath, checks, warnings, errors };
|
|
146
|
+
}
|
|
147
|
+
let vault;
|
|
148
|
+
try {
|
|
149
|
+
vault = await resolveVault(vaultPath);
|
|
150
|
+
checks.push({ label: "vault found", status: "ok", detail: vault.getPath() });
|
|
151
|
+
} catch (err) {
|
|
152
|
+
checks.push({
|
|
153
|
+
label: "vault found",
|
|
154
|
+
status: "error",
|
|
155
|
+
detail: err?.message || "Unable to locate vault"
|
|
156
|
+
});
|
|
157
|
+
errors++;
|
|
158
|
+
return { vaultPath, checks, warnings, errors };
|
|
159
|
+
}
|
|
160
|
+
const stats = await vault.stats();
|
|
161
|
+
const documents = await vault.list();
|
|
162
|
+
const handoffs = await vault.list("handoffs");
|
|
163
|
+
const inbox = await vault.list("inbox");
|
|
164
|
+
const qmdCollection = vault.getQmdCollection();
|
|
165
|
+
if (qmdCollection) {
|
|
166
|
+
checks.push({ label: "qmd collection configured", status: "ok", detail: qmdCollection });
|
|
167
|
+
} else {
|
|
168
|
+
checks.push({
|
|
169
|
+
label: "qmd collection configured",
|
|
170
|
+
status: "warn",
|
|
171
|
+
hint: "Set qmd collection in .clawvault.json"
|
|
172
|
+
});
|
|
173
|
+
warnings++;
|
|
174
|
+
}
|
|
175
|
+
const latestDoc = documents.slice().sort((a, b) => b.modified.getTime() - a.modified.getTime())[0];
|
|
176
|
+
const latestDocAge = latestDoc ? daysSince(latestDoc.modified) : null;
|
|
177
|
+
const graphIndex = loadMemoryGraphIndex(vault.getPath());
|
|
178
|
+
if (!graphIndex) {
|
|
179
|
+
checks.push({
|
|
180
|
+
label: "memory graph index",
|
|
181
|
+
status: "warn",
|
|
182
|
+
detail: "No graph index found",
|
|
183
|
+
hint: "Run `clawvault graph --refresh` to build .clawvault/graph-index.json."
|
|
184
|
+
});
|
|
185
|
+
warnings++;
|
|
186
|
+
} else {
|
|
187
|
+
const generatedAt = new Date(graphIndex.generatedAt);
|
|
188
|
+
const generatedAge = describeAge(generatedAt);
|
|
189
|
+
const latestDocIsNewer = latestDoc ? latestDoc.modified.getTime() > generatedAt.getTime() + 1e3 : false;
|
|
190
|
+
if (latestDocIsNewer) {
|
|
191
|
+
checks.push({
|
|
192
|
+
label: "memory graph index",
|
|
193
|
+
status: "warn",
|
|
194
|
+
detail: `Stale graph index (generated ${generatedAge} ago)`,
|
|
195
|
+
hint: "Run `clawvault graph --refresh` to resync index."
|
|
196
|
+
});
|
|
197
|
+
warnings++;
|
|
198
|
+
} else {
|
|
199
|
+
checks.push({
|
|
200
|
+
label: "memory graph index",
|
|
201
|
+
status: "ok",
|
|
202
|
+
detail: `${graphIndex.graph.stats.nodeCount} nodes, ${graphIndex.graph.stats.edgeCount} edges`
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
let lastHandoffAge = null;
|
|
207
|
+
if (handoffs.length === 0) {
|
|
208
|
+
checks.push({
|
|
209
|
+
label: "recent handoff",
|
|
210
|
+
status: "warn",
|
|
211
|
+
hint: "Run `clawvault sleep` at the end of sessions."
|
|
212
|
+
});
|
|
213
|
+
warnings++;
|
|
214
|
+
} else {
|
|
215
|
+
const latestHandoff = handoffs.slice().sort((a, b) => b.modified.getTime() - a.modified.getTime())[0];
|
|
216
|
+
lastHandoffAge = daysSince(latestHandoff.modified);
|
|
217
|
+
const ageLabel = describeAge(latestHandoff.modified);
|
|
218
|
+
if (lastHandoffAge > 1) {
|
|
219
|
+
checks.push({
|
|
220
|
+
label: "recent handoff",
|
|
221
|
+
status: "warn",
|
|
222
|
+
detail: `Last handoff ${ageLabel} ago`,
|
|
223
|
+
hint: "Run `clawvault sleep` before long pauses."
|
|
224
|
+
});
|
|
225
|
+
warnings++;
|
|
226
|
+
} else {
|
|
227
|
+
checks.push({
|
|
228
|
+
label: "recent handoff",
|
|
229
|
+
status: "ok",
|
|
230
|
+
detail: `Last handoff ${ageLabel} ago`
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const checkpointInfo = loadCheckpointTimestamp(vault.getPath());
|
|
235
|
+
const activeUse = latestDocAge !== null && latestDocAge <= ACTIVE_USE_DAYS || lastHandoffAge !== null && lastHandoffAge <= ACTIVE_USE_DAYS;
|
|
236
|
+
if (checkpointInfo.error) {
|
|
237
|
+
checks.push({
|
|
238
|
+
label: "checkpoint freshness",
|
|
239
|
+
status: "warn",
|
|
240
|
+
detail: checkpointInfo.error
|
|
241
|
+
});
|
|
242
|
+
warnings++;
|
|
243
|
+
} else if (!checkpointInfo.timestamp) {
|
|
244
|
+
const status = activeUse ? "warn" : "ok";
|
|
245
|
+
if (status === "warn") warnings++;
|
|
246
|
+
checks.push({
|
|
247
|
+
label: "checkpoint freshness",
|
|
248
|
+
status,
|
|
249
|
+
detail: activeUse ? "No checkpoint found" : "No checkpoint found (vault appears inactive)",
|
|
250
|
+
hint: activeUse ? "Run `clawvault checkpoint` during heavy work." : void 0
|
|
251
|
+
});
|
|
252
|
+
} else {
|
|
253
|
+
const checkpointDate = new Date(checkpointInfo.timestamp);
|
|
254
|
+
const checkpointAge = daysSince(checkpointDate);
|
|
255
|
+
const ageLabel = describeAge(checkpointDate);
|
|
256
|
+
if (activeUse && checkpointAge > 1) {
|
|
257
|
+
checks.push({
|
|
258
|
+
label: "checkpoint freshness",
|
|
259
|
+
status: "warn",
|
|
260
|
+
detail: `Last checkpoint ${ageLabel} ago`,
|
|
261
|
+
hint: "Checkpoint at least once per active day."
|
|
262
|
+
});
|
|
263
|
+
warnings++;
|
|
264
|
+
} else {
|
|
265
|
+
checks.push({
|
|
266
|
+
label: "checkpoint freshness",
|
|
267
|
+
status: "ok",
|
|
268
|
+
detail: `Last checkpoint ${ageLabel} ago`
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const observerStaleness = getObserverStaleness(vault.getPath());
|
|
273
|
+
if (observerStaleness.staleCount > 0) {
|
|
274
|
+
checks.push({
|
|
275
|
+
label: "observer freshness",
|
|
276
|
+
status: "warn",
|
|
277
|
+
detail: `${observerStaleness.staleCount} stale session cursor(s); oldest ${formatAge(observerStaleness.oldestMs)} ago`,
|
|
278
|
+
hint: "Run `clawvault observe --cron` and verify cron/hook scheduling."
|
|
279
|
+
});
|
|
280
|
+
warnings++;
|
|
281
|
+
} else {
|
|
282
|
+
checks.push({
|
|
283
|
+
label: "observer freshness",
|
|
284
|
+
status: "ok"
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
const linkScan = scanVaultLinks(vault.getPath());
|
|
288
|
+
if (linkScan.orphans.length > 20) {
|
|
289
|
+
checks.push({
|
|
290
|
+
label: "orphan links",
|
|
291
|
+
status: "warn",
|
|
292
|
+
detail: `${linkScan.orphans.length} orphan link(s)`,
|
|
293
|
+
hint: "Run `clawvault link --orphans` to review."
|
|
294
|
+
});
|
|
295
|
+
warnings++;
|
|
296
|
+
} else {
|
|
297
|
+
checks.push({
|
|
298
|
+
label: "orphan links",
|
|
299
|
+
status: "ok",
|
|
300
|
+
detail: `${linkScan.orphans.length} orphan link(s)`
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (inbox.length > 5) {
|
|
304
|
+
checks.push({
|
|
305
|
+
label: "inbox backlog",
|
|
306
|
+
status: "warn",
|
|
307
|
+
detail: `${inbox.length} inbox item(s) pending`,
|
|
308
|
+
hint: "Process inbox items to keep memory tidy."
|
|
309
|
+
});
|
|
310
|
+
warnings++;
|
|
311
|
+
} else {
|
|
312
|
+
checks.push({
|
|
313
|
+
label: "inbox backlog",
|
|
314
|
+
status: "ok",
|
|
315
|
+
detail: `${inbox.length} inbox item(s) pending`
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (stats.documents < 5) {
|
|
319
|
+
checks.push({
|
|
320
|
+
label: "vault activity",
|
|
321
|
+
status: "warn",
|
|
322
|
+
detail: `${stats.documents} total documents`,
|
|
323
|
+
hint: "Start capturing decisions, lessons, and projects."
|
|
324
|
+
});
|
|
325
|
+
warnings++;
|
|
326
|
+
}
|
|
327
|
+
return { vaultPath: vault.getPath(), checks, warnings, errors };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export {
|
|
331
|
+
doctor
|
|
332
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
hasQmd
|
|
3
|
-
|
|
2
|
+
hasQmd,
|
|
3
|
+
withQmdIndexArgs
|
|
4
|
+
} from "./chunk-O7XHXF7F.js";
|
|
4
5
|
import {
|
|
5
6
|
DEFAULT_CATEGORIES
|
|
6
7
|
} from "./chunk-2CDEETQN.js";
|
|
@@ -337,7 +338,7 @@ async function setupCommand(options = {}) {
|
|
|
337
338
|
if (hasQmd()) {
|
|
338
339
|
const { collection, root } = getQmdConfig(target.vaultPath);
|
|
339
340
|
try {
|
|
340
|
-
execFileSync("qmd", ["collection", "add", root, "--name", collection, "--mask", "**/*.md"], {
|
|
341
|
+
execFileSync("qmd", withQmdIndexArgs(["collection", "add", root, "--name", collection, "--mask", "**/*.md"], options.qmdIndexName), {
|
|
341
342
|
stdio: "ignore"
|
|
342
343
|
});
|
|
343
344
|
console.log(`\u2713 qmd collection ready: ${collection}`);
|
|
@@ -5,6 +5,7 @@ import * as path from "path";
|
|
|
5
5
|
var QMD_INSTALL_URL = "https://github.com/tobi/qmd";
|
|
6
6
|
var QMD_INSTALL_COMMAND = "bun install -g github:tobi/qmd";
|
|
7
7
|
var QMD_NOT_INSTALLED_MESSAGE = `ClawVault requires qmd. Install: ${QMD_INSTALL_COMMAND}`;
|
|
8
|
+
var QMD_INDEX_ENV_VAR = "CLAWVAULT_QMD_INDEX";
|
|
8
9
|
var QmdUnavailableError = class extends Error {
|
|
9
10
|
constructor(message = QMD_NOT_INSTALLED_MESSAGE) {
|
|
10
11
|
super(message);
|
|
@@ -14,6 +15,24 @@ var QmdUnavailableError = class extends Error {
|
|
|
14
15
|
function ensureJsonArgs(args) {
|
|
15
16
|
return args.includes("--json") ? args : [...args, "--json"];
|
|
16
17
|
}
|
|
18
|
+
function resolveQmdIndexName(indexName) {
|
|
19
|
+
const explicit = indexName?.trim();
|
|
20
|
+
if (explicit) {
|
|
21
|
+
return explicit;
|
|
22
|
+
}
|
|
23
|
+
const fromEnv = process.env[QMD_INDEX_ENV_VAR]?.trim();
|
|
24
|
+
return fromEnv || void 0;
|
|
25
|
+
}
|
|
26
|
+
function withQmdIndexArgs(args, indexName) {
|
|
27
|
+
if (args.includes("--index")) {
|
|
28
|
+
return [...args];
|
|
29
|
+
}
|
|
30
|
+
const resolvedIndexName = resolveQmdIndexName(indexName);
|
|
31
|
+
if (!resolvedIndexName) {
|
|
32
|
+
return [...args];
|
|
33
|
+
}
|
|
34
|
+
return ["--index", resolvedIndexName, ...args];
|
|
35
|
+
}
|
|
17
36
|
function tryParseJson(raw) {
|
|
18
37
|
try {
|
|
19
38
|
return JSON.parse(raw);
|
|
@@ -64,9 +83,9 @@ function ensureQmdAvailable() {
|
|
|
64
83
|
throw new QmdUnavailableError();
|
|
65
84
|
}
|
|
66
85
|
}
|
|
67
|
-
function execQmd(args) {
|
|
86
|
+
function execQmd(args, indexName) {
|
|
68
87
|
ensureQmdAvailable();
|
|
69
|
-
const finalArgs = ensureJsonArgs(args);
|
|
88
|
+
const finalArgs = withQmdIndexArgs(ensureJsonArgs(args), indexName);
|
|
70
89
|
try {
|
|
71
90
|
const result = execFileSync("qmd", finalArgs, {
|
|
72
91
|
encoding: "utf-8",
|
|
@@ -94,27 +113,28 @@ function hasQmd() {
|
|
|
94
113
|
const result = spawnSync("qmd", ["--version"], { stdio: "ignore" });
|
|
95
114
|
return !result.error;
|
|
96
115
|
}
|
|
97
|
-
function qmdUpdate(collection) {
|
|
116
|
+
function qmdUpdate(collection, indexName) {
|
|
98
117
|
ensureQmdAvailable();
|
|
99
118
|
const args = ["update"];
|
|
100
119
|
if (collection) {
|
|
101
120
|
args.push("-c", collection);
|
|
102
121
|
}
|
|
103
|
-
execFileSync("qmd", args, { stdio: "inherit" });
|
|
122
|
+
execFileSync("qmd", withQmdIndexArgs(args, indexName), { stdio: "inherit" });
|
|
104
123
|
}
|
|
105
|
-
function qmdEmbed(collection) {
|
|
124
|
+
function qmdEmbed(collection, indexName) {
|
|
106
125
|
ensureQmdAvailable();
|
|
107
126
|
const args = ["embed"];
|
|
108
127
|
if (collection) {
|
|
109
128
|
args.push("-c", collection);
|
|
110
129
|
}
|
|
111
|
-
execFileSync("qmd", args, { stdio: "inherit" });
|
|
130
|
+
execFileSync("qmd", withQmdIndexArgs(args, indexName), { stdio: "inherit" });
|
|
112
131
|
}
|
|
113
132
|
var SearchEngine = class {
|
|
114
133
|
documents = /* @__PURE__ */ new Map();
|
|
115
134
|
collection = "clawvault";
|
|
116
135
|
vaultPath = "";
|
|
117
136
|
collectionRoot = "";
|
|
137
|
+
qmdIndexName;
|
|
118
138
|
/**
|
|
119
139
|
* Set the collection name (usually vault name)
|
|
120
140
|
*/
|
|
@@ -133,6 +153,12 @@ var SearchEngine = class {
|
|
|
133
153
|
setCollectionRoot(root) {
|
|
134
154
|
this.collectionRoot = path.resolve(root);
|
|
135
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Set qmd index name (defaults to qmd global default when omitted)
|
|
158
|
+
*/
|
|
159
|
+
setIndexName(indexName) {
|
|
160
|
+
this.qmdIndexName = indexName;
|
|
161
|
+
}
|
|
136
162
|
/**
|
|
137
163
|
* Add or update a document in the local cache
|
|
138
164
|
* Note: qmd indexing happens via qmd update command
|
|
@@ -189,7 +215,7 @@ var SearchEngine = class {
|
|
|
189
215
|
if (this.collection) {
|
|
190
216
|
args.push("-c", this.collection);
|
|
191
217
|
}
|
|
192
|
-
const qmdResults = execQmd(args);
|
|
218
|
+
const qmdResults = execQmd(args, this.qmdIndexName);
|
|
193
219
|
return this.convertResults(qmdResults, {
|
|
194
220
|
limit,
|
|
195
221
|
minScore,
|
|
@@ -339,6 +365,7 @@ export {
|
|
|
339
365
|
QMD_INSTALL_URL,
|
|
340
366
|
QMD_INSTALL_COMMAND,
|
|
341
367
|
QmdUnavailableError,
|
|
368
|
+
withQmdIndexArgs,
|
|
342
369
|
hasQmd,
|
|
343
370
|
qmdUpdate,
|
|
344
371
|
qmdEmbed,
|