@hasna/mementos 0.14.87 → 0.14.88
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/bun.lock +3 -0
- package/dist/cli/brains.d.ts.map +1 -1
- package/dist/cli/commands/io-backup.d.ts.map +1 -1
- package/dist/cli/commands/io-restore.d.ts.map +1 -1
- package/dist/cli/commands/system-profile.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +952 -681
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/memories.d.ts.map +1 -1
- package/dist/db/pg-migrate.d.ts.map +1 -1
- package/dist/diagnostics/historical-project-registration-receipt.js +116 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +808 -543
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/model-config.d.ts +1 -1
- package/dist/lib/paths.d.ts +51 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/profile-sync.d.ts.map +1 -1
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/storage-sync.d.ts.map +1 -1
- package/dist/lib/sync.d.ts.map +1 -1
- package/dist/mcp/index.js +815 -548
- package/dist/project-registration.js +179 -42
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/helpers.d.ts +31 -0
- package/dist/server/helpers.d.ts.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +872 -554
- package/dist/server/routes/system-synthesis.d.ts.map +1 -1
- package/dist/storage.d.ts +18 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +134 -17
- package/package.json +5 -3
- package/postinstall.mjs +34 -0
|
@@ -152,11 +152,119 @@ var init_retired_storage_mode = __esm(() => {
|
|
|
152
152
|
];
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
//
|
|
156
|
-
import { Database } from "bun:sqlite";
|
|
157
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
155
|
+
// ../../node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
158
156
|
import { homedir } from "os";
|
|
159
157
|
import { join } from "path";
|
|
158
|
+
function assertApp(app) {
|
|
159
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
160
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
161
|
+
}
|
|
162
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
163
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function envOf(options) {
|
|
167
|
+
return options.env ?? process.env;
|
|
168
|
+
}
|
|
169
|
+
function envValue(options, kind) {
|
|
170
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
171
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
172
|
+
}
|
|
173
|
+
function isMacOS(platform) {
|
|
174
|
+
return platform === "darwin";
|
|
175
|
+
}
|
|
176
|
+
function baseDir(kind, options) {
|
|
177
|
+
const override = envValue(options, kind);
|
|
178
|
+
if (override)
|
|
179
|
+
return override;
|
|
180
|
+
const home = options.home ?? homedir();
|
|
181
|
+
const platform = options.platform ?? process.platform;
|
|
182
|
+
if (isMacOS(platform)) {
|
|
183
|
+
switch (kind) {
|
|
184
|
+
case "config":
|
|
185
|
+
case "data":
|
|
186
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
187
|
+
case "cache":
|
|
188
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
189
|
+
case "state":
|
|
190
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
switch (kind) {
|
|
194
|
+
case "config":
|
|
195
|
+
return join(home, ".config", "hasna");
|
|
196
|
+
case "data":
|
|
197
|
+
return join(home, ".local", "share", "hasna");
|
|
198
|
+
case "state":
|
|
199
|
+
return join(home, ".local", "state", "hasna");
|
|
200
|
+
case "cache":
|
|
201
|
+
return join(home, ".cache", "hasna");
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function resolvePath(kind, options) {
|
|
205
|
+
assertApp(options.app);
|
|
206
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
207
|
+
return join(baseDir(kind, options), appSegment);
|
|
208
|
+
}
|
|
209
|
+
function dataDir(options) {
|
|
210
|
+
return resolvePath("data", options);
|
|
211
|
+
}
|
|
212
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
213
|
+
var init_dist = __esm(() => {
|
|
214
|
+
KIND_ENV = {
|
|
215
|
+
config: "HASNA_CONFIG_HOME",
|
|
216
|
+
data: "HASNA_DATA_HOME",
|
|
217
|
+
state: "HASNA_STATE_HOME",
|
|
218
|
+
cache: "HASNA_CACHE_HOME"
|
|
219
|
+
};
|
|
220
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// src/lib/paths.ts
|
|
224
|
+
import { existsSync } from "fs";
|
|
225
|
+
import { homedir as homedir2 } from "os";
|
|
226
|
+
import { join as join2, resolve } from "path";
|
|
227
|
+
function effectiveHome() {
|
|
228
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir2() || "/tmp";
|
|
229
|
+
}
|
|
230
|
+
function legacyDataRoot() {
|
|
231
|
+
return join2(effectiveHome(), ".hasna", "mementos");
|
|
232
|
+
}
|
|
233
|
+
function resolverDataRoot() {
|
|
234
|
+
return dataDir({
|
|
235
|
+
app: "mementos",
|
|
236
|
+
home: process.env["HOME"] || process.env["USERPROFILE"] || undefined
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function adoptResolverDataRoot(resolved, env = process.env) {
|
|
240
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
241
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
242
|
+
return true;
|
|
243
|
+
return existsSync(join2(resolved, "mementos.db"));
|
|
244
|
+
}
|
|
245
|
+
function exactDataRoot() {
|
|
246
|
+
for (const key of ["HASNA_MEMENTOS_HOME", "MEMENTOS_HOME"]) {
|
|
247
|
+
const dir = process.env[key]?.trim();
|
|
248
|
+
if (dir)
|
|
249
|
+
return resolve(dir);
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
function getDataRoot() {
|
|
254
|
+
const exact = exactDataRoot();
|
|
255
|
+
if (exact)
|
|
256
|
+
return exact;
|
|
257
|
+
const resolved = resolverDataRoot();
|
|
258
|
+
return adoptResolverDataRoot(resolved) ? resolve(resolved) : resolve(legacyDataRoot());
|
|
259
|
+
}
|
|
260
|
+
var init_paths = __esm(() => {
|
|
261
|
+
init_dist();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// src/storage.ts
|
|
265
|
+
import { Database } from "bun:sqlite";
|
|
266
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
267
|
+
import { join as join3 } from "path";
|
|
160
268
|
import { fileURLToPath } from "url";
|
|
161
269
|
import { Worker } from "worker_threads";
|
|
162
270
|
import pg from "pg";
|
|
@@ -415,7 +523,7 @@ function readEnv(name) {
|
|
|
415
523
|
return value ? value : null;
|
|
416
524
|
}
|
|
417
525
|
function readConfigFile() {
|
|
418
|
-
if (!
|
|
526
|
+
if (!existsSync2(STORAGE_CONFIG_PATH)) {
|
|
419
527
|
return {};
|
|
420
528
|
}
|
|
421
529
|
try {
|
|
@@ -677,11 +785,7 @@ function saveStorageConfig(config) {
|
|
|
677
785
|
function getConfiguredConnectionString() {
|
|
678
786
|
return getStorageDatabaseUrl() ?? undefined;
|
|
679
787
|
}
|
|
680
|
-
function
|
|
681
|
-
assertNoLegacyStorageMode2();
|
|
682
|
-
if (!isServerContext()) {
|
|
683
|
-
throw new Error("Refusing to construct an RDS Postgres DSN outside the mementos-serve server. " + "The raw database DSN is NEVER distributed to client machines. " + "Clients must use the HTTP API: set HASNA_MEMENTOS_API_URL and " + "HASNA_MEMENTOS_API_KEY (and unset HASNA_MEMENTOS_DATABASE_URL).");
|
|
684
|
-
}
|
|
788
|
+
function resolveConfiguredConnectionString(dbName) {
|
|
685
789
|
const envConnectionString = getConfiguredConnectionString();
|
|
686
790
|
if (envConnectionString) {
|
|
687
791
|
const validation = validatePostgresConnectionString(envConnectionString);
|
|
@@ -700,7 +804,7 @@ function getStorageConnectionString(dbName = "mementos") {
|
|
|
700
804
|
missing.push("storage.rds.username");
|
|
701
805
|
}
|
|
702
806
|
if (missing.length > 0) {
|
|
703
|
-
throw new Error(`Remote storage database is not configured. Missing ${missing.join(", ")}. Set HASNA_MEMENTOS_DATABASE_URL or configure
|
|
807
|
+
throw new Error(`Remote storage database is not configured. Missing ${missing.join(", ")}. Set HASNA_MEMENTOS_DATABASE_URL or configure ${STORAGE_CONFIG_PATH}.`);
|
|
704
808
|
}
|
|
705
809
|
const password = process.env[password_env];
|
|
706
810
|
if (!password) {
|
|
@@ -709,6 +813,17 @@ function getStorageConnectionString(dbName = "mementos") {
|
|
|
709
813
|
const sslParam = ssl ? "?sslmode=require" : "";
|
|
710
814
|
return `postgres://${username}:${encodeURIComponent(password)}@${host}:${port}/${dbName}${sslParam}`;
|
|
711
815
|
}
|
|
816
|
+
function getStorageConnectionString(dbName = "mementos") {
|
|
817
|
+
assertNoLegacyStorageMode2();
|
|
818
|
+
if (!isServerContext()) {
|
|
819
|
+
throw new Error("Refusing to construct an RDS Postgres DSN outside the mementos-serve server. " + "The raw database DSN is NEVER distributed to client machines. " + "Clients must use the HTTP API: set HASNA_MEMENTOS_API_URL and " + "HASNA_MEMENTOS_API_KEY (and unset HASNA_MEMENTOS_DATABASE_URL).");
|
|
820
|
+
}
|
|
821
|
+
return resolveConfiguredConnectionString(dbName);
|
|
822
|
+
}
|
|
823
|
+
function getStorageConnectionStringForOperator(dbName = "mementos") {
|
|
824
|
+
assertNoLegacyStorageMode2();
|
|
825
|
+
return resolveConfiguredConnectionString(dbName);
|
|
826
|
+
}
|
|
712
827
|
function isSyncExcludedTable(table) {
|
|
713
828
|
return SYNC_EXCLUDED_TABLE_PATTERNS.some((pattern) => pattern.test(table));
|
|
714
829
|
}
|
|
@@ -878,6 +993,7 @@ CREATE TABLE IF NOT EXISTS _sync_meta (
|
|
|
878
993
|
var init_storage = __esm(() => {
|
|
879
994
|
init_backend();
|
|
880
995
|
init_retired_storage_mode();
|
|
996
|
+
init_paths();
|
|
881
997
|
PgSyncPool = class PgSyncPool {
|
|
882
998
|
worker;
|
|
883
999
|
status;
|
|
@@ -895,12 +1011,12 @@ var init_storage = __esm(() => {
|
|
|
895
1011
|
const ext = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
|
|
896
1012
|
const here = fileURLToPath(new URL(".", import.meta.url));
|
|
897
1013
|
const candidates = [
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1014
|
+
join3(here, `pg-sync-worker${ext}`),
|
|
1015
|
+
join3(here, "..", `pg-sync-worker${ext}`),
|
|
1016
|
+
join3(here, "..", "..", `pg-sync-worker${ext}`)
|
|
901
1017
|
];
|
|
902
1018
|
for (const candidate of candidates) {
|
|
903
|
-
if (
|
|
1019
|
+
if (existsSync2(candidate))
|
|
904
1020
|
return candidate;
|
|
905
1021
|
}
|
|
906
1022
|
return candidates[0];
|
|
@@ -988,7 +1104,7 @@ var init_storage = __esm(() => {
|
|
|
988
1104
|
MEMENTOS_STORAGE_FALLBACK_ENV = {
|
|
989
1105
|
databaseUrl: "MEMENTOS_DATABASE_URL"
|
|
990
1106
|
};
|
|
991
|
-
LOCAL_DATA_DIR =
|
|
1107
|
+
LOCAL_DATA_DIR = getDataRoot();
|
|
992
1108
|
DEFAULT_STORAGE_CONFIG = {
|
|
993
1109
|
rds: {
|
|
994
1110
|
host: "",
|
|
@@ -1003,8 +1119,8 @@ var init_storage = __esm(() => {
|
|
|
1003
1119
|
schedule_minutes: 0
|
|
1004
1120
|
}
|
|
1005
1121
|
};
|
|
1006
|
-
STORAGE_CONFIG_DIR =
|
|
1007
|
-
STORAGE_CONFIG_PATH =
|
|
1122
|
+
STORAGE_CONFIG_DIR = join3(LOCAL_DATA_DIR, "storage");
|
|
1123
|
+
STORAGE_CONFIG_PATH = join3(STORAGE_CONFIG_DIR, "config.json");
|
|
1008
1124
|
DATABASE_ENV_NAMES = [
|
|
1009
1125
|
{ name: MEMENTOS_STORAGE_ENV.databaseUrl, deprecated: false },
|
|
1010
1126
|
{ name: MEMENTOS_STORAGE_FALLBACK_ENV.databaseUrl, deprecated: false }
|
|
@@ -1030,7 +1146,7 @@ var init_storage = __esm(() => {
|
|
|
1030
1146
|
|
|
1031
1147
|
// src/db/api-mode.ts
|
|
1032
1148
|
import { tmpdir } from "os";
|
|
1033
|
-
import { join as
|
|
1149
|
+
import { join as join4 } from "path";
|
|
1034
1150
|
import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
1035
1151
|
import { randomUUID } from "crypto";
|
|
1036
1152
|
function firstEnv2(keys) {
|
|
@@ -1140,7 +1256,7 @@ x-api-key: ${cfg.apiKey}
|
|
|
1140
1256
|
];
|
|
1141
1257
|
let bodyFile;
|
|
1142
1258
|
if (hasBody) {
|
|
1143
|
-
bodyFile =
|
|
1259
|
+
bodyFile = join4(tmpdir(), `mem-req-${process.pid}-${randomUUID()}.json`);
|
|
1144
1260
|
writeFileSync2(bodyFile, JSON.stringify(body), { mode: 384 });
|
|
1145
1261
|
args.push("--data-binary", `@${bodyFile}`);
|
|
1146
1262
|
}
|
|
@@ -2660,18 +2776,18 @@ __export(exports_database, {
|
|
|
2660
2776
|
escapeLikePrefix: () => escapeLikePrefix,
|
|
2661
2777
|
closeDatabase: () => closeDatabase
|
|
2662
2778
|
});
|
|
2663
|
-
import { existsSync as
|
|
2664
|
-
import { dirname, join as
|
|
2779
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, cpSync } from "fs";
|
|
2780
|
+
import { dirname, join as join5, resolve as resolve2 } from "path";
|
|
2665
2781
|
function isInMemoryDb(path) {
|
|
2666
2782
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
2667
2783
|
}
|
|
2668
2784
|
function findNearestMementosDb(startDir) {
|
|
2669
|
-
let dir =
|
|
2785
|
+
let dir = resolve2(startDir);
|
|
2670
2786
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
2671
|
-
const legacyHomeDb =
|
|
2787
|
+
const legacyHomeDb = resolve2(home, ".mementos", "mementos.db");
|
|
2672
2788
|
while (true) {
|
|
2673
|
-
const candidate =
|
|
2674
|
-
if (
|
|
2789
|
+
const candidate = join5(dir, ".mementos", "mementos.db");
|
|
2790
|
+
if (existsSync3(candidate) && resolve2(candidate) !== legacyHomeDb)
|
|
2675
2791
|
return candidate;
|
|
2676
2792
|
const parent = dirname(dir);
|
|
2677
2793
|
if (parent === dir)
|
|
@@ -2681,9 +2797,9 @@ function findNearestMementosDb(startDir) {
|
|
|
2681
2797
|
return null;
|
|
2682
2798
|
}
|
|
2683
2799
|
function findGitRoot(startDir) {
|
|
2684
|
-
let dir =
|
|
2800
|
+
let dir = resolve2(startDir);
|
|
2685
2801
|
while (true) {
|
|
2686
|
-
if (
|
|
2802
|
+
if (existsSync3(join5(dir, ".git")))
|
|
2687
2803
|
return dir;
|
|
2688
2804
|
const parent = dirname(dir);
|
|
2689
2805
|
if (parent === dir)
|
|
@@ -2694,10 +2810,10 @@ function findGitRoot(startDir) {
|
|
|
2694
2810
|
}
|
|
2695
2811
|
function migrateGlobalDir() {
|
|
2696
2812
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
2697
|
-
const newDir =
|
|
2698
|
-
const oldDir =
|
|
2699
|
-
if (!
|
|
2700
|
-
mkdirSync2(
|
|
2813
|
+
const newDir = getDataRoot();
|
|
2814
|
+
const oldDir = join5(home, ".mementos");
|
|
2815
|
+
if (!existsSync3(newDir) && existsSync3(oldDir)) {
|
|
2816
|
+
mkdirSync2(dirname(newDir), { recursive: true });
|
|
2701
2817
|
cpSync(oldDir, newDir, { recursive: true });
|
|
2702
2818
|
}
|
|
2703
2819
|
}
|
|
@@ -2714,18 +2830,17 @@ function getDbPath() {
|
|
|
2714
2830
|
if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
|
|
2715
2831
|
const gitRoot = findGitRoot(cwd);
|
|
2716
2832
|
if (gitRoot) {
|
|
2717
|
-
return
|
|
2833
|
+
return join5(gitRoot, ".mementos", "mementos.db");
|
|
2718
2834
|
}
|
|
2719
2835
|
}
|
|
2720
2836
|
migrateGlobalDir();
|
|
2721
|
-
|
|
2722
|
-
return join3(home, ".hasna", "mementos", "mementos.db");
|
|
2837
|
+
return join5(getDataRoot(), "mementos.db");
|
|
2723
2838
|
}
|
|
2724
2839
|
function ensureDir(filePath) {
|
|
2725
2840
|
if (isInMemoryDb(filePath))
|
|
2726
2841
|
return;
|
|
2727
|
-
const dir = dirname(
|
|
2728
|
-
if (!
|
|
2842
|
+
const dir = dirname(resolve2(filePath));
|
|
2843
|
+
if (!existsSync3(dir)) {
|
|
2729
2844
|
mkdirSync2(dir, { recursive: true });
|
|
2730
2845
|
}
|
|
2731
2846
|
}
|
|
@@ -2863,6 +2978,7 @@ var init_database = __esm(() => {
|
|
|
2863
2978
|
init_storage();
|
|
2864
2979
|
init_api_mode();
|
|
2865
2980
|
init_migrations();
|
|
2981
|
+
init_paths();
|
|
2866
2982
|
ALLOWED_TABLES = new Set([
|
|
2867
2983
|
"memories",
|
|
2868
2984
|
"agents",
|
|
@@ -2882,7 +2998,7 @@ var init_database = __esm(() => {
|
|
|
2882
2998
|
|
|
2883
2999
|
// src/project-registration/authority.ts
|
|
2884
3000
|
import { createHash as createHash2 } from "crypto";
|
|
2885
|
-
import { resolve as
|
|
3001
|
+
import { resolve as resolve3 } from "path";
|
|
2886
3002
|
|
|
2887
3003
|
// src/db/projects.ts
|
|
2888
3004
|
init_database();
|
|
@@ -2891,13 +3007,13 @@ import { createHash } from "crypto";
|
|
|
2891
3007
|
|
|
2892
3008
|
// src/lib/package-version.ts
|
|
2893
3009
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2894
|
-
import { dirname as dirname2, join as
|
|
3010
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
2895
3011
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2896
3012
|
function getMementosPackageVersion() {
|
|
2897
3013
|
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
2898
3014
|
for (const candidate of [
|
|
2899
|
-
|
|
2900
|
-
|
|
3015
|
+
join6(here, "..", "..", "package.json"),
|
|
3016
|
+
join6(here, "..", "package.json")
|
|
2901
3017
|
]) {
|
|
2902
3018
|
try {
|
|
2903
3019
|
const parsed = JSON.parse(readFileSync2(candidate, "utf8"));
|
|
@@ -3750,7 +3866,7 @@ function ownedPath(target) {
|
|
|
3750
3866
|
}
|
|
3751
3867
|
const path = target.withOwnedPath((value) => value);
|
|
3752
3868
|
requireString(path, "target path", { max: 4096 });
|
|
3753
|
-
if (path !==
|
|
3869
|
+
if (path !== resolve3(path)) {
|
|
3754
3870
|
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "target path must already be canonical and absolute");
|
|
3755
3871
|
}
|
|
3756
3872
|
return path;
|
|
@@ -5443,12 +5559,22 @@ function createMemory(input, dedupeMode = "merge", db) {
|
|
|
5443
5559
|
const effectiveMode = dedupeMode === "overwrite" ? "merge" : dedupeMode === "version-fork" ? "create" : dedupeMode;
|
|
5444
5560
|
if (effectiveMode === "error") {
|
|
5445
5561
|
const existing = d.query(`SELECT id, agent_id, updated_at FROM memories
|
|
5446
|
-
WHERE key = ? AND scope = ? AND COALESCE(project_id, '') = ?
|
|
5562
|
+
WHERE key = ? AND scope = ? AND COALESCE(project_id, '') = ?
|
|
5447
5563
|
LIMIT 1`).get(input.key, input.scope || "private", input.project_id || "");
|
|
5448
5564
|
if (existing) {
|
|
5449
5565
|
throw new MemoryConflictError(input.key, existing);
|
|
5450
5566
|
}
|
|
5451
5567
|
}
|
|
5568
|
+
if (effectiveMode === "create") {
|
|
5569
|
+
const existing = d.query(`SELECT id, agent_id, updated_at FROM memories
|
|
5570
|
+
WHERE key = ? AND scope = ?
|
|
5571
|
+
AND COALESCE(agent_id, '') = ?
|
|
5572
|
+
AND COALESCE(project_id, '') = ?
|
|
5573
|
+
AND COALESCE(session_id, '') = ?`).get(input.key, input.scope || "private", input.agent_id || "", input.project_id || "", input.session_id || "");
|
|
5574
|
+
if (existing) {
|
|
5575
|
+
throw new MemoryConflictError(input.key, existing);
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5452
5578
|
if (effectiveMode === "merge") {
|
|
5453
5579
|
const existing = d.query(`SELECT id, version FROM memories
|
|
5454
5580
|
WHERE key = ? AND scope = ?
|
|
@@ -5876,6 +6002,17 @@ function updateMemory(id, input, db) {
|
|
|
5876
6002
|
if (existing.version !== input.version) {
|
|
5877
6003
|
throw new VersionConflictError(id, input.version, existing.version);
|
|
5878
6004
|
}
|
|
6005
|
+
if (input.scope !== undefined && input.scope !== existing.scope) {
|
|
6006
|
+
const conflict = d.query(`SELECT id, agent_id, updated_at FROM memories
|
|
6007
|
+
WHERE key = ? AND scope = ?
|
|
6008
|
+
AND COALESCE(agent_id, '') = ?
|
|
6009
|
+
AND COALESCE(project_id, '') = ?
|
|
6010
|
+
AND COALESCE(session_id, '') = ?
|
|
6011
|
+
AND id != ?`).get(existing.key, input.scope, existing.agent_id || "", existing.project_id || "", existing.session_id || "", memoryId);
|
|
6012
|
+
if (conflict) {
|
|
6013
|
+
throw new MemoryConflictError(existing.key, conflict);
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
5879
6016
|
const sets = ["version = version + 1", "updated_at = ?"];
|
|
5880
6017
|
const params = [now()];
|
|
5881
6018
|
if (input.value !== undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAqBA,OAAO,EAGL,KAAK,cAAc,EAEpB,MAAM,uBAAuB,CAAC;AA0C/B,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAgCzD;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,GACjC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAmB1B;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C"}
|
package/dist/server/helpers.d.ts
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
export declare const CORS_HEADERS: Record<string, string>;
|
|
2
|
+
/** True for methods that mutate state — the CSRF-relevant request surface. */
|
|
3
|
+
export declare function isStateChangingMethod(method: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* The configured allowlist of origins permitted to mutate state.
|
|
6
|
+
*
|
|
7
|
+
* `MEMENTOS_CORS_ORIGIN` accepts a comma-separated list; each entry may be a
|
|
8
|
+
* full origin (`http://localhost:19428`) or a bare `host[:port]`. The default
|
|
9
|
+
* is the local dashboard origin. An empty value yields an empty allowlist,
|
|
10
|
+
* which fails closed (no origin or host is allowed to mutate state).
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAllowedOrigins(): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Reject state-changing requests whose Origin (when present) or Host (when no
|
|
15
|
+
* Origin is present) is not on the configured allowlist. Read-only methods
|
|
16
|
+
* pass through untouched. Returns an error `Response` to reject, or `null`.
|
|
17
|
+
*
|
|
18
|
+
* This is the non-OPTIONS sibling of the preflight gate: a hostile page can
|
|
19
|
+
* forge a POST/PATCH/DELETE with any Origin it likes, so those methods must
|
|
20
|
+
* be allowlisted on every request, not only at preflight time.
|
|
21
|
+
*/
|
|
22
|
+
export declare function checkOriginOrHost(req: Request, method: string): Response | null;
|
|
23
|
+
/**
|
|
24
|
+
* The allowlist check itself: reject a request whose Origin (when present) or
|
|
25
|
+
* Host (when no Origin is present) is not on the configured allowlist.
|
|
26
|
+
*
|
|
27
|
+
* GET requests are CORS "simple requests" — a hostile cross-origin page can
|
|
28
|
+
* trigger one with no preflight — so a GET route whose handler writes state
|
|
29
|
+
* (a touch/recency update, a cache write, an LLM call) must be gated exactly
|
|
30
|
+
* like a state-changing method, even though its HTTP method is not one.
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkWriteOriginOrHost(req: Request): Response | null;
|
|
2
33
|
export declare const MIME_TYPES: Record<string, string>;
|
|
3
34
|
export declare function json(data: unknown, status?: number): Response;
|
|
4
35
|
export declare function errorResponse(message: string, status: number, details?: unknown): Response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/server/helpers.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/server/helpers.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC;AAQF,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAM5C;AAWD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAG/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAkBpE;AAMD,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAU7C,CAAC;AAMF,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,QAAQ,CAK1D;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,OAAO,GAChB,QAAQ,CAIV;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAWrE;AAKD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAU7D;AAMD,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWpE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAqBjE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMhE;AAMD,wBAAgB,mBAAmB,IAAI,MAAM,CAiB5C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAMjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA+CH,OAAO,sBAAsB,CAAC;AAC9B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,kCAAkC,CAAC;AAC1C,OAAO,sBAAsB,CAAC;AAC9B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,oBAAoB,CAAC;AA8F5B,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA+CH,OAAO,sBAAsB,CAAC;AAC9B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,kCAAkC,CAAC;AAC1C,OAAO,sBAAsB,CAAC;AAC9B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,oBAAoB,CAAC;AA8F5B,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkM9C"}
|