@hasna/mementos 0.14.47 → 0.14.48
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/Dockerfile.package +30 -0
- package/bun.lock +405 -0
- package/dist/cli/index.js +141 -70
- package/dist/db/pg-migrations.d.ts.map +1 -1
- package/dist/generated/storage-kit/health.d.ts +20 -0
- package/dist/generated/storage-kit/health.d.ts.map +1 -0
- package/dist/generated/storage-kit/index.d.ts +8 -0
- package/dist/generated/storage-kit/index.d.ts.map +1 -0
- package/dist/generated/storage-kit/migrations.d.ts +48 -0
- package/dist/generated/storage-kit/migrations.d.ts.map +1 -0
- package/dist/generated/storage-kit/mode.d.ts +48 -0
- package/dist/generated/storage-kit/mode.d.ts.map +1 -0
- package/dist/generated/storage-kit/pool.d.ts +34 -0
- package/dist/generated/storage-kit/pool.d.ts.map +1 -0
- package/dist/generated/storage-kit/query.d.ts +36 -0
- package/dist/generated/storage-kit/query.d.ts.map +1 -0
- package/dist/generated/storage-kit/tls.d.ts +26 -0
- package/dist/generated/storage-kit/tls.d.ts.map +1 -0
- package/dist/index.js +96 -64
- package/dist/mcp/index.js +135 -64
- package/dist/pg-sync-worker.d.ts +2 -0
- package/dist/pg-sync-worker.d.ts.map +1 -0
- package/dist/pg-sync-worker.js +47 -0
- package/dist/sdk/index.d.ts +27 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +25 -6
- package/dist/server/auth.d.ts +11 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +362 -129
- package/dist/server/openapi.d.ts +2 -0
- package/dist/server/openapi.d.ts.map +1 -0
- package/dist/storage.d.ts +36 -3
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +99 -64
- package/docker-entrypoint.sh +46 -0
- package/hasna.contract.json +16 -0
- package/package.json +7 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/server/openapi.ts"],"names":[],"mappings":"AAeA,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsE7E"}
|
package/dist/storage.d.ts
CHANGED
|
@@ -32,12 +32,44 @@ export declare class SqliteAdapter implements DbAdapter {
|
|
|
32
32
|
transaction<T>(fn: () => T): T;
|
|
33
33
|
get raw(): Database;
|
|
34
34
|
}
|
|
35
|
+
export declare function translateSql(sql: string): string;
|
|
35
36
|
export declare function shouldUsePgSsl(connectionString: string): boolean;
|
|
37
|
+
/** Build a pg Pool with adapter-controlled SSL from a connection string. */
|
|
38
|
+
export declare function makePool(connectionString: string): Pool;
|
|
39
|
+
interface SyncQueryResult {
|
|
40
|
+
rows: any[];
|
|
41
|
+
rowCount: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Synchronous Postgres access backed by a worker thread (see
|
|
45
|
+
* `pg-sync-worker.ts`). The worker owns one long-lived `pg.Client` and runs
|
|
46
|
+
* queries on its own event loop; the main thread blocks on `Atomics.wait`
|
|
47
|
+
* against a SharedArrayBuffer until the worker writes the response. This is the
|
|
48
|
+
* only way to expose a truly synchronous API (which the entire mementos data
|
|
49
|
+
* layer requires) over async pg I/O without deadlocking the main event loop.
|
|
50
|
+
*/
|
|
51
|
+
export declare class PgSyncPool {
|
|
52
|
+
private readonly worker;
|
|
53
|
+
private readonly status;
|
|
54
|
+
private readonly data;
|
|
55
|
+
private closed;
|
|
56
|
+
private lastError;
|
|
57
|
+
private static readonly DATA_BYTES;
|
|
58
|
+
private static readonly QUERY_TIMEOUT_MS;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the worker entry file. `storage` is bundled into several entry
|
|
61
|
+
* points at different depths (dist/cli, dist/mcp, dist/server) as well as run
|
|
62
|
+
* directly from source, so probe candidate locations relative to this module.
|
|
63
|
+
*/
|
|
64
|
+
private static resolveWorkerPath;
|
|
65
|
+
constructor(connectionString: string);
|
|
66
|
+
query(sql: string, params: any[]): SyncQueryResult;
|
|
67
|
+
end(): void;
|
|
68
|
+
}
|
|
36
69
|
export declare class PgAdapter implements DbAdapter {
|
|
37
70
|
private readonly pool;
|
|
38
71
|
constructor(connectionString: string);
|
|
39
|
-
constructor(pool:
|
|
40
|
-
private runSync;
|
|
72
|
+
constructor(pool: PgSyncPool);
|
|
41
73
|
run(sql: string, ...params: any[]): RunResult;
|
|
42
74
|
get(sql: string, ...params: any[]): any;
|
|
43
75
|
all(sql: string, ...params: any[]): any[];
|
|
@@ -51,7 +83,7 @@ export declare class PgAdapter implements DbAdapter {
|
|
|
51
83
|
query(sql: string): PreparedStatement;
|
|
52
84
|
close(): void;
|
|
53
85
|
transaction<T>(fn: () => T): T;
|
|
54
|
-
get raw():
|
|
86
|
+
get raw(): PgSyncPool;
|
|
55
87
|
}
|
|
56
88
|
export declare class PgAdapterAsync {
|
|
57
89
|
private readonly pool;
|
|
@@ -176,4 +208,5 @@ export declare function getSyncMetaAll(db: DbAdapter): SyncMeta[];
|
|
|
176
208
|
export declare function getSyncMetaForTable(db: DbAdapter, table: string): SyncMeta | null;
|
|
177
209
|
export declare function resetSyncMeta(db: DbAdapter, table: string): void;
|
|
178
210
|
export declare function resetAllSyncMeta(db: DbAdapter): void;
|
|
211
|
+
export {};
|
|
179
212
|
//# sourceMappingURL=storage.d.ts.map
|
package/dist/storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/storage.js
CHANGED
|
@@ -51,6 +51,8 @@ import { Database } from "bun:sqlite";
|
|
|
51
51
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
52
52
|
import { homedir } from "os";
|
|
53
53
|
import { join } from "path";
|
|
54
|
+
import { fileURLToPath } from "url";
|
|
55
|
+
import { Worker } from "worker_threads";
|
|
54
56
|
import pg from "pg";
|
|
55
57
|
function normalizeParams(params) {
|
|
56
58
|
const flat = params.length === 1 && Array.isArray(params[0]) ? params[0] : params;
|
|
@@ -113,13 +115,15 @@ class SqliteAdapter {
|
|
|
113
115
|
function translateSql(sql) {
|
|
114
116
|
let parameterIndex = 0;
|
|
115
117
|
let translated = sql.replace(/\?/g, () => `$${++parameterIndex}`);
|
|
116
|
-
|
|
118
|
+
const ISO_FMT = `'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'`;
|
|
119
|
+
translated = translated.replace(/datetime\s*\(\s*'now'\s*\)/gi, `to_char(now() AT TIME ZONE 'UTC', ${ISO_FMT})`);
|
|
117
120
|
translated = translated.replace(/datetime\s*\(\s*'now'\s*,\s*'(-?\d+)\s+(minutes?|hours?|days?|seconds?)'\s*\)/gi, (_match, amount, unit) => {
|
|
118
121
|
const parsed = parseInt(String(amount), 10);
|
|
119
122
|
const absolute = Math.abs(parsed);
|
|
120
123
|
const normalizedUnit = String(unit).toLowerCase().replace(/s$/, "");
|
|
121
124
|
const pluralUnit = absolute === 1 ? normalizedUnit : `${normalizedUnit}s`;
|
|
122
|
-
|
|
125
|
+
const op = parsed < 0 ? "-" : "+";
|
|
126
|
+
return `to_char((now() ${op} INTERVAL '${absolute} ${pluralUnit}') AT TIME ZONE 'UTC', ${ISO_FMT})`;
|
|
123
127
|
});
|
|
124
128
|
translated = translated.replace(/lower\s*\(\s*hex\s*\(\s*randomblob\s*\(\s*\d+\s*\)\s*\)\s*\)/gi, "gen_random_uuid()::text");
|
|
125
129
|
translated = translated.replace(/\bIFNULL\s*\(/gi, "COALESCE(");
|
|
@@ -176,56 +180,24 @@ function makePool(connectionString) {
|
|
|
176
180
|
class PgAdapter {
|
|
177
181
|
pool;
|
|
178
182
|
constructor(input) {
|
|
179
|
-
this.pool = typeof input === "string" ?
|
|
180
|
-
}
|
|
181
|
-
runSync(fn) {
|
|
182
|
-
let result;
|
|
183
|
-
let error;
|
|
184
|
-
let done = false;
|
|
185
|
-
fn().then((value) => {
|
|
186
|
-
result = value;
|
|
187
|
-
done = true;
|
|
188
|
-
}).catch((caught) => {
|
|
189
|
-
error = caught;
|
|
190
|
-
done = true;
|
|
191
|
-
});
|
|
192
|
-
const deadline = Date.now() + 30000;
|
|
193
|
-
while (!done && Date.now() < deadline) {
|
|
194
|
-
Bun.sleepSync(1);
|
|
195
|
-
}
|
|
196
|
-
if (error) {
|
|
197
|
-
throw error;
|
|
198
|
-
}
|
|
199
|
-
if (!done) {
|
|
200
|
-
throw new Error("PostgreSQL query timed out after 30s");
|
|
201
|
-
}
|
|
202
|
-
return result;
|
|
183
|
+
this.pool = typeof input === "string" ? new PgSyncPool(input) : input;
|
|
203
184
|
}
|
|
204
185
|
run(sql, ...params) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
};
|
|
211
|
-
});
|
|
186
|
+
const result = this.pool.query(translateSql(sql), normalizeParams(params));
|
|
187
|
+
return {
|
|
188
|
+
changes: result.rowCount ?? 0,
|
|
189
|
+
lastInsertRowid: result.rows?.[0]?.id ?? 0
|
|
190
|
+
};
|
|
212
191
|
}
|
|
213
192
|
get(sql, ...params) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return result.rows[0] ?? null;
|
|
217
|
-
});
|
|
193
|
+
const result = this.pool.query(translateSql(sql), normalizeParams(params));
|
|
194
|
+
return result.rows[0] ?? null;
|
|
218
195
|
}
|
|
219
196
|
all(sql, ...params) {
|
|
220
|
-
return this.
|
|
221
|
-
const result = await this.pool.query(translateSql(sql), normalizeParams(params));
|
|
222
|
-
return result.rows;
|
|
223
|
-
});
|
|
197
|
+
return this.pool.query(translateSql(sql), normalizeParams(params)).rows;
|
|
224
198
|
}
|
|
225
199
|
exec(sql) {
|
|
226
|
-
this.
|
|
227
|
-
await this.pool.query(sql);
|
|
228
|
-
});
|
|
200
|
+
this.pool.query(sql, []);
|
|
229
201
|
}
|
|
230
202
|
prepare(sql) {
|
|
231
203
|
return {
|
|
@@ -239,28 +211,20 @@ class PgAdapter {
|
|
|
239
211
|
return this.prepare(sql);
|
|
240
212
|
}
|
|
241
213
|
close() {
|
|
242
|
-
this.
|
|
243
|
-
await this.pool.end();
|
|
244
|
-
});
|
|
214
|
+
this.pool.end();
|
|
245
215
|
}
|
|
246
216
|
transaction(fn) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const
|
|
217
|
+
this.pool.query("BEGIN", []);
|
|
218
|
+
try {
|
|
219
|
+
const value = fn();
|
|
220
|
+
this.pool.query("COMMIT", []);
|
|
221
|
+
return value;
|
|
222
|
+
} catch (error) {
|
|
250
223
|
try {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return value;
|
|
256
|
-
} catch (error) {
|
|
257
|
-
await client.query("ROLLBACK");
|
|
258
|
-
throw error;
|
|
259
|
-
} finally {
|
|
260
|
-
this.pool.query = originalQuery;
|
|
261
|
-
client.release();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
224
|
+
this.pool.query("ROLLBACK", []);
|
|
225
|
+
} catch {}
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
264
228
|
}
|
|
265
229
|
get raw() {
|
|
266
230
|
return this.pool;
|
|
@@ -610,7 +574,7 @@ function resetAllSyncMeta(db) {
|
|
|
610
574
|
ensureSyncMetaTable(db);
|
|
611
575
|
db.run("DELETE FROM _sync_meta");
|
|
612
576
|
}
|
|
613
|
-
var MEMENTOS_STORAGE_TABLES, STORAGE_TABLES, MEMENTOS_STORAGE_ENV, MEMENTOS_STORAGE_FALLBACK_ENV, DEFAULT_STORAGE_CONFIG, STORAGE_CONFIG_DIR, STORAGE_CONFIG_PATH, DATABASE_ENV_NAMES, MODE_ENV_NAMES, warnedDeprecatedModes, getMementosStorageStatus, SYNC_EXCLUDED_TABLE_PATTERNS, SYNC_META_TABLE_SQL = `
|
|
577
|
+
var PgSyncPool, MEMENTOS_STORAGE_TABLES, STORAGE_TABLES, MEMENTOS_STORAGE_ENV, MEMENTOS_STORAGE_FALLBACK_ENV, DEFAULT_STORAGE_CONFIG, STORAGE_CONFIG_DIR, STORAGE_CONFIG_PATH, DATABASE_ENV_NAMES, MODE_ENV_NAMES, warnedDeprecatedModes, getMementosStorageStatus, SYNC_EXCLUDED_TABLE_PATTERNS, SYNC_META_TABLE_SQL = `
|
|
614
578
|
CREATE TABLE IF NOT EXISTS _sync_meta (
|
|
615
579
|
table_name TEXT PRIMARY KEY,
|
|
616
580
|
last_synced_at TEXT,
|
|
@@ -618,6 +582,74 @@ CREATE TABLE IF NOT EXISTS _sync_meta (
|
|
|
618
582
|
direction TEXT DEFAULT 'push'
|
|
619
583
|
)`;
|
|
620
584
|
var init_storage = __esm(() => {
|
|
585
|
+
PgSyncPool = class PgSyncPool {
|
|
586
|
+
worker;
|
|
587
|
+
status;
|
|
588
|
+
data;
|
|
589
|
+
closed = false;
|
|
590
|
+
lastError = null;
|
|
591
|
+
static DATA_BYTES = 128 * 1024 * 1024;
|
|
592
|
+
static QUERY_TIMEOUT_MS = 60000;
|
|
593
|
+
static resolveWorkerPath() {
|
|
594
|
+
const ext = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
|
|
595
|
+
const here = fileURLToPath(new URL(".", import.meta.url));
|
|
596
|
+
const candidates = [
|
|
597
|
+
join(here, `pg-sync-worker${ext}`),
|
|
598
|
+
join(here, "..", `pg-sync-worker${ext}`),
|
|
599
|
+
join(here, "..", "..", `pg-sync-worker${ext}`)
|
|
600
|
+
];
|
|
601
|
+
for (const candidate of candidates) {
|
|
602
|
+
if (existsSync(candidate))
|
|
603
|
+
return candidate;
|
|
604
|
+
}
|
|
605
|
+
return candidates[0];
|
|
606
|
+
}
|
|
607
|
+
constructor(connectionString) {
|
|
608
|
+
const control = new SharedArrayBuffer(8);
|
|
609
|
+
const dataSab = new SharedArrayBuffer(PgSyncPool.DATA_BYTES);
|
|
610
|
+
this.status = new Int32Array(control);
|
|
611
|
+
this.data = new Uint8Array(dataSab);
|
|
612
|
+
this.worker = new Worker(PgSyncPool.resolveWorkerPath(), {
|
|
613
|
+
workerData: {
|
|
614
|
+
dsn: stripSslParams(connectionString),
|
|
615
|
+
ssl: sslConfigFor(connectionString),
|
|
616
|
+
control,
|
|
617
|
+
data: dataSab
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
this.worker.unref();
|
|
621
|
+
this.worker.on("error", (err) => {
|
|
622
|
+
this.lastError = err;
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
query(sql, params) {
|
|
626
|
+
if (this.closed)
|
|
627
|
+
throw new Error("PgSyncPool is closed");
|
|
628
|
+
if (this.lastError)
|
|
629
|
+
throw this.lastError;
|
|
630
|
+
Atomics.store(this.status, 0, 0);
|
|
631
|
+
this.worker.postMessage({ sql, params });
|
|
632
|
+
const waitResult = Atomics.wait(this.status, 0, 0, PgSyncPool.QUERY_TIMEOUT_MS);
|
|
633
|
+
const code = Atomics.load(this.status, 0);
|
|
634
|
+
if (code === 0 || waitResult === "timed-out") {
|
|
635
|
+
if (this.lastError)
|
|
636
|
+
throw this.lastError;
|
|
637
|
+
throw new Error("PostgreSQL query timed out after 60s");
|
|
638
|
+
}
|
|
639
|
+
const len = Atomics.load(this.status, 1);
|
|
640
|
+
const payload = JSON.parse(new TextDecoder().decode(this.data.subarray(0, len)));
|
|
641
|
+
if (code === 2) {
|
|
642
|
+
throw new Error(payload.message ?? "PostgreSQL error");
|
|
643
|
+
}
|
|
644
|
+
return payload;
|
|
645
|
+
}
|
|
646
|
+
end() {
|
|
647
|
+
if (this.closed)
|
|
648
|
+
return;
|
|
649
|
+
this.closed = true;
|
|
650
|
+
this.worker.terminate();
|
|
651
|
+
}
|
|
652
|
+
};
|
|
621
653
|
MEMENTOS_STORAGE_TABLES = [
|
|
622
654
|
"projects",
|
|
623
655
|
"agents",
|
|
@@ -681,10 +713,12 @@ var init_storage = __esm(() => {
|
|
|
681
713
|
init_storage();
|
|
682
714
|
|
|
683
715
|
export {
|
|
716
|
+
translateSql,
|
|
684
717
|
shouldUsePgSsl,
|
|
685
718
|
saveStorageConfig,
|
|
686
719
|
resetSyncMeta,
|
|
687
720
|
resetAllSyncMeta,
|
|
721
|
+
makePool,
|
|
688
722
|
listSqliteTables,
|
|
689
723
|
isSyncExcludedTable,
|
|
690
724
|
incrementalSyncPush,
|
|
@@ -705,6 +739,7 @@ export {
|
|
|
705
739
|
SqliteAdapter,
|
|
706
740
|
SYNC_EXCLUDED_TABLE_PATTERNS,
|
|
707
741
|
STORAGE_TABLES,
|
|
742
|
+
PgSyncPool,
|
|
708
743
|
PgAdapterAsync,
|
|
709
744
|
PgAdapter,
|
|
710
745
|
MEMENTOS_STORAGE_TABLES,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# mementos container entrypoint
|
|
4
|
+
# -----------------------------------------------------------------------------
|
|
5
|
+
# Bridges the hasna-app Terraform module's injected env (DATABASE_URL,
|
|
6
|
+
# API_KEY_SIGNING_SECRET, PORT) to mementos' native env, forces pure-remote
|
|
7
|
+
# cloud storage, and binds to all interfaces so the ALB target group is
|
|
8
|
+
# reachable. Migrations run against the OWNER DSN (DDL); the long-running
|
|
9
|
+
# service runs against the least-privilege APP DSN.
|
|
10
|
+
# =============================================================================
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
# Bind on 0.0.0.0 inside the container (default is 127.0.0.1 for local dev).
|
|
14
|
+
export MEMENTOS_HOST="${MEMENTOS_HOST:-0.0.0.0}"
|
|
15
|
+
|
|
16
|
+
# Amendment A1 — serve/CLI read+write RDS directly.
|
|
17
|
+
export HASNA_MEMENTOS_STORAGE_MODE="${HASNA_MEMENTOS_STORAGE_MODE:-cloud}"
|
|
18
|
+
|
|
19
|
+
# Select the DSN by workload: migrations need the owner role (DDL); everything
|
|
20
|
+
# else uses the app role. MIGRATION_DATABASE_URL is optional; falls back to
|
|
21
|
+
# DATABASE_URL when unset.
|
|
22
|
+
case " $* " in
|
|
23
|
+
*" migrate "*)
|
|
24
|
+
export HASNA_MEMENTOS_DATABASE_URL="${HASNA_MEMENTOS_DATABASE_URL:-${MIGRATION_DATABASE_URL:-${DATABASE_URL}}}"
|
|
25
|
+
;;
|
|
26
|
+
*)
|
|
27
|
+
export HASNA_MEMENTOS_DATABASE_URL="${HASNA_MEMENTOS_DATABASE_URL:-${DATABASE_URL}}"
|
|
28
|
+
;;
|
|
29
|
+
esac
|
|
30
|
+
|
|
31
|
+
# Contracts auth reads API_KEY_SIGNING_SECRET directly; also expose the
|
|
32
|
+
# app-scoped alias for the issuer/CLI.
|
|
33
|
+
export HASNA_MEMENTOS_API_SIGNING_KEY="${HASNA_MEMENTOS_API_SIGNING_KEY:-${API_KEY_SIGNING_SECRET}}"
|
|
34
|
+
|
|
35
|
+
# Map published bin names to their dist entrypoints.
|
|
36
|
+
cmd="${1:-mementos-serve}"
|
|
37
|
+
[ "$#" -gt 0 ] && shift || true
|
|
38
|
+
case "$cmd" in
|
|
39
|
+
mementos-serve) set -- bun /app/dist/server/index.js "$@" ;;
|
|
40
|
+
mementos-mcp) set -- bun /app/dist/mcp/index.js "$@" ;;
|
|
41
|
+
mementos) set -- bun /app/dist/cli/index.js "$@" ;;
|
|
42
|
+
bun|/*) set -- "$cmd" "$@" ;;
|
|
43
|
+
*) set -- "$cmd" "$@" ;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
exec "$@"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@hasna/contracts/dist/hasna.contract.schema.json",
|
|
3
|
+
"schema": "hasna.service_contract.v1",
|
|
4
|
+
"name": "mementos",
|
|
5
|
+
"class": "service",
|
|
6
|
+
"contractVersion": "v1",
|
|
7
|
+
"kitVersion": "0.4.1",
|
|
8
|
+
"description": "Universal memory system for AI agents — CLI + MCP server + REST serve API + typed SDK. self_hosted service backed by pure-remote Postgres (Amendment A1).",
|
|
9
|
+
"bins": ["mementos", "mementos-mcp", "mementos-serve"],
|
|
10
|
+
"storage": {
|
|
11
|
+
"mode": "cloud",
|
|
12
|
+
"envPrefix": "HASNA_MEMENTOS_",
|
|
13
|
+
"aliasEnvPrefix": "MEMENTOS_",
|
|
14
|
+
"databaseUrlSecretRef": "hasna/oss/mementos/database-url"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/mementos",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.48",
|
|
4
4
|
"description": "Universal memory system for AI agents - CLI + MCP server + library API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,12 +27,16 @@
|
|
|
27
27
|
"files": [
|
|
28
28
|
"dist",
|
|
29
29
|
"dashboard/dist",
|
|
30
|
+
"Dockerfile.package",
|
|
31
|
+
"docker-entrypoint.sh",
|
|
32
|
+
"bun.lock",
|
|
33
|
+
"hasna.contract.json",
|
|
30
34
|
"LICENSE",
|
|
31
35
|
"README.md"
|
|
32
36
|
],
|
|
33
37
|
"scripts": {
|
|
34
38
|
"clean": "rm -rf dist",
|
|
35
|
-
"build": "bun run clean && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external pg && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external pg && bun build src/server/index.ts --outdir dist/server --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external pg && bun build src/index.ts src/storage.ts --outdir dist --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external pg && bun build src/sdk/index.ts --outdir dist/sdk --target bun && tsc --emitDeclarationOnly --outDir dist",
|
|
39
|
+
"build": "bun run clean && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/server/index.ts --outdir dist/server --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/index.ts src/storage.ts src/pg-sync-worker.ts --outdir dist --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/sdk/index.ts --outdir dist/sdk --target bun && tsc --emitDeclarationOnly --outDir dist",
|
|
36
40
|
"prepare": "bun run build",
|
|
37
41
|
"prepublishOnly": "bun run typecheck && bun run test",
|
|
38
42
|
"typecheck": "tsc --noEmit",
|
|
@@ -75,7 +79,7 @@
|
|
|
75
79
|
"@ai-sdk/anthropic": "^3.0.82",
|
|
76
80
|
"@ai-sdk/openai": "^3.0.69",
|
|
77
81
|
"@ai-sdk/openai-compatible": "^2.0.48",
|
|
78
|
-
"@hasna/contracts": "
|
|
82
|
+
"@hasna/contracts": "0.4.1",
|
|
79
83
|
"@hasna/events": "^0.1.6",
|
|
80
84
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
81
85
|
"ai": "^6.0.199",
|