@alfe.ai/openclaw-memory-cloud 0.0.38 → 0.0.39

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.
Files changed (58) hide show
  1. package/README.md +37 -0
  2. package/dist/index.cjs +2 -0
  3. package/dist/index.d.cts +2 -0
  4. package/dist/index.d.ts +2 -60
  5. package/dist/index.js +2 -396
  6. package/dist/plugin.cjs +2 -0
  7. package/dist/plugin.d.cts +59 -0
  8. package/dist/plugin.d.cts.map +1 -0
  9. package/dist/plugin.d.ts +59 -0
  10. package/dist/plugin.d.ts.map +1 -0
  11. package/dist/plugin.js +2 -0
  12. package/dist/plugin2.cjs +1107 -0
  13. package/dist/plugin2.d.cts +2 -0
  14. package/dist/plugin2.d.ts +2 -0
  15. package/dist/plugin2.js +1104 -0
  16. package/dist/plugin2.js.map +1 -0
  17. package/openclaw.plugin.json +6 -5
  18. package/package.json +27 -7
  19. package/.turbo/turbo-build.log +0 -4
  20. package/CHANGELOG.md +0 -320
  21. package/dist/auto-capture.d.ts +0 -45
  22. package/dist/auto-capture.d.ts.map +0 -1
  23. package/dist/auto-capture.js +0 -101
  24. package/dist/auto-capture.js.map +0 -1
  25. package/dist/auto-recall.d.ts +0 -22
  26. package/dist/auto-recall.d.ts.map +0 -1
  27. package/dist/auto-recall.js +0 -63
  28. package/dist/auto-recall.js.map +0 -1
  29. package/dist/formatter.d.ts +0 -7
  30. package/dist/formatter.d.ts.map +0 -1
  31. package/dist/formatter.js +0 -27
  32. package/dist/formatter.js.map +0 -1
  33. package/dist/index.d.ts.map +0 -1
  34. package/dist/index.js.map +0 -1
  35. package/dist/ingest-epoch.d.ts +0 -38
  36. package/dist/ingest-epoch.d.ts.map +0 -1
  37. package/dist/ingest-epoch.js +0 -66
  38. package/dist/ingest-epoch.js.map +0 -1
  39. package/dist/session-backfill.d.ts +0 -54
  40. package/dist/session-backfill.d.ts.map +0 -1
  41. package/dist/session-backfill.js +0 -192
  42. package/dist/session-backfill.js.map +0 -1
  43. package/dist/types.d.ts +0 -113
  44. package/dist/types.d.ts.map +0 -1
  45. package/dist/types.js +0 -2
  46. package/dist/types.js.map +0 -1
  47. package/src/__tests__/auto-capture.test.ts +0 -115
  48. package/src/__tests__/ingest-epoch.test.ts +0 -67
  49. package/src/__tests__/session-backfill.test.ts +0 -289
  50. package/src/auto-capture.ts +0 -108
  51. package/src/auto-recall.ts +0 -66
  52. package/src/formatter.ts +0 -30
  53. package/src/index.ts +0 -464
  54. package/src/ingest-epoch.ts +0 -78
  55. package/src/session-backfill.ts +0 -220
  56. package/src/types.ts +0 -93
  57. package/sst-env.d.ts +0 -10
  58. package/tsconfig.json +0 -20
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # `@alfe.ai/openclaw-memory-cloud`
2
+
3
+ OpenClaw's private, per-agent cloud-memory plugin. It captures bounded
4
+ conversation windows, recalls escaped context, and exposes tools for vector
5
+ memory and the per-agent knowledge graph through the Alfe Agent API.
6
+
7
+ ## Safety model
8
+
9
+ Live capture state is isolated by the canonical OpenClaw `sessionKey`; there is
10
+ no process-wide current session. Flushes for one session are serialized so the
11
+ memory service's high-water mark cannot observe a later batch first. A
12
+ strictly monotonic, owner-only epoch fences daemon restarts. If that state
13
+ cannot be secured, auto-capture is disabled while recall and explicit tools
14
+ remain available.
15
+
16
+ `memory_forget` is a two-step operation: the first call previews up to five
17
+ current matches and the second must confirm those exact IDs in the same order.
18
+ `memory_learn` accepts bounded inline text or a regular, non-symlink file under
19
+ the configured runtime workspace. Service responses are normalized before
20
+ they reach the model, and recalled context is escaped and capped at 16 KiB.
21
+
22
+ ## Development
23
+
24
+ ```bash
25
+ pnpm --filter @alfe.ai/openclaw-memory-cloud lint
26
+ pnpm --filter @alfe.ai/openclaw-memory-cloud typecheck
27
+ pnpm --filter @alfe.ai/openclaw-memory-cloud test
28
+ pnpm --filter @alfe.ai/openclaw-memory-cloud build
29
+ ```
30
+
31
+ The package publishes ESM and CJS entrypoints. The OpenClaw loader uses the
32
+ default-only `./plugin` export. Keep the tool
33
+ catalog and configuration bounds aligned with `openclaw.plugin.json` and the
34
+ memory service's agent routes.
35
+
36
+ Part of [Alfe](https://alfe.ai). See the [documentation](https://docs.alfe.ai)
37
+ for platform setup.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ const require_plugin = require("./plugin2.cjs");
2
+ module.exports = require_plugin.plugin;
@@ -0,0 +1,2 @@
1
+ import { t as plugin } from "./plugin.cjs";
2
+ export { plugin as default };
package/dist/index.d.ts CHANGED
@@ -1,60 +1,2 @@
1
- /**
2
- * memory-cloud OpenClaw memory extension
3
- *
4
- * Replaces the builtin LanceDB memory extension with cloud-backed storage:
5
- * - Turbopuffer for vector storage (via services/memory Lambda proxy)
6
- * - DynamoDB for knowledge graph
7
- * - Haiku for classification + entity extraction
8
- *
9
- * Registers:
10
- * - Memory tools: memory_recall, memory_store, memory_forget, memory_navigate, memory_graph, memory_stats
11
- * - Lifecycle hooks: before_agent_start (auto-recall), agent_end (auto-capture), message_received (idle debounce)
12
- * - Memory runtime: replaces builtin SQLite backend with cloud backend
13
- */
14
- interface PluginApi {
15
- pluginConfig?: Record<string, unknown>;
16
- config: Record<string, unknown>;
17
- logger: {
18
- info: (msg: string, ctx?: Record<string, unknown>) => void;
19
- debug: (msg: string, ctx?: Record<string, unknown>) => void;
20
- warn: (msg: string, ctx?: Record<string, unknown>) => void;
21
- error: (msg: string, ctx?: Record<string, unknown>) => void;
22
- };
23
- registerTool: (factory: (ctx: ToolContext) => Tool, opts?: {
24
- names?: string[];
25
- }) => void;
26
- registerHook: (events: string | string[], handler: (...args: unknown[]) => unknown, opts?: {
27
- name?: string;
28
- description?: string;
29
- }) => void;
30
- on: (hookName: string, handler: (...args: unknown[]) => unknown, opts?: {
31
- priority?: number;
32
- }) => void;
33
- registerMemoryPromptSection: (builder: (params: {
34
- availableTools: Set<string>;
35
- }) => string[]) => void;
36
- registerMemoryRuntime: (runtime: unknown) => void;
37
- }
38
- interface ToolContext {
39
- agentId?: string;
40
- sessionKey?: string;
41
- sessionId?: string;
42
- messageChannel?: string;
43
- }
44
- interface Tool {
45
- name: string;
46
- label: string;
47
- description: string;
48
- parameters: Record<string, unknown>;
49
- execute: (toolCallId: string, params: Record<string, unknown>) => Promise<unknown>;
50
- }
51
- declare const _default: {
52
- id: string;
53
- name: string;
54
- description: string;
55
- version: string;
56
- kind: "memory";
57
- register(api: PluginApi): void;
58
- };
59
- export default _default;
60
- //# sourceMappingURL=index.d.ts.map
1
+ import { t as plugin } from "./plugin.js";
2
+ export { plugin as default };
package/dist/index.js CHANGED
@@ -1,396 +1,2 @@
1
- /**
2
- * memory-cloud OpenClaw memory extension
3
- *
4
- * Replaces the builtin LanceDB memory extension with cloud-backed storage:
5
- * - Turbopuffer for vector storage (via services/memory Lambda proxy)
6
- * - DynamoDB for knowledge graph
7
- * - Haiku for classification + entity extraction
8
- *
9
- * Registers:
10
- * - Memory tools: memory_recall, memory_store, memory_forget, memory_navigate, memory_graph, memory_stats
11
- * - Lifecycle hooks: before_agent_start (auto-recall), agent_end (auto-capture), message_received (idle debounce)
12
- * - Memory runtime: replaces builtin SQLite backend with cloud backend
13
- */
14
- import * as fs from "node:fs/promises";
15
- import * as path from "node:path";
16
- import { resolveConfig } from "@alfe.ai/config";
17
- import { AgentApiClient, installToolErrorCapture } from "@alfe.ai/agent-api-client";
18
- import { AutoCapture } from "./auto-capture.js";
19
- import { AutoRecall } from "./auto-recall.js";
20
- import { formatSearchResults } from "./formatter.js";
21
- import { runSessionsBackfill } from "./session-backfill.js";
22
- import { resolveIngestEpoch } from "./ingest-epoch.js";
23
- import { createRequire } from 'node:module';
24
- const require = createRequire(import.meta.url);
25
- const pkg = require('../package.json');
26
- const DEFAULT_CONFIG = {
27
- autoCapture: true,
28
- autoRecall: true,
29
- captureMaxChars: 500,
30
- idleFlushSeconds: 60,
31
- backfillSessions: true,
32
- backfillMaxSessions: 50,
33
- };
34
- function resolvePluginConfig(pluginConfig) {
35
- return {
36
- autoCapture: typeof pluginConfig?.autoCapture === "boolean" ? pluginConfig.autoCapture : DEFAULT_CONFIG.autoCapture,
37
- autoRecall: typeof pluginConfig?.autoRecall === "boolean" ? pluginConfig.autoRecall : DEFAULT_CONFIG.autoRecall,
38
- captureMaxChars: typeof pluginConfig?.captureMaxChars === "number" ? pluginConfig.captureMaxChars : DEFAULT_CONFIG.captureMaxChars,
39
- idleFlushSeconds: typeof pluginConfig?.idleFlushSeconds === "number" ? pluginConfig.idleFlushSeconds : DEFAULT_CONFIG.idleFlushSeconds,
40
- backfillSessions: typeof pluginConfig?.backfillSessions === "boolean" ? pluginConfig.backfillSessions : DEFAULT_CONFIG.backfillSessions,
41
- backfillMaxSessions: typeof pluginConfig?.backfillMaxSessions === "number" && Number.isFinite(pluginConfig.backfillMaxSessions) && pluginConfig.backfillMaxSessions > 0
42
- ? Math.floor(pluginConfig.backfillMaxSessions)
43
- : DEFAULT_CONFIG.backfillMaxSessions,
44
- };
45
- }
46
- export default {
47
- id: "@alfe.ai/openclaw-memory-cloud",
48
- name: "Cloud Memory",
49
- description: "Persistent agent memory backed by Turbopuffer + DynamoDB knowledge graph",
50
- version: pkg.version,
51
- kind: "memory",
52
- register(api) {
53
- // First thing, before any registerTool call: tool failures emit a
54
- // deterministic [ERROR] line the gateway's runtime-output monitor captures
55
- // to Sentry. See @alfe.ai/agent-api-client tool-error-capture.
56
- installToolErrorCapture(api, { plugin: "openclaw-memory-cloud" });
57
- const config = resolvePluginConfig(api.pluginConfig);
58
- const logger = api.logger;
59
- const alfeConfig = resolveConfig();
60
- const client = new AgentApiClient({
61
- apiKey: alfeConfig.apiKey,
62
- apiUrl: alfeConfig.apiUrl,
63
- });
64
- // Strictly-monotonic per-boot epoch, resolved once at process start.
65
- // Guards against a backward wall-clock step across a restart (which would
66
- // otherwise trap every live-capture flush in the server's stale-boot
67
- // branch and silently drop it). See ingest-epoch.ts.
68
- const ingestEpoch = resolveIngestEpoch({ logger });
69
- const autoCapture = new AutoCapture(client, config, logger, ingestEpoch);
70
- const autoRecall = new AutoRecall(client, config, logger);
71
- // ─── Memory prompt section ──────────────────────────────────
72
- api.registerMemoryPromptSection(({ availableTools }) => {
73
- const lines = ["## Memory"];
74
- if (availableTools.has("memory_recall")) {
75
- lines.push("Use memory_recall to search your conversation history and knowledge graph.");
76
- lines.push("Results include structured facts (from knowledge graph) and relevant conversation excerpts.");
77
- }
78
- if (availableTools.has("memory_store")) {
79
- lines.push("Use memory_store to explicitly save important information for future reference.");
80
- }
81
- if (availableTools.has("memory_learn")) {
82
- lines.push("Use memory_learn when the user asks you to learn or remember something — or when you read a doc with durable facts. Pass the source text directly; the system auto-classifies and extracts entities.");
83
- }
84
- if (availableTools.has("memory_graph")) {
85
- lines.push("Use memory_graph to look up what you know about a specific entity.");
86
- }
87
- return lines;
88
- });
89
- // ─── Tools ──────────────────────────────────────────────────
90
- api.registerTool(() => ({
91
- name: "memory_recall",
92
- label: "Memory Recall",
93
- description: "Search conversation memory and knowledge graph. Returns structured facts and relevant conversation excerpts.",
94
- parameters: {
95
- type: "object",
96
- properties: {
97
- query: { type: "string", description: "What to search for" },
98
- limit: { type: "number", description: "Maximum results (default 10)" },
99
- topic: { type: "string", description: "Filter by topic" },
100
- tag: { type: "string", description: "Filter by tag (fact/decision/preference/event/discovery)" },
101
- },
102
- required: ["query"],
103
- },
104
- execute: async (_toolCallId, params) => {
105
- const results = await client.memorySearch(params.query, {
106
- limit: params.limit,
107
- topic: params.topic,
108
- tag: params.tag,
109
- });
110
- return formatSearchResults(results);
111
- },
112
- }), { names: ["memory_recall", "memory_search"] });
113
- api.registerTool(() => ({
114
- name: "memory_store",
115
- label: "Memory Store",
116
- description: "Explicitly save a piece of information to long-term memory.",
117
- parameters: {
118
- type: "object",
119
- properties: {
120
- text: { type: "string", description: "The information to remember" },
121
- topic: { type: "string", description: "Topic category (e.g., person name, project)" },
122
- tag: { type: "string", description: "Memory type: fact, decision, preference, event, discovery" },
123
- importance: { type: "number", description: "Importance 0-1 (default 0.7)" },
124
- },
125
- required: ["text"],
126
- },
127
- execute: async (_toolCallId, params) => {
128
- const result = await client.memoryStore(params.text, {
129
- topic: params.topic,
130
- tag: params.tag,
131
- importance: params.importance,
132
- });
133
- return `Stored memory: ${result.memoryId}`;
134
- },
135
- }), { names: ["memory_store"] });
136
- api.registerTool(() => ({
137
- name: "memory_learn",
138
- label: "Memory Learn",
139
- description: "Save arbitrary content (a paragraph, a doc, a fact list) into long-term memory. The system auto-classifies and extracts entities. Use this when the user asks you to learn, remember, or study something — or when you read a document worth retaining. Pass the source text directly; do not paraphrase first.",
140
- parameters: {
141
- type: "object",
142
- properties: {
143
- content: { type: "string", description: "Inline text to ingest. Provide either content OR path, not both." },
144
- path: { type: "string", description: "Workspace-relative file path to read and ingest. Provide either content OR path, not both." },
145
- source: { type: "string", description: "Optional label describing where the content came from (e.g. doc title, url)." },
146
- },
147
- },
148
- execute: async (_toolCallId, params) => {
149
- const content = typeof params.content === "string" ? params.content : undefined;
150
- const filePath = typeof params.path === "string" ? params.path : undefined;
151
- const source = typeof params.source === "string" ? params.source : undefined;
152
- if (!content && !filePath) {
153
- return "Error: provide either `content` or `path`.";
154
- }
155
- if (content && filePath) {
156
- return "Error: provide either `content` or `path`, not both.";
157
- }
158
- let text;
159
- let resolvedSource = source;
160
- let sourceType = "inline";
161
- if (filePath !== undefined) {
162
- const cwd = process.cwd();
163
- const resolved = path.resolve(cwd, filePath);
164
- if (!resolved.startsWith(cwd + path.sep) && resolved !== cwd) {
165
- return `Error: path "${filePath}" escapes the workspace.`;
166
- }
167
- try {
168
- text = await fs.readFile(resolved, "utf8");
169
- }
170
- catch (err) {
171
- return `Error reading "${filePath}": ${err instanceof Error ? err.message : String(err)}`;
172
- }
173
- resolvedSource = source ?? filePath;
174
- sourceType = "file";
175
- }
176
- else if (content !== undefined) {
177
- text = content;
178
- }
179
- else {
180
- return "Error: provide either `content` or `path`.";
181
- }
182
- try {
183
- const result = await client.memoryLearn({ text, source: resolvedSource, sourceType });
184
- const label = result.source ?? "content";
185
- return `Stored ${String(result.memoriesStored)} memories (${String(result.triplesStored)} facts, ${String(result.chunks)} chunks) from ${label}.`;
186
- }
187
- catch (err) {
188
- logger.warn("memory_learn failed", { err: String(err) });
189
- return `Error: failed to store memory — ${err instanceof Error ? err.message : String(err)}`;
190
- }
191
- },
192
- }), { names: ["memory_learn"] });
193
- api.registerTool(() => ({
194
- name: "memory_forget",
195
- label: "Memory Forget",
196
- description: "Search for and delete memories matching a query.",
197
- parameters: {
198
- type: "object",
199
- properties: {
200
- query: { type: "string", description: "Search for memories to delete" },
201
- },
202
- required: ["query"],
203
- },
204
- execute: async (_toolCallId, params) => {
205
- const results = await client.memorySearch(params.query, { limit: 5 });
206
- if (results.memories.length === 0)
207
- return "No matching memories found.";
208
- const deleted = [];
209
- for (const mem of results.memories) {
210
- try {
211
- await client.memoryDelete(mem.id);
212
- deleted.push(mem.id);
213
- }
214
- catch {
215
- logger.warn("Failed to delete memory", { memoryId: mem.id });
216
- }
217
- }
218
- return `Deleted ${String(deleted.length)} of ${String(results.memories.length)} matching memories.`;
219
- },
220
- }), { names: ["memory_forget"] });
221
- api.registerTool(() => ({
222
- name: "memory_graph",
223
- label: "Knowledge Graph",
224
- description: "Look up what you know about a specific entity from the knowledge graph.",
225
- parameters: {
226
- type: "object",
227
- properties: {
228
- entity: { type: "string", description: "The entity to look up (person, concept, system)" },
229
- },
230
- required: ["entity"],
231
- },
232
- execute: async (_toolCallId, params) => {
233
- const result = await client.memoryLookupEntity(params.entity);
234
- if (result.triples.length === 0)
235
- return `No knowledge found about "${params.entity}".`;
236
- const facts = result.triples.map((t) => `- ${result.subject} ${t.predicate} ${t.object} (since ${t.validFrom.slice(0, 10)})`);
237
- return `Known facts about ${result.subject}:\n${facts.join("\n")}`;
238
- },
239
- }), { names: ["memory_graph"] });
240
- api.registerTool(() => ({
241
- name: "memory_stats",
242
- label: "Memory Stats",
243
- description: "Get memory storage statistics.",
244
- parameters: { type: "object", properties: {} },
245
- execute: async () => {
246
- const s = await client.memoryStats();
247
- return `Memories: ${String(s.vectorCount)}, Knowledge facts: ${String(s.tripleCount)}, Storage: ${String(Math.round(s.storageEstimateBytes / 1024))} KB`;
248
- },
249
- }), { names: ["memory_stats"] });
250
- api.registerTool(() => ({
251
- name: "memory_navigate",
252
- label: "Memory Navigate",
253
- description: "Browse your memory palace structure — list topics, subtopics, and memory counts.",
254
- parameters: { type: "object", properties: {} },
255
- execute: async () => {
256
- const nav = await client.memoryNavigate();
257
- const topics = nav.topics;
258
- if (topics.length === 0)
259
- return "No memories stored yet.";
260
- const lines = topics.map((t) => `- ${t.name} (${String(t.tripleCount)} facts, subtopics: ${t.subtopics.join(", ") || "none"})`);
261
- return `Memory topics:\n${lines.join("\n")}`;
262
- },
263
- }), { names: ["memory_navigate"] });
264
- // ─── Lifecycle hooks ────────────────────────────────────────
265
- // Auto-recall: inject relevant memories at session start
266
- api.on("before_agent_start", async (event, ctx) => {
267
- const startEvent = event;
268
- const agentCtx = ctx;
269
- const prompt = typeof startEvent.prompt === "string" ? startEvent.prompt : "";
270
- const sessionKey = typeof agentCtx.sessionKey === "string" ? agentCtx.sessionKey : undefined;
271
- const channelId = typeof agentCtx.channelId === "string" ? agentCtx.channelId : undefined;
272
- if (sessionKey) {
273
- autoCapture.setSession(sessionKey, { channelId });
274
- }
275
- const contextXml = await autoRecall.loadForPrompt(prompt);
276
- if (contextXml) {
277
- return { prependContext: contextXml };
278
- }
279
- return undefined;
280
- }, { priority: 10 });
281
- // Track incoming messages for idle debounce
282
- api.on("message_received", (event) => {
283
- const msgEvent = event;
284
- const content = typeof msgEvent.content === "string" ? msgEvent.content : "";
285
- autoCapture.trackMessage("user", content);
286
- });
287
- // Track outgoing messages
288
- api.on("message_sending", (event) => {
289
- const msgEvent = event;
290
- const content = typeof msgEvent.content === "string" ? msgEvent.content : "";
291
- autoCapture.trackMessage("assistant", content);
292
- });
293
- // Final flush on session end
294
- api.on("agent_end", async (event) => {
295
- const endEvent = event;
296
- if (endEvent.success !== false) {
297
- await autoCapture.onAgentEnd();
298
- }
299
- });
300
- // Fire-and-forget first-run sync: workspace files (MEMORY.md / memory/*.md)
301
- // and pre-existing chat sessions, each idempotent via its own
302
- // PalaceMetadata flag (bootstrapSyncedAt / sessionsBackfillSyncedAt).
303
- void runStartupSync(client, config, logger).catch((err) => {
304
- logger.warn("memory startup sync failed; will retry on next startup", { err: String(err) });
305
- });
306
- logger.info("memory-cloud extension registered", { autoCapture: config.autoCapture, autoRecall: config.autoRecall });
307
- },
308
- };
309
- async function runStartupSync(client, config, logger) {
310
- // Fetch status ONCE, before the file bootstrap runs: the sessions backfill
311
- // computes its dedup cutoff from the pre-bootstrap `syncedAt` (an agent
312
- // that already had memory installed captured everything after that moment
313
- // live, so backfilling past it would duplicate memories).
314
- let status;
315
- try {
316
- status = await client.memoryBootstrapStatus();
317
- }
318
- catch (err) {
319
- logger.debug("memory bootstrap status check failed; skipping", { err: String(err) });
320
- return;
321
- }
322
- const startupMs = Date.now();
323
- if (status.synced) {
324
- logger.debug("memory bootstrap: already synced, skipping");
325
- }
326
- else {
327
- try {
328
- await runBootstrap(client, logger);
329
- }
330
- catch (err) {
331
- logger.warn("memory bootstrap failed; will retry on next startup", { err: String(err) });
332
- }
333
- }
334
- // Strict `=== false` on purpose: an old server (deployed before the
335
- // sessions-backfill release) omits the field entirely, and its mark
336
- // endpoint would clobber `bootstrapSyncedAt` — corrupting the cutoff
337
- // anchor. Defer until the service is deployed and reports the flag.
338
- if (config.backfillSessions && status.sessionsBackfillSynced === false) {
339
- const installedAtMs = status.syncedAt ? Date.parse(status.syncedAt) : Number.POSITIVE_INFINITY;
340
- const cutoffMs = Math.min(startupMs, Number.isNaN(installedAtMs) ? Number.POSITIVE_INFINITY : installedAtMs);
341
- await runSessionsBackfill(client, config, logger, { cutoffMs });
342
- }
343
- }
344
- async function runBootstrap(client, logger) {
345
- const cwd = process.cwd();
346
- const filesToSync = [];
347
- try {
348
- await fs.access(path.join(cwd, "MEMORY.md"));
349
- filesToSync.push("MEMORY.md");
350
- }
351
- catch { /* missing — fine */ }
352
- try {
353
- const memoryDir = path.join(cwd, "memory");
354
- const entries = await fs.readdir(memoryDir, { withFileTypes: true });
355
- for (const entry of entries) {
356
- if (entry.isFile() && entry.name.endsWith(".md")) {
357
- filesToSync.push(path.join("memory", entry.name));
358
- }
359
- }
360
- }
361
- catch { /* no memory/ dir — fine */ }
362
- if (filesToSync.length === 0) {
363
- logger.debug("memory bootstrap: no files to sync, marking complete");
364
- try {
365
- await client.memoryBootstrapStatusMark();
366
- }
367
- catch { /* retry next start */ }
368
- return;
369
- }
370
- logger.info("memory bootstrap: ingesting files", { count: filesToSync.length });
371
- for (const relPath of filesToSync) {
372
- try {
373
- const text = await fs.readFile(path.join(cwd, relPath), "utf8");
374
- if (text.trim().length === 0)
375
- continue;
376
- const result = await client.memoryLearn({ text, source: relPath, sourceType: "file" });
377
- logger.debug("memory bootstrap: file ingested", {
378
- file: relPath,
379
- memoriesStored: result.memoriesStored,
380
- triplesStored: result.triplesStored,
381
- });
382
- }
383
- catch (err) {
384
- logger.warn("memory bootstrap: file failed; will retry on next startup", { file: relPath, err: String(err) });
385
- return;
386
- }
387
- }
388
- try {
389
- await client.memoryBootstrapStatusMark();
390
- logger.info("memory bootstrap: complete");
391
- }
392
- catch (err) {
393
- logger.warn("memory bootstrap: mark failed; will retry on next startup", { err: String(err) });
394
- }
395
- }
396
- //# sourceMappingURL=index.js.map
1
+ import { t as plugin } from "./plugin2.js";
2
+ export { plugin as default };
@@ -0,0 +1,2 @@
1
+ const require_plugin = require("./plugin2.cjs");
2
+ module.exports = require_plugin.plugin;
@@ -0,0 +1,59 @@
1
+ import { TSchema } from "@sinclair/typebox";
2
+
3
+ //#region ../openclaw-plugin-kit/dist/index.d.ts
4
+
5
+ //# sourceMappingURL=types.d.ts.map
6
+ //#endregion
7
+ //#region src/tools.d.ts
8
+ /** Shape returned to OpenClaw from a tool `execute`. */
9
+ interface ToolResult {
10
+ content: {
11
+ type: "text";
12
+ text: string;
13
+ }[];
14
+ details: unknown;
15
+ isError?: boolean;
16
+ }
17
+ interface ToolDef<TParameters = unknown> {
18
+ name: string;
19
+ description: string;
20
+ label: string;
21
+ parameters: TParameters;
22
+ execute: (toolCallId: string, params: Record<string, unknown>) => Promise<ToolResult>;
23
+ }
24
+ /** Deliberately model-safe validation/usage failure. Other exceptions stay private. */
25
+ //#endregion
26
+ //#region src/runtime.d.ts
27
+ interface PluginLogger {
28
+ info(message: string, context?: Record<string, unknown>): void;
29
+ debug(message: string, context?: Record<string, unknown>): void;
30
+ warn(message: string, context?: Record<string, unknown>): void;
31
+ error(message: string, context?: Record<string, unknown>): void;
32
+ }
33
+ interface PluginApi {
34
+ pluginConfig?: unknown;
35
+ logger: PluginLogger;
36
+ registerTool(tool: ToolDef<TSchema>, options?: {
37
+ names?: string[];
38
+ }): void;
39
+ on(hookName: string, handler: (...args: unknown[]) => unknown, options?: {
40
+ priority?: number;
41
+ }): void;
42
+ registerMemoryPromptSection(builder: (params: {
43
+ availableTools: Set<string>;
44
+ }) => string[]): void;
45
+ }
46
+ interface MemoryCloudPlugin {
47
+ id: string;
48
+ name: string;
49
+ description: string;
50
+ version: string;
51
+ kind: "memory";
52
+ register(api: PluginApi): void;
53
+ }
54
+ //#endregion
55
+ //#region src/plugin.d.ts
56
+ declare const plugin: MemoryCloudPlugin;
57
+ //#endregion
58
+ export { plugin as t };
59
+ //# sourceMappingURL=plugin.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.cts","names":["KitLogger","ToolResult","ToolDef","TParameters","Record","Promise","PublicToolError","Error","publicToolError","ok","errResult","defineTool","IpcResponse","IpcClient","IpcModule","ConnectToDaemonOptions","ConnectToDaemonDependencies","connectToDaemon","ResolveOpenClawSdkOptions","ResolveOpenClawSdkDependencies","resolveOpenClawSdk","T","getActivationKey","isActivated","resetActivation","guardedStart"],"sources":["../../openclaw-plugin-kit/dist/index.d.ts","../src/runtime.ts","../src/plugin.ts"],"sourcesContent":["//#region src/types.d.ts\n/**\n * Minimal logger contract shared by every helper in the kit.\n *\n * Deliberately the *narrowest* shape in the fleet: some plugins declare\n * variadic loggers (`info(msg: string, ...args: unknown[])`), others\n * single-arg (`info(msg: string)`). Both are assignable to this. The kit\n * only ever calls with a single string.\n */\ninterface KitLogger {\n info(msg: string): void;\n warn(msg: string): void;\n error(msg: string): void;\n debug(msg: string): void;\n}\n//# sourceMappingURL=types.d.ts.map\n//#endregion\n//#region src/tools.d.ts\n/** Shape returned to OpenClaw from a tool `execute`. */\ninterface ToolResult {\n content: {\n type: \"text\";\n text: string;\n }[];\n details: unknown;\n isError?: boolean;\n}\ninterface ToolDef<TParameters = unknown> {\n name: string;\n description: string;\n label: string;\n parameters: TParameters;\n execute: (toolCallId: string, params: Record<string, unknown>) => Promise<ToolResult>;\n}\n/** Deliberately model-safe validation/usage failure. Other exceptions stay private. */\ndeclare class PublicToolError extends Error {\n readonly name = \"PublicToolError\";\n}\ndeclare function publicToolError(message: string): PublicToolError;\n/** Wrap bounded JSON in the OpenClaw tool-result envelope. */\ndeclare function ok(data: unknown): ToolResult;\n/** Wrap an explicitly public error in a captured OpenClaw error envelope. */\ndeclare function errResult(message: string): ToolResult;\n/**\n * Define a tool whose unexpected exceptions never expose provider, filesystem,\n * credential, or transport diagnostics to the model. Throw `PublicToolError`\n * only for a message deliberately safe for model display.\n */\ndeclare function defineTool<TParameters>(def: {\n name: string;\n description: string;\n parameters: TParameters;\n handler: (params: Record<string, unknown>) => Promise<unknown>;\n}): ToolDef<TParameters>;\n//# sourceMappingURL=tools.d.ts.map\n//#endregion\n//#region src/daemon.d.ts\ninterface IpcResponse {\n ok: boolean;\n error?: {\n message?: string;\n };\n [key: string]: unknown;\n}\ninterface IpcClient {\n on(event: string, handler: (...args: unknown[]) => void): void;\n request(method: string, params: Record<string, unknown>): Promise<IpcResponse>;\n start(): void;\n stop(): void;\n}\ninterface IpcModule {\n IPCClient: new (socketPath: string, log: KitLogger) => IpcClient;\n}\ninterface ConnectToDaemonOptions {\n pluginId: string;\n capabilities?: readonly string[];\n onMessage?: (msg: Record<string, unknown>) => void;\n standaloneNote?: string;\n}\ninterface ConnectToDaemonDependencies {\n loadIpcModule?: () => Promise<IpcModule>;\n}\ndeclare function connectToDaemon(socketPath: string, log: KitLogger, options: ConnectToDaemonOptions, dependencies?: ConnectToDaemonDependencies): Promise<IpcClient | null>;\n//#endregion\n//#region src/sdk.d.ts\ninterface ResolveOpenClawSdkOptions {\n specifier?: string;\n exportName?: string;\n unresolvableNote?: string;\n}\ninterface ResolveOpenClawSdkDependencies {\n anchors?: readonly string[];\n globalPackageJsonPath?: string;\n requireFrom?: (anchor: string) => (specifier: string) => unknown;\n}\ndeclare function resolveOpenClawSdk<T = unknown>(log: KitLogger, options?: ResolveOpenClawSdkOptions, dependencies?: ResolveOpenClawSdkDependencies): T | null;\n//# sourceMappingURL=sdk.d.ts.map\n\n//#endregion\n//#region src/activation.d.ts\n/**\n * Canonical activation-flag key for a plugin: `__alfe<Name>PluginActivated`.\n *\n * Accepts a short name (`\"google\"`, `\"google-chat\"`) or a full package name\n * (`\"@alfe.ai/openclaw-teams\"`); scope + `openclaw-` prefix are stripped\n * and the remainder PascalCased:\n *\n * getActivationKey(\"google\") → \"__alfeGooglePluginActivated\"\n * getActivationKey(\"google-chat\") → \"__alfeGoogleChatPluginActivated\"\n * getActivationKey(\"@alfe.ai/openclaw-teams\") → \"__alfeTeamsPluginActivated\"\n */\ndeclare function getActivationKey(name: string): string;\n/** True when the activation flag for `key` is currently set. */\ndeclare function isActivated(key: string): boolean;\n/**\n * Clear the activation flag so a later start can run again.\n *\n * Call this LAST in stop/deactivate paths — after side effects are stopped\n * (see the ordering rule in the module doc). Also exported for soft-failure\n * paths inside a `guardedStart` fn that want to log at a custom level and\n * return normally instead of throwing.\n */\ndeclare function resetActivation(key: string): void;\n/**\n * Run a service start exactly once per activation cycle.\n *\n * - If the flag is already set, logs at debug and returns `false` (skipped).\n * - Otherwise sets the flag and runs `fn`.\n * - If `fn` throws synchronously OR returns a promise that rejects, the\n * flag is RESET (so a later activate can retry) and the error is logged.\n * Errors are not rethrown — matching fleet behavior where a failed start\n * must never crash the host's plugin loader.\n *\n * Returns `true` when the start was initiated (even if an async portion\n * later fails), `false` when skipped or when `fn` threw synchronously.\n *\n * Note: cleaning up partial side effects on failure is `fn`'s job (throw\n * only after tearing down what was started); the kit only guarantees the\n * flag reset happens after `fn` has failed — i.e. after `fn`'s own cleanup.\n */\ndeclare function guardedStart(key: string, log: KitLogger, fn: () => void | Promise<void>): boolean;\n//# sourceMappingURL=activation.d.ts.map\n\n//#endregion\nexport { type ConnectToDaemonDependencies, type ConnectToDaemonOptions, type IpcClient, type IpcResponse, type KitLogger, PublicToolError, type ResolveOpenClawSdkDependencies, type ResolveOpenClawSdkOptions, type ToolDef, type ToolResult, connectToDaemon, defineTool, errResult, getActivationKey, guardedStart, isActivated, ok, publicToolError, resetActivation, resolveOpenClawSdk };\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;;;;;;;UAmBUC,UAAAA,CCiCyB;EAAM,OAAA,EAAA;IAGxB,IAAA,EAAA,MAAS;IAAA,IAAA,EAAA,MAAA;;SAGG,EAAA,OAAA;SAAR,CAAA,EAAA,OAAA;;UD/BXC,OCiC2D,CAAA,cAAA,OAAA,CAAA,CAAA;EAUrE,IAAiB,EAAA,MAAA;;;cDvCHC;EE/BiE,OAEzE,EAAA,CAAA,UAAqD,EAA7C,MAAA,EAAA,MAAA,EF8B0BC,ME9BmB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GF8BSC,OE9BT,CF8BiBJ,UE9BjB,CAAA;;;;;AF6B7CE,UCiBG,YAAA,CDjBHA;MAC0BC,CAAAA,OAAAA,EAAAA,MAAAA,EAAAA,OAAAA,CAAAA,ECiBN,MDjBMA,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,CAAAA,EAAAA,IAAAA;OAAoCH,CAAAA,OAAAA,EAAAA,MAAAA,EAAAA,OAAAA,CAAAA,ECkBzC,MDlByCA,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,CAAAA,EAAAA,IAAAA;MAARI,CAAAA,OAAAA,EAAAA,MAAAA,EAAAA,OAAAA,CAAAA,ECmBlC,MDnBkCA,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,CAAAA,EAAAA,IAAAA;EAAO,KAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,CAAA,ECoBxC,MDpBwC,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAAA,IAAA;;UCuB1D,SAAA;;EAPA,MAAA,EASP,YATmB;EAAA,YAAA,CAAA,IAAA,EAUR,OAVQ,CAUA,OAVA,CAAA,EAAA,QAAA,EAAA;IACK,KAAA,CAAA,EAAA,MAAA,EAAA;MACC,IAAA;KACD,QAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,OAAA,EAAA,OACO,CADP,EAAA;IACC,QAAA,CAAA,EAAA,MAAA;EAAM,CAAA,CAAA,EAAA,IAAA;EAGxB,2BAAS,CAAA,OAAA,EAAA,CAAA,MAAA,EAAA;IAAA,cAAA,EAKwC,GALxC,CAAA,MAAA,CAAA;KAEhB,GAAA,MAAA,EAAA,CAAA,EAAA,IAAA;;UAaO,iBAAA;;;;;;gBAMD;;;;cC1EV,QAAQ"}
@@ -0,0 +1,59 @@
1
+ import { TSchema } from "@sinclair/typebox";
2
+
3
+ //#region ../openclaw-plugin-kit/dist/index.d.ts
4
+
5
+ //# sourceMappingURL=types.d.ts.map
6
+ //#endregion
7
+ //#region src/tools.d.ts
8
+ /** Shape returned to OpenClaw from a tool `execute`. */
9
+ interface ToolResult {
10
+ content: {
11
+ type: "text";
12
+ text: string;
13
+ }[];
14
+ details: unknown;
15
+ isError?: boolean;
16
+ }
17
+ interface ToolDef<TParameters = unknown> {
18
+ name: string;
19
+ description: string;
20
+ label: string;
21
+ parameters: TParameters;
22
+ execute: (toolCallId: string, params: Record<string, unknown>) => Promise<ToolResult>;
23
+ }
24
+ /** Deliberately model-safe validation/usage failure. Other exceptions stay private. */
25
+ //#endregion
26
+ //#region src/runtime.d.ts
27
+ interface PluginLogger {
28
+ info(message: string, context?: Record<string, unknown>): void;
29
+ debug(message: string, context?: Record<string, unknown>): void;
30
+ warn(message: string, context?: Record<string, unknown>): void;
31
+ error(message: string, context?: Record<string, unknown>): void;
32
+ }
33
+ interface PluginApi {
34
+ pluginConfig?: unknown;
35
+ logger: PluginLogger;
36
+ registerTool(tool: ToolDef<TSchema>, options?: {
37
+ names?: string[];
38
+ }): void;
39
+ on(hookName: string, handler: (...args: unknown[]) => unknown, options?: {
40
+ priority?: number;
41
+ }): void;
42
+ registerMemoryPromptSection(builder: (params: {
43
+ availableTools: Set<string>;
44
+ }) => string[]): void;
45
+ }
46
+ interface MemoryCloudPlugin {
47
+ id: string;
48
+ name: string;
49
+ description: string;
50
+ version: string;
51
+ kind: "memory";
52
+ register(api: PluginApi): void;
53
+ }
54
+ //#endregion
55
+ //#region src/plugin.d.ts
56
+ declare const plugin: MemoryCloudPlugin;
57
+ //#endregion
58
+ export { plugin as t };
59
+ //# sourceMappingURL=plugin.d.ts.map