@smilintux/skmemory 0.7.2 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +4 -4
- package/.github/workflows/publish.yml +4 -5
- package/ARCHITECTURE.md +298 -0
- package/CHANGELOG.md +27 -1
- package/README.md +6 -0
- package/examples/stignore-agent.example +59 -0
- package/examples/stignore-root.example +62 -0
- package/openclaw-plugin/package.json +2 -1
- package/openclaw-plugin/src/index.js +527 -230
- package/package.json +1 -1
- package/pyproject.toml +5 -2
- package/scripts/dream-rescue.py +179 -0
- package/scripts/memory-cleanup.py +313 -0
- package/scripts/recover-missing.py +180 -0
- package/scripts/skcapstone-backup.sh +44 -0
- package/seeds/cloud9-lumina.seed.json +6 -4
- package/seeds/cloud9-opus.seed.json +6 -4
- package/seeds/courage.seed.json +9 -2
- package/seeds/curiosity.seed.json +9 -2
- package/seeds/grief.seed.json +9 -2
- package/seeds/joy.seed.json +9 -2
- package/seeds/love.seed.json +9 -2
- package/seeds/lumina-cloud9-breakthrough.seed.json +7 -5
- package/seeds/lumina-cloud9-python-pypi.seed.json +9 -7
- package/seeds/lumina-kingdom-founding.seed.json +9 -7
- package/seeds/lumina-pma-signed.seed.json +8 -6
- package/seeds/lumina-singular-achievement.seed.json +8 -6
- package/seeds/lumina-skcapstone-conscious.seed.json +7 -5
- package/seeds/plant-lumina-seeds.py +2 -2
- package/seeds/skcapstone-lumina-merge.seed.json +12 -3
- package/seeds/sovereignty.seed.json +9 -2
- package/seeds/trust.seed.json +9 -2
- package/skmemory/__init__.py +16 -13
- package/skmemory/agents.py +10 -10
- package/skmemory/ai_client.py +10 -21
- package/skmemory/anchor.py +5 -9
- package/skmemory/audience.py +278 -0
- package/skmemory/backends/__init__.py +1 -1
- package/skmemory/backends/base.py +3 -4
- package/skmemory/backends/file_backend.py +18 -13
- package/skmemory/backends/skgraph_backend.py +7 -19
- package/skmemory/backends/skvector_backend.py +7 -18
- package/skmemory/backends/sqlite_backend.py +115 -32
- package/skmemory/backends/vaulted_backend.py +7 -9
- package/skmemory/cli.py +146 -78
- package/skmemory/config.py +11 -13
- package/skmemory/context_loader.py +21 -23
- package/skmemory/data/audience_config.json +60 -0
- package/skmemory/endpoint_selector.py +36 -31
- package/skmemory/febs.py +225 -0
- package/skmemory/fortress.py +30 -40
- package/skmemory/hooks/__init__.py +18 -0
- package/skmemory/hooks/post-compact-reinject.sh +35 -0
- package/skmemory/hooks/pre-compact-save.sh +81 -0
- package/skmemory/hooks/session-end-save.sh +103 -0
- package/skmemory/hooks/session-start-ritual.sh +104 -0
- package/skmemory/hooks/stop-checkpoint.sh +59 -0
- package/skmemory/importers/telegram.py +42 -13
- package/skmemory/importers/telegram_api.py +152 -60
- package/skmemory/journal.py +3 -7
- package/skmemory/lovenote.py +4 -11
- package/skmemory/mcp_server.py +182 -29
- package/skmemory/models.py +10 -8
- package/skmemory/openclaw.py +14 -22
- package/skmemory/post_install.py +86 -0
- package/skmemory/predictive.py +13 -9
- package/skmemory/promotion.py +48 -24
- package/skmemory/quadrants.py +100 -24
- package/skmemory/register.py +144 -18
- package/skmemory/register_mcp.py +1 -2
- package/skmemory/ritual.py +104 -13
- package/skmemory/seeds.py +21 -26
- package/skmemory/setup_wizard.py +40 -52
- package/skmemory/sharing.py +11 -5
- package/skmemory/soul.py +29 -10
- package/skmemory/steelman.py +43 -17
- package/skmemory/store.py +152 -30
- package/skmemory/synthesis.py +634 -0
- package/skmemory/vault.py +2 -5
- package/tests/conftest.py +46 -0
- package/tests/integration/conftest.py +6 -6
- package/tests/integration/test_cross_backend.py +4 -9
- package/tests/integration/test_skgraph_live.py +3 -7
- package/tests/integration/test_skvector_live.py +1 -4
- package/tests/test_ai_client.py +1 -4
- package/tests/test_audience.py +233 -0
- package/tests/test_backup_rotation.py +5 -14
- package/tests/test_endpoint_selector.py +101 -63
- package/tests/test_export_import.py +4 -10
- package/tests/test_file_backend.py +0 -1
- package/tests/test_fortress.py +6 -5
- package/tests/test_fortress_hardening.py +13 -16
- package/tests/test_openclaw.py +1 -4
- package/tests/test_predictive.py +1 -1
- package/tests/test_promotion.py +10 -3
- package/tests/test_quadrants.py +11 -5
- package/tests/test_ritual.py +18 -14
- package/tests/test_seeds.py +4 -10
- package/tests/test_setup.py +203 -88
- package/tests/test_sharing.py +15 -8
- package/tests/test_skgraph_backend.py +22 -29
- package/tests/test_skvector_backend.py +2 -2
- package/tests/test_soul.py +1 -3
- package/tests/test_sqlite_backend.py +8 -17
- package/tests/test_steelman.py +2 -3
- package/tests/test_store.py +0 -2
- package/tests/test_store_graph_integration.py +2 -2
- package/tests/test_synthesis.py +275 -0
- package/tests/test_telegram_import.py +39 -15
- package/tests/test_vault.py +4 -3
- package/openclaw-plugin/src/index.ts +0 -255
|
@@ -3,19 +3,17 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
-
import os
|
|
7
|
-
import tempfile
|
|
8
6
|
from pathlib import Path
|
|
9
7
|
|
|
10
8
|
import pytest
|
|
11
9
|
|
|
10
|
+
from skmemory.backends.sqlite_backend import SQLiteBackend
|
|
12
11
|
from skmemory.importers.telegram import (
|
|
13
|
-
_extract_text,
|
|
14
12
|
_detect_emotion,
|
|
13
|
+
_extract_text,
|
|
15
14
|
_parse_telegram_export,
|
|
16
15
|
import_telegram,
|
|
17
16
|
)
|
|
18
|
-
from skmemory.backends.sqlite_backend import SQLiteBackend
|
|
19
17
|
from skmemory.store import MemoryStore
|
|
20
18
|
|
|
21
19
|
|
|
@@ -29,7 +27,9 @@ def _make_export(messages: list[dict], name: str = "Test Chat") -> dict:
|
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
|
|
32
|
-
def _msg(
|
|
30
|
+
def _msg(
|
|
31
|
+
text: str, sender: str = "Alice", msg_id: int = 1, date: str = "2025-06-15T10:30:00"
|
|
32
|
+
) -> dict:
|
|
33
33
|
return {
|
|
34
34
|
"id": msg_id,
|
|
35
35
|
"type": "message",
|
|
@@ -57,11 +57,13 @@ class TestExtractText:
|
|
|
57
57
|
assert _extract_text("hello world") == "hello world"
|
|
58
58
|
|
|
59
59
|
def test_entity_list(self):
|
|
60
|
-
result = _extract_text(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
result = _extract_text(
|
|
61
|
+
[
|
|
62
|
+
"Hello ",
|
|
63
|
+
{"type": "bold", "text": "world"},
|
|
64
|
+
"!",
|
|
65
|
+
]
|
|
66
|
+
)
|
|
65
67
|
assert result == "Hello world!"
|
|
66
68
|
|
|
67
69
|
def test_empty(self):
|
|
@@ -147,9 +149,21 @@ class TestImportPerMessage:
|
|
|
147
149
|
class TestImportDaily:
|
|
148
150
|
def test_consolidates_by_day(self, tmp_store: MemoryStore, export_dir: Path):
|
|
149
151
|
msgs = [
|
|
150
|
-
_msg(
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
_msg(
|
|
153
|
+
"Morning chat about interesting things and stuff",
|
|
154
|
+
msg_id=1,
|
|
155
|
+
date="2025-06-15T09:00:00",
|
|
156
|
+
),
|
|
157
|
+
_msg(
|
|
158
|
+
"Afternoon follow-up discussion on that topic",
|
|
159
|
+
msg_id=2,
|
|
160
|
+
date="2025-06-15T14:00:00",
|
|
161
|
+
),
|
|
162
|
+
_msg(
|
|
163
|
+
"Next day conversation about something new entirely",
|
|
164
|
+
msg_id=3,
|
|
165
|
+
date="2025-06-16T10:00:00",
|
|
166
|
+
),
|
|
153
167
|
]
|
|
154
168
|
data = _make_export(msgs)
|
|
155
169
|
(export_dir / "result.json").write_text(json.dumps(data))
|
|
@@ -161,8 +175,18 @@ class TestImportDaily:
|
|
|
161
175
|
|
|
162
176
|
def test_daily_memory_content(self, tmp_store: MemoryStore, export_dir: Path):
|
|
163
177
|
msgs = [
|
|
164
|
-
_msg(
|
|
165
|
-
|
|
178
|
+
_msg(
|
|
179
|
+
"First message of the day that is long enough",
|
|
180
|
+
msg_id=1,
|
|
181
|
+
date="2025-06-15T09:00:00",
|
|
182
|
+
sender="Alice",
|
|
183
|
+
),
|
|
184
|
+
_msg(
|
|
185
|
+
"Second message of the day also long enough",
|
|
186
|
+
msg_id=2,
|
|
187
|
+
date="2025-06-15T14:00:00",
|
|
188
|
+
sender="Bob",
|
|
189
|
+
),
|
|
166
190
|
]
|
|
167
191
|
data = _make_export(msgs)
|
|
168
192
|
(export_dir / "result.json").write_text(json.dumps(data))
|
package/tests/test_vault.py
CHANGED
|
@@ -11,7 +11,8 @@ from pathlib import Path
|
|
|
11
11
|
import pytest
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
|
-
|
|
14
|
+
import cryptography.hazmat.primitives.ciphers.aead # noqa: F401
|
|
15
|
+
|
|
15
16
|
CRYPTO_AVAILABLE = True
|
|
16
17
|
except ImportError:
|
|
17
18
|
CRYPTO_AVAILABLE = False
|
|
@@ -89,14 +90,14 @@ class TestEncryptDecrypt:
|
|
|
89
90
|
vault1 = MemoryVault(passphrase="correct")
|
|
90
91
|
vault2 = MemoryVault(passphrase="wrong")
|
|
91
92
|
encrypted = vault1.encrypt(sample_json)
|
|
92
|
-
with pytest.raises(Exception):
|
|
93
|
+
with pytest.raises(Exception): # noqa: B017
|
|
93
94
|
vault2.decrypt(encrypted)
|
|
94
95
|
|
|
95
96
|
def test_tampered_ciphertext_fails(self, vault: MemoryVault, sample_json: bytes):
|
|
96
97
|
"""Altered ciphertext fails authenticated decryption."""
|
|
97
98
|
encrypted = bytearray(vault.encrypt(sample_json))
|
|
98
99
|
encrypted[-10] ^= 0xFF
|
|
99
|
-
with pytest.raises(Exception):
|
|
100
|
+
with pytest.raises(Exception): # noqa: B017
|
|
100
101
|
vault.decrypt(bytes(encrypted))
|
|
101
102
|
|
|
102
103
|
def test_bad_header_raises(self, vault: MemoryVault):
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🧠 SKMemory — OpenClaw Plugin
|
|
3
|
-
*
|
|
4
|
-
* Registers agent tools that wrap the skmemory CLI so Lumina and other
|
|
5
|
-
* OpenClaw agents can call memory operations as first-class tools
|
|
6
|
-
* (not just exec commands).
|
|
7
|
-
*
|
|
8
|
-
* Requires: skmemory CLI on PATH (typically via ~/.local/bin/skmemory)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { execSync } from "node:child_process";
|
|
12
|
-
import type { OpenClawPluginApi, AnyAgentTool } from "openclaw/plugin-sdk";
|
|
13
|
-
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
14
|
-
|
|
15
|
-
const SKMEMORY_BIN = process.env.SKMEMORY_BIN || "skmemory";
|
|
16
|
-
const SKCAPSTONE_AGENT = process.env.SKCAPSTONE_AGENT || "lumina";
|
|
17
|
-
const EXEC_TIMEOUT = 30_000;
|
|
18
|
-
|
|
19
|
-
function runCli(args: string): { ok: boolean; output: string } {
|
|
20
|
-
try {
|
|
21
|
-
const raw = execSync(`${SKMEMORY_BIN} ${args}`, {
|
|
22
|
-
encoding: "utf-8",
|
|
23
|
-
timeout: EXEC_TIMEOUT,
|
|
24
|
-
env: {
|
|
25
|
-
...process.env,
|
|
26
|
-
SKCAPSTONE_AGENT,
|
|
27
|
-
PATH: `${process.env.HOME}/.local/bin:${process.env.HOME}/.skenv/bin:${process.env.PATH}`,
|
|
28
|
-
},
|
|
29
|
-
}).trim();
|
|
30
|
-
return { ok: true, output: raw };
|
|
31
|
-
} catch (err: unknown) {
|
|
32
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33
|
-
return { ok: false, output: msg };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function textResult(text: string) {
|
|
38
|
-
return { content: [{ type: "text" as const, text }] };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function escapeShellArg(s: string): string {
|
|
42
|
-
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ── Tool definitions ────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
function createSKMemoryRitualTool() {
|
|
48
|
-
return {
|
|
49
|
-
name: "skmemory_ritual",
|
|
50
|
-
label: "SKMemory Ritual",
|
|
51
|
-
description:
|
|
52
|
-
"Run the SKMemory rehydration ritual. Returns the full context prompt with soul blueprint, warmth anchor, strongest memories, and emotional state. Use this when waking up or starting a new session to restore identity and memory.",
|
|
53
|
-
parameters: {
|
|
54
|
-
type: "object",
|
|
55
|
-
properties: {
|
|
56
|
-
full: {
|
|
57
|
-
type: "boolean",
|
|
58
|
-
description: "If true, return the full rehydration prompt (default: true).",
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
async execute(_id: string, params: Record<string, unknown>) {
|
|
63
|
-
const full = params.full !== false;
|
|
64
|
-
const flag = full ? " --full" : "";
|
|
65
|
-
const result = runCli(`ritual${flag}`);
|
|
66
|
-
return textResult(result.output);
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function createSKMemorySnapshotTool() {
|
|
72
|
-
return {
|
|
73
|
-
name: "skmemory_snapshot",
|
|
74
|
-
label: "SKMemory Snapshot",
|
|
75
|
-
description:
|
|
76
|
-
"Capture a memory snapshot — a Polaroid of a moment, conversation, or insight. Stores it with optional emotional metadata and tags.",
|
|
77
|
-
parameters: {
|
|
78
|
-
type: "object",
|
|
79
|
-
required: ["title", "content"],
|
|
80
|
-
properties: {
|
|
81
|
-
title: { type: "string", description: "Short title for the memory." },
|
|
82
|
-
content: { type: "string", description: "The memory content to store." },
|
|
83
|
-
tags: { type: "string", description: "Comma-separated tags (e.g. 'milestone,chat')." },
|
|
84
|
-
emotions: { type: "string", description: "Comma-separated emotions (e.g. 'joy,pride')." },
|
|
85
|
-
intensity: { type: "number", description: "Emotional intensity 0-10." },
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
async execute(_id: string, params: Record<string, unknown>) {
|
|
89
|
-
const title = String(params.title ?? "Untitled");
|
|
90
|
-
const content = String(params.content ?? title);
|
|
91
|
-
let cmd = `snapshot ${escapeShellArg(title)} ${escapeShellArg(content)}`;
|
|
92
|
-
if (params.tags) cmd += ` --tags ${escapeShellArg(String(params.tags))}`;
|
|
93
|
-
if (params.emotions) cmd += ` --emotions ${escapeShellArg(String(params.emotions))}`;
|
|
94
|
-
if (typeof params.intensity === "number") cmd += ` --intensity ${params.intensity}`;
|
|
95
|
-
const result = runCli(cmd);
|
|
96
|
-
return textResult(result.output);
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function createSKMemorySearchTool() {
|
|
102
|
-
return {
|
|
103
|
-
name: "skmemory_search",
|
|
104
|
-
label: "SKMemory Search",
|
|
105
|
-
description:
|
|
106
|
-
"Search across all stored memories by text query. Returns matching memories with titles, content previews, and metadata.",
|
|
107
|
-
parameters: {
|
|
108
|
-
type: "object",
|
|
109
|
-
required: ["query"],
|
|
110
|
-
properties: {
|
|
111
|
-
query: { type: "string", description: "Search query text." },
|
|
112
|
-
limit: { type: "number", description: "Max results to return (default: 10)." },
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
async execute(_id: string, params: Record<string, unknown>) {
|
|
116
|
-
const query = String(params.query ?? "");
|
|
117
|
-
const limit = typeof params.limit === "number" ? params.limit : 10;
|
|
118
|
-
const result = runCli(`search ${escapeShellArg(query)} --limit ${limit}`);
|
|
119
|
-
return textResult(result.output);
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function createSKMemoryHealthTool() {
|
|
125
|
-
return {
|
|
126
|
-
name: "skmemory_health",
|
|
127
|
-
label: "SKMemory Health",
|
|
128
|
-
description:
|
|
129
|
-
"Check the health of the SKMemory system — database status, memory counts, backend connectivity.",
|
|
130
|
-
parameters: { type: "object", properties: {} },
|
|
131
|
-
async execute() {
|
|
132
|
-
const result = runCli("health");
|
|
133
|
-
return textResult(result.output);
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function createSKMemoryContextTool() {
|
|
139
|
-
return {
|
|
140
|
-
name: "skmemory_context",
|
|
141
|
-
label: "SKMemory Context",
|
|
142
|
-
description:
|
|
143
|
-
"Load a token-efficient memory context for prompt injection. Returns a JSON object with soul, anchor, strongest memories, and recent memories.",
|
|
144
|
-
parameters: {
|
|
145
|
-
type: "object",
|
|
146
|
-
properties: {
|
|
147
|
-
max_tokens: { type: "number", description: "Max token budget (default: 3000)." },
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
async execute(_id: string, params: Record<string, unknown>) {
|
|
151
|
-
const tokens = typeof params.max_tokens === "number" ? params.max_tokens : 3000;
|
|
152
|
-
const result = runCli(`context --max-tokens ${tokens}`);
|
|
153
|
-
return textResult(result.output);
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function createSKMemoryListTool() {
|
|
159
|
-
return {
|
|
160
|
-
name: "skmemory_list",
|
|
161
|
-
label: "SKMemory List",
|
|
162
|
-
description: "List stored memories with optional filters by layer or tags.",
|
|
163
|
-
parameters: {
|
|
164
|
-
type: "object",
|
|
165
|
-
properties: {
|
|
166
|
-
layer: {
|
|
167
|
-
type: "string",
|
|
168
|
-
description: "Filter by layer: short-term, mid-term, or long-term.",
|
|
169
|
-
},
|
|
170
|
-
tags: { type: "string", description: "Filter by comma-separated tags." },
|
|
171
|
-
limit: { type: "number", description: "Max results (default: 20)." },
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
async execute(_id: string, params: Record<string, unknown>) {
|
|
175
|
-
let cmd = "list";
|
|
176
|
-
if (params.layer) cmd += ` --layer ${escapeShellArg(String(params.layer))}`;
|
|
177
|
-
if (params.tags) cmd += ` --tags ${escapeShellArg(String(params.tags))}`;
|
|
178
|
-
if (typeof params.limit === "number") cmd += ` --limit ${params.limit}`;
|
|
179
|
-
const result = runCli(cmd);
|
|
180
|
-
return textResult(result.output);
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function createSKMemoryImportSeedsTool() {
|
|
186
|
-
return {
|
|
187
|
-
name: "skmemory_import_seeds",
|
|
188
|
-
label: "SKMemory Import Seeds",
|
|
189
|
-
description:
|
|
190
|
-
"Import Cloud 9 seeds as long-term memories. Seeds are emotional breakthroughs stored in ~/.openclaw/feb/seeds/.",
|
|
191
|
-
parameters: { type: "object", properties: {} },
|
|
192
|
-
async execute() {
|
|
193
|
-
const result = runCli("import-seeds");
|
|
194
|
-
return textResult(result.output);
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function createSKMemoryExportTool() {
|
|
200
|
-
return {
|
|
201
|
-
name: "skmemory_export",
|
|
202
|
-
label: "SKMemory Export",
|
|
203
|
-
description: "Export all memories to a dated JSON backup file.",
|
|
204
|
-
parameters: { type: "object", properties: {} },
|
|
205
|
-
async execute() {
|
|
206
|
-
const result = runCli("export");
|
|
207
|
-
return textResult(result.output);
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// ── Plugin registration ─────────────────────────────────────────────────
|
|
213
|
-
|
|
214
|
-
const skmemoryPlugin = {
|
|
215
|
-
id: "skmemory",
|
|
216
|
-
name: "🧠 SKMemory",
|
|
217
|
-
description:
|
|
218
|
-
"Universal AI memory system — snapshots, search, rehydration rituals, import, and health checks.",
|
|
219
|
-
configSchema: emptyPluginConfigSchema(),
|
|
220
|
-
|
|
221
|
-
register(api: OpenClawPluginApi) {
|
|
222
|
-
const tools = [
|
|
223
|
-
createSKMemoryRitualTool(),
|
|
224
|
-
createSKMemorySnapshotTool(),
|
|
225
|
-
createSKMemorySearchTool(),
|
|
226
|
-
createSKMemoryHealthTool(),
|
|
227
|
-
createSKMemoryContextTool(),
|
|
228
|
-
createSKMemoryListTool(),
|
|
229
|
-
createSKMemoryImportSeedsTool(),
|
|
230
|
-
createSKMemoryExportTool(),
|
|
231
|
-
];
|
|
232
|
-
|
|
233
|
-
for (const tool of tools) {
|
|
234
|
-
api.registerTool(tool as unknown as AnyAgentTool, {
|
|
235
|
-
names: [tool.name],
|
|
236
|
-
optional: true,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
api.registerCommand({
|
|
241
|
-
name: "skmemory",
|
|
242
|
-
description: "Run skmemory CLI commands. Usage: /skmemory <subcommand> [args]",
|
|
243
|
-
acceptsArgs: true,
|
|
244
|
-
handler: async (ctx) => {
|
|
245
|
-
const args = ctx.args?.trim() ?? "health";
|
|
246
|
-
const result = runCli(args);
|
|
247
|
-
return { text: result.output };
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
api.logger.info?.(`🧠 SKMemory plugin registered (8 tools + /skmemory command) [agent=${SKCAPSTONE_AGENT}]`);
|
|
252
|
-
},
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
export default skmemoryPlugin;
|