clawvault 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -16
- package/bin/clawvault.js +0 -2
- package/bin/command-registration.test.js +13 -1
- package/bin/help-contract.test.js +14 -0
- package/bin/register-core-commands.js +88 -0
- package/bin/register-core-commands.test.js +80 -0
- package/bin/register-maintenance-commands.js +57 -6
- package/bin/register-query-commands.js +10 -28
- package/bin/test-helpers/cli-command-fixtures.js +1 -0
- package/dist/chunk-2PKBIKDH.js +130 -0
- package/dist/{chunk-U67V476Y.js → chunk-2ZDO52B4.js} +18 -1
- package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
- package/dist/{chunk-AZYOKJYC.js → chunk-4PY655YM.js} +13 -1
- package/dist/{chunk-2JQ3O2YL.js → chunk-5EFSWZO6.js} +3 -3
- package/dist/{chunk-Y3TIJEBP.js → chunk-7SWP5FKU.js} +34 -613
- package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
- package/dist/{chunk-URXDAUVH.js → chunk-AXSJIFOJ.js} +174 -1
- package/dist/{chunk-4ITRXIVT.js → chunk-BLQXXX7Q.js} +6 -6
- package/dist/chunk-CSHO3PJB.js +684 -0
- package/dist/{chunk-S5OJEGFG.js → chunk-DOIUYIXV.js} +2 -2
- package/dist/{chunk-YXQCA6B7.js → chunk-DVOUSOR3.js} +112 -7
- package/dist/{chunk-YDWHS4LJ.js → chunk-ECGJYWNA.js} +205 -33
- package/dist/{chunk-QMHPQYUV.js → chunk-EL6UBSX5.js} +7 -6
- package/dist/chunk-FZ5I2NF7.js +352 -0
- package/dist/{chunk-WJVWINEM.js → chunk-GFCHWMGD.js} +55 -6
- package/dist/{chunk-GNJL4YGR.js → chunk-GJO3CFUN.js} +30 -6
- package/dist/chunk-H3JZIB5O.js +322 -0
- package/dist/chunk-HEHO7SMV.js +51 -0
- package/dist/{chunk-UCQAOZHW.js → chunk-HGDDW24U.js} +3 -3
- package/dist/chunk-J3YUXVID.js +907 -0
- package/dist/{chunk-Y6VJKXGL.js → chunk-KCYWJDDW.js} +1 -1
- package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
- package/dist/{chunk-YNIPYN4F.js → chunk-OFOCU2V4.js} +6 -5
- package/dist/{chunk-42MXU7A6.js → chunk-P62WHA27.js} +58 -47
- package/dist/chunk-PTWPPVC7.js +972 -0
- package/dist/{chunk-FAKNOB7Y.js → chunk-QFWERBDP.js} +2 -2
- package/dist/{chunk-IIOU45CK.js → chunk-S7N7HI5E.js} +2 -2
- package/dist/{chunk-ECRZL5XR.js → chunk-T7E764W3.js} +23 -7
- package/dist/chunk-TDWFBDAQ.js +1016 -0
- package/dist/{chunk-MNPUYCHQ.js → chunk-TWMI3SNN.js} +6 -5
- package/dist/{chunk-2RAZ4ZFE.js → chunk-VBILES4B.js} +1 -1
- package/dist/{chunk-PI4WMLMG.js → chunk-VXAGOLDP.js} +1 -1
- package/dist/chunk-YCUVAOFC.js +158 -0
- package/dist/{chunk-SS4B7P7V.js → chunk-YIDV4VV2.js} +1 -1
- package/dist/chunk-ZKWPCBYT.js +600 -0
- package/dist/cli/index.js +27 -21
- package/dist/commands/archive.js +3 -3
- package/dist/commands/backlog.js +1 -1
- package/dist/commands/benchmark.d.ts +12 -0
- package/dist/commands/benchmark.js +12 -0
- package/dist/commands/blocked.js +1 -1
- package/dist/commands/canvas.js +2 -2
- package/dist/commands/checkpoint.js +1 -1
- package/dist/commands/compat.js +1 -1
- package/dist/commands/context.js +8 -7
- package/dist/commands/doctor.d.ts +8 -3
- package/dist/commands/doctor.js +8 -22
- package/dist/commands/embed.js +6 -5
- package/dist/commands/entities.js +2 -2
- package/dist/commands/graph.js +4 -4
- package/dist/commands/inbox.d.ts +23 -0
- package/dist/commands/inbox.js +11 -0
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +5 -5
- package/dist/commands/kanban.js +1 -1
- package/dist/commands/link.js +9 -9
- package/dist/commands/maintain.d.ts +32 -0
- package/dist/commands/maintain.js +12 -0
- package/dist/commands/migrate-observations.js +3 -3
- package/dist/commands/observe.js +11 -10
- package/dist/commands/project.js +2 -2
- package/dist/commands/rebuild-embeddings.js +48 -17
- package/dist/commands/rebuild.js +9 -8
- package/dist/commands/recover.js +1 -1
- package/dist/commands/reflect.js +6 -6
- package/dist/commands/repair-session.js +1 -1
- package/dist/commands/replay.js +10 -9
- package/dist/commands/session-recap.js +1 -1
- package/dist/commands/setup.js +4 -3
- package/dist/commands/shell-init.js +1 -1
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +20 -18
- package/dist/commands/status.js +40 -26
- package/dist/commands/sync-bd.js +3 -3
- package/dist/commands/tailscale.js +3 -3
- package/dist/commands/task.js +1 -1
- package/dist/commands/template.js +1 -1
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +10 -9
- package/dist/index.d.ts +175 -16
- package/dist/index.js +277 -108
- package/dist/{inject-DYUrDqQO.d.ts → inject-DEb_jpLi.d.ts} +3 -1
- package/dist/lib/auto-linker.js +2 -2
- package/dist/lib/canvas-layout.js +1 -1
- package/dist/lib/config.js +2 -2
- package/dist/lib/entity-index.js +1 -1
- package/dist/lib/project-utils.js +2 -2
- package/dist/lib/session-repair.js +1 -1
- package/dist/lib/session-utils.js +1 -1
- package/dist/lib/tailscale.js +1 -1
- package/dist/lib/task-utils.js +1 -1
- package/dist/lib/template-engine.js +1 -1
- package/dist/lib/webdav.js +1 -1
- package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
- package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
- package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
- package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
- package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
- package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
- package/dist/openclaw-plugin.d.ts +8 -0
- package/dist/openclaw-plugin.js +14 -0
- package/dist/transformers.node-A2ZRORSQ.js +46775 -0
- package/dist/{types-BbWJoC1c.d.ts → types-DslKvCaj.d.ts} +51 -1
- package/hooks/clawvault/HOOK.md +25 -8
- package/hooks/clawvault/handler.js +215 -78
- package/hooks/clawvault/handler.test.js +109 -43
- package/hooks/clawvault/integrity.js +112 -0
- package/hooks/clawvault/integrity.test.js +32 -0
- package/hooks/clawvault/openclaw.plugin.json +133 -15
- package/openclaw.plugin.json +131 -203
- package/package.json +10 -7
- package/bin/register-workgraph-commands.js +0 -451
- package/dist/chunk-5PJ4STIC.js +0 -465
- package/dist/chunk-ERNE2FZ5.js +0 -189
- package/dist/chunk-HR4KN6S2.js +0 -152
- package/dist/chunk-IJBFGPCS.js +0 -33
- package/dist/chunk-K7PNYS45.js +0 -93
- package/dist/chunk-NTOPJI7W.js +0 -207
- package/dist/chunk-PG56HX5T.js +0 -154
- package/dist/chunk-QPDDIHXE.js +0 -501
- package/dist/chunk-WIOLLGAD.js +0 -190
- package/dist/chunk-WMGIIABP.js +0 -15
- package/dist/ledger-B7g7jhqG.d.ts +0 -44
- package/dist/plugin/index.d.ts +0 -352
- package/dist/plugin/index.js +0 -4264
- package/dist/registry-BR4326o0.d.ts +0 -30
- package/dist/store-CA-6sKCJ.d.ts +0 -34
- package/dist/thread-B9LhXNU0.d.ts +0 -41
- package/dist/workgraph/index.d.ts +0 -5
- package/dist/workgraph/index.js +0 -23
- package/dist/workgraph/ledger.d.ts +0 -2
- package/dist/workgraph/ledger.js +0 -25
- package/dist/workgraph/registry.d.ts +0 -2
- package/dist/workgraph/registry.js +0 -19
- package/dist/workgraph/store.d.ts +0 -2
- package/dist/workgraph/store.js +0 -25
- package/dist/workgraph/thread.d.ts +0 -2
- package/dist/workgraph/thread.js +0 -25
- package/dist/workgraph/types.d.ts +0 -54
- package/dist/workgraph/types.js +0 -7
|
@@ -10,10 +10,43 @@ var DEFAULT_MODELS = {
|
|
|
10
10
|
openclaw: "gpt-4o-mini"
|
|
11
11
|
};
|
|
12
12
|
var XAI_BASE_URL = "https://api.x.ai/v1";
|
|
13
|
+
var VAULT_CONFIG_FILE = ".clawvault.json";
|
|
14
|
+
var LLM_MODEL_TIERS = ["background", "default", "complex"];
|
|
15
|
+
function resolveOpenClawHome() {
|
|
16
|
+
return process.env.OPENCLAW_HOME?.trim() || path.join(os.homedir(), ".openclaw");
|
|
17
|
+
}
|
|
18
|
+
function resolveOpenClawGatewayProvider() {
|
|
19
|
+
try {
|
|
20
|
+
const configPath = path.join(resolveOpenClawHome(), "openclaw.json");
|
|
21
|
+
if (!fs.existsSync(configPath)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const raw = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
25
|
+
const enabled = raw.gateway?.http?.endpoints?.chatCompletions?.enabled === true;
|
|
26
|
+
const apiKey = raw.gateway?.auth?.token?.trim();
|
|
27
|
+
const port = raw.gateway?.port;
|
|
28
|
+
if (!enabled || !apiKey || typeof port !== "number" || !Number.isFinite(port) || port <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const defaultModel = raw.agents?.defaults?.model?.trim() || DEFAULT_MODELS.openclaw;
|
|
32
|
+
const host = raw.gateway?.bind === "loopback" ? "127.0.0.1" : "127.0.0.1";
|
|
33
|
+
return {
|
|
34
|
+
baseUrl: `http://${host}:${port}/v1`,
|
|
35
|
+
apiKey,
|
|
36
|
+
api: "openai-completions",
|
|
37
|
+
defaultModel
|
|
38
|
+
};
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
13
43
|
function resolveOpenClawProvider() {
|
|
44
|
+
const gatewayProvider = resolveOpenClawGatewayProvider();
|
|
45
|
+
if (gatewayProvider) {
|
|
46
|
+
return gatewayProvider;
|
|
47
|
+
}
|
|
14
48
|
try {
|
|
15
|
-
const
|
|
16
|
-
const modelsPath = path.join(openclawHome, "agents", "main", "agent", "models.json");
|
|
49
|
+
const modelsPath = path.join(resolveOpenClawHome(), "agents", "main", "agent", "models.json");
|
|
17
50
|
if (!fs.existsSync(modelsPath)) {
|
|
18
51
|
return null;
|
|
19
52
|
}
|
|
@@ -57,6 +90,78 @@ function resolveLlmProvider() {
|
|
|
57
90
|
}
|
|
58
91
|
return null;
|
|
59
92
|
}
|
|
93
|
+
function resolveNearestVaultPath(startPath) {
|
|
94
|
+
let current = path.resolve(startPath);
|
|
95
|
+
while (true) {
|
|
96
|
+
if (fs.existsSync(path.join(current, VAULT_CONFIG_FILE))) {
|
|
97
|
+
return current;
|
|
98
|
+
}
|
|
99
|
+
const parent = path.dirname(current);
|
|
100
|
+
if (parent === current) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
current = parent;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function resolveVaultPathForModelConfig() {
|
|
107
|
+
const configuredVaultPath = process.env.CLAWVAULT_PATH?.trim();
|
|
108
|
+
if (configuredVaultPath) {
|
|
109
|
+
return path.resolve(configuredVaultPath);
|
|
110
|
+
}
|
|
111
|
+
return resolveNearestVaultPath(process.cwd());
|
|
112
|
+
}
|
|
113
|
+
function readTieredModelConfig() {
|
|
114
|
+
const vaultPath = resolveVaultPathForModelConfig();
|
|
115
|
+
if (!vaultPath) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const configPath = path.join(vaultPath, VAULT_CONFIG_FILE);
|
|
119
|
+
if (!fs.existsSync(configPath)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
124
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const models = parsed.models;
|
|
128
|
+
if (!models || typeof models !== "object" || Array.isArray(models)) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const normalized = {};
|
|
132
|
+
for (const tier of LLM_MODEL_TIERS) {
|
|
133
|
+
const candidate = models[tier];
|
|
134
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
135
|
+
normalized[tier] = candidate.trim();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return Object.keys(normalized).length > 0 ? normalized : null;
|
|
139
|
+
} catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function resolveTieredModel(tier) {
|
|
144
|
+
const tieredConfig = readTieredModelConfig();
|
|
145
|
+
if (!tieredConfig) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
return tieredConfig[tier] ?? tieredConfig.default ?? null;
|
|
149
|
+
}
|
|
150
|
+
function resolveRequestModel(options, fallbackModel) {
|
|
151
|
+
if (typeof options.model === "string" && options.model.trim()) {
|
|
152
|
+
return options.model.trim();
|
|
153
|
+
}
|
|
154
|
+
const tier = options.tier ?? "default";
|
|
155
|
+
const configuredTierModel = resolveTieredModel(tier);
|
|
156
|
+
if (configuredTierModel) {
|
|
157
|
+
return configuredTierModel;
|
|
158
|
+
}
|
|
159
|
+
const envModel = process.env.CLAWVAULT_MODEL?.trim();
|
|
160
|
+
if (envModel) {
|
|
161
|
+
return envModel;
|
|
162
|
+
}
|
|
163
|
+
return fallbackModel;
|
|
164
|
+
}
|
|
60
165
|
async function requestLlmCompletion(options) {
|
|
61
166
|
const provider = options.provider ?? resolveLlmProvider();
|
|
62
167
|
if (!provider) {
|
|
@@ -90,7 +195,7 @@ async function callAnthropic(options, provider) {
|
|
|
90
195
|
"anthropic-version": "2023-06-01"
|
|
91
196
|
},
|
|
92
197
|
body: JSON.stringify({
|
|
93
|
-
model: options
|
|
198
|
+
model: resolveRequestModel(options, DEFAULT_MODELS[provider]),
|
|
94
199
|
temperature: options.temperature ?? 0.1,
|
|
95
200
|
max_tokens: options.maxTokens ?? 1200,
|
|
96
201
|
messages: [{ role: "user", content: options.prompt }]
|
|
@@ -120,7 +225,7 @@ async function callOpenAI(options, provider) {
|
|
|
120
225
|
authorization: `Bearer ${apiKey}`
|
|
121
226
|
},
|
|
122
227
|
body: JSON.stringify({
|
|
123
|
-
model: options
|
|
228
|
+
model: resolveRequestModel(options, DEFAULT_MODELS[provider]),
|
|
124
229
|
temperature: options.temperature ?? 0.1,
|
|
125
230
|
max_tokens: options.maxTokens ?? 1200,
|
|
126
231
|
messages
|
|
@@ -150,7 +255,7 @@ async function callXAI(options, provider) {
|
|
|
150
255
|
authorization: `Bearer ${apiKey}`
|
|
151
256
|
},
|
|
152
257
|
body: JSON.stringify({
|
|
153
|
-
model: options
|
|
258
|
+
model: resolveRequestModel(options, DEFAULT_MODELS[provider]),
|
|
154
259
|
temperature: options.temperature ?? 0.1,
|
|
155
260
|
max_tokens: options.maxTokens ?? 1200,
|
|
156
261
|
messages
|
|
@@ -168,7 +273,7 @@ async function callGemini(options, provider) {
|
|
|
168
273
|
return "";
|
|
169
274
|
}
|
|
170
275
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
171
|
-
const model = options
|
|
276
|
+
const model = resolveRequestModel(options, DEFAULT_MODELS[provider]);
|
|
172
277
|
const response = await fetchImpl(
|
|
173
278
|
`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`,
|
|
174
279
|
{
|
|
@@ -207,7 +312,7 @@ async function callOpenClaw(options) {
|
|
|
207
312
|
authorization: `Bearer ${config.apiKey}`
|
|
208
313
|
},
|
|
209
314
|
body: JSON.stringify({
|
|
210
|
-
model: options
|
|
315
|
+
model: resolveRequestModel(options, config.defaultModel),
|
|
211
316
|
temperature: options.temperature ?? 0.1,
|
|
212
317
|
max_tokens: options.maxTokens ?? 1200,
|
|
213
318
|
messages
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
DEFAULT_CATEGORIES,
|
|
3
|
+
TYPE_TO_CATEGORY
|
|
4
|
+
} from "./chunk-2CDEETQN.js";
|
|
5
|
+
import {
|
|
6
|
+
loadVaultQmdConfig,
|
|
7
|
+
recoverQmdEmbeddingIfNeeded
|
|
8
|
+
} from "./chunk-FZ5I2NF7.js";
|
|
4
9
|
import {
|
|
5
|
-
QmdUnavailableError,
|
|
6
10
|
SearchEngine,
|
|
7
11
|
extractTags,
|
|
8
12
|
extractWikiLinks,
|
|
9
13
|
hasQmd,
|
|
10
14
|
qmdEmbed,
|
|
11
15
|
qmdUpdate
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import {
|
|
14
|
-
DEFAULT_CATEGORIES,
|
|
15
|
-
TYPE_TO_CATEGORY
|
|
16
|
-
} from "./chunk-2CDEETQN.js";
|
|
16
|
+
} from "./chunk-PTWPPVC7.js";
|
|
17
17
|
import {
|
|
18
18
|
buildOrUpdateMemoryGraphIndex
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-33DOSHTA.js";
|
|
20
20
|
|
|
21
21
|
// src/lib/vault.ts
|
|
22
22
|
import * as fs from "fs";
|
|
@@ -31,17 +31,19 @@ var ClawVault = class {
|
|
|
31
31
|
search;
|
|
32
32
|
initialized = false;
|
|
33
33
|
constructor(vaultPath) {
|
|
34
|
-
if (!
|
|
35
|
-
|
|
36
|
-
console.error(error.toUserMessage());
|
|
37
|
-
throw error;
|
|
34
|
+
if (typeof vaultPath !== "string" || !vaultPath.trim()) {
|
|
35
|
+
throw new Error(`Invalid vault path: expected a non-empty string, received ${typeof vaultPath}`);
|
|
38
36
|
}
|
|
39
37
|
this.config = {
|
|
40
38
|
path: path.resolve(vaultPath),
|
|
41
39
|
name: path.basename(vaultPath),
|
|
42
40
|
categories: DEFAULT_CATEGORIES,
|
|
43
41
|
qmdCollection: void 0,
|
|
44
|
-
qmdRoot: void 0
|
|
42
|
+
qmdRoot: void 0,
|
|
43
|
+
search: {
|
|
44
|
+
backend: "in-process",
|
|
45
|
+
qmdFallback: true
|
|
46
|
+
}
|
|
45
47
|
};
|
|
46
48
|
this.search = new SearchEngine();
|
|
47
49
|
this.applyQmdConfig();
|
|
@@ -50,11 +52,6 @@ var ClawVault = class {
|
|
|
50
52
|
* Initialize a new vault
|
|
51
53
|
*/
|
|
52
54
|
async init(options = {}, initFlags) {
|
|
53
|
-
if (!hasQmd()) {
|
|
54
|
-
const error = new QmdUnavailableError("NOT_INSTALLED");
|
|
55
|
-
console.error(error.toUserMessage());
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
55
|
const vaultPath = this.config.path;
|
|
59
56
|
const flags = initFlags || {};
|
|
60
57
|
this.config = { ...this.config, ...options };
|
|
@@ -95,7 +92,8 @@ var ClawVault = class {
|
|
|
95
92
|
categories: this.config.categories,
|
|
96
93
|
documentCount: 0,
|
|
97
94
|
qmdCollection: this.getQmdCollection(),
|
|
98
|
-
qmdRoot: this.getQmdRoot()
|
|
95
|
+
qmdRoot: this.getQmdRoot(),
|
|
96
|
+
search: this.config.search ?? { backend: "in-process", qmdFallback: true }
|
|
99
97
|
};
|
|
100
98
|
fs.writeFileSync(configPath, JSON.stringify(meta, null, 2));
|
|
101
99
|
if (!flags.skipBases && this.config.categories.includes("tasks")) {
|
|
@@ -206,27 +204,41 @@ var ClawVault = class {
|
|
|
206
204
|
* Load an existing vault
|
|
207
205
|
*/
|
|
208
206
|
async load() {
|
|
209
|
-
if (!hasQmd()) {
|
|
210
|
-
const error = new QmdUnavailableError("NOT_INSTALLED");
|
|
211
|
-
console.error(error.toUserMessage());
|
|
212
|
-
throw error;
|
|
213
|
-
}
|
|
214
207
|
const vaultPath = this.config.path;
|
|
215
208
|
const configPath = path.join(vaultPath, CONFIG_FILE);
|
|
216
209
|
if (!fs.existsSync(configPath)) {
|
|
217
210
|
throw new Error(`Not a ClawVault: ${vaultPath} (missing ${CONFIG_FILE})`);
|
|
218
211
|
}
|
|
219
212
|
const meta = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
220
|
-
this.config.name = meta.name;
|
|
221
|
-
this.config.categories = meta.categories;
|
|
222
|
-
this.config.qmdCollection = meta.qmdCollection;
|
|
223
|
-
this.config.qmdRoot = meta.qmdRoot;
|
|
213
|
+
this.config.name = typeof meta.name === "string" ? meta.name : this.config.name;
|
|
214
|
+
this.config.categories = Array.isArray(meta.categories) ? meta.categories : this.config.categories;
|
|
215
|
+
this.config.qmdCollection = typeof meta.qmdCollection === "string" ? meta.qmdCollection : void 0;
|
|
216
|
+
this.config.qmdRoot = typeof meta.qmdRoot === "string" ? meta.qmdRoot : void 0;
|
|
217
|
+
this.config.search = meta.search && typeof meta.search === "object" && !Array.isArray(meta.search) ? meta.search : this.config.search;
|
|
224
218
|
if (!meta.qmdCollection || !meta.qmdRoot) {
|
|
225
219
|
meta.qmdCollection = meta.qmdCollection || meta.name;
|
|
226
220
|
meta.qmdRoot = meta.qmdRoot || this.config.path;
|
|
227
221
|
fs.writeFileSync(configPath, JSON.stringify(meta, null, 2));
|
|
228
222
|
}
|
|
229
223
|
this.applyQmdConfig(meta);
|
|
224
|
+
if (hasQmd()) {
|
|
225
|
+
try {
|
|
226
|
+
const recovery = recoverQmdEmbeddingIfNeeded({
|
|
227
|
+
vaultPath: this.config.path,
|
|
228
|
+
collection: this.getQmdCollection(),
|
|
229
|
+
rootPath: this.getQmdRoot(),
|
|
230
|
+
mode: "marker-only",
|
|
231
|
+
onLog: (message) => console.warn(`[clawvault] ${message}`)
|
|
232
|
+
});
|
|
233
|
+
if (recovery.recovered) {
|
|
234
|
+
console.warn(`[clawvault] qmd embedding recovery finished for "${this.getQmdCollection()}".`);
|
|
235
|
+
}
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.warn(
|
|
238
|
+
`[clawvault] qmd embedding recovery failed: ${err?.message || "unknown error"}`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
230
242
|
await this.reindex();
|
|
231
243
|
this.initialized = true;
|
|
232
244
|
}
|
|
@@ -322,6 +334,28 @@ var ClawVault = class {
|
|
|
322
334
|
}
|
|
323
335
|
return doc;
|
|
324
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Patch an existing document and incrementally refresh index state for that file only.
|
|
339
|
+
*/
|
|
340
|
+
async patch(options) {
|
|
341
|
+
const relativePath = this.resolveDocumentRelativePath(options.idOrPath);
|
|
342
|
+
const absolutePath = path.join(this.config.path, relativePath);
|
|
343
|
+
if (!fs.existsSync(absolutePath)) {
|
|
344
|
+
throw new Error(`Document not found: ${options.idOrPath}`);
|
|
345
|
+
}
|
|
346
|
+
const raw = fs.readFileSync(absolutePath, "utf-8");
|
|
347
|
+
const { frontmatter, body } = this.splitFrontmatter(raw);
|
|
348
|
+
const updatedBody = this.applyPatchToBody(body, options);
|
|
349
|
+
if (updatedBody === body) {
|
|
350
|
+
throw new Error("Patch made no changes to the document body.");
|
|
351
|
+
}
|
|
352
|
+
fs.writeFileSync(absolutePath, `${frontmatter}${updatedBody}`);
|
|
353
|
+
const doc = await this.reindexDocument(relativePath);
|
|
354
|
+
if (!doc) {
|
|
355
|
+
throw new Error(`Failed to reload patched document: ${options.idOrPath}`);
|
|
356
|
+
}
|
|
357
|
+
return doc;
|
|
358
|
+
}
|
|
325
359
|
/**
|
|
326
360
|
* Quick store to inbox
|
|
327
361
|
*/
|
|
@@ -334,19 +368,19 @@ var ClawVault = class {
|
|
|
334
368
|
});
|
|
335
369
|
}
|
|
336
370
|
/**
|
|
337
|
-
* Search the vault (
|
|
371
|
+
* Search the vault (in-process hybrid by default, qmd fallback optional)
|
|
338
372
|
*/
|
|
339
373
|
async find(query, options = {}) {
|
|
340
374
|
return this.search.search(query, options);
|
|
341
375
|
}
|
|
342
376
|
/**
|
|
343
|
-
* Semantic/vector search (
|
|
377
|
+
* Semantic/vector search (hosted embeddings, qmd fallback optional)
|
|
344
378
|
*/
|
|
345
379
|
async vsearch(query, options = {}) {
|
|
346
380
|
return this.search.vsearch(query, options);
|
|
347
381
|
}
|
|
348
382
|
/**
|
|
349
|
-
* Combined search
|
|
383
|
+
* Combined search entrypoint (currently aliases hybrid search)
|
|
350
384
|
*/
|
|
351
385
|
async query(query, options = {}) {
|
|
352
386
|
return this.search.query(query, options);
|
|
@@ -723,6 +757,142 @@ var ClawVault = class {
|
|
|
723
757
|
}
|
|
724
758
|
return fallback || (/* @__PURE__ */ new Date()).toISOString();
|
|
725
759
|
}
|
|
760
|
+
async reindexDocument(relativePath) {
|
|
761
|
+
const doc = await this.loadDocument(relativePath);
|
|
762
|
+
if (!doc) return null;
|
|
763
|
+
this.search.addDocument(doc);
|
|
764
|
+
await this.saveIndex();
|
|
765
|
+
await this.syncMemoryGraphIndex();
|
|
766
|
+
return doc;
|
|
767
|
+
}
|
|
768
|
+
resolveDocumentRelativePath(idOrPath) {
|
|
769
|
+
if (typeof idOrPath !== "string" || !idOrPath.trim()) {
|
|
770
|
+
throw new Error("idOrPath is required");
|
|
771
|
+
}
|
|
772
|
+
const trimmed = idOrPath.trim().replace(/^[\\/]+/, "");
|
|
773
|
+
const withExtension = trimmed.endsWith(".md") ? trimmed : `${trimmed}.md`;
|
|
774
|
+
const normalized = path.normalize(withExtension);
|
|
775
|
+
const resolved = path.resolve(this.config.path, normalized);
|
|
776
|
+
const relative2 = path.relative(this.config.path, resolved);
|
|
777
|
+
if (relative2.startsWith("..") || path.isAbsolute(relative2)) {
|
|
778
|
+
throw new Error(`Document path escapes vault: ${idOrPath}`);
|
|
779
|
+
}
|
|
780
|
+
return relative2;
|
|
781
|
+
}
|
|
782
|
+
splitFrontmatter(raw) {
|
|
783
|
+
const match = raw.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
|
|
784
|
+
if (!match) {
|
|
785
|
+
return { frontmatter: "", body: raw };
|
|
786
|
+
}
|
|
787
|
+
const frontmatter = match[0];
|
|
788
|
+
return {
|
|
789
|
+
frontmatter,
|
|
790
|
+
body: raw.slice(frontmatter.length)
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
applyPatchToBody(body, options) {
|
|
794
|
+
if (options.mode === "append") {
|
|
795
|
+
if (typeof options.append !== "string" || options.append.length === 0) {
|
|
796
|
+
throw new Error("Append mode requires non-empty append text.");
|
|
797
|
+
}
|
|
798
|
+
if (options.section) {
|
|
799
|
+
return this.patchMarkdownSection(
|
|
800
|
+
body,
|
|
801
|
+
options.section,
|
|
802
|
+
(sectionBody) => this.appendText(sectionBody, options.append)
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
return this.appendText(body, options.append);
|
|
806
|
+
}
|
|
807
|
+
if (options.mode === "replace") {
|
|
808
|
+
if (typeof options.replace !== "string" || options.replace.length === 0) {
|
|
809
|
+
throw new Error("Replace mode requires non-empty --replace text.");
|
|
810
|
+
}
|
|
811
|
+
if (typeof options.with !== "string") {
|
|
812
|
+
throw new Error("Replace mode requires --with text.");
|
|
813
|
+
}
|
|
814
|
+
if (options.section) {
|
|
815
|
+
return this.patchMarkdownSection(
|
|
816
|
+
body,
|
|
817
|
+
options.section,
|
|
818
|
+
(sectionBody) => this.replaceAllOccurrences(sectionBody, options.replace, options.with, `section "${options.section}"`)
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
return this.replaceAllOccurrences(body, options.replace, options.with, "document");
|
|
822
|
+
}
|
|
823
|
+
if (options.mode === "content") {
|
|
824
|
+
if (typeof options.content !== "string") {
|
|
825
|
+
throw new Error("Content mode requires --content text.");
|
|
826
|
+
}
|
|
827
|
+
if (options.section) {
|
|
828
|
+
return this.patchMarkdownSection(body, options.section, () => options.content);
|
|
829
|
+
}
|
|
830
|
+
return options.content;
|
|
831
|
+
}
|
|
832
|
+
throw new Error(`Unsupported patch mode: ${String(options.mode)}`);
|
|
833
|
+
}
|
|
834
|
+
appendText(existing, addition) {
|
|
835
|
+
if (addition.length === 0) return existing;
|
|
836
|
+
if (existing.length === 0) return addition;
|
|
837
|
+
return existing.endsWith("\n") ? `${existing}${addition}` : `${existing}
|
|
838
|
+
${addition}`;
|
|
839
|
+
}
|
|
840
|
+
replaceAllOccurrences(input, searchText, replacement, scopeLabel) {
|
|
841
|
+
if (!input.includes(searchText)) {
|
|
842
|
+
throw new Error(`No matches found for "${searchText}" in ${scopeLabel}.`);
|
|
843
|
+
}
|
|
844
|
+
return input.split(searchText).join(replacement);
|
|
845
|
+
}
|
|
846
|
+
patchMarkdownSection(markdown, sectionName, applySectionPatch) {
|
|
847
|
+
const lines = markdown.split(/\r?\n/);
|
|
848
|
+
const normalize2 = (value) => value.replace(/^#+\s*/, "").trim().toLowerCase();
|
|
849
|
+
const targetName = normalize2(sectionName);
|
|
850
|
+
let sectionStart = -1;
|
|
851
|
+
let sectionLevel = 0;
|
|
852
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
853
|
+
const line = lines[i];
|
|
854
|
+
const match = line.match(/^(#{1,6})\s+(.*?)\s*$/);
|
|
855
|
+
if (!match) continue;
|
|
856
|
+
const [, marks, heading] = match;
|
|
857
|
+
if (normalize2(heading) === targetName) {
|
|
858
|
+
sectionStart = i;
|
|
859
|
+
sectionLevel = marks.length;
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (sectionStart < 0) {
|
|
864
|
+
throw new Error(`Section not found: ${sectionName}`);
|
|
865
|
+
}
|
|
866
|
+
let sectionEnd = lines.length;
|
|
867
|
+
for (let i = sectionStart + 1; i < lines.length; i += 1) {
|
|
868
|
+
const match = lines[i].match(/^(#{1,6})\s+(.*?)\s*$/);
|
|
869
|
+
if (!match) continue;
|
|
870
|
+
if (match[1].length <= sectionLevel) {
|
|
871
|
+
sectionEnd = i;
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
const existingSectionBody = lines.slice(sectionStart + 1, sectionEnd).join("\n");
|
|
876
|
+
const updatedSectionBody = applySectionPatch(existingSectionBody);
|
|
877
|
+
const rebuiltSection = updatedSectionBody.length > 0 ? `${lines[sectionStart]}
|
|
878
|
+
${updatedSectionBody}` : lines[sectionStart];
|
|
879
|
+
const head = lines.slice(0, sectionStart).join("\n");
|
|
880
|
+
const tail = lines.slice(sectionEnd).join("\n");
|
|
881
|
+
if (head.length > 0 && tail.length > 0) {
|
|
882
|
+
return `${head}
|
|
883
|
+
${rebuiltSection}
|
|
884
|
+
${tail}`;
|
|
885
|
+
}
|
|
886
|
+
if (head.length > 0) {
|
|
887
|
+
return `${head}
|
|
888
|
+
${rebuiltSection}`;
|
|
889
|
+
}
|
|
890
|
+
if (tail.length > 0) {
|
|
891
|
+
return `${rebuiltSection}
|
|
892
|
+
${tail}`;
|
|
893
|
+
}
|
|
894
|
+
return rebuiltSection;
|
|
895
|
+
}
|
|
726
896
|
/**
|
|
727
897
|
* Extract the date portion (YYYY-MM-DD) from an ISO date string or Date object.
|
|
728
898
|
* Provides safe handling for various date formats.
|
|
@@ -739,15 +909,17 @@ var ClawVault = class {
|
|
|
739
909
|
const explicitRoot = meta?.qmdRoot || this.config.qmdRoot || this.config.path;
|
|
740
910
|
const qmdConfig = loadVaultQmdConfig(this.config.path);
|
|
741
911
|
const collection = explicitCollection || qmdConfig.qmdCollection || this.config.name;
|
|
742
|
-
const root = explicitRoot || qmdConfig.qmdRoot;
|
|
912
|
+
const root = (typeof explicitRoot === "string" ? explicitRoot : void 0) || qmdConfig.qmdRoot || this.config.path;
|
|
743
913
|
if (qmdConfig.autoDetected) {
|
|
744
914
|
console.warn(`[clawvault] Auto-detected qmd collection: ${collection}`);
|
|
745
915
|
}
|
|
746
916
|
this.config.qmdCollection = collection;
|
|
747
917
|
this.config.qmdRoot = root;
|
|
918
|
+
this.config.search = meta?.search && typeof meta.search === "object" && !Array.isArray(meta.search) ? meta.search : this.config.search ?? { backend: "in-process", qmdFallback: true };
|
|
748
919
|
this.search.setVaultPath(this.config.path);
|
|
749
920
|
this.search.setCollection(collection);
|
|
750
921
|
this.search.setCollectionRoot(root);
|
|
922
|
+
this.search.setSearchConfig(this.config.search);
|
|
751
923
|
}
|
|
752
924
|
slugify(text) {
|
|
753
925
|
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
hasQmd,
|
|
3
|
-
withQmdIndexArgs
|
|
4
|
-
} from "./chunk-5PJ4STIC.js";
|
|
5
1
|
import {
|
|
6
2
|
DEFAULT_CATEGORIES
|
|
7
3
|
} from "./chunk-2CDEETQN.js";
|
|
4
|
+
import {
|
|
5
|
+
hasQmd,
|
|
6
|
+
withQmdIndexArgs
|
|
7
|
+
} from "./chunk-PTWPPVC7.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/setup.ts
|
|
10
10
|
import * as fs from "fs";
|
|
@@ -339,14 +339,15 @@ async function setupCommand(options = {}) {
|
|
|
339
339
|
const { collection, root } = getQmdConfig(target.vaultPath);
|
|
340
340
|
try {
|
|
341
341
|
execFileSync("qmd", withQmdIndexArgs(["collection", "add", root, "--name", collection, "--mask", "**/*.md"], options.qmdIndexName), {
|
|
342
|
-
stdio: "ignore"
|
|
342
|
+
stdio: "ignore",
|
|
343
|
+
shell: process.platform === "win32"
|
|
343
344
|
});
|
|
344
345
|
console.log(`\u2713 qmd collection ready: ${collection}`);
|
|
345
346
|
} catch {
|
|
346
347
|
console.log("\u2298 qmd collection already exists.");
|
|
347
348
|
}
|
|
348
349
|
} else {
|
|
349
|
-
console.log("\u2298 qmd not found \u2014 skipping
|
|
350
|
+
console.log("\u2298 qmd not found \u2014 skipping optional qmd fallback setup.");
|
|
350
351
|
}
|
|
351
352
|
console.log("\nTip: add this to your shell config:");
|
|
352
353
|
console.log(` export CLAWVAULT_PATH="${target.vaultPath}"`);
|