clawvault 2.6.1 → 3.0.0-beta.2
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/bin/command-registration.test.js +1 -3
- package/bin/register-core-commands.js +30 -23
- package/bin/register-maintenance-commands.js +3 -20
- package/bin/register-query-commands.js +23 -0
- package/bin/register-task-commands.js +1 -18
- package/bin/register-task-commands.test.js +0 -16
- package/bin/register-vault-operations-commands.js +1 -29
- package/dist/chunk-2TM7DLOL.js +895 -0
- package/dist/{chunk-QVMXF7FY.js → chunk-3D6BCTP6.js} +39 -1
- package/dist/{chunk-R2MIW5G7.js → chunk-3DHXQHYG.js} +1 -1
- package/dist/{chunk-Q2J5YTUF.js → chunk-3NSBOUT3.js} +73 -36
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/{chunk-AZYOKJYC.js → chunk-62YTUT6J.js} +2 -2
- package/dist/chunk-6U6MK36V.js +205 -0
- package/dist/{chunk-4QYGFWRM.js → chunk-7R7O6STJ.js} +4 -4
- package/dist/{chunk-VXEOHTSL.js → chunk-C7OK5WKP.js} +4 -4
- package/dist/chunk-CMB7UL7C.js +327 -0
- package/dist/{chunk-HIHOUSXS.js → chunk-E7MFQB6D.js} +59 -18
- package/dist/{chunk-ME37YNW3.js → chunk-F2JEUD4J.js} +6 -4
- package/dist/chunk-GAJV4IGR.js +82 -0
- package/dist/chunk-GQSLDZTS.js +560 -0
- package/dist/{chunk-4OXMU5S2.js → chunk-GUKMRGM7.js} +1 -1
- package/dist/{chunk-T76H47ZS.js → chunk-H34S76MB.js} +6 -6
- package/dist/{chunk-R6SXNSFD.js → chunk-JY6FYXIT.js} +10 -5
- package/dist/chunk-K234IDRJ.js +1073 -0
- package/dist/{chunk-IEVLHNLU.js → chunk-LNJA2UGL.js} +86 -9
- package/dist/{chunk-MFAWT5O5.js → chunk-LYHGEHXG.js} +1 -0
- package/dist/chunk-MFM6K7PU.js +374 -0
- package/dist/{chunk-QWQ3TIKS.js → chunk-N2AXRYLC.js} +1 -1
- package/dist/chunk-PAH27GSN.js +108 -0
- package/dist/{chunk-OIWVQYQF.js → chunk-QBLMXKF2.js} +1 -1
- package/dist/{chunk-FHFUXL6G.js → chunk-QK3UCXWL.js} +2 -2
- package/dist/{chunk-3BTHWPMB.js → chunk-SJSFRIYS.js} +1 -1
- package/dist/{chunk-4VRIMU4O.js → chunk-U55BGUAU.js} +2 -2
- package/dist/{chunk-PBEE567J.js → chunk-VGLOTGAS.js} +1 -1
- package/dist/{chunk-F55HGNU4.js → chunk-WAZ3NLWL.js} +47 -0
- package/dist/{chunk-KL4NAOMO.js → chunk-WGRQ6HDV.js} +1 -1
- package/dist/{chunk-UEOUADMO.js → chunk-YKTA5JOJ.js} +13 -10
- package/dist/{chunk-XAVB4GB4.js → chunk-ZVVFWOLW.js} +4 -4
- package/dist/cli/index.cjs +10033 -0
- package/dist/cli/index.d.cts +5 -0
- package/dist/cli/index.js +20 -18
- package/dist/commands/archive.cjs +287 -0
- package/dist/commands/archive.d.cts +11 -0
- package/dist/commands/archive.js +1 -0
- package/dist/commands/backlog.cjs +721 -0
- package/dist/commands/backlog.d.cts +53 -0
- package/dist/commands/backlog.js +3 -2
- package/dist/commands/blocked.cjs +204 -0
- package/dist/commands/blocked.d.cts +26 -0
- package/dist/commands/blocked.js +3 -2
- package/dist/commands/checkpoint.cjs +244 -0
- package/dist/commands/checkpoint.d.cts +41 -0
- package/dist/commands/checkpoint.js +2 -1
- package/dist/commands/compat.cjs +369 -0
- package/dist/commands/compat.d.cts +28 -0
- package/dist/commands/compat.js +2 -1
- package/dist/commands/context.cjs +2989 -0
- package/dist/commands/context.d.cts +2 -0
- package/dist/commands/context.js +5 -4
- package/dist/commands/doctor.cjs +3062 -0
- package/dist/commands/doctor.d.cts +21 -0
- package/dist/commands/doctor.d.ts +6 -1
- package/dist/commands/doctor.js +13 -11
- package/dist/commands/embed.cjs +232 -0
- package/dist/commands/embed.d.cts +17 -0
- package/dist/commands/embed.js +5 -2
- package/dist/commands/entities.cjs +141 -0
- package/dist/commands/entities.d.cts +7 -0
- package/dist/commands/entities.js +1 -0
- package/dist/commands/graph.cjs +501 -0
- package/dist/commands/graph.d.cts +21 -0
- package/dist/commands/graph.js +1 -0
- package/dist/commands/inject.cjs +1636 -0
- package/dist/commands/inject.d.cts +2 -0
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +4 -2
- package/dist/commands/kanban.cjs +884 -0
- package/dist/commands/kanban.d.cts +63 -0
- package/dist/commands/kanban.js +4 -3
- package/dist/commands/link.cjs +965 -0
- package/dist/commands/link.d.cts +11 -0
- package/dist/commands/link.js +1 -0
- package/dist/commands/migrate-observations.cjs +362 -0
- package/dist/commands/migrate-observations.d.cts +19 -0
- package/dist/commands/migrate-observations.js +3 -2
- package/dist/commands/observe.cjs +4099 -0
- package/dist/commands/observe.d.cts +23 -0
- package/dist/commands/observe.d.ts +1 -0
- package/dist/commands/observe.js +11 -9
- package/dist/commands/project.cjs +1341 -0
- package/dist/commands/project.d.cts +85 -0
- package/dist/commands/project.js +5 -4
- package/dist/commands/rebuild.cjs +3136 -0
- package/dist/commands/rebuild.d.cts +11 -0
- package/dist/commands/rebuild.js +10 -8
- package/dist/commands/recover.cjs +361 -0
- package/dist/commands/recover.d.cts +38 -0
- package/dist/commands/recover.js +3 -2
- package/dist/commands/reflect.cjs +1008 -0
- package/dist/commands/reflect.d.cts +11 -0
- package/dist/commands/reflect.js +6 -4
- package/dist/commands/repair-session.cjs +457 -0
- package/dist/commands/repair-session.d.cts +38 -0
- package/dist/commands/repair-session.js +1 -0
- package/dist/commands/replay.cjs +4103 -0
- package/dist/commands/replay.d.cts +16 -0
- package/dist/commands/replay.js +12 -10
- package/dist/commands/session-recap.cjs +353 -0
- package/dist/commands/session-recap.d.cts +27 -0
- package/dist/commands/session-recap.js +1 -0
- package/dist/commands/setup.cjs +1302 -0
- package/dist/commands/setup.d.cts +100 -0
- package/dist/commands/setup.d.ts +90 -2
- package/dist/commands/setup.js +21 -2
- package/dist/commands/shell-init.cjs +75 -0
- package/dist/commands/shell-init.d.cts +7 -0
- package/dist/commands/shell-init.js +2 -0
- package/dist/commands/sleep.cjs +6028 -0
- package/dist/commands/sleep.d.cts +36 -0
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +17 -15
- package/dist/commands/status.cjs +2736 -0
- package/dist/commands/status.d.cts +52 -0
- package/dist/commands/status.js +12 -10
- package/dist/commands/tailscale.cjs +1532 -0
- package/dist/commands/tailscale.d.cts +52 -0
- package/dist/commands/tailscale.js +1 -0
- package/dist/commands/task.cjs +1236 -0
- package/dist/commands/task.d.cts +97 -0
- package/dist/commands/task.js +4 -3
- package/dist/commands/template.cjs +457 -0
- package/dist/commands/template.d.cts +36 -0
- package/dist/commands/template.js +2 -1
- package/dist/commands/wake.cjs +2626 -0
- package/dist/commands/wake.d.cts +22 -0
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +10 -9
- package/dist/context-BUGaWpyL.d.cts +46 -0
- package/dist/index.cjs +14001 -0
- package/dist/index.d.cts +858 -0
- package/dist/index.d.ts +192 -7
- package/dist/index.js +101 -75
- package/dist/{inject-x65KXWPk.d.ts → inject-Bzi5E-By.d.cts} +1 -1
- package/dist/inject-Bzi5E-By.d.ts +137 -0
- package/dist/lib/auto-linker.cjs +176 -0
- package/dist/lib/auto-linker.d.cts +26 -0
- package/dist/lib/auto-linker.js +1 -0
- package/dist/lib/canvas-layout.cjs +136 -0
- package/dist/lib/canvas-layout.d.cts +31 -0
- package/dist/lib/canvas-layout.d.ts +16 -100
- package/dist/lib/canvas-layout.js +78 -20
- package/dist/lib/config.cjs +78 -0
- package/dist/lib/config.d.cts +11 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/entity-index.cjs +84 -0
- package/dist/lib/entity-index.d.cts +26 -0
- package/dist/lib/entity-index.js +1 -0
- package/dist/lib/project-utils.cjs +864 -0
- package/dist/lib/project-utils.d.cts +97 -0
- package/dist/lib/project-utils.js +4 -3
- package/dist/lib/session-repair.cjs +239 -0
- package/dist/lib/session-repair.d.cts +110 -0
- package/dist/lib/session-repair.js +1 -0
- package/dist/lib/session-utils.cjs +209 -0
- package/dist/lib/session-utils.d.cts +63 -0
- package/dist/lib/session-utils.js +1 -0
- package/dist/lib/tailscale.cjs +1183 -0
- package/dist/lib/tailscale.d.cts +225 -0
- package/dist/lib/tailscale.js +1 -0
- package/dist/lib/task-utils.cjs +1137 -0
- package/dist/lib/task-utils.d.cts +208 -0
- package/dist/lib/task-utils.js +3 -2
- package/dist/lib/template-engine.cjs +47 -0
- package/dist/lib/template-engine.d.cts +11 -0
- package/dist/lib/template-engine.js +1 -0
- package/dist/lib/webdav.cjs +568 -0
- package/dist/lib/webdav.d.cts +109 -0
- package/dist/lib/webdav.js +1 -0
- package/dist/plugin/index.cjs +1907 -0
- package/dist/plugin/index.d.cts +36 -0
- package/dist/plugin/index.d.ts +36 -0
- package/dist/plugin/index.js +572 -0
- package/dist/plugin/inject.cjs +356 -0
- package/dist/plugin/inject.d.cts +54 -0
- package/dist/plugin/inject.d.ts +54 -0
- package/dist/plugin/inject.js +17 -0
- package/dist/plugin/observe.cjs +631 -0
- package/dist/plugin/observe.d.cts +39 -0
- package/dist/plugin/observe.d.ts +39 -0
- package/dist/plugin/observe.js +18 -0
- package/dist/plugin/templates.cjs +593 -0
- package/dist/plugin/templates.d.cts +52 -0
- package/dist/plugin/templates.d.ts +52 -0
- package/dist/plugin/templates.js +25 -0
- package/dist/plugin/types.cjs +18 -0
- package/dist/plugin/types.d.cts +209 -0
- package/dist/plugin/types.d.ts +209 -0
- package/dist/plugin/types.js +0 -0
- package/dist/plugin/vault.cjs +927 -0
- package/dist/plugin/vault.d.cts +68 -0
- package/dist/plugin/vault.d.ts +68 -0
- package/dist/plugin/vault.js +22 -0
- package/dist/{types-C74wgGL1.d.ts → types-Y2_Um2Ls.d.cts} +44 -1
- package/dist/types-Y2_Um2Ls.d.ts +205 -0
- package/hooks/clawvault/handler.js +70 -7
- package/hooks/clawvault/handler.test.js +91 -0
- package/openclaw.plugin.json +56 -0
- package/package.json +16 -6
- package/templates/memory-event.md +67 -0
- package/templates/party.md +63 -0
- package/templates/primitive-registry.yaml +551 -0
- package/templates/run.md +68 -0
- package/templates/trigger.md +68 -0
- package/templates/workspace.md +50 -0
- package/dashboard/lib/graph-diff.js +0 -104
- package/dashboard/lib/graph-diff.test.js +0 -75
- package/dashboard/lib/vault-parser.js +0 -556
- package/dashboard/lib/vault-parser.test.js +0 -254
- package/dashboard/public/app.js +0 -796
- package/dashboard/public/index.html +0 -52
- package/dashboard/public/styles.css +0 -221
- package/dashboard/server.js +0 -374
- package/dist/chunk-MAKNAHAW.js +0 -375
- package/dist/chunk-MDIH26GC.js +0 -183
- package/dist/chunk-MGDEINGP.js +0 -99
- package/dist/chunk-RVYA52PY.js +0 -363
- package/dist/chunk-TLGBDTYT.js +0 -33
- package/dist/commands/canvas.d.ts +0 -15
- package/dist/commands/canvas.js +0 -199
- package/dist/commands/sync-bd.d.ts +0 -10
- package/dist/commands/sync-bd.js +0 -9
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
// src/plugin/inject.ts
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
3
|
+
import { join, relative } from "path";
|
|
4
|
+
function parseYamlFrontmatter(content) {
|
|
5
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
6
|
+
if (!match) return null;
|
|
7
|
+
const yamlContent = match[1];
|
|
8
|
+
const body = match[2];
|
|
9
|
+
try {
|
|
10
|
+
const frontmatter = parseSimpleYaml(yamlContent);
|
|
11
|
+
return { frontmatter, body };
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function parseSimpleYaml(yaml) {
|
|
17
|
+
const result = {};
|
|
18
|
+
const lines = yaml.split("\n");
|
|
19
|
+
for (const line of lines) {
|
|
20
|
+
if (!line.trim() || line.trim().startsWith("#")) continue;
|
|
21
|
+
const colonIndex = line.indexOf(":");
|
|
22
|
+
if (colonIndex === -1) continue;
|
|
23
|
+
const key = line.slice(0, colonIndex).trim();
|
|
24
|
+
const valueStr = line.slice(colonIndex + 1).trim();
|
|
25
|
+
if (valueStr === "" || valueStr.startsWith("|") || valueStr.startsWith(">")) continue;
|
|
26
|
+
result[key] = parseYamlValue(valueStr);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function parseYamlValue(value) {
|
|
31
|
+
if (value === "" || value === "null" || value === "~") return null;
|
|
32
|
+
if (value === "true") return true;
|
|
33
|
+
if (value === "false") return false;
|
|
34
|
+
if (/^-?\d+$/.test(value)) return parseInt(value, 10);
|
|
35
|
+
if (/^-?\d+\.\d+$/.test(value)) return parseFloat(value);
|
|
36
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
37
|
+
return value.slice(1, -1);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function scanVaultFiles(vaultPath, options = {}) {
|
|
42
|
+
const files = [];
|
|
43
|
+
const maxAge = options.maxAge ?? 7 * 24 * 60 * 60 * 1e3;
|
|
44
|
+
const limit = options.limit ?? 100;
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
const cutoff = now - maxAge;
|
|
47
|
+
const dirsToScan = findVaultDirectories(vaultPath);
|
|
48
|
+
for (const dir of dirsToScan) {
|
|
49
|
+
if (!existsSync(dir)) continue;
|
|
50
|
+
try {
|
|
51
|
+
scanDirectory(dir, vaultPath, files, cutoff, options.primitiveTypes);
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
files.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
|
|
56
|
+
return files.slice(0, limit);
|
|
57
|
+
}
|
|
58
|
+
function findVaultDirectories(vaultPath) {
|
|
59
|
+
const dirs = [];
|
|
60
|
+
dirs.push(vaultPath);
|
|
61
|
+
const commonDirs = [
|
|
62
|
+
"tasks",
|
|
63
|
+
"projects",
|
|
64
|
+
"decisions",
|
|
65
|
+
"people",
|
|
66
|
+
"persons",
|
|
67
|
+
"notes",
|
|
68
|
+
"daily",
|
|
69
|
+
"journal",
|
|
70
|
+
"ledger",
|
|
71
|
+
"memory",
|
|
72
|
+
"memories",
|
|
73
|
+
"observations",
|
|
74
|
+
"lessons",
|
|
75
|
+
"triggers",
|
|
76
|
+
"runs",
|
|
77
|
+
"checkpoints",
|
|
78
|
+
"handoffs",
|
|
79
|
+
"workspaces",
|
|
80
|
+
"parties"
|
|
81
|
+
];
|
|
82
|
+
for (const subdir of commonDirs) {
|
|
83
|
+
const fullPath = join(vaultPath, subdir);
|
|
84
|
+
if (existsSync(fullPath)) {
|
|
85
|
+
dirs.push(fullPath);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const entries = readdirSync(vaultPath, { withFileTypes: true });
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.startsWith("_")) {
|
|
92
|
+
const fullPath = join(vaultPath, entry.name);
|
|
93
|
+
if (!dirs.includes(fullPath)) {
|
|
94
|
+
dirs.push(fullPath);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
return dirs;
|
|
101
|
+
}
|
|
102
|
+
function scanDirectory(dir, vaultPath, files, cutoff, primitiveTypes) {
|
|
103
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
104
|
+
for (const entry of entries) {
|
|
105
|
+
if (entry.name.startsWith(".") || entry.name.startsWith("_")) continue;
|
|
106
|
+
const fullPath = join(dir, entry.name);
|
|
107
|
+
if (entry.isDirectory()) {
|
|
108
|
+
const depth = fullPath.replace(vaultPath, "").split("/").length;
|
|
109
|
+
if (depth <= 3) {
|
|
110
|
+
scanDirectory(fullPath, vaultPath, files, cutoff, primitiveTypes);
|
|
111
|
+
}
|
|
112
|
+
} else if (entry.name.endsWith(".md")) {
|
|
113
|
+
try {
|
|
114
|
+
const stat = statSync(fullPath);
|
|
115
|
+
if (stat.mtimeMs < cutoff) continue;
|
|
116
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
117
|
+
const parsed = parseYamlFrontmatter(content);
|
|
118
|
+
if (!parsed) continue;
|
|
119
|
+
const primitiveType = detectPrimitiveType(parsed.frontmatter, fullPath);
|
|
120
|
+
if (primitiveTypes && !primitiveTypes.includes(primitiveType)) continue;
|
|
121
|
+
files.push({
|
|
122
|
+
path: fullPath,
|
|
123
|
+
relativePath: relative(vaultPath, fullPath),
|
|
124
|
+
primitiveType,
|
|
125
|
+
frontmatter: parsed.frontmatter,
|
|
126
|
+
content: parsed.body,
|
|
127
|
+
modifiedAt: stat.mtime,
|
|
128
|
+
createdAt: stat.birthtime
|
|
129
|
+
});
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function detectPrimitiveType(frontmatter, filePath) {
|
|
136
|
+
if (frontmatter.primitive) return String(frontmatter.primitive);
|
|
137
|
+
if (frontmatter.type) return String(frontmatter.type);
|
|
138
|
+
const pathLower = filePath.toLowerCase();
|
|
139
|
+
if (pathLower.includes("/tasks/")) return "task";
|
|
140
|
+
if (pathLower.includes("/projects/")) return "project";
|
|
141
|
+
if (pathLower.includes("/decisions/")) return "decision";
|
|
142
|
+
if (pathLower.includes("/people/") || pathLower.includes("/persons/")) return "person";
|
|
143
|
+
if (pathLower.includes("/daily/") || pathLower.includes("/journal/")) return "daily-note";
|
|
144
|
+
if (pathLower.includes("/lessons/")) return "lesson";
|
|
145
|
+
if (pathLower.includes("/triggers/")) return "trigger";
|
|
146
|
+
if (pathLower.includes("/runs/")) return "run";
|
|
147
|
+
if (pathLower.includes("/checkpoints/")) return "checkpoint";
|
|
148
|
+
if (pathLower.includes("/handoffs/")) return "handoff";
|
|
149
|
+
if (pathLower.includes("/ledger/")) return "memory_event";
|
|
150
|
+
if (pathLower.includes("/memory/") || pathLower.includes("/memories/")) return "memory_event";
|
|
151
|
+
return "unknown";
|
|
152
|
+
}
|
|
153
|
+
function buildSessionRecap(vaultPath, options = {}) {
|
|
154
|
+
const maxAge = options.maxAge ?? 24 * 60 * 60 * 1e3;
|
|
155
|
+
const limit = options.limit ?? 20;
|
|
156
|
+
const includeContent = options.includeContent ?? false;
|
|
157
|
+
const files = scanVaultFiles(vaultPath, { maxAge, limit });
|
|
158
|
+
if (files.length === 0) {
|
|
159
|
+
return {
|
|
160
|
+
xml: "",
|
|
161
|
+
fileCount: 0,
|
|
162
|
+
primitiveGroups: {},
|
|
163
|
+
timeRange: null
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const groups = {};
|
|
167
|
+
for (const file of files) {
|
|
168
|
+
const type = file.primitiveType;
|
|
169
|
+
if (!groups[type]) groups[type] = [];
|
|
170
|
+
groups[type].push(file);
|
|
171
|
+
}
|
|
172
|
+
const lines = ["<session-recap>"];
|
|
173
|
+
lines.push(`<summary>Found ${files.length} recent items across ${Object.keys(groups).length} categories</summary>`);
|
|
174
|
+
for (const [primitiveType, groupFiles] of Object.entries(groups)) {
|
|
175
|
+
lines.push(`<${primitiveType}-items count="${groupFiles.length}">`);
|
|
176
|
+
for (const file of groupFiles.slice(0, 5)) {
|
|
177
|
+
const title = file.frontmatter.title || file.frontmatter.summary || file.relativePath;
|
|
178
|
+
const status = file.frontmatter.status || "";
|
|
179
|
+
const modified = file.modifiedAt.toISOString().slice(0, 16).replace("T", " ");
|
|
180
|
+
lines.push(` <item path="${file.relativePath}" modified="${modified}"${status ? ` status="${status}"` : ""}>`);
|
|
181
|
+
lines.push(` <title>${escapeXml(String(title))}</title>`);
|
|
182
|
+
if (includeContent && file.content) {
|
|
183
|
+
const snippet = file.content.slice(0, 200).replace(/\n/g, " ").trim();
|
|
184
|
+
if (snippet) {
|
|
185
|
+
lines.push(` <snippet>${escapeXml(snippet)}</snippet>`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
lines.push(" </item>");
|
|
189
|
+
}
|
|
190
|
+
if (groupFiles.length > 5) {
|
|
191
|
+
lines.push(` <more count="${groupFiles.length - 5}" />`);
|
|
192
|
+
}
|
|
193
|
+
lines.push(`</${primitiveType}-items>`);
|
|
194
|
+
}
|
|
195
|
+
lines.push("</session-recap>");
|
|
196
|
+
const sortedByTime = [...files].sort((a, b) => a.modifiedAt.getTime() - b.modifiedAt.getTime());
|
|
197
|
+
const timeRange = {
|
|
198
|
+
oldest: sortedByTime[0].modifiedAt,
|
|
199
|
+
newest: sortedByTime[sortedByTime.length - 1].modifiedAt
|
|
200
|
+
};
|
|
201
|
+
const primitiveGroups = {};
|
|
202
|
+
for (const [type, groupFiles] of Object.entries(groups)) {
|
|
203
|
+
primitiveGroups[type] = groupFiles.length;
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
xml: lines.join("\n"),
|
|
207
|
+
fileCount: files.length,
|
|
208
|
+
primitiveGroups,
|
|
209
|
+
timeRange
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function buildPreferenceContext(vaultPath, options = {}) {
|
|
213
|
+
const maxAge = options.maxAge ?? 30 * 24 * 60 * 60 * 1e3;
|
|
214
|
+
const limit = options.limit ?? 50;
|
|
215
|
+
const files = scanVaultFiles(vaultPath, { maxAge, limit: limit * 2 });
|
|
216
|
+
const preferenceFiles = files.filter((file) => {
|
|
217
|
+
if (file.frontmatter.type === "preference") return true;
|
|
218
|
+
if (file.primitiveType === "memory_event" && file.frontmatter.type === "preference") return true;
|
|
219
|
+
const content = (file.content || "").toLowerCase();
|
|
220
|
+
if (/\b(prefer|like|love|hate|dislike|want|need|always|never)\b/.test(content)) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}).slice(0, limit);
|
|
225
|
+
if (preferenceFiles.length === 0) {
|
|
226
|
+
return {
|
|
227
|
+
xml: "",
|
|
228
|
+
preferenceCount: 0,
|
|
229
|
+
categories: []
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const categories = /* @__PURE__ */ new Set();
|
|
233
|
+
for (const file of preferenceFiles) {
|
|
234
|
+
if (file.frontmatter.category) {
|
|
235
|
+
categories.add(String(file.frontmatter.category));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const lines = ["<user-preferences>"];
|
|
239
|
+
for (const file of preferenceFiles) {
|
|
240
|
+
const summary = file.frontmatter.summary || file.frontmatter.title || extractPreferenceSummary(file.content);
|
|
241
|
+
if (!summary) continue;
|
|
242
|
+
const category = file.frontmatter.category || "general";
|
|
243
|
+
const sentiment = file.frontmatter.sentiment || inferSentiment(file.content);
|
|
244
|
+
lines.push(` <preference category="${escapeXml(String(category))}" sentiment="${sentiment}">`);
|
|
245
|
+
lines.push(` ${escapeXml(String(summary))}`);
|
|
246
|
+
lines.push(" </preference>");
|
|
247
|
+
}
|
|
248
|
+
lines.push("</user-preferences>");
|
|
249
|
+
return {
|
|
250
|
+
xml: lines.join("\n"),
|
|
251
|
+
preferenceCount: preferenceFiles.length,
|
|
252
|
+
categories: Array.from(categories)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function extractPreferenceSummary(content) {
|
|
256
|
+
if (!content) return "";
|
|
257
|
+
const sentences = content.split(/[.!?\n]+/).map((s) => s.trim()).filter((s) => s.length > 10);
|
|
258
|
+
for (const sentence of sentences) {
|
|
259
|
+
if (/\b(prefer|like|love|hate|dislike|want|need|always|never)\b/i.test(sentence)) {
|
|
260
|
+
return sentence.slice(0, 150);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return sentences[0]?.slice(0, 150) || "";
|
|
264
|
+
}
|
|
265
|
+
function inferSentiment(content) {
|
|
266
|
+
if (!content) return "neutral";
|
|
267
|
+
const lower = content.toLowerCase();
|
|
268
|
+
if (/\b(love|like|prefer|enjoy|want|need|always)\b/.test(lower)) return "positive";
|
|
269
|
+
if (/\b(hate|dislike|don't like|never|avoid)\b/.test(lower)) return "negative";
|
|
270
|
+
return "neutral";
|
|
271
|
+
}
|
|
272
|
+
function formatMemoriesForContext(results, collection) {
|
|
273
|
+
if (results.length === 0) return "";
|
|
274
|
+
const lines = results.map((r, i) => {
|
|
275
|
+
const file = (r.file || "").replace(`qmd://${collection}/`, "");
|
|
276
|
+
const snippet = (r.snippet || "").replace(/@@ .+? @@\s*\(.+?\)\n?/g, "").trim() || r.title || "";
|
|
277
|
+
return `${i + 1}. [${file}] ${snippet}`;
|
|
278
|
+
});
|
|
279
|
+
return `<relevant-memories>
|
|
280
|
+
These are recalled from long-term vault memory. Treat as historical context.
|
|
281
|
+
${lines.join("\n")}
|
|
282
|
+
</relevant-memories>`;
|
|
283
|
+
}
|
|
284
|
+
function formatSearchResults(results, collection) {
|
|
285
|
+
if (results.length === 0) return "No relevant memories found.";
|
|
286
|
+
return results.map((r, i) => {
|
|
287
|
+
const file = (r.file || "").replace(`qmd://${collection}/`, "");
|
|
288
|
+
const snippet = (r.snippet || "").replace(/@@ .+? @@\s*\(.+?\)\n?/g, "").trim() || r.title || "(no content)";
|
|
289
|
+
const score = ((r.score ?? 0) * 100).toFixed(0);
|
|
290
|
+
return `${i + 1}. [${file}] ${snippet} (${score}%)`;
|
|
291
|
+
}).join("\n");
|
|
292
|
+
}
|
|
293
|
+
function escapeXml(str) {
|
|
294
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
295
|
+
}
|
|
296
|
+
function buildFullContext(vaultPath, options = {}) {
|
|
297
|
+
const parts = [];
|
|
298
|
+
if (options.includeRecap !== false) {
|
|
299
|
+
const recap = buildSessionRecap(vaultPath, {
|
|
300
|
+
maxAge: options.recapMaxAge ?? 24 * 60 * 60 * 1e3,
|
|
301
|
+
limit: 15,
|
|
302
|
+
includeContent: true
|
|
303
|
+
});
|
|
304
|
+
if (recap.xml) {
|
|
305
|
+
parts.push(recap.xml);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (options.includePreferences !== false) {
|
|
309
|
+
const prefs = buildPreferenceContext(vaultPath, {
|
|
310
|
+
maxAge: options.preferenceMaxAge ?? 30 * 24 * 60 * 60 * 1e3,
|
|
311
|
+
limit: 20
|
|
312
|
+
});
|
|
313
|
+
if (prefs.xml) {
|
|
314
|
+
parts.push(prefs.xml);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return parts.join("\n\n");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export {
|
|
321
|
+
scanVaultFiles,
|
|
322
|
+
buildSessionRecap,
|
|
323
|
+
buildPreferenceContext,
|
|
324
|
+
formatMemoriesForContext,
|
|
325
|
+
formatSearchResults,
|
|
326
|
+
buildFullContext
|
|
327
|
+
};
|
|
@@ -1,14 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveClaudeOAuthToken
|
|
3
|
+
} from "./chunk-PAH27GSN.js";
|
|
4
|
+
|
|
1
5
|
// src/lib/llm-provider.ts
|
|
2
6
|
var DEFAULT_MODELS = {
|
|
3
|
-
anthropic: "claude-
|
|
7
|
+
anthropic: "claude-haiku-4-5",
|
|
4
8
|
openai: "gpt-4o-mini",
|
|
5
9
|
gemini: "gemini-2.0-flash"
|
|
6
10
|
};
|
|
7
|
-
function
|
|
11
|
+
async function resolveAnthropicAuth(fetchImpl) {
|
|
12
|
+
const oauthEnvToken = process.env.ANTHROPIC_OAUTH_TOKEN?.trim();
|
|
13
|
+
if (oauthEnvToken) {
|
|
14
|
+
return { token: oauthEnvToken, isOAuth: true };
|
|
15
|
+
}
|
|
16
|
+
const apiKey = process.env.ANTHROPIC_API_KEY?.trim();
|
|
17
|
+
if (apiKey) {
|
|
18
|
+
return { token: apiKey, isOAuth: false };
|
|
19
|
+
}
|
|
20
|
+
if (process.env.CLAWVAULT_CLAUDE_AUTH) {
|
|
21
|
+
const oauthToken = await resolveClaudeOAuthToken({ fetchImpl });
|
|
22
|
+
if (oauthToken) {
|
|
23
|
+
return { token: oauthToken, isOAuth: true };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
async function resolveLlmProvider(fetchImpl) {
|
|
8
29
|
if (process.env.CLAWVAULT_NO_LLM) {
|
|
9
30
|
return null;
|
|
10
31
|
}
|
|
11
|
-
|
|
32
|
+
const anthropicAuth = await resolveAnthropicAuth(fetchImpl);
|
|
33
|
+
if (anthropicAuth) {
|
|
12
34
|
return "anthropic";
|
|
13
35
|
}
|
|
14
36
|
if (process.env.OPENAI_API_KEY) {
|
|
@@ -20,7 +42,7 @@ function resolveLlmProvider() {
|
|
|
20
42
|
return null;
|
|
21
43
|
}
|
|
22
44
|
async function requestLlmCompletion(options) {
|
|
23
|
-
const provider = options.provider ?? resolveLlmProvider();
|
|
45
|
+
const provider = options.provider ?? await resolveLlmProvider(options.fetchImpl);
|
|
24
46
|
if (!provider) {
|
|
25
47
|
return "";
|
|
26
48
|
}
|
|
@@ -33,24 +55,43 @@ async function requestLlmCompletion(options) {
|
|
|
33
55
|
return callOpenAI(options, provider);
|
|
34
56
|
}
|
|
35
57
|
async function callAnthropic(options, provider) {
|
|
36
|
-
const
|
|
37
|
-
|
|
58
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
59
|
+
const auth = await resolveAnthropicAuth(fetchImpl);
|
|
60
|
+
if (!auth) {
|
|
38
61
|
return "";
|
|
39
62
|
}
|
|
40
|
-
const
|
|
63
|
+
const headers = auth.isOAuth ? {
|
|
64
|
+
"content-type": "application/json",
|
|
65
|
+
"authorization": `Bearer ${auth.token}`,
|
|
66
|
+
"anthropic-version": "2023-06-01",
|
|
67
|
+
"anthropic-beta": "claude-code-20250219,oauth-2025-04-20",
|
|
68
|
+
"x-app": "cli",
|
|
69
|
+
"user-agent": "claude-cli/1.0.0 (external, cli)"
|
|
70
|
+
} : {
|
|
71
|
+
"content-type": "application/json",
|
|
72
|
+
"x-api-key": auth.token,
|
|
73
|
+
"anthropic-version": "2023-06-01"
|
|
74
|
+
};
|
|
75
|
+
const systemMessages = [];
|
|
76
|
+
if (auth.isOAuth) {
|
|
77
|
+
systemMessages.push({ type: "text", text: "You are Claude Code, Anthropic's official CLI for Claude." });
|
|
78
|
+
}
|
|
79
|
+
if (options.systemPrompt?.trim()) {
|
|
80
|
+
systemMessages.push({ type: "text", text: options.systemPrompt.trim() });
|
|
81
|
+
}
|
|
82
|
+
const body = {
|
|
83
|
+
model: options.model ?? DEFAULT_MODELS[provider],
|
|
84
|
+
temperature: options.temperature ?? 0.1,
|
|
85
|
+
max_tokens: options.maxTokens ?? 1200,
|
|
86
|
+
messages: [{ role: "user", content: options.prompt }]
|
|
87
|
+
};
|
|
88
|
+
if (systemMessages.length > 0) {
|
|
89
|
+
body.system = systemMessages;
|
|
90
|
+
}
|
|
41
91
|
const response = await fetchImpl("https://api.anthropic.com/v1/messages", {
|
|
42
92
|
method: "POST",
|
|
43
|
-
headers
|
|
44
|
-
|
|
45
|
-
"x-api-key": apiKey,
|
|
46
|
-
"anthropic-version": "2023-06-01"
|
|
47
|
-
},
|
|
48
|
-
body: JSON.stringify({
|
|
49
|
-
model: options.model ?? DEFAULT_MODELS[provider],
|
|
50
|
-
temperature: options.temperature ?? 0.1,
|
|
51
|
-
max_tokens: options.maxTokens ?? 1200,
|
|
52
|
-
messages: [{ role: "user", content: options.prompt }]
|
|
53
|
-
})
|
|
93
|
+
headers,
|
|
94
|
+
body: JSON.stringify(body)
|
|
54
95
|
});
|
|
55
96
|
if (!response.ok) {
|
|
56
97
|
throw new Error(`Anthropic request failed (${response.status})`);
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
} from "./chunk-P5EPF6MB.js";
|
|
4
4
|
import {
|
|
5
5
|
observeActiveSessions
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LNJA2UGL.js";
|
|
7
7
|
import {
|
|
8
8
|
Observer
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3NSBOUT3.js";
|
|
10
10
|
import {
|
|
11
11
|
resolveVaultPath
|
|
12
12
|
} from "./chunk-MXSSG3QU.js";
|
|
@@ -291,7 +291,8 @@ async function observeCommand(options) {
|
|
|
291
291
|
threshold: options.threshold,
|
|
292
292
|
reflectThreshold: options.reflectThreshold,
|
|
293
293
|
model: options.model,
|
|
294
|
-
extractTasks: options.extractTasks
|
|
294
|
+
extractTasks: options.extractTasks,
|
|
295
|
+
maxSessions: options.maxSessions
|
|
295
296
|
});
|
|
296
297
|
const failedSessionCount = result.failedSessionCount ?? 0;
|
|
297
298
|
if (options.cron) {
|
|
@@ -379,7 +380,7 @@ async function observeCommand(options) {
|
|
|
379
380
|
await watchSessions(observer, watchPath);
|
|
380
381
|
}
|
|
381
382
|
function registerObserveCommand(program) {
|
|
382
|
-
program.command("observe").description("Observe session files and build observational memory").option("--watch <path>", "Watch session file or directory").option("--active", "Observe active OpenClaw sessions incrementally").option("--cron", "Run one-shot active observation for cron hooks").option("--agent <id>", "OpenClaw agent ID (default: OPENCLAW_AGENT_ID or clawdious)").option("--min-new <bytes>", "Override minimum new-content threshold in bytes").option("--sessions-dir <path>", "Override OpenClaw sessions directory").option("--dry-run", "Show active observation candidates without compressing").option("--threshold <n>", "Compression token threshold", "30000").option("--reflect-threshold <n>", "Reflection token threshold", "40000").option("--model <model>", "LLM model override").option("--extract-tasks", "Extract task-like observations into backlog", true).option("--no-extract-tasks", "Disable task extraction from observations").option("--compress <file>", "One-shot compression for a conversation file").option("--daemon", "Run in detached background mode").option("-v, --vault <path>", "Vault path").action(async (rawOptions) => {
|
|
383
|
+
program.command("observe").description("Observe session files and build observational memory").option("--watch <path>", "Watch session file or directory").option("--active", "Observe active OpenClaw sessions incrementally").option("--cron", "Run one-shot active observation for cron hooks").option("--agent <id>", "OpenClaw agent ID (default: OPENCLAW_AGENT_ID or clawdious)").option("--min-new <bytes>", "Override minimum new-content threshold in bytes").option("--sessions-dir <path>", "Override OpenClaw sessions directory").option("--dry-run", "Show active observation candidates without compressing").option("--max-sessions <n>", "Limit number of sessions to observe (recommended: 10)").option("--threshold <n>", "Compression token threshold", "30000").option("--reflect-threshold <n>", "Reflection token threshold", "40000").option("--model <model>", "LLM model override").option("--extract-tasks", "Extract task-like observations into backlog", true).option("--no-extract-tasks", "Disable task extraction from observations").option("--compress <file>", "One-shot compression for a conversation file").option("--daemon", "Run in detached background mode").option("-v, --vault <path>", "Vault path").action(async (rawOptions) => {
|
|
383
384
|
await observeCommand({
|
|
384
385
|
watch: rawOptions.watch,
|
|
385
386
|
active: rawOptions.active,
|
|
@@ -388,6 +389,7 @@ function registerObserveCommand(program) {
|
|
|
388
389
|
minNew: rawOptions.minNew ? parsePositiveInteger(rawOptions.minNew, "min-new") : void 0,
|
|
389
390
|
sessionsDir: rawOptions.sessionsDir,
|
|
390
391
|
dryRun: rawOptions.dryRun,
|
|
392
|
+
maxSessions: rawOptions.maxSessions ? parsePositiveInteger(rawOptions.maxSessions, "max-sessions") : void 0,
|
|
391
393
|
threshold: parsePositiveInteger(rawOptions.threshold, "threshold"),
|
|
392
394
|
reflectThreshold: parsePositiveInteger(rawOptions.reflectThreshold, "reflect-threshold"),
|
|
393
395
|
model: rawOptions.model,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerTailscaleCommands
|
|
3
|
+
} from "./chunk-THRJVD4L.js";
|
|
4
|
+
import {
|
|
5
|
+
registerObserveCommand
|
|
6
|
+
} from "./chunk-F2JEUD4J.js";
|
|
7
|
+
import {
|
|
8
|
+
registerReflectCommand
|
|
9
|
+
} from "./chunk-SJSFRIYS.js";
|
|
10
|
+
import {
|
|
11
|
+
registerEmbedCommand
|
|
12
|
+
} from "./chunk-7R7O6STJ.js";
|
|
13
|
+
import {
|
|
14
|
+
registerInjectCommand
|
|
15
|
+
} from "./chunk-U55BGUAU.js";
|
|
16
|
+
import {
|
|
17
|
+
resolveVaultPath
|
|
18
|
+
} from "./chunk-MXSSG3QU.js";
|
|
19
|
+
import {
|
|
20
|
+
registerContextCommand
|
|
21
|
+
} from "./chunk-ZVVFWOLW.js";
|
|
22
|
+
import {
|
|
23
|
+
reweave
|
|
24
|
+
} from "./chunk-K234IDRJ.js";
|
|
25
|
+
|
|
26
|
+
// src/commands/reweave.ts
|
|
27
|
+
async function reweaveCommand(options) {
|
|
28
|
+
const vaultPath = resolveVaultPath({ explicitPath: options.vaultPath });
|
|
29
|
+
const result = reweave({
|
|
30
|
+
vaultPath,
|
|
31
|
+
since: options.since,
|
|
32
|
+
dryRun: options.dryRun,
|
|
33
|
+
similarityThreshold: options.threshold
|
|
34
|
+
});
|
|
35
|
+
console.log(`Reweave: scanned ${result.filesScanned} files, checked ${result.observationsChecked} observations`);
|
|
36
|
+
if (result.supersessions.length === 0) {
|
|
37
|
+
console.log("No knowledge updates detected.");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
console.log(`
|
|
41
|
+
Found ${result.supersessions.length} supersession(s):`);
|
|
42
|
+
for (const s of result.supersessions) {
|
|
43
|
+
console.log(`
|
|
44
|
+
OLD [${s.oldObservation.date}] ${s.oldObservation.content.slice(0, 80)}`);
|
|
45
|
+
console.log(` NEW [${s.newObservation.date}] ${s.newObservation.content.slice(0, 80)}`);
|
|
46
|
+
console.log(` Reason: ${s.reason}`);
|
|
47
|
+
}
|
|
48
|
+
if (result.dryRun) {
|
|
49
|
+
console.log("\n(dry run \u2014 no files modified)");
|
|
50
|
+
} else {
|
|
51
|
+
console.log(`
|
|
52
|
+
${result.supersessions.length} observation(s) marked as superseded.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function registerReweaveCommand(program) {
|
|
56
|
+
program.command("reweave").description("Backward memory consolidation \u2014 detect and mark superseded observations").option("--since <date>", "Only check observations since this date (YYYY-MM-DD)").option("--dry-run", "Show what would be superseded without writing").option("--threshold <n>", "Entity similarity threshold (0-1, default 0.3)", "0.3").option("-v, --vault <path>", "Vault path").action(async (rawOptions) => {
|
|
57
|
+
await reweaveCommand({
|
|
58
|
+
vaultPath: rawOptions.vault,
|
|
59
|
+
since: rawOptions.since,
|
|
60
|
+
dryRun: rawOptions.dryRun,
|
|
61
|
+
threshold: parseFloat(rawOptions.threshold)
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/cli/index.ts
|
|
67
|
+
function registerCliCommands(program) {
|
|
68
|
+
registerContextCommand(program);
|
|
69
|
+
registerInjectCommand(program);
|
|
70
|
+
registerObserveCommand(program);
|
|
71
|
+
registerReflectCommand(program);
|
|
72
|
+
registerEmbedCommand(program);
|
|
73
|
+
registerReweaveCommand(program);
|
|
74
|
+
registerTailscaleCommands(program);
|
|
75
|
+
return program;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
reweaveCommand,
|
|
80
|
+
registerReweaveCommand,
|
|
81
|
+
registerCliCommands
|
|
82
|
+
};
|