clawvault 3.2.1 → 3.4.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 +15 -2
- package/bin/help-contract.test.js +16 -0
- package/bin/register-core-commands.js +88 -0
- package/bin/register-core-commands.test.js +80 -0
- package/bin/register-maintenance-commands.js +84 -7
- package/bin/register-query-commands.js +45 -28
- package/bin/register-query-commands.test.js +15 -0
- 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-35JCYSRR.js +158 -0
- 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-D5U3Q4N5.js +872 -0
- package/dist/chunk-DCF4KMFD.js +158 -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-NSXYM6EZ.js +255 -0
- 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-QYQAGBTM.js +2097 -0
- package/dist/chunk-RL2L6I6K.js +223 -0
- package/dist/{chunk-IIOU45CK.js → chunk-S7N7HI5E.js} +2 -2
- package/dist/{chunk-ECRZL5XR.js → chunk-T7E764W3.js} +23 -7
- 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-SS4B7P7V.js → chunk-YIDV4VV2.js} +1 -1
- package/dist/chunk-YTRZNA64.js +37 -0
- package/dist/chunk-ZKWPCBYT.js +600 -0
- package/dist/cli/index.js +28 -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.d.ts +8 -1
- package/dist/commands/entities.js +46 -3
- 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 +5 -5
- package/dist/commands/maintain.d.ts +32 -0
- package/dist/commands/maintain.js +13 -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/recall.d.ts +14 -0
- package/dist/commands/recall.js +15 -0
- 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 +233 -16
- package/dist/index.js +325 -111
- 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--gqA2BZw.d.ts +267 -0
- package/dist/openclaw-plugin.d.ts +4 -0
- package/dist/openclaw-plugin.js +20 -0
- package/dist/transformers.node-A2ZRORSQ.js +46775 -0
- package/dist/types-CbL-wIKi.d.ts +36 -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 +161 -194
- package/package.json +8 -5
- 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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerTailscaleCommands
|
|
3
|
+
} from "./chunk-KCYWJDDW.js";
|
|
4
|
+
import {
|
|
5
|
+
registerReflectCommand
|
|
6
|
+
} from "./chunk-DOIUYIXV.js";
|
|
7
|
+
import {
|
|
8
|
+
registerInjectCommand
|
|
9
|
+
} from "./chunk-OFOCU2V4.js";
|
|
10
|
+
import {
|
|
11
|
+
registerMaintainCommand
|
|
12
|
+
} from "./chunk-D5U3Q4N5.js";
|
|
13
|
+
import {
|
|
14
|
+
registerObserveCommand
|
|
15
|
+
} from "./chunk-BLQXXX7Q.js";
|
|
16
|
+
import {
|
|
17
|
+
registerContextCommand
|
|
18
|
+
} from "./chunk-GFCHWMGD.js";
|
|
19
|
+
import {
|
|
20
|
+
registerEmbedCommand
|
|
21
|
+
} from "./chunk-T7E764W3.js";
|
|
22
|
+
import {
|
|
23
|
+
registerInboxCommand
|
|
24
|
+
} from "./chunk-HEHO7SMV.js";
|
|
25
|
+
import {
|
|
26
|
+
ClawVault
|
|
27
|
+
} from "./chunk-ECGJYWNA.js";
|
|
28
|
+
import {
|
|
29
|
+
resolveVaultPath
|
|
30
|
+
} from "./chunk-GJO3CFUN.js";
|
|
31
|
+
import {
|
|
32
|
+
registerBenchmarkCommand
|
|
33
|
+
} from "./chunk-ZKWPCBYT.js";
|
|
34
|
+
|
|
35
|
+
// src/commands/patch.ts
|
|
36
|
+
function normalizeSectionHeading(heading) {
|
|
37
|
+
const trimmed = heading.trim();
|
|
38
|
+
if (!trimmed) {
|
|
39
|
+
throw new Error("Section heading cannot be empty.");
|
|
40
|
+
}
|
|
41
|
+
if (trimmed.startsWith("#")) {
|
|
42
|
+
return trimmed;
|
|
43
|
+
}
|
|
44
|
+
return `## ${trimmed}`;
|
|
45
|
+
}
|
|
46
|
+
function buildSectionAppendText(heading, content) {
|
|
47
|
+
const headingLine = normalizeSectionHeading(heading);
|
|
48
|
+
return `
|
|
49
|
+
${headingLine}
|
|
50
|
+
${content}`;
|
|
51
|
+
}
|
|
52
|
+
function isSectionNotFoundError(error) {
|
|
53
|
+
return error instanceof Error && error.message.startsWith("Section not found:");
|
|
54
|
+
}
|
|
55
|
+
function resolvePatchOptions(idOrPath, options) {
|
|
56
|
+
const appendSelected = typeof options.append === "string";
|
|
57
|
+
const replaceSelected = typeof options.replace === "string" || typeof options.with === "string";
|
|
58
|
+
const sectionSelected = typeof options.section === "string" || typeof options.content === "string";
|
|
59
|
+
const selectedModeCount = [appendSelected, replaceSelected, sectionSelected].filter(Boolean).length;
|
|
60
|
+
if (selectedModeCount !== 1) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"Select exactly one patch mode: --append, --replace with --with, or --section with --content."
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (appendSelected) {
|
|
66
|
+
return {
|
|
67
|
+
idOrPath,
|
|
68
|
+
mode: "append",
|
|
69
|
+
append: options.append
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (replaceSelected) {
|
|
73
|
+
if (typeof options.replace !== "string" || typeof options.with !== "string") {
|
|
74
|
+
throw new Error("Replace mode requires both --replace and --with.");
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
idOrPath,
|
|
78
|
+
mode: "replace",
|
|
79
|
+
replace: options.replace,
|
|
80
|
+
with: options.with
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (typeof options.section !== "string" || typeof options.content !== "string") {
|
|
84
|
+
throw new Error("Section mode requires both --section and --content.");
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
idOrPath,
|
|
88
|
+
mode: "content",
|
|
89
|
+
section: options.section,
|
|
90
|
+
content: options.content
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function runSectionUpsert(vault, idOrPath, section, content) {
|
|
94
|
+
try {
|
|
95
|
+
return await vault.patch({
|
|
96
|
+
idOrPath,
|
|
97
|
+
mode: "content",
|
|
98
|
+
section,
|
|
99
|
+
content
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (!isSectionNotFoundError(error)) {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
return vault.patch({
|
|
106
|
+
idOrPath,
|
|
107
|
+
mode: "append",
|
|
108
|
+
append: buildSectionAppendText(section, content)
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function patchCommand(idOrPath, options) {
|
|
113
|
+
const patchOptions = resolvePatchOptions(idOrPath, options);
|
|
114
|
+
const vaultPath = resolveVaultPath({ explicitPath: options.vaultPath });
|
|
115
|
+
const vault = new ClawVault(vaultPath);
|
|
116
|
+
await vault.load();
|
|
117
|
+
if (patchOptions.mode === "content") {
|
|
118
|
+
return runSectionUpsert(
|
|
119
|
+
vault,
|
|
120
|
+
patchOptions.idOrPath,
|
|
121
|
+
patchOptions.section,
|
|
122
|
+
patchOptions.content
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return vault.patch(patchOptions);
|
|
126
|
+
}
|
|
127
|
+
function registerPatchCommand(program) {
|
|
128
|
+
program.command("patch <path>").description("Patch an existing memory document").option("--append <content>", "Append text to the end of a document").option("--replace <old>", "Text to find for replacement").option("--with <new>", "Replacement text used with --replace").option("--section <heading>", "Markdown heading to upsert").option("--content <body>", "Section body content used with --section").option("-v, --vault <path>", "Vault path").action(async (pathArg, rawOptions) => {
|
|
129
|
+
const doc = await patchCommand(pathArg, {
|
|
130
|
+
vaultPath: rawOptions.vault,
|
|
131
|
+
append: rawOptions.append,
|
|
132
|
+
replace: rawOptions.replace,
|
|
133
|
+
with: rawOptions.with,
|
|
134
|
+
section: rawOptions.section,
|
|
135
|
+
content: rawOptions.content
|
|
136
|
+
});
|
|
137
|
+
console.log(`Patched: ${doc.id}`);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/cli/index.ts
|
|
142
|
+
function registerCliCommands(program) {
|
|
143
|
+
registerBenchmarkCommand(program);
|
|
144
|
+
registerContextCommand(program);
|
|
145
|
+
registerInjectCommand(program);
|
|
146
|
+
registerObserveCommand(program);
|
|
147
|
+
registerReflectCommand(program);
|
|
148
|
+
registerEmbedCommand(program);
|
|
149
|
+
registerInboxCommand(program);
|
|
150
|
+
registerMaintainCommand(program);
|
|
151
|
+
registerPatchCommand(program);
|
|
152
|
+
registerTailscaleCommands(program);
|
|
153
|
+
return program;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
registerCliCommands
|
|
158
|
+
};
|
|
@@ -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();
|