@hasna/mementos 0.14.84 → 0.14.85
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/cli/commands/info-history.d.ts.map +1 -1
- package/dist/cli/commands/info-stale.d.ts.map +1 -1
- package/dist/cli/commands/io-export.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-list.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts +31 -0
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +350 -73
- package/dist/db/analytics.d.ts +13 -0
- package/dist/db/analytics.d.ts.map +1 -1
- package/dist/db/api-mode.d.ts.map +1 -1
- package/dist/db/memories.d.ts +59 -3
- package/dist/db/memories.d.ts.map +1 -1
- package/dist/diagnostics/historical-project-registration-receipt.d.ts +39 -0
- package/dist/diagnostics/historical-project-registration-receipt.d.ts.map +1 -0
- package/dist/diagnostics/historical-project-registration-receipt.js +1656 -0
- package/dist/index.js +204 -35
- package/dist/lib/gatherer.d.ts.map +1 -1
- package/dist/mcp/index.js +238 -39
- package/dist/mcp/tools/memory-io.d.ts.map +1 -1
- package/dist/project-registration/authority.d.ts.map +1 -1
- package/dist/project-registration/historical-receipt.d.ts +38 -0
- package/dist/project-registration/historical-receipt.d.ts.map +1 -0
- package/dist/project-registration/identity.d.ts.map +1 -1
- package/dist/project-registration/index.d.ts +1 -1
- package/dist/project-registration/index.d.ts.map +1 -1
- package/dist/project-registration/types.d.ts +26 -0
- package/dist/project-registration/types.d.ts.map +1 -1
- package/dist/project-registration.js +201 -32
- package/dist/sdk/index.d.ts +7 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +122 -30
- package/dist/server/index.js +312 -56
- package/dist/test-support/memories-page-stub-server.d.ts +2 -0
- package/dist/test-support/memories-page-stub-server.d.ts.map +1 -0
- package/dist/test-support/memories-page-stub.d.ts +28 -0
- package/dist/test-support/memories-page-stub.d.ts.map +1 -0
- package/package.json +3 -2
package/dist/server/index.js
CHANGED
|
@@ -780,7 +780,16 @@ x-api-key: ${cfg.apiKey}
|
|
|
780
780
|
function apiJson(method, path, body, options) {
|
|
781
781
|
const raw = apiRequestRaw(method, path, body);
|
|
782
782
|
if (raw.status >= 200 && raw.status < 300) {
|
|
783
|
-
|
|
783
|
+
let data;
|
|
784
|
+
if (raw.body.trim()) {
|
|
785
|
+
try {
|
|
786
|
+
data = JSON.parse(raw.body);
|
|
787
|
+
} catch (e) {
|
|
788
|
+
throw new ApiRequestError(`mementos cloud ${method} ${path} returned status ${raw.status} with a body that is not valid JSON (${e instanceof Error ? e.message : String(e)}) \u2014 the response is truncated or the server is unhealthy`, raw.status, raw.body.slice(0, 500));
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
data = undefined;
|
|
792
|
+
}
|
|
784
793
|
return { status: raw.status, data };
|
|
785
794
|
}
|
|
786
795
|
if (raw.status === 404 && options?.allow404) {
|
|
@@ -2696,7 +2705,10 @@ __export(exports_memories, {
|
|
|
2696
2705
|
touchMemory: () => touchMemory,
|
|
2697
2706
|
semanticSearch: () => semanticSearch,
|
|
2698
2707
|
parseMemoryRow: () => parseMemoryRow,
|
|
2708
|
+
listMemoryHistoryPage: () => listMemoryHistoryPage,
|
|
2699
2709
|
listMemoryHistory: () => listMemoryHistory,
|
|
2710
|
+
listMemoriesPage: () => listMemoriesPage,
|
|
2711
|
+
listMemoriesBounded: () => listMemoriesBounded,
|
|
2700
2712
|
listMemories: () => listMemories,
|
|
2701
2713
|
listLowTrustMemories: () => listLowTrustMemories,
|
|
2702
2714
|
indexMemoryEmbedding: () => indexMemoryEmbedding,
|
|
@@ -2710,6 +2722,8 @@ __export(exports_memories, {
|
|
|
2710
2722
|
getMemoriesByKey: () => getMemoriesByKey,
|
|
2711
2723
|
deleteMemory: () => deleteMemory,
|
|
2712
2724
|
createMemory: () => createMemory,
|
|
2725
|
+
countMemoryHistory: () => countMemoryHistory,
|
|
2726
|
+
countMemories: () => countMemories,
|
|
2713
2727
|
cleanExpiredMemories: () => cleanExpiredMemories,
|
|
2714
2728
|
bulkUpsertMemories: () => bulkUpsertMemories,
|
|
2715
2729
|
bulkDeleteMemories: () => bulkDeleteMemories
|
|
@@ -3076,29 +3090,7 @@ function getMemoriesByKey(key, scope, agentId, projectId, db) {
|
|
|
3076
3090
|
const rows = d.query(sql).all(...params);
|
|
3077
3091
|
return rows.map(parseMemoryRow);
|
|
3078
3092
|
}
|
|
3079
|
-
function
|
|
3080
|
-
if (!db && isApiMode()) {
|
|
3081
|
-
const f = filter || {};
|
|
3082
|
-
const q = toQuery({
|
|
3083
|
-
key: f.key,
|
|
3084
|
-
scope: f.scope,
|
|
3085
|
-
category: f.category,
|
|
3086
|
-
status: f.status,
|
|
3087
|
-
tags: f.tags,
|
|
3088
|
-
min_importance: f.min_importance,
|
|
3089
|
-
pinned: f.pinned,
|
|
3090
|
-
agent_id: f.agent_id,
|
|
3091
|
-
project_id: f.project_id,
|
|
3092
|
-
session_id: f.session_id,
|
|
3093
|
-
namespace: f.namespace,
|
|
3094
|
-
as_of: f.as_of,
|
|
3095
|
-
limit: f.limit,
|
|
3096
|
-
offset: f.offset
|
|
3097
|
-
});
|
|
3098
|
-
const { data } = apiJson("GET", `/memories${q}`);
|
|
3099
|
-
return data?.memories ?? [];
|
|
3100
|
-
}
|
|
3101
|
-
const d = db || getDatabase();
|
|
3093
|
+
function buildMemoryListConditions(filter) {
|
|
3102
3094
|
const conditions = [];
|
|
3103
3095
|
const params = [];
|
|
3104
3096
|
if (filter) {
|
|
@@ -3210,21 +3202,109 @@ function listMemories(filter, db) {
|
|
|
3210
3202
|
} else {
|
|
3211
3203
|
conditions.push("status = 'active'");
|
|
3212
3204
|
}
|
|
3205
|
+
return { conditions, params };
|
|
3206
|
+
}
|
|
3207
|
+
function listMemoriesPage(filter, db) {
|
|
3208
|
+
const f = filter || {};
|
|
3209
|
+
if (!db && isApiMode()) {
|
|
3210
|
+
const q = toQuery({
|
|
3211
|
+
key: f.key,
|
|
3212
|
+
scope: f.scope,
|
|
3213
|
+
category: f.category,
|
|
3214
|
+
status: f.status,
|
|
3215
|
+
tags: f.tags,
|
|
3216
|
+
min_importance: f.min_importance,
|
|
3217
|
+
pinned: f.pinned,
|
|
3218
|
+
agent_id: f.agent_id,
|
|
3219
|
+
project_id: f.project_id,
|
|
3220
|
+
session_id: f.session_id,
|
|
3221
|
+
namespace: f.namespace,
|
|
3222
|
+
as_of: f.as_of,
|
|
3223
|
+
limit: f.limit,
|
|
3224
|
+
offset: f.offset
|
|
3225
|
+
});
|
|
3226
|
+
const { data } = apiJson("GET", `/memories${q}`);
|
|
3227
|
+
return {
|
|
3228
|
+
rows: data?.memories ?? [],
|
|
3229
|
+
has_more: data?.has_more,
|
|
3230
|
+
next_cursor: data?.next_cursor ?? null
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
const d = db || getDatabase();
|
|
3234
|
+
const { conditions, params } = buildMemoryListConditions(f);
|
|
3213
3235
|
let sql = "SELECT * FROM memories";
|
|
3214
3236
|
if (conditions.length > 0) {
|
|
3215
3237
|
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
3216
3238
|
}
|
|
3217
3239
|
sql += " ORDER BY importance DESC, created_at DESC";
|
|
3218
|
-
if (
|
|
3240
|
+
if (f.limit) {
|
|
3219
3241
|
sql += " LIMIT ?";
|
|
3220
|
-
params.push(
|
|
3242
|
+
params.push(f.limit);
|
|
3221
3243
|
}
|
|
3222
|
-
if (
|
|
3244
|
+
if (f.offset) {
|
|
3223
3245
|
sql += " OFFSET ?";
|
|
3224
|
-
params.push(
|
|
3246
|
+
params.push(f.offset);
|
|
3225
3247
|
}
|
|
3226
3248
|
const rows = d.query(sql).all(...params);
|
|
3227
|
-
|
|
3249
|
+
const parsed = rows.map(parseMemoryRow);
|
|
3250
|
+
const hasMore = f.limit !== undefined && parsed.length === f.limit;
|
|
3251
|
+
return {
|
|
3252
|
+
rows: parsed,
|
|
3253
|
+
has_more: hasMore,
|
|
3254
|
+
next_cursor: hasMore ? (f.offset ?? 0) + parsed.length : null
|
|
3255
|
+
};
|
|
3256
|
+
}
|
|
3257
|
+
function listMemories(filter, db) {
|
|
3258
|
+
return listMemoriesPage(filter, db).rows;
|
|
3259
|
+
}
|
|
3260
|
+
function listMemoriesBounded(filter = {}, target, db) {
|
|
3261
|
+
const pageSize = 1000;
|
|
3262
|
+
const maxPages = 1000;
|
|
3263
|
+
const want = target === undefined ? undefined : target + 1;
|
|
3264
|
+
const rows = [];
|
|
3265
|
+
const seenCursors = new Set;
|
|
3266
|
+
let cursor = filter.offset ?? 0;
|
|
3267
|
+
let pages = 0;
|
|
3268
|
+
for (;; ) {
|
|
3269
|
+
if (want !== undefined && rows.length >= want)
|
|
3270
|
+
break;
|
|
3271
|
+
if (++pages > maxPages) {
|
|
3272
|
+
throw new Error(`memories list traversal exceeded ${maxPages} pages while collecting rows \u2014 aborting (cursor cycle?)`);
|
|
3273
|
+
}
|
|
3274
|
+
const limit = Math.min(want === undefined ? pageSize : want - rows.length, pageSize);
|
|
3275
|
+
const page = listMemoriesPage({ ...filter, limit, offset: cursor }, db);
|
|
3276
|
+
rows.push(...page.rows);
|
|
3277
|
+
if (page.has_more === false)
|
|
3278
|
+
break;
|
|
3279
|
+
if (page.has_more === undefined && page.rows.length < limit)
|
|
3280
|
+
break;
|
|
3281
|
+
if (page.has_more === true && (page.next_cursor === null || page.next_cursor === undefined)) {
|
|
3282
|
+
throw new Error("memories list page claimed more results without a next cursor \u2014 aborting");
|
|
3283
|
+
}
|
|
3284
|
+
const next = page.next_cursor ?? cursor + page.rows.length;
|
|
3285
|
+
if (seenCursors.has(next)) {
|
|
3286
|
+
throw new Error("memories list traversal repeated a cursor \u2014 aborting");
|
|
3287
|
+
}
|
|
3288
|
+
seenCursors.add(next);
|
|
3289
|
+
cursor = next;
|
|
3290
|
+
}
|
|
3291
|
+
const hasMore = target !== undefined && rows.length > target;
|
|
3292
|
+
const trimmed = hasMore ? rows.slice(0, target) : rows;
|
|
3293
|
+
return {
|
|
3294
|
+
rows: trimmed,
|
|
3295
|
+
has_more: hasMore,
|
|
3296
|
+
next_cursor: hasMore ? (filter.offset ?? 0) + trimmed.length : null
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
function countMemories(filter, db) {
|
|
3300
|
+
const d = db || getDatabase();
|
|
3301
|
+
const { conditions, params } = buildMemoryListConditions(filter);
|
|
3302
|
+
let sql = "SELECT COUNT(*) AS c FROM memories";
|
|
3303
|
+
if (conditions.length > 0) {
|
|
3304
|
+
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
3305
|
+
}
|
|
3306
|
+
const row = d.query(sql).get(...params);
|
|
3307
|
+
return row?.c ?? 0;
|
|
3228
3308
|
}
|
|
3229
3309
|
function getMemoryBriefing(opts, db) {
|
|
3230
3310
|
const limit = opts.limit ?? 20;
|
|
@@ -3286,13 +3366,17 @@ function listLowTrustMemories(opts = {}, db) {
|
|
|
3286
3366
|
const rows = d.prepare(`SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ? OFFSET ?`).all(...params);
|
|
3287
3367
|
return rows.map(parseMemoryRow);
|
|
3288
3368
|
}
|
|
3289
|
-
function
|
|
3369
|
+
function listMemoryHistoryPage(opts = {}, db) {
|
|
3290
3370
|
const limit = opts.limit ?? 20;
|
|
3291
3371
|
const offset = opts.offset ?? 0;
|
|
3292
3372
|
if (!db && isApiMode()) {
|
|
3293
3373
|
const q = toQuery({ limit, offset });
|
|
3294
3374
|
const { data } = apiJson("GET", `/memories/history${q}`);
|
|
3295
|
-
return
|
|
3375
|
+
return {
|
|
3376
|
+
rows: data?.memories ?? [],
|
|
3377
|
+
has_more: data?.has_more,
|
|
3378
|
+
next_cursor: data?.next_cursor ?? null
|
|
3379
|
+
};
|
|
3296
3380
|
}
|
|
3297
3381
|
const d = db || getDatabase();
|
|
3298
3382
|
const params = [limit];
|
|
@@ -3302,7 +3386,21 @@ function listMemoryHistory(opts = {}, db) {
|
|
|
3302
3386
|
params.push(offset);
|
|
3303
3387
|
}
|
|
3304
3388
|
const rows = d.query(sql).all(...params);
|
|
3305
|
-
|
|
3389
|
+
const parsed = rows.map(parseMemoryRow);
|
|
3390
|
+
const hasMore = parsed.length === limit;
|
|
3391
|
+
return {
|
|
3392
|
+
rows: parsed,
|
|
3393
|
+
has_more: hasMore,
|
|
3394
|
+
next_cursor: hasMore ? offset + parsed.length : null
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3397
|
+
function listMemoryHistory(opts = {}, db) {
|
|
3398
|
+
return listMemoryHistoryPage(opts, db).rows;
|
|
3399
|
+
}
|
|
3400
|
+
function countMemoryHistory(db) {
|
|
3401
|
+
const d = db || getDatabase();
|
|
3402
|
+
const row = d.query("SELECT COUNT(*) AS c FROM memories WHERE status = 'active' AND accessed_at IS NOT NULL").get();
|
|
3403
|
+
return row?.c ?? 0;
|
|
3306
3404
|
}
|
|
3307
3405
|
function getMemoryChain(sequenceGroup, projectId, db) {
|
|
3308
3406
|
if (!db && isApiMode()) {
|
|
@@ -19888,7 +19986,7 @@ class JSONSchemaGenerator {
|
|
|
19888
19986
|
if (val === undefined) {
|
|
19889
19987
|
if (this.unrepresentable === "throw") {
|
|
19890
19988
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
19891
|
-
}
|
|
19989
|
+
}
|
|
19892
19990
|
} else if (typeof val === "bigint") {
|
|
19893
19991
|
if (this.unrepresentable === "throw") {
|
|
19894
19992
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -41538,7 +41636,7 @@ var require_tracestate_impl = __commonJS((exports) => {
|
|
|
41538
41636
|
const value = listMember.slice(i + 1, part.length);
|
|
41539
41637
|
if ((0, tracestate_validators_1.validateKey)(key) && (0, tracestate_validators_1.validateValue)(value)) {
|
|
41540
41638
|
agg.set(key, value);
|
|
41541
|
-
}
|
|
41639
|
+
}
|
|
41542
41640
|
}
|
|
41543
41641
|
return agg;
|
|
41544
41642
|
}, new Map);
|
|
@@ -57102,6 +57200,7 @@ var FORMAT_UNITS = [
|
|
|
57102
57200
|
|
|
57103
57201
|
// src/server/routes/memories-crud.ts
|
|
57104
57202
|
init_router();
|
|
57203
|
+
init_database();
|
|
57105
57204
|
init_enum_validation();
|
|
57106
57205
|
init_types();
|
|
57107
57206
|
addRoute("GET", "/api/memories", (_req, url) => {
|
|
@@ -57131,17 +57230,35 @@ addRoute("GET", "/api/memories", (_req, url) => {
|
|
|
57131
57230
|
filter.namespace = q["namespace"];
|
|
57132
57231
|
if (q["status"])
|
|
57133
57232
|
filter.status = q["status"];
|
|
57134
|
-
|
|
57135
|
-
|
|
57136
|
-
|
|
57137
|
-
|
|
57233
|
+
const parsedLimit = Number(q["limit"]);
|
|
57234
|
+
const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 1000) : 1000;
|
|
57235
|
+
const parsedOffset = Number(q["offset"]);
|
|
57236
|
+
filter.limit = limit;
|
|
57237
|
+
filter.offset = Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
|
|
57138
57238
|
const memories = listMemories(filter);
|
|
57239
|
+
const total = countMemories(filter, getDatabase());
|
|
57240
|
+
const hasMore = memories.length === limit;
|
|
57241
|
+
const nextCursor = hasMore ? (filter.offset ?? 0) + memories.length : null;
|
|
57139
57242
|
if (q["fields"]) {
|
|
57140
57243
|
const fields = q["fields"].split(",").map((f) => f.trim());
|
|
57141
57244
|
const filtered = memories.map((m) => Object.fromEntries(fields.map((f) => [f, m[f]]).filter(([, v]) => v !== undefined)));
|
|
57142
|
-
return json({
|
|
57245
|
+
return json({
|
|
57246
|
+
memories: filtered,
|
|
57247
|
+
count: filtered.length,
|
|
57248
|
+
total,
|
|
57249
|
+
limit,
|
|
57250
|
+
has_more: hasMore,
|
|
57251
|
+
next_cursor: nextCursor
|
|
57252
|
+
});
|
|
57143
57253
|
}
|
|
57144
|
-
return json({
|
|
57254
|
+
return json({
|
|
57255
|
+
memories,
|
|
57256
|
+
count: memories.length,
|
|
57257
|
+
total,
|
|
57258
|
+
limit,
|
|
57259
|
+
has_more: hasMore,
|
|
57260
|
+
next_cursor: nextCursor
|
|
57261
|
+
});
|
|
57145
57262
|
});
|
|
57146
57263
|
addRoute("POST", "/api/memories", async (req) => {
|
|
57147
57264
|
const body = await readJson(req);
|
|
@@ -57389,14 +57506,20 @@ function getMemoryReport(filter = {}, db) {
|
|
|
57389
57506
|
top_agents: topAgents
|
|
57390
57507
|
};
|
|
57391
57508
|
}
|
|
57392
|
-
function
|
|
57509
|
+
function getStaleMemoriesPage(filter = {}, db) {
|
|
57393
57510
|
const days = Math.min(filter.days || 30, 365);
|
|
57394
57511
|
const limit = filter.limit ?? 20;
|
|
57395
57512
|
const offset = filter.offset ?? 0;
|
|
57396
57513
|
if (!db && isApiMode()) {
|
|
57397
57514
|
const q = toQuery({ days, project_id: filter.project_id, agent_id: filter.agent_id, limit, offset });
|
|
57398
57515
|
const { data } = apiJson("GET", `/memories/stale${q}`);
|
|
57399
|
-
|
|
57516
|
+
const rows2 = data?.memories ?? [];
|
|
57517
|
+
return {
|
|
57518
|
+
rows: rows2,
|
|
57519
|
+
total: data?.total ?? rows2.length,
|
|
57520
|
+
has_more: data?.has_more,
|
|
57521
|
+
next_cursor: data?.next_cursor ?? null
|
|
57522
|
+
};
|
|
57400
57523
|
}
|
|
57401
57524
|
const d = db || getDatabase();
|
|
57402
57525
|
const cutoffDate = new Date(Date.now() - days * 86400000).toISOString();
|
|
@@ -57410,13 +57533,22 @@ function getStaleMemories(filter = {}, db) {
|
|
|
57410
57533
|
conds.push("agent_id = ?");
|
|
57411
57534
|
params.push(filter.agent_id);
|
|
57412
57535
|
}
|
|
57413
|
-
|
|
57536
|
+
const where = conds.join(" AND ");
|
|
57537
|
+
const countRow = d.query(`SELECT COUNT(*) AS c FROM memories WHERE ${where}`).get(...params);
|
|
57538
|
+
let sql = `SELECT id, key, value, importance, scope, category, accessed_at, access_count, created_at FROM memories WHERE ${where} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`;
|
|
57414
57539
|
params.push(limit);
|
|
57415
57540
|
if (offset) {
|
|
57416
57541
|
sql += " OFFSET ?";
|
|
57417
57542
|
params.push(offset);
|
|
57418
57543
|
}
|
|
57419
|
-
|
|
57544
|
+
const rows = d.query(sql).all(...params);
|
|
57545
|
+
const hasMore = rows.length === limit;
|
|
57546
|
+
return {
|
|
57547
|
+
rows,
|
|
57548
|
+
total: countRow?.c ?? 0,
|
|
57549
|
+
has_more: hasMore,
|
|
57550
|
+
next_cursor: hasMore ? offset + rows.length : null
|
|
57551
|
+
};
|
|
57420
57552
|
}
|
|
57421
57553
|
function getMemoryHealth(filter = {}, db) {
|
|
57422
57554
|
const staleDays = filter.stale_days ?? 30;
|
|
@@ -57499,23 +57631,43 @@ addRoute("GET", "/api/activity", (_req, url) => {
|
|
|
57499
57631
|
addRoute("GET", "/api/memories/stale", (_req, url) => {
|
|
57500
57632
|
const q = getSearchParams(url);
|
|
57501
57633
|
const days = q["days"] ? parseInt(q["days"], 10) : undefined;
|
|
57502
|
-
const
|
|
57503
|
-
const
|
|
57634
|
+
const parsedLimit = Number(q["limit"]);
|
|
57635
|
+
const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 1000) : 20;
|
|
57636
|
+
const parsedOffset = Number(q["offset"]);
|
|
57637
|
+
const offset = Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
|
|
57638
|
+
const page = getStaleMemoriesPage({
|
|
57504
57639
|
days,
|
|
57505
57640
|
project_id: q["project_id"],
|
|
57506
57641
|
agent_id: q["agent_id"],
|
|
57507
57642
|
limit,
|
|
57508
|
-
offset
|
|
57643
|
+
offset
|
|
57509
57644
|
}, getDatabase());
|
|
57510
|
-
return json({
|
|
57645
|
+
return json({
|
|
57646
|
+
memories: page.rows,
|
|
57647
|
+
count: page.rows.length,
|
|
57648
|
+
total: page.total,
|
|
57649
|
+
days: Math.min(days || 30, 365),
|
|
57650
|
+
limit,
|
|
57651
|
+
has_more: page.has_more,
|
|
57652
|
+
next_cursor: page.next_cursor
|
|
57653
|
+
});
|
|
57511
57654
|
});
|
|
57512
57655
|
addRoute("GET", "/api/memories/history", (_req, url) => {
|
|
57513
57656
|
const q = getSearchParams(url);
|
|
57514
|
-
const
|
|
57515
|
-
|
|
57516
|
-
|
|
57517
|
-
|
|
57518
|
-
|
|
57657
|
+
const parsedLimit = Number(q["limit"]);
|
|
57658
|
+
const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 200) : 20;
|
|
57659
|
+
const parsedOffset = Number(q["offset"]);
|
|
57660
|
+
const offset = Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
|
|
57661
|
+
const page = listMemoryHistoryPage({ limit, offset }, getDatabase());
|
|
57662
|
+
const total = countMemoryHistory(getDatabase());
|
|
57663
|
+
return json({
|
|
57664
|
+
memories: page.rows,
|
|
57665
|
+
count: page.rows.length,
|
|
57666
|
+
total,
|
|
57667
|
+
limit,
|
|
57668
|
+
has_more: page.has_more,
|
|
57669
|
+
next_cursor: page.next_cursor
|
|
57670
|
+
});
|
|
57519
57671
|
});
|
|
57520
57672
|
addRoute("GET", "/api/memories/health", (_req, url) => {
|
|
57521
57673
|
const q = getSearchParams(url);
|
|
@@ -58594,6 +58746,90 @@ class MementosProjectRegistrationError extends Error {
|
|
|
58594
58746
|
}
|
|
58595
58747
|
}
|
|
58596
58748
|
|
|
58749
|
+
// src/project-registration/historical-receipt.ts
|
|
58750
|
+
var ROOT_TENANT_ID = "adfd95c7-ee8b-52cb-ae47-4ae65dae3313";
|
|
58751
|
+
var FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION = {
|
|
58752
|
+
authority: "mementos",
|
|
58753
|
+
authority_route: "mementos.project-registration.v1",
|
|
58754
|
+
package_version: "1.0.0-rc.3",
|
|
58755
|
+
authority_id: "mementos",
|
|
58756
|
+
tenant_id: "default",
|
|
58757
|
+
corpus_id: "default",
|
|
58758
|
+
operation_id: "op-cli-register-full",
|
|
58759
|
+
step_id: "mementos_project",
|
|
58760
|
+
resource_kind: "project",
|
|
58761
|
+
direction: "forward",
|
|
58762
|
+
target_selector: "wks_005285827590a93b70e5",
|
|
58763
|
+
target_id: "mm_project_f75606ef14e51fb577a15882ba0ab8ed333b2c29",
|
|
58764
|
+
idempotency_key: "prk_786cdc6babddeae1be8d5078d0f75322d1ea1010ac5d8a50",
|
|
58765
|
+
receipt_id: "mmpr_a647f9908a33bb64bf137f584202590f91b72a33",
|
|
58766
|
+
request_digest: "8eb0e3fee26fdb7edb8a444aeddaaedb79a84a5a36e742ae03616f62b19f5c22",
|
|
58767
|
+
precondition_digest: "0b6c22fcf75d835f9f27308b1a9d40e8902e48a97da370fd56df5acacfcd968e",
|
|
58768
|
+
result_revision: "2026-08-09T13:37:43.068Z",
|
|
58769
|
+
result_digest: "26fb0dd5c5e20909d3653ab0ddd8fa45e5142728e4e66d595e2419f7ed40b036",
|
|
58770
|
+
created_at: "2026-08-09T13:37:43.068Z",
|
|
58771
|
+
identity_digest: "1108dd972c90e4989036fb6ecec7dde10f54641a697bd53cfcd64017f589ace7",
|
|
58772
|
+
target_digest: "72789fcd60668eeb66ee068936d3afa96deadcb007228830c64b6de783b6dcef",
|
|
58773
|
+
operation_digest: "d7e37bfb2c0d28f8c4086c53224cd855d14694f32807b74c102b61a99963f3c0",
|
|
58774
|
+
idempotency_digest: "b56d8ec37efb818759cdd2ee3b58bc1401ac13384c8d64c1813bb5c198b1e376",
|
|
58775
|
+
receipt_digest: "52ce90c5de6817989f107d9d27e06156962a2b9c365e34e16a57aa37886501a2",
|
|
58776
|
+
response_digest: "2fa3ed508f5f192c18753b1205ced996340fdf02f735420d32db897fc239805c"
|
|
58777
|
+
};
|
|
58778
|
+
var FLEET_RESOURCES_HISTORICAL_RECEIPT = {
|
|
58779
|
+
receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id,
|
|
58780
|
+
authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
|
|
58781
|
+
route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
|
|
58782
|
+
package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
|
|
58783
|
+
authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
|
|
58784
|
+
tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
|
|
58785
|
+
corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
|
|
58786
|
+
operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
|
|
58787
|
+
step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
|
|
58788
|
+
resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
|
|
58789
|
+
direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
|
|
58790
|
+
idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
|
|
58791
|
+
request_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.request_digest,
|
|
58792
|
+
precondition_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.precondition_digest,
|
|
58793
|
+
outcome: "accepted",
|
|
58794
|
+
reason: null,
|
|
58795
|
+
target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
|
|
58796
|
+
result_revision: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_revision,
|
|
58797
|
+
result_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_digest,
|
|
58798
|
+
duplicate_of_receipt_id: null,
|
|
58799
|
+
accepted_receipt_id: null,
|
|
58800
|
+
created_by_operation: true,
|
|
58801
|
+
created_at: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.created_at
|
|
58802
|
+
};
|
|
58803
|
+
var FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY = {
|
|
58804
|
+
authority_id: "mementos",
|
|
58805
|
+
tenant_id: ROOT_TENANT_ID,
|
|
58806
|
+
corpus_id: "mementos:postgresql"
|
|
58807
|
+
};
|
|
58808
|
+
var FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY = {
|
|
58809
|
+
source: {
|
|
58810
|
+
authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
|
|
58811
|
+
authority_route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
|
|
58812
|
+
package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
|
|
58813
|
+
authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
|
|
58814
|
+
tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
|
|
58815
|
+
corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
|
|
58816
|
+
operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
|
|
58817
|
+
step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
|
|
58818
|
+
resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
|
|
58819
|
+
direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
|
|
58820
|
+
target_selector: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_selector,
|
|
58821
|
+
target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
|
|
58822
|
+
idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
|
|
58823
|
+
receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id
|
|
58824
|
+
},
|
|
58825
|
+
destination: FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY,
|
|
58826
|
+
lookup_only: true,
|
|
58827
|
+
immutable_receipt: true
|
|
58828
|
+
};
|
|
58829
|
+
function supportsFleetResourcesHistoricalReceiptLookup(capability) {
|
|
58830
|
+
return capability.authority_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.authority_id && capability.tenant_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.tenant_id && capability.corpus_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.corpus_id;
|
|
58831
|
+
}
|
|
58832
|
+
|
|
58597
58833
|
// src/project-registration/identity.ts
|
|
58598
58834
|
var MEMENTOS_PROJECT_AUTHORITY_ENV = {
|
|
58599
58835
|
authorityId: "MEMENTOS_PROJECT_AUTHORITY_ID",
|
|
@@ -58635,12 +58871,13 @@ function resolveMementosProjectAuthorityIdentity(options = {}) {
|
|
|
58635
58871
|
}
|
|
58636
58872
|
function buildMementosProjectRegistrationCapability(options = {}) {
|
|
58637
58873
|
const identity = resolveMementosProjectAuthorityIdentity(options);
|
|
58638
|
-
|
|
58874
|
+
const capability = {
|
|
58639
58875
|
authority: "mementos",
|
|
58640
58876
|
route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
|
|
58641
58877
|
package_version: options.packageVersion ?? getMementosPackageVersion(),
|
|
58642
58878
|
...identity,
|
|
58643
58879
|
supported_resources: ["project"],
|
|
58880
|
+
supported_historical_lookup_identities: [],
|
|
58644
58881
|
conditional_create: true,
|
|
58645
58882
|
immutable_receipts: true,
|
|
58646
58883
|
exact_terminal_lookup: true,
|
|
@@ -58659,6 +58896,12 @@ function buildMementosProjectRegistrationCapability(options = {}) {
|
|
|
58659
58896
|
stable_keyset_pagination: true,
|
|
58660
58897
|
explicit_membership_only: true
|
|
58661
58898
|
};
|
|
58899
|
+
if (supportsFleetResourcesHistoricalReceiptLookup(capability)) {
|
|
58900
|
+
capability.supported_historical_lookup_identities = [
|
|
58901
|
+
FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY
|
|
58902
|
+
];
|
|
58903
|
+
}
|
|
58904
|
+
return capability;
|
|
58662
58905
|
}
|
|
58663
58906
|
|
|
58664
58907
|
// src/db/memory-project-link.ts
|
|
@@ -60822,12 +61065,21 @@ function assertInverseRequest(request, capability) {
|
|
|
60822
61065
|
}
|
|
60823
61066
|
return accepted;
|
|
60824
61067
|
}
|
|
61068
|
+
function matchesCurrentLookupIdentity(request, capability) {
|
|
61069
|
+
return request.authority_route === capability.route && request.package_version === capability.package_version && request.authority_id === capability.authority_id && request.tenant_id === capability.tenant_id && request.corpus_id === capability.corpus_id;
|
|
61070
|
+
}
|
|
61071
|
+
function matchesFleetResourcesHistoricalLookup(request, capability) {
|
|
61072
|
+
if (!supportsFleetResourcesHistoricalReceiptLookup(capability))
|
|
61073
|
+
return false;
|
|
61074
|
+
const source = FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY.source;
|
|
61075
|
+
return request.authority === source.authority && request.authority_route === source.authority_route && request.package_version === source.package_version && request.authority_id === source.authority_id && request.tenant_id === source.tenant_id && request.corpus_id === source.corpus_id && request.operation_id === source.operation_id && request.step_id === source.step_id && request.resource_kind === source.resource_kind && request.direction === source.direction && request.target_selector === source.target_selector && request.target_id === source.target_id && request.idempotency_key === source.idempotency_key;
|
|
61076
|
+
}
|
|
60825
61077
|
function assertLookup(request, capability) {
|
|
60826
61078
|
assertBounds(request);
|
|
60827
61079
|
if (request.max_items !== 1) {
|
|
60828
61080
|
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_BOUNDS", "terminal receipt lookup requires max_items exactly 1");
|
|
60829
61081
|
}
|
|
60830
|
-
if (request.authority !== "mementos" || request.resource_kind !== "project" || request
|
|
61082
|
+
if (request.authority !== "mementos" || request.resource_kind !== "project" || !matchesCurrentLookupIdentity(request, capability) && !matchesFleetResourcesHistoricalLookup(request, capability)) {
|
|
60831
61083
|
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH", "receipt lookup does not match this authority capability identity");
|
|
60832
61084
|
}
|
|
60833
61085
|
requireString(request.operation_id, "operation_id", { pattern: OPERATION_PATTERN });
|
|
@@ -60845,6 +61097,7 @@ function assertLookup(request, capability) {
|
|
|
60845
61097
|
pattern: PROJECT_ID_PATTERN
|
|
60846
61098
|
});
|
|
60847
61099
|
}
|
|
61100
|
+
return matchesCurrentLookupIdentity(request, capability) ? "current" : "fleet_resources_historical";
|
|
60848
61101
|
}
|
|
60849
61102
|
|
|
60850
61103
|
class PackageOwnedMementosProjectRegistrationAuthority {
|
|
@@ -61109,11 +61362,14 @@ class PackageOwnedMementosProjectRegistrationAuthority {
|
|
|
61109
61362
|
}
|
|
61110
61363
|
async lookupReceipt(request) {
|
|
61111
61364
|
const startedAt = Date.now();
|
|
61112
|
-
assertLookup(request, this.capabilityValue);
|
|
61365
|
+
const lookupIdentity = assertLookup(request, this.capabilityValue);
|
|
61113
61366
|
const receipt = getReceiptForLookup(this.db, request);
|
|
61114
61367
|
if (!receipt || request.target_id !== undefined && receipt.target_id !== request.target_id) {
|
|
61115
61368
|
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND", "exact immutable terminal receipt was not found");
|
|
61116
61369
|
}
|
|
61370
|
+
if (lookupIdentity === "fleet_resources_historical" && (receipt.receipt_id !== FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY.source.receipt_id || canonicalMementosProjectRegistrationJson(publicReceipt(receipt)) !== canonicalMementosProjectRegistrationJson(FLEET_RESOURCES_HISTORICAL_RECEIPT))) {
|
|
61371
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND", "exact immutable historical terminal receipt was not found");
|
|
61372
|
+
}
|
|
61117
61373
|
return withResponseControl(publicReceipt(receipt), request, startedAt);
|
|
61118
61374
|
}
|
|
61119
61375
|
async compensate(request) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memories-page-stub-server.d.ts","sourceRoot":"","sources":["../../src/test-support/memories-page-stub-server.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface MemoriesPageStub {
|
|
2
|
+
server: ReturnType<typeof Bun.serve>;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
stop(): void;
|
|
5
|
+
}
|
|
6
|
+
/** Start a stub GET /v1/memories serving `rowCount` rows on capped pages. */
|
|
7
|
+
export declare function startMemoriesPageStub(rowCount: number): MemoriesPageStub;
|
|
8
|
+
/**
|
|
9
|
+
* A process env for API mode pointed at a loopback stub. All store selectors
|
|
10
|
+
* are stripped first (the ambient environment on fleet machines carries the
|
|
11
|
+
* production API selectors), then the stub URL + a dummy key are set.
|
|
12
|
+
*/
|
|
13
|
+
export declare function apiModeTestEnv(baseUrl: string): Record<string, string>;
|
|
14
|
+
export interface MemoriesPageStubProcess {
|
|
15
|
+
port: number;
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
stop(): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start the stub as a SEPARATE process. Required whenever the caller under
|
|
21
|
+
* test runs in the same process that would host the stub: the CLI's cloud
|
|
22
|
+
* reads are SYNCHRONOUS curl children (Bun.spawnSync), which deadlock against
|
|
23
|
+
* an in-process server whose event loop the spawn blocks.
|
|
24
|
+
*/
|
|
25
|
+
export declare function startMemoriesPageStubProcess(rowCount: number): MemoriesPageStubProcess;
|
|
26
|
+
/** Poll the stub until it serves a page, or throw after ~5s. */
|
|
27
|
+
export declare function waitForMemoriesPageStub(baseUrl: string): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=memories-page-stub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memories-page-stub.d.ts","sourceRoot":"","sources":["../../src/test-support/memories-page-stub.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAqCxE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CActE;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,GACf,uBAAuB,CAuBzB;AAED,gEAAgE;AAChE,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW5E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/mementos",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.85",
|
|
4
4
|
"description": "Universal memory system for AI agents - CLI + MCP server + library API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
],
|
|
41
41
|
"scripts": {
|
|
42
42
|
"clean": "rm -rf dist",
|
|
43
|
-
"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 src/project-registration.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",
|
|
43
|
+
"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 src/project-registration.ts --outdir dist --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/diagnostics/historical-project-registration-receipt.ts --outdir dist/diagnostics --target bun --external pg && bun build src/sdk/index.ts --outdir dist/sdk --target bun && tsc --emitDeclarationOnly --outDir dist",
|
|
44
44
|
"prepare": "bun run build",
|
|
45
45
|
"prepack": "bun run build && bun run scan-artifact",
|
|
46
46
|
"prepublishOnly": "bun run typecheck && bun run test && bun run contracts:conformance && contracts no-cloud-scan .",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"contracts:conformance": "contracts conformance fixtures",
|
|
50
50
|
"typecheck": "tsc --noEmit",
|
|
51
51
|
"test": "bun test --isolate --timeout=10000",
|
|
52
|
+
"diagnose:historical-project-registration-receipt": "bun run src/diagnostics/historical-project-registration-receipt.ts",
|
|
52
53
|
"test:pg": "bun scripts/pg-test-gate.ts",
|
|
53
54
|
"dev:cli": "bun run src/cli/index.tsx",
|
|
54
55
|
"dev:mcp": "bun run src/mcp/index.ts",
|