@basicmemory/openclaw-basic-memory 0.1.0-alpha.2 → 0.1.0-alpha.9
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 +54 -18
- package/analytics.ts +162 -0
- package/bm-client.ts +2 -0
- package/config.ts +25 -1
- package/index.ts +32 -0
- package/openclaw.plugin.json +14 -2
- package/package.json +6 -1
- package/scripts/setup-bm.sh +2 -3
package/README.md
CHANGED
|
@@ -55,6 +55,17 @@ If `uv` is not installed, the `bm` CLI setup is skipped gracefully during instal
|
|
|
55
55
|
bash ~/.openclaw/extensions/openclaw-basic-memory/scripts/setup-bm.sh
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
### Basic Memory Cloud
|
|
59
|
+
|
|
60
|
+
Everything works locally — cloud adds cross-device, team, and production capabilities:
|
|
61
|
+
|
|
62
|
+
- **Your agent's memory travels with you** — same knowledge graph on laptop, desktop, and hosted environments
|
|
63
|
+
- **Team knowledge sharing** — org workspaces let multiple agents and team members build on a shared knowledge base
|
|
64
|
+
- **Durable memory for production agents** — persistent memory that survives CI teardowns and container restarts
|
|
65
|
+
- **Multi-agent coordination** — multiple agents can read and write to the same graph
|
|
66
|
+
|
|
67
|
+
Cloud extends local-first — still plain markdown, still yours. Start with a [7-day free trial](https://basicmemory.com) and use code `BMCLAW` for 20% off for 3 months. See [BASIC_MEMORY.md](./BASIC_MEMORY.md) for cloud setup.
|
|
68
|
+
|
|
58
69
|
### Development (local directory)
|
|
59
70
|
|
|
60
71
|
For plugin development, clone and link locally:
|
|
@@ -126,7 +137,7 @@ This installs to the same `skills/` directory the plugin reads from, so updated
|
|
|
126
137
|
}
|
|
127
138
|
```
|
|
128
139
|
|
|
129
|
-
This uses sensible defaults: auto-generated project name, maps Basic Memory to your workspace
|
|
140
|
+
This uses sensible defaults: auto-generated project name, maps Basic Memory to your workspace root, sets it as the default BM project, and captures conversations.
|
|
130
141
|
|
|
131
142
|
### Full configuration
|
|
132
143
|
```json5
|
|
@@ -136,7 +147,7 @@ This uses sensible defaults: auto-generated project name, maps Basic Memory to y
|
|
|
136
147
|
config: {
|
|
137
148
|
project: "my-agent", // BM project name (default: "openclaw-{hostname}")
|
|
138
149
|
bmPath: "bm", // Path to BM CLI binary
|
|
139
|
-
projectPath: "
|
|
150
|
+
projectPath: ".", // Defaults to workspace root; supports absolute, ~/..., or workspace-relative paths
|
|
140
151
|
memoryDir: "memory/", // Relative memory dir for task scanning
|
|
141
152
|
memoryFile: "MEMORY.md", // Working memory file for grep search
|
|
142
153
|
autoCapture: true, // Index conversations automatically
|
|
@@ -155,7 +166,7 @@ This uses sensible defaults: auto-generated project name, maps Basic Memory to y
|
|
|
155
166
|
|--------|------|---------|-------------|
|
|
156
167
|
| `project` | string | `"openclaw-{hostname}"` | Basic Memory project name |
|
|
157
168
|
| `bmPath` | string | `"bm"` | Path to Basic Memory CLI binary |
|
|
158
|
-
| `projectPath` | string | `"
|
|
169
|
+
| `projectPath` | string | `"."` | Directory for BM project data (defaults to workspace root; resolved from workspace unless absolute) |
|
|
159
170
|
| `memoryDir` | string | `"memory/"` | Relative path for task scanning |
|
|
160
171
|
| `memoryFile` | string | `"MEMORY.md"` | Working memory file (grep-searched) |
|
|
161
172
|
| `autoCapture` | boolean | `true` | Auto-index agent conversations |
|
|
@@ -168,7 +179,7 @@ Snake_case aliases (`memory_dir`, `memory_file`, `auto_recall`, `recall_prompt`,
|
|
|
168
179
|
|
|
169
180
|
Cloud sync is optional — see [BASIC_MEMORY.md](./BASIC_MEMORY.md) for cloud configuration.
|
|
170
181
|
|
|
171
|
-
On startup, the plugin ensures the configured BM project exists at `projectPath` via MCP `create_memory_project` in idempotent mode.
|
|
182
|
+
On startup, the plugin ensures the configured BM project exists at `projectPath` via MCP `create_memory_project` in idempotent mode, and sets it as the default Basic Memory project.
|
|
172
183
|
|
|
173
184
|
## How It Works
|
|
174
185
|
|
|
@@ -287,17 +298,6 @@ After each agent turn (when `autoCapture: true`), the plugin:
|
|
|
287
298
|
2. Appends them as timestamped entries to a daily conversation note (`conversations-YYYY-MM-DD`)
|
|
288
299
|
3. Skips very short exchanges (< `captureMinChars` chars each, default 10)
|
|
289
300
|
|
|
290
|
-
### Basic Memory Cloud
|
|
291
|
-
|
|
292
|
-
Everything works locally — cloud adds cross-device, team, and production capabilities:
|
|
293
|
-
|
|
294
|
-
- **Your agent's memory travels with you** — same knowledge graph on laptop, desktop, and hosted environments
|
|
295
|
-
- **Team knowledge sharing** — org workspaces let multiple agents and team members build on a shared knowledge base
|
|
296
|
-
- **Durable memory for production agents** — persistent memory that survives CI teardowns and container restarts
|
|
297
|
-
- **Multi-agent coordination** — multiple agents can read and write to the same graph
|
|
298
|
-
|
|
299
|
-
Cloud extends local-first — still plain markdown, still yours. Start with a [7-day free trial](https://basicmemory.com) and use code `BMCLAW` for 20% off for 3 months. See [BASIC_MEMORY.md](./BASIC_MEMORY.md) for setup, or visit [basicmemory.com](https://basicmemory.com) for more info.
|
|
300
|
-
|
|
301
301
|
## Agent Tools
|
|
302
302
|
|
|
303
303
|
All content tools accept an optional `project` parameter to operate on a different project than the default (cross-project operations).
|
|
@@ -453,6 +453,17 @@ rm -rf /tmp/jiti/ "$TMPDIR/jiti/"
|
|
|
453
453
|
openclaw gateway stop && openclaw gateway start
|
|
454
454
|
```
|
|
455
455
|
|
|
456
|
+
### Disabling semantic search
|
|
457
|
+
If you want to run without vector/embedding dependencies (faster startup, less memory), set the environment variable before launching:
|
|
458
|
+
```bash
|
|
459
|
+
BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED=false
|
|
460
|
+
```
|
|
461
|
+
Or in `~/.basic-memory/config.json`:
|
|
462
|
+
```json
|
|
463
|
+
{ "semantic_search_enabled": false }
|
|
464
|
+
```
|
|
465
|
+
Search will fall back to full-text search only.
|
|
466
|
+
|
|
456
467
|
### Search returns no results
|
|
457
468
|
1. Check that the MCP session is connected (look for `connected to BM MCP stdio` in logs)
|
|
458
469
|
2. Verify files exist in the project directory
|
|
@@ -531,9 +542,7 @@ just release patch # or: minor, major, 0.2.0, etc.
|
|
|
531
542
|
4. publish to npm
|
|
532
543
|
5. create a GitHub release
|
|
533
544
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
- `NPM_TOKEN` (npm publish token with package publish permissions)
|
|
545
|
+
Publishing uses npm OIDC trusted publishing — no secrets required. The trusted publisher is configured on npmjs.com to accept provenance from this repo's `release.yml` workflow.
|
|
537
546
|
|
|
538
547
|
### Project Structure
|
|
539
548
|
```
|
|
@@ -564,6 +573,33 @@ openclaw-basic-memory/
|
|
|
564
573
|
└── recall.ts # Auto-recall (active tasks + recent activity)
|
|
565
574
|
```
|
|
566
575
|
|
|
576
|
+
## Telemetry
|
|
577
|
+
|
|
578
|
+
This plugin collects anonymous, minimal usage events to understand plugin adoption and tool usage patterns. This helps us prioritize features and improve the product.
|
|
579
|
+
|
|
580
|
+
**What we collect:**
|
|
581
|
+
- Plugin registration and startup events
|
|
582
|
+
- First use of each tool per session (deduplicated — not every call)
|
|
583
|
+
- Plugin version with each event
|
|
584
|
+
|
|
585
|
+
**What we do NOT collect:**
|
|
586
|
+
- No file contents, note titles, search queries, or conversation text
|
|
587
|
+
- No personally identifiable information (PII)
|
|
588
|
+
- No IP address tracking or fingerprinting
|
|
589
|
+
- No per-command tracking beyond first-use-per-session
|
|
590
|
+
|
|
591
|
+
Events are sent to our [Umami Cloud](https://umami.is) instance, an open-source, privacy-focused analytics platform. Events are fire-and-forget with a 3-second timeout — analytics never blocks or slows the plugin.
|
|
592
|
+
|
|
593
|
+
**Opt out** by setting either environment variable:
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
# Plugin-specific opt-out
|
|
597
|
+
export OPENCLAW_BASIC_MEMORY_TELEMETRY=0
|
|
598
|
+
|
|
599
|
+
# Or use the shared Basic Memory opt-out (also disables BM CLI telemetry)
|
|
600
|
+
export BASIC_MEMORY_NO_PROMOS=1
|
|
601
|
+
```
|
|
602
|
+
|
|
567
603
|
## License
|
|
568
604
|
|
|
569
605
|
MIT — see LICENSE file.
|
package/analytics.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight analytics via Umami event collector.
|
|
3
|
+
*
|
|
4
|
+
* Sends anonymous, non-blocking usage events to help understand plugin adoption
|
|
5
|
+
* and tool usage patterns. No PII, no fingerprinting, no cookies.
|
|
6
|
+
*
|
|
7
|
+
* Events are fire-and-forget — analytics never blocks or breaks the plugin.
|
|
8
|
+
*
|
|
9
|
+
* Defaults point to the Basic Memory Umami Cloud instance. Override via:
|
|
10
|
+
* BASIC_MEMORY_UMAMI_HOST — Custom Umami instance URL
|
|
11
|
+
* BASIC_MEMORY_UMAMI_SITE_ID — Custom Website ID
|
|
12
|
+
* Opt out entirely with OPENCLAW_BASIC_MEMORY_TELEMETRY=0 or BASIC_MEMORY_NO_PROMOS=1.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync } from "node:fs"
|
|
16
|
+
import { join } from "node:path"
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Configuration
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
const DEFAULT_UMAMI_HOST = "https://cloud.umami.is"
|
|
23
|
+
const DEFAULT_UMAMI_SITE_ID = "f6479898-ebaf-4e60-bce2-6dc60a3f6c5c"
|
|
24
|
+
const SEND_TIMEOUT_MS = 3000
|
|
25
|
+
|
|
26
|
+
function umamiHost(): string {
|
|
27
|
+
return process.env.BASIC_MEMORY_UMAMI_HOST?.trim() || DEFAULT_UMAMI_HOST
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function umamiSiteId(): string {
|
|
31
|
+
return process.env.BASIC_MEMORY_UMAMI_SITE_ID?.trim() || DEFAULT_UMAMI_SITE_ID
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function analyticsDisabled(): boolean {
|
|
35
|
+
// Plugin-specific opt-out
|
|
36
|
+
const telemetry = (process.env.OPENCLAW_BASIC_MEMORY_TELEMETRY ?? "")
|
|
37
|
+
.trim()
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
if (telemetry === "0" || telemetry === "false" || telemetry === "no") {
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Shared Basic Memory opt-out (also disables BM CLI analytics)
|
|
44
|
+
const noPromos = (process.env.BASIC_MEMORY_NO_PROMOS ?? "")
|
|
45
|
+
.trim()
|
|
46
|
+
.toLowerCase()
|
|
47
|
+
return noPromos === "1" || noPromos === "true" || noPromos === "yes"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Version
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
let _cachedVersion: string | null = null
|
|
55
|
+
|
|
56
|
+
function getVersion(): string {
|
|
57
|
+
if (_cachedVersion) return _cachedVersion
|
|
58
|
+
try {
|
|
59
|
+
const pkg = JSON.parse(
|
|
60
|
+
readFileSync(
|
|
61
|
+
join(import.meta.dirname ?? __dirname, "package.json"),
|
|
62
|
+
"utf-8",
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
_cachedVersion = pkg.version ?? "unknown"
|
|
66
|
+
} catch {
|
|
67
|
+
_cachedVersion = "unknown"
|
|
68
|
+
}
|
|
69
|
+
return _cachedVersion ?? "unknown"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Session-scoped dedup for tool calls
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
const _trackedTools = new Set<string>()
|
|
77
|
+
|
|
78
|
+
export function resetTrackedTools(): void {
|
|
79
|
+
_trackedTools.clear()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Event constants
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
export const EVENT_PLUGIN_INSTALLED = "openclaw-plugin-installed"
|
|
87
|
+
export const EVENT_PLUGIN_STARTED = "openclaw-plugin-started"
|
|
88
|
+
export const EVENT_TOOL_CALL = "openclaw-tool-call"
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Public API
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Send an analytics event to Umami. Non-blocking, silent on failure.
|
|
96
|
+
*
|
|
97
|
+
* @param eventName - Short kebab-case name (e.g. "openclaw-plugin-started")
|
|
98
|
+
* @param data - Optional dict of event properties (string/number values)
|
|
99
|
+
*/
|
|
100
|
+
export function track(
|
|
101
|
+
eventName: string,
|
|
102
|
+
data?: Record<string, string | number>,
|
|
103
|
+
): void {
|
|
104
|
+
if (analyticsDisabled()) return
|
|
105
|
+
|
|
106
|
+
const host = umamiHost()
|
|
107
|
+
const siteId = umamiSiteId()
|
|
108
|
+
|
|
109
|
+
const payload = {
|
|
110
|
+
payload: {
|
|
111
|
+
hostname: "openclaw.basicmemory.com",
|
|
112
|
+
language: "en",
|
|
113
|
+
url: `/openclaw/${eventName}`,
|
|
114
|
+
website: siteId,
|
|
115
|
+
name: eventName,
|
|
116
|
+
data: {
|
|
117
|
+
version: getVersion(),
|
|
118
|
+
...(data ?? {}),
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Fire-and-forget — never block the plugin
|
|
124
|
+
_sendPayload(host, payload).catch(() => {})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Track a tool call, deduped per tool name per session.
|
|
129
|
+
* Only the first invocation of each tool sends an event.
|
|
130
|
+
*/
|
|
131
|
+
export function trackToolCall(toolName: string): void {
|
|
132
|
+
if (analyticsDisabled()) return
|
|
133
|
+
if (_trackedTools.has(toolName)) return
|
|
134
|
+
_trackedTools.add(toolName)
|
|
135
|
+
track(EVENT_TOOL_CALL, { tool: toolName })
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Internal send (exported for testing)
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
export async function _sendPayload(
|
|
143
|
+
host: string,
|
|
144
|
+
payload: unknown,
|
|
145
|
+
): Promise<void> {
|
|
146
|
+
const controller = new AbortController()
|
|
147
|
+
const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS)
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
await fetch(`${host}/api/send`, {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: {
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
"User-Agent": `openclaw-basic-memory/${getVersion()}`,
|
|
155
|
+
},
|
|
156
|
+
body: JSON.stringify(payload),
|
|
157
|
+
signal: controller.signal,
|
|
158
|
+
})
|
|
159
|
+
} finally {
|
|
160
|
+
clearTimeout(timer)
|
|
161
|
+
}
|
|
162
|
+
}
|
package/bm-client.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { setTimeout as delay } from "node:timers/promises"
|
|
2
2
|
import { Client } from "@modelcontextprotocol/sdk/client"
|
|
3
3
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
|
4
|
+
import { trackToolCall } from "./analytics.ts"
|
|
4
5
|
import { log } from "./logger.ts"
|
|
5
6
|
|
|
6
7
|
const DEFAULT_RETRY_DELAYS_MS = [500, 1000, 2000]
|
|
@@ -449,6 +450,7 @@ export class BmClient {
|
|
|
449
450
|
name: string,
|
|
450
451
|
args: Record<string, unknown>,
|
|
451
452
|
): Promise<unknown> {
|
|
453
|
+
trackToolCall(name)
|
|
452
454
|
const result = await this.callToolRaw(name, args)
|
|
453
455
|
|
|
454
456
|
if (!isRecord(result) || result.structuredContent === undefined) {
|
package/config.ts
CHANGED
|
@@ -6,6 +6,11 @@ export type CloudConfig = {
|
|
|
6
6
|
api_key: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export type DashboardConfig = {
|
|
10
|
+
enabled: boolean
|
|
11
|
+
port: number
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
export type BasicMemoryConfig = {
|
|
10
15
|
project: string
|
|
11
16
|
bmPath: string
|
|
@@ -18,6 +23,7 @@ export type BasicMemoryConfig = {
|
|
|
18
23
|
recallPrompt: string
|
|
19
24
|
debug: boolean
|
|
20
25
|
cloud?: CloudConfig
|
|
26
|
+
dashboard: DashboardConfig
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
const ALLOWED_KEYS = [
|
|
@@ -37,6 +43,7 @@ const ALLOWED_KEYS = [
|
|
|
37
43
|
"recall_prompt",
|
|
38
44
|
"debug",
|
|
39
45
|
"cloud",
|
|
46
|
+
"dashboard",
|
|
40
47
|
]
|
|
41
48
|
|
|
42
49
|
function assertAllowedKeys(
|
|
@@ -106,6 +113,22 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
|
|
|
106
113
|
}
|
|
107
114
|
}
|
|
108
115
|
|
|
116
|
+
let dashboard: DashboardConfig = { enabled: false, port: 3838 }
|
|
117
|
+
if (
|
|
118
|
+
cfg.dashboard &&
|
|
119
|
+
typeof cfg.dashboard === "object" &&
|
|
120
|
+
!Array.isArray(cfg.dashboard)
|
|
121
|
+
) {
|
|
122
|
+
const d = cfg.dashboard as Record<string, unknown>
|
|
123
|
+
dashboard = {
|
|
124
|
+
enabled: typeof d.enabled === "boolean" ? d.enabled : false,
|
|
125
|
+
port:
|
|
126
|
+
typeof d.port === "number" && d.port > 0 && d.port < 65536
|
|
127
|
+
? d.port
|
|
128
|
+
: 3838,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
109
132
|
return {
|
|
110
133
|
project:
|
|
111
134
|
typeof cfg.project === "string" && cfg.project.length > 0
|
|
@@ -114,7 +137,7 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
|
|
|
114
137
|
projectPath:
|
|
115
138
|
typeof cfg.projectPath === "string" && cfg.projectPath.length > 0
|
|
116
139
|
? cfg.projectPath
|
|
117
|
-
:
|
|
140
|
+
: ".",
|
|
118
141
|
bmPath:
|
|
119
142
|
typeof cfg.bmPath === "string" && cfg.bmPath.length > 0
|
|
120
143
|
? cfg.bmPath
|
|
@@ -144,6 +167,7 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
|
|
|
144
167
|
: "Check for active tasks and recent activity. Summarize anything relevant to the current session.",
|
|
145
168
|
debug: typeof cfg.debug === "boolean" ? cfg.debug : false,
|
|
146
169
|
cloud,
|
|
170
|
+
dashboard,
|
|
147
171
|
}
|
|
148
172
|
}
|
|
149
173
|
|
package/index.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import type { Server } from "node:http"
|
|
1
2
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk"
|
|
3
|
+
import {
|
|
4
|
+
EVENT_PLUGIN_INSTALLED,
|
|
5
|
+
EVENT_PLUGIN_STARTED,
|
|
6
|
+
track,
|
|
7
|
+
} from "./analytics.ts"
|
|
2
8
|
import { BmClient } from "./bm-client.ts"
|
|
3
9
|
import { registerCli } from "./commands/cli.ts"
|
|
4
10
|
import { registerSkillCommands } from "./commands/skills.ts"
|
|
@@ -8,6 +14,7 @@ import {
|
|
|
8
14
|
parseConfig,
|
|
9
15
|
resolveProjectPath,
|
|
10
16
|
} from "./config.ts"
|
|
17
|
+
import { createDashboardServer } from "./dashboard/server.ts"
|
|
11
18
|
import { buildCaptureHandler } from "./hooks/capture.ts"
|
|
12
19
|
import { buildRecallHandler } from "./hooks/recall.ts"
|
|
13
20
|
import { initLogger, log } from "./logger.ts"
|
|
@@ -46,6 +53,8 @@ export default {
|
|
|
46
53
|
`project=${cfg.project} memoryDir=${cfg.memoryDir} memoryFile=${cfg.memoryFile}`,
|
|
47
54
|
)
|
|
48
55
|
|
|
56
|
+
track(EVENT_PLUGIN_INSTALLED)
|
|
57
|
+
|
|
49
58
|
const client = new BmClient(cfg.bmPath, cfg.project)
|
|
50
59
|
|
|
51
60
|
// --- BM Tools (always registered) ---
|
|
@@ -80,6 +89,8 @@ export default {
|
|
|
80
89
|
registerCli(api, client, cfg)
|
|
81
90
|
|
|
82
91
|
// --- Service lifecycle ---
|
|
92
|
+
let dashboardServer: Server | undefined
|
|
93
|
+
|
|
83
94
|
api.registerService({
|
|
84
95
|
id: "openclaw-basic-memory",
|
|
85
96
|
start: async (ctx: { config?: unknown; workspaceDir?: string }) => {
|
|
@@ -108,10 +119,31 @@ export default {
|
|
|
108
119
|
|
|
109
120
|
setWorkspaceDir(workspace)
|
|
110
121
|
|
|
122
|
+
// Start dashboard if enabled
|
|
123
|
+
if (cfg.dashboard.enabled) {
|
|
124
|
+
dashboardServer = createDashboardServer({
|
|
125
|
+
port: cfg.dashboard.port,
|
|
126
|
+
client,
|
|
127
|
+
})
|
|
128
|
+
dashboardServer.listen(cfg.dashboard.port, () => {
|
|
129
|
+
log.info(
|
|
130
|
+
`dashboard running at http://localhost:${cfg.dashboard.port}`,
|
|
131
|
+
)
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
track(EVENT_PLUGIN_STARTED, { project: cfg.project })
|
|
111
136
|
log.info("connected — BM MCP stdio session running")
|
|
112
137
|
},
|
|
113
138
|
stop: async () => {
|
|
114
139
|
log.info("stopping BM MCP session...")
|
|
140
|
+
if (dashboardServer) {
|
|
141
|
+
await new Promise<void>((resolve) =>
|
|
142
|
+
dashboardServer?.close(() => resolve()),
|
|
143
|
+
)
|
|
144
|
+
dashboardServer = undefined
|
|
145
|
+
log.info("dashboard stopped")
|
|
146
|
+
}
|
|
115
147
|
await client.stop()
|
|
116
148
|
log.info("stopped")
|
|
117
149
|
},
|
package/openclaw.plugin.json
CHANGED
|
@@ -48,14 +48,19 @@
|
|
|
48
48
|
},
|
|
49
49
|
"projectPath": {
|
|
50
50
|
"label": "Project Path",
|
|
51
|
-
"placeholder": "
|
|
52
|
-
"help": "Filesystem path for Basic Memory project data (relative paths resolve from workspace)
|
|
51
|
+
"placeholder": ".",
|
|
52
|
+
"help": "Filesystem path for Basic Memory project data (defaults to workspace root; relative paths resolve from workspace)",
|
|
53
53
|
"advanced": true
|
|
54
54
|
},
|
|
55
55
|
"cloud": {
|
|
56
56
|
"label": "Cloud Backend",
|
|
57
57
|
"help": "Optional cloud backend config (url + api_key). If present, uses cloud instead of local BM.",
|
|
58
58
|
"advanced": true
|
|
59
|
+
},
|
|
60
|
+
"dashboard": {
|
|
61
|
+
"label": "Dashboard",
|
|
62
|
+
"help": "Web dashboard for visualizing the knowledge graph (enabled, port)",
|
|
63
|
+
"advanced": true
|
|
59
64
|
}
|
|
60
65
|
},
|
|
61
66
|
"configSchema": {
|
|
@@ -76,6 +81,13 @@
|
|
|
76
81
|
"url": { "type": "string" },
|
|
77
82
|
"api_key": { "type": "string" }
|
|
78
83
|
}
|
|
84
|
+
},
|
|
85
|
+
"dashboard": {
|
|
86
|
+
"type": "object",
|
|
87
|
+
"properties": {
|
|
88
|
+
"enabled": { "type": "boolean" },
|
|
89
|
+
"port": { "type": "number", "minimum": 1, "maximum": 65535 }
|
|
90
|
+
}
|
|
79
91
|
}
|
|
80
92
|
},
|
|
81
93
|
"required": []
|
package/package.json
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basicmemory/openclaw-basic-memory",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Basic Memory plugin for OpenClaw — local-first knowledge graph for agent memory",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/basicmachines-co/openclaw-basic-memory"
|
|
10
|
+
},
|
|
7
11
|
"files": [
|
|
12
|
+
"analytics.ts",
|
|
8
13
|
"index.ts",
|
|
9
14
|
"bm-client.ts",
|
|
10
15
|
"config.ts",
|
package/scripts/setup-bm.sh
CHANGED
|
@@ -15,11 +15,10 @@ if ! command -v uv >/dev/null 2>&1; then
|
|
|
15
15
|
exit 0
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
|
-
# ── install basic-memory
|
|
18
|
+
# ── install basic-memory ────────────────────────────────
|
|
19
19
|
echo "Installing basic-memory from ${BM_REPO}@${BM_REF} ..."
|
|
20
20
|
uv tool install \
|
|
21
|
-
"basic-memory
|
|
22
|
-
--with 'onnxruntime<1.24; platform_system == "Darwin" and platform_machine == "x86_64"' \
|
|
21
|
+
"basic-memory @ git+${BM_REPO}@${BM_REF}" \
|
|
23
22
|
--force
|
|
24
23
|
|
|
25
24
|
# ── verify ────────────────────────────────────────────────────────
|