clawvault 2.6.1 → 2.6.4
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 +352 -20
- package/bin/clawvault.js +8 -2
- package/bin/command-runtime.js +9 -1
- package/bin/register-maintenance-commands.js +19 -0
- package/bin/register-query-commands.js +58 -6
- package/bin/register-workgraph-commands.js +451 -0
- package/dist/{chunk-VXEOHTSL.js → chunk-2JQ3O2YL.js} +1 -1
- package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
- package/dist/chunk-2ZDO52B4.js +52 -0
- package/dist/chunk-4BQTQMJP.js +93 -0
- package/dist/{chunk-MAKNAHAW.js → chunk-5PJ4STIC.js} +98 -8
- package/dist/{chunk-IEVLHNLU.js → chunk-627Q3QWK.js} +3 -3
- package/dist/{chunk-R6SXNSFD.js → chunk-6NYYDNNG.js} +3 -3
- package/dist/chunk-ECRZL5XR.js +50 -0
- package/dist/chunk-GNJL4YGR.js +79 -0
- package/dist/{chunk-OZ7RIXTO.js → chunk-IIOU45CK.js} +1 -1
- package/dist/chunk-L4HSSQ6T.js +152 -0
- package/dist/{chunk-XAVB4GB4.js → chunk-LIGHWOH6.js} +1 -1
- package/dist/{chunk-PBEE567J.js → chunk-LUBZXECN.js} +2 -2
- package/dist/{chunk-UEOUADMO.js → chunk-MFL6EEPF.js} +204 -35
- package/dist/chunk-MM6QGW3P.js +207 -0
- package/dist/{chunk-T76H47ZS.js → chunk-MNPUYCHQ.js} +1 -1
- package/dist/{chunk-TLGBDTYT.js → chunk-MPOSMDMU.js} +6 -6
- package/dist/{chunk-RVYA52PY.js → chunk-NJYJL5AA.js} +1 -1
- package/dist/{chunk-Q2J5YTUF.js → chunk-OQGYFZ4A.js} +669 -33
- package/dist/{chunk-ME37YNW3.js → chunk-P7SY3D4E.js} +3 -3
- package/dist/chunk-RHISK3SZ.js +189 -0
- package/dist/{chunk-3BTHWPMB.js → chunk-S5OJEGFG.js} +2 -2
- package/dist/{chunk-MGDEINGP.js → chunk-SS4B7P7V.js} +1 -1
- package/dist/chunk-U4O6C46S.js +154 -0
- package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
- package/dist/chunk-WIOLLGAD.js +190 -0
- package/dist/chunk-WMGIIABP.js +15 -0
- package/dist/{chunk-QVMXF7FY.js → chunk-X3SPPUFG.js} +50 -0
- package/dist/{chunk-THRJVD4L.js → chunk-Y6VJKXGL.js} +1 -1
- package/dist/{chunk-KL4NAOMO.js → chunk-YDWHS4LJ.js} +49 -9
- package/dist/{chunk-4VRIMU4O.js → chunk-YNIPYN4F.js} +4 -4
- package/dist/{chunk-HIHOUSXS.js → chunk-YXQCA6B7.js} +105 -1
- package/dist/cli/index.js +18 -16
- package/dist/commands/archive.js +3 -2
- package/dist/commands/backlog.js +1 -0
- package/dist/commands/blocked.js +1 -0
- package/dist/commands/canvas.js +1 -0
- package/dist/commands/checkpoint.js +1 -0
- package/dist/commands/compat.js +2 -1
- package/dist/commands/context.js +5 -3
- package/dist/commands/doctor.d.ts +10 -1
- package/dist/commands/doctor.js +11 -8
- package/dist/commands/embed.js +5 -3
- package/dist/commands/entities.js +2 -1
- package/dist/commands/graph.js +3 -2
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +4 -3
- package/dist/commands/kanban.js +1 -0
- package/dist/commands/link.js +2 -1
- package/dist/commands/migrate-observations.js +3 -2
- package/dist/commands/observe.js +8 -6
- package/dist/commands/project.js +1 -0
- package/dist/commands/rebuild-embeddings.d.ts +21 -0
- package/dist/commands/rebuild-embeddings.js +91 -0
- package/dist/commands/rebuild.js +6 -4
- package/dist/commands/recover.js +1 -0
- package/dist/commands/reflect.js +5 -4
- package/dist/commands/repair-session.js +1 -0
- package/dist/commands/replay.js +7 -6
- package/dist/commands/session-recap.js +1 -0
- package/dist/commands/setup.js +3 -2
- package/dist/commands/shell-init.js +2 -0
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +8 -6
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +35 -24
- package/dist/commands/sync-bd.js +3 -2
- package/dist/commands/tailscale.js +3 -2
- package/dist/commands/task.js +1 -0
- package/dist/commands/template.js +1 -0
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +4 -2
- package/dist/index.d.ts +333 -10
- package/dist/index.js +320 -33
- package/dist/{inject-x65KXWPk.d.ts → inject-DYUrDqQO.d.ts} +2 -2
- package/dist/ledger-B7g7jhqG.d.ts +44 -0
- package/dist/lib/auto-linker.js +1 -0
- package/dist/lib/canvas-layout.js +1 -0
- package/dist/lib/config.d.ts +27 -3
- package/dist/lib/config.js +4 -1
- package/dist/lib/entity-index.js +1 -0
- package/dist/lib/project-utils.js +1 -0
- package/dist/lib/session-repair.js +1 -0
- package/dist/lib/session-utils.js +1 -0
- package/dist/lib/tailscale.js +1 -0
- package/dist/lib/task-utils.js +1 -0
- package/dist/lib/template-engine.js +1 -0
- package/dist/lib/webdav.js +1 -0
- 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/registry-BR4326o0.d.ts +30 -0
- package/dist/store-CA-6sKCJ.d.ts +34 -0
- package/dist/thread-B9LhXNU0.d.ts +41 -0
- package/dist/transformers.node-A2ZRORSQ.js +46775 -0
- package/dist/{types-C74wgGL1.d.ts → types-BbWJoC1c.d.ts} +1 -1
- package/dist/workgraph/index.d.ts +5 -0
- package/dist/workgraph/index.js +23 -0
- package/dist/workgraph/ledger.d.ts +2 -0
- package/dist/workgraph/ledger.js +25 -0
- package/dist/workgraph/registry.d.ts +2 -0
- package/dist/workgraph/registry.js +19 -0
- package/dist/workgraph/store.d.ts +2 -0
- package/dist/workgraph/store.js +25 -0
- package/dist/workgraph/thread.d.ts +2 -0
- package/dist/workgraph/thread.js +25 -0
- package/dist/workgraph/types.d.ts +54 -0
- package/dist/workgraph/types.js +7 -0
- package/hooks/clawvault/HOOK.md +34 -4
- package/hooks/clawvault/handler.js +751 -8
- package/hooks/clawvault/handler.test.js +247 -0
- package/hooks/clawvault/openclaw.plugin.json +72 -0
- package/openclaw.plugin.json +84 -0
- package/package.json +8 -4
- package/dist/chunk-4QYGFWRM.js +0 -88
- package/dist/chunk-MXSSG3QU.js +0 -42
|
@@ -4,12 +4,57 @@ import * as fs from "fs";
|
|
|
4
4
|
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
|
-
var QMD_NOT_INSTALLED_MESSAGE = `ClawVault requires qmd. Install: ${QMD_INSTALL_COMMAND}`;
|
|
8
7
|
var QMD_INDEX_ENV_VAR = "CLAWVAULT_QMD_INDEX";
|
|
8
|
+
var QMD_ERROR_MESSAGES = {
|
|
9
|
+
NOT_INSTALLED: {
|
|
10
|
+
code: "NOT_INSTALLED",
|
|
11
|
+
message: "qmd is not installed",
|
|
12
|
+
hint: `Install qmd to enable ClawVault search and indexing:
|
|
13
|
+
${QMD_INSTALL_COMMAND}
|
|
14
|
+
|
|
15
|
+
For more information: ${QMD_INSTALL_URL}`
|
|
16
|
+
},
|
|
17
|
+
NOT_CONFIGURED: {
|
|
18
|
+
code: "NOT_CONFIGURED",
|
|
19
|
+
message: "qmd collection is not configured",
|
|
20
|
+
hint: "Run `clawvault doctor` to diagnose configuration issues, or `clawvault migrate` to fix common setup problems."
|
|
21
|
+
},
|
|
22
|
+
COLLECTION_NOT_FOUND: {
|
|
23
|
+
code: "COLLECTION_NOT_FOUND",
|
|
24
|
+
message: "qmd collection not found",
|
|
25
|
+
hint: "The configured qmd collection does not exist. Run `clawvault migrate` to recreate it, or `qmd collection add <name> <path>` manually."
|
|
26
|
+
},
|
|
27
|
+
EXECUTION_FAILED: {
|
|
28
|
+
code: "EXECUTION_FAILED",
|
|
29
|
+
message: "qmd command failed",
|
|
30
|
+
hint: "Run `clawvault doctor` to diagnose qmd issues."
|
|
31
|
+
}
|
|
32
|
+
};
|
|
9
33
|
var QmdUnavailableError = class extends Error {
|
|
10
|
-
|
|
11
|
-
|
|
34
|
+
code;
|
|
35
|
+
hint;
|
|
36
|
+
constructor(code = "NOT_INSTALLED", additionalContext) {
|
|
37
|
+
const details = QMD_ERROR_MESSAGES[code];
|
|
38
|
+
const fullMessage = additionalContext ? `${details.message}: ${additionalContext}` : details.message;
|
|
39
|
+
super(fullMessage);
|
|
12
40
|
this.name = "QmdUnavailableError";
|
|
41
|
+
this.code = code;
|
|
42
|
+
this.hint = details.hint;
|
|
43
|
+
}
|
|
44
|
+
toUserMessage() {
|
|
45
|
+
return `Error: ${this.message}
|
|
46
|
+
|
|
47
|
+
${this.hint}`;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function getQmdErrorDetails(code) {
|
|
51
|
+
return QMD_ERROR_MESSAGES[code];
|
|
52
|
+
}
|
|
53
|
+
var QmdConfigurationError = class extends Error {
|
|
54
|
+
constructor(message, hint) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.hint = hint;
|
|
57
|
+
this.name = "QmdConfigurationError";
|
|
13
58
|
}
|
|
14
59
|
};
|
|
15
60
|
function ensureJsonArgs(args) {
|
|
@@ -80,9 +125,39 @@ function parseQmdOutput(raw) {
|
|
|
80
125
|
}
|
|
81
126
|
function ensureQmdAvailable() {
|
|
82
127
|
if (!hasQmd()) {
|
|
83
|
-
throw new QmdUnavailableError();
|
|
128
|
+
throw new QmdUnavailableError("NOT_INSTALLED");
|
|
84
129
|
}
|
|
85
130
|
}
|
|
131
|
+
function detectQmdError(output, args) {
|
|
132
|
+
const lowerOutput = output.toLowerCase();
|
|
133
|
+
if (lowerOutput.includes("missing required arguments") || lowerOutput.includes("unknown option")) {
|
|
134
|
+
return new QmdConfigurationError(
|
|
135
|
+
'qmd does not support the search command with the expected arguments. This may indicate an incompatible qmd version or a different tool named "qmd".',
|
|
136
|
+
`Ensure you have the correct qmd installed: ${QMD_INSTALL_COMMAND}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (lowerOutput.includes("collection not found") || lowerOutput.includes("no collection")) {
|
|
140
|
+
const collectionArg = args.findIndex((a) => a === "-c");
|
|
141
|
+
const collectionName = collectionArg >= 0 && args[collectionArg + 1] ? args[collectionArg + 1] : "unknown";
|
|
142
|
+
return new QmdConfigurationError(
|
|
143
|
+
`qmd collection "${collectionName}" not found.`,
|
|
144
|
+
'Run `qmd update -c <collection>` to create the collection, or check your vault\'s .clawvault.json "name" field.'
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (lowerOutput.includes("no index") || lowerOutput.includes("index not found")) {
|
|
148
|
+
return new QmdConfigurationError(
|
|
149
|
+
"qmd index not found. The vault may not be indexed yet.",
|
|
150
|
+
"Run `clawvault rebuild` or `qmd update` to build the search index."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (lowerOutput.includes("embedding") && (lowerOutput.includes("not found") || lowerOutput.includes("missing"))) {
|
|
154
|
+
return new QmdConfigurationError(
|
|
155
|
+
"qmd embeddings not found. Vector search requires embeddings to be generated.",
|
|
156
|
+
"Run `clawvault embed` or `qmd embed` to generate embeddings for semantic search."
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
86
161
|
function execQmd(args, indexName) {
|
|
87
162
|
ensureQmdAvailable();
|
|
88
163
|
const finalArgs = withQmdIndexArgs(ensureJsonArgs(args), indexName);
|
|
@@ -96,17 +171,24 @@ function execQmd(args, indexName) {
|
|
|
96
171
|
return parseQmdOutput(result);
|
|
97
172
|
} catch (err) {
|
|
98
173
|
if (err?.code === "ENOENT") {
|
|
99
|
-
throw new QmdUnavailableError();
|
|
174
|
+
throw new QmdUnavailableError("NOT_INSTALLED");
|
|
100
175
|
}
|
|
101
176
|
const output = [err?.stdout, err?.stderr].filter(Boolean).join("\n");
|
|
177
|
+
const detectedError = detectQmdError(output, finalArgs);
|
|
178
|
+
if (detectedError) {
|
|
179
|
+
throw detectedError;
|
|
180
|
+
}
|
|
102
181
|
if (output) {
|
|
103
182
|
try {
|
|
104
183
|
return parseQmdOutput(output);
|
|
105
184
|
} catch {
|
|
106
185
|
}
|
|
186
|
+
if (output.includes("collection not found") || output.includes("no such collection")) {
|
|
187
|
+
throw new QmdUnavailableError("COLLECTION_NOT_FOUND", output.trim());
|
|
188
|
+
}
|
|
107
189
|
}
|
|
108
|
-
const
|
|
109
|
-
throw new
|
|
190
|
+
const errorDetail = err?.message || "unknown error";
|
|
191
|
+
throw new QmdUnavailableError("EXECUTION_FAILED", errorDetail);
|
|
110
192
|
}
|
|
111
193
|
}
|
|
112
194
|
function hasQmd() {
|
|
@@ -131,7 +213,7 @@ function qmdEmbed(collection, indexName) {
|
|
|
131
213
|
}
|
|
132
214
|
var SearchEngine = class {
|
|
133
215
|
documents = /* @__PURE__ */ new Map();
|
|
134
|
-
collection = "
|
|
216
|
+
collection = "";
|
|
135
217
|
vaultPath = "";
|
|
136
218
|
collectionRoot = "";
|
|
137
219
|
qmdIndexName;
|
|
@@ -141,6 +223,12 @@ var SearchEngine = class {
|
|
|
141
223
|
setCollection(name) {
|
|
142
224
|
this.collection = name;
|
|
143
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Get the current collection name
|
|
228
|
+
*/
|
|
229
|
+
getCollection() {
|
|
230
|
+
return this.collection;
|
|
231
|
+
}
|
|
144
232
|
/**
|
|
145
233
|
* Set the vault path for file resolution
|
|
146
234
|
*/
|
|
@@ -365,6 +453,8 @@ export {
|
|
|
365
453
|
QMD_INSTALL_URL,
|
|
366
454
|
QMD_INSTALL_COMMAND,
|
|
367
455
|
QmdUnavailableError,
|
|
456
|
+
getQmdErrorDetails,
|
|
457
|
+
QmdConfigurationError,
|
|
368
458
|
withQmdIndexArgs,
|
|
369
459
|
hasQmd,
|
|
370
460
|
qmdUpdate,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runReflection
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MNPUYCHQ.js";
|
|
4
4
|
import {
|
|
5
5
|
Observer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OQGYFZ4A.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveVaultPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GNJL4YGR.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/replay.ts
|
|
12
12
|
import * as fs from "fs";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadVaultQmdConfig
|
|
3
|
+
} from "./chunk-WIOLLGAD.js";
|
|
4
|
+
import {
|
|
5
|
+
QmdUnavailableError,
|
|
6
|
+
hasQmd,
|
|
7
|
+
qmdEmbed
|
|
8
|
+
} from "./chunk-5PJ4STIC.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveVaultPath
|
|
11
|
+
} from "./chunk-GNJL4YGR.js";
|
|
12
|
+
|
|
13
|
+
// src/commands/embed.ts
|
|
14
|
+
async function embedCommand(options = {}) {
|
|
15
|
+
if (!hasQmd()) {
|
|
16
|
+
throw new QmdUnavailableError();
|
|
17
|
+
}
|
|
18
|
+
const vaultPath = resolveVaultPath({ explicitPath: options.vaultPath });
|
|
19
|
+
const qmdConfig = loadVaultQmdConfig(vaultPath);
|
|
20
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21
|
+
if (!options.quiet) {
|
|
22
|
+
console.log(
|
|
23
|
+
`Embedding pending documents for collection "${qmdConfig.qmdCollection}" (root: ${qmdConfig.qmdRoot})...`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
qmdEmbed(qmdConfig.qmdCollection);
|
|
27
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28
|
+
if (!options.quiet) {
|
|
29
|
+
console.log(`\u2713 Embedding complete for "${qmdConfig.qmdCollection}"`);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
vaultPath,
|
|
33
|
+
qmdCollection: qmdConfig.qmdCollection,
|
|
34
|
+
qmdRoot: qmdConfig.qmdRoot,
|
|
35
|
+
startedAt,
|
|
36
|
+
finishedAt
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function registerEmbedCommand(program) {
|
|
40
|
+
program.command("embed").description("Run qmd embedding for pending vault documents").option("-v, --vault <path>", "Vault path").action(async (rawOptions) => {
|
|
41
|
+
await embedCommand({
|
|
42
|
+
vaultPath: rawOptions.vault
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
embedCommand,
|
|
49
|
+
registerEmbedCommand
|
|
50
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/lib/config.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
function getVaultPath() {
|
|
5
|
+
const vaultPath = process.env.CLAWVAULT_PATH;
|
|
6
|
+
if (!vaultPath) {
|
|
7
|
+
throw new Error("CLAWVAULT_PATH environment variable not set");
|
|
8
|
+
}
|
|
9
|
+
return path.resolve(vaultPath);
|
|
10
|
+
}
|
|
11
|
+
function findNearestVaultPath(startPath = process.cwd()) {
|
|
12
|
+
let current = path.resolve(startPath);
|
|
13
|
+
while (true) {
|
|
14
|
+
if (fs.existsSync(path.join(current, ".clawvault.json"))) {
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
const parent = path.dirname(current);
|
|
18
|
+
if (parent === current) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
current = parent;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function validateVaultPath(vaultPath) {
|
|
25
|
+
if (!vaultPath || typeof vaultPath !== "string") return null;
|
|
26
|
+
const resolved = path.resolve(vaultPath);
|
|
27
|
+
if (!path.isAbsolute(resolved)) return null;
|
|
28
|
+
try {
|
|
29
|
+
const stat = fs.statSync(resolved);
|
|
30
|
+
if (!stat.isDirectory()) return null;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const configPath = path.join(resolved, ".clawvault.json");
|
|
35
|
+
if (!fs.existsSync(configPath)) return null;
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
38
|
+
function resolveAgentVaultPath(agentVaults, agentId) {
|
|
39
|
+
if (!agentId || typeof agentId !== "string") return null;
|
|
40
|
+
if (!agentVaults || typeof agentVaults !== "object" || Array.isArray(agentVaults)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const agentPath = agentVaults[agentId];
|
|
44
|
+
if (!agentPath || typeof agentPath !== "string") return null;
|
|
45
|
+
return validateVaultPath(agentPath);
|
|
46
|
+
}
|
|
47
|
+
function resolveVaultPath(options = {}) {
|
|
48
|
+
if (options.explicitPath) {
|
|
49
|
+
return path.resolve(options.explicitPath);
|
|
50
|
+
}
|
|
51
|
+
if (options.agentId && options.pluginConfig?.agentVaults) {
|
|
52
|
+
const agentVaultPath = resolveAgentVaultPath(
|
|
53
|
+
options.pluginConfig.agentVaults,
|
|
54
|
+
options.agentId
|
|
55
|
+
);
|
|
56
|
+
if (agentVaultPath) {
|
|
57
|
+
return agentVaultPath;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (options.pluginConfig?.vaultPath) {
|
|
61
|
+
const validated = validateVaultPath(options.pluginConfig.vaultPath);
|
|
62
|
+
if (validated) return validated;
|
|
63
|
+
}
|
|
64
|
+
if (process.env.CLAWVAULT_PATH) {
|
|
65
|
+
return path.resolve(process.env.CLAWVAULT_PATH);
|
|
66
|
+
}
|
|
67
|
+
const discovered = findNearestVaultPath(options.cwd ?? process.cwd());
|
|
68
|
+
if (discovered) {
|
|
69
|
+
return discovered;
|
|
70
|
+
}
|
|
71
|
+
throw new Error("No vault path found. Set CLAWVAULT_PATH, use --vault, or run inside a vault.");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
getVaultPath,
|
|
76
|
+
findNearestVaultPath,
|
|
77
|
+
resolveAgentVaultPath,
|
|
78
|
+
resolveVaultPath
|
|
79
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getType,
|
|
3
|
+
loadRegistry
|
|
4
|
+
} from "./chunk-MM6QGW3P.js";
|
|
5
|
+
import {
|
|
6
|
+
append
|
|
7
|
+
} from "./chunk-4BQTQMJP.js";
|
|
8
|
+
import {
|
|
9
|
+
__export
|
|
10
|
+
} from "./chunk-2ZDO52B4.js";
|
|
11
|
+
|
|
12
|
+
// src/workgraph/store.ts
|
|
13
|
+
var store_exports = {};
|
|
14
|
+
__export(store_exports, {
|
|
15
|
+
activeThreads: () => activeThreads,
|
|
16
|
+
blockedThreads: () => blockedThreads,
|
|
17
|
+
create: () => create,
|
|
18
|
+
findByField: () => findByField,
|
|
19
|
+
list: () => list,
|
|
20
|
+
openThreads: () => openThreads,
|
|
21
|
+
read: () => read,
|
|
22
|
+
remove: () => remove,
|
|
23
|
+
update: () => update
|
|
24
|
+
});
|
|
25
|
+
import fs from "fs";
|
|
26
|
+
import path from "path";
|
|
27
|
+
import matter from "gray-matter";
|
|
28
|
+
function create(vaultPath, typeName, fields, body, actor) {
|
|
29
|
+
const typeDef = getType(vaultPath, typeName);
|
|
30
|
+
if (!typeDef) {
|
|
31
|
+
throw new Error(`Unknown primitive type "${typeName}". Run \`clawvault primitive list\` to see available types, or \`clawvault primitive define\` to create one.`);
|
|
32
|
+
}
|
|
33
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34
|
+
const merged = applyDefaults(typeDef, {
|
|
35
|
+
...fields,
|
|
36
|
+
created: fields.created ?? now,
|
|
37
|
+
updated: now
|
|
38
|
+
});
|
|
39
|
+
const slug = slugify(String(merged.title ?? merged.name ?? typeName));
|
|
40
|
+
const relDir = typeDef.directory;
|
|
41
|
+
const relPath = `${relDir}/${slug}.md`;
|
|
42
|
+
const absDir = path.join(vaultPath, relDir);
|
|
43
|
+
const absPath = path.join(vaultPath, relPath);
|
|
44
|
+
if (!fs.existsSync(absDir)) fs.mkdirSync(absDir, { recursive: true });
|
|
45
|
+
if (fs.existsSync(absPath)) {
|
|
46
|
+
throw new Error(`File already exists: ${relPath}. Use update instead.`);
|
|
47
|
+
}
|
|
48
|
+
const content = matter.stringify(body, stripUndefined(merged));
|
|
49
|
+
fs.writeFileSync(absPath, content, "utf-8");
|
|
50
|
+
append(vaultPath, actor, "create", relPath, typeName, {
|
|
51
|
+
title: merged.title ?? slug
|
|
52
|
+
});
|
|
53
|
+
return { path: relPath, type: typeName, fields: merged, body };
|
|
54
|
+
}
|
|
55
|
+
function read(vaultPath, relPath) {
|
|
56
|
+
const absPath = path.join(vaultPath, relPath);
|
|
57
|
+
if (!fs.existsSync(absPath)) return null;
|
|
58
|
+
const raw = fs.readFileSync(absPath, "utf-8");
|
|
59
|
+
const { data, content } = matter(raw);
|
|
60
|
+
const typeName = inferType(vaultPath, relPath);
|
|
61
|
+
return { path: relPath, type: typeName, fields: data, body: content.trim() };
|
|
62
|
+
}
|
|
63
|
+
function list(vaultPath, typeName) {
|
|
64
|
+
const typeDef = getType(vaultPath, typeName);
|
|
65
|
+
if (!typeDef) return [];
|
|
66
|
+
const dir = path.join(vaultPath, typeDef.directory);
|
|
67
|
+
if (!fs.existsSync(dir)) return [];
|
|
68
|
+
const files = fs.readdirSync(dir).filter((f) => f.endsWith(".md"));
|
|
69
|
+
const instances = [];
|
|
70
|
+
for (const file of files) {
|
|
71
|
+
const relPath = `${typeDef.directory}/${file}`;
|
|
72
|
+
const inst = read(vaultPath, relPath);
|
|
73
|
+
if (inst) instances.push(inst);
|
|
74
|
+
}
|
|
75
|
+
return instances;
|
|
76
|
+
}
|
|
77
|
+
function update(vaultPath, relPath, fieldUpdates, bodyUpdate, actor) {
|
|
78
|
+
const existing = read(vaultPath, relPath);
|
|
79
|
+
if (!existing) throw new Error(`Not found: ${relPath}`);
|
|
80
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
81
|
+
const newFields = { ...existing.fields, ...fieldUpdates, updated: now };
|
|
82
|
+
const newBody = bodyUpdate ?? existing.body;
|
|
83
|
+
const absPath = path.join(vaultPath, relPath);
|
|
84
|
+
const content = matter.stringify(newBody, stripUndefined(newFields));
|
|
85
|
+
fs.writeFileSync(absPath, content, "utf-8");
|
|
86
|
+
append(vaultPath, actor, "update", relPath, existing.type, {
|
|
87
|
+
changed: Object.keys(fieldUpdates)
|
|
88
|
+
});
|
|
89
|
+
return { path: relPath, type: existing.type, fields: newFields, body: newBody };
|
|
90
|
+
}
|
|
91
|
+
function remove(vaultPath, relPath, actor) {
|
|
92
|
+
const absPath = path.join(vaultPath, relPath);
|
|
93
|
+
if (!fs.existsSync(absPath)) throw new Error(`Not found: ${relPath}`);
|
|
94
|
+
const archiveDir = path.join(vaultPath, ".clawvault", "archive");
|
|
95
|
+
if (!fs.existsSync(archiveDir)) fs.mkdirSync(archiveDir, { recursive: true });
|
|
96
|
+
const archivePath = path.join(archiveDir, path.basename(relPath));
|
|
97
|
+
fs.renameSync(absPath, archivePath);
|
|
98
|
+
const typeName = inferType(vaultPath, relPath);
|
|
99
|
+
append(vaultPath, actor, "delete", relPath, typeName);
|
|
100
|
+
}
|
|
101
|
+
function findByField(vaultPath, typeName, field, value) {
|
|
102
|
+
return list(vaultPath, typeName).filter((inst) => inst.fields[field] === value);
|
|
103
|
+
}
|
|
104
|
+
function openThreads(vaultPath) {
|
|
105
|
+
return findByField(vaultPath, "thread", "status", "open");
|
|
106
|
+
}
|
|
107
|
+
function activeThreads(vaultPath) {
|
|
108
|
+
return findByField(vaultPath, "thread", "status", "active");
|
|
109
|
+
}
|
|
110
|
+
function blockedThreads(vaultPath) {
|
|
111
|
+
return findByField(vaultPath, "thread", "status", "blocked");
|
|
112
|
+
}
|
|
113
|
+
function slugify(text) {
|
|
114
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
|
|
115
|
+
}
|
|
116
|
+
function applyDefaults(typeDef, fields) {
|
|
117
|
+
const result = { ...fields };
|
|
118
|
+
for (const [key, def] of Object.entries(typeDef.fields)) {
|
|
119
|
+
if (result[key] === void 0 && def.default !== void 0) {
|
|
120
|
+
result[key] = def.default;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
function stripUndefined(obj) {
|
|
126
|
+
const result = {};
|
|
127
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
128
|
+
if (v !== void 0) result[k] = v;
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
function inferType(vaultPath, relPath) {
|
|
133
|
+
const registry = loadRegistry(vaultPath);
|
|
134
|
+
const dir = relPath.split("/")[0];
|
|
135
|
+
for (const typeDef of Object.values(registry.types)) {
|
|
136
|
+
if (typeDef.directory === dir) return typeDef.name;
|
|
137
|
+
}
|
|
138
|
+
return "unknown";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
create,
|
|
143
|
+
read,
|
|
144
|
+
list,
|
|
145
|
+
update,
|
|
146
|
+
remove,
|
|
147
|
+
findByField,
|
|
148
|
+
openThreads,
|
|
149
|
+
activeThreads,
|
|
150
|
+
blockedThreads,
|
|
151
|
+
store_exports
|
|
152
|
+
};
|