memorix 1.7.2 → 1.8.0
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 +59 -1
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/assets/star-history-dark.svg +4 -4
- package/assets/star-history-light.svg +4 -4
- package/assets/star-history.json +47 -3
- package/dist/cli/index.js +1801 -254
- package/dist/dashboard/static/app.js +88 -4
- package/dist/dashboard/static/index.html +10 -0
- package/dist/dashboard/static/style.css +86 -0
- package/dist/index.js +1241 -224
- package/dist/maintenance-runner.js +972 -126
- package/dist/media-audio-runner.js +967 -121
- package/dist/media-video-runner.js +972 -126
- package/dist/memcode-runtime/CHANGELOG.md +59 -1
- package/dist/sdk.js +1240 -223
- package/dist/types.d.ts +8 -0
- package/dist/vector-backfill-runner.js +972 -126
- package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
- package/docs/1.8.0-RELEASE-CANDIDATE-SPEC.md +75 -0
- package/docs/API_REFERENCE.md +37 -1
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/CONFIGURATION.md +57 -1
- package/docs/DASHBOARD.md +10 -0
- package/docs/DEVELOPMENT.md +3 -2
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/PERFORMANCE.md +3 -1
- package/docs/README.md +11 -1
- package/docs/SETUP.md +2 -1
- package/package.json +1 -1
- package/plugins/antigravity/memorix/rules/memorix.md +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/memorix/SKILL.md +1 -1
- package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +2 -2
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/skills/memorix-memory/SKILL.md +2 -2
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +2 -2
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +2 -2
- package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +2 -2
- package/plugins/gemini/memorix/GEMINI.md +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +2 -2
- package/server.json +2 -2
- package/src/cli/capability-map.ts +2 -0
- package/src/cli/commands/config-migrate.ts +7 -0
- package/src/cli/commands/context.ts +11 -0
- package/src/cli/commands/doctor.ts +5 -1
- package/src/cli/commands/evidence.ts +56 -0
- package/src/cli/commands/feedback.ts +58 -0
- package/src/cli/commands/init.ts +17 -0
- package/src/cli/commands/resume.ts +2 -0
- package/src/cli/commands/serve-http.ts +201 -12
- package/src/cli/commands/status.ts +2 -0
- package/src/cli/fallback-budget.ts +59 -0
- package/src/cli/index.ts +5 -1
- package/src/compact/engine.ts +26 -1
- package/src/config/dotenv-loader.ts +17 -0
- package/src/config/resolved-config.ts +110 -12
- package/src/config/toml-loader.ts +8 -0
- package/src/config/yaml-loader.ts +9 -0
- package/src/dashboard/config-provenance.ts +17 -0
- package/src/dashboard/evidence.ts +63 -0
- package/src/dashboard/server.ts +93 -68
- package/src/dashboard/static/index.html +10 -0
- package/src/dashboard/static/style.css +86 -0
- package/src/hooks/installers/index.ts +1 -1
- package/src/hooks/official-skills.ts +3 -3
- package/src/hooks/rules/memorix-agent-rules.md +1 -1
- package/src/llm/provider.ts +33 -7
- package/src/memory/feedback-model.ts +4 -0
- package/src/memory/feedback.ts +220 -0
- package/src/memory/observations.ts +19 -0
- package/src/memory/retention.ts +38 -5
- package/src/multimodal/image-loader.ts +6 -3
- package/src/rerank/http-provider.ts +125 -0
- package/src/rerank/index.ts +81 -0
- package/src/rerank/policy.ts +88 -0
- package/src/server/mcp-binding-store.ts +79 -0
- package/src/server/mcp-diagnostics.ts +40 -0
- package/src/server/tool-profile.ts +4 -0
- package/src/server.ts +121 -1
- package/src/store/evidence-store.ts +261 -0
- package/src/store/orama-store.ts +79 -53
- package/src/store/sqlite-db.ts +104 -0
- package/src/types.ts +8 -0
package/dist/index.js
CHANGED
|
@@ -402,7 +402,7 @@ function closeAllDatabases() {
|
|
|
402
402
|
_dbCache.delete(key);
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
|
-
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
405
|
+
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
406
406
|
var init_sqlite_db = __esm({
|
|
407
407
|
"src/store/sqlite-db.ts"() {
|
|
408
408
|
"use strict";
|
|
@@ -1048,6 +1048,79 @@ CREATE TABLE IF NOT EXISTS compaction_checkpoints (
|
|
|
1048
1048
|
created_at TEXT NOT NULL,
|
|
1049
1049
|
updated_at TEXT NOT NULL
|
|
1050
1050
|
);
|
|
1051
|
+
`;
|
|
1052
|
+
CREATE_EVIDENCE_CARDS_TABLE = `
|
|
1053
|
+
CREATE TABLE IF NOT EXISTS evidence_cards (
|
|
1054
|
+
id TEXT PRIMARY KEY,
|
|
1055
|
+
project_id TEXT NOT NULL,
|
|
1056
|
+
candidate_kind TEXT NOT NULL,
|
|
1057
|
+
candidate_id TEXT NOT NULL,
|
|
1058
|
+
title TEXT NOT NULL,
|
|
1059
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
1060
|
+
entity_name TEXT,
|
|
1061
|
+
source_kind TEXT NOT NULL,
|
|
1062
|
+
source_ref TEXT NOT NULL,
|
|
1063
|
+
locator TEXT,
|
|
1064
|
+
captured_hash TEXT,
|
|
1065
|
+
session_id TEXT,
|
|
1066
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
1067
|
+
verification TEXT NOT NULL DEFAULT 'unverified',
|
|
1068
|
+
freshness TEXT NOT NULL DEFAULT 'current',
|
|
1069
|
+
stale_reason TEXT,
|
|
1070
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
1071
|
+
related_entities_json TEXT NOT NULL DEFAULT '[]',
|
|
1072
|
+
created_at TEXT NOT NULL,
|
|
1073
|
+
updated_at TEXT NOT NULL,
|
|
1074
|
+
UNIQUE(project_id, candidate_kind, candidate_id)
|
|
1075
|
+
);
|
|
1076
|
+
`;
|
|
1077
|
+
CREATE_EVIDENCE_CARD_EVENTS_TABLE = `
|
|
1078
|
+
CREATE TABLE IF NOT EXISTS evidence_card_events (
|
|
1079
|
+
id TEXT PRIMARY KEY,
|
|
1080
|
+
project_id TEXT NOT NULL,
|
|
1081
|
+
card_id TEXT NOT NULL,
|
|
1082
|
+
kind TEXT NOT NULL,
|
|
1083
|
+
detail TEXT,
|
|
1084
|
+
created_at TEXT NOT NULL,
|
|
1085
|
+
FOREIGN KEY (card_id) REFERENCES evidence_cards(id) ON DELETE CASCADE
|
|
1086
|
+
);
|
|
1087
|
+
`;
|
|
1088
|
+
CREATE_MEMORY_FEEDBACK_STATES_TABLE = `
|
|
1089
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_states (
|
|
1090
|
+
project_id TEXT NOT NULL,
|
|
1091
|
+
candidate_kind TEXT NOT NULL,
|
|
1092
|
+
candidate_id TEXT NOT NULL,
|
|
1093
|
+
weight REAL NOT NULL DEFAULT 1.0,
|
|
1094
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'active',
|
|
1095
|
+
updated_at TEXT NOT NULL,
|
|
1096
|
+
PRIMARY KEY (project_id, candidate_kind, candidate_id)
|
|
1097
|
+
);
|
|
1098
|
+
`;
|
|
1099
|
+
CREATE_MEMORY_FEEDBACK_EVENTS_TABLE = `
|
|
1100
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
1101
|
+
id TEXT PRIMARY KEY,
|
|
1102
|
+
project_id TEXT NOT NULL,
|
|
1103
|
+
candidate_kind TEXT NOT NULL,
|
|
1104
|
+
candidate_id TEXT NOT NULL,
|
|
1105
|
+
signal TEXT NOT NULL,
|
|
1106
|
+
actor TEXT,
|
|
1107
|
+
note TEXT,
|
|
1108
|
+
source_ref TEXT NOT NULL,
|
|
1109
|
+
target_event_id TEXT,
|
|
1110
|
+
delta REAL NOT NULL DEFAULT 0,
|
|
1111
|
+
observed_at TEXT NOT NULL
|
|
1112
|
+
);
|
|
1113
|
+
`;
|
|
1114
|
+
CREATE_MCP_BINDINGS_TABLE = `
|
|
1115
|
+
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
1116
|
+
handle_id TEXT PRIMARY KEY,
|
|
1117
|
+
project_id TEXT NOT NULL,
|
|
1118
|
+
project_root TEXT NOT NULL,
|
|
1119
|
+
data_dir TEXT NOT NULL,
|
|
1120
|
+
created_at TEXT NOT NULL,
|
|
1121
|
+
last_used_at TEXT NOT NULL,
|
|
1122
|
+
expires_at TEXT
|
|
1123
|
+
);
|
|
1051
1124
|
`;
|
|
1052
1125
|
CREATE_INDEXES = `
|
|
1053
1126
|
CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
|
|
@@ -1110,6 +1183,12 @@ CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_target
|
|
|
1110
1183
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
|
|
1111
1184
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
|
|
1112
1185
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
|
|
1186
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC);
|
|
1187
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id);
|
|
1188
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1189
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1190
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1191
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1113
1192
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1114
1193
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1115
1194
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1265,6 +1344,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1265
1344
|
}
|
|
1266
1345
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_media_jobs_source_asset ON media_jobs(project_id, source_asset_id, status)");
|
|
1267
1346
|
}
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
id: "1.8-context-control-plane",
|
|
1350
|
+
apply: (db2) => {
|
|
1351
|
+
db2.exec(CREATE_EVIDENCE_CARDS_TABLE);
|
|
1352
|
+
db2.exec(CREATE_EVIDENCE_CARD_EVENTS_TABLE);
|
|
1353
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_STATES_TABLE);
|
|
1354
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_EVENTS_TABLE);
|
|
1355
|
+
db2.exec(CREATE_MCP_BINDINGS_TABLE);
|
|
1356
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC)");
|
|
1357
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id)");
|
|
1358
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at)");
|
|
1359
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1360
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC)");
|
|
1361
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1362
|
+
}
|
|
1268
1363
|
}
|
|
1269
1364
|
];
|
|
1270
1365
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -2793,6 +2888,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
2793
2888
|
llm: { ...userConfig.llm, ...projectConfig.llm },
|
|
2794
2889
|
agent: { ...userConfig.agent, ...projectConfig.agent },
|
|
2795
2890
|
embedding: { ...userConfig.embedding, ...projectConfig.embedding },
|
|
2891
|
+
rerank: { ...userConfig.rerank, ...projectConfig.rerank },
|
|
2796
2892
|
git: { ...userConfig.git, ...projectConfig.git },
|
|
2797
2893
|
codegraph: { ...userConfig.codegraph, ...projectConfig.codegraph },
|
|
2798
2894
|
behavior: { ...userConfig.behavior, ...projectConfig.behavior },
|
|
@@ -3068,6 +3164,7 @@ function mergeTomlConfig(base, override) {
|
|
|
3068
3164
|
llm: { ...base.memory?.llm, ...override.memory?.llm }
|
|
3069
3165
|
},
|
|
3070
3166
|
embedding: { ...base.embedding, ...override.embedding },
|
|
3167
|
+
rerank: { ...base.rerank, ...override.rerank },
|
|
3071
3168
|
hooks: { ...base.hooks, ...override.hooks },
|
|
3072
3169
|
git: { ...base.git, ...override.git },
|
|
3073
3170
|
codegraph: { ...base.codegraph, ...override.codegraph },
|
|
@@ -3160,6 +3257,8 @@ var init_toml_loader = __esm({
|
|
|
3160
3257
|
var dotenv_loader_exports = {};
|
|
3161
3258
|
__export(dotenv_loader_exports, {
|
|
3162
3259
|
getLoadedEnvFiles: () => getLoadedEnvFiles,
|
|
3260
|
+
getLoadedEnvKeys: () => getLoadedEnvKeys,
|
|
3261
|
+
getLoadedEnvValue: () => getLoadedEnvValue,
|
|
3163
3262
|
loadDotenv: () => loadDotenv,
|
|
3164
3263
|
resetDotenv: () => resetDotenv
|
|
3165
3264
|
});
|
|
@@ -3171,6 +3270,8 @@ function loadEnvFile(filePath) {
|
|
|
3171
3270
|
const parsed = parse(readFileSync6(filePath, "utf-8"));
|
|
3172
3271
|
for (const [key, value] of Object.entries(parsed)) {
|
|
3173
3272
|
if (!(key in process.env)) {
|
|
3273
|
+
loadedEnvKeys.add(key);
|
|
3274
|
+
loadedEnvValues.set(key, value);
|
|
3174
3275
|
process.env[key] = value;
|
|
3175
3276
|
injectedKeys.add(key);
|
|
3176
3277
|
}
|
|
@@ -3183,6 +3284,8 @@ function loadDotenv(projectRoot, options = {}) {
|
|
|
3183
3284
|
resetDotenv();
|
|
3184
3285
|
}
|
|
3185
3286
|
loadedEnvFiles.length = 0;
|
|
3287
|
+
loadedEnvKeys.clear();
|
|
3288
|
+
loadedEnvValues.clear();
|
|
3186
3289
|
if (projectRoot) {
|
|
3187
3290
|
loadEnvFile(getProjectDotenvPath(projectRoot));
|
|
3188
3291
|
}
|
|
@@ -3198,11 +3301,18 @@ function resetDotenv() {
|
|
|
3198
3301
|
dotenvLoaded = false;
|
|
3199
3302
|
dotenvProjectRoot = null;
|
|
3200
3303
|
loadedEnvFiles.length = 0;
|
|
3304
|
+
loadedEnvKeys.clear();
|
|
3201
3305
|
}
|
|
3202
3306
|
function getLoadedEnvFiles() {
|
|
3203
3307
|
return loadedEnvFiles;
|
|
3204
3308
|
}
|
|
3205
|
-
|
|
3309
|
+
function getLoadedEnvKeys() {
|
|
3310
|
+
return loadedEnvKeys;
|
|
3311
|
+
}
|
|
3312
|
+
function getLoadedEnvValue(key) {
|
|
3313
|
+
return loadedEnvValues.get(key);
|
|
3314
|
+
}
|
|
3315
|
+
var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
|
|
3206
3316
|
var init_dotenv_loader = __esm({
|
|
3207
3317
|
"src/config/dotenv-loader.ts"() {
|
|
3208
3318
|
"use strict";
|
|
@@ -3211,6 +3321,8 @@ var init_dotenv_loader = __esm({
|
|
|
3211
3321
|
dotenvLoaded = false;
|
|
3212
3322
|
dotenvProjectRoot = null;
|
|
3213
3323
|
loadedEnvFiles = [];
|
|
3324
|
+
loadedEnvKeys = /* @__PURE__ */ new Set();
|
|
3325
|
+
loadedEnvValues = /* @__PURE__ */ new Map();
|
|
3214
3326
|
injectedKeys = /* @__PURE__ */ new Set();
|
|
3215
3327
|
}
|
|
3216
3328
|
});
|
|
@@ -3223,6 +3335,7 @@ __export(resolved_config_exports, {
|
|
|
3223
3335
|
getResolvedConfigForCwd: () => getResolvedConfigForCwd,
|
|
3224
3336
|
getResolvedEmbeddingLane: () => getResolvedEmbeddingLane,
|
|
3225
3337
|
getResolvedMemoryLane: () => getResolvedMemoryLane,
|
|
3338
|
+
getResolvedRerankLane: () => getResolvedRerankLane,
|
|
3226
3339
|
resetResolvedConfigCache: () => resetResolvedConfigCache
|
|
3227
3340
|
});
|
|
3228
3341
|
import { homedir as homedir5 } from "os";
|
|
@@ -3255,6 +3368,16 @@ function getResolvedConfig(options = {}) {
|
|
|
3255
3368
|
legacy.llm?.baseUrl
|
|
3256
3369
|
);
|
|
3257
3370
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
3371
|
+
const memoryLlmApiKey = first(
|
|
3372
|
+
process.env.MEMORIX_LLM_API_KEY,
|
|
3373
|
+
process.env.MEMORIX_API_KEY,
|
|
3374
|
+
toml.memory?.llm?.api_key,
|
|
3375
|
+
yaml.llm?.apiKey,
|
|
3376
|
+
legacy.llm?.apiKey,
|
|
3377
|
+
process.env.OPENAI_API_KEY,
|
|
3378
|
+
process.env.ANTHROPIC_API_KEY,
|
|
3379
|
+
openRouterMemoryLlmApiKey
|
|
3380
|
+
);
|
|
3258
3381
|
const resolved = {
|
|
3259
3382
|
agent: {
|
|
3260
3383
|
provider: first(
|
|
@@ -3295,16 +3418,7 @@ function getResolvedConfig(options = {}) {
|
|
|
3295
3418
|
provider: memoryLlmProvider,
|
|
3296
3419
|
model: memoryLlmModel,
|
|
3297
3420
|
baseUrl: memoryLlmBaseUrl,
|
|
3298
|
-
apiKey:
|
|
3299
|
-
process.env.MEMORIX_LLM_API_KEY,
|
|
3300
|
-
process.env.MEMORIX_API_KEY,
|
|
3301
|
-
toml.memory?.llm?.api_key,
|
|
3302
|
-
yaml.llm?.apiKey,
|
|
3303
|
-
legacy.llm?.apiKey,
|
|
3304
|
-
process.env.OPENAI_API_KEY,
|
|
3305
|
-
process.env.ANTHROPIC_API_KEY,
|
|
3306
|
-
openRouterMemoryLlmApiKey
|
|
3307
|
-
)
|
|
3421
|
+
apiKey: memoryLlmApiKey
|
|
3308
3422
|
}
|
|
3309
3423
|
},
|
|
3310
3424
|
embedding: {
|
|
@@ -3314,6 +3428,12 @@ function getResolvedConfig(options = {}) {
|
|
|
3314
3428
|
apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
|
|
3315
3429
|
dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
|
|
3316
3430
|
},
|
|
3431
|
+
rerank: resolveRerankLane({
|
|
3432
|
+
toml,
|
|
3433
|
+
yaml,
|
|
3434
|
+
memoryLlmApiKey,
|
|
3435
|
+
memoryLlmBaseUrl
|
|
3436
|
+
}),
|
|
3317
3437
|
git: {
|
|
3318
3438
|
autoHook: firstBool(toml.git?.auto_hook, yaml.git?.autoHook),
|
|
3319
3439
|
ingestOnCommit: firstBool(toml.git?.ingest_on_commit, yaml.git?.ingestOnCommit),
|
|
@@ -3383,6 +3503,9 @@ function getResolvedMemoryLane(options = {}) {
|
|
|
3383
3503
|
function getResolvedEmbeddingLane(options = {}) {
|
|
3384
3504
|
return getResolvedConfig(options).embedding;
|
|
3385
3505
|
}
|
|
3506
|
+
function getResolvedRerankLane(options = {}) {
|
|
3507
|
+
return getResolvedConfig(options).rerank;
|
|
3508
|
+
}
|
|
3386
3509
|
function resetResolvedConfigCache() {
|
|
3387
3510
|
}
|
|
3388
3511
|
function first(...values) {
|
|
@@ -3425,6 +3548,10 @@ function getEnvSourceNames() {
|
|
|
3425
3548
|
"MEMORIX_EMBEDDING_BASE_URL",
|
|
3426
3549
|
"MEMORIX_EMBEDDING_MODEL",
|
|
3427
3550
|
"MEMORIX_EMBEDDING_DIMENSIONS",
|
|
3551
|
+
"MEMORIX_RERANK_PROVIDER",
|
|
3552
|
+
"MEMORIX_RERANK_MODEL",
|
|
3553
|
+
"MEMORIX_RERANK_BASE_URL",
|
|
3554
|
+
"MEMORIX_RERANK_API_KEY",
|
|
3428
3555
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
3429
3556
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
3430
3557
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
@@ -3448,6 +3575,63 @@ function normalizeExternalContext(value) {
|
|
|
3448
3575
|
if (normalized === "auto" || normalized === "off") return normalized;
|
|
3449
3576
|
return void 0;
|
|
3450
3577
|
}
|
|
3578
|
+
function normalizeRerankProvider(value) {
|
|
3579
|
+
const normalized = value?.trim().toLowerCase();
|
|
3580
|
+
if (normalized === "http") return "http";
|
|
3581
|
+
return "off";
|
|
3582
|
+
}
|
|
3583
|
+
function resolveRerankLane(args) {
|
|
3584
|
+
const provider2 = normalizeRerankProvider(first(
|
|
3585
|
+
process.env.MEMORIX_RERANK_PROVIDER,
|
|
3586
|
+
args.toml.rerank?.provider,
|
|
3587
|
+
args.yaml.rerank?.provider,
|
|
3588
|
+
"off"
|
|
3589
|
+
));
|
|
3590
|
+
const model = first(
|
|
3591
|
+
process.env.MEMORIX_RERANK_MODEL,
|
|
3592
|
+
args.toml.rerank?.model,
|
|
3593
|
+
args.yaml.rerank?.model
|
|
3594
|
+
);
|
|
3595
|
+
const explicitBaseUrl = first(
|
|
3596
|
+
process.env.MEMORIX_RERANK_BASE_URL,
|
|
3597
|
+
args.toml.rerank?.base_url,
|
|
3598
|
+
args.yaml.rerank?.baseUrl
|
|
3599
|
+
);
|
|
3600
|
+
const baseUrl = provider2 === "http" ? first(explicitBaseUrl, args.memoryLlmBaseUrl) : explicitBaseUrl;
|
|
3601
|
+
const dedicatedApiKey = first(
|
|
3602
|
+
process.env.MEMORIX_RERANK_API_KEY,
|
|
3603
|
+
args.toml.rerank?.api_key,
|
|
3604
|
+
args.yaml.rerank?.apiKey
|
|
3605
|
+
);
|
|
3606
|
+
const sameEndpoint = provider2 === "http" && sameTrustedEndpoint(baseUrl, args.memoryLlmBaseUrl);
|
|
3607
|
+
const inheritedApiKey = sameEndpoint ? args.memoryLlmApiKey : void 0;
|
|
3608
|
+
const apiKey = first(dedicatedApiKey, inheritedApiKey);
|
|
3609
|
+
const canSendRequest = provider2 === "http" && Boolean(baseUrl) && (Boolean(apiKey) || !args.memoryLlmApiKey || sameEndpoint);
|
|
3610
|
+
return { provider: provider2, model, baseUrl, apiKey, canSendRequest };
|
|
3611
|
+
}
|
|
3612
|
+
function sameTrustedEndpoint(left, right) {
|
|
3613
|
+
const a = normalizeTrustedEndpoint(left);
|
|
3614
|
+
const b = normalizeTrustedEndpoint(right);
|
|
3615
|
+
return Boolean(a && b && a === b);
|
|
3616
|
+
}
|
|
3617
|
+
function normalizeTrustedEndpoint(value) {
|
|
3618
|
+
const trimmed = value?.trim();
|
|
3619
|
+
if (!trimmed) return void 0;
|
|
3620
|
+
try {
|
|
3621
|
+
const url = new URL(trimmed);
|
|
3622
|
+
const protocol = url.protocol.toLowerCase();
|
|
3623
|
+
const hostname = url.hostname.toLowerCase();
|
|
3624
|
+
const port = url.port;
|
|
3625
|
+
let pathname = url.pathname.replace(/\/+$/, "");
|
|
3626
|
+
if (pathname.toLowerCase().endsWith("/rerank")) {
|
|
3627
|
+
pathname = pathname.slice(0, -"/rerank".length).replace(/\/+$/, "");
|
|
3628
|
+
}
|
|
3629
|
+
return `${protocol}//${hostname}${port ? `:${port}` : ""}${pathname}`;
|
|
3630
|
+
} catch {
|
|
3631
|
+
const fallback = trimmed.replace(/\/+$/, "").replace(/\/rerank$/i, "").replace(/\/+$/, "");
|
|
3632
|
+
return fallback.toLowerCase() || void 0;
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3451
3635
|
var init_resolved_config = __esm({
|
|
3452
3636
|
"src/config/resolved-config.ts"() {
|
|
3453
3637
|
"use strict";
|
|
@@ -5683,9 +5867,27 @@ __export(provider_exports2, {
|
|
|
5683
5867
|
getLLMConfig: () => getLLMConfig,
|
|
5684
5868
|
initLLM: () => initLLM,
|
|
5685
5869
|
isLLMEnabled: () => isLLMEnabled,
|
|
5870
|
+
normalizeOpenAICompatibleBaseUrl: () => normalizeOpenAICompatibleBaseUrl,
|
|
5686
5871
|
parseLLMTimeoutMs: () => parseLLMTimeoutMs,
|
|
5687
5872
|
setLLMConfig: () => setLLMConfig
|
|
5688
5873
|
});
|
|
5874
|
+
function normalizeOpenAICompatibleBaseUrl(baseUrl) {
|
|
5875
|
+
const base = baseUrl.trim().replace(/\/+$/, "");
|
|
5876
|
+
if (!base) return base;
|
|
5877
|
+
let pathname = "";
|
|
5878
|
+
try {
|
|
5879
|
+
pathname = new URL(base).pathname.replace(/\/+$/, "");
|
|
5880
|
+
} catch {
|
|
5881
|
+
pathname = base.split(/[?#]/, 1)[0].replace(/\/+$/, "");
|
|
5882
|
+
}
|
|
5883
|
+
const lastSegment = pathname.split("/").filter(Boolean).at(-1);
|
|
5884
|
+
if (lastSegment && OPENAI_API_VERSION_SEGMENT.test(lastSegment)) {
|
|
5885
|
+
return base;
|
|
5886
|
+
}
|
|
5887
|
+
const queryOrHash = base.match(/[?#].*$/)?.[0] ?? "";
|
|
5888
|
+
const pathWithoutQuery = base.slice(0, base.length - queryOrHash.length).replace(/\/+$/, "");
|
|
5889
|
+
return `${pathWithoutQuery}/v1${queryOrHash}`;
|
|
5890
|
+
}
|
|
5689
5891
|
function parseLLMTimeoutMs(raw) {
|
|
5690
5892
|
if (raw === void 0 || raw.trim() === "") return LLM_TIMEOUT_DEFAULT_MS;
|
|
5691
5893
|
const parsed = Number(raw);
|
|
@@ -5789,8 +5991,7 @@ async function callLLM(systemPrompt, userMessage, signal) {
|
|
|
5789
5991
|
}
|
|
5790
5992
|
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
5791
5993
|
const config = currentConfig;
|
|
5792
|
-
|
|
5793
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
5994
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
5794
5995
|
const url = `${base}/chat/completions`;
|
|
5795
5996
|
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5796
5997
|
const response = await fetch(url, {
|
|
@@ -5869,8 +6070,7 @@ async function callLLMWithTools(messages, tools, signal) {
|
|
|
5869
6070
|
}
|
|
5870
6071
|
async function callOpenAIWithTools(messages, tools, signal) {
|
|
5871
6072
|
const config = currentConfig;
|
|
5872
|
-
|
|
5873
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
6073
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
5874
6074
|
const url = `${base}/chat/completions`;
|
|
5875
6075
|
const openaiMessages = messages.map((msg) => {
|
|
5876
6076
|
if (msg.role === "tool") {
|
|
@@ -6020,8 +6220,7 @@ async function callAnthropicWithTools(messages, tools, signal) {
|
|
|
6020
6220
|
}
|
|
6021
6221
|
async function* callOpenAIWithToolsStream(messages, tools) {
|
|
6022
6222
|
const config = currentConfig;
|
|
6023
|
-
|
|
6024
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
6223
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
6025
6224
|
const url = `${base}/chat/completions`;
|
|
6026
6225
|
const openaiMessages = messages.map((msg) => {
|
|
6027
6226
|
if (msg.role === "tool") {
|
|
@@ -6269,7 +6468,7 @@ async function* callAnthropicWithToolsStream(messages, tools) {
|
|
|
6269
6468
|
}
|
|
6270
6469
|
};
|
|
6271
6470
|
}
|
|
6272
|
-
var LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_MIN_MS, LLM_TIMEOUT_MAX_MS, MAX_LLM_RESPONSE_BYTES, LLM_CALL_TIMEOUT_MS, PROVIDER_DEFAULTS, currentConfig;
|
|
6471
|
+
var LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_MIN_MS, LLM_TIMEOUT_MAX_MS, MAX_LLM_RESPONSE_BYTES, OPENAI_API_VERSION_SEGMENT, LLM_CALL_TIMEOUT_MS, PROVIDER_DEFAULTS, currentConfig;
|
|
6273
6472
|
var init_provider2 = __esm({
|
|
6274
6473
|
"src/llm/provider.ts"() {
|
|
6275
6474
|
"use strict";
|
|
@@ -6279,6 +6478,7 @@ var init_provider2 = __esm({
|
|
|
6279
6478
|
LLM_TIMEOUT_MIN_MS = 1e3;
|
|
6280
6479
|
LLM_TIMEOUT_MAX_MS = 3e5;
|
|
6281
6480
|
MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
6481
|
+
OPENAI_API_VERSION_SEGMENT = /^v\d+(?:[a-z][a-z0-9-]*)?$/i;
|
|
6282
6482
|
LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);
|
|
6283
6483
|
PROVIDER_DEFAULTS = {
|
|
6284
6484
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
@@ -6338,6 +6538,48 @@ Rules:
|
|
|
6338
6538
|
}
|
|
6339
6539
|
});
|
|
6340
6540
|
|
|
6541
|
+
// src/rerank/policy.ts
|
|
6542
|
+
function parseRerankTimeoutMs(raw) {
|
|
6543
|
+
const value = raw?.trim();
|
|
6544
|
+
if (!value) return DEFAULT_RERANK_TIMEOUT_MS;
|
|
6545
|
+
const parsed = Number(value);
|
|
6546
|
+
if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {
|
|
6547
|
+
console.warn(
|
|
6548
|
+
`[memorix] MEMORIX_RERANK_TIMEOUT_MS="${raw}" is invalid (must be a positive integer between ${RERANK_TIMEOUT_MIN_MS}-${RERANK_TIMEOUT_MAX_MS}ms). Using default ${DEFAULT_RERANK_TIMEOUT_MS}ms.`
|
|
6549
|
+
);
|
|
6550
|
+
return DEFAULT_RERANK_TIMEOUT_MS;
|
|
6551
|
+
}
|
|
6552
|
+
if (parsed < RERANK_TIMEOUT_MIN_MS) return RERANK_TIMEOUT_MIN_MS;
|
|
6553
|
+
if (parsed > RERANK_TIMEOUT_MAX_MS) return RERANK_TIMEOUT_MAX_MS;
|
|
6554
|
+
return parsed;
|
|
6555
|
+
}
|
|
6556
|
+
function resolveRerankTimeoutMs(explicitTimeoutMs) {
|
|
6557
|
+
if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
|
|
6558
|
+
return explicitTimeoutMs;
|
|
6559
|
+
}
|
|
6560
|
+
return parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
6561
|
+
}
|
|
6562
|
+
function shouldAttemptHttpRerank(input) {
|
|
6563
|
+
return input.quality === "thorough" && input.hasQuery && input.candidateCount >= MIN_RERANK_CANDIDATES;
|
|
6564
|
+
}
|
|
6565
|
+
function shouldAttemptLlmRerank(input) {
|
|
6566
|
+
if (input.httpRerankConfigured) return false;
|
|
6567
|
+
if (input.quality !== "thorough" || input.tier !== "heavy" || !input.hasQuery) return false;
|
|
6568
|
+
if (input.candidateCount < MIN_RERANK_CANDIDATES) return false;
|
|
6569
|
+
return input.topScore > 0 && input.secondScore / input.topScore > 0.7;
|
|
6570
|
+
}
|
|
6571
|
+
var DEFAULT_RERANK_TIMEOUT_MS, RERANK_TIMEOUT_MIN_MS, RERANK_TIMEOUT_MAX_MS, MIN_RERANK_CANDIDATES;
|
|
6572
|
+
var init_policy = __esm({
|
|
6573
|
+
"src/rerank/policy.ts"() {
|
|
6574
|
+
"use strict";
|
|
6575
|
+
init_esm_shims();
|
|
6576
|
+
DEFAULT_RERANK_TIMEOUT_MS = 3e4;
|
|
6577
|
+
RERANK_TIMEOUT_MIN_MS = 1e3;
|
|
6578
|
+
RERANK_TIMEOUT_MAX_MS = 3e5;
|
|
6579
|
+
MIN_RERANK_CANDIDATES = 3;
|
|
6580
|
+
}
|
|
6581
|
+
});
|
|
6582
|
+
|
|
6341
6583
|
// src/timeout.ts
|
|
6342
6584
|
function withTimeout(promise, ms, label) {
|
|
6343
6585
|
return new Promise((resolve2, reject) => {
|
|
@@ -6623,6 +6865,148 @@ var init_aliases = __esm({
|
|
|
6623
6865
|
}
|
|
6624
6866
|
});
|
|
6625
6867
|
|
|
6868
|
+
// src/rerank/http-provider.ts
|
|
6869
|
+
function buildRerankUrl(baseUrl) {
|
|
6870
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
6871
|
+
if (trimmed.endsWith("/rerank")) return trimmed;
|
|
6872
|
+
return `${trimmed}/rerank`;
|
|
6873
|
+
}
|
|
6874
|
+
function parseRerankResponse(payload) {
|
|
6875
|
+
const rows = extractRows(payload);
|
|
6876
|
+
if (rows.length === 0) {
|
|
6877
|
+
throw new Error("Neural rerank response contained no ranked results");
|
|
6878
|
+
}
|
|
6879
|
+
return rows.sort((a, b) => b.score - a.score);
|
|
6880
|
+
}
|
|
6881
|
+
function extractRows(payload) {
|
|
6882
|
+
if (Array.isArray(payload)) {
|
|
6883
|
+
return payload.map(rowFromUnknown).filter((row) => row !== null);
|
|
6884
|
+
}
|
|
6885
|
+
if (payload && typeof payload === "object" && "results" in payload) {
|
|
6886
|
+
const results = payload.results;
|
|
6887
|
+
if (Array.isArray(results)) {
|
|
6888
|
+
return results.map(rowFromUnknown).filter((row) => row !== null);
|
|
6889
|
+
}
|
|
6890
|
+
}
|
|
6891
|
+
throw new Error("Neural rerank response was not Cohere or TEI shaped");
|
|
6892
|
+
}
|
|
6893
|
+
function rowFromUnknown(value) {
|
|
6894
|
+
if (!value || typeof value !== "object") return null;
|
|
6895
|
+
const row = value;
|
|
6896
|
+
if (typeof row.index !== "number" || !Number.isFinite(row.index)) return null;
|
|
6897
|
+
const score = typeof row.relevance_score === "number" ? row.relevance_score : typeof row.score === "number" ? row.score : null;
|
|
6898
|
+
if (score === null || !Number.isFinite(score)) return null;
|
|
6899
|
+
return { index: row.index, score };
|
|
6900
|
+
}
|
|
6901
|
+
function buildRerankBody(query, documents, model) {
|
|
6902
|
+
const body = {
|
|
6903
|
+
query,
|
|
6904
|
+
documents,
|
|
6905
|
+
top_n: documents.length,
|
|
6906
|
+
return_documents: false
|
|
6907
|
+
};
|
|
6908
|
+
const trimmed = model?.trim();
|
|
6909
|
+
if (trimmed) body.model = trimmed;
|
|
6910
|
+
return body;
|
|
6911
|
+
}
|
|
6912
|
+
async function rerankViaHttp(query, documents, config) {
|
|
6913
|
+
if (documents.length === 0) return [];
|
|
6914
|
+
const url = buildRerankUrl(config.baseUrl);
|
|
6915
|
+
const headers = {
|
|
6916
|
+
"content-type": "application/json"
|
|
6917
|
+
};
|
|
6918
|
+
if (config.apiKey) {
|
|
6919
|
+
headers.authorization = `Bearer ${config.apiKey}`;
|
|
6920
|
+
}
|
|
6921
|
+
const controller = new AbortController();
|
|
6922
|
+
const timeoutMs = resolveRerankTimeoutMs(config.timeoutMs);
|
|
6923
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6924
|
+
try {
|
|
6925
|
+
const fetchImpl = config.fetchImpl ?? fetch;
|
|
6926
|
+
const response = await fetchImpl(url, {
|
|
6927
|
+
method: "POST",
|
|
6928
|
+
headers,
|
|
6929
|
+
signal: controller.signal,
|
|
6930
|
+
body: JSON.stringify(buildRerankBody(query, documents, config.model))
|
|
6931
|
+
});
|
|
6932
|
+
if (!response.ok) {
|
|
6933
|
+
throw new Error(`Neural rerank HTTP ${response.status} from ${url}`);
|
|
6934
|
+
}
|
|
6935
|
+
return parseRerankResponse(await response.json());
|
|
6936
|
+
} finally {
|
|
6937
|
+
clearTimeout(timer);
|
|
6938
|
+
}
|
|
6939
|
+
}
|
|
6940
|
+
var init_http_provider = __esm({
|
|
6941
|
+
"src/rerank/http-provider.ts"() {
|
|
6942
|
+
"use strict";
|
|
6943
|
+
init_esm_shims();
|
|
6944
|
+
init_policy();
|
|
6945
|
+
}
|
|
6946
|
+
});
|
|
6947
|
+
|
|
6948
|
+
// src/rerank/index.ts
|
|
6949
|
+
var rerank_exports = {};
|
|
6950
|
+
__export(rerank_exports, {
|
|
6951
|
+
DEFAULT_RERANK_TIMEOUT_MS: () => DEFAULT_RERANK_TIMEOUT_MS,
|
|
6952
|
+
MIN_RERANK_CANDIDATES: () => MIN_RERANK_CANDIDATES,
|
|
6953
|
+
isNeuralRerankEnabled: () => isNeuralRerankEnabled,
|
|
6954
|
+
neuralRerankCandidates: () => neuralRerankCandidates,
|
|
6955
|
+
parseRerankTimeoutMs: () => parseRerankTimeoutMs,
|
|
6956
|
+
resolveRerankTimeoutMs: () => resolveRerankTimeoutMs,
|
|
6957
|
+
shouldAttemptHttpRerank: () => shouldAttemptHttpRerank,
|
|
6958
|
+
shouldAttemptLlmRerank: () => shouldAttemptLlmRerank
|
|
6959
|
+
});
|
|
6960
|
+
function isNeuralRerankEnabled(options = {}) {
|
|
6961
|
+
const lane = getResolvedRerankLane(options);
|
|
6962
|
+
return lane.provider === "http" && Boolean(lane.baseUrl);
|
|
6963
|
+
}
|
|
6964
|
+
async function neuralRerankCandidates(query, candidates, options = {}) {
|
|
6965
|
+
if (!isNeuralRerankEnabled(options) || candidates.length === 0) return null;
|
|
6966
|
+
const lane = getResolvedRerankLane(options);
|
|
6967
|
+
if (!lane.canSendRequest || !lane.baseUrl) return null;
|
|
6968
|
+
const toRerank = candidates.slice(0, MAX_RERANK);
|
|
6969
|
+
const rest = candidates.slice(MAX_RERANK);
|
|
6970
|
+
const documents = toRerank.map((candidate) => candidateText(candidate));
|
|
6971
|
+
const ranked = await rerankViaHttp(query, documents, {
|
|
6972
|
+
provider: "http",
|
|
6973
|
+
model: lane.model,
|
|
6974
|
+
baseUrl: lane.baseUrl,
|
|
6975
|
+
apiKey: lane.apiKey,
|
|
6976
|
+
timeoutMs: resolveRerankTimeoutMs()
|
|
6977
|
+
});
|
|
6978
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6979
|
+
const reranked = [];
|
|
6980
|
+
for (const row of ranked) {
|
|
6981
|
+
const candidate = toRerank[row.index];
|
|
6982
|
+
if (!candidate || seen.has(row.index)) continue;
|
|
6983
|
+
reranked.push(candidate);
|
|
6984
|
+
seen.add(row.index);
|
|
6985
|
+
}
|
|
6986
|
+
for (const [index, candidate] of toRerank.entries()) {
|
|
6987
|
+
if (!seen.has(index)) reranked.push(candidate);
|
|
6988
|
+
}
|
|
6989
|
+
reranked.push(...rest);
|
|
6990
|
+
return reranked;
|
|
6991
|
+
}
|
|
6992
|
+
function candidateText(candidate) {
|
|
6993
|
+
const narrative = candidate.narrative?.trim();
|
|
6994
|
+
if (narrative) return `${candidate.title} \u2014 ${narrative.slice(0, 200)}`;
|
|
6995
|
+
return candidate.title;
|
|
6996
|
+
}
|
|
6997
|
+
var MAX_RERANK;
|
|
6998
|
+
var init_rerank = __esm({
|
|
6999
|
+
"src/rerank/index.ts"() {
|
|
7000
|
+
"use strict";
|
|
7001
|
+
init_esm_shims();
|
|
7002
|
+
init_resolved_config();
|
|
7003
|
+
init_http_provider();
|
|
7004
|
+
init_policy();
|
|
7005
|
+
init_policy();
|
|
7006
|
+
MAX_RERANK = 10;
|
|
7007
|
+
}
|
|
7008
|
+
});
|
|
7009
|
+
|
|
6626
7010
|
// src/llm/quality.ts
|
|
6627
7011
|
var quality_exports = {};
|
|
6628
7012
|
__export(quality_exports, {
|
|
@@ -6662,9 +7046,9 @@ async function rerankResults(query, candidates) {
|
|
|
6662
7046
|
if (!isLLMEnabled() || candidates.length <= 2) {
|
|
6663
7047
|
return { reranked: candidates, usedLLM: false };
|
|
6664
7048
|
}
|
|
6665
|
-
const
|
|
6666
|
-
const toRerank = candidates.slice(0,
|
|
6667
|
-
const rest = candidates.slice(
|
|
7049
|
+
const MAX_RERANK2 = 10;
|
|
7050
|
+
const toRerank = candidates.slice(0, MAX_RERANK2);
|
|
7051
|
+
const rest = candidates.slice(MAX_RERANK2);
|
|
6668
7052
|
try {
|
|
6669
7053
|
const candidateList = toRerank.map(
|
|
6670
7054
|
(c) => `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` \u2014 ${c.narrative.substring(0, 100)}` : ""}`
|
|
@@ -7557,46 +7941,78 @@ async function searchObservations(options) {
|
|
|
7557
7941
|
}
|
|
7558
7942
|
}
|
|
7559
7943
|
}
|
|
7560
|
-
const
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
})
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7944
|
+
const httpGate = shouldAttemptHttpRerank({
|
|
7945
|
+
quality,
|
|
7946
|
+
hasQuery: Boolean(hasQuery),
|
|
7947
|
+
candidateCount: intermediate.length
|
|
7948
|
+
});
|
|
7949
|
+
const llmGateWithoutHttp = shouldAttemptLlmRerank({
|
|
7950
|
+
quality,
|
|
7951
|
+
tier,
|
|
7952
|
+
hasQuery: Boolean(hasQuery),
|
|
7953
|
+
candidateCount: intermediate.length,
|
|
7954
|
+
topScore: intermediate[0]?.score ?? 0,
|
|
7955
|
+
secondScore: intermediate[1]?.score ?? 0,
|
|
7956
|
+
httpRerankConfigured: false
|
|
7957
|
+
});
|
|
7958
|
+
if (httpGate || llmGateWithoutHttp) {
|
|
7959
|
+
const narrativeMap = /* @__PURE__ */ new Map();
|
|
7960
|
+
for (const hit of results.hits) {
|
|
7961
|
+
const doc = hit.document;
|
|
7962
|
+
narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);
|
|
7963
|
+
}
|
|
7964
|
+
const RERANK_TOP_K = 5;
|
|
7965
|
+
const toRerank = intermediate.slice(0, RERANK_TOP_K);
|
|
7966
|
+
const candidates = toRerank.map((e2, index) => ({
|
|
7967
|
+
id: `r${index + 1}`,
|
|
7968
|
+
title: e2.title,
|
|
7969
|
+
type: e2.type,
|
|
7970
|
+
score: e2.score,
|
|
7971
|
+
narrative: narrativeMap.get(makeEntryKey(e2.projectId, e2.id))
|
|
7972
|
+
}));
|
|
7973
|
+
const RERANK_TIMEOUT_MS = parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
7974
|
+
const candidateMap = new Map(candidates.map((candidate, index) => [candidate.id, toRerank[index]]));
|
|
7975
|
+
const { isNeuralRerankEnabled: isNeuralRerankEnabled2, neuralRerankCandidates: neuralRerankCandidates2 } = await Promise.resolve().then(() => (init_rerank(), rerank_exports));
|
|
7976
|
+
const httpConfigured = isNeuralRerankEnabled2();
|
|
7977
|
+
if (httpConfigured && httpGate) {
|
|
7978
|
+
try {
|
|
7979
|
+
const neural = await withTimeout(
|
|
7980
|
+
neuralRerankCandidates2(originalQuery, candidates),
|
|
7981
|
+
RERANK_TIMEOUT_MS,
|
|
7982
|
+
"neural rerank"
|
|
7983
|
+
);
|
|
7984
|
+
if (neural && neural.length > 0) {
|
|
7985
|
+
const rerankedTop = neural.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
7986
|
+
if (rerankedTop.length > 0) {
|
|
7987
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
7988
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + neural rerank");
|
|
7989
|
+
mark("rerank(usedNeural=true)");
|
|
7990
|
+
}
|
|
7596
7991
|
}
|
|
7992
|
+
} catch {
|
|
7993
|
+
console.error("[memorix] neural rerank failed or timed out; keeping original order");
|
|
7597
7994
|
}
|
|
7598
|
-
}
|
|
7599
|
-
|
|
7995
|
+
} else if (!httpConfigured && llmGateWithoutHttp) {
|
|
7996
|
+
try {
|
|
7997
|
+
const { rerankResults: rerankResults2 } = await Promise.resolve().then(() => (init_quality(), quality_exports));
|
|
7998
|
+
const { reranked, usedLLM } = await withTimeout(
|
|
7999
|
+
rerankResults2(originalQuery, candidates),
|
|
8000
|
+
RERANK_TIMEOUT_MS,
|
|
8001
|
+
"LLM rerank"
|
|
8002
|
+
);
|
|
8003
|
+
mark(`rerank(usedLLM=${usedLLM})`);
|
|
8004
|
+
if (usedLLM) {
|
|
8005
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
8006
|
+
const rerankedTop = reranked.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
8007
|
+
if (rerankedTop.length > 0) {
|
|
8008
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
8009
|
+
}
|
|
8010
|
+
}
|
|
8011
|
+
} catch {
|
|
8012
|
+
console.error("[memorix] LLM rerank failed or timed out, using original order");
|
|
8013
|
+
}
|
|
8014
|
+
} else {
|
|
8015
|
+
mark(`rerank(skipped,tier=${tier})`);
|
|
7600
8016
|
}
|
|
7601
8017
|
} else {
|
|
7602
8018
|
mark(`rerank(skipped,tier=${tier})`);
|
|
@@ -7777,6 +8193,7 @@ var init_orama_store = __esm({
|
|
|
7777
8193
|
init_project_affinity();
|
|
7778
8194
|
init_intent_detector();
|
|
7779
8195
|
init_query_expansion();
|
|
8196
|
+
init_policy();
|
|
7780
8197
|
init_timeout();
|
|
7781
8198
|
db = null;
|
|
7782
8199
|
dbInitPromise = null;
|
|
@@ -8996,6 +9413,226 @@ var init_lifecycle = __esm({
|
|
|
8996
9413
|
}
|
|
8997
9414
|
});
|
|
8998
9415
|
|
|
9416
|
+
// src/store/evidence-store.ts
|
|
9417
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
9418
|
+
function safeJson(value, fallback) {
|
|
9419
|
+
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
9420
|
+
try {
|
|
9421
|
+
return JSON.parse(value);
|
|
9422
|
+
} catch {
|
|
9423
|
+
return fallback;
|
|
9424
|
+
}
|
|
9425
|
+
}
|
|
9426
|
+
function rowToCard(row) {
|
|
9427
|
+
return {
|
|
9428
|
+
id: String(row.id),
|
|
9429
|
+
projectId: String(row.project_id),
|
|
9430
|
+
candidateKind: row.candidate_kind,
|
|
9431
|
+
candidateId: String(row.candidate_id),
|
|
9432
|
+
title: String(row.title),
|
|
9433
|
+
summary: String(row.summary ?? ""),
|
|
9434
|
+
...row.entity_name ? { entityName: String(row.entity_name) } : {},
|
|
9435
|
+
sourceKind: String(row.source_kind),
|
|
9436
|
+
sourceRef: String(row.source_ref),
|
|
9437
|
+
...row.locator ? { locator: String(row.locator) } : {},
|
|
9438
|
+
...row.captured_hash ? { capturedHash: String(row.captured_hash) } : {},
|
|
9439
|
+
...row.session_id ? { sessionId: String(row.session_id) } : {},
|
|
9440
|
+
status: String(row.status ?? "active"),
|
|
9441
|
+
verification: row.verification,
|
|
9442
|
+
freshness: row.freshness,
|
|
9443
|
+
...row.stale_reason ? { staleReason: String(row.stale_reason) } : {},
|
|
9444
|
+
files: safeJson(row.files_json, []),
|
|
9445
|
+
relatedEntities: safeJson(row.related_entities_json, []),
|
|
9446
|
+
createdAt: String(row.created_at),
|
|
9447
|
+
updatedAt: String(row.updated_at)
|
|
9448
|
+
};
|
|
9449
|
+
}
|
|
9450
|
+
function observationHash(observation) {
|
|
9451
|
+
return createHash3("sha256").update(JSON.stringify({
|
|
9452
|
+
projectId: observation.projectId,
|
|
9453
|
+
id: observation.id,
|
|
9454
|
+
title: observation.title,
|
|
9455
|
+
narrative: observation.narrative,
|
|
9456
|
+
facts: observation.facts,
|
|
9457
|
+
files: observation.filesModified,
|
|
9458
|
+
relatedEntities: observation.relatedEntities
|
|
9459
|
+
})).digest("hex");
|
|
9460
|
+
}
|
|
9461
|
+
function sourceKind(observation) {
|
|
9462
|
+
if (observation.source === "git" || observation.sourceDetail === "git-ingest") return "git";
|
|
9463
|
+
if (observation.sourceDetail === "hook") return "hook";
|
|
9464
|
+
return observation.source ?? "agent";
|
|
9465
|
+
}
|
|
9466
|
+
var EvidenceCardStore;
|
|
9467
|
+
var init_evidence_store = __esm({
|
|
9468
|
+
"src/store/evidence-store.ts"() {
|
|
9469
|
+
"use strict";
|
|
9470
|
+
init_esm_shims();
|
|
9471
|
+
init_sqlite_db();
|
|
9472
|
+
EvidenceCardStore = class {
|
|
9473
|
+
db = null;
|
|
9474
|
+
async init(dataDir) {
|
|
9475
|
+
this.db = getDatabase(dataDir);
|
|
9476
|
+
}
|
|
9477
|
+
requireDb() {
|
|
9478
|
+
if (!this.db) throw new Error("EvidenceCardStore is not initialized.");
|
|
9479
|
+
return this.db;
|
|
9480
|
+
}
|
|
9481
|
+
upsertObservation(observation) {
|
|
9482
|
+
const db2 = this.requireDb();
|
|
9483
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
9484
|
+
const card = {
|
|
9485
|
+
id: `evidence:observation:${observation.projectId}:${observation.id}`,
|
|
9486
|
+
projectId: observation.projectId,
|
|
9487
|
+
candidateKind: "observation",
|
|
9488
|
+
candidateId: String(observation.id),
|
|
9489
|
+
title: observation.title,
|
|
9490
|
+
summary: observation.narrative.slice(0, 500),
|
|
9491
|
+
entityName: observation.entityName,
|
|
9492
|
+
sourceKind: sourceKind(observation),
|
|
9493
|
+
sourceRef: `observation:${observation.id}`,
|
|
9494
|
+
locator: observation.filesModified?.join(", ") || `observation:${observation.id}`,
|
|
9495
|
+
capturedHash: observationHash(observation),
|
|
9496
|
+
...observation.sessionId ? { sessionId: observation.sessionId } : {},
|
|
9497
|
+
status: observation.status ?? "active",
|
|
9498
|
+
verification: observation.status === "resolved" ? "verified" : "unverified",
|
|
9499
|
+
freshness: "current",
|
|
9500
|
+
files: observation.filesModified ?? [],
|
|
9501
|
+
relatedEntities: observation.relatedEntities ?? [],
|
|
9502
|
+
createdAt: observation.createdAt,
|
|
9503
|
+
updatedAt: now3
|
|
9504
|
+
};
|
|
9505
|
+
db2.prepare(`
|
|
9506
|
+
INSERT INTO evidence_cards (
|
|
9507
|
+
id, project_id, candidate_kind, candidate_id, title, summary, entity_name,
|
|
9508
|
+
source_kind, source_ref, locator, captured_hash, session_id, status,
|
|
9509
|
+
verification, freshness, stale_reason, files_json, related_entities_json,
|
|
9510
|
+
created_at, updated_at
|
|
9511
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?)
|
|
9512
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
9513
|
+
title = excluded.title,
|
|
9514
|
+
summary = excluded.summary,
|
|
9515
|
+
entity_name = excluded.entity_name,
|
|
9516
|
+
source_kind = excluded.source_kind,
|
|
9517
|
+
source_ref = excluded.source_ref,
|
|
9518
|
+
locator = excluded.locator,
|
|
9519
|
+
captured_hash = excluded.captured_hash,
|
|
9520
|
+
session_id = excluded.session_id,
|
|
9521
|
+
status = excluded.status,
|
|
9522
|
+
freshness = 'current',
|
|
9523
|
+
stale_reason = NULL,
|
|
9524
|
+
files_json = excluded.files_json,
|
|
9525
|
+
related_entities_json = excluded.related_entities_json,
|
|
9526
|
+
updated_at = excluded.updated_at
|
|
9527
|
+
`).run(
|
|
9528
|
+
card.id,
|
|
9529
|
+
card.projectId,
|
|
9530
|
+
card.candidateKind,
|
|
9531
|
+
card.candidateId,
|
|
9532
|
+
card.title,
|
|
9533
|
+
card.summary,
|
|
9534
|
+
card.entityName ?? null,
|
|
9535
|
+
card.sourceKind,
|
|
9536
|
+
card.sourceRef,
|
|
9537
|
+
card.locator ?? null,
|
|
9538
|
+
card.capturedHash ?? null,
|
|
9539
|
+
card.sessionId ?? null,
|
|
9540
|
+
card.status,
|
|
9541
|
+
card.verification,
|
|
9542
|
+
card.freshness,
|
|
9543
|
+
JSON.stringify(card.files),
|
|
9544
|
+
JSON.stringify(card.relatedEntities),
|
|
9545
|
+
card.createdAt,
|
|
9546
|
+
card.updatedAt
|
|
9547
|
+
);
|
|
9548
|
+
return this.get(card.projectId, card.candidateKind, card.candidateId) ?? card;
|
|
9549
|
+
}
|
|
9550
|
+
get(projectId, candidateKind, candidateId) {
|
|
9551
|
+
const row = this.requireDb().prepare(`
|
|
9552
|
+
SELECT * FROM evidence_cards WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
9553
|
+
`).get(projectId, candidateKind, candidateId);
|
|
9554
|
+
return row ? rowToCard(row) : void 0;
|
|
9555
|
+
}
|
|
9556
|
+
list(projectId, options = {}) {
|
|
9557
|
+
const limit2 = Math.min(100, Math.max(1, Math.floor(options.limit ?? 20)));
|
|
9558
|
+
const clauses = ["project_id = ?"];
|
|
9559
|
+
const args = [projectId];
|
|
9560
|
+
if (options.freshness) {
|
|
9561
|
+
clauses.push("freshness = ?");
|
|
9562
|
+
args.push(options.freshness);
|
|
9563
|
+
}
|
|
9564
|
+
if (options.status) {
|
|
9565
|
+
clauses.push("status = ?");
|
|
9566
|
+
args.push(options.status);
|
|
9567
|
+
}
|
|
9568
|
+
args.push(limit2);
|
|
9569
|
+
const rows = this.requireDb().prepare(`
|
|
9570
|
+
SELECT * FROM evidence_cards WHERE ${clauses.join(" AND ")} ORDER BY updated_at DESC, id DESC LIMIT ?
|
|
9571
|
+
`).all(...args);
|
|
9572
|
+
return rows.map(rowToCard);
|
|
9573
|
+
}
|
|
9574
|
+
syncObservations(observations2) {
|
|
9575
|
+
return observations2.map((observation) => this.upsertObservation(observation));
|
|
9576
|
+
}
|
|
9577
|
+
markStaleForPaths(projectId, paths, reason = "source file changed") {
|
|
9578
|
+
const normalized = new Set(paths.map((value) => value.replace(/\\/g, "/").toLowerCase()));
|
|
9579
|
+
if (normalized.size === 0) return 0;
|
|
9580
|
+
const db2 = this.requireDb();
|
|
9581
|
+
const rows = db2.prepare(`SELECT * FROM evidence_cards WHERE project_id = ? AND freshness != 'stale'`).all(projectId);
|
|
9582
|
+
const update2 = db2.prepare(`
|
|
9583
|
+
UPDATE evidence_cards SET freshness = 'stale', stale_reason = ?, updated_at = ?
|
|
9584
|
+
WHERE id = ?
|
|
9585
|
+
`);
|
|
9586
|
+
let changed = 0;
|
|
9587
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
9588
|
+
const run = db2.transaction(() => {
|
|
9589
|
+
for (const row of rows) {
|
|
9590
|
+
const files = safeJson(row.files_json, []);
|
|
9591
|
+
if (!files.some((file) => normalized.has(file.replace(/\\/g, "/").toLowerCase()))) continue;
|
|
9592
|
+
update2.run(reason, now3, row.id);
|
|
9593
|
+
changed++;
|
|
9594
|
+
}
|
|
9595
|
+
});
|
|
9596
|
+
run();
|
|
9597
|
+
return changed;
|
|
9598
|
+
}
|
|
9599
|
+
setVerification(projectId, cardId, verification) {
|
|
9600
|
+
this.requireDb().prepare(`
|
|
9601
|
+
UPDATE evidence_cards SET verification = ?, updated_at = ? WHERE project_id = ? AND id = ?
|
|
9602
|
+
`).run(verification, (/* @__PURE__ */ new Date()).toISOString(), projectId, cardId);
|
|
9603
|
+
}
|
|
9604
|
+
recordEvent(projectId, cardId, kind, detail) {
|
|
9605
|
+
const event = {
|
|
9606
|
+
id: randomUUID3(),
|
|
9607
|
+
projectId,
|
|
9608
|
+
cardId,
|
|
9609
|
+
kind,
|
|
9610
|
+
...detail ? { detail: detail.slice(0, 2e3) } : {},
|
|
9611
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9612
|
+
};
|
|
9613
|
+
this.requireDb().prepare(`
|
|
9614
|
+
INSERT INTO evidence_card_events (id, project_id, card_id, kind, detail, created_at)
|
|
9615
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
9616
|
+
`).run(event.id, event.projectId, event.cardId, event.kind, event.detail ?? null, event.createdAt);
|
|
9617
|
+
return event;
|
|
9618
|
+
}
|
|
9619
|
+
listEvents(cardId, limit2 = 50) {
|
|
9620
|
+
const rows = this.requireDb().prepare(`
|
|
9621
|
+
SELECT * FROM evidence_card_events WHERE card_id = ? ORDER BY created_at DESC LIMIT ?
|
|
9622
|
+
`).all(cardId, Math.min(200, Math.max(1, Math.floor(limit2))));
|
|
9623
|
+
return rows.map((row) => ({
|
|
9624
|
+
id: String(row.id),
|
|
9625
|
+
projectId: String(row.project_id),
|
|
9626
|
+
cardId: String(row.card_id),
|
|
9627
|
+
kind: String(row.kind),
|
|
9628
|
+
...row.detail ? { detail: String(row.detail) } : {},
|
|
9629
|
+
createdAt: String(row.created_at)
|
|
9630
|
+
}));
|
|
9631
|
+
}
|
|
9632
|
+
};
|
|
9633
|
+
}
|
|
9634
|
+
});
|
|
9635
|
+
|
|
8999
9636
|
// src/runtime/isolated-maintenance.ts
|
|
9000
9637
|
import { spawn } from "child_process";
|
|
9001
9638
|
import { existsSync as existsSync8 } from "fs";
|
|
@@ -9157,7 +9794,7 @@ var workspace_store_exports = {};
|
|
|
9157
9794
|
__export(workspace_store_exports, {
|
|
9158
9795
|
KnowledgeWorkspaceStore: () => KnowledgeWorkspaceStore
|
|
9159
9796
|
});
|
|
9160
|
-
import { randomUUID as
|
|
9797
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
9161
9798
|
function arrayValue(raw) {
|
|
9162
9799
|
if (typeof raw !== "string" || !raw) return [];
|
|
9163
9800
|
try {
|
|
@@ -9298,7 +9935,7 @@ var init_workspace_store = __esm({
|
|
|
9298
9935
|
}
|
|
9299
9936
|
createProposal(input) {
|
|
9300
9937
|
const proposal = {
|
|
9301
|
-
id: input.id ??
|
|
9938
|
+
id: input.id ?? randomUUID4(),
|
|
9302
9939
|
...input,
|
|
9303
9940
|
status: input.status ?? "pending",
|
|
9304
9941
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -9351,13 +9988,13 @@ __export(workspace_exports, {
|
|
|
9351
9988
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
9352
9989
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
9353
9990
|
});
|
|
9354
|
-
import { createHash as
|
|
9991
|
+
import { createHash as createHash4 } from "crypto";
|
|
9355
9992
|
import { execFile } from "child_process";
|
|
9356
9993
|
import { promises as fs9 } from "fs";
|
|
9357
9994
|
import path13 from "path";
|
|
9358
9995
|
import { promisify } from "util";
|
|
9359
9996
|
function hash(value) {
|
|
9360
|
-
return
|
|
9997
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
9361
9998
|
}
|
|
9362
9999
|
function workspaceId(projectId, mode) {
|
|
9363
10000
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -9957,7 +10594,7 @@ var media_store_exports = {};
|
|
|
9957
10594
|
__export(media_store_exports, {
|
|
9958
10595
|
MediaStore: () => MediaStore
|
|
9959
10596
|
});
|
|
9960
|
-
import { randomUUID as
|
|
10597
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
9961
10598
|
function asOptionalText(value) {
|
|
9962
10599
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
9963
10600
|
}
|
|
@@ -10127,7 +10764,7 @@ var init_media_store = __esm({
|
|
|
10127
10764
|
return { asset: this.getAsset(input.projectId, existing.id), deduplicated: true };
|
|
10128
10765
|
}
|
|
10129
10766
|
const asset = {
|
|
10130
|
-
id:
|
|
10767
|
+
id: randomUUID5(),
|
|
10131
10768
|
...input,
|
|
10132
10769
|
createdAt: now3,
|
|
10133
10770
|
updatedAt: now3
|
|
@@ -10207,7 +10844,7 @@ var init_media_store = __esm({
|
|
|
10207
10844
|
`).get(input.assetId, input.observationId ?? null, input.role);
|
|
10208
10845
|
if (existing) return rowToLink(existing);
|
|
10209
10846
|
const link = {
|
|
10210
|
-
id:
|
|
10847
|
+
id: randomUUID5(),
|
|
10211
10848
|
assetId: input.assetId,
|
|
10212
10849
|
projectId: input.projectId,
|
|
10213
10850
|
...input.observationId !== void 0 ? { observationId: input.observationId } : {},
|
|
@@ -10246,7 +10883,7 @@ var init_media_store = __esm({
|
|
|
10246
10883
|
return rowToDerivation(this.db.prepare("SELECT * FROM media_derivations WHERE id = ?").get(existing.id));
|
|
10247
10884
|
}
|
|
10248
10885
|
const derivation = {
|
|
10249
|
-
id:
|
|
10886
|
+
id: randomUUID5(),
|
|
10250
10887
|
...input,
|
|
10251
10888
|
content,
|
|
10252
10889
|
...error ? { error } : {},
|
|
@@ -10333,7 +10970,7 @@ var init_media_store = __esm({
|
|
|
10333
10970
|
createJob(input) {
|
|
10334
10971
|
const now3 = Date.now();
|
|
10335
10972
|
const job = {
|
|
10336
|
-
id:
|
|
10973
|
+
id: randomUUID5(),
|
|
10337
10974
|
projectId: input.projectId,
|
|
10338
10975
|
kind: input.kind,
|
|
10339
10976
|
status: "queued",
|
|
@@ -10509,14 +11146,14 @@ __export(asset_store_exports, {
|
|
|
10509
11146
|
readMediaAsset: () => readMediaAsset,
|
|
10510
11147
|
removeMediaAsset: () => removeMediaAsset
|
|
10511
11148
|
});
|
|
10512
|
-
import { createHash as
|
|
11149
|
+
import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
|
|
10513
11150
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
10514
11151
|
import path14 from "path";
|
|
10515
11152
|
function mediaRoot(dataDir) {
|
|
10516
11153
|
return path14.resolve(dataDir, "media");
|
|
10517
11154
|
}
|
|
10518
11155
|
function projectStorageKey(projectId) {
|
|
10519
|
-
return
|
|
11156
|
+
return createHash5("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
10520
11157
|
}
|
|
10521
11158
|
function validateUnderRoot(root, candidate) {
|
|
10522
11159
|
const resolved = path14.resolve(candidate);
|
|
@@ -10576,14 +11213,14 @@ async function readHeader(filePath, bytes = 32) {
|
|
|
10576
11213
|
}
|
|
10577
11214
|
async function sha256File(filePath) {
|
|
10578
11215
|
const bytes = await readFile3(filePath);
|
|
10579
|
-
return
|
|
11216
|
+
return createHash5("sha256").update(bytes).digest("hex");
|
|
10580
11217
|
}
|
|
10581
11218
|
function destinationFor(root, projectId, sha256, extension3) {
|
|
10582
11219
|
const relative3 = path14.join("assets", projectStorageKey(projectId), sha256.slice(0, 2), `${sha256}${extension3}`);
|
|
10583
11220
|
return { relative: relative3, absolute: validateUnderRoot(root, path14.join(root, relative3)) };
|
|
10584
11221
|
}
|
|
10585
11222
|
function deletionStagingPath(root, assetId) {
|
|
10586
|
-
return validateUnderRoot(root, path14.join(root, ".trash", `${assetId}.${
|
|
11223
|
+
return validateUnderRoot(root, path14.join(root, ".trash", `${assetId}.${randomUUID6()}.pending-delete`));
|
|
10587
11224
|
}
|
|
10588
11225
|
async function destinationExists(destination) {
|
|
10589
11226
|
try {
|
|
@@ -10597,7 +11234,7 @@ async function destinationExists(destination) {
|
|
|
10597
11234
|
async function persistFile(source, destination) {
|
|
10598
11235
|
await mkdir3(path14.dirname(destination), { recursive: true });
|
|
10599
11236
|
if (await destinationExists(destination)) return false;
|
|
10600
|
-
const temporary = `${destination}.${
|
|
11237
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
10601
11238
|
try {
|
|
10602
11239
|
await copyFile(source, temporary);
|
|
10603
11240
|
await rename2(temporary, destination);
|
|
@@ -10613,7 +11250,7 @@ async function persistFile(source, destination) {
|
|
|
10613
11250
|
async function persistBuffer(bytes, destination) {
|
|
10614
11251
|
await mkdir3(path14.dirname(destination), { recursive: true });
|
|
10615
11252
|
if (await destinationExists(destination)) return false;
|
|
10616
|
-
const temporary = `${destination}.${
|
|
11253
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
10617
11254
|
try {
|
|
10618
11255
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
10619
11256
|
await rename2(temporary, destination);
|
|
@@ -10682,7 +11319,7 @@ async function importMediaBuffer(input) {
|
|
|
10682
11319
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
10683
11320
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
10684
11321
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
10685
|
-
const sha256 =
|
|
11322
|
+
const sha256 = createHash5("sha256").update(input.bytes).digest("hex");
|
|
10686
11323
|
return importKnownMedia({
|
|
10687
11324
|
dataDir: input.dataDir,
|
|
10688
11325
|
projectId: input.projectId,
|
|
@@ -10700,7 +11337,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
10700
11337
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
10701
11338
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
10702
11339
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
10703
|
-
const sha256 =
|
|
11340
|
+
const sha256 = createHash5("sha256").update(bytes).digest("hex");
|
|
10704
11341
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
10705
11342
|
return bytes;
|
|
10706
11343
|
}
|
|
@@ -63570,7 +64207,7 @@ var require_gaxios = __commonJS({
|
|
|
63570
64207
|
var retry_js_1 = require_retry3();
|
|
63571
64208
|
var stream_1 = __require("stream");
|
|
63572
64209
|
var interceptor_js_1 = require_interceptor();
|
|
63573
|
-
var
|
|
64210
|
+
var randomUUID19 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
63574
64211
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
63575
64212
|
var Gaxios = class {
|
|
63576
64213
|
agentCache = /* @__PURE__ */ new Map();
|
|
@@ -63843,7 +64480,7 @@ var require_gaxios = __commonJS({
|
|
|
63843
64480
|
*/
|
|
63844
64481
|
["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
63845
64482
|
if (opts.multipart?.length) {
|
|
63846
|
-
const boundary = await
|
|
64483
|
+
const boundary = await randomUUID19();
|
|
63847
64484
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
63848
64485
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
63849
64486
|
} else if (shouldDirectlyPassData) {
|
|
@@ -76070,7 +76707,7 @@ var require_websocket = __commonJS({
|
|
|
76070
76707
|
var http3 = __require("http");
|
|
76071
76708
|
var net = __require("net");
|
|
76072
76709
|
var tls = __require("tls");
|
|
76073
|
-
var { randomBytes: randomBytes2, createHash:
|
|
76710
|
+
var { randomBytes: randomBytes2, createHash: createHash17 } = __require("crypto");
|
|
76074
76711
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
76075
76712
|
var { URL: URL2 } = __require("url");
|
|
76076
76713
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -76738,7 +77375,7 @@ var require_websocket = __commonJS({
|
|
|
76738
77375
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
76739
77376
|
return;
|
|
76740
77377
|
}
|
|
76741
|
-
const digest2 =
|
|
77378
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
76742
77379
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
76743
77380
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
76744
77381
|
return;
|
|
@@ -77110,7 +77747,7 @@ var require_websocket_server = __commonJS({
|
|
|
77110
77747
|
var EventEmitter2 = __require("events");
|
|
77111
77748
|
var http3 = __require("http");
|
|
77112
77749
|
var { Duplex } = __require("stream");
|
|
77113
|
-
var { createHash:
|
|
77750
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
77114
77751
|
var extension3 = require_extension();
|
|
77115
77752
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
77116
77753
|
var subprotocol2 = require_subprotocol();
|
|
@@ -77417,7 +78054,7 @@ var require_websocket_server = __commonJS({
|
|
|
77417
78054
|
);
|
|
77418
78055
|
}
|
|
77419
78056
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
77420
|
-
const digest2 =
|
|
78057
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
77421
78058
|
const headers = [
|
|
77422
78059
|
"HTTP/1.1 101 Switching Protocols",
|
|
77423
78060
|
"Upgrade: websocket",
|
|
@@ -144671,6 +145308,186 @@ var init_audio_jobs = __esm({
|
|
|
144671
145308
|
}
|
|
144672
145309
|
});
|
|
144673
145310
|
|
|
145311
|
+
// src/memory/feedback-model.ts
|
|
145312
|
+
function feedbackWeightMultiplier(weight) {
|
|
145313
|
+
return Math.max(0.35, Math.min(1.4, 0.35 + Math.max(0, Math.min(2, weight)) * 0.525));
|
|
145314
|
+
}
|
|
145315
|
+
var init_feedback_model = __esm({
|
|
145316
|
+
"src/memory/feedback-model.ts"() {
|
|
145317
|
+
"use strict";
|
|
145318
|
+
init_esm_shims();
|
|
145319
|
+
}
|
|
145320
|
+
});
|
|
145321
|
+
|
|
145322
|
+
// src/memory/feedback.ts
|
|
145323
|
+
var feedback_exports = {};
|
|
145324
|
+
__export(feedback_exports, {
|
|
145325
|
+
FEEDBACK_DELTAS: () => FEEDBACK_DELTAS,
|
|
145326
|
+
MemoryFeedbackStore: () => MemoryFeedbackStore,
|
|
145327
|
+
applyMemoryFeedback: () => applyMemoryFeedback,
|
|
145328
|
+
feedbackWeightMultiplier: () => feedbackWeightMultiplier
|
|
145329
|
+
});
|
|
145330
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
145331
|
+
function applyMemoryFeedback(current, event) {
|
|
145332
|
+
const delta = event.signal === "revoke" ? 0 : FEEDBACK_DELTAS[event.signal];
|
|
145333
|
+
const weight = Math.max(0, Math.min(2, current.weight + delta));
|
|
145334
|
+
const status = (event.signal === "code-conflict" || event.signal === "user-correction" || event.signal === "weaken") && weight < 0.5 ? "archived" : current.status;
|
|
145335
|
+
return { weight, status, audit: [...current.audit, { ...event }] };
|
|
145336
|
+
}
|
|
145337
|
+
function rowToEvent(row) {
|
|
145338
|
+
return {
|
|
145339
|
+
id: String(row.id),
|
|
145340
|
+
projectId: String(row.project_id),
|
|
145341
|
+
candidateKind: row.candidate_kind,
|
|
145342
|
+
candidateId: String(row.candidate_id),
|
|
145343
|
+
signal: row.signal,
|
|
145344
|
+
...row.observed_at ? { at: String(row.observed_at) } : { at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
145345
|
+
...row.actor ? { actor: String(row.actor) } : {},
|
|
145346
|
+
...row.note ? { note: String(row.note) } : {},
|
|
145347
|
+
...row.source_ref ? { sourceRef: String(row.source_ref) } : {},
|
|
145348
|
+
...row.target_event_id ? { targetEventId: String(row.target_event_id) } : {},
|
|
145349
|
+
delta: Number(row.delta ?? 0)
|
|
145350
|
+
};
|
|
145351
|
+
}
|
|
145352
|
+
var FEEDBACK_DELTAS, MemoryFeedbackStore;
|
|
145353
|
+
var init_feedback = __esm({
|
|
145354
|
+
"src/memory/feedback.ts"() {
|
|
145355
|
+
"use strict";
|
|
145356
|
+
init_esm_shims();
|
|
145357
|
+
init_sqlite_db();
|
|
145358
|
+
init_feedback_model();
|
|
145359
|
+
FEEDBACK_DELTAS = {
|
|
145360
|
+
"user-correction": -0.35,
|
|
145361
|
+
"verification-success": 0.25,
|
|
145362
|
+
"verification-failure": -0.25,
|
|
145363
|
+
"code-change": -0.15,
|
|
145364
|
+
used: 0.1,
|
|
145365
|
+
"not-used": -0.05,
|
|
145366
|
+
"code-conflict": -0.4,
|
|
145367
|
+
strengthen: 0.2,
|
|
145368
|
+
weaken: -0.2
|
|
145369
|
+
};
|
|
145370
|
+
MemoryFeedbackStore = class {
|
|
145371
|
+
db = null;
|
|
145372
|
+
async init(dataDir) {
|
|
145373
|
+
this.db = getDatabase(dataDir);
|
|
145374
|
+
}
|
|
145375
|
+
requireDb() {
|
|
145376
|
+
if (!this.db) throw new Error("MemoryFeedbackStore is not initialized.");
|
|
145377
|
+
return this.db;
|
|
145378
|
+
}
|
|
145379
|
+
loadEvents(projectId, candidateKind, candidateId) {
|
|
145380
|
+
return this.requireDb().prepare(`
|
|
145381
|
+
SELECT * FROM memory_feedback_events
|
|
145382
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145383
|
+
ORDER BY observed_at ASC, rowid ASC
|
|
145384
|
+
`).all(projectId, candidateKind, candidateId).map(rowToEvent);
|
|
145385
|
+
}
|
|
145386
|
+
rebuild(projectId, candidateKind, candidateId) {
|
|
145387
|
+
const events = this.loadEvents(projectId, candidateKind, candidateId);
|
|
145388
|
+
const revoked = new Set(events.filter((event) => event.signal === "revoke" && event.targetEventId).map((event) => event.targetEventId));
|
|
145389
|
+
let state = { weight: 1, status: "active", audit: [] };
|
|
145390
|
+
for (const event of events) {
|
|
145391
|
+
if (event.signal === "revoke" || revoked.has(event.id)) {
|
|
145392
|
+
state.audit.push(event);
|
|
145393
|
+
continue;
|
|
145394
|
+
}
|
|
145395
|
+
state = applyMemoryFeedback(state, event);
|
|
145396
|
+
}
|
|
145397
|
+
this.requireDb().prepare(`
|
|
145398
|
+
INSERT INTO memory_feedback_states (project_id, candidate_kind, candidate_id, weight, lifecycle_status, updated_at)
|
|
145399
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
145400
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
145401
|
+
weight = excluded.weight, lifecycle_status = excluded.lifecycle_status, updated_at = excluded.updated_at
|
|
145402
|
+
`).run(projectId, candidateKind, candidateId, state.weight, state.status, (/* @__PURE__ */ new Date()).toISOString());
|
|
145403
|
+
return state;
|
|
145404
|
+
}
|
|
145405
|
+
getState(projectId, candidateKind, candidateId) {
|
|
145406
|
+
const row = this.requireDb().prepare(`
|
|
145407
|
+
SELECT weight, lifecycle_status FROM memory_feedback_states
|
|
145408
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145409
|
+
`).get(projectId, candidateKind, candidateId);
|
|
145410
|
+
if (!row) return { weight: 1, status: "active", audit: [] };
|
|
145411
|
+
return {
|
|
145412
|
+
weight: Number(row.weight ?? 1),
|
|
145413
|
+
status: row.lifecycle_status ?? "active",
|
|
145414
|
+
audit: this.loadEvents(projectId, candidateKind, candidateId)
|
|
145415
|
+
};
|
|
145416
|
+
}
|
|
145417
|
+
listStates(projectId, candidateKind = "observation") {
|
|
145418
|
+
return this.requireDb().prepare(`
|
|
145419
|
+
SELECT candidate_id, weight, lifecycle_status, updated_at
|
|
145420
|
+
FROM memory_feedback_states WHERE project_id = ? AND candidate_kind = ?
|
|
145421
|
+
ORDER BY updated_at DESC
|
|
145422
|
+
`).all(projectId, candidateKind).map((row) => ({
|
|
145423
|
+
candidateId: String(row.candidate_id),
|
|
145424
|
+
weight: Number(row.weight),
|
|
145425
|
+
status: row.lifecycle_status,
|
|
145426
|
+
updatedAt: String(row.updated_at)
|
|
145427
|
+
}));
|
|
145428
|
+
}
|
|
145429
|
+
weights(projectId, candidateKind = "observation") {
|
|
145430
|
+
const states = /* @__PURE__ */ new Map();
|
|
145431
|
+
for (const row of this.listStates(projectId, candidateKind)) {
|
|
145432
|
+
states.set(row.candidateId, this.getState(projectId, candidateKind, row.candidateId));
|
|
145433
|
+
}
|
|
145434
|
+
return states;
|
|
145435
|
+
}
|
|
145436
|
+
record(input) {
|
|
145437
|
+
if (input.signal === "revoke" && !input.targetEventId) {
|
|
145438
|
+
throw new Error("A revoke feedback event requires targetEventId.");
|
|
145439
|
+
}
|
|
145440
|
+
if (input.signal === "revoke") {
|
|
145441
|
+
const target = this.requireDb().prepare(`
|
|
145442
|
+
SELECT 1 FROM memory_feedback_events
|
|
145443
|
+
WHERE id = ? AND project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145444
|
+
`).get(input.targetEventId, input.projectId, input.candidateKind, input.candidateId);
|
|
145445
|
+
if (!target) throw new Error("The feedback event to revoke was not found in the same candidate scope.");
|
|
145446
|
+
}
|
|
145447
|
+
const event = {
|
|
145448
|
+
id: randomUUID7(),
|
|
145449
|
+
projectId: input.projectId,
|
|
145450
|
+
candidateKind: input.candidateKind,
|
|
145451
|
+
candidateId: input.candidateId,
|
|
145452
|
+
signal: input.signal,
|
|
145453
|
+
sourceRef: input.sourceRef,
|
|
145454
|
+
...input.actor ? { actor: input.actor } : {},
|
|
145455
|
+
...input.note ? { note: input.note.slice(0, 2e3) } : {},
|
|
145456
|
+
...input.targetEventId ? { targetEventId: input.targetEventId } : {},
|
|
145457
|
+
at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
145458
|
+
delta: input.signal === "revoke" ? 0 : FEEDBACK_DELTAS[input.signal]
|
|
145459
|
+
};
|
|
145460
|
+
this.requireDb().prepare(`
|
|
145461
|
+
INSERT INTO memory_feedback_events (
|
|
145462
|
+
id, project_id, candidate_kind, candidate_id, signal, actor, note,
|
|
145463
|
+
source_ref, target_event_id, delta, observed_at
|
|
145464
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
145465
|
+
`).run(
|
|
145466
|
+
event.id,
|
|
145467
|
+
event.projectId,
|
|
145468
|
+
event.candidateKind,
|
|
145469
|
+
event.candidateId,
|
|
145470
|
+
event.signal,
|
|
145471
|
+
event.actor ?? null,
|
|
145472
|
+
event.note ?? null,
|
|
145473
|
+
event.sourceRef,
|
|
145474
|
+
event.targetEventId ?? null,
|
|
145475
|
+
event.delta,
|
|
145476
|
+
event.at
|
|
145477
|
+
);
|
|
145478
|
+
return { event, state: this.rebuild(input.projectId, input.candidateKind, input.candidateId) };
|
|
145479
|
+
}
|
|
145480
|
+
audit(projectId, candidateKind, candidateId, limit2 = 100) {
|
|
145481
|
+
return this.requireDb().prepare(`
|
|
145482
|
+
SELECT * FROM memory_feedback_events
|
|
145483
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145484
|
+
ORDER BY observed_at DESC, rowid DESC LIMIT ?
|
|
145485
|
+
`).all(projectId, candidateKind, candidateId, Math.min(200, Math.max(1, Math.floor(limit2)))).map(rowToEvent);
|
|
145486
|
+
}
|
|
145487
|
+
};
|
|
145488
|
+
}
|
|
145489
|
+
});
|
|
145490
|
+
|
|
144674
145491
|
// src/memory/retention.ts
|
|
144675
145492
|
var retention_exports = {};
|
|
144676
145493
|
__export(retention_exports, {
|
|
@@ -144712,6 +145529,7 @@ function getEffectiveRetentionDays(doc) {
|
|
|
144712
145529
|
}
|
|
144713
145530
|
function isImmune(doc) {
|
|
144714
145531
|
if (doc.type === "probe") return false;
|
|
145532
|
+
if (doc.feedbackStatus === "archived") return false;
|
|
144715
145533
|
if (doc.admissionState === "candidate" || doc.admissionState === "ephemeral") return false;
|
|
144716
145534
|
if (doc.valueCategory === "core") return true;
|
|
144717
145535
|
const importance = getImportanceLevel(doc);
|
|
@@ -144744,7 +145562,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
144744
145562
|
const decayFactor = Math.exp(-ageDays / retention);
|
|
144745
145563
|
const accessCount = doc.accessCount ?? 0;
|
|
144746
145564
|
const accessBoost = Math.min(2, 1 + 0.1 * accessCount);
|
|
144747
|
-
|
|
145565
|
+
const feedbackMultiplier = doc.feedbackWeight === void 0 ? 1 : feedbackWeightMultiplier(doc.feedbackWeight);
|
|
145566
|
+
let totalScore = base * decayFactor * accessBoost * feedbackMultiplier;
|
|
144748
145567
|
const immune = isImmune(doc);
|
|
144749
145568
|
if (immune) {
|
|
144750
145569
|
totalScore = Math.max(totalScore, 0.5);
|
|
@@ -144756,7 +145575,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
144756
145575
|
decayFactor,
|
|
144757
145576
|
accessBoost,
|
|
144758
145577
|
ageDays,
|
|
144759
|
-
isImmune: immune
|
|
145578
|
+
isImmune: immune,
|
|
145579
|
+
feedbackMultiplier
|
|
144760
145580
|
};
|
|
144761
145581
|
}
|
|
144762
145582
|
function rankByRelevance(docs, referenceTime) {
|
|
@@ -144764,6 +145584,7 @@ function rankByRelevance(docs, referenceTime) {
|
|
|
144764
145584
|
}
|
|
144765
145585
|
function getRetentionZone(doc, referenceTime) {
|
|
144766
145586
|
const now3 = referenceTime ?? /* @__PURE__ */ new Date();
|
|
145587
|
+
if (doc.feedbackStatus === "archived") return "archive-candidate";
|
|
144767
145588
|
const importance = getImportanceLevel(doc);
|
|
144768
145589
|
const retention = getEffectiveRetentionDays(doc);
|
|
144769
145590
|
const createdAt = new Date(doc.createdAt);
|
|
@@ -144835,7 +145656,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
144835
145656
|
summary: parts.join(" ; ")
|
|
144836
145657
|
};
|
|
144837
145658
|
}
|
|
144838
|
-
function toRetentionDocument(obs, accessMap) {
|
|
145659
|
+
function toRetentionDocument(obs, accessMap, feedback) {
|
|
144839
145660
|
const access3 = accessMap?.get(obs.id);
|
|
144840
145661
|
return {
|
|
144841
145662
|
id: `obs-${obs.id}`,
|
|
@@ -144857,11 +145678,12 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
144857
145678
|
sourceDetail: obs.sourceDetail ?? "",
|
|
144858
145679
|
valueCategory: obs.valueCategory ?? "",
|
|
144859
145680
|
admissionState: obs.admissionState ?? "",
|
|
144860
|
-
admissionReason: obs.admissionReason ?? ""
|
|
145681
|
+
admissionReason: obs.admissionReason ?? "",
|
|
145682
|
+
...feedback ? { feedbackWeight: feedback.weight, feedbackStatus: feedback.status } : {}
|
|
144861
145683
|
};
|
|
144862
145684
|
}
|
|
144863
145685
|
function projectObservationRetention(observation, options = {}) {
|
|
144864
|
-
const document2 = toRetentionDocument(observation, options.accessMap);
|
|
145686
|
+
const document2 = toRetentionDocument(observation, options.accessMap, options.feedback);
|
|
144865
145687
|
const relevance = calculateRelevance(document2, options.referenceTime);
|
|
144866
145688
|
const explanation = explainRetention(document2, options.referenceTime);
|
|
144867
145689
|
return {
|
|
@@ -144886,7 +145708,17 @@ function summarizeRetentionProjections(projections) {
|
|
|
144886
145708
|
}
|
|
144887
145709
|
return { active, stale, archiveCandidates, immune };
|
|
144888
145710
|
}
|
|
144889
|
-
async function
|
|
145711
|
+
async function loadFeedbackStore(dataDir) {
|
|
145712
|
+
try {
|
|
145713
|
+
const { MemoryFeedbackStore: MemoryFeedbackStore2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
|
|
145714
|
+
const store = new MemoryFeedbackStore2();
|
|
145715
|
+
await store.init(dataDir);
|
|
145716
|
+
return store;
|
|
145717
|
+
} catch {
|
|
145718
|
+
return void 0;
|
|
145719
|
+
}
|
|
145720
|
+
}
|
|
145721
|
+
async function archiveExpiredBatch(projectDir2, options) {
|
|
144890
145722
|
const store = getObservationStore();
|
|
144891
145723
|
const limit2 = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));
|
|
144892
145724
|
const afterId = Math.max(0, Math.floor(options.afterId ?? 0));
|
|
@@ -144895,11 +145727,13 @@ async function archiveExpiredBatch(_projectDir, options) {
|
|
|
144895
145727
|
afterId,
|
|
144896
145728
|
limit: limit2 + 1
|
|
144897
145729
|
});
|
|
145730
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
144898
145731
|
const hasMore = page.length > limit2;
|
|
144899
145732
|
const scanned = hasMore ? page.slice(0, limit2) : page;
|
|
144900
145733
|
const candidateIds = scanned.filter((observation) => !options.reader || canManageObservation(observation, options.reader)).filter((observation) => projectObservationRetention(observation, {
|
|
144901
145734
|
accessMap: options.accessMap,
|
|
144902
|
-
referenceTime: options.referenceTime
|
|
145735
|
+
referenceTime: options.referenceTime,
|
|
145736
|
+
...feedback ? { feedback: feedback.getState(options.projectId, "observation", String(observation.id)) } : {}
|
|
144903
145737
|
}).zone === "archive-candidate").map((observation) => observation.id);
|
|
144904
145738
|
const archived = candidateIds.length === 0 ? 0 : await store.atomic(async (tx) => {
|
|
144905
145739
|
const updates = await Promise.all(
|
|
@@ -144930,6 +145764,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
144930
145764
|
const remaining = reader2 ? remainingObservations.filter((observation) => canManageObservation(observation, reader2)).length : remainingObservations.length;
|
|
144931
145765
|
return { archived, remaining };
|
|
144932
145766
|
}
|
|
145767
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
144933
145768
|
return await store.atomic(async (tx) => {
|
|
144934
145769
|
const allObs = await tx.loadAll();
|
|
144935
145770
|
const activeObs = allObs.filter(
|
|
@@ -144937,7 +145772,11 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
144937
145772
|
);
|
|
144938
145773
|
const archivedIds = [];
|
|
144939
145774
|
for (const obs of activeObs) {
|
|
144940
|
-
const retention = projectObservationRetention(obs, {
|
|
145775
|
+
const retention = projectObservationRetention(obs, {
|
|
145776
|
+
accessMap,
|
|
145777
|
+
referenceTime,
|
|
145778
|
+
...feedback ? { feedback: feedback.getState(obs.projectId, "observation", String(obs.id)) } : {}
|
|
145779
|
+
});
|
|
144941
145780
|
if (retention.zone === "archive-candidate") {
|
|
144942
145781
|
archivedIds.push(obs.id);
|
|
144943
145782
|
}
|
|
@@ -144957,6 +145796,7 @@ var init_retention = __esm({
|
|
|
144957
145796
|
init_esm_shims();
|
|
144958
145797
|
init_obs_store();
|
|
144959
145798
|
init_visibility();
|
|
145799
|
+
init_feedback_model();
|
|
144960
145800
|
RETENTION_DAYS = {
|
|
144961
145801
|
critical: 365,
|
|
144962
145802
|
high: 180,
|
|
@@ -144997,7 +145837,7 @@ var owner_exports = {};
|
|
|
144997
145837
|
__export(owner_exports, {
|
|
144998
145838
|
resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
|
|
144999
145839
|
});
|
|
145000
|
-
import { randomUUID as
|
|
145840
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
145001
145841
|
import { promises as fs12 } from "fs";
|
|
145002
145842
|
import path20 from "path";
|
|
145003
145843
|
function ownerPath(dataDir) {
|
|
@@ -145027,7 +145867,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
|
|
|
145027
145867
|
await fs12.mkdir(path20.dirname(filePath), { recursive: true });
|
|
145028
145868
|
const created = {
|
|
145029
145869
|
version: 1,
|
|
145030
|
-
id: "local-" +
|
|
145870
|
+
id: "local-" + randomUUID8(),
|
|
145031
145871
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
145032
145872
|
};
|
|
145033
145873
|
try {
|
|
@@ -145050,7 +145890,7 @@ var init_owner = __esm({
|
|
|
145050
145890
|
});
|
|
145051
145891
|
|
|
145052
145892
|
// src/memory/long-term-store.ts
|
|
145053
|
-
import { randomUUID as
|
|
145893
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
145054
145894
|
function optionalText2(value) {
|
|
145055
145895
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
145056
145896
|
}
|
|
@@ -145101,7 +145941,7 @@ function rowToEvidence(row) {
|
|
|
145101
145941
|
createdAt: row.createdAt
|
|
145102
145942
|
};
|
|
145103
145943
|
}
|
|
145104
|
-
function
|
|
145944
|
+
function rowToEvent2(row) {
|
|
145105
145945
|
return {
|
|
145106
145946
|
id: row.id,
|
|
145107
145947
|
memoryId: row.memoryId,
|
|
@@ -145210,7 +146050,7 @@ var init_long_term_store = __esm({
|
|
|
145210
146050
|
}
|
|
145211
146051
|
insertEvidence(input) {
|
|
145212
146052
|
const evidence = {
|
|
145213
|
-
id:
|
|
146053
|
+
id: randomUUID9(),
|
|
145214
146054
|
...input,
|
|
145215
146055
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
145216
146056
|
};
|
|
@@ -145237,7 +146077,7 @@ var init_long_term_store = __esm({
|
|
|
145237
146077
|
}
|
|
145238
146078
|
recordEvent(input) {
|
|
145239
146079
|
const event = {
|
|
145240
|
-
id:
|
|
146080
|
+
id: randomUUID9(),
|
|
145241
146081
|
...input,
|
|
145242
146082
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
145243
146083
|
};
|
|
@@ -145258,7 +146098,7 @@ var init_long_term_store = __esm({
|
|
|
145258
146098
|
listEvents(memoryId) {
|
|
145259
146099
|
return this.db.prepare(`
|
|
145260
146100
|
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
145261
|
-
`).all(memoryId).map(
|
|
146101
|
+
`).all(memoryId).map(rowToEvent2);
|
|
145262
146102
|
}
|
|
145263
146103
|
markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
145264
146104
|
const unique2 = [...new Set(ids.filter(Boolean))];
|
|
@@ -145327,7 +146167,7 @@ __export(long_term_exports, {
|
|
|
145327
146167
|
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
145328
146168
|
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
145329
146169
|
});
|
|
145330
|
-
import { randomUUID as
|
|
146170
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
145331
146171
|
function isOneOf(value, values) {
|
|
145332
146172
|
return typeof value === "string" && values.includes(value);
|
|
145333
146173
|
}
|
|
@@ -145509,7 +146349,7 @@ async function createManualLongTermMemory(input) {
|
|
|
145509
146349
|
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
145510
146350
|
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
145511
146351
|
assertScope(input.scope);
|
|
145512
|
-
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" +
|
|
146352
|
+
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID10(), relation: "supports" }];
|
|
145513
146353
|
return createLongTermMemoryWithDataDir({
|
|
145514
146354
|
dataDir: input.dataDir,
|
|
145515
146355
|
originProjectId: input.projectId,
|
|
@@ -145564,7 +146404,7 @@ async function createLongTermMemoryWithDataDir(input) {
|
|
|
145564
146404
|
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
145565
146405
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
145566
146406
|
const memory = {
|
|
145567
|
-
id:
|
|
146407
|
+
id: randomUUID10(),
|
|
145568
146408
|
originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
|
|
145569
146409
|
ownerId: compactText(input.ownerId, "owner id", 160),
|
|
145570
146410
|
scope: input.scope,
|
|
@@ -145882,9 +146722,9 @@ var init_long_term = __esm({
|
|
|
145882
146722
|
});
|
|
145883
146723
|
|
|
145884
146724
|
// src/codegraph/ids.ts
|
|
145885
|
-
import { createHash as
|
|
146725
|
+
import { createHash as createHash6 } from "crypto";
|
|
145886
146726
|
function digest(input) {
|
|
145887
|
-
return
|
|
146727
|
+
return createHash6("sha256").update(input).digest("hex").slice(0, 16);
|
|
145888
146728
|
}
|
|
145889
146729
|
function normalizeCodePath(path37) {
|
|
145890
146730
|
return path37.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -145919,7 +146759,7 @@ var store_exports = {};
|
|
|
145919
146759
|
__export(store_exports, {
|
|
145920
146760
|
CodeGraphStore: () => CodeGraphStore
|
|
145921
146761
|
});
|
|
145922
|
-
import { randomUUID as
|
|
146762
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
145923
146763
|
import { posix as pathPosix } from "path";
|
|
145924
146764
|
function rowToFile(row) {
|
|
145925
146765
|
return {
|
|
@@ -146636,7 +147476,7 @@ var init_store = __esm({
|
|
|
146636
147476
|
* so an interrupted scan cannot be advertised as complete.
|
|
146637
147477
|
*/
|
|
146638
147478
|
recordCodeStateSnapshot(input) {
|
|
146639
|
-
const id =
|
|
147479
|
+
const id = randomUUID11();
|
|
146640
147480
|
let snapshot;
|
|
146641
147481
|
const tx = this.db.transaction(() => {
|
|
146642
147482
|
const previous = this.db.prepare(
|
|
@@ -146714,7 +147554,7 @@ var init_store = __esm({
|
|
|
146714
147554
|
|
|
146715
147555
|
// src/codegraph/code-state.ts
|
|
146716
147556
|
import { execFile as execFile2 } from "child_process";
|
|
146717
|
-
import { createHash as
|
|
147557
|
+
import { createHash as createHash7 } from "crypto";
|
|
146718
147558
|
import { promisify as promisify3 } from "util";
|
|
146719
147559
|
async function runGit(rootPath, args) {
|
|
146720
147560
|
try {
|
|
@@ -146743,7 +147583,7 @@ function changedPathCount(status) {
|
|
|
146743
147583
|
return count2;
|
|
146744
147584
|
}
|
|
146745
147585
|
function fingerprint(baseRevision, status) {
|
|
146746
|
-
return
|
|
147586
|
+
return createHash7("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
146747
147587
|
}
|
|
146748
147588
|
async function collectCodeStateSnapshot(input) {
|
|
146749
147589
|
const [revision, status] = await Promise.all([
|
|
@@ -146843,11 +147683,11 @@ __export(lite_provider_exports, {
|
|
|
146843
147683
|
indexProjectLite: () => indexProjectLite,
|
|
146844
147684
|
refreshProjectLite: () => refreshProjectLite
|
|
146845
147685
|
});
|
|
146846
|
-
import { createHash as
|
|
147686
|
+
import { createHash as createHash8 } from "crypto";
|
|
146847
147687
|
import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
|
|
146848
147688
|
import { join as join4, relative } from "path";
|
|
146849
147689
|
function hashText(text2) {
|
|
146850
|
-
return
|
|
147690
|
+
return createHash8("sha256").update(text2).digest("hex");
|
|
146851
147691
|
}
|
|
146852
147692
|
function extension2(path37) {
|
|
146853
147693
|
const index = path37.lastIndexOf(".");
|
|
@@ -147414,7 +148254,7 @@ var claim_store_exports = {};
|
|
|
147414
148254
|
__export(claim_store_exports, {
|
|
147415
148255
|
ClaimStore: () => ClaimStore
|
|
147416
148256
|
});
|
|
147417
|
-
import { createHash as
|
|
148257
|
+
import { createHash as createHash9, randomUUID as randomUUID12 } from "crypto";
|
|
147418
148258
|
function optionalText3(value) {
|
|
147419
148259
|
return typeof value === "string" && value ? value : void 0;
|
|
147420
148260
|
}
|
|
@@ -147453,7 +148293,7 @@ function rowToEvidence2(row) {
|
|
|
147453
148293
|
createdAt: row.createdAt
|
|
147454
148294
|
};
|
|
147455
148295
|
}
|
|
147456
|
-
function
|
|
148296
|
+
function rowToEvent3(row) {
|
|
147457
148297
|
return {
|
|
147458
148298
|
id: row.id,
|
|
147459
148299
|
projectId: row.projectId,
|
|
@@ -147467,7 +148307,7 @@ function rowToEvent2(row) {
|
|
|
147467
148307
|
};
|
|
147468
148308
|
}
|
|
147469
148309
|
function evidenceKey(input) {
|
|
147470
|
-
return
|
|
148310
|
+
return createHash9("sha256").update(JSON.stringify([
|
|
147471
148311
|
input.evidenceKind,
|
|
147472
148312
|
input.evidenceId,
|
|
147473
148313
|
input.relation,
|
|
@@ -147598,7 +148438,7 @@ var init_claim_store = __esm({
|
|
|
147598
148438
|
locator, capturedHash, evidenceKey, createdAt
|
|
147599
148439
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
147600
148440
|
`).run(
|
|
147601
|
-
|
|
148441
|
+
randomUUID12(),
|
|
147602
148442
|
input.claimId,
|
|
147603
148443
|
input.evidenceKind,
|
|
147604
148444
|
input.evidenceId,
|
|
@@ -147620,7 +148460,7 @@ var init_claim_store = __esm({
|
|
|
147620
148460
|
}
|
|
147621
148461
|
recordEvent(input) {
|
|
147622
148462
|
const event = {
|
|
147623
|
-
id:
|
|
148463
|
+
id: randomUUID12(),
|
|
147624
148464
|
...input,
|
|
147625
148465
|
...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
|
|
147626
148466
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -147648,7 +148488,7 @@ var init_claim_store = __esm({
|
|
|
147648
148488
|
SELECT * FROM knowledge_claim_events
|
|
147649
148489
|
WHERE claimId = ?
|
|
147650
148490
|
ORDER BY createdAt ASC, id
|
|
147651
|
-
`).all(claimId).map(
|
|
148491
|
+
`).all(claimId).map(rowToEvent3);
|
|
147652
148492
|
}
|
|
147653
148493
|
};
|
|
147654
148494
|
}
|
|
@@ -147665,7 +148505,7 @@ __export(claims_exports, {
|
|
|
147665
148505
|
supersedeClaim: () => supersedeClaim,
|
|
147666
148506
|
writeClaim: () => writeClaim
|
|
147667
148507
|
});
|
|
147668
|
-
import { createHash as
|
|
148508
|
+
import { createHash as createHash10, randomUUID as randomUUID13 } from "crypto";
|
|
147669
148509
|
function compactText2(value, field) {
|
|
147670
148510
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
147671
148511
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -147677,7 +148517,7 @@ function normalizedTerm(value) {
|
|
|
147677
148517
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
147678
148518
|
}
|
|
147679
148519
|
function hashIdentity(parts) {
|
|
147680
|
-
return
|
|
148520
|
+
return createHash10("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
147681
148521
|
}
|
|
147682
148522
|
function buildClaimIdentity(input) {
|
|
147683
148523
|
const subject = normalizedTerm(input.subject);
|
|
@@ -147751,7 +148591,7 @@ function normalizeClaimInput(input) {
|
|
|
147751
148591
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
147752
148592
|
return {
|
|
147753
148593
|
claim: {
|
|
147754
|
-
id:
|
|
148594
|
+
id: randomUUID13(),
|
|
147755
148595
|
projectId,
|
|
147756
148596
|
subject,
|
|
147757
148597
|
predicate,
|
|
@@ -147918,7 +148758,7 @@ function supersedeClaim(store, input) {
|
|
|
147918
148758
|
});
|
|
147919
148759
|
}
|
|
147920
148760
|
function hashObservation(observation) {
|
|
147921
|
-
return
|
|
148761
|
+
return createHash10("sha256").update(JSON.stringify([
|
|
147922
148762
|
observation.title,
|
|
147923
148763
|
observation.narrative,
|
|
147924
148764
|
observation.facts,
|
|
@@ -148162,11 +149002,11 @@ var init_frontmatter = __esm({
|
|
|
148162
149002
|
});
|
|
148163
149003
|
|
|
148164
149004
|
// src/knowledge/markdown.ts
|
|
148165
|
-
import { createHash as
|
|
149005
|
+
import { createHash as createHash11 } from "crypto";
|
|
148166
149006
|
import { promises as fs13 } from "fs";
|
|
148167
149007
|
import path21 from "path";
|
|
148168
149008
|
function hashContent(content) {
|
|
148169
|
-
return
|
|
149009
|
+
return createHash11("sha256").update(content).digest("hex");
|
|
148170
149010
|
}
|
|
148171
149011
|
function stringField(data, key) {
|
|
148172
149012
|
const value = data[key];
|
|
@@ -148292,11 +149132,11 @@ __export(wiki_exports, {
|
|
|
148292
149132
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
148293
149133
|
readKnowledgePage: () => readKnowledgePage
|
|
148294
149134
|
});
|
|
148295
|
-
import { createHash as
|
|
149135
|
+
import { createHash as createHash12 } from "crypto";
|
|
148296
149136
|
import { promises as fs14 } from "fs";
|
|
148297
149137
|
import path22 from "path";
|
|
148298
149138
|
function hash2(value) {
|
|
148299
|
-
return
|
|
149139
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
148300
149140
|
}
|
|
148301
149141
|
function now() {
|
|
148302
149142
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -148840,7 +149680,7 @@ var workflow_store_exports = {};
|
|
|
148840
149680
|
__export(workflow_store_exports, {
|
|
148841
149681
|
WorkflowStore: () => WorkflowStore
|
|
148842
149682
|
});
|
|
148843
|
-
import { randomUUID as
|
|
149683
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
148844
149684
|
function parseJson(value, fallback) {
|
|
148845
149685
|
if (typeof value !== "string" || !value) return fallback;
|
|
148846
149686
|
try {
|
|
@@ -148940,7 +149780,7 @@ var init_workflow_store = __esm({
|
|
|
148940
149780
|
}
|
|
148941
149781
|
recordRun(input) {
|
|
148942
149782
|
const run = {
|
|
148943
|
-
id:
|
|
149783
|
+
id: randomUUID14(),
|
|
148944
149784
|
workflowId: input.workflowId,
|
|
148945
149785
|
projectId: input.projectId,
|
|
148946
149786
|
task: input.task.trim(),
|
|
@@ -149018,7 +149858,7 @@ var init_outcome_types = __esm({
|
|
|
149018
149858
|
});
|
|
149019
149859
|
|
|
149020
149860
|
// src/knowledge/outcome-store.ts
|
|
149021
|
-
import { randomUUID as
|
|
149861
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
149022
149862
|
function optionalText5(value) {
|
|
149023
149863
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
149024
149864
|
}
|
|
@@ -149062,7 +149902,7 @@ var init_outcome_store = __esm({
|
|
|
149062
149902
|
}
|
|
149063
149903
|
record(input) {
|
|
149064
149904
|
const signal = {
|
|
149065
|
-
id:
|
|
149905
|
+
id: randomUUID15(),
|
|
149066
149906
|
projectId: text(input.projectId, "project id"),
|
|
149067
149907
|
candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
|
|
149068
149908
|
candidateId: text(input.candidateId, "candidate id"),
|
|
@@ -149489,11 +150329,11 @@ __export(workflows_exports, {
|
|
|
149489
150329
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
149490
150330
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
149491
150331
|
});
|
|
149492
|
-
import { createHash as
|
|
150332
|
+
import { createHash as createHash13 } from "crypto";
|
|
149493
150333
|
import { promises as fs15 } from "fs";
|
|
149494
150334
|
import path23 from "path";
|
|
149495
150335
|
function hash3(value) {
|
|
149496
|
-
return
|
|
150336
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
149497
150337
|
}
|
|
149498
150338
|
function now2() {
|
|
149499
150339
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -150890,6 +151730,16 @@ async function bindObservationCodeRefsBestEffort(observation) {
|
|
|
150890
151730
|
} catch {
|
|
150891
151731
|
}
|
|
150892
151732
|
}
|
|
151733
|
+
async function persistEvidenceCard(observation) {
|
|
151734
|
+
if (!projectDir) return;
|
|
151735
|
+
try {
|
|
151736
|
+
const evidence = new EvidenceCardStore();
|
|
151737
|
+
await evidence.init(projectDir);
|
|
151738
|
+
evidence.upsertObservation(observation);
|
|
151739
|
+
} catch (error) {
|
|
151740
|
+
console.error(`[memorix] Evidence card projection failed for obs-${observation.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
151741
|
+
}
|
|
151742
|
+
}
|
|
150893
151743
|
function queueClaimDerivation(observation) {
|
|
150894
151744
|
const dataDir = projectDir;
|
|
150895
151745
|
const isExplicit = observation.sourceDetail === "explicit";
|
|
@@ -151236,6 +152086,7 @@ async function storeObservation(input) {
|
|
|
151236
152086
|
}
|
|
151237
152087
|
if (!persistedCallbackInvoked) await input.onPersisted?.(observation);
|
|
151238
152088
|
await bindObservationCodeRefsBestEffort(observation);
|
|
152089
|
+
await persistEvidenceCard(observation);
|
|
151239
152090
|
queueObservationQualification(observation);
|
|
151240
152091
|
if (resolveObservationVisibility(observation) === "project") {
|
|
151241
152092
|
queueClaimDerivation(observation);
|
|
@@ -151328,6 +152179,7 @@ async function upsertObservation(existing, input, now3) {
|
|
|
151328
152179
|
await store.update(existing);
|
|
151329
152180
|
}
|
|
151330
152181
|
await bindObservationCodeRefsBestEffort(existing);
|
|
152182
|
+
await persistEvidenceCard(existing);
|
|
151331
152183
|
queueObservationQualification(existing);
|
|
151332
152184
|
if (resolveObservationVisibility(existing) === "project") {
|
|
151333
152185
|
queueClaimDerivation(existing);
|
|
@@ -151461,6 +152313,7 @@ async function resolveObservations(ids, status = "resolved") {
|
|
|
151461
152313
|
await Promise.all(changed.map((observation) => tx.update(observation)));
|
|
151462
152314
|
});
|
|
151463
152315
|
}
|
|
152316
|
+
for (const observation of changed) await persistEvidenceCard(observation);
|
|
151464
152317
|
return { resolved, notFound };
|
|
151465
152318
|
}
|
|
151466
152319
|
function getProjectObservations(projectId) {
|
|
@@ -151798,6 +152651,7 @@ var init_observations = __esm({
|
|
|
151798
152651
|
init_secret_filter();
|
|
151799
152652
|
init_lifecycle();
|
|
151800
152653
|
init_visibility();
|
|
152654
|
+
init_evidence_store();
|
|
151801
152655
|
observations = [];
|
|
151802
152656
|
nextId = 1;
|
|
151803
152657
|
projectDir = null;
|
|
@@ -152629,9 +153483,27 @@ function normalizeMemoryBrowseQuery(query) {
|
|
|
152629
153483
|
async function compactSearch(options, surface = "mcp") {
|
|
152630
153484
|
await ensureFreshIndex();
|
|
152631
153485
|
const searchOptions = { ...options, query: normalizeMemoryBrowseQuery(options.query) };
|
|
152632
|
-
|
|
153486
|
+
let entries = (await searchObservations(searchOptions)).map(
|
|
152633
153487
|
(entry) => entry.projectId || !options.projectId ? entry : { ...entry, projectId: options.projectId }
|
|
152634
153488
|
);
|
|
153489
|
+
if (options.projectId) {
|
|
153490
|
+
try {
|
|
153491
|
+
const feedback = new MemoryFeedbackStore();
|
|
153492
|
+
await feedback.init(await getProjectDataDir(options.projectId));
|
|
153493
|
+
const states = feedback.weights(options.projectId, "observation");
|
|
153494
|
+
entries = entries.map((entry) => {
|
|
153495
|
+
const state = states.get(String(entry.id));
|
|
153496
|
+
if (!state) return entry;
|
|
153497
|
+
return {
|
|
153498
|
+
...entry,
|
|
153499
|
+
score: (entry.score ?? 0) * feedbackWeightMultiplier(state.weight),
|
|
153500
|
+
feedbackWeight: state.weight,
|
|
153501
|
+
feedbackStatus: state.status
|
|
153502
|
+
};
|
|
153503
|
+
}).filter((entry) => entry.feedbackStatus !== "archived" || options.status === "all").sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
153504
|
+
} catch {
|
|
153505
|
+
}
|
|
153506
|
+
}
|
|
152635
153507
|
let formatted = formatIndexTable(entries, searchOptions.query, !options.projectId, surface);
|
|
152636
153508
|
if (entries.length === 0 && options.projectId) {
|
|
152637
153509
|
const allObservations = filterReadableObservations(getAllObservations(), options.reader);
|
|
@@ -152950,6 +153822,8 @@ var init_engine3 = __esm({
|
|
|
152950
153822
|
init_mini_skills();
|
|
152951
153823
|
init_secret_filter();
|
|
152952
153824
|
init_visibility();
|
|
153825
|
+
init_persistence();
|
|
153826
|
+
init_feedback();
|
|
152953
153827
|
}
|
|
152954
153828
|
});
|
|
152955
153829
|
|
|
@@ -153571,9 +154445,9 @@ var init_graph_context = __esm({
|
|
|
153571
154445
|
});
|
|
153572
154446
|
|
|
153573
154447
|
// src/rules/utils.ts
|
|
153574
|
-
import { createHash as
|
|
154448
|
+
import { createHash as createHash14 } from "crypto";
|
|
153575
154449
|
function hashContent2(content) {
|
|
153576
|
-
return
|
|
154450
|
+
return createHash14("sha256").update(content.trim()).digest("hex").substring(0, 16);
|
|
153577
154451
|
}
|
|
153578
154452
|
function generateRuleId(source, filePath) {
|
|
153579
154453
|
const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
|
|
@@ -156004,6 +156878,10 @@ var init_tool_profile = __esm({
|
|
|
156004
156878
|
// multimodal support to one additional schema rather than enabling lite.
|
|
156005
156879
|
memorix_session_start: ["micro", "lite", "team", "full"],
|
|
156006
156880
|
memorix_media: ["micro", "lite", "team", "full"],
|
|
156881
|
+
// Evidence and feedback are deliberate operator/context-control surfaces;
|
|
156882
|
+
// keep the default micro profile at its nine-tool token budget.
|
|
156883
|
+
memorix_evidence: ["lite", "team", "full"],
|
|
156884
|
+
memorix_feedback: ["lite", "team", "full"],
|
|
156007
156885
|
// ── lite: extended solo memory surface ────────────────────────────
|
|
156008
156886
|
memorix_graph_context: ["lite", "team", "full"],
|
|
156009
156887
|
memorix_timeline: ["lite", "team", "full"],
|
|
@@ -159462,7 +160340,7 @@ var compaction_checkpoint_store_exports = {};
|
|
|
159462
160340
|
__export(compaction_checkpoint_store_exports, {
|
|
159463
160341
|
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
159464
160342
|
});
|
|
159465
|
-
import { createHash as
|
|
160343
|
+
import { createHash as createHash15, randomUUID as randomUUID16 } from "crypto";
|
|
159466
160344
|
function optionalText7(value) {
|
|
159467
160345
|
return typeof value === "string" && value ? value : void 0;
|
|
159468
160346
|
}
|
|
@@ -159504,7 +160382,7 @@ function sourceKeyFor(input, summary) {
|
|
|
159504
160382
|
input.tokensBefore ?? "",
|
|
159505
160383
|
input.firstKeptEntryId ?? ""
|
|
159506
160384
|
].join("\0");
|
|
159507
|
-
return `derived:${
|
|
160385
|
+
return `derived:${createHash15("sha256").update(material).digest("hex").slice(0, 32)}`;
|
|
159508
160386
|
}
|
|
159509
160387
|
function rowToCheckpoint(row) {
|
|
159510
160388
|
return {
|
|
@@ -159563,7 +160441,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
159563
160441
|
if (pending) return rowToCheckpoint(pending);
|
|
159564
160442
|
const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
159565
160443
|
const checkpoint = {
|
|
159566
|
-
id:
|
|
160444
|
+
id: randomUUID16(),
|
|
159567
160445
|
projectId: input.projectId,
|
|
159568
160446
|
sessionId: input.sessionId,
|
|
159569
160447
|
agent: input.agent,
|
|
@@ -159571,7 +160449,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
159571
160449
|
captureKind: "preflight",
|
|
159572
160450
|
reason: safeReason(input.reason),
|
|
159573
160451
|
sourceEvent: input.sourceEvent,
|
|
159574
|
-
sourceKey: `pre:${
|
|
160452
|
+
sourceKey: `pre:${randomUUID16()}`,
|
|
159575
160453
|
transcriptAvailable: Boolean(input.transcriptAvailable),
|
|
159576
160454
|
status: "active",
|
|
159577
160455
|
preCapturedAt: now3,
|
|
@@ -159637,7 +160515,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
159637
160515
|
return this.get(checkpoint2.id);
|
|
159638
160516
|
}
|
|
159639
160517
|
const checkpoint = {
|
|
159640
|
-
id:
|
|
160518
|
+
id: randomUUID16(),
|
|
159641
160519
|
projectId: input.projectId,
|
|
159642
160520
|
sessionId: input.sessionId,
|
|
159643
160521
|
agent: input.agent,
|
|
@@ -161001,7 +161879,7 @@ __export(team_store_exports, {
|
|
|
161001
161879
|
isTeamStoreInitialized: () => isTeamStoreInitialized,
|
|
161002
161880
|
resetTeamStore: () => resetTeamStore
|
|
161003
161881
|
});
|
|
161004
|
-
import { randomUUID as
|
|
161882
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
161005
161883
|
import path30 from "path";
|
|
161006
161884
|
import fs18 from "fs";
|
|
161007
161885
|
function getTeamStore() {
|
|
@@ -161290,7 +162168,7 @@ var init_team_store = __esm({
|
|
|
161290
162168
|
* reactivate it (preserving agent_id). Otherwise create a new one.
|
|
161291
162169
|
*/
|
|
161292
162170
|
registerAgent(input) {
|
|
161293
|
-
const instanceId = input.instanceId ||
|
|
162171
|
+
const instanceId = input.instanceId || randomUUID17();
|
|
161294
162172
|
const now3 = Date.now();
|
|
161295
162173
|
const existing = this.stmtAgentFindByInstance.get(
|
|
161296
162174
|
input.projectId,
|
|
@@ -161316,7 +162194,7 @@ var init_team_store = __esm({
|
|
|
161316
162194
|
this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
|
|
161317
162195
|
return row2;
|
|
161318
162196
|
}
|
|
161319
|
-
const agentId =
|
|
162197
|
+
const agentId = randomUUID17();
|
|
161320
162198
|
this.stmtAgentUpsert.run({
|
|
161321
162199
|
agent_id: agentId,
|
|
161322
162200
|
project_id: input.projectId,
|
|
@@ -161418,7 +162296,7 @@ var init_team_store = __esm({
|
|
|
161418
162296
|
return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
|
|
161419
162297
|
}
|
|
161420
162298
|
}
|
|
161421
|
-
const id =
|
|
162299
|
+
const id = randomUUID17();
|
|
161422
162300
|
const now3 = Date.now();
|
|
161423
162301
|
const row = {
|
|
161424
162302
|
id,
|
|
@@ -161468,7 +162346,7 @@ var init_team_store = __esm({
|
|
|
161468
162346
|
// Task Operations (with atomic claim semantics)
|
|
161469
162347
|
// ═══════════════════════════════════════════════════════════════════
|
|
161470
162348
|
createTask(input) {
|
|
161471
|
-
const taskId =
|
|
162349
|
+
const taskId = randomUUID17();
|
|
161472
162350
|
const now3 = Date.now();
|
|
161473
162351
|
const row = {
|
|
161474
162352
|
task_id: taskId,
|
|
@@ -161740,7 +162618,7 @@ var init_team_store = __esm({
|
|
|
161740
162618
|
for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
|
|
161741
162619
|
for (const msg of msgs) {
|
|
161742
162620
|
this.stmtMsgInsert.run({
|
|
161743
|
-
id: msg.id ??
|
|
162621
|
+
id: msg.id ?? randomUUID17(),
|
|
161744
162622
|
project_id: "migrated",
|
|
161745
162623
|
sender_agent_id: msg.from ?? "unknown",
|
|
161746
162624
|
recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
|
|
@@ -162611,6 +163489,23 @@ var init_maintenance = __esm({
|
|
|
162611
163489
|
}
|
|
162612
163490
|
});
|
|
162613
163491
|
|
|
163492
|
+
// src/dashboard/config-provenance.ts
|
|
163493
|
+
function resolveDashboardKeySource({ value, envKeys, configSource }) {
|
|
163494
|
+
for (const envKey of envKeys) {
|
|
163495
|
+
const envValue = process.env[envKey];
|
|
163496
|
+
if (envValue !== value) continue;
|
|
163497
|
+
return getLoadedEnvValue(envKey) === envValue ? ".env" : `env:${envKey}`;
|
|
163498
|
+
}
|
|
163499
|
+
return configSource;
|
|
163500
|
+
}
|
|
163501
|
+
var init_config_provenance = __esm({
|
|
163502
|
+
"src/dashboard/config-provenance.ts"() {
|
|
163503
|
+
"use strict";
|
|
163504
|
+
init_esm_shims();
|
|
163505
|
+
init_dotenv_loader();
|
|
163506
|
+
}
|
|
163507
|
+
});
|
|
163508
|
+
|
|
162614
163509
|
// src/dashboard/project-classification.ts
|
|
162615
163510
|
var project_classification_exports = {};
|
|
162616
163511
|
__export(project_classification_exports, {
|
|
@@ -163390,6 +164285,20 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
163390
164285
|
sendJson(res, observations2);
|
|
163391
164286
|
break;
|
|
163392
164287
|
}
|
|
164288
|
+
case "/evidence": {
|
|
164289
|
+
const observations2 = filterDashboardObservations(
|
|
164290
|
+
await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
|
|
164291
|
+
effectiveProjectId
|
|
164292
|
+
);
|
|
164293
|
+
const evidenceStore = new EvidenceCardStore();
|
|
164294
|
+
await evidenceStore.init(effectiveDataDir);
|
|
164295
|
+
evidenceStore.syncObservations(observations2);
|
|
164296
|
+
const query = url.searchParams.get("q") || "";
|
|
164297
|
+
const limit2 = Number(url.searchParams.get("limit") || 20);
|
|
164298
|
+
const cards = evidenceStore.list(effectiveProjectId, { limit: Math.min(100, Math.max(1, limit2)) }).filter((card) => !query || [card.title, card.summary, card.sourceRef, card.locator ?? ""].join(" ").toLowerCase().includes(query.toLowerCase()));
|
|
164299
|
+
sendJson(res, { cards, projectId: effectiveProjectId });
|
|
164300
|
+
break;
|
|
164301
|
+
}
|
|
163393
164302
|
case "/sessions": {
|
|
163394
164303
|
const allSessions = await getSessionStore().loadAll();
|
|
163395
164304
|
const sessions = filterByProject(allSessions, effectiveProjectId);
|
|
@@ -163437,8 +164346,13 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
163437
164346
|
filesModified: o.filesModified
|
|
163438
164347
|
}));
|
|
163439
164348
|
const retentionReferenceTime = new Date(now3);
|
|
164349
|
+
const feedback = new MemoryFeedbackStore();
|
|
164350
|
+
await feedback.init(effectiveDataDir).catch(() => void 0);
|
|
163440
164351
|
const retention = summarizeRetentionProjections(
|
|
163441
|
-
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
164352
|
+
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
164353
|
+
referenceTime: retentionReferenceTime,
|
|
164354
|
+
feedback: feedback.getState(effectiveProjectId, "observation", String(observation.id))
|
|
164355
|
+
}))
|
|
163442
164356
|
);
|
|
163443
164357
|
const retentionSummary = {
|
|
163444
164358
|
active: retention.active,
|
|
@@ -163532,9 +164446,14 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
163532
164446
|
effectiveProjectId
|
|
163533
164447
|
);
|
|
163534
164448
|
const referenceTime = /* @__PURE__ */ new Date();
|
|
164449
|
+
const feedback = new MemoryFeedbackStore();
|
|
164450
|
+
await feedback.init(effectiveDataDir).catch(() => void 0);
|
|
163535
164451
|
const rows = observations2.filter((observation) => observation.type !== "probe").map((observation) => ({
|
|
163536
164452
|
observation,
|
|
163537
|
-
retention: projectObservationRetention(observation, {
|
|
164453
|
+
retention: projectObservationRetention(observation, {
|
|
164454
|
+
referenceTime,
|
|
164455
|
+
feedback: feedback.getState(effectiveProjectId, "observation", String(observation.id))
|
|
164456
|
+
})
|
|
163538
164457
|
})).sort((a, b) => b.retention.displayScore - a.retention.displayScore);
|
|
163539
164458
|
const summary = summarizeRetentionProjections(rows.map((row) => row.retention));
|
|
163540
164459
|
const scored = rows.map(({ observation, retention }) => ({
|
|
@@ -163605,23 +164524,13 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
163605
164524
|
const os6 = await import("os");
|
|
163606
164525
|
const { existsSync: existsSync21 } = await import("fs");
|
|
163607
164526
|
const { join: join26 } = await import("path");
|
|
163608
|
-
let yml = {};
|
|
163609
164527
|
const configProjectRoot = effectiveProjectRoot;
|
|
163610
|
-
|
|
163611
|
-
const { loadYamlConfig: loadYamlConfig2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
|
|
163612
|
-
yml = configProjectRoot ? loadYamlConfig2(configProjectRoot) : loadYamlConfig2(null);
|
|
163613
|
-
} catch {
|
|
163614
|
-
}
|
|
163615
|
-
if (configProjectRoot) {
|
|
163616
|
-
try {
|
|
163617
|
-
const { loadDotenv: loadDotenv2 } = await Promise.resolve().then(() => (init_dotenv_loader(), dotenv_loader_exports));
|
|
163618
|
-
loadDotenv2(configProjectRoot);
|
|
163619
|
-
} catch {
|
|
163620
|
-
}
|
|
163621
|
-
}
|
|
164528
|
+
const resolved = getResolvedConfig({ projectRoot: configProjectRoot });
|
|
163622
164529
|
const files = {
|
|
163623
164530
|
"project memorix.yml": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
163624
164531
|
"user memorix.yml": { exists: false, path: "" },
|
|
164532
|
+
"project memorix.toml": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
164533
|
+
"user config.toml": { exists: false, path: "" },
|
|
163625
164534
|
"project .env": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
163626
164535
|
"user .env": { exists: false, path: "" },
|
|
163627
164536
|
"legacy config.json": { exists: false, path: "" }
|
|
@@ -163631,6 +164540,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
163631
164540
|
const paths = {
|
|
163632
164541
|
"project memorix.yml": configProjectRoot ? join26(configProjectRoot, "memorix.yml") : null,
|
|
163633
164542
|
"user memorix.yml": join26(home, ".memorix", "memorix.yml"),
|
|
164543
|
+
"project memorix.toml": configProjectRoot ? join26(configProjectRoot, "memorix.toml") : null,
|
|
164544
|
+
"user config.toml": join26(home, ".memorix", "config.toml"),
|
|
163634
164545
|
"project .env": configProjectRoot ? join26(configProjectRoot, ".env") : null,
|
|
163635
164546
|
"user .env": join26(home, ".memorix", ".env"),
|
|
163636
164547
|
"legacy config.json": join26(home, ".memorix", "config.json")
|
|
@@ -163645,67 +164556,61 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
163645
164556
|
} catch {
|
|
163646
164557
|
}
|
|
163647
164558
|
const values = [];
|
|
163648
|
-
const
|
|
163649
|
-
|
|
163650
|
-
|
|
163651
|
-
|
|
163652
|
-
|
|
163653
|
-
|
|
163654
|
-
|
|
163655
|
-
|
|
163656
|
-
|
|
163657
|
-
|
|
163658
|
-
|
|
163659
|
-
|
|
163660
|
-
|
|
163661
|
-
|
|
163662
|
-
|
|
163663
|
-
|
|
163664
|
-
|
|
164559
|
+
const tomlSource = configProjectRoot && files["project memorix.toml"].exists ? "memorix.toml" : files["user config.toml"].exists ? "config.toml" : "default";
|
|
164560
|
+
const legacySource = files["project memorix.yml"].exists || files["user memorix.yml"].exists ? "memorix.yml" : files["legacy config.json"].exists ? "config.json" : "default";
|
|
164561
|
+
const configSource = resolved.sources.toml.length > 0 ? tomlSource : resolved.sources.legacy.length > 0 ? legacySource : "default";
|
|
164562
|
+
const source = (envKey) => resolveDashboardKeySource({
|
|
164563
|
+
value: process.env[envKey] ?? "",
|
|
164564
|
+
envKeys: [envKey],
|
|
164565
|
+
configSource
|
|
164566
|
+
});
|
|
164567
|
+
if (resolved.memory.llm.provider) values.push({ key: "llm.provider", value: resolved.memory.llm.provider, source: source("MEMORIX_LLM_PROVIDER") });
|
|
164568
|
+
if (resolved.memory.llm.model) values.push({ key: "llm.model", value: resolved.memory.llm.model, source: source("MEMORIX_LLM_MODEL") });
|
|
164569
|
+
const llmKey = resolved.memory.llm.apiKey;
|
|
164570
|
+
const memoryKeyEnv = [
|
|
164571
|
+
"MEMORIX_LLM_API_KEY",
|
|
164572
|
+
"MEMORIX_API_KEY",
|
|
164573
|
+
"OPENAI_API_KEY",
|
|
164574
|
+
"ANTHROPIC_API_KEY",
|
|
164575
|
+
...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : []
|
|
164576
|
+
];
|
|
163665
164577
|
if (llmKey) {
|
|
163666
|
-
|
|
163667
|
-
if (process.env.MEMORIX_LLM_API_KEY) src = await getEnvSource("MEMORIX_LLM_API_KEY");
|
|
163668
|
-
else if (process.env.MEMORIX_API_KEY) src = await getEnvSource("MEMORIX_API_KEY");
|
|
163669
|
-
else if (yml.llm?.apiKey) src = "memorix.yml (move to .env!)";
|
|
163670
|
-
else if (process.env.OPENAI_API_KEY) src = await getEnvSource("OPENAI_API_KEY");
|
|
164578
|
+
const src = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
|
|
163671
164579
|
values.push({ key: "llm.apiKey", value: "****" + llmKey.slice(-4), source: src, sensitive: true });
|
|
163672
164580
|
} else {
|
|
163673
164581
|
values.push({ key: "llm.apiKey", value: "not set", source: "none" });
|
|
163674
164582
|
}
|
|
163675
|
-
|
|
163676
|
-
|
|
163677
|
-
|
|
163678
|
-
|
|
163679
|
-
|
|
163680
|
-
|
|
163681
|
-
|
|
163682
|
-
}
|
|
163683
|
-
const agentModel = process.env.MEMORIX_AGENT_MODEL || process.env.MEMORIX_AGENT_LLM_MODEL || yml.agent?.model;
|
|
163684
|
-
if (agentModel) {
|
|
163685
|
-
let source;
|
|
163686
|
-
if (process.env.MEMORIX_AGENT_MODEL) source = await getEnvSource("MEMORIX_AGENT_MODEL");
|
|
163687
|
-
else if (process.env.MEMORIX_AGENT_LLM_MODEL) source = `${await getEnvSource("MEMORIX_AGENT_LLM_MODEL")} (legacy)`;
|
|
163688
|
-
else source = yml.agent?.model ? "memorix.yml" : "default";
|
|
163689
|
-
values.push({ key: "agent.model", value: agentModel, source });
|
|
163690
|
-
}
|
|
163691
|
-
const agentKey = process.env.MEMORIX_AGENT_API_KEY || process.env.MEMORIX_AGENT_LLM_API_KEY || yml.agent?.apiKey;
|
|
164583
|
+
if (resolved.agent.provider) {
|
|
164584
|
+
values.push({ key: "agent.provider", value: resolved.agent.provider, source: source("MEMORIX_AGENT_PROVIDER") });
|
|
164585
|
+
}
|
|
164586
|
+
if (resolved.agent.model) {
|
|
164587
|
+
values.push({ key: "agent.model", value: resolved.agent.model, source: source("MEMORIX_AGENT_MODEL") });
|
|
164588
|
+
}
|
|
164589
|
+
const agentKey = resolved.agent.apiKey;
|
|
163692
164590
|
if (agentKey) {
|
|
163693
|
-
|
|
163694
|
-
|
|
163695
|
-
|
|
163696
|
-
|
|
164591
|
+
const src = resolveDashboardKeySource({
|
|
164592
|
+
value: agentKey,
|
|
164593
|
+
envKeys: ["MEMORIX_AGENT_API_KEY", "MEMORIX_AGENT_LLM_API_KEY"],
|
|
164594
|
+
configSource
|
|
164595
|
+
});
|
|
163697
164596
|
values.push({ key: "agent.apiKey", value: "****" + agentKey.slice(-4), source: src, sensitive: true });
|
|
163698
164597
|
} else {
|
|
163699
|
-
values.push({
|
|
163700
|
-
|
|
163701
|
-
|
|
163702
|
-
|
|
163703
|
-
|
|
163704
|
-
|
|
163705
|
-
|
|
163706
|
-
if (
|
|
163707
|
-
|
|
163708
|
-
|
|
164598
|
+
values.push({
|
|
164599
|
+
key: "agent.apiKey",
|
|
164600
|
+
value: "fallback to llm.apiKey",
|
|
164601
|
+
source: llmKey ? resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource }) : "default"
|
|
164602
|
+
});
|
|
164603
|
+
}
|
|
164604
|
+
values.push({ key: "embedding.provider", value: resolved.embedding.provider || "off", source: source("MEMORIX_EMBEDDING") });
|
|
164605
|
+
if (resolved.embedding.model) values.push({ key: "embedding.model", value: resolved.embedding.model, source: source("MEMORIX_EMBEDDING_MODEL") });
|
|
164606
|
+
if (resolved.rerank.provider !== "off") {
|
|
164607
|
+
values.push({ key: "rerank.provider", value: resolved.rerank.provider, source: source("MEMORIX_RERANK_PROVIDER") });
|
|
164608
|
+
if (resolved.rerank.model) values.push({ key: "rerank.model", value: resolved.rerank.model, source: source("MEMORIX_RERANK_MODEL") });
|
|
164609
|
+
}
|
|
164610
|
+
values.push({ key: "git.autoHook", value: String(resolved.git.autoHook ?? false), source: configSource });
|
|
164611
|
+
values.push({ key: "git.skipMergeCommits", value: String(resolved.git.skipMergeCommits ?? true), source: configSource });
|
|
164612
|
+
values.push({ key: "server.transport", value: resolved.server.transport || "stdio", source: configSource });
|
|
164613
|
+
values.push({ key: "server.dashboard", value: String(resolved.server.dashboard ?? true), source: configSource });
|
|
163709
164614
|
sendJson(res, { files, values });
|
|
163710
164615
|
break;
|
|
163711
164616
|
}
|
|
@@ -164153,10 +165058,14 @@ var init_server = __esm({
|
|
|
164153
165058
|
init_dotenv_loader();
|
|
164154
165059
|
init_yaml_loader();
|
|
164155
165060
|
init_yaml_loader();
|
|
165061
|
+
init_resolved_config();
|
|
164156
165062
|
init_graph_scope();
|
|
164157
165063
|
init_retention();
|
|
164158
165064
|
init_visibility();
|
|
165065
|
+
init_evidence_store();
|
|
165066
|
+
init_feedback();
|
|
164159
165067
|
init_maintenance();
|
|
165068
|
+
init_config_provenance();
|
|
164160
165069
|
MIME_TYPES = {
|
|
164161
165070
|
".html": "text/html; charset=utf-8",
|
|
164162
165071
|
".css": "text/css; charset=utf-8",
|
|
@@ -164624,7 +165533,7 @@ __export(planner_exports, {
|
|
|
164624
165533
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
164625
165534
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
164626
165535
|
});
|
|
164627
|
-
import { randomUUID as
|
|
165536
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
164628
165537
|
function isPlannerTask(metadata) {
|
|
164629
165538
|
if (!metadata) return null;
|
|
164630
165539
|
try {
|
|
@@ -164682,7 +165591,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
|
|
|
164682
165591
|
const maxIterations = config.maxIterations ?? 3;
|
|
164683
165592
|
const taskBudget = config.taskBudget ?? 15;
|
|
164684
165593
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
164685
|
-
const pipelineId =
|
|
165594
|
+
const pipelineId = randomUUID18();
|
|
164686
165595
|
const meta = {
|
|
164687
165596
|
plannerType: "plan",
|
|
164688
165597
|
pipelineId,
|
|
@@ -165217,8 +166126,7 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
|
|
|
165217
166126
|
if (!apiKey) {
|
|
165218
166127
|
throw new Error("No LLM API key configured for image analysis.");
|
|
165219
166128
|
}
|
|
165220
|
-
|
|
165221
|
-
if (!baseUrl.endsWith("/v1")) baseUrl += "/v1";
|
|
166129
|
+
const baseUrl = normalizeOpenAICompatibleBaseUrl(getLLMBaseUrl("https://api.openai.com/v1"));
|
|
165222
166130
|
const model = getLLMModel("gpt-4o");
|
|
165223
166131
|
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
165224
166132
|
method: "POST",
|
|
@@ -165355,8 +166263,8 @@ var init_official_skills = __esm({
|
|
|
165355
166263
|
"",
|
|
165356
166264
|
"| Situation | Prefer | CLI fallback |",
|
|
165357
166265
|
"|---|---|---|",
|
|
165358
|
-
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --brief-json` |',
|
|
165359
|
-
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
|
|
166266
|
+
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --fallback --brief-json` |',
|
|
166267
|
+
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --fallback --brief-json` |',
|
|
165360
166268
|
'| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
|
|
165361
166269
|
'| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
|
|
165362
166270
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
@@ -165369,7 +166277,7 @@ var init_official_skills = __esm({
|
|
|
165369
166277
|
"",
|
|
165370
166278
|
"- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user's actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.",
|
|
165371
166279
|
"- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client's tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.",
|
|
165372
|
-
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
166280
|
+
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --fallback --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --fallback --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
165373
166281
|
"- After a successful `memorix_project_context`, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use Context Pack, search, or detail only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
165374
166282
|
"- If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
165375
166283
|
"- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer. Fetch detail only for a result you still need after the brief.",
|
|
@@ -166628,7 +167536,7 @@ alwaysApply: true
|
|
|
166628
167536
|
"",
|
|
166629
167537
|
`Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). When the task is continuing prior work, the same brief also includes a bounded prior-work projection. Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
166630
167538
|
"",
|
|
166631
|
-
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --brief-json`. For a new task, use `memorix context "<task>" --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
167539
|
+
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --fallback --brief-json`. For a new task, use `memorix context "<task>" --fallback --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
166632
167540
|
"",
|
|
166633
167541
|
"After a successful `memorix_project_context` result, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use `memorix_context_pack`, `memorix_search`, or `memorix_detail` only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
166634
167542
|
"If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
@@ -166926,7 +167834,7 @@ __export(server_exports2, {
|
|
|
166926
167834
|
createMemorixServer: () => createMemorixServer,
|
|
166927
167835
|
shouldAwaitProjectRuntime: () => shouldAwaitProjectRuntime
|
|
166928
167836
|
});
|
|
166929
|
-
import { createHash as
|
|
167837
|
+
import { createHash as createHash16 } from "crypto";
|
|
166930
167838
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
166931
167839
|
import { z as z626 } from "zod";
|
|
166932
167840
|
function formatFormationStageDurations(stageDurationsMs) {
|
|
@@ -167010,7 +167918,7 @@ function coerceObjectArray(val) {
|
|
|
167010
167918
|
return [];
|
|
167011
167919
|
}
|
|
167012
167920
|
function createDeterministicInstanceId(projectId, agentType, agentName) {
|
|
167013
|
-
const digest2 =
|
|
167921
|
+
const digest2 = createHash16("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
|
|
167014
167922
|
return `auto-${digest2}`;
|
|
167015
167923
|
}
|
|
167016
167924
|
function shouldAwaitProjectRuntime(toolName) {
|
|
@@ -167302,7 +168210,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
167302
168210
|
};
|
|
167303
168211
|
const server = existingServer ?? new McpServer({
|
|
167304
168212
|
name: "memorix",
|
|
167305
|
-
version: true ? "1.
|
|
168213
|
+
version: true ? "1.8.0" : "1.0.1"
|
|
167306
168214
|
});
|
|
167307
168215
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
167308
168216
|
server.registerTool = ((name, ...args) => {
|
|
@@ -170481,7 +171389,7 @@ ${json2}
|
|
|
170481
171389
|
dashboardRunning = true;
|
|
170482
171390
|
const { exec: execCmd } = await import("child_process");
|
|
170483
171391
|
const openCmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
170484
|
-
execCmd(openCmd, () => {
|
|
171392
|
+
execCmd(openCmd, { windowsHide: true }, () => {
|
|
170485
171393
|
});
|
|
170486
171394
|
return {
|
|
170487
171395
|
content: [{
|
|
@@ -170505,6 +171413,113 @@ ${json2}
|
|
|
170505
171413
|
}
|
|
170506
171414
|
}
|
|
170507
171415
|
);
|
|
171416
|
+
server.registerTool(
|
|
171417
|
+
"memorix_evidence",
|
|
171418
|
+
{
|
|
171419
|
+
title: "Evidence Cards",
|
|
171420
|
+
description: "Inspect the bounded, project-scoped provenance cards behind Memorix context. Use list for a compact index, get/events for one source, sync to repair the projection, and stale when known source files changed. Cards expose sourceRef, locator, capturedHash, and freshness.",
|
|
171421
|
+
inputSchema: {
|
|
171422
|
+
action: z626.enum(["list", "get", "sync", "stale", "events"]).describe("Evidence operation"),
|
|
171423
|
+
candidateKind: z626.enum(["observation", "code", "git", "test", "document", "workflow", "graph"]).optional().default("observation"),
|
|
171424
|
+
candidateId: z626.string().optional().describe("Candidate id, usually an observation id"),
|
|
171425
|
+
query: z626.string().optional().describe("Optional title/source query for list"),
|
|
171426
|
+
paths: z626.array(z626.string()).max(200).optional().describe("Changed source paths for stale"),
|
|
171427
|
+
reason: z626.string().max(500).optional().describe("Why evidence became stale"),
|
|
171428
|
+
limit: z626.number().int().positive().max(100).optional().default(20)
|
|
171429
|
+
}
|
|
171430
|
+
},
|
|
171431
|
+
async ({ action, candidateKind, candidateId, query, paths, reason, limit: limit2 }) => {
|
|
171432
|
+
const unresolved = requireResolvedProject("inspect evidence cards for the current project");
|
|
171433
|
+
if (unresolved) return unresolved;
|
|
171434
|
+
const cards = new EvidenceCardStore();
|
|
171435
|
+
await cards.init(projectDir2);
|
|
171436
|
+
if (action === "sync") {
|
|
171437
|
+
const observations2 = await getObservationStore().loadByProject(project.id);
|
|
171438
|
+
const synced = cards.syncObservations(observations2);
|
|
171439
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, synced: synced.length, cards: synced.slice(0, limit2 ?? 20) }, null, 2) }] };
|
|
171440
|
+
}
|
|
171441
|
+
if (action === "stale") {
|
|
171442
|
+
const changed = cards.markStaleForPaths(project.id, paths ?? [], reason ?? "source file changed");
|
|
171443
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, staleMarked: changed, paths: paths ?? [] }, null, 2) }] };
|
|
171444
|
+
}
|
|
171445
|
+
if (action === "get") {
|
|
171446
|
+
if (!candidateId?.trim()) return { content: [{ type: "text", text: "candidateId is required for evidence get." }], isError: true };
|
|
171447
|
+
const card = cards.get(project.id, candidateKind ?? "observation", candidateId.trim());
|
|
171448
|
+
if (!card) return { content: [{ type: "text", text: "Evidence card not found." }], isError: true };
|
|
171449
|
+
return { content: [{ type: "text", text: JSON.stringify({ card, events: cards.listEvents(card.id), projectId: project.id }, null, 2) }] };
|
|
171450
|
+
}
|
|
171451
|
+
if (action === "events") {
|
|
171452
|
+
if (!candidateId?.trim()) return { content: [{ type: "text", text: "candidateId is required for evidence events." }], isError: true };
|
|
171453
|
+
const card = cards.get(project.id, candidateKind ?? "observation", candidateId.trim());
|
|
171454
|
+
if (!card) return { content: [{ type: "text", text: "Evidence card not found." }], isError: true };
|
|
171455
|
+
return { content: [{ type: "text", text: JSON.stringify(cards.listEvents(card.id, limit2), null, 2) }] };
|
|
171456
|
+
}
|
|
171457
|
+
const needle = query?.trim().toLowerCase();
|
|
171458
|
+
const listed = cards.list(project.id, { limit: Math.max(limit2 ?? 20, 100) }).filter((card) => !needle || [card.title, card.summary, card.sourceRef, card.locator ?? ""].join(" ").toLowerCase().includes(needle)).slice(0, limit2 ?? 20);
|
|
171459
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, cards: listed }, null, 2) }] };
|
|
171460
|
+
}
|
|
171461
|
+
);
|
|
171462
|
+
server.registerTool(
|
|
171463
|
+
"memorix_feedback",
|
|
171464
|
+
{
|
|
171465
|
+
title: "Memory Feedback",
|
|
171466
|
+
description: "Record or inspect auditable memory outcomes. Positive verification/use strengthens recall; correction, conflict, source change, or weaken lowers it. Use revoke with targetEventId to undo one prior signal without deleting audit history.",
|
|
171467
|
+
inputSchema: {
|
|
171468
|
+
action: z626.enum(["record", "show", "audit"]).describe("Feedback operation"),
|
|
171469
|
+
candidateKind: z626.enum(["observation", "claim", "durable-memory", "workflow"]).optional().default("observation"),
|
|
171470
|
+
candidateId: z626.string().describe("Memory or knowledge candidate id"),
|
|
171471
|
+
signal: z626.enum(["user-correction", "verification-success", "verification-failure", "code-change", "used", "not-used", "code-conflict", "strengthen", "weaken", "revoke"]).optional(),
|
|
171472
|
+
sourceRef: z626.string().max(500).optional().describe("Source of this feedback, such as test:run-42 or user:chat"),
|
|
171473
|
+
actor: z626.string().max(200).optional(),
|
|
171474
|
+
note: z626.string().max(2e3).optional(),
|
|
171475
|
+
targetEventId: z626.string().optional().describe("Existing event id when action=record and signal=revoke"),
|
|
171476
|
+
limit: z626.number().int().positive().max(200).optional().default(100)
|
|
171477
|
+
}
|
|
171478
|
+
},
|
|
171479
|
+
async ({ action, candidateKind, candidateId, signal, sourceRef, actor, note, targetEventId, limit: limit2 }) => {
|
|
171480
|
+
const unresolved = requireResolvedProject("record memory feedback for the current project");
|
|
171481
|
+
if (unresolved) return unresolved;
|
|
171482
|
+
const feedback = new MemoryFeedbackStore();
|
|
171483
|
+
await feedback.init(projectDir2);
|
|
171484
|
+
const kind = candidateKind ?? "observation";
|
|
171485
|
+
if (action === "show") {
|
|
171486
|
+
return { content: [{ type: "text", text: JSON.stringify(feedback.getState(project.id, kind, candidateId), null, 2) }] };
|
|
171487
|
+
}
|
|
171488
|
+
if (action === "audit") {
|
|
171489
|
+
return { content: [{ type: "text", text: JSON.stringify(feedback.audit(project.id, kind, candidateId, limit2), null, 2) }] };
|
|
171490
|
+
}
|
|
171491
|
+
if (!signal || !sourceRef?.trim()) {
|
|
171492
|
+
return { content: [{ type: "text", text: "record requires signal and sourceRef." }], isError: true };
|
|
171493
|
+
}
|
|
171494
|
+
try {
|
|
171495
|
+
const result = feedback.record({
|
|
171496
|
+
projectId: project.id,
|
|
171497
|
+
candidateKind: kind,
|
|
171498
|
+
candidateId,
|
|
171499
|
+
signal,
|
|
171500
|
+
sourceRef,
|
|
171501
|
+
...actor || currentAgentId ? { actor: actor ?? currentAgentId } : {},
|
|
171502
|
+
...note ? { note } : {},
|
|
171503
|
+
...targetEventId ? { targetEventId } : {}
|
|
171504
|
+
});
|
|
171505
|
+
if (kind === "observation") {
|
|
171506
|
+
const cards = new EvidenceCardStore();
|
|
171507
|
+
await cards.init(projectDir2);
|
|
171508
|
+
const card = cards.get(project.id, "observation", candidateId);
|
|
171509
|
+
if (card) {
|
|
171510
|
+
const verification = signal === "verification-success" || signal === "strengthen" ? "verified" : signal === "user-correction" || signal === "code-conflict" || signal === "weaken" ? "conflicted" : card.verification;
|
|
171511
|
+
cards.recordEvent(project.id, card.id, `feedback:${signal}`, note);
|
|
171512
|
+
if (verification !== card.verification) {
|
|
171513
|
+
cards.setVerification(project.id, card.id, verification);
|
|
171514
|
+
}
|
|
171515
|
+
}
|
|
171516
|
+
}
|
|
171517
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
171518
|
+
} catch (error) {
|
|
171519
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true };
|
|
171520
|
+
}
|
|
171521
|
+
}
|
|
171522
|
+
);
|
|
170508
171523
|
if (teamFeaturesEnabled) {
|
|
170509
171524
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
170510
171525
|
initTeamStoreForProject = initTeamStore2;
|
|
@@ -171558,6 +172573,8 @@ var init_server2 = __esm({
|
|
|
171558
172573
|
init_launch_root();
|
|
171559
172574
|
init_aliases();
|
|
171560
172575
|
init_persistence();
|
|
172576
|
+
init_evidence_store();
|
|
172577
|
+
init_feedback();
|
|
171561
172578
|
init_syncer();
|
|
171562
172579
|
init_engine4();
|
|
171563
172580
|
init_tool_profile();
|
|
@@ -171742,7 +172759,7 @@ var init_serve_shared = __esm({
|
|
|
171742
172759
|
|
|
171743
172760
|
// src/cli/version.ts
|
|
171744
172761
|
function getCliVersion() {
|
|
171745
|
-
return true ? "1.
|
|
172762
|
+
return true ? "1.8.0" : pkg.version;
|
|
171746
172763
|
}
|
|
171747
172764
|
var init_version3 = __esm({
|
|
171748
172765
|
"src/cli/version.ts"() {
|