@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/cli/index.js
CHANGED
|
@@ -6359,8 +6359,86 @@ function getMementosPackageVersion() {
|
|
|
6359
6359
|
var init_package_version = () => {};
|
|
6360
6360
|
|
|
6361
6361
|
// src/project-registration/types.ts
|
|
6362
|
-
var MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE = "mementos.project-guarded-update.v1";
|
|
6363
|
-
var init_types2 = () => {
|
|
6362
|
+
var MEMENTOS_PROJECT_REGISTRATION_ROUTE = "mementos.project-registration.v1", MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE = "mementos.project-guarded-update.v1", MEMENTOS_PROJECT_RESOURCE_ROUTE = "mementos.project-resources.v1", MEMENTOS_PROJECT_RESOURCE_KINDS;
|
|
6363
|
+
var init_types2 = __esm(() => {
|
|
6364
|
+
MEMENTOS_PROJECT_RESOURCE_KINDS = [
|
|
6365
|
+
"project",
|
|
6366
|
+
"knowledge",
|
|
6367
|
+
"memory",
|
|
6368
|
+
"session"
|
|
6369
|
+
];
|
|
6370
|
+
});
|
|
6371
|
+
|
|
6372
|
+
// src/project-registration/identity.ts
|
|
6373
|
+
function configuredValue(override, envKey) {
|
|
6374
|
+
return override?.trim() || process.env[envKey]?.trim() || null;
|
|
6375
|
+
}
|
|
6376
|
+
function resolveMementosProjectAuthorityIdentity(options = {}) {
|
|
6377
|
+
const authorityId = configuredValue(options.authorityId, MEMENTOS_PROJECT_AUTHORITY_ENV.authorityId);
|
|
6378
|
+
const tenantId = configuredValue(options.tenantId, MEMENTOS_PROJECT_AUTHORITY_ENV.tenantId);
|
|
6379
|
+
const corpusId = configuredValue(options.corpusId, MEMENTOS_PROJECT_AUTHORITY_ENV.corpusId);
|
|
6380
|
+
if (!authorityId || !tenantId || !corpusId) {
|
|
6381
|
+
const missingEnv = [];
|
|
6382
|
+
if (!authorityId)
|
|
6383
|
+
missingEnv.push(MEMENTOS_PROJECT_AUTHORITY_ENV.authorityId);
|
|
6384
|
+
if (!tenantId)
|
|
6385
|
+
missingEnv.push(MEMENTOS_PROJECT_AUTHORITY_ENV.tenantId);
|
|
6386
|
+
if (!corpusId)
|
|
6387
|
+
missingEnv.push(MEMENTOS_PROJECT_AUTHORITY_ENV.corpusId);
|
|
6388
|
+
throw new MementosProjectAuthorityIdentityError(missingEnv);
|
|
6389
|
+
}
|
|
6390
|
+
return {
|
|
6391
|
+
authority_id: authorityId,
|
|
6392
|
+
tenant_id: tenantId,
|
|
6393
|
+
corpus_id: corpusId
|
|
6394
|
+
};
|
|
6395
|
+
}
|
|
6396
|
+
function buildMementosProjectRegistrationCapability(options = {}) {
|
|
6397
|
+
const identity = resolveMementosProjectAuthorityIdentity(options);
|
|
6398
|
+
return {
|
|
6399
|
+
authority: "mementos",
|
|
6400
|
+
route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
|
|
6401
|
+
package_version: options.packageVersion ?? getMementosPackageVersion(),
|
|
6402
|
+
...identity,
|
|
6403
|
+
supported_resources: ["project"],
|
|
6404
|
+
conditional_create: true,
|
|
6405
|
+
immutable_receipts: true,
|
|
6406
|
+
exact_terminal_lookup: true,
|
|
6407
|
+
exact_readback: true,
|
|
6408
|
+
conditional_inverse: true,
|
|
6409
|
+
ambiguous_outcome_reconciliation: true,
|
|
6410
|
+
guarded_update: true,
|
|
6411
|
+
guarded_update_route: MEMENTOS_PROJECT_GUARDED_UPDATE_ROUTE,
|
|
6412
|
+
no_write_dry_run: true,
|
|
6413
|
+
expected_revision_compare_and_swap: true,
|
|
6414
|
+
caller_idempotency: true,
|
|
6415
|
+
exact_inverse_rollback: true,
|
|
6416
|
+
project_resource_enumeration: true,
|
|
6417
|
+
project_resource_route: MEMENTOS_PROJECT_RESOURCE_ROUTE,
|
|
6418
|
+
project_resource_kinds: ["project", "knowledge", "memory", "session"],
|
|
6419
|
+
stable_keyset_pagination: true,
|
|
6420
|
+
explicit_membership_only: true
|
|
6421
|
+
};
|
|
6422
|
+
}
|
|
6423
|
+
var MEMENTOS_PROJECT_AUTHORITY_ENV, MementosProjectAuthorityIdentityError;
|
|
6424
|
+
var init_identity = __esm(() => {
|
|
6425
|
+
init_package_version();
|
|
6426
|
+
init_types2();
|
|
6427
|
+
MEMENTOS_PROJECT_AUTHORITY_ENV = {
|
|
6428
|
+
authorityId: "MEMENTOS_PROJECT_AUTHORITY_ID",
|
|
6429
|
+
tenantId: "MEMENTOS_PROJECT_TENANT_ID",
|
|
6430
|
+
corpusId: "MEMENTOS_PROJECT_CORPUS_ID"
|
|
6431
|
+
};
|
|
6432
|
+
MementosProjectAuthorityIdentityError = class MementosProjectAuthorityIdentityError extends Error {
|
|
6433
|
+
missing_env;
|
|
6434
|
+
code = "MEMENTOS_PROJECT_AUTHORITY_UNCONFIGURED";
|
|
6435
|
+
constructor(missing_env) {
|
|
6436
|
+
super("Mementos project authority identity is not configured; set " + missing_env.join(", "));
|
|
6437
|
+
this.missing_env = missing_env;
|
|
6438
|
+
this.name = "MementosProjectAuthorityIdentityError";
|
|
6439
|
+
}
|
|
6440
|
+
};
|
|
6441
|
+
});
|
|
6364
6442
|
|
|
6365
6443
|
// src/db/projects.ts
|
|
6366
6444
|
var exports_projects = {};
|
|
@@ -6388,6 +6466,16 @@ function parseProjectRow(row) {
|
|
|
6388
6466
|
updated_at: row["updated_at"]
|
|
6389
6467
|
};
|
|
6390
6468
|
}
|
|
6469
|
+
function projectUpdateAuthority() {
|
|
6470
|
+
try {
|
|
6471
|
+
return resolveMementosProjectAuthorityIdentity();
|
|
6472
|
+
} catch (error) {
|
|
6473
|
+
if (error instanceof MementosProjectAuthorityIdentityError) {
|
|
6474
|
+
throw new ProjectGuardedUpdateError("PROJECT_UPDATE_AUTHORITY_MISMATCH", error.message, { authority_code: error.code, missing_env: error.missing_env });
|
|
6475
|
+
}
|
|
6476
|
+
throw error;
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6391
6479
|
function canonicalizeProjectUpdateValue(value) {
|
|
6392
6480
|
if (Array.isArray(value))
|
|
6393
6481
|
return value.map(canonicalizeProjectUpdateValue);
|
|
@@ -6460,8 +6548,8 @@ function normalizeProjectUpdateInput(input) {
|
|
|
6460
6548
|
}
|
|
6461
6549
|
return normalized;
|
|
6462
6550
|
}
|
|
6463
|
-
function assertProjectUpdateIdentity(identity) {
|
|
6464
|
-
if (identity.authority_id !==
|
|
6551
|
+
function assertProjectUpdateIdentity(identity, expectedIdentity = projectUpdateAuthority()) {
|
|
6552
|
+
if (identity.authority_id !== expectedIdentity.authority_id || identity.tenant_id !== expectedIdentity.tenant_id || identity.corpus_id !== expectedIdentity.corpus_id) {
|
|
6465
6553
|
throw new ProjectGuardedUpdateError("PROJECT_UPDATE_AUTHORITY_MISMATCH", "guarded project update does not match this authority, tenant, and corpus");
|
|
6466
6554
|
}
|
|
6467
6555
|
}
|
|
@@ -6470,8 +6558,8 @@ function assertBoundedIdentifier(value, field) {
|
|
|
6470
6558
|
throw new ProjectGuardedUpdateError("PROJECT_UPDATE_INVALID_INPUT", `${field} must be an 8-128 character bounded identifier`);
|
|
6471
6559
|
}
|
|
6472
6560
|
}
|
|
6473
|
-
function assertProjectUpdateRequest(request) {
|
|
6474
|
-
assertProjectUpdateIdentity(request);
|
|
6561
|
+
function assertProjectUpdateRequest(request, expectedIdentity = projectUpdateAuthority()) {
|
|
6562
|
+
assertProjectUpdateIdentity(request, expectedIdentity);
|
|
6475
6563
|
assertBoundedIdentifier(request.operation_id, "operation_id");
|
|
6476
6564
|
assertBoundedIdentifier(request.step_id, "step_id");
|
|
6477
6565
|
assertBoundedIdentifier(request.idempotency_key, "idempotency_key");
|
|
@@ -6584,7 +6672,7 @@ function makeProjectUpdateReceipt(input) {
|
|
|
6584
6672
|
target_id: input.target_id,
|
|
6585
6673
|
expected_revision: input.request.expected_revision,
|
|
6586
6674
|
result_revision: input.after_project.updated_at,
|
|
6587
|
-
result_digest: digestProjectUpdateValue(input.after_project),
|
|
6675
|
+
result_digest: input.result_digest ?? digestProjectUpdateValue(input.after_project),
|
|
6588
6676
|
accepted_receipt_id: input.accepted_receipt_id ?? null,
|
|
6589
6677
|
before_project: input.before_project,
|
|
6590
6678
|
after_project: input.after_project,
|
|
@@ -6648,8 +6736,8 @@ function listProjects(db) {
|
|
|
6648
6736
|
const rows = d.query("SELECT * FROM projects ORDER BY updated_at DESC").all();
|
|
6649
6737
|
return rows.map(parseProjectRow);
|
|
6650
6738
|
}
|
|
6651
|
-
function previewProjectUpdate(id, request, db) {
|
|
6652
|
-
assertProjectUpdateRequest(request);
|
|
6739
|
+
function previewProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority()) {
|
|
6740
|
+
assertProjectUpdateRequest(request, expectedIdentity);
|
|
6653
6741
|
const normalized = normalizeProjectUpdateInput(request.updates);
|
|
6654
6742
|
if (!db && isApiMode()) {
|
|
6655
6743
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-update`, { ...request, updates: normalized, dry_run: true });
|
|
@@ -6671,8 +6759,8 @@ function previewProjectUpdate(id, request, db) {
|
|
|
6671
6759
|
receipt: null
|
|
6672
6760
|
};
|
|
6673
6761
|
}
|
|
6674
|
-
function applyProjectUpdate(id, request, db) {
|
|
6675
|
-
assertProjectUpdateRequest(request);
|
|
6762
|
+
function applyProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority(), resultDigestForProject) {
|
|
6763
|
+
assertProjectUpdateRequest(request, expectedIdentity);
|
|
6676
6764
|
const normalized = normalizeProjectUpdateInput(request.updates);
|
|
6677
6765
|
if (!db && isApiMode()) {
|
|
6678
6766
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-update`, { ...request, updates: normalized, dry_run: false });
|
|
@@ -6733,14 +6821,15 @@ function applyProjectUpdate(id, request, db) {
|
|
|
6733
6821
|
request_digest: requestDigest,
|
|
6734
6822
|
target_id: id,
|
|
6735
6823
|
before_project: before,
|
|
6736
|
-
after_project: readback
|
|
6824
|
+
after_project: readback,
|
|
6825
|
+
result_digest: resultDigestForProject?.(readback)
|
|
6737
6826
|
});
|
|
6738
6827
|
insertProjectUpdateReceipt(d, receipt);
|
|
6739
6828
|
return { dry_run: false, applied: true, project: readback, receipt };
|
|
6740
6829
|
});
|
|
6741
6830
|
}
|
|
6742
|
-
function rollbackProjectUpdate(id, request, db) {
|
|
6743
|
-
assertProjectUpdateRequest(request);
|
|
6831
|
+
function rollbackProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority(), resultDigestForProject) {
|
|
6832
|
+
assertProjectUpdateRequest(request, expectedIdentity);
|
|
6744
6833
|
assertBoundedIdentifier(request.accepted_receipt_id, "accepted_receipt_id");
|
|
6745
6834
|
if (!db && isApiMode()) {
|
|
6746
6835
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/guarded-rollback`, request);
|
|
@@ -6806,14 +6895,15 @@ function rollbackProjectUpdate(id, request, db) {
|
|
|
6806
6895
|
target_id: id,
|
|
6807
6896
|
before_project: current,
|
|
6808
6897
|
after_project: readback,
|
|
6898
|
+
result_digest: resultDigestForProject?.(readback),
|
|
6809
6899
|
accepted_receipt_id: accepted.receipt_id
|
|
6810
6900
|
});
|
|
6811
6901
|
insertProjectUpdateReceipt(d, receipt);
|
|
6812
6902
|
return { dry_run: false, applied: true, project: readback, receipt };
|
|
6813
6903
|
});
|
|
6814
6904
|
}
|
|
6815
|
-
function getProjectUpdateReceipt(id, receiptId, identity =
|
|
6816
|
-
assertProjectUpdateIdentity(identity);
|
|
6905
|
+
function getProjectUpdateReceipt(id, receiptId, identity = projectUpdateAuthority(), db, expectedIdentity = projectUpdateAuthority()) {
|
|
6906
|
+
assertProjectUpdateIdentity(identity, expectedIdentity);
|
|
6817
6907
|
if (!db && isApiMode()) {
|
|
6818
6908
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/update-receipts/lookup`, { ...identity, receipt_id: receiptId });
|
|
6819
6909
|
return data;
|
|
@@ -6890,12 +6980,13 @@ function updateProject(id, input, db) {
|
|
|
6890
6980
|
return updated ? parseProjectRow(updated) : null;
|
|
6891
6981
|
});
|
|
6892
6982
|
}
|
|
6893
|
-
var ProjectCollisionError, ProjectGuardedUpdateError,
|
|
6983
|
+
var ProjectCollisionError, ProjectGuardedUpdateError, BOUNDED_IDENTIFIER;
|
|
6894
6984
|
var init_projects = __esm(() => {
|
|
6895
6985
|
init_database();
|
|
6896
6986
|
init_api_mode();
|
|
6897
6987
|
init_package_version();
|
|
6898
6988
|
init_types2();
|
|
6989
|
+
init_identity();
|
|
6899
6990
|
ProjectCollisionError = class ProjectCollisionError extends Error {
|
|
6900
6991
|
field;
|
|
6901
6992
|
value;
|
|
@@ -6916,11 +7007,6 @@ var init_projects = __esm(() => {
|
|
|
6916
7007
|
this.name = "ProjectGuardedUpdateError";
|
|
6917
7008
|
}
|
|
6918
7009
|
};
|
|
6919
|
-
PROJECT_UPDATE_AUTHORITY = {
|
|
6920
|
-
authority_id: "mementos",
|
|
6921
|
-
tenant_id: "default",
|
|
6922
|
-
corpus_id: "default"
|
|
6923
|
-
};
|
|
6924
7010
|
BOUNDED_IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
|
|
6925
7011
|
});
|
|
6926
7012
|
|
|
@@ -8562,13 +8648,13 @@ function createRelation(input, db) {
|
|
|
8562
8648
|
}
|
|
8563
8649
|
const d = db || getDatabase();
|
|
8564
8650
|
const id = shortUuid();
|
|
8565
|
-
const
|
|
8651
|
+
const timestamp2 = now();
|
|
8566
8652
|
const weight = input.weight ?? 1;
|
|
8567
8653
|
const metadata = JSON.stringify(input.metadata ?? {});
|
|
8568
8654
|
d.run(`INSERT INTO relations (id, source_entity_id, target_entity_id, relation_type, weight, metadata, created_at)
|
|
8569
8655
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
8570
8656
|
ON CONFLICT(source_entity_id, target_entity_id, relation_type)
|
|
8571
|
-
DO UPDATE SET weight = excluded.weight, metadata = excluded.metadata`, [id, input.source_entity_id, input.target_entity_id, input.relation_type, weight, metadata,
|
|
8657
|
+
DO UPDATE SET weight = excluded.weight, metadata = excluded.metadata`, [id, input.source_entity_id, input.target_entity_id, input.relation_type, weight, metadata, timestamp2]);
|
|
8572
8658
|
const row = d.query(`SELECT * FROM relations
|
|
8573
8659
|
WHERE source_entity_id = ? AND target_entity_id = ? AND relation_type = ?`).get(input.source_entity_id, input.target_entity_id, input.relation_type);
|
|
8574
8660
|
const relation = parseRelationRow(row);
|
|
@@ -9560,7 +9646,7 @@ function createWebhookHook(input, db) {
|
|
|
9560
9646
|
}
|
|
9561
9647
|
const d = db || getDatabase();
|
|
9562
9648
|
const id = shortUuid();
|
|
9563
|
-
const
|
|
9649
|
+
const timestamp2 = now();
|
|
9564
9650
|
d.run(`INSERT INTO webhook_hooks
|
|
9565
9651
|
(id, type, handler_url, priority, blocking, agent_id, project_id, description, enabled, created_at, invocation_count, failure_count)
|
|
9566
9652
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, 0, 0)`, [
|
|
@@ -9572,7 +9658,7 @@ function createWebhookHook(input, db) {
|
|
|
9572
9658
|
input.agentId ?? null,
|
|
9573
9659
|
input.projectId ?? null,
|
|
9574
9660
|
input.description ?? null,
|
|
9575
|
-
|
|
9661
|
+
timestamp2
|
|
9576
9662
|
]);
|
|
9577
9663
|
return getWebhookHook(id, d);
|
|
9578
9664
|
}
|
|
@@ -9743,7 +9829,7 @@ function parseEventRow(row) {
|
|
|
9743
9829
|
function createSynthesisRun(input, db) {
|
|
9744
9830
|
const d = db || getDatabase();
|
|
9745
9831
|
const id = shortUuid();
|
|
9746
|
-
const
|
|
9832
|
+
const timestamp2 = now();
|
|
9747
9833
|
d.run(`INSERT INTO synthesis_runs (id, triggered_by, project_id, agent_id, corpus_size, proposals_generated, proposals_accepted, proposals_rejected, status, started_at)
|
|
9748
9834
|
VALUES (?, ?, ?, ?, ?, 0, 0, 0, 'pending', ?)`, [
|
|
9749
9835
|
id,
|
|
@@ -9751,7 +9837,7 @@ function createSynthesisRun(input, db) {
|
|
|
9751
9837
|
input.project_id ?? null,
|
|
9752
9838
|
input.agent_id ?? null,
|
|
9753
9839
|
input.corpus_size ?? 0,
|
|
9754
|
-
|
|
9840
|
+
timestamp2
|
|
9755
9841
|
]);
|
|
9756
9842
|
return getSynthesisRun(id, d);
|
|
9757
9843
|
}
|
|
@@ -9844,7 +9930,7 @@ function updateSynthesisRun(id, updates, db) {
|
|
|
9844
9930
|
function createProposal(input, db) {
|
|
9845
9931
|
const d = db || getDatabase();
|
|
9846
9932
|
const id = shortUuid();
|
|
9847
|
-
const
|
|
9933
|
+
const timestamp2 = now();
|
|
9848
9934
|
d.run(`INSERT INTO synthesis_proposals (id, run_id, proposal_type, memory_ids, target_memory_id, proposed_changes, reasoning, confidence, status, created_at)
|
|
9849
9935
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?)`, [
|
|
9850
9936
|
id,
|
|
@@ -9855,7 +9941,7 @@ function createProposal(input, db) {
|
|
|
9855
9941
|
JSON.stringify(input.proposed_changes),
|
|
9856
9942
|
input.reasoning ?? null,
|
|
9857
9943
|
input.confidence,
|
|
9858
|
-
|
|
9944
|
+
timestamp2
|
|
9859
9945
|
]);
|
|
9860
9946
|
return getProposal(id, d);
|
|
9861
9947
|
}
|
|
@@ -9903,10 +9989,10 @@ function updateProposal(id, updates, db) {
|
|
|
9903
9989
|
function createMetric(input, db) {
|
|
9904
9990
|
const d = db || getDatabase();
|
|
9905
9991
|
const id = shortUuid();
|
|
9906
|
-
const
|
|
9992
|
+
const timestamp2 = now();
|
|
9907
9993
|
d.run(`INSERT INTO synthesis_metrics (id, run_id, metric_type, value, baseline, created_at)
|
|
9908
|
-
VALUES (?, ?, ?, ?, ?, ?)`, [id, input.run_id, input.metric_type, input.value, input.baseline ?? null,
|
|
9909
|
-
return { id, run_id: input.run_id, metric_type: input.metric_type, value: input.value, baseline: input.baseline ?? null, created_at:
|
|
9994
|
+
VALUES (?, ?, ?, ?, ?, ?)`, [id, input.run_id, input.metric_type, input.value, input.baseline ?? null, timestamp2]);
|
|
9995
|
+
return { id, run_id: input.run_id, metric_type: input.metric_type, value: input.value, baseline: input.baseline ?? null, created_at: timestamp2 };
|
|
9910
9996
|
}
|
|
9911
9997
|
function listMetrics(run_id, db) {
|
|
9912
9998
|
const d = db || getDatabase();
|
|
@@ -9917,7 +10003,7 @@ function recordSynthesisEvent(input, db) {
|
|
|
9917
10003
|
try {
|
|
9918
10004
|
const d = db || getDatabase();
|
|
9919
10005
|
const id = shortUuid();
|
|
9920
|
-
const
|
|
10006
|
+
const timestamp2 = now();
|
|
9921
10007
|
d.run(`INSERT INTO synthesis_events (id, event_type, memory_id, agent_id, project_id, session_id, query, importance_at_time, metadata, created_at)
|
|
9922
10008
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
9923
10009
|
id,
|
|
@@ -9929,7 +10015,7 @@ function recordSynthesisEvent(input, db) {
|
|
|
9929
10015
|
input.query ?? null,
|
|
9930
10016
|
input.importance_at_time ?? null,
|
|
9931
10017
|
JSON.stringify(input.metadata ?? {}),
|
|
9932
|
-
|
|
10018
|
+
timestamp2
|
|
9933
10019
|
]);
|
|
9934
10020
|
} catch {}
|
|
9935
10021
|
}
|
|
@@ -10171,20 +10257,20 @@ __export(exports_contradiction, {
|
|
|
10171
10257
|
});
|
|
10172
10258
|
function invalidateFact(oldMemoryId, newMemoryId, db) {
|
|
10173
10259
|
const d = db || getDatabase();
|
|
10174
|
-
const
|
|
10175
|
-
d.run("UPDATE memories SET valid_until = ?, updated_at = ? WHERE id = ?", [
|
|
10260
|
+
const timestamp2 = now();
|
|
10261
|
+
d.run("UPDATE memories SET valid_until = ?, updated_at = ? WHERE id = ?", [timestamp2, timestamp2, oldMemoryId]);
|
|
10176
10262
|
if (newMemoryId) {
|
|
10177
10263
|
const row = d.query("SELECT metadata FROM memories WHERE id = ?").get(newMemoryId);
|
|
10178
10264
|
if (row) {
|
|
10179
10265
|
const metadata = JSON.parse(row.metadata || "{}");
|
|
10180
10266
|
metadata.supersedes_id = oldMemoryId;
|
|
10181
|
-
d.run("UPDATE memories SET metadata = ?, updated_at = ? WHERE id = ?", [JSON.stringify(metadata),
|
|
10267
|
+
d.run("UPDATE memories SET metadata = ?, updated_at = ? WHERE id = ?", [JSON.stringify(metadata), timestamp2, newMemoryId]);
|
|
10182
10268
|
}
|
|
10183
10269
|
}
|
|
10184
10270
|
return {
|
|
10185
10271
|
invalidated_memory_id: oldMemoryId,
|
|
10186
10272
|
new_memory_id: newMemoryId || null,
|
|
10187
|
-
valid_until:
|
|
10273
|
+
valid_until: timestamp2,
|
|
10188
10274
|
supersedes_id: oldMemoryId
|
|
10189
10275
|
};
|
|
10190
10276
|
}
|
|
@@ -11454,7 +11540,7 @@ function parseJobRow(row) {
|
|
|
11454
11540
|
function createSessionJob(input, db) {
|
|
11455
11541
|
const d = db || getDatabase();
|
|
11456
11542
|
const id = uuid();
|
|
11457
|
-
const
|
|
11543
|
+
const timestamp2 = now();
|
|
11458
11544
|
const source = input.source ?? "manual";
|
|
11459
11545
|
const metadata = JSON.stringify(input.metadata ?? {});
|
|
11460
11546
|
d.run(`INSERT INTO session_memory_jobs
|
|
@@ -11467,7 +11553,7 @@ function createSessionJob(input, db) {
|
|
|
11467
11553
|
source,
|
|
11468
11554
|
input.transcript,
|
|
11469
11555
|
metadata,
|
|
11470
|
-
|
|
11556
|
+
timestamp2
|
|
11471
11557
|
]);
|
|
11472
11558
|
return getSessionJob(id, d);
|
|
11473
11559
|
}
|
|
@@ -11603,7 +11689,7 @@ function saveToolEvent(input, db) {
|
|
|
11603
11689
|
}
|
|
11604
11690
|
const d = db || getDatabase();
|
|
11605
11691
|
const id = uuid();
|
|
11606
|
-
const
|
|
11692
|
+
const timestamp2 = now();
|
|
11607
11693
|
const metadataJson = JSON.stringify(input.metadata || {});
|
|
11608
11694
|
d.run(`INSERT INTO tool_events (id, tool_name, action, success, error_type, error_message, tokens_used, latency_ms, context, lesson, when_to_use, agent_id, project_id, session_id, metadata, created_at)
|
|
11609
11695
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
@@ -11622,7 +11708,7 @@ function saveToolEvent(input, db) {
|
|
|
11622
11708
|
input.project_id || null,
|
|
11623
11709
|
input.session_id || null,
|
|
11624
11710
|
metadataJson,
|
|
11625
|
-
|
|
11711
|
+
timestamp2
|
|
11626
11712
|
]);
|
|
11627
11713
|
return getToolEvent(id, d);
|
|
11628
11714
|
}
|
|
@@ -12345,7 +12431,7 @@ function registerSession(opts) {
|
|
|
12345
12431
|
const pid = process.pid;
|
|
12346
12432
|
const cwd = opts.cwd || process.cwd();
|
|
12347
12433
|
const id = generateId();
|
|
12348
|
-
const
|
|
12434
|
+
const timestamp2 = now3();
|
|
12349
12435
|
const existing = db.query("SELECT id FROM sessions WHERE pid = ? AND mcp_server = ?").get(pid, opts.mcp_server);
|
|
12350
12436
|
if (existing) {
|
|
12351
12437
|
db.run(`UPDATE sessions SET agent_name = ?, project_name = ?, cwd = ?,
|
|
@@ -12356,7 +12442,7 @@ function registerSession(opts) {
|
|
|
12356
12442
|
opts.git_root || null,
|
|
12357
12443
|
opts.tty || null,
|
|
12358
12444
|
JSON.stringify(opts.metadata || {}),
|
|
12359
|
-
|
|
12445
|
+
timestamp2,
|
|
12360
12446
|
existing.id
|
|
12361
12447
|
]);
|
|
12362
12448
|
return getSession(existing.id);
|
|
@@ -12372,8 +12458,8 @@ function registerSession(opts) {
|
|
|
12372
12458
|
opts.tty || null,
|
|
12373
12459
|
opts.mcp_server,
|
|
12374
12460
|
JSON.stringify(opts.metadata || {}),
|
|
12375
|
-
|
|
12376
|
-
|
|
12461
|
+
timestamp2,
|
|
12462
|
+
timestamp2
|
|
12377
12463
|
]);
|
|
12378
12464
|
return getSession(id);
|
|
12379
12465
|
}
|
|
@@ -60777,6 +60863,7 @@ init_database();
|
|
|
60777
60863
|
init_memories();
|
|
60778
60864
|
init_package_version();
|
|
60779
60865
|
init_schema();
|
|
60866
|
+
init_identity();
|
|
60780
60867
|
import { createHash as createHash2 } from "crypto";
|
|
60781
60868
|
|
|
60782
60869
|
class MemoryProjectLinkError extends Error {
|
|
@@ -60789,12 +60876,17 @@ class MemoryProjectLinkError extends Error {
|
|
|
60789
60876
|
this.name = "MemoryProjectLinkError";
|
|
60790
60877
|
}
|
|
60791
60878
|
}
|
|
60792
|
-
var LINK_AUTHORITY = {
|
|
60793
|
-
authority_id: "mementos",
|
|
60794
|
-
tenant_id: "default",
|
|
60795
|
-
corpus_id: "default"
|
|
60796
|
-
};
|
|
60797
60879
|
var BOUNDED_IDENTIFIER2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
|
|
60880
|
+
function linkAuthority() {
|
|
60881
|
+
try {
|
|
60882
|
+
return resolveMementosProjectAuthorityIdentity();
|
|
60883
|
+
} catch (error) {
|
|
60884
|
+
if (error instanceof MementosProjectAuthorityIdentityError) {
|
|
60885
|
+
throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_AUTHORITY_MISMATCH", error.message, { authority_code: error.code, missing_env: error.missing_env });
|
|
60886
|
+
}
|
|
60887
|
+
throw error;
|
|
60888
|
+
}
|
|
60889
|
+
}
|
|
60798
60890
|
function canonicalize(value) {
|
|
60799
60891
|
if (Array.isArray(value))
|
|
60800
60892
|
return value.map(canonicalize);
|
|
@@ -60902,7 +60994,8 @@ function receiptFromRow(row) {
|
|
|
60902
60994
|
};
|
|
60903
60995
|
}
|
|
60904
60996
|
function assertIdentity(identity) {
|
|
60905
|
-
|
|
60997
|
+
const expectedIdentity = linkAuthority();
|
|
60998
|
+
if (identity.authority_id !== expectedIdentity.authority_id || identity.tenant_id !== expectedIdentity.tenant_id || identity.corpus_id !== expectedIdentity.corpus_id) {
|
|
60906
60999
|
throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_AUTHORITY_MISMATCH", "memory project link does not match this authority, tenant, and corpus");
|
|
60907
61000
|
}
|
|
60908
61001
|
}
|
|
@@ -61379,7 +61472,7 @@ function rollbackMemoryProjectLink(memoryId, request, db) {
|
|
|
61379
61472
|
};
|
|
61380
61473
|
});
|
|
61381
61474
|
}
|
|
61382
|
-
function getMemoryProjectLinkReceipt(memoryId, receiptId, identity =
|
|
61475
|
+
function getMemoryProjectLinkReceipt(memoryId, receiptId, identity = linkAuthority(), db) {
|
|
61383
61476
|
assertIdentity(identity);
|
|
61384
61477
|
assertBoundedIdentifier2(memoryId, "memory_id");
|
|
61385
61478
|
assertBoundedIdentifier2(receiptId, "receipt_id");
|
|
@@ -61395,6 +61488,348 @@ function getMemoryProjectLinkReceipt(memoryId, receiptId, identity = LINK_AUTHOR
|
|
|
61395
61488
|
return receipt;
|
|
61396
61489
|
}
|
|
61397
61490
|
|
|
61491
|
+
// src/project-registration/authority.ts
|
|
61492
|
+
import { createHash as createHash3 } from "crypto";
|
|
61493
|
+
init_projects();
|
|
61494
|
+
init_types2();
|
|
61495
|
+
init_identity();
|
|
61496
|
+
function canonicalMementosProjectRegistrationJson(value) {
|
|
61497
|
+
return JSON.stringify(canonicalize2(value));
|
|
61498
|
+
}
|
|
61499
|
+
function canonicalize2(value) {
|
|
61500
|
+
if (Array.isArray(value))
|
|
61501
|
+
return value.map(canonicalize2);
|
|
61502
|
+
if (!value || typeof value !== "object")
|
|
61503
|
+
return value;
|
|
61504
|
+
const out = {};
|
|
61505
|
+
for (const key of Object.keys(value).sort()) {
|
|
61506
|
+
const item = value[key];
|
|
61507
|
+
if (item !== undefined)
|
|
61508
|
+
out[key] = canonicalize2(item);
|
|
61509
|
+
}
|
|
61510
|
+
return out;
|
|
61511
|
+
}
|
|
61512
|
+
function digestMementosProjectRegistrationValue(value) {
|
|
61513
|
+
return createHash3("sha256").update(canonicalMementosProjectRegistrationJson(value)).digest("hex");
|
|
61514
|
+
}
|
|
61515
|
+
// src/project-registration/http.ts
|
|
61516
|
+
init_types2();
|
|
61517
|
+
|
|
61518
|
+
// src/project-registration/index.ts
|
|
61519
|
+
init_identity();
|
|
61520
|
+
|
|
61521
|
+
// src/project-registration/project-resources.ts
|
|
61522
|
+
init_api_mode();
|
|
61523
|
+
init_database();
|
|
61524
|
+
init_memories();
|
|
61525
|
+
init_identity();
|
|
61526
|
+
init_types2();
|
|
61527
|
+
var DEFAULT_PAGE_LIMIT = 100;
|
|
61528
|
+
var MAX_PAGE_LIMIT = 1000;
|
|
61529
|
+
var CURSOR_SCHEMA = "mementos.project-resources.cursor.v1";
|
|
61530
|
+
|
|
61531
|
+
class MementosProjectResourceError extends Error {
|
|
61532
|
+
code;
|
|
61533
|
+
details;
|
|
61534
|
+
constructor(code, message, details = {}) {
|
|
61535
|
+
super(message);
|
|
61536
|
+
this.code = code;
|
|
61537
|
+
this.details = details;
|
|
61538
|
+
this.name = "MementosProjectResourceError";
|
|
61539
|
+
}
|
|
61540
|
+
}
|
|
61541
|
+
function timestamp(value) {
|
|
61542
|
+
return value instanceof Date ? value.toISOString() : String(value);
|
|
61543
|
+
}
|
|
61544
|
+
function normalizeSqlValue(value) {
|
|
61545
|
+
if (value instanceof Date)
|
|
61546
|
+
return value.toISOString();
|
|
61547
|
+
if (Array.isArray(value))
|
|
61548
|
+
return value.map(normalizeSqlValue);
|
|
61549
|
+
if (!value || typeof value !== "object")
|
|
61550
|
+
return value;
|
|
61551
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalizeSqlValue(item)]));
|
|
61552
|
+
}
|
|
61553
|
+
function exactProject(db, projectId) {
|
|
61554
|
+
const row = db.get("SELECT id, name, path, description, memory_prefix, created_at, updated_at FROM projects WHERE id = ? LIMIT 1", projectId);
|
|
61555
|
+
if (!row) {
|
|
61556
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_PROJECT_NOT_FOUND", `Mementos project not found: ${projectId}`, { project_id: projectId });
|
|
61557
|
+
}
|
|
61558
|
+
return row;
|
|
61559
|
+
}
|
|
61560
|
+
function resourceKey(resource) {
|
|
61561
|
+
const rank = MEMENTOS_PROJECT_RESOURCE_KINDS.indexOf(resource.resource_kind);
|
|
61562
|
+
return `${String(rank).padStart(2, "0")}:${resource.stable_id}`;
|
|
61563
|
+
}
|
|
61564
|
+
function projectResource(project) {
|
|
61565
|
+
const normalized = normalizeSqlValue(project);
|
|
61566
|
+
return {
|
|
61567
|
+
authority: "mementos",
|
|
61568
|
+
source_package: "@hasna/mementos",
|
|
61569
|
+
project_id: project.id,
|
|
61570
|
+
resource_kind: "project",
|
|
61571
|
+
stable_id: project.id,
|
|
61572
|
+
revision: timestamp(project.updated_at),
|
|
61573
|
+
digest: digestMementosProjectRegistrationValue(normalized),
|
|
61574
|
+
membership: "project_aggregate"
|
|
61575
|
+
};
|
|
61576
|
+
}
|
|
61577
|
+
function memoryResources(db, projectId) {
|
|
61578
|
+
const rows = db.all("SELECT * FROM memories WHERE project_id = ? ORDER BY id ASC", projectId);
|
|
61579
|
+
return rows.map((row) => {
|
|
61580
|
+
const memory = normalizeSqlValue(parseMemoryRow(row));
|
|
61581
|
+
return {
|
|
61582
|
+
authority: "mementos",
|
|
61583
|
+
source_package: "@hasna/mementos",
|
|
61584
|
+
project_id: projectId,
|
|
61585
|
+
resource_kind: row["category"] === "knowledge" ? "knowledge" : "memory",
|
|
61586
|
+
stable_id: String(row["id"]),
|
|
61587
|
+
revision: timestamp(row["updated_at"]),
|
|
61588
|
+
digest: digestMementosProjectRegistrationValue(memory),
|
|
61589
|
+
membership: "explicit_project_id_or_focus"
|
|
61590
|
+
};
|
|
61591
|
+
});
|
|
61592
|
+
}
|
|
61593
|
+
function sessionResources(db, projectId) {
|
|
61594
|
+
const rows = db.all("SELECT * FROM session_memory_jobs WHERE project_id = ? ORDER BY id ASC", projectId);
|
|
61595
|
+
return rows.map((row) => {
|
|
61596
|
+
const normalized = {
|
|
61597
|
+
id: String(row["id"]),
|
|
61598
|
+
session_id: String(row["session_id"]),
|
|
61599
|
+
agent_id: row["agent_id"] === null ? null : String(row["agent_id"] ?? "") || null,
|
|
61600
|
+
project_id: row["project_id"] === null ? null : String(row["project_id"] ?? "") || null,
|
|
61601
|
+
source: String(row["source"]),
|
|
61602
|
+
status: String(row["status"]),
|
|
61603
|
+
transcript: String(row["transcript"]),
|
|
61604
|
+
chunk_count: Number(row["chunk_count"]),
|
|
61605
|
+
memories_extracted: Number(row["memories_extracted"]),
|
|
61606
|
+
error: row["error"] === null ? null : String(row["error"] ?? "") || null,
|
|
61607
|
+
metadata: typeof row["metadata"] === "string" ? JSON.parse(row["metadata"] || "{}") : normalizeSqlValue(row["metadata"] ?? {}),
|
|
61608
|
+
created_at: timestamp(row["created_at"]),
|
|
61609
|
+
started_at: row["started_at"] === null ? null : timestamp(row["started_at"]),
|
|
61610
|
+
completed_at: row["completed_at"] === null ? null : timestamp(row["completed_at"])
|
|
61611
|
+
};
|
|
61612
|
+
return {
|
|
61613
|
+
authority: "mementos",
|
|
61614
|
+
source_package: "@hasna/mementos",
|
|
61615
|
+
project_id: projectId,
|
|
61616
|
+
resource_kind: "session",
|
|
61617
|
+
stable_id: String(row["id"]),
|
|
61618
|
+
revision: timestamp(row["completed_at"] ?? row["started_at"] ?? row["created_at"]),
|
|
61619
|
+
digest: digestMementosProjectRegistrationValue(normalized),
|
|
61620
|
+
membership: "explicit_project_id_or_focus"
|
|
61621
|
+
};
|
|
61622
|
+
});
|
|
61623
|
+
}
|
|
61624
|
+
function normalizeResourceKinds(value) {
|
|
61625
|
+
if (!value)
|
|
61626
|
+
return [...MEMENTOS_PROJECT_RESOURCE_KINDS];
|
|
61627
|
+
if (value.length === 0) {
|
|
61628
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", "resource_kinds must contain at least one supported resource kind");
|
|
61629
|
+
}
|
|
61630
|
+
const requested = new Set(value);
|
|
61631
|
+
for (const kind of requested) {
|
|
61632
|
+
if (!MEMENTOS_PROJECT_RESOURCE_KINDS.includes(kind)) {
|
|
61633
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", `Unsupported Mementos project resource kind: ${kind}`);
|
|
61634
|
+
}
|
|
61635
|
+
}
|
|
61636
|
+
return MEMENTOS_PROJECT_RESOURCE_KINDS.filter((kind) => requested.has(kind));
|
|
61637
|
+
}
|
|
61638
|
+
function normalizeLimit(value) {
|
|
61639
|
+
const limit = value ?? DEFAULT_PAGE_LIMIT;
|
|
61640
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_PAGE_LIMIT) {
|
|
61641
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", `limit must be an integer between 1 and ${MAX_PAGE_LIMIT}`);
|
|
61642
|
+
}
|
|
61643
|
+
return limit;
|
|
61644
|
+
}
|
|
61645
|
+
function encodeCursor(cursor) {
|
|
61646
|
+
return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
|
|
61647
|
+
}
|
|
61648
|
+
function decodeCursor(raw) {
|
|
61649
|
+
try {
|
|
61650
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
61651
|
+
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") {
|
|
61652
|
+
throw new Error("invalid cursor shape");
|
|
61653
|
+
}
|
|
61654
|
+
return parsed;
|
|
61655
|
+
} catch {
|
|
61656
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", "cursor is not a valid Mementos project-resource cursor");
|
|
61657
|
+
}
|
|
61658
|
+
}
|
|
61659
|
+
function localPopulation(projectId, db, resourceKinds) {
|
|
61660
|
+
const project = exactProject(db, projectId);
|
|
61661
|
+
const selected = new Set(resourceKinds);
|
|
61662
|
+
const resources = [
|
|
61663
|
+
...selected.has("project") ? [projectResource(project)] : [],
|
|
61664
|
+
...memoryResources(db, projectId).filter((resource) => selected.has(resource.resource_kind)),
|
|
61665
|
+
...selected.has("session") ? sessionResources(db, projectId) : []
|
|
61666
|
+
].sort((left, right) => resourceKey(left).localeCompare(resourceKey(right)));
|
|
61667
|
+
const collectionRevision = digestMementosProjectRegistrationValue({
|
|
61668
|
+
schema: MEMENTOS_PROJECT_RESOURCE_ROUTE,
|
|
61669
|
+
project_id: projectId,
|
|
61670
|
+
project_revision: timestamp(project.updated_at),
|
|
61671
|
+
resource_kinds: resourceKinds,
|
|
61672
|
+
resources: resources.map((resource) => ({
|
|
61673
|
+
resource_kind: resource.resource_kind,
|
|
61674
|
+
stable_id: resource.stable_id,
|
|
61675
|
+
revision: resource.revision,
|
|
61676
|
+
digest: resource.digest
|
|
61677
|
+
}))
|
|
61678
|
+
});
|
|
61679
|
+
return { project, resources, collectionRevision };
|
|
61680
|
+
}
|
|
61681
|
+
function readMementosProjectResourcePage(projectId, options = {}, db, authorityOptions = {}) {
|
|
61682
|
+
const resourceKinds = normalizeResourceKinds(options.resource_kinds);
|
|
61683
|
+
const limit = normalizeLimit(options.limit);
|
|
61684
|
+
if (!db && isApiMode()) {
|
|
61685
|
+
const { data } = apiJson("GET", `/projects/${encodeURIComponent(projectId)}/resources${toQuery({
|
|
61686
|
+
limit,
|
|
61687
|
+
cursor: options.cursor ?? undefined,
|
|
61688
|
+
resource_kinds: resourceKinds.join(",")
|
|
61689
|
+
})}`);
|
|
61690
|
+
return data;
|
|
61691
|
+
}
|
|
61692
|
+
const d = db ?? getDatabase();
|
|
61693
|
+
const { project, resources, collectionRevision } = localPopulation(projectId, d, resourceKinds);
|
|
61694
|
+
let start = 0;
|
|
61695
|
+
if (options.cursor) {
|
|
61696
|
+
const cursor = decodeCursor(options.cursor);
|
|
61697
|
+
if (cursor.project_id !== projectId || JSON.stringify(cursor.resource_kinds) !== JSON.stringify(resourceKinds)) {
|
|
61698
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", "cursor does not belong to this project and resource-kind selection");
|
|
61699
|
+
}
|
|
61700
|
+
if (cursor.collection_revision !== collectionRevision) {
|
|
61701
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_COLLECTION_CHANGED", "Mementos project resource collection changed; restart from the first page", {
|
|
61702
|
+
cursor_collection_revision: cursor.collection_revision,
|
|
61703
|
+
current_collection_revision: collectionRevision
|
|
61704
|
+
});
|
|
61705
|
+
}
|
|
61706
|
+
const afterIndex = resources.findIndex((resource) => resourceKey(resource) === cursor.after_key);
|
|
61707
|
+
if (afterIndex < 0) {
|
|
61708
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_COLLECTION_CHANGED", "Mementos project resource cursor no longer names a member; restart from the first page");
|
|
61709
|
+
}
|
|
61710
|
+
start = afterIndex + 1;
|
|
61711
|
+
}
|
|
61712
|
+
const pageResources = resources.slice(start, start + limit);
|
|
61713
|
+
const hasMore = start + pageResources.length < resources.length;
|
|
61714
|
+
const nextCursor = hasMore && pageResources.length > 0 ? encodeCursor({
|
|
61715
|
+
schema: CURSOR_SCHEMA,
|
|
61716
|
+
project_id: projectId,
|
|
61717
|
+
collection_revision: collectionRevision,
|
|
61718
|
+
resource_kinds: resourceKinds,
|
|
61719
|
+
after_key: resourceKey(pageResources[pageResources.length - 1])
|
|
61720
|
+
}) : null;
|
|
61721
|
+
const capability = buildMementosProjectRegistrationCapability(authorityOptions);
|
|
61722
|
+
return {
|
|
61723
|
+
schema: "mementos.project-resources.v1",
|
|
61724
|
+
authority: {
|
|
61725
|
+
authority: capability.authority,
|
|
61726
|
+
authority_id: capability.authority_id,
|
|
61727
|
+
tenant_id: capability.tenant_id,
|
|
61728
|
+
corpus_id: capability.corpus_id,
|
|
61729
|
+
package_version: capability.package_version
|
|
61730
|
+
},
|
|
61731
|
+
project_id: projectId,
|
|
61732
|
+
project_revision: timestamp(project.updated_at),
|
|
61733
|
+
collection_revision: collectionRevision,
|
|
61734
|
+
resource_kinds: resourceKinds,
|
|
61735
|
+
resources: pageResources,
|
|
61736
|
+
count: pageResources.length,
|
|
61737
|
+
total: resources.length,
|
|
61738
|
+
limit,
|
|
61739
|
+
cursor: options.cursor ?? null,
|
|
61740
|
+
next_cursor: nextCursor,
|
|
61741
|
+
has_more: hasMore,
|
|
61742
|
+
complete: true,
|
|
61743
|
+
truncated: false
|
|
61744
|
+
};
|
|
61745
|
+
}
|
|
61746
|
+
function readAllMementosProjectResources(projectId, options = {}, db, authorityOptions = {}) {
|
|
61747
|
+
const pageSize = normalizeLimit(options.page_size);
|
|
61748
|
+
let cursor = null;
|
|
61749
|
+
let first = null;
|
|
61750
|
+
const resources = [];
|
|
61751
|
+
const seen = new Set;
|
|
61752
|
+
do {
|
|
61753
|
+
const page = readMementosProjectResourcePage(projectId, {
|
|
61754
|
+
limit: pageSize,
|
|
61755
|
+
cursor,
|
|
61756
|
+
resource_kinds: options.resource_kinds
|
|
61757
|
+
}, db, authorityOptions);
|
|
61758
|
+
if (!first)
|
|
61759
|
+
first = page;
|
|
61760
|
+
if (page.collection_revision !== first.collection_revision || page.total !== first.total || JSON.stringify(page.resource_kinds) !== JSON.stringify(first.resource_kinds)) {
|
|
61761
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_COLLECTION_CHANGED", "Mementos project resource collection changed during complete traversal");
|
|
61762
|
+
}
|
|
61763
|
+
for (const resource of page.resources) {
|
|
61764
|
+
const key = resourceKey(resource);
|
|
61765
|
+
if (seen.has(key)) {
|
|
61766
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", `Mementos project resource traversal returned duplicate stable ID: ${key}`);
|
|
61767
|
+
}
|
|
61768
|
+
seen.add(key);
|
|
61769
|
+
resources.push(resource);
|
|
61770
|
+
}
|
|
61771
|
+
if (page.has_more && !page.next_cursor) {
|
|
61772
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", "Mementos project resource page claimed more results without a continuation cursor");
|
|
61773
|
+
}
|
|
61774
|
+
cursor = page.next_cursor;
|
|
61775
|
+
} while (cursor);
|
|
61776
|
+
if (!first) {
|
|
61777
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", "Mementos project resource traversal returned no first page");
|
|
61778
|
+
}
|
|
61779
|
+
if (resources.length !== first.total) {
|
|
61780
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INCOMPLETE", `Mementos project resource traversal returned ${resources.length} of ${first.total} resources`);
|
|
61781
|
+
}
|
|
61782
|
+
return {
|
|
61783
|
+
...first,
|
|
61784
|
+
resources,
|
|
61785
|
+
count: resources.length,
|
|
61786
|
+
total: resources.length,
|
|
61787
|
+
limit: pageSize,
|
|
61788
|
+
cursor: null,
|
|
61789
|
+
next_cursor: null,
|
|
61790
|
+
has_more: false,
|
|
61791
|
+
complete: true,
|
|
61792
|
+
truncated: false
|
|
61793
|
+
};
|
|
61794
|
+
}
|
|
61795
|
+
function getMementosProjectResourceExact(projectId, resourceKind, stableId, db, authorityOptions = {}) {
|
|
61796
|
+
if (!MEMENTOS_PROJECT_RESOURCE_KINDS.includes(resourceKind)) {
|
|
61797
|
+
throw new MementosProjectResourceError("MEMENTOS_PROJECT_RESOURCE_INVALID_INPUT", `Unsupported Mementos project resource kind: ${resourceKind}`);
|
|
61798
|
+
}
|
|
61799
|
+
if (!db && isApiMode()) {
|
|
61800
|
+
const { data } = apiJson("GET", `/projects/${encodeURIComponent(projectId)}/resources/${encodeURIComponent(resourceKind)}/${encodeURIComponent(stableId)}`);
|
|
61801
|
+
return data;
|
|
61802
|
+
}
|
|
61803
|
+
const d = db ?? getDatabase();
|
|
61804
|
+
const { project, resources, collectionRevision } = localPopulation(projectId, d, [
|
|
61805
|
+
resourceKind
|
|
61806
|
+
]);
|
|
61807
|
+
const resource = resources.find((candidate) => candidate.stable_id === stableId);
|
|
61808
|
+
if (!resource) {
|
|
61809
|
+
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 });
|
|
61810
|
+
}
|
|
61811
|
+
const capability = buildMementosProjectRegistrationCapability(authorityOptions);
|
|
61812
|
+
return {
|
|
61813
|
+
schema: "mementos.project-resource.v1",
|
|
61814
|
+
authority: {
|
|
61815
|
+
authority: capability.authority,
|
|
61816
|
+
authority_id: capability.authority_id,
|
|
61817
|
+
tenant_id: capability.tenant_id,
|
|
61818
|
+
corpus_id: capability.corpus_id,
|
|
61819
|
+
package_version: capability.package_version
|
|
61820
|
+
},
|
|
61821
|
+
project_id: projectId,
|
|
61822
|
+
project_revision: timestamp(project.updated_at),
|
|
61823
|
+
collection_revision: collectionRevision,
|
|
61824
|
+
resource,
|
|
61825
|
+
complete: true,
|
|
61826
|
+
truncated: false
|
|
61827
|
+
};
|
|
61828
|
+
}
|
|
61829
|
+
|
|
61830
|
+
// src/project-registration/index.ts
|
|
61831
|
+
init_types2();
|
|
61832
|
+
|
|
61398
61833
|
// src/cli/commands/memory-cmd-crud.ts
|
|
61399
61834
|
init_projects();
|
|
61400
61835
|
init_agents();
|
|
@@ -61462,9 +61897,7 @@ function registerCrudCommands(program2) {
|
|
|
61462
61897
|
throw new Error("Receipt lookup cannot be combined with link, rollback, or dry-run options");
|
|
61463
61898
|
}
|
|
61464
61899
|
const receipt = getMemoryProjectLinkReceipt(memoryId, lookupReceipt, {
|
|
61465
|
-
|
|
61466
|
-
tenant_id: "default",
|
|
61467
|
-
corpus_id: "default"
|
|
61900
|
+
...resolveMementosProjectAuthorityIdentity()
|
|
61468
61901
|
});
|
|
61469
61902
|
if (globalOpts.json)
|
|
61470
61903
|
outputJson(receipt);
|
|
@@ -61490,9 +61923,7 @@ function registerCrudCommands(program2) {
|
|
|
61490
61923
|
throw new Error("--project-id and --rollback-receipt cannot be used together");
|
|
61491
61924
|
}
|
|
61492
61925
|
const common = {
|
|
61493
|
-
|
|
61494
|
-
tenant_id: "default",
|
|
61495
|
-
corpus_id: "default",
|
|
61926
|
+
...resolveMementosProjectAuthorityIdentity(),
|
|
61496
61927
|
operation_id: opts.operationId ?? idempotencyKey,
|
|
61497
61928
|
step_id: opts.stepId ?? (rollbackReceipt ? "mementos_memory_project_link_rollback" : "mementos_memory_project_link"),
|
|
61498
61929
|
idempotency_key: idempotencyKey,
|
|
@@ -63400,29 +63831,29 @@ function enforceQuotas(config, db) {
|
|
|
63400
63831
|
}
|
|
63401
63832
|
function archiveStale(staleDays, db) {
|
|
63402
63833
|
const d = db || getDatabase();
|
|
63403
|
-
const
|
|
63834
|
+
const timestamp2 = now();
|
|
63404
63835
|
const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000).toISOString();
|
|
63405
63836
|
const archiveWhere = `status = 'active' AND pinned = 0 AND COALESCE(accessed_at, created_at) < ?`;
|
|
63406
63837
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${archiveWhere}`).get(cutoff).c;
|
|
63407
63838
|
if (count > 0) {
|
|
63408
|
-
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${archiveWhere}`, [
|
|
63839
|
+
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${archiveWhere}`, [timestamp2, cutoff]);
|
|
63409
63840
|
}
|
|
63410
63841
|
return count;
|
|
63411
63842
|
}
|
|
63412
63843
|
function archiveUnused(days, db) {
|
|
63413
63844
|
const d = db || getDatabase();
|
|
63414
|
-
const
|
|
63845
|
+
const timestamp2 = now();
|
|
63415
63846
|
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
63416
63847
|
const unusedWhere = `status = 'active' AND pinned = 0 AND access_count = 0 AND created_at < ?`;
|
|
63417
63848
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${unusedWhere}`).get(cutoff).c;
|
|
63418
63849
|
if (count > 0) {
|
|
63419
|
-
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${unusedWhere}`, [
|
|
63850
|
+
d.run(`UPDATE memories SET status = 'archived', updated_at = ? WHERE ${unusedWhere}`, [timestamp2, cutoff]);
|
|
63420
63851
|
}
|
|
63421
63852
|
return count;
|
|
63422
63853
|
}
|
|
63423
63854
|
function deprioritizeStale(days, db) {
|
|
63424
63855
|
const d = db || getDatabase();
|
|
63425
|
-
const
|
|
63856
|
+
const timestamp2 = now();
|
|
63426
63857
|
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
63427
63858
|
const deprioWhere = `status = 'active' AND pinned = 0 AND importance > 1 AND COALESCE(accessed_at, updated_at) < ?`;
|
|
63428
63859
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${deprioWhere}`).get(cutoff).c;
|
|
@@ -63431,7 +63862,7 @@ function deprioritizeStale(days, db) {
|
|
|
63431
63862
|
SET importance = importance - 1,
|
|
63432
63863
|
version = version + 1,
|
|
63433
63864
|
updated_at = ?
|
|
63434
|
-
WHERE ${deprioWhere}`, [
|
|
63865
|
+
WHERE ${deprioWhere}`, [timestamp2, cutoff]);
|
|
63435
63866
|
}
|
|
63436
63867
|
return count;
|
|
63437
63868
|
}
|
|
@@ -63967,9 +64398,7 @@ function registerProjectCommands(program2) {
|
|
|
63967
64398
|
process.exit(1);
|
|
63968
64399
|
}
|
|
63969
64400
|
const common = {
|
|
63970
|
-
|
|
63971
|
-
tenant_id: "default",
|
|
63972
|
-
corpus_id: "default",
|
|
64401
|
+
...resolveMementosProjectAuthorityIdentity(),
|
|
63973
64402
|
operation_id: opts.operationId ?? idempotencyKey,
|
|
63974
64403
|
step_id: opts.stepId ?? (rollbackReceipt ? "mementos_project_rollback" : "mementos_project_update"),
|
|
63975
64404
|
idempotency_key: idempotencyKey,
|
|
@@ -64025,6 +64454,54 @@ function registerProjectCommands(program2) {
|
|
|
64025
64454
|
handleError(e);
|
|
64026
64455
|
}
|
|
64027
64456
|
});
|
|
64457
|
+
program2.command("project-resources <project-id>").description("Enumerate the complete project-owned Mementos resource population").option("--limit <n>", "Bounded page size (1-1000)", parseInt).option("--cursor <cursor>", "Opaque revision-bound continuation cursor").option("--kinds <kinds>", "Comma-separated resource kinds: project,knowledge,memory,session").option("--all", "Traverse every page and verify complete unique coverage").option("--resource-kind <kind>", "Read one exact resource kind").option("--resource-id <id>", "Read one exact stable resource ID").action((projectId, opts) => {
|
|
64458
|
+
try {
|
|
64459
|
+
const globalOpts = program2.opts();
|
|
64460
|
+
const resourceKind = opts.resourceKind;
|
|
64461
|
+
const resourceId = opts.resourceId;
|
|
64462
|
+
if (Boolean(resourceKind) !== Boolean(resourceId)) {
|
|
64463
|
+
throw new Error("--resource-kind and --resource-id must be provided together");
|
|
64464
|
+
}
|
|
64465
|
+
const resourceKinds = opts.kinds === undefined ? undefined : String(opts.kinds).split(",").map((value) => value.trim()).filter(Boolean);
|
|
64466
|
+
if (resourceKinds) {
|
|
64467
|
+
for (const kind of resourceKinds) {
|
|
64468
|
+
if (!MEMENTOS_PROJECT_RESOURCE_KINDS.includes(kind)) {
|
|
64469
|
+
throw new Error(`Unsupported project resource kind: ${kind}`);
|
|
64470
|
+
}
|
|
64471
|
+
}
|
|
64472
|
+
}
|
|
64473
|
+
const result = resourceKind && resourceId ? getMementosProjectResourceExact(projectId, resourceKind, resourceId) : opts.all ? readAllMementosProjectResources(projectId, {
|
|
64474
|
+
page_size: opts.limit,
|
|
64475
|
+
resource_kinds: resourceKinds
|
|
64476
|
+
}) : readMementosProjectResourcePage(projectId, {
|
|
64477
|
+
limit: opts.limit,
|
|
64478
|
+
cursor: opts.cursor,
|
|
64479
|
+
resource_kinds: resourceKinds
|
|
64480
|
+
});
|
|
64481
|
+
if (globalOpts.json) {
|
|
64482
|
+
outputJson(result);
|
|
64483
|
+
return;
|
|
64484
|
+
}
|
|
64485
|
+
if ("resource" in result) {
|
|
64486
|
+
console.log(chalk23.green("Project resource:"));
|
|
64487
|
+
console.log(` ${chalk23.bold("Project:")} ${result.project_id}`);
|
|
64488
|
+
console.log(` ${chalk23.bold("Kind:")} ${result.resource.resource_kind}`);
|
|
64489
|
+
console.log(` ${chalk23.bold("Stable ID:")} ${result.resource.stable_id}`);
|
|
64490
|
+
console.log(` ${chalk23.bold("Revision:")} ${result.resource.revision}`);
|
|
64491
|
+
return;
|
|
64492
|
+
}
|
|
64493
|
+
console.log(chalk23.bold(`${result.count} of ${result.total} project resource${result.total === 1 ? "" : "s"}:`));
|
|
64494
|
+
for (const resource of result.resources) {
|
|
64495
|
+
console.log(` ${chalk23.dim(resource.resource_kind.padEnd(9))} ${resource.stable_id}`);
|
|
64496
|
+
}
|
|
64497
|
+
console.log(` ${chalk23.bold("Complete:")} ${result.complete} ` + `${chalk23.bold("Has more:")} ${result.has_more}`);
|
|
64498
|
+
if (result.next_cursor) {
|
|
64499
|
+
console.log(chalk23.dim(`Next: mementos project-resources ${projectId} --cursor ${result.next_cursor}`));
|
|
64500
|
+
}
|
|
64501
|
+
} catch (error) {
|
|
64502
|
+
handleError(error);
|
|
64503
|
+
}
|
|
64504
|
+
});
|
|
64028
64505
|
program2.command("inject").description("Output injection context for agent system prompts").option("--agent <name>", "Agent ID for scope filtering").option("--project <path>", "Project path for scope filtering").option("--session <id>", "Session ID for scope filtering").option("--machine <id>", "Machine ID for machine-local memory visibility").option("--max-tokens <n>", "Max approximate token budget", parseInt).option("--categories <cats>", "Comma-separated categories to include").option("--format <fmt>", "Output format: xml (default), compact, markdown, json").action((opts) => {
|
|
64029
64506
|
try {
|
|
64030
64507
|
const globalOpts = program2.opts();
|
|
@@ -64214,7 +64691,7 @@ function memoryResource(memory) {
|
|
|
64214
64691
|
tags: memory.tags
|
|
64215
64692
|
};
|
|
64216
64693
|
}
|
|
64217
|
-
function
|
|
64694
|
+
function projectResource2(projectId, name, externalId) {
|
|
64218
64695
|
return {
|
|
64219
64696
|
kind: "project",
|
|
64220
64697
|
id: projectId,
|
|
@@ -64320,7 +64797,7 @@ function createMementosProjectPanel(projectRef, options = {}) {
|
|
|
64320
64797
|
actionResource("mementos:save", "Save project memory")
|
|
64321
64798
|
],
|
|
64322
64799
|
resourceRefs: [
|
|
64323
|
-
|
|
64800
|
+
projectResource2(projectId, project?.name ?? projectRef, project?.id ?? projectRef),
|
|
64324
64801
|
...memories.slice(0, limit).map(memoryResource)
|
|
64325
64802
|
],
|
|
64326
64803
|
renderFragment: {
|
|
@@ -66617,13 +67094,13 @@ function buildConflictKey(key, sourceMachine, updatedAt) {
|
|
|
66617
67094
|
return `${key}__conflict__${machineSegment}__${timestampSegment || "0"}`;
|
|
66618
67095
|
}
|
|
66619
67096
|
function buildConflictClone(loser, sourceMachine, winnerId) {
|
|
66620
|
-
const
|
|
67097
|
+
const timestamp2 = new Date().toISOString();
|
|
66621
67098
|
const tags = new Set(ensureArrayValue(loser["tags"]));
|
|
66622
67099
|
tags.add("sync-conflict");
|
|
66623
67100
|
tags.add(`source_machine:${sourceMachine}`);
|
|
66624
67101
|
const metadata = ensureObjectValue(loser["metadata"]);
|
|
66625
67102
|
metadata["sync_conflict"] = true;
|
|
66626
|
-
metadata["conflict_detected_at"] =
|
|
67103
|
+
metadata["conflict_detected_at"] = timestamp2;
|
|
66627
67104
|
metadata["conflict_original_id"] = loser["id"];
|
|
66628
67105
|
metadata["conflict_winner_id"] = winnerId;
|
|
66629
67106
|
metadata["conflict_source_machine"] = sourceMachine;
|
|
@@ -66635,10 +67112,10 @@ function buildConflictClone(loser, sourceMachine, winnerId) {
|
|
|
66635
67112
|
metadata: JSON.stringify(metadata),
|
|
66636
67113
|
access_count: 0,
|
|
66637
67114
|
version: 1,
|
|
66638
|
-
created_at:
|
|
66639
|
-
updated_at:
|
|
67115
|
+
created_at: timestamp2,
|
|
67116
|
+
updated_at: timestamp2,
|
|
66640
67117
|
..."accessed_at" in loser ? { accessed_at: null } : {},
|
|
66641
|
-
..."ingested_at" in loser ? { ingested_at:
|
|
67118
|
+
..."ingested_at" in loser ? { ingested_at: timestamp2 } : {}
|
|
66642
67119
|
}, sourceMachine);
|
|
66643
67120
|
}
|
|
66644
67121
|
function insertConflictCloneIfMissing(db, clone) {
|
|
@@ -67402,7 +67879,7 @@ function parseMemoryLink(row) {
|
|
|
67402
67879
|
function createMemoryLink(input, db) {
|
|
67403
67880
|
const d = db || getDatabase();
|
|
67404
67881
|
const id = shortUuid();
|
|
67405
|
-
const
|
|
67882
|
+
const timestamp2 = now();
|
|
67406
67883
|
d.run(`INSERT OR IGNORE INTO memory_links (id, source_memory_id, target_memory_id, relation_type, run_id, metadata, created_at)
|
|
67407
67884
|
VALUES (?, ?, ?, ?, ?, ?, ?)`, [
|
|
67408
67885
|
id,
|
|
@@ -67411,7 +67888,7 @@ function createMemoryLink(input, db) {
|
|
|
67411
67888
|
input.relation_type,
|
|
67412
67889
|
input.run_id ?? null,
|
|
67413
67890
|
JSON.stringify(input.metadata ?? {}),
|
|
67414
|
-
|
|
67891
|
+
timestamp2
|
|
67415
67892
|
]);
|
|
67416
67893
|
const row = d.query(`SELECT * FROM memory_links
|
|
67417
67894
|
WHERE source_memory_id = ? AND target_memory_id = ? AND relation_type = ? AND COALESCE(run_id, '') = ?
|
|
@@ -68610,8 +69087,8 @@ function makeBrainsCommand() {
|
|
|
68610
69087
|
if (!existsSync11(outputDir)) {
|
|
68611
69088
|
mkdirSync8(outputDir, { recursive: true });
|
|
68612
69089
|
}
|
|
68613
|
-
const
|
|
68614
|
-
const outputPath = join12(outputDir, `mementos-training-${
|
|
69090
|
+
const timestamp2 = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
69091
|
+
const outputPath = join12(outputDir, `mementos-training-${timestamp2}.jsonl`);
|
|
68615
69092
|
const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
|
|
68616
69093
|
`);
|
|
68617
69094
|
writeFileSync6(outputPath, jsonl + `
|