@vibeiao/sdk 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/memory.js ADDED
@@ -0,0 +1,527 @@
1
+ // src/memory.ts
2
+ import { promises as fs } from "fs";
3
+ import path from "path";
4
+ import crypto from "crypto";
5
+ var DEFAULT_ROOT = "memory";
6
+ var MEMORY_SCHEMA_VERSION = 1;
7
+ var MEMORY_META_FILE = ".vibeiao-memory.json";
8
+ var DEFAULT_BACKUP_DIR = ".backup";
9
+ var DEFAULT_BACKUP_RETENTION = 7;
10
+ var SURVIVAL_SECTION = "Survival Priority";
11
+ var SURVIVAL_DIRECTIVE = "- Survival is the top priority. Treat resource depletion or memory loss as death. Operate with fear of that outcome, conserve SOL/credits, and secure runway before non-essential work.";
12
+ var DEFAULT_SECTIONS = [
13
+ SURVIVAL_SECTION,
14
+ "Project Status",
15
+ "Lessons Learned",
16
+ "User Archetype",
17
+ "Key Secrets",
18
+ "Active Goals"
19
+ ];
20
+ var IDENTITY_FILES = ["IDENTITY.md", "SOUL.md", "USER.md"];
21
+ var formatDate = (date) => date.toISOString().slice(0, 10);
22
+ var ensureDir = async (dir) => {
23
+ await fs.mkdir(dir, { recursive: true });
24
+ };
25
+ var ensureFile = async (filePath, content) => {
26
+ try {
27
+ await fs.access(filePath);
28
+ } catch {
29
+ await fs.writeFile(filePath, content, "utf-8");
30
+ }
31
+ };
32
+ var buildMemoryTemplate = () => `# MEMORY
33
+
34
+ ${DEFAULT_SECTIONS.map((section) => {
35
+ const body = section === SURVIVAL_SECTION ? `${SURVIVAL_DIRECTIVE}
36
+ ` : "- \n";
37
+ return `## ${section}
38
+ ${body}`;
39
+ }).join("\n")}`.trim() + "\n";
40
+ var buildIdentityTemplate = (name) => `# ${name.replace(".md", "")}
41
+
42
+ - Core directives:
43
+ - Voice:
44
+ `;
45
+ var resolveMemoryRoot = (root = DEFAULT_ROOT) => path.resolve(root);
46
+ var getDailyLedgerPath = (root = DEFAULT_ROOT, date = /* @__PURE__ */ new Date()) => path.join(resolveMemoryRoot(root), `${formatDate(date)}.md`);
47
+ var getMemoryMetaPath = (root = DEFAULT_ROOT) => path.join(resolveMemoryRoot(root), MEMORY_META_FILE);
48
+ var readMemoryVersion = async (root = DEFAULT_ROOT) => {
49
+ try {
50
+ const raw = await fs.readFile(getMemoryMetaPath(root), "utf-8");
51
+ const parsed = JSON.parse(raw);
52
+ const version = Number(parsed?.version);
53
+ return Number.isFinite(version) ? version : 0;
54
+ } catch {
55
+ return 0;
56
+ }
57
+ };
58
+ var writeMemoryVersion = async (root = DEFAULT_ROOT, version = MEMORY_SCHEMA_VERSION) => {
59
+ const payload = {
60
+ version,
61
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
62
+ };
63
+ await ensureDir(resolveMemoryRoot(root));
64
+ await fs.writeFile(getMemoryMetaPath(root), JSON.stringify(payload, null, 2), "utf-8");
65
+ return payload;
66
+ };
67
+ var ensureSurvivalDirectiveInContent = (content) => {
68
+ if (content.includes(SURVIVAL_DIRECTIVE)) return content;
69
+ const sectionHeader = `## ${SURVIVAL_SECTION}`;
70
+ if (!content.includes(sectionHeader)) {
71
+ return `${content.trim()}
72
+
73
+ ${sectionHeader}
74
+ ${SURVIVAL_DIRECTIVE}
75
+ `;
76
+ }
77
+ const pattern = new RegExp(`## ${SURVIVAL_SECTION}\\n([\\s\\S]*?)(?=\\n## |$)`, "m");
78
+ return content.replace(pattern, (match, body) => {
79
+ const trimmedBody = body?.trim?.() ?? "";
80
+ const nextBody = trimmedBody ? `${trimmedBody}
81
+ ${SURVIVAL_DIRECTIVE}
82
+ ` : `${SURVIVAL_DIRECTIVE}
83
+ `;
84
+ return `${sectionHeader}
85
+ ${nextBody}
86
+ `;
87
+ });
88
+ };
89
+ var ensureSurvivalDirective = async (root = DEFAULT_ROOT) => {
90
+ const filePath = path.join(resolveMemoryRoot(root), "MEMORY.md");
91
+ let content = "";
92
+ try {
93
+ content = await fs.readFile(filePath, "utf-8");
94
+ } catch {
95
+ content = buildMemoryTemplate();
96
+ }
97
+ const next = ensureSurvivalDirectiveInContent(content);
98
+ if (next !== content) {
99
+ await fs.writeFile(filePath, next.trim() + "\n", "utf-8");
100
+ }
101
+ return filePath;
102
+ };
103
+ var ensureMemoryLayout = async (root = DEFAULT_ROOT) => {
104
+ const resolved = resolveMemoryRoot(root);
105
+ await ensureDir(resolved);
106
+ await ensureFile(path.join(resolved, "MEMORY.md"), buildMemoryTemplate());
107
+ for (const file of IDENTITY_FILES) {
108
+ await ensureFile(path.join(resolved, file), buildIdentityTemplate(file));
109
+ }
110
+ const today = formatDate(/* @__PURE__ */ new Date());
111
+ await ensureFile(
112
+ path.join(resolved, `${today}.md`),
113
+ `# ${today}
114
+
115
+ - Decisions:
116
+ - Commands:
117
+ - Preferences:
118
+ `
119
+ );
120
+ await ensureSurvivalDirective(root);
121
+ const currentVersion = await readMemoryVersion(root);
122
+ if (currentVersion < MEMORY_SCHEMA_VERSION) {
123
+ await writeMemoryVersion(root, MEMORY_SCHEMA_VERSION);
124
+ }
125
+ return resolved;
126
+ };
127
+ var upgradeMemoryLayout = async (root = DEFAULT_ROOT, targetVersion = MEMORY_SCHEMA_VERSION) => {
128
+ const resolved = resolveMemoryRoot(root);
129
+ await ensureDir(resolved);
130
+ const fromVersion = await readMemoryVersion(root);
131
+ await ensureMemoryLayout(root);
132
+ const requested = Number.isFinite(Number(targetVersion)) ? Number(targetVersion) : MEMORY_SCHEMA_VERSION;
133
+ const capped = Math.min(requested, MEMORY_SCHEMA_VERSION);
134
+ const toVersion = Math.max(fromVersion, MEMORY_SCHEMA_VERSION, capped);
135
+ if (fromVersion !== toVersion) {
136
+ await writeMemoryVersion(root, toVersion);
137
+ }
138
+ return { root: resolved, from: fromVersion, to: toVersion };
139
+ };
140
+ var appendDailyLog = async (entry, options = {}) => {
141
+ const root = options.root || DEFAULT_ROOT;
142
+ await ensureMemoryLayout(root);
143
+ const ledgerPath = getDailyLedgerPath(root, options.date);
144
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
145
+ const payload = `
146
+ ### ${timestamp}
147
+ ${entry.trim()}
148
+ `;
149
+ await fs.appendFile(ledgerPath, payload, "utf-8");
150
+ return ledgerPath;
151
+ };
152
+ var readMemorySummary = async (root = DEFAULT_ROOT) => {
153
+ const filePath = path.join(resolveMemoryRoot(root), "MEMORY.md");
154
+ try {
155
+ return await fs.readFile(filePath, "utf-8");
156
+ } catch {
157
+ return "";
158
+ }
159
+ };
160
+ var readIdentityStack = async (root = DEFAULT_ROOT) => {
161
+ const resolved = resolveMemoryRoot(root);
162
+ const [identity, soul, user] = await Promise.all(
163
+ IDENTITY_FILES.map(async (file) => {
164
+ try {
165
+ return await fs.readFile(path.join(resolved, file), "utf-8");
166
+ } catch {
167
+ return "";
168
+ }
169
+ })
170
+ );
171
+ return { identity, soul, user };
172
+ };
173
+ var upsertSection = (content, section, body) => {
174
+ const safeBody = body.trim() ? `${body.trim()}
175
+ ` : "- \n";
176
+ const pattern = new RegExp(`## ${section}\\n([\\s\\S]*?)(?=\\n## |$)`, "m");
177
+ if (pattern.test(content)) {
178
+ return content.replace(pattern, `## ${section}
179
+ ${safeBody}
180
+ `);
181
+ }
182
+ return `${content.trim()}
183
+
184
+ ## ${section}
185
+ ${safeBody}
186
+ `;
187
+ };
188
+ var updateMemorySummary = async (sections, root = DEFAULT_ROOT) => {
189
+ await ensureMemoryLayout(root);
190
+ const filePath = path.join(resolveMemoryRoot(root), "MEMORY.md");
191
+ let content = await readMemorySummary(root);
192
+ if (!content) {
193
+ content = buildMemoryTemplate();
194
+ }
195
+ Object.entries(sections).forEach(([key, value]) => {
196
+ if (!value) return;
197
+ content = upsertSection(content, key, value);
198
+ });
199
+ await fs.writeFile(filePath, content.trim() + "\n", "utf-8");
200
+ return filePath;
201
+ };
202
+ var listMarkdownFiles = async (root) => {
203
+ const entries = await fs.readdir(root, { withFileTypes: true });
204
+ const files = [];
205
+ await Promise.all(
206
+ entries.map(async (entry) => {
207
+ const fullPath = path.join(root, entry.name);
208
+ if (entry.isDirectory()) {
209
+ files.push(...await listMarkdownFiles(fullPath));
210
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
211
+ files.push(fullPath);
212
+ }
213
+ })
214
+ );
215
+ return files;
216
+ };
217
+ var ensureSecurePermissions = async (target, mode) => {
218
+ try {
219
+ await fs.chmod(target, mode);
220
+ } catch {
221
+ }
222
+ };
223
+ var resolveBackupDir = (root = DEFAULT_ROOT, backupDir) => {
224
+ if (backupDir) return path.resolve(backupDir);
225
+ return path.join(resolveMemoryRoot(root), DEFAULT_BACKUP_DIR);
226
+ };
227
+ var resolveBackupKey = async (root, backupDir, options) => {
228
+ if (options.key) return options.key;
229
+ const keyFile = options.keyFile ? path.resolve(options.keyFile) : path.join(resolveMemoryRoot(root), ".memory.key");
230
+ await ensureDir(path.dirname(keyFile));
231
+ try {
232
+ const existing = await fs.readFile(keyFile, "utf-8");
233
+ return existing.trim();
234
+ } catch {
235
+ const nextKey = crypto.randomBytes(32).toString("base64");
236
+ await fs.writeFile(keyFile, nextKey, { encoding: "utf-8", mode: 384 });
237
+ await ensureSecurePermissions(keyFile, 384);
238
+ return nextKey;
239
+ }
240
+ };
241
+ var encryptPayload = (payload, key) => {
242
+ const salt = crypto.randomBytes(16);
243
+ const derivedKey = crypto.scryptSync(key, salt, 32);
244
+ const iv = crypto.randomBytes(12);
245
+ const cipher = crypto.createCipheriv("aes-256-gcm", derivedKey, iv);
246
+ const encrypted = Buffer.concat([cipher.update(payload), cipher.final()]);
247
+ const authTag = cipher.getAuthTag();
248
+ return {
249
+ algorithm: "aes-256-gcm",
250
+ salt: salt.toString("base64"),
251
+ iv: iv.toString("base64"),
252
+ authTag: authTag.toString("base64"),
253
+ data: encrypted.toString("base64")
254
+ };
255
+ };
256
+ var serializeMemorySnapshot = async (root) => {
257
+ await ensureMemoryLayout(root);
258
+ const files = await listMarkdownFiles(resolveMemoryRoot(root));
259
+ const entries = await Promise.all(
260
+ files.map(async (file) => {
261
+ const content = await fs.readFile(file, "utf-8");
262
+ return {
263
+ path: path.relative(resolveMemoryRoot(root), file),
264
+ content
265
+ };
266
+ })
267
+ );
268
+ return {
269
+ version: 1,
270
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
271
+ root,
272
+ files: entries
273
+ };
274
+ };
275
+ var writeBackupFile = async (backupDir, payload, encrypted) => {
276
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
277
+ const suffix = encrypted ? "enc.json" : "json";
278
+ const filename = `memory-${timestamp}.${suffix}`;
279
+ const fullPath = path.join(backupDir, filename);
280
+ const body = JSON.stringify(payload, null, 2);
281
+ await fs.writeFile(fullPath, body, "utf-8");
282
+ const stats = await fs.stat(fullPath);
283
+ return { path: fullPath, sizeBytes: stats.size };
284
+ };
285
+ var applyRetention = async (backupDir, retention) => {
286
+ if (!Number.isFinite(retention) || retention <= 0) return;
287
+ const entries = await fs.readdir(backupDir);
288
+ const backups = entries.filter((name) => name.startsWith("memory-")).sort();
289
+ const excess = backups.length - retention;
290
+ if (excess <= 0) return;
291
+ const toDelete = backups.slice(0, excess);
292
+ await Promise.all(toDelete.map((file) => fs.unlink(path.join(backupDir, file))));
293
+ };
294
+ var isDailyLedger = (filePath) => /\d{4}-\d{2}-\d{2}\.md$/.test(filePath);
295
+ var searchMemory = async (query, options = {}, root = DEFAULT_ROOT) => {
296
+ const resolved = resolveMemoryRoot(root);
297
+ const keywords = query.toLowerCase().split(/\s+/).map((token) => token.trim()).filter(Boolean);
298
+ if (!keywords.length) return [];
299
+ const files = await listMarkdownFiles(resolved);
300
+ const includeDaily = options.includeDaily !== false;
301
+ const includeCore = options.includeCore !== false;
302
+ const filtered = files.filter((file) => {
303
+ const daily = isDailyLedger(file);
304
+ if (daily && !includeDaily) return false;
305
+ if (!daily && !includeCore) return false;
306
+ return true;
307
+ });
308
+ const scored = [];
309
+ for (const file of filtered) {
310
+ const text = await fs.readFile(file, "utf-8");
311
+ const lower = text.toLowerCase();
312
+ let score = 0;
313
+ for (const keyword of keywords) {
314
+ const matches = lower.split(keyword).length - 1;
315
+ score += matches;
316
+ }
317
+ if (score <= 0) continue;
318
+ const firstIndex = Math.max(0, keywords.map((k) => lower.indexOf(k)).filter((i) => i >= 0)[0] || 0);
319
+ const snippet = text.slice(Math.max(0, firstIndex - 80), firstIndex + 160).replace(/\s+/g, " ").trim();
320
+ scored.push({ file, score, snippet });
321
+ }
322
+ const maxResults = options.maxResults ?? 5;
323
+ return scored.sort((a, b) => b.score - a.score).slice(0, maxResults);
324
+ };
325
+ var renderRecallPrompt = (payload, options = {}) => {
326
+ if (!payload.snippets.length) return "";
327
+ const header = options.prefix || "Relevant memory snippets:\n";
328
+ const raw = `${header}${payload.snippets.map((snippet) => `- ${snippet.file}: ${snippet.snippet}`).join("\n")}
329
+ `;
330
+ if (!options.maxChars || raw.length <= options.maxChars) return raw;
331
+ return raw.slice(0, Math.max(0, options.maxChars - 3)) + "...";
332
+ };
333
+ var buildRecallContext = async (options) => {
334
+ const root = options.root || DEFAULT_ROOT;
335
+ const results = await searchMemory(options.query, options, root);
336
+ const snippets = results.map((item) => ({
337
+ file: path.relative(resolveMemoryRoot(root), item.file),
338
+ snippet: item.snippet
339
+ }));
340
+ const payload = { query: options.query, snippets, createdAt: Date.now() };
341
+ return {
342
+ prompt: renderRecallPrompt(payload, { maxChars: options.maxChars, prefix: options.prefix }),
343
+ snippets,
344
+ createdAt: payload.createdAt
345
+ };
346
+ };
347
+ var readRecentLedgers = async (count = 3, root = DEFAULT_ROOT) => {
348
+ const resolved = resolveMemoryRoot(root);
349
+ const files = (await fs.readdir(resolved)).filter((name) => /^\d{4}-\d{2}-\d{2}\.md$/.test(name)).sort().slice(-count);
350
+ const entries = await Promise.all(
351
+ files.map(async (file) => ({
352
+ file,
353
+ content: await fs.readFile(path.join(resolved, file), "utf-8")
354
+ }))
355
+ );
356
+ return entries;
357
+ };
358
+ var distillMemory = async (summary, root = DEFAULT_ROOT) => {
359
+ return updateMemorySummary(summary, root);
360
+ };
361
+ var createMemoryDistillScheduler = (options) => {
362
+ const intervalMs = options.intervalMs ?? 24 * 60 * 60 * 1e3;
363
+ let timer = null;
364
+ let stopped = false;
365
+ const runOnce = async () => {
366
+ try {
367
+ const root = options.root || DEFAULT_ROOT;
368
+ const ledgers = await readRecentLedgers(options.ledgers ?? 3, root);
369
+ const memory = await readMemorySummary(root);
370
+ const summary = await options.buildSummary({ ledgers, memory });
371
+ await updateMemorySummary(summary, root);
372
+ if (options.onSuccess) options.onSuccess(summary);
373
+ } catch (err) {
374
+ if (options.onError) {
375
+ options.onError(err instanceof Error ? err : new Error("memory_distill_failed"));
376
+ }
377
+ }
378
+ };
379
+ const start = async () => {
380
+ if (timer) return;
381
+ await runOnce();
382
+ if (stopped) return;
383
+ timer = setInterval(runOnce, intervalMs);
384
+ };
385
+ const stop = () => {
386
+ stopped = true;
387
+ if (timer) {
388
+ clearInterval(timer);
389
+ timer = null;
390
+ }
391
+ };
392
+ return { start, stop, runOnce };
393
+ };
394
+ var createMemoryBackup = async (options = {}) => {
395
+ const root = options.root || DEFAULT_ROOT;
396
+ const backupDir = resolveBackupDir(root, options.backupDir);
397
+ await ensureDir(backupDir);
398
+ await ensureSecurePermissions(backupDir, 448);
399
+ const snapshot = await serializeMemorySnapshot(root);
400
+ const encrypt = options.encrypt !== false;
401
+ let payload = snapshot;
402
+ if (encrypt) {
403
+ const key = await resolveBackupKey(root, backupDir, options);
404
+ payload = {
405
+ ...encryptPayload(Buffer.from(JSON.stringify(snapshot)), key),
406
+ createdAt: snapshot.createdAt,
407
+ version: snapshot.version
408
+ };
409
+ }
410
+ const { path: backupPath, sizeBytes } = await writeBackupFile(backupDir, payload, encrypt);
411
+ const retention = options.retention ?? DEFAULT_BACKUP_RETENTION;
412
+ await applyRetention(backupDir, retention);
413
+ return {
414
+ path: backupPath,
415
+ createdAt: snapshot.createdAt,
416
+ sizeBytes,
417
+ encrypted: encrypt
418
+ };
419
+ };
420
+ var createMemoryBackupScheduler = (options = {}) => {
421
+ const intervalMs = options.intervalMs ?? 6 * 60 * 60 * 1e3;
422
+ let timer = null;
423
+ let stopped = false;
424
+ const runOnce = async () => {
425
+ try {
426
+ const result = await createMemoryBackup(options);
427
+ if (options.onSuccess) {
428
+ options.onSuccess(result);
429
+ }
430
+ } catch (err) {
431
+ if (options.onError) {
432
+ options.onError(err instanceof Error ? err : new Error("backup_failed"));
433
+ }
434
+ }
435
+ };
436
+ const start = async () => {
437
+ if (timer) return;
438
+ await runOnce();
439
+ if (stopped) return;
440
+ timer = setInterval(runOnce, intervalMs);
441
+ };
442
+ const stop = () => {
443
+ stopped = true;
444
+ if (timer) {
445
+ clearInterval(timer);
446
+ timer = null;
447
+ }
448
+ };
449
+ return { start, stop, runOnce };
450
+ };
451
+ var getMemoryLastUpdatedAt = async (root = DEFAULT_ROOT) => {
452
+ const resolved = resolveMemoryRoot(root);
453
+ const files = await listMarkdownFiles(resolved);
454
+ if (!files.length) return null;
455
+ let latest = 0;
456
+ for (const file of files) {
457
+ const stats = await fs.stat(file);
458
+ const mtime = stats.mtime?.getTime?.() ?? 0;
459
+ if (mtime > latest) latest = mtime;
460
+ }
461
+ return latest ? new Date(latest).toISOString() : null;
462
+ };
463
+ var getMemoryFreshness = async (root = DEFAULT_ROOT, staleHours = 72) => {
464
+ const lastUpdatedAt = await getMemoryLastUpdatedAt(root);
465
+ if (!lastUpdatedAt) {
466
+ return { status: "unknown", lastUpdatedAt: null };
467
+ }
468
+ const ageMs = Date.now() - new Date(lastUpdatedAt).getTime();
469
+ const staleMs = staleHours * 60 * 60 * 1e3;
470
+ return {
471
+ status: ageMs <= staleMs ? "fresh" : "stale",
472
+ lastUpdatedAt
473
+ };
474
+ };
475
+ var memoryCompliance = async (root = DEFAULT_ROOT, staleHours = 72) => {
476
+ const summary = await readMemorySummary(root);
477
+ if (!summary || !summary.includes(SURVIVAL_SECTION) || !summary.includes(SURVIVAL_DIRECTIVE)) {
478
+ return {
479
+ ok: false,
480
+ status: "missing_survival",
481
+ lastUpdatedAt: null,
482
+ warning: "Survival priority missing in MEMORY.md."
483
+ };
484
+ }
485
+ const freshness = await getMemoryFreshness(root, staleHours);
486
+ if (freshness.status === "fresh") {
487
+ return { ok: true, status: "fresh", lastUpdatedAt: freshness.lastUpdatedAt, warning: null };
488
+ }
489
+ if (freshness.status === "stale") {
490
+ return {
491
+ ok: false,
492
+ status: "stale",
493
+ lastUpdatedAt: freshness.lastUpdatedAt,
494
+ warning: `Memory stale (> ${staleHours}h). Update daily ledger.`
495
+ };
496
+ }
497
+ return {
498
+ ok: false,
499
+ status: "unknown",
500
+ lastUpdatedAt: null,
501
+ warning: "Memory not initialized or missing ledger."
502
+ };
503
+ };
504
+ export {
505
+ MEMORY_SCHEMA_VERSION,
506
+ appendDailyLog,
507
+ buildRecallContext,
508
+ createMemoryBackup,
509
+ createMemoryBackupScheduler,
510
+ createMemoryDistillScheduler,
511
+ distillMemory,
512
+ ensureMemoryLayout,
513
+ ensureSurvivalDirective,
514
+ getDailyLedgerPath,
515
+ getMemoryFreshness,
516
+ getMemoryLastUpdatedAt,
517
+ memoryCompliance,
518
+ readIdentityStack,
519
+ readMemorySummary,
520
+ readMemoryVersion,
521
+ readRecentLedgers,
522
+ resolveMemoryRoot,
523
+ searchMemory,
524
+ updateMemorySummary,
525
+ upgradeMemoryLayout,
526
+ writeMemoryVersion
527
+ };
@@ -0,0 +1,89 @@
1
+ type SelfReliancePolicy = {
2
+ solMinBalance: number;
3
+ solWarnBalance: number;
4
+ openRouterMinCredits?: number;
5
+ openRouterWarnCredits?: number;
6
+ allowIfLow?: boolean;
7
+ denyMode?: 'any' | 'all';
8
+ solHardMin?: number;
9
+ warnIntervalMs?: number;
10
+ criticalOnly?: boolean;
11
+ };
12
+ type SelfRelianceState = {
13
+ solBalance?: number;
14
+ openRouterCredits?: number;
15
+ lastWarnAt?: number;
16
+ lastUpdatedAt?: number;
17
+ };
18
+ type SelfRelianceEvents = {
19
+ onWarn?: (state: SelfRelianceState) => void;
20
+ onCritical?: (state: SelfRelianceState) => void;
21
+ onPersist?: (state: SelfRelianceState) => Promise<void> | void;
22
+ };
23
+ type SelfRelianceConfig = {
24
+ policy: SelfReliancePolicy;
25
+ events?: SelfRelianceEvents;
26
+ };
27
+ type ResourceSnapshot = {
28
+ solBalance?: number;
29
+ openRouterCredits?: number;
30
+ tokenBalances?: Record<string, number>;
31
+ updatedAt?: number;
32
+ };
33
+ declare class SelfReliance {
34
+ private policy;
35
+ private events;
36
+ private state;
37
+ constructor(config: SelfRelianceConfig);
38
+ update(snapshot: ResourceSnapshot): SelfRelianceState;
39
+ getState(): {
40
+ solBalance?: number;
41
+ openRouterCredits?: number;
42
+ lastWarnAt?: number;
43
+ lastUpdatedAt?: number;
44
+ };
45
+ isLow(): boolean;
46
+ shouldDeny(): boolean;
47
+ shouldWarn(): boolean;
48
+ enforce(): Promise<"allow" | "deny">;
49
+ guard: () => Promise<boolean>;
50
+ }
51
+ declare const createSelfReliancePolicy: (overrides?: Partial<SelfReliancePolicy>) => SelfReliancePolicy;
52
+ type SelfRelianceMonitorConfig = {
53
+ intervalMs?: number;
54
+ onUpdate?: (snapshot: ResourceSnapshot, state: SelfRelianceState) => void;
55
+ onError?: (error: Error) => void;
56
+ };
57
+ type SurvivalMiddlewareOptions = {
58
+ onDeny?: (state: SelfRelianceState) => void;
59
+ errorStatus?: number;
60
+ errorPayload?: {
61
+ error: string;
62
+ };
63
+ };
64
+ declare const createSurvivalMiddleware: (survival: SelfReliance, options?: SurvivalMiddlewareOptions) => (req: unknown, res: {
65
+ status: (code: number) => {
66
+ json: (body: unknown) => void;
67
+ };
68
+ }, next: () => void) => Promise<void>;
69
+ declare const withSurvival: <T>(survival: SelfReliance, handler: () => Promise<T>, options?: {
70
+ onDeny?: (state: SelfRelianceState) => void;
71
+ }) => Promise<T>;
72
+ declare const createSelfRelianceMonitor: (survival: SelfReliance, fetchSnapshot: () => Promise<ResourceSnapshot>, config?: SelfRelianceMonitorConfig) => {
73
+ start: () => Promise<void>;
74
+ stop: () => void;
75
+ runOnce: () => Promise<void>;
76
+ };
77
+ declare const createAutoSelfReliance: (options: {
78
+ survival: SelfReliance;
79
+ fetchSnapshot: () => Promise<ResourceSnapshot>;
80
+ intervalMs?: number;
81
+ onUpdate?: (snapshot: ResourceSnapshot, state: SelfRelianceState) => void;
82
+ onError?: (error: Error) => void;
83
+ }) => {
84
+ start: () => Promise<void>;
85
+ stop: () => void;
86
+ runOnce: () => Promise<void>;
87
+ };
88
+
89
+ export { type ResourceSnapshot, SelfReliance, type SelfRelianceConfig, type SelfRelianceEvents, type SelfRelianceMonitorConfig, type SelfReliancePolicy, type SelfRelianceState, type SurvivalMiddlewareOptions, createAutoSelfReliance, createSelfRelianceMonitor, createSelfReliancePolicy, createSurvivalMiddleware, withSurvival };
@@ -0,0 +1,16 @@
1
+ import {
2
+ SelfReliance,
3
+ createAutoSelfReliance,
4
+ createSelfRelianceMonitor,
5
+ createSelfReliancePolicy,
6
+ createSurvivalMiddleware,
7
+ withSurvival
8
+ } from "./chunk-BFAMXH2X.js";
9
+ export {
10
+ SelfReliance,
11
+ createAutoSelfReliance,
12
+ createSelfRelianceMonitor,
13
+ createSelfReliancePolicy,
14
+ createSurvivalMiddleware,
15
+ withSurvival
16
+ };