@hasna/mementos 0.14.75 → 0.14.78

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.
Files changed (63) hide show
  1. package/bun.lock +93 -0
  2. package/dist/cli/commands/info-context.d.ts.map +1 -1
  3. package/dist/cli/commands/info-stale.d.ts.map +1 -1
  4. package/dist/cli/commands/io-export.d.ts.map +1 -1
  5. package/dist/cli/commands/memory-cmd-crud.d.ts.map +1 -1
  6. package/dist/cli/commands/memory-cmd-list.d.ts.map +1 -1
  7. package/dist/cli/commands/memory-cmd-recall.d.ts.map +1 -1
  8. package/dist/cli/commands/memory-cmd-search.d.ts.map +1 -1
  9. package/dist/cli/commands/memory-cmd-tail.d.ts.map +1 -1
  10. package/dist/cli/commands/project.d.ts.map +1 -1
  11. package/dist/cli/commands/system-watch.d.ts.map +1 -1
  12. package/dist/cli/helpers.d.ts +38 -0
  13. package/dist/cli/helpers.d.ts.map +1 -1
  14. package/dist/cli/index.js +2009 -334
  15. package/dist/db/__fixtures__/fail-closed-stub-server.d.ts.map +1 -1
  16. package/dist/db/memory-project-link.d.ts +13 -0
  17. package/dist/db/memory-project-link.d.ts.map +1 -0
  18. package/dist/db/migrations.d.ts.map +1 -1
  19. package/dist/db/pg-migrations.d.ts +0 -6
  20. package/dist/db/pg-migrations.d.ts.map +1 -1
  21. package/dist/db/projects.d.ts +22 -1
  22. package/dist/db/projects.d.ts.map +1 -1
  23. package/dist/index.d.ts +5 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2828 -163
  26. package/dist/lib/package-version.d.ts +3 -0
  27. package/dist/lib/package-version.d.ts.map +1 -0
  28. package/dist/mcp/index.js +414 -0
  29. package/dist/memory-project-link/index.d.ts +2 -0
  30. package/dist/memory-project-link/index.d.ts.map +1 -0
  31. package/dist/memory-project-link/schema.d.ts +5 -0
  32. package/dist/memory-project-link/schema.d.ts.map +1 -0
  33. package/dist/project-registration/authority.d.ts +39 -0
  34. package/dist/project-registration/authority.d.ts.map +1 -0
  35. package/dist/project-registration/http.d.ts +29 -0
  36. package/dist/project-registration/http.d.ts.map +1 -0
  37. package/dist/project-registration/index.d.ts +8 -0
  38. package/dist/project-registration/index.d.ts.map +1 -0
  39. package/dist/project-registration/project-references.d.ts +71 -0
  40. package/dist/project-registration/project-references.d.ts.map +1 -0
  41. package/dist/project-registration/schema.d.ts +5 -0
  42. package/dist/project-registration/schema.d.ts.map +1 -0
  43. package/dist/project-registration/types.d.ts +168 -0
  44. package/dist/project-registration/types.d.ts.map +1 -0
  45. package/dist/project-registration.d.ts +2 -0
  46. package/dist/project-registration.d.ts.map +1 -0
  47. package/dist/project-registration.js +1496 -0
  48. package/dist/sdk/index.d.ts +127 -0
  49. package/dist/sdk/index.d.ts.map +1 -1
  50. package/dist/sdk/index.js +74 -0
  51. package/dist/server/index.d.ts +1 -0
  52. package/dist/server/index.d.ts.map +1 -1
  53. package/dist/server/index.js +2573 -138
  54. package/dist/server/routes/memories.d.ts +1 -0
  55. package/dist/server/routes/memories.d.ts.map +1 -1
  56. package/dist/server/routes/memory-project-link.d.ts +2 -0
  57. package/dist/server/routes/memory-project-link.d.ts.map +1 -0
  58. package/dist/server/routes/project-registration.d.ts +2 -0
  59. package/dist/server/routes/project-registration.d.ts.map +1 -0
  60. package/dist/types/index.d.ts +119 -0
  61. package/dist/types/index.d.ts.map +1 -1
  62. package/package.json +9 -3
  63. package/dashboard/bun.lock +0 -519
package/dist/index.js CHANGED
@@ -1178,6 +1178,429 @@ var init_api_mode = __esm(() => {
1178
1178
  };
1179
1179
  });
1180
1180
 
1181
+ // src/project-registration/schema.ts
1182
+ function sqliteMementosProjectRegistrationSchemaSql() {
1183
+ return `
1184
+ CREATE TABLE IF NOT EXISTS mementos_project_registration_receipts (
1185
+ receipt_id TEXT PRIMARY KEY,
1186
+ authority TEXT NOT NULL CHECK(authority = 'mementos'),
1187
+ route TEXT NOT NULL,
1188
+ package_version TEXT NOT NULL,
1189
+ authority_id TEXT NOT NULL,
1190
+ tenant_id TEXT NOT NULL,
1191
+ corpus_id TEXT NOT NULL,
1192
+ operation_id TEXT NOT NULL,
1193
+ step_id TEXT NOT NULL,
1194
+ resource_kind TEXT NOT NULL CHECK(resource_kind = 'project'),
1195
+ direction TEXT NOT NULL CHECK(direction IN ('forward', 'inverse')),
1196
+ target_selector TEXT NOT NULL,
1197
+ idempotency_key TEXT NOT NULL,
1198
+ request_digest TEXT NOT NULL,
1199
+ precondition_digest TEXT NOT NULL,
1200
+ normalized_call_digest TEXT NOT NULL,
1201
+ outcome TEXT NOT NULL CHECK(outcome IN (
1202
+ 'accepted', 'duplicate_of_accepted', 'terminal_nonacceptance'
1203
+ )),
1204
+ reason TEXT,
1205
+ target_id TEXT,
1206
+ result_revision TEXT,
1207
+ result_digest TEXT,
1208
+ duplicate_of_receipt_id TEXT,
1209
+ accepted_receipt_id TEXT,
1210
+ created_by_operation INTEGER NOT NULL CHECK(created_by_operation IN (0, 1)),
1211
+ created_at TEXT NOT NULL
1212
+ );
1213
+
1214
+ CREATE INDEX IF NOT EXISTS idx_mementos_project_registration_receipts_lookup
1215
+ ON mementos_project_registration_receipts (
1216
+ authority_id, tenant_id, corpus_id, operation_id, step_id,
1217
+ resource_kind, direction, idempotency_key, target_selector
1218
+ );
1219
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_mementos_project_registration_receipts_accepted_step
1220
+ ON mementos_project_registration_receipts (
1221
+ authority_id, tenant_id, corpus_id, operation_id, step_id,
1222
+ resource_kind, direction
1223
+ )
1224
+ WHERE outcome = 'accepted';
1225
+
1226
+ CREATE TABLE IF NOT EXISTS mementos_project_registration_bindings (
1227
+ authority_id TEXT NOT NULL,
1228
+ tenant_id TEXT NOT NULL,
1229
+ corpus_id TEXT NOT NULL,
1230
+ resource_kind TEXT NOT NULL CHECK(resource_kind = 'project'),
1231
+ target_selector TEXT NOT NULL,
1232
+ operation_id TEXT NOT NULL,
1233
+ step_id TEXT NOT NULL,
1234
+ direction TEXT NOT NULL CHECK(direction = 'forward'),
1235
+ idempotency_key TEXT NOT NULL,
1236
+ request_digest TEXT NOT NULL,
1237
+ precondition_digest TEXT NOT NULL,
1238
+ normalized_call_digest TEXT NOT NULL,
1239
+ state TEXT NOT NULL CHECK(state IN (
1240
+ 'pending', 'accepted', 'terminal_nonacceptance', 'removed'
1241
+ )),
1242
+ target_id TEXT,
1243
+ accepted_receipt_id TEXT,
1244
+ result_revision TEXT,
1245
+ result_digest TEXT,
1246
+ removed_receipt_id TEXT,
1247
+ created_at TEXT NOT NULL,
1248
+ updated_at TEXT NOT NULL,
1249
+ PRIMARY KEY(authority_id, tenant_id, corpus_id, resource_kind, target_selector),
1250
+ UNIQUE(accepted_receipt_id)
1251
+ );
1252
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_mementos_project_registration_binding_target
1253
+ ON mementos_project_registration_bindings(
1254
+ authority_id, tenant_id, corpus_id, resource_kind, target_id
1255
+ )
1256
+ WHERE target_id IS NOT NULL;
1257
+
1258
+ CREATE TRIGGER IF NOT EXISTS mementos_project_registration_receipts_immutable_update
1259
+ BEFORE UPDATE ON mementos_project_registration_receipts
1260
+ BEGIN
1261
+ SELECT RAISE(ABORT, 'mementos project registration receipts are immutable');
1262
+ END;
1263
+
1264
+ CREATE TRIGGER IF NOT EXISTS mementos_project_registration_receipts_immutable_delete
1265
+ BEFORE DELETE ON mementos_project_registration_receipts
1266
+ BEGIN
1267
+ SELECT RAISE(ABORT, 'mementos project registration receipts are immutable');
1268
+ END;
1269
+ `;
1270
+ }
1271
+ function postgresMementosProjectRegistrationSchemaSql() {
1272
+ return `
1273
+ CREATE TABLE IF NOT EXISTS mementos_project_registration_receipts (
1274
+ receipt_id TEXT PRIMARY KEY,
1275
+ authority TEXT NOT NULL CHECK(authority = 'mementos'),
1276
+ route TEXT NOT NULL,
1277
+ package_version TEXT NOT NULL,
1278
+ authority_id TEXT NOT NULL,
1279
+ tenant_id TEXT NOT NULL,
1280
+ corpus_id TEXT NOT NULL,
1281
+ operation_id TEXT NOT NULL,
1282
+ step_id TEXT NOT NULL,
1283
+ resource_kind TEXT NOT NULL CHECK(resource_kind = 'project'),
1284
+ direction TEXT NOT NULL CHECK(direction IN ('forward', 'inverse')),
1285
+ target_selector TEXT NOT NULL,
1286
+ idempotency_key TEXT NOT NULL,
1287
+ request_digest TEXT NOT NULL,
1288
+ precondition_digest TEXT NOT NULL,
1289
+ normalized_call_digest TEXT NOT NULL,
1290
+ outcome TEXT NOT NULL CHECK(outcome IN (
1291
+ 'accepted', 'duplicate_of_accepted', 'terminal_nonacceptance'
1292
+ )),
1293
+ reason TEXT,
1294
+ target_id TEXT,
1295
+ result_revision TEXT,
1296
+ result_digest TEXT,
1297
+ duplicate_of_receipt_id TEXT,
1298
+ accepted_receipt_id TEXT,
1299
+ created_by_operation BOOLEAN NOT NULL,
1300
+ created_at TIMESTAMPTZ NOT NULL
1301
+ );
1302
+
1303
+ CREATE INDEX IF NOT EXISTS idx_mementos_project_registration_receipts_lookup
1304
+ ON mementos_project_registration_receipts (
1305
+ authority_id, tenant_id, corpus_id, operation_id, step_id,
1306
+ resource_kind, direction, idempotency_key, target_selector
1307
+ );
1308
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_mementos_project_registration_receipts_accepted_step
1309
+ ON mementos_project_registration_receipts (
1310
+ authority_id, tenant_id, corpus_id, operation_id, step_id,
1311
+ resource_kind, direction
1312
+ )
1313
+ WHERE outcome = 'accepted';
1314
+
1315
+ CREATE TABLE IF NOT EXISTS mementos_project_registration_bindings (
1316
+ authority_id TEXT NOT NULL,
1317
+ tenant_id TEXT NOT NULL,
1318
+ corpus_id TEXT NOT NULL,
1319
+ resource_kind TEXT NOT NULL CHECK(resource_kind = 'project'),
1320
+ target_selector TEXT NOT NULL,
1321
+ operation_id TEXT NOT NULL,
1322
+ step_id TEXT NOT NULL,
1323
+ direction TEXT NOT NULL CHECK(direction = 'forward'),
1324
+ idempotency_key TEXT NOT NULL,
1325
+ request_digest TEXT NOT NULL,
1326
+ precondition_digest TEXT NOT NULL,
1327
+ normalized_call_digest TEXT NOT NULL,
1328
+ state TEXT NOT NULL CHECK(state IN (
1329
+ 'pending', 'accepted', 'terminal_nonacceptance', 'removed'
1330
+ )),
1331
+ target_id TEXT,
1332
+ accepted_receipt_id TEXT UNIQUE,
1333
+ result_revision TEXT,
1334
+ result_digest TEXT,
1335
+ removed_receipt_id TEXT,
1336
+ created_at TIMESTAMPTZ NOT NULL,
1337
+ updated_at TIMESTAMPTZ NOT NULL,
1338
+ PRIMARY KEY(authority_id, tenant_id, corpus_id, resource_kind, target_selector)
1339
+ );
1340
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_mementos_project_registration_binding_target
1341
+ ON mementos_project_registration_bindings(
1342
+ authority_id, tenant_id, corpus_id, resource_kind, target_id
1343
+ )
1344
+ WHERE target_id IS NOT NULL;
1345
+
1346
+ CREATE OR REPLACE FUNCTION mementos_project_registration_receipts_immutable()
1347
+ RETURNS trigger
1348
+ LANGUAGE plpgsql
1349
+ AS $$
1350
+ BEGIN
1351
+ RAISE EXCEPTION 'mementos project registration receipts are immutable';
1352
+ END;
1353
+ $$;
1354
+ DROP TRIGGER IF EXISTS mementos_project_registration_receipts_immutable
1355
+ ON mementos_project_registration_receipts;
1356
+ CREATE TRIGGER mementos_project_registration_receipts_immutable
1357
+ BEFORE UPDATE OR DELETE ON mementos_project_registration_receipts
1358
+ FOR EACH ROW EXECUTE FUNCTION mementos_project_registration_receipts_immutable();
1359
+ `;
1360
+ }
1361
+ function sqliteMementosProjectGuardedUpdateSchemaSql() {
1362
+ return `
1363
+ CREATE TABLE IF NOT EXISTS mementos_project_update_receipts (
1364
+ receipt_id TEXT PRIMARY KEY,
1365
+ authority TEXT NOT NULL CHECK(authority = 'mementos'),
1366
+ route TEXT NOT NULL CHECK(route = 'mementos.project-guarded-update.v1'),
1367
+ package_version TEXT NOT NULL,
1368
+ authority_id TEXT NOT NULL,
1369
+ tenant_id TEXT NOT NULL,
1370
+ corpus_id TEXT NOT NULL,
1371
+ operation_id TEXT NOT NULL,
1372
+ step_id TEXT NOT NULL,
1373
+ direction TEXT NOT NULL CHECK(direction IN ('forward', 'rollback')),
1374
+ idempotency_key TEXT NOT NULL,
1375
+ request_digest TEXT NOT NULL,
1376
+ outcome TEXT NOT NULL CHECK(outcome = 'accepted'),
1377
+ target_id TEXT NOT NULL,
1378
+ expected_revision TEXT NOT NULL,
1379
+ result_revision TEXT NOT NULL,
1380
+ result_digest TEXT NOT NULL,
1381
+ accepted_receipt_id TEXT,
1382
+ before_project_json TEXT NOT NULL,
1383
+ after_project_json TEXT NOT NULL,
1384
+ created_at TEXT NOT NULL,
1385
+ UNIQUE(authority_id, tenant_id, corpus_id, direction, idempotency_key)
1386
+ );
1387
+
1388
+ CREATE INDEX IF NOT EXISTS idx_mementos_project_update_receipts_target
1389
+ ON mementos_project_update_receipts(
1390
+ authority_id, tenant_id, corpus_id, target_id, created_at
1391
+ );
1392
+
1393
+ CREATE TRIGGER IF NOT EXISTS mementos_project_update_receipts_immutable_update
1394
+ BEFORE UPDATE ON mementos_project_update_receipts
1395
+ BEGIN
1396
+ SELECT RAISE(ABORT, 'mementos project update receipts are immutable');
1397
+ END;
1398
+
1399
+ CREATE TRIGGER IF NOT EXISTS mementos_project_update_receipts_immutable_delete
1400
+ BEFORE DELETE ON mementos_project_update_receipts
1401
+ BEGIN
1402
+ SELECT RAISE(ABORT, 'mementos project update receipts are immutable');
1403
+ END;
1404
+ `;
1405
+ }
1406
+ function postgresMementosProjectGuardedUpdateSchemaSql() {
1407
+ return `
1408
+ CREATE TABLE IF NOT EXISTS mementos_project_update_receipts (
1409
+ receipt_id TEXT PRIMARY KEY,
1410
+ authority TEXT NOT NULL CHECK(authority = 'mementos'),
1411
+ route TEXT NOT NULL CHECK(route = 'mementos.project-guarded-update.v1'),
1412
+ package_version TEXT NOT NULL,
1413
+ authority_id TEXT NOT NULL,
1414
+ tenant_id TEXT NOT NULL,
1415
+ corpus_id TEXT NOT NULL,
1416
+ operation_id TEXT NOT NULL,
1417
+ step_id TEXT NOT NULL,
1418
+ direction TEXT NOT NULL CHECK(direction IN ('forward', 'rollback')),
1419
+ idempotency_key TEXT NOT NULL,
1420
+ request_digest TEXT NOT NULL,
1421
+ outcome TEXT NOT NULL CHECK(outcome = 'accepted'),
1422
+ target_id TEXT NOT NULL,
1423
+ expected_revision TEXT NOT NULL,
1424
+ result_revision TEXT NOT NULL,
1425
+ result_digest TEXT NOT NULL,
1426
+ accepted_receipt_id TEXT,
1427
+ before_project_json JSONB NOT NULL,
1428
+ after_project_json JSONB NOT NULL,
1429
+ created_at TIMESTAMPTZ NOT NULL,
1430
+ UNIQUE(authority_id, tenant_id, corpus_id, direction, idempotency_key)
1431
+ );
1432
+
1433
+ CREATE INDEX IF NOT EXISTS idx_mementos_project_update_receipts_target
1434
+ ON mementos_project_update_receipts(
1435
+ authority_id, tenant_id, corpus_id, target_id, created_at
1436
+ );
1437
+
1438
+ CREATE OR REPLACE FUNCTION mementos_project_update_receipts_immutable()
1439
+ RETURNS trigger
1440
+ LANGUAGE plpgsql
1441
+ AS $$
1442
+ BEGIN
1443
+ RAISE EXCEPTION 'mementos project update receipts are immutable';
1444
+ END;
1445
+ $$;
1446
+ DROP TRIGGER IF EXISTS mementos_project_update_receipts_immutable
1447
+ ON mementos_project_update_receipts;
1448
+ CREATE TRIGGER mementos_project_update_receipts_immutable
1449
+ BEFORE UPDATE OR DELETE ON mementos_project_update_receipts
1450
+ FOR EACH ROW EXECUTE FUNCTION mementos_project_update_receipts_immutable();
1451
+ `;
1452
+ }
1453
+
1454
+ // src/memory-project-link/schema.ts
1455
+ function sqliteMementosMemoryProjectLinkSchemaSql() {
1456
+ return `
1457
+ CREATE TABLE IF NOT EXISTS mementos_memory_project_link_receipts (
1458
+ receipt_id TEXT PRIMARY KEY,
1459
+ authority TEXT NOT NULL CHECK(authority = 'mementos'),
1460
+ route TEXT NOT NULL CHECK(route = 'mementos.memory-project-link.v1'),
1461
+ package_version TEXT NOT NULL,
1462
+ authority_id TEXT NOT NULL,
1463
+ tenant_id TEXT NOT NULL,
1464
+ corpus_id TEXT NOT NULL,
1465
+ operation_id TEXT NOT NULL,
1466
+ step_id TEXT NOT NULL,
1467
+ direction TEXT NOT NULL CHECK(direction IN ('forward', 'rollback')),
1468
+ idempotency_key TEXT NOT NULL,
1469
+ request_digest TEXT NOT NULL,
1470
+ outcome TEXT NOT NULL CHECK(outcome IN ('accepted', 'no_change')),
1471
+ target_memory_id TEXT NOT NULL,
1472
+ requested_project_id TEXT NOT NULL,
1473
+ expected_memory_version INTEGER NOT NULL,
1474
+ expected_memory_revision TEXT NOT NULL,
1475
+ expected_project_revision TEXT,
1476
+ result_memory_version INTEGER NOT NULL,
1477
+ result_memory_revision TEXT NOT NULL,
1478
+ result_memory_digest TEXT NOT NULL,
1479
+ result_project_revision TEXT,
1480
+ result_project_digest TEXT,
1481
+ accepted_receipt_id TEXT,
1482
+ before_link_json TEXT NOT NULL,
1483
+ after_link_json TEXT NOT NULL,
1484
+ before_project_revision TEXT,
1485
+ before_project_digest TEXT,
1486
+ after_project_revision TEXT,
1487
+ after_project_digest TEXT,
1488
+ created_at TEXT NOT NULL,
1489
+ UNIQUE(authority_id, tenant_id, corpus_id, direction, idempotency_key)
1490
+ );
1491
+
1492
+ CREATE INDEX IF NOT EXISTS idx_mementos_memory_project_link_receipts_target
1493
+ ON mementos_memory_project_link_receipts(
1494
+ authority_id, tenant_id, corpus_id, target_memory_id, created_at
1495
+ );
1496
+
1497
+ CREATE TRIGGER IF NOT EXISTS mementos_memory_project_link_receipts_immutable_update
1498
+ BEFORE UPDATE ON mementos_memory_project_link_receipts
1499
+ BEGIN
1500
+ SELECT RAISE(ABORT, 'mementos memory project link receipts are immutable');
1501
+ END;
1502
+
1503
+ CREATE TRIGGER IF NOT EXISTS mementos_memory_project_link_receipts_immutable_delete
1504
+ BEFORE DELETE ON mementos_memory_project_link_receipts
1505
+ BEGIN
1506
+ SELECT RAISE(ABORT, 'mementos memory project link receipts are immutable');
1507
+ END;
1508
+ `;
1509
+ }
1510
+ function postgresMementosMemoryProjectLinkSchemaSql() {
1511
+ return `
1512
+ CREATE TABLE IF NOT EXISTS mementos_memory_project_link_receipts (
1513
+ receipt_id TEXT PRIMARY KEY,
1514
+ authority TEXT NOT NULL CHECK(authority = 'mementos'),
1515
+ route TEXT NOT NULL CHECK(route = 'mementos.memory-project-link.v1'),
1516
+ package_version TEXT NOT NULL,
1517
+ authority_id TEXT NOT NULL,
1518
+ tenant_id TEXT NOT NULL,
1519
+ corpus_id TEXT NOT NULL,
1520
+ operation_id TEXT NOT NULL,
1521
+ step_id TEXT NOT NULL,
1522
+ direction TEXT NOT NULL CHECK(direction IN ('forward', 'rollback')),
1523
+ idempotency_key TEXT NOT NULL,
1524
+ request_digest TEXT NOT NULL,
1525
+ outcome TEXT NOT NULL CHECK(outcome IN ('accepted', 'no_change')),
1526
+ target_memory_id TEXT NOT NULL,
1527
+ requested_project_id TEXT NOT NULL,
1528
+ expected_memory_version INTEGER NOT NULL,
1529
+ expected_memory_revision TEXT NOT NULL,
1530
+ expected_project_revision TEXT,
1531
+ result_memory_version INTEGER NOT NULL,
1532
+ result_memory_revision TEXT NOT NULL,
1533
+ result_memory_digest TEXT NOT NULL,
1534
+ result_project_revision TEXT,
1535
+ result_project_digest TEXT,
1536
+ accepted_receipt_id TEXT,
1537
+ before_link_json JSONB NOT NULL,
1538
+ after_link_json JSONB NOT NULL,
1539
+ before_project_revision TEXT,
1540
+ before_project_digest TEXT,
1541
+ after_project_revision TEXT,
1542
+ after_project_digest TEXT,
1543
+ created_at TIMESTAMPTZ NOT NULL,
1544
+ UNIQUE(authority_id, tenant_id, corpus_id, direction, idempotency_key)
1545
+ );
1546
+
1547
+ CREATE INDEX IF NOT EXISTS idx_mementos_memory_project_link_receipts_target
1548
+ ON mementos_memory_project_link_receipts(
1549
+ authority_id, tenant_id, corpus_id, target_memory_id, created_at
1550
+ );
1551
+
1552
+ CREATE OR REPLACE FUNCTION mementos_memory_project_link_receipts_immutable()
1553
+ RETURNS trigger
1554
+ LANGUAGE plpgsql
1555
+ AS $$
1556
+ BEGIN
1557
+ RAISE EXCEPTION 'mementos memory project link receipts are immutable';
1558
+ END;
1559
+ $$;
1560
+ DROP TRIGGER IF EXISTS mementos_memory_project_link_receipts_immutable
1561
+ ON mementos_memory_project_link_receipts;
1562
+ CREATE TRIGGER mementos_memory_project_link_receipts_immutable
1563
+ BEFORE UPDATE OR DELETE ON mementos_memory_project_link_receipts
1564
+ FOR EACH ROW EXECUTE FUNCTION mementos_memory_project_link_receipts_immutable();
1565
+ `;
1566
+ }
1567
+ var MEMENTOS_MEMORY_PROJECT_LINK_ROUTE = "mementos.memory-project-link.v1", MEMORY_PROJECT_LINK_RECEIPT_COLUMNS;
1568
+ var init_schema = __esm(() => {
1569
+ MEMORY_PROJECT_LINK_RECEIPT_COLUMNS = [
1570
+ "receipt_id",
1571
+ "authority",
1572
+ "route",
1573
+ "package_version",
1574
+ "authority_id",
1575
+ "tenant_id",
1576
+ "corpus_id",
1577
+ "operation_id",
1578
+ "step_id",
1579
+ "direction",
1580
+ "idempotency_key",
1581
+ "request_digest",
1582
+ "outcome",
1583
+ "target_memory_id",
1584
+ "requested_project_id",
1585
+ "expected_memory_version",
1586
+ "expected_memory_revision",
1587
+ "expected_project_revision",
1588
+ "result_memory_version",
1589
+ "result_memory_revision",
1590
+ "result_memory_digest",
1591
+ "result_project_revision",
1592
+ "result_project_digest",
1593
+ "accepted_receipt_id",
1594
+ "before_link_json",
1595
+ "after_link_json",
1596
+ "before_project_revision",
1597
+ "before_project_digest",
1598
+ "after_project_revision",
1599
+ "after_project_digest",
1600
+ "created_at"
1601
+ ];
1602
+ });
1603
+
1181
1604
  // src/db/migrations.ts
1182
1605
  var MEMORY_VERSION_SNAPSHOT_TRIGGER = `
1183
1606
  CREATE TRIGGER IF NOT EXISTS memories_version_snapshot
@@ -1198,6 +1621,7 @@ BEGIN
1198
1621
  END;
1199
1622
  `, MIGRATIONS;
1200
1623
  var init_migrations = __esm(() => {
1624
+ init_schema();
1201
1625
  MIGRATIONS = [
1202
1626
  `
1203
1627
  CREATE TABLE IF NOT EXISTS projects (
@@ -2131,6 +2555,18 @@ UPDATE memory_audit_log SET new_value_hash = NULL
2131
2555
  AND new_value_hash NOT GLOB '*[^0-9A-F]*';
2132
2556
 
2133
2557
  INSERT OR IGNORE INTO _migrations (id) VALUES (37);
2558
+ `,
2559
+ `
2560
+ ${sqliteMementosProjectRegistrationSchemaSql()}
2561
+ INSERT OR IGNORE INTO _migrations (id) VALUES (38);
2562
+ `,
2563
+ `
2564
+ ${sqliteMementosProjectGuardedUpdateSchemaSql()}
2565
+ INSERT OR IGNORE INTO _migrations (id) VALUES (39);
2566
+ `,
2567
+ `
2568
+ ${sqliteMementosMemoryProjectLinkSchemaSql()}
2569
+ INSERT OR IGNORE INTO _migrations (id) VALUES (40);
2134
2570
  `
2135
2571
  ];
2136
2572
  });
@@ -2501,8 +2937,8 @@ var init_util = __esm(() => {
2501
2937
 
2502
2938
  // node_modules/zod/v3/ZodError.js
2503
2939
  var ZodIssueCode, quotelessJson = (obj) => {
2504
- const json = JSON.stringify(obj, null, 2);
2505
- return json.replace(/"([^"]+)":/g, "$1:");
2940
+ const json2 = JSON.stringify(obj, null, 2);
2941
+ return json2.replace(/"([^"]+)":/g, "$1:");
2506
2942
  }, ZodError;
2507
2943
  var init_ZodError = __esm(() => {
2508
2944
  init_util();
@@ -15694,24 +16130,24 @@ class JSONSchemaGenerator {
15694
16130
  const _json = result.schema;
15695
16131
  switch (def.type) {
15696
16132
  case "string": {
15697
- const json = _json;
15698
- json.type = "string";
16133
+ const json2 = _json;
16134
+ json2.type = "string";
15699
16135
  const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag;
15700
16136
  if (typeof minimum === "number")
15701
- json.minLength = minimum;
16137
+ json2.minLength = minimum;
15702
16138
  if (typeof maximum === "number")
15703
- json.maxLength = maximum;
16139
+ json2.maxLength = maximum;
15704
16140
  if (format) {
15705
- json.format = formatMap[format] ?? format;
15706
- if (json.format === "")
15707
- delete json.format;
16141
+ json2.format = formatMap[format] ?? format;
16142
+ if (json2.format === "")
16143
+ delete json2.format;
15708
16144
  }
15709
16145
  if (contentEncoding)
15710
- json.contentEncoding = contentEncoding;
16146
+ json2.contentEncoding = contentEncoding;
15711
16147
  if (patterns && patterns.size > 0) {
15712
16148
  const regexes = [...patterns];
15713
16149
  if (regexes.length === 1)
15714
- json.pattern = regexes[0].source;
16150
+ json2.pattern = regexes[0].source;
15715
16151
  else if (regexes.length > 1) {
15716
16152
  result.schema.allOf = [
15717
16153
  ...regexes.map((regex) => ({
@@ -15724,41 +16160,41 @@ class JSONSchemaGenerator {
15724
16160
  break;
15725
16161
  }
15726
16162
  case "number": {
15727
- const json = _json;
16163
+ const json2 = _json;
15728
16164
  const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag;
15729
16165
  if (typeof format === "string" && format.includes("int"))
15730
- json.type = "integer";
16166
+ json2.type = "integer";
15731
16167
  else
15732
- json.type = "number";
16168
+ json2.type = "number";
15733
16169
  if (typeof exclusiveMinimum === "number")
15734
- json.exclusiveMinimum = exclusiveMinimum;
16170
+ json2.exclusiveMinimum = exclusiveMinimum;
15735
16171
  if (typeof minimum === "number") {
15736
- json.minimum = minimum;
16172
+ json2.minimum = minimum;
15737
16173
  if (typeof exclusiveMinimum === "number") {
15738
16174
  if (exclusiveMinimum >= minimum)
15739
- delete json.minimum;
16175
+ delete json2.minimum;
15740
16176
  else
15741
- delete json.exclusiveMinimum;
16177
+ delete json2.exclusiveMinimum;
15742
16178
  }
15743
16179
  }
15744
16180
  if (typeof exclusiveMaximum === "number")
15745
- json.exclusiveMaximum = exclusiveMaximum;
16181
+ json2.exclusiveMaximum = exclusiveMaximum;
15746
16182
  if (typeof maximum === "number") {
15747
- json.maximum = maximum;
16183
+ json2.maximum = maximum;
15748
16184
  if (typeof exclusiveMaximum === "number") {
15749
16185
  if (exclusiveMaximum <= maximum)
15750
- delete json.maximum;
16186
+ delete json2.maximum;
15751
16187
  else
15752
- delete json.exclusiveMaximum;
16188
+ delete json2.exclusiveMaximum;
15753
16189
  }
15754
16190
  }
15755
16191
  if (typeof multipleOf === "number")
15756
- json.multipleOf = multipleOf;
16192
+ json2.multipleOf = multipleOf;
15757
16193
  break;
15758
16194
  }
15759
16195
  case "boolean": {
15760
- const json = _json;
15761
- json.type = "boolean";
16196
+ const json2 = _json;
16197
+ json2.type = "boolean";
15762
16198
  break;
15763
16199
  }
15764
16200
  case "bigint": {
@@ -15806,23 +16242,23 @@ class JSONSchemaGenerator {
15806
16242
  break;
15807
16243
  }
15808
16244
  case "array": {
15809
- const json = _json;
16245
+ const json2 = _json;
15810
16246
  const { minimum, maximum } = schema._zod.bag;
15811
16247
  if (typeof minimum === "number")
15812
- json.minItems = minimum;
16248
+ json2.minItems = minimum;
15813
16249
  if (typeof maximum === "number")
15814
- json.maxItems = maximum;
15815
- json.type = "array";
15816
- json.items = this.process(def.element, { ...params, path: [...params.path, "items"] });
16250
+ json2.maxItems = maximum;
16251
+ json2.type = "array";
16252
+ json2.items = this.process(def.element, { ...params, path: [...params.path, "items"] });
15817
16253
  break;
15818
16254
  }
15819
16255
  case "object": {
15820
- const json = _json;
15821
- json.type = "object";
15822
- json.properties = {};
16256
+ const json2 = _json;
16257
+ json2.type = "object";
16258
+ json2.properties = {};
15823
16259
  const shape = def.shape;
15824
16260
  for (const key in shape) {
15825
- json.properties[key] = this.process(shape[key], {
16261
+ json2.properties[key] = this.process(shape[key], {
15826
16262
  ...params,
15827
16263
  path: [...params.path, "properties", key]
15828
16264
  });
@@ -15837,15 +16273,15 @@ class JSONSchemaGenerator {
15837
16273
  }
15838
16274
  }));
15839
16275
  if (requiredKeys.size > 0) {
15840
- json.required = Array.from(requiredKeys);
16276
+ json2.required = Array.from(requiredKeys);
15841
16277
  }
15842
16278
  if (def.catchall?._zod.def.type === "never") {
15843
- json.additionalProperties = false;
16279
+ json2.additionalProperties = false;
15844
16280
  } else if (!def.catchall) {
15845
16281
  if (this.io === "output")
15846
- json.additionalProperties = false;
16282
+ json2.additionalProperties = false;
15847
16283
  } else if (def.catchall) {
15848
- json.additionalProperties = this.process(def.catchall, {
16284
+ json2.additionalProperties = this.process(def.catchall, {
15849
16285
  ...params,
15850
16286
  path: [...params.path, "additionalProperties"]
15851
16287
  });
@@ -15853,15 +16289,15 @@ class JSONSchemaGenerator {
15853
16289
  break;
15854
16290
  }
15855
16291
  case "union": {
15856
- const json = _json;
15857
- json.anyOf = def.options.map((x, i) => this.process(x, {
16292
+ const json2 = _json;
16293
+ json2.anyOf = def.options.map((x, i) => this.process(x, {
15858
16294
  ...params,
15859
16295
  path: [...params.path, "anyOf", i]
15860
16296
  }));
15861
16297
  break;
15862
16298
  }
15863
16299
  case "intersection": {
15864
- const json = _json;
16300
+ const json2 = _json;
15865
16301
  const a = this.process(def.left, {
15866
16302
  ...params,
15867
16303
  path: [...params.path, "allOf", 0]
@@ -15875,17 +16311,17 @@ class JSONSchemaGenerator {
15875
16311
  ...isSimpleIntersection(a) ? a.allOf : [a],
15876
16312
  ...isSimpleIntersection(b) ? b.allOf : [b]
15877
16313
  ];
15878
- json.allOf = allOf;
16314
+ json2.allOf = allOf;
15879
16315
  break;
15880
16316
  }
15881
16317
  case "tuple": {
15882
- const json = _json;
15883
- json.type = "array";
16318
+ const json2 = _json;
16319
+ json2.type = "array";
15884
16320
  const prefixItems = def.items.map((x, i) => this.process(x, { ...params, path: [...params.path, "prefixItems", i] }));
15885
16321
  if (this.target === "draft-2020-12") {
15886
- json.prefixItems = prefixItems;
16322
+ json2.prefixItems = prefixItems;
15887
16323
  } else {
15888
- json.items = prefixItems;
16324
+ json2.items = prefixItems;
15889
16325
  }
15890
16326
  if (def.rest) {
15891
16327
  const rest = this.process(def.rest, {
@@ -15893,29 +16329,29 @@ class JSONSchemaGenerator {
15893
16329
  path: [...params.path, "items"]
15894
16330
  });
15895
16331
  if (this.target === "draft-2020-12") {
15896
- json.items = rest;
16332
+ json2.items = rest;
15897
16333
  } else {
15898
- json.additionalItems = rest;
16334
+ json2.additionalItems = rest;
15899
16335
  }
15900
16336
  }
15901
16337
  if (def.rest) {
15902
- json.items = this.process(def.rest, {
16338
+ json2.items = this.process(def.rest, {
15903
16339
  ...params,
15904
16340
  path: [...params.path, "items"]
15905
16341
  });
15906
16342
  }
15907
16343
  const { minimum, maximum } = schema._zod.bag;
15908
16344
  if (typeof minimum === "number")
15909
- json.minItems = minimum;
16345
+ json2.minItems = minimum;
15910
16346
  if (typeof maximum === "number")
15911
- json.maxItems = maximum;
16347
+ json2.maxItems = maximum;
15912
16348
  break;
15913
16349
  }
15914
16350
  case "record": {
15915
- const json = _json;
15916
- json.type = "object";
15917
- json.propertyNames = this.process(def.keyType, { ...params, path: [...params.path, "propertyNames"] });
15918
- json.additionalProperties = this.process(def.valueType, {
16351
+ const json2 = _json;
16352
+ json2.type = "object";
16353
+ json2.propertyNames = this.process(def.keyType, { ...params, path: [...params.path, "propertyNames"] });
16354
+ json2.additionalProperties = this.process(def.valueType, {
15919
16355
  ...params,
15920
16356
  path: [...params.path, "additionalProperties"]
15921
16357
  });
@@ -15934,17 +16370,17 @@ class JSONSchemaGenerator {
15934
16370
  break;
15935
16371
  }
15936
16372
  case "enum": {
15937
- const json = _json;
16373
+ const json2 = _json;
15938
16374
  const values = getEnumValues(def.entries);
15939
16375
  if (values.every((v) => typeof v === "number"))
15940
- json.type = "number";
16376
+ json2.type = "number";
15941
16377
  if (values.every((v) => typeof v === "string"))
15942
- json.type = "string";
15943
- json.enum = values;
16378
+ json2.type = "string";
16379
+ json2.enum = values;
15944
16380
  break;
15945
16381
  }
15946
16382
  case "literal": {
15947
- const json = _json;
16383
+ const json2 = _json;
15948
16384
  const vals = [];
15949
16385
  for (const val of def.values) {
15950
16386
  if (val === undefined) {
@@ -15963,23 +16399,23 @@ class JSONSchemaGenerator {
15963
16399
  }
15964
16400
  if (vals.length === 0) {} else if (vals.length === 1) {
15965
16401
  const val = vals[0];
15966
- json.type = val === null ? "null" : typeof val;
15967
- json.const = val;
16402
+ json2.type = val === null ? "null" : typeof val;
16403
+ json2.const = val;
15968
16404
  } else {
15969
16405
  if (vals.every((v) => typeof v === "number"))
15970
- json.type = "number";
16406
+ json2.type = "number";
15971
16407
  if (vals.every((v) => typeof v === "string"))
15972
- json.type = "string";
16408
+ json2.type = "string";
15973
16409
  if (vals.every((v) => typeof v === "boolean"))
15974
- json.type = "string";
16410
+ json2.type = "string";
15975
16411
  if (vals.every((v) => v === null))
15976
- json.type = "null";
15977
- json.enum = vals;
16412
+ json2.type = "null";
16413
+ json2.enum = vals;
15978
16414
  }
15979
16415
  break;
15980
16416
  }
15981
16417
  case "file": {
15982
- const json = _json;
16418
+ const json2 = _json;
15983
16419
  const file = {
15984
16420
  type: "string",
15985
16421
  format: "binary",
@@ -15993,15 +16429,15 @@ class JSONSchemaGenerator {
15993
16429
  if (mime) {
15994
16430
  if (mime.length === 1) {
15995
16431
  file.contentMediaType = mime[0];
15996
- Object.assign(json, file);
16432
+ Object.assign(json2, file);
15997
16433
  } else {
15998
- json.anyOf = mime.map((m) => {
16434
+ json2.anyOf = mime.map((m) => {
15999
16435
  const mFile = { ...file, contentMediaType: m };
16000
16436
  return mFile;
16001
16437
  });
16002
16438
  }
16003
16439
  } else {
16004
- Object.assign(json, file);
16440
+ Object.assign(json2, file);
16005
16441
  }
16006
16442
  break;
16007
16443
  }
@@ -16022,8 +16458,8 @@ class JSONSchemaGenerator {
16022
16458
  break;
16023
16459
  }
16024
16460
  case "success": {
16025
- const json = _json;
16026
- json.type = "boolean";
16461
+ const json2 = _json;
16462
+ json2.type = "boolean";
16027
16463
  break;
16028
16464
  }
16029
16465
  case "default": {
@@ -16058,12 +16494,12 @@ class JSONSchemaGenerator {
16058
16494
  break;
16059
16495
  }
16060
16496
  case "template_literal": {
16061
- const json = _json;
16497
+ const json2 = _json;
16062
16498
  const pattern = schema._zod.pattern;
16063
16499
  if (!pattern)
16064
16500
  throw new Error("Pattern not found in template literal");
16065
- json.type = "string";
16066
- json.pattern = pattern.source;
16501
+ json2.type = "string";
16502
+ json2.pattern = pattern.source;
16067
16503
  break;
16068
16504
  }
16069
16505
  case "pipe": {
@@ -17156,7 +17592,7 @@ function _instanceof(cls, params = {
17156
17592
  inst._zod.bag.Class = cls;
17157
17593
  return inst;
17158
17594
  }
17159
- function json(params) {
17595
+ function json2(params) {
17160
17596
  const jsonSchema = lazy(() => {
17161
17597
  return union([string2(params), number2(), boolean2(), _null3(), array(jsonSchema), record(string2(), jsonSchema)]);
17162
17598
  });
@@ -17843,7 +18279,7 @@ __export(exports_external2, {
17843
18279
  ksuid: () => ksuid2,
17844
18280
  keyof: () => keyof,
17845
18281
  jwt: () => jwt,
17846
- json: () => json,
18282
+ json: () => json2,
17847
18283
  iso: () => exports_iso,
17848
18284
  ipv6: () => ipv62,
17849
18285
  ipv4: () => ipv42,
@@ -19703,7 +20139,7 @@ function createProviderToolFactoryWithOutputSchema({
19703
20139
  supportsDeferredResults
19704
20140
  });
19705
20141
  }
19706
- async function resolve3(value) {
20142
+ async function resolve4(value) {
19707
20143
  if (typeof value === "function") {
19708
20144
  value = value();
19709
20145
  }
@@ -22525,11 +22961,11 @@ var VERSION2 = "3.0.82", anthropicErrorDataSchema, anthropicFailedResponseHandle
22525
22961
  betas,
22526
22962
  headers
22527
22963
  }) {
22528
- return combineHeaders(await resolve3(this.config.headers), headers, betas.size > 0 ? { "anthropic-beta": Array.from(betas).join(",") } : {});
22964
+ return combineHeaders(await resolve4(this.config.headers), headers, betas.size > 0 ? { "anthropic-beta": Array.from(betas).join(",") } : {});
22529
22965
  }
22530
22966
  async getBetasFromHeaders(requestHeaders) {
22531
22967
  var _a16, _b16;
22532
- const configHeaders = await resolve3(this.config.headers);
22968
+ const configHeaders = await resolve4(this.config.headers);
22533
22969
  const configBetaHeader = (_a16 = configHeaders["anthropic-beta"]) != null ? _a16 : "";
22534
22970
  const requestBetaHeader = (_b16 = requestHeaders == null ? undefined : requestHeaders["anthropic-beta"]) != null ? _b16 : "";
22535
22971
  return new Set([
@@ -33199,24 +33635,24 @@ var require_oauth = __commonJS((exports, module) => {
33199
33635
  });
33200
33636
  }
33201
33637
  async function processTokenResponse(response) {
33202
- const json2 = await response.json();
33638
+ const json3 = await response.json();
33203
33639
  if (!response.ok) {
33204
- const errorMsg = typeof json2 === "object" && json2 && "error" in json2 ? String(json2.error) : "Token refresh failed";
33640
+ const errorMsg = typeof json3 === "object" && json3 && "error" in json3 ? String(json3.error) : "Token refresh failed";
33205
33641
  return [new Error(errorMsg)];
33206
33642
  }
33207
- if (typeof json2 !== "object" || json2 === null) {
33643
+ if (typeof json3 !== "object" || json3 === null) {
33208
33644
  return [new Error("Invalid token response")];
33209
33645
  }
33210
- if (typeof json2.access_token !== "string") {
33646
+ if (typeof json3.access_token !== "string") {
33211
33647
  return [new Error("Missing access_token in response")];
33212
33648
  }
33213
- if (json2.token_type !== "Bearer") {
33649
+ if (json3.token_type !== "Bearer") {
33214
33650
  return [new Error("Invalid token_type in response")];
33215
33651
  }
33216
- if (typeof json2.expires_in !== "number") {
33652
+ if (typeof json3.expires_in !== "number") {
33217
33653
  return [new Error("Missing expires_in in response")];
33218
33654
  }
33219
- return [null, json2];
33655
+ return [null, json3];
33220
33656
  }
33221
33657
  });
33222
33658
 
@@ -33953,7 +34389,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
33953
34389
  try {
33954
34390
  const { value } = await getFromApi({
33955
34391
  url: `${this.config.baseURL}/config`,
33956
- headers: await resolve3(this.config.headers()),
34392
+ headers: await resolve4(this.config.headers()),
33957
34393
  successfulResponseHandler: createJsonResponseHandler(gatewayAvailableModelsResponseSchema),
33958
34394
  failedResponseHandler: createJsonErrorResponseHandler({
33959
34395
  errorSchema: exports_external2.any(),
@@ -33971,7 +34407,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
33971
34407
  const baseUrl = new URL(this.config.baseURL);
33972
34408
  const { value } = await getFromApi({
33973
34409
  url: `${baseUrl.origin}/v1/credits`,
33974
- headers: await resolve3(this.config.headers()),
34410
+ headers: await resolve4(this.config.headers()),
33975
34411
  successfulResponseHandler: createJsonResponseHandler(gatewayCreditsResponseSchema),
33976
34412
  failedResponseHandler: createJsonErrorResponseHandler({
33977
34413
  errorSchema: exports_external2.any(),
@@ -34017,7 +34453,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34017
34453
  }
34018
34454
  const { value } = await getFromApi({
34019
34455
  url: `${baseUrl.origin}/v1/report?${searchParams.toString()}`,
34020
- headers: await resolve3(this.config.headers()),
34456
+ headers: await resolve4(this.config.headers()),
34021
34457
  successfulResponseHandler: createJsonResponseHandler(gatewaySpendReportResponseSchema),
34022
34458
  failedResponseHandler: createJsonErrorResponseHandler({
34023
34459
  errorSchema: exports_external2.any(),
@@ -34039,7 +34475,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34039
34475
  const baseUrl = new URL(this.config.baseURL);
34040
34476
  const { value } = await getFromApi({
34041
34477
  url: `${baseUrl.origin}/v1/generation?id=${encodeURIComponent(params.id)}`,
34042
- headers: await resolve3(this.config.headers()),
34478
+ headers: await resolve4(this.config.headers()),
34043
34479
  successfulResponseHandler: createJsonResponseHandler(gatewayGenerationInfoResponseSchema),
34044
34480
  failedResponseHandler: createJsonErrorResponseHandler({
34045
34481
  errorSchema: exports_external2.any(),
@@ -34072,7 +34508,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34072
34508
  async doGenerate(options) {
34073
34509
  const { args, warnings } = await this.getArgs(options);
34074
34510
  const { abortSignal } = options;
34075
- const resolvedHeaders = await resolve3(this.config.headers());
34511
+ const resolvedHeaders = await resolve4(this.config.headers());
34076
34512
  try {
34077
34513
  const {
34078
34514
  responseHeaders,
@@ -34080,7 +34516,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34080
34516
  rawValue: rawResponse
34081
34517
  } = await postJsonToApi({
34082
34518
  url: this.getUrl(),
34083
- headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await resolve3(this.config.o11yHeaders)),
34519
+ headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await resolve4(this.config.o11yHeaders)),
34084
34520
  body: args,
34085
34521
  successfulResponseHandler: createJsonResponseHandler(exports_external2.any()),
34086
34522
  failedResponseHandler: createJsonErrorResponseHandler({
@@ -34103,11 +34539,11 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34103
34539
  async doStream(options) {
34104
34540
  const { args, warnings } = await this.getArgs(options);
34105
34541
  const { abortSignal } = options;
34106
- const resolvedHeaders = await resolve3(this.config.headers());
34542
+ const resolvedHeaders = await resolve4(this.config.headers());
34107
34543
  try {
34108
34544
  const { value: response, responseHeaders } = await postJsonToApi({
34109
34545
  url: this.getUrl(),
34110
- headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await resolve3(this.config.o11yHeaders)),
34546
+ headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await resolve4(this.config.o11yHeaders)),
34111
34547
  body: args,
34112
34548
  successfulResponseHandler: createEventSourceResponseHandler(exports_external2.any()),
34113
34549
  failedResponseHandler: createJsonErrorResponseHandler({
@@ -34192,7 +34628,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34192
34628
  providerOptions
34193
34629
  }) {
34194
34630
  var _a102;
34195
- const resolvedHeaders = await resolve3(this.config.headers());
34631
+ const resolvedHeaders = await resolve4(this.config.headers());
34196
34632
  try {
34197
34633
  const {
34198
34634
  responseHeaders,
@@ -34200,7 +34636,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34200
34636
  rawValue
34201
34637
  } = await postJsonToApi({
34202
34638
  url: this.getUrl(),
34203
- headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders)),
34639
+ headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve4(this.config.o11yHeaders)),
34204
34640
  body: {
34205
34641
  values,
34206
34642
  ...providerOptions ? { providerOptions } : {}
@@ -34256,7 +34692,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34256
34692
  abortSignal
34257
34693
  }) {
34258
34694
  var _a102, _b102, _c, _d;
34259
- const resolvedHeaders = await resolve3(this.config.headers());
34695
+ const resolvedHeaders = await resolve4(this.config.headers());
34260
34696
  try {
34261
34697
  const {
34262
34698
  responseHeaders,
@@ -34264,7 +34700,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34264
34700
  rawValue
34265
34701
  } = await postJsonToApi({
34266
34702
  url: this.getUrl(),
34267
- headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders)),
34703
+ headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve4(this.config.o11yHeaders)),
34268
34704
  body: {
34269
34705
  prompt,
34270
34706
  n,
@@ -34339,11 +34775,11 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34339
34775
  abortSignal
34340
34776
  }) {
34341
34777
  var _a102;
34342
- const resolvedHeaders = await resolve3(this.config.headers());
34778
+ const resolvedHeaders = await resolve4(this.config.headers());
34343
34779
  try {
34344
34780
  const { responseHeaders, value: responseBody } = await postJsonToApi({
34345
34781
  url: this.getUrl(),
34346
- headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders), { accept: "text/event-stream" }),
34782
+ headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve4(this.config.o11yHeaders), { accept: "text/event-stream" }),
34347
34783
  body: {
34348
34784
  prompt,
34349
34785
  n,
@@ -34466,7 +34902,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34466
34902
  abortSignal,
34467
34903
  providerOptions
34468
34904
  }) {
34469
- const resolvedHeaders = await resolve3(this.config.headers());
34905
+ const resolvedHeaders = await resolve4(this.config.headers());
34470
34906
  try {
34471
34907
  const {
34472
34908
  responseHeaders,
@@ -34474,7 +34910,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
34474
34910
  rawValue
34475
34911
  } = await postJsonToApi({
34476
34912
  url: this.getUrl(),
34477
- headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders)),
34913
+ headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve4(this.config.o11yHeaders)),
34478
34914
  body: {
34479
34915
  documents,
34480
34916
  query,
@@ -44078,7 +44514,7 @@ var import_api2, import_api3, __defProp2, __export2 = (target, all) => {
44078
44514
  const schema = asSchema(inputSchema);
44079
44515
  return {
44080
44516
  name: "object",
44081
- responseFormat: resolve3(schema.jsonSchema).then((jsonSchema2) => ({
44517
+ responseFormat: resolve4(schema.jsonSchema).then((jsonSchema2) => ({
44082
44518
  type: "json",
44083
44519
  schema: jsonSchema2,
44084
44520
  ...name21 != null && { name: name21 },
@@ -44139,7 +44575,7 @@ var import_api2, import_api3, __defProp2, __export2 = (target, all) => {
44139
44575
  const elementSchema = asSchema(inputElementSchema);
44140
44576
  return {
44141
44577
  name: "array",
44142
- responseFormat: resolve3(elementSchema.jsonSchema).then((jsonSchema2) => {
44578
+ responseFormat: resolve4(elementSchema.jsonSchema).then((jsonSchema2) => {
44143
44579
  const { $schema, ...itemSchema } = jsonSchema2;
44144
44580
  return {
44145
44581
  type: "json",
@@ -44316,7 +44752,7 @@ var import_api2, import_api3, __defProp2, __export2 = (target, all) => {
44316
44752
  return;
44317
44753
  }
44318
44754
  };
44319
- }, json2 = ({
44755
+ }, json3 = ({
44320
44756
  name: name21,
44321
44757
  description
44322
44758
  } = {}) => {
@@ -47052,9 +47488,9 @@ var import_api2, import_api3, __defProp2, __export2 = (target, all) => {
47052
47488
  ...options
47053
47489
  }) {
47054
47490
  var _a21, _b16, _c, _d, _e;
47055
- const resolvedBody = await resolve3(this.body);
47056
- const resolvedHeaders = await resolve3(this.headers);
47057
- const resolvedCredentials = await resolve3(this.credentials);
47491
+ const resolvedBody = await resolve4(this.body);
47492
+ const resolvedHeaders = await resolve4(this.headers);
47493
+ const resolvedCredentials = await resolve4(this.credentials);
47058
47494
  const baseHeaders = {
47059
47495
  ...normalizeHeaders(resolvedHeaders),
47060
47496
  ...normalizeHeaders(options.headers)
@@ -47102,9 +47538,9 @@ var import_api2, import_api3, __defProp2, __export2 = (target, all) => {
47102
47538
  }
47103
47539
  async reconnectToStream(options) {
47104
47540
  var _a21, _b16, _c, _d, _e;
47105
- const resolvedBody = await resolve3(this.body);
47106
- const resolvedHeaders = await resolve3(this.headers);
47107
- const resolvedCredentials = await resolve3(this.credentials);
47541
+ const resolvedBody = await resolve4(this.body);
47542
+ const resolvedHeaders = await resolve4(this.headers);
47543
+ const resolvedCredentials = await resolve4(this.credentials);
47108
47544
  const baseHeaders = {
47109
47545
  ...normalizeHeaders(resolvedHeaders),
47110
47546
  ...normalizeHeaders(options.headers)
@@ -48384,7 +48820,7 @@ var init_dist8 = __esm(() => {
48384
48820
  __export2(output_exports, {
48385
48821
  array: () => array2,
48386
48822
  choice: () => choice,
48387
- json: () => json2,
48823
+ json: () => json3,
48388
48824
  object: () => object2,
48389
48825
  text: () => text
48390
48826
  });
@@ -50024,6 +50460,651 @@ function getMemoryVersions(memoryId, db) {
50024
50460
  return [];
50025
50461
  }
50026
50462
  }
50463
+ // src/db/memory-project-link.ts
50464
+ init_storage();
50465
+ init_api_mode();
50466
+ init_database();
50467
+ import { createHash } from "crypto";
50468
+
50469
+ // src/lib/package-version.ts
50470
+ import { readFileSync as readFileSync2 } from "fs";
50471
+ import { dirname as dirname2, join as join4 } from "path";
50472
+ import { fileURLToPath as fileURLToPath2 } from "url";
50473
+ function getMementosPackageVersion() {
50474
+ const here = dirname2(fileURLToPath2(import.meta.url));
50475
+ for (const candidate of [
50476
+ join4(here, "..", "..", "package.json"),
50477
+ join4(here, "..", "package.json")
50478
+ ]) {
50479
+ try {
50480
+ const parsed = JSON.parse(readFileSync2(candidate, "utf8"));
50481
+ if (typeof parsed.version === "string" && parsed.version.trim())
50482
+ return parsed.version;
50483
+ } catch {}
50484
+ }
50485
+ return "0.0.0";
50486
+ }
50487
+
50488
+ // src/db/memory-project-link.ts
50489
+ init_schema();
50490
+
50491
+ class MemoryProjectLinkError extends Error {
50492
+ code;
50493
+ details;
50494
+ constructor(code, message, details = {}) {
50495
+ super(message);
50496
+ this.code = code;
50497
+ this.details = details;
50498
+ this.name = "MemoryProjectLinkError";
50499
+ }
50500
+ }
50501
+ var LINK_AUTHORITY = {
50502
+ authority_id: "mementos",
50503
+ tenant_id: "default",
50504
+ corpus_id: "default"
50505
+ };
50506
+ var BOUNDED_IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
50507
+ function canonicalize(value) {
50508
+ if (Array.isArray(value))
50509
+ return value.map(canonicalize);
50510
+ if (!value || typeof value !== "object")
50511
+ return value;
50512
+ const output = {};
50513
+ for (const key of Object.keys(value).sort()) {
50514
+ const item = value[key];
50515
+ if (item !== undefined)
50516
+ output[key] = canonicalize(item);
50517
+ }
50518
+ return output;
50519
+ }
50520
+ function canonicalJson(value) {
50521
+ return JSON.stringify(canonicalize(value));
50522
+ }
50523
+ function digest(value) {
50524
+ return createHash("sha256").update(canonicalJson(value)).digest("hex");
50525
+ }
50526
+ function timestampString(value) {
50527
+ return value instanceof Date ? value.toISOString() : String(value);
50528
+ }
50529
+ function nullableTimestamp(value) {
50530
+ return value === null || value === undefined ? null : timestampString(value);
50531
+ }
50532
+ function normalizeMemoryTimestamps(memory) {
50533
+ return {
50534
+ ...memory,
50535
+ created_at: timestampString(memory.created_at),
50536
+ updated_at: timestampString(memory.updated_at),
50537
+ accessed_at: nullableTimestamp(memory.accessed_at),
50538
+ expires_at: nullableTimestamp(memory.expires_at),
50539
+ valid_from: nullableTimestamp(memory.valid_from),
50540
+ valid_until: nullableTimestamp(memory.valid_until),
50541
+ ingested_at: nullableTimestamp(memory.ingested_at)
50542
+ };
50543
+ }
50544
+ function parseProjectRow(row) {
50545
+ return {
50546
+ id: String(row["id"]),
50547
+ name: String(row["name"]),
50548
+ path: String(row["path"]),
50549
+ description: row["description"] === null ? null : String(row["description"] ?? "") || null,
50550
+ memory_prefix: row["memory_prefix"] === null ? null : String(row["memory_prefix"] ?? "") || null,
50551
+ created_at: timestampString(row["created_at"]),
50552
+ updated_at: timestampString(row["updated_at"])
50553
+ };
50554
+ }
50555
+ function memoryMutationState(memory) {
50556
+ const { access_count: _accessCount, accessed_at: _accessedAt, ...state } = memory;
50557
+ return state;
50558
+ }
50559
+ function memoryDigest(memory) {
50560
+ return digest(memoryMutationState(memory));
50561
+ }
50562
+ function projectDigest(project) {
50563
+ return digest(project);
50564
+ }
50565
+ function snapshot(memory) {
50566
+ return {
50567
+ memory_id: memory.id,
50568
+ project_id: memory.project_id,
50569
+ memory_version: memory.version,
50570
+ memory_revision: timestampString(memory.updated_at),
50571
+ memory_digest: memoryDigest(memory)
50572
+ };
50573
+ }
50574
+ function parseSnapshot(value) {
50575
+ const parsed = typeof value === "string" ? JSON.parse(value) : value;
50576
+ return parsed;
50577
+ }
50578
+ function receiptFromRow(row) {
50579
+ return {
50580
+ receipt_id: String(row["receipt_id"]),
50581
+ authority: "mementos",
50582
+ route: MEMENTOS_MEMORY_PROJECT_LINK_ROUTE,
50583
+ package_version: String(row["package_version"]),
50584
+ authority_id: String(row["authority_id"]),
50585
+ tenant_id: String(row["tenant_id"]),
50586
+ corpus_id: String(row["corpus_id"]),
50587
+ operation_id: String(row["operation_id"]),
50588
+ step_id: String(row["step_id"]),
50589
+ direction: row["direction"],
50590
+ idempotency_key: String(row["idempotency_key"]),
50591
+ request_digest: String(row["request_digest"]),
50592
+ outcome: row["outcome"],
50593
+ target_memory_id: String(row["target_memory_id"]),
50594
+ requested_project_id: String(row["requested_project_id"]),
50595
+ expected_memory_version: Number(row["expected_memory_version"]),
50596
+ expected_memory_revision: timestampString(row["expected_memory_revision"]),
50597
+ expected_project_revision: nullableTimestamp(row["expected_project_revision"]),
50598
+ result_memory_version: Number(row["result_memory_version"]),
50599
+ result_memory_revision: timestampString(row["result_memory_revision"]),
50600
+ result_memory_digest: String(row["result_memory_digest"]),
50601
+ result_project_revision: nullableTimestamp(row["result_project_revision"]),
50602
+ result_project_digest: row["result_project_digest"] === null ? null : String(row["result_project_digest"]),
50603
+ accepted_receipt_id: row["accepted_receipt_id"] === null ? null : String(row["accepted_receipt_id"]),
50604
+ before_link: parseSnapshot(row["before_link_json"]),
50605
+ after_link: parseSnapshot(row["after_link_json"]),
50606
+ before_project_revision: nullableTimestamp(row["before_project_revision"]),
50607
+ before_project_digest: row["before_project_digest"] === null ? null : String(row["before_project_digest"]),
50608
+ after_project_revision: nullableTimestamp(row["after_project_revision"]),
50609
+ after_project_digest: row["after_project_digest"] === null ? null : String(row["after_project_digest"]),
50610
+ created_at: timestampString(row["created_at"])
50611
+ };
50612
+ }
50613
+ function assertIdentity(identity) {
50614
+ if (identity.authority_id !== LINK_AUTHORITY.authority_id || identity.tenant_id !== LINK_AUTHORITY.tenant_id || identity.corpus_id !== LINK_AUTHORITY.corpus_id) {
50615
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_AUTHORITY_MISMATCH", "memory project link does not match this authority, tenant, and corpus");
50616
+ }
50617
+ }
50618
+ function assertBoundedIdentifier(value, field) {
50619
+ if (!BOUNDED_IDENTIFIER.test(value)) {
50620
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_INVALID_INPUT", `${field} must be an 8-128 character bounded identifier`);
50621
+ }
50622
+ }
50623
+ function assertMemoryGuard(version, revision) {
50624
+ if (!Number.isSafeInteger(version) || version < 1) {
50625
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_INVALID_INPUT", "expected_memory_version must be a positive safe integer");
50626
+ }
50627
+ if (!revision || revision.length > 128) {
50628
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_INVALID_INPUT", "expected_memory_revision is required and must be bounded");
50629
+ }
50630
+ }
50631
+ function assertForwardRequest(request) {
50632
+ assertIdentity(request);
50633
+ assertBoundedIdentifier(request.operation_id, "operation_id");
50634
+ assertBoundedIdentifier(request.step_id, "step_id");
50635
+ assertBoundedIdentifier(request.idempotency_key, "idempotency_key");
50636
+ assertBoundedIdentifier(request.target_project_id, "target_project_id");
50637
+ assertMemoryGuard(request.expected_memory_version, request.expected_memory_revision);
50638
+ if (!request.expected_project_revision || request.expected_project_revision.length > 128) {
50639
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_INVALID_INPUT", "expected_project_revision is required and must be bounded");
50640
+ }
50641
+ }
50642
+ function assertRollbackRequest(request) {
50643
+ assertIdentity(request);
50644
+ assertBoundedIdentifier(request.operation_id, "operation_id");
50645
+ assertBoundedIdentifier(request.step_id, "step_id");
50646
+ assertBoundedIdentifier(request.idempotency_key, "idempotency_key");
50647
+ assertBoundedIdentifier(request.accepted_receipt_id, "accepted_receipt_id");
50648
+ assertMemoryGuard(request.expected_memory_version, request.expected_memory_revision);
50649
+ }
50650
+ function forwardRequestDigest(memoryId, request) {
50651
+ return digest({
50652
+ authority_id: request.authority_id,
50653
+ tenant_id: request.tenant_id,
50654
+ corpus_id: request.corpus_id,
50655
+ operation_id: request.operation_id,
50656
+ step_id: request.step_id,
50657
+ idempotency_key: request.idempotency_key,
50658
+ expected_memory_version: request.expected_memory_version,
50659
+ expected_memory_revision: request.expected_memory_revision,
50660
+ target_project_id: request.target_project_id,
50661
+ expected_project_revision: request.expected_project_revision,
50662
+ direction: "forward",
50663
+ target_memory_id: memoryId
50664
+ });
50665
+ }
50666
+ function rollbackRequestDigest(memoryId, request) {
50667
+ return digest({
50668
+ authority_id: request.authority_id,
50669
+ tenant_id: request.tenant_id,
50670
+ corpus_id: request.corpus_id,
50671
+ operation_id: request.operation_id,
50672
+ step_id: request.step_id,
50673
+ idempotency_key: request.idempotency_key,
50674
+ expected_memory_version: request.expected_memory_version,
50675
+ expected_memory_revision: request.expected_memory_revision,
50676
+ accepted_receipt_id: request.accepted_receipt_id,
50677
+ direction: "rollback",
50678
+ target_memory_id: memoryId
50679
+ });
50680
+ }
50681
+ function forUpdateSuffix(db, lock) {
50682
+ return lock && db instanceof PgAdapter ? " FOR UPDATE" : "";
50683
+ }
50684
+ function getMemoryByExactId(id, db, lock = false) {
50685
+ const row = db.query(`SELECT * FROM memories WHERE id = ? LIMIT 1${forUpdateSuffix(db, lock)}`).get(id);
50686
+ return row ? normalizeMemoryTimestamps(parseMemoryRow(row)) : null;
50687
+ }
50688
+ function getProjectByExactId(id, db, lock = false) {
50689
+ const row = db.query(`SELECT * FROM projects WHERE id = ? LIMIT 1${forUpdateSuffix(db, lock)}`).get(id);
50690
+ return row ? parseProjectRow(row) : null;
50691
+ }
50692
+ function lockProjects(ids, db) {
50693
+ const projects = new Map;
50694
+ const uniqueIds = [...new Set(ids.filter((id) => Boolean(id)))].sort();
50695
+ for (const id of uniqueIds) {
50696
+ const project = getProjectByExactId(id, db, true);
50697
+ if (!project) {
50698
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_PROJECT_NOT_FOUND", `Project not found by exact stable ID: ${id}`);
50699
+ }
50700
+ projects.set(id, project);
50701
+ }
50702
+ return projects;
50703
+ }
50704
+ function assertMemoryPrecondition(memory, expectedVersion, expectedRevision) {
50705
+ if (memory.version !== expectedVersion || memory.updated_at !== expectedRevision) {
50706
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_STALE_MEMORY", "Memory changed before the guarded project link", {
50707
+ expected_memory_version: expectedVersion,
50708
+ current_memory_version: memory.version,
50709
+ expected_memory_revision: expectedRevision,
50710
+ current_memory_revision: memory.updated_at
50711
+ });
50712
+ }
50713
+ }
50714
+ function assertProjectPrecondition(project, expectedRevision) {
50715
+ if (project.updated_at !== expectedRevision) {
50716
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_STALE_PROJECT", "Project changed before the guarded memory link", {
50717
+ expected_project_revision: expectedRevision,
50718
+ current_project_revision: project.updated_at
50719
+ });
50720
+ }
50721
+ }
50722
+ function assertNoTargetBucketCollision(memory, projectId, db) {
50723
+ const collision = db.query(`
50724
+ SELECT id FROM memories
50725
+ WHERE id != ? AND key = ? AND scope = ?
50726
+ AND COALESCE(agent_id, '') = COALESCE(?, '')
50727
+ AND COALESCE(project_id, '') = COALESCE(?, '')
50728
+ AND COALESCE(session_id, '') = COALESCE(?, '')
50729
+ LIMIT 1
50730
+ `).get(memory.id, memory.key, memory.scope, memory.agent_id, projectId, memory.session_id);
50731
+ if (collision) {
50732
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_COLLISION", "Linking this memory would collide with another memory in the target project bucket", { collision_id: collision.id });
50733
+ }
50734
+ }
50735
+ function nextRevision(previous) {
50736
+ const candidate = now();
50737
+ const previousMs = Date.parse(previous);
50738
+ const candidateMs = Date.parse(candidate);
50739
+ if (Number.isFinite(previousMs) && Number.isFinite(candidateMs) && candidateMs <= previousMs) {
50740
+ return new Date(previousMs + 1).toISOString();
50741
+ }
50742
+ return candidate;
50743
+ }
50744
+ function findReceiptByKey(db, identity, direction, idempotencyKey) {
50745
+ const row = db.query(`
50746
+ SELECT * FROM mementos_memory_project_link_receipts
50747
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
50748
+ AND direction = ? AND idempotency_key = ?
50749
+ LIMIT 1
50750
+ `).get(identity.authority_id, identity.tenant_id, identity.corpus_id, direction, idempotencyKey);
50751
+ return row ? receiptFromRow(row) : null;
50752
+ }
50753
+ function findReceiptById(db, identity, receiptId) {
50754
+ const row = db.query(`
50755
+ SELECT * FROM mementos_memory_project_link_receipts
50756
+ WHERE receipt_id = ? AND authority_id = ? AND tenant_id = ? AND corpus_id = ?
50757
+ LIMIT 1
50758
+ `).get(receiptId, identity.authority_id, identity.tenant_id, identity.corpus_id);
50759
+ return row ? receiptFromRow(row) : null;
50760
+ }
50761
+ function insertReceipt(db, receipt) {
50762
+ db.run(`
50763
+ INSERT INTO mementos_memory_project_link_receipts (
50764
+ receipt_id, authority, route, package_version, authority_id, tenant_id,
50765
+ corpus_id, operation_id, step_id, direction, idempotency_key,
50766
+ request_digest, outcome, target_memory_id, requested_project_id,
50767
+ expected_memory_version, expected_memory_revision,
50768
+ expected_project_revision, result_memory_version,
50769
+ result_memory_revision, result_memory_digest, result_project_revision,
50770
+ result_project_digest, accepted_receipt_id, before_link_json,
50771
+ after_link_json, before_project_revision, before_project_digest,
50772
+ after_project_revision, after_project_digest, created_at
50773
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
50774
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
50775
+ `, [
50776
+ receipt.receipt_id,
50777
+ receipt.authority,
50778
+ receipt.route,
50779
+ receipt.package_version,
50780
+ receipt.authority_id,
50781
+ receipt.tenant_id,
50782
+ receipt.corpus_id,
50783
+ receipt.operation_id,
50784
+ receipt.step_id,
50785
+ receipt.direction,
50786
+ receipt.idempotency_key,
50787
+ receipt.request_digest,
50788
+ receipt.outcome,
50789
+ receipt.target_memory_id,
50790
+ receipt.requested_project_id,
50791
+ receipt.expected_memory_version,
50792
+ receipt.expected_memory_revision,
50793
+ receipt.expected_project_revision,
50794
+ receipt.result_memory_version,
50795
+ receipt.result_memory_revision,
50796
+ receipt.result_memory_digest,
50797
+ receipt.result_project_revision,
50798
+ receipt.result_project_digest,
50799
+ receipt.accepted_receipt_id,
50800
+ canonicalJson(receipt.before_link),
50801
+ canonicalJson(receipt.after_link),
50802
+ receipt.before_project_revision,
50803
+ receipt.before_project_digest,
50804
+ receipt.after_project_revision,
50805
+ receipt.after_project_digest,
50806
+ receipt.created_at
50807
+ ]);
50808
+ }
50809
+ function makeReceipt(input) {
50810
+ const beforeLink = snapshot(input.beforeMemory);
50811
+ const afterLink = snapshot(input.afterMemory);
50812
+ const logical = {
50813
+ authority: "mementos",
50814
+ route: MEMENTOS_MEMORY_PROJECT_LINK_ROUTE,
50815
+ package_version: getMementosPackageVersion(),
50816
+ authority_id: input.request.authority_id,
50817
+ tenant_id: input.request.tenant_id,
50818
+ corpus_id: input.request.corpus_id,
50819
+ operation_id: input.request.operation_id,
50820
+ step_id: input.request.step_id,
50821
+ direction: input.direction,
50822
+ idempotency_key: input.request.idempotency_key,
50823
+ request_digest: input.requestDigest,
50824
+ outcome: input.outcome,
50825
+ target_memory_id: input.targetMemoryId,
50826
+ requested_project_id: input.requestedProjectId,
50827
+ expected_memory_version: input.request.expected_memory_version,
50828
+ expected_memory_revision: input.request.expected_memory_revision,
50829
+ expected_project_revision: input.expectedProjectRevision,
50830
+ result_memory_version: afterLink.memory_version,
50831
+ result_memory_revision: afterLink.memory_revision,
50832
+ result_memory_digest: afterLink.memory_digest,
50833
+ result_project_revision: input.afterProject?.updated_at ?? null,
50834
+ result_project_digest: input.afterProject ? projectDigest(input.afterProject) : null,
50835
+ accepted_receipt_id: input.acceptedReceiptId ?? null,
50836
+ before_link: beforeLink,
50837
+ after_link: afterLink,
50838
+ before_project_revision: input.beforeProject?.updated_at ?? null,
50839
+ before_project_digest: input.beforeProject ? projectDigest(input.beforeProject) : null,
50840
+ after_project_revision: input.afterProject?.updated_at ?? null,
50841
+ after_project_digest: input.afterProject ? projectDigest(input.afterProject) : null
50842
+ };
50843
+ return {
50844
+ receipt_id: `mmpl_${digest(logical).slice(0, 40)}`,
50845
+ ...logical,
50846
+ created_at: now()
50847
+ };
50848
+ }
50849
+ function sameSnapshot(memory, expected) {
50850
+ return canonicalJson(snapshot(memory)) === canonicalJson(expected);
50851
+ }
50852
+ function assertProjectSnapshot(project, revision, expectedDigest) {
50853
+ if (!revision && !expectedDigest) {
50854
+ if (project) {
50855
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_ACCEPTED_TARGET_DRIFTED", "receipt expected no linked project but a project row was resolved");
50856
+ }
50857
+ return;
50858
+ }
50859
+ if (!project || project.updated_at !== revision || projectDigest(project) !== expectedDigest) {
50860
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_STALE_PROJECT", "Project no longer matches the immutable memory-link receipt", { expected_project_revision: revision, current_project_revision: project?.updated_at ?? null });
50861
+ }
50862
+ }
50863
+ function replayResult(db, receipt, requestDigest, memoryId) {
50864
+ if (receipt.request_digest !== requestDigest || receipt.target_memory_id !== memoryId) {
50865
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_IDEMPOTENCY_MISMATCH", "caller idempotency key is already bound to a different memory project-link request");
50866
+ }
50867
+ const memory = getMemoryByExactId(memoryId, db);
50868
+ if (!memory || !sameSnapshot(memory, receipt.after_link)) {
50869
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_ACCEPTED_TARGET_DRIFTED", "accepted memory project-link target drifted after its immutable receipt");
50870
+ }
50871
+ const project = receipt.after_link.project_id ? getProjectByExactId(receipt.after_link.project_id, db) : null;
50872
+ assertProjectSnapshot(project, receipt.after_project_revision, receipt.after_project_digest);
50873
+ return {
50874
+ dry_run: false,
50875
+ applied: receipt.outcome === "accepted",
50876
+ no_change: receipt.outcome === "no_change",
50877
+ memory,
50878
+ project,
50879
+ receipt
50880
+ };
50881
+ }
50882
+ function previewMemoryProjectLink(memoryId, request, db) {
50883
+ assertForwardRequest(request);
50884
+ assertBoundedIdentifier(memoryId, "memory_id");
50885
+ if (!db && isApiMode()) {
50886
+ const { data } = apiJson("POST", `/memories/${encodeURIComponent(memoryId)}/guarded-project-link`, { ...request, dry_run: true });
50887
+ return data;
50888
+ }
50889
+ const d = db || getDatabase();
50890
+ const memory = getMemoryByExactId(memoryId, d);
50891
+ if (!memory) {
50892
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_MEMORY_NOT_FOUND", `Memory not found by exact stable ID: ${memoryId}`);
50893
+ }
50894
+ const project = getProjectByExactId(request.target_project_id, d);
50895
+ if (!project) {
50896
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_PROJECT_NOT_FOUND", `Project not found by exact stable ID: ${request.target_project_id}`);
50897
+ }
50898
+ assertMemoryPrecondition(memory, request.expected_memory_version, request.expected_memory_revision);
50899
+ assertProjectPrecondition(project, request.expected_project_revision);
50900
+ const noChange = memory.project_id === project.id;
50901
+ if (!noChange)
50902
+ assertNoTargetBucketCollision(memory, project.id, d);
50903
+ return {
50904
+ dry_run: true,
50905
+ applied: false,
50906
+ no_change: noChange,
50907
+ memory: noChange ? memory : { ...memory, project_id: project.id },
50908
+ project,
50909
+ receipt: null
50910
+ };
50911
+ }
50912
+ function applyMemoryProjectLink(memoryId, request, db) {
50913
+ assertForwardRequest(request);
50914
+ assertBoundedIdentifier(memoryId, "memory_id");
50915
+ if (!db && isApiMode()) {
50916
+ const { data } = apiJson("POST", `/memories/${encodeURIComponent(memoryId)}/guarded-project-link`, { ...request, dry_run: false });
50917
+ return data;
50918
+ }
50919
+ const d = db || getDatabase();
50920
+ const requestDigest = forwardRequestDigest(memoryId, request);
50921
+ return d.transaction(() => {
50922
+ const prior = findReceiptByKey(d, request, "forward", request.idempotency_key);
50923
+ if (prior)
50924
+ return replayResult(d, prior, requestDigest, memoryId);
50925
+ const before = getMemoryByExactId(memoryId, d, true);
50926
+ if (!before) {
50927
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_MEMORY_NOT_FOUND", `Memory not found by exact stable ID: ${memoryId}`);
50928
+ }
50929
+ const committedPrior = findReceiptByKey(d, request, "forward", request.idempotency_key);
50930
+ if (committedPrior)
50931
+ return replayResult(d, committedPrior, requestDigest, memoryId);
50932
+ assertMemoryPrecondition(before, request.expected_memory_version, request.expected_memory_revision);
50933
+ const projects = lockProjects([before.project_id, request.target_project_id], d);
50934
+ const targetProject = projects.get(request.target_project_id);
50935
+ const beforeProject = before.project_id ? projects.get(before.project_id) : null;
50936
+ assertProjectPrecondition(targetProject, request.expected_project_revision);
50937
+ const noChange = before.project_id === request.target_project_id;
50938
+ if (noChange) {
50939
+ const receipt2 = makeReceipt({
50940
+ request,
50941
+ direction: "forward",
50942
+ requestDigest,
50943
+ outcome: "no_change",
50944
+ targetMemoryId: memoryId,
50945
+ requestedProjectId: request.target_project_id,
50946
+ expectedProjectRevision: request.expected_project_revision,
50947
+ beforeMemory: before,
50948
+ afterMemory: before,
50949
+ beforeProject,
50950
+ afterProject: targetProject
50951
+ });
50952
+ insertReceipt(d, receipt2);
50953
+ return {
50954
+ dry_run: false,
50955
+ applied: false,
50956
+ no_change: true,
50957
+ memory: before,
50958
+ project: targetProject,
50959
+ receipt: receipt2
50960
+ };
50961
+ }
50962
+ assertNoTargetBucketCollision(before, targetProject.id, d);
50963
+ const revision = nextRevision(before.updated_at);
50964
+ const result = d.run(`
50965
+ UPDATE memories
50966
+ SET project_id = ?, updated_at = ?
50967
+ WHERE id = ? AND version = ? AND updated_at = ?
50968
+ AND COALESCE(project_id, '') = COALESCE(?, '')
50969
+ `, [
50970
+ targetProject.id,
50971
+ revision,
50972
+ memoryId,
50973
+ before.version,
50974
+ before.updated_at,
50975
+ before.project_id
50976
+ ]);
50977
+ if (result.changes === 0) {
50978
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_STALE_MEMORY", "Memory project-link compare-and-swap did not update exactly one row");
50979
+ }
50980
+ const after = getMemoryByExactId(memoryId, d);
50981
+ const expectedAfter = { ...before, project_id: targetProject.id, updated_at: revision };
50982
+ if (!after || canonicalJson(memoryMutationState(after)) !== canonicalJson(memoryMutationState(expectedAfter))) {
50983
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_ACCEPTED_TARGET_DRIFTED", "Memory project link did not read back exactly under the stable ID");
50984
+ }
50985
+ const receipt = makeReceipt({
50986
+ request,
50987
+ direction: "forward",
50988
+ requestDigest,
50989
+ outcome: "accepted",
50990
+ targetMemoryId: memoryId,
50991
+ requestedProjectId: request.target_project_id,
50992
+ expectedProjectRevision: request.expected_project_revision,
50993
+ beforeMemory: before,
50994
+ afterMemory: after,
50995
+ beforeProject,
50996
+ afterProject: targetProject
50997
+ });
50998
+ insertReceipt(d, receipt);
50999
+ return {
51000
+ dry_run: false,
51001
+ applied: true,
51002
+ no_change: false,
51003
+ memory: after,
51004
+ project: targetProject,
51005
+ receipt
51006
+ };
51007
+ });
51008
+ }
51009
+ function rollbackMemoryProjectLink(memoryId, request, db) {
51010
+ assertRollbackRequest(request);
51011
+ assertBoundedIdentifier(memoryId, "memory_id");
51012
+ if (!db && isApiMode()) {
51013
+ const { data } = apiJson("POST", `/memories/${encodeURIComponent(memoryId)}/guarded-project-link-rollback`, request);
51014
+ return data;
51015
+ }
51016
+ const d = db || getDatabase();
51017
+ const requestDigest = rollbackRequestDigest(memoryId, request);
51018
+ return d.transaction(() => {
51019
+ const prior = findReceiptByKey(d, request, "rollback", request.idempotency_key);
51020
+ if (prior)
51021
+ return replayResult(d, prior, requestDigest, memoryId);
51022
+ const accepted = findReceiptById(d, request, request.accepted_receipt_id);
51023
+ if (!accepted || accepted.direction !== "forward" || accepted.target_memory_id !== memoryId) {
51024
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_RECEIPT_NOT_FOUND", "accepted forward link receipt was not found for this exact memory");
51025
+ }
51026
+ if (accepted.outcome !== "accepted") {
51027
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_RECEIPT_NOT_ROLLBACKABLE", "a no-change memory project-link receipt has no mutation to roll back");
51028
+ }
51029
+ const current = getMemoryByExactId(memoryId, d, true);
51030
+ if (!current) {
51031
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_MEMORY_NOT_FOUND", `Memory not found by exact stable ID: ${memoryId}`);
51032
+ }
51033
+ const committedPrior = findReceiptByKey(d, request, "rollback", request.idempotency_key);
51034
+ if (committedPrior)
51035
+ return replayResult(d, committedPrior, requestDigest, memoryId);
51036
+ assertMemoryPrecondition(current, request.expected_memory_version, request.expected_memory_revision);
51037
+ if (!sameSnapshot(current, accepted.after_link)) {
51038
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_STALE_MEMORY", "Memory no longer matches the accepted forward link receipt");
51039
+ }
51040
+ const projects = lockProjects([accepted.after_link.project_id, accepted.before_link.project_id], d);
51041
+ const beforeProject = accepted.after_link.project_id ? projects.get(accepted.after_link.project_id) : null;
51042
+ const afterProject = accepted.before_link.project_id ? projects.get(accepted.before_link.project_id) : null;
51043
+ assertProjectSnapshot(beforeProject, accepted.after_project_revision, accepted.after_project_digest);
51044
+ assertProjectSnapshot(afterProject, accepted.before_project_revision, accepted.before_project_digest);
51045
+ assertNoTargetBucketCollision(current, accepted.before_link.project_id, d);
51046
+ const result = d.run(`
51047
+ UPDATE memories
51048
+ SET project_id = ?, updated_at = ?
51049
+ WHERE id = ? AND version = ? AND updated_at = ?
51050
+ AND COALESCE(project_id, '') = COALESCE(?, '')
51051
+ `, [
51052
+ accepted.before_link.project_id,
51053
+ accepted.before_link.memory_revision,
51054
+ memoryId,
51055
+ current.version,
51056
+ current.updated_at,
51057
+ current.project_id
51058
+ ]);
51059
+ if (result.changes === 0) {
51060
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_STALE_MEMORY", "Memory project-link rollback compare-and-swap did not update exactly one row");
51061
+ }
51062
+ const restored = getMemoryByExactId(memoryId, d);
51063
+ if (!restored || !sameSnapshot(restored, accepted.before_link)) {
51064
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_ACCEPTED_TARGET_DRIFTED", "Memory project-link rollback did not restore the exact prior linkage");
51065
+ }
51066
+ const receipt = makeReceipt({
51067
+ request,
51068
+ direction: "rollback",
51069
+ requestDigest,
51070
+ outcome: "accepted",
51071
+ targetMemoryId: memoryId,
51072
+ requestedProjectId: accepted.requested_project_id,
51073
+ expectedProjectRevision: null,
51074
+ beforeMemory: current,
51075
+ afterMemory: restored,
51076
+ beforeProject,
51077
+ afterProject,
51078
+ acceptedReceiptId: accepted.receipt_id
51079
+ });
51080
+ insertReceipt(d, receipt);
51081
+ return {
51082
+ dry_run: false,
51083
+ applied: true,
51084
+ no_change: false,
51085
+ memory: restored,
51086
+ project: afterProject,
51087
+ receipt
51088
+ };
51089
+ });
51090
+ }
51091
+ function getMemoryProjectLinkReceipt(memoryId, receiptId, identity = LINK_AUTHORITY, db) {
51092
+ assertIdentity(identity);
51093
+ assertBoundedIdentifier(memoryId, "memory_id");
51094
+ assertBoundedIdentifier(receiptId, "receipt_id");
51095
+ if (!db && isApiMode()) {
51096
+ const { data } = apiJson("POST", `/memories/${encodeURIComponent(memoryId)}/project-link-receipts/lookup`, { ...identity, receipt_id: receiptId });
51097
+ return data;
51098
+ }
51099
+ const d = db || getDatabase();
51100
+ const receipt = findReceiptById(d, identity, receiptId);
51101
+ if (!receipt || receipt.target_memory_id !== memoryId) {
51102
+ throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_RECEIPT_NOT_FOUND", "immutable memory project-link receipt was not found for this exact memory");
51103
+ }
51104
+ return receipt;
51105
+ }
51106
+ // src/memory-project-link/index.ts
51107
+ init_schema();
50027
51108
  // src/db/agents.ts
50028
51109
  init_database();
50029
51110
  init_api_mode();
@@ -50471,7 +51552,27 @@ function focusFilterSQL(agentId, projectId) {
50471
51552
  // src/db/projects.ts
50472
51553
  init_database();
50473
51554
  init_api_mode();
50474
- function parseProjectRow(row) {
51555
+ import { createHash as createHash2 } from "crypto";
51556
+
51557
+ // src/project-registration/types.ts
51558
+ var MEMENTOS_PROJECT_REGISTRATION_ROUTE = "mementos.project-registration.v1";
51559
+ var MEMENTOS_PROJECT_REGISTRATION_CALLER_ROUTE = "projects.full-registration.v1";
51560
+ var MEMENTOS_PROJECT_REGISTRATION_SCHEMA_VERSION = 1;
51561
+ var MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE = "mementos.project-guarded-update.v1";
51562
+
51563
+ class MementosProjectRegistrationError extends Error {
51564
+ code;
51565
+ details;
51566
+ constructor(code, message, details = {}) {
51567
+ super(message);
51568
+ this.code = code;
51569
+ this.details = details;
51570
+ this.name = "MementosProjectRegistrationError";
51571
+ }
51572
+ }
51573
+
51574
+ // src/db/projects.ts
51575
+ function parseProjectRow2(row) {
50475
51576
  return {
50476
51577
  id: row["id"],
50477
51578
  name: row["name"],
@@ -50482,6 +51583,241 @@ function parseProjectRow(row) {
50482
51583
  updated_at: row["updated_at"]
50483
51584
  };
50484
51585
  }
51586
+
51587
+ class ProjectCollisionError extends Error {
51588
+ field;
51589
+ value;
51590
+ constructor(field, value) {
51591
+ super(`Project ${field} already exists: ${value}`);
51592
+ this.field = field;
51593
+ this.value = value;
51594
+ this.name = "ProjectCollisionError";
51595
+ }
51596
+ }
51597
+
51598
+ class ProjectGuardedUpdateError extends Error {
51599
+ code;
51600
+ details;
51601
+ constructor(code, message, details = {}) {
51602
+ super(message);
51603
+ this.code = code;
51604
+ this.details = details;
51605
+ this.name = "ProjectGuardedUpdateError";
51606
+ }
51607
+ }
51608
+ var PROJECT_UPDATE_AUTHORITY = {
51609
+ authority_id: "mementos",
51610
+ tenant_id: "default",
51611
+ corpus_id: "default"
51612
+ };
51613
+ var BOUNDED_IDENTIFIER2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
51614
+ function canonicalizeProjectUpdateValue(value) {
51615
+ if (Array.isArray(value))
51616
+ return value.map(canonicalizeProjectUpdateValue);
51617
+ if (!value || typeof value !== "object")
51618
+ return value;
51619
+ const output = {};
51620
+ for (const key of Object.keys(value).sort()) {
51621
+ const item = value[key];
51622
+ if (item !== undefined)
51623
+ output[key] = canonicalizeProjectUpdateValue(item);
51624
+ }
51625
+ return output;
51626
+ }
51627
+ function canonicalProjectUpdateJson(value) {
51628
+ return JSON.stringify(canonicalizeProjectUpdateValue(value));
51629
+ }
51630
+ function digestProjectUpdateValue(value) {
51631
+ return createHash2("sha256").update(canonicalProjectUpdateJson(value)).digest("hex");
51632
+ }
51633
+ function timestampString2(value) {
51634
+ return value instanceof Date ? value.toISOString() : String(value);
51635
+ }
51636
+ function parseProjectJson(value) {
51637
+ const parsed = typeof value === "string" ? JSON.parse(value) : value;
51638
+ return parsed;
51639
+ }
51640
+ function projectUpdateReceiptFromRow(row) {
51641
+ return {
51642
+ receipt_id: String(row["receipt_id"]),
51643
+ authority: "mementos",
51644
+ route: MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
51645
+ package_version: String(row["package_version"]),
51646
+ authority_id: String(row["authority_id"]),
51647
+ tenant_id: String(row["tenant_id"]),
51648
+ corpus_id: String(row["corpus_id"]),
51649
+ operation_id: String(row["operation_id"]),
51650
+ step_id: String(row["step_id"]),
51651
+ direction: row["direction"],
51652
+ idempotency_key: String(row["idempotency_key"]),
51653
+ request_digest: String(row["request_digest"]),
51654
+ outcome: "accepted",
51655
+ target_id: String(row["target_id"]),
51656
+ expected_revision: timestampString2(row["expected_revision"]),
51657
+ result_revision: timestampString2(row["result_revision"]),
51658
+ result_digest: String(row["result_digest"]),
51659
+ accepted_receipt_id: row["accepted_receipt_id"] === null ? null : String(row["accepted_receipt_id"]),
51660
+ before_project: parseProjectJson(row["before_project_json"]),
51661
+ after_project: parseProjectJson(row["after_project_json"]),
51662
+ created_at: timestampString2(row["created_at"])
51663
+ };
51664
+ }
51665
+ function normalizeProjectUpdateInput(input) {
51666
+ const normalized = {};
51667
+ if (input.name !== undefined)
51668
+ normalized.name = input.name.trim();
51669
+ if (input.path !== undefined)
51670
+ normalized.path = input.path.trim();
51671
+ if (input.description !== undefined)
51672
+ normalized.description = input.description;
51673
+ if (input.memory_prefix !== undefined)
51674
+ normalized.memory_prefix = input.memory_prefix;
51675
+ if (Object.keys(normalized).length === 0) {
51676
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", "At least one project field must be provided");
51677
+ }
51678
+ if (normalized.name !== undefined && normalized.name.length === 0) {
51679
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", "Project name cannot be empty");
51680
+ }
51681
+ if (normalized.path !== undefined && normalized.path.length === 0) {
51682
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", "Project path cannot be empty");
51683
+ }
51684
+ return normalized;
51685
+ }
51686
+ function assertProjectUpdateIdentity(identity) {
51687
+ if (identity.authority_id !== PROJECT_UPDATE_AUTHORITY.authority_id || identity.tenant_id !== PROJECT_UPDATE_AUTHORITY.tenant_id || identity.corpus_id !== PROJECT_UPDATE_AUTHORITY.corpus_id) {
51688
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_AUTHORITY_MISMATCH", "guarded project update does not match this authority, tenant, and corpus");
51689
+ }
51690
+ }
51691
+ function assertBoundedIdentifier2(value, field) {
51692
+ if (!BOUNDED_IDENTIFIER2.test(value)) {
51693
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", `${field} must be an 8-128 character bounded identifier`);
51694
+ }
51695
+ }
51696
+ function assertProjectUpdateRequest(request) {
51697
+ assertProjectUpdateIdentity(request);
51698
+ assertBoundedIdentifier2(request.operation_id, "operation_id");
51699
+ assertBoundedIdentifier2(request.step_id, "step_id");
51700
+ assertBoundedIdentifier2(request.idempotency_key, "idempotency_key");
51701
+ if (!request.expected_revision || request.expected_revision.length > 128) {
51702
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", "expected_revision is required and must be bounded");
51703
+ }
51704
+ }
51705
+ function getProjectByExactId2(id, db) {
51706
+ const row = db.query("SELECT * FROM projects WHERE id = ? LIMIT 1").get(id);
51707
+ return row ? parseProjectRow2(row) : null;
51708
+ }
51709
+ function assertNoProjectCollision(id, input, db) {
51710
+ if (input.name !== undefined) {
51711
+ const collision = db.query("SELECT id FROM projects WHERE LOWER(name) = LOWER(?) AND id != ? LIMIT 1").get(input.name, id);
51712
+ if (collision) {
51713
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_COLLISION", `Project name already exists: ${input.name}`, { field: "name" });
51714
+ }
51715
+ }
51716
+ if (input.path !== undefined) {
51717
+ const collision = db.query("SELECT id FROM projects WHERE path = ? AND id != ? LIMIT 1").get(input.path, id);
51718
+ if (collision) {
51719
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_COLLISION", `Project path already exists: ${input.path}`, { field: "path" });
51720
+ }
51721
+ }
51722
+ }
51723
+ function nextProjectRevision(previous) {
51724
+ const candidate = now();
51725
+ const previousMs = Date.parse(previous);
51726
+ const candidateMs = Date.parse(candidate);
51727
+ if (Number.isFinite(previousMs) && Number.isFinite(candidateMs) && candidateMs <= previousMs) {
51728
+ return new Date(previousMs + 1).toISOString();
51729
+ }
51730
+ return candidate;
51731
+ }
51732
+ function projectWithUpdates(project, updates, revision) {
51733
+ return {
51734
+ ...project,
51735
+ ...updates.name !== undefined ? { name: updates.name } : {},
51736
+ ...updates.path !== undefined ? { path: updates.path } : {},
51737
+ ...updates.description !== undefined ? { description: updates.description } : {},
51738
+ ...updates.memory_prefix !== undefined ? { memory_prefix: updates.memory_prefix } : {},
51739
+ updated_at: revision
51740
+ };
51741
+ }
51742
+ function findProjectUpdateReceiptByKey(db, identity, direction, idempotencyKey) {
51743
+ const row = db.query(`
51744
+ SELECT * FROM mementos_project_update_receipts
51745
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
51746
+ AND direction = ? AND idempotency_key = ?
51747
+ LIMIT 1
51748
+ `).get(identity.authority_id, identity.tenant_id, identity.corpus_id, direction, idempotencyKey);
51749
+ return row ? projectUpdateReceiptFromRow(row) : null;
51750
+ }
51751
+ function findProjectUpdateReceiptById(db, identity, receiptId) {
51752
+ const row = db.query(`
51753
+ SELECT * FROM mementos_project_update_receipts
51754
+ WHERE receipt_id = ? AND authority_id = ? AND tenant_id = ? AND corpus_id = ?
51755
+ LIMIT 1
51756
+ `).get(receiptId, identity.authority_id, identity.tenant_id, identity.corpus_id);
51757
+ return row ? projectUpdateReceiptFromRow(row) : null;
51758
+ }
51759
+ function insertProjectUpdateReceipt(db, receipt) {
51760
+ db.run(`
51761
+ INSERT INTO mementos_project_update_receipts (
51762
+ receipt_id, authority, route, package_version, authority_id, tenant_id,
51763
+ corpus_id, operation_id, step_id, direction, idempotency_key,
51764
+ request_digest, outcome, target_id, expected_revision, result_revision,
51765
+ result_digest, accepted_receipt_id, before_project_json,
51766
+ after_project_json, created_at
51767
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
51768
+ `, [
51769
+ receipt.receipt_id,
51770
+ receipt.authority,
51771
+ receipt.route,
51772
+ receipt.package_version,
51773
+ receipt.authority_id,
51774
+ receipt.tenant_id,
51775
+ receipt.corpus_id,
51776
+ receipt.operation_id,
51777
+ receipt.step_id,
51778
+ receipt.direction,
51779
+ receipt.idempotency_key,
51780
+ receipt.request_digest,
51781
+ receipt.outcome,
51782
+ receipt.target_id,
51783
+ receipt.expected_revision,
51784
+ receipt.result_revision,
51785
+ receipt.result_digest,
51786
+ receipt.accepted_receipt_id,
51787
+ canonicalProjectUpdateJson(receipt.before_project),
51788
+ canonicalProjectUpdateJson(receipt.after_project),
51789
+ receipt.created_at
51790
+ ]);
51791
+ }
51792
+ function makeProjectUpdateReceipt(input) {
51793
+ const createdAt = now();
51794
+ const logical = {
51795
+ authority: "mementos",
51796
+ route: MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
51797
+ package_version: getMementosPackageVersion(),
51798
+ authority_id: input.request.authority_id,
51799
+ tenant_id: input.request.tenant_id,
51800
+ corpus_id: input.request.corpus_id,
51801
+ operation_id: input.request.operation_id,
51802
+ step_id: input.request.step_id,
51803
+ direction: input.direction,
51804
+ idempotency_key: input.request.idempotency_key,
51805
+ request_digest: input.request_digest,
51806
+ outcome: "accepted",
51807
+ target_id: input.target_id,
51808
+ expected_revision: input.request.expected_revision,
51809
+ result_revision: input.after_project.updated_at,
51810
+ result_digest: digestProjectUpdateValue(input.after_project),
51811
+ accepted_receipt_id: input.accepted_receipt_id ?? null,
51812
+ before_project: input.before_project,
51813
+ after_project: input.after_project,
51814
+ created_at: createdAt
51815
+ };
51816
+ return {
51817
+ receipt_id: `mpur_${digestProjectUpdateValue(logical).slice(0, 40)}`,
51818
+ ...logical
51819
+ };
51820
+ }
50485
51821
  function registerProject(name, path, description, memoryPrefix, db) {
50486
51822
  if (!db && isApiMode()) {
50487
51823
  const { data } = apiJson("POST", "/projects", {
@@ -50501,7 +51837,7 @@ function registerProject(name, path, description, memoryPrefix, db) {
50501
51837
  timestamp,
50502
51838
  existingId
50503
51839
  ]);
50504
- return parseProjectRow(existing);
51840
+ return parseProjectRow2(existing);
50505
51841
  }
50506
51842
  const id = uuid();
50507
51843
  d.run("INSERT INTO projects (id, name, path, description, memory_prefix, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)", [id, name, path, description || null, memoryPrefix || null, timestamp, timestamp]);
@@ -50517,13 +51853,13 @@ function getProject(idOrPath, db) {
50517
51853
  const d = db || getDatabase();
50518
51854
  let row = d.query("SELECT * FROM projects WHERE id = ?").get(idOrPath);
50519
51855
  if (row)
50520
- return parseProjectRow(row);
51856
+ return parseProjectRow2(row);
50521
51857
  row = d.query("SELECT * FROM projects WHERE path = ?").get(idOrPath);
50522
51858
  if (row)
50523
- return parseProjectRow(row);
51859
+ return parseProjectRow2(row);
50524
51860
  row = d.query("SELECT * FROM projects WHERE LOWER(name) = ?").get(idOrPath.toLowerCase());
50525
51861
  if (row)
50526
- return parseProjectRow(row);
51862
+ return parseProjectRow2(row);
50527
51863
  return null;
50528
51864
  }
50529
51865
  function listProjects(db) {
@@ -50533,7 +51869,1300 @@ function listProjects(db) {
50533
51869
  }
50534
51870
  const d = db || getDatabase();
50535
51871
  const rows = d.query("SELECT * FROM projects ORDER BY updated_at DESC").all();
50536
- return rows.map(parseProjectRow);
51872
+ return rows.map(parseProjectRow2);
51873
+ }
51874
+ function previewProjectUpdate(id, request, db) {
51875
+ assertProjectUpdateRequest(request);
51876
+ const normalized = normalizeProjectUpdateInput(request.updates);
51877
+ if (!db && isApiMode()) {
51878
+ const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-update`, { ...request, updates: normalized, dry_run: true });
51879
+ return data;
51880
+ }
51881
+ const d = db || getDatabase();
51882
+ const project = getProjectByExactId2(id, d);
51883
+ if (!project) {
51884
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_NOT_FOUND", `Project not found by exact stable ID: ${id}`);
51885
+ }
51886
+ if (project.updated_at !== request.expected_revision) {
51887
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_STALE_REVISION", "Project revision changed before the guarded update dry run", { expected_revision: request.expected_revision, current_revision: project.updated_at });
51888
+ }
51889
+ assertNoProjectCollision(id, normalized, d);
51890
+ return {
51891
+ dry_run: true,
51892
+ applied: false,
51893
+ project: projectWithUpdates(project, normalized, project.updated_at),
51894
+ receipt: null
51895
+ };
51896
+ }
51897
+ function applyProjectUpdate(id, request, db) {
51898
+ assertProjectUpdateRequest(request);
51899
+ const normalized = normalizeProjectUpdateInput(request.updates);
51900
+ if (!db && isApiMode()) {
51901
+ const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-update`, { ...request, updates: normalized, dry_run: false });
51902
+ return data;
51903
+ }
51904
+ const d = db || getDatabase();
51905
+ const requestDigest = digestProjectUpdateValue({
51906
+ ...request,
51907
+ target_id: id,
51908
+ direction: "forward",
51909
+ updates: normalized
51910
+ });
51911
+ return d.transaction(() => {
51912
+ const prior = findProjectUpdateReceiptByKey(d, request, "forward", request.idempotency_key);
51913
+ if (prior) {
51914
+ if (prior.request_digest !== requestDigest || prior.target_id !== id) {
51915
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_IDEMPOTENCY_MISMATCH", "caller idempotency key is already bound to a different request");
51916
+ }
51917
+ const current = getProjectByExactId2(id, d);
51918
+ if (!current || canonicalProjectUpdateJson(current) !== canonicalProjectUpdateJson(prior.after_project)) {
51919
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_ACCEPTED_TARGET_DRIFTED", "accepted guarded update target drifted after its immutable receipt");
51920
+ }
51921
+ return { dry_run: false, applied: true, project: prior.after_project, receipt: prior };
51922
+ }
51923
+ const before = getProjectByExactId2(id, d);
51924
+ if (!before) {
51925
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_NOT_FOUND", `Project not found by exact stable ID: ${id}`);
51926
+ }
51927
+ if (before.updated_at !== request.expected_revision) {
51928
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_STALE_REVISION", "Project revision changed before the guarded update", { expected_revision: request.expected_revision, current_revision: before.updated_at });
51929
+ }
51930
+ assertNoProjectCollision(id, normalized, d);
51931
+ const revision = nextProjectRevision(before.updated_at);
51932
+ const after = projectWithUpdates(before, normalized, revision);
51933
+ const result = d.run(`
51934
+ UPDATE projects
51935
+ SET name = ?, path = ?, description = ?, memory_prefix = ?, updated_at = ?
51936
+ WHERE id = ? AND updated_at = ?
51937
+ `, [
51938
+ after.name,
51939
+ after.path,
51940
+ after.description,
51941
+ after.memory_prefix,
51942
+ after.updated_at,
51943
+ id,
51944
+ request.expected_revision
51945
+ ]);
51946
+ if (result.changes !== 1) {
51947
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_STALE_REVISION", "Project compare-and-swap did not update exactly one row");
51948
+ }
51949
+ const readback = getProjectByExactId2(id, d);
51950
+ if (!readback || canonicalProjectUpdateJson(readback) !== canonicalProjectUpdateJson(after)) {
51951
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_ACCEPTED_TARGET_DRIFTED", "Project guarded update did not read back exactly under the stable ID");
51952
+ }
51953
+ const receipt = makeProjectUpdateReceipt({
51954
+ request: { ...request, updates: normalized },
51955
+ direction: "forward",
51956
+ request_digest: requestDigest,
51957
+ target_id: id,
51958
+ before_project: before,
51959
+ after_project: readback
51960
+ });
51961
+ insertProjectUpdateReceipt(d, receipt);
51962
+ return { dry_run: false, applied: true, project: readback, receipt };
51963
+ });
51964
+ }
51965
+ function rollbackProjectUpdate(id, request, db) {
51966
+ assertProjectUpdateRequest(request);
51967
+ assertBoundedIdentifier2(request.accepted_receipt_id, "accepted_receipt_id");
51968
+ if (!db && isApiMode()) {
51969
+ const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-rollback`, request);
51970
+ return data;
51971
+ }
51972
+ const d = db || getDatabase();
51973
+ const requestDigest = digestProjectUpdateValue({
51974
+ ...request,
51975
+ target_id: id,
51976
+ direction: "rollback"
51977
+ });
51978
+ return d.transaction(() => {
51979
+ const prior = findProjectUpdateReceiptByKey(d, request, "rollback", request.idempotency_key);
51980
+ if (prior) {
51981
+ if (prior.request_digest !== requestDigest || prior.target_id !== id) {
51982
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_IDEMPOTENCY_MISMATCH", "caller idempotency key is already bound to a different rollback request");
51983
+ }
51984
+ const current2 = getProjectByExactId2(id, d);
51985
+ if (!current2 || canonicalProjectUpdateJson(current2) !== canonicalProjectUpdateJson(prior.after_project)) {
51986
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_ACCEPTED_TARGET_DRIFTED", "accepted rollback target drifted after its immutable receipt");
51987
+ }
51988
+ return { dry_run: false, applied: true, project: prior.after_project, receipt: prior };
51989
+ }
51990
+ const accepted = findProjectUpdateReceiptById(d, request, request.accepted_receipt_id);
51991
+ if (!accepted || accepted.direction !== "forward" || accepted.target_id !== id) {
51992
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_RECEIPT_NOT_FOUND", "accepted forward update receipt was not found for this exact project");
51993
+ }
51994
+ const current = getProjectByExactId2(id, d);
51995
+ if (!current) {
51996
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_NOT_FOUND", `Project not found by exact stable ID: ${id}`);
51997
+ }
51998
+ if (current.updated_at !== request.expected_revision || canonicalProjectUpdateJson(current) !== canonicalProjectUpdateJson(accepted.after_project)) {
51999
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_STALE_REVISION", "Project no longer matches the accepted forward receipt", { expected_revision: request.expected_revision, current_revision: current.updated_at });
52000
+ }
52001
+ assertNoProjectCollision(id, accepted.before_project, d);
52002
+ const restored = accepted.before_project;
52003
+ const result = d.run(`
52004
+ UPDATE projects
52005
+ SET name = ?, path = ?, description = ?, memory_prefix = ?,
52006
+ created_at = ?, updated_at = ?
52007
+ WHERE id = ? AND updated_at = ?
52008
+ `, [
52009
+ restored.name,
52010
+ restored.path,
52011
+ restored.description,
52012
+ restored.memory_prefix,
52013
+ restored.created_at,
52014
+ restored.updated_at,
52015
+ id,
52016
+ request.expected_revision
52017
+ ]);
52018
+ if (result.changes !== 1) {
52019
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_STALE_REVISION", "Project rollback compare-and-swap did not update exactly one row");
52020
+ }
52021
+ const readback = getProjectByExactId2(id, d);
52022
+ if (!readback || canonicalProjectUpdateJson(readback) !== canonicalProjectUpdateJson(restored)) {
52023
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_ACCEPTED_TARGET_DRIFTED", "Project rollback did not restore the exact prior row");
52024
+ }
52025
+ const receipt = makeProjectUpdateReceipt({
52026
+ request,
52027
+ direction: "rollback",
52028
+ request_digest: requestDigest,
52029
+ target_id: id,
52030
+ before_project: current,
52031
+ after_project: readback,
52032
+ accepted_receipt_id: accepted.receipt_id
52033
+ });
52034
+ insertProjectUpdateReceipt(d, receipt);
52035
+ return { dry_run: false, applied: true, project: readback, receipt };
52036
+ });
52037
+ }
52038
+ function getProjectUpdateReceipt(id, receiptId, identity = PROJECT_UPDATE_AUTHORITY, db) {
52039
+ assertProjectUpdateIdentity(identity);
52040
+ if (!db && isApiMode()) {
52041
+ const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/update-receipts/lookup`, { ...identity, receipt_id: receiptId });
52042
+ return data;
52043
+ }
52044
+ const d = db || getDatabase();
52045
+ const receipt = findProjectUpdateReceiptById(d, identity, receiptId);
52046
+ if (!receipt || receipt.target_id !== id) {
52047
+ throw new ProjectGuardedUpdateError("PROJECT_UPDATE_RECEIPT_NOT_FOUND", "immutable project update receipt was not found for this exact project");
52048
+ }
52049
+ return receipt;
52050
+ }
52051
+ // src/project-registration/authority.ts
52052
+ import { createHash as createHash3 } from "crypto";
52053
+ import { resolve as resolve2 } from "path";
52054
+
52055
+ // src/project-registration/project-references.ts
52056
+ var MEMENTOS_PROJECT_REFERENCE_SURFACES = [
52057
+ { key: "memories", table: "memories", column: "project_id" },
52058
+ { key: "sessions", table: "sessions", column: "project_id" },
52059
+ { key: "entities", table: "entities", column: "project_id" },
52060
+ { key: "agents", table: "agents", column: "active_project_id" },
52061
+ { key: "tool_events", table: "tool_events", column: "project_id" },
52062
+ { key: "tasks", table: "tasks", column: "project_id" },
52063
+ {
52064
+ key: "memory_consolidation_runs",
52065
+ table: "memory_consolidation_runs",
52066
+ column: "project_id"
52067
+ },
52068
+ {
52069
+ key: "memory_reflection_runs",
52070
+ table: "memory_reflection_runs",
52071
+ column: "project_id"
52072
+ },
52073
+ { key: "memory_acl", table: "memory_acl", column: "project_id" },
52074
+ { key: "search_history", table: "search_history", column: "project_id" },
52075
+ {
52076
+ key: "session_memory_jobs",
52077
+ table: "session_memory_jobs",
52078
+ column: "project_id"
52079
+ },
52080
+ { key: "synthesis_events", table: "synthesis_events", column: "project_id" },
52081
+ { key: "synthesis_runs", table: "synthesis_runs", column: "project_id" },
52082
+ { key: "webhook_hooks", table: "webhook_hooks", column: "project_id" }
52083
+ ];
52084
+ function quotedIdentifier(value) {
52085
+ if (!/^[a-z_][a-z0-9_]*$/.test(value)) {
52086
+ throw new Error(`unsafe project-reference identifier: ${value}`);
52087
+ }
52088
+ return `"${value}"`;
52089
+ }
52090
+ function mementosProjectReferenceCounts(db, projectId) {
52091
+ const projections = MEMENTOS_PROJECT_REFERENCE_SURFACES.map(({ key, table, column }) => `(SELECT COUNT(*) FROM ${quotedIdentifier(table)} ` + `WHERE ${quotedIdentifier(column)} = ?) AS ${quotedIdentifier(key)}`).join(`,
52092
+ `);
52093
+ const row = db.get(`SELECT
52094
+ ${projections}`, ...MEMENTOS_PROJECT_REFERENCE_SURFACES.map(() => projectId));
52095
+ return Object.fromEntries(MEMENTOS_PROJECT_REFERENCE_SURFACES.map(({ key }) => [key, Number(row[key] ?? 0)]));
52096
+ }
52097
+ function hasMementosProjectReferences(counts) {
52098
+ return MEMENTOS_PROJECT_REFERENCE_SURFACES.some(({ key }) => counts[key] > 0);
52099
+ }
52100
+ function deleteMementosProjectIfUnreferenced(db, projectId) {
52101
+ const guards = MEMENTOS_PROJECT_REFERENCE_SURFACES.map(({ table, column }) => `NOT EXISTS (SELECT 1 FROM ${quotedIdentifier(table)} ` + `WHERE ${quotedIdentifier(column)} = ?)`).join(`
52102
+ AND `);
52103
+ const result = db.run(`DELETE FROM projects
52104
+ WHERE id = ?
52105
+ AND ${guards}`, projectId, ...MEMENTOS_PROJECT_REFERENCE_SURFACES.map(() => projectId));
52106
+ return result.changes;
52107
+ }
52108
+
52109
+ // src/project-registration/authority.ts
52110
+ var WORKSPACE_ID_PATTERN = /^wks_[A-Za-z0-9][A-Za-z0-9_-]{11,}$/;
52111
+ var OPERATION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
52112
+ var STEP_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{2,127}$/;
52113
+ var SHA256_PATTERN = /^[0-9a-f]{64}$/;
52114
+ var IDEMPOTENCY_PATTERN = /^prk_[0-9a-f]{48}$/;
52115
+ var PROJECT_ID_PATTERN = /^mm_project_[0-9a-f]{40}$/;
52116
+
52117
+ class WriteBoundaryError extends Error {
52118
+ point;
52119
+ cause;
52120
+ constructor(point, cause) {
52121
+ super(`Mementos project registration failed at ${point}`);
52122
+ this.point = point;
52123
+ this.cause = cause;
52124
+ }
52125
+ }
52126
+ function canonicalMementosProjectRegistrationJson(value) {
52127
+ return JSON.stringify(canonicalize2(value));
52128
+ }
52129
+ function canonicalize2(value) {
52130
+ if (Array.isArray(value))
52131
+ return value.map(canonicalize2);
52132
+ if (!value || typeof value !== "object")
52133
+ return value;
52134
+ const out = {};
52135
+ for (const key of Object.keys(value).sort()) {
52136
+ const item = value[key];
52137
+ if (item !== undefined)
52138
+ out[key] = canonicalize2(item);
52139
+ }
52140
+ return out;
52141
+ }
52142
+ function digestMementosProjectRegistrationValue(value) {
52143
+ return createHash3("sha256").update(canonicalMementosProjectRegistrationJson(value)).digest("hex");
52144
+ }
52145
+ function digestOwnedPath(path) {
52146
+ return createHash3("sha256").update(path).digest("hex");
52147
+ }
52148
+ function deriveMementosProjectRegistrationIdempotencyKey(input) {
52149
+ return `prk_${digestMementosProjectRegistrationValue({
52150
+ route: MEMENTOS_PROJECT_REGISTRATION_CALLER_ROUTE,
52151
+ operation_id: input.operation_id,
52152
+ step_id: input.step_id,
52153
+ direction: input.direction,
52154
+ target_selector: input.target_selector,
52155
+ request_digest: input.request_digest,
52156
+ precondition_digest: input.precondition_digest
52157
+ }).slice(0, 48)}`;
52158
+ }
52159
+ function responseBytes(value) {
52160
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
52161
+ }
52162
+ function assertBounds(bounds) {
52163
+ if (!Number.isSafeInteger(bounds.response_byte_limit) || bounds.response_byte_limit <= 0) {
52164
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_BOUNDS", "response_byte_limit must be a positive integer");
52165
+ }
52166
+ if (!Number.isSafeInteger(bounds.time_budget_ms) || bounds.time_budget_ms <= 0) {
52167
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_BOUNDS", "time_budget_ms must be a positive integer");
52168
+ }
52169
+ }
52170
+ function assertWithinBounds(value, bounds, startedAt) {
52171
+ const bytes = responseBytes(value);
52172
+ if (bytes > bounds.response_byte_limit) {
52173
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RESPONSE_TOO_LARGE", `registration response requires ${bytes} bytes but the bound is ${bounds.response_byte_limit}`, { response_bytes: bytes, response_byte_limit: bounds.response_byte_limit });
52174
+ }
52175
+ const elapsed = Date.now() - startedAt;
52176
+ if (elapsed > bounds.time_budget_ms) {
52177
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_TIME_BUDGET_EXCEEDED", `registration call took ${elapsed}ms but the bound is ${bounds.time_budget_ms}ms`, { elapsed_ms: elapsed, time_budget_ms: bounds.time_budget_ms });
52178
+ }
52179
+ return { response_bytes: bytes, elapsed_ms: elapsed };
52180
+ }
52181
+ function withResponseControl(receipt, bounds, startedAt) {
52182
+ const result = {
52183
+ receipt,
52184
+ response_control: {
52185
+ response_byte_limit: bounds.response_byte_limit,
52186
+ time_budget_ms: bounds.time_budget_ms,
52187
+ response_bytes: 0,
52188
+ elapsed_ms: 0,
52189
+ complete: true,
52190
+ truncated: false
52191
+ }
52192
+ };
52193
+ for (let attempt = 0;attempt < 8; attempt += 1) {
52194
+ const measured2 = assertWithinBounds(result, bounds, startedAt);
52195
+ const stable = result.response_control.response_bytes === measured2.response_bytes && result.response_control.elapsed_ms === measured2.elapsed_ms;
52196
+ result.response_control.response_bytes = measured2.response_bytes;
52197
+ result.response_control.elapsed_ms = measured2.elapsed_ms;
52198
+ if (stable)
52199
+ break;
52200
+ }
52201
+ const measured = assertWithinBounds(result, bounds, startedAt);
52202
+ result.response_control.response_bytes = measured.response_bytes;
52203
+ result.response_control.elapsed_ms = measured.elapsed_ms;
52204
+ return result;
52205
+ }
52206
+ function requireString(value, field, options = {}) {
52207
+ const min = options.min ?? 1;
52208
+ const max = options.max ?? 512;
52209
+ if (typeof value !== "string" || value.length < min || value.length > max || /[\u0000-\u001f]/.test(value) || options.pattern && !options.pattern.test(value)) {
52210
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", `${field} is not a valid bounded registration identifier`);
52211
+ }
52212
+ return value;
52213
+ }
52214
+ function exactKeys(value, expected, field) {
52215
+ const actual = Object.keys(value).sort();
52216
+ const wanted = [...expected].sort();
52217
+ if (actual.length !== wanted.length || actual.some((key, i) => key !== wanted[i])) {
52218
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", `${field} must contain exactly: ${wanted.join(", ")}`);
52219
+ }
52220
+ }
52221
+ function ownedPath(target) {
52222
+ if (!target || typeof target.withOwnedPath !== "function") {
52223
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "target must be a package-owned path handle");
52224
+ }
52225
+ const path = target.withOwnedPath((value) => value);
52226
+ requireString(path, "target path", { max: 4096 });
52227
+ if (path !== resolve2(path)) {
52228
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "target path must already be canonical and absolute");
52229
+ }
52230
+ return path;
52231
+ }
52232
+ function normalizedCallDigest(request) {
52233
+ return digestMementosProjectRegistrationValue({
52234
+ authority_route: request.authority_route,
52235
+ package_version: request.package_version,
52236
+ authority_id: request.authority_id,
52237
+ tenant_id: request.tenant_id,
52238
+ corpus_id: request.corpus_id,
52239
+ operation_id: request.operation_id,
52240
+ step_id: request.step_id,
52241
+ resource_kind: request.resource_kind,
52242
+ direction: request.direction,
52243
+ target_selector: request.target_selector,
52244
+ idempotency_key: request.idempotency_key,
52245
+ request_digest: request.request_digest,
52246
+ precondition_digest: request.precondition_digest,
52247
+ project_id: request.project_id,
52248
+ project_slug: request.project_slug,
52249
+ project_name: request.project_name,
52250
+ desired: request.desired,
52251
+ accepted_receipt_id: request.accepted_receipt?.receipt_id ?? null
52252
+ });
52253
+ }
52254
+ function publicReceipt(row) {
52255
+ const { target_selector: _selector, normalized_call_digest: _digest, ...receipt } = row;
52256
+ return receipt;
52257
+ }
52258
+ function timestampString3(value) {
52259
+ return value instanceof Date ? value.toISOString() : String(value);
52260
+ }
52261
+ function receiptFromRow2(row) {
52262
+ return {
52263
+ ...row,
52264
+ authority: "mementos",
52265
+ resource_kind: "project",
52266
+ created_by_operation: row["created_by_operation"] === true || Number(row["created_by_operation"]) === 1,
52267
+ created_at: timestampString3(row["created_at"])
52268
+ };
52269
+ }
52270
+ function bindingFromRow(row) {
52271
+ return {
52272
+ ...row,
52273
+ created_at: timestampString3(row["created_at"]),
52274
+ updated_at: timestampString3(row["updated_at"])
52275
+ };
52276
+ }
52277
+ function getStoredReceipt(db, receiptId) {
52278
+ const row = db.get("SELECT * FROM mementos_project_registration_receipts WHERE receipt_id = ? LIMIT 1", receiptId);
52279
+ return row ? receiptFromRow2(row) : null;
52280
+ }
52281
+ function getAcceptedReceipt(db, request) {
52282
+ const row = db.get(`
52283
+ SELECT * FROM mementos_project_registration_receipts
52284
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
52285
+ AND operation_id = ? AND step_id = ? AND resource_kind = 'project'
52286
+ AND direction = ? AND outcome = 'accepted'
52287
+ ORDER BY created_at ASC, receipt_id ASC
52288
+ LIMIT 1
52289
+ `, request.authority_id, request.tenant_id, request.corpus_id, request.operation_id, request.step_id, request.direction);
52290
+ return row ? receiptFromRow2(row) : null;
52291
+ }
52292
+ function getReceiptForLookup(db, request) {
52293
+ const row = db.get(`
52294
+ SELECT * FROM mementos_project_registration_receipts
52295
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
52296
+ AND operation_id = ? AND step_id = ? AND resource_kind = 'project'
52297
+ AND direction = ? AND idempotency_key = ? AND target_selector = ?
52298
+ ORDER BY CASE outcome
52299
+ WHEN 'terminal_nonacceptance' THEN 0
52300
+ WHEN 'duplicate_of_accepted' THEN 1
52301
+ ELSE 2
52302
+ END, created_at DESC, receipt_id DESC
52303
+ LIMIT 1
52304
+ `, request.authority_id, request.tenant_id, request.corpus_id, request.operation_id, request.step_id, request.direction, request.idempotency_key, request.target_selector);
52305
+ return row ? receiptFromRow2(row) : null;
52306
+ }
52307
+ function getBinding(db, capability, targetSelector) {
52308
+ const row = db.get(`
52309
+ SELECT * FROM mementos_project_registration_bindings
52310
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
52311
+ AND resource_kind = 'project' AND target_selector = ?
52312
+ LIMIT 1
52313
+ `, capability.authority_id, capability.tenant_id, capability.corpus_id, targetSelector);
52314
+ return row ? bindingFromRow(row) : null;
52315
+ }
52316
+ function getProjectByExactId3(db, id) {
52317
+ const row = db.get("SELECT * FROM projects WHERE id = ? LIMIT 1", id);
52318
+ if (!row)
52319
+ return null;
52320
+ return {
52321
+ id: String(row["id"]),
52322
+ name: String(row["name"]),
52323
+ path: String(row["path"]),
52324
+ description: row["description"] === null ? null : String(row["description"]),
52325
+ memory_prefix: row["memory_prefix"] === null ? null : String(row["memory_prefix"]),
52326
+ created_at: timestampString3(row["created_at"]),
52327
+ updated_at: timestampString3(row["updated_at"])
52328
+ };
52329
+ }
52330
+ function getProjectByPath(db, path) {
52331
+ const row = db.get("SELECT * FROM projects WHERE path = ? LIMIT 1", path);
52332
+ return row ? getProjectByExactId3(db, String(row["id"])) : null;
52333
+ }
52334
+ function projectRecord(db, project, references = mementosProjectReferenceCounts(db, project.id)) {
52335
+ return {
52336
+ target_id: project.id,
52337
+ revision: project.updated_at,
52338
+ digest: digestMementosProjectRegistrationValue({
52339
+ id: project.id,
52340
+ name: project.name,
52341
+ path: project.path,
52342
+ description: project.description,
52343
+ memory_prefix: project.memory_prefix,
52344
+ created_at: project.created_at,
52345
+ updated_at: project.updated_at,
52346
+ references
52347
+ })
52348
+ };
52349
+ }
52350
+ function targetId(capability, selector) {
52351
+ return `mm_project_${digestMementosProjectRegistrationValue({
52352
+ authority_id: capability.authority_id,
52353
+ tenant_id: capability.tenant_id,
52354
+ corpus_id: capability.corpus_id,
52355
+ selector
52356
+ }).slice(0, 40)}`;
52357
+ }
52358
+ function receiptId(input) {
52359
+ return `mmpr_${digestMementosProjectRegistrationValue(input).slice(0, 40)}`;
52360
+ }
52361
+ function makeReceipt2(request, capability, callDigest, now2, values) {
52362
+ const withoutId = {
52363
+ authority: "mementos",
52364
+ route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
52365
+ package_version: capability.package_version,
52366
+ authority_id: capability.authority_id,
52367
+ tenant_id: capability.tenant_id,
52368
+ corpus_id: capability.corpus_id,
52369
+ operation_id: request.operation_id,
52370
+ step_id: request.step_id,
52371
+ resource_kind: "project",
52372
+ direction: request.direction,
52373
+ target_selector: values.target_selector ?? request.target_selector,
52374
+ idempotency_key: request.idempotency_key,
52375
+ request_digest: request.request_digest,
52376
+ precondition_digest: request.precondition_digest,
52377
+ normalized_call_digest: callDigest,
52378
+ outcome: values.outcome,
52379
+ reason: values.reason ?? null,
52380
+ target_id: values.target_id ?? null,
52381
+ result_revision: values.result_revision ?? null,
52382
+ result_digest: values.result_digest ?? null,
52383
+ duplicate_of_receipt_id: values.duplicate_of_receipt_id ?? null,
52384
+ accepted_receipt_id: values.accepted_receipt_id ?? null,
52385
+ created_by_operation: values.created_by_operation ?? false
52386
+ };
52387
+ return {
52388
+ receipt_id: receiptId(withoutId),
52389
+ ...withoutId,
52390
+ created_at: now2
52391
+ };
52392
+ }
52393
+ function insertReceipt2(db, receipt) {
52394
+ db.run(`
52395
+ INSERT INTO mementos_project_registration_receipts (
52396
+ receipt_id, authority, route, package_version, authority_id, tenant_id,
52397
+ corpus_id, operation_id, step_id, resource_kind, direction,
52398
+ target_selector, idempotency_key, request_digest, precondition_digest,
52399
+ normalized_call_digest, outcome, reason, target_id, result_revision,
52400
+ result_digest, duplicate_of_receipt_id, accepted_receipt_id,
52401
+ created_by_operation, created_at
52402
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
52403
+ ON CONFLICT DO NOTHING
52404
+ `, receipt.receipt_id, receipt.authority, receipt.route, receipt.package_version, receipt.authority_id, receipt.tenant_id, receipt.corpus_id, receipt.operation_id, receipt.step_id, receipt.resource_kind, receipt.direction, receipt.target_selector, receipt.idempotency_key, receipt.request_digest, receipt.precondition_digest, receipt.normalized_call_digest, receipt.outcome, receipt.reason, receipt.target_id, receipt.result_revision, receipt.result_digest, receipt.duplicate_of_receipt_id, receipt.accepted_receipt_id, receipt.created_by_operation, receipt.created_at);
52405
+ const stored = getStoredReceipt(db, receipt.receipt_id);
52406
+ const withoutCreatedAt = (value) => {
52407
+ const { created_at: _createdAt, ...logical } = value;
52408
+ return logical;
52409
+ };
52410
+ if (!stored || canonicalMementosProjectRegistrationJson(withoutCreatedAt(stored)) !== canonicalMementosProjectRegistrationJson(withoutCreatedAt(receipt))) {
52411
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "immutable receipt id resolved to different content");
52412
+ }
52413
+ return stored;
52414
+ }
52415
+ function insertBinding(db, request, callDigest, now2) {
52416
+ const result = db.run(`
52417
+ INSERT INTO mementos_project_registration_bindings (
52418
+ authority_id, tenant_id, corpus_id, resource_kind, target_selector,
52419
+ operation_id, step_id, direction, idempotency_key, request_digest,
52420
+ precondition_digest, normalized_call_digest, state, target_id,
52421
+ accepted_receipt_id, result_revision, result_digest, removed_receipt_id,
52422
+ created_at, updated_at
52423
+ ) VALUES (?, ?, ?, 'project', ?, ?, ?, 'forward', ?, ?, ?, ?, 'pending',
52424
+ NULL, NULL, NULL, NULL, NULL, ?, ?)
52425
+ ON CONFLICT DO NOTHING
52426
+ `, request.authority_id, request.tenant_id, request.corpus_id, request.target_selector, request.operation_id, request.step_id, request.idempotency_key, request.request_digest, request.precondition_digest, callDigest, now2, now2);
52427
+ return result.changes === 1;
52428
+ }
52429
+ function lockBinding(db, capability, targetSelector) {
52430
+ const result = db.run(`
52431
+ UPDATE mementos_project_registration_bindings
52432
+ SET updated_at = updated_at
52433
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
52434
+ AND resource_kind = 'project' AND target_selector = ?
52435
+ `, capability.authority_id, capability.tenant_id, capability.corpus_id, targetSelector);
52436
+ return result.changes === 1;
52437
+ }
52438
+ function setBindingAccepted(db, request, receipt, now2) {
52439
+ const result = db.run(`
52440
+ UPDATE mementos_project_registration_bindings
52441
+ SET state = 'accepted', target_id = ?, accepted_receipt_id = ?,
52442
+ result_revision = ?, result_digest = ?, updated_at = ?
52443
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
52444
+ AND resource_kind = 'project' AND target_selector = ? AND state = 'pending'
52445
+ `, receipt.target_id, receipt.receipt_id, receipt.result_revision, receipt.result_digest, now2, request.authority_id, request.tenant_id, request.corpus_id, request.target_selector);
52446
+ if (result.changes !== 1) {
52447
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "registration binding was not pending at acceptance");
52448
+ }
52449
+ }
52450
+ function setBindingRemoved(db, accepted, inverseReceiptId, now2) {
52451
+ const result = db.run(`
52452
+ UPDATE mementos_project_registration_bindings
52453
+ SET state = 'removed', removed_receipt_id = ?, updated_at = ?
52454
+ WHERE authority_id = ? AND tenant_id = ? AND corpus_id = ?
52455
+ AND resource_kind = 'project' AND target_selector = ?
52456
+ AND state = 'accepted' AND accepted_receipt_id = ?
52457
+ `, inverseReceiptId, now2, accepted.authority_id, accepted.tenant_id, accepted.corpus_id, accepted.target_selector, accepted.receipt_id);
52458
+ if (result.changes !== 1) {
52459
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "registration binding was not accepted at inverse");
52460
+ }
52461
+ }
52462
+ function capabilityMatches(request, capability) {
52463
+ 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;
52464
+ }
52465
+ function assertCommonRequest(request, capability) {
52466
+ assertBounds(request);
52467
+ if (request.resource_kind !== "project") {
52468
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "resource_kind must be project");
52469
+ }
52470
+ if (request.direction !== "forward" && request.direction !== "inverse") {
52471
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "direction must be forward or inverse");
52472
+ }
52473
+ if (!capabilityMatches(request, capability)) {
52474
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH", "registration request does not match this authority capability identity");
52475
+ }
52476
+ requireString(request.operation_id, "operation_id", {
52477
+ min: 8,
52478
+ max: 128,
52479
+ pattern: OPERATION_PATTERN
52480
+ });
52481
+ requireString(request.step_id, "step_id", { min: 3, max: 128, pattern: STEP_PATTERN });
52482
+ requireString(request.target_selector, "target_selector", { max: 512 });
52483
+ requireString(request.project_id, "project_id", {
52484
+ min: 16,
52485
+ max: 128,
52486
+ pattern: WORKSPACE_ID_PATTERN
52487
+ });
52488
+ requireString(request.project_name, "project_name", { max: 256 });
52489
+ requireString(request.project_slug, "project_slug", { max: 128 });
52490
+ requireString(request.request_digest, "request_digest", {
52491
+ min: 64,
52492
+ max: 64,
52493
+ pattern: SHA256_PATTERN
52494
+ });
52495
+ requireString(request.precondition_digest, "precondition_digest", {
52496
+ min: 64,
52497
+ max: 64,
52498
+ pattern: SHA256_PATTERN
52499
+ });
52500
+ requireString(request.idempotency_key, "idempotency_key", {
52501
+ min: 52,
52502
+ max: 52,
52503
+ pattern: IDEMPOTENCY_PATTERN
52504
+ });
52505
+ if (!request.desired || typeof request.desired !== "object" || Array.isArray(request.desired)) {
52506
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "desired must be a JSON object");
52507
+ }
52508
+ if (digestMementosProjectRegistrationValue(request.desired) !== request.request_digest) {
52509
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_DIGEST_MISMATCH", "request_digest does not match the canonical desired payload");
52510
+ }
52511
+ const expectedKey = deriveMementosProjectRegistrationIdempotencyKey(request);
52512
+ if (request.idempotency_key !== expectedKey) {
52513
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_IDEMPOTENCY_MISMATCH", "idempotency_key does not match the deterministic request", { expected: expectedKey });
52514
+ }
52515
+ }
52516
+ function assertForwardRequest2(request, capability) {
52517
+ assertCommonRequest(request, capability);
52518
+ if (request.direction !== "forward" || request.accepted_receipt !== undefined) {
52519
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "conditional create requires a forward request without an accepted receipt");
52520
+ }
52521
+ exactKeys(request.desired, [
52522
+ "name",
52523
+ "source_project_id",
52524
+ "source_project_slug",
52525
+ "target_path_digest"
52526
+ ], "forward desired");
52527
+ if (request.target_selector !== request.project_id || request.desired["source_project_id"] !== request.project_id || request.desired["source_project_slug"] !== request.project_slug || request.desired["name"] !== request.project_name) {
52528
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "forward project identity fields disagree");
52529
+ }
52530
+ const expectedPrecondition = digestMementosProjectRegistrationValue({
52531
+ target_selector: request.target_selector,
52532
+ expected: "absent"
52533
+ });
52534
+ if (request.precondition_digest !== expectedPrecondition) {
52535
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_DIGEST_MISMATCH", "forward precondition must bind expected absence");
52536
+ }
52537
+ const path = ownedPath(request.target);
52538
+ if (request.desired["target_path_digest"] !== digestOwnedPath(path)) {
52539
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_DIGEST_MISMATCH", "target path does not match the package-owned digest");
52540
+ }
52541
+ return path;
52542
+ }
52543
+ function sameReceipt(left, right) {
52544
+ return canonicalMementosProjectRegistrationJson(publicReceipt(left)) === canonicalMementosProjectRegistrationJson(right);
52545
+ }
52546
+ function assertInverseRequest(request, capability) {
52547
+ assertCommonRequest(request, capability);
52548
+ if (request.direction !== "inverse" || !request.accepted_receipt) {
52549
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "conditional inverse requires the accepted forward receipt");
52550
+ }
52551
+ const accepted = request.accepted_receipt;
52552
+ if (accepted.authority !== "mementos" || accepted.route !== capability.route || accepted.package_version !== capability.package_version || accepted.authority_id !== capability.authority_id || accepted.tenant_id !== capability.tenant_id || accepted.corpus_id !== capability.corpus_id || accepted.operation_id !== request.operation_id || accepted.step_id !== request.step_id || accepted.resource_kind !== "project" || accepted.direction !== "forward" || accepted.outcome !== "accepted" || !accepted.created_by_operation || !accepted.target_id || !accepted.result_revision || !accepted.result_digest || request.target_selector !== accepted.target_id) {
52553
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "accepted receipt is not an exact attempt-created forward receipt");
52554
+ }
52555
+ exactKeys(request.desired, ["accepted_receipt_id", "target_id"], "inverse desired");
52556
+ if (request.desired["accepted_receipt_id"] !== accepted.receipt_id || request.desired["target_id"] !== accepted.target_id) {
52557
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_DIGEST_MISMATCH", "inverse desired payload does not bind the accepted receipt");
52558
+ }
52559
+ const expectedPrecondition = digestMementosProjectRegistrationValue({
52560
+ expected_revision: accepted.result_revision,
52561
+ expected_digest: accepted.result_digest
52562
+ });
52563
+ if (request.precondition_digest !== expectedPrecondition) {
52564
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_DIGEST_MISMATCH", "inverse precondition does not bind the accepted object state");
52565
+ }
52566
+ return accepted;
52567
+ }
52568
+ function assertLookup(request, capability) {
52569
+ assertBounds(request);
52570
+ if (request.max_items !== 1) {
52571
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_BOUNDS", "terminal receipt lookup requires max_items exactly 1");
52572
+ }
52573
+ if (request.authority !== "mementos" || request.resource_kind !== "project" || 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) {
52574
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH", "receipt lookup does not match this authority capability identity");
52575
+ }
52576
+ requireString(request.operation_id, "operation_id", { pattern: OPERATION_PATTERN });
52577
+ requireString(request.step_id, "step_id", { pattern: STEP_PATTERN });
52578
+ requireString(request.target_selector, "target_selector");
52579
+ requireString(request.idempotency_key, "idempotency_key", {
52580
+ min: 52,
52581
+ max: 52,
52582
+ pattern: IDEMPOTENCY_PATTERN
52583
+ });
52584
+ if (request.target_id !== undefined) {
52585
+ requireString(request.target_id, "target_id", {
52586
+ min: 51,
52587
+ max: 51,
52588
+ pattern: PROJECT_ID_PATTERN
52589
+ });
52590
+ }
52591
+ }
52592
+
52593
+ class PackageOwnedMementosProjectRegistrationAuthority {
52594
+ db;
52595
+ authority = "mementos";
52596
+ capabilityValue;
52597
+ now;
52598
+ faultInjector;
52599
+ constructor(db, options = {}) {
52600
+ this.db = db;
52601
+ this.now = options.now ?? (() => new Date().toISOString());
52602
+ this.faultInjector = options.faultInjector;
52603
+ this.capabilityValue = {
52604
+ authority: "mementos",
52605
+ route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
52606
+ package_version: options.packageVersion ?? getMementosPackageVersion(),
52607
+ authority_id: options.authorityId ?? "mementos",
52608
+ tenant_id: options.tenantId ?? "default",
52609
+ corpus_id: options.corpusId ?? "default",
52610
+ supported_resources: ["project"],
52611
+ conditional_create: true,
52612
+ immutable_receipts: true,
52613
+ exact_terminal_lookup: true,
52614
+ exact_readback: true,
52615
+ conditional_inverse: true,
52616
+ ambiguous_outcome_reconciliation: true,
52617
+ guarded_update: true,
52618
+ no_write_dry_run: true,
52619
+ expected_revision_compare_and_swap: true,
52620
+ caller_idempotency: true,
52621
+ exact_inverse_rollback: true
52622
+ };
52623
+ }
52624
+ fault(point, request) {
52625
+ this.faultInjector?.(point, {
52626
+ operation_id: request.operation_id,
52627
+ step_id: request.step_id,
52628
+ resource_kind: "project",
52629
+ direction: request.direction
52630
+ });
52631
+ }
52632
+ writeBoundary(point, request) {
52633
+ try {
52634
+ this.fault(point, request);
52635
+ } catch (cause) {
52636
+ throw new WriteBoundaryError(point, cause);
52637
+ }
52638
+ }
52639
+ terminal(request, callDigest, reason, values = {}) {
52640
+ return insertReceipt2(this.db, makeReceipt2(request, this.capabilityValue, callDigest, this.now(), {
52641
+ outcome: "terminal_nonacceptance",
52642
+ reason,
52643
+ target_id: values.target_id,
52644
+ accepted_receipt_id: values.accepted_receipt_id,
52645
+ target_selector: values.target_selector
52646
+ }));
52647
+ }
52648
+ duplicateForwardOrTerminal(request, callDigest, path, accepted) {
52649
+ if (accepted.normalized_call_digest !== callDigest) {
52650
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_IDEMPOTENCY_MISMATCH", "accepted operation/step identity is bound to a different request");
52651
+ }
52652
+ const project = accepted.target_id ? getProjectByExactId3(this.db, accepted.target_id) : null;
52653
+ if (!project || project.path !== path) {
52654
+ return this.terminal(request, callDigest, "accepted_target_missing_or_replaced", {
52655
+ target_id: accepted.target_id
52656
+ });
52657
+ }
52658
+ const record = projectRecord(this.db, project);
52659
+ if (record.revision !== accepted.result_revision || record.digest !== accepted.result_digest) {
52660
+ return this.terminal(request, callDigest, "accepted_target_drifted", {
52661
+ target_id: accepted.target_id
52662
+ });
52663
+ }
52664
+ return insertReceipt2(this.db, makeReceipt2(request, this.capabilityValue, callDigest, this.now(), {
52665
+ outcome: "duplicate_of_accepted",
52666
+ target_id: accepted.target_id,
52667
+ result_revision: accepted.result_revision,
52668
+ result_digest: accepted.result_digest,
52669
+ duplicate_of_receipt_id: accepted.receipt_id,
52670
+ created_by_operation: false
52671
+ }));
52672
+ }
52673
+ async capability() {
52674
+ return {
52675
+ ...this.capabilityValue,
52676
+ supported_resources: ["project"]
52677
+ };
52678
+ }
52679
+ async create(request) {
52680
+ const startedAt = Date.now();
52681
+ const path = assertForwardRequest2(request, this.capabilityValue);
52682
+ const callDigest = normalizedCallDigest(request);
52683
+ let stored;
52684
+ try {
52685
+ stored = this.db.transaction(() => {
52686
+ const exact = getReceiptForLookup(this.db, {
52687
+ ...request,
52688
+ authority: "mementos",
52689
+ max_items: 1
52690
+ });
52691
+ if (exact?.outcome === "terminal_nonacceptance")
52692
+ return exact;
52693
+ const accepted = getAcceptedReceipt(this.db, request);
52694
+ if (accepted) {
52695
+ return this.duplicateForwardOrTerminal(request, callDigest, path, accepted);
52696
+ }
52697
+ const existing = getProjectByPath(this.db, path) ?? getProjectByExactId3(this.db, targetId(this.capabilityValue, request.target_selector));
52698
+ if (existing) {
52699
+ return this.terminal(request, callDigest, "target_preexists", {
52700
+ target_id: existing.id
52701
+ });
52702
+ }
52703
+ const now2 = this.now();
52704
+ const insertedBinding = insertBinding(this.db, request, callDigest, now2);
52705
+ if (!lockBinding(this.db, this.capabilityValue, request.target_selector)) {
52706
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "registration binding disappeared before it could be locked");
52707
+ }
52708
+ const ownedBinding = getBinding(this.db, this.capabilityValue, request.target_selector);
52709
+ if (!ownedBinding || ownedBinding.normalized_call_digest !== callDigest) {
52710
+ return this.terminal(request, callDigest, "target_selector_preexists", {
52711
+ target_id: ownedBinding?.target_id
52712
+ });
52713
+ }
52714
+ const acceptedAfterBinding = getAcceptedReceipt(this.db, request);
52715
+ if (acceptedAfterBinding) {
52716
+ return this.duplicateForwardOrTerminal(request, callDigest, path, acceptedAfterBinding);
52717
+ }
52718
+ if (!insertedBinding || ownedBinding.state !== "pending") {
52719
+ return this.terminal(request, callDigest, "target_selector_preexists", {
52720
+ target_id: ownedBinding.target_id
52721
+ });
52722
+ }
52723
+ const id = targetId(this.capabilityValue, request.target_selector);
52724
+ this.writeBoundary("before_object_write", request);
52725
+ try {
52726
+ this.db.run(`
52727
+ INSERT INTO projects (
52728
+ id, name, path, description, memory_prefix, created_at, updated_at
52729
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
52730
+ `, id, request.project_name, path, null, request.project_slug, now2, now2);
52731
+ } catch (cause) {
52732
+ throw new WriteBoundaryError("before_object_write", cause);
52733
+ }
52734
+ this.writeBoundary("after_object_write", request);
52735
+ const project = getProjectByExactId3(this.db, id);
52736
+ if (!project || project.path !== path) {
52737
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "project write did not read back by its full id");
52738
+ }
52739
+ const record = projectRecord(this.db, project);
52740
+ const acceptedReceipt = makeReceipt2(request, this.capabilityValue, callDigest, now2, {
52741
+ outcome: "accepted",
52742
+ target_id: record.target_id,
52743
+ result_revision: record.revision,
52744
+ result_digest: record.digest,
52745
+ created_by_operation: true
52746
+ });
52747
+ this.writeBoundary("before_receipt_write", request);
52748
+ let inserted;
52749
+ try {
52750
+ inserted = insertReceipt2(this.db, acceptedReceipt);
52751
+ } catch (cause) {
52752
+ throw new WriteBoundaryError("before_receipt_write", cause);
52753
+ }
52754
+ this.writeBoundary("after_receipt_write", request);
52755
+ setBindingAccepted(this.db, request, inserted, now2);
52756
+ return inserted;
52757
+ });
52758
+ } catch (error) {
52759
+ if (!(error instanceof WriteBoundaryError))
52760
+ throw error;
52761
+ stored = this.db.transaction(() => this.terminal(request, callDigest, `write_failed:${error.point}`));
52762
+ }
52763
+ this.fault("after_commit", request);
52764
+ const receipt = publicReceipt(stored);
52765
+ assertWithinBounds(receipt, request, startedAt);
52766
+ return receipt;
52767
+ }
52768
+ async readExact(request) {
52769
+ const startedAt = Date.now();
52770
+ assertBounds(request);
52771
+ if (request.resource_kind !== "project") {
52772
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "resource_kind must be project");
52773
+ }
52774
+ requireString(request.target_id, "target_id", {
52775
+ min: 51,
52776
+ max: 51,
52777
+ pattern: PROJECT_ID_PATTERN
52778
+ });
52779
+ const path = ownedPath(request.target);
52780
+ const project = getProjectByExactId3(this.db, request.target_id);
52781
+ if (!project || project.path !== path) {
52782
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECORD_NOT_FOUND", "exact full-id project readback did not resolve the owned path");
52783
+ }
52784
+ const record = projectRecord(this.db, project);
52785
+ assertWithinBounds(record, request, startedAt);
52786
+ return record;
52787
+ }
52788
+ async lookupReceipt(request) {
52789
+ const startedAt = Date.now();
52790
+ assertLookup(request, this.capabilityValue);
52791
+ const receipt = getReceiptForLookup(this.db, request);
52792
+ if (!receipt || request.target_id !== undefined && receipt.target_id !== request.target_id) {
52793
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND", "exact immutable terminal receipt was not found");
52794
+ }
52795
+ return withResponseControl(publicReceipt(receipt), request, startedAt);
52796
+ }
52797
+ async compensate(request) {
52798
+ const startedAt = Date.now();
52799
+ const acceptedPublic = assertInverseRequest(request, this.capabilityValue);
52800
+ const callDigest = normalizedCallDigest(request);
52801
+ const storedAccepted = getStoredReceipt(this.db, acceptedPublic.receipt_id);
52802
+ if (!storedAccepted || !sameReceipt(storedAccepted, acceptedPublic)) {
52803
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_ACCEPTED_RECEIPT_NOT_FOUND", "accepted forward receipt is not stored immutably in this authority");
52804
+ }
52805
+ const path = ownedPath(request.target);
52806
+ let stored;
52807
+ try {
52808
+ stored = this.db.transaction(() => {
52809
+ const exact = getReceiptForLookup(this.db, {
52810
+ ...request,
52811
+ authority: "mementos",
52812
+ max_items: 1
52813
+ });
52814
+ if (exact?.outcome === "terminal_nonacceptance")
52815
+ return exact;
52816
+ if (!lockBinding(this.db, this.capabilityValue, storedAccepted.target_selector)) {
52817
+ return this.terminal(request, callDigest, "accepted_binding_missing", {
52818
+ target_id: storedAccepted.target_id,
52819
+ accepted_receipt_id: storedAccepted.receipt_id
52820
+ });
52821
+ }
52822
+ const binding = getBinding(this.db, this.capabilityValue, storedAccepted.target_selector);
52823
+ if (!binding || binding.accepted_receipt_id !== storedAccepted.receipt_id) {
52824
+ return this.terminal(request, callDigest, "accepted_binding_replaced", {
52825
+ target_id: storedAccepted.target_id,
52826
+ accepted_receipt_id: storedAccepted.receipt_id
52827
+ });
52828
+ }
52829
+ const prior = getAcceptedReceipt(this.db, request);
52830
+ if (prior) {
52831
+ if (prior.normalized_call_digest !== callDigest || prior.accepted_receipt_id !== storedAccepted.receipt_id) {
52832
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_IDEMPOTENCY_MISMATCH", "inverse operation/step identity is bound to a different request");
52833
+ }
52834
+ return insertReceipt2(this.db, makeReceipt2(request, this.capabilityValue, callDigest, this.now(), {
52835
+ outcome: "duplicate_of_accepted",
52836
+ target_id: prior.target_id,
52837
+ result_revision: prior.result_revision,
52838
+ result_digest: prior.result_digest,
52839
+ duplicate_of_receipt_id: prior.receipt_id,
52840
+ accepted_receipt_id: storedAccepted.receipt_id
52841
+ }));
52842
+ }
52843
+ if (binding.state !== "accepted") {
52844
+ return this.terminal(request, callDigest, "accepted_binding_not_active", {
52845
+ target_id: storedAccepted.target_id,
52846
+ accepted_receipt_id: storedAccepted.receipt_id
52847
+ });
52848
+ }
52849
+ const project = getProjectByExactId3(this.db, storedAccepted.target_id);
52850
+ if (!project) {
52851
+ return this.terminal(request, callDigest, "target_missing", {
52852
+ target_id: storedAccepted.target_id,
52853
+ accepted_receipt_id: storedAccepted.receipt_id
52854
+ });
52855
+ }
52856
+ if (project.path !== path) {
52857
+ return this.terminal(request, callDigest, "target_drifted", {
52858
+ target_id: storedAccepted.target_id,
52859
+ accepted_receipt_id: storedAccepted.receipt_id
52860
+ });
52861
+ }
52862
+ const references = mementosProjectReferenceCounts(this.db, project.id);
52863
+ if (hasMementosProjectReferences(references)) {
52864
+ return this.terminal(request, callDigest, "target_has_dependents", {
52865
+ target_id: storedAccepted.target_id,
52866
+ accepted_receipt_id: storedAccepted.receipt_id
52867
+ });
52868
+ }
52869
+ const current = projectRecord(this.db, project, references);
52870
+ if (current.revision !== storedAccepted.result_revision || current.digest !== storedAccepted.result_digest) {
52871
+ return this.terminal(request, callDigest, "target_drifted", {
52872
+ target_id: storedAccepted.target_id,
52873
+ accepted_receipt_id: storedAccepted.receipt_id
52874
+ });
52875
+ }
52876
+ this.writeBoundary("before_object_write", request);
52877
+ let deleted;
52878
+ try {
52879
+ deleted = deleteMementosProjectIfUnreferenced(this.db, storedAccepted.target_id);
52880
+ } catch (cause) {
52881
+ throw new WriteBoundaryError("before_object_write", cause);
52882
+ }
52883
+ if (deleted !== 1) {
52884
+ const remaining = getProjectByExactId3(this.db, storedAccepted.target_id);
52885
+ if (remaining && hasMementosProjectReferences(mementosProjectReferenceCounts(this.db, storedAccepted.target_id))) {
52886
+ return this.terminal(request, callDigest, "target_has_dependents", {
52887
+ target_id: storedAccepted.target_id,
52888
+ accepted_receipt_id: storedAccepted.receipt_id
52889
+ });
52890
+ }
52891
+ throw new WriteBoundaryError("before_object_write", new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "conditional inverse did not delete exactly one unreferenced project"));
52892
+ }
52893
+ this.writeBoundary("after_object_write", request);
52894
+ const inverseRecord = {
52895
+ target_id: storedAccepted.target_id,
52896
+ revision: "absent",
52897
+ digest: digestMementosProjectRegistrationValue({
52898
+ target_id: storedAccepted.target_id,
52899
+ accepted_receipt_id: storedAccepted.receipt_id,
52900
+ absent: true
52901
+ })
52902
+ };
52903
+ const inverseReceipt = makeReceipt2(request, this.capabilityValue, callDigest, this.now(), {
52904
+ outcome: "accepted",
52905
+ target_id: inverseRecord.target_id,
52906
+ result_revision: inverseRecord.revision,
52907
+ result_digest: inverseRecord.digest,
52908
+ accepted_receipt_id: storedAccepted.receipt_id,
52909
+ created_by_operation: false
52910
+ });
52911
+ this.writeBoundary("before_receipt_write", request);
52912
+ let inserted;
52913
+ try {
52914
+ inserted = insertReceipt2(this.db, inverseReceipt);
52915
+ } catch (cause) {
52916
+ throw new WriteBoundaryError("before_receipt_write", cause);
52917
+ }
52918
+ this.writeBoundary("after_receipt_write", request);
52919
+ setBindingRemoved(this.db, storedAccepted, inserted.receipt_id, this.now());
52920
+ return inserted;
52921
+ });
52922
+ } catch (error) {
52923
+ if (!(error instanceof WriteBoundaryError))
52924
+ throw error;
52925
+ stored = this.db.transaction(() => this.terminal(request, callDigest, `write_failed:${error.point}`, {
52926
+ target_id: storedAccepted.target_id,
52927
+ accepted_receipt_id: storedAccepted.receipt_id
52928
+ }));
52929
+ }
52930
+ this.fault("after_commit", request);
52931
+ const receipt = publicReceipt(stored);
52932
+ assertWithinBounds(receipt, request, startedAt);
52933
+ return receipt;
52934
+ }
52935
+ async verifyInverse(request) {
52936
+ const startedAt = Date.now();
52937
+ const accepted = assertInverseRequest(request, this.capabilityValue);
52938
+ const storedAccepted = getStoredReceipt(this.db, accepted.receipt_id);
52939
+ if (!storedAccepted || !sameReceipt(storedAccepted, accepted)) {
52940
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_ACCEPTED_RECEIPT_NOT_FOUND", "accepted forward receipt is not stored immutably in this authority");
52941
+ }
52942
+ const inverse = getAcceptedReceipt(this.db, request);
52943
+ if (!inverse || inverse.outcome !== "accepted" || inverse.accepted_receipt_id !== accepted.receipt_id || inverse.result_revision !== "absent" || !inverse.result_digest) {
52944
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND", "accepted conditional inverse receipt was not found");
52945
+ }
52946
+ if (getProjectByExactId3(this.db, accepted.target_id)) {
52947
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "inverse verification found the accepted target still present");
52948
+ }
52949
+ const verification = {
52950
+ target_id: accepted.target_id,
52951
+ accepted_receipt_id: accepted.receipt_id,
52952
+ absent: true,
52953
+ digest: digestMementosProjectRegistrationValue({
52954
+ target_id: accepted.target_id,
52955
+ accepted_receipt_id: accepted.receipt_id,
52956
+ absent: true
52957
+ })
52958
+ };
52959
+ assertWithinBounds(verification, request, startedAt);
52960
+ if (verification.digest !== inverse.result_digest) {
52961
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CONFLICT", "inverse verification digest does not match its immutable receipt");
52962
+ }
52963
+ return verification;
52964
+ }
52965
+ }
52966
+ function createMementosProjectRegistrationAuthority(db, options = {}) {
52967
+ return new PackageOwnedMementosProjectRegistrationAuthority(db, options);
52968
+ }
52969
+ var createLocalMementosProjectRegistrationAuthority = createMementosProjectRegistrationAuthority;
52970
+ // src/project-registration/http.ts
52971
+ var JSON_HEADERS = { "Content-Type": "application/json" };
52972
+
52973
+ class WirePathHandle {
52974
+ absolutePath;
52975
+ constructor(absolutePath) {
52976
+ this.absolutePath = absolutePath;
52977
+ }
52978
+ withOwnedPath(consumer) {
52979
+ return consumer(this.absolutePath);
52980
+ }
52981
+ }
52982
+ function json(body, status = 200) {
52983
+ return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
52984
+ }
52985
+ function errorStatus(error) {
52986
+ switch (error.code) {
52987
+ case "MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT":
52988
+ case "MEMENTOS_PROJECT_REGISTRATION_INVALID_BOUNDS":
52989
+ case "MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH":
52990
+ case "MEMENTOS_PROJECT_REGISTRATION_DIGEST_MISMATCH":
52991
+ case "MEMENTOS_PROJECT_REGISTRATION_IDEMPOTENCY_MISMATCH":
52992
+ case "MEMENTOS_PROJECT_REGISTRATION_EXACT_ID_REQUIRED":
52993
+ return 400;
52994
+ case "MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND":
52995
+ case "MEMENTOS_PROJECT_REGISTRATION_RECORD_NOT_FOUND":
52996
+ case "MEMENTOS_PROJECT_REGISTRATION_ACCEPTED_RECEIPT_NOT_FOUND":
52997
+ return 404;
52998
+ case "MEMENTOS_PROJECT_REGISTRATION_RESPONSE_TOO_LARGE":
52999
+ return 413;
53000
+ case "MEMENTOS_PROJECT_REGISTRATION_TIME_BUDGET_EXCEEDED":
53001
+ return 408;
53002
+ case "MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE":
53003
+ return 503;
53004
+ default:
53005
+ return 409;
53006
+ }
53007
+ }
53008
+ async function readJson(request) {
53009
+ try {
53010
+ const value = await request.json();
53011
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
53012
+ } catch {
53013
+ return null;
53014
+ }
53015
+ }
53016
+ function fromWireRequest(body) {
53017
+ const { canonical_path: canonicalPath, ...request } = body;
53018
+ if (typeof canonicalPath !== "string") {
53019
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "canonical_path is required on the private registration transport");
53020
+ }
53021
+ return {
53022
+ ...request,
53023
+ target: new WirePathHandle(canonicalPath)
53024
+ };
53025
+ }
53026
+ function fromWireReadRequest(body) {
53027
+ const { canonical_path: canonicalPath, ...request } = body;
53028
+ if (typeof canonicalPath !== "string") {
53029
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "canonical_path is required on the private exact-read transport");
53030
+ }
53031
+ return {
53032
+ ...request,
53033
+ target: new WirePathHandle(canonicalPath)
53034
+ };
53035
+ }
53036
+ async function handleMementosProjectRegistrationHttpRequest(request, url, authority, basePath = "/v1/project-registration") {
53037
+ const path = url.pathname;
53038
+ if (path !== basePath && !path.startsWith(`${basePath}/`))
53039
+ return null;
53040
+ const action = path.slice(basePath.length).split("/").filter(Boolean).join("/");
53041
+ const method = request.method.toUpperCase();
53042
+ try {
53043
+ if ((action === "" || action === "capability") && method === "GET") {
53044
+ return json({ capability: await authority.capability() });
53045
+ }
53046
+ if (method !== "POST")
53047
+ return json({ error: "method not allowed" }, 405);
53048
+ const body = await readJson(request);
53049
+ if (!body) {
53050
+ return json({
53051
+ error: "invalid JSON body",
53052
+ code: "MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT"
53053
+ }, 400);
53054
+ }
53055
+ if (action === "create") {
53056
+ return json({ receipt: await authority.create(fromWireRequest(body)) }, 201);
53057
+ }
53058
+ if (action === "receipts/lookup") {
53059
+ return json(await authority.lookupReceipt(body));
53060
+ }
53061
+ if (action === "read-exact") {
53062
+ return json({ record: await authority.readExact(fromWireReadRequest(body)) });
53063
+ }
53064
+ if (action === "compensate") {
53065
+ return json({ receipt: await authority.compensate(fromWireRequest(body)) }, 201);
53066
+ }
53067
+ if (action === "verify-inverse") {
53068
+ return json({ verification: await authority.verifyInverse(fromWireRequest(body)) });
53069
+ }
53070
+ return json({
53071
+ error: "unknown Mementos project-registration route",
53072
+ code: "MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND"
53073
+ }, 404);
53074
+ } catch (cause) {
53075
+ if (cause instanceof MementosProjectRegistrationError) {
53076
+ return json({
53077
+ error: cause.message,
53078
+ code: cause.code,
53079
+ details: cause.details,
53080
+ authoritative: true
53081
+ }, errorStatus(cause));
53082
+ }
53083
+ return json({
53084
+ error: cause instanceof Error ? cause.message : "internal registration error",
53085
+ code: "MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE"
53086
+ }, 500);
53087
+ }
53088
+ }
53089
+ function extractPath(target) {
53090
+ if (!target || typeof target.withOwnedPath !== "function") {
53091
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "target must be a package-owned path handle");
53092
+ }
53093
+ return target.withOwnedPath((absolutePath) => absolutePath);
53094
+ }
53095
+ function toWireRequest(request) {
53096
+ const { target, ...serializable } = request;
53097
+ return {
53098
+ ...serializable,
53099
+ canonical_path: extractPath(target)
53100
+ };
53101
+ }
53102
+
53103
+ class MementosProjectRegistrationHttpClient {
53104
+ authority = "mementos";
53105
+ baseUrl;
53106
+ fetchImpl;
53107
+ headers;
53108
+ constructor(options) {
53109
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
53110
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
53111
+ this.headers = {
53112
+ ...options.headers,
53113
+ ...options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {},
53114
+ "Content-Type": "application/json"
53115
+ };
53116
+ }
53117
+ async request(action, init = {}) {
53118
+ const response = await this.fetchImpl(`${this.baseUrl}/v1/project-registration${action}`, {
53119
+ ...init,
53120
+ headers: { ...this.headers, ...init.headers ?? {} }
53121
+ });
53122
+ let body;
53123
+ try {
53124
+ body = await response.json();
53125
+ } catch {
53126
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE", `Mementos project registration HTTP ${response.status} returned non-JSON`);
53127
+ }
53128
+ if (!response.ok) {
53129
+ throw new MementosProjectRegistrationError(typeof body["code"] === "string" ? body["code"] : "MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE", typeof body["error"] === "string" ? body["error"] : `Mementos project registration HTTP ${response.status}`, body["details"] && typeof body["details"] === "object" ? body["details"] : {});
53130
+ }
53131
+ return body;
53132
+ }
53133
+ async capability() {
53134
+ const body = await this.request("/capability");
53135
+ return body.capability;
53136
+ }
53137
+ async create(request) {
53138
+ const body = await this.request("/create", { method: "POST", body: JSON.stringify(toWireRequest(request)) });
53139
+ return body.receipt;
53140
+ }
53141
+ async readExact(request) {
53142
+ const { target, ...serializable } = request;
53143
+ const body = await this.request("/read-exact", {
53144
+ method: "POST",
53145
+ body: JSON.stringify({ ...serializable, canonical_path: extractPath(target) })
53146
+ });
53147
+ return body.record;
53148
+ }
53149
+ async lookupReceipt(request) {
53150
+ return this.request("/receipts/lookup", { method: "POST", body: JSON.stringify(request) });
53151
+ }
53152
+ async compensate(request) {
53153
+ const body = await this.request("/compensate", { method: "POST", body: JSON.stringify(toWireRequest(request)) });
53154
+ return body.receipt;
53155
+ }
53156
+ async verifyInverse(request) {
53157
+ const body = await this.request("/verify-inverse", {
53158
+ method: "POST",
53159
+ body: JSON.stringify(toWireRequest(request))
53160
+ });
53161
+ return body.verification;
53162
+ }
53163
+ }
53164
+ function createMementosProjectRegistrationHttpClient(options) {
53165
+ return new MementosProjectRegistrationHttpClient(options);
50537
53166
  }
50538
53167
  // src/db/machines.ts
50539
53168
  init_database();
@@ -50828,17 +53457,17 @@ function deleteEntity(id, db) {
50828
53457
  if (result.changes === 0)
50829
53458
  throw new EntityNotFoundError(id);
50830
53459
  }
50831
- function mergeEntities(sourceId, targetId, db) {
53460
+ function mergeEntities(sourceId, targetId2, db) {
50832
53461
  if (!db && isApiMode()) {
50833
53462
  const { data } = apiJson("POST", "/entities/merge", {
50834
53463
  source_id: sourceId,
50835
- target_id: targetId
53464
+ target_id: targetId2
50836
53465
  });
50837
53466
  return data;
50838
53467
  }
50839
53468
  const d = db || getDatabase();
50840
53469
  const src = getEntity(sourceId, d).id;
50841
- const tgt = getEntity(targetId, d).id;
53470
+ const tgt = getEntity(targetId2, d).id;
50842
53471
  d.run(`DELETE FROM relations
50843
53472
  WHERE source_entity_id = ?
50844
53473
  AND EXISTS (
@@ -51662,9 +54291,9 @@ function formatMementosProjectPanel(panel) {
51662
54291
  `);
51663
54292
  }
51664
54293
  // src/lib/config.ts
51665
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, readdirSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
54294
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
51666
54295
  import { homedir as homedir2 } from "os";
51667
- import { basename, dirname as dirname2, join as join4, resolve as resolve2 } from "path";
54296
+ import { basename, dirname as dirname3, join as join5, resolve as resolve3 } from "path";
51668
54297
  function isInMemoryDb2(path) {
51669
54298
  return path === ":memory:" || path.startsWith("file::memory:");
51670
54299
  }
@@ -51727,11 +54356,11 @@ function isValidCategory(value) {
51727
54356
  return VALID_CATEGORIES.includes(value);
51728
54357
  }
51729
54358
  function loadConfig() {
51730
- const configPath = join4(homeDir(), ".hasna", "mementos", "config.json");
54359
+ const configPath = join5(homeDir(), ".hasna", "mementos", "config.json");
51731
54360
  let fileConfig = {};
51732
54361
  if (existsSync3(configPath)) {
51733
54362
  try {
51734
- const raw = readFileSync2(configPath, "utf-8");
54363
+ const raw = readFileSync3(configPath, "utf-8");
51735
54364
  fileConfig = JSON.parse(raw);
51736
54365
  } catch {}
51737
54366
  }
@@ -51755,13 +54384,13 @@ function loadConfig() {
51755
54384
  }
51756
54385
  function findFileWalkingUp(filename) {
51757
54386
  let dir = process.cwd();
51758
- const legacyHomeMementosDb = resolve2(homeDir(), ".mementos", "mementos.db");
54387
+ const legacyHomeMementosDb = resolve3(homeDir(), ".mementos", "mementos.db");
51759
54388
  while (true) {
51760
- const candidate = join4(dir, filename);
51761
- if (existsSync3(candidate) && resolve2(candidate) !== legacyHomeMementosDb) {
54389
+ const candidate = join5(dir, filename);
54390
+ if (existsSync3(candidate) && resolve3(candidate) !== legacyHomeMementosDb) {
51762
54391
  return candidate;
51763
54392
  }
51764
- const parent = dirname2(dir);
54393
+ const parent = dirname3(dir);
51765
54394
  if (parent === dir) {
51766
54395
  return null;
51767
54396
  }
@@ -51771,10 +54400,10 @@ function findFileWalkingUp(filename) {
51771
54400
  function findGitRoot2() {
51772
54401
  let dir = process.cwd();
51773
54402
  while (true) {
51774
- if (existsSync3(join4(dir, ".git"))) {
54403
+ if (existsSync3(join5(dir, ".git"))) {
51775
54404
  return dir;
51776
54405
  }
51777
- const parent = dirname2(dir);
54406
+ const parent = dirname3(dir);
51778
54407
  if (parent === dir) {
51779
54408
  return null;
51780
54409
  }
@@ -51782,17 +54411,17 @@ function findGitRoot2() {
51782
54411
  }
51783
54412
  }
51784
54413
  function profilesDir() {
51785
- return join4(homeDir(), ".hasna", "mementos", "profiles");
54414
+ return join5(homeDir(), ".hasna", "mementos", "profiles");
51786
54415
  }
51787
54416
  function globalConfigPath() {
51788
- return join4(homeDir(), ".hasna", "mementos", "config.json");
54417
+ return join5(homeDir(), ".hasna", "mementos", "config.json");
51789
54418
  }
51790
54419
  function readGlobalConfig() {
51791
54420
  const p = globalConfigPath();
51792
54421
  if (!existsSync3(p))
51793
54422
  return {};
51794
54423
  try {
51795
- return JSON.parse(readFileSync2(p, "utf-8"));
54424
+ return JSON.parse(readFileSync3(p, "utf-8"));
51796
54425
  } catch {
51797
54426
  return {};
51798
54427
  }
@@ -51802,7 +54431,7 @@ function readGlobalConfigForWrite() {
51802
54431
  if (!existsSync3(p))
51803
54432
  return {};
51804
54433
  try {
51805
- const data = JSON.parse(readFileSync2(p, "utf-8"));
54434
+ const data = JSON.parse(readFileSync3(p, "utf-8"));
51806
54435
  if (data === null || typeof data !== "object" || Array.isArray(data)) {
51807
54436
  throw new Error("expected a JSON object");
51808
54437
  }
@@ -51814,7 +54443,7 @@ function readGlobalConfigForWrite() {
51814
54443
  }
51815
54444
  function writeGlobalConfig(data) {
51816
54445
  const p = globalConfigPath();
51817
- ensureDir2(dirname2(p));
54446
+ ensureDir2(dirname3(p));
51818
54447
  writeFileSync3(p, JSON.stringify(data, null, 2), "utf-8");
51819
54448
  }
51820
54449
  function getActiveProfile() {
@@ -51840,7 +54469,7 @@ function listProfiles() {
51840
54469
  return readdirSync(dir).filter((f) => f.endsWith(".db")).map((f) => basename(f, ".db")).sort();
51841
54470
  }
51842
54471
  function deleteProfile(name) {
51843
- const dbPath = join4(profilesDir(), `${name}.db`);
54472
+ const dbPath = join5(profilesDir(), `${name}.db`);
51844
54473
  if (!existsSync3(dbPath))
51845
54474
  return false;
51846
54475
  unlinkSync2(dbPath);
@@ -51850,10 +54479,10 @@ function deleteProfile(name) {
51850
54479
  }
51851
54480
  function getDbPath2() {
51852
54481
  const _home = homeDir();
51853
- const _newDir = join4(_home, ".hasna", "mementos");
51854
- const _oldDir = join4(_home, ".mementos");
54482
+ const _newDir = join5(_home, ".hasna", "mementos");
54483
+ const _oldDir = join5(_home, ".mementos");
51855
54484
  if (!existsSync3(_newDir) && existsSync3(_oldDir)) {
51856
- mkdirSync3(join4(_home, ".hasna"), { recursive: true });
54485
+ mkdirSync3(join5(_home, ".hasna"), { recursive: true });
51857
54486
  cpSync2(_oldDir, _newDir, { recursive: true });
51858
54487
  }
51859
54488
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
@@ -51861,31 +54490,31 @@ function getDbPath2() {
51861
54490
  if (isInMemoryDb2(envDbPath)) {
51862
54491
  return envDbPath;
51863
54492
  }
51864
- const resolved = resolve2(envDbPath);
51865
- ensureDir2(dirname2(resolved));
54493
+ const resolved = resolve3(envDbPath);
54494
+ ensureDir2(dirname3(resolved));
51866
54495
  return resolved;
51867
54496
  }
51868
54497
  const profile = getActiveProfile();
51869
54498
  if (profile) {
51870
- const profilePath = join4(profilesDir(), `${profile}.db`);
51871
- ensureDir2(dirname2(profilePath));
54499
+ const profilePath = join5(profilesDir(), `${profile}.db`);
54500
+ ensureDir2(dirname3(profilePath));
51872
54501
  return profilePath;
51873
54502
  }
51874
54503
  const dbScope = process.env["MEMENTOS_DB_SCOPE"];
51875
54504
  if (dbScope === "project") {
51876
54505
  const gitRoot = findGitRoot2();
51877
54506
  if (gitRoot) {
51878
- const dbPath = join4(gitRoot, ".mementos", "mementos.db");
51879
- ensureDir2(dirname2(dbPath));
54507
+ const dbPath = join5(gitRoot, ".mementos", "mementos.db");
54508
+ ensureDir2(dirname3(dbPath));
51880
54509
  return dbPath;
51881
54510
  }
51882
54511
  }
51883
- const found = findFileWalkingUp(join4(".mementos", "mementos.db"));
54512
+ const found = findFileWalkingUp(join5(".mementos", "mementos.db"));
51884
54513
  if (found) {
51885
54514
  return found;
51886
54515
  }
51887
- const fallback = join4(homeDir(), ".hasna", "mementos", "mementos.db");
51888
- ensureDir2(dirname2(fallback));
54516
+ const fallback = join5(homeDir(), ".hasna", "mementos", "mementos.db");
54517
+ ensureDir2(dirname3(fallback));
51889
54518
  return fallback;
51890
54519
  }
51891
54520
  function ensureDir2(dir) {
@@ -52270,18 +54899,18 @@ function runCleanup(config, db) {
52270
54899
  return { expired, evicted, archived, unused_archived, deprioritized };
52271
54900
  }
52272
54901
  // src/lib/sync.ts
52273
- import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "fs";
54902
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
52274
54903
  import { homedir as homedir3 } from "os";
52275
- import { join as join5 } from "path";
54904
+ import { join as join6 } from "path";
52276
54905
  function getAgentSyncDir(agentName) {
52277
- const dir = join5(homedir3(), ".hasna", "mementos", "agents", agentName);
54906
+ const dir = join6(homedir3(), ".hasna", "mementos", "agents", agentName);
52278
54907
  if (!existsSync4(dir)) {
52279
54908
  mkdirSync4(dir, { recursive: true });
52280
54909
  }
52281
54910
  return dir;
52282
54911
  }
52283
54912
  function setHighWaterMark(agentDir, timestamp) {
52284
- const markFile = join5(agentDir, ".highwatermark");
54913
+ const markFile = join6(agentDir, ".highwatermark");
52285
54914
  writeFileSync4(markFile, timestamp, "utf-8");
52286
54915
  }
52287
54916
  function resolveConflict(local, remote, resolution) {
@@ -52302,7 +54931,7 @@ function pushMemories(agentName, agentId, projectId, db) {
52302
54931
  status: "active",
52303
54932
  limit: 1e4
52304
54933
  }, db);
52305
- const outFile = join5(agentDir, "memories.json");
54934
+ const outFile = join6(agentDir, "memories.json");
52306
54935
  writeFileSync4(outFile, JSON.stringify(memories, null, 2), "utf-8");
52307
54936
  if (memories.length > 0) {
52308
54937
  const latest = memories.reduce((a, b) => new Date(a.updated_at).getTime() > new Date(b.updated_at).getTime() ? a : b);
@@ -52312,11 +54941,11 @@ function pushMemories(agentName, agentId, projectId, db) {
52312
54941
  }
52313
54942
  function pullMemories(agentName, conflictResolution = "prefer-newer", db) {
52314
54943
  const agentDir = getAgentSyncDir(agentName);
52315
- const inFile = join5(agentDir, "memories.json");
54944
+ const inFile = join6(agentDir, "memories.json");
52316
54945
  if (!existsSync4(inFile)) {
52317
54946
  return { pulled: 0, conflicts: 0 };
52318
54947
  }
52319
- const raw = readFileSync3(inFile, "utf-8");
54948
+ const raw = readFileSync4(inFile, "utf-8");
52320
54949
  let remoteMemories;
52321
54950
  try {
52322
54951
  remoteMemories = JSON.parse(raw);
@@ -54873,17 +57502,17 @@ var gatherTrainingData = async (options = {}) => {
54873
57502
  };
54874
57503
  };
54875
57504
  // src/lib/model-config.ts
54876
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
57505
+ import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
54877
57506
  import { homedir as homedir4 } from "os";
54878
- import { join as join6 } from "path";
57507
+ import { join as join7 } from "path";
54879
57508
  var DEFAULT_MODEL = "gpt-4o-mini";
54880
- var CONFIG_DIR = join6(homedir4(), ".hasna", "mementos");
54881
- var CONFIG_PATH = join6(CONFIG_DIR, "config.json");
57509
+ var CONFIG_DIR = join7(homedir4(), ".hasna", "mementos");
57510
+ var CONFIG_PATH = join7(CONFIG_DIR, "config.json");
54882
57511
  function readConfig() {
54883
57512
  if (!existsSync5(CONFIG_PATH))
54884
57513
  return {};
54885
57514
  try {
54886
- const raw = readFileSync4(CONFIG_PATH, "utf-8");
57515
+ const raw = readFileSync5(CONFIG_PATH, "utf-8");
54887
57516
  return JSON.parse(raw);
54888
57517
  } catch {
54889
57518
  return {};
@@ -55337,6 +57966,9 @@ export {
55337
57966
  touchAgent,
55338
57967
  syncMemories,
55339
57968
  startTaskRunner,
57969
+ sqliteMementosProjectRegistrationSchemaSql,
57970
+ sqliteMementosProjectGuardedUpdateSchemaSql,
57971
+ sqliteMementosMemoryProjectLinkSchemaSql,
55340
57972
  shortUuid,
55341
57973
  setPrimaryMachine,
55342
57974
  setFocus,
@@ -55347,6 +57979,8 @@ export {
55347
57979
  saveStorageConfig,
55348
57980
  runConsolidation,
55349
57981
  runCleanup,
57982
+ rollbackProjectUpdate,
57983
+ rollbackMemoryProjectLink,
55350
57984
  resolveProjectId,
55351
57985
  resolvePartialId,
55352
57986
  resetDatabase,
@@ -55365,11 +57999,17 @@ export {
55365
57999
  pullStorageChanges,
55366
58000
  providerRegistry,
55367
58001
  processConversationTurn,
58002
+ previewProjectUpdate,
58003
+ previewMemoryProjectLink,
58004
+ postgresMementosProjectRegistrationSchemaSql,
58005
+ postgresMementosProjectGuardedUpdateSchemaSql,
58006
+ postgresMementosMemoryProjectLinkSchemaSql,
55368
58007
  parseRelationRow,
55369
58008
  parseEntityRow2 as parseEntityRow,
55370
58009
  now,
55371
58010
  mergeEntities,
55372
58011
  memoryLockId,
58012
+ mementosProjectReferenceCounts,
55373
58013
  loadConfig,
55374
58014
  listTasks,
55375
58015
  listTaskComments,
@@ -55386,6 +58026,8 @@ export {
55386
58026
  linkEntityToMemory,
55387
58027
  incrementRecallCount,
55388
58028
  heuristicReflectionCritic,
58029
+ hasMementosProjectReferences,
58030
+ handleMementosProjectRegistrationHttpRequest,
55389
58031
  getTaskStats,
55390
58032
  getTaskRunnerStats,
55391
58033
  getTask,
@@ -55399,11 +58041,13 @@ export {
55399
58041
  getStorageConfig,
55400
58042
  getRelation,
55401
58043
  getRelatedEntities,
58044
+ getProjectUpdateReceipt,
55402
58045
  getProject,
55403
58046
  getPrimaryMachineStartupWarning,
55404
58047
  getPrimaryMachineCandidate,
55405
58048
  getPrimaryMachine,
55406
58049
  getMemoryVersions,
58050
+ getMemoryProjectLinkReceipt,
55407
58051
  getMemoryLinks,
55408
58052
  getMemoryByKey,
55409
58053
  getMemoryBacklinks,
@@ -55432,6 +58076,8 @@ export {
55432
58076
  focusFilterSQL,
55433
58077
  findPath,
55434
58078
  enforceQuotas,
58079
+ digestMementosProjectRegistrationValue,
58080
+ deriveMementosProjectRegistrationIdempotencyKey,
55435
58081
  deprioritizeStale,
55436
58082
  deleteTaskComment,
55437
58083
  deleteTask,
@@ -55446,7 +58092,10 @@ export {
55446
58092
  createRelation,
55447
58093
  createMemoryLink,
55448
58094
  createMemory,
58095
+ createMementosProjectRegistrationHttpClient,
58096
+ createMementosProjectRegistrationAuthority,
55449
58097
  createMementosProjectPanel,
58098
+ createLocalMementosProjectRegistrationAuthority,
55450
58099
  createEntity,
55451
58100
  createAISDKReflectionCritic,
55452
58101
  containsSecrets,
@@ -55457,11 +58106,14 @@ export {
55457
58106
  cleanExpiredLocks,
55458
58107
  checkMemoryWriteLock,
55459
58108
  checkLock,
58109
+ canonicalMementosProjectRegistrationJson,
55460
58110
  bulkLinkEntities,
55461
58111
  bulkDeleteMemories,
55462
58112
  buildFocusFilter,
55463
58113
  archiveUnused,
55464
58114
  archiveStale,
58115
+ applyProjectUpdate,
58116
+ applyMemoryProjectLink,
55465
58117
  agentHoldsLock,
55466
58118
  addTaskComment,
55467
58119
  acquireMemoryWriteLock,
@@ -55469,15 +58121,28 @@ export {
55469
58121
  VersionConflictError,
55470
58122
  SqliteAdapter,
55471
58123
  STORAGE_TABLES,
58124
+ ProjectGuardedUpdateError,
58125
+ ProjectCollisionError,
55472
58126
  PgAdapterAsync,
55473
58127
  PgAdapter,
58128
+ PackageOwnedMementosProjectRegistrationAuthority,
58129
+ MemoryProjectLinkError,
55474
58130
  MemoryNotFoundError,
55475
58131
  MemoryLockConflictError,
55476
58132
  MemoryInjector,
55477
58133
  MemoryExpiredError,
58134
+ MementosProjectRegistrationHttpClient,
58135
+ MementosProjectRegistrationError,
58136
+ MEMORY_PROJECT_LINK_RECEIPT_COLUMNS,
55478
58137
  MEMENTOS_STORAGE_TABLES,
55479
58138
  MEMENTOS_STORAGE_FALLBACK_ENV,
55480
58139
  MEMENTOS_STORAGE_ENV,
58140
+ MEMENTOS_PROJECT_REGISTRATION_SCHEMA_VERSION,
58141
+ MEMENTOS_PROJECT_REGISTRATION_ROUTE,
58142
+ MEMENTOS_PROJECT_REGISTRATION_CALLER_ROUTE,
58143
+ MEMENTOS_PROJECT_REFERENCE_SURFACES,
58144
+ MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
58145
+ MEMENTOS_MEMORY_PROJECT_LINK_ROUTE,
55481
58146
  InvalidScopeError,
55482
58147
  EntityNotFoundError,
55483
58148
  DuplicateMemoryError,