@hasna/mementos 0.14.81 → 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 +547 -72
- package/dist/db/memory-project-link.d.ts.map +1 -1
- package/dist/db/projects.d.ts.map +1 -1
- package/dist/index.js +460 -81
- package/dist/project-registration/authority.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 +52 -0
- package/dist/project-registration/types.d.ts.map +1 -1
- package/dist/project-registration.js +1488 -55
- 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 +644 -145
- 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,7 +6548,7 @@ function normalizeProjectUpdateInput(input) {
|
|
|
6460
6548
|
}
|
|
6461
6549
|
return normalized;
|
|
6462
6550
|
}
|
|
6463
|
-
function assertProjectUpdateIdentity(identity, expectedIdentity =
|
|
6551
|
+
function assertProjectUpdateIdentity(identity, expectedIdentity = projectUpdateAuthority()) {
|
|
6464
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
|
}
|
|
@@ -6470,7 +6558,7 @@ 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, expectedIdentity =
|
|
6561
|
+
function assertProjectUpdateRequest(request, expectedIdentity = projectUpdateAuthority()) {
|
|
6474
6562
|
assertProjectUpdateIdentity(request, expectedIdentity);
|
|
6475
6563
|
assertBoundedIdentifier(request.operation_id, "operation_id");
|
|
6476
6564
|
assertBoundedIdentifier(request.step_id, "step_id");
|
|
@@ -6648,7 +6736,7 @@ 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, expectedIdentity =
|
|
6739
|
+
function previewProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority()) {
|
|
6652
6740
|
assertProjectUpdateRequest(request, expectedIdentity);
|
|
6653
6741
|
const normalized = normalizeProjectUpdateInput(request.updates);
|
|
6654
6742
|
if (!db && isApiMode()) {
|
|
@@ -6671,7 +6759,7 @@ function previewProjectUpdate(id, request, db, expectedIdentity = PROJECT_UPDATE
|
|
|
6671
6759
|
receipt: null
|
|
6672
6760
|
};
|
|
6673
6761
|
}
|
|
6674
|
-
function applyProjectUpdate(id, request, db, expectedIdentity =
|
|
6762
|
+
function applyProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority(), resultDigestForProject) {
|
|
6675
6763
|
assertProjectUpdateRequest(request, expectedIdentity);
|
|
6676
6764
|
const normalized = normalizeProjectUpdateInput(request.updates);
|
|
6677
6765
|
if (!db && isApiMode()) {
|
|
@@ -6740,7 +6828,7 @@ function applyProjectUpdate(id, request, db, expectedIdentity = PROJECT_UPDATE_A
|
|
|
6740
6828
|
return { dry_run: false, applied: true, project: readback, receipt };
|
|
6741
6829
|
});
|
|
6742
6830
|
}
|
|
6743
|
-
function rollbackProjectUpdate(id, request, db, expectedIdentity =
|
|
6831
|
+
function rollbackProjectUpdate(id, request, db, expectedIdentity = projectUpdateAuthority(), resultDigestForProject) {
|
|
6744
6832
|
assertProjectUpdateRequest(request, expectedIdentity);
|
|
6745
6833
|
assertBoundedIdentifier(request.accepted_receipt_id, "accepted_receipt_id");
|
|
6746
6834
|
if (!db && isApiMode()) {
|
|
@@ -6814,7 +6902,7 @@ function rollbackProjectUpdate(id, request, db, expectedIdentity = PROJECT_UPDAT
|
|
|
6814
6902
|
return { dry_run: false, applied: true, project: readback, receipt };
|
|
6815
6903
|
});
|
|
6816
6904
|
}
|
|
6817
|
-
function getProjectUpdateReceipt(id, receiptId, identity =
|
|
6905
|
+
function getProjectUpdateReceipt(id, receiptId, identity = projectUpdateAuthority(), db, expectedIdentity = projectUpdateAuthority()) {
|
|
6818
6906
|
assertProjectUpdateIdentity(identity, expectedIdentity);
|
|
6819
6907
|
if (!db && isApiMode()) {
|
|
6820
6908
|
const { data } = apiJson("POST", `/projects/${encodeURIComponent(id)}/update-receipts/lookup`, { ...identity, receipt_id: receiptId });
|
|
@@ -6892,12 +6980,13 @@ function updateProject(id, input, db) {
|
|
|
6892
6980
|
return updated ? parseProjectRow(updated) : null;
|
|
6893
6981
|
});
|
|
6894
6982
|
}
|
|
6895
|
-
var ProjectCollisionError, ProjectGuardedUpdateError,
|
|
6983
|
+
var ProjectCollisionError, ProjectGuardedUpdateError, BOUNDED_IDENTIFIER;
|
|
6896
6984
|
var init_projects = __esm(() => {
|
|
6897
6985
|
init_database();
|
|
6898
6986
|
init_api_mode();
|
|
6899
6987
|
init_package_version();
|
|
6900
6988
|
init_types2();
|
|
6989
|
+
init_identity();
|
|
6901
6990
|
ProjectCollisionError = class ProjectCollisionError extends Error {
|
|
6902
6991
|
field;
|
|
6903
6992
|
value;
|
|
@@ -6918,11 +7007,6 @@ var init_projects = __esm(() => {
|
|
|
6918
7007
|
this.name = "ProjectGuardedUpdateError";
|
|
6919
7008
|
}
|
|
6920
7009
|
};
|
|
6921
|
-
PROJECT_UPDATE_AUTHORITY = {
|
|
6922
|
-
authority_id: "mementos",
|
|
6923
|
-
tenant_id: "default",
|
|
6924
|
-
corpus_id: "default"
|
|
6925
|
-
};
|
|
6926
7010
|
BOUNDED_IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
|
|
6927
7011
|
});
|
|
6928
7012
|
|
|
@@ -8564,13 +8648,13 @@ function createRelation(input, db) {
|
|
|
8564
8648
|
}
|
|
8565
8649
|
const d = db || getDatabase();
|
|
8566
8650
|
const id = shortUuid();
|
|
8567
|
-
const
|
|
8651
|
+
const timestamp2 = now();
|
|
8568
8652
|
const weight = input.weight ?? 1;
|
|
8569
8653
|
const metadata = JSON.stringify(input.metadata ?? {});
|
|
8570
8654
|
d.run(`INSERT INTO relations (id, source_entity_id, target_entity_id, relation_type, weight, metadata, created_at)
|
|
8571
8655
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
8572
8656
|
ON CONFLICT(source_entity_id, target_entity_id, relation_type)
|
|
8573
|
-
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]);
|
|
8574
8658
|
const row = d.query(`SELECT * FROM relations
|
|
8575
8659
|
WHERE source_entity_id = ? AND target_entity_id = ? AND relation_type = ?`).get(input.source_entity_id, input.target_entity_id, input.relation_type);
|
|
8576
8660
|
const relation = parseRelationRow(row);
|
|
@@ -9562,7 +9646,7 @@ function createWebhookHook(input, db) {
|
|
|
9562
9646
|
}
|
|
9563
9647
|
const d = db || getDatabase();
|
|
9564
9648
|
const id = shortUuid();
|
|
9565
|
-
const
|
|
9649
|
+
const timestamp2 = now();
|
|
9566
9650
|
d.run(`INSERT INTO webhook_hooks
|
|
9567
9651
|
(id, type, handler_url, priority, blocking, agent_id, project_id, description, enabled, created_at, invocation_count, failure_count)
|
|
9568
9652
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, 0, 0)`, [
|
|
@@ -9574,7 +9658,7 @@ function createWebhookHook(input, db) {
|
|
|
9574
9658
|
input.agentId ?? null,
|
|
9575
9659
|
input.projectId ?? null,
|
|
9576
9660
|
input.description ?? null,
|
|
9577
|
-
|
|
9661
|
+
timestamp2
|
|
9578
9662
|
]);
|
|
9579
9663
|
return getWebhookHook(id, d);
|
|
9580
9664
|
}
|
|
@@ -9745,7 +9829,7 @@ function parseEventRow(row) {
|
|
|
9745
9829
|
function createSynthesisRun(input, db) {
|
|
9746
9830
|
const d = db || getDatabase();
|
|
9747
9831
|
const id = shortUuid();
|
|
9748
|
-
const
|
|
9832
|
+
const timestamp2 = now();
|
|
9749
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)
|
|
9750
9834
|
VALUES (?, ?, ?, ?, ?, 0, 0, 0, 'pending', ?)`, [
|
|
9751
9835
|
id,
|
|
@@ -9753,7 +9837,7 @@ function createSynthesisRun(input, db) {
|
|
|
9753
9837
|
input.project_id ?? null,
|
|
9754
9838
|
input.agent_id ?? null,
|
|
9755
9839
|
input.corpus_size ?? 0,
|
|
9756
|
-
|
|
9840
|
+
timestamp2
|
|
9757
9841
|
]);
|
|
9758
9842
|
return getSynthesisRun(id, d);
|
|
9759
9843
|
}
|
|
@@ -9846,7 +9930,7 @@ function updateSynthesisRun(id, updates, db) {
|
|
|
9846
9930
|
function createProposal(input, db) {
|
|
9847
9931
|
const d = db || getDatabase();
|
|
9848
9932
|
const id = shortUuid();
|
|
9849
|
-
const
|
|
9933
|
+
const timestamp2 = now();
|
|
9850
9934
|
d.run(`INSERT INTO synthesis_proposals (id, run_id, proposal_type, memory_ids, target_memory_id, proposed_changes, reasoning, confidence, status, created_at)
|
|
9851
9935
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?)`, [
|
|
9852
9936
|
id,
|
|
@@ -9857,7 +9941,7 @@ function createProposal(input, db) {
|
|
|
9857
9941
|
JSON.stringify(input.proposed_changes),
|
|
9858
9942
|
input.reasoning ?? null,
|
|
9859
9943
|
input.confidence,
|
|
9860
|
-
|
|
9944
|
+
timestamp2
|
|
9861
9945
|
]);
|
|
9862
9946
|
return getProposal(id, d);
|
|
9863
9947
|
}
|
|
@@ -9905,10 +9989,10 @@ function updateProposal(id, updates, db) {
|
|
|
9905
9989
|
function createMetric(input, db) {
|
|
9906
9990
|
const d = db || getDatabase();
|
|
9907
9991
|
const id = shortUuid();
|
|
9908
|
-
const
|
|
9992
|
+
const timestamp2 = now();
|
|
9909
9993
|
d.run(`INSERT INTO synthesis_metrics (id, run_id, metric_type, value, baseline, created_at)
|
|
9910
|
-
VALUES (?, ?, ?, ?, ?, ?)`, [id, input.run_id, input.metric_type, input.value, input.baseline ?? null,
|
|
9911
|
-
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 };
|
|
9912
9996
|
}
|
|
9913
9997
|
function listMetrics(run_id, db) {
|
|
9914
9998
|
const d = db || getDatabase();
|
|
@@ -9919,7 +10003,7 @@ function recordSynthesisEvent(input, db) {
|
|
|
9919
10003
|
try {
|
|
9920
10004
|
const d = db || getDatabase();
|
|
9921
10005
|
const id = shortUuid();
|
|
9922
|
-
const
|
|
10006
|
+
const timestamp2 = now();
|
|
9923
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)
|
|
9924
10008
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
9925
10009
|
id,
|
|
@@ -9931,7 +10015,7 @@ function recordSynthesisEvent(input, db) {
|
|
|
9931
10015
|
input.query ?? null,
|
|
9932
10016
|
input.importance_at_time ?? null,
|
|
9933
10017
|
JSON.stringify(input.metadata ?? {}),
|
|
9934
|
-
|
|
10018
|
+
timestamp2
|
|
9935
10019
|
]);
|
|
9936
10020
|
} catch {}
|
|
9937
10021
|
}
|
|
@@ -10173,20 +10257,20 @@ __export(exports_contradiction, {
|
|
|
10173
10257
|
});
|
|
10174
10258
|
function invalidateFact(oldMemoryId, newMemoryId, db) {
|
|
10175
10259
|
const d = db || getDatabase();
|
|
10176
|
-
const
|
|
10177
|
-
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]);
|
|
10178
10262
|
if (newMemoryId) {
|
|
10179
10263
|
const row = d.query("SELECT metadata FROM memories WHERE id = ?").get(newMemoryId);
|
|
10180
10264
|
if (row) {
|
|
10181
10265
|
const metadata = JSON.parse(row.metadata || "{}");
|
|
10182
10266
|
metadata.supersedes_id = oldMemoryId;
|
|
10183
|
-
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]);
|
|
10184
10268
|
}
|
|
10185
10269
|
}
|
|
10186
10270
|
return {
|
|
10187
10271
|
invalidated_memory_id: oldMemoryId,
|
|
10188
10272
|
new_memory_id: newMemoryId || null,
|
|
10189
|
-
valid_until:
|
|
10273
|
+
valid_until: timestamp2,
|
|
10190
10274
|
supersedes_id: oldMemoryId
|
|
10191
10275
|
};
|
|
10192
10276
|
}
|
|
@@ -11456,7 +11540,7 @@ function parseJobRow(row) {
|
|
|
11456
11540
|
function createSessionJob(input, db) {
|
|
11457
11541
|
const d = db || getDatabase();
|
|
11458
11542
|
const id = uuid();
|
|
11459
|
-
const
|
|
11543
|
+
const timestamp2 = now();
|
|
11460
11544
|
const source = input.source ?? "manual";
|
|
11461
11545
|
const metadata = JSON.stringify(input.metadata ?? {});
|
|
11462
11546
|
d.run(`INSERT INTO session_memory_jobs
|
|
@@ -11469,7 +11553,7 @@ function createSessionJob(input, db) {
|
|
|
11469
11553
|
source,
|
|
11470
11554
|
input.transcript,
|
|
11471
11555
|
metadata,
|
|
11472
|
-
|
|
11556
|
+
timestamp2
|
|
11473
11557
|
]);
|
|
11474
11558
|
return getSessionJob(id, d);
|
|
11475
11559
|
}
|
|
@@ -11605,7 +11689,7 @@ function saveToolEvent(input, db) {
|
|
|
11605
11689
|
}
|
|
11606
11690
|
const d = db || getDatabase();
|
|
11607
11691
|
const id = uuid();
|
|
11608
|
-
const
|
|
11692
|
+
const timestamp2 = now();
|
|
11609
11693
|
const metadataJson = JSON.stringify(input.metadata || {});
|
|
11610
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)
|
|
11611
11695
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
@@ -11624,7 +11708,7 @@ function saveToolEvent(input, db) {
|
|
|
11624
11708
|
input.project_id || null,
|
|
11625
11709
|
input.session_id || null,
|
|
11626
11710
|
metadataJson,
|
|
11627
|
-
|
|
11711
|
+
timestamp2
|
|
11628
11712
|
]);
|
|
11629
11713
|
return getToolEvent(id, d);
|
|
11630
11714
|
}
|
|
@@ -12347,7 +12431,7 @@ function registerSession(opts) {
|
|
|
12347
12431
|
const pid = process.pid;
|
|
12348
12432
|
const cwd = opts.cwd || process.cwd();
|
|
12349
12433
|
const id = generateId();
|
|
12350
|
-
const
|
|
12434
|
+
const timestamp2 = now3();
|
|
12351
12435
|
const existing = db.query("SELECT id FROM sessions WHERE pid = ? AND mcp_server = ?").get(pid, opts.mcp_server);
|
|
12352
12436
|
if (existing) {
|
|
12353
12437
|
db.run(`UPDATE sessions SET agent_name = ?, project_name = ?, cwd = ?,
|
|
@@ -12358,7 +12442,7 @@ function registerSession(opts) {
|
|
|
12358
12442
|
opts.git_root || null,
|
|
12359
12443
|
opts.tty || null,
|
|
12360
12444
|
JSON.stringify(opts.metadata || {}),
|
|
12361
|
-
|
|
12445
|
+
timestamp2,
|
|
12362
12446
|
existing.id
|
|
12363
12447
|
]);
|
|
12364
12448
|
return getSession(existing.id);
|
|
@@ -12374,8 +12458,8 @@ function registerSession(opts) {
|
|
|
12374
12458
|
opts.tty || null,
|
|
12375
12459
|
opts.mcp_server,
|
|
12376
12460
|
JSON.stringify(opts.metadata || {}),
|
|
12377
|
-
|
|
12378
|
-
|
|
12461
|
+
timestamp2,
|
|
12462
|
+
timestamp2
|
|
12379
12463
|
]);
|
|
12380
12464
|
return getSession(id);
|
|
12381
12465
|
}
|
|
@@ -60779,6 +60863,7 @@ init_database();
|
|
|
60779
60863
|
init_memories();
|
|
60780
60864
|
init_package_version();
|
|
60781
60865
|
init_schema();
|
|
60866
|
+
init_identity();
|
|
60782
60867
|
import { createHash as createHash2 } from "crypto";
|
|
60783
60868
|
|
|
60784
60869
|
class MemoryProjectLinkError extends Error {
|
|
@@ -60791,12 +60876,17 @@ class MemoryProjectLinkError extends Error {
|
|
|
60791
60876
|
this.name = "MemoryProjectLinkError";
|
|
60792
60877
|
}
|
|
60793
60878
|
}
|
|
60794
|
-
var LINK_AUTHORITY = {
|
|
60795
|
-
authority_id: "mementos",
|
|
60796
|
-
tenant_id: "default",
|
|
60797
|
-
corpus_id: "default"
|
|
60798
|
-
};
|
|
60799
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
|
+
}
|
|
60800
60890
|
function canonicalize(value) {
|
|
60801
60891
|
if (Array.isArray(value))
|
|
60802
60892
|
return value.map(canonicalize);
|
|
@@ -60904,7 +60994,8 @@ function receiptFromRow(row) {
|
|
|
60904
60994
|
};
|
|
60905
60995
|
}
|
|
60906
60996
|
function assertIdentity(identity) {
|
|
60907
|
-
|
|
60997
|
+
const expectedIdentity = linkAuthority();
|
|
60998
|
+
if (identity.authority_id !== expectedIdentity.authority_id || identity.tenant_id !== expectedIdentity.tenant_id || identity.corpus_id !== expectedIdentity.corpus_id) {
|
|
60908
60999
|
throw new MemoryProjectLinkError("MEMORY_PROJECT_LINK_AUTHORITY_MISMATCH", "memory project link does not match this authority, tenant, and corpus");
|
|
60909
61000
|
}
|
|
60910
61001
|
}
|
|
@@ -61381,7 +61472,7 @@ function rollbackMemoryProjectLink(memoryId, request, db) {
|
|
|
61381
61472
|
};
|
|
61382
61473
|
});
|
|
61383
61474
|
}
|
|
61384
|
-
function getMemoryProjectLinkReceipt(memoryId, receiptId, identity =
|
|
61475
|
+
function getMemoryProjectLinkReceipt(memoryId, receiptId, identity = linkAuthority(), db) {
|
|
61385
61476
|
assertIdentity(identity);
|
|
61386
61477
|
assertBoundedIdentifier2(memoryId, "memory_id");
|
|
61387
61478
|
assertBoundedIdentifier2(receiptId, "receipt_id");
|
|
@@ -61397,6 +61488,348 @@ function getMemoryProjectLinkReceipt(memoryId, receiptId, identity = LINK_AUTHOR
|
|
|
61397
61488
|
return receipt;
|
|
61398
61489
|
}
|
|
61399
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
|
+
|
|
61400
61833
|
// src/cli/commands/memory-cmd-crud.ts
|
|
61401
61834
|
init_projects();
|
|
61402
61835
|
init_agents();
|
|
@@ -61464,9 +61897,7 @@ function registerCrudCommands(program2) {
|
|
|
61464
61897
|
throw new Error("Receipt lookup cannot be combined with link, rollback, or dry-run options");
|
|
61465
61898
|
}
|
|
61466
61899
|
const receipt = getMemoryProjectLinkReceipt(memoryId, lookupReceipt, {
|
|
61467
|
-
|
|
61468
|
-
tenant_id: "default",
|
|
61469
|
-
corpus_id: "default"
|
|
61900
|
+
...resolveMementosProjectAuthorityIdentity()
|
|
61470
61901
|
});
|
|
61471
61902
|
if (globalOpts.json)
|
|
61472
61903
|
outputJson(receipt);
|
|
@@ -61492,9 +61923,7 @@ function registerCrudCommands(program2) {
|
|
|
61492
61923
|
throw new Error("--project-id and --rollback-receipt cannot be used together");
|
|
61493
61924
|
}
|
|
61494
61925
|
const common = {
|
|
61495
|
-
|
|
61496
|
-
tenant_id: "default",
|
|
61497
|
-
corpus_id: "default",
|
|
61926
|
+
...resolveMementosProjectAuthorityIdentity(),
|
|
61498
61927
|
operation_id: opts.operationId ?? idempotencyKey,
|
|
61499
61928
|
step_id: opts.stepId ?? (rollbackReceipt ? "mementos_memory_project_link_rollback" : "mementos_memory_project_link"),
|
|
61500
61929
|
idempotency_key: idempotencyKey,
|
|
@@ -63402,29 +63831,29 @@ function enforceQuotas(config, db) {
|
|
|
63402
63831
|
}
|
|
63403
63832
|
function archiveStale(staleDays, db) {
|
|
63404
63833
|
const d = db || getDatabase();
|
|
63405
|
-
const
|
|
63834
|
+
const timestamp2 = now();
|
|
63406
63835
|
const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000).toISOString();
|
|
63407
63836
|
const archiveWhere = `status = 'active' AND pinned = 0 AND COALESCE(accessed_at, created_at) < ?`;
|
|
63408
63837
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${archiveWhere}`).get(cutoff).c;
|
|
63409
63838
|
if (count > 0) {
|
|
63410
|
-
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]);
|
|
63411
63840
|
}
|
|
63412
63841
|
return count;
|
|
63413
63842
|
}
|
|
63414
63843
|
function archiveUnused(days, db) {
|
|
63415
63844
|
const d = db || getDatabase();
|
|
63416
|
-
const
|
|
63845
|
+
const timestamp2 = now();
|
|
63417
63846
|
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
63418
63847
|
const unusedWhere = `status = 'active' AND pinned = 0 AND access_count = 0 AND created_at < ?`;
|
|
63419
63848
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${unusedWhere}`).get(cutoff).c;
|
|
63420
63849
|
if (count > 0) {
|
|
63421
|
-
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]);
|
|
63422
63851
|
}
|
|
63423
63852
|
return count;
|
|
63424
63853
|
}
|
|
63425
63854
|
function deprioritizeStale(days, db) {
|
|
63426
63855
|
const d = db || getDatabase();
|
|
63427
|
-
const
|
|
63856
|
+
const timestamp2 = now();
|
|
63428
63857
|
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
63429
63858
|
const deprioWhere = `status = 'active' AND pinned = 0 AND importance > 1 AND COALESCE(accessed_at, updated_at) < ?`;
|
|
63430
63859
|
const count = d.query(`SELECT COUNT(*) as c FROM memories WHERE ${deprioWhere}`).get(cutoff).c;
|
|
@@ -63433,7 +63862,7 @@ function deprioritizeStale(days, db) {
|
|
|
63433
63862
|
SET importance = importance - 1,
|
|
63434
63863
|
version = version + 1,
|
|
63435
63864
|
updated_at = ?
|
|
63436
|
-
WHERE ${deprioWhere}`, [
|
|
63865
|
+
WHERE ${deprioWhere}`, [timestamp2, cutoff]);
|
|
63437
63866
|
}
|
|
63438
63867
|
return count;
|
|
63439
63868
|
}
|
|
@@ -63969,9 +64398,7 @@ function registerProjectCommands(program2) {
|
|
|
63969
64398
|
process.exit(1);
|
|
63970
64399
|
}
|
|
63971
64400
|
const common = {
|
|
63972
|
-
|
|
63973
|
-
tenant_id: "default",
|
|
63974
|
-
corpus_id: "default",
|
|
64401
|
+
...resolveMementosProjectAuthorityIdentity(),
|
|
63975
64402
|
operation_id: opts.operationId ?? idempotencyKey,
|
|
63976
64403
|
step_id: opts.stepId ?? (rollbackReceipt ? "mementos_project_rollback" : "mementos_project_update"),
|
|
63977
64404
|
idempotency_key: idempotencyKey,
|
|
@@ -64027,6 +64454,54 @@ function registerProjectCommands(program2) {
|
|
|
64027
64454
|
handleError(e);
|
|
64028
64455
|
}
|
|
64029
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
|
+
});
|
|
64030
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) => {
|
|
64031
64506
|
try {
|
|
64032
64507
|
const globalOpts = program2.opts();
|
|
@@ -64216,7 +64691,7 @@ function memoryResource(memory) {
|
|
|
64216
64691
|
tags: memory.tags
|
|
64217
64692
|
};
|
|
64218
64693
|
}
|
|
64219
|
-
function
|
|
64694
|
+
function projectResource2(projectId, name, externalId) {
|
|
64220
64695
|
return {
|
|
64221
64696
|
kind: "project",
|
|
64222
64697
|
id: projectId,
|
|
@@ -64322,7 +64797,7 @@ function createMementosProjectPanel(projectRef, options = {}) {
|
|
|
64322
64797
|
actionResource("mementos:save", "Save project memory")
|
|
64323
64798
|
],
|
|
64324
64799
|
resourceRefs: [
|
|
64325
|
-
|
|
64800
|
+
projectResource2(projectId, project?.name ?? projectRef, project?.id ?? projectRef),
|
|
64326
64801
|
...memories.slice(0, limit).map(memoryResource)
|
|
64327
64802
|
],
|
|
64328
64803
|
renderFragment: {
|
|
@@ -66619,13 +67094,13 @@ function buildConflictKey(key, sourceMachine, updatedAt) {
|
|
|
66619
67094
|
return `${key}__conflict__${machineSegment}__${timestampSegment || "0"}`;
|
|
66620
67095
|
}
|
|
66621
67096
|
function buildConflictClone(loser, sourceMachine, winnerId) {
|
|
66622
|
-
const
|
|
67097
|
+
const timestamp2 = new Date().toISOString();
|
|
66623
67098
|
const tags = new Set(ensureArrayValue(loser["tags"]));
|
|
66624
67099
|
tags.add("sync-conflict");
|
|
66625
67100
|
tags.add(`source_machine:${sourceMachine}`);
|
|
66626
67101
|
const metadata = ensureObjectValue(loser["metadata"]);
|
|
66627
67102
|
metadata["sync_conflict"] = true;
|
|
66628
|
-
metadata["conflict_detected_at"] =
|
|
67103
|
+
metadata["conflict_detected_at"] = timestamp2;
|
|
66629
67104
|
metadata["conflict_original_id"] = loser["id"];
|
|
66630
67105
|
metadata["conflict_winner_id"] = winnerId;
|
|
66631
67106
|
metadata["conflict_source_machine"] = sourceMachine;
|
|
@@ -66637,10 +67112,10 @@ function buildConflictClone(loser, sourceMachine, winnerId) {
|
|
|
66637
67112
|
metadata: JSON.stringify(metadata),
|
|
66638
67113
|
access_count: 0,
|
|
66639
67114
|
version: 1,
|
|
66640
|
-
created_at:
|
|
66641
|
-
updated_at:
|
|
67115
|
+
created_at: timestamp2,
|
|
67116
|
+
updated_at: timestamp2,
|
|
66642
67117
|
..."accessed_at" in loser ? { accessed_at: null } : {},
|
|
66643
|
-
..."ingested_at" in loser ? { ingested_at:
|
|
67118
|
+
..."ingested_at" in loser ? { ingested_at: timestamp2 } : {}
|
|
66644
67119
|
}, sourceMachine);
|
|
66645
67120
|
}
|
|
66646
67121
|
function insertConflictCloneIfMissing(db, clone) {
|
|
@@ -67404,7 +67879,7 @@ function parseMemoryLink(row) {
|
|
|
67404
67879
|
function createMemoryLink(input, db) {
|
|
67405
67880
|
const d = db || getDatabase();
|
|
67406
67881
|
const id = shortUuid();
|
|
67407
|
-
const
|
|
67882
|
+
const timestamp2 = now();
|
|
67408
67883
|
d.run(`INSERT OR IGNORE INTO memory_links (id, source_memory_id, target_memory_id, relation_type, run_id, metadata, created_at)
|
|
67409
67884
|
VALUES (?, ?, ?, ?, ?, ?, ?)`, [
|
|
67410
67885
|
id,
|
|
@@ -67413,7 +67888,7 @@ function createMemoryLink(input, db) {
|
|
|
67413
67888
|
input.relation_type,
|
|
67414
67889
|
input.run_id ?? null,
|
|
67415
67890
|
JSON.stringify(input.metadata ?? {}),
|
|
67416
|
-
|
|
67891
|
+
timestamp2
|
|
67417
67892
|
]);
|
|
67418
67893
|
const row = d.query(`SELECT * FROM memory_links
|
|
67419
67894
|
WHERE source_memory_id = ? AND target_memory_id = ? AND relation_type = ? AND COALESCE(run_id, '') = ?
|
|
@@ -68612,8 +69087,8 @@ function makeBrainsCommand() {
|
|
|
68612
69087
|
if (!existsSync11(outputDir)) {
|
|
68613
69088
|
mkdirSync8(outputDir, { recursive: true });
|
|
68614
69089
|
}
|
|
68615
|
-
const
|
|
68616
|
-
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`);
|
|
68617
69092
|
const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
|
|
68618
69093
|
`);
|
|
68619
69094
|
writeFileSync6(outputPath, jsonl + `
|