memorix 1.4.5 → 1.4.6
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/CHANGELOG.md +54 -0
- package/CLAUDE.md +7 -3
- package/README.md +5 -2
- package/dist/cli/index.js +1456 -1013
- package/dist/index.js +1265 -988
- package/dist/{maintenance-jobs-B1-W0ssz.d.ts → maintenance-jobs-DVRF-46r.d.ts} +1 -1
- package/dist/maintenance-runner.d.ts +1 -1
- package/dist/maintenance-runner.js +1755 -829
- package/dist/media-audio-runner.js +1760 -835
- package/dist/media-video-runner.js +1755 -830
- package/dist/memcode-runtime/CHANGELOG.md +54 -0
- package/dist/sdk.js +1257 -987
- package/dist/types.d.ts +6 -0
- package/dist/vector-backfill-runner.d.ts +1 -1
- package/dist/vector-backfill-runner.js +1751 -826
- package/docs/1.4.5-AGENT-AUTO-MEMORY-RESEARCH.md +95 -0
- package/docs/API_REFERENCE.md +23 -4
- package/docs/CONFIGURATION.md +17 -3
- package/docs/SETUP.md +5 -3
- package/package.json +1 -1
- package/plugins/antigravity/memorix/mcp_config.json +3 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/memorix/.mcp.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.mcp.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.mcp.json +1 -1
- package/plugins/copilot/memorix/.mcp.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +4 -2
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/openclaw/memorix/.mcp.json +3 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/dashboard.ts +14 -3
- package/src/cli/commands/ingest-commit.ts +47 -3
- package/src/cli/commands/memory.ts +17 -4
- package/src/cli/commands/purge.ts +120 -0
- package/src/cli/commands/serve-http.ts +39 -5
- package/src/cli/commands/setup.ts +3 -1
- package/src/cli/index.ts +3 -804
- package/src/codegraph/auto-context.ts +82 -1
- package/src/config/yaml-loader.ts +3 -8
- package/src/config.ts +0 -5
- package/src/evaluation/session-replay.ts +98 -0
- package/src/git/extractor.ts +5 -3
- package/src/hooks/installers/index.ts +15 -0
- package/src/knowledge/workset.ts +58 -0
- package/src/memory/long-term.ts +97 -2
- package/src/runtime/control-plane-maintenance.ts +1 -0
- package/src/runtime/isolated-maintenance.ts +1 -0
- package/src/runtime/lifecycle.ts +19 -0
- package/src/runtime/maintenance-jobs.ts +1 -0
- package/src/runtime/project-maintenance.ts +8 -0
- package/src/search/surfaced-registry.ts +62 -0
- package/src/server.ts +74 -14
- package/src/store/orama-store.ts +17 -1
- package/src/types.ts +6 -0
- package/src/cli/commands/audit-list.ts +0 -89
- package/src/cli/commands/purge-all-memory.ts +0 -85
- package/src/cli/commands/purge-project-memory.ts +0 -83
- package/src/cli/commands/uninstall-project-artifacts.ts +0 -86
- package/src/cli/tui/Sidebar.tsx +0 -179
- package/src/cli/tui/interactive-commands.ts +0 -261
- package/src/cli/tui/markdown-render.tsx +0 -371
- package/src/cli/tui/use-mouse.ts +0 -157
- package/src/cli/tui/useNavigation.ts +0 -56
- package/src/orchestrate/context-compact.ts +0 -188
- package/src/team/file-locks.ts +0 -173
- package/src/team/index.ts +0 -23
- package/src/team/messages.ts +0 -203
- package/src/team/persistence.ts +0 -96
- package/src/team/registry.ts +0 -158
- package/src/team/tasks.ts +0 -211
package/dist/index.js
CHANGED
|
@@ -3389,7 +3389,6 @@ __export(config_exports, {
|
|
|
3389
3389
|
getLLMProvider: () => getLLMProvider,
|
|
3390
3390
|
getLoadedEnvFiles: () => getLoadedEnvFiles,
|
|
3391
3391
|
getServerConfig: () => getServerConfig,
|
|
3392
|
-
getTeamConfig: () => getTeamConfig,
|
|
3393
3392
|
loadDotenv: () => loadDotenv,
|
|
3394
3393
|
loadFileConfig: () => loadFileConfig,
|
|
3395
3394
|
loadYamlConfig: () => loadYamlConfig,
|
|
@@ -3461,14 +3460,10 @@ function getServerConfig() {
|
|
|
3461
3460
|
port: server.port
|
|
3462
3461
|
};
|
|
3463
3462
|
}
|
|
3464
|
-
function getTeamConfig() {
|
|
3465
|
-
return loadYamlConfig().team ?? {};
|
|
3466
|
-
}
|
|
3467
3463
|
var init_config = __esm({
|
|
3468
3464
|
"src/config.ts"() {
|
|
3469
3465
|
"use strict";
|
|
3470
3466
|
init_esm_shims();
|
|
3471
|
-
init_yaml_loader();
|
|
3472
3467
|
init_resolved_config();
|
|
3473
3468
|
init_dotenv_loader();
|
|
3474
3469
|
init_legacy_loader();
|
|
@@ -5753,9 +5748,9 @@ async function saveRegistry(baseDir) {
|
|
|
5753
5748
|
await fs7.mkdir(path9.dirname(filePath), { recursive: true });
|
|
5754
5749
|
await fs7.writeFile(filePath, JSON.stringify(registryCache, null, 2), "utf-8");
|
|
5755
5750
|
}
|
|
5756
|
-
function findMatchingGroup(
|
|
5751
|
+
function findMatchingGroup(registry2, projectInfo) {
|
|
5757
5752
|
const normalizedRoot = normalizePath(projectInfo.rootPath);
|
|
5758
|
-
for (const group of
|
|
5753
|
+
for (const group of registry2.groups) {
|
|
5759
5754
|
if (group.aliases.includes(projectInfo.id)) return group;
|
|
5760
5755
|
if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;
|
|
5761
5756
|
if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {
|
|
@@ -5768,9 +5763,9 @@ function selectCanonical(aliases) {
|
|
|
5768
5763
|
return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];
|
|
5769
5764
|
}
|
|
5770
5765
|
async function registerAlias(projectInfo, baseDir) {
|
|
5771
|
-
const
|
|
5766
|
+
const registry2 = await loadRegistry(baseDir);
|
|
5772
5767
|
const normalizedRoot = normalizePath(projectInfo.rootPath);
|
|
5773
|
-
const existingGroup = findMatchingGroup(
|
|
5768
|
+
const existingGroup = findMatchingGroup(registry2, projectInfo);
|
|
5774
5769
|
if (existingGroup) {
|
|
5775
5770
|
let changed = false;
|
|
5776
5771
|
if (!existingGroup.aliases.includes(projectInfo.id)) {
|
|
@@ -5801,13 +5796,13 @@ async function registerAlias(projectInfo, baseDir) {
|
|
|
5801
5796
|
rootPaths: [normalizedRoot],
|
|
5802
5797
|
...projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}
|
|
5803
5798
|
};
|
|
5804
|
-
|
|
5799
|
+
registry2.groups.push(newGroup);
|
|
5805
5800
|
await saveRegistry(baseDir);
|
|
5806
5801
|
return newGroup.canonical;
|
|
5807
5802
|
}
|
|
5808
5803
|
async function resolveAliases(projectId, baseDir) {
|
|
5809
|
-
const
|
|
5810
|
-
for (const group of
|
|
5804
|
+
const registry2 = await loadRegistry(baseDir);
|
|
5805
|
+
for (const group of registry2.groups) {
|
|
5811
5806
|
if (group.aliases.includes(projectId) || group.canonical === projectId) {
|
|
5812
5807
|
return [...group.aliases];
|
|
5813
5808
|
}
|
|
@@ -5815,8 +5810,8 @@ async function resolveAliases(projectId, baseDir) {
|
|
|
5815
5810
|
return [projectId];
|
|
5816
5811
|
}
|
|
5817
5812
|
async function getCanonicalId(projectId, baseDir) {
|
|
5818
|
-
const
|
|
5819
|
-
for (const group of
|
|
5813
|
+
const registry2 = await loadRegistry(baseDir);
|
|
5814
|
+
for (const group of registry2.groups) {
|
|
5820
5815
|
if (group.aliases.includes(projectId) || group.canonical === projectId) {
|
|
5821
5816
|
return group.canonical;
|
|
5822
5817
|
}
|
|
@@ -5824,12 +5819,12 @@ async function getCanonicalId(projectId, baseDir) {
|
|
|
5824
5819
|
return projectId;
|
|
5825
5820
|
}
|
|
5826
5821
|
async function getAllAliasGroups(baseDir) {
|
|
5827
|
-
const
|
|
5828
|
-
return
|
|
5822
|
+
const registry2 = await loadRegistry(baseDir);
|
|
5823
|
+
return registry2.groups;
|
|
5829
5824
|
}
|
|
5830
5825
|
async function autoMergeByBaseName(observedIds, baseDir) {
|
|
5831
5826
|
if (observedIds.length <= 1) return 0;
|
|
5832
|
-
const
|
|
5827
|
+
const registry2 = await loadRegistry(baseDir);
|
|
5833
5828
|
const byBaseName = /* @__PURE__ */ new Map();
|
|
5834
5829
|
for (const id of observedIds) {
|
|
5835
5830
|
const baseName = id.split("/").pop() ?? id;
|
|
@@ -5842,7 +5837,7 @@ async function autoMergeByBaseName(observedIds, baseDir) {
|
|
|
5842
5837
|
const existingGroups = /* @__PURE__ */ new Set();
|
|
5843
5838
|
const ungroupedIds = [];
|
|
5844
5839
|
for (const id of ids) {
|
|
5845
|
-
const groupIdx =
|
|
5840
|
+
const groupIdx = registry2.groups.findIndex(
|
|
5846
5841
|
(g) => g.aliases.includes(id) || g.canonical === id
|
|
5847
5842
|
);
|
|
5848
5843
|
if (groupIdx >= 0) {
|
|
@@ -5856,7 +5851,7 @@ async function autoMergeByBaseName(observedIds, baseDir) {
|
|
|
5856
5851
|
const canonical = selectCanonical(allIdsInGroup);
|
|
5857
5852
|
if (existingGroups.size > 0) {
|
|
5858
5853
|
const primaryIdx = [...existingGroups][0];
|
|
5859
|
-
const primaryGroup =
|
|
5854
|
+
const primaryGroup = registry2.groups[primaryIdx];
|
|
5860
5855
|
for (const id of allIdsInGroup) {
|
|
5861
5856
|
if (!primaryGroup.aliases.includes(id)) {
|
|
5862
5857
|
primaryGroup.aliases.push(id);
|
|
@@ -5864,7 +5859,7 @@ async function autoMergeByBaseName(observedIds, baseDir) {
|
|
|
5864
5859
|
}
|
|
5865
5860
|
const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);
|
|
5866
5861
|
for (const idx of otherIdxs) {
|
|
5867
|
-
const other =
|
|
5862
|
+
const other = registry2.groups[idx];
|
|
5868
5863
|
for (const alias of other.aliases) {
|
|
5869
5864
|
if (!primaryGroup.aliases.includes(alias)) {
|
|
5870
5865
|
primaryGroup.aliases.push(alias);
|
|
@@ -5878,12 +5873,12 @@ async function autoMergeByBaseName(observedIds, baseDir) {
|
|
|
5878
5873
|
if (other.gitRemote && !primaryGroup.gitRemote) {
|
|
5879
5874
|
primaryGroup.gitRemote = other.gitRemote;
|
|
5880
5875
|
}
|
|
5881
|
-
|
|
5876
|
+
registry2.groups.splice(idx, 1);
|
|
5882
5877
|
}
|
|
5883
5878
|
primaryGroup.canonical = selectCanonical(primaryGroup.aliases);
|
|
5884
5879
|
mergeCount++;
|
|
5885
5880
|
} else {
|
|
5886
|
-
|
|
5881
|
+
registry2.groups.push({
|
|
5887
5882
|
canonical,
|
|
5888
5883
|
aliases: allIdsInGroup,
|
|
5889
5884
|
rootPaths: []
|
|
@@ -6519,7 +6514,7 @@ async function searchObservations(options) {
|
|
|
6519
6514
|
const expandedEmbeddingQuery = quality === "thorough" && tier === "heavy" ? await maybeExpandSearchQuery(options.query) : options.query;
|
|
6520
6515
|
mark("queryExpansion");
|
|
6521
6516
|
const intentResult = quality === "fast" || !hasQuery ? null : detectQueryIntent(originalQuery);
|
|
6522
|
-
const requestLimit = projectIds ? (options.limit ?? 20) * 3 : options.limit ?? 20;
|
|
6517
|
+
const requestLimit = projectIds || options.surfacedIds && options.surfacedIds.length > 0 ? (options.limit ?? 20) * 3 : options.limit ?? 20;
|
|
6523
6518
|
const defaultBoost = {
|
|
6524
6519
|
title: 3,
|
|
6525
6520
|
entityName: 2,
|
|
@@ -6751,6 +6746,14 @@ async function searchObservations(options) {
|
|
|
6751
6746
|
});
|
|
6752
6747
|
intermediate.sort((a, b) => b.score - a.score);
|
|
6753
6748
|
}
|
|
6749
|
+
if (options.surfacedIds && options.surfacedIds.length > 0) {
|
|
6750
|
+
const SURFACED_PENALTY = 0.5;
|
|
6751
|
+
const surfaced = new Set(options.surfacedIds);
|
|
6752
|
+
intermediate = intermediate.map(
|
|
6753
|
+
(entry) => surfaced.has(entry.id) ? { ...entry, score: (entry.score ?? 0) * SURFACED_PENALTY } : entry
|
|
6754
|
+
);
|
|
6755
|
+
intermediate.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
6756
|
+
}
|
|
6754
6757
|
if (options.since) {
|
|
6755
6758
|
const sinceDate = new Date(options.since).getTime();
|
|
6756
6759
|
intermediate = intermediate.filter((e2) => new Date(e2.rawTime).getTime() >= sinceDate);
|
|
@@ -7742,7 +7745,8 @@ var init_maintenance_jobs = __esm({
|
|
|
7742
7745
|
"claim-requalification",
|
|
7743
7746
|
"knowledge-compile",
|
|
7744
7747
|
"knowledge-lint",
|
|
7745
|
-
"workflow-index"
|
|
7748
|
+
"workflow-index",
|
|
7749
|
+
"long-term-maintenance"
|
|
7746
7750
|
];
|
|
7747
7751
|
DEFAULT_MAX_ATTEMPTS = 8;
|
|
7748
7752
|
DEFAULT_LEASE_MS = 3e4;
|
|
@@ -8151,6 +8155,7 @@ __export(lifecycle_exports, {
|
|
|
8151
8155
|
enqueueClaimRequalification: () => enqueueClaimRequalification,
|
|
8152
8156
|
enqueueCodegraphRefresh: () => enqueueCodegraphRefresh,
|
|
8153
8157
|
enqueueKnowledgeFollowups: () => enqueueKnowledgeFollowups,
|
|
8158
|
+
enqueueLongTermMaintenance: () => enqueueLongTermMaintenance,
|
|
8154
8159
|
enqueueObservationQualification: () => enqueueObservationQualification
|
|
8155
8160
|
});
|
|
8156
8161
|
function queueFor(input) {
|
|
@@ -8194,6 +8199,14 @@ function enqueueObservationQualification(input) {
|
|
|
8194
8199
|
payload: { source: input.source, limit: 100 }
|
|
8195
8200
|
});
|
|
8196
8201
|
}
|
|
8202
|
+
function enqueueLongTermMaintenance(input) {
|
|
8203
|
+
queueFor(input).enqueue({
|
|
8204
|
+
projectId: input.projectId,
|
|
8205
|
+
kind: "long-term-maintenance",
|
|
8206
|
+
dedupeKey: "long-term-maintenance",
|
|
8207
|
+
payload: { source: input.source }
|
|
8208
|
+
});
|
|
8209
|
+
}
|
|
8197
8210
|
function enqueueKnowledgeFollowups(input) {
|
|
8198
8211
|
const queue = queueFor(input);
|
|
8199
8212
|
const payload = {
|
|
@@ -8373,7 +8386,8 @@ var init_isolated_maintenance = __esm({
|
|
|
8373
8386
|
"claim-requalification",
|
|
8374
8387
|
"knowledge-compile",
|
|
8375
8388
|
"knowledge-lint",
|
|
8376
|
-
"workflow-index"
|
|
8389
|
+
"workflow-index",
|
|
8390
|
+
"long-term-maintenance"
|
|
8377
8391
|
];
|
|
8378
8392
|
DEFAULT_TIMEOUT_MS = 5 * 6e4;
|
|
8379
8393
|
MAX_CHILD_OUTPUT_BYTES = 1e6;
|
|
@@ -144220,6 +144234,889 @@ var init_retention = __esm({
|
|
|
144220
144234
|
}
|
|
144221
144235
|
});
|
|
144222
144236
|
|
|
144237
|
+
// src/memory/owner.ts
|
|
144238
|
+
var owner_exports = {};
|
|
144239
|
+
__export(owner_exports, {
|
|
144240
|
+
resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
|
|
144241
|
+
});
|
|
144242
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
144243
|
+
import { promises as fs12 } from "fs";
|
|
144244
|
+
import path19 from "path";
|
|
144245
|
+
function ownerPath(dataDir) {
|
|
144246
|
+
const resolved = path19.resolve(dataDir);
|
|
144247
|
+
const home = path19.basename(resolved).toLocaleLowerCase("en-US") === "data" ? path19.dirname(resolved) : resolved;
|
|
144248
|
+
return path19.join(home, "memorix-user.json");
|
|
144249
|
+
}
|
|
144250
|
+
function normalizedOwnerId(value) {
|
|
144251
|
+
const trimmed = value?.trim();
|
|
144252
|
+
return trimmed && ID_PATTERN.test(trimmed) ? trimmed : void 0;
|
|
144253
|
+
}
|
|
144254
|
+
async function readOwnerFile(filePath) {
|
|
144255
|
+
try {
|
|
144256
|
+
const value = JSON.parse(await fs12.readFile(filePath, "utf8"));
|
|
144257
|
+
const id = typeof value.id === "string" ? normalizedOwnerId(value.id) : void 0;
|
|
144258
|
+
return id ? { id, source: "local-file" } : void 0;
|
|
144259
|
+
} catch {
|
|
144260
|
+
return void 0;
|
|
144261
|
+
}
|
|
144262
|
+
}
|
|
144263
|
+
async function resolveLocalMemoryOwner(dataDir, options = {}) {
|
|
144264
|
+
const configured = normalizedOwnerId(process.env.MEMORIX_USER_ID);
|
|
144265
|
+
if (configured) return { id: configured, source: "environment" };
|
|
144266
|
+
const filePath = ownerPath(dataDir);
|
|
144267
|
+
const existing = await readOwnerFile(filePath);
|
|
144268
|
+
if (existing || !options.create) return existing;
|
|
144269
|
+
await fs12.mkdir(path19.dirname(filePath), { recursive: true });
|
|
144270
|
+
const created = {
|
|
144271
|
+
version: 1,
|
|
144272
|
+
id: "local-" + randomUUID6(),
|
|
144273
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
144274
|
+
};
|
|
144275
|
+
try {
|
|
144276
|
+
await fs12.writeFile(filePath, JSON.stringify(created, null, 2) + "\n", { encoding: "utf8", flag: "wx" });
|
|
144277
|
+
return { id: created.id, source: "local-file" };
|
|
144278
|
+
} catch (error) {
|
|
144279
|
+
if (error?.code !== "EEXIST") throw error;
|
|
144280
|
+
const concurrent = await readOwnerFile(filePath);
|
|
144281
|
+
if (concurrent) return concurrent;
|
|
144282
|
+
throw new Error("Memorix could not establish a valid local memory owner identity.");
|
|
144283
|
+
}
|
|
144284
|
+
}
|
|
144285
|
+
var ID_PATTERN;
|
|
144286
|
+
var init_owner = __esm({
|
|
144287
|
+
"src/memory/owner.ts"() {
|
|
144288
|
+
"use strict";
|
|
144289
|
+
init_esm_shims();
|
|
144290
|
+
ID_PATTERN = /^[A-Za-z0-9:_-]{3,160}$/;
|
|
144291
|
+
}
|
|
144292
|
+
});
|
|
144293
|
+
|
|
144294
|
+
// src/memory/long-term-store.ts
|
|
144295
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
144296
|
+
function optionalText2(value) {
|
|
144297
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
144298
|
+
}
|
|
144299
|
+
function arrayValue2(value) {
|
|
144300
|
+
if (typeof value !== "string" || !value) return [];
|
|
144301
|
+
try {
|
|
144302
|
+
const parsed = JSON.parse(value);
|
|
144303
|
+
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
144304
|
+
} catch {
|
|
144305
|
+
return [];
|
|
144306
|
+
}
|
|
144307
|
+
}
|
|
144308
|
+
function rowToMemory(row) {
|
|
144309
|
+
return {
|
|
144310
|
+
id: row.id,
|
|
144311
|
+
originProjectId: row.originProjectId,
|
|
144312
|
+
ownerId: row.ownerId,
|
|
144313
|
+
scope: row.scope,
|
|
144314
|
+
kind: row.kind,
|
|
144315
|
+
state: row.state,
|
|
144316
|
+
portability: row.portability,
|
|
144317
|
+
title: row.title,
|
|
144318
|
+
content: row.content,
|
|
144319
|
+
facts: arrayValue2(row.factsJson),
|
|
144320
|
+
tags: arrayValue2(row.tagsJson),
|
|
144321
|
+
...optionalText2(row.applicability) ? { applicability: row.applicability } : {},
|
|
144322
|
+
origin: row.origin,
|
|
144323
|
+
createdAt: row.createdAt,
|
|
144324
|
+
updatedAt: row.updatedAt,
|
|
144325
|
+
...optionalText2(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
|
|
144326
|
+
...optionalText2(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
|
|
144327
|
+
...optionalText2(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
|
|
144328
|
+
...optionalText2(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
|
|
144329
|
+
...optionalText2(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
|
|
144330
|
+
accessCount: Number(row.accessCount ?? 0),
|
|
144331
|
+
...optionalText2(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
|
|
144332
|
+
};
|
|
144333
|
+
}
|
|
144334
|
+
function rowToEvidence(row) {
|
|
144335
|
+
return {
|
|
144336
|
+
id: row.id,
|
|
144337
|
+
memoryId: row.memoryId,
|
|
144338
|
+
kind: row.kind,
|
|
144339
|
+
referenceId: row.referenceId,
|
|
144340
|
+
relation: row.relation,
|
|
144341
|
+
...optionalText2(row.locator) ? { locator: row.locator } : {},
|
|
144342
|
+
...optionalText2(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
|
|
144343
|
+
createdAt: row.createdAt
|
|
144344
|
+
};
|
|
144345
|
+
}
|
|
144346
|
+
function rowToEvent(row) {
|
|
144347
|
+
return {
|
|
144348
|
+
id: row.id,
|
|
144349
|
+
memoryId: row.memoryId,
|
|
144350
|
+
kind: row.kind,
|
|
144351
|
+
...optionalText2(row.fromState) ? { fromState: row.fromState } : {},
|
|
144352
|
+
...optionalText2(row.toState) ? { toState: row.toState } : {},
|
|
144353
|
+
...optionalText2(row.detail) ? { detail: row.detail } : {},
|
|
144354
|
+
createdAt: row.createdAt
|
|
144355
|
+
};
|
|
144356
|
+
}
|
|
144357
|
+
var LongTermMemoryStore;
|
|
144358
|
+
var init_long_term_store = __esm({
|
|
144359
|
+
"src/memory/long-term-store.ts"() {
|
|
144360
|
+
"use strict";
|
|
144361
|
+
init_esm_shims();
|
|
144362
|
+
init_sqlite_db();
|
|
144363
|
+
LongTermMemoryStore = class {
|
|
144364
|
+
db = null;
|
|
144365
|
+
async init(dataDir) {
|
|
144366
|
+
this.db = getDatabase(dataDir);
|
|
144367
|
+
}
|
|
144368
|
+
transaction(fn) {
|
|
144369
|
+
return this.db.transaction(fn)();
|
|
144370
|
+
}
|
|
144371
|
+
get(id) {
|
|
144372
|
+
const row = this.db.prepare("SELECT * FROM long_term_memories WHERE id = ?").get(id);
|
|
144373
|
+
return row ? rowToMemory(row) : void 0;
|
|
144374
|
+
}
|
|
144375
|
+
list(options = {}) {
|
|
144376
|
+
const limit2 = Math.max(1, Math.min(1e3, Math.floor(options.limit ?? 500)));
|
|
144377
|
+
const clauses = [];
|
|
144378
|
+
const params = [];
|
|
144379
|
+
if (options.ownerId) {
|
|
144380
|
+
clauses.push("ownerId = ?");
|
|
144381
|
+
params.push(options.ownerId);
|
|
144382
|
+
}
|
|
144383
|
+
if (options.originProjectId) {
|
|
144384
|
+
clauses.push("originProjectId = ?");
|
|
144385
|
+
params.push(options.originProjectId);
|
|
144386
|
+
}
|
|
144387
|
+
const where = clauses.length ? " WHERE " + clauses.join(" AND ") : "";
|
|
144388
|
+
const rows = this.db.prepare(
|
|
144389
|
+
"SELECT * FROM long_term_memories" + where + " ORDER BY updatedAt DESC, id LIMIT ?"
|
|
144390
|
+
).all(...params, limit2);
|
|
144391
|
+
return rows.map(rowToMemory);
|
|
144392
|
+
}
|
|
144393
|
+
insert(memory) {
|
|
144394
|
+
this.db.prepare(`
|
|
144395
|
+
INSERT INTO long_term_memories (
|
|
144396
|
+
id, originProjectId, ownerId, scope, kind, state, portability,
|
|
144397
|
+
title, content, factsJson, tagsJson, applicability, origin,
|
|
144398
|
+
createdAt, updatedAt, qualifiedAt, approvedAt, archivedAt,
|
|
144399
|
+
supersededBy, lastValidatedAt, accessCount, lastAccessedAt
|
|
144400
|
+
) VALUES (
|
|
144401
|
+
@id, @originProjectId, @ownerId, @scope, @kind, @state, @portability,
|
|
144402
|
+
@title, @content, @factsJson, @tagsJson, @applicability, @origin,
|
|
144403
|
+
@createdAt, @updatedAt, @qualifiedAt, @approvedAt, @archivedAt,
|
|
144404
|
+
@supersededBy, @lastValidatedAt, @accessCount, @lastAccessedAt
|
|
144405
|
+
)
|
|
144406
|
+
`).run({
|
|
144407
|
+
...memory,
|
|
144408
|
+
factsJson: JSON.stringify(memory.facts),
|
|
144409
|
+
tagsJson: JSON.stringify(memory.tags),
|
|
144410
|
+
applicability: memory.applicability ?? null,
|
|
144411
|
+
qualifiedAt: memory.qualifiedAt ?? null,
|
|
144412
|
+
approvedAt: memory.approvedAt ?? null,
|
|
144413
|
+
archivedAt: memory.archivedAt ?? null,
|
|
144414
|
+
supersededBy: memory.supersededBy ?? null,
|
|
144415
|
+
lastValidatedAt: memory.lastValidatedAt ?? null,
|
|
144416
|
+
lastAccessedAt: memory.lastAccessedAt ?? null
|
|
144417
|
+
});
|
|
144418
|
+
}
|
|
144419
|
+
update(memory) {
|
|
144420
|
+
this.db.prepare(`
|
|
144421
|
+
UPDATE long_term_memories SET
|
|
144422
|
+
scope = @scope,
|
|
144423
|
+
kind = @kind,
|
|
144424
|
+
state = @state,
|
|
144425
|
+
portability = @portability,
|
|
144426
|
+
title = @title,
|
|
144427
|
+
content = @content,
|
|
144428
|
+
factsJson = @factsJson,
|
|
144429
|
+
tagsJson = @tagsJson,
|
|
144430
|
+
applicability = @applicability,
|
|
144431
|
+
updatedAt = @updatedAt,
|
|
144432
|
+
qualifiedAt = @qualifiedAt,
|
|
144433
|
+
approvedAt = @approvedAt,
|
|
144434
|
+
archivedAt = @archivedAt,
|
|
144435
|
+
supersededBy = @supersededBy,
|
|
144436
|
+
lastValidatedAt = @lastValidatedAt,
|
|
144437
|
+
accessCount = @accessCount,
|
|
144438
|
+
lastAccessedAt = @lastAccessedAt
|
|
144439
|
+
WHERE id = @id
|
|
144440
|
+
`).run({
|
|
144441
|
+
...memory,
|
|
144442
|
+
factsJson: JSON.stringify(memory.facts),
|
|
144443
|
+
tagsJson: JSON.stringify(memory.tags),
|
|
144444
|
+
applicability: memory.applicability ?? null,
|
|
144445
|
+
qualifiedAt: memory.qualifiedAt ?? null,
|
|
144446
|
+
approvedAt: memory.approvedAt ?? null,
|
|
144447
|
+
archivedAt: memory.archivedAt ?? null,
|
|
144448
|
+
supersededBy: memory.supersededBy ?? null,
|
|
144449
|
+
lastValidatedAt: memory.lastValidatedAt ?? null,
|
|
144450
|
+
lastAccessedAt: memory.lastAccessedAt ?? null
|
|
144451
|
+
});
|
|
144452
|
+
}
|
|
144453
|
+
insertEvidence(input) {
|
|
144454
|
+
const evidence = {
|
|
144455
|
+
id: randomUUID7(),
|
|
144456
|
+
...input,
|
|
144457
|
+
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
144458
|
+
};
|
|
144459
|
+
this.db.prepare(`
|
|
144460
|
+
INSERT INTO long_term_memory_evidence (
|
|
144461
|
+
id, memoryId, kind, referenceId, relation, locator, capturedHash, createdAt
|
|
144462
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
144463
|
+
`).run(
|
|
144464
|
+
evidence.id,
|
|
144465
|
+
evidence.memoryId,
|
|
144466
|
+
evidence.kind,
|
|
144467
|
+
evidence.referenceId,
|
|
144468
|
+
evidence.relation,
|
|
144469
|
+
evidence.locator ?? null,
|
|
144470
|
+
evidence.capturedHash ?? null,
|
|
144471
|
+
evidence.createdAt
|
|
144472
|
+
);
|
|
144473
|
+
return evidence;
|
|
144474
|
+
}
|
|
144475
|
+
listEvidence(memoryId) {
|
|
144476
|
+
return this.db.prepare(`
|
|
144477
|
+
SELECT * FROM long_term_memory_evidence WHERE memoryId = ? ORDER BY createdAt ASC, id
|
|
144478
|
+
`).all(memoryId).map(rowToEvidence);
|
|
144479
|
+
}
|
|
144480
|
+
recordEvent(input) {
|
|
144481
|
+
const event = {
|
|
144482
|
+
id: randomUUID7(),
|
|
144483
|
+
...input,
|
|
144484
|
+
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
144485
|
+
};
|
|
144486
|
+
this.db.prepare(`
|
|
144487
|
+
INSERT INTO long_term_memory_events (id, memoryId, kind, fromState, toState, detail, createdAt)
|
|
144488
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
144489
|
+
`).run(
|
|
144490
|
+
event.id,
|
|
144491
|
+
event.memoryId,
|
|
144492
|
+
event.kind,
|
|
144493
|
+
event.fromState ?? null,
|
|
144494
|
+
event.toState ?? null,
|
|
144495
|
+
event.detail ?? null,
|
|
144496
|
+
event.createdAt
|
|
144497
|
+
);
|
|
144498
|
+
return event;
|
|
144499
|
+
}
|
|
144500
|
+
listEvents(memoryId) {
|
|
144501
|
+
return this.db.prepare(`
|
|
144502
|
+
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
144503
|
+
`).all(memoryId).map(rowToEvent);
|
|
144504
|
+
}
|
|
144505
|
+
markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
144506
|
+
const unique2 = [...new Set(ids.filter(Boolean))];
|
|
144507
|
+
if (unique2.length === 0) return;
|
|
144508
|
+
const statement = this.db.prepare(`
|
|
144509
|
+
UPDATE long_term_memories
|
|
144510
|
+
SET accessCount = accessCount + 1, lastAccessedAt = ?
|
|
144511
|
+
WHERE id = ?
|
|
144512
|
+
`);
|
|
144513
|
+
this.db.transaction(() => {
|
|
144514
|
+
for (const id of unique2) statement.run(at, id);
|
|
144515
|
+
})();
|
|
144516
|
+
}
|
|
144517
|
+
};
|
|
144518
|
+
}
|
|
144519
|
+
});
|
|
144520
|
+
|
|
144521
|
+
// src/memory/long-term-types.ts
|
|
144522
|
+
var LONG_TERM_MEMORY_KINDS, LONG_TERM_MEMORY_SCOPES, LONG_TERM_MEMORY_PORTABILITIES, LONG_TERM_MEMORY_EVIDENCE_KINDS, LONG_TERM_MEMORY_EVIDENCE_RELATIONS;
|
|
144523
|
+
var init_long_term_types = __esm({
|
|
144524
|
+
"src/memory/long-term-types.ts"() {
|
|
144525
|
+
"use strict";
|
|
144526
|
+
init_esm_shims();
|
|
144527
|
+
LONG_TERM_MEMORY_KINDS = ["episodic", "semantic", "procedural"];
|
|
144528
|
+
LONG_TERM_MEMORY_SCOPES = ["project", "user", "team"];
|
|
144529
|
+
LONG_TERM_MEMORY_PORTABILITIES = ["project-bound", "portable"];
|
|
144530
|
+
LONG_TERM_MEMORY_EVIDENCE_KINDS = [
|
|
144531
|
+
"observation",
|
|
144532
|
+
"claim",
|
|
144533
|
+
"workflow",
|
|
144534
|
+
"session",
|
|
144535
|
+
"checkpoint",
|
|
144536
|
+
"git",
|
|
144537
|
+
"code",
|
|
144538
|
+
"test",
|
|
144539
|
+
"run",
|
|
144540
|
+
"document",
|
|
144541
|
+
"manual",
|
|
144542
|
+
"user"
|
|
144543
|
+
];
|
|
144544
|
+
LONG_TERM_MEMORY_EVIDENCE_RELATIONS = [
|
|
144545
|
+
"supports",
|
|
144546
|
+
"verifies",
|
|
144547
|
+
"derives",
|
|
144548
|
+
"user-confirmed"
|
|
144549
|
+
];
|
|
144550
|
+
}
|
|
144551
|
+
});
|
|
144552
|
+
|
|
144553
|
+
// src/memory/long-term.ts
|
|
144554
|
+
var long_term_exports = {};
|
|
144555
|
+
__export(long_term_exports, {
|
|
144556
|
+
approveLongTermMemory: () => approveLongTermMemory,
|
|
144557
|
+
archiveLongTermMemory: () => archiveLongTermMemory,
|
|
144558
|
+
canReadLongTermMemory: () => canReadLongTermMemory,
|
|
144559
|
+
createLongTermMemoryCandidate: () => createLongTermMemoryCandidate,
|
|
144560
|
+
createManualLongTermMemory: () => createManualLongTermMemory,
|
|
144561
|
+
getLongTermMemoryDetail: () => getLongTermMemoryDetail,
|
|
144562
|
+
isEligibleLongTermMemory: () => isEligibleLongTermMemory,
|
|
144563
|
+
listLongTermMemories: () => listLongTermMemories,
|
|
144564
|
+
maintainLongTermMemories: () => maintainLongTermMemories,
|
|
144565
|
+
maybeAutoQualifyLongTermMemory: () => maybeAutoQualifyLongTermMemory,
|
|
144566
|
+
promoteObservationToLongTermMemory: () => promoteObservationToLongTermMemory,
|
|
144567
|
+
qualifyLongTermMemory: () => qualifyLongTermMemory,
|
|
144568
|
+
renderLongTermMemorySummary: () => renderLongTermMemorySummary,
|
|
144569
|
+
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
144570
|
+
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
144571
|
+
});
|
|
144572
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
144573
|
+
function isOneOf(value, values) {
|
|
144574
|
+
return typeof value === "string" && values.includes(value);
|
|
144575
|
+
}
|
|
144576
|
+
function compactText(value, field, max = MAX_TEXT_LENGTH) {
|
|
144577
|
+
if (typeof value !== "string") throw new Error("Long-term memory " + field + " must be text.");
|
|
144578
|
+
const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
|
|
144579
|
+
if (!safe) throw new Error("Long-term memory " + field + " is required.");
|
|
144580
|
+
if (safe.length > max) throw new Error("Long-term memory " + field + " is too long.");
|
|
144581
|
+
return safe;
|
|
144582
|
+
}
|
|
144583
|
+
function compactList(values, field) {
|
|
144584
|
+
if (!values) return [];
|
|
144585
|
+
if (!Array.isArray(values)) throw new Error("Long-term memory " + field + " must be an array.");
|
|
144586
|
+
return [...new Set(values.filter((value) => typeof value === "string").map((value) => compactText(value, field, 500)))].slice(0, MAX_LIST_ITEMS);
|
|
144587
|
+
}
|
|
144588
|
+
function normalizeEvidence(input) {
|
|
144589
|
+
if (!Array.isArray(input) || input.length === 0) {
|
|
144590
|
+
throw new Error("A long-term memory requires at least one source evidence reference.");
|
|
144591
|
+
}
|
|
144592
|
+
return input.map((evidence) => {
|
|
144593
|
+
if (!evidence || !isOneOf(evidence.kind, LONG_TERM_MEMORY_EVIDENCE_KINDS)) {
|
|
144594
|
+
throw new Error("Long-term memory evidence kind is invalid.");
|
|
144595
|
+
}
|
|
144596
|
+
if (!isOneOf(evidence.relation, LONG_TERM_MEMORY_EVIDENCE_RELATIONS)) {
|
|
144597
|
+
throw new Error("Long-term memory evidence relation is invalid.");
|
|
144598
|
+
}
|
|
144599
|
+
return {
|
|
144600
|
+
kind: evidence.kind,
|
|
144601
|
+
referenceId: compactText(evidence.referenceId, "evidence reference", 1e3),
|
|
144602
|
+
relation: evidence.relation,
|
|
144603
|
+
...evidence.locator ? { locator: compactText(evidence.locator, "evidence locator", 1e3) } : {},
|
|
144604
|
+
...evidence.capturedHash ? { capturedHash: compactText(evidence.capturedHash, "evidence hash", 1e3) } : {}
|
|
144605
|
+
};
|
|
144606
|
+
});
|
|
144607
|
+
}
|
|
144608
|
+
function assertScope(scope) {
|
|
144609
|
+
if (!isOneOf(scope, LONG_TERM_MEMORY_SCOPES)) throw new Error("Long-term memory scope is invalid.");
|
|
144610
|
+
}
|
|
144611
|
+
function assertKind(kind) {
|
|
144612
|
+
if (!isOneOf(kind, LONG_TERM_MEMORY_KINDS)) throw new Error("Long-term memory kind is invalid.");
|
|
144613
|
+
}
|
|
144614
|
+
function assertPortability(value) {
|
|
144615
|
+
if (!isOneOf(value, LONG_TERM_MEMORY_PORTABILITIES)) {
|
|
144616
|
+
throw new Error("Long-term memory portability is invalid.");
|
|
144617
|
+
}
|
|
144618
|
+
}
|
|
144619
|
+
function assertPortableEvidence(scope, portability, evidence) {
|
|
144620
|
+
if (portability !== "portable") return;
|
|
144621
|
+
if (scope !== "user") {
|
|
144622
|
+
throw new Error("Only user-scoped long-term memories may be portable across projects.");
|
|
144623
|
+
}
|
|
144624
|
+
if (evidence.some((item) => !PORTABLE_EVIDENCE_KINDS.has(item.kind))) {
|
|
144625
|
+
throw new Error("Portable user memory may only use manual or user-confirmed evidence; project code, Git, observation, test, session, claim, and workflow evidence must remain project-bound.");
|
|
144626
|
+
}
|
|
144627
|
+
}
|
|
144628
|
+
function requireTeamReader(scope, reader) {
|
|
144629
|
+
if (scope === "team" && reader?.isTeamMember !== true) {
|
|
144630
|
+
throw new Error("Team long-term memory requires an explicit active team identity for this project.");
|
|
144631
|
+
}
|
|
144632
|
+
}
|
|
144633
|
+
function matchesScope(memory, reader) {
|
|
144634
|
+
if (memory.scope === "project") return memory.originProjectId === reader.projectId;
|
|
144635
|
+
if (memory.scope === "team") {
|
|
144636
|
+
return memory.originProjectId === reader.projectId && reader.isTeamMember === true;
|
|
144637
|
+
}
|
|
144638
|
+
if (!reader.ownerId || memory.ownerId !== reader.ownerId) return false;
|
|
144639
|
+
return memory.portability === "portable" || memory.originProjectId === reader.projectId;
|
|
144640
|
+
}
|
|
144641
|
+
function canReadLongTermMemory(memory, reader) {
|
|
144642
|
+
return matchesScope(memory, reader);
|
|
144643
|
+
}
|
|
144644
|
+
function isEligibleLongTermMemory(memory) {
|
|
144645
|
+
return memory.state === "qualified" || memory.state === "approved";
|
|
144646
|
+
}
|
|
144647
|
+
function taskTerms(task) {
|
|
144648
|
+
const matches = task.toLocaleLowerCase("en-US").match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
|
|
144649
|
+
return [...new Set(matches.filter((term) => term.length > 1 && !STOP_TERMS.has(term)))].slice(0, 16);
|
|
144650
|
+
}
|
|
144651
|
+
function kindFitScore(kind, task) {
|
|
144652
|
+
const normalized = task.toLocaleLowerCase("en-US");
|
|
144653
|
+
const hints = {
|
|
144654
|
+
episodic: ["resume", "continue", "handoff", "previous", "session", "\u63A5\u624B", "\u7EE7\u7EED", "\u4EA4\u63A5", "\u4E0A\u6B21", "\u4F1A\u8BDD"],
|
|
144655
|
+
semantic: ["why", "what", "architecture", "design", "decision", "reason", "\u4E3A\u4EC0\u4E48", "\u662F\u4EC0\u4E48", "\u67B6\u6784", "\u8BBE\u8BA1", "\u51B3\u7B56", "\u539F\u56E0"],
|
|
144656
|
+
procedural: ["how", "steps", "procedure", "run", "release", "publish", "verify", "implement", "\u6D41\u7A0B", "\u6B65\u9AA4", "\u53D1\u5E03", "\u9A8C\u8BC1", "\u4FEE\u590D", "\u5B9E\u73B0"]
|
|
144657
|
+
};
|
|
144658
|
+
return hints[kind].some((hint) => normalized.includes(hint)) ? 1 : 0;
|
|
144659
|
+
}
|
|
144660
|
+
function validationFreshnessScore(memory) {
|
|
144661
|
+
const validatedAt = memory.lastValidatedAt ?? memory.approvedAt ?? memory.qualifiedAt;
|
|
144662
|
+
if (!validatedAt) return 0;
|
|
144663
|
+
const time = Date.parse(validatedAt);
|
|
144664
|
+
if (!Number.isFinite(time)) return 0;
|
|
144665
|
+
const ageDays = Math.max(0, Date.now() - time) / (24 * 60 * 60 * 1e3);
|
|
144666
|
+
if (ageDays <= 30) return 0.35;
|
|
144667
|
+
if (ageDays <= 90) return 0.15;
|
|
144668
|
+
return 0;
|
|
144669
|
+
}
|
|
144670
|
+
function scoreForTask(memory, task) {
|
|
144671
|
+
const terms = taskTerms(task);
|
|
144672
|
+
if (terms.length === 0) return void 0;
|
|
144673
|
+
const title = memory.title.toLocaleLowerCase("en-US");
|
|
144674
|
+
const content = memory.content.toLocaleLowerCase("en-US");
|
|
144675
|
+
const facts = memory.facts.join(" ").toLocaleLowerCase("en-US");
|
|
144676
|
+
const tags = memory.tags.join(" ").toLocaleLowerCase("en-US");
|
|
144677
|
+
const applicability = (memory.applicability ?? "").toLocaleLowerCase("en-US");
|
|
144678
|
+
let score = memory.state === "approved" ? 0.5 : 0;
|
|
144679
|
+
const matched = [];
|
|
144680
|
+
for (const term of terms) {
|
|
144681
|
+
let termScore = 0;
|
|
144682
|
+
if (title.includes(term)) termScore += 5;
|
|
144683
|
+
if (tags.includes(term)) termScore += 4;
|
|
144684
|
+
if (applicability.includes(term)) termScore += 3;
|
|
144685
|
+
if (facts.includes(term)) termScore += 2;
|
|
144686
|
+
if (content.includes(term)) termScore += 1;
|
|
144687
|
+
if (termScore > 0) {
|
|
144688
|
+
score += termScore;
|
|
144689
|
+
matched.push(term);
|
|
144690
|
+
}
|
|
144691
|
+
}
|
|
144692
|
+
if (matched.length === 0) return void 0;
|
|
144693
|
+
score += kindFitScore(memory.kind, task);
|
|
144694
|
+
score += validationFreshnessScore(memory);
|
|
144695
|
+
const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
|
|
144696
|
+
const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
|
|
144697
|
+
return { score, reason: kindLabel + " matches " + matched.slice(0, 3).join(", ") + freshness };
|
|
144698
|
+
}
|
|
144699
|
+
function semanticText(memory) {
|
|
144700
|
+
return sanitizeCredentials([
|
|
144701
|
+
memory.title,
|
|
144702
|
+
memory.applicability,
|
|
144703
|
+
memory.tags.join(" "),
|
|
144704
|
+
memory.facts.join(" "),
|
|
144705
|
+
memory.content
|
|
144706
|
+
].filter((value) => Boolean(value)).join("\n")).replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
|
|
144707
|
+
}
|
|
144708
|
+
function cosineSimilarity(left, right) {
|
|
144709
|
+
if (left.length === 0 || left.length !== right.length) return 0;
|
|
144710
|
+
let dot = 0;
|
|
144711
|
+
let leftMagnitude = 0;
|
|
144712
|
+
let rightMagnitude = 0;
|
|
144713
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
144714
|
+
const a = left[index];
|
|
144715
|
+
const b = right[index];
|
|
144716
|
+
if (!Number.isFinite(a) || !Number.isFinite(b)) return 0;
|
|
144717
|
+
dot += a * b;
|
|
144718
|
+
leftMagnitude += a * a;
|
|
144719
|
+
rightMagnitude += b * b;
|
|
144720
|
+
}
|
|
144721
|
+
if (leftMagnitude === 0 || rightMagnitude === 0) return 0;
|
|
144722
|
+
return dot / Math.sqrt(leftMagnitude * rightMagnitude);
|
|
144723
|
+
}
|
|
144724
|
+
function semanticSelection(memory, similarity, task) {
|
|
144725
|
+
if (similarity < MIN_SEMANTIC_SIMILARITY) return void 0;
|
|
144726
|
+
const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
|
|
144727
|
+
const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
|
|
144728
|
+
return {
|
|
144729
|
+
score: similarity * 10 + (memory.state === "approved" ? 0.5 : 0) + kindFitScore(memory.kind, task) + validationFreshnessScore(memory),
|
|
144730
|
+
reason: kindLabel + " semantic match " + similarity.toFixed(2) + freshness
|
|
144731
|
+
};
|
|
144732
|
+
}
|
|
144733
|
+
async function resolveSemanticProvider(explicit) {
|
|
144734
|
+
if (explicit !== void 0) return explicit;
|
|
144735
|
+
try {
|
|
144736
|
+
const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
|
|
144737
|
+
return await withTimeout(
|
|
144738
|
+
getEmbeddingProvider2({ requestTimeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS, retry: false }),
|
|
144739
|
+
SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
144740
|
+
"Long-term semantic provider initialization"
|
|
144741
|
+
);
|
|
144742
|
+
} catch {
|
|
144743
|
+
return null;
|
|
144744
|
+
}
|
|
144745
|
+
}
|
|
144746
|
+
function createStore(dataDir) {
|
|
144747
|
+
const store = new LongTermMemoryStore();
|
|
144748
|
+
return store.init(dataDir).then(() => store);
|
|
144749
|
+
}
|
|
144750
|
+
async function createManualLongTermMemory(input) {
|
|
144751
|
+
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
144752
|
+
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
144753
|
+
assertScope(input.scope);
|
|
144754
|
+
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID8(), relation: "supports" }];
|
|
144755
|
+
return createLongTermMemoryWithDataDir({
|
|
144756
|
+
dataDir: input.dataDir,
|
|
144757
|
+
originProjectId: input.projectId,
|
|
144758
|
+
ownerId: owner.id,
|
|
144759
|
+
scope: input.scope,
|
|
144760
|
+
kind: input.kind,
|
|
144761
|
+
portability: input.portability,
|
|
144762
|
+
title: input.title,
|
|
144763
|
+
content: input.content,
|
|
144764
|
+
facts: input.facts,
|
|
144765
|
+
tags: input.tags,
|
|
144766
|
+
applicability: input.applicability,
|
|
144767
|
+
origin: "manual",
|
|
144768
|
+
evidence,
|
|
144769
|
+
reader: input.reader
|
|
144770
|
+
});
|
|
144771
|
+
}
|
|
144772
|
+
async function promoteObservationToLongTermMemory(input) {
|
|
144773
|
+
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
144774
|
+
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
144775
|
+
return createLongTermMemoryWithDataDir({
|
|
144776
|
+
dataDir: input.dataDir,
|
|
144777
|
+
originProjectId: input.observation.projectId,
|
|
144778
|
+
ownerId: owner.id,
|
|
144779
|
+
scope: input.scope,
|
|
144780
|
+
kind: input.kind,
|
|
144781
|
+
portability: "project-bound",
|
|
144782
|
+
title: input.observation.title,
|
|
144783
|
+
content: input.observation.narrative,
|
|
144784
|
+
facts: input.observation.facts,
|
|
144785
|
+
tags: input.tags ?? input.observation.concepts,
|
|
144786
|
+
applicability: input.applicability,
|
|
144787
|
+
origin: input.observation.source === "git" ? "git" : "agent",
|
|
144788
|
+
evidence: [{
|
|
144789
|
+
kind: "observation",
|
|
144790
|
+
referenceId: "obs:" + input.observation.projectId + ":" + input.observation.id,
|
|
144791
|
+
relation: "derives"
|
|
144792
|
+
}],
|
|
144793
|
+
reader: input.reader
|
|
144794
|
+
});
|
|
144795
|
+
}
|
|
144796
|
+
async function createLongTermMemoryCandidate(input) {
|
|
144797
|
+
return createLongTermMemoryWithDataDir(input);
|
|
144798
|
+
}
|
|
144799
|
+
async function createLongTermMemoryWithDataDir(input) {
|
|
144800
|
+
assertScope(input.scope);
|
|
144801
|
+
assertKind(input.kind);
|
|
144802
|
+
const portability = input.portability ?? "project-bound";
|
|
144803
|
+
assertPortability(portability);
|
|
144804
|
+
requireTeamReader(input.scope, input.reader);
|
|
144805
|
+
const evidenceInputs = normalizeEvidence(input.evidence);
|
|
144806
|
+
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
144807
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
144808
|
+
const memory = {
|
|
144809
|
+
id: randomUUID8(),
|
|
144810
|
+
originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
|
|
144811
|
+
ownerId: compactText(input.ownerId, "owner id", 160),
|
|
144812
|
+
scope: input.scope,
|
|
144813
|
+
kind: input.kind,
|
|
144814
|
+
state: "candidate",
|
|
144815
|
+
portability,
|
|
144816
|
+
title: compactText(input.title, "title", 500),
|
|
144817
|
+
content: compactText(input.content, "content"),
|
|
144818
|
+
facts: compactList(input.facts, "facts"),
|
|
144819
|
+
tags: compactList(input.tags, "tags"),
|
|
144820
|
+
...input.applicability ? { applicability: compactText(input.applicability, "applicability", 1e3) } : {},
|
|
144821
|
+
origin: input.origin ?? "manual",
|
|
144822
|
+
createdAt: now3,
|
|
144823
|
+
updatedAt: now3,
|
|
144824
|
+
accessCount: 0
|
|
144825
|
+
};
|
|
144826
|
+
const store = await createStore(input.dataDir);
|
|
144827
|
+
const evidence = store.transaction(() => {
|
|
144828
|
+
store.insert(memory);
|
|
144829
|
+
const written = evidenceInputs.map((item) => store.insertEvidence({ memoryId: memory.id, ...item, createdAt: now3 }));
|
|
144830
|
+
store.recordEvent({
|
|
144831
|
+
memoryId: memory.id,
|
|
144832
|
+
kind: "created",
|
|
144833
|
+
toState: "candidate",
|
|
144834
|
+
detail: "Created as a source-backed long-term memory candidate.",
|
|
144835
|
+
createdAt: now3
|
|
144836
|
+
});
|
|
144837
|
+
return written;
|
|
144838
|
+
});
|
|
144839
|
+
return { memory, evidence };
|
|
144840
|
+
}
|
|
144841
|
+
function transitionDetail(value) {
|
|
144842
|
+
return compactText(value, "transition reason", 1e3);
|
|
144843
|
+
}
|
|
144844
|
+
async function transitionMemory(input) {
|
|
144845
|
+
const store = await createStore(input.dataDir);
|
|
144846
|
+
return store.transaction(() => {
|
|
144847
|
+
const current = store.get(input.id);
|
|
144848
|
+
if (!current) throw new Error("Long-term memory was not found.");
|
|
144849
|
+
if (current.state !== input.expected) {
|
|
144850
|
+
throw new Error("Long-term memory must be " + input.expected + " before it can be " + input.next + ".");
|
|
144851
|
+
}
|
|
144852
|
+
const evidence = store.listEvidence(current.id);
|
|
144853
|
+
if (evidence.length === 0) throw new Error("Long-term memory cannot advance without source evidence.");
|
|
144854
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
144855
|
+
const next = {
|
|
144856
|
+
...current,
|
|
144857
|
+
state: input.next,
|
|
144858
|
+
updatedAt: now3,
|
|
144859
|
+
lastValidatedAt: now3,
|
|
144860
|
+
...input.next === "qualified" ? { qualifiedAt: now3 } : { approvedAt: now3 }
|
|
144861
|
+
};
|
|
144862
|
+
store.update(next);
|
|
144863
|
+
store.recordEvent({
|
|
144864
|
+
memoryId: next.id,
|
|
144865
|
+
kind: input.event,
|
|
144866
|
+
fromState: current.state,
|
|
144867
|
+
toState: next.state,
|
|
144868
|
+
detail: transitionDetail(input.reason),
|
|
144869
|
+
createdAt: now3
|
|
144870
|
+
});
|
|
144871
|
+
return next;
|
|
144872
|
+
});
|
|
144873
|
+
}
|
|
144874
|
+
async function qualifyLongTermMemory(input) {
|
|
144875
|
+
return transitionMemory({ ...input, expected: "candidate", next: "qualified", event: "qualified" });
|
|
144876
|
+
}
|
|
144877
|
+
async function approveLongTermMemory(input) {
|
|
144878
|
+
return transitionMemory({ ...input, expected: "qualified", next: "approved", event: "approved" });
|
|
144879
|
+
}
|
|
144880
|
+
async function archiveLongTermMemory(input) {
|
|
144881
|
+
const store = await createStore(input.dataDir);
|
|
144882
|
+
return store.transaction(() => {
|
|
144883
|
+
const current = store.get(input.id);
|
|
144884
|
+
if (!current) throw new Error("Long-term memory was not found.");
|
|
144885
|
+
if (current.state === "archived" || current.state === "superseded") {
|
|
144886
|
+
throw new Error("Long-term memory is already inactive.");
|
|
144887
|
+
}
|
|
144888
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
144889
|
+
const next = { ...current, state: "archived", archivedAt: now3, updatedAt: now3 };
|
|
144890
|
+
store.update(next);
|
|
144891
|
+
store.recordEvent({
|
|
144892
|
+
memoryId: next.id,
|
|
144893
|
+
kind: "archived",
|
|
144894
|
+
fromState: current.state,
|
|
144895
|
+
toState: "archived",
|
|
144896
|
+
detail: transitionDetail(input.reason),
|
|
144897
|
+
createdAt: now3
|
|
144898
|
+
});
|
|
144899
|
+
return next;
|
|
144900
|
+
});
|
|
144901
|
+
}
|
|
144902
|
+
async function supersedeLongTermMemory(input) {
|
|
144903
|
+
const store = await createStore(input.dataDir);
|
|
144904
|
+
return store.transaction(() => {
|
|
144905
|
+
const current = store.get(input.id);
|
|
144906
|
+
if (!current) throw new Error("Long-term memory was not found.");
|
|
144907
|
+
if (current.state === "archived" || current.state === "superseded") {
|
|
144908
|
+
throw new Error("Long-term memory is already inactive.");
|
|
144909
|
+
}
|
|
144910
|
+
if (current.id === input.supersededBy) {
|
|
144911
|
+
throw new Error("Long-term memory cannot supersede itself.");
|
|
144912
|
+
}
|
|
144913
|
+
const replacement = store.get(input.supersededBy);
|
|
144914
|
+
if (!replacement || !isEligibleLongTermMemory(replacement)) {
|
|
144915
|
+
throw new Error("Replacement long-term memory must be qualified or approved.");
|
|
144916
|
+
}
|
|
144917
|
+
if (replacement.scope !== current.scope) {
|
|
144918
|
+
throw new Error("Replacement long-term memory must use the same scope.");
|
|
144919
|
+
}
|
|
144920
|
+
if (current.scope === "user" && replacement.ownerId !== current.ownerId) {
|
|
144921
|
+
throw new Error("User long-term memory may only be superseded by the same local owner.");
|
|
144922
|
+
}
|
|
144923
|
+
if (current.scope !== "user" && replacement.originProjectId !== current.originProjectId) {
|
|
144924
|
+
throw new Error("Project and team long-term memory may only be superseded within the same project.");
|
|
144925
|
+
}
|
|
144926
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
144927
|
+
const next = {
|
|
144928
|
+
...current,
|
|
144929
|
+
state: "superseded",
|
|
144930
|
+
supersededBy: replacement.id,
|
|
144931
|
+
updatedAt: now3
|
|
144932
|
+
};
|
|
144933
|
+
store.update(next);
|
|
144934
|
+
store.recordEvent({
|
|
144935
|
+
memoryId: next.id,
|
|
144936
|
+
kind: "superseded",
|
|
144937
|
+
fromState: current.state,
|
|
144938
|
+
toState: "superseded",
|
|
144939
|
+
detail: transitionDetail(input.reason),
|
|
144940
|
+
createdAt: now3
|
|
144941
|
+
});
|
|
144942
|
+
return next;
|
|
144943
|
+
});
|
|
144944
|
+
}
|
|
144945
|
+
async function maybeAutoQualifyLongTermMemory(input) {
|
|
144946
|
+
if (input.source !== "manual" && input.sourceDetail !== "explicit") return null;
|
|
144947
|
+
try {
|
|
144948
|
+
return await qualifyLongTermMemory({
|
|
144949
|
+
dataDir: input.dataDir,
|
|
144950
|
+
id: input.id,
|
|
144951
|
+
reason: "auto-qualified: explicit request carries its own source evidence"
|
|
144952
|
+
});
|
|
144953
|
+
} catch {
|
|
144954
|
+
return null;
|
|
144955
|
+
}
|
|
144956
|
+
}
|
|
144957
|
+
async function maintainLongTermMemories(input) {
|
|
144958
|
+
const now3 = input.now ?? /* @__PURE__ */ new Date();
|
|
144959
|
+
const decayDays = input.decayDays ?? 30;
|
|
144960
|
+
const cutoff = now3.getTime() - decayDays * 24 * 60 * 60 * 1e3;
|
|
144961
|
+
const result = { archived: 0, superseded: 0 };
|
|
144962
|
+
const store = await createStore(input.dataDir);
|
|
144963
|
+
const all = store.list({ originProjectId: input.projectId });
|
|
144964
|
+
for (const memory of all) {
|
|
144965
|
+
if (memory.state !== "qualified" && memory.state !== "approved") continue;
|
|
144966
|
+
const lastActivity = Date.parse(memory.lastAccessedAt ?? memory.updatedAt);
|
|
144967
|
+
if (!Number.isFinite(lastActivity) || lastActivity >= cutoff) continue;
|
|
144968
|
+
try {
|
|
144969
|
+
await archiveLongTermMemory({
|
|
144970
|
+
dataDir: input.dataDir,
|
|
144971
|
+
id: memory.id,
|
|
144972
|
+
reason: "auto-archive: no activity since " + new Date(lastActivity).toISOString().slice(0, 10)
|
|
144973
|
+
});
|
|
144974
|
+
result.archived += 1;
|
|
144975
|
+
} catch {
|
|
144976
|
+
}
|
|
144977
|
+
}
|
|
144978
|
+
const groups = /* @__PURE__ */ new Map();
|
|
144979
|
+
for (const memory of store.list({ originProjectId: input.projectId })) {
|
|
144980
|
+
if (memory.state !== "qualified" && memory.state !== "approved") continue;
|
|
144981
|
+
const key = memory.scope + "\0" + memory.kind + "\0" + memory.title.trim().toLowerCase();
|
|
144982
|
+
const group = groups.get(key) ?? [];
|
|
144983
|
+
group.push(memory);
|
|
144984
|
+
groups.set(key, group);
|
|
144985
|
+
}
|
|
144986
|
+
for (const group of groups.values()) {
|
|
144987
|
+
if (group.length < 2) continue;
|
|
144988
|
+
group.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));
|
|
144989
|
+
const newest = group[0];
|
|
144990
|
+
for (const older of group.slice(1)) {
|
|
144991
|
+
try {
|
|
144992
|
+
await supersedeLongTermMemory({
|
|
144993
|
+
dataDir: input.dataDir,
|
|
144994
|
+
id: older.id,
|
|
144995
|
+
supersededBy: newest.id,
|
|
144996
|
+
reason: "auto-supersede: a newer record shares the same title"
|
|
144997
|
+
});
|
|
144998
|
+
result.superseded += 1;
|
|
144999
|
+
} catch {
|
|
145000
|
+
}
|
|
145001
|
+
}
|
|
145002
|
+
}
|
|
145003
|
+
return result;
|
|
145004
|
+
}
|
|
145005
|
+
async function listLongTermMemories(input) {
|
|
145006
|
+
const store = await createStore(input.dataDir);
|
|
145007
|
+
return store.list({ limit: input.limit ?? 100 }).filter((memory) => canReadLongTermMemory(memory, input.reader)).filter((memory) => input.includeInactive || memory.state !== "archived" && memory.state !== "superseded").map((memory) => ({ memory, evidence: store.listEvidence(memory.id) }));
|
|
145008
|
+
}
|
|
145009
|
+
async function getLongTermMemoryDetail(input) {
|
|
145010
|
+
const store = await createStore(input.dataDir);
|
|
145011
|
+
const memory = store.get(input.id);
|
|
145012
|
+
if (!memory || !canReadLongTermMemory(memory, input.reader)) {
|
|
145013
|
+
throw new Error("Long-term memory was not found in the active scope.");
|
|
145014
|
+
}
|
|
145015
|
+
store.markAccess([memory.id]);
|
|
145016
|
+
return { memory, evidence: store.listEvidence(memory.id), events: store.listEvents(memory.id) };
|
|
145017
|
+
}
|
|
145018
|
+
async function selectLongTermMemoriesForTask(input) {
|
|
145019
|
+
const task = input.task?.trim();
|
|
145020
|
+
if (!task) return [];
|
|
145021
|
+
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: false });
|
|
145022
|
+
const reader = {
|
|
145023
|
+
projectId: input.projectId,
|
|
145024
|
+
...owner ? { ownerId: owner.id } : {},
|
|
145025
|
+
...input.agentId ? { agentId: input.agentId } : {},
|
|
145026
|
+
...input.isTeamMember ? { isTeamMember: true } : {}
|
|
145027
|
+
};
|
|
145028
|
+
const store = await createStore(input.dataDir);
|
|
145029
|
+
const eligible = store.list({ limit: 1e3 }).filter((memory) => isEligibleLongTermMemory(memory) && canReadLongTermMemory(memory, reader));
|
|
145030
|
+
let selected = eligible.map((memory) => {
|
|
145031
|
+
const ranked = scoreForTask(memory, task);
|
|
145032
|
+
return ranked ? {
|
|
145033
|
+
memory,
|
|
145034
|
+
evidence: store.listEvidence(memory.id),
|
|
145035
|
+
score: ranked.score,
|
|
145036
|
+
reason: ranked.reason
|
|
145037
|
+
} : void 0;
|
|
145038
|
+
}).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
|
|
145039
|
+
if (selected.length === 0 && eligible.length > 0) {
|
|
145040
|
+
const provider2 = await resolveSemanticProvider(input.embeddingProvider);
|
|
145041
|
+
const candidates = eligible.slice(0, MAX_SEMANTIC_CANDIDATES);
|
|
145042
|
+
if (provider2 && candidates.length > 0) {
|
|
145043
|
+
try {
|
|
145044
|
+
const vectors = await withTimeout(
|
|
145045
|
+
provider2.embedBatch([task, ...candidates.map(semanticText)], {
|
|
145046
|
+
timeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
145047
|
+
retry: false
|
|
145048
|
+
}),
|
|
145049
|
+
SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
145050
|
+
"Long-term semantic retrieval"
|
|
145051
|
+
);
|
|
145052
|
+
const query = vectors[0];
|
|
145053
|
+
if (Array.isArray(query)) {
|
|
145054
|
+
selected = candidates.map((memory, index) => {
|
|
145055
|
+
const vector = vectors[index + 1];
|
|
145056
|
+
const ranked = Array.isArray(vector) ? semanticSelection(memory, cosineSimilarity(query, vector), task) : void 0;
|
|
145057
|
+
return ranked ? {
|
|
145058
|
+
memory,
|
|
145059
|
+
evidence: store.listEvidence(memory.id),
|
|
145060
|
+
score: ranked.score,
|
|
145061
|
+
reason: ranked.reason
|
|
145062
|
+
} : void 0;
|
|
145063
|
+
}).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
|
|
145064
|
+
}
|
|
145065
|
+
} catch {
|
|
145066
|
+
}
|
|
145067
|
+
}
|
|
145068
|
+
}
|
|
145069
|
+
selected = selected.slice(0, Math.max(1, Math.min(input.limit ?? 3, 5)));
|
|
145070
|
+
store.markAccess(selected.map((item) => item.memory.id));
|
|
145071
|
+
return selected;
|
|
145072
|
+
}
|
|
145073
|
+
function renderLongTermMemorySummary(memory, maxTokens = 22) {
|
|
145074
|
+
const source = [memory.title, memory.applicability, memory.content].filter(Boolean).join(": ");
|
|
145075
|
+
const safe = sanitizeCredentials(source).replace(/\s+/g, " ").trim();
|
|
145076
|
+
return countTextTokens(safe) <= maxTokens ? safe : truncateToTokenBudget(safe, maxTokens);
|
|
145077
|
+
}
|
|
145078
|
+
var MAX_TEXT_LENGTH, MAX_LIST_ITEMS, MAX_SEMANTIC_CANDIDATES, SEMANTIC_RETRIEVAL_TIMEOUT_MS, MIN_SEMANTIC_SIMILARITY, PORTABLE_EVIDENCE_KINDS, STOP_TERMS;
|
|
145079
|
+
var init_long_term = __esm({
|
|
145080
|
+
"src/memory/long-term.ts"() {
|
|
145081
|
+
"use strict";
|
|
145082
|
+
init_esm_shims();
|
|
145083
|
+
init_token_budget();
|
|
145084
|
+
init_timeout();
|
|
145085
|
+
init_secret_filter();
|
|
145086
|
+
init_owner();
|
|
145087
|
+
init_long_term_store();
|
|
145088
|
+
init_long_term_types();
|
|
145089
|
+
MAX_TEXT_LENGTH = 12e3;
|
|
145090
|
+
MAX_LIST_ITEMS = 40;
|
|
145091
|
+
MAX_SEMANTIC_CANDIDATES = 48;
|
|
145092
|
+
SEMANTIC_RETRIEVAL_TIMEOUT_MS = 1800;
|
|
145093
|
+
MIN_SEMANTIC_SIMILARITY = 0.58;
|
|
145094
|
+
PORTABLE_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["manual", "user"]);
|
|
145095
|
+
STOP_TERMS = /* @__PURE__ */ new Set([
|
|
145096
|
+
"the",
|
|
145097
|
+
"and",
|
|
145098
|
+
"for",
|
|
145099
|
+
"with",
|
|
145100
|
+
"from",
|
|
145101
|
+
"that",
|
|
145102
|
+
"this",
|
|
145103
|
+
"into",
|
|
145104
|
+
"when",
|
|
145105
|
+
"what",
|
|
145106
|
+
"\u5982\u4F55",
|
|
145107
|
+
"\u4EC0\u4E48",
|
|
145108
|
+
"\u8FD9\u4E2A",
|
|
145109
|
+
"\u90A3\u4E2A",
|
|
145110
|
+
"\u6211\u4EEC",
|
|
145111
|
+
"\u9879\u76EE",
|
|
145112
|
+
"\u8FDB\u884C",
|
|
145113
|
+
"\u9700\u8981",
|
|
145114
|
+
"\u7EE7\u7EED",
|
|
145115
|
+
"\u5904\u7406"
|
|
145116
|
+
]);
|
|
145117
|
+
}
|
|
145118
|
+
});
|
|
145119
|
+
|
|
144223
145120
|
// src/codegraph/ids.ts
|
|
144224
145121
|
import { createHash as createHash5 } from "crypto";
|
|
144225
145122
|
function digest(input) {
|
|
@@ -144258,7 +145155,7 @@ var store_exports = {};
|
|
|
144258
145155
|
__export(store_exports, {
|
|
144259
145156
|
CodeGraphStore: () => CodeGraphStore
|
|
144260
145157
|
});
|
|
144261
|
-
import { randomUUID as
|
|
145158
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
144262
145159
|
import { posix as pathPosix } from "path";
|
|
144263
145160
|
function rowToFile(row) {
|
|
144264
145161
|
return {
|
|
@@ -144975,7 +145872,7 @@ var init_store = __esm({
|
|
|
144975
145872
|
* so an interrupted scan cannot be advertised as complete.
|
|
144976
145873
|
*/
|
|
144977
145874
|
recordCodeStateSnapshot(input) {
|
|
144978
|
-
const id =
|
|
145875
|
+
const id = randomUUID9();
|
|
144979
145876
|
let snapshot;
|
|
144980
145877
|
const tx = this.db.transaction(() => {
|
|
144981
145878
|
const previous = this.db.prepare(
|
|
@@ -145753,8 +146650,8 @@ var claim_store_exports = {};
|
|
|
145753
146650
|
__export(claim_store_exports, {
|
|
145754
146651
|
ClaimStore: () => ClaimStore
|
|
145755
146652
|
});
|
|
145756
|
-
import { createHash as createHash8, randomUUID as
|
|
145757
|
-
function
|
|
146653
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "crypto";
|
|
146654
|
+
function optionalText3(value) {
|
|
145758
146655
|
return typeof value === "string" && value ? value : void 0;
|
|
145759
146656
|
}
|
|
145760
146657
|
function rowToClaim(row) {
|
|
@@ -145770,38 +146667,38 @@ function rowToClaim(row) {
|
|
|
145770
146667
|
status: row.status,
|
|
145771
146668
|
confidence: Number(row.confidence),
|
|
145772
146669
|
observedAt: row.observedAt,
|
|
145773
|
-
...
|
|
145774
|
-
...
|
|
145775
|
-
...
|
|
146670
|
+
...optionalText3(row.validFrom) ? { validFrom: row.validFrom } : {},
|
|
146671
|
+
...optionalText3(row.validTo) ? { validTo: row.validTo } : {},
|
|
146672
|
+
...optionalText3(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
|
|
145776
146673
|
reviewState: row.reviewState,
|
|
145777
146674
|
origin: row.origin,
|
|
145778
146675
|
createdAt: row.createdAt,
|
|
145779
146676
|
updatedAt: row.updatedAt
|
|
145780
146677
|
};
|
|
145781
146678
|
}
|
|
145782
|
-
function
|
|
146679
|
+
function rowToEvidence2(row) {
|
|
145783
146680
|
return {
|
|
145784
146681
|
id: row.id,
|
|
145785
146682
|
claimId: row.claimId,
|
|
145786
146683
|
evidenceKind: row.evidenceKind,
|
|
145787
146684
|
evidenceId: row.evidenceId,
|
|
145788
146685
|
relation: row.relation,
|
|
145789
|
-
...
|
|
145790
|
-
...
|
|
145791
|
-
...
|
|
146686
|
+
...optionalText3(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
|
|
146687
|
+
...optionalText3(row.locator) ? { locator: row.locator } : {},
|
|
146688
|
+
...optionalText3(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
|
|
145792
146689
|
createdAt: row.createdAt
|
|
145793
146690
|
};
|
|
145794
146691
|
}
|
|
145795
|
-
function
|
|
146692
|
+
function rowToEvent2(row) {
|
|
145796
146693
|
return {
|
|
145797
146694
|
id: row.id,
|
|
145798
146695
|
projectId: row.projectId,
|
|
145799
146696
|
claimId: row.claimId,
|
|
145800
146697
|
kind: row.kind,
|
|
145801
|
-
...
|
|
145802
|
-
...
|
|
145803
|
-
...
|
|
145804
|
-
...
|
|
146698
|
+
...optionalText3(row.fromStatus) ? { fromStatus: row.fromStatus } : {},
|
|
146699
|
+
...optionalText3(row.toStatus) ? { toStatus: row.toStatus } : {},
|
|
146700
|
+
...optionalText3(row.relatedClaimId) ? { relatedClaimId: row.relatedClaimId } : {},
|
|
146701
|
+
...optionalText3(row.detail) ? { detail: row.detail } : {},
|
|
145805
146702
|
createdAt: row.createdAt
|
|
145806
146703
|
};
|
|
145807
146704
|
}
|
|
@@ -145937,7 +146834,7 @@ var init_claim_store = __esm({
|
|
|
145937
146834
|
locator, capturedHash, evidenceKey, createdAt
|
|
145938
146835
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
145939
146836
|
`).run(
|
|
145940
|
-
|
|
146837
|
+
randomUUID10(),
|
|
145941
146838
|
input.claimId,
|
|
145942
146839
|
input.evidenceKind,
|
|
145943
146840
|
input.evidenceId,
|
|
@@ -145955,11 +146852,11 @@ var init_claim_store = __esm({
|
|
|
145955
146852
|
SELECT * FROM knowledge_claim_evidence
|
|
145956
146853
|
WHERE claimId = ?
|
|
145957
146854
|
ORDER BY createdAt ASC, id
|
|
145958
|
-
`).all(claimId).map(
|
|
146855
|
+
`).all(claimId).map(rowToEvidence2);
|
|
145959
146856
|
}
|
|
145960
146857
|
recordEvent(input) {
|
|
145961
146858
|
const event = {
|
|
145962
|
-
id:
|
|
146859
|
+
id: randomUUID10(),
|
|
145963
146860
|
...input,
|
|
145964
146861
|
...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
|
|
145965
146862
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -145987,7 +146884,7 @@ var init_claim_store = __esm({
|
|
|
145987
146884
|
SELECT * FROM knowledge_claim_events
|
|
145988
146885
|
WHERE claimId = ?
|
|
145989
146886
|
ORDER BY createdAt ASC, id
|
|
145990
|
-
`).all(claimId).map(
|
|
146887
|
+
`).all(claimId).map(rowToEvent2);
|
|
145991
146888
|
}
|
|
145992
146889
|
};
|
|
145993
146890
|
}
|
|
@@ -146004,8 +146901,8 @@ __export(claims_exports, {
|
|
|
146004
146901
|
supersedeClaim: () => supersedeClaim,
|
|
146005
146902
|
writeClaim: () => writeClaim
|
|
146006
146903
|
});
|
|
146007
|
-
import { createHash as createHash9, randomUUID as
|
|
146008
|
-
function
|
|
146904
|
+
import { createHash as createHash9, randomUUID as randomUUID11 } from "crypto";
|
|
146905
|
+
function compactText2(value, field) {
|
|
146009
146906
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
146010
146907
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
146011
146908
|
if (!sanitized) throw new Error("Claim " + field + " is required");
|
|
@@ -146013,7 +146910,7 @@ function compactText(value, field) {
|
|
|
146013
146910
|
return sanitized;
|
|
146014
146911
|
}
|
|
146015
146912
|
function normalizedTerm(value) {
|
|
146016
|
-
return
|
|
146913
|
+
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
146017
146914
|
}
|
|
146018
146915
|
function hashIdentity(parts) {
|
|
146019
146916
|
return createHash9("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
@@ -146042,7 +146939,7 @@ function validateEvidence(input) {
|
|
|
146042
146939
|
if (!evidence || typeof evidence !== "object") {
|
|
146043
146940
|
throw new Error("Claim evidence must be an object");
|
|
146044
146941
|
}
|
|
146045
|
-
const evidenceId =
|
|
146942
|
+
const evidenceId = compactText2(evidence.evidenceId, "evidence id");
|
|
146046
146943
|
if (evidenceId.length > MAX_EVIDENCE_ID_LENGTH) {
|
|
146047
146944
|
throw new Error("Claim evidence id is too long");
|
|
146048
146945
|
}
|
|
@@ -146056,9 +146953,9 @@ function validateEvidence(input) {
|
|
|
146056
146953
|
evidenceKind: evidence.evidenceKind,
|
|
146057
146954
|
evidenceId,
|
|
146058
146955
|
relation: evidence.relation,
|
|
146059
|
-
...evidence.snapshotId ? { snapshotId:
|
|
146060
|
-
...evidence.locator ? { locator:
|
|
146061
|
-
...evidence.capturedHash ? { capturedHash:
|
|
146956
|
+
...evidence.snapshotId ? { snapshotId: compactText2(evidence.snapshotId, "evidence snapshot id") } : {},
|
|
146957
|
+
...evidence.locator ? { locator: compactText2(evidence.locator, "evidence locator") } : {},
|
|
146958
|
+
...evidence.capturedHash ? { capturedHash: compactText2(evidence.capturedHash, "evidence hash") } : {}
|
|
146062
146959
|
};
|
|
146063
146960
|
});
|
|
146064
146961
|
}
|
|
@@ -146066,10 +146963,10 @@ function normalizeClaimInput(input) {
|
|
|
146066
146963
|
if (!["project", "workspace", "team", "workflow", "task"].includes(input.scope)) {
|
|
146067
146964
|
throw new Error("Claim scope is invalid");
|
|
146068
146965
|
}
|
|
146069
|
-
const projectId =
|
|
146070
|
-
const subject =
|
|
146071
|
-
const predicate =
|
|
146072
|
-
const objectValue =
|
|
146966
|
+
const projectId = compactText2(input.projectId, "project id");
|
|
146967
|
+
const subject = compactText2(input.subject, "subject");
|
|
146968
|
+
const predicate = compactText2(input.predicate, "predicate");
|
|
146969
|
+
const objectValue = compactText2(input.objectValue, "object value");
|
|
146073
146970
|
const identity = buildClaimIdentity({ subject, predicate, objectValue, scope: input.scope });
|
|
146074
146971
|
const origin = input.origin ?? "explicit";
|
|
146075
146972
|
let reviewState = input.reviewState ?? "approved";
|
|
@@ -146090,7 +146987,7 @@ function normalizeClaimInput(input) {
|
|
|
146090
146987
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
146091
146988
|
return {
|
|
146092
146989
|
claim: {
|
|
146093
|
-
id:
|
|
146990
|
+
id: randomUUID11(),
|
|
146094
146991
|
projectId,
|
|
146095
146992
|
subject,
|
|
146096
146993
|
predicate,
|
|
@@ -146190,7 +147087,7 @@ function reviewClaim(store, input) {
|
|
|
146190
147087
|
if (input.reviewState !== "approved" && input.reviewState !== "rejected") {
|
|
146191
147088
|
throw new Error("A claim review must approve or reject the claim");
|
|
146192
147089
|
}
|
|
146193
|
-
const detail =
|
|
147090
|
+
const detail = compactText2(input.detail, "review detail");
|
|
146194
147091
|
return store.transaction(() => {
|
|
146195
147092
|
const claim = store.getClaim(input.claimId);
|
|
146196
147093
|
if (!claim) throw new Error("Claim was not found");
|
|
@@ -146502,8 +147399,8 @@ var init_frontmatter = __esm({
|
|
|
146502
147399
|
|
|
146503
147400
|
// src/knowledge/markdown.ts
|
|
146504
147401
|
import { createHash as createHash10 } from "crypto";
|
|
146505
|
-
import { promises as
|
|
146506
|
-
import
|
|
147402
|
+
import { promises as fs13 } from "fs";
|
|
147403
|
+
import path20 from "path";
|
|
146507
147404
|
function hashContent(content) {
|
|
146508
147405
|
return createHash10("sha256").update(content).digest("hex");
|
|
146509
147406
|
}
|
|
@@ -146561,8 +147458,8 @@ function extractInternalMarkdownLinks(body) {
|
|
|
146561
147458
|
return [...links].sort();
|
|
146562
147459
|
}
|
|
146563
147460
|
function resolvePageLink(sourceRelativePath, target) {
|
|
146564
|
-
const sourceDir =
|
|
146565
|
-
const normalized =
|
|
147461
|
+
const sourceDir = path20.posix.dirname(sourceRelativePath.replace(/\\/g, "/"));
|
|
147462
|
+
const normalized = path20.posix.normalize(path20.posix.join(sourceDir, target.replace(/\\/g, "/")));
|
|
146566
147463
|
if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../")) return void 0;
|
|
146567
147464
|
return normalized;
|
|
146568
147465
|
}
|
|
@@ -146584,13 +147481,13 @@ function renderKnowledgePage(frontmatter, body) {
|
|
|
146584
147481
|
});
|
|
146585
147482
|
}
|
|
146586
147483
|
async function readKnowledgePage(absolutePath, workspaceRoot) {
|
|
146587
|
-
const raw = await
|
|
147484
|
+
const raw = await fs13.readFile(absolutePath, "utf8");
|
|
146588
147485
|
try {
|
|
146589
147486
|
const parsed = frontmatter_default(raw);
|
|
146590
147487
|
const frontmatter = validateKnowledgePageFrontmatter(parsed.data);
|
|
146591
147488
|
return {
|
|
146592
147489
|
absolutePath,
|
|
146593
|
-
relativePath: workspaceRoot ?
|
|
147490
|
+
relativePath: workspaceRoot ? path20.relative(workspaceRoot, absolutePath).split(path20.sep).join("/") : path20.basename(absolutePath),
|
|
146594
147491
|
frontmatter,
|
|
146595
147492
|
body: parsed.content.trim(),
|
|
146596
147493
|
contentHash: hashContent(raw),
|
|
@@ -146602,7 +147499,7 @@ async function readKnowledgePage(absolutePath, workspaceRoot) {
|
|
|
146602
147499
|
}
|
|
146603
147500
|
}
|
|
146604
147501
|
async function writeKnowledgePage(absolutePath, content) {
|
|
146605
|
-
await
|
|
147502
|
+
await fs13.mkdir(path20.dirname(absolutePath), { recursive: true });
|
|
146606
147503
|
await atomicWriteFile(absolutePath, content);
|
|
146607
147504
|
return hashContent(content);
|
|
146608
147505
|
}
|
|
@@ -146632,8 +147529,8 @@ __export(wiki_exports, {
|
|
|
146632
147529
|
readKnowledgePage: () => readKnowledgePage
|
|
146633
147530
|
});
|
|
146634
147531
|
import { createHash as createHash11 } from "crypto";
|
|
146635
|
-
import { promises as
|
|
146636
|
-
import
|
|
147532
|
+
import { promises as fs14 } from "fs";
|
|
147533
|
+
import path21 from "path";
|
|
146637
147534
|
function hash2(value) {
|
|
146638
147535
|
return createHash11("sha256").update(value).digest("hex");
|
|
146639
147536
|
}
|
|
@@ -146765,7 +147662,7 @@ function candidatePage(workspace, title, claims, store) {
|
|
|
146765
147662
|
}
|
|
146766
147663
|
async function fileHashIfPresent(filePath) {
|
|
146767
147664
|
try {
|
|
146768
|
-
return pageContentHash(await
|
|
147665
|
+
return pageContentHash(await fs14.readFile(filePath, "utf8"));
|
|
146769
147666
|
} catch (error) {
|
|
146770
147667
|
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
146771
147668
|
if (code === "ENOENT") return void 0;
|
|
@@ -146789,8 +147686,8 @@ async function writeIndex(workspace, store) {
|
|
|
146789
147686
|
lines.push("No pending proposals.");
|
|
146790
147687
|
} else {
|
|
146791
147688
|
for (const proposal of pending) {
|
|
146792
|
-
const relative3 =
|
|
146793
|
-
lines.push("- [" +
|
|
147689
|
+
const relative3 = path21.relative(paths.root, proposal.proposalPath).split(path21.sep).join("/");
|
|
147690
|
+
lines.push("- [" + path21.basename(proposal.proposalPath, ".md") + "](" + relative3 + ")");
|
|
146794
147691
|
}
|
|
146795
147692
|
}
|
|
146796
147693
|
lines.push("");
|
|
@@ -146798,7 +147695,7 @@ async function writeIndex(workspace, store) {
|
|
|
146798
147695
|
}
|
|
146799
147696
|
async function appendLog(workspace, line) {
|
|
146800
147697
|
const logPath = getKnowledgeWorkspacePaths(workspace).log;
|
|
146801
|
-
await
|
|
147698
|
+
await fs14.appendFile(logPath, "- " + now() + " " + line + "\n", "utf8");
|
|
146802
147699
|
}
|
|
146803
147700
|
function toPageRecord(workspace, page, status, contentHash, manualContentHash) {
|
|
146804
147701
|
return {
|
|
@@ -146883,9 +147780,9 @@ async function applyKnowledgeProposal(input) {
|
|
|
146883
147780
|
}
|
|
146884
147781
|
if (proposal.status !== "pending") throw new Error("Knowledge proposal is not pending review");
|
|
146885
147782
|
const root = getKnowledgeWorkspacePaths(input.workspace).root;
|
|
146886
|
-
const targetPath =
|
|
146887
|
-
const proposalPath =
|
|
146888
|
-
if (!targetPath.startsWith(root +
|
|
147783
|
+
const targetPath = path21.resolve(proposal.targetPath);
|
|
147784
|
+
const proposalPath = path21.resolve(proposal.proposalPath);
|
|
147785
|
+
if (!targetPath.startsWith(root + path21.sep) || !proposalPath.startsWith(root + path21.sep)) {
|
|
146889
147786
|
throw new Error("Knowledge proposal path escapes its workspace");
|
|
146890
147787
|
}
|
|
146891
147788
|
await withFileLock(root, async () => {
|
|
@@ -146923,12 +147820,12 @@ async function markdownFiles(directory) {
|
|
|
146923
147820
|
const files = [];
|
|
146924
147821
|
let entries;
|
|
146925
147822
|
try {
|
|
146926
|
-
entries = await
|
|
147823
|
+
entries = await fs14.readdir(directory, { withFileTypes: true });
|
|
146927
147824
|
} catch {
|
|
146928
147825
|
return files;
|
|
146929
147826
|
}
|
|
146930
147827
|
for (const entry of entries) {
|
|
146931
|
-
const filePath =
|
|
147828
|
+
const filePath = path21.join(directory, entry.name);
|
|
146932
147829
|
if (entry.isDirectory()) {
|
|
146933
147830
|
files.push(...await markdownFiles(filePath));
|
|
146934
147831
|
} else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
|
|
@@ -146951,13 +147848,13 @@ async function lintKnowledgeWorkspace(input) {
|
|
|
146951
147848
|
kind: "malformed-frontmatter",
|
|
146952
147849
|
severity: "error",
|
|
146953
147850
|
message: error instanceof Error ? error.message : "Malformed knowledge page.",
|
|
146954
|
-
relativePath:
|
|
147851
|
+
relativePath: path21.relative(paths.root, filePath).split(path21.sep).join("/")
|
|
146955
147852
|
});
|
|
146956
147853
|
}
|
|
146957
147854
|
}
|
|
146958
147855
|
const indexed = /* @__PURE__ */ new Set();
|
|
146959
147856
|
try {
|
|
146960
|
-
const index = await
|
|
147857
|
+
const index = await fs14.readFile(paths.index, "utf8");
|
|
146961
147858
|
for (const link of extractInternalMarkdownLinks(index)) {
|
|
146962
147859
|
const resolved = resolvePageLink("index.md", link);
|
|
146963
147860
|
if (resolved) indexed.add(resolved);
|
|
@@ -147046,7 +147943,7 @@ async function lintKnowledgeWorkspace(input) {
|
|
|
147046
147943
|
kind: "manual-edit-protected",
|
|
147047
147944
|
severity: "warning",
|
|
147048
147945
|
message: "A newer proposal was held because the target page has manual edits.",
|
|
147049
|
-
relativePath:
|
|
147946
|
+
relativePath: path21.relative(paths.root, proposal.targetPath).split(path21.sep).join("/")
|
|
147050
147947
|
});
|
|
147051
147948
|
}
|
|
147052
147949
|
}
|
|
@@ -147179,7 +148076,7 @@ var workflow_store_exports = {};
|
|
|
147179
148076
|
__export(workflow_store_exports, {
|
|
147180
148077
|
WorkflowStore: () => WorkflowStore
|
|
147181
148078
|
});
|
|
147182
|
-
import { randomUUID as
|
|
148079
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
147183
148080
|
function parseJson(value, fallback) {
|
|
147184
148081
|
if (typeof value !== "string" || !value) return fallback;
|
|
147185
148082
|
try {
|
|
@@ -147188,7 +148085,7 @@ function parseJson(value, fallback) {
|
|
|
147188
148085
|
return fallback;
|
|
147189
148086
|
}
|
|
147190
148087
|
}
|
|
147191
|
-
function
|
|
148088
|
+
function optionalText4(value) {
|
|
147192
148089
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
147193
148090
|
}
|
|
147194
148091
|
function rowToWorkflow(row) {
|
|
@@ -147225,14 +148122,14 @@ function rowToRun(row) {
|
|
|
147225
148122
|
workflowId: row.workflowId,
|
|
147226
148123
|
projectId: row.projectId,
|
|
147227
148124
|
task: row.task,
|
|
147228
|
-
...
|
|
148125
|
+
...optionalText4(row.startingSnapshotId) ? { startingSnapshotId: row.startingSnapshotId } : {},
|
|
147229
148126
|
selectedEvidence: parseJson(row.selectedEvidenceJson, []),
|
|
147230
148127
|
phaseState: parseJson(row.phaseStateJson, {}),
|
|
147231
148128
|
outcome: row.outcome,
|
|
147232
148129
|
verificationVerdict: row.verificationVerdict,
|
|
147233
|
-
...
|
|
148130
|
+
...optionalText4(row.failureReason) ? { failureReason: row.failureReason } : {},
|
|
147234
148131
|
startedAt: row.startedAt,
|
|
147235
|
-
...
|
|
148132
|
+
...optionalText4(row.completedAt) ? { completedAt: row.completedAt } : {}
|
|
147236
148133
|
};
|
|
147237
148134
|
}
|
|
147238
148135
|
var WorkflowStore;
|
|
@@ -147279,7 +148176,7 @@ var init_workflow_store = __esm({
|
|
|
147279
148176
|
}
|
|
147280
148177
|
recordRun(input) {
|
|
147281
148178
|
const run = {
|
|
147282
|
-
id:
|
|
148179
|
+
id: randomUUID12(),
|
|
147283
148180
|
workflowId: input.workflowId,
|
|
147284
148181
|
projectId: input.projectId,
|
|
147285
148182
|
task: input.task.trim(),
|
|
@@ -147357,8 +148254,8 @@ var init_outcome_types = __esm({
|
|
|
147357
148254
|
});
|
|
147358
148255
|
|
|
147359
148256
|
// src/knowledge/outcome-store.ts
|
|
147360
|
-
import { randomUUID as
|
|
147361
|
-
function
|
|
148257
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
148258
|
+
function optionalText5(value) {
|
|
147362
148259
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
147363
148260
|
}
|
|
147364
148261
|
function text(value, field, max = 1e3) {
|
|
@@ -147381,8 +148278,8 @@ function rowToSignal(row) {
|
|
|
147381
148278
|
candidateId: row.candidateId,
|
|
147382
148279
|
kind: row.kind,
|
|
147383
148280
|
sourceRef: row.sourceRef,
|
|
147384
|
-
...
|
|
147385
|
-
...
|
|
148281
|
+
...optionalText5(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
|
|
148282
|
+
...optionalText5(row.detail) ? { detail: row.detail } : {},
|
|
147386
148283
|
observedAt: row.observedAt
|
|
147387
148284
|
};
|
|
147388
148285
|
}
|
|
@@ -147401,7 +148298,7 @@ var init_outcome_store = __esm({
|
|
|
147401
148298
|
}
|
|
147402
148299
|
record(input) {
|
|
147403
148300
|
const signal = {
|
|
147404
|
-
id:
|
|
148301
|
+
id: randomUUID13(),
|
|
147405
148302
|
projectId: text(input.projectId, "project id"),
|
|
147406
148303
|
candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
|
|
147407
148304
|
candidateId: text(input.candidateId, "candidate id"),
|
|
@@ -147828,8 +148725,8 @@ __export(workflows_exports, {
|
|
|
147828
148725
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
147829
148726
|
});
|
|
147830
148727
|
import { createHash as createHash12 } from "crypto";
|
|
147831
|
-
import { promises as
|
|
147832
|
-
import
|
|
148728
|
+
import { promises as fs15 } from "fs";
|
|
148729
|
+
import path22 from "path";
|
|
147833
148730
|
function hash3(value) {
|
|
147834
148731
|
return createHash12("sha256").update(value).digest("hex");
|
|
147835
148732
|
}
|
|
@@ -147850,7 +148747,7 @@ function requiredText(data, key) {
|
|
|
147850
148747
|
}
|
|
147851
148748
|
return value.trim();
|
|
147852
148749
|
}
|
|
147853
|
-
function
|
|
148750
|
+
function optionalText6(data, key) {
|
|
147854
148751
|
const value = data[key];
|
|
147855
148752
|
if (value === void 0 || value === null || value === "") return void 0;
|
|
147856
148753
|
if (typeof value !== "string") throw new Error("workflow frontmatter field " + key + " must be text");
|
|
@@ -147893,11 +148790,11 @@ function phaseFromValue(value, index) {
|
|
|
147893
148790
|
}
|
|
147894
148791
|
const data = value;
|
|
147895
148792
|
const title = requiredText(data, "title");
|
|
147896
|
-
const phaseId =
|
|
148793
|
+
const phaseId = optionalText6(data, "id") ?? slug(title) + "-" + (index + 1);
|
|
147897
148794
|
return {
|
|
147898
148795
|
id: phaseId,
|
|
147899
148796
|
title,
|
|
147900
|
-
instructions:
|
|
148797
|
+
instructions: optionalText6(data, "instructions") ?? "",
|
|
147901
148798
|
branches: optionalStringArray(data, "branches"),
|
|
147902
148799
|
expectedOutputs: optionalStringArray(data, "expectedOutputs"),
|
|
147903
148800
|
verificationGates: optionalStringArray(data, "verificationGates")
|
|
@@ -147932,7 +148829,7 @@ function phasesFromBody(body) {
|
|
|
147932
148829
|
}
|
|
147933
148830
|
function normalizeSourcePath(sourcePath) {
|
|
147934
148831
|
const normalized = sourcePath.replace(/\\/g, "/");
|
|
147935
|
-
if (!normalized.startsWith("workflows/") || !normalized.toLowerCase().endsWith(".md") || normalized.includes("../") ||
|
|
148832
|
+
if (!normalized.startsWith("workflows/") || !normalized.toLowerCase().endsWith(".md") || normalized.includes("../") || path22.posix.normalize(normalized) !== normalized) {
|
|
147936
148833
|
throw new Error("workflow source path must be a safe workflows/*.md path");
|
|
147937
148834
|
}
|
|
147938
148835
|
return normalized;
|
|
@@ -148006,7 +148903,7 @@ function parsedWorkflow(data, body, input) {
|
|
|
148006
148903
|
id: requiredText(data, "id"),
|
|
148007
148904
|
workspaceId: input.workspaceId,
|
|
148008
148905
|
title: requiredText(data, "title"),
|
|
148009
|
-
description:
|
|
148906
|
+
description: optionalText6(data, "description") ?? "",
|
|
148010
148907
|
status: optionalStatus(data),
|
|
148011
148908
|
version: optionalNumber(data, "version", 1),
|
|
148012
148909
|
taskLenses: optionalStringArray(data, "taskLenses"),
|
|
@@ -148025,9 +148922,9 @@ function parsedWorkflow(data, body, input) {
|
|
|
148025
148922
|
sourcePath: normalizeSourcePath(input.sourcePath),
|
|
148026
148923
|
sourceHash: "",
|
|
148027
148924
|
contentHash: input.contentHash,
|
|
148028
|
-
createdAt:
|
|
148029
|
-
updatedAt:
|
|
148030
|
-
...
|
|
148925
|
+
createdAt: optionalText6(data, "createdAt") ?? now2(),
|
|
148926
|
+
updatedAt: optionalText6(data, "updatedAt") ?? now2(),
|
|
148927
|
+
...optionalText6(data, "importedFrom") ? { importedFrom: optionalText6(data, "importedFrom") } : {}
|
|
148031
148928
|
};
|
|
148032
148929
|
if (candidate.phases.length === 0) {
|
|
148033
148930
|
throw new Error("workflow must contain at least one phase or a non-empty body");
|
|
@@ -148081,7 +148978,7 @@ async function writeCanonicalWorkflow(input) {
|
|
|
148081
148978
|
const filePath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);
|
|
148082
148979
|
const content = renderWorkflowMarkdown(workflow);
|
|
148083
148980
|
await withFileLock(paths.root, async () => {
|
|
148084
|
-
await
|
|
148981
|
+
await fs15.mkdir(path22.dirname(filePath), { recursive: true });
|
|
148085
148982
|
await atomicWriteFile(filePath, content);
|
|
148086
148983
|
});
|
|
148087
148984
|
const store = await storeFor2(input.workspace);
|
|
@@ -148090,13 +148987,13 @@ async function writeCanonicalWorkflow(input) {
|
|
|
148090
148987
|
async function markdownFiles2(directory) {
|
|
148091
148988
|
let entries;
|
|
148092
148989
|
try {
|
|
148093
|
-
entries = await
|
|
148990
|
+
entries = await fs15.readdir(directory, { withFileTypes: true });
|
|
148094
148991
|
} catch {
|
|
148095
148992
|
return [];
|
|
148096
148993
|
}
|
|
148097
148994
|
const files = [];
|
|
148098
148995
|
for (const entry of entries) {
|
|
148099
|
-
const absolutePath =
|
|
148996
|
+
const absolutePath = path22.join(directory, entry.name);
|
|
148100
148997
|
if (entry.isDirectory()) {
|
|
148101
148998
|
files.push(...await markdownFiles2(absolutePath));
|
|
148102
148999
|
} else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
|
|
@@ -148111,9 +149008,9 @@ async function syncCanonicalWorkflows(workspace) {
|
|
|
148111
149008
|
const workflows = [];
|
|
148112
149009
|
const errors = [];
|
|
148113
149010
|
for (const absolutePath of await markdownFiles2(paths.workflows)) {
|
|
148114
|
-
const sourcePath =
|
|
149011
|
+
const sourcePath = path22.relative(paths.root, absolutePath).split(path22.sep).join("/");
|
|
148115
149012
|
try {
|
|
148116
|
-
const raw = await
|
|
149013
|
+
const raw = await fs15.readFile(absolutePath, "utf8");
|
|
148117
149014
|
const workflow = parseWorkflowMarkdown(raw, { workspaceId: workspace.id, sourcePath });
|
|
148118
149015
|
workflows.push(store.upsertWorkflow(workflow));
|
|
148119
149016
|
} catch (error) {
|
|
@@ -148225,21 +149122,21 @@ function importedWorkflowSpec(input) {
|
|
|
148225
149122
|
return materializeWorkflow(spec);
|
|
148226
149123
|
}
|
|
148227
149124
|
async function importWindsurfWorkflows(input) {
|
|
148228
|
-
const sourceDirectory =
|
|
149125
|
+
const sourceDirectory = path22.join(path22.resolve(input.projectRoot), ".windsurf", "workflows");
|
|
148229
149126
|
const paths = getKnowledgeWorkspacePaths(input.workspace);
|
|
148230
149127
|
const imported = [];
|
|
148231
149128
|
const skipped = [];
|
|
148232
149129
|
let entries;
|
|
148233
149130
|
try {
|
|
148234
|
-
entries = await
|
|
149131
|
+
entries = await fs15.readdir(sourceDirectory, { withFileTypes: true });
|
|
148235
149132
|
} catch {
|
|
148236
149133
|
return { imported, skipped };
|
|
148237
149134
|
}
|
|
148238
149135
|
for (const entry of entries.filter((item) => item.isFile() && item.name.toLowerCase().endsWith(".md"))) {
|
|
148239
|
-
const originalPath =
|
|
148240
|
-
const sourcePath =
|
|
149136
|
+
const originalPath = path22.join(sourceDirectory, entry.name);
|
|
149137
|
+
const sourcePath = path22.relative(path22.resolve(input.projectRoot), originalPath).split(path22.sep).join("/");
|
|
148241
149138
|
try {
|
|
148242
|
-
const raw = await
|
|
149139
|
+
const raw = await fs15.readFile(originalPath, "utf8");
|
|
148243
149140
|
const workflow = importedWorkflowSpec({
|
|
148244
149141
|
workspace: input.workspace,
|
|
148245
149142
|
sourceName: entry.name,
|
|
@@ -148248,7 +149145,7 @@ async function importWindsurfWorkflows(input) {
|
|
|
148248
149145
|
});
|
|
148249
149146
|
const targetPath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);
|
|
148250
149147
|
try {
|
|
148251
|
-
await
|
|
149148
|
+
await fs15.access(targetPath);
|
|
148252
149149
|
skipped.push({ sourcePath, reason: "canonical workflow already exists and was preserved" });
|
|
148253
149150
|
continue;
|
|
148254
149151
|
} catch {
|
|
@@ -148261,12 +149158,12 @@ async function importWindsurfWorkflows(input) {
|
|
|
148261
149158
|
});
|
|
148262
149159
|
}
|
|
148263
149160
|
}
|
|
148264
|
-
await
|
|
149161
|
+
await fs15.mkdir(paths.workflows, { recursive: true });
|
|
148265
149162
|
return { imported, skipped };
|
|
148266
149163
|
}
|
|
148267
149164
|
function isWithin2(root, candidate) {
|
|
148268
|
-
const relative3 =
|
|
148269
|
-
return relative3 !== "" && relative3 !== ".." && !relative3.startsWith(".." +
|
|
149165
|
+
const relative3 = path22.relative(root, candidate);
|
|
149166
|
+
return relative3 !== "" && relative3 !== ".." && !relative3.startsWith(".." + path22.sep) && !path22.isAbsolute(relative3);
|
|
148270
149167
|
}
|
|
148271
149168
|
function adapterRelativePath(workflow, agent) {
|
|
148272
149169
|
const name = "memorix-workflow-" + slug(workflow.id.replace(/^workflow:/, ""));
|
|
@@ -148352,15 +149249,15 @@ async function previewWorkflowAdapter(input) {
|
|
|
148352
149249
|
reason: "The canonical workflow does not declare compatibility with this agent."
|
|
148353
149250
|
};
|
|
148354
149251
|
}
|
|
148355
|
-
const projectRoot =
|
|
148356
|
-
const targetPath =
|
|
149252
|
+
const projectRoot = path22.resolve(input.projectRoot);
|
|
149253
|
+
const targetPath = path22.resolve(projectRoot, adapterRelativePath(input.workflow, input.agent));
|
|
148357
149254
|
if (!isWithin2(projectRoot, targetPath)) {
|
|
148358
149255
|
throw new Error("Workflow adapter target escapes the project root");
|
|
148359
149256
|
}
|
|
148360
149257
|
const content = adapterContent(input.workflow, input.agent);
|
|
148361
149258
|
let existing;
|
|
148362
149259
|
try {
|
|
148363
|
-
existing = await
|
|
149260
|
+
existing = await fs15.readFile(targetPath, "utf8");
|
|
148364
149261
|
} catch (error) {
|
|
148365
149262
|
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
148366
149263
|
if (code !== "ENOENT") throw error;
|
|
@@ -148381,11 +149278,11 @@ async function applyWorkflowAdapter(input) {
|
|
|
148381
149278
|
if (initial.status === "unsupported" || initial.status === "conflict" || initial.status === "unchanged") {
|
|
148382
149279
|
return initial;
|
|
148383
149280
|
}
|
|
148384
|
-
const projectRoot =
|
|
149281
|
+
const projectRoot = path22.resolve(input.projectRoot);
|
|
148385
149282
|
return withFileLock(projectRoot, async () => {
|
|
148386
149283
|
const current = await previewWorkflowAdapter(input);
|
|
148387
149284
|
if (current.status !== "create" && current.status !== "update") return current;
|
|
148388
|
-
await
|
|
149285
|
+
await fs15.mkdir(path22.dirname(current.targetPath), { recursive: true });
|
|
148389
149286
|
await atomicWriteFile(current.targetPath, current.content);
|
|
148390
149287
|
return current;
|
|
148391
149288
|
});
|
|
@@ -148675,6 +149572,11 @@ function createProjectMaintenanceHandler(projectId, projectDir2, projectRoot, op
|
|
|
148675
149572
|
}
|
|
148676
149573
|
return { action: "complete" };
|
|
148677
149574
|
}
|
|
149575
|
+
if (job.kind === "long-term-maintenance") {
|
|
149576
|
+
const { maintainLongTermMemories: maintainLongTermMemories2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
|
|
149577
|
+
await maintainLongTermMemories2({ dataDir: projectDir2, projectId });
|
|
149578
|
+
return { action: "reschedule", delayMs: 24 * 60 * 60 * 1e3, resetAttempts: true };
|
|
149579
|
+
}
|
|
148678
149580
|
if (job.kind === "consolidation") {
|
|
148679
149581
|
const limit2 = consolidationBatchSize(job.payload);
|
|
148680
149582
|
const result2 = await runAutomaticConsolidation(projectId, projectDir2, {
|
|
@@ -149016,15 +149918,15 @@ __export(vector_backfill_runner_exports, {
|
|
|
149016
149918
|
});
|
|
149017
149919
|
import { spawn as spawn4 } from "child_process";
|
|
149018
149920
|
import { existsSync as existsSync10 } from "fs";
|
|
149019
|
-
import
|
|
149921
|
+
import path23 from "path";
|
|
149020
149922
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
149021
149923
|
function isNonEmptyString(value) {
|
|
149022
149924
|
return typeof value === "string" && value.trim().length > 0;
|
|
149023
149925
|
}
|
|
149024
149926
|
function resolveVectorBackfillRunnerPath(moduleUrl = import.meta.url) {
|
|
149025
|
-
const moduleDir =
|
|
149026
|
-
const distDir =
|
|
149027
|
-
return
|
|
149927
|
+
const moduleDir = path23.dirname(fileURLToPath5(moduleUrl));
|
|
149928
|
+
const distDir = path23.basename(moduleDir) === "cli" ? path23.dirname(moduleDir) : path23.basename(moduleDir) === "runtime" && path23.basename(path23.dirname(moduleDir)) === "src" ? path23.join(path23.dirname(path23.dirname(moduleDir)), "dist") : moduleDir;
|
|
149929
|
+
return path23.join(distDir, "vector-backfill-runner.js");
|
|
149028
149930
|
}
|
|
149029
149931
|
function parseVectorBackfillRequest(raw) {
|
|
149030
149932
|
let value;
|
|
@@ -149033,7 +149935,7 @@ function parseVectorBackfillRequest(raw) {
|
|
|
149033
149935
|
} catch {
|
|
149034
149936
|
throw new Error("Vector backfill runner received invalid JSON input");
|
|
149035
149937
|
}
|
|
149036
|
-
if (!value || typeof value !== "object" || !isNonEmptyString(value.projectId) || !isNonEmptyString(value.projectRoot) || !isNonEmptyString(value.dataDir) || !
|
|
149938
|
+
if (!value || typeof value !== "object" || !isNonEmptyString(value.projectId) || !isNonEmptyString(value.projectRoot) || !isNonEmptyString(value.dataDir) || !path23.isAbsolute(value.projectRoot) || !path23.isAbsolute(value.dataDir)) {
|
|
149037
149939
|
throw new Error("Vector backfill runner received an invalid request");
|
|
149038
149940
|
}
|
|
149039
149941
|
return {
|
|
@@ -150115,8 +151017,16 @@ var init_observations = __esm({
|
|
|
150115
151017
|
});
|
|
150116
151018
|
|
|
150117
151019
|
// src/store/session-store.ts
|
|
150118
|
-
|
|
150119
|
-
|
|
151020
|
+
var session_store_exports = {};
|
|
151021
|
+
__export(session_store_exports, {
|
|
151022
|
+
SessionGracefulDegrade: () => SessionGracefulDegrade,
|
|
151023
|
+
SessionSqliteStore: () => SessionSqliteStore,
|
|
151024
|
+
getSessionStore: () => getSessionStore,
|
|
151025
|
+
initSessionStore: () => initSessionStore,
|
|
151026
|
+
resetSessionStore: () => resetSessionStore
|
|
151027
|
+
});
|
|
151028
|
+
import path24 from "path";
|
|
151029
|
+
import fs16 from "fs";
|
|
150120
151030
|
function sessionToRow(session) {
|
|
150121
151031
|
return {
|
|
150122
151032
|
id: session.id,
|
|
@@ -150145,6 +151055,10 @@ function getSessionStore() {
|
|
|
150145
151055
|
}
|
|
150146
151056
|
return _store3;
|
|
150147
151057
|
}
|
|
151058
|
+
function resetSessionStore() {
|
|
151059
|
+
_store3 = null;
|
|
151060
|
+
_storeDataDir3 = null;
|
|
151061
|
+
}
|
|
150148
151062
|
async function initSessionStore(dataDir) {
|
|
150149
151063
|
if (_store3 && _storeDataDir3 === dataDir) return _store3;
|
|
150150
151064
|
_store3 = null;
|
|
@@ -150198,10 +151112,10 @@ var init_session_store = __esm({
|
|
|
150198
151112
|
async migrateFromJsonIfNeeded() {
|
|
150199
151113
|
const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM sessions`).get();
|
|
150200
151114
|
if (count2.cnt > 0) return;
|
|
150201
|
-
const jsonPath =
|
|
150202
|
-
if (!
|
|
151115
|
+
const jsonPath = path24.join(this.dataDir, "sessions.json");
|
|
151116
|
+
if (!fs16.existsSync(jsonPath)) return;
|
|
150203
151117
|
try {
|
|
150204
|
-
const raw =
|
|
151118
|
+
const raw = fs16.readFileSync(jsonPath, "utf-8");
|
|
150205
151119
|
const sessions = JSON.parse(raw);
|
|
150206
151120
|
if (!Array.isArray(sessions) || sessions.length === 0) return;
|
|
150207
151121
|
console.error(`[memorix] Migrating ${sessions.length} sessions from JSON to SQLite...`);
|
|
@@ -152555,8 +153469,8 @@ var init_trae = __esm({
|
|
|
152555
153469
|
});
|
|
152556
153470
|
|
|
152557
153471
|
// src/rules/syncer.ts
|
|
152558
|
-
import { promises as
|
|
152559
|
-
import
|
|
153472
|
+
import { promises as fs17 } from "fs";
|
|
153473
|
+
import path25 from "path";
|
|
152560
153474
|
var RulesSyncer;
|
|
152561
153475
|
var init_syncer = __esm({
|
|
152562
153476
|
"src/rules/syncer.ts"() {
|
|
@@ -152601,8 +153515,8 @@ var init_syncer = __esm({
|
|
|
152601
153515
|
const found = await this.findFiles(scanPath);
|
|
152602
153516
|
for (const filePath of found) {
|
|
152603
153517
|
try {
|
|
152604
|
-
const content = await
|
|
152605
|
-
const relativePath =
|
|
153518
|
+
const content = await fs17.readFile(filePath, "utf-8");
|
|
153519
|
+
const relativePath = path25.relative(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
152606
153520
|
const parsed = entry.adapter.parse(relativePath, content);
|
|
152607
153521
|
rules.push(...parsed);
|
|
152608
153522
|
} catch {
|
|
@@ -152670,7 +153584,7 @@ var init_syncer = __esm({
|
|
|
152670
153584
|
const entries = [];
|
|
152671
153585
|
for (const adapter of this.adapters.values()) {
|
|
152672
153586
|
const absolutePaths = adapter.filePatterns.map(
|
|
152673
|
-
(p) =>
|
|
153587
|
+
(p) => path25.join(this.projectRoot, p)
|
|
152674
153588
|
);
|
|
152675
153589
|
entries.push({ adapter, paths: absolutePaths });
|
|
152676
153590
|
}
|
|
@@ -152678,13 +153592,13 @@ var init_syncer = __esm({
|
|
|
152678
153592
|
}
|
|
152679
153593
|
/** Find files matching a glob-like path (simple implementation) */
|
|
152680
153594
|
async findFiles(pattern) {
|
|
152681
|
-
const dir =
|
|
152682
|
-
const fileGlob =
|
|
153595
|
+
const dir = path25.dirname(pattern);
|
|
153596
|
+
const fileGlob = path25.basename(pattern);
|
|
152683
153597
|
try {
|
|
152684
|
-
const stat4 = await
|
|
153598
|
+
const stat4 = await fs17.stat(dir);
|
|
152685
153599
|
if (!stat4.isDirectory()) {
|
|
152686
153600
|
try {
|
|
152687
|
-
await
|
|
153601
|
+
await fs17.access(pattern);
|
|
152688
153602
|
return [pattern];
|
|
152689
153603
|
} catch {
|
|
152690
153604
|
return [];
|
|
@@ -152692,7 +153606,7 @@ var init_syncer = __esm({
|
|
|
152692
153606
|
}
|
|
152693
153607
|
} catch {
|
|
152694
153608
|
try {
|
|
152695
|
-
await
|
|
153609
|
+
await fs17.access(pattern);
|
|
152696
153610
|
return [pattern];
|
|
152697
153611
|
} catch {
|
|
152698
153612
|
return [];
|
|
@@ -152700,16 +153614,16 @@ var init_syncer = __esm({
|
|
|
152700
153614
|
}
|
|
152701
153615
|
if (fileGlob.includes("*")) {
|
|
152702
153616
|
try {
|
|
152703
|
-
const files = await
|
|
153617
|
+
const files = await fs17.readdir(dir);
|
|
152704
153618
|
const ext = fileGlob.replace("*", "");
|
|
152705
|
-
return files.filter((f3) => ext ? f3.endsWith(ext) : true).map((f3) =>
|
|
153619
|
+
return files.filter((f3) => ext ? f3.endsWith(ext) : true).map((f3) => path25.join(dir, f3));
|
|
152706
153620
|
} catch {
|
|
152707
153621
|
return [];
|
|
152708
153622
|
}
|
|
152709
153623
|
}
|
|
152710
153624
|
try {
|
|
152711
|
-
await
|
|
152712
|
-
return [
|
|
153625
|
+
await fs17.access(path25.join(dir, fileGlob));
|
|
153626
|
+
return [path25.join(dir, fileGlob)];
|
|
152713
153627
|
} catch {
|
|
152714
153628
|
return [];
|
|
152715
153629
|
}
|
|
@@ -155288,12 +156202,52 @@ var init_formation_timeout = __esm({
|
|
|
155288
156202
|
}
|
|
155289
156203
|
});
|
|
155290
156204
|
|
|
156205
|
+
// src/search/surfaced-registry.ts
|
|
156206
|
+
function touch(key) {
|
|
156207
|
+
const ids = registry.get(key);
|
|
156208
|
+
if (!ids) return [];
|
|
156209
|
+
registry.delete(key);
|
|
156210
|
+
registry.set(key, ids);
|
|
156211
|
+
return ids;
|
|
156212
|
+
}
|
|
156213
|
+
function getSurfacedIds(key) {
|
|
156214
|
+
return [...touch(key)];
|
|
156215
|
+
}
|
|
156216
|
+
function recordSurfacedIds(key, ids) {
|
|
156217
|
+
if (ids.length === 0) return;
|
|
156218
|
+
let list = registry.get(key) ?? [];
|
|
156219
|
+
const known = new Set(list);
|
|
156220
|
+
for (const id of ids) {
|
|
156221
|
+
if (known.has(id)) continue;
|
|
156222
|
+
known.add(id);
|
|
156223
|
+
list.push(id);
|
|
156224
|
+
}
|
|
156225
|
+
if (list.length > MAX_IDS) {
|
|
156226
|
+
list = list.slice(list.length - MAX_IDS);
|
|
156227
|
+
}
|
|
156228
|
+
registry.set(key, list);
|
|
156229
|
+
if (registry.size > MAX_KEYS) {
|
|
156230
|
+
const oldestKey = registry.keys().next().value;
|
|
156231
|
+
if (oldestKey !== void 0 && oldestKey !== key) registry.delete(oldestKey);
|
|
156232
|
+
}
|
|
156233
|
+
}
|
|
156234
|
+
var MAX_KEYS, MAX_IDS, registry;
|
|
156235
|
+
var init_surfaced_registry = __esm({
|
|
156236
|
+
"src/search/surfaced-registry.ts"() {
|
|
156237
|
+
"use strict";
|
|
156238
|
+
init_esm_shims();
|
|
156239
|
+
MAX_KEYS = 64;
|
|
156240
|
+
MAX_IDS = 200;
|
|
156241
|
+
registry = /* @__PURE__ */ new Map();
|
|
156242
|
+
}
|
|
156243
|
+
});
|
|
156244
|
+
|
|
155291
156245
|
// src/server/request-context.ts
|
|
155292
|
-
import
|
|
156246
|
+
import path26 from "path";
|
|
155293
156247
|
function resolveRoot(projectRoot) {
|
|
155294
156248
|
const value = projectRoot.trim();
|
|
155295
156249
|
if (!value) throw new Error("Project binding requires a non-empty project root");
|
|
155296
|
-
return
|
|
156250
|
+
return path26.resolve(value);
|
|
155297
156251
|
}
|
|
155298
156252
|
function createProjectBindingController(projectRoot) {
|
|
155299
156253
|
return new ProjectBindingController(projectRoot);
|
|
@@ -155942,827 +156896,6 @@ var init_session = __esm({
|
|
|
155942
156896
|
}
|
|
155943
156897
|
});
|
|
155944
156898
|
|
|
155945
|
-
// src/memory/owner.ts
|
|
155946
|
-
var owner_exports = {};
|
|
155947
|
-
__export(owner_exports, {
|
|
155948
|
-
resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
|
|
155949
|
-
});
|
|
155950
|
-
import { randomUUID as randomUUID11 } from "crypto";
|
|
155951
|
-
import { promises as fs17 } from "fs";
|
|
155952
|
-
import path26 from "path";
|
|
155953
|
-
function ownerPath(dataDir) {
|
|
155954
|
-
const resolved = path26.resolve(dataDir);
|
|
155955
|
-
const home = path26.basename(resolved).toLocaleLowerCase("en-US") === "data" ? path26.dirname(resolved) : resolved;
|
|
155956
|
-
return path26.join(home, "memorix-user.json");
|
|
155957
|
-
}
|
|
155958
|
-
function normalizedOwnerId(value) {
|
|
155959
|
-
const trimmed = value?.trim();
|
|
155960
|
-
return trimmed && ID_PATTERN.test(trimmed) ? trimmed : void 0;
|
|
155961
|
-
}
|
|
155962
|
-
async function readOwnerFile(filePath) {
|
|
155963
|
-
try {
|
|
155964
|
-
const value = JSON.parse(await fs17.readFile(filePath, "utf8"));
|
|
155965
|
-
const id = typeof value.id === "string" ? normalizedOwnerId(value.id) : void 0;
|
|
155966
|
-
return id ? { id, source: "local-file" } : void 0;
|
|
155967
|
-
} catch {
|
|
155968
|
-
return void 0;
|
|
155969
|
-
}
|
|
155970
|
-
}
|
|
155971
|
-
async function resolveLocalMemoryOwner(dataDir, options = {}) {
|
|
155972
|
-
const configured = normalizedOwnerId(process.env.MEMORIX_USER_ID);
|
|
155973
|
-
if (configured) return { id: configured, source: "environment" };
|
|
155974
|
-
const filePath = ownerPath(dataDir);
|
|
155975
|
-
const existing = await readOwnerFile(filePath);
|
|
155976
|
-
if (existing || !options.create) return existing;
|
|
155977
|
-
await fs17.mkdir(path26.dirname(filePath), { recursive: true });
|
|
155978
|
-
const created = {
|
|
155979
|
-
version: 1,
|
|
155980
|
-
id: "local-" + randomUUID11(),
|
|
155981
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
155982
|
-
};
|
|
155983
|
-
try {
|
|
155984
|
-
await fs17.writeFile(filePath, JSON.stringify(created, null, 2) + "\n", { encoding: "utf8", flag: "wx" });
|
|
155985
|
-
return { id: created.id, source: "local-file" };
|
|
155986
|
-
} catch (error) {
|
|
155987
|
-
if (error?.code !== "EEXIST") throw error;
|
|
155988
|
-
const concurrent = await readOwnerFile(filePath);
|
|
155989
|
-
if (concurrent) return concurrent;
|
|
155990
|
-
throw new Error("Memorix could not establish a valid local memory owner identity.");
|
|
155991
|
-
}
|
|
155992
|
-
}
|
|
155993
|
-
var ID_PATTERN;
|
|
155994
|
-
var init_owner = __esm({
|
|
155995
|
-
"src/memory/owner.ts"() {
|
|
155996
|
-
"use strict";
|
|
155997
|
-
init_esm_shims();
|
|
155998
|
-
ID_PATTERN = /^[A-Za-z0-9:_-]{3,160}$/;
|
|
155999
|
-
}
|
|
156000
|
-
});
|
|
156001
|
-
|
|
156002
|
-
// src/memory/long-term-store.ts
|
|
156003
|
-
import { randomUUID as randomUUID12 } from "crypto";
|
|
156004
|
-
function optionalText6(value) {
|
|
156005
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
156006
|
-
}
|
|
156007
|
-
function arrayValue2(value) {
|
|
156008
|
-
if (typeof value !== "string" || !value) return [];
|
|
156009
|
-
try {
|
|
156010
|
-
const parsed = JSON.parse(value);
|
|
156011
|
-
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
156012
|
-
} catch {
|
|
156013
|
-
return [];
|
|
156014
|
-
}
|
|
156015
|
-
}
|
|
156016
|
-
function rowToMemory(row) {
|
|
156017
|
-
return {
|
|
156018
|
-
id: row.id,
|
|
156019
|
-
originProjectId: row.originProjectId,
|
|
156020
|
-
ownerId: row.ownerId,
|
|
156021
|
-
scope: row.scope,
|
|
156022
|
-
kind: row.kind,
|
|
156023
|
-
state: row.state,
|
|
156024
|
-
portability: row.portability,
|
|
156025
|
-
title: row.title,
|
|
156026
|
-
content: row.content,
|
|
156027
|
-
facts: arrayValue2(row.factsJson),
|
|
156028
|
-
tags: arrayValue2(row.tagsJson),
|
|
156029
|
-
...optionalText6(row.applicability) ? { applicability: row.applicability } : {},
|
|
156030
|
-
origin: row.origin,
|
|
156031
|
-
createdAt: row.createdAt,
|
|
156032
|
-
updatedAt: row.updatedAt,
|
|
156033
|
-
...optionalText6(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
|
|
156034
|
-
...optionalText6(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
|
|
156035
|
-
...optionalText6(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
|
|
156036
|
-
...optionalText6(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
|
|
156037
|
-
...optionalText6(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
|
|
156038
|
-
accessCount: Number(row.accessCount ?? 0),
|
|
156039
|
-
...optionalText6(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
|
|
156040
|
-
};
|
|
156041
|
-
}
|
|
156042
|
-
function rowToEvidence2(row) {
|
|
156043
|
-
return {
|
|
156044
|
-
id: row.id,
|
|
156045
|
-
memoryId: row.memoryId,
|
|
156046
|
-
kind: row.kind,
|
|
156047
|
-
referenceId: row.referenceId,
|
|
156048
|
-
relation: row.relation,
|
|
156049
|
-
...optionalText6(row.locator) ? { locator: row.locator } : {},
|
|
156050
|
-
...optionalText6(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
|
|
156051
|
-
createdAt: row.createdAt
|
|
156052
|
-
};
|
|
156053
|
-
}
|
|
156054
|
-
function rowToEvent2(row) {
|
|
156055
|
-
return {
|
|
156056
|
-
id: row.id,
|
|
156057
|
-
memoryId: row.memoryId,
|
|
156058
|
-
kind: row.kind,
|
|
156059
|
-
...optionalText6(row.fromState) ? { fromState: row.fromState } : {},
|
|
156060
|
-
...optionalText6(row.toState) ? { toState: row.toState } : {},
|
|
156061
|
-
...optionalText6(row.detail) ? { detail: row.detail } : {},
|
|
156062
|
-
createdAt: row.createdAt
|
|
156063
|
-
};
|
|
156064
|
-
}
|
|
156065
|
-
var LongTermMemoryStore;
|
|
156066
|
-
var init_long_term_store = __esm({
|
|
156067
|
-
"src/memory/long-term-store.ts"() {
|
|
156068
|
-
"use strict";
|
|
156069
|
-
init_esm_shims();
|
|
156070
|
-
init_sqlite_db();
|
|
156071
|
-
LongTermMemoryStore = class {
|
|
156072
|
-
db = null;
|
|
156073
|
-
async init(dataDir) {
|
|
156074
|
-
this.db = getDatabase(dataDir);
|
|
156075
|
-
}
|
|
156076
|
-
transaction(fn) {
|
|
156077
|
-
return this.db.transaction(fn)();
|
|
156078
|
-
}
|
|
156079
|
-
get(id) {
|
|
156080
|
-
const row = this.db.prepare("SELECT * FROM long_term_memories WHERE id = ?").get(id);
|
|
156081
|
-
return row ? rowToMemory(row) : void 0;
|
|
156082
|
-
}
|
|
156083
|
-
list(options = {}) {
|
|
156084
|
-
const limit2 = Math.max(1, Math.min(1e3, Math.floor(options.limit ?? 500)));
|
|
156085
|
-
const clauses = [];
|
|
156086
|
-
const params = [];
|
|
156087
|
-
if (options.ownerId) {
|
|
156088
|
-
clauses.push("ownerId = ?");
|
|
156089
|
-
params.push(options.ownerId);
|
|
156090
|
-
}
|
|
156091
|
-
if (options.originProjectId) {
|
|
156092
|
-
clauses.push("originProjectId = ?");
|
|
156093
|
-
params.push(options.originProjectId);
|
|
156094
|
-
}
|
|
156095
|
-
const where = clauses.length ? " WHERE " + clauses.join(" AND ") : "";
|
|
156096
|
-
const rows = this.db.prepare(
|
|
156097
|
-
"SELECT * FROM long_term_memories" + where + " ORDER BY updatedAt DESC, id LIMIT ?"
|
|
156098
|
-
).all(...params, limit2);
|
|
156099
|
-
return rows.map(rowToMemory);
|
|
156100
|
-
}
|
|
156101
|
-
insert(memory) {
|
|
156102
|
-
this.db.prepare(`
|
|
156103
|
-
INSERT INTO long_term_memories (
|
|
156104
|
-
id, originProjectId, ownerId, scope, kind, state, portability,
|
|
156105
|
-
title, content, factsJson, tagsJson, applicability, origin,
|
|
156106
|
-
createdAt, updatedAt, qualifiedAt, approvedAt, archivedAt,
|
|
156107
|
-
supersededBy, lastValidatedAt, accessCount, lastAccessedAt
|
|
156108
|
-
) VALUES (
|
|
156109
|
-
@id, @originProjectId, @ownerId, @scope, @kind, @state, @portability,
|
|
156110
|
-
@title, @content, @factsJson, @tagsJson, @applicability, @origin,
|
|
156111
|
-
@createdAt, @updatedAt, @qualifiedAt, @approvedAt, @archivedAt,
|
|
156112
|
-
@supersededBy, @lastValidatedAt, @accessCount, @lastAccessedAt
|
|
156113
|
-
)
|
|
156114
|
-
`).run({
|
|
156115
|
-
...memory,
|
|
156116
|
-
factsJson: JSON.stringify(memory.facts),
|
|
156117
|
-
tagsJson: JSON.stringify(memory.tags),
|
|
156118
|
-
applicability: memory.applicability ?? null,
|
|
156119
|
-
qualifiedAt: memory.qualifiedAt ?? null,
|
|
156120
|
-
approvedAt: memory.approvedAt ?? null,
|
|
156121
|
-
archivedAt: memory.archivedAt ?? null,
|
|
156122
|
-
supersededBy: memory.supersededBy ?? null,
|
|
156123
|
-
lastValidatedAt: memory.lastValidatedAt ?? null,
|
|
156124
|
-
lastAccessedAt: memory.lastAccessedAt ?? null
|
|
156125
|
-
});
|
|
156126
|
-
}
|
|
156127
|
-
update(memory) {
|
|
156128
|
-
this.db.prepare(`
|
|
156129
|
-
UPDATE long_term_memories SET
|
|
156130
|
-
scope = @scope,
|
|
156131
|
-
kind = @kind,
|
|
156132
|
-
state = @state,
|
|
156133
|
-
portability = @portability,
|
|
156134
|
-
title = @title,
|
|
156135
|
-
content = @content,
|
|
156136
|
-
factsJson = @factsJson,
|
|
156137
|
-
tagsJson = @tagsJson,
|
|
156138
|
-
applicability = @applicability,
|
|
156139
|
-
updatedAt = @updatedAt,
|
|
156140
|
-
qualifiedAt = @qualifiedAt,
|
|
156141
|
-
approvedAt = @approvedAt,
|
|
156142
|
-
archivedAt = @archivedAt,
|
|
156143
|
-
supersededBy = @supersededBy,
|
|
156144
|
-
lastValidatedAt = @lastValidatedAt,
|
|
156145
|
-
accessCount = @accessCount,
|
|
156146
|
-
lastAccessedAt = @lastAccessedAt
|
|
156147
|
-
WHERE id = @id
|
|
156148
|
-
`).run({
|
|
156149
|
-
...memory,
|
|
156150
|
-
factsJson: JSON.stringify(memory.facts),
|
|
156151
|
-
tagsJson: JSON.stringify(memory.tags),
|
|
156152
|
-
applicability: memory.applicability ?? null,
|
|
156153
|
-
qualifiedAt: memory.qualifiedAt ?? null,
|
|
156154
|
-
approvedAt: memory.approvedAt ?? null,
|
|
156155
|
-
archivedAt: memory.archivedAt ?? null,
|
|
156156
|
-
supersededBy: memory.supersededBy ?? null,
|
|
156157
|
-
lastValidatedAt: memory.lastValidatedAt ?? null,
|
|
156158
|
-
lastAccessedAt: memory.lastAccessedAt ?? null
|
|
156159
|
-
});
|
|
156160
|
-
}
|
|
156161
|
-
insertEvidence(input) {
|
|
156162
|
-
const evidence = {
|
|
156163
|
-
id: randomUUID12(),
|
|
156164
|
-
...input,
|
|
156165
|
-
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
156166
|
-
};
|
|
156167
|
-
this.db.prepare(`
|
|
156168
|
-
INSERT INTO long_term_memory_evidence (
|
|
156169
|
-
id, memoryId, kind, referenceId, relation, locator, capturedHash, createdAt
|
|
156170
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
156171
|
-
`).run(
|
|
156172
|
-
evidence.id,
|
|
156173
|
-
evidence.memoryId,
|
|
156174
|
-
evidence.kind,
|
|
156175
|
-
evidence.referenceId,
|
|
156176
|
-
evidence.relation,
|
|
156177
|
-
evidence.locator ?? null,
|
|
156178
|
-
evidence.capturedHash ?? null,
|
|
156179
|
-
evidence.createdAt
|
|
156180
|
-
);
|
|
156181
|
-
return evidence;
|
|
156182
|
-
}
|
|
156183
|
-
listEvidence(memoryId) {
|
|
156184
|
-
return this.db.prepare(`
|
|
156185
|
-
SELECT * FROM long_term_memory_evidence WHERE memoryId = ? ORDER BY createdAt ASC, id
|
|
156186
|
-
`).all(memoryId).map(rowToEvidence2);
|
|
156187
|
-
}
|
|
156188
|
-
recordEvent(input) {
|
|
156189
|
-
const event = {
|
|
156190
|
-
id: randomUUID12(),
|
|
156191
|
-
...input,
|
|
156192
|
-
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
156193
|
-
};
|
|
156194
|
-
this.db.prepare(`
|
|
156195
|
-
INSERT INTO long_term_memory_events (id, memoryId, kind, fromState, toState, detail, createdAt)
|
|
156196
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
156197
|
-
`).run(
|
|
156198
|
-
event.id,
|
|
156199
|
-
event.memoryId,
|
|
156200
|
-
event.kind,
|
|
156201
|
-
event.fromState ?? null,
|
|
156202
|
-
event.toState ?? null,
|
|
156203
|
-
event.detail ?? null,
|
|
156204
|
-
event.createdAt
|
|
156205
|
-
);
|
|
156206
|
-
return event;
|
|
156207
|
-
}
|
|
156208
|
-
listEvents(memoryId) {
|
|
156209
|
-
return this.db.prepare(`
|
|
156210
|
-
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
156211
|
-
`).all(memoryId).map(rowToEvent2);
|
|
156212
|
-
}
|
|
156213
|
-
markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
156214
|
-
const unique2 = [...new Set(ids.filter(Boolean))];
|
|
156215
|
-
if (unique2.length === 0) return;
|
|
156216
|
-
const statement = this.db.prepare(`
|
|
156217
|
-
UPDATE long_term_memories
|
|
156218
|
-
SET accessCount = accessCount + 1, lastAccessedAt = ?
|
|
156219
|
-
WHERE id = ?
|
|
156220
|
-
`);
|
|
156221
|
-
this.db.transaction(() => {
|
|
156222
|
-
for (const id of unique2) statement.run(at, id);
|
|
156223
|
-
})();
|
|
156224
|
-
}
|
|
156225
|
-
};
|
|
156226
|
-
}
|
|
156227
|
-
});
|
|
156228
|
-
|
|
156229
|
-
// src/memory/long-term-types.ts
|
|
156230
|
-
var LONG_TERM_MEMORY_KINDS, LONG_TERM_MEMORY_SCOPES, LONG_TERM_MEMORY_PORTABILITIES, LONG_TERM_MEMORY_EVIDENCE_KINDS, LONG_TERM_MEMORY_EVIDENCE_RELATIONS;
|
|
156231
|
-
var init_long_term_types = __esm({
|
|
156232
|
-
"src/memory/long-term-types.ts"() {
|
|
156233
|
-
"use strict";
|
|
156234
|
-
init_esm_shims();
|
|
156235
|
-
LONG_TERM_MEMORY_KINDS = ["episodic", "semantic", "procedural"];
|
|
156236
|
-
LONG_TERM_MEMORY_SCOPES = ["project", "user", "team"];
|
|
156237
|
-
LONG_TERM_MEMORY_PORTABILITIES = ["project-bound", "portable"];
|
|
156238
|
-
LONG_TERM_MEMORY_EVIDENCE_KINDS = [
|
|
156239
|
-
"observation",
|
|
156240
|
-
"claim",
|
|
156241
|
-
"workflow",
|
|
156242
|
-
"session",
|
|
156243
|
-
"checkpoint",
|
|
156244
|
-
"git",
|
|
156245
|
-
"code",
|
|
156246
|
-
"test",
|
|
156247
|
-
"run",
|
|
156248
|
-
"document",
|
|
156249
|
-
"manual",
|
|
156250
|
-
"user"
|
|
156251
|
-
];
|
|
156252
|
-
LONG_TERM_MEMORY_EVIDENCE_RELATIONS = [
|
|
156253
|
-
"supports",
|
|
156254
|
-
"verifies",
|
|
156255
|
-
"derives",
|
|
156256
|
-
"user-confirmed"
|
|
156257
|
-
];
|
|
156258
|
-
}
|
|
156259
|
-
});
|
|
156260
|
-
|
|
156261
|
-
// src/memory/long-term.ts
|
|
156262
|
-
var long_term_exports = {};
|
|
156263
|
-
__export(long_term_exports, {
|
|
156264
|
-
approveLongTermMemory: () => approveLongTermMemory,
|
|
156265
|
-
archiveLongTermMemory: () => archiveLongTermMemory,
|
|
156266
|
-
canReadLongTermMemory: () => canReadLongTermMemory,
|
|
156267
|
-
createLongTermMemoryCandidate: () => createLongTermMemoryCandidate,
|
|
156268
|
-
createManualLongTermMemory: () => createManualLongTermMemory,
|
|
156269
|
-
getLongTermMemoryDetail: () => getLongTermMemoryDetail,
|
|
156270
|
-
isEligibleLongTermMemory: () => isEligibleLongTermMemory,
|
|
156271
|
-
listLongTermMemories: () => listLongTermMemories,
|
|
156272
|
-
promoteObservationToLongTermMemory: () => promoteObservationToLongTermMemory,
|
|
156273
|
-
qualifyLongTermMemory: () => qualifyLongTermMemory,
|
|
156274
|
-
renderLongTermMemorySummary: () => renderLongTermMemorySummary,
|
|
156275
|
-
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
156276
|
-
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
156277
|
-
});
|
|
156278
|
-
import { randomUUID as randomUUID13 } from "crypto";
|
|
156279
|
-
function isOneOf(value, values) {
|
|
156280
|
-
return typeof value === "string" && values.includes(value);
|
|
156281
|
-
}
|
|
156282
|
-
function compactText2(value, field, max = MAX_TEXT_LENGTH) {
|
|
156283
|
-
if (typeof value !== "string") throw new Error("Long-term memory " + field + " must be text.");
|
|
156284
|
-
const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
|
|
156285
|
-
if (!safe) throw new Error("Long-term memory " + field + " is required.");
|
|
156286
|
-
if (safe.length > max) throw new Error("Long-term memory " + field + " is too long.");
|
|
156287
|
-
return safe;
|
|
156288
|
-
}
|
|
156289
|
-
function compactList(values, field) {
|
|
156290
|
-
if (!values) return [];
|
|
156291
|
-
if (!Array.isArray(values)) throw new Error("Long-term memory " + field + " must be an array.");
|
|
156292
|
-
return [...new Set(values.filter((value) => typeof value === "string").map((value) => compactText2(value, field, 500)))].slice(0, MAX_LIST_ITEMS);
|
|
156293
|
-
}
|
|
156294
|
-
function normalizeEvidence(input) {
|
|
156295
|
-
if (!Array.isArray(input) || input.length === 0) {
|
|
156296
|
-
throw new Error("A long-term memory requires at least one source evidence reference.");
|
|
156297
|
-
}
|
|
156298
|
-
return input.map((evidence) => {
|
|
156299
|
-
if (!evidence || !isOneOf(evidence.kind, LONG_TERM_MEMORY_EVIDENCE_KINDS)) {
|
|
156300
|
-
throw new Error("Long-term memory evidence kind is invalid.");
|
|
156301
|
-
}
|
|
156302
|
-
if (!isOneOf(evidence.relation, LONG_TERM_MEMORY_EVIDENCE_RELATIONS)) {
|
|
156303
|
-
throw new Error("Long-term memory evidence relation is invalid.");
|
|
156304
|
-
}
|
|
156305
|
-
return {
|
|
156306
|
-
kind: evidence.kind,
|
|
156307
|
-
referenceId: compactText2(evidence.referenceId, "evidence reference", 1e3),
|
|
156308
|
-
relation: evidence.relation,
|
|
156309
|
-
...evidence.locator ? { locator: compactText2(evidence.locator, "evidence locator", 1e3) } : {},
|
|
156310
|
-
...evidence.capturedHash ? { capturedHash: compactText2(evidence.capturedHash, "evidence hash", 1e3) } : {}
|
|
156311
|
-
};
|
|
156312
|
-
});
|
|
156313
|
-
}
|
|
156314
|
-
function assertScope(scope) {
|
|
156315
|
-
if (!isOneOf(scope, LONG_TERM_MEMORY_SCOPES)) throw new Error("Long-term memory scope is invalid.");
|
|
156316
|
-
}
|
|
156317
|
-
function assertKind(kind) {
|
|
156318
|
-
if (!isOneOf(kind, LONG_TERM_MEMORY_KINDS)) throw new Error("Long-term memory kind is invalid.");
|
|
156319
|
-
}
|
|
156320
|
-
function assertPortability(value) {
|
|
156321
|
-
if (!isOneOf(value, LONG_TERM_MEMORY_PORTABILITIES)) {
|
|
156322
|
-
throw new Error("Long-term memory portability is invalid.");
|
|
156323
|
-
}
|
|
156324
|
-
}
|
|
156325
|
-
function assertPortableEvidence(scope, portability, evidence) {
|
|
156326
|
-
if (portability !== "portable") return;
|
|
156327
|
-
if (scope !== "user") {
|
|
156328
|
-
throw new Error("Only user-scoped long-term memories may be portable across projects.");
|
|
156329
|
-
}
|
|
156330
|
-
if (evidence.some((item) => !PORTABLE_EVIDENCE_KINDS.has(item.kind))) {
|
|
156331
|
-
throw new Error("Portable user memory may only use manual or user-confirmed evidence; project code, Git, observation, test, session, claim, and workflow evidence must remain project-bound.");
|
|
156332
|
-
}
|
|
156333
|
-
}
|
|
156334
|
-
function requireTeamReader(scope, reader) {
|
|
156335
|
-
if (scope === "team" && reader?.isTeamMember !== true) {
|
|
156336
|
-
throw new Error("Team long-term memory requires an explicit active team identity for this project.");
|
|
156337
|
-
}
|
|
156338
|
-
}
|
|
156339
|
-
function matchesScope(memory, reader) {
|
|
156340
|
-
if (memory.scope === "project") return memory.originProjectId === reader.projectId;
|
|
156341
|
-
if (memory.scope === "team") {
|
|
156342
|
-
return memory.originProjectId === reader.projectId && reader.isTeamMember === true;
|
|
156343
|
-
}
|
|
156344
|
-
if (!reader.ownerId || memory.ownerId !== reader.ownerId) return false;
|
|
156345
|
-
return memory.portability === "portable" || memory.originProjectId === reader.projectId;
|
|
156346
|
-
}
|
|
156347
|
-
function canReadLongTermMemory(memory, reader) {
|
|
156348
|
-
return matchesScope(memory, reader);
|
|
156349
|
-
}
|
|
156350
|
-
function isEligibleLongTermMemory(memory) {
|
|
156351
|
-
return memory.state === "qualified" || memory.state === "approved";
|
|
156352
|
-
}
|
|
156353
|
-
function taskTerms(task) {
|
|
156354
|
-
const matches = task.toLocaleLowerCase("en-US").match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
|
|
156355
|
-
return [...new Set(matches.filter((term) => term.length > 1 && !STOP_TERMS.has(term)))].slice(0, 16);
|
|
156356
|
-
}
|
|
156357
|
-
function kindFitScore(kind, task) {
|
|
156358
|
-
const normalized = task.toLocaleLowerCase("en-US");
|
|
156359
|
-
const hints = {
|
|
156360
|
-
episodic: ["resume", "continue", "handoff", "previous", "session", "\u63A5\u624B", "\u7EE7\u7EED", "\u4EA4\u63A5", "\u4E0A\u6B21", "\u4F1A\u8BDD"],
|
|
156361
|
-
semantic: ["why", "what", "architecture", "design", "decision", "reason", "\u4E3A\u4EC0\u4E48", "\u662F\u4EC0\u4E48", "\u67B6\u6784", "\u8BBE\u8BA1", "\u51B3\u7B56", "\u539F\u56E0"],
|
|
156362
|
-
procedural: ["how", "steps", "procedure", "run", "release", "publish", "verify", "implement", "\u6D41\u7A0B", "\u6B65\u9AA4", "\u53D1\u5E03", "\u9A8C\u8BC1", "\u4FEE\u590D", "\u5B9E\u73B0"]
|
|
156363
|
-
};
|
|
156364
|
-
return hints[kind].some((hint) => normalized.includes(hint)) ? 1 : 0;
|
|
156365
|
-
}
|
|
156366
|
-
function validationFreshnessScore(memory) {
|
|
156367
|
-
const validatedAt = memory.lastValidatedAt ?? memory.approvedAt ?? memory.qualifiedAt;
|
|
156368
|
-
if (!validatedAt) return 0;
|
|
156369
|
-
const time = Date.parse(validatedAt);
|
|
156370
|
-
if (!Number.isFinite(time)) return 0;
|
|
156371
|
-
const ageDays = Math.max(0, Date.now() - time) / (24 * 60 * 60 * 1e3);
|
|
156372
|
-
if (ageDays <= 30) return 0.35;
|
|
156373
|
-
if (ageDays <= 90) return 0.15;
|
|
156374
|
-
return 0;
|
|
156375
|
-
}
|
|
156376
|
-
function scoreForTask(memory, task) {
|
|
156377
|
-
const terms = taskTerms(task);
|
|
156378
|
-
if (terms.length === 0) return void 0;
|
|
156379
|
-
const title = memory.title.toLocaleLowerCase("en-US");
|
|
156380
|
-
const content = memory.content.toLocaleLowerCase("en-US");
|
|
156381
|
-
const facts = memory.facts.join(" ").toLocaleLowerCase("en-US");
|
|
156382
|
-
const tags = memory.tags.join(" ").toLocaleLowerCase("en-US");
|
|
156383
|
-
const applicability = (memory.applicability ?? "").toLocaleLowerCase("en-US");
|
|
156384
|
-
let score = memory.state === "approved" ? 0.5 : 0;
|
|
156385
|
-
const matched = [];
|
|
156386
|
-
for (const term of terms) {
|
|
156387
|
-
let termScore = 0;
|
|
156388
|
-
if (title.includes(term)) termScore += 5;
|
|
156389
|
-
if (tags.includes(term)) termScore += 4;
|
|
156390
|
-
if (applicability.includes(term)) termScore += 3;
|
|
156391
|
-
if (facts.includes(term)) termScore += 2;
|
|
156392
|
-
if (content.includes(term)) termScore += 1;
|
|
156393
|
-
if (termScore > 0) {
|
|
156394
|
-
score += termScore;
|
|
156395
|
-
matched.push(term);
|
|
156396
|
-
}
|
|
156397
|
-
}
|
|
156398
|
-
if (matched.length === 0) return void 0;
|
|
156399
|
-
score += kindFitScore(memory.kind, task);
|
|
156400
|
-
score += validationFreshnessScore(memory);
|
|
156401
|
-
const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
|
|
156402
|
-
const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
|
|
156403
|
-
return { score, reason: kindLabel + " matches " + matched.slice(0, 3).join(", ") + freshness };
|
|
156404
|
-
}
|
|
156405
|
-
function semanticText(memory) {
|
|
156406
|
-
return sanitizeCredentials([
|
|
156407
|
-
memory.title,
|
|
156408
|
-
memory.applicability,
|
|
156409
|
-
memory.tags.join(" "),
|
|
156410
|
-
memory.facts.join(" "),
|
|
156411
|
-
memory.content
|
|
156412
|
-
].filter((value) => Boolean(value)).join("\n")).replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
|
|
156413
|
-
}
|
|
156414
|
-
function cosineSimilarity(left, right) {
|
|
156415
|
-
if (left.length === 0 || left.length !== right.length) return 0;
|
|
156416
|
-
let dot = 0;
|
|
156417
|
-
let leftMagnitude = 0;
|
|
156418
|
-
let rightMagnitude = 0;
|
|
156419
|
-
for (let index = 0; index < left.length; index += 1) {
|
|
156420
|
-
const a = left[index];
|
|
156421
|
-
const b = right[index];
|
|
156422
|
-
if (!Number.isFinite(a) || !Number.isFinite(b)) return 0;
|
|
156423
|
-
dot += a * b;
|
|
156424
|
-
leftMagnitude += a * a;
|
|
156425
|
-
rightMagnitude += b * b;
|
|
156426
|
-
}
|
|
156427
|
-
if (leftMagnitude === 0 || rightMagnitude === 0) return 0;
|
|
156428
|
-
return dot / Math.sqrt(leftMagnitude * rightMagnitude);
|
|
156429
|
-
}
|
|
156430
|
-
function semanticSelection(memory, similarity, task) {
|
|
156431
|
-
if (similarity < MIN_SEMANTIC_SIMILARITY) return void 0;
|
|
156432
|
-
const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
|
|
156433
|
-
const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
|
|
156434
|
-
return {
|
|
156435
|
-
score: similarity * 10 + (memory.state === "approved" ? 0.5 : 0) + kindFitScore(memory.kind, task) + validationFreshnessScore(memory),
|
|
156436
|
-
reason: kindLabel + " semantic match " + similarity.toFixed(2) + freshness
|
|
156437
|
-
};
|
|
156438
|
-
}
|
|
156439
|
-
async function resolveSemanticProvider(explicit) {
|
|
156440
|
-
if (explicit !== void 0) return explicit;
|
|
156441
|
-
try {
|
|
156442
|
-
const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
|
|
156443
|
-
return await withTimeout(
|
|
156444
|
-
getEmbeddingProvider2({ requestTimeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS, retry: false }),
|
|
156445
|
-
SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
156446
|
-
"Long-term semantic provider initialization"
|
|
156447
|
-
);
|
|
156448
|
-
} catch {
|
|
156449
|
-
return null;
|
|
156450
|
-
}
|
|
156451
|
-
}
|
|
156452
|
-
function createStore(dataDir) {
|
|
156453
|
-
const store = new LongTermMemoryStore();
|
|
156454
|
-
return store.init(dataDir).then(() => store);
|
|
156455
|
-
}
|
|
156456
|
-
async function createManualLongTermMemory(input) {
|
|
156457
|
-
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
156458
|
-
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
156459
|
-
assertScope(input.scope);
|
|
156460
|
-
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID13(), relation: "supports" }];
|
|
156461
|
-
return createLongTermMemoryWithDataDir({
|
|
156462
|
-
dataDir: input.dataDir,
|
|
156463
|
-
originProjectId: input.projectId,
|
|
156464
|
-
ownerId: owner.id,
|
|
156465
|
-
scope: input.scope,
|
|
156466
|
-
kind: input.kind,
|
|
156467
|
-
portability: input.portability,
|
|
156468
|
-
title: input.title,
|
|
156469
|
-
content: input.content,
|
|
156470
|
-
facts: input.facts,
|
|
156471
|
-
tags: input.tags,
|
|
156472
|
-
applicability: input.applicability,
|
|
156473
|
-
origin: "manual",
|
|
156474
|
-
evidence,
|
|
156475
|
-
reader: input.reader
|
|
156476
|
-
});
|
|
156477
|
-
}
|
|
156478
|
-
async function promoteObservationToLongTermMemory(input) {
|
|
156479
|
-
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
156480
|
-
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
156481
|
-
return createLongTermMemoryWithDataDir({
|
|
156482
|
-
dataDir: input.dataDir,
|
|
156483
|
-
originProjectId: input.observation.projectId,
|
|
156484
|
-
ownerId: owner.id,
|
|
156485
|
-
scope: input.scope,
|
|
156486
|
-
kind: input.kind,
|
|
156487
|
-
portability: "project-bound",
|
|
156488
|
-
title: input.observation.title,
|
|
156489
|
-
content: input.observation.narrative,
|
|
156490
|
-
facts: input.observation.facts,
|
|
156491
|
-
tags: input.tags ?? input.observation.concepts,
|
|
156492
|
-
applicability: input.applicability,
|
|
156493
|
-
origin: input.observation.source === "git" ? "git" : "agent",
|
|
156494
|
-
evidence: [{
|
|
156495
|
-
kind: "observation",
|
|
156496
|
-
referenceId: "obs:" + input.observation.projectId + ":" + input.observation.id,
|
|
156497
|
-
relation: "derives"
|
|
156498
|
-
}],
|
|
156499
|
-
reader: input.reader
|
|
156500
|
-
});
|
|
156501
|
-
}
|
|
156502
|
-
async function createLongTermMemoryCandidate(input) {
|
|
156503
|
-
return createLongTermMemoryWithDataDir(input);
|
|
156504
|
-
}
|
|
156505
|
-
async function createLongTermMemoryWithDataDir(input) {
|
|
156506
|
-
assertScope(input.scope);
|
|
156507
|
-
assertKind(input.kind);
|
|
156508
|
-
const portability = input.portability ?? "project-bound";
|
|
156509
|
-
assertPortability(portability);
|
|
156510
|
-
requireTeamReader(input.scope, input.reader);
|
|
156511
|
-
const evidenceInputs = normalizeEvidence(input.evidence);
|
|
156512
|
-
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
156513
|
-
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
156514
|
-
const memory = {
|
|
156515
|
-
id: randomUUID13(),
|
|
156516
|
-
originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
|
|
156517
|
-
ownerId: compactText2(input.ownerId, "owner id", 160),
|
|
156518
|
-
scope: input.scope,
|
|
156519
|
-
kind: input.kind,
|
|
156520
|
-
state: "candidate",
|
|
156521
|
-
portability,
|
|
156522
|
-
title: compactText2(input.title, "title", 500),
|
|
156523
|
-
content: compactText2(input.content, "content"),
|
|
156524
|
-
facts: compactList(input.facts, "facts"),
|
|
156525
|
-
tags: compactList(input.tags, "tags"),
|
|
156526
|
-
...input.applicability ? { applicability: compactText2(input.applicability, "applicability", 1e3) } : {},
|
|
156527
|
-
origin: input.origin ?? "manual",
|
|
156528
|
-
createdAt: now3,
|
|
156529
|
-
updatedAt: now3,
|
|
156530
|
-
accessCount: 0
|
|
156531
|
-
};
|
|
156532
|
-
const store = await createStore(input.dataDir);
|
|
156533
|
-
const evidence = store.transaction(() => {
|
|
156534
|
-
store.insert(memory);
|
|
156535
|
-
const written = evidenceInputs.map((item) => store.insertEvidence({ memoryId: memory.id, ...item, createdAt: now3 }));
|
|
156536
|
-
store.recordEvent({
|
|
156537
|
-
memoryId: memory.id,
|
|
156538
|
-
kind: "created",
|
|
156539
|
-
toState: "candidate",
|
|
156540
|
-
detail: "Created as a source-backed long-term memory candidate.",
|
|
156541
|
-
createdAt: now3
|
|
156542
|
-
});
|
|
156543
|
-
return written;
|
|
156544
|
-
});
|
|
156545
|
-
return { memory, evidence };
|
|
156546
|
-
}
|
|
156547
|
-
function transitionDetail(value) {
|
|
156548
|
-
return compactText2(value, "transition reason", 1e3);
|
|
156549
|
-
}
|
|
156550
|
-
async function transitionMemory(input) {
|
|
156551
|
-
const store = await createStore(input.dataDir);
|
|
156552
|
-
return store.transaction(() => {
|
|
156553
|
-
const current = store.get(input.id);
|
|
156554
|
-
if (!current) throw new Error("Long-term memory was not found.");
|
|
156555
|
-
if (current.state !== input.expected) {
|
|
156556
|
-
throw new Error("Long-term memory must be " + input.expected + " before it can be " + input.next + ".");
|
|
156557
|
-
}
|
|
156558
|
-
const evidence = store.listEvidence(current.id);
|
|
156559
|
-
if (evidence.length === 0) throw new Error("Long-term memory cannot advance without source evidence.");
|
|
156560
|
-
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
156561
|
-
const next = {
|
|
156562
|
-
...current,
|
|
156563
|
-
state: input.next,
|
|
156564
|
-
updatedAt: now3,
|
|
156565
|
-
lastValidatedAt: now3,
|
|
156566
|
-
...input.next === "qualified" ? { qualifiedAt: now3 } : { approvedAt: now3 }
|
|
156567
|
-
};
|
|
156568
|
-
store.update(next);
|
|
156569
|
-
store.recordEvent({
|
|
156570
|
-
memoryId: next.id,
|
|
156571
|
-
kind: input.event,
|
|
156572
|
-
fromState: current.state,
|
|
156573
|
-
toState: next.state,
|
|
156574
|
-
detail: transitionDetail(input.reason),
|
|
156575
|
-
createdAt: now3
|
|
156576
|
-
});
|
|
156577
|
-
return next;
|
|
156578
|
-
});
|
|
156579
|
-
}
|
|
156580
|
-
async function qualifyLongTermMemory(input) {
|
|
156581
|
-
return transitionMemory({ ...input, expected: "candidate", next: "qualified", event: "qualified" });
|
|
156582
|
-
}
|
|
156583
|
-
async function approveLongTermMemory(input) {
|
|
156584
|
-
return transitionMemory({ ...input, expected: "qualified", next: "approved", event: "approved" });
|
|
156585
|
-
}
|
|
156586
|
-
async function archiveLongTermMemory(input) {
|
|
156587
|
-
const store = await createStore(input.dataDir);
|
|
156588
|
-
return store.transaction(() => {
|
|
156589
|
-
const current = store.get(input.id);
|
|
156590
|
-
if (!current) throw new Error("Long-term memory was not found.");
|
|
156591
|
-
if (current.state === "archived" || current.state === "superseded") {
|
|
156592
|
-
throw new Error("Long-term memory is already inactive.");
|
|
156593
|
-
}
|
|
156594
|
-
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
156595
|
-
const next = { ...current, state: "archived", archivedAt: now3, updatedAt: now3 };
|
|
156596
|
-
store.update(next);
|
|
156597
|
-
store.recordEvent({
|
|
156598
|
-
memoryId: next.id,
|
|
156599
|
-
kind: "archived",
|
|
156600
|
-
fromState: current.state,
|
|
156601
|
-
toState: "archived",
|
|
156602
|
-
detail: transitionDetail(input.reason),
|
|
156603
|
-
createdAt: now3
|
|
156604
|
-
});
|
|
156605
|
-
return next;
|
|
156606
|
-
});
|
|
156607
|
-
}
|
|
156608
|
-
async function supersedeLongTermMemory(input) {
|
|
156609
|
-
const store = await createStore(input.dataDir);
|
|
156610
|
-
return store.transaction(() => {
|
|
156611
|
-
const current = store.get(input.id);
|
|
156612
|
-
if (!current) throw new Error("Long-term memory was not found.");
|
|
156613
|
-
if (current.state === "archived" || current.state === "superseded") {
|
|
156614
|
-
throw new Error("Long-term memory is already inactive.");
|
|
156615
|
-
}
|
|
156616
|
-
if (current.id === input.supersededBy) {
|
|
156617
|
-
throw new Error("Long-term memory cannot supersede itself.");
|
|
156618
|
-
}
|
|
156619
|
-
const replacement = store.get(input.supersededBy);
|
|
156620
|
-
if (!replacement || !isEligibleLongTermMemory(replacement)) {
|
|
156621
|
-
throw new Error("Replacement long-term memory must be qualified or approved.");
|
|
156622
|
-
}
|
|
156623
|
-
if (replacement.scope !== current.scope) {
|
|
156624
|
-
throw new Error("Replacement long-term memory must use the same scope.");
|
|
156625
|
-
}
|
|
156626
|
-
if (current.scope === "user" && replacement.ownerId !== current.ownerId) {
|
|
156627
|
-
throw new Error("User long-term memory may only be superseded by the same local owner.");
|
|
156628
|
-
}
|
|
156629
|
-
if (current.scope !== "user" && replacement.originProjectId !== current.originProjectId) {
|
|
156630
|
-
throw new Error("Project and team long-term memory may only be superseded within the same project.");
|
|
156631
|
-
}
|
|
156632
|
-
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
156633
|
-
const next = {
|
|
156634
|
-
...current,
|
|
156635
|
-
state: "superseded",
|
|
156636
|
-
supersededBy: replacement.id,
|
|
156637
|
-
updatedAt: now3
|
|
156638
|
-
};
|
|
156639
|
-
store.update(next);
|
|
156640
|
-
store.recordEvent({
|
|
156641
|
-
memoryId: next.id,
|
|
156642
|
-
kind: "superseded",
|
|
156643
|
-
fromState: current.state,
|
|
156644
|
-
toState: "superseded",
|
|
156645
|
-
detail: transitionDetail(input.reason),
|
|
156646
|
-
createdAt: now3
|
|
156647
|
-
});
|
|
156648
|
-
return next;
|
|
156649
|
-
});
|
|
156650
|
-
}
|
|
156651
|
-
async function listLongTermMemories(input) {
|
|
156652
|
-
const store = await createStore(input.dataDir);
|
|
156653
|
-
return store.list({ limit: input.limit ?? 100 }).filter((memory) => canReadLongTermMemory(memory, input.reader)).filter((memory) => input.includeInactive || memory.state !== "archived" && memory.state !== "superseded").map((memory) => ({ memory, evidence: store.listEvidence(memory.id) }));
|
|
156654
|
-
}
|
|
156655
|
-
async function getLongTermMemoryDetail(input) {
|
|
156656
|
-
const store = await createStore(input.dataDir);
|
|
156657
|
-
const memory = store.get(input.id);
|
|
156658
|
-
if (!memory || !canReadLongTermMemory(memory, input.reader)) {
|
|
156659
|
-
throw new Error("Long-term memory was not found in the active scope.");
|
|
156660
|
-
}
|
|
156661
|
-
store.markAccess([memory.id]);
|
|
156662
|
-
return { memory, evidence: store.listEvidence(memory.id), events: store.listEvents(memory.id) };
|
|
156663
|
-
}
|
|
156664
|
-
async function selectLongTermMemoriesForTask(input) {
|
|
156665
|
-
const task = input.task?.trim();
|
|
156666
|
-
if (!task) return [];
|
|
156667
|
-
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: false });
|
|
156668
|
-
const reader = {
|
|
156669
|
-
projectId: input.projectId,
|
|
156670
|
-
...owner ? { ownerId: owner.id } : {},
|
|
156671
|
-
...input.agentId ? { agentId: input.agentId } : {},
|
|
156672
|
-
...input.isTeamMember ? { isTeamMember: true } : {}
|
|
156673
|
-
};
|
|
156674
|
-
const store = await createStore(input.dataDir);
|
|
156675
|
-
const eligible = store.list({ limit: 1e3 }).filter((memory) => isEligibleLongTermMemory(memory) && canReadLongTermMemory(memory, reader));
|
|
156676
|
-
let selected = eligible.map((memory) => {
|
|
156677
|
-
const ranked = scoreForTask(memory, task);
|
|
156678
|
-
return ranked ? {
|
|
156679
|
-
memory,
|
|
156680
|
-
evidence: store.listEvidence(memory.id),
|
|
156681
|
-
score: ranked.score,
|
|
156682
|
-
reason: ranked.reason
|
|
156683
|
-
} : void 0;
|
|
156684
|
-
}).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
|
|
156685
|
-
if (selected.length === 0 && eligible.length > 0) {
|
|
156686
|
-
const provider2 = await resolveSemanticProvider(input.embeddingProvider);
|
|
156687
|
-
const candidates = eligible.slice(0, MAX_SEMANTIC_CANDIDATES);
|
|
156688
|
-
if (provider2 && candidates.length > 0) {
|
|
156689
|
-
try {
|
|
156690
|
-
const vectors = await withTimeout(
|
|
156691
|
-
provider2.embedBatch([task, ...candidates.map(semanticText)], {
|
|
156692
|
-
timeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
156693
|
-
retry: false
|
|
156694
|
-
}),
|
|
156695
|
-
SEMANTIC_RETRIEVAL_TIMEOUT_MS,
|
|
156696
|
-
"Long-term semantic retrieval"
|
|
156697
|
-
);
|
|
156698
|
-
const query = vectors[0];
|
|
156699
|
-
if (Array.isArray(query)) {
|
|
156700
|
-
selected = candidates.map((memory, index) => {
|
|
156701
|
-
const vector = vectors[index + 1];
|
|
156702
|
-
const ranked = Array.isArray(vector) ? semanticSelection(memory, cosineSimilarity(query, vector), task) : void 0;
|
|
156703
|
-
return ranked ? {
|
|
156704
|
-
memory,
|
|
156705
|
-
evidence: store.listEvidence(memory.id),
|
|
156706
|
-
score: ranked.score,
|
|
156707
|
-
reason: ranked.reason
|
|
156708
|
-
} : void 0;
|
|
156709
|
-
}).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
|
|
156710
|
-
}
|
|
156711
|
-
} catch {
|
|
156712
|
-
}
|
|
156713
|
-
}
|
|
156714
|
-
}
|
|
156715
|
-
selected = selected.slice(0, Math.max(1, Math.min(input.limit ?? 3, 5)));
|
|
156716
|
-
store.markAccess(selected.map((item) => item.memory.id));
|
|
156717
|
-
return selected;
|
|
156718
|
-
}
|
|
156719
|
-
function renderLongTermMemorySummary(memory, maxTokens = 22) {
|
|
156720
|
-
const source = [memory.title, memory.applicability, memory.content].filter(Boolean).join(": ");
|
|
156721
|
-
const safe = sanitizeCredentials(source).replace(/\s+/g, " ").trim();
|
|
156722
|
-
return countTextTokens(safe) <= maxTokens ? safe : truncateToTokenBudget(safe, maxTokens);
|
|
156723
|
-
}
|
|
156724
|
-
var MAX_TEXT_LENGTH, MAX_LIST_ITEMS, MAX_SEMANTIC_CANDIDATES, SEMANTIC_RETRIEVAL_TIMEOUT_MS, MIN_SEMANTIC_SIMILARITY, PORTABLE_EVIDENCE_KINDS, STOP_TERMS;
|
|
156725
|
-
var init_long_term = __esm({
|
|
156726
|
-
"src/memory/long-term.ts"() {
|
|
156727
|
-
"use strict";
|
|
156728
|
-
init_esm_shims();
|
|
156729
|
-
init_token_budget();
|
|
156730
|
-
init_timeout();
|
|
156731
|
-
init_secret_filter();
|
|
156732
|
-
init_owner();
|
|
156733
|
-
init_long_term_store();
|
|
156734
|
-
init_long_term_types();
|
|
156735
|
-
MAX_TEXT_LENGTH = 12e3;
|
|
156736
|
-
MAX_LIST_ITEMS = 40;
|
|
156737
|
-
MAX_SEMANTIC_CANDIDATES = 48;
|
|
156738
|
-
SEMANTIC_RETRIEVAL_TIMEOUT_MS = 1800;
|
|
156739
|
-
MIN_SEMANTIC_SIMILARITY = 0.58;
|
|
156740
|
-
PORTABLE_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["manual", "user"]);
|
|
156741
|
-
STOP_TERMS = /* @__PURE__ */ new Set([
|
|
156742
|
-
"the",
|
|
156743
|
-
"and",
|
|
156744
|
-
"for",
|
|
156745
|
-
"with",
|
|
156746
|
-
"from",
|
|
156747
|
-
"that",
|
|
156748
|
-
"this",
|
|
156749
|
-
"into",
|
|
156750
|
-
"when",
|
|
156751
|
-
"what",
|
|
156752
|
-
"\u5982\u4F55",
|
|
156753
|
-
"\u4EC0\u4E48",
|
|
156754
|
-
"\u8FD9\u4E2A",
|
|
156755
|
-
"\u90A3\u4E2A",
|
|
156756
|
-
"\u6211\u4EEC",
|
|
156757
|
-
"\u9879\u76EE",
|
|
156758
|
-
"\u8FDB\u884C",
|
|
156759
|
-
"\u9700\u8981",
|
|
156760
|
-
"\u7EE7\u7EED",
|
|
156761
|
-
"\u5904\u7406"
|
|
156762
|
-
]);
|
|
156763
|
-
}
|
|
156764
|
-
});
|
|
156765
|
-
|
|
156766
156899
|
// src/knowledge/workset.ts
|
|
156767
156900
|
function unique(values) {
|
|
156768
156901
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -156970,6 +157103,37 @@ function renderTaskWorksetPrompt(input) {
|
|
|
156970
157103
|
trust: "source-backed"
|
|
156971
157104
|
});
|
|
156972
157105
|
appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
|
|
157106
|
+
if (input.alwaysOn) {
|
|
157107
|
+
const hasAlwaysOn = input.alwaysOn.profile.length > 0 || Boolean(input.alwaysOn.state) || input.alwaysOn.durable.length > 0;
|
|
157108
|
+
if (hasAlwaysOn) {
|
|
157109
|
+
appendLine(lines, "", maxTokens, omitted, "always-on-heading");
|
|
157110
|
+
appendLine(lines, "You and this workspace", maxTokens, omitted, "always-on-heading");
|
|
157111
|
+
for (const profile of input.alwaysOn.profile.slice(0, 2)) {
|
|
157112
|
+
appendLine(lines, "- " + short(profile, 26), maxTokens, omitted, "always-on-profile", selected, {
|
|
157113
|
+
kind: "memory",
|
|
157114
|
+
id: "profile",
|
|
157115
|
+
reason: "user profile memory",
|
|
157116
|
+
trust: "source-backed"
|
|
157117
|
+
});
|
|
157118
|
+
}
|
|
157119
|
+
if (input.alwaysOn.state) {
|
|
157120
|
+
appendLine(lines, "- Recently: " + short(input.alwaysOn.state, 40), maxTokens, omitted, "always-on-state", selected, {
|
|
157121
|
+
kind: "continuation",
|
|
157122
|
+
id: "workspace-state",
|
|
157123
|
+
reason: "latest session summary for this workspace",
|
|
157124
|
+
trust: "historical"
|
|
157125
|
+
});
|
|
157126
|
+
}
|
|
157127
|
+
for (const durable of input.alwaysOn.durable.slice(0, 2)) {
|
|
157128
|
+
appendLine(lines, "- " + short(durable, 28), maxTokens, omitted, "always-on-durable", selected, {
|
|
157129
|
+
kind: "durable-memory",
|
|
157130
|
+
id: "durable-always",
|
|
157131
|
+
reason: "recent durable memory for this workspace",
|
|
157132
|
+
trust: "source-backed"
|
|
157133
|
+
});
|
|
157134
|
+
}
|
|
157135
|
+
}
|
|
157136
|
+
}
|
|
156973
157137
|
const hasContinuation = Boolean(
|
|
156974
157138
|
input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0 || input.continuation?.compactCheckpoint
|
|
156975
157139
|
);
|
|
@@ -157440,6 +157604,7 @@ async function buildTaskWorkset(input) {
|
|
|
157440
157604
|
version: "1.3",
|
|
157441
157605
|
task,
|
|
157442
157606
|
lens: input.lens,
|
|
157607
|
+
...input.alwaysOn && (input.alwaysOn.profile.length > 0 || input.alwaysOn.state || input.alwaysOn.durable.length > 0) ? { alwaysOn: input.alwaysOn } : {},
|
|
157443
157608
|
currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
|
|
157444
157609
|
...continuation ? { continuation } : {},
|
|
157445
157610
|
...input.codeState ? { codeState: short(input.codeState, 28) } : {},
|
|
@@ -158592,6 +158757,33 @@ function activeProjectObservations(observations2, projectId) {
|
|
|
158592
158757
|
function deliveryEligibleProjectObservations(observations2, projectId) {
|
|
158593
158758
|
return activeProjectObservations(observations2, projectId).filter((observation) => isEligibleForAutomaticDelivery(observation));
|
|
158594
158759
|
}
|
|
158760
|
+
async function buildAlwaysOnBlock(input) {
|
|
158761
|
+
const profile = filterReadableObservations(input.eligible, input.reader).filter((observation) => observation.visibility === "personal" && observation.entityName === "user-profile").slice(0, 2).map((observation) => compactContinuationText(observation.title, 22));
|
|
158762
|
+
let state;
|
|
158763
|
+
try {
|
|
158764
|
+
await initSessionStore(input.dataDir);
|
|
158765
|
+
const { getSessionStore: getSessionStore2 } = await Promise.resolve().then(() => (init_session_store(), session_store_exports));
|
|
158766
|
+
const sessions = await getSessionStore2().loadByProject(input.projectId);
|
|
158767
|
+
const latest = sessions.filter((session) => session.endedAt && session.summary?.trim()).sort((a, b) => Date.parse(b.endedAt ?? "") - Date.parse(a.endedAt ?? ""))[0];
|
|
158768
|
+
if (latest?.summary) state = compactContinuationText(latest.summary, 40);
|
|
158769
|
+
} catch {
|
|
158770
|
+
}
|
|
158771
|
+
const durable = [];
|
|
158772
|
+
try {
|
|
158773
|
+
const items = await listLongTermMemories({
|
|
158774
|
+
dataDir: input.dataDir,
|
|
158775
|
+
reader: {
|
|
158776
|
+
projectId: input.projectId,
|
|
158777
|
+
...input.reader.agentId ? { agentId: input.reader.agentId } : {},
|
|
158778
|
+
...input.reader.isTeamMember ? { isTeamMember: true } : {}
|
|
158779
|
+
},
|
|
158780
|
+
limit: 10
|
|
158781
|
+
});
|
|
158782
|
+
durable.push(...items.filter((item) => item.memory.state === "approved").sort((a, b) => (b.memory.updatedAt ?? "").localeCompare(a.memory.updatedAt ?? "")).slice(0, 2).map((item) => item.memory.kind + ": " + compactContinuationText(item.memory.title, 22)));
|
|
158783
|
+
} catch {
|
|
158784
|
+
}
|
|
158785
|
+
return { profile, state, durable };
|
|
158786
|
+
}
|
|
158595
158787
|
function decideRefresh(input) {
|
|
158596
158788
|
if (input.mode === "never") {
|
|
158597
158789
|
return { performed: false, reason: "disabled", message: "Automatic project scan disabled." };
|
|
@@ -158796,12 +158988,19 @@ async function buildAutoProjectContext(input) {
|
|
|
158796
158988
|
};
|
|
158797
158989
|
}
|
|
158798
158990
|
}
|
|
158991
|
+
const alwaysOn = await buildAlwaysOnBlock({
|
|
158992
|
+
dataDir: input.dataDir,
|
|
158993
|
+
projectId: input.project.id,
|
|
158994
|
+
reader: input.reader ?? { projectId: input.project.id },
|
|
158995
|
+
eligible: deliveryEligibleProjectObservations(input.observations, input.project.id)
|
|
158996
|
+
});
|
|
158799
158997
|
const workset = await buildTaskWorkset({
|
|
158800
158998
|
projectId: input.project.id,
|
|
158801
158999
|
dataDir: input.dataDir,
|
|
158802
159000
|
...task ? { task } : {},
|
|
158803
159001
|
lens: lens.id,
|
|
158804
159002
|
startHere,
|
|
159003
|
+
...alwaysOn.profile.length > 0 || alwaysOn.state || alwaysOn.durable.length > 0 ? { alwaysOn } : {},
|
|
158805
159004
|
...externalOutline ? { semanticCode: externalOutline } : {},
|
|
158806
159005
|
providerQuality: providerQuality2,
|
|
158807
159006
|
currentFacts: worksetFactLines(currentFacts),
|
|
@@ -158984,7 +159183,16 @@ function formatAutoProjectContextSummary(context) {
|
|
|
158984
159183
|
lensLine(context),
|
|
158985
159184
|
"",
|
|
158986
159185
|
...formatCurrentFactsLines(context.currentFacts),
|
|
158987
|
-
""
|
|
159186
|
+
""
|
|
159187
|
+
].filter(Boolean);
|
|
159188
|
+
if (context.workset.alwaysOn && (context.workset.alwaysOn.profile.length > 0 || context.workset.alwaysOn.state || context.workset.alwaysOn.durable.length > 0)) {
|
|
159189
|
+
lines.push("You and this workspace");
|
|
159190
|
+
for (const profile of context.workset.alwaysOn.profile.slice(0, 2)) lines.push(`- ${profile}`);
|
|
159191
|
+
if (context.workset.alwaysOn.state) lines.push(`- Recently: ${context.workset.alwaysOn.state}`);
|
|
159192
|
+
for (const durable of context.workset.alwaysOn.durable.slice(0, 2)) lines.push(`- ${durable}`);
|
|
159193
|
+
lines.push("");
|
|
159194
|
+
}
|
|
159195
|
+
lines.push(...[
|
|
158988
159196
|
`- Code memory: ${context.overview.code.files} files / ${context.overview.code.symbols} symbols / ${context.overview.code.refs} memory links`,
|
|
158989
159197
|
`- Code provider: ${context.providerQuality.selected} (${context.providerQuality.selectedQuality})`,
|
|
158990
159198
|
`- Languages: ${formatLanguages(context.overview)}`,
|
|
@@ -158993,7 +159201,7 @@ function formatAutoProjectContextSummary(context) {
|
|
|
158993
159201
|
`- Refresh: ${context.refresh.message}`,
|
|
158994
159202
|
"",
|
|
158995
159203
|
"Start here"
|
|
158996
|
-
].filter(Boolean);
|
|
159204
|
+
].filter(Boolean));
|
|
158997
159205
|
if (startHere.length > 0) {
|
|
158998
159206
|
startHere.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
|
|
158999
159207
|
} else {
|
|
@@ -159117,6 +159325,8 @@ var init_auto_context = __esm({
|
|
|
159117
159325
|
init_store();
|
|
159118
159326
|
init_admission();
|
|
159119
159327
|
init_session();
|
|
159328
|
+
init_long_term();
|
|
159329
|
+
init_visibility();
|
|
159120
159330
|
init_session_store();
|
|
159121
159331
|
init_task_lens();
|
|
159122
159332
|
DEFAULT_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
@@ -162067,8 +162277,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
162067
162277
|
const { promises: fsP } = await import("fs");
|
|
162068
162278
|
const registryPath = path30.join(baseDir, ".project-aliases.json");
|
|
162069
162279
|
const raw = await fsP.readFile(registryPath, "utf-8");
|
|
162070
|
-
const
|
|
162071
|
-
aliasGroups =
|
|
162280
|
+
const registry2 = JSON.parse(raw);
|
|
162281
|
+
aliasGroups = registry2.groups || [];
|
|
162072
162282
|
} catch {
|
|
162073
162283
|
}
|
|
162074
162284
|
const currentGroup = aliasGroups.find((g) => g.aliases?.includes(effectiveProjectId) || g.canonical === effectiveProjectId);
|
|
@@ -164984,13 +165194,28 @@ alwaysApply: true
|
|
|
164984
165194
|
'- For "why" decisions, use `memorix_store_reasoning`',
|
|
164985
165195
|
'- For a stable fact, reusable procedure, or completed episode that merits deliberate long-term review, include `longTerm` in `memorix_store` with the appropriate kind and normally `scope: "project"`. It creates a candidate only: do not use it for routine updates, do not make project-derived evidence portable user memory, and do not assume it enters context until an operator qualifies and approves it through `memorix memory long-term`.',
|
|
164986
165196
|
"- A `user` + `portable` durable memory delivered in a task brief is intentionally available across projects. When it matches the task, use it as reusable background even if its origin differs; do not treat it as a current-project fact. Expand it only when needed with `memorix_detail` using its `durable:<id>` reference and a specific purpose.",
|
|
165197
|
+
'- Record the user profile: the user\u2019s role, expertise, preferences, and goals. Save these with `entityName: "user-profile"` and `visibility: "personal"` so they stay private and appear in every brief as the "who you are" context.',
|
|
164987
165198
|
"",
|
|
164988
165199
|
"**Don't store:** greetings, simple file reads, trivial commands (ls, pwd, git status).",
|
|
164989
165200
|
"",
|
|
165201
|
+
"**Only store what a future session cannot re-derive.** Code structure, file contents, and Git history are live in the checkout \u2014 do not store facts already visible there. A memory earns its place by capturing the why, the context, or a conclusion the checkout alone cannot show.",
|
|
165202
|
+
"",
|
|
165203
|
+
`**Record what worked, not only what failed.** Store validated approaches and explicit user confirmations alongside corrections. Saving only failures drifts behavior away from what the user already accepted; a clear "yes, that's right" is feedback worth keeping too.`,
|
|
165204
|
+
"",
|
|
165205
|
+
"**Recalled memory is a claim about the past.** A memory naming a specific file, function, or flag describes the past at write time \u2014 check the file exists or grep the symbol before recommending it. If the user says to ignore or not use memory, proceed as if memory were empty: do not apply, cite, compare, or mention stored content.",
|
|
165206
|
+
"",
|
|
164990
165207
|
"## When to resolve memory",
|
|
164991
165208
|
"",
|
|
164992
165209
|
"Use `memorix_resolve` when a task is done or a bug is fixed. This keeps future searches focused on active work instead of surfacing completed items.",
|
|
164993
165210
|
"",
|
|
165211
|
+
"## End sessions with a summary",
|
|
165212
|
+
"",
|
|
165213
|
+
"When a session finishes, call `memorix_session_end` with a short structured summary so the next agent can resume. Recommended sections:",
|
|
165214
|
+
"- **Goal** \u2014 what this session was working on",
|
|
165215
|
+
"- **Discoveries** \u2014 findings, gotchas, learnings",
|
|
165216
|
+
"- **Accomplished** \u2014 completed items, plus PENDING items for the next session",
|
|
165217
|
+
"- **Relevant Files** \u2014 paths and what changed",
|
|
165218
|
+
"",
|
|
164994
165219
|
"## Tools quick reference",
|
|
164995
165220
|
"",
|
|
164996
165221
|
"| Tool | Use when |",
|
|
@@ -165541,6 +165766,12 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
|
|
|
165541
165766
|
kind: "consolidation",
|
|
165542
165767
|
dedupeKey: "startup-consolidation"
|
|
165543
165768
|
});
|
|
165769
|
+
lifecycle.enqueueLongTermMaintenance({
|
|
165770
|
+
dataDir: projectDir2,
|
|
165771
|
+
projectId: project.id,
|
|
165772
|
+
source: "startup",
|
|
165773
|
+
queue
|
|
165774
|
+
});
|
|
165544
165775
|
}
|
|
165545
165776
|
try {
|
|
165546
165777
|
const { CodeGraphStore: CodeGraphStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
@@ -165590,7 +165821,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
165590
165821
|
};
|
|
165591
165822
|
const server = existingServer ?? new McpServer({
|
|
165592
165823
|
name: "memorix",
|
|
165593
|
-
version: true ? "1.4.
|
|
165824
|
+
version: true ? "1.4.6" : "1.0.1"
|
|
165594
165825
|
});
|
|
165595
165826
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
165596
165827
|
server.registerTool = ((name, ...args) => {
|
|
@@ -166075,7 +166306,7 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
|
|
|
166075
166306
|
let longTermNote = "";
|
|
166076
166307
|
if (longTerm) {
|
|
166077
166308
|
try {
|
|
166078
|
-
const { promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
|
|
166309
|
+
const { promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2, maybeAutoQualifyLongTermMemory: maybeAutoQualifyLongTermMemory2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
|
|
166079
166310
|
const promoted = await promoteObservationToLongTermMemory2({
|
|
166080
166311
|
dataDir: projectDir2,
|
|
166081
166312
|
observation: obs,
|
|
@@ -166089,7 +166320,24 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
|
|
|
166089
166320
|
...reader.isTeamMember ? { isTeamMember: true } : {}
|
|
166090
166321
|
}
|
|
166091
166322
|
});
|
|
166092
|
-
|
|
166323
|
+
const autoQualified = await maybeAutoQualifyLongTermMemory2({
|
|
166324
|
+
dataDir: projectDir2,
|
|
166325
|
+
id: promoted.memory.id,
|
|
166326
|
+
sourceDetail: "explicit"
|
|
166327
|
+
});
|
|
166328
|
+
if (autoQualified) {
|
|
166329
|
+
try {
|
|
166330
|
+
const { enqueueLongTermMaintenance: enqueueLongTermMaintenance2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
|
|
166331
|
+
enqueueLongTermMaintenance2({
|
|
166332
|
+
dataDir: projectDir2,
|
|
166333
|
+
projectId: project.id,
|
|
166334
|
+
source: "long-term:" + promoted.memory.id
|
|
166335
|
+
});
|
|
166336
|
+
} catch {
|
|
166337
|
+
}
|
|
166338
|
+
}
|
|
166339
|
+
longTermNote = autoQualified ? `
|
|
166340
|
+
Long-term memory: ${promoted.memory.id} (${promoted.memory.kind}/${promoted.memory.scope}, auto-qualified) and now enters briefs as durable context. Audit with \`memorix memory long-term list\`.` : `
|
|
166093
166341
|
Long-term candidate: ${promoted.memory.id} (${promoted.memory.kind}/${promoted.memory.scope}). Review it with the CLI before it is delivered automatically.`;
|
|
166094
166342
|
} catch (longTermError) {
|
|
166095
166343
|
longTermNote = `
|
|
@@ -166285,6 +166533,13 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
166285
166533
|
const boundary = requireExplicitAutopilotExpansion("memorix_search", purpose);
|
|
166286
166534
|
if (boundary) return boundary;
|
|
166287
166535
|
}
|
|
166536
|
+
let surfacedKey = `project:${project.id}`;
|
|
166537
|
+
try {
|
|
166538
|
+
const { getActiveSession: getActiveSession2 } = await Promise.resolve().then(() => (init_session(), session_exports));
|
|
166539
|
+
const active = await getActiveSession2(projectDir2, project.id);
|
|
166540
|
+
if (active) surfacedKey = `session:${active.id}`;
|
|
166541
|
+
} catch {
|
|
166542
|
+
}
|
|
166288
166543
|
return withFreshIndex(async () => {
|
|
166289
166544
|
const safeLimit2 = limit2 != null ? coerceNumber(limit2, 20) : void 0;
|
|
166290
166545
|
const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : void 0;
|
|
@@ -166302,7 +166557,8 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
166302
166557
|
status: status ?? "active",
|
|
166303
166558
|
source,
|
|
166304
166559
|
quality,
|
|
166305
|
-
reader: getObservationReader(scope === "global" ? "global" : "project")
|
|
166560
|
+
reader: getObservationReader(scope === "global" ? "global" : "project"),
|
|
166561
|
+
surfacedIds: getSurfacedIds(surfacedKey)
|
|
166306
166562
|
});
|
|
166307
166563
|
let result;
|
|
166308
166564
|
try {
|
|
@@ -166321,6 +166577,7 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
166321
166577
|
}
|
|
166322
166578
|
throw error;
|
|
166323
166579
|
}
|
|
166580
|
+
recordSurfacedIds(surfacedKey, result.entries.map((entry) => entry.id));
|
|
166324
166581
|
const activeBoundary = getActiveAutopilotRetrievalBoundary();
|
|
166325
166582
|
if (scope !== "global" && activeBoundary && !force && result.entries.length > 0 && result.entries.every((entry) => activeBoundary.coveredObservationIds.has(entry.id))) {
|
|
166326
166583
|
const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
|
|
@@ -169283,13 +169540,26 @@ ${lines.join("\n")}` }] };
|
|
|
169283
169540
|
if (bytes.length >= 12 && Buffer.from(bytes.subarray(0, 4)).toString("ascii") === "RIFF" && Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP") return "image/webp";
|
|
169284
169541
|
return void 0;
|
|
169285
169542
|
}
|
|
169543
|
+
const mediaGenerationEnabled = process.env.MEMORIX_MCP_MEDIA_GENERATION === "1";
|
|
169544
|
+
const mediaTranscriptionEnabled = process.env.MEMORIX_MCP_MEDIA_TRANSCRIPTION === "1";
|
|
169545
|
+
const mediaGenerationOrTranscription = mediaGenerationEnabled || mediaTranscriptionEnabled;
|
|
169286
169546
|
server.registerTool(
|
|
169287
169547
|
"memorix_media",
|
|
169288
169548
|
{
|
|
169289
169549
|
title: "Manage Controlled Media",
|
|
169290
169550
|
description: "Use the controlled local media library for an explicit import, attachment, inspection, or MiniMax generation request. Assets stay outside the Git worktree and enter normal memory only when attach is explicitly true. Use the CLI for destructive removal, quota cleanup, and direct generation. MCP generation is disabled by default and requires MEMORIX_MCP_MEDIA_GENERATION=1 after the operator reviews provider billing.",
|
|
169291
169551
|
inputSchema: {
|
|
169292
|
-
action: z626.enum([
|
|
169552
|
+
action: z626.enum([
|
|
169553
|
+
"import",
|
|
169554
|
+
"attach",
|
|
169555
|
+
"list",
|
|
169556
|
+
"show",
|
|
169557
|
+
"derive-pdf",
|
|
169558
|
+
"status",
|
|
169559
|
+
"cancel",
|
|
169560
|
+
...mediaTranscriptionEnabled ? ["derive-audio"] : [],
|
|
169561
|
+
...mediaGenerationEnabled ? ["generate-image", "generate-video"] : []
|
|
169562
|
+
]),
|
|
169293
169563
|
path: z626.string().optional().describe("Explicit local image/audio/video/PDF path for import."),
|
|
169294
169564
|
assetId: z626.string().optional().describe("Controlled MediaAsset ID for attach/show."),
|
|
169295
169565
|
jobId: z626.string().optional().describe("Durable media job ID for status."),
|
|
@@ -169297,20 +169567,26 @@ ${lines.join("\n")}` }] };
|
|
|
169297
169567
|
limit: z626.number().int().min(1).max(100).optional().describe("Maximum assets to list."),
|
|
169298
169568
|
title: z626.string().optional().describe("Observation title when attaching generated/imported output."),
|
|
169299
169569
|
narrative: z626.string().optional().describe("Short retrieval text when attaching an asset."),
|
|
169300
|
-
prompt: z626.string().optional().describe("Explicit MiniMax generation prompt."),
|
|
169301
|
-
image: z626.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
|
|
169302
|
-
model: z626.string().max(160).optional().describe("Provider model for the selected media action."),
|
|
169303
|
-
provider: z626.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
|
|
169304
|
-
language: z626.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription."),
|
|
169305
|
-
region: z626.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
|
|
169306
|
-
n: z626.number().int().min(1).max(4).optional().describe("Image output count."),
|
|
169307
|
-
ratio: z626.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
|
|
169308
|
-
width: z626.number().int().min(1).max(8192).optional().describe("Requested image width."),
|
|
169309
|
-
height: z626.number().int().min(1).max(8192).optional().describe("Requested image height."),
|
|
169310
|
-
duration: z626.union([z626.literal(5), z626.literal(10)]).optional().describe("MiniMax video duration in seconds."),
|
|
169311
169570
|
maxPages: z626.number().int().min(1).max(100).optional().describe("Bounded PDF extraction page limit."),
|
|
169312
169571
|
maxChars: z626.number().int().min(1).max(6e4).optional().describe("Bounded PDF extraction character limit."),
|
|
169313
|
-
attach: z626.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly.")
|
|
169572
|
+
attach: z626.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly."),
|
|
169573
|
+
...mediaGenerationOrTranscription ? {
|
|
169574
|
+
model: z626.string().max(160).optional().describe("Provider model for the selected media action."),
|
|
169575
|
+
prompt: z626.string().optional().describe("Explicit prompt for generation or transcription.")
|
|
169576
|
+
} : {},
|
|
169577
|
+
...mediaTranscriptionEnabled ? {
|
|
169578
|
+
provider: z626.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
|
|
169579
|
+
language: z626.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription.")
|
|
169580
|
+
} : {},
|
|
169581
|
+
...mediaGenerationEnabled ? {
|
|
169582
|
+
image: z626.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
|
|
169583
|
+
region: z626.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
|
|
169584
|
+
n: z626.number().int().min(1).max(4).optional().describe("Image output count."),
|
|
169585
|
+
ratio: z626.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
|
|
169586
|
+
width: z626.number().int().min(1).max(8192).optional().describe("Requested image width."),
|
|
169587
|
+
height: z626.number().int().min(1).max(8192).optional().describe("Requested image height."),
|
|
169588
|
+
duration: z626.union([z626.literal(5), z626.literal(10)]).optional().describe("MiniMax video duration in seconds.")
|
|
169589
|
+
} : {}
|
|
169314
169590
|
}
|
|
169315
169591
|
},
|
|
169316
169592
|
async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
|
|
@@ -169794,6 +170070,7 @@ var init_server2 = __esm({
|
|
|
169794
170070
|
init_formation_timeout();
|
|
169795
170071
|
init_timeout();
|
|
169796
170072
|
init_secret_filter();
|
|
170073
|
+
init_surfaced_registry();
|
|
169797
170074
|
init_request_context();
|
|
169798
170075
|
FORMATION_TIMEOUT_MS = parseFormationTimeoutMs(process.env.MEMORIX_FORMATION_TIMEOUT_MS);
|
|
169799
170076
|
COMPACT_ON_WRITE_TIMEOUT_MS = 12e3;
|
|
@@ -169923,7 +170200,7 @@ var init_serve_shared = __esm({
|
|
|
169923
170200
|
|
|
169924
170201
|
// src/cli/version.ts
|
|
169925
170202
|
function getCliVersion() {
|
|
169926
|
-
return true ? "1.4.
|
|
170203
|
+
return true ? "1.4.6" : pkg.version;
|
|
169927
170204
|
}
|
|
169928
170205
|
var init_version3 = __esm({
|
|
169929
170206
|
"src/cli/version.ts"() {
|