clawvault 2.6.3 → 2.6.5

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 (127) hide show
  1. package/README.md +351 -21
  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-2GKPENIR.js +66 -0
  8. package/dist/{chunk-VXEOHTSL.js → chunk-2JQ3O2YL.js} +1 -1
  9. package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
  10. package/dist/chunk-2ZDO52B4.js +52 -0
  11. package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
  12. package/dist/chunk-4BQTQMJP.js +93 -0
  13. package/dist/{chunk-MAKNAHAW.js → chunk-5PJ4STIC.js} +98 -8
  14. package/dist/{chunk-RVYA52PY.js → chunk-5UM4PMMM.js} +1 -1
  15. package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
  16. package/dist/{chunk-4VRIMU4O.js → chunk-A4EAUO7T.js} +5 -5
  17. package/dist/{chunk-R6SXNSFD.js → chunk-BV5KWZKR.js} +3 -3
  18. package/dist/chunk-FBITHIZF.js +351 -0
  19. package/dist/{chunk-Q2J5YTUF.js → chunk-FUSLEY6L.js} +751 -34
  20. package/dist/chunk-GNJL4YGR.js +79 -0
  21. package/dist/{chunk-42MXU7A6.js → chunk-K4GFGKFD.js} +51 -47
  22. package/dist/{chunk-PBEE567J.js → chunk-KSZROBFH.js} +2 -2
  23. package/dist/chunk-L4HSSQ6T.js +152 -0
  24. package/dist/{chunk-PZ2AUU2W.js → chunk-LMKQ7NIF.js} +206 -37
  25. package/dist/{chunk-6546Q4OR.js → chunk-M5O6FQ66.js} +6 -6
  26. package/dist/chunk-MM6QGW3P.js +207 -0
  27. package/dist/{chunk-T76H47ZS.js → chunk-MNPUYCHQ.js} +1 -1
  28. package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
  29. package/dist/{chunk-OZ7RIXTO.js → chunk-QSRRMEYM.js} +2 -2
  30. package/dist/chunk-RHISK3SZ.js +189 -0
  31. package/dist/{chunk-3BTHWPMB.js → chunk-S5OJEGFG.js} +2 -2
  32. package/dist/{chunk-MGDEINGP.js → chunk-SS4B7P7V.js} +1 -1
  33. package/dist/{chunk-ME37YNW3.js → chunk-SV7T4HRE.js} +4 -4
  34. package/dist/{chunk-IEVLHNLU.js → chunk-T3FKSZSN.js} +3 -3
  35. package/dist/{chunk-DTEHFAL7.js → chunk-TS6NDVOU.js} +2 -2
  36. package/dist/chunk-U4O6C46S.js +154 -0
  37. package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
  38. package/dist/chunk-WMGIIABP.js +15 -0
  39. package/dist/{chunk-QVMXF7FY.js → chunk-X3SPPUFG.js} +50 -0
  40. package/dist/{chunk-THRJVD4L.js → chunk-Y6VJKXGL.js} +1 -1
  41. package/dist/{chunk-RCBMXTWS.js → chunk-YD7SVXTF.js} +39 -7
  42. package/dist/{chunk-HIHOUSXS.js → chunk-YXQCA6B7.js} +105 -1
  43. package/dist/cli/index.js +20 -18
  44. package/dist/commands/archive.js +3 -2
  45. package/dist/commands/backlog.js +1 -0
  46. package/dist/commands/blocked.js +1 -0
  47. package/dist/commands/canvas.js +2 -1
  48. package/dist/commands/checkpoint.js +1 -0
  49. package/dist/commands/compat.js +2 -1
  50. package/dist/commands/context.js +6 -4
  51. package/dist/commands/doctor.d.ts +10 -1
  52. package/dist/commands/doctor.js +13 -10
  53. package/dist/commands/embed.js +5 -3
  54. package/dist/commands/entities.js +2 -1
  55. package/dist/commands/graph.js +4 -3
  56. package/dist/commands/inject.d.ts +1 -1
  57. package/dist/commands/inject.js +5 -4
  58. package/dist/commands/kanban.js +1 -0
  59. package/dist/commands/link.js +5 -4
  60. package/dist/commands/migrate-observations.js +3 -2
  61. package/dist/commands/observe.js +9 -7
  62. package/dist/commands/project.js +1 -0
  63. package/dist/commands/rebuild-embeddings.d.ts +21 -0
  64. package/dist/commands/rebuild-embeddings.js +91 -0
  65. package/dist/commands/rebuild.js +6 -4
  66. package/dist/commands/recover.js +1 -0
  67. package/dist/commands/reflect.js +5 -4
  68. package/dist/commands/repair-session.js +1 -0
  69. package/dist/commands/replay.js +7 -6
  70. package/dist/commands/session-recap.js +1 -0
  71. package/dist/commands/setup.js +3 -2
  72. package/dist/commands/shell-init.js +2 -0
  73. package/dist/commands/sleep.d.ts +1 -1
  74. package/dist/commands/sleep.js +10 -8
  75. package/dist/commands/status.js +13 -82
  76. package/dist/commands/sync-bd.js +3 -2
  77. package/dist/commands/tailscale.js +3 -2
  78. package/dist/commands/task.js +1 -0
  79. package/dist/commands/template.js +1 -0
  80. package/dist/commands/wake.d.ts +1 -1
  81. package/dist/commands/wake.js +5 -3
  82. package/dist/index.d.ts +254 -10
  83. package/dist/index.js +288 -155
  84. package/dist/{inject-x65KXWPk.d.ts → inject-DYUrDqQO.d.ts} +2 -2
  85. package/dist/ledger-B7g7jhqG.d.ts +44 -0
  86. package/dist/lib/auto-linker.js +2 -1
  87. package/dist/lib/canvas-layout.js +1 -0
  88. package/dist/lib/config.d.ts +27 -3
  89. package/dist/lib/config.js +4 -1
  90. package/dist/lib/entity-index.js +1 -0
  91. package/dist/lib/project-utils.js +1 -0
  92. package/dist/lib/session-repair.js +1 -0
  93. package/dist/lib/session-utils.js +1 -0
  94. package/dist/lib/tailscale.js +1 -0
  95. package/dist/lib/task-utils.js +1 -0
  96. package/dist/lib/template-engine.js +1 -0
  97. package/dist/lib/webdav.js +1 -0
  98. package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
  99. package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
  100. package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
  101. package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
  102. package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
  103. package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
  104. package/dist/registry-BR4326o0.d.ts +30 -0
  105. package/dist/store-CA-6sKCJ.d.ts +34 -0
  106. package/dist/thread-B9LhXNU0.d.ts +41 -0
  107. package/dist/transformers.node-A2ZRORSQ.js +46775 -0
  108. package/dist/{types-C74wgGL1.d.ts → types-BbWJoC1c.d.ts} +1 -1
  109. package/dist/workgraph/index.d.ts +5 -0
  110. package/dist/workgraph/index.js +23 -0
  111. package/dist/workgraph/ledger.d.ts +2 -0
  112. package/dist/workgraph/ledger.js +25 -0
  113. package/dist/workgraph/registry.d.ts +2 -0
  114. package/dist/workgraph/registry.js +19 -0
  115. package/dist/workgraph/store.d.ts +2 -0
  116. package/dist/workgraph/store.js +25 -0
  117. package/dist/workgraph/thread.d.ts +2 -0
  118. package/dist/workgraph/thread.js +25 -0
  119. package/dist/workgraph/types.d.ts +54 -0
  120. package/dist/workgraph/types.js +7 -0
  121. package/hooks/clawvault/handler.js +714 -2
  122. package/hooks/clawvault/handler.test.js +153 -0
  123. package/hooks/clawvault/openclaw.plugin.json +72 -0
  124. package/openclaw.plugin.json +14 -2
  125. package/package.json +5 -4
  126. package/dist/chunk-4QYGFWRM.js +0 -88
  127. package/dist/chunk-MXSSG3QU.js +0 -42
@@ -4,12 +4,100 @@ import * as path from "path";
4
4
  var JSONL_SAMPLE_LIMIT = 20;
5
5
  var MARKDOWN_SIGNAL_RE = /^(#{1,6}\s|[-*+]\s|>\s)/;
6
6
  var MARKDOWN_INLINE_RE = /(\[[^\]]+\]\([^)]+\)|[*_`~])/;
7
+ var BASE64_DATA_URI_RE = /\bdata:[^;\s]+;base64,[A-Za-z0-9+/=]{24,}\b/gi;
8
+ var LONG_BASE64_TOKEN_RE = /\b[A-Za-z0-9+/]{80,}={0,2}\b/g;
9
+ var STRUCTURED_NOISE_MARKER_RE = /\b(?:tool[_-]?result|tool[_-]?use|toolcallid|tooluseid|function[_-]?(?:call|result)|stdout|stderr|exitcode|recordedat|trace(?:_|-)?id|parent(?:_|-)?id|session(?:_|-)?id|metadata|base64|mime(?:type)?)\b/i;
10
+ var NOISY_PREFIX_RE = /^(?:metadata|system metadata|session metadata)\s*:/i;
11
+ function normalizeToken(value) {
12
+ return value.trim().toLowerCase().replace(/[\s_-]+/g, "");
13
+ }
7
14
  function normalizeText(value) {
8
15
  return value.replace(/\s+/g, " ").trim();
9
16
  }
17
+ function shouldDropRole(role) {
18
+ const normalized = normalizeToken(role);
19
+ if (!normalized) {
20
+ return false;
21
+ }
22
+ if (normalized === "system" || normalized === "developer" || normalized === "metadata") {
23
+ return true;
24
+ }
25
+ return normalized.startsWith("tool");
26
+ }
27
+ function isConversationRolePrefix(role) {
28
+ const normalized = normalizeToken(role);
29
+ if (!normalized) {
30
+ return false;
31
+ }
32
+ if (normalized === "user" || normalized === "assistant" || normalized === "system") {
33
+ return true;
34
+ }
35
+ if (normalized === "developer" || normalized === "metadata") {
36
+ return true;
37
+ }
38
+ return normalized.startsWith("tool");
39
+ }
40
+ function isNoisyBlockType(value) {
41
+ if (typeof value !== "string") {
42
+ return false;
43
+ }
44
+ const normalized = normalizeToken(value);
45
+ if (!normalized || normalized === "text" || normalized === "markdown") {
46
+ return false;
47
+ }
48
+ return normalized.includes("tool") || normalized.includes("functioncall") || normalized.includes("functionresult") || normalized.includes("thinking") || normalized.includes("reason") || normalized.includes("metadata");
49
+ }
50
+ function stripNoisyData(value) {
51
+ return normalizeText(
52
+ value.replace(BASE64_DATA_URI_RE, " ").replace(LONG_BASE64_TOKEN_RE, " ")
53
+ );
54
+ }
55
+ function isLikelyStructuredNoise(value) {
56
+ const trimmed = value.trim();
57
+ if (!trimmed) {
58
+ return true;
59
+ }
60
+ if (NOISY_PREFIX_RE.test(trimmed)) {
61
+ return true;
62
+ }
63
+ const looksStructured = trimmed.startsWith("{") || trimmed.startsWith("[");
64
+ if (looksStructured && STRUCTURED_NOISE_MARKER_RE.test(trimmed) && trimmed.length >= 40) {
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+ function sanitizeExtractedText(value) {
70
+ const stripped = stripNoisyData(value);
71
+ if (!stripped) {
72
+ return "";
73
+ }
74
+ if (isLikelyStructuredNoise(stripped)) {
75
+ return "";
76
+ }
77
+ return stripped;
78
+ }
79
+ function sanitizeParsedMessage(message) {
80
+ const normalized = normalizeText(message);
81
+ if (!normalized) {
82
+ return "";
83
+ }
84
+ const roleMatch = /^([a-z][a-z0-9_-]{1,31})\s*:\s*(.+)$/i.exec(normalized);
85
+ if (roleMatch && isConversationRolePrefix(roleMatch[1])) {
86
+ const role = normalizeRole(roleMatch[1]);
87
+ if (shouldDropRole(role)) {
88
+ return "";
89
+ }
90
+ const content = sanitizeExtractedText(roleMatch[2]);
91
+ if (!content) {
92
+ return "";
93
+ }
94
+ return role ? `${role}: ${content}` : content;
95
+ }
96
+ return sanitizeExtractedText(normalized);
97
+ }
10
98
  function extractText(value) {
11
99
  if (typeof value === "string") {
12
- return normalizeText(value);
100
+ return sanitizeExtractedText(value);
13
101
  }
14
102
  if (Array.isArray(value)) {
15
103
  const parts = [];
@@ -25,11 +113,17 @@ function extractText(value) {
25
113
  return "";
26
114
  }
27
115
  const record = value;
116
+ if (isNoisyBlockType(record.type)) {
117
+ return "";
118
+ }
28
119
  if (typeof record.text === "string") {
29
- return normalizeText(record.text);
120
+ return sanitizeExtractedText(record.text);
30
121
  }
31
122
  if (typeof record.content === "string") {
32
- return normalizeText(record.content);
123
+ return sanitizeExtractedText(record.content);
124
+ }
125
+ if (record.content !== void 0) {
126
+ return extractText(record.content);
33
127
  }
34
128
  return "";
35
129
  }
@@ -69,16 +163,18 @@ function parseJsonLine(line) {
69
163
  const entry = parsed;
70
164
  if ("role" in entry && "content" in entry) {
71
165
  const role = normalizeRole(entry.role);
166
+ if (shouldDropRole(role)) return "";
72
167
  const content = extractText(entry.content);
73
168
  if (!content) return "";
74
- return role ? `${role}: ${content}` : content;
169
+ return sanitizeParsedMessage(role ? `${role}: ${content}` : content);
75
170
  }
76
171
  if (entry.type === "message" && entry.message && typeof entry.message === "object") {
77
172
  const message = entry.message;
78
173
  const role = normalizeRole(message.role);
174
+ if (shouldDropRole(role)) return "";
79
175
  const content = extractText(message.content);
80
176
  if (!content) return "";
81
- return role ? `${role}: ${content}` : content;
177
+ return sanitizeParsedMessage(role ? `${role}: ${content}` : content);
82
178
  }
83
179
  return "";
84
180
  }
@@ -119,17 +215,21 @@ function parseMarkdown(raw) {
119
215
  if (roleMatch) {
120
216
  const role = normalizeRole(roleMatch[1]);
121
217
  const content = normalizeText(roleMatch[2]);
122
- if (content) {
123
- messages.push(`${role}: ${content}`);
218
+ const parsed2 = sanitizeParsedMessage(`${role}: ${content}`);
219
+ if (parsed2) {
220
+ messages.push(parsed2);
124
221
  }
125
222
  continue;
126
223
  }
127
- messages.push(joined);
224
+ const parsed = sanitizeParsedMessage(joined);
225
+ if (parsed) {
226
+ messages.push(parsed);
227
+ }
128
228
  }
129
229
  return messages;
130
230
  }
131
231
  function parsePlainText(raw) {
132
- return raw.split(/\r?\n/).map((line) => normalizeText(line)).filter(Boolean);
232
+ return raw.split(/\r?\n/).map((line) => sanitizeParsedMessage(line)).filter(Boolean);
133
233
  }
134
234
  function detectSessionFormat(raw, filePath) {
135
235
  const nonEmptyLines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
@@ -163,10 +263,7 @@ function parseSessionFile(filePath) {
163
263
  const raw = fs.readFileSync(resolved, "utf-8");
164
264
  const format = detectSessionFormat(raw, resolved);
165
265
  if (format === "jsonl") {
166
- const parsed = parseJsonLines(raw);
167
- if (parsed.length > 0) {
168
- return parsed;
169
- }
266
+ return parseJsonLines(raw);
170
267
  }
171
268
  if (format === "markdown") {
172
269
  const parsed = parseMarkdown(raw);
@@ -1,10 +1,10 @@
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
7
- } from "./chunk-ZZA73MFY.js";
7
+ } from "./chunk-33DOSHTA.js";
8
8
 
9
9
  // src/commands/graph.ts
10
10
  function formatGraphSummary(summary) {
@@ -0,0 +1,189 @@
1
+ import {
2
+ create,
3
+ read,
4
+ update
5
+ } from "./chunk-L4HSSQ6T.js";
6
+ import {
7
+ THREAD_STATUS_TRANSITIONS
8
+ } from "./chunk-WMGIIABP.js";
9
+ import {
10
+ append,
11
+ currentOwner
12
+ } from "./chunk-4BQTQMJP.js";
13
+ import {
14
+ __export
15
+ } from "./chunk-2ZDO52B4.js";
16
+
17
+ // src/workgraph/thread.ts
18
+ var thread_exports = {};
19
+ __export(thread_exports, {
20
+ block: () => block,
21
+ cancel: () => cancel,
22
+ claim: () => claim,
23
+ createThread: () => createThread,
24
+ decompose: () => decompose,
25
+ done: () => done,
26
+ release: () => release,
27
+ unblock: () => unblock
28
+ });
29
+ function createThread(vaultPath, title, goal, actor, opts = {}) {
30
+ return create(vaultPath, "thread", {
31
+ title,
32
+ goal,
33
+ status: "open",
34
+ priority: opts.priority ?? "medium",
35
+ deps: opts.deps ?? [],
36
+ parent: opts.parent,
37
+ context_refs: opts.context_refs ?? [],
38
+ tags: opts.tags ?? []
39
+ }, `## Goal
40
+
41
+ ${goal}
42
+ `, actor);
43
+ }
44
+ function claim(vaultPath, threadPath, actor) {
45
+ const thread = read(vaultPath, threadPath);
46
+ if (!thread) throw new Error(`Thread not found: ${threadPath}`);
47
+ const status = thread.fields.status;
48
+ if (status !== "open") {
49
+ throw new Error(`Cannot claim thread in "${status}" state. Only "open" threads can be claimed.`);
50
+ }
51
+ const owner = currentOwner(vaultPath, threadPath);
52
+ if (owner) {
53
+ throw new Error(`Thread already claimed by "${owner}". Wait for release or use a different thread.`);
54
+ }
55
+ append(vaultPath, actor, "claim", threadPath, "thread");
56
+ return update(vaultPath, threadPath, {
57
+ status: "active",
58
+ owner: actor
59
+ }, void 0, actor);
60
+ }
61
+ function release(vaultPath, threadPath, actor, reason) {
62
+ const thread = read(vaultPath, threadPath);
63
+ if (!thread) throw new Error(`Thread not found: ${threadPath}`);
64
+ assertOwner(vaultPath, threadPath, actor);
65
+ append(
66
+ vaultPath,
67
+ actor,
68
+ "release",
69
+ threadPath,
70
+ "thread",
71
+ reason ? { reason } : void 0
72
+ );
73
+ return update(vaultPath, threadPath, {
74
+ status: "open",
75
+ owner: null
76
+ }, void 0, actor);
77
+ }
78
+ function block(vaultPath, threadPath, actor, blockedBy, reason) {
79
+ const thread = read(vaultPath, threadPath);
80
+ if (!thread) throw new Error(`Thread not found: ${threadPath}`);
81
+ assertTransition(thread.fields.status, "blocked");
82
+ append(vaultPath, actor, "block", threadPath, "thread", {
83
+ blocked_by: blockedBy,
84
+ ...reason ? { reason } : {}
85
+ });
86
+ const currentDeps = thread.fields.deps ?? [];
87
+ const updatedDeps = currentDeps.includes(blockedBy) ? currentDeps : [...currentDeps, blockedBy];
88
+ return update(vaultPath, threadPath, {
89
+ status: "blocked",
90
+ deps: updatedDeps
91
+ }, void 0, actor);
92
+ }
93
+ function unblock(vaultPath, threadPath, actor) {
94
+ const thread = read(vaultPath, threadPath);
95
+ if (!thread) throw new Error(`Thread not found: ${threadPath}`);
96
+ assertTransition(thread.fields.status, "active");
97
+ append(vaultPath, actor, "unblock", threadPath, "thread");
98
+ return update(vaultPath, threadPath, {
99
+ status: "active"
100
+ }, void 0, actor);
101
+ }
102
+ function done(vaultPath, threadPath, actor, output) {
103
+ const thread = read(vaultPath, threadPath);
104
+ if (!thread) throw new Error(`Thread not found: ${threadPath}`);
105
+ assertTransition(thread.fields.status, "done");
106
+ assertOwner(vaultPath, threadPath, actor);
107
+ append(
108
+ vaultPath,
109
+ actor,
110
+ "done",
111
+ threadPath,
112
+ "thread",
113
+ output ? { output } : void 0
114
+ );
115
+ const newBody = output ? `${thread.body}
116
+
117
+ ## Output
118
+
119
+ ${output}
120
+ ` : thread.body;
121
+ return update(vaultPath, threadPath, {
122
+ status: "done"
123
+ }, newBody, actor);
124
+ }
125
+ function cancel(vaultPath, threadPath, actor, reason) {
126
+ const thread = read(vaultPath, threadPath);
127
+ if (!thread) throw new Error(`Thread not found: ${threadPath}`);
128
+ assertTransition(thread.fields.status, "cancelled");
129
+ append(
130
+ vaultPath,
131
+ actor,
132
+ "cancel",
133
+ threadPath,
134
+ "thread",
135
+ reason ? { reason } : void 0
136
+ );
137
+ return update(vaultPath, threadPath, {
138
+ status: "cancelled",
139
+ owner: null
140
+ }, void 0, actor);
141
+ }
142
+ function decompose(vaultPath, parentPath, subthreads, actor) {
143
+ const parent = read(vaultPath, parentPath);
144
+ if (!parent) throw new Error(`Thread not found: ${parentPath}`);
145
+ const created = [];
146
+ for (const sub of subthreads) {
147
+ const inst = createThread(vaultPath, sub.title, sub.goal, actor, {
148
+ parent: parentPath,
149
+ deps: sub.deps
150
+ });
151
+ created.push(inst);
152
+ }
153
+ const childRefs = created.map((c) => `[[${c.path}]]`);
154
+ const decomposeNote = `
155
+
156
+ ## Sub-threads
157
+
158
+ ${childRefs.map((r) => `- ${r}`).join("\n")}
159
+ `;
160
+ update(vaultPath, parentPath, {}, parent.body + decomposeNote, actor);
161
+ append(vaultPath, actor, "decompose", parentPath, "thread", {
162
+ children: created.map((c) => c.path)
163
+ });
164
+ return created;
165
+ }
166
+ function assertTransition(from, to) {
167
+ const allowed = THREAD_STATUS_TRANSITIONS[from];
168
+ if (!allowed?.includes(to)) {
169
+ throw new Error(`Invalid transition: "${from}" \u2192 "${to}". Allowed: ${allowed?.join(", ") ?? "none"}`);
170
+ }
171
+ }
172
+ function assertOwner(vaultPath, threadPath, actor) {
173
+ const owner = currentOwner(vaultPath, threadPath);
174
+ if (owner && owner !== actor) {
175
+ throw new Error(`Thread is owned by "${owner}", not "${actor}". Only the owner can perform this action.`);
176
+ }
177
+ }
178
+
179
+ export {
180
+ createThread,
181
+ claim,
182
+ release,
183
+ block,
184
+ unblock,
185
+ done,
186
+ cancel,
187
+ decompose,
188
+ thread_exports
189
+ };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runReflection
3
- } from "./chunk-T76H47ZS.js";
3
+ } from "./chunk-MNPUYCHQ.js";
4
4
  import {
5
5
  resolveVaultPath
6
- } from "./chunk-MXSSG3QU.js";
6
+ } from "./chunk-GNJL4YGR.js";
7
7
 
8
8
  // src/commands/reflect.ts
9
9
  function parsePositiveInteger(raw, label) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveVaultPath
3
- } from "./chunk-MXSSG3QU.js";
3
+ } from "./chunk-GNJL4YGR.js";
4
4
 
5
5
  // src/commands/sync-bd.ts
6
6
  import * as fs from "fs";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  parseSessionFile
3
- } from "./chunk-P5EPF6MB.js";
3
+ } from "./chunk-MW5C6ZQA.js";
4
4
  import {
5
5
  observeActiveSessions
6
- } from "./chunk-IEVLHNLU.js";
6
+ } from "./chunk-T3FKSZSN.js";
7
7
  import {
8
8
  Observer
9
- } from "./chunk-Q2J5YTUF.js";
9
+ } from "./chunk-FUSLEY6L.js";
10
10
  import {
11
11
  resolveVaultPath
12
- } from "./chunk-MXSSG3QU.js";
12
+ } from "./chunk-GNJL4YGR.js";
13
13
  import {
14
14
  getObservationPath
15
15
  } from "./chunk-Z2XBWN7A.js";
@@ -1,9 +1,9 @@
1
+ import {
2
+ Observer
3
+ } from "./chunk-FUSLEY6L.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
  ClawVault
3
- } from "./chunk-RCBMXTWS.js";
3
+ } from "./chunk-YD7SVXTF.js";
4
4
  import {
5
5
  parseObservationMarkdown
6
6
  } from "./chunk-FHFUXL6G.js";
7
7
  import {
8
8
  getMemoryGraph
9
- } from "./chunk-ZZA73MFY.js";
9
+ } from "./chunk-33DOSHTA.js";
10
10
  import {
11
11
  listObservationFiles
12
12
  } from "./chunk-Z2XBWN7A.js";
@@ -0,0 +1,154 @@
1
+ // src/lib/hybrid-search.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ var embeddingPipeline = null;
5
+ var pipelineLoading = null;
6
+ async function getEmbeddingPipeline() {
7
+ if (embeddingPipeline) return embeddingPipeline;
8
+ if (pipelineLoading) return pipelineLoading;
9
+ pipelineLoading = (async () => {
10
+ const { pipeline } = await import("./transformers.node-A2ZRORSQ.js");
11
+ embeddingPipeline = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2", {
12
+ dtype: "fp32"
13
+ });
14
+ return embeddingPipeline;
15
+ })();
16
+ return pipelineLoading;
17
+ }
18
+ async function embed(text) {
19
+ const pipe = await getEmbeddingPipeline();
20
+ const result = await pipe(text, { pooling: "mean", normalize: true });
21
+ return new Float32Array(result.data);
22
+ }
23
+ async function embedBatch(texts) {
24
+ const pipe = await getEmbeddingPipeline();
25
+ const results = [];
26
+ const batchSize = 32;
27
+ for (let i = 0; i < texts.length; i += batchSize) {
28
+ const batch = texts.slice(i, i + batchSize);
29
+ for (const text of batch) {
30
+ const result = await pipe(text, { pooling: "mean", normalize: true });
31
+ results.push(new Float32Array(result.data));
32
+ }
33
+ }
34
+ return results;
35
+ }
36
+ function cosineSimilarity(a, b) {
37
+ let dot = 0;
38
+ for (let i = 0; i < a.length; i++) {
39
+ dot += a[i] * b[i];
40
+ }
41
+ return dot;
42
+ }
43
+ var EmbeddingCache = class {
44
+ cachePath;
45
+ cache = /* @__PURE__ */ new Map();
46
+ dirty = false;
47
+ constructor(vaultPath) {
48
+ this.cachePath = path.join(vaultPath, ".clawvault", "embeddings.bin");
49
+ }
50
+ /**
51
+ * Load cache from disk
52
+ */
53
+ load() {
54
+ try {
55
+ if (!fs.existsSync(this.cachePath)) return;
56
+ const data = JSON.parse(fs.readFileSync(this.cachePath + ".json", "utf-8"));
57
+ for (const [key, arr] of Object.entries(data)) {
58
+ this.cache.set(key, new Float32Array(arr));
59
+ }
60
+ } catch {
61
+ }
62
+ }
63
+ /**
64
+ * Save cache to disk
65
+ */
66
+ save() {
67
+ if (!this.dirty) return;
68
+ const dir = path.dirname(this.cachePath);
69
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
70
+ const data = {};
71
+ for (const [key, arr] of this.cache.entries()) {
72
+ data[key] = Array.from(arr);
73
+ }
74
+ fs.writeFileSync(this.cachePath + ".json", JSON.stringify(data));
75
+ this.dirty = false;
76
+ }
77
+ get(key) {
78
+ return this.cache.get(key);
79
+ }
80
+ set(key, embedding) {
81
+ this.cache.set(key, embedding);
82
+ this.dirty = true;
83
+ }
84
+ has(key) {
85
+ return this.cache.has(key);
86
+ }
87
+ entries() {
88
+ return this.cache.entries();
89
+ }
90
+ get size() {
91
+ return this.cache.size;
92
+ }
93
+ };
94
+ function reciprocalRankFusion(list1, list2, k = 60) {
95
+ const scores = /* @__PURE__ */ new Map();
96
+ for (let rank = 0; rank < list1.length; rank++) {
97
+ const { id } = list1[rank];
98
+ scores.set(id, (scores.get(id) || 0) + 1 / (k + rank + 1));
99
+ }
100
+ for (let rank = 0; rank < list2.length; rank++) {
101
+ const { id } = list2[rank];
102
+ scores.set(id, (scores.get(id) || 0) + 1 / (k + rank + 1));
103
+ }
104
+ return Array.from(scores.entries()).map(([id, score]) => ({ id, score })).sort((a, b) => b.score - a.score);
105
+ }
106
+ async function semanticSearch(query, cache, topK = 20) {
107
+ const queryEmb = await embed(query);
108
+ const results = [];
109
+ for (const [id, docEmb] of cache.entries()) {
110
+ results.push({ id, score: cosineSimilarity(queryEmb, docEmb) });
111
+ }
112
+ results.sort((a, b) => b.score - a.score);
113
+ return results.slice(0, topK);
114
+ }
115
+ async function hybridSearch(query, bm25Results, cache, options = {}) {
116
+ const { topK = 20, rrfK = 60 } = options;
117
+ const bm25Ranked = bm25Results.map((r) => ({ id: r.document.path || r.document.id, score: r.score }));
118
+ const semanticRanked = await semanticSearch(query, cache, topK);
119
+ const fused = reciprocalRankFusion(bm25Ranked, semanticRanked, rrfK);
120
+ const bm25Map = new Map(bm25Results.map((r) => [r.document.path || r.document.id, r]));
121
+ return fused.slice(0, topK).map(({ id, score }) => {
122
+ const existing = bm25Map.get(id);
123
+ if (existing) {
124
+ return { ...existing, score };
125
+ }
126
+ const minimalDoc = {
127
+ id: id.replace(/\.md$/, ""),
128
+ path: id.endsWith(".md") ? id : id + ".md",
129
+ title: (id.split("/").pop() || id).replace(/\.md$/, ""),
130
+ content: "",
131
+ category: id.split("/")[0] || "root",
132
+ frontmatter: {},
133
+ links: [],
134
+ tags: [],
135
+ modified: /* @__PURE__ */ new Date()
136
+ };
137
+ return {
138
+ document: minimalDoc,
139
+ score,
140
+ snippet: "",
141
+ matchedTerms: []
142
+ };
143
+ });
144
+ }
145
+
146
+ export {
147
+ embed,
148
+ embedBatch,
149
+ cosineSimilarity,
150
+ EmbeddingCache,
151
+ reciprocalRankFusion,
152
+ semanticSearch,
153
+ hybridSearch
154
+ };
@@ -6,16 +6,21 @@ import {
6
6
  import * as fs from "fs";
7
7
  import * as path from "path";
8
8
  var CONFIG_FILE = ".clawvault.json";
9
- var OBSERVE_PROVIDERS = ["anthropic", "openai", "gemini"];
9
+ var OBSERVE_PROVIDERS = ["anthropic", "openai", "gemini", "xai", "openclaw"];
10
10
  var OBSERVER_COMPRESSION_PROVIDERS = [
11
11
  "anthropic",
12
12
  "openai",
13
13
  "gemini",
14
+ "xai",
14
15
  "openai-compatible",
15
- "ollama"
16
+ "ollama",
17
+ "openclaw",
18
+ "minimax",
19
+ "zai"
16
20
  ];
17
21
  var THEMES = ["neural", "minimal", "none"];
18
22
  var CONTEXT_PROFILES = ["default", "planning", "incident", "handoff", "auto"];
23
+ var FACT_EXTRACTION_MODES = ["off", "rule", "llm", "hybrid"];
19
24
  var SUPPORTED_CONFIG_KEYS = [
20
25
  "name",
21
26
  "categories",
@@ -26,6 +31,7 @@ var SUPPORTED_CONFIG_KEYS = [
26
31
  "observer.compression.model",
27
32
  "observer.compression.baseUrl",
28
33
  "observer.compression.apiKey",
34
+ "observer.factExtractionMode",
29
35
  "context.maxResults",
30
36
  "context.defaultProfile",
31
37
  "graph.maxHops",
@@ -36,6 +42,7 @@ var SUPPORTED_CONFIG_KEYS = [
36
42
  var DEFAULT_THEME = "none";
37
43
  var DEFAULT_OBSERVE_MODEL = "gemini-2.0-flash";
38
44
  var DEFAULT_OBSERVE_PROVIDER = "gemini";
45
+ var DEFAULT_FACT_EXTRACTION_MODE = "llm";
39
46
  var DEFAULT_CONTEXT_MAX_RESULTS = 5;
40
47
  var DEFAULT_CONTEXT_PROFILE = "default";
41
48
  var DEFAULT_GRAPH_MAX_HOPS = 2;
@@ -113,6 +120,9 @@ function isTheme(value) {
113
120
  function isContextProfile(value) {
114
121
  return typeof value === "string" && CONTEXT_PROFILES.includes(value);
115
122
  }
123
+ function isFactExtractionMode(value) {
124
+ return typeof value === "string" && FACT_EXTRACTION_MODES.includes(value);
125
+ }
116
126
  function normalizeRouteTarget(target) {
117
127
  const trimmed = target.trim().replace(/^\/+/, "").replace(/\/+$/, "");
118
128
  if (!trimmed) {
@@ -196,7 +206,8 @@ function withDefaults(vaultPath, config) {
196
206
  provider: DEFAULT_OBSERVE_PROVIDER
197
207
  },
198
208
  observer: {
199
- compression: {}
209
+ compression: {},
210
+ factExtractionMode: DEFAULT_FACT_EXTRACTION_MODE
200
211
  },
201
212
  context: {
202
213
  maxResults: DEFAULT_CONTEXT_MAX_RESULTS,
@@ -247,7 +258,8 @@ function withDefaults(vaultPath, config) {
247
258
  },
248
259
  observer: {
249
260
  ...observerRecord,
250
- compression: normalizedCompression
261
+ compression: normalizedCompression,
262
+ factExtractionMode: isFactExtractionMode(observerRecord.factExtractionMode) ? observerRecord.factExtractionMode : defaults.observer.factExtractionMode
251
263
  },
252
264
  context: {
253
265
  ...contextRecord,
@@ -335,6 +347,12 @@ function coerceManagedValue(key, value) {
335
347
  }
336
348
  return value.trim();
337
349
  }
350
+ if (key === "observer.factExtractionMode") {
351
+ if (!isFactExtractionMode(value)) {
352
+ throw new Error(`Config key "observer.factExtractionMode" must be one of: ${FACT_EXTRACTION_MODES.join(", ")}`);
353
+ }
354
+ return value;
355
+ }
338
356
  if (key === "context.maxResults") {
339
357
  const parsed = asPositiveInteger(value);
340
358
  if (parsed === null) {
@@ -424,7 +442,8 @@ function resetConfig(vaultPath) {
424
442
  const observerRecord = document.observer && typeof document.observer === "object" && !Array.isArray(document.observer) ? document.observer : {};
425
443
  document.observer = {
426
444
  ...observerRecord,
427
- compression: {}
445
+ compression: {},
446
+ factExtractionMode: DEFAULT_FACT_EXTRACTION_MODE
428
447
  };
429
448
  document.context = {
430
449
  maxResults: DEFAULT_CONTEXT_MAX_RESULTS,