@hasna/mementos 0.14.80 → 0.14.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/memory-cmd-crud.d.ts.map +1 -1
- package/dist/cli/commands/project.d.ts.map +1 -1
- package/dist/cli/index.js +557 -80
- package/dist/db/memory-project-link.d.ts.map +1 -1
- package/dist/db/projects.d.ts +4 -4
- package/dist/db/projects.d.ts.map +1 -1
- package/dist/index.js +703 -93
- package/dist/project-registration/authority.d.ts +5 -1
- package/dist/project-registration/authority.d.ts.map +1 -1
- package/dist/project-registration/http.d.ts +4 -1
- package/dist/project-registration/http.d.ts.map +1 -1
- package/dist/project-registration/identity.d.ts +20 -0
- package/dist/project-registration/identity.d.ts.map +1 -0
- package/dist/project-registration/index.d.ts +5 -2
- package/dist/project-registration/index.d.ts.map +1 -1
- package/dist/project-registration/project-resources.d.ts +22 -0
- package/dist/project-registration/project-resources.d.ts.map +1 -0
- package/dist/project-registration/types.d.ts +125 -0
- package/dist/project-registration/types.d.ts.map +1 -1
- package/dist/project-registration.js +4959 -327
- package/dist/sdk/index.d.ts +57 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +56 -0
- package/dist/server/index.js +863 -157
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/test-support/project-authority-identity.d.ts +8 -0
- package/dist/test-support/project-authority-identity.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -50488,6 +50488,98 @@ function getMementosPackageVersion() {
|
|
|
50488
50488
|
// src/db/memory-project-link.ts
|
|
50489
50489
|
init_schema();
|
|
50490
50490
|
|
|
50491
|
+
// src/project-registration/types.ts
|
|
50492
|
+
var MEMENTOS_PROJECT_REGISTRATION_ROUTE = "mementos.project-registration.v1";
|
|
50493
|
+
var MEMENTOS_PROJECT_REGISTRATION_CALLER_ROUTE = "projects.full-registration.v1";
|
|
50494
|
+
var MEMENTOS_PROJECT_REGISTRATION_SCHEMA_VERSION = 1;
|
|
50495
|
+
var MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE = "mementos.project-guarded-update.v1";
|
|
50496
|
+
var MEMENTOS_PROJECT_RESOURCE_ROUTE = "mementos.project-resources.v1";
|
|
50497
|
+
var MEMENTOS_PROJECT_RESOURCE_KINDS = [
|
|
50498
|
+
"project",
|
|
50499
|
+
"knowledge",
|
|
50500
|
+
"memory",
|
|
50501
|
+
"session"
|
|
50502
|
+
];
|
|
50503
|
+
|
|
50504
|
+
class MementosProjectRegistrationError extends Error {
|
|
50505
|
+
code;
|
|
50506
|
+
details;
|
|
50507
|
+
constructor(code, message, details = {}) {
|
|
50508
|
+
super(message);
|
|
50509
|
+
this.code = code;
|
|
50510
|
+
this.details = details;
|
|
50511
|
+
this.name = "MementosProjectRegistrationError";
|
|
50512
|
+
}
|
|
50513
|
+
}
|
|
50514
|
+
|
|
50515
|
+
// src/project-registration/identity.ts
|
|
50516
|
+
var MEMENTOS_PROJECT_AUTHORITY_ENV = {
|
|
50517
|
+
authorityId: "MEMENTOS_PROJECT_AUTHORITY_ID",
|
|
50518
|
+
tenantId: "MEMENTOS_PROJECT_TENANT_ID",
|
|
50519
|
+
corpusId: "MEMENTOS_PROJECT_CORPUS_ID"
|
|
50520
|
+
};
|
|
50521
|
+
function configuredValue(override, envKey) {
|
|
50522
|
+
return override?.trim() || process.env[envKey]?.trim() || null;
|
|
50523
|
+
}
|
|
50524
|
+
|
|
50525
|
+
class MementosProjectAuthorityIdentityError extends Error {
|
|
50526
|
+
missing_env;
|
|
50527
|
+
code = "MEMENTOS_PROJECT_AUTHORITY_UNCONFIGURED";
|
|
50528
|
+
constructor(missing_env) {
|
|
50529
|
+
super("Mementos project authority identity is not configured; set " + missing_env.join(", "));
|
|
50530
|
+
this.missing_env = missing_env;
|
|
50531
|
+
this.name = "MementosProjectAuthorityIdentityError";
|
|
50532
|
+
}
|
|
50533
|
+
}
|
|
50534
|
+
function resolveMementosProjectAuthorityIdentity(options = {}) {
|
|
50535
|
+
const authorityId = configuredValue(options.authorityId, MEMENTOS_PROJECT_AUTHORITY_ENV.authorityId);
|
|
50536
|
+
const tenantId = configuredValue(options.tenantId, MEMENTOS_PROJECT_AUTHORITY_ENV.tenantId);
|
|
50537
|
+
const corpusId = configuredValue(options.corpusId, MEMENTOS_PROJECT_AUTHORITY_ENV.corpusId);
|
|
50538
|
+
if (!authorityId || !tenantId || !corpusId) {
|
|
50539
|
+
const missingEnv = [];
|
|
50540
|
+
if (!authorityId)
|
|
50541
|
+
missingEnv.push(MEMENTOS_PROJECT_AUTHORITY_ENV.authorityId);
|
|
50542
|
+
if (!tenantId)
|
|
50543
|
+
missingEnv.push(MEMENTOS_PROJECT_AUTHORITY_ENV.tenantId);
|
|
50544
|
+
if (!corpusId)
|
|
50545
|
+
missingEnv.push(MEMENTOS_PROJECT_AUTHORITY_ENV.corpusId);
|
|
50546
|
+
throw new MementosProjectAuthorityIdentityError(missingEnv);
|
|
50547
|
+
}
|
|
50548
|
+
return {
|
|
50549
|
+
authority_id: authorityId,
|
|
50550
|
+
tenant_id: tenantId,
|
|
50551
|
+
corpus_id: corpusId
|
|
50552
|
+
};
|
|
50553
|
+
}
|
|
50554
|
+
function buildMementosProjectRegistrationCapability(options = {}) {
|
|
50555
|
+
const identity = resolveMementosProjectAuthorityIdentity(options);
|
|
50556
|
+
return {
|
|
50557
|
+
authority: "mementos",
|
|
50558
|
+
route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
|
|
50559
|
+
package_version: options.packageVersion ?? getMementosPackageVersion(),
|
|
50560
|
+
...identity,
|
|
50561
|
+
supported_resources: ["project"],
|
|
50562
|
+
conditional_create: true,
|
|
50563
|
+
immutable_receipts: true,
|
|
50564
|
+
exact_terminal_lookup: true,
|
|
50565
|
+
exact_readback: true,
|
|
50566
|
+
conditional_inverse: true,
|
|
50567
|
+
ambiguous_outcome_reconciliation: true,
|
|
50568
|
+
guarded_update: true,
|
|
50569
|
+
guarded_update_route: MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
|
|
50570
|
+
no_write_dry_run: true,
|
|
50571
|
+
expected_revision_compare_and_swap: true,
|
|
50572
|
+
caller_idempotency: true,
|
|
50573
|
+
exact_inverse_rollback: true,
|
|
50574
|
+
project_resource_enumeration: true,
|
|
50575
|
+
project_resource_route: MEMENTOS_PROJECT_RESOURCE_ROUTE,
|
|
50576
|
+
project_resource_kinds: ["project", "knowledge", "memory", "session"],
|
|
50577
|
+
stable_keyset_pagination: true,
|
|
50578
|
+
explicit_membership_only: true
|
|
50579
|
+
};
|
|
50580
|
+
}
|
|
50581
|
+
|
|
50582
|
+
// src/db/memory-project-link.ts
|
|
50491
50583
|
class MemoryProjectLinkError extends Error {
|
|
50492
50584
|
code;
|
|
50493
50585
|
details;
|
|
@@ -50498,12 +50590,17 @@ class MemoryProjectLinkError extends Error {
|
|
|
50498
50590
|
this.name = "MemoryProjectLinkError";
|
|
50499
50591
|
}
|
|
50500
50592
|
}
|
|
50501
|
-
var LINK_AUTHORITY = {
|
|
50502
|
-
authority_id: "mementos",
|
|
50503
|
-
tenant_id: "default",
|
|
50504
|
-
corpus_id: "default"
|
|
50505
|
-
};
|
|
50506
50593
|
var BOUNDED_IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
|
|
50594
|
+
function linkAuthority() {
|
|
50595
|
+
try {
|
|
50596
|
+
return resolveMementosProjectAuthorityIdentity();
|
|
50597
|
+
} catch (error) {
|
|
50598
|
+
if (error instanceof MementosProjectAuthorityIdentityError) {
|
|
50599
|
+
throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_AUTHORITY_MISMATCH", error.message, { authority_code: error.code, missing_env: error.missing_env });
|
|
50600
|
+
}
|
|
50601
|
+
throw error;
|
|
50602
|
+
}
|
|
50603
|
+
}
|
|
50507
50604
|
function canonicalize(value) {
|
|
50508
50605
|
if (Array.isArray(value))
|
|
50509
50606
|
return value.map(canonicalize);
|
|
@@ -50611,7 +50708,8 @@ function receiptFromRow(row) {
|
|
|
50611
50708
|
};
|
|
50612
50709
|
}
|
|
50613
50710
|
function assertIdentity(identity) {
|
|
50614
|
-
|
|
50711
|
+
const expectedIdentity = linkAuthority();
|
|
50712
|
+
if (identity.authority_id !== expectedIdentity.authority_id || identity.tenant_id !== expectedIdentity.tenant_id || identity.corpus_id !== expectedIdentity.corpus_id) {
|
|
50615
50713
|
throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_AUTHORITY_MISMATCH", "memory project link does not match this authority, tenant, and corpus");
|
|
50616
50714
|
}
|
|
50617
50715
|
}
|
|
@@ -51088,7 +51186,7 @@ function rollbackMemoryProjectLink(memoryId, request, db) {
|
|
|
51088
51186
|
};
|
|
51089
51187
|
});
|
|
51090
51188
|
}
|
|
51091
|
-
function getMemoryProjectLinkReceipt(memoryId, receiptId, identity =
|
|
51189
|
+
function getMemoryProjectLinkReceipt(memoryId, receiptId, identity = linkAuthority(), db) {
|
|
51092
51190
|
assertIdentity(identity);
|
|
51093
51191
|
assertBoundedIdentifier(memoryId, "memory_id");
|
|
51094
51192
|
assertBoundedIdentifier(receiptId, "receipt_id");
|
|
@@ -51553,25 +51651,6 @@ function focusFilterSQL(agentId, projectId) {
|
|
|
51553
51651
|
init_database();
|
|
51554
51652
|
init_api_mode();
|
|
51555
51653
|
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
51654
|
function parseProjectRow2(row) {
|
|
51576
51655
|
return {
|
|
51577
51656
|
id: row["id"],
|
|
@@ -51605,12 +51684,17 @@ class ProjectGuardedUpdateError extends Error {
|
|
|
51605
51684
|
this.name = "ProjectGuardedUpdateError";
|
|
51606
51685
|
}
|
|
51607
51686
|
}
|
|
51608
|
-
var PROJECT_UPDATE_AUTHORITY = {
|
|
51609
|
-
authority_id: "mementos",
|
|
51610
|
-
tenant_id: "default",
|
|
51611
|
-
corpus_id: "default"
|
|
51612
|
-
};
|
|
51613
51687
|
var BOUNDED_IDENTIFIER2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
|
|
51688
|
+
function projectUpdateAuthority() {
|
|
51689
|
+
try {
|
|
51690
|
+
return resolveMementosProjectAuthorityIdentity();
|
|
51691
|
+
} catch (error) {
|
|
51692
|
+
if (error instanceof MementosProjectAuthorityIdentityError) {
|
|
51693
|
+
throw new ProjectGuardedUpdateError("PROJECT_UPDATE_AUTHORITY_MISMATCH", error.message, { authority_code: error.code, missing_env: error.missing_env });
|
|
51694
|
+
}
|
|
51695
|
+
throw error;
|
|
51696
|
+
}
|
|
51697
|
+
}
|
|
51614
51698
|
function canonicalizeProjectUpdateValue(value) {
|
|
51615
51699
|
if (Array.isArray(value))
|
|
51616
51700
|
return value.map(canonicalizeProjectUpdateValue);
|
|
@@ -51683,8 +51767,8 @@ function normalizeProjectUpdateInput(input) {
|
|
|
51683
51767
|
}
|
|
51684
51768
|
return normalized;
|
|
51685
51769
|
}
|
|
51686
|
-
function assertProjectUpdateIdentity(identity) {
|
|
51687
|
-
if (identity.authority_id !==
|
|
51770
|
+
function assertProjectUpdateIdentity(identity, expectedIdentity = projectUpdateAuthority()) {
|
|
51771
|
+
if (identity.authority_id !== expectedIdentity.authority_id || identity.tenant_id !== expectedIdentity.tenant_id || identity.corpus_id !== expectedIdentity.corpus_id) {
|
|
51688
51772
|
throw new ProjectGuardedUpdateError("PROJECT_UPDATE_AUTHORITY_MISMATCH", "guarded project update does not match this authority, tenant, and corpus");
|
|
51689
51773
|
}
|
|
51690
51774
|
}
|
|
@@ -51693,8 +51777,8 @@ function assertBoundedIdentifier2(value, field) {
|
|
|
51693
51777
|
throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", `${field} must be an 8-128 character bounded identifier`);
|
|
51694
51778
|
}
|
|
51695
51779
|
}
|
|
51696
|
-
function assertProjectUpdateRequest(request) {
|
|
51697
|
-
assertProjectUpdateIdentity(request);
|
|
51780
|
+
function assertProjectUpdateRequest(request, expectedIdentity = projectUpdateAuthority()) {
|
|
51781
|
+
assertProjectUpdateIdentity(request, expectedIdentity);
|
|
51698
51782
|
assertBoundedIdentifier2(request.operation_id, "operation_id");
|
|
51699
51783
|
assertBoundedIdentifier2(request.step_id, "step_id");
|
|
51700
51784
|
assertBoundedIdentifier2(request.idempotency_key, "idempotency_key");
|
|
@@ -51807,7 +51891,7 @@ function makeProjectUpdateReceipt(input) {
|
|
|
51807
51891
|
target_id: input.target_id,
|
|
51808
51892
|
expected_revision: input.request.expected_revision,
|
|
51809
51893
|
result_revision: input.after_project.updated_at,
|
|
51810
|
-
result_digest: digestProjectUpdateValue(input.after_project),
|
|
51894
|
+
result_digest: input.result_digest ?? digestProjectUpdateValue(input.after_project),
|
|
51811
51895
|
accepted_receipt_id: input.accepted_receipt_id ?? null,
|
|
51812
51896
|
before_project: input.before_project,
|
|
51813
51897
|
after_project: input.after_project,
|
|
@@ -51871,8 +51955,8 @@ function listProjects(db) {
|
|
|
51871
51955
|
const rows = d.query("SELECT * FROM projects ORDER BY updated_at DESC").all();
|
|
51872
51956
|
return rows.map(parseProjectRow2);
|
|
51873
51957
|
}
|
|
51874
|
-
function previewProjectUpdate(id, request, db) {
|
|
51875
|
-
assertProjectUpdateRequest(request);
|
|
51958
|
+
function previewProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority()) {
|
|
51959
|
+
assertProjectUpdateRequest(request, expectedIdentity);
|
|
51876
51960
|
const normalized = normalizeProjectUpdateInput(request.updates);
|
|
51877
51961
|
if (!db && isApiMode()) {
|
|
51878
51962
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-update`, { ...request, updates: normalized, dry_run: true });
|
|
@@ -51894,8 +51978,8 @@ function previewProjectUpdate(id, request, db) {
|
|
|
51894
51978
|
receipt: null
|
|
51895
51979
|
};
|
|
51896
51980
|
}
|
|
51897
|
-
function applyProjectUpdate(id, request, db) {
|
|
51898
|
-
assertProjectUpdateRequest(request);
|
|
51981
|
+
function applyProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority(), resultDigestForProject) {
|
|
51982
|
+
assertProjectUpdateRequest(request, expectedIdentity);
|
|
51899
51983
|
const normalized = normalizeProjectUpdateInput(request.updates);
|
|
51900
51984
|
if (!db && isApiMode()) {
|
|
51901
51985
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-update`, { ...request, updates: normalized, dry_run: false });
|
|
@@ -51956,14 +52040,15 @@ function applyProjectUpdate(id, request, db) {
|
|
|
51956
52040
|
request_digest: requestDigest,
|
|
51957
52041
|
target_id: id,
|
|
51958
52042
|
before_project: before,
|
|
51959
|
-
after_project: readback
|
|
52043
|
+
after_project: readback,
|
|
52044
|
+
result_digest: resultDigestForProject?.(readback)
|
|
51960
52045
|
});
|
|
51961
52046
|
insertProjectUpdateReceipt(d, receipt);
|
|
51962
52047
|
return { dry_run: false, applied: true, project: readback, receipt };
|
|
51963
52048
|
});
|
|
51964
52049
|
}
|
|
51965
|
-
function rollbackProjectUpdate(id, request, db) {
|
|
51966
|
-
assertProjectUpdateRequest(request);
|
|
52050
|
+
function rollbackProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority(), resultDigestForProject) {
|
|
52051
|
+
assertProjectUpdateRequest(request, expectedIdentity);
|
|
51967
52052
|
assertBoundedIdentifier2(request.accepted_receipt_id, "accepted_receipt_id");
|
|
51968
52053
|
if (!db && isApiMode()) {
|
|
51969
52054
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-rollback`, request);
|
|
@@ -52029,14 +52114,15 @@ function rollbackProjectUpdate(id, request, db) {
|
|
|
52029
52114
|
target_id: id,
|
|
52030
52115
|
before_project: current,
|
|
52031
52116
|
after_project: readback,
|
|
52117
|
+
result_digest: resultDigestForProject?.(readback),
|
|
52032
52118
|
accepted_receipt_id: accepted.receipt_id
|
|
52033
52119
|
});
|
|
52034
52120
|
insertProjectUpdateReceipt(d, receipt);
|
|
52035
52121
|
return { dry_run: false, applied: true, project: readback, receipt };
|
|
52036
52122
|
});
|
|
52037
52123
|
}
|
|
52038
|
-
function getProjectUpdateReceipt(id, receiptId, identity =
|
|
52039
|
-
assertProjectUpdateIdentity(identity);
|
|
52124
|
+
function getProjectUpdateReceipt(id, receiptId, identity = projectUpdateAuthority(), db, expectedIdentity = projectUpdateAuthority()) {
|
|
52125
|
+
assertProjectUpdateIdentity(identity, expectedIdentity);
|
|
52040
52126
|
if (!db && isApiMode()) {
|
|
52041
52127
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/update-receipts/lookup`, { ...identity, receipt_id: receiptId });
|
|
52042
52128
|
return data;
|
|
@@ -52178,9 +52264,9 @@ function assertWithinBounds(value, bounds, startedAt) {
|
|
|
52178
52264
|
}
|
|
52179
52265
|
return { response_bytes: bytes, elapsed_ms: elapsed };
|
|
52180
52266
|
}
|
|
52181
|
-
function
|
|
52267
|
+
function withBoundedResponseControl(payload, bounds, startedAt) {
|
|
52182
52268
|
const result = {
|
|
52183
|
-
|
|
52269
|
+
...payload,
|
|
52184
52270
|
response_control: {
|
|
52185
52271
|
response_byte_limit: bounds.response_byte_limit,
|
|
52186
52272
|
time_budget_ms: bounds.time_budget_ms,
|
|
@@ -52203,6 +52289,9 @@ function withResponseControl(receipt, bounds, startedAt) {
|
|
|
52203
52289
|
result.response_control.elapsed_ms = measured.elapsed_ms;
|
|
52204
52290
|
return result;
|
|
52205
52291
|
}
|
|
52292
|
+
function withResponseControl(receipt, bounds, startedAt) {
|
|
52293
|
+
return withBoundedResponseControl({ receipt }, bounds, startedAt);
|
|
52294
|
+
}
|
|
52206
52295
|
function requireString(value, field, options = {}) {
|
|
52207
52296
|
const min = options.min ?? 1;
|
|
52208
52297
|
const max = options.max ?? 512;
|
|
@@ -52229,6 +52318,80 @@ function ownedPath(target) {
|
|
|
52229
52318
|
}
|
|
52230
52319
|
return path;
|
|
52231
52320
|
}
|
|
52321
|
+
function guardedAuthorityIdentity(capability) {
|
|
52322
|
+
return {
|
|
52323
|
+
authority_id: capability.authority_id,
|
|
52324
|
+
tenant_id: capability.tenant_id,
|
|
52325
|
+
corpus_id: capability.corpus_id
|
|
52326
|
+
};
|
|
52327
|
+
}
|
|
52328
|
+
function assertGuardedAuthorityRequest(targetId, request, capability) {
|
|
52329
|
+
assertBounds(request);
|
|
52330
|
+
requireString(targetId, "target_id", { min: 8, max: 128, pattern: OPERATION_PATTERN });
|
|
52331
|
+
if (request.authority !== "mementos" || request.authority_route !== MEMENTOS_PROJECT_GUARDED_UPDATE_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) {
|
|
52332
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH", "guarded project request does not match this authority capability identity");
|
|
52333
|
+
}
|
|
52334
|
+
return guardedAuthorityIdentity(capability);
|
|
52335
|
+
}
|
|
52336
|
+
function assertGuardedOperationFields(request) {
|
|
52337
|
+
requireString(request.operation_id, "operation_id", {
|
|
52338
|
+
min: 8,
|
|
52339
|
+
max: 128,
|
|
52340
|
+
pattern: OPERATION_PATTERN
|
|
52341
|
+
});
|
|
52342
|
+
requireString(request.step_id, "step_id", {
|
|
52343
|
+
min: 8,
|
|
52344
|
+
max: 128,
|
|
52345
|
+
pattern: OPERATION_PATTERN
|
|
52346
|
+
});
|
|
52347
|
+
requireString(request.idempotency_key, "idempotency_key", {
|
|
52348
|
+
min: 8,
|
|
52349
|
+
max: 128,
|
|
52350
|
+
pattern: OPERATION_PATTERN
|
|
52351
|
+
});
|
|
52352
|
+
requireString(request.expected_revision, "expected_revision", { max: 128 });
|
|
52353
|
+
}
|
|
52354
|
+
function assertGuardedUpdateRequest(targetId, request, capability) {
|
|
52355
|
+
const identity = assertGuardedAuthorityRequest(targetId, request, capability);
|
|
52356
|
+
assertGuardedOperationFields(request);
|
|
52357
|
+
if (!request.updates || typeof request.updates !== "object") {
|
|
52358
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "guarded project updates must contain exactly one private path handle");
|
|
52359
|
+
}
|
|
52360
|
+
exactKeys(request.updates, ["path"], "updates");
|
|
52361
|
+
return { identity, path: ownedPath(request.updates.path) };
|
|
52362
|
+
}
|
|
52363
|
+
function publicGuardedUpdateReceipt(receipt, capability) {
|
|
52364
|
+
return {
|
|
52365
|
+
receipt_id: receipt.receipt_id,
|
|
52366
|
+
authority: "mementos",
|
|
52367
|
+
route: MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
|
|
52368
|
+
package_version: capability.package_version,
|
|
52369
|
+
authority_id: capability.authority_id,
|
|
52370
|
+
tenant_id: capability.tenant_id,
|
|
52371
|
+
corpus_id: capability.corpus_id,
|
|
52372
|
+
operation_id: receipt.operation_id,
|
|
52373
|
+
step_id: receipt.step_id,
|
|
52374
|
+
direction: receipt.direction,
|
|
52375
|
+
idempotency_key: receipt.idempotency_key,
|
|
52376
|
+
request_digest: receipt.request_digest,
|
|
52377
|
+
outcome: "accepted",
|
|
52378
|
+
target_id: receipt.target_id,
|
|
52379
|
+
expected_revision: receipt.expected_revision,
|
|
52380
|
+
result_revision: receipt.result_revision,
|
|
52381
|
+
result_digest: receipt.result_digest,
|
|
52382
|
+
accepted_receipt_id: receipt.accepted_receipt_id,
|
|
52383
|
+
created_at: receipt.created_at
|
|
52384
|
+
};
|
|
52385
|
+
}
|
|
52386
|
+
function guardedProjectError(cause) {
|
|
52387
|
+
if (cause instanceof MementosProjectRegistrationError)
|
|
52388
|
+
throw cause;
|
|
52389
|
+
if (cause instanceof ProjectGuardedUpdateError) {
|
|
52390
|
+
const code = cause.code === "PROJECT_UPDATE_INVALID_INPUT" ? "MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT" : cause.code === "PROJECT_UPDATE_AUTHORITY_MISMATCH" ? "MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH" : cause.code === "PROJECT_UPDATE_NOT_FOUND" ? "MEMENTOS_PROJECT_REGISTRATION_RECORD_NOT_FOUND" : cause.code === "PROJECT_UPDATE_RECEIPT_NOT_FOUND" ? "MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND" : "MEMENTOS_PROJECT_REGISTRATION_CONFLICT";
|
|
52391
|
+
throw new MementosProjectRegistrationError(code, "guarded project operation was rejected without exposing private project data", { project_update_code: cause.code });
|
|
52392
|
+
}
|
|
52393
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE", "guarded project operation failed before a bounded public result was available");
|
|
52394
|
+
}
|
|
52232
52395
|
function normalizedCallDigest(request) {
|
|
52233
52396
|
return digestMementosProjectRegistrationValue({
|
|
52234
52397
|
authority_route: request.authority_route,
|
|
@@ -52600,26 +52763,7 @@ class PackageOwnedMementosProjectRegistrationAuthority {
|
|
|
52600
52763
|
this.db = db;
|
|
52601
52764
|
this.now = options.now ?? (() => new Date().toISOString());
|
|
52602
52765
|
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
|
-
};
|
|
52766
|
+
this.capabilityValue = buildMementosProjectRegistrationCapability(options);
|
|
52623
52767
|
}
|
|
52624
52768
|
fault(point, request) {
|
|
52625
52769
|
this.faultInjector?.(point, {
|
|
@@ -52676,6 +52820,90 @@ class PackageOwnedMementosProjectRegistrationAuthority {
|
|
|
52676
52820
|
supported_resources: ["project"]
|
|
52677
52821
|
};
|
|
52678
52822
|
}
|
|
52823
|
+
boundedGuardedUpdateResult(targetId2, project, receipt, bounds, startedAt) {
|
|
52824
|
+
if (!receipt || project.id !== targetId2 || receipt.target_id !== targetId2) {
|
|
52825
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE", "guarded project operation did not return its exact immutable receipt");
|
|
52826
|
+
}
|
|
52827
|
+
if (project.updated_at !== receipt.result_revision) {
|
|
52828
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_ATOMICITY_UNAVAILABLE", "guarded project result revision did not match its immutable receipt");
|
|
52829
|
+
}
|
|
52830
|
+
const record = {
|
|
52831
|
+
target_id: targetId2,
|
|
52832
|
+
revision: receipt.result_revision,
|
|
52833
|
+
digest: receipt.result_digest
|
|
52834
|
+
};
|
|
52835
|
+
return withBoundedResponseControl({
|
|
52836
|
+
dry_run: false,
|
|
52837
|
+
applied: true,
|
|
52838
|
+
record,
|
|
52839
|
+
receipt: publicGuardedUpdateReceipt(receipt, this.capabilityValue)
|
|
52840
|
+
}, bounds, startedAt);
|
|
52841
|
+
}
|
|
52842
|
+
async guardedUpdateProject(targetId2, request) {
|
|
52843
|
+
const startedAt = Date.now();
|
|
52844
|
+
const { identity, path } = assertGuardedUpdateRequest(targetId2, request, this.capabilityValue);
|
|
52845
|
+
try {
|
|
52846
|
+
const result = applyProjectUpdate(targetId2, {
|
|
52847
|
+
...identity,
|
|
52848
|
+
operation_id: request.operation_id,
|
|
52849
|
+
step_id: request.step_id,
|
|
52850
|
+
idempotency_key: request.idempotency_key,
|
|
52851
|
+
expected_revision: request.expected_revision,
|
|
52852
|
+
updates: { path }
|
|
52853
|
+
}, this.db, identity, (project) => projectRecord(this.db, project).digest);
|
|
52854
|
+
return this.boundedGuardedUpdateResult(targetId2, result.project, result.receipt, request, startedAt);
|
|
52855
|
+
} catch (cause) {
|
|
52856
|
+
return guardedProjectError(cause);
|
|
52857
|
+
}
|
|
52858
|
+
}
|
|
52859
|
+
async getGuardedProjectUpdateReceipt(targetId2, receiptId2, request) {
|
|
52860
|
+
const startedAt = Date.now();
|
|
52861
|
+
const identity = assertGuardedAuthorityRequest(targetId2, request, this.capabilityValue);
|
|
52862
|
+
requireString(receiptId2, "receipt_id", {
|
|
52863
|
+
min: 8,
|
|
52864
|
+
max: 128,
|
|
52865
|
+
pattern: OPERATION_PATTERN
|
|
52866
|
+
});
|
|
52867
|
+
try {
|
|
52868
|
+
const receipt = getProjectUpdateReceipt(targetId2, receiptId2, identity, this.db, identity);
|
|
52869
|
+
return withBoundedResponseControl({
|
|
52870
|
+
receipt: publicGuardedUpdateReceipt(receipt, this.capabilityValue)
|
|
52871
|
+
}, request, startedAt);
|
|
52872
|
+
} catch (cause) {
|
|
52873
|
+
return guardedProjectError(cause);
|
|
52874
|
+
}
|
|
52875
|
+
}
|
|
52876
|
+
async rollbackGuardedProjectUpdate(targetId2, request) {
|
|
52877
|
+
const startedAt = Date.now();
|
|
52878
|
+
const identity = assertGuardedAuthorityRequest(targetId2, request, this.capabilityValue);
|
|
52879
|
+
assertGuardedOperationFields(request);
|
|
52880
|
+
if (!request.accepted_receipt || typeof request.accepted_receipt !== "object") {
|
|
52881
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "conditional rollback requires the exact sanitized accepted receipt");
|
|
52882
|
+
}
|
|
52883
|
+
requireString(request.accepted_receipt.receipt_id, "accepted_receipt.receipt_id", {
|
|
52884
|
+
min: 8,
|
|
52885
|
+
max: 128,
|
|
52886
|
+
pattern: OPERATION_PATTERN
|
|
52887
|
+
});
|
|
52888
|
+
try {
|
|
52889
|
+
const internalAccepted = getProjectUpdateReceipt(targetId2, request.accepted_receipt.receipt_id, identity, this.db, identity);
|
|
52890
|
+
const accepted = publicGuardedUpdateReceipt(internalAccepted, this.capabilityValue);
|
|
52891
|
+
if (accepted.direction !== "forward" || accepted.target_id !== targetId2 || request.expected_revision !== accepted.result_revision || canonicalMementosProjectRegistrationJson(request.accepted_receipt) !== canonicalMementosProjectRegistrationJson(accepted)) {
|
|
52892
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "conditional rollback receipt does not exactly match the accepted forward update");
|
|
52893
|
+
}
|
|
52894
|
+
const result = rollbackProjectUpdate(targetId2, {
|
|
52895
|
+
...identity,
|
|
52896
|
+
operation_id: request.operation_id,
|
|
52897
|
+
step_id: request.step_id,
|
|
52898
|
+
idempotency_key: request.idempotency_key,
|
|
52899
|
+
expected_revision: request.expected_revision,
|
|
52900
|
+
accepted_receipt_id: accepted.receipt_id
|
|
52901
|
+
}, this.db, identity, (project) => projectRecord(this.db, project).digest);
|
|
52902
|
+
return this.boundedGuardedUpdateResult(targetId2, result.project, result.receipt, request, startedAt);
|
|
52903
|
+
} catch (cause) {
|
|
52904
|
+
return guardedProjectError(cause);
|
|
52905
|
+
}
|
|
52906
|
+
}
|
|
52679
52907
|
async create(request) {
|
|
52680
52908
|
const startedAt = Date.now();
|
|
52681
52909
|
const path = assertForwardRequest2(request, this.capabilityValue);
|
|
@@ -52772,9 +53000,9 @@ class PackageOwnedMementosProjectRegistrationAuthority {
|
|
|
52772
53000
|
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "resource_kind must be project");
|
|
52773
53001
|
}
|
|
52774
53002
|
requireString(request.target_id, "target_id", {
|
|
52775
|
-
min:
|
|
52776
|
-
max:
|
|
52777
|
-
pattern:
|
|
53003
|
+
min: 8,
|
|
53004
|
+
max: 128,
|
|
53005
|
+
pattern: OPERATION_PATTERN
|
|
52778
53006
|
});
|
|
52779
53007
|
const path = ownedPath(request.target);
|
|
52780
53008
|
const project = getProjectByExactId3(this.db, request.target_id);
|
|
@@ -53033,6 +53261,31 @@ function fromWireReadRequest(body) {
|
|
|
53033
53261
|
target: new WirePathHandle(canonicalPath)
|
|
53034
53262
|
};
|
|
53035
53263
|
}
|
|
53264
|
+
function fromWireGuardedUpdateRequest(body) {
|
|
53265
|
+
const { target_id: targetId2, updates, ...request } = body;
|
|
53266
|
+
if (typeof targetId2 !== "string") {
|
|
53267
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "target_id is required on the private guarded-update transport");
|
|
53268
|
+
}
|
|
53269
|
+
if (!updates || typeof updates !== "object" || Array.isArray(updates) || typeof updates["path"] !== "string") {
|
|
53270
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", "updates.path is required on the private guarded-update transport");
|
|
53271
|
+
}
|
|
53272
|
+
return {
|
|
53273
|
+
targetId: targetId2,
|
|
53274
|
+
request: {
|
|
53275
|
+
...request,
|
|
53276
|
+
updates: {
|
|
53277
|
+
path: new WirePathHandle(String(updates["path"]))
|
|
53278
|
+
}
|
|
53279
|
+
}
|
|
53280
|
+
};
|
|
53281
|
+
}
|
|
53282
|
+
function exactWireIdentifier(body, field) {
|
|
53283
|
+
const value = body[field];
|
|
53284
|
+
if (typeof value !== "string") {
|
|
53285
|
+
throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_INPUT", `${field} is required on the guarded-update transport`);
|
|
53286
|
+
}
|
|
53287
|
+
return value;
|
|
53288
|
+
}
|
|
53036
53289
|
async function handleMementosProjectRegistrationHttpRequest(request, url, authority, basePath = "/v1/project-registration") {
|
|
53037
53290
|
const path = url.pathname;
|
|
53038
53291
|
if (path !== basePath && !path.startsWith(`${basePath}/`))
|
|
@@ -53067,6 +53320,21 @@ async function handleMementosProjectRegistrationHttpRequest(request, url, author
|
|
|
53067
53320
|
if (action === "verify-inverse") {
|
|
53068
53321
|
return json({ verification: await authority.verifyInverse(fromWireRequest(body)) });
|
|
53069
53322
|
}
|
|
53323
|
+
if (action === "projects/guarded-update") {
|
|
53324
|
+
const guarded = fromWireGuardedUpdateRequest(body);
|
|
53325
|
+
return json(await authority.guardedUpdateProject(guarded.targetId, guarded.request));
|
|
53326
|
+
}
|
|
53327
|
+
if (action === "projects/update-receipts/lookup") {
|
|
53328
|
+
const targetId2 = exactWireIdentifier(body, "target_id");
|
|
53329
|
+
const receiptId2 = exactWireIdentifier(body, "receipt_id");
|
|
53330
|
+
const { target_id: _targetId, receipt_id: _receiptId, ...lookup } = body;
|
|
53331
|
+
return json(await authority.getGuardedProjectUpdateReceipt(targetId2, receiptId2, lookup));
|
|
53332
|
+
}
|
|
53333
|
+
if (action === "projects/guarded-rollback") {
|
|
53334
|
+
const targetId2 = exactWireIdentifier(body, "target_id");
|
|
53335
|
+
const { target_id: _targetId, ...rollback } = body;
|
|
53336
|
+
return json(await authority.rollbackGuardedProjectUpdate(targetId2, rollback));
|
|
53337
|
+
}
|
|
53070
53338
|
return json({
|
|
53071
53339
|
error: "unknown Mementos project-registration route",
|
|
53072
53340
|
code: "MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND"
|
|
@@ -53099,6 +53367,15 @@ function toWireRequest(request) {
|
|
|
53099
53367
|
canonical_path: extractPath(target)
|
|
53100
53368
|
};
|
|
53101
53369
|
}
|
|
53370
|
+
function toWireGuardedUpdateRequest(targetId2, request) {
|
|
53371
|
+
return {
|
|
53372
|
+
...request,
|
|
53373
|
+
target_id: targetId2,
|
|
53374
|
+
updates: {
|
|
53375
|
+
path: extractPath(request.updates.path)
|
|
53376
|
+
}
|
|
53377
|
+
};
|
|
53378
|
+
}
|
|
53102
53379
|
|
|
53103
53380
|
class MementosProjectRegistrationHttpClient {
|
|
53104
53381
|
authority = "mementos";
|
|
@@ -53160,10 +53437,333 @@ class MementosProjectRegistrationHttpClient {
|
|
|
53160
53437
|
});
|
|
53161
53438
|
return body.verification;
|
|
53162
53439
|
}
|
|
53440
|
+
async guardedUpdateProject(targetId2, request) {
|
|
53441
|
+
return this.request("/projects/guarded-update", {
|
|
53442
|
+
method: "POST",
|
|
53443
|
+
body: JSON.stringify(toWireGuardedUpdateRequest(targetId2, request))
|
|
53444
|
+
});
|
|
53445
|
+
}
|
|
53446
|
+
async getGuardedProjectUpdateReceipt(targetId2, receiptId2, request) {
|
|
53447
|
+
return this.request("/projects/update-receipts/lookup", {
|
|
53448
|
+
method: "POST",
|
|
53449
|
+
body: JSON.stringify({ ...request, target_id: targetId2, receipt_id: receiptId2 })
|
|
53450
|
+
});
|
|
53451
|
+
}
|
|
53452
|
+
async rollbackGuardedProjectUpdate(targetId2, request) {
|
|
53453
|
+
return this.request("/projects/guarded-rollback", {
|
|
53454
|
+
method: "POST",
|
|
53455
|
+
body: JSON.stringify({ ...request, target_id: targetId2 })
|
|
53456
|
+
});
|
|
53457
|
+
}
|
|
53163
53458
|
}
|
|
53164
53459
|
function createMementosProjectRegistrationHttpClient(options) {
|
|
53165
53460
|
return new MementosProjectRegistrationHttpClient(options);
|
|
53166
53461
|
}
|
|
53462
|
+
// src/project-registration/project-resources.ts
|
|
53463
|
+
init_api_mode();
|
|
53464
|
+
init_database();
|
|
53465
|
+
var DEFAULT_PAGE_LIMIT = 100;
|
|
53466
|
+
var MAX_PAGE_LIMIT = 1000;
|
|
53467
|
+
var CURSOR_SCHEMA = "mementos.project-resources.cursor.v1";
|
|
53468
|
+
|
|
53469
|
+
class MementosProjectResourceError extends Error {
|
|
53470
|
+
code;
|
|
53471
|
+
details;
|
|
53472
|
+
constructor(code, message, details = {}) {
|
|
53473
|
+
super(message);
|
|
53474
|
+
this.code = code;
|
|
53475
|
+
this.details = details;
|
|
53476
|
+
this.name = "MementosProjectResourceError";
|
|
53477
|
+
}
|
|
53478
|
+
}
|
|
53479
|
+
function timestamp(value) {
|
|
53480
|
+
return value instanceof Date ? value.toISOString() : String(value);
|
|
53481
|
+
}
|
|
53482
|
+
function normalizeSqlValue(value) {
|
|
53483
|
+
if (value instanceof Date)
|
|
53484
|
+
return value.toISOString();
|
|
53485
|
+
if (Array.isArray(value))
|
|
53486
|
+
return value.map(normalizeSqlValue);
|
|
53487
|
+
if (!value || typeof value !== "object")
|
|
53488
|
+
return value;
|
|
53489
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalizeSqlValue(item)]));
|
|
53490
|
+
}
|
|
53491
|
+
function exactProject(db, projectId) {
|
|
53492
|
+
const row = db.get("SELECT id, name, path, description, memory_prefix, created_at, updated_at FROM projects WHERE id = ? LIMIT 1", projectId);
|
|
53493
|
+
if (!row) {
|
|
53494
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_PROJECT_NOT_FOUND", `Mementos project not found: ${projectId}`, { project_id: projectId });
|
|
53495
|
+
}
|
|
53496
|
+
return row;
|
|
53497
|
+
}
|
|
53498
|
+
function resourceKey(resource) {
|
|
53499
|
+
const rank = MEMENTOS_PROJECT_RESOURCE_KINDS.indexOf(resource.resource_kind);
|
|
53500
|
+
return `${String(rank).padStart(2, "0")}:${resource.stable_id}`;
|
|
53501
|
+
}
|
|
53502
|
+
function projectResource(project) {
|
|
53503
|
+
const normalized = normalizeSqlValue(project);
|
|
53504
|
+
return {
|
|
53505
|
+
authority: "mementos",
|
|
53506
|
+
source_package: "@hasna/mementos",
|
|
53507
|
+
project_id: project.id,
|
|
53508
|
+
resource_kind: "project",
|
|
53509
|
+
stable_id: project.id,
|
|
53510
|
+
revision: timestamp(project.updated_at),
|
|
53511
|
+
digest: digestMementosProjectRegistrationValue(normalized),
|
|
53512
|
+
membership: "project_aggregate"
|
|
53513
|
+
};
|
|
53514
|
+
}
|
|
53515
|
+
function memoryResources(db, projectId) {
|
|
53516
|
+
const rows = db.all("SELECT * FROM memories WHERE project_id = ? ORDER BY id ASC", projectId);
|
|
53517
|
+
return rows.map((row) => {
|
|
53518
|
+
const memory = normalizeSqlValue(parseMemoryRow(row));
|
|
53519
|
+
return {
|
|
53520
|
+
authority: "mementos",
|
|
53521
|
+
source_package: "@hasna/mementos",
|
|
53522
|
+
project_id: projectId,
|
|
53523
|
+
resource_kind: row["category"] === "knowledge" ? "knowledge" : "memory",
|
|
53524
|
+
stable_id: String(row["id"]),
|
|
53525
|
+
revision: timestamp(row["updated_at"]),
|
|
53526
|
+
digest: digestMementosProjectRegistrationValue(memory),
|
|
53527
|
+
membership: "explicit_project_id_or_focus"
|
|
53528
|
+
};
|
|
53529
|
+
});
|
|
53530
|
+
}
|
|
53531
|
+
function sessionResources(db, projectId) {
|
|
53532
|
+
const rows = db.all("SELECT * FROM session_memory_jobs WHERE project_id = ? ORDER BY id ASC", projectId);
|
|
53533
|
+
return rows.map((row) => {
|
|
53534
|
+
const normalized = {
|
|
53535
|
+
id: String(row["id"]),
|
|
53536
|
+
session_id: String(row["session_id"]),
|
|
53537
|
+
agent_id: row["agent_id"] === null ? null : String(row["agent_id"] ?? "") || null,
|
|
53538
|
+
project_id: row["project_id"] === null ? null : String(row["project_id"] ?? "") || null,
|
|
53539
|
+
source: String(row["source"]),
|
|
53540
|
+
status: String(row["status"]),
|
|
53541
|
+
transcript: String(row["transcript"]),
|
|
53542
|
+
chunk_count: Number(row["chunk_count"]),
|
|
53543
|
+
memories_extracted: Number(row["memories_extracted"]),
|
|
53544
|
+
error: row["error"] === null ? null : String(row["error"] ?? "") || null,
|
|
53545
|
+
metadata: typeof row["metadata"] === "string" ? JSON.parse(row["metadata"] || "{}") : normalizeSqlValue(row["metadata"] ?? {}),
|
|
53546
|
+
created_at: timestamp(row["created_at"]),
|
|
53547
|
+
started_at: row["started_at"] === null ? null : timestamp(row["started_at"]),
|
|
53548
|
+
completed_at: row["completed_at"] === null ? null : timestamp(row["completed_at"])
|
|
53549
|
+
};
|
|
53550
|
+
return {
|
|
53551
|
+
authority: "mementos",
|
|
53552
|
+
source_package: "@hasna/mementos",
|
|
53553
|
+
project_id: projectId,
|
|
53554
|
+
resource_kind: "session",
|
|
53555
|
+
stable_id: String(row["id"]),
|
|
53556
|
+
revision: timestamp(row["completed_at"] ?? row["started_at"] ?? row["created_at"]),
|
|
53557
|
+
digest: digestMementosProjectRegistrationValue(normalized),
|
|
53558
|
+
membership: "explicit_project_id_or_focus"
|
|
53559
|
+
};
|
|
53560
|
+
});
|
|
53561
|
+
}
|
|
53562
|
+
function normalizeResourceKinds(value) {
|
|
53563
|
+
if (!value)
|
|
53564
|
+
return [...MEMENTOS_PROJECT_RESOURCE_KINDS];
|
|
53565
|
+
if (value.length === 0) {
|
|
53566
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", "resource_kinds must contain at least one supported resource kind");
|
|
53567
|
+
}
|
|
53568
|
+
const requested = new Set(value);
|
|
53569
|
+
for (const kind of requested) {
|
|
53570
|
+
if (!MEMENTOS_PROJECT_RESOURCE_KINDS.includes(kind)) {
|
|
53571
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", `Unsupported Mementos project resource kind: ${kind}`);
|
|
53572
|
+
}
|
|
53573
|
+
}
|
|
53574
|
+
return MEMENTOS_PROJECT_RESOURCE_KINDS.filter((kind) => requested.has(kind));
|
|
53575
|
+
}
|
|
53576
|
+
function normalizeLimit(value) {
|
|
53577
|
+
const limit = value ?? DEFAULT_PAGE_LIMIT;
|
|
53578
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_PAGE_LIMIT) {
|
|
53579
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", `limit must be an integer between 1 and ${MAX_PAGE_LIMIT}`);
|
|
53580
|
+
}
|
|
53581
|
+
return limit;
|
|
53582
|
+
}
|
|
53583
|
+
function encodeCursor(cursor) {
|
|
53584
|
+
return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
|
|
53585
|
+
}
|
|
53586
|
+
function decodeCursor(raw) {
|
|
53587
|
+
try {
|
|
53588
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
53589
|
+
if (parsed.schema !== CURSOR_SCHEMA || typeof parsed.project_id !== "string" || typeof parsed.collection_revision !== "string" || !Array.isArray(parsed.resource_kinds) || typeof parsed.after_key !== "string") {
|
|
53590
|
+
throw new Error("invalid cursor shape");
|
|
53591
|
+
}
|
|
53592
|
+
return parsed;
|
|
53593
|
+
} catch {
|
|
53594
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", "cursor is not a valid Mementos project-resource cursor");
|
|
53595
|
+
}
|
|
53596
|
+
}
|
|
53597
|
+
function localPopulation(projectId, db, resourceKinds) {
|
|
53598
|
+
const project = exactProject(db, projectId);
|
|
53599
|
+
const selected = new Set(resourceKinds);
|
|
53600
|
+
const resources = [
|
|
53601
|
+
...selected.has("project") ? [projectResource(project)] : [],
|
|
53602
|
+
...memoryResources(db, projectId).filter((resource) => selected.has(resource.resource_kind)),
|
|
53603
|
+
...selected.has("session") ? sessionResources(db, projectId) : []
|
|
53604
|
+
].sort((left, right) => resourceKey(left).localeCompare(resourceKey(right)));
|
|
53605
|
+
const collectionRevision = digestMementosProjectRegistrationValue({
|
|
53606
|
+
schema: MEMENTOS_PROJECT_RESOURCE_ROUTE,
|
|
53607
|
+
project_id: projectId,
|
|
53608
|
+
project_revision: timestamp(project.updated_at),
|
|
53609
|
+
resource_kinds: resourceKinds,
|
|
53610
|
+
resources: resources.map((resource) => ({
|
|
53611
|
+
resource_kind: resource.resource_kind,
|
|
53612
|
+
stable_id: resource.stable_id,
|
|
53613
|
+
revision: resource.revision,
|
|
53614
|
+
digest: resource.digest
|
|
53615
|
+
}))
|
|
53616
|
+
});
|
|
53617
|
+
return { project, resources, collectionRevision };
|
|
53618
|
+
}
|
|
53619
|
+
function readMementosProjectResourcePage(projectId, options = {}, db, authorityOptions = {}) {
|
|
53620
|
+
const resourceKinds = normalizeResourceKinds(options.resource_kinds);
|
|
53621
|
+
const limit = normalizeLimit(options.limit);
|
|
53622
|
+
if (!db && isApiMode()) {
|
|
53623
|
+
const { data } = apiJson("GET", `/projects/${encodeURIComponent(projectId)}/resources${toQuery({
|
|
53624
|
+
limit,
|
|
53625
|
+
cursor: options.cursor ?? undefined,
|
|
53626
|
+
resource_kinds: resourceKinds.join(",")
|
|
53627
|
+
})}`);
|
|
53628
|
+
return data;
|
|
53629
|
+
}
|
|
53630
|
+
const d = db ?? getDatabase();
|
|
53631
|
+
const { project, resources, collectionRevision } = localPopulation(projectId, d, resourceKinds);
|
|
53632
|
+
let start = 0;
|
|
53633
|
+
if (options.cursor) {
|
|
53634
|
+
const cursor = decodeCursor(options.cursor);
|
|
53635
|
+
if (cursor.project_id !== projectId || JSON.stringify(cursor.resource_kinds) !== JSON.stringify(resourceKinds)) {
|
|
53636
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", "cursor does not belong to this project and resource-kind selection");
|
|
53637
|
+
}
|
|
53638
|
+
if (cursor.collection_revision !== collectionRevision) {
|
|
53639
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_COLLECTION_CHANGED", "Mementos project resource collection changed; restart from the first page", {
|
|
53640
|
+
cursor_collection_revision: cursor.collection_revision,
|
|
53641
|
+
current_collection_revision: collectionRevision
|
|
53642
|
+
});
|
|
53643
|
+
}
|
|
53644
|
+
const afterIndex = resources.findIndex((resource) => resourceKey(resource) === cursor.after_key);
|
|
53645
|
+
if (afterIndex < 0) {
|
|
53646
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_COLLECTION_CHANGED", "Mementos project resource cursor no longer names a member; restart from the first page");
|
|
53647
|
+
}
|
|
53648
|
+
start = afterIndex + 1;
|
|
53649
|
+
}
|
|
53650
|
+
const pageResources = resources.slice(start, start + limit);
|
|
53651
|
+
const hasMore = start + pageResources.length < resources.length;
|
|
53652
|
+
const nextCursor = hasMore && pageResources.length > 0 ? encodeCursor({
|
|
53653
|
+
schema: CURSOR_SCHEMA,
|
|
53654
|
+
project_id: projectId,
|
|
53655
|
+
collection_revision: collectionRevision,
|
|
53656
|
+
resource_kinds: resourceKinds,
|
|
53657
|
+
after_key: resourceKey(pageResources[pageResources.length - 1])
|
|
53658
|
+
}) : null;
|
|
53659
|
+
const capability = buildMementosProjectRegistrationCapability(authorityOptions);
|
|
53660
|
+
return {
|
|
53661
|
+
schema: "mementos.project-resources.v1",
|
|
53662
|
+
authority: {
|
|
53663
|
+
authority: capability.authority,
|
|
53664
|
+
authority_id: capability.authority_id,
|
|
53665
|
+
tenant_id: capability.tenant_id,
|
|
53666
|
+
corpus_id: capability.corpus_id,
|
|
53667
|
+
package_version: capability.package_version
|
|
53668
|
+
},
|
|
53669
|
+
project_id: projectId,
|
|
53670
|
+
project_revision: timestamp(project.updated_at),
|
|
53671
|
+
collection_revision: collectionRevision,
|
|
53672
|
+
resource_kinds: resourceKinds,
|
|
53673
|
+
resources: pageResources,
|
|
53674
|
+
count: pageResources.length,
|
|
53675
|
+
total: resources.length,
|
|
53676
|
+
limit,
|
|
53677
|
+
cursor: options.cursor ?? null,
|
|
53678
|
+
next_cursor: nextCursor,
|
|
53679
|
+
has_more: hasMore,
|
|
53680
|
+
complete: true,
|
|
53681
|
+
truncated: false
|
|
53682
|
+
};
|
|
53683
|
+
}
|
|
53684
|
+
function readAllMementosProjectResources(projectId, options = {}, db, authorityOptions = {}) {
|
|
53685
|
+
const pageSize = normalizeLimit(options.page_size);
|
|
53686
|
+
let cursor = null;
|
|
53687
|
+
let first = null;
|
|
53688
|
+
const resources = [];
|
|
53689
|
+
const seen = new Set;
|
|
53690
|
+
do {
|
|
53691
|
+
const page = readMementosProjectResourcePage(projectId, {
|
|
53692
|
+
limit: pageSize,
|
|
53693
|
+
cursor,
|
|
53694
|
+
resource_kinds: options.resource_kinds
|
|
53695
|
+
}, db, authorityOptions);
|
|
53696
|
+
if (!first)
|
|
53697
|
+
first = page;
|
|
53698
|
+
if (page.collection_revision !== first.collection_revision || page.total !== first.total || JSON.stringify(page.resource_kinds) !== JSON.stringify(first.resource_kinds)) {
|
|
53699
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_COLLECTION_CHANGED", "Mementos project resource collection changed during complete traversal");
|
|
53700
|
+
}
|
|
53701
|
+
for (const resource of page.resources) {
|
|
53702
|
+
const key = resourceKey(resource);
|
|
53703
|
+
if (seen.has(key)) {
|
|
53704
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", `Mementos project resource traversal returned duplicate stable ID: ${key}`);
|
|
53705
|
+
}
|
|
53706
|
+
seen.add(key);
|
|
53707
|
+
resources.push(resource);
|
|
53708
|
+
}
|
|
53709
|
+
if (page.has_more && !page.next_cursor) {
|
|
53710
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", "Mementos project resource page claimed more results without a continuation cursor");
|
|
53711
|
+
}
|
|
53712
|
+
cursor = page.next_cursor;
|
|
53713
|
+
} while (cursor);
|
|
53714
|
+
if (!first) {
|
|
53715
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", "Mementos project resource traversal returned no first page");
|
|
53716
|
+
}
|
|
53717
|
+
if (resources.length !== first.total) {
|
|
53718
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", `Mementos project resource traversal returned ${resources.length} of ${first.total} resources`);
|
|
53719
|
+
}
|
|
53720
|
+
return {
|
|
53721
|
+
...first,
|
|
53722
|
+
resources,
|
|
53723
|
+
count: resources.length,
|
|
53724
|
+
total: resources.length,
|
|
53725
|
+
limit: pageSize,
|
|
53726
|
+
cursor: null,
|
|
53727
|
+
next_cursor: null,
|
|
53728
|
+
has_more: false,
|
|
53729
|
+
complete: true,
|
|
53730
|
+
truncated: false
|
|
53731
|
+
};
|
|
53732
|
+
}
|
|
53733
|
+
function getMementosProjectResourceExact(projectId, resourceKind, stableId, db, authorityOptions = {}) {
|
|
53734
|
+
if (!MEMENTOS_PROJECT_RESOURCE_KINDS.includes(resourceKind)) {
|
|
53735
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", `Unsupported Mementos project resource kind: ${resourceKind}`);
|
|
53736
|
+
}
|
|
53737
|
+
if (!db && isApiMode()) {
|
|
53738
|
+
const { data } = apiJson("GET", `/projects/${encodeURIComponent(projectId)}/resources/${encodeURIComponent(resourceKind)}/${encodeURIComponent(stableId)}`);
|
|
53739
|
+
return data;
|
|
53740
|
+
}
|
|
53741
|
+
const d = db ?? getDatabase();
|
|
53742
|
+
const { project, resources, collectionRevision } = localPopulation(projectId, d, [
|
|
53743
|
+
resourceKind
|
|
53744
|
+
]);
|
|
53745
|
+
const resource = resources.find((candidate) => candidate.stable_id === stableId);
|
|
53746
|
+
if (!resource) {
|
|
53747
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_NOT_FOUND", `Mementos ${resourceKind} resource not found in project ${projectId}: ${stableId}`, { project_id: projectId, resource_kind: resourceKind, stable_id: stableId });
|
|
53748
|
+
}
|
|
53749
|
+
const capability = buildMementosProjectRegistrationCapability(authorityOptions);
|
|
53750
|
+
return {
|
|
53751
|
+
schema: "mementos.project-resource.v1",
|
|
53752
|
+
authority: {
|
|
53753
|
+
authority: capability.authority,
|
|
53754
|
+
authority_id: capability.authority_id,
|
|
53755
|
+
tenant_id: capability.tenant_id,
|
|
53756
|
+
corpus_id: capability.corpus_id,
|
|
53757
|
+
package_version: capability.package_version
|
|
53758
|
+
},
|
|
53759
|
+
project_id: projectId,
|
|
53760
|
+
project_revision: timestamp(project.updated_at),
|
|
53761
|
+
collection_revision: collectionRevision,
|
|
53762
|
+
resource,
|
|
53763
|
+
complete: true,
|
|
53764
|
+
truncated: false
|
|
53765
|
+
};
|
|
53766
|
+
}
|
|
53167
53767
|
// src/db/machines.ts
|
|
53168
53768
|
init_database();
|
|
53169
53769
|
import { hostname, platform } from "os";
|
|
@@ -53288,13 +53888,13 @@ function createEntity(input, db) {
|
|
|
53288
53888
|
return data;
|
|
53289
53889
|
}
|
|
53290
53890
|
const d = db || getDatabase();
|
|
53291
|
-
const
|
|
53891
|
+
const timestamp2 = now();
|
|
53292
53892
|
const metadataJson = JSON.stringify(input.metadata || {});
|
|
53293
53893
|
const existing = d.query(`SELECT * FROM entities
|
|
53294
53894
|
WHERE name = ? AND type = ? AND COALESCE(project_id, '') = ?`).get(input.name, input.type, input.project_id || "");
|
|
53295
53895
|
if (existing) {
|
|
53296
53896
|
const sets = ["updated_at = ?"];
|
|
53297
|
-
const params = [
|
|
53897
|
+
const params = [timestamp2];
|
|
53298
53898
|
if (input.description !== undefined) {
|
|
53299
53899
|
sets.push("description = ?");
|
|
53300
53900
|
params.push(input.description);
|
|
@@ -53317,8 +53917,8 @@ function createEntity(input, db) {
|
|
|
53317
53917
|
input.description || null,
|
|
53318
53918
|
metadataJson,
|
|
53319
53919
|
input.project_id || null,
|
|
53320
|
-
|
|
53321
|
-
|
|
53920
|
+
timestamp2,
|
|
53921
|
+
timestamp2
|
|
53322
53922
|
]);
|
|
53323
53923
|
hookRegistry.runHooks("PostEntityCreate", {
|
|
53324
53924
|
entityId: id,
|
|
@@ -54146,7 +54746,7 @@ function memoryResource(memory) {
|
|
|
54146
54746
|
tags: memory.tags
|
|
54147
54747
|
};
|
|
54148
54748
|
}
|
|
54149
|
-
function
|
|
54749
|
+
function projectResource2(projectId, name, externalId) {
|
|
54150
54750
|
return {
|
|
54151
54751
|
kind: "project",
|
|
54152
54752
|
id: projectId,
|
|
@@ -54252,7 +54852,7 @@ function createMementosProjectPanel(projectRef, options = {}) {
|
|
|
54252
54852
|
actionResource("mementos:save", "Save project memory")
|
|
54253
54853
|
],
|
|
54254
54854
|
resourceRefs: [
|
|
54255
|
-
|
|
54855
|
+
projectResource2(projectId, project?.name ?? projectRef, project?.id ?? projectRef),
|
|
54256
54856
|
...memories.slice(0, limit).map(memoryResource)
|
|
54257
54857
|
],
|
|
54258
54858
|
renderFragment: {
|
|
@@ -54854,29 +55454,29 @@ function enforceQuotas(config, db) {
|
|
|
54854
55454
|
}
|
|
54855
55455
|
function archiveStale(staleDays, db) {
|
|
54856
55456
|
const d = db || getDatabase();
|
|
54857
|
-
const
|
|
55457
|
+
const timestamp2 = now();
|
|
54858
55458
|
const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000).toISOString();
|
|
54859
55459
|
const archiveWhere = `status = 'active' AND pinned = 0 AND COALESCE(accessed_at, created_at) < ?`;
|
|
54860
55460
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${archiveWhere}`).get(cutoff).c;
|
|
54861
55461
|
if (count > 0) {
|
|
54862
|
-
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${archiveWhere}`, [
|
|
55462
|
+
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${archiveWhere}`, [timestamp2, cutoff]);
|
|
54863
55463
|
}
|
|
54864
55464
|
return count;
|
|
54865
55465
|
}
|
|
54866
55466
|
function archiveUnused(days, db) {
|
|
54867
55467
|
const d = db || getDatabase();
|
|
54868
|
-
const
|
|
55468
|
+
const timestamp2 = now();
|
|
54869
55469
|
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
54870
55470
|
const unusedWhere = `status = 'active' AND pinned = 0 AND access_count = 0 AND created_at < ?`;
|
|
54871
55471
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${unusedWhere}`).get(cutoff).c;
|
|
54872
55472
|
if (count > 0) {
|
|
54873
|
-
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${unusedWhere}`, [
|
|
55473
|
+
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${unusedWhere}`, [timestamp2, cutoff]);
|
|
54874
55474
|
}
|
|
54875
55475
|
return count;
|
|
54876
55476
|
}
|
|
54877
55477
|
function deprioritizeStale(days, db) {
|
|
54878
55478
|
const d = db || getDatabase();
|
|
54879
|
-
const
|
|
55479
|
+
const timestamp2 = now();
|
|
54880
55480
|
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
54881
55481
|
const deprioWhere = `status = 'active' AND pinned = 0 AND importance > 1 AND COALESCE(accessed_at, updated_at) < ?`;
|
|
54882
55482
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${deprioWhere}`).get(cutoff).c;
|
|
@@ -54885,7 +55485,7 @@ function deprioritizeStale(days, db) {
|
|
|
54885
55485
|
SET importance = importance - 1,
|
|
54886
55486
|
version = version + 1,
|
|
54887
55487
|
updated_at = ?
|
|
54888
|
-
WHERE ${deprioWhere}`, [
|
|
55488
|
+
WHERE ${deprioWhere}`, [timestamp2, cutoff]);
|
|
54889
55489
|
}
|
|
54890
55490
|
return count;
|
|
54891
55491
|
}
|
|
@@ -54909,9 +55509,9 @@ function getAgentSyncDir(agentName) {
|
|
|
54909
55509
|
}
|
|
54910
55510
|
return dir;
|
|
54911
55511
|
}
|
|
54912
|
-
function setHighWaterMark(agentDir,
|
|
55512
|
+
function setHighWaterMark(agentDir, timestamp2) {
|
|
54913
55513
|
const markFile = join6(agentDir, ".highwatermark");
|
|
54914
|
-
writeFileSync4(markFile,
|
|
55514
|
+
writeFileSync4(markFile, timestamp2, "utf-8");
|
|
54915
55515
|
}
|
|
54916
55516
|
function resolveConflict(local, remote, resolution) {
|
|
54917
55517
|
switch (resolution) {
|
|
@@ -55231,13 +55831,13 @@ function buildConflictKey(key, sourceMachine, updatedAt) {
|
|
|
55231
55831
|
return `${key}__conflict__${machineSegment}__${timestampSegment || "0"}`;
|
|
55232
55832
|
}
|
|
55233
55833
|
function buildConflictClone(loser, sourceMachine, winnerId) {
|
|
55234
|
-
const
|
|
55834
|
+
const timestamp2 = new Date().toISOString();
|
|
55235
55835
|
const tags = new Set(ensureArrayValue(loser["tags"]));
|
|
55236
55836
|
tags.add("sync-conflict");
|
|
55237
55837
|
tags.add(`source_machine:${sourceMachine}`);
|
|
55238
55838
|
const metadata = ensureObjectValue(loser["metadata"]);
|
|
55239
55839
|
metadata["sync_conflict"] = true;
|
|
55240
|
-
metadata["conflict_detected_at"] =
|
|
55840
|
+
metadata["conflict_detected_at"] = timestamp2;
|
|
55241
55841
|
metadata["conflict_original_id"] = loser["id"];
|
|
55242
55842
|
metadata["conflict_winner_id"] = winnerId;
|
|
55243
55843
|
metadata["conflict_source_machine"] = sourceMachine;
|
|
@@ -55249,10 +55849,10 @@ function buildConflictClone(loser, sourceMachine, winnerId) {
|
|
|
55249
55849
|
metadata: JSON.stringify(metadata),
|
|
55250
55850
|
access_count: 0,
|
|
55251
55851
|
version: 1,
|
|
55252
|
-
created_at:
|
|
55253
|
-
updated_at:
|
|
55852
|
+
created_at: timestamp2,
|
|
55853
|
+
updated_at: timestamp2,
|
|
55254
55854
|
..."accessed_at" in loser ? { accessed_at: null } : {},
|
|
55255
|
-
..."ingested_at" in loser ? { ingested_at:
|
|
55855
|
+
..."ingested_at" in loser ? { ingested_at: timestamp2 } : {}
|
|
55256
55856
|
}, sourceMachine);
|
|
55257
55857
|
}
|
|
55258
55858
|
function insertConflictCloneIfMissing(db, clone) {
|
|
@@ -55502,13 +56102,13 @@ function createRelation(input, db) {
|
|
|
55502
56102
|
}
|
|
55503
56103
|
const d = db || getDatabase();
|
|
55504
56104
|
const id = shortUuid();
|
|
55505
|
-
const
|
|
56105
|
+
const timestamp2 = now();
|
|
55506
56106
|
const weight = input.weight ?? 1;
|
|
55507
56107
|
const metadata = JSON.stringify(input.metadata ?? {});
|
|
55508
56108
|
d.run(`INSERT INTO relations (id, source_entity_id, target_entity_id, relation_type, weight, metadata, created_at)
|
|
55509
56109
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
55510
56110
|
ON CONFLICT(source_entity_id, target_entity_id, relation_type)
|
|
55511
|
-
DO UPDATE SET weight = excluded.weight, metadata = excluded.metadata`, [id, input.source_entity_id, input.target_entity_id, input.relation_type, weight, metadata,
|
|
56111
|
+
DO UPDATE SET weight = excluded.weight, metadata = excluded.metadata`, [id, input.source_entity_id, input.target_entity_id, input.relation_type, weight, metadata, timestamp2]);
|
|
55512
56112
|
const row = d.query(`SELECT * FROM relations
|
|
55513
56113
|
WHERE source_entity_id = ? AND target_entity_id = ? AND relation_type = ?`).get(input.source_entity_id, input.target_entity_id, input.relation_type);
|
|
55514
56114
|
const relation = parseRelationRow(row);
|
|
@@ -55685,7 +56285,7 @@ function parseMemoryLink(row) {
|
|
|
55685
56285
|
function createMemoryLink(input, db) {
|
|
55686
56286
|
const d = db || getDatabase();
|
|
55687
56287
|
const id = shortUuid();
|
|
55688
|
-
const
|
|
56288
|
+
const timestamp2 = now();
|
|
55689
56289
|
d.run(`INSERT OR IGNORE INTO memory_links (id, source_memory_id, target_memory_id, relation_type, run_id, metadata, created_at)
|
|
55690
56290
|
VALUES (?, ?, ?, ?, ?, ?, ?)`, [
|
|
55691
56291
|
id,
|
|
@@ -55694,7 +56294,7 @@ function createMemoryLink(input, db) {
|
|
|
55694
56294
|
input.relation_type,
|
|
55695
56295
|
input.run_id ?? null,
|
|
55696
56296
|
JSON.stringify(input.metadata ?? {}),
|
|
55697
|
-
|
|
56297
|
+
timestamp2
|
|
55698
56298
|
]);
|
|
55699
56299
|
const row = d.query(`SELECT * FROM memory_links
|
|
55700
56300
|
WHERE source_memory_id = ? AND target_memory_id = ? AND relation_type = ? AND COALESCE(run_id, '') = ?
|
|
@@ -57983,6 +58583,7 @@ export {
|
|
|
57983
58583
|
rollbackMemoryProjectLink,
|
|
57984
58584
|
resolveProjectId,
|
|
57985
58585
|
resolvePartialId,
|
|
58586
|
+
resolveMementosProjectAuthorityIdentity,
|
|
57986
58587
|
resetDatabase,
|
|
57987
58588
|
renameMachine,
|
|
57988
58589
|
releaseResourceLocks,
|
|
@@ -57995,6 +58596,8 @@ export {
|
|
|
57995
58596
|
registerAgent,
|
|
57996
58597
|
reflectOnTrajectory,
|
|
57997
58598
|
redactSecrets,
|
|
58599
|
+
readMementosProjectResourcePage,
|
|
58600
|
+
readAllMementosProjectResources,
|
|
57998
58601
|
pushStorageChanges,
|
|
57999
58602
|
pullStorageChanges,
|
|
58000
58603
|
providerRegistry,
|
|
@@ -58055,6 +58658,7 @@ export {
|
|
|
58055
58658
|
getMemoriesForEntity,
|
|
58056
58659
|
getMemoriesByKey,
|
|
58057
58660
|
getMementosStorageStatus,
|
|
58661
|
+
getMementosProjectResourceExact,
|
|
58058
58662
|
getMachine,
|
|
58059
58663
|
getFocus,
|
|
58060
58664
|
getFallbackSyncTargetMachine,
|
|
@@ -58109,6 +58713,7 @@ export {
|
|
|
58109
58713
|
canonicalMementosProjectRegistrationJson,
|
|
58110
58714
|
bulkLinkEntities,
|
|
58111
58715
|
bulkDeleteMemories,
|
|
58716
|
+
buildMementosProjectRegistrationCapability,
|
|
58112
58717
|
buildFocusFilter,
|
|
58113
58718
|
archiveUnused,
|
|
58114
58719
|
archiveStale,
|
|
@@ -58131,17 +58736,22 @@ export {
|
|
|
58131
58736
|
MemoryLockConflictError,
|
|
58132
58737
|
MemoryInjector,
|
|
58133
58738
|
MemoryExpiredError,
|
|
58739
|
+
MementosProjectResourceError,
|
|
58134
58740
|
MementosProjectRegistrationHttpClient,
|
|
58135
58741
|
MementosProjectRegistrationError,
|
|
58742
|
+
MementosProjectAuthorityIdentityError,
|
|
58136
58743
|
MEMORY_PROJECT_LINK_RECEIPT_COLUMNS,
|
|
58137
58744
|
MEMENTOS_STORAGE_TABLES,
|
|
58138
58745
|
MEMENTOS_STORAGE_FALLBACK_ENV,
|
|
58139
58746
|
MEMENTOS_STORAGE_ENV,
|
|
58747
|
+
MEMENTOS_PROJECT_RESOURCE_ROUTE,
|
|
58748
|
+
MEMENTOS_PROJECT_RESOURCE_KINDS,
|
|
58140
58749
|
MEMENTOS_PROJECT_REGISTRATION_SCHEMA_VERSION,
|
|
58141
58750
|
MEMENTOS_PROJECT_REGISTRATION_ROUTE,
|
|
58142
58751
|
MEMENTOS_PROJECT_REGISTRATION_CALLER_ROUTE,
|
|
58143
58752
|
MEMENTOS_PROJECT_REFERENCE_SURFACES,
|
|
58144
58753
|
MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
|
|
58754
|
+
MEMENTOS_PROJECT_AUTHORITY_ENV,
|
|
58145
58755
|
MEMENTOS_MEMORY_PROJECT_LINK_ROUTE,
|
|
58146
58756
|
InvalidScopeError,
|
|
58147
58757
|
EntityNotFoundError,
|