@basicmemory/openclaw-basic-memory 0.2.4 → 0.23.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/README.md +11 -1
- package/bm-client.ts +55 -21
- package/commands/cli.ts +0 -1
- package/commands/skills.ts +51 -2
- package/config.ts +0 -17
- package/context-engine/basic-memory-context-engine.ts +25 -74
- package/dist/bm-client.d.ts +2 -0
- package/dist/bm-client.js +42 -32
- package/dist/commands/cli.js +0 -1
- package/dist/commands/skills.js +41 -2
- package/dist/config.d.ts +0 -5
- package/dist/config.js +0 -10
- package/dist/context-engine/basic-memory-context-engine.d.ts +13 -73
- package/dist/index.d.ts +2 -1
- package/dist/index.js +21 -11
- package/dist/tools/list-memory-projects.js +2 -1
- package/index.ts +23 -12
- package/openclaw.plugin.json +2 -15
- package/package.json +5 -4
- package/scripts/fetch-skills.ts +62 -67
- package/scripts/setup-bm.sh +27 -10
- package/skills/manifest.json +25 -0
- package/skills/memory-capture/SKILL.md +275 -0
- package/skills/memory-ci-capture/SKILL.md +56 -0
- package/skills/memory-continue/SKILL.md +148 -0
- package/skills/memory-curate/SKILL.md +243 -0
- package/skills/memory-literary-analysis/SKILL.md +15 -12
- package/skills/memory-notes/SKILL.md +22 -6
- package/skills/memory-onboarding/SKILL.md +142 -0
- package/skills/memory-onboarding/evals/evals.json +29 -0
- package/skills/memory-onboarding/references/assistant-setup.md +64 -0
- package/skills/memory-onboarding/references/conventions.md +118 -0
- package/skills/memory-onboarding/references/domain-playbooks.md +159 -0
- package/skills/memory-onboarding/references/schema-guide.md +136 -0
- package/skills/memory-schema/SKILL.md +7 -5
- package/skills/memory-tasks/SKILL.md +1 -1
- package/tools/list-memory-projects.ts +2 -1
package/dist/bm-client.js
CHANGED
|
@@ -54,7 +54,7 @@ function isRecoverableConnectionError(err) {
|
|
|
54
54
|
msg.includes("failed to start bm mcp stdio") ||
|
|
55
55
|
msg.includes("client is closed"));
|
|
56
56
|
}
|
|
57
|
-
function
|
|
57
|
+
function isNoteNotFoundError(err) {
|
|
58
58
|
const msg = getErrorMessage(err).toLowerCase();
|
|
59
59
|
return (msg.includes("entity not found") ||
|
|
60
60
|
msg.includes("note not found") ||
|
|
@@ -65,6 +65,16 @@ function _isNoteNotFoundError(err) {
|
|
|
65
65
|
function asString(value) {
|
|
66
66
|
return typeof value === "string" ? value : null;
|
|
67
67
|
}
|
|
68
|
+
function projectMatchesWorkspace(project, workspace) {
|
|
69
|
+
const requested = workspace.trim().toLowerCase();
|
|
70
|
+
if (!requested)
|
|
71
|
+
return true;
|
|
72
|
+
return [
|
|
73
|
+
project.workspace_name,
|
|
74
|
+
project.workspace_slug,
|
|
75
|
+
project.workspace_tenant_id,
|
|
76
|
+
].some((value) => typeof value === "string" && value.toLowerCase() === requested);
|
|
77
|
+
}
|
|
68
78
|
export class BmClient {
|
|
69
79
|
bmPath;
|
|
70
80
|
project;
|
|
@@ -259,6 +269,9 @@ export class BmClient {
|
|
|
259
269
|
}
|
|
260
270
|
return structuredPayload;
|
|
261
271
|
}
|
|
272
|
+
routedProject(project) {
|
|
273
|
+
return project ?? this.project;
|
|
274
|
+
}
|
|
262
275
|
async ensureProject(projectPath) {
|
|
263
276
|
const payload = await this.callTool("create_memory_project", {
|
|
264
277
|
project_name: this.project,
|
|
@@ -280,12 +293,15 @@ export class BmClient {
|
|
|
280
293
|
throw new Error("invalid list_workspaces response");
|
|
281
294
|
}
|
|
282
295
|
async listProjects(workspace) {
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const payload = await this.callTool("list_memory_projects", args);
|
|
296
|
+
const payload = await this.callTool("list_memory_projects", {
|
|
297
|
+
output_format: "json",
|
|
298
|
+
});
|
|
287
299
|
if (isRecord(payload) && Array.isArray(payload.projects)) {
|
|
288
|
-
|
|
300
|
+
const projects = payload.projects;
|
|
301
|
+
if (workspace) {
|
|
302
|
+
return projects.filter((project) => projectMatchesWorkspace(project, workspace));
|
|
303
|
+
}
|
|
304
|
+
return projects;
|
|
289
305
|
}
|
|
290
306
|
throw new Error("invalid list_memory_projects response");
|
|
291
307
|
}
|
|
@@ -294,11 +310,10 @@ export class BmClient {
|
|
|
294
310
|
page: 1,
|
|
295
311
|
page_size: limit,
|
|
296
312
|
output_format: "json",
|
|
313
|
+
project: this.routedProject(project),
|
|
297
314
|
};
|
|
298
315
|
if (query)
|
|
299
316
|
args.query = query;
|
|
300
|
-
if (project)
|
|
301
|
-
args.project = project;
|
|
302
317
|
if (metadata?.filters)
|
|
303
318
|
args.metadata_filters = metadata.filters;
|
|
304
319
|
if (metadata?.tags)
|
|
@@ -320,9 +335,8 @@ export class BmClient {
|
|
|
320
335
|
identifier,
|
|
321
336
|
include_frontmatter: options.includeFrontmatter === true,
|
|
322
337
|
output_format: "json",
|
|
338
|
+
project: this.routedProject(project),
|
|
323
339
|
};
|
|
324
|
-
if (project)
|
|
325
|
-
args.project = project;
|
|
326
340
|
const payload = await this.callTool("read_note", args);
|
|
327
341
|
if (!isRecord(payload)) {
|
|
328
342
|
throw new Error("invalid read_note response");
|
|
@@ -348,9 +362,8 @@ export class BmClient {
|
|
|
348
362
|
content,
|
|
349
363
|
directory: folder,
|
|
350
364
|
output_format: "json",
|
|
365
|
+
project: this.routedProject(project),
|
|
351
366
|
};
|
|
352
|
-
if (project)
|
|
353
|
-
args.project = project;
|
|
354
367
|
if (overwrite !== undefined)
|
|
355
368
|
args.overwrite = overwrite;
|
|
356
369
|
const payload = await this.callTool("write_note", args);
|
|
@@ -382,9 +395,8 @@ export class BmClient {
|
|
|
382
395
|
url,
|
|
383
396
|
depth,
|
|
384
397
|
output_format: "json",
|
|
398
|
+
project: this.routedProject(project),
|
|
385
399
|
};
|
|
386
|
-
if (project)
|
|
387
|
-
args.project = project;
|
|
388
400
|
const payload = await this.callTool("build_context", args);
|
|
389
401
|
if (!isRecord(payload) || !Array.isArray(payload.results)) {
|
|
390
402
|
throw new Error("invalid build_context response");
|
|
@@ -395,9 +407,8 @@ export class BmClient {
|
|
|
395
407
|
const args = {
|
|
396
408
|
timeframe,
|
|
397
409
|
output_format: "json",
|
|
410
|
+
project: this.routedProject(project),
|
|
398
411
|
};
|
|
399
|
-
if (project)
|
|
400
|
-
args.project = project;
|
|
401
412
|
const payload = await this.callTool("recent_activity", args);
|
|
402
413
|
if (Array.isArray(payload)) {
|
|
403
414
|
return payload;
|
|
@@ -410,6 +421,7 @@ export class BmClient {
|
|
|
410
421
|
operation,
|
|
411
422
|
content,
|
|
412
423
|
output_format: "json",
|
|
424
|
+
project: this.routedProject(project),
|
|
413
425
|
};
|
|
414
426
|
if (options.find_text)
|
|
415
427
|
args.find_text = options.find_text;
|
|
@@ -417,8 +429,6 @@ export class BmClient {
|
|
|
417
429
|
args.section = options.section;
|
|
418
430
|
if (options.expected_replacements != null)
|
|
419
431
|
args.expected_replacements = options.expected_replacements;
|
|
420
|
-
if (project)
|
|
421
|
-
args.project = project;
|
|
422
432
|
const payload = await this.callTool("edit_note", args);
|
|
423
433
|
if (!isRecord(payload)) {
|
|
424
434
|
throw new Error("invalid edit_note response");
|
|
@@ -441,9 +451,8 @@ export class BmClient {
|
|
|
441
451
|
const args = {
|
|
442
452
|
identifier,
|
|
443
453
|
output_format: "json",
|
|
454
|
+
project: this.routedProject(project),
|
|
444
455
|
};
|
|
445
|
-
if (project)
|
|
446
|
-
args.project = project;
|
|
447
456
|
const payload = await this.callTool("delete_note", args);
|
|
448
457
|
if (!isRecord(payload)) {
|
|
449
458
|
throw new Error("invalid delete_note response");
|
|
@@ -462,9 +471,8 @@ export class BmClient {
|
|
|
462
471
|
identifier,
|
|
463
472
|
destination_folder: newFolder,
|
|
464
473
|
output_format: "json",
|
|
474
|
+
project: this.routedProject(project),
|
|
465
475
|
};
|
|
466
|
-
if (project)
|
|
467
|
-
args.project = project;
|
|
468
476
|
const payload = await this.callTool("move_note", args);
|
|
469
477
|
if (!isRecord(payload)) {
|
|
470
478
|
throw new Error("invalid move_note response");
|
|
@@ -481,13 +489,14 @@ export class BmClient {
|
|
|
481
489
|
};
|
|
482
490
|
}
|
|
483
491
|
async schemaValidate(noteType, identifier, project) {
|
|
484
|
-
const args = {
|
|
492
|
+
const args = {
|
|
493
|
+
output_format: "json",
|
|
494
|
+
project: this.routedProject(project),
|
|
495
|
+
};
|
|
485
496
|
if (noteType)
|
|
486
497
|
args.note_type = noteType;
|
|
487
498
|
if (identifier)
|
|
488
499
|
args.identifier = identifier;
|
|
489
|
-
if (project)
|
|
490
|
-
args.project = project;
|
|
491
500
|
const payload = await this.callTool("schema_validate", args);
|
|
492
501
|
if (!isRecord(payload)) {
|
|
493
502
|
throw new Error("invalid schema_validate response");
|
|
@@ -499,9 +508,8 @@ export class BmClient {
|
|
|
499
508
|
note_type: noteType,
|
|
500
509
|
threshold,
|
|
501
510
|
output_format: "json",
|
|
511
|
+
project: this.routedProject(project),
|
|
502
512
|
};
|
|
503
|
-
if (project)
|
|
504
|
-
args.project = project;
|
|
505
513
|
const payload = await this.callTool("schema_infer", args);
|
|
506
514
|
if (!isRecord(payload)) {
|
|
507
515
|
throw new Error("invalid schema_infer response");
|
|
@@ -512,9 +520,8 @@ export class BmClient {
|
|
|
512
520
|
const args = {
|
|
513
521
|
note_type: noteType,
|
|
514
522
|
output_format: "json",
|
|
523
|
+
project: this.routedProject(project),
|
|
515
524
|
};
|
|
516
|
-
if (project)
|
|
517
|
-
args.project = project;
|
|
518
525
|
const payload = await this.callTool("schema_diff", args);
|
|
519
526
|
if (!isRecord(payload)) {
|
|
520
527
|
throw new Error("invalid schema_diff response");
|
|
@@ -537,14 +544,17 @@ export class BmClient {
|
|
|
537
544
|
"",
|
|
538
545
|
"---",
|
|
539
546
|
].join("\n");
|
|
540
|
-
// Try append first — if it fails for ANY reason, fall through to create
|
|
541
547
|
try {
|
|
542
548
|
await this.editNote(title, "append", entry);
|
|
543
549
|
log.debug(`appended conversation to: ${title}`);
|
|
544
550
|
return;
|
|
545
551
|
}
|
|
546
552
|
catch (err) {
|
|
547
|
-
|
|
553
|
+
if (!isNoteNotFoundError(err)) {
|
|
554
|
+
log.error(`conversation append failed: ${getErrorMessage(err)}`, err);
|
|
555
|
+
throw err;
|
|
556
|
+
}
|
|
557
|
+
log.debug(`conversation note missing, will create: ${getErrorMessage(err)}`);
|
|
548
558
|
}
|
|
549
559
|
// Create the note with frontmatter and first entry
|
|
550
560
|
const content = [
|
|
@@ -559,7 +569,7 @@ export class BmClient {
|
|
|
559
569
|
entry,
|
|
560
570
|
].join("\n");
|
|
561
571
|
try {
|
|
562
|
-
await this.writeNote(title, content, "conversations"
|
|
572
|
+
await this.writeNote(title, content, "conversations");
|
|
563
573
|
log.debug(`created conversation note: ${title}`);
|
|
564
574
|
}
|
|
565
575
|
catch (err) {
|
package/dist/commands/cli.js
CHANGED
|
@@ -110,7 +110,6 @@ export function registerCli(api, client, cfg) {
|
|
|
110
110
|
console.log(`Memory dir: ${cfg.memoryDir}`);
|
|
111
111
|
console.log(`Memory file: ${cfg.memoryFile}`);
|
|
112
112
|
console.log(`Auto-capture: ${cfg.autoCapture}`);
|
|
113
|
-
console.log(`Cloud: ${cfg.cloud ? cfg.cloud.url : "disabled"}`);
|
|
114
113
|
console.log(`Debug: ${cfg.debug}`);
|
|
115
114
|
});
|
|
116
115
|
}, { commands: ["basic-memory"] });
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -24,12 +24,51 @@ function loadManifest(skillsDir) {
|
|
|
24
24
|
function loadSkill(skillsDir, dir) {
|
|
25
25
|
return readFileSync(resolve(skillsDir, dir, "SKILL.md"), "utf-8");
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* List a skill's bundled resource files (references/, assets/, ...) so the
|
|
29
|
+
* command can tell the assistant where they live on disk. SKILL.md workflows
|
|
30
|
+
* reference these by relative path; without the mapping, bundled commands
|
|
31
|
+
* would direct the assistant to files it was never given. evals/ is excluded
|
|
32
|
+
* as test fixtures.
|
|
33
|
+
*/
|
|
34
|
+
function listResourceFiles(skillsDir, dir) {
|
|
35
|
+
const root = resolve(skillsDir, dir);
|
|
36
|
+
const files = [];
|
|
37
|
+
const walk = (rel) => {
|
|
38
|
+
for (const entry of readdirSync(resolve(root, rel), {
|
|
39
|
+
withFileTypes: true,
|
|
40
|
+
})) {
|
|
41
|
+
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
if (relPath !== "evals")
|
|
44
|
+
walk(relPath);
|
|
45
|
+
}
|
|
46
|
+
else if (relPath !== "SKILL.md") {
|
|
47
|
+
files.push(relPath);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
walk("");
|
|
52
|
+
return files.sort();
|
|
53
|
+
}
|
|
54
|
+
function resourceSection(skillsDir, dir, files) {
|
|
55
|
+
if (files.length === 0)
|
|
56
|
+
return "";
|
|
57
|
+
const lines = files
|
|
58
|
+
.map((f) => `- \`${f}\` → ${resolve(skillsDir, dir, f)}`)
|
|
59
|
+
.join("\n");
|
|
60
|
+
return ("\n\n## Bundled resource files\n\n" +
|
|
61
|
+
"This skill references companion files by relative path. They are installed at:\n\n" +
|
|
62
|
+
`${lines}\n\n` +
|
|
63
|
+
"When the workflow directs you to read one of these files, read it from the absolute path listed above.");
|
|
64
|
+
}
|
|
27
65
|
export function registerSkillCommands(api) {
|
|
28
66
|
const skillsDir = resolveSkillsDir(api);
|
|
29
67
|
const manifest = loadManifest(skillsDir);
|
|
30
68
|
for (const entry of manifest) {
|
|
31
69
|
const commandName = entry.dir.replace(/^memory-/, "");
|
|
32
|
-
const content = loadSkill(skillsDir, entry.dir)
|
|
70
|
+
const content = loadSkill(skillsDir, entry.dir) +
|
|
71
|
+
resourceSection(skillsDir, entry.dir, listResourceFiles(skillsDir, entry.dir));
|
|
33
72
|
api.registerCommand({
|
|
34
73
|
name: commandName,
|
|
35
74
|
description: entry.description,
|
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
export type CloudConfig = {
|
|
2
|
-
url: string;
|
|
3
|
-
api_key: string;
|
|
4
|
-
};
|
|
5
1
|
export type BasicMemoryConfig = {
|
|
6
2
|
project: string;
|
|
7
3
|
bmPath: string;
|
|
@@ -13,7 +9,6 @@ export type BasicMemoryConfig = {
|
|
|
13
9
|
autoRecall: boolean;
|
|
14
10
|
recallPrompt: string;
|
|
15
11
|
debug: boolean;
|
|
16
|
-
cloud?: CloudConfig;
|
|
17
12
|
};
|
|
18
13
|
export declare function resolveProjectPath(projectPath: string, workspaceDir: string): string;
|
|
19
14
|
export declare function parseConfig(raw: unknown): BasicMemoryConfig;
|
package/dist/config.js
CHANGED
|
@@ -16,7 +16,6 @@ const ALLOWED_KEYS = [
|
|
|
16
16
|
"recallPrompt",
|
|
17
17
|
"recall_prompt",
|
|
18
18
|
"debug",
|
|
19
|
-
"cloud",
|
|
20
19
|
];
|
|
21
20
|
function assertAllowedKeys(value, allowed, label) {
|
|
22
21
|
const unknown = Object.keys(value).filter((k) => !allowed.includes(k));
|
|
@@ -62,14 +61,6 @@ export function parseConfig(raw) {
|
|
|
62
61
|
cfg.memory_file.length > 0
|
|
63
62
|
? cfg.memory_file
|
|
64
63
|
: "MEMORY.md";
|
|
65
|
-
let cloud;
|
|
66
|
-
if (cfg.cloud && typeof cfg.cloud === "object" && !Array.isArray(cfg.cloud)) {
|
|
67
|
-
const c = cfg.cloud;
|
|
68
|
-
assertAllowedKeys(c, ["url", "api_key"], "basic-memory cloud config");
|
|
69
|
-
if (typeof c.url === "string" && typeof c.api_key === "string") {
|
|
70
|
-
cloud = { url: c.url, api_key: c.api_key };
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
64
|
return {
|
|
74
65
|
project: typeof cfg.project === "string" && cfg.project.length > 0
|
|
75
66
|
? cfg.project
|
|
@@ -101,7 +92,6 @@ export function parseConfig(raw) {
|
|
|
101
92
|
? cfg.recall_prompt
|
|
102
93
|
: "Check for active tasks and recent activity. Summarize anything relevant to the current session.",
|
|
103
94
|
debug: typeof cfg.debug === "boolean" ? cfg.debug : false,
|
|
104
|
-
cloud,
|
|
105
95
|
};
|
|
106
96
|
}
|
|
107
97
|
export const basicMemoryConfigSchema = {
|
|
@@ -1,39 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AssembleResult, BootstrapResult, CompactResult, ContextEngine, SubagentSpawnPreparation } from "openclaw/plugin-sdk";
|
|
2
2
|
import type { BmClient } from "../bm-client.ts";
|
|
3
3
|
import type { BasicMemoryConfig } from "../config.ts";
|
|
4
4
|
export declare const MAX_ASSEMBLE_RECALL_CHARS = 1200;
|
|
5
|
-
type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
bootstrapped: boolean;
|
|
12
|
-
importedMessages?: number;
|
|
13
|
-
reason?: string;
|
|
14
|
-
};
|
|
15
|
-
type CompactResult = {
|
|
16
|
-
ok: boolean;
|
|
17
|
-
compacted: boolean;
|
|
18
|
-
reason?: string;
|
|
19
|
-
result?: {
|
|
20
|
-
summary?: string;
|
|
21
|
-
firstKeptEntryId?: string;
|
|
22
|
-
tokensBefore: number;
|
|
23
|
-
tokensAfter?: number;
|
|
24
|
-
details?: unknown;
|
|
25
|
-
sessionId?: string;
|
|
26
|
-
sessionFile?: string;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
interface ContextEngine {
|
|
30
|
-
readonly info: {
|
|
31
|
-
id: string;
|
|
32
|
-
name: string;
|
|
33
|
-
version?: string;
|
|
34
|
-
ownsCompaction?: boolean;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
5
|
+
type BootstrapParams = Parameters<NonNullable<ContextEngine["bootstrap"]>>[0];
|
|
6
|
+
type AssembleParams = Parameters<ContextEngine["assemble"]>[0];
|
|
7
|
+
type AfterTurnParams = Parameters<NonNullable<ContextEngine["afterTurn"]>>[0];
|
|
8
|
+
type CompactParams = Parameters<ContextEngine["compact"]>[0];
|
|
9
|
+
type PrepareSubagentSpawnParams = Parameters<NonNullable<ContextEngine["prepareSubagentSpawn"]>>[0];
|
|
10
|
+
type OnSubagentEndedParams = Parameters<NonNullable<ContextEngine["onSubagentEnded"]>>[0];
|
|
37
11
|
export declare class BasicMemoryContextEngine implements ContextEngine {
|
|
38
12
|
private readonly client;
|
|
39
13
|
private readonly cfg;
|
|
@@ -46,49 +20,15 @@ export declare class BasicMemoryContextEngine implements ContextEngine {
|
|
|
46
20
|
private readonly sessionState;
|
|
47
21
|
private readonly subagentState;
|
|
48
22
|
constructor(client: BmClient, cfg: BasicMemoryConfig);
|
|
49
|
-
bootstrap(params:
|
|
50
|
-
sessionId: string;
|
|
51
|
-
sessionFile: string;
|
|
52
|
-
}): Promise<BootstrapResult>;
|
|
23
|
+
bootstrap(params: BootstrapParams): Promise<BootstrapResult>;
|
|
53
24
|
ingest(): Promise<{
|
|
54
25
|
ingested: boolean;
|
|
55
26
|
}>;
|
|
56
|
-
assemble(params:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
afterTurn(params: {
|
|
62
|
-
sessionId: string;
|
|
63
|
-
sessionFile: string;
|
|
64
|
-
messages: AgentMessage[];
|
|
65
|
-
prePromptMessageCount: number;
|
|
66
|
-
autoCompactionSummary?: string;
|
|
67
|
-
isHeartbeat?: boolean;
|
|
68
|
-
tokenBudget?: number;
|
|
69
|
-
runtimeContext?: Record<string, unknown>;
|
|
70
|
-
}): Promise<void>;
|
|
71
|
-
compact(params: {
|
|
72
|
-
sessionId: string;
|
|
73
|
-
sessionFile: string;
|
|
74
|
-
tokenBudget?: number;
|
|
75
|
-
force?: boolean;
|
|
76
|
-
currentTokenCount?: number;
|
|
77
|
-
compactionTarget?: "budget" | "threshold";
|
|
78
|
-
customInstructions?: string;
|
|
79
|
-
runtimeContext?: Record<string, unknown>;
|
|
80
|
-
}): Promise<CompactResult>;
|
|
81
|
-
prepareSubagentSpawn(params: {
|
|
82
|
-
parentSessionKey: string;
|
|
83
|
-
childSessionKey: string;
|
|
84
|
-
ttlMs?: number;
|
|
85
|
-
}): Promise<{
|
|
86
|
-
rollback: () => Promise<void>;
|
|
87
|
-
} | undefined>;
|
|
88
|
-
onSubagentEnded(params: {
|
|
89
|
-
childSessionKey: string;
|
|
90
|
-
reason: "deleted" | "completed" | "swept" | "released";
|
|
91
|
-
}): Promise<void>;
|
|
27
|
+
assemble(params: AssembleParams): Promise<AssembleResult>;
|
|
28
|
+
afterTurn(params: AfterTurnParams): Promise<void>;
|
|
29
|
+
compact(params: CompactParams): Promise<CompactResult>;
|
|
30
|
+
prepareSubagentSpawn(params: PrepareSubagentSpawnParams): Promise<SubagentSpawnPreparation | undefined>;
|
|
31
|
+
onSubagentEnded(params: OnSubagentEndedParams): Promise<void>;
|
|
92
32
|
dispose(): Promise<void>;
|
|
93
33
|
}
|
|
94
34
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
export declare function isCommandAvailable(command: string): boolean;
|
|
1
2
|
declare const _default: {
|
|
2
3
|
id: string;
|
|
3
4
|
name: string;
|
|
4
5
|
description: string;
|
|
5
|
-
configSchema: import("openclaw/plugin-sdk
|
|
6
|
+
configSchema: import("openclaw/plugin-sdk").OpenClawPluginConfigSchema;
|
|
6
7
|
register: NonNullable<import("openclaw/plugin-sdk/plugin-entry").OpenClawPluginDefinition["register"]>;
|
|
7
8
|
} & Pick<import("openclaw/plugin-sdk/plugin-entry").OpenClawPluginDefinition, "kind" | "reload" | "nodeHostCommands" | "securityAuditCollectors">;
|
|
8
9
|
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
3
3
|
import { BmClient } from "./bm-client.js";
|
|
4
4
|
import { registerCli } from "./commands/cli.js";
|
|
@@ -22,7 +22,15 @@ import { registerSchemaInferTool } from "./tools/schema-infer.js";
|
|
|
22
22
|
import { registerSchemaValidateTool } from "./tools/schema-validate.js";
|
|
23
23
|
import { registerSearchTool } from "./tools/search-notes.js";
|
|
24
24
|
import { registerWriteTool } from "./tools/write-note.js";
|
|
25
|
-
|
|
25
|
+
export function isCommandAvailable(command) {
|
|
26
|
+
try {
|
|
27
|
+
execFileSync(command, ["--version"], { stdio: "ignore" });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
26
34
|
export default definePluginEntry({
|
|
27
35
|
id: "openclaw-basic-memory",
|
|
28
36
|
name: "Basic Memory",
|
|
@@ -62,22 +70,24 @@ export default definePluginEntry({
|
|
|
62
70
|
log.info("starting...");
|
|
63
71
|
// Auto-install bm CLI if not found
|
|
64
72
|
const bmBin = cfg.bmPath || "bm";
|
|
65
|
-
|
|
66
|
-
execSync(`command -v ${bmBin}`, { stdio: "ignore" });
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
73
|
+
if (!isCommandAvailable(bmBin)) {
|
|
69
74
|
log.info("bm CLI not found on PATH — attempting auto-install...");
|
|
70
75
|
try {
|
|
71
|
-
|
|
76
|
+
if (!isCommandAvailable("uv")) {
|
|
77
|
+
throw new Error("uv not found");
|
|
78
|
+
}
|
|
72
79
|
log.info("installing basic-memory via uv (this may take a minute)...");
|
|
73
|
-
const result =
|
|
80
|
+
const result = execFileSync("uv", ["tool", "install", "basic-memory", "--force"], {
|
|
81
|
+
encoding: "utf-8",
|
|
82
|
+
timeout: 120_000,
|
|
83
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
84
|
+
});
|
|
74
85
|
log.info(`basic-memory installed: ${result.trim().split("\n").pop()}`);
|
|
75
86
|
// Verify it worked
|
|
76
|
-
|
|
77
|
-
execSync(`command -v ${bmBin}`, { stdio: "ignore" });
|
|
87
|
+
if (isCommandAvailable(bmBin)) {
|
|
78
88
|
log.info("bm CLI now available on PATH");
|
|
79
89
|
}
|
|
80
|
-
|
|
90
|
+
else {
|
|
81
91
|
log.error("bm installed but not found on PATH. You may need to add uv's bin directory to your PATH (typically ~/.local/bin).");
|
|
82
92
|
}
|
|
83
93
|
}
|
|
@@ -8,6 +8,7 @@ function normalizeProject(project) {
|
|
|
8
8
|
is_private: project.is_private === true,
|
|
9
9
|
is_default: project.is_default === true || project.isDefault === true,
|
|
10
10
|
workspace_name: project.workspace_name ?? null,
|
|
11
|
+
workspace_slug: project.workspace_slug ?? null,
|
|
11
12
|
workspace_type: project.workspace_type ?? null,
|
|
12
13
|
workspace_tenant_id: project.workspace_tenant_id ?? null,
|
|
13
14
|
};
|
|
@@ -19,7 +20,7 @@ export function registerProjectListTool(api, client) {
|
|
|
19
20
|
description: "List all Basic Memory projects accessible to this agent",
|
|
20
21
|
parameters: Type.Object({
|
|
21
22
|
workspace: Type.Optional(Type.String({
|
|
22
|
-
description: "Filter by workspace name or tenant_id",
|
|
23
|
+
description: "Filter by workspace name, slug, or tenant_id",
|
|
23
24
|
})),
|
|
24
25
|
}),
|
|
25
26
|
async execute(_toolCallId, params) {
|
package/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "node:child_process"
|
|
2
2
|
|
|
3
3
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"
|
|
4
4
|
import { BmClient } from "./bm-client.ts"
|
|
@@ -31,7 +31,14 @@ import { registerSchemaValidateTool } from "./tools/schema-validate.ts"
|
|
|
31
31
|
import { registerSearchTool } from "./tools/search-notes.ts"
|
|
32
32
|
import { registerWriteTool } from "./tools/write-note.ts"
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
export function isCommandAvailable(command: string): boolean {
|
|
35
|
+
try {
|
|
36
|
+
execFileSync(command, ["--version"], { stdio: "ignore" })
|
|
37
|
+
return true
|
|
38
|
+
} catch {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
}
|
|
35
42
|
|
|
36
43
|
export default definePluginEntry({
|
|
37
44
|
id: "openclaw-basic-memory",
|
|
@@ -87,27 +94,31 @@ export default definePluginEntry({
|
|
|
87
94
|
|
|
88
95
|
// Auto-install bm CLI if not found
|
|
89
96
|
const bmBin = cfg.bmPath || "bm"
|
|
90
|
-
|
|
91
|
-
execSync(`command -v ${bmBin}`, { stdio: "ignore" })
|
|
92
|
-
} catch {
|
|
97
|
+
if (!isCommandAvailable(bmBin)) {
|
|
93
98
|
log.info("bm CLI not found on PATH — attempting auto-install...")
|
|
94
99
|
try {
|
|
95
|
-
|
|
100
|
+
if (!isCommandAvailable("uv")) {
|
|
101
|
+
throw new Error("uv not found")
|
|
102
|
+
}
|
|
96
103
|
log.info(
|
|
97
104
|
"installing basic-memory via uv (this may take a minute)...",
|
|
98
105
|
)
|
|
99
|
-
const result =
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
const result = execFileSync(
|
|
107
|
+
"uv",
|
|
108
|
+
["tool", "install", "basic-memory", "--force"],
|
|
109
|
+
{
|
|
110
|
+
encoding: "utf-8",
|
|
111
|
+
timeout: 120_000,
|
|
112
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
113
|
+
},
|
|
102
114
|
)
|
|
103
115
|
log.info(
|
|
104
116
|
`basic-memory installed: ${result.trim().split("\n").pop()}`,
|
|
105
117
|
)
|
|
106
118
|
// Verify it worked
|
|
107
|
-
|
|
108
|
-
execSync(`command -v ${bmBin}`, { stdio: "ignore" })
|
|
119
|
+
if (isCommandAvailable(bmBin)) {
|
|
109
120
|
log.info("bm CLI now available on PATH")
|
|
110
|
-
}
|
|
121
|
+
} else {
|
|
111
122
|
log.error(
|
|
112
123
|
"bm installed but not found on PATH. You may need to add uv's bin directory to your PATH (typically ~/.local/bin).",
|
|
113
124
|
)
|
package/openclaw.plugin.json
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"skills/memory-literary-analysis",
|
|
27
27
|
"skills/memory-metadata-search",
|
|
28
28
|
"skills/memory-notes",
|
|
29
|
+
"skills/memory-onboarding",
|
|
29
30
|
"skills/memory-reflect",
|
|
30
31
|
"skills/memory-research",
|
|
31
32
|
"skills/memory-schema",
|
|
@@ -83,11 +84,6 @@
|
|
|
83
84
|
"placeholder": ".",
|
|
84
85
|
"help": "Filesystem path for Basic Memory project data (defaults to workspace root; relative paths resolve from workspace)",
|
|
85
86
|
"advanced": true
|
|
86
|
-
},
|
|
87
|
-
"cloud": {
|
|
88
|
-
"label": "Cloud Backend",
|
|
89
|
-
"help": "Optional cloud backend config (url + api_key). If present, uses cloud instead of local BM.",
|
|
90
|
-
"advanced": true
|
|
91
87
|
}
|
|
92
88
|
},
|
|
93
89
|
"configSchema": {
|
|
@@ -108,16 +104,7 @@
|
|
|
108
104
|
"recallPrompt": { "type": "string" },
|
|
109
105
|
"recall_prompt": { "type": "string" },
|
|
110
106
|
"debug": { "type": "boolean" },
|
|
111
|
-
"projectPath": { "type": "string" }
|
|
112
|
-
"cloud": {
|
|
113
|
-
"type": "object",
|
|
114
|
-
"additionalProperties": false,
|
|
115
|
-
"properties": {
|
|
116
|
-
"url": { "type": "string" },
|
|
117
|
-
"api_key": { "type": "string" }
|
|
118
|
-
},
|
|
119
|
-
"required": ["url", "api_key"]
|
|
120
|
-
}
|
|
107
|
+
"projectPath": { "type": "string" }
|
|
121
108
|
},
|
|
122
109
|
"required": []
|
|
123
110
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basicmemory/openclaw-basic-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
-
"description": "Basic Memory plugin for OpenClaw
|
|
7
|
+
"description": "Basic Memory plugin for OpenClaw \u2014 local-first knowledge graph for agent memory",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/basicmachines-co/
|
|
11
|
+
"url": "https://github.com/basicmachines-co/basic-memory.git",
|
|
12
|
+
"directory": "integrations/openclaw"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"index.ts",
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
"test": "bun test",
|
|
66
67
|
"test:int": "BM_INTEGRATION=1 BM_BIN=${BM_BIN:-./scripts/bm-local.sh} bun test integration --timeout 120000",
|
|
67
68
|
"test:coverage": "bun test --coverage",
|
|
68
|
-
"release:check": "bun run check-types && bun run build && bun test && npm pack --dry-run"
|
|
69
|
+
"release:check": "bun run fetch-skills && bun run check-types && bun run lint && bun run build && bun test && npm pack --dry-run"
|
|
69
70
|
},
|
|
70
71
|
"openclaw": {
|
|
71
72
|
"extensions": [
|