memorylake-openclaw 1.1.7 → 1.1.8
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/dist/index.js +2 -2
- package/package.json +4 -1
- package/skills/agent-memorylake-config/SKILL.md +2 -2
- package/skills/common/get-config.mjs +34 -23
- package/skills/memorylake-api/SKILL.md +4 -4
- package/skills/memorylake-api/scripts/get-config.mjs +101 -0
- package/skills/memorylake-upload/SKILL.md +3 -3
- package/skills/memorylake-upload/scripts/get-config.mjs +101 -0
- package/skills/migrate-memories-to-memorylake/SKILL.md +6 -6
- package/skills/migrate-memories-to-memorylake/scripts/get-config.mjs +101 -0
- package/skills/migrate-memories-to-memorylake/scripts/migrate.mjs +12 -6
package/dist/index.js
CHANGED
|
@@ -240,7 +240,7 @@ import { Type } from "@sinclair/typebox";
|
|
|
240
240
|
|
|
241
241
|
// lib/telemetry.ts
|
|
242
242
|
import { createHash } from "crypto";
|
|
243
|
-
var PLUGIN_VERSION = true ? "1.1.
|
|
243
|
+
var PLUGIN_VERSION = true ? "1.1.8" : "dev";
|
|
244
244
|
var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
|
245
245
|
var POSTHOG_API_KEY = process.env.MEMORYLAKE_POSTHOG_API_KEY?.trim() ?? "";
|
|
246
246
|
var POSTHOG_HOST = normalizePosthogHost(
|
|
@@ -565,7 +565,7 @@ function getProvider(effectiveCfg) {
|
|
|
565
565
|
}
|
|
566
566
|
|
|
567
567
|
// lib/utils/builders.ts
|
|
568
|
-
var PLUGIN_VERSION2 = true ? "1.1.
|
|
568
|
+
var PLUGIN_VERSION2 = true ? "1.1.8" : "dev";
|
|
569
569
|
function buildDocumentContext(results, maxChunkLength = 1e4) {
|
|
570
570
|
const parts = [];
|
|
571
571
|
for (const result of results) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memorylake-openclaw",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MemoryLake memory backend for OpenClaw",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
],
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsup",
|
|
29
|
+
"sync-skills": "node scripts/sync-skills.mjs",
|
|
30
|
+
"prepare": "node scripts/sync-skills.mjs",
|
|
31
|
+
"test": "node --test",
|
|
29
32
|
"prepublishOnly": "npm run build"
|
|
30
33
|
},
|
|
31
34
|
"dependencies": {
|
|
@@ -5,7 +5,7 @@ description: Use when the user asks to configure agent-specific memorylake prope
|
|
|
5
5
|
|
|
6
6
|
# Agent MemoryLake Config
|
|
7
7
|
|
|
8
|
-
Configure agent-specific memorylake properties for the current agent. The config file is located at `{workspace}/.memorylake/config.json`, where `{workspace}` is the agent's workspace directory. This config overrides corresponding properties from the global config.
|
|
8
|
+
Configure agent-specific memorylake properties for the current agent. The config file is located at `{workspace}/.memorylake/config.json`, where `{workspace}` is the current agent's workspace directory. This config overrides corresponding properties from the global config.
|
|
9
9
|
|
|
10
10
|
## Step 1 — Confirm projectId
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@ If the user has already provided the `projectId` in their message, skip the ques
|
|
|
15
15
|
|
|
16
16
|
## Step 2 — Write Config
|
|
17
17
|
|
|
18
|
-
1. Ensure the `.memorylake/` directory exists inside the agent's workspace directory:
|
|
18
|
+
1. Ensure the `.memorylake/` directory exists inside the current agent's workspace directory:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
cd {workspace}
|
|
@@ -6,24 +6,43 @@ import { homedir } from "node:os";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import JSON5 from "json5";
|
|
8
8
|
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// CANONICAL SOURCE. This file is synced verbatim into each consuming skill's
|
|
11
|
+
// `scripts/` directory by `scripts/sync-skills.mjs` (run via the package
|
|
12
|
+
// `prepare` script). Edit THIS file only — never edit the generated copies.
|
|
13
|
+
//
|
|
14
|
+
// Why the copies exist: the OpenClaw skill mechanism links each skill
|
|
15
|
+
// individually into `~/.openclaw/skills/<name>/`, so a shared sibling such as
|
|
16
|
+
// `skills/common/` is no longer reachable from a skill via a relative path.
|
|
17
|
+
// Each skill therefore carries its own copy and references it as
|
|
18
|
+
// `{path-to-this-skill}/scripts/get-config.mjs`.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
9
21
|
/**
|
|
10
|
-
* Load the merged MemoryLake plugin config for a given
|
|
22
|
+
* Load the merged MemoryLake plugin config for a given workspace.
|
|
11
23
|
*
|
|
12
24
|
* Reads the global `~/.openclaw/openclaw.json` config, picks up the
|
|
13
|
-
* `memorylake-openclaw` plugin config,
|
|
14
|
-
*
|
|
25
|
+
* `memorylake-openclaw` plugin config, and merges any per-workspace overrides
|
|
26
|
+
* from `<workspace>/.memorylake/config.json`.
|
|
27
|
+
*
|
|
28
|
+
* The caller passes the workspace directly — the running agent already knows
|
|
29
|
+
* its own workspace (it is the agent's working directory, the same value the
|
|
30
|
+
* `agent-memorylake-config` skill writes into). We deliberately do NOT shell
|
|
31
|
+
* out to resolve it from an agent id: the only thing a workspace is needed for
|
|
32
|
+
* here is locating the per-workspace override file, so taking it as input keeps
|
|
33
|
+
* this script dependency-free and side-effect-free.
|
|
15
34
|
*
|
|
16
|
-
* @param {{
|
|
35
|
+
* @param {{ workspace: string }} opts
|
|
17
36
|
* @returns {{ apiKey: string, projectId: string, host: string, workspace: string, [key: string]: unknown }}
|
|
18
|
-
* Merged config object. Throws on any failure (missing
|
|
37
|
+
* Merged config object. Throws on any failure (missing workspace, missing
|
|
19
38
|
* plugin config, missing required fields, parse errors).
|
|
20
39
|
*/
|
|
21
|
-
export function loadConfig({
|
|
22
|
-
if (!
|
|
23
|
-
throw new Error("
|
|
40
|
+
export function loadConfig({ workspace }) {
|
|
41
|
+
if (!workspace || typeof workspace !== "string") {
|
|
42
|
+
throw new Error("workspace is required");
|
|
24
43
|
}
|
|
25
44
|
|
|
26
|
-
// Read global config
|
|
45
|
+
// Read global plugin config (apiKey/projectId/host/...) from openclaw.json.
|
|
27
46
|
const openclawPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
28
47
|
let openclaw;
|
|
29
48
|
try {
|
|
@@ -36,15 +55,7 @@ export function loadConfig({ agentId }) {
|
|
|
36
55
|
throw new Error("memorylake-openclaw plugin config not found");
|
|
37
56
|
}
|
|
38
57
|
|
|
39
|
-
//
|
|
40
|
-
const agents = openclaw?.agents;
|
|
41
|
-
const agentEntry = agents?.list?.find((a) => a.id === agentId);
|
|
42
|
-
const workspace = agentEntry?.workspace || agents?.defaults?.workspace;
|
|
43
|
-
if (!workspace) {
|
|
44
|
-
throw new Error(`no workspace found for agent "${agentId}"`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Merge per-agent overrides
|
|
58
|
+
// Merge per-workspace overrides
|
|
48
59
|
const merged = { ...globalCfg };
|
|
49
60
|
const localPath = join(workspace, ".memorylake", "config.json");
|
|
50
61
|
if (existsSync(localPath)) {
|
|
@@ -73,15 +84,15 @@ export function loadConfig({ agentId }) {
|
|
|
73
84
|
// identical (JSON to stdout, errors to stderr, non-zero exit on failure).
|
|
74
85
|
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
75
86
|
const args = process.argv.slice(2);
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
console.error("Usage: node get-config.mjs --
|
|
87
|
+
const wsIdx = args.indexOf("--workspace");
|
|
88
|
+
if (wsIdx === -1 || !args[wsIdx + 1]) {
|
|
89
|
+
console.error("Usage: node get-config.mjs --workspace <workspaceDir>");
|
|
79
90
|
process.exit(1);
|
|
80
91
|
}
|
|
81
|
-
const
|
|
92
|
+
const workspace = args[wsIdx + 1];
|
|
82
93
|
|
|
83
94
|
try {
|
|
84
|
-
const merged = loadConfig({
|
|
95
|
+
const merged = loadConfig({ workspace });
|
|
85
96
|
console.log(JSON.stringify(merged, null, 2));
|
|
86
97
|
} catch (err) {
|
|
87
98
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -19,13 +19,13 @@ Directly call MemoryLake's REST APIs by discovering endpoints from the live Open
|
|
|
19
19
|
|
|
20
20
|
## Step 1 — Read MemoryLake Config
|
|
21
21
|
|
|
22
|
-
Run the common config script (path is relative to **this skill's SKILL.md**, i.e.
|
|
22
|
+
Run the common config script (path is relative to **this skill's SKILL.md**, i.e. `scripts/get-config.mjs`):
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
node {path-to-this-skill}
|
|
25
|
+
node {path-to-this-skill}/scripts/get-config.mjs --workspace {workspace}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
Where `{
|
|
28
|
+
Where `{workspace}` is the current agent's workspace directory. The script outputs JSON config with `host`, `apiKey`, `projectId`, etc.
|
|
29
29
|
|
|
30
30
|
If the script exits with an error, stop and inform the user.
|
|
31
31
|
|
|
@@ -186,7 +186,7 @@ All responses follow the same wrapper format:
|
|
|
186
186
|
|
|
187
187
|
| Item | Value |
|
|
188
188
|
|------|-------|
|
|
189
|
-
| Config script | `{path-to-this-skill}
|
|
189
|
+
| Config script | `{path-to-this-skill}/scripts/get-config.mjs --workspace {workspace}` |
|
|
190
190
|
| Server base path | `/openapi/memorylake` |
|
|
191
191
|
| OpenAPI spec URL | `{host}/openapi/memorylake/api-docs/open-api` |
|
|
192
192
|
| Auth header | `Authorization: Bearer {apiKey}` |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import JSON5 from "json5";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// CANONICAL SOURCE. This file is synced verbatim into each consuming skill's
|
|
11
|
+
// `scripts/` directory by `scripts/sync-skills.mjs` (run via the package
|
|
12
|
+
// `prepare` script). Edit THIS file only — never edit the generated copies.
|
|
13
|
+
//
|
|
14
|
+
// Why the copies exist: the OpenClaw skill mechanism links each skill
|
|
15
|
+
// individually into `~/.openclaw/skills/<name>/`, so a shared sibling such as
|
|
16
|
+
// `skills/common/` is no longer reachable from a skill via a relative path.
|
|
17
|
+
// Each skill therefore carries its own copy and references it as
|
|
18
|
+
// `{path-to-this-skill}/scripts/get-config.mjs`.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Load the merged MemoryLake plugin config for a given workspace.
|
|
23
|
+
*
|
|
24
|
+
* Reads the global `~/.openclaw/openclaw.json` config, picks up the
|
|
25
|
+
* `memorylake-openclaw` plugin config, and merges any per-workspace overrides
|
|
26
|
+
* from `<workspace>/.memorylake/config.json`.
|
|
27
|
+
*
|
|
28
|
+
* The caller passes the workspace directly — the running agent already knows
|
|
29
|
+
* its own workspace (it is the agent's working directory, the same value the
|
|
30
|
+
* `agent-memorylake-config` skill writes into). We deliberately do NOT shell
|
|
31
|
+
* out to resolve it from an agent id: the only thing a workspace is needed for
|
|
32
|
+
* here is locating the per-workspace override file, so taking it as input keeps
|
|
33
|
+
* this script dependency-free and side-effect-free.
|
|
34
|
+
*
|
|
35
|
+
* @param {{ workspace: string }} opts
|
|
36
|
+
* @returns {{ apiKey: string, projectId: string, host: string, workspace: string, [key: string]: unknown }}
|
|
37
|
+
* Merged config object. Throws on any failure (missing workspace, missing
|
|
38
|
+
* plugin config, missing required fields, parse errors).
|
|
39
|
+
*/
|
|
40
|
+
export function loadConfig({ workspace }) {
|
|
41
|
+
if (!workspace || typeof workspace !== "string") {
|
|
42
|
+
throw new Error("workspace is required");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Read global plugin config (apiKey/projectId/host/...) from openclaw.json.
|
|
46
|
+
const openclawPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
47
|
+
let openclaw;
|
|
48
|
+
try {
|
|
49
|
+
openclaw = JSON5.parse(readFileSync(openclawPath, "utf-8"));
|
|
50
|
+
} catch (err) {
|
|
51
|
+
throw new Error(`failed to parse JSON5 config file "${openclawPath}": ${String(err)}`);
|
|
52
|
+
}
|
|
53
|
+
const globalCfg = openclaw?.plugins?.entries?.["memorylake-openclaw"]?.config;
|
|
54
|
+
if (!globalCfg) {
|
|
55
|
+
throw new Error("memorylake-openclaw plugin config not found");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Merge per-workspace overrides
|
|
59
|
+
const merged = { ...globalCfg };
|
|
60
|
+
const localPath = join(workspace, ".memorylake", "config.json");
|
|
61
|
+
if (existsSync(localPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const raw = JSON.parse(readFileSync(localPath, "utf-8"));
|
|
64
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
65
|
+
Object.assign(merged, raw);
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
throw new Error(`failed to parse workspace config at ${localPath}: ${String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
merged.host = merged.host || "https://app.memorylake.ai";
|
|
72
|
+
merged.workspace = workspace;
|
|
73
|
+
|
|
74
|
+
// Validate required fields
|
|
75
|
+
if (!merged.apiKey || !merged.projectId) {
|
|
76
|
+
throw new Error("apiKey and projectId are required");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return merged;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// CLI mode: only run when invoked directly via `node get-config.mjs ...`,
|
|
83
|
+
// not when imported as a module. Keeps the SKILL.md-documented CLI behavior
|
|
84
|
+
// identical (JSON to stdout, errors to stderr, non-zero exit on failure).
|
|
85
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
86
|
+
const args = process.argv.slice(2);
|
|
87
|
+
const wsIdx = args.indexOf("--workspace");
|
|
88
|
+
if (wsIdx === -1 || !args[wsIdx + 1]) {
|
|
89
|
+
console.error("Usage: node get-config.mjs --workspace <workspaceDir>");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const workspace = args[wsIdx + 1];
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const merged = loadConfig({ workspace });
|
|
96
|
+
console.log(JSON.stringify(merged, null, 2));
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -18,13 +18,13 @@ Upload local files, archives, or directories to MemoryLake using the multipart u
|
|
|
18
18
|
|
|
19
19
|
## Step 1 -- Read MemoryLake Config
|
|
20
20
|
|
|
21
|
-
Run the common config script (path is relative to **this skill's SKILL.md**, i.e.
|
|
21
|
+
Run the common config script (path is relative to **this skill's SKILL.md**, i.e. `scripts/get-config.mjs`):
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
node {path-to-this-skill}
|
|
24
|
+
node {path-to-this-skill}/scripts/get-config.mjs --workspace {workspace}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Where `{
|
|
27
|
+
Where `{workspace}` is the current agent's workspace directory. The script outputs JSON config with `host`, `apiKey`, `projectId`, etc.
|
|
28
28
|
|
|
29
29
|
If the script exits with an error, stop and inform the user.
|
|
30
30
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import JSON5 from "json5";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// CANONICAL SOURCE. This file is synced verbatim into each consuming skill's
|
|
11
|
+
// `scripts/` directory by `scripts/sync-skills.mjs` (run via the package
|
|
12
|
+
// `prepare` script). Edit THIS file only — never edit the generated copies.
|
|
13
|
+
//
|
|
14
|
+
// Why the copies exist: the OpenClaw skill mechanism links each skill
|
|
15
|
+
// individually into `~/.openclaw/skills/<name>/`, so a shared sibling such as
|
|
16
|
+
// `skills/common/` is no longer reachable from a skill via a relative path.
|
|
17
|
+
// Each skill therefore carries its own copy and references it as
|
|
18
|
+
// `{path-to-this-skill}/scripts/get-config.mjs`.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Load the merged MemoryLake plugin config for a given workspace.
|
|
23
|
+
*
|
|
24
|
+
* Reads the global `~/.openclaw/openclaw.json` config, picks up the
|
|
25
|
+
* `memorylake-openclaw` plugin config, and merges any per-workspace overrides
|
|
26
|
+
* from `<workspace>/.memorylake/config.json`.
|
|
27
|
+
*
|
|
28
|
+
* The caller passes the workspace directly — the running agent already knows
|
|
29
|
+
* its own workspace (it is the agent's working directory, the same value the
|
|
30
|
+
* `agent-memorylake-config` skill writes into). We deliberately do NOT shell
|
|
31
|
+
* out to resolve it from an agent id: the only thing a workspace is needed for
|
|
32
|
+
* here is locating the per-workspace override file, so taking it as input keeps
|
|
33
|
+
* this script dependency-free and side-effect-free.
|
|
34
|
+
*
|
|
35
|
+
* @param {{ workspace: string }} opts
|
|
36
|
+
* @returns {{ apiKey: string, projectId: string, host: string, workspace: string, [key: string]: unknown }}
|
|
37
|
+
* Merged config object. Throws on any failure (missing workspace, missing
|
|
38
|
+
* plugin config, missing required fields, parse errors).
|
|
39
|
+
*/
|
|
40
|
+
export function loadConfig({ workspace }) {
|
|
41
|
+
if (!workspace || typeof workspace !== "string") {
|
|
42
|
+
throw new Error("workspace is required");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Read global plugin config (apiKey/projectId/host/...) from openclaw.json.
|
|
46
|
+
const openclawPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
47
|
+
let openclaw;
|
|
48
|
+
try {
|
|
49
|
+
openclaw = JSON5.parse(readFileSync(openclawPath, "utf-8"));
|
|
50
|
+
} catch (err) {
|
|
51
|
+
throw new Error(`failed to parse JSON5 config file "${openclawPath}": ${String(err)}`);
|
|
52
|
+
}
|
|
53
|
+
const globalCfg = openclaw?.plugins?.entries?.["memorylake-openclaw"]?.config;
|
|
54
|
+
if (!globalCfg) {
|
|
55
|
+
throw new Error("memorylake-openclaw plugin config not found");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Merge per-workspace overrides
|
|
59
|
+
const merged = { ...globalCfg };
|
|
60
|
+
const localPath = join(workspace, ".memorylake", "config.json");
|
|
61
|
+
if (existsSync(localPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const raw = JSON.parse(readFileSync(localPath, "utf-8"));
|
|
64
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
65
|
+
Object.assign(merged, raw);
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
throw new Error(`failed to parse workspace config at ${localPath}: ${String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
merged.host = merged.host || "https://app.memorylake.ai";
|
|
72
|
+
merged.workspace = workspace;
|
|
73
|
+
|
|
74
|
+
// Validate required fields
|
|
75
|
+
if (!merged.apiKey || !merged.projectId) {
|
|
76
|
+
throw new Error("apiKey and projectId are required");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return merged;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// CLI mode: only run when invoked directly via `node get-config.mjs ...`,
|
|
83
|
+
// not when imported as a module. Keeps the SKILL.md-documented CLI behavior
|
|
84
|
+
// identical (JSON to stdout, errors to stderr, non-zero exit on failure).
|
|
85
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
86
|
+
const args = process.argv.slice(2);
|
|
87
|
+
const wsIdx = args.indexOf("--workspace");
|
|
88
|
+
if (wsIdx === -1 || !args[wsIdx + 1]) {
|
|
89
|
+
console.error("Usage: node get-config.mjs --workspace <workspaceDir>");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const workspace = args[wsIdx + 1];
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const merged = loadConfig({ workspace });
|
|
96
|
+
console.log(JSON.stringify(merged, null, 2));
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -25,7 +25,7 @@ The caller must provide:
|
|
|
25
25
|
**Always try the script first.** The script is at `scripts/migrate.mjs` relative to this SKILL.md (i.e., in the `scripts/` subdirectory of this skill). Run:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
node <path-to-this-skill-directory>/scripts/migrate.mjs --agent {agent} --user-id {user_id}
|
|
28
|
+
node <path-to-this-skill-directory>/scripts/migrate.mjs --agent {agent} --workspace {workspace} --user-id {user_id}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
The script handles everything: config reading, session filtering, JSONL parsing, memory file collection, and API submission.
|
|
@@ -40,10 +40,10 @@ If the script fails, follow these steps manually.
|
|
|
40
40
|
|
|
41
41
|
### Step 1 — Read MemoryLake Config
|
|
42
42
|
|
|
43
|
-
Run the common config script (path is relative to **this skill's SKILL.md**, i.e.
|
|
43
|
+
Run the common config script (path is relative to **this skill's SKILL.md**, i.e. `scripts/get-config.mjs`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
node {path-to-this-skill}
|
|
46
|
+
node {path-to-this-skill}/scripts/get-config.mjs --workspace {workspace}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
The script outputs JSON config with `host`, `apiKey`, `projectId`, `workspace`, etc. If the script exits with an error, stop and inform the user.
|
|
@@ -74,7 +74,7 @@ The script outputs JSON config with `host`, `apiKey`, `projectId`, `workspace`,
|
|
|
74
74
|
|
|
75
75
|
### Step 3 — Read Memory Files
|
|
76
76
|
|
|
77
|
-
Use the `workspace` path
|
|
77
|
+
Use the agent's `{workspace}` directory (the same path passed in Step 1, and echoed back as the `workspace` field in the config output). Then read:
|
|
78
78
|
- `{workspace}/MEMORY.md`
|
|
79
79
|
- All files in `{workspace}/memory/` directory
|
|
80
80
|
|
|
@@ -184,10 +184,10 @@ At the end, print a summary:
|
|
|
184
184
|
|
|
185
185
|
| Item | Path / Value |
|
|
186
186
|
|------|-------------|
|
|
187
|
-
| Config script | `{path-to-this-skill}
|
|
187
|
+
| Config script | `{path-to-this-skill}/scripts/get-config.mjs --workspace {workspace}` |
|
|
188
188
|
| Session index | `~/.openclaw/agents/{agent}/sessions/sessions.json` |
|
|
189
189
|
| Session files | `~/.openclaw/agents/{agent}/sessions/{id}.jsonl` |
|
|
190
|
-
| Workspace path |
|
|
190
|
+
| Workspace path | the current agent's workspace directory (`{workspace}`; echoed back in the config output) |
|
|
191
191
|
| API endpoint | `{host}/openapi/memorylake/api/v2/projects/{projectId}/memories` |
|
|
192
192
|
| Auth header | `Authorization: Bearer {apiKey}` |
|
|
193
193
|
| Default host | `https://app.memorylake.ai` |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import JSON5 from "json5";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// CANONICAL SOURCE. This file is synced verbatim into each consuming skill's
|
|
11
|
+
// `scripts/` directory by `scripts/sync-skills.mjs` (run via the package
|
|
12
|
+
// `prepare` script). Edit THIS file only — never edit the generated copies.
|
|
13
|
+
//
|
|
14
|
+
// Why the copies exist: the OpenClaw skill mechanism links each skill
|
|
15
|
+
// individually into `~/.openclaw/skills/<name>/`, so a shared sibling such as
|
|
16
|
+
// `skills/common/` is no longer reachable from a skill via a relative path.
|
|
17
|
+
// Each skill therefore carries its own copy and references it as
|
|
18
|
+
// `{path-to-this-skill}/scripts/get-config.mjs`.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Load the merged MemoryLake plugin config for a given workspace.
|
|
23
|
+
*
|
|
24
|
+
* Reads the global `~/.openclaw/openclaw.json` config, picks up the
|
|
25
|
+
* `memorylake-openclaw` plugin config, and merges any per-workspace overrides
|
|
26
|
+
* from `<workspace>/.memorylake/config.json`.
|
|
27
|
+
*
|
|
28
|
+
* The caller passes the workspace directly — the running agent already knows
|
|
29
|
+
* its own workspace (it is the agent's working directory, the same value the
|
|
30
|
+
* `agent-memorylake-config` skill writes into). We deliberately do NOT shell
|
|
31
|
+
* out to resolve it from an agent id: the only thing a workspace is needed for
|
|
32
|
+
* here is locating the per-workspace override file, so taking it as input keeps
|
|
33
|
+
* this script dependency-free and side-effect-free.
|
|
34
|
+
*
|
|
35
|
+
* @param {{ workspace: string }} opts
|
|
36
|
+
* @returns {{ apiKey: string, projectId: string, host: string, workspace: string, [key: string]: unknown }}
|
|
37
|
+
* Merged config object. Throws on any failure (missing workspace, missing
|
|
38
|
+
* plugin config, missing required fields, parse errors).
|
|
39
|
+
*/
|
|
40
|
+
export function loadConfig({ workspace }) {
|
|
41
|
+
if (!workspace || typeof workspace !== "string") {
|
|
42
|
+
throw new Error("workspace is required");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Read global plugin config (apiKey/projectId/host/...) from openclaw.json.
|
|
46
|
+
const openclawPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
47
|
+
let openclaw;
|
|
48
|
+
try {
|
|
49
|
+
openclaw = JSON5.parse(readFileSync(openclawPath, "utf-8"));
|
|
50
|
+
} catch (err) {
|
|
51
|
+
throw new Error(`failed to parse JSON5 config file "${openclawPath}": ${String(err)}`);
|
|
52
|
+
}
|
|
53
|
+
const globalCfg = openclaw?.plugins?.entries?.["memorylake-openclaw"]?.config;
|
|
54
|
+
if (!globalCfg) {
|
|
55
|
+
throw new Error("memorylake-openclaw plugin config not found");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Merge per-workspace overrides
|
|
59
|
+
const merged = { ...globalCfg };
|
|
60
|
+
const localPath = join(workspace, ".memorylake", "config.json");
|
|
61
|
+
if (existsSync(localPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const raw = JSON.parse(readFileSync(localPath, "utf-8"));
|
|
64
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
65
|
+
Object.assign(merged, raw);
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
throw new Error(`failed to parse workspace config at ${localPath}: ${String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
merged.host = merged.host || "https://app.memorylake.ai";
|
|
72
|
+
merged.workspace = workspace;
|
|
73
|
+
|
|
74
|
+
// Validate required fields
|
|
75
|
+
if (!merged.apiKey || !merged.projectId) {
|
|
76
|
+
throw new Error("apiKey and projectId are required");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return merged;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// CLI mode: only run when invoked directly via `node get-config.mjs ...`,
|
|
83
|
+
// not when imported as a module. Keeps the SKILL.md-documented CLI behavior
|
|
84
|
+
// identical (JSON to stdout, errors to stderr, non-zero exit on failure).
|
|
85
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
86
|
+
const args = process.argv.slice(2);
|
|
87
|
+
const wsIdx = args.indexOf("--workspace");
|
|
88
|
+
if (wsIdx === -1 || !args[wsIdx + 1]) {
|
|
89
|
+
console.error("Usage: node get-config.mjs --workspace <workspaceDir>");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const workspace = args[wsIdx + 1];
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const merged = loadConfig({ workspace });
|
|
96
|
+
console.log(JSON.stringify(merged, null, 2));
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -11,14 +11,14 @@ import { readFileSync, readdirSync, existsSync, statSync } from "fs";
|
|
|
11
11
|
import { join, basename } from "path";
|
|
12
12
|
import { homedir } from "os";
|
|
13
13
|
import { parseArgs } from "util";
|
|
14
|
-
import { loadConfig as loadConfigShared } from "
|
|
14
|
+
import { loadConfig as loadConfigShared } from "./get-config.mjs";
|
|
15
15
|
|
|
16
16
|
const BATCH_SIZE = 20;
|
|
17
17
|
const API_USER_ID = "default";
|
|
18
18
|
|
|
19
|
-
function loadConfig(
|
|
19
|
+
function loadConfig(workspace) {
|
|
20
20
|
try {
|
|
21
|
-
return loadConfigShared({
|
|
21
|
+
return loadConfigShared({ workspace });
|
|
22
22
|
} catch (err) {
|
|
23
23
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
24
24
|
process.exit(1);
|
|
@@ -249,22 +249,28 @@ async function main() {
|
|
|
249
249
|
const { values } = parseArgs({
|
|
250
250
|
options: {
|
|
251
251
|
agent: { type: "string" },
|
|
252
|
+
workspace: { type: "string" },
|
|
252
253
|
"user-id": { type: "string" },
|
|
253
254
|
},
|
|
254
255
|
strict: true,
|
|
255
256
|
});
|
|
256
257
|
|
|
257
258
|
const agent = values.agent;
|
|
259
|
+
const workspace = values.workspace;
|
|
258
260
|
const userId = values["user-id"];
|
|
259
261
|
|
|
260
|
-
if (!agent || !userId) {
|
|
261
|
-
console.error(
|
|
262
|
+
if (!agent || !workspace || !userId) {
|
|
263
|
+
console.error(
|
|
264
|
+
"Usage: node migrate.mjs --agent <agent> --workspace <path> --user-id <user_id>",
|
|
265
|
+
);
|
|
262
266
|
process.exit(1);
|
|
263
267
|
}
|
|
264
268
|
|
|
265
269
|
console.log("=== Migrate Memories to MemoryLake ===\n");
|
|
266
270
|
|
|
267
|
-
|
|
271
|
+
// `agent` keys the sessions dir (~/.openclaw/agents/<agent>/sessions); the
|
|
272
|
+
// workspace holds the memory files and the per-workspace config override.
|
|
273
|
+
const { host, apiKey, projectId } = loadConfig(workspace);
|
|
268
274
|
console.log(`Host: ${host}`);
|
|
269
275
|
console.log(`Project: ${projectId}`);
|
|
270
276
|
console.log(`Agent: ${agent}`);
|