clawmem 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +660 -0
- package/CLAUDE.md +660 -0
- package/LICENSE +21 -0
- package/README.md +993 -0
- package/SKILL.md +717 -0
- package/bin/clawmem +75 -0
- package/package.json +72 -0
- package/src/amem.ts +797 -0
- package/src/beads.ts +263 -0
- package/src/clawmem.ts +1849 -0
- package/src/collections.ts +405 -0
- package/src/config.ts +178 -0
- package/src/consolidation.ts +123 -0
- package/src/directory-context.ts +248 -0
- package/src/errors.ts +41 -0
- package/src/formatter.ts +427 -0
- package/src/graph-traversal.ts +247 -0
- package/src/hooks/context-surfacing.ts +317 -0
- package/src/hooks/curator-nudge.ts +89 -0
- package/src/hooks/decision-extractor.ts +639 -0
- package/src/hooks/feedback-loop.ts +214 -0
- package/src/hooks/handoff-generator.ts +345 -0
- package/src/hooks/postcompact-inject.ts +226 -0
- package/src/hooks/precompact-extract.ts +314 -0
- package/src/hooks/pretool-inject.ts +79 -0
- package/src/hooks/session-bootstrap.ts +324 -0
- package/src/hooks/staleness-check.ts +130 -0
- package/src/hooks.ts +367 -0
- package/src/indexer.ts +327 -0
- package/src/intent.ts +294 -0
- package/src/limits.ts +26 -0
- package/src/llm.ts +1175 -0
- package/src/mcp.ts +2138 -0
- package/src/memory.ts +336 -0
- package/src/mmr.ts +93 -0
- package/src/observer.ts +269 -0
- package/src/openclaw/engine.ts +283 -0
- package/src/openclaw/index.ts +221 -0
- package/src/openclaw/plugin.json +83 -0
- package/src/openclaw/shell.ts +207 -0
- package/src/openclaw/tools.ts +304 -0
- package/src/profile.ts +346 -0
- package/src/promptguard.ts +218 -0
- package/src/retrieval-gate.ts +106 -0
- package/src/search-utils.ts +127 -0
- package/src/server.ts +783 -0
- package/src/splitter.ts +325 -0
- package/src/store.ts +4062 -0
- package/src/validation.ts +67 -0
- package/src/watcher.ts +58 -0
package/src/beads.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beads Integration - Dolt-backed task dependency graph
|
|
3
|
+
*
|
|
4
|
+
* Queries Beads via `bd` CLI (v0.58.0+, Dolt backend) and syncs issues to ClawMem.
|
|
5
|
+
* Replaces legacy JSONL parser — Dolt is now source of truth.
|
|
6
|
+
*
|
|
7
|
+
* Reference: https://github.com/steveyegge/beads
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { execSync } from "node:child_process";
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Types (matches bd list --json output: IssueWithCounts)
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
export interface BeadsDependency {
|
|
19
|
+
issue_id: string;
|
|
20
|
+
depends_on_id: string;
|
|
21
|
+
type: string; // blocks, parent-child, waits-for, discovered-from, relates-to, etc.
|
|
22
|
+
created_at: string;
|
|
23
|
+
created_by?: string;
|
|
24
|
+
metadata?: string;
|
|
25
|
+
thread_id?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface BeadsIssue {
|
|
29
|
+
id: string;
|
|
30
|
+
title: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
notes?: string;
|
|
33
|
+
status: string; // open, in_progress, blocked, deferred, closed
|
|
34
|
+
priority: number; // 0-4
|
|
35
|
+
issue_type?: string; // task, bug, feature, epic, chore, decision, etc.
|
|
36
|
+
assignee?: string;
|
|
37
|
+
owner?: string;
|
|
38
|
+
created_at: string;
|
|
39
|
+
updated_at?: string;
|
|
40
|
+
closed_at?: string;
|
|
41
|
+
close_reason?: string;
|
|
42
|
+
external_ref?: string;
|
|
43
|
+
metadata?: Record<string, unknown>;
|
|
44
|
+
labels?: string[];
|
|
45
|
+
dependencies?: BeadsDependency[];
|
|
46
|
+
quality_score?: number;
|
|
47
|
+
// Computed counts from bd list --json
|
|
48
|
+
dependency_count?: number;
|
|
49
|
+
dependent_count?: number;
|
|
50
|
+
comment_count?: number;
|
|
51
|
+
parent?: string;
|
|
52
|
+
// Legacy compat fields (mapped from new schema)
|
|
53
|
+
type: string; // alias for issue_type
|
|
54
|
+
tags: string[]; // alias for labels
|
|
55
|
+
blocks: string[]; // extracted from dependencies
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// CLI Interface
|
|
60
|
+
// =============================================================================
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Find the `bd` binary. Checks PATH, common locations.
|
|
64
|
+
*/
|
|
65
|
+
function findBdBinary(): string | null {
|
|
66
|
+
// Check PATH first
|
|
67
|
+
try {
|
|
68
|
+
const path = execSync("which bd 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
69
|
+
if (path) return path;
|
|
70
|
+
} catch { /* not on PATH */ }
|
|
71
|
+
|
|
72
|
+
// Check common locations
|
|
73
|
+
const candidates = [
|
|
74
|
+
join(process.env.HOME || "", "go/bin/bd"),
|
|
75
|
+
"/usr/local/bin/bd",
|
|
76
|
+
];
|
|
77
|
+
for (const p of candidates) {
|
|
78
|
+
if (existsSync(p)) return p;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Run a bd CLI command and return stdout.
|
|
85
|
+
* Executes in the project directory containing .beads/.
|
|
86
|
+
*/
|
|
87
|
+
function runBd(projectDir: string, args: string[], timeoutMs = 10000): string | null {
|
|
88
|
+
const bd = findBdBinary();
|
|
89
|
+
if (!bd) {
|
|
90
|
+
console.warn("[beads] bd binary not found — cannot sync from Dolt backend");
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
return execSync(`${bd} ${args.join(" ")}`, {
|
|
96
|
+
cwd: projectDir,
|
|
97
|
+
encoding: "utf-8",
|
|
98
|
+
timeout: timeoutMs,
|
|
99
|
+
env: { ...process.env },
|
|
100
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
101
|
+
});
|
|
102
|
+
} catch (err: any) {
|
|
103
|
+
console.warn(`[beads] bd ${args[0]} failed: ${err.message?.slice(0, 200)}`);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// =============================================================================
|
|
109
|
+
// Query Functions
|
|
110
|
+
// =============================================================================
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Query all beads from Dolt via `bd list --json`.
|
|
114
|
+
* Returns parsed issues with labels and dependencies populated.
|
|
115
|
+
*/
|
|
116
|
+
export function queryBeadsList(projectDir: string): BeadsIssue[] {
|
|
117
|
+
const output = runBd(projectDir, ["list", "--json"]);
|
|
118
|
+
if (!output) return [];
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const raw = JSON.parse(output);
|
|
122
|
+
if (!Array.isArray(raw)) return [];
|
|
123
|
+
|
|
124
|
+
return raw.map((item: any) => normalizeBeadsIssue(item));
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.warn(`[beads] Failed to parse bd list output: ${err}`);
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Normalize a Beads JSON issue into our BeadsIssue type.
|
|
133
|
+
* Maps new Dolt schema fields to legacy compat fields.
|
|
134
|
+
*/
|
|
135
|
+
function normalizeBeadsIssue(raw: any): BeadsIssue {
|
|
136
|
+
const deps: BeadsDependency[] = raw.dependencies || [];
|
|
137
|
+
|
|
138
|
+
// Extract "blocks" relationships for legacy compat
|
|
139
|
+
const blocks = deps
|
|
140
|
+
.filter((d: BeadsDependency) => d.type === "blocks" && d.issue_id === raw.id)
|
|
141
|
+
.map((d: BeadsDependency) => d.depends_on_id);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
id: raw.id,
|
|
145
|
+
title: raw.title || "",
|
|
146
|
+
description: raw.description,
|
|
147
|
+
notes: raw.notes,
|
|
148
|
+
status: raw.status || "open",
|
|
149
|
+
priority: raw.priority ?? 2,
|
|
150
|
+
issue_type: raw.issue_type,
|
|
151
|
+
assignee: raw.assignee,
|
|
152
|
+
owner: raw.owner,
|
|
153
|
+
created_at: raw.created_at || new Date().toISOString(),
|
|
154
|
+
updated_at: raw.updated_at,
|
|
155
|
+
closed_at: raw.closed_at,
|
|
156
|
+
close_reason: raw.close_reason,
|
|
157
|
+
external_ref: raw.external_ref,
|
|
158
|
+
metadata: raw.metadata,
|
|
159
|
+
labels: raw.labels || [],
|
|
160
|
+
dependencies: deps,
|
|
161
|
+
quality_score: raw.quality_score,
|
|
162
|
+
dependency_count: raw.dependency_count,
|
|
163
|
+
dependent_count: raw.dependent_count,
|
|
164
|
+
comment_count: raw.comment_count,
|
|
165
|
+
parent: raw.parent,
|
|
166
|
+
// Legacy compat
|
|
167
|
+
type: raw.issue_type || "task",
|
|
168
|
+
tags: raw.labels || [],
|
|
169
|
+
blocks,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// =============================================================================
|
|
174
|
+
// Detection
|
|
175
|
+
// =============================================================================
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Detect if a directory contains a Beads project (Dolt-backed).
|
|
179
|
+
* Returns the project directory path if found, null otherwise.
|
|
180
|
+
*
|
|
181
|
+
* Checks for .beads/ directory (Dolt backend).
|
|
182
|
+
* Falls back to checking .beads/beads.jsonl for legacy installations.
|
|
183
|
+
*/
|
|
184
|
+
export function detectBeadsProject(cwd: string): string | null {
|
|
185
|
+
const beadsDir = join(cwd, ".beads");
|
|
186
|
+
if (existsSync(beadsDir)) return cwd;
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// =============================================================================
|
|
191
|
+
// Markdown Formatting
|
|
192
|
+
// =============================================================================
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Format a Beads issue as markdown for ClawMem indexing.
|
|
196
|
+
*/
|
|
197
|
+
export function formatBeadsIssueAsMarkdown(issue: BeadsIssue): string {
|
|
198
|
+
const lines = [
|
|
199
|
+
`# ${issue.title}`,
|
|
200
|
+
``,
|
|
201
|
+
`**ID**: ${issue.id}`,
|
|
202
|
+
`**Type**: ${issue.type || issue.issue_type || "task"}`,
|
|
203
|
+
`**Status**: ${issue.status}`,
|
|
204
|
+
`**Priority**: P${issue.priority}`,
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
if (issue.assignee) lines.push(`**Assignee**: ${issue.assignee}`);
|
|
208
|
+
if (issue.owner) lines.push(`**Owner**: ${issue.owner}`);
|
|
209
|
+
if (issue.parent) lines.push(`**Parent**: ${issue.parent}`);
|
|
210
|
+
if (issue.tags && issue.tags.length > 0) lines.push(`**Tags**: ${issue.tags.join(", ")}`);
|
|
211
|
+
if (issue.labels && issue.labels.length > 0 && !issue.tags?.length) {
|
|
212
|
+
lines.push(`**Labels**: ${issue.labels.join(", ")}`);
|
|
213
|
+
}
|
|
214
|
+
if (issue.blocks && issue.blocks.length > 0) lines.push(`**Blocks**: ${issue.blocks.join(", ")}`);
|
|
215
|
+
if (issue.external_ref) lines.push(`**External Ref**: ${issue.external_ref}`);
|
|
216
|
+
if (issue.quality_score != null) lines.push(`**Quality Score**: ${issue.quality_score}`);
|
|
217
|
+
|
|
218
|
+
if (issue.description) {
|
|
219
|
+
lines.push("", "## Description", "", issue.description);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (issue.notes) {
|
|
223
|
+
lines.push("", "## Notes", "", issue.notes);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Include dependency details
|
|
227
|
+
if (issue.dependencies && issue.dependencies.length > 0) {
|
|
228
|
+
lines.push("", "## Dependencies", "");
|
|
229
|
+
for (const dep of issue.dependencies) {
|
|
230
|
+
const dir = dep.issue_id === issue.id ? `→ ${dep.depends_on_id}` : `← ${dep.issue_id}`;
|
|
231
|
+
lines.push(`- ${dep.type}: ${dir}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return lines.join("\n");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// =============================================================================
|
|
239
|
+
// Legacy Compat (parseBeadsJsonl — kept for migration, not active use)
|
|
240
|
+
// =============================================================================
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @deprecated Use queryBeadsList() instead. Beads v0.58.0+ uses Dolt backend.
|
|
244
|
+
* Kept only for one-time migration of pre-Dolt installations.
|
|
245
|
+
*/
|
|
246
|
+
export function parseBeadsJsonl(path: string): BeadsIssue[] {
|
|
247
|
+
console.warn("[beads] parseBeadsJsonl is deprecated — Beads v0.58.0+ uses Dolt backend. Use queryBeadsList() instead.");
|
|
248
|
+
const { readFileSync } = require("node:fs");
|
|
249
|
+
const content = readFileSync(path, "utf-8");
|
|
250
|
+
const lines = content.trim().split("\n");
|
|
251
|
+
|
|
252
|
+
return lines
|
|
253
|
+
.filter((line: string) => line.trim())
|
|
254
|
+
.map((line: string) => {
|
|
255
|
+
try {
|
|
256
|
+
const raw = JSON.parse(line);
|
|
257
|
+
return normalizeBeadsIssue(raw);
|
|
258
|
+
} catch {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
.filter((issue: BeadsIssue | null): issue is BeadsIssue => issue !== null);
|
|
263
|
+
}
|