@tensakulabs/memory 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.js ADDED
@@ -0,0 +1,171 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
15
+ // lib.ts
16
+ var exports_lib = {};
17
+ __export(exports_lib, {
18
+ readJsonl: () => readJsonl,
19
+ loadConfig: () => loadConfig,
20
+ generateId: () => generateId,
21
+ coldSearch: () => coldSearch,
22
+ coldAdd: () => coldAdd
23
+ });
24
+ import { readFileSync, existsSync } from "fs";
25
+ import { join, resolve, dirname } from "path";
26
+ var {$ } = globalThis.Bun;
27
+ function loadConfig(explicitPath) {
28
+ const home = process.env.HOME || "~";
29
+ const candidates = [];
30
+ if (explicitPath) {
31
+ candidates.push(resolve(explicitPath));
32
+ }
33
+ if (process.env.MEMORY_CONFIG) {
34
+ candidates.push(resolve(process.env.MEMORY_CONFIG));
35
+ }
36
+ candidates.push(join(home, ".pai", "memory", CONFIG_FILENAME));
37
+ candidates.push(join(dirname(Bun.main), CONFIG_FILENAME));
38
+ candidates.push(resolve(CONFIG_FILENAME));
39
+ const configPath = candidates.find((p) => existsSync(p));
40
+ if (!configPath) {
41
+ console.error(`Config not found. Searched:`);
42
+ for (const c of candidates)
43
+ console.error(` - ${c}`);
44
+ console.error(`
45
+ Run: memory init`);
46
+ process.exit(1);
47
+ }
48
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
49
+ const configDir = dirname(configPath);
50
+ const config = {
51
+ agent: raw.agent || "unknown",
52
+ hot: {
53
+ path: resolvePath(configDir, raw.hot?.path || "./MEMORY.md")
54
+ },
55
+ warm: {
56
+ path: resolvePath(configDir, raw.warm?.path || "./warm.jsonl"),
57
+ ttlDays: raw.warm?.ttlDays ?? 7
58
+ },
59
+ cold: {
60
+ mode: raw.cold?.mode || "mcp",
61
+ endpoint: raw.cold?.endpoint,
62
+ userId: raw.cold?.userId || "justin"
63
+ },
64
+ remSleep: {
65
+ maxColdWrites: raw.remSleep?.maxColdWrites ?? 5,
66
+ dedupThreshold: raw.remSleep?.dedupThreshold ?? 0.85,
67
+ stagingPath: resolvePath(configDir, raw.remSleep?.stagingPath || "./rem-staging.jsonl")
68
+ }
69
+ };
70
+ if (config.cold.mode === "http" && !config.cold.endpoint) {
71
+ console.error("cold.mode is 'http' but no cold.endpoint specified.");
72
+ process.exit(1);
73
+ }
74
+ return { config, configDir };
75
+ }
76
+ function resolvePath(base, p) {
77
+ if (p.startsWith("/") || p.startsWith("~"))
78
+ return p.replace(/^~/, process.env.HOME || "~");
79
+ return resolve(base, p);
80
+ }
81
+ async function coldSearch(config, query) {
82
+ if (config.cold.mode === "mcp") {
83
+ return coldSearchMcp(query, config.cold.userId);
84
+ } else {
85
+ return coldSearchHttp(config.cold.endpoint, query, config.cold.userId);
86
+ }
87
+ }
88
+ async function coldAdd(config, fact) {
89
+ if (config.cold.mode === "mcp") {
90
+ return coldAddMcp(fact, config.cold.userId);
91
+ } else {
92
+ return coldAddHttp(config.cold.endpoint, fact, config.cold.userId);
93
+ }
94
+ }
95
+ async function coldSearchMcp(query, userId) {
96
+ try {
97
+ const escaped = query.replace(/"/g, "\\\"");
98
+ const prompt = `Search mem0 for this fact and report if it already exists. Use search_memories with query: "${escaped}" and user_id "${userId}". If results exist with high relevance, respond ONLY with: FOUND|<score>|<matching text>. If no close match, respond ONLY with: NOT_FOUND|0|none. Do not explain.`;
99
+ const result = await $`claude -p ${prompt} --allowedTools "mcp__mem0__search_memories" 2>/dev/null`.text();
100
+ const line = result.trim().split(`
101
+ `).pop() || "";
102
+ if (line.startsWith("FOUND|")) {
103
+ const parts = line.split("|");
104
+ return { score: parseFloat(parts[1]) || 0, text: parts[2] || "" };
105
+ }
106
+ return { score: 0, text: "" };
107
+ } catch {
108
+ return { score: 0, text: "" };
109
+ }
110
+ }
111
+ async function coldAddMcp(fact, userId) {
112
+ try {
113
+ const escaped = fact.replace(/"/g, "\\\"");
114
+ const prompt = `Add this fact to mem0. Use add_memory with text: "${escaped}" and user_id "${userId}". Respond ONLY with: DONE or FAILED.`;
115
+ const result = await $`claude -p ${prompt} --allowedTools "mcp__mem0__add_memory" 2>/dev/null`.text();
116
+ return result.trim().includes("DONE");
117
+ } catch {
118
+ return false;
119
+ }
120
+ }
121
+ async function coldSearchHttp(endpoint, query, userId) {
122
+ try {
123
+ const res = await fetch(`${endpoint}/v1/memories/search/`, {
124
+ method: "POST",
125
+ headers: { "Content-Type": "application/json" },
126
+ body: JSON.stringify({ query, user_id: userId })
127
+ });
128
+ if (!res.ok)
129
+ return { score: 0, text: "" };
130
+ const data = await res.json();
131
+ const top = data.results?.[0];
132
+ if (top) {
133
+ return { score: top.score ?? 0, text: top.memory ?? "" };
134
+ }
135
+ return { score: 0, text: "" };
136
+ } catch {
137
+ return { score: 0, text: "" };
138
+ }
139
+ }
140
+ async function coldAddHttp(endpoint, fact, userId) {
141
+ try {
142
+ const res = await fetch(`${endpoint}/v1/memories/`, {
143
+ method: "POST",
144
+ headers: { "Content-Type": "application/json" },
145
+ body: JSON.stringify({ text: fact, user_id: userId })
146
+ });
147
+ return res.ok;
148
+ } catch {
149
+ return false;
150
+ }
151
+ }
152
+ function generateId() {
153
+ return `rem-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
154
+ }
155
+ function readJsonl(path) {
156
+ if (!existsSync(path))
157
+ return [];
158
+ return readFileSync(path, "utf-8").trim().split(`
159
+ `).filter(Boolean).map((line) => JSON.parse(line));
160
+ }
161
+ var CONFIG_FILENAME = "memory-config.json";
162
+ var init_lib = () => {};
163
+ init_lib();
164
+
165
+ export {
166
+ readJsonl,
167
+ loadConfig,
168
+ generateId,
169
+ coldSearch,
170
+ coldAdd
171
+ };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Memory Module — REM Sleep Batch Processor
4
+ *
5
+ * Reads staged facts, classifies (hot/warm/cold), deduplicates against
6
+ * mem0, and routes to appropriate tier. All config from memory-config.json.
7
+ *
8
+ * Usage:
9
+ * bun rem-sleep.ts # Full run
10
+ * bun rem-sleep.ts --dry-run # Show decisions without executing
11
+ * bun rem-sleep.ts --stats # Show staging stats only
12
+ */
13
+ export declare function run(args: string[]): Promise<void>;
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ var __defProp = Object.defineProperty;
4
+ var __export = (target, all) => {
5
+ for (var name in all)
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true,
9
+ configurable: true,
10
+ set: (newValue) => all[name] = () => newValue
11
+ });
12
+ };
13
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
14
+ var __require = import.meta.require;
15
+
16
+ // lib.ts
17
+ var exports_lib = {};
18
+ __export(exports_lib, {
19
+ readJsonl: () => readJsonl,
20
+ loadConfig: () => loadConfig,
21
+ generateId: () => generateId,
22
+ coldSearch: () => coldSearch,
23
+ coldAdd: () => coldAdd
24
+ });
25
+ import { readFileSync, existsSync } from "fs";
26
+ import { join, resolve, dirname } from "path";
27
+ var {$ } = globalThis.Bun;
28
+ function loadConfig(explicitPath) {
29
+ const home = process.env.HOME || "~";
30
+ const candidates = [];
31
+ if (explicitPath) {
32
+ candidates.push(resolve(explicitPath));
33
+ }
34
+ if (process.env.MEMORY_CONFIG) {
35
+ candidates.push(resolve(process.env.MEMORY_CONFIG));
36
+ }
37
+ candidates.push(join(home, ".pai", "memory", CONFIG_FILENAME));
38
+ candidates.push(join(dirname(Bun.main), CONFIG_FILENAME));
39
+ candidates.push(resolve(CONFIG_FILENAME));
40
+ const configPath = candidates.find((p) => existsSync(p));
41
+ if (!configPath) {
42
+ console.error(`Config not found. Searched:`);
43
+ for (const c of candidates)
44
+ console.error(` - ${c}`);
45
+ console.error(`
46
+ Run: memory init`);
47
+ process.exit(1);
48
+ }
49
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
50
+ const configDir = dirname(configPath);
51
+ const config = {
52
+ agent: raw.agent || "unknown",
53
+ hot: {
54
+ path: resolvePath(configDir, raw.hot?.path || "./MEMORY.md")
55
+ },
56
+ warm: {
57
+ path: resolvePath(configDir, raw.warm?.path || "./warm.jsonl"),
58
+ ttlDays: raw.warm?.ttlDays ?? 7
59
+ },
60
+ cold: {
61
+ mode: raw.cold?.mode || "mcp",
62
+ endpoint: raw.cold?.endpoint,
63
+ userId: raw.cold?.userId || "justin"
64
+ },
65
+ remSleep: {
66
+ maxColdWrites: raw.remSleep?.maxColdWrites ?? 5,
67
+ dedupThreshold: raw.remSleep?.dedupThreshold ?? 0.85,
68
+ stagingPath: resolvePath(configDir, raw.remSleep?.stagingPath || "./rem-staging.jsonl")
69
+ }
70
+ };
71
+ if (config.cold.mode === "http" && !config.cold.endpoint) {
72
+ console.error("cold.mode is 'http' but no cold.endpoint specified.");
73
+ process.exit(1);
74
+ }
75
+ return { config, configDir };
76
+ }
77
+ function resolvePath(base, p) {
78
+ if (p.startsWith("/") || p.startsWith("~"))
79
+ return p.replace(/^~/, process.env.HOME || "~");
80
+ return resolve(base, p);
81
+ }
82
+ async function coldSearch(config, query) {
83
+ if (config.cold.mode === "mcp") {
84
+ return coldSearchMcp(query, config.cold.userId);
85
+ } else {
86
+ return coldSearchHttp(config.cold.endpoint, query, config.cold.userId);
87
+ }
88
+ }
89
+ async function coldAdd(config, fact) {
90
+ if (config.cold.mode === "mcp") {
91
+ return coldAddMcp(fact, config.cold.userId);
92
+ } else {
93
+ return coldAddHttp(config.cold.endpoint, fact, config.cold.userId);
94
+ }
95
+ }
96
+ async function coldSearchMcp(query, userId) {
97
+ try {
98
+ const escaped = query.replace(/"/g, "\\\"");
99
+ const prompt = `Search mem0 for this fact and report if it already exists. Use search_memories with query: "${escaped}" and user_id "${userId}". If results exist with high relevance, respond ONLY with: FOUND|<score>|<matching text>. If no close match, respond ONLY with: NOT_FOUND|0|none. Do not explain.`;
100
+ const result = await $`claude -p ${prompt} --allowedTools "mcp__mem0__search_memories" 2>/dev/null`.text();
101
+ const line = result.trim().split(`
102
+ `).pop() || "";
103
+ if (line.startsWith("FOUND|")) {
104
+ const parts = line.split("|");
105
+ return { score: parseFloat(parts[1]) || 0, text: parts[2] || "" };
106
+ }
107
+ return { score: 0, text: "" };
108
+ } catch {
109
+ return { score: 0, text: "" };
110
+ }
111
+ }
112
+ async function coldAddMcp(fact, userId) {
113
+ try {
114
+ const escaped = fact.replace(/"/g, "\\\"");
115
+ const prompt = `Add this fact to mem0. Use add_memory with text: "${escaped}" and user_id "${userId}". Respond ONLY with: DONE or FAILED.`;
116
+ const result = await $`claude -p ${prompt} --allowedTools "mcp__mem0__add_memory" 2>/dev/null`.text();
117
+ return result.trim().includes("DONE");
118
+ } catch {
119
+ return false;
120
+ }
121
+ }
122
+ async function coldSearchHttp(endpoint, query, userId) {
123
+ try {
124
+ const res = await fetch(`${endpoint}/v1/memories/search/`, {
125
+ method: "POST",
126
+ headers: { "Content-Type": "application/json" },
127
+ body: JSON.stringify({ query, user_id: userId })
128
+ });
129
+ if (!res.ok)
130
+ return { score: 0, text: "" };
131
+ const data = await res.json();
132
+ const top = data.results?.[0];
133
+ if (top) {
134
+ return { score: top.score ?? 0, text: top.memory ?? "" };
135
+ }
136
+ return { score: 0, text: "" };
137
+ } catch {
138
+ return { score: 0, text: "" };
139
+ }
140
+ }
141
+ async function coldAddHttp(endpoint, fact, userId) {
142
+ try {
143
+ const res = await fetch(`${endpoint}/v1/memories/`, {
144
+ method: "POST",
145
+ headers: { "Content-Type": "application/json" },
146
+ body: JSON.stringify({ text: fact, user_id: userId })
147
+ });
148
+ return res.ok;
149
+ } catch {
150
+ return false;
151
+ }
152
+ }
153
+ function generateId() {
154
+ return `rem-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
155
+ }
156
+ function readJsonl(path) {
157
+ if (!existsSync(path))
158
+ return [];
159
+ return readFileSync(path, "utf-8").trim().split(`
160
+ `).filter(Boolean).map((line) => JSON.parse(line));
161
+ }
162
+ var CONFIG_FILENAME = "memory-config.json";
163
+ var init_lib = () => {};
164
+
165
+ // rem-sleep.ts
166
+ var exports_rem_sleep = {};
167
+ __export(exports_rem_sleep, {
168
+ run: () => run
169
+ });
170
+ import { writeFileSync, appendFileSync } from "fs";
171
+ import { join as join2, dirname as dirname2 } from "path";
172
+ function classify(fact) {
173
+ if (fact.tier_hint !== "auto") {
174
+ return { ...fact, tier: fact.tier_hint, reason: `explicit: ${fact.tier_hint}` };
175
+ }
176
+ const text = `${fact.fact} ${fact.context}`;
177
+ const hot = HOT_SIGNALS.reduce((s, r) => s + (r.test(text) ? 1 : 0), 0);
178
+ const warm = WARM_SIGNALS.reduce((s, r) => s + (r.test(text) ? 1 : 0), 0);
179
+ const cold = COLD_SIGNALS.reduce((s, r) => s + (r.test(text) ? 1 : 0), 0);
180
+ if (hot > warm && hot > cold)
181
+ return { ...fact, tier: "hot", reason: `hot signals: ${hot}` };
182
+ if (warm > cold)
183
+ return { ...fact, tier: "warm", reason: `warm signals: ${warm}` };
184
+ if (cold > 0)
185
+ return { ...fact, tier: "cold", reason: `cold signals: ${cold}` };
186
+ return { ...fact, tier: "warm", reason: "default (no strong signals)" };
187
+ }
188
+ function appendToWarm(fact) {
189
+ const entry = {
190
+ id: fact.id,
191
+ fact: fact.fact,
192
+ origin: "new",
193
+ created: fact.timestamp,
194
+ last_access: new Date().toISOString(),
195
+ access_count: 1,
196
+ context: fact.context
197
+ };
198
+ appendFileSync(WARM, JSON.stringify(entry) + `
199
+ `);
200
+ }
201
+ async function run(args) {
202
+ const dryRun = args.includes("--dry-run");
203
+ const statsOnly = args.includes("--stats");
204
+ const allEntries = readJsonl(STAGING);
205
+ const pending = allEntries.filter((e) => !e.processed);
206
+ if (statsOnly) {
207
+ console.log(`Agent: ${config.agent}`);
208
+ console.log(`Cold mode: ${config.cold.mode}`);
209
+ console.log(`Total entries: ${allEntries.length}`);
210
+ console.log(`Pending: ${pending.length}`);
211
+ console.log(`Processed: ${allEntries.length - pending.length}`);
212
+ return;
213
+ }
214
+ if (pending.length === 0) {
215
+ console.log("No pending facts. Staging is clean.");
216
+ return;
217
+ }
218
+ console.log(`
219
+ \uD83C\uDF19 REM Sleep [${config.agent}] \u2014 Processing ${pending.length} fact(s)${dryRun ? " [DRY RUN]" : ""}`);
220
+ console.log(` Cold mode: ${config.cold.mode} | Max writes: ${config.remSleep.maxColdWrites} | Dedup: ${config.remSleep.dedupThreshold}
221
+ `);
222
+ const classified = pending.map(classify);
223
+ const hot = classified.filter((f) => f.tier === "hot");
224
+ const warm = classified.filter((f) => f.tier === "warm");
225
+ const cold = classified.filter((f) => f.tier === "cold");
226
+ console.log(`\uD83D\uDCCA Classification: ${hot.length} hot, ${warm.length} warm, ${cold.length} cold
227
+ `);
228
+ if (hot.length > 0) {
229
+ console.log("\uD83D\uDD25 HOT \u2014 Suggested MEMORY.md additions (review manually):");
230
+ console.log(` Target: ${config.hot.path}`);
231
+ for (const f of hot)
232
+ console.log(` - ${f.fact} (${f.reason})`);
233
+ console.log();
234
+ }
235
+ if (warm.length > 0) {
236
+ console.log("\u2668\uFE0F WARM \u2014 Cross-agent shared facts:");
237
+ for (const f of warm) {
238
+ console.log(` - ${f.fact}`);
239
+ if (!dryRun)
240
+ appendToWarm(f);
241
+ }
242
+ console.log(dryRun ? ` \u2192 Would write to ${WARM}
243
+ ` : ` \u2192 Written to ${WARM}
244
+ `);
245
+ }
246
+ let coldWritten = 0;
247
+ let coldSkipped = 0;
248
+ let coldCapped = 0;
249
+ if (cold.length > 0) {
250
+ console.log("\uD83E\uDDCA COLD \u2014 Long-tail facts (mem0 candidates):");
251
+ for (const f of cold) {
252
+ if (coldWritten >= config.remSleep.maxColdWrites) {
253
+ console.log(` \u23F8 ${f.fact} \u2192 DEFERRED (cap reached)`);
254
+ coldCapped++;
255
+ continue;
256
+ }
257
+ console.log(` - ${f.fact}`);
258
+ if (dryRun) {
259
+ console.log(` \u2192 Would search mem0 (${config.cold.mode}) then add if new`);
260
+ continue;
261
+ }
262
+ const match = await coldSearch(config, f.fact);
263
+ if (match.score >= config.remSleep.dedupThreshold) {
264
+ console.log(` \u2192 SKIP (dup: ${(match.score * 100).toFixed(0)}% \u2014 "${match.text.slice(0, 60)}...")`);
265
+ coldSkipped++;
266
+ } else {
267
+ const ok = await coldAdd(config, f.fact);
268
+ console.log(ok ? ` \u2192 ADDED to mem0` : ` \u2192 FAILED`);
269
+ if (ok)
270
+ coldWritten++;
271
+ }
272
+ }
273
+ console.log();
274
+ }
275
+ if (!dryRun) {
276
+ const cappedIds = new Set(cold.slice(config.remSleep.maxColdWrites).map((f) => f.id));
277
+ const updated = allEntries.map((e) => !e.processed && !cappedIds.has(e.id) ? { ...e, processed: true } : e);
278
+ writeFileSync(STAGING, updated.map((e) => JSON.stringify(e)).join(`
279
+ `) + `
280
+ `);
281
+ }
282
+ const report = {
283
+ timestamp: new Date().toISOString(),
284
+ agent: config.agent,
285
+ coldMode: config.cold.mode,
286
+ dryRun,
287
+ staged: pending.length,
288
+ classified: { hot: hot.length, warm: warm.length, cold: cold.length },
289
+ written: { cold: coldWritten, warm: dryRun ? 0 : warm.length, hotSuggested: hot.length },
290
+ skipped: coldSkipped,
291
+ deferred: coldCapped,
292
+ cost: `~$${(coldWritten * 0.001).toFixed(4)}`
293
+ };
294
+ if (!dryRun)
295
+ writeFileSync(REPORT, JSON.stringify(report, null, 2));
296
+ console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
297
+ console.log(`\u2705 REM Sleep [${config.agent}] complete${dryRun ? " (dry run)" : ""}`);
298
+ console.log(` Hot: ${hot.length} suggested | Warm: ${dryRun ? 0 : warm.length} written | Cold: ${coldWritten} added, ${coldSkipped} dup, ${coldCapped} deferred`);
299
+ console.log(` Cost: ${report.cost}`);
300
+ }
301
+ var config, configDir, STAGING, WARM, REPORT, HOT_SIGNALS, WARM_SIGNALS, COLD_SIGNALS;
302
+ var init_rem_sleep = __esm(() => {
303
+ init_lib();
304
+ ({ config, configDir } = loadConfig());
305
+ STAGING = config.remSleep.stagingPath;
306
+ WARM = config.warm.path;
307
+ REPORT = join2(dirname2(STAGING), "last-run.json");
308
+ HOT_SIGNALS = [
309
+ /\bmy (model|config|cron|path|key|token|port|setup)\b/i,
310
+ /\b(localhost|127\.0\.0\.1|~\/|\/home\/)/i,
311
+ /\b(launchd|plist|systemd|crontab)\b/i,
312
+ /\b(heartbeat) model\b/i
313
+ ];
314
+ WARM_SIGNALS = [
315
+ /\b(we|our|us|together|both agents|cross-agent)\b/i,
316
+ /\b(prefers|wants|decided|likes|agreed)\b/i,
317
+ /\b(strategy|approach|decision|convention)\b/i,
318
+ /\b(project|milestone|roadmap|plan)\b/i
319
+ ];
320
+ COLD_SIGNALS = [
321
+ /\b(PR #\d+|issue #\d+|bug #\d+)\b/i,
322
+ /\b(benchmark|pricing|per M tokens)\b/i,
323
+ /\b(workaround|root cause|known issue)\b/i,
324
+ /\b(research|found|discovered|learned)\b/i
325
+ ];
326
+ if (import.meta.main) {
327
+ run(process.argv.slice(2)).catch((err) => {
328
+ console.error("REM Sleep failed:", err);
329
+ process.exit(1);
330
+ });
331
+ }
332
+ });
333
+ init_rem_sleep();
334
+
335
+ export {
336
+ run
337
+ };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Memory Module — Stage
4
+ *
5
+ * Appends a fact to rem-staging.jsonl for later batch processing.
6
+ * All paths from memory-config.json.
7
+ *
8
+ * Usage:
9
+ * memory stage "fact text" [--context "..."] [--tier hot|warm|cold]
10
+ * memory stage --list | --count
11
+ * bun stage.ts "fact text" (standalone mode)
12
+ */
13
+ export declare function run(args: string[]): Promise<void>;