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.
Files changed (125) hide show
  1. package/README.md +352 -20
  2. package/bin/clawvault.js +8 -2
  3. package/bin/command-runtime.js +9 -1
  4. package/bin/register-maintenance-commands.js +19 -0
  5. package/bin/register-query-commands.js +58 -6
  6. package/bin/register-workgraph-commands.js +451 -0
  7. package/dist/{chunk-VXEOHTSL.js → chunk-2JQ3O2YL.js} +1 -1
  8. package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
  9. package/dist/chunk-2ZDO52B4.js +52 -0
  10. package/dist/chunk-4BQTQMJP.js +93 -0
  11. package/dist/{chunk-MAKNAHAW.js → chunk-5PJ4STIC.js} +98 -8
  12. package/dist/{chunk-IEVLHNLU.js → chunk-627Q3QWK.js} +3 -3
  13. package/dist/{chunk-R6SXNSFD.js → chunk-6NYYDNNG.js} +3 -3
  14. package/dist/chunk-ECRZL5XR.js +50 -0
  15. package/dist/chunk-GNJL4YGR.js +79 -0
  16. package/dist/{chunk-OZ7RIXTO.js → chunk-IIOU45CK.js} +1 -1
  17. package/dist/chunk-L4HSSQ6T.js +152 -0
  18. package/dist/{chunk-XAVB4GB4.js → chunk-LIGHWOH6.js} +1 -1
  19. package/dist/{chunk-PBEE567J.js → chunk-LUBZXECN.js} +2 -2
  20. package/dist/{chunk-UEOUADMO.js → chunk-MFL6EEPF.js} +204 -35
  21. package/dist/chunk-MM6QGW3P.js +207 -0
  22. package/dist/{chunk-T76H47ZS.js → chunk-MNPUYCHQ.js} +1 -1
  23. package/dist/{chunk-TLGBDTYT.js → chunk-MPOSMDMU.js} +6 -6
  24. package/dist/{chunk-RVYA52PY.js → chunk-NJYJL5AA.js} +1 -1
  25. package/dist/{chunk-Q2J5YTUF.js → chunk-OQGYFZ4A.js} +669 -33
  26. package/dist/{chunk-ME37YNW3.js → chunk-P7SY3D4E.js} +3 -3
  27. package/dist/chunk-RHISK3SZ.js +189 -0
  28. package/dist/{chunk-3BTHWPMB.js → chunk-S5OJEGFG.js} +2 -2
  29. package/dist/{chunk-MGDEINGP.js → chunk-SS4B7P7V.js} +1 -1
  30. package/dist/chunk-U4O6C46S.js +154 -0
  31. package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
  32. package/dist/chunk-WIOLLGAD.js +190 -0
  33. package/dist/chunk-WMGIIABP.js +15 -0
  34. package/dist/{chunk-QVMXF7FY.js → chunk-X3SPPUFG.js} +50 -0
  35. package/dist/{chunk-THRJVD4L.js → chunk-Y6VJKXGL.js} +1 -1
  36. package/dist/{chunk-KL4NAOMO.js → chunk-YDWHS4LJ.js} +49 -9
  37. package/dist/{chunk-4VRIMU4O.js → chunk-YNIPYN4F.js} +4 -4
  38. package/dist/{chunk-HIHOUSXS.js → chunk-YXQCA6B7.js} +105 -1
  39. package/dist/cli/index.js +18 -16
  40. package/dist/commands/archive.js +3 -2
  41. package/dist/commands/backlog.js +1 -0
  42. package/dist/commands/blocked.js +1 -0
  43. package/dist/commands/canvas.js +1 -0
  44. package/dist/commands/checkpoint.js +1 -0
  45. package/dist/commands/compat.js +2 -1
  46. package/dist/commands/context.js +5 -3
  47. package/dist/commands/doctor.d.ts +10 -1
  48. package/dist/commands/doctor.js +11 -8
  49. package/dist/commands/embed.js +5 -3
  50. package/dist/commands/entities.js +2 -1
  51. package/dist/commands/graph.js +3 -2
  52. package/dist/commands/inject.d.ts +1 -1
  53. package/dist/commands/inject.js +4 -3
  54. package/dist/commands/kanban.js +1 -0
  55. package/dist/commands/link.js +2 -1
  56. package/dist/commands/migrate-observations.js +3 -2
  57. package/dist/commands/observe.js +8 -6
  58. package/dist/commands/project.js +1 -0
  59. package/dist/commands/rebuild-embeddings.d.ts +21 -0
  60. package/dist/commands/rebuild-embeddings.js +91 -0
  61. package/dist/commands/rebuild.js +6 -4
  62. package/dist/commands/recover.js +1 -0
  63. package/dist/commands/reflect.js +5 -4
  64. package/dist/commands/repair-session.js +1 -0
  65. package/dist/commands/replay.js +7 -6
  66. package/dist/commands/session-recap.js +1 -0
  67. package/dist/commands/setup.js +3 -2
  68. package/dist/commands/shell-init.js +2 -0
  69. package/dist/commands/sleep.d.ts +1 -1
  70. package/dist/commands/sleep.js +8 -6
  71. package/dist/commands/status.d.ts +2 -0
  72. package/dist/commands/status.js +35 -24
  73. package/dist/commands/sync-bd.js +3 -2
  74. package/dist/commands/tailscale.js +3 -2
  75. package/dist/commands/task.js +1 -0
  76. package/dist/commands/template.js +1 -0
  77. package/dist/commands/wake.d.ts +1 -1
  78. package/dist/commands/wake.js +4 -2
  79. package/dist/index.d.ts +333 -10
  80. package/dist/index.js +320 -33
  81. package/dist/{inject-x65KXWPk.d.ts → inject-DYUrDqQO.d.ts} +2 -2
  82. package/dist/ledger-B7g7jhqG.d.ts +44 -0
  83. package/dist/lib/auto-linker.js +1 -0
  84. package/dist/lib/canvas-layout.js +1 -0
  85. package/dist/lib/config.d.ts +27 -3
  86. package/dist/lib/config.js +4 -1
  87. package/dist/lib/entity-index.js +1 -0
  88. package/dist/lib/project-utils.js +1 -0
  89. package/dist/lib/session-repair.js +1 -0
  90. package/dist/lib/session-utils.js +1 -0
  91. package/dist/lib/tailscale.js +1 -0
  92. package/dist/lib/task-utils.js +1 -0
  93. package/dist/lib/template-engine.js +1 -0
  94. package/dist/lib/webdav.js +1 -0
  95. package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
  96. package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
  97. package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
  98. package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
  99. package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
  100. package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
  101. package/dist/registry-BR4326o0.d.ts +30 -0
  102. package/dist/store-CA-6sKCJ.d.ts +34 -0
  103. package/dist/thread-B9LhXNU0.d.ts +41 -0
  104. package/dist/transformers.node-A2ZRORSQ.js +46775 -0
  105. package/dist/{types-C74wgGL1.d.ts → types-BbWJoC1c.d.ts} +1 -1
  106. package/dist/workgraph/index.d.ts +5 -0
  107. package/dist/workgraph/index.js +23 -0
  108. package/dist/workgraph/ledger.d.ts +2 -0
  109. package/dist/workgraph/ledger.js +25 -0
  110. package/dist/workgraph/registry.d.ts +2 -0
  111. package/dist/workgraph/registry.js +19 -0
  112. package/dist/workgraph/store.d.ts +2 -0
  113. package/dist/workgraph/store.js +25 -0
  114. package/dist/workgraph/thread.d.ts +2 -0
  115. package/dist/workgraph/thread.js +25 -0
  116. package/dist/workgraph/types.d.ts +54 -0
  117. package/dist/workgraph/types.js +7 -0
  118. package/hooks/clawvault/HOOK.md +34 -4
  119. package/hooks/clawvault/handler.js +751 -8
  120. package/hooks/clawvault/handler.test.js +247 -0
  121. package/hooks/clawvault/openclaw.plugin.json +72 -0
  122. package/openclaw.plugin.json +84 -0
  123. package/package.json +8 -4
  124. package/dist/chunk-4QYGFWRM.js +0 -88
  125. 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
- constructor(message = QMD_NOT_INSTALLED_MESSAGE) {
11
- super(message);
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 message = err?.message ? `qmd failed: ${err.message}` : "qmd failed";
109
- throw new Error(message);
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 = "clawvault";
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,9 +1,9 @@
1
+ import {
2
+ Observer
3
+ } from "./chunk-OQGYFZ4A.js";
1
4
  import {
2
5
  getSessionsDir
3
6
  } from "./chunk-HRLWZGMA.js";
4
- import {
5
- Observer
6
- } from "./chunk-Q2J5YTUF.js";
7
7
 
8
8
  // src/observer/active-session-observer.ts
9
9
  import * as fs from "fs";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  runReflection
3
- } from "./chunk-T76H47ZS.js";
3
+ } from "./chunk-MNPUYCHQ.js";
4
4
  import {
5
5
  Observer
6
- } from "./chunk-Q2J5YTUF.js";
6
+ } from "./chunk-OQGYFZ4A.js";
7
7
  import {
8
8
  resolveVaultPath
9
- } from "./chunk-MXSSG3QU.js";
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
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveVaultPath
3
- } from "./chunk-MXSSG3QU.js";
3
+ } from "./chunk-GNJL4YGR.js";
4
4
  import {
5
5
  buildOrUpdateMemoryGraphIndex,
6
6
  loadMemoryGraphIndex
@@ -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
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ClawVault
3
- } from "./chunk-KL4NAOMO.js";
3
+ } from "./chunk-YDWHS4LJ.js";
4
4
  import {
5
5
  parseObservationMarkdown
6
6
  } from "./chunk-FHFUXL6G.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  Observer
3
- } from "./chunk-Q2J5YTUF.js";
3
+ } from "./chunk-OQGYFZ4A.js";
4
4
  import {
5
5
  resolveVaultPath
6
- } from "./chunk-MXSSG3QU.js";
6
+ } from "./chunk-GNJL4YGR.js";
7
7
  import {
8
8
  getLegacyObservationPath,
9
9
  getObservationPath,