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/sdk.js
CHANGED
|
@@ -437,7 +437,7 @@ function isSqliteAvailable() {
|
|
|
437
437
|
return false;
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
|
-
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;
|
|
440
|
+
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;
|
|
441
441
|
var init_sqlite_db = __esm({
|
|
442
442
|
"src/store/sqlite-db.ts"() {
|
|
443
443
|
"use strict";
|
|
@@ -1083,6 +1083,79 @@ CREATE TABLE IF NOT EXISTS compaction_checkpoints (
|
|
|
1083
1083
|
created_at TEXT NOT NULL,
|
|
1084
1084
|
updated_at TEXT NOT NULL
|
|
1085
1085
|
);
|
|
1086
|
+
`;
|
|
1087
|
+
CREATE_EVIDENCE_CARDS_TABLE = `
|
|
1088
|
+
CREATE TABLE IF NOT EXISTS evidence_cards (
|
|
1089
|
+
id TEXT PRIMARY KEY,
|
|
1090
|
+
project_id TEXT NOT NULL,
|
|
1091
|
+
candidate_kind TEXT NOT NULL,
|
|
1092
|
+
candidate_id TEXT NOT NULL,
|
|
1093
|
+
title TEXT NOT NULL,
|
|
1094
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
1095
|
+
entity_name TEXT,
|
|
1096
|
+
source_kind TEXT NOT NULL,
|
|
1097
|
+
source_ref TEXT NOT NULL,
|
|
1098
|
+
locator TEXT,
|
|
1099
|
+
captured_hash TEXT,
|
|
1100
|
+
session_id TEXT,
|
|
1101
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
1102
|
+
verification TEXT NOT NULL DEFAULT 'unverified',
|
|
1103
|
+
freshness TEXT NOT NULL DEFAULT 'current',
|
|
1104
|
+
stale_reason TEXT,
|
|
1105
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
1106
|
+
related_entities_json TEXT NOT NULL DEFAULT '[]',
|
|
1107
|
+
created_at TEXT NOT NULL,
|
|
1108
|
+
updated_at TEXT NOT NULL,
|
|
1109
|
+
UNIQUE(project_id, candidate_kind, candidate_id)
|
|
1110
|
+
);
|
|
1111
|
+
`;
|
|
1112
|
+
CREATE_EVIDENCE_CARD_EVENTS_TABLE = `
|
|
1113
|
+
CREATE TABLE IF NOT EXISTS evidence_card_events (
|
|
1114
|
+
id TEXT PRIMARY KEY,
|
|
1115
|
+
project_id TEXT NOT NULL,
|
|
1116
|
+
card_id TEXT NOT NULL,
|
|
1117
|
+
kind TEXT NOT NULL,
|
|
1118
|
+
detail TEXT,
|
|
1119
|
+
created_at TEXT NOT NULL,
|
|
1120
|
+
FOREIGN KEY (card_id) REFERENCES evidence_cards(id) ON DELETE CASCADE
|
|
1121
|
+
);
|
|
1122
|
+
`;
|
|
1123
|
+
CREATE_MEMORY_FEEDBACK_STATES_TABLE = `
|
|
1124
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_states (
|
|
1125
|
+
project_id TEXT NOT NULL,
|
|
1126
|
+
candidate_kind TEXT NOT NULL,
|
|
1127
|
+
candidate_id TEXT NOT NULL,
|
|
1128
|
+
weight REAL NOT NULL DEFAULT 1.0,
|
|
1129
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'active',
|
|
1130
|
+
updated_at TEXT NOT NULL,
|
|
1131
|
+
PRIMARY KEY (project_id, candidate_kind, candidate_id)
|
|
1132
|
+
);
|
|
1133
|
+
`;
|
|
1134
|
+
CREATE_MEMORY_FEEDBACK_EVENTS_TABLE = `
|
|
1135
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
1136
|
+
id TEXT PRIMARY KEY,
|
|
1137
|
+
project_id TEXT NOT NULL,
|
|
1138
|
+
candidate_kind TEXT NOT NULL,
|
|
1139
|
+
candidate_id TEXT NOT NULL,
|
|
1140
|
+
signal TEXT NOT NULL,
|
|
1141
|
+
actor TEXT,
|
|
1142
|
+
note TEXT,
|
|
1143
|
+
source_ref TEXT NOT NULL,
|
|
1144
|
+
target_event_id TEXT,
|
|
1145
|
+
delta REAL NOT NULL DEFAULT 0,
|
|
1146
|
+
observed_at TEXT NOT NULL
|
|
1147
|
+
);
|
|
1148
|
+
`;
|
|
1149
|
+
CREATE_MCP_BINDINGS_TABLE = `
|
|
1150
|
+
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
1151
|
+
handle_id TEXT PRIMARY KEY,
|
|
1152
|
+
project_id TEXT NOT NULL,
|
|
1153
|
+
project_root TEXT NOT NULL,
|
|
1154
|
+
data_dir TEXT NOT NULL,
|
|
1155
|
+
created_at TEXT NOT NULL,
|
|
1156
|
+
last_used_at TEXT NOT NULL,
|
|
1157
|
+
expires_at TEXT
|
|
1158
|
+
);
|
|
1086
1159
|
`;
|
|
1087
1160
|
CREATE_INDEXES = `
|
|
1088
1161
|
CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
|
|
@@ -1145,6 +1218,12 @@ CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_target
|
|
|
1145
1218
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
|
|
1146
1219
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
|
|
1147
1220
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
|
|
1221
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC);
|
|
1222
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id);
|
|
1223
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1224
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1225
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1226
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1148
1227
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1149
1228
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1150
1229
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1300,6 +1379,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1300
1379
|
}
|
|
1301
1380
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_media_jobs_source_asset ON media_jobs(project_id, source_asset_id, status)");
|
|
1302
1381
|
}
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
id: "1.8-context-control-plane",
|
|
1385
|
+
apply: (db2) => {
|
|
1386
|
+
db2.exec(CREATE_EVIDENCE_CARDS_TABLE);
|
|
1387
|
+
db2.exec(CREATE_EVIDENCE_CARD_EVENTS_TABLE);
|
|
1388
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_STATES_TABLE);
|
|
1389
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_EVENTS_TABLE);
|
|
1390
|
+
db2.exec(CREATE_MCP_BINDINGS_TABLE);
|
|
1391
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC)");
|
|
1392
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id)");
|
|
1393
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at)");
|
|
1394
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1395
|
+
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)");
|
|
1396
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1397
|
+
}
|
|
1303
1398
|
}
|
|
1304
1399
|
];
|
|
1305
1400
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -2781,6 +2876,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
2781
2876
|
llm: { ...userConfig.llm, ...projectConfig.llm },
|
|
2782
2877
|
agent: { ...userConfig.agent, ...projectConfig.agent },
|
|
2783
2878
|
embedding: { ...userConfig.embedding, ...projectConfig.embedding },
|
|
2879
|
+
rerank: { ...userConfig.rerank, ...projectConfig.rerank },
|
|
2784
2880
|
git: { ...userConfig.git, ...projectConfig.git },
|
|
2785
2881
|
codegraph: { ...userConfig.codegraph, ...projectConfig.codegraph },
|
|
2786
2882
|
behavior: { ...userConfig.behavior, ...projectConfig.behavior },
|
|
@@ -3056,6 +3152,7 @@ function mergeTomlConfig(base, override) {
|
|
|
3056
3152
|
llm: { ...base.memory?.llm, ...override.memory?.llm }
|
|
3057
3153
|
},
|
|
3058
3154
|
embedding: { ...base.embedding, ...override.embedding },
|
|
3155
|
+
rerank: { ...base.rerank, ...override.rerank },
|
|
3059
3156
|
hooks: { ...base.hooks, ...override.hooks },
|
|
3060
3157
|
git: { ...base.git, ...override.git },
|
|
3061
3158
|
codegraph: { ...base.codegraph, ...override.codegraph },
|
|
@@ -3148,6 +3245,8 @@ var init_toml_loader = __esm({
|
|
|
3148
3245
|
var dotenv_loader_exports = {};
|
|
3149
3246
|
__export(dotenv_loader_exports, {
|
|
3150
3247
|
getLoadedEnvFiles: () => getLoadedEnvFiles,
|
|
3248
|
+
getLoadedEnvKeys: () => getLoadedEnvKeys,
|
|
3249
|
+
getLoadedEnvValue: () => getLoadedEnvValue,
|
|
3151
3250
|
loadDotenv: () => loadDotenv,
|
|
3152
3251
|
resetDotenv: () => resetDotenv
|
|
3153
3252
|
});
|
|
@@ -3159,6 +3258,8 @@ function loadEnvFile(filePath) {
|
|
|
3159
3258
|
const parsed = parse(readFileSync6(filePath, "utf-8"));
|
|
3160
3259
|
for (const [key, value] of Object.entries(parsed)) {
|
|
3161
3260
|
if (!(key in process.env)) {
|
|
3261
|
+
loadedEnvKeys.add(key);
|
|
3262
|
+
loadedEnvValues.set(key, value);
|
|
3162
3263
|
process.env[key] = value;
|
|
3163
3264
|
injectedKeys.add(key);
|
|
3164
3265
|
}
|
|
@@ -3171,6 +3272,8 @@ function loadDotenv(projectRoot, options = {}) {
|
|
|
3171
3272
|
resetDotenv();
|
|
3172
3273
|
}
|
|
3173
3274
|
loadedEnvFiles.length = 0;
|
|
3275
|
+
loadedEnvKeys.clear();
|
|
3276
|
+
loadedEnvValues.clear();
|
|
3174
3277
|
if (projectRoot) {
|
|
3175
3278
|
loadEnvFile(getProjectDotenvPath(projectRoot));
|
|
3176
3279
|
}
|
|
@@ -3186,11 +3289,18 @@ function resetDotenv() {
|
|
|
3186
3289
|
dotenvLoaded = false;
|
|
3187
3290
|
dotenvProjectRoot = null;
|
|
3188
3291
|
loadedEnvFiles.length = 0;
|
|
3292
|
+
loadedEnvKeys.clear();
|
|
3189
3293
|
}
|
|
3190
3294
|
function getLoadedEnvFiles() {
|
|
3191
3295
|
return loadedEnvFiles;
|
|
3192
3296
|
}
|
|
3193
|
-
|
|
3297
|
+
function getLoadedEnvKeys() {
|
|
3298
|
+
return loadedEnvKeys;
|
|
3299
|
+
}
|
|
3300
|
+
function getLoadedEnvValue(key) {
|
|
3301
|
+
return loadedEnvValues.get(key);
|
|
3302
|
+
}
|
|
3303
|
+
var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
|
|
3194
3304
|
var init_dotenv_loader = __esm({
|
|
3195
3305
|
"src/config/dotenv-loader.ts"() {
|
|
3196
3306
|
"use strict";
|
|
@@ -3199,6 +3309,8 @@ var init_dotenv_loader = __esm({
|
|
|
3199
3309
|
dotenvLoaded = false;
|
|
3200
3310
|
dotenvProjectRoot = null;
|
|
3201
3311
|
loadedEnvFiles = [];
|
|
3312
|
+
loadedEnvKeys = /* @__PURE__ */ new Set();
|
|
3313
|
+
loadedEnvValues = /* @__PURE__ */ new Map();
|
|
3202
3314
|
injectedKeys = /* @__PURE__ */ new Set();
|
|
3203
3315
|
}
|
|
3204
3316
|
});
|
|
@@ -3211,6 +3323,7 @@ __export(resolved_config_exports, {
|
|
|
3211
3323
|
getResolvedConfigForCwd: () => getResolvedConfigForCwd,
|
|
3212
3324
|
getResolvedEmbeddingLane: () => getResolvedEmbeddingLane,
|
|
3213
3325
|
getResolvedMemoryLane: () => getResolvedMemoryLane,
|
|
3326
|
+
getResolvedRerankLane: () => getResolvedRerankLane,
|
|
3214
3327
|
resetResolvedConfigCache: () => resetResolvedConfigCache
|
|
3215
3328
|
});
|
|
3216
3329
|
import { homedir as homedir5 } from "os";
|
|
@@ -3243,6 +3356,16 @@ function getResolvedConfig(options = {}) {
|
|
|
3243
3356
|
legacy.llm?.baseUrl
|
|
3244
3357
|
);
|
|
3245
3358
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
3359
|
+
const memoryLlmApiKey = first(
|
|
3360
|
+
process.env.MEMORIX_LLM_API_KEY,
|
|
3361
|
+
process.env.MEMORIX_API_KEY,
|
|
3362
|
+
toml.memory?.llm?.api_key,
|
|
3363
|
+
yaml.llm?.apiKey,
|
|
3364
|
+
legacy.llm?.apiKey,
|
|
3365
|
+
process.env.OPENAI_API_KEY,
|
|
3366
|
+
process.env.ANTHROPIC_API_KEY,
|
|
3367
|
+
openRouterMemoryLlmApiKey
|
|
3368
|
+
);
|
|
3246
3369
|
const resolved = {
|
|
3247
3370
|
agent: {
|
|
3248
3371
|
provider: first(
|
|
@@ -3283,16 +3406,7 @@ function getResolvedConfig(options = {}) {
|
|
|
3283
3406
|
provider: memoryLlmProvider,
|
|
3284
3407
|
model: memoryLlmModel,
|
|
3285
3408
|
baseUrl: memoryLlmBaseUrl,
|
|
3286
|
-
apiKey:
|
|
3287
|
-
process.env.MEMORIX_LLM_API_KEY,
|
|
3288
|
-
process.env.MEMORIX_API_KEY,
|
|
3289
|
-
toml.memory?.llm?.api_key,
|
|
3290
|
-
yaml.llm?.apiKey,
|
|
3291
|
-
legacy.llm?.apiKey,
|
|
3292
|
-
process.env.OPENAI_API_KEY,
|
|
3293
|
-
process.env.ANTHROPIC_API_KEY,
|
|
3294
|
-
openRouterMemoryLlmApiKey
|
|
3295
|
-
)
|
|
3409
|
+
apiKey: memoryLlmApiKey
|
|
3296
3410
|
}
|
|
3297
3411
|
},
|
|
3298
3412
|
embedding: {
|
|
@@ -3302,6 +3416,12 @@ function getResolvedConfig(options = {}) {
|
|
|
3302
3416
|
apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
|
|
3303
3417
|
dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
|
|
3304
3418
|
},
|
|
3419
|
+
rerank: resolveRerankLane({
|
|
3420
|
+
toml,
|
|
3421
|
+
yaml,
|
|
3422
|
+
memoryLlmApiKey,
|
|
3423
|
+
memoryLlmBaseUrl
|
|
3424
|
+
}),
|
|
3305
3425
|
git: {
|
|
3306
3426
|
autoHook: firstBool(toml.git?.auto_hook, yaml.git?.autoHook),
|
|
3307
3427
|
ingestOnCommit: firstBool(toml.git?.ingest_on_commit, yaml.git?.ingestOnCommit),
|
|
@@ -3371,6 +3491,9 @@ function getResolvedMemoryLane(options = {}) {
|
|
|
3371
3491
|
function getResolvedEmbeddingLane(options = {}) {
|
|
3372
3492
|
return getResolvedConfig(options).embedding;
|
|
3373
3493
|
}
|
|
3494
|
+
function getResolvedRerankLane(options = {}) {
|
|
3495
|
+
return getResolvedConfig(options).rerank;
|
|
3496
|
+
}
|
|
3374
3497
|
function resetResolvedConfigCache() {
|
|
3375
3498
|
}
|
|
3376
3499
|
function first(...values) {
|
|
@@ -3413,6 +3536,10 @@ function getEnvSourceNames() {
|
|
|
3413
3536
|
"MEMORIX_EMBEDDING_BASE_URL",
|
|
3414
3537
|
"MEMORIX_EMBEDDING_MODEL",
|
|
3415
3538
|
"MEMORIX_EMBEDDING_DIMENSIONS",
|
|
3539
|
+
"MEMORIX_RERANK_PROVIDER",
|
|
3540
|
+
"MEMORIX_RERANK_MODEL",
|
|
3541
|
+
"MEMORIX_RERANK_BASE_URL",
|
|
3542
|
+
"MEMORIX_RERANK_API_KEY",
|
|
3416
3543
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
3417
3544
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
3418
3545
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
@@ -3436,6 +3563,63 @@ function normalizeExternalContext(value) {
|
|
|
3436
3563
|
if (normalized === "auto" || normalized === "off") return normalized;
|
|
3437
3564
|
return void 0;
|
|
3438
3565
|
}
|
|
3566
|
+
function normalizeRerankProvider(value) {
|
|
3567
|
+
const normalized = value?.trim().toLowerCase();
|
|
3568
|
+
if (normalized === "http") return "http";
|
|
3569
|
+
return "off";
|
|
3570
|
+
}
|
|
3571
|
+
function resolveRerankLane(args) {
|
|
3572
|
+
const provider2 = normalizeRerankProvider(first(
|
|
3573
|
+
process.env.MEMORIX_RERANK_PROVIDER,
|
|
3574
|
+
args.toml.rerank?.provider,
|
|
3575
|
+
args.yaml.rerank?.provider,
|
|
3576
|
+
"off"
|
|
3577
|
+
));
|
|
3578
|
+
const model = first(
|
|
3579
|
+
process.env.MEMORIX_RERANK_MODEL,
|
|
3580
|
+
args.toml.rerank?.model,
|
|
3581
|
+
args.yaml.rerank?.model
|
|
3582
|
+
);
|
|
3583
|
+
const explicitBaseUrl = first(
|
|
3584
|
+
process.env.MEMORIX_RERANK_BASE_URL,
|
|
3585
|
+
args.toml.rerank?.base_url,
|
|
3586
|
+
args.yaml.rerank?.baseUrl
|
|
3587
|
+
);
|
|
3588
|
+
const baseUrl = provider2 === "http" ? first(explicitBaseUrl, args.memoryLlmBaseUrl) : explicitBaseUrl;
|
|
3589
|
+
const dedicatedApiKey = first(
|
|
3590
|
+
process.env.MEMORIX_RERANK_API_KEY,
|
|
3591
|
+
args.toml.rerank?.api_key,
|
|
3592
|
+
args.yaml.rerank?.apiKey
|
|
3593
|
+
);
|
|
3594
|
+
const sameEndpoint = provider2 === "http" && sameTrustedEndpoint(baseUrl, args.memoryLlmBaseUrl);
|
|
3595
|
+
const inheritedApiKey = sameEndpoint ? args.memoryLlmApiKey : void 0;
|
|
3596
|
+
const apiKey = first(dedicatedApiKey, inheritedApiKey);
|
|
3597
|
+
const canSendRequest = provider2 === "http" && Boolean(baseUrl) && (Boolean(apiKey) || !args.memoryLlmApiKey || sameEndpoint);
|
|
3598
|
+
return { provider: provider2, model, baseUrl, apiKey, canSendRequest };
|
|
3599
|
+
}
|
|
3600
|
+
function sameTrustedEndpoint(left, right) {
|
|
3601
|
+
const a = normalizeTrustedEndpoint(left);
|
|
3602
|
+
const b = normalizeTrustedEndpoint(right);
|
|
3603
|
+
return Boolean(a && b && a === b);
|
|
3604
|
+
}
|
|
3605
|
+
function normalizeTrustedEndpoint(value) {
|
|
3606
|
+
const trimmed = value?.trim();
|
|
3607
|
+
if (!trimmed) return void 0;
|
|
3608
|
+
try {
|
|
3609
|
+
const url = new URL(trimmed);
|
|
3610
|
+
const protocol = url.protocol.toLowerCase();
|
|
3611
|
+
const hostname = url.hostname.toLowerCase();
|
|
3612
|
+
const port = url.port;
|
|
3613
|
+
let pathname = url.pathname.replace(/\/+$/, "");
|
|
3614
|
+
if (pathname.toLowerCase().endsWith("/rerank")) {
|
|
3615
|
+
pathname = pathname.slice(0, -"/rerank".length).replace(/\/+$/, "");
|
|
3616
|
+
}
|
|
3617
|
+
return `${protocol}//${hostname}${port ? `:${port}` : ""}${pathname}`;
|
|
3618
|
+
} catch {
|
|
3619
|
+
const fallback = trimmed.replace(/\/+$/, "").replace(/\/rerank$/i, "").replace(/\/+$/, "");
|
|
3620
|
+
return fallback.toLowerCase() || void 0;
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3439
3623
|
var init_resolved_config = __esm({
|
|
3440
3624
|
"src/config/resolved-config.ts"() {
|
|
3441
3625
|
"use strict";
|
|
@@ -5671,9 +5855,27 @@ __export(provider_exports2, {
|
|
|
5671
5855
|
getLLMConfig: () => getLLMConfig,
|
|
5672
5856
|
initLLM: () => initLLM,
|
|
5673
5857
|
isLLMEnabled: () => isLLMEnabled,
|
|
5858
|
+
normalizeOpenAICompatibleBaseUrl: () => normalizeOpenAICompatibleBaseUrl,
|
|
5674
5859
|
parseLLMTimeoutMs: () => parseLLMTimeoutMs,
|
|
5675
5860
|
setLLMConfig: () => setLLMConfig
|
|
5676
5861
|
});
|
|
5862
|
+
function normalizeOpenAICompatibleBaseUrl(baseUrl) {
|
|
5863
|
+
const base = baseUrl.trim().replace(/\/+$/, "");
|
|
5864
|
+
if (!base) return base;
|
|
5865
|
+
let pathname = "";
|
|
5866
|
+
try {
|
|
5867
|
+
pathname = new URL(base).pathname.replace(/\/+$/, "");
|
|
5868
|
+
} catch {
|
|
5869
|
+
pathname = base.split(/[?#]/, 1)[0].replace(/\/+$/, "");
|
|
5870
|
+
}
|
|
5871
|
+
const lastSegment = pathname.split("/").filter(Boolean).at(-1);
|
|
5872
|
+
if (lastSegment && OPENAI_API_VERSION_SEGMENT.test(lastSegment)) {
|
|
5873
|
+
return base;
|
|
5874
|
+
}
|
|
5875
|
+
const queryOrHash = base.match(/[?#].*$/)?.[0] ?? "";
|
|
5876
|
+
const pathWithoutQuery = base.slice(0, base.length - queryOrHash.length).replace(/\/+$/, "");
|
|
5877
|
+
return `${pathWithoutQuery}/v1${queryOrHash}`;
|
|
5878
|
+
}
|
|
5677
5879
|
function parseLLMTimeoutMs(raw) {
|
|
5678
5880
|
if (raw === void 0 || raw.trim() === "") return LLM_TIMEOUT_DEFAULT_MS;
|
|
5679
5881
|
const parsed = Number(raw);
|
|
@@ -5777,8 +5979,7 @@ async function callLLM(systemPrompt, userMessage, signal) {
|
|
|
5777
5979
|
}
|
|
5778
5980
|
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
5779
5981
|
const config = currentConfig;
|
|
5780
|
-
|
|
5781
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
5982
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
5782
5983
|
const url = `${base}/chat/completions`;
|
|
5783
5984
|
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5784
5985
|
const response = await fetch(url, {
|
|
@@ -5857,8 +6058,7 @@ async function callLLMWithTools(messages, tools, signal) {
|
|
|
5857
6058
|
}
|
|
5858
6059
|
async function callOpenAIWithTools(messages, tools, signal) {
|
|
5859
6060
|
const config = currentConfig;
|
|
5860
|
-
|
|
5861
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
6061
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
5862
6062
|
const url = `${base}/chat/completions`;
|
|
5863
6063
|
const openaiMessages = messages.map((msg) => {
|
|
5864
6064
|
if (msg.role === "tool") {
|
|
@@ -6008,8 +6208,7 @@ async function callAnthropicWithTools(messages, tools, signal) {
|
|
|
6008
6208
|
}
|
|
6009
6209
|
async function* callOpenAIWithToolsStream(messages, tools) {
|
|
6010
6210
|
const config = currentConfig;
|
|
6011
|
-
|
|
6012
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
6211
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
6013
6212
|
const url = `${base}/chat/completions`;
|
|
6014
6213
|
const openaiMessages = messages.map((msg) => {
|
|
6015
6214
|
if (msg.role === "tool") {
|
|
@@ -6257,7 +6456,7 @@ async function* callAnthropicWithToolsStream(messages, tools) {
|
|
|
6257
6456
|
}
|
|
6258
6457
|
};
|
|
6259
6458
|
}
|
|
6260
|
-
var LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_MIN_MS, LLM_TIMEOUT_MAX_MS, MAX_LLM_RESPONSE_BYTES, LLM_CALL_TIMEOUT_MS, PROVIDER_DEFAULTS, currentConfig;
|
|
6459
|
+
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;
|
|
6261
6460
|
var init_provider2 = __esm({
|
|
6262
6461
|
"src/llm/provider.ts"() {
|
|
6263
6462
|
"use strict";
|
|
@@ -6267,6 +6466,7 @@ var init_provider2 = __esm({
|
|
|
6267
6466
|
LLM_TIMEOUT_MIN_MS = 1e3;
|
|
6268
6467
|
LLM_TIMEOUT_MAX_MS = 3e5;
|
|
6269
6468
|
MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
6469
|
+
OPENAI_API_VERSION_SEGMENT = /^v\d+(?:[a-z][a-z0-9-]*)?$/i;
|
|
6270
6470
|
LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);
|
|
6271
6471
|
PROVIDER_DEFAULTS = {
|
|
6272
6472
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
@@ -6326,6 +6526,48 @@ Rules:
|
|
|
6326
6526
|
}
|
|
6327
6527
|
});
|
|
6328
6528
|
|
|
6529
|
+
// src/rerank/policy.ts
|
|
6530
|
+
function parseRerankTimeoutMs(raw) {
|
|
6531
|
+
const value = raw?.trim();
|
|
6532
|
+
if (!value) return DEFAULT_RERANK_TIMEOUT_MS;
|
|
6533
|
+
const parsed = Number(value);
|
|
6534
|
+
if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {
|
|
6535
|
+
console.warn(
|
|
6536
|
+
`[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.`
|
|
6537
|
+
);
|
|
6538
|
+
return DEFAULT_RERANK_TIMEOUT_MS;
|
|
6539
|
+
}
|
|
6540
|
+
if (parsed < RERANK_TIMEOUT_MIN_MS) return RERANK_TIMEOUT_MIN_MS;
|
|
6541
|
+
if (parsed > RERANK_TIMEOUT_MAX_MS) return RERANK_TIMEOUT_MAX_MS;
|
|
6542
|
+
return parsed;
|
|
6543
|
+
}
|
|
6544
|
+
function resolveRerankTimeoutMs(explicitTimeoutMs) {
|
|
6545
|
+
if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
|
|
6546
|
+
return explicitTimeoutMs;
|
|
6547
|
+
}
|
|
6548
|
+
return parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
6549
|
+
}
|
|
6550
|
+
function shouldAttemptHttpRerank(input) {
|
|
6551
|
+
return input.quality === "thorough" && input.hasQuery && input.candidateCount >= MIN_RERANK_CANDIDATES;
|
|
6552
|
+
}
|
|
6553
|
+
function shouldAttemptLlmRerank(input) {
|
|
6554
|
+
if (input.httpRerankConfigured) return false;
|
|
6555
|
+
if (input.quality !== "thorough" || input.tier !== "heavy" || !input.hasQuery) return false;
|
|
6556
|
+
if (input.candidateCount < MIN_RERANK_CANDIDATES) return false;
|
|
6557
|
+
return input.topScore > 0 && input.secondScore / input.topScore > 0.7;
|
|
6558
|
+
}
|
|
6559
|
+
var DEFAULT_RERANK_TIMEOUT_MS, RERANK_TIMEOUT_MIN_MS, RERANK_TIMEOUT_MAX_MS, MIN_RERANK_CANDIDATES;
|
|
6560
|
+
var init_policy = __esm({
|
|
6561
|
+
"src/rerank/policy.ts"() {
|
|
6562
|
+
"use strict";
|
|
6563
|
+
init_esm_shims();
|
|
6564
|
+
DEFAULT_RERANK_TIMEOUT_MS = 3e4;
|
|
6565
|
+
RERANK_TIMEOUT_MIN_MS = 1e3;
|
|
6566
|
+
RERANK_TIMEOUT_MAX_MS = 3e5;
|
|
6567
|
+
MIN_RERANK_CANDIDATES = 3;
|
|
6568
|
+
}
|
|
6569
|
+
});
|
|
6570
|
+
|
|
6329
6571
|
// src/timeout.ts
|
|
6330
6572
|
function withTimeout(promise, ms, label) {
|
|
6331
6573
|
return new Promise((resolve2, reject) => {
|
|
@@ -6611,6 +6853,148 @@ var init_aliases = __esm({
|
|
|
6611
6853
|
}
|
|
6612
6854
|
});
|
|
6613
6855
|
|
|
6856
|
+
// src/rerank/http-provider.ts
|
|
6857
|
+
function buildRerankUrl(baseUrl) {
|
|
6858
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
6859
|
+
if (trimmed.endsWith("/rerank")) return trimmed;
|
|
6860
|
+
return `${trimmed}/rerank`;
|
|
6861
|
+
}
|
|
6862
|
+
function parseRerankResponse(payload) {
|
|
6863
|
+
const rows = extractRows(payload);
|
|
6864
|
+
if (rows.length === 0) {
|
|
6865
|
+
throw new Error("Neural rerank response contained no ranked results");
|
|
6866
|
+
}
|
|
6867
|
+
return rows.sort((a, b) => b.score - a.score);
|
|
6868
|
+
}
|
|
6869
|
+
function extractRows(payload) {
|
|
6870
|
+
if (Array.isArray(payload)) {
|
|
6871
|
+
return payload.map(rowFromUnknown).filter((row) => row !== null);
|
|
6872
|
+
}
|
|
6873
|
+
if (payload && typeof payload === "object" && "results" in payload) {
|
|
6874
|
+
const results = payload.results;
|
|
6875
|
+
if (Array.isArray(results)) {
|
|
6876
|
+
return results.map(rowFromUnknown).filter((row) => row !== null);
|
|
6877
|
+
}
|
|
6878
|
+
}
|
|
6879
|
+
throw new Error("Neural rerank response was not Cohere or TEI shaped");
|
|
6880
|
+
}
|
|
6881
|
+
function rowFromUnknown(value) {
|
|
6882
|
+
if (!value || typeof value !== "object") return null;
|
|
6883
|
+
const row = value;
|
|
6884
|
+
if (typeof row.index !== "number" || !Number.isFinite(row.index)) return null;
|
|
6885
|
+
const score = typeof row.relevance_score === "number" ? row.relevance_score : typeof row.score === "number" ? row.score : null;
|
|
6886
|
+
if (score === null || !Number.isFinite(score)) return null;
|
|
6887
|
+
return { index: row.index, score };
|
|
6888
|
+
}
|
|
6889
|
+
function buildRerankBody(query, documents, model) {
|
|
6890
|
+
const body = {
|
|
6891
|
+
query,
|
|
6892
|
+
documents,
|
|
6893
|
+
top_n: documents.length,
|
|
6894
|
+
return_documents: false
|
|
6895
|
+
};
|
|
6896
|
+
const trimmed = model?.trim();
|
|
6897
|
+
if (trimmed) body.model = trimmed;
|
|
6898
|
+
return body;
|
|
6899
|
+
}
|
|
6900
|
+
async function rerankViaHttp(query, documents, config) {
|
|
6901
|
+
if (documents.length === 0) return [];
|
|
6902
|
+
const url = buildRerankUrl(config.baseUrl);
|
|
6903
|
+
const headers = {
|
|
6904
|
+
"content-type": "application/json"
|
|
6905
|
+
};
|
|
6906
|
+
if (config.apiKey) {
|
|
6907
|
+
headers.authorization = `Bearer ${config.apiKey}`;
|
|
6908
|
+
}
|
|
6909
|
+
const controller = new AbortController();
|
|
6910
|
+
const timeoutMs = resolveRerankTimeoutMs(config.timeoutMs);
|
|
6911
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6912
|
+
try {
|
|
6913
|
+
const fetchImpl = config.fetchImpl ?? fetch;
|
|
6914
|
+
const response = await fetchImpl(url, {
|
|
6915
|
+
method: "POST",
|
|
6916
|
+
headers,
|
|
6917
|
+
signal: controller.signal,
|
|
6918
|
+
body: JSON.stringify(buildRerankBody(query, documents, config.model))
|
|
6919
|
+
});
|
|
6920
|
+
if (!response.ok) {
|
|
6921
|
+
throw new Error(`Neural rerank HTTP ${response.status} from ${url}`);
|
|
6922
|
+
}
|
|
6923
|
+
return parseRerankResponse(await response.json());
|
|
6924
|
+
} finally {
|
|
6925
|
+
clearTimeout(timer);
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
var init_http_provider = __esm({
|
|
6929
|
+
"src/rerank/http-provider.ts"() {
|
|
6930
|
+
"use strict";
|
|
6931
|
+
init_esm_shims();
|
|
6932
|
+
init_policy();
|
|
6933
|
+
}
|
|
6934
|
+
});
|
|
6935
|
+
|
|
6936
|
+
// src/rerank/index.ts
|
|
6937
|
+
var rerank_exports = {};
|
|
6938
|
+
__export(rerank_exports, {
|
|
6939
|
+
DEFAULT_RERANK_TIMEOUT_MS: () => DEFAULT_RERANK_TIMEOUT_MS,
|
|
6940
|
+
MIN_RERANK_CANDIDATES: () => MIN_RERANK_CANDIDATES,
|
|
6941
|
+
isNeuralRerankEnabled: () => isNeuralRerankEnabled,
|
|
6942
|
+
neuralRerankCandidates: () => neuralRerankCandidates,
|
|
6943
|
+
parseRerankTimeoutMs: () => parseRerankTimeoutMs,
|
|
6944
|
+
resolveRerankTimeoutMs: () => resolveRerankTimeoutMs,
|
|
6945
|
+
shouldAttemptHttpRerank: () => shouldAttemptHttpRerank,
|
|
6946
|
+
shouldAttemptLlmRerank: () => shouldAttemptLlmRerank
|
|
6947
|
+
});
|
|
6948
|
+
function isNeuralRerankEnabled(options = {}) {
|
|
6949
|
+
const lane = getResolvedRerankLane(options);
|
|
6950
|
+
return lane.provider === "http" && Boolean(lane.baseUrl);
|
|
6951
|
+
}
|
|
6952
|
+
async function neuralRerankCandidates(query, candidates, options = {}) {
|
|
6953
|
+
if (!isNeuralRerankEnabled(options) || candidates.length === 0) return null;
|
|
6954
|
+
const lane = getResolvedRerankLane(options);
|
|
6955
|
+
if (!lane.canSendRequest || !lane.baseUrl) return null;
|
|
6956
|
+
const toRerank = candidates.slice(0, MAX_RERANK);
|
|
6957
|
+
const rest = candidates.slice(MAX_RERANK);
|
|
6958
|
+
const documents = toRerank.map((candidate) => candidateText(candidate));
|
|
6959
|
+
const ranked = await rerankViaHttp(query, documents, {
|
|
6960
|
+
provider: "http",
|
|
6961
|
+
model: lane.model,
|
|
6962
|
+
baseUrl: lane.baseUrl,
|
|
6963
|
+
apiKey: lane.apiKey,
|
|
6964
|
+
timeoutMs: resolveRerankTimeoutMs()
|
|
6965
|
+
});
|
|
6966
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6967
|
+
const reranked = [];
|
|
6968
|
+
for (const row of ranked) {
|
|
6969
|
+
const candidate = toRerank[row.index];
|
|
6970
|
+
if (!candidate || seen.has(row.index)) continue;
|
|
6971
|
+
reranked.push(candidate);
|
|
6972
|
+
seen.add(row.index);
|
|
6973
|
+
}
|
|
6974
|
+
for (const [index, candidate] of toRerank.entries()) {
|
|
6975
|
+
if (!seen.has(index)) reranked.push(candidate);
|
|
6976
|
+
}
|
|
6977
|
+
reranked.push(...rest);
|
|
6978
|
+
return reranked;
|
|
6979
|
+
}
|
|
6980
|
+
function candidateText(candidate) {
|
|
6981
|
+
const narrative = candidate.narrative?.trim();
|
|
6982
|
+
if (narrative) return `${candidate.title} \u2014 ${narrative.slice(0, 200)}`;
|
|
6983
|
+
return candidate.title;
|
|
6984
|
+
}
|
|
6985
|
+
var MAX_RERANK;
|
|
6986
|
+
var init_rerank = __esm({
|
|
6987
|
+
"src/rerank/index.ts"() {
|
|
6988
|
+
"use strict";
|
|
6989
|
+
init_esm_shims();
|
|
6990
|
+
init_resolved_config();
|
|
6991
|
+
init_http_provider();
|
|
6992
|
+
init_policy();
|
|
6993
|
+
init_policy();
|
|
6994
|
+
MAX_RERANK = 10;
|
|
6995
|
+
}
|
|
6996
|
+
});
|
|
6997
|
+
|
|
6614
6998
|
// src/llm/quality.ts
|
|
6615
6999
|
var quality_exports = {};
|
|
6616
7000
|
__export(quality_exports, {
|
|
@@ -6650,9 +7034,9 @@ async function rerankResults(query, candidates) {
|
|
|
6650
7034
|
if (!isLLMEnabled() || candidates.length <= 2) {
|
|
6651
7035
|
return { reranked: candidates, usedLLM: false };
|
|
6652
7036
|
}
|
|
6653
|
-
const
|
|
6654
|
-
const toRerank = candidates.slice(0,
|
|
6655
|
-
const rest = candidates.slice(
|
|
7037
|
+
const MAX_RERANK2 = 10;
|
|
7038
|
+
const toRerank = candidates.slice(0, MAX_RERANK2);
|
|
7039
|
+
const rest = candidates.slice(MAX_RERANK2);
|
|
6656
7040
|
try {
|
|
6657
7041
|
const candidateList = toRerank.map(
|
|
6658
7042
|
(c) => `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` \u2014 ${c.narrative.substring(0, 100)}` : ""}`
|
|
@@ -7545,46 +7929,78 @@ async function searchObservations(options) {
|
|
|
7545
7929
|
}
|
|
7546
7930
|
}
|
|
7547
7931
|
}
|
|
7548
|
-
const
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
})
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7932
|
+
const httpGate = shouldAttemptHttpRerank({
|
|
7933
|
+
quality,
|
|
7934
|
+
hasQuery: Boolean(hasQuery),
|
|
7935
|
+
candidateCount: intermediate.length
|
|
7936
|
+
});
|
|
7937
|
+
const llmGateWithoutHttp = shouldAttemptLlmRerank({
|
|
7938
|
+
quality,
|
|
7939
|
+
tier,
|
|
7940
|
+
hasQuery: Boolean(hasQuery),
|
|
7941
|
+
candidateCount: intermediate.length,
|
|
7942
|
+
topScore: intermediate[0]?.score ?? 0,
|
|
7943
|
+
secondScore: intermediate[1]?.score ?? 0,
|
|
7944
|
+
httpRerankConfigured: false
|
|
7945
|
+
});
|
|
7946
|
+
if (httpGate || llmGateWithoutHttp) {
|
|
7947
|
+
const narrativeMap = /* @__PURE__ */ new Map();
|
|
7948
|
+
for (const hit of results.hits) {
|
|
7949
|
+
const doc = hit.document;
|
|
7950
|
+
narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);
|
|
7951
|
+
}
|
|
7952
|
+
const RERANK_TOP_K = 5;
|
|
7953
|
+
const toRerank = intermediate.slice(0, RERANK_TOP_K);
|
|
7954
|
+
const candidates = toRerank.map((e2, index) => ({
|
|
7955
|
+
id: `r${index + 1}`,
|
|
7956
|
+
title: e2.title,
|
|
7957
|
+
type: e2.type,
|
|
7958
|
+
score: e2.score,
|
|
7959
|
+
narrative: narrativeMap.get(makeEntryKey(e2.projectId, e2.id))
|
|
7960
|
+
}));
|
|
7961
|
+
const RERANK_TIMEOUT_MS = parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
7962
|
+
const candidateMap = new Map(candidates.map((candidate, index) => [candidate.id, toRerank[index]]));
|
|
7963
|
+
const { isNeuralRerankEnabled: isNeuralRerankEnabled2, neuralRerankCandidates: neuralRerankCandidates2 } = await Promise.resolve().then(() => (init_rerank(), rerank_exports));
|
|
7964
|
+
const httpConfigured = isNeuralRerankEnabled2();
|
|
7965
|
+
if (httpConfigured && httpGate) {
|
|
7966
|
+
try {
|
|
7967
|
+
const neural = await withTimeout(
|
|
7968
|
+
neuralRerankCandidates2(originalQuery, candidates),
|
|
7969
|
+
RERANK_TIMEOUT_MS,
|
|
7970
|
+
"neural rerank"
|
|
7971
|
+
);
|
|
7972
|
+
if (neural && neural.length > 0) {
|
|
7973
|
+
const rerankedTop = neural.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
7974
|
+
if (rerankedTop.length > 0) {
|
|
7975
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
7976
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + neural rerank");
|
|
7977
|
+
mark("rerank(usedNeural=true)");
|
|
7978
|
+
}
|
|
7584
7979
|
}
|
|
7980
|
+
} catch {
|
|
7981
|
+
console.error("[memorix] neural rerank failed or timed out; keeping original order");
|
|
7585
7982
|
}
|
|
7586
|
-
}
|
|
7587
|
-
|
|
7983
|
+
} else if (!httpConfigured && llmGateWithoutHttp) {
|
|
7984
|
+
try {
|
|
7985
|
+
const { rerankResults: rerankResults2 } = await Promise.resolve().then(() => (init_quality(), quality_exports));
|
|
7986
|
+
const { reranked, usedLLM } = await withTimeout(
|
|
7987
|
+
rerankResults2(originalQuery, candidates),
|
|
7988
|
+
RERANK_TIMEOUT_MS,
|
|
7989
|
+
"LLM rerank"
|
|
7990
|
+
);
|
|
7991
|
+
mark(`rerank(usedLLM=${usedLLM})`);
|
|
7992
|
+
if (usedLLM) {
|
|
7993
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
7994
|
+
const rerankedTop = reranked.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
7995
|
+
if (rerankedTop.length > 0) {
|
|
7996
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
} catch {
|
|
8000
|
+
console.error("[memorix] LLM rerank failed or timed out, using original order");
|
|
8001
|
+
}
|
|
8002
|
+
} else {
|
|
8003
|
+
mark(`rerank(skipped,tier=${tier})`);
|
|
7588
8004
|
}
|
|
7589
8005
|
} else {
|
|
7590
8006
|
mark(`rerank(skipped,tier=${tier})`);
|
|
@@ -7765,6 +8181,7 @@ var init_orama_store = __esm({
|
|
|
7765
8181
|
init_project_affinity();
|
|
7766
8182
|
init_intent_detector();
|
|
7767
8183
|
init_query_expansion();
|
|
8184
|
+
init_policy();
|
|
7768
8185
|
init_timeout();
|
|
7769
8186
|
db = null;
|
|
7770
8187
|
dbInitPromise = null;
|
|
@@ -8984,6 +9401,226 @@ var init_lifecycle = __esm({
|
|
|
8984
9401
|
}
|
|
8985
9402
|
});
|
|
8986
9403
|
|
|
9404
|
+
// src/store/evidence-store.ts
|
|
9405
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
9406
|
+
function safeJson(value, fallback) {
|
|
9407
|
+
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
9408
|
+
try {
|
|
9409
|
+
return JSON.parse(value);
|
|
9410
|
+
} catch {
|
|
9411
|
+
return fallback;
|
|
9412
|
+
}
|
|
9413
|
+
}
|
|
9414
|
+
function rowToCard(row) {
|
|
9415
|
+
return {
|
|
9416
|
+
id: String(row.id),
|
|
9417
|
+
projectId: String(row.project_id),
|
|
9418
|
+
candidateKind: row.candidate_kind,
|
|
9419
|
+
candidateId: String(row.candidate_id),
|
|
9420
|
+
title: String(row.title),
|
|
9421
|
+
summary: String(row.summary ?? ""),
|
|
9422
|
+
...row.entity_name ? { entityName: String(row.entity_name) } : {},
|
|
9423
|
+
sourceKind: String(row.source_kind),
|
|
9424
|
+
sourceRef: String(row.source_ref),
|
|
9425
|
+
...row.locator ? { locator: String(row.locator) } : {},
|
|
9426
|
+
...row.captured_hash ? { capturedHash: String(row.captured_hash) } : {},
|
|
9427
|
+
...row.session_id ? { sessionId: String(row.session_id) } : {},
|
|
9428
|
+
status: String(row.status ?? "active"),
|
|
9429
|
+
verification: row.verification,
|
|
9430
|
+
freshness: row.freshness,
|
|
9431
|
+
...row.stale_reason ? { staleReason: String(row.stale_reason) } : {},
|
|
9432
|
+
files: safeJson(row.files_json, []),
|
|
9433
|
+
relatedEntities: safeJson(row.related_entities_json, []),
|
|
9434
|
+
createdAt: String(row.created_at),
|
|
9435
|
+
updatedAt: String(row.updated_at)
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9438
|
+
function observationHash(observation) {
|
|
9439
|
+
return createHash3("sha256").update(JSON.stringify({
|
|
9440
|
+
projectId: observation.projectId,
|
|
9441
|
+
id: observation.id,
|
|
9442
|
+
title: observation.title,
|
|
9443
|
+
narrative: observation.narrative,
|
|
9444
|
+
facts: observation.facts,
|
|
9445
|
+
files: observation.filesModified,
|
|
9446
|
+
relatedEntities: observation.relatedEntities
|
|
9447
|
+
})).digest("hex");
|
|
9448
|
+
}
|
|
9449
|
+
function sourceKind(observation) {
|
|
9450
|
+
if (observation.source === "git" || observation.sourceDetail === "git-ingest") return "git";
|
|
9451
|
+
if (observation.sourceDetail === "hook") return "hook";
|
|
9452
|
+
return observation.source ?? "agent";
|
|
9453
|
+
}
|
|
9454
|
+
var EvidenceCardStore;
|
|
9455
|
+
var init_evidence_store = __esm({
|
|
9456
|
+
"src/store/evidence-store.ts"() {
|
|
9457
|
+
"use strict";
|
|
9458
|
+
init_esm_shims();
|
|
9459
|
+
init_sqlite_db();
|
|
9460
|
+
EvidenceCardStore = class {
|
|
9461
|
+
db = null;
|
|
9462
|
+
async init(dataDir) {
|
|
9463
|
+
this.db = getDatabase(dataDir);
|
|
9464
|
+
}
|
|
9465
|
+
requireDb() {
|
|
9466
|
+
if (!this.db) throw new Error("EvidenceCardStore is not initialized.");
|
|
9467
|
+
return this.db;
|
|
9468
|
+
}
|
|
9469
|
+
upsertObservation(observation) {
|
|
9470
|
+
const db2 = this.requireDb();
|
|
9471
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
9472
|
+
const card = {
|
|
9473
|
+
id: `evidence:observation:${observation.projectId}:${observation.id}`,
|
|
9474
|
+
projectId: observation.projectId,
|
|
9475
|
+
candidateKind: "observation",
|
|
9476
|
+
candidateId: String(observation.id),
|
|
9477
|
+
title: observation.title,
|
|
9478
|
+
summary: observation.narrative.slice(0, 500),
|
|
9479
|
+
entityName: observation.entityName,
|
|
9480
|
+
sourceKind: sourceKind(observation),
|
|
9481
|
+
sourceRef: `observation:${observation.id}`,
|
|
9482
|
+
locator: observation.filesModified?.join(", ") || `observation:${observation.id}`,
|
|
9483
|
+
capturedHash: observationHash(observation),
|
|
9484
|
+
...observation.sessionId ? { sessionId: observation.sessionId } : {},
|
|
9485
|
+
status: observation.status ?? "active",
|
|
9486
|
+
verification: observation.status === "resolved" ? "verified" : "unverified",
|
|
9487
|
+
freshness: "current",
|
|
9488
|
+
files: observation.filesModified ?? [],
|
|
9489
|
+
relatedEntities: observation.relatedEntities ?? [],
|
|
9490
|
+
createdAt: observation.createdAt,
|
|
9491
|
+
updatedAt: now3
|
|
9492
|
+
};
|
|
9493
|
+
db2.prepare(`
|
|
9494
|
+
INSERT INTO evidence_cards (
|
|
9495
|
+
id, project_id, candidate_kind, candidate_id, title, summary, entity_name,
|
|
9496
|
+
source_kind, source_ref, locator, captured_hash, session_id, status,
|
|
9497
|
+
verification, freshness, stale_reason, files_json, related_entities_json,
|
|
9498
|
+
created_at, updated_at
|
|
9499
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?)
|
|
9500
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
9501
|
+
title = excluded.title,
|
|
9502
|
+
summary = excluded.summary,
|
|
9503
|
+
entity_name = excluded.entity_name,
|
|
9504
|
+
source_kind = excluded.source_kind,
|
|
9505
|
+
source_ref = excluded.source_ref,
|
|
9506
|
+
locator = excluded.locator,
|
|
9507
|
+
captured_hash = excluded.captured_hash,
|
|
9508
|
+
session_id = excluded.session_id,
|
|
9509
|
+
status = excluded.status,
|
|
9510
|
+
freshness = 'current',
|
|
9511
|
+
stale_reason = NULL,
|
|
9512
|
+
files_json = excluded.files_json,
|
|
9513
|
+
related_entities_json = excluded.related_entities_json,
|
|
9514
|
+
updated_at = excluded.updated_at
|
|
9515
|
+
`).run(
|
|
9516
|
+
card.id,
|
|
9517
|
+
card.projectId,
|
|
9518
|
+
card.candidateKind,
|
|
9519
|
+
card.candidateId,
|
|
9520
|
+
card.title,
|
|
9521
|
+
card.summary,
|
|
9522
|
+
card.entityName ?? null,
|
|
9523
|
+
card.sourceKind,
|
|
9524
|
+
card.sourceRef,
|
|
9525
|
+
card.locator ?? null,
|
|
9526
|
+
card.capturedHash ?? null,
|
|
9527
|
+
card.sessionId ?? null,
|
|
9528
|
+
card.status,
|
|
9529
|
+
card.verification,
|
|
9530
|
+
card.freshness,
|
|
9531
|
+
JSON.stringify(card.files),
|
|
9532
|
+
JSON.stringify(card.relatedEntities),
|
|
9533
|
+
card.createdAt,
|
|
9534
|
+
card.updatedAt
|
|
9535
|
+
);
|
|
9536
|
+
return this.get(card.projectId, card.candidateKind, card.candidateId) ?? card;
|
|
9537
|
+
}
|
|
9538
|
+
get(projectId, candidateKind, candidateId) {
|
|
9539
|
+
const row = this.requireDb().prepare(`
|
|
9540
|
+
SELECT * FROM evidence_cards WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
9541
|
+
`).get(projectId, candidateKind, candidateId);
|
|
9542
|
+
return row ? rowToCard(row) : void 0;
|
|
9543
|
+
}
|
|
9544
|
+
list(projectId, options = {}) {
|
|
9545
|
+
const limit2 = Math.min(100, Math.max(1, Math.floor(options.limit ?? 20)));
|
|
9546
|
+
const clauses = ["project_id = ?"];
|
|
9547
|
+
const args = [projectId];
|
|
9548
|
+
if (options.freshness) {
|
|
9549
|
+
clauses.push("freshness = ?");
|
|
9550
|
+
args.push(options.freshness);
|
|
9551
|
+
}
|
|
9552
|
+
if (options.status) {
|
|
9553
|
+
clauses.push("status = ?");
|
|
9554
|
+
args.push(options.status);
|
|
9555
|
+
}
|
|
9556
|
+
args.push(limit2);
|
|
9557
|
+
const rows = this.requireDb().prepare(`
|
|
9558
|
+
SELECT * FROM evidence_cards WHERE ${clauses.join(" AND ")} ORDER BY updated_at DESC, id DESC LIMIT ?
|
|
9559
|
+
`).all(...args);
|
|
9560
|
+
return rows.map(rowToCard);
|
|
9561
|
+
}
|
|
9562
|
+
syncObservations(observations2) {
|
|
9563
|
+
return observations2.map((observation) => this.upsertObservation(observation));
|
|
9564
|
+
}
|
|
9565
|
+
markStaleForPaths(projectId, paths, reason = "source file changed") {
|
|
9566
|
+
const normalized = new Set(paths.map((value) => value.replace(/\\/g, "/").toLowerCase()));
|
|
9567
|
+
if (normalized.size === 0) return 0;
|
|
9568
|
+
const db2 = this.requireDb();
|
|
9569
|
+
const rows = db2.prepare(`SELECT * FROM evidence_cards WHERE project_id = ? AND freshness != 'stale'`).all(projectId);
|
|
9570
|
+
const update2 = db2.prepare(`
|
|
9571
|
+
UPDATE evidence_cards SET freshness = 'stale', stale_reason = ?, updated_at = ?
|
|
9572
|
+
WHERE id = ?
|
|
9573
|
+
`);
|
|
9574
|
+
let changed = 0;
|
|
9575
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
9576
|
+
const run = db2.transaction(() => {
|
|
9577
|
+
for (const row of rows) {
|
|
9578
|
+
const files = safeJson(row.files_json, []);
|
|
9579
|
+
if (!files.some((file) => normalized.has(file.replace(/\\/g, "/").toLowerCase()))) continue;
|
|
9580
|
+
update2.run(reason, now3, row.id);
|
|
9581
|
+
changed++;
|
|
9582
|
+
}
|
|
9583
|
+
});
|
|
9584
|
+
run();
|
|
9585
|
+
return changed;
|
|
9586
|
+
}
|
|
9587
|
+
setVerification(projectId, cardId, verification) {
|
|
9588
|
+
this.requireDb().prepare(`
|
|
9589
|
+
UPDATE evidence_cards SET verification = ?, updated_at = ? WHERE project_id = ? AND id = ?
|
|
9590
|
+
`).run(verification, (/* @__PURE__ */ new Date()).toISOString(), projectId, cardId);
|
|
9591
|
+
}
|
|
9592
|
+
recordEvent(projectId, cardId, kind, detail) {
|
|
9593
|
+
const event = {
|
|
9594
|
+
id: randomUUID3(),
|
|
9595
|
+
projectId,
|
|
9596
|
+
cardId,
|
|
9597
|
+
kind,
|
|
9598
|
+
...detail ? { detail: detail.slice(0, 2e3) } : {},
|
|
9599
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9600
|
+
};
|
|
9601
|
+
this.requireDb().prepare(`
|
|
9602
|
+
INSERT INTO evidence_card_events (id, project_id, card_id, kind, detail, created_at)
|
|
9603
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
9604
|
+
`).run(event.id, event.projectId, event.cardId, event.kind, event.detail ?? null, event.createdAt);
|
|
9605
|
+
return event;
|
|
9606
|
+
}
|
|
9607
|
+
listEvents(cardId, limit2 = 50) {
|
|
9608
|
+
const rows = this.requireDb().prepare(`
|
|
9609
|
+
SELECT * FROM evidence_card_events WHERE card_id = ? ORDER BY created_at DESC LIMIT ?
|
|
9610
|
+
`).all(cardId, Math.min(200, Math.max(1, Math.floor(limit2))));
|
|
9611
|
+
return rows.map((row) => ({
|
|
9612
|
+
id: String(row.id),
|
|
9613
|
+
projectId: String(row.project_id),
|
|
9614
|
+
cardId: String(row.card_id),
|
|
9615
|
+
kind: String(row.kind),
|
|
9616
|
+
...row.detail ? { detail: String(row.detail) } : {},
|
|
9617
|
+
createdAt: String(row.created_at)
|
|
9618
|
+
}));
|
|
9619
|
+
}
|
|
9620
|
+
};
|
|
9621
|
+
}
|
|
9622
|
+
});
|
|
9623
|
+
|
|
8987
9624
|
// src/runtime/isolated-maintenance.ts
|
|
8988
9625
|
import { spawn } from "child_process";
|
|
8989
9626
|
import { existsSync as existsSync8 } from "fs";
|
|
@@ -9145,7 +9782,7 @@ var workspace_store_exports = {};
|
|
|
9145
9782
|
__export(workspace_store_exports, {
|
|
9146
9783
|
KnowledgeWorkspaceStore: () => KnowledgeWorkspaceStore
|
|
9147
9784
|
});
|
|
9148
|
-
import { randomUUID as
|
|
9785
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
9149
9786
|
function arrayValue(raw) {
|
|
9150
9787
|
if (typeof raw !== "string" || !raw) return [];
|
|
9151
9788
|
try {
|
|
@@ -9286,7 +9923,7 @@ var init_workspace_store = __esm({
|
|
|
9286
9923
|
}
|
|
9287
9924
|
createProposal(input) {
|
|
9288
9925
|
const proposal = {
|
|
9289
|
-
id: input.id ??
|
|
9926
|
+
id: input.id ?? randomUUID4(),
|
|
9290
9927
|
...input,
|
|
9291
9928
|
status: input.status ?? "pending",
|
|
9292
9929
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -9339,13 +9976,13 @@ __export(workspace_exports, {
|
|
|
9339
9976
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
9340
9977
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
9341
9978
|
});
|
|
9342
|
-
import { createHash as
|
|
9979
|
+
import { createHash as createHash4 } from "crypto";
|
|
9343
9980
|
import { execFile } from "child_process";
|
|
9344
9981
|
import { promises as fs9 } from "fs";
|
|
9345
9982
|
import path13 from "path";
|
|
9346
9983
|
import { promisify } from "util";
|
|
9347
9984
|
function hash(value) {
|
|
9348
|
-
return
|
|
9985
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
9349
9986
|
}
|
|
9350
9987
|
function workspaceId(projectId, mode) {
|
|
9351
9988
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -9945,7 +10582,7 @@ var media_store_exports = {};
|
|
|
9945
10582
|
__export(media_store_exports, {
|
|
9946
10583
|
MediaStore: () => MediaStore
|
|
9947
10584
|
});
|
|
9948
|
-
import { randomUUID as
|
|
10585
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
9949
10586
|
function asOptionalText(value) {
|
|
9950
10587
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
9951
10588
|
}
|
|
@@ -10115,7 +10752,7 @@ var init_media_store = __esm({
|
|
|
10115
10752
|
return { asset: this.getAsset(input.projectId, existing.id), deduplicated: true };
|
|
10116
10753
|
}
|
|
10117
10754
|
const asset = {
|
|
10118
|
-
id:
|
|
10755
|
+
id: randomUUID5(),
|
|
10119
10756
|
...input,
|
|
10120
10757
|
createdAt: now3,
|
|
10121
10758
|
updatedAt: now3
|
|
@@ -10195,7 +10832,7 @@ var init_media_store = __esm({
|
|
|
10195
10832
|
`).get(input.assetId, input.observationId ?? null, input.role);
|
|
10196
10833
|
if (existing) return rowToLink(existing);
|
|
10197
10834
|
const link = {
|
|
10198
|
-
id:
|
|
10835
|
+
id: randomUUID5(),
|
|
10199
10836
|
assetId: input.assetId,
|
|
10200
10837
|
projectId: input.projectId,
|
|
10201
10838
|
...input.observationId !== void 0 ? { observationId: input.observationId } : {},
|
|
@@ -10234,7 +10871,7 @@ var init_media_store = __esm({
|
|
|
10234
10871
|
return rowToDerivation(this.db.prepare("SELECT * FROM media_derivations WHERE id = ?").get(existing.id));
|
|
10235
10872
|
}
|
|
10236
10873
|
const derivation = {
|
|
10237
|
-
id:
|
|
10874
|
+
id: randomUUID5(),
|
|
10238
10875
|
...input,
|
|
10239
10876
|
content,
|
|
10240
10877
|
...error ? { error } : {},
|
|
@@ -10321,7 +10958,7 @@ var init_media_store = __esm({
|
|
|
10321
10958
|
createJob(input) {
|
|
10322
10959
|
const now3 = Date.now();
|
|
10323
10960
|
const job = {
|
|
10324
|
-
id:
|
|
10961
|
+
id: randomUUID5(),
|
|
10325
10962
|
projectId: input.projectId,
|
|
10326
10963
|
kind: input.kind,
|
|
10327
10964
|
status: "queued",
|
|
@@ -10497,14 +11134,14 @@ __export(asset_store_exports, {
|
|
|
10497
11134
|
readMediaAsset: () => readMediaAsset,
|
|
10498
11135
|
removeMediaAsset: () => removeMediaAsset
|
|
10499
11136
|
});
|
|
10500
|
-
import { createHash as
|
|
11137
|
+
import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
|
|
10501
11138
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
10502
11139
|
import path14 from "path";
|
|
10503
11140
|
function mediaRoot(dataDir) {
|
|
10504
11141
|
return path14.resolve(dataDir, "media");
|
|
10505
11142
|
}
|
|
10506
11143
|
function projectStorageKey(projectId) {
|
|
10507
|
-
return
|
|
11144
|
+
return createHash5("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
10508
11145
|
}
|
|
10509
11146
|
function validateUnderRoot(root, candidate) {
|
|
10510
11147
|
const resolved = path14.resolve(candidate);
|
|
@@ -10564,14 +11201,14 @@ async function readHeader(filePath, bytes = 32) {
|
|
|
10564
11201
|
}
|
|
10565
11202
|
async function sha256File(filePath) {
|
|
10566
11203
|
const bytes = await readFile3(filePath);
|
|
10567
|
-
return
|
|
11204
|
+
return createHash5("sha256").update(bytes).digest("hex");
|
|
10568
11205
|
}
|
|
10569
11206
|
function destinationFor(root, projectId, sha256, extension3) {
|
|
10570
11207
|
const relative3 = path14.join("assets", projectStorageKey(projectId), sha256.slice(0, 2), `${sha256}${extension3}`);
|
|
10571
11208
|
return { relative: relative3, absolute: validateUnderRoot(root, path14.join(root, relative3)) };
|
|
10572
11209
|
}
|
|
10573
11210
|
function deletionStagingPath(root, assetId) {
|
|
10574
|
-
return validateUnderRoot(root, path14.join(root, ".trash", `${assetId}.${
|
|
11211
|
+
return validateUnderRoot(root, path14.join(root, ".trash", `${assetId}.${randomUUID6()}.pending-delete`));
|
|
10575
11212
|
}
|
|
10576
11213
|
async function destinationExists(destination) {
|
|
10577
11214
|
try {
|
|
@@ -10585,7 +11222,7 @@ async function destinationExists(destination) {
|
|
|
10585
11222
|
async function persistFile(source, destination) {
|
|
10586
11223
|
await mkdir3(path14.dirname(destination), { recursive: true });
|
|
10587
11224
|
if (await destinationExists(destination)) return false;
|
|
10588
|
-
const temporary = `${destination}.${
|
|
11225
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
10589
11226
|
try {
|
|
10590
11227
|
await copyFile(source, temporary);
|
|
10591
11228
|
await rename2(temporary, destination);
|
|
@@ -10601,7 +11238,7 @@ async function persistFile(source, destination) {
|
|
|
10601
11238
|
async function persistBuffer(bytes, destination) {
|
|
10602
11239
|
await mkdir3(path14.dirname(destination), { recursive: true });
|
|
10603
11240
|
if (await destinationExists(destination)) return false;
|
|
10604
|
-
const temporary = `${destination}.${
|
|
11241
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
10605
11242
|
try {
|
|
10606
11243
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
10607
11244
|
await rename2(temporary, destination);
|
|
@@ -10670,7 +11307,7 @@ async function importMediaBuffer(input) {
|
|
|
10670
11307
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
10671
11308
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
10672
11309
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
10673
|
-
const sha256 =
|
|
11310
|
+
const sha256 = createHash5("sha256").update(input.bytes).digest("hex");
|
|
10674
11311
|
return importKnownMedia({
|
|
10675
11312
|
dataDir: input.dataDir,
|
|
10676
11313
|
projectId: input.projectId,
|
|
@@ -10688,7 +11325,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
10688
11325
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
10689
11326
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
10690
11327
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
10691
|
-
const sha256 =
|
|
11328
|
+
const sha256 = createHash5("sha256").update(bytes).digest("hex");
|
|
10692
11329
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
10693
11330
|
return bytes;
|
|
10694
11331
|
}
|
|
@@ -63558,7 +64195,7 @@ var require_gaxios = __commonJS({
|
|
|
63558
64195
|
var retry_js_1 = require_retry3();
|
|
63559
64196
|
var stream_1 = __require("stream");
|
|
63560
64197
|
var interceptor_js_1 = require_interceptor();
|
|
63561
|
-
var
|
|
64198
|
+
var randomUUID19 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
63562
64199
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
63563
64200
|
var Gaxios = class {
|
|
63564
64201
|
agentCache = /* @__PURE__ */ new Map();
|
|
@@ -63831,7 +64468,7 @@ var require_gaxios = __commonJS({
|
|
|
63831
64468
|
*/
|
|
63832
64469
|
["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
63833
64470
|
if (opts.multipart?.length) {
|
|
63834
|
-
const boundary = await
|
|
64471
|
+
const boundary = await randomUUID19();
|
|
63835
64472
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
63836
64473
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
63837
64474
|
} else if (shouldDirectlyPassData) {
|
|
@@ -76058,7 +76695,7 @@ var require_websocket = __commonJS({
|
|
|
76058
76695
|
var http3 = __require("http");
|
|
76059
76696
|
var net = __require("net");
|
|
76060
76697
|
var tls = __require("tls");
|
|
76061
|
-
var { randomBytes: randomBytes2, createHash:
|
|
76698
|
+
var { randomBytes: randomBytes2, createHash: createHash17 } = __require("crypto");
|
|
76062
76699
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
76063
76700
|
var { URL: URL2 } = __require("url");
|
|
76064
76701
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -76726,7 +77363,7 @@ var require_websocket = __commonJS({
|
|
|
76726
77363
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
76727
77364
|
return;
|
|
76728
77365
|
}
|
|
76729
|
-
const digest2 =
|
|
77366
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
76730
77367
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
76731
77368
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
76732
77369
|
return;
|
|
@@ -77098,7 +77735,7 @@ var require_websocket_server = __commonJS({
|
|
|
77098
77735
|
var EventEmitter2 = __require("events");
|
|
77099
77736
|
var http3 = __require("http");
|
|
77100
77737
|
var { Duplex } = __require("stream");
|
|
77101
|
-
var { createHash:
|
|
77738
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
77102
77739
|
var extension3 = require_extension();
|
|
77103
77740
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
77104
77741
|
var subprotocol2 = require_subprotocol();
|
|
@@ -77405,7 +78042,7 @@ var require_websocket_server = __commonJS({
|
|
|
77405
78042
|
);
|
|
77406
78043
|
}
|
|
77407
78044
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
77408
|
-
const digest2 =
|
|
78045
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
77409
78046
|
const headers = [
|
|
77410
78047
|
"HTTP/1.1 101 Switching Protocols",
|
|
77411
78048
|
"Upgrade: websocket",
|
|
@@ -144659,6 +145296,186 @@ var init_audio_jobs = __esm({
|
|
|
144659
145296
|
}
|
|
144660
145297
|
});
|
|
144661
145298
|
|
|
145299
|
+
// src/memory/feedback-model.ts
|
|
145300
|
+
function feedbackWeightMultiplier(weight) {
|
|
145301
|
+
return Math.max(0.35, Math.min(1.4, 0.35 + Math.max(0, Math.min(2, weight)) * 0.525));
|
|
145302
|
+
}
|
|
145303
|
+
var init_feedback_model = __esm({
|
|
145304
|
+
"src/memory/feedback-model.ts"() {
|
|
145305
|
+
"use strict";
|
|
145306
|
+
init_esm_shims();
|
|
145307
|
+
}
|
|
145308
|
+
});
|
|
145309
|
+
|
|
145310
|
+
// src/memory/feedback.ts
|
|
145311
|
+
var feedback_exports = {};
|
|
145312
|
+
__export(feedback_exports, {
|
|
145313
|
+
FEEDBACK_DELTAS: () => FEEDBACK_DELTAS,
|
|
145314
|
+
MemoryFeedbackStore: () => MemoryFeedbackStore,
|
|
145315
|
+
applyMemoryFeedback: () => applyMemoryFeedback,
|
|
145316
|
+
feedbackWeightMultiplier: () => feedbackWeightMultiplier
|
|
145317
|
+
});
|
|
145318
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
145319
|
+
function applyMemoryFeedback(current, event) {
|
|
145320
|
+
const delta = event.signal === "revoke" ? 0 : FEEDBACK_DELTAS[event.signal];
|
|
145321
|
+
const weight = Math.max(0, Math.min(2, current.weight + delta));
|
|
145322
|
+
const status = (event.signal === "code-conflict" || event.signal === "user-correction" || event.signal === "weaken") && weight < 0.5 ? "archived" : current.status;
|
|
145323
|
+
return { weight, status, audit: [...current.audit, { ...event }] };
|
|
145324
|
+
}
|
|
145325
|
+
function rowToEvent(row) {
|
|
145326
|
+
return {
|
|
145327
|
+
id: String(row.id),
|
|
145328
|
+
projectId: String(row.project_id),
|
|
145329
|
+
candidateKind: row.candidate_kind,
|
|
145330
|
+
candidateId: String(row.candidate_id),
|
|
145331
|
+
signal: row.signal,
|
|
145332
|
+
...row.observed_at ? { at: String(row.observed_at) } : { at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
145333
|
+
...row.actor ? { actor: String(row.actor) } : {},
|
|
145334
|
+
...row.note ? { note: String(row.note) } : {},
|
|
145335
|
+
...row.source_ref ? { sourceRef: String(row.source_ref) } : {},
|
|
145336
|
+
...row.target_event_id ? { targetEventId: String(row.target_event_id) } : {},
|
|
145337
|
+
delta: Number(row.delta ?? 0)
|
|
145338
|
+
};
|
|
145339
|
+
}
|
|
145340
|
+
var FEEDBACK_DELTAS, MemoryFeedbackStore;
|
|
145341
|
+
var init_feedback = __esm({
|
|
145342
|
+
"src/memory/feedback.ts"() {
|
|
145343
|
+
"use strict";
|
|
145344
|
+
init_esm_shims();
|
|
145345
|
+
init_sqlite_db();
|
|
145346
|
+
init_feedback_model();
|
|
145347
|
+
FEEDBACK_DELTAS = {
|
|
145348
|
+
"user-correction": -0.35,
|
|
145349
|
+
"verification-success": 0.25,
|
|
145350
|
+
"verification-failure": -0.25,
|
|
145351
|
+
"code-change": -0.15,
|
|
145352
|
+
used: 0.1,
|
|
145353
|
+
"not-used": -0.05,
|
|
145354
|
+
"code-conflict": -0.4,
|
|
145355
|
+
strengthen: 0.2,
|
|
145356
|
+
weaken: -0.2
|
|
145357
|
+
};
|
|
145358
|
+
MemoryFeedbackStore = class {
|
|
145359
|
+
db = null;
|
|
145360
|
+
async init(dataDir) {
|
|
145361
|
+
this.db = getDatabase(dataDir);
|
|
145362
|
+
}
|
|
145363
|
+
requireDb() {
|
|
145364
|
+
if (!this.db) throw new Error("MemoryFeedbackStore is not initialized.");
|
|
145365
|
+
return this.db;
|
|
145366
|
+
}
|
|
145367
|
+
loadEvents(projectId, candidateKind, candidateId) {
|
|
145368
|
+
return this.requireDb().prepare(`
|
|
145369
|
+
SELECT * FROM memory_feedback_events
|
|
145370
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145371
|
+
ORDER BY observed_at ASC, rowid ASC
|
|
145372
|
+
`).all(projectId, candidateKind, candidateId).map(rowToEvent);
|
|
145373
|
+
}
|
|
145374
|
+
rebuild(projectId, candidateKind, candidateId) {
|
|
145375
|
+
const events = this.loadEvents(projectId, candidateKind, candidateId);
|
|
145376
|
+
const revoked = new Set(events.filter((event) => event.signal === "revoke" && event.targetEventId).map((event) => event.targetEventId));
|
|
145377
|
+
let state = { weight: 1, status: "active", audit: [] };
|
|
145378
|
+
for (const event of events) {
|
|
145379
|
+
if (event.signal === "revoke" || revoked.has(event.id)) {
|
|
145380
|
+
state.audit.push(event);
|
|
145381
|
+
continue;
|
|
145382
|
+
}
|
|
145383
|
+
state = applyMemoryFeedback(state, event);
|
|
145384
|
+
}
|
|
145385
|
+
this.requireDb().prepare(`
|
|
145386
|
+
INSERT INTO memory_feedback_states (project_id, candidate_kind, candidate_id, weight, lifecycle_status, updated_at)
|
|
145387
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
145388
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
145389
|
+
weight = excluded.weight, lifecycle_status = excluded.lifecycle_status, updated_at = excluded.updated_at
|
|
145390
|
+
`).run(projectId, candidateKind, candidateId, state.weight, state.status, (/* @__PURE__ */ new Date()).toISOString());
|
|
145391
|
+
return state;
|
|
145392
|
+
}
|
|
145393
|
+
getState(projectId, candidateKind, candidateId) {
|
|
145394
|
+
const row = this.requireDb().prepare(`
|
|
145395
|
+
SELECT weight, lifecycle_status FROM memory_feedback_states
|
|
145396
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145397
|
+
`).get(projectId, candidateKind, candidateId);
|
|
145398
|
+
if (!row) return { weight: 1, status: "active", audit: [] };
|
|
145399
|
+
return {
|
|
145400
|
+
weight: Number(row.weight ?? 1),
|
|
145401
|
+
status: row.lifecycle_status ?? "active",
|
|
145402
|
+
audit: this.loadEvents(projectId, candidateKind, candidateId)
|
|
145403
|
+
};
|
|
145404
|
+
}
|
|
145405
|
+
listStates(projectId, candidateKind = "observation") {
|
|
145406
|
+
return this.requireDb().prepare(`
|
|
145407
|
+
SELECT candidate_id, weight, lifecycle_status, updated_at
|
|
145408
|
+
FROM memory_feedback_states WHERE project_id = ? AND candidate_kind = ?
|
|
145409
|
+
ORDER BY updated_at DESC
|
|
145410
|
+
`).all(projectId, candidateKind).map((row) => ({
|
|
145411
|
+
candidateId: String(row.candidate_id),
|
|
145412
|
+
weight: Number(row.weight),
|
|
145413
|
+
status: row.lifecycle_status,
|
|
145414
|
+
updatedAt: String(row.updated_at)
|
|
145415
|
+
}));
|
|
145416
|
+
}
|
|
145417
|
+
weights(projectId, candidateKind = "observation") {
|
|
145418
|
+
const states = /* @__PURE__ */ new Map();
|
|
145419
|
+
for (const row of this.listStates(projectId, candidateKind)) {
|
|
145420
|
+
states.set(row.candidateId, this.getState(projectId, candidateKind, row.candidateId));
|
|
145421
|
+
}
|
|
145422
|
+
return states;
|
|
145423
|
+
}
|
|
145424
|
+
record(input) {
|
|
145425
|
+
if (input.signal === "revoke" && !input.targetEventId) {
|
|
145426
|
+
throw new Error("A revoke feedback event requires targetEventId.");
|
|
145427
|
+
}
|
|
145428
|
+
if (input.signal === "revoke") {
|
|
145429
|
+
const target = this.requireDb().prepare(`
|
|
145430
|
+
SELECT 1 FROM memory_feedback_events
|
|
145431
|
+
WHERE id = ? AND project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145432
|
+
`).get(input.targetEventId, input.projectId, input.candidateKind, input.candidateId);
|
|
145433
|
+
if (!target) throw new Error("The feedback event to revoke was not found in the same candidate scope.");
|
|
145434
|
+
}
|
|
145435
|
+
const event = {
|
|
145436
|
+
id: randomUUID7(),
|
|
145437
|
+
projectId: input.projectId,
|
|
145438
|
+
candidateKind: input.candidateKind,
|
|
145439
|
+
candidateId: input.candidateId,
|
|
145440
|
+
signal: input.signal,
|
|
145441
|
+
sourceRef: input.sourceRef,
|
|
145442
|
+
...input.actor ? { actor: input.actor } : {},
|
|
145443
|
+
...input.note ? { note: input.note.slice(0, 2e3) } : {},
|
|
145444
|
+
...input.targetEventId ? { targetEventId: input.targetEventId } : {},
|
|
145445
|
+
at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
145446
|
+
delta: input.signal === "revoke" ? 0 : FEEDBACK_DELTAS[input.signal]
|
|
145447
|
+
};
|
|
145448
|
+
this.requireDb().prepare(`
|
|
145449
|
+
INSERT INTO memory_feedback_events (
|
|
145450
|
+
id, project_id, candidate_kind, candidate_id, signal, actor, note,
|
|
145451
|
+
source_ref, target_event_id, delta, observed_at
|
|
145452
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
145453
|
+
`).run(
|
|
145454
|
+
event.id,
|
|
145455
|
+
event.projectId,
|
|
145456
|
+
event.candidateKind,
|
|
145457
|
+
event.candidateId,
|
|
145458
|
+
event.signal,
|
|
145459
|
+
event.actor ?? null,
|
|
145460
|
+
event.note ?? null,
|
|
145461
|
+
event.sourceRef,
|
|
145462
|
+
event.targetEventId ?? null,
|
|
145463
|
+
event.delta,
|
|
145464
|
+
event.at
|
|
145465
|
+
);
|
|
145466
|
+
return { event, state: this.rebuild(input.projectId, input.candidateKind, input.candidateId) };
|
|
145467
|
+
}
|
|
145468
|
+
audit(projectId, candidateKind, candidateId, limit2 = 100) {
|
|
145469
|
+
return this.requireDb().prepare(`
|
|
145470
|
+
SELECT * FROM memory_feedback_events
|
|
145471
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
145472
|
+
ORDER BY observed_at DESC, rowid DESC LIMIT ?
|
|
145473
|
+
`).all(projectId, candidateKind, candidateId, Math.min(200, Math.max(1, Math.floor(limit2)))).map(rowToEvent);
|
|
145474
|
+
}
|
|
145475
|
+
};
|
|
145476
|
+
}
|
|
145477
|
+
});
|
|
145478
|
+
|
|
144662
145479
|
// src/memory/retention.ts
|
|
144663
145480
|
var retention_exports = {};
|
|
144664
145481
|
__export(retention_exports, {
|
|
@@ -144700,6 +145517,7 @@ function getEffectiveRetentionDays(doc) {
|
|
|
144700
145517
|
}
|
|
144701
145518
|
function isImmune(doc) {
|
|
144702
145519
|
if (doc.type === "probe") return false;
|
|
145520
|
+
if (doc.feedbackStatus === "archived") return false;
|
|
144703
145521
|
if (doc.admissionState === "candidate" || doc.admissionState === "ephemeral") return false;
|
|
144704
145522
|
if (doc.valueCategory === "core") return true;
|
|
144705
145523
|
const importance = getImportanceLevel(doc);
|
|
@@ -144732,7 +145550,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
144732
145550
|
const decayFactor = Math.exp(-ageDays / retention);
|
|
144733
145551
|
const accessCount = doc.accessCount ?? 0;
|
|
144734
145552
|
const accessBoost = Math.min(2, 1 + 0.1 * accessCount);
|
|
144735
|
-
|
|
145553
|
+
const feedbackMultiplier = doc.feedbackWeight === void 0 ? 1 : feedbackWeightMultiplier(doc.feedbackWeight);
|
|
145554
|
+
let totalScore = base * decayFactor * accessBoost * feedbackMultiplier;
|
|
144736
145555
|
const immune = isImmune(doc);
|
|
144737
145556
|
if (immune) {
|
|
144738
145557
|
totalScore = Math.max(totalScore, 0.5);
|
|
@@ -144744,7 +145563,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
144744
145563
|
decayFactor,
|
|
144745
145564
|
accessBoost,
|
|
144746
145565
|
ageDays,
|
|
144747
|
-
isImmune: immune
|
|
145566
|
+
isImmune: immune,
|
|
145567
|
+
feedbackMultiplier
|
|
144748
145568
|
};
|
|
144749
145569
|
}
|
|
144750
145570
|
function rankByRelevance(docs, referenceTime) {
|
|
@@ -144752,6 +145572,7 @@ function rankByRelevance(docs, referenceTime) {
|
|
|
144752
145572
|
}
|
|
144753
145573
|
function getRetentionZone(doc, referenceTime) {
|
|
144754
145574
|
const now3 = referenceTime ?? /* @__PURE__ */ new Date();
|
|
145575
|
+
if (doc.feedbackStatus === "archived") return "archive-candidate";
|
|
144755
145576
|
const importance = getImportanceLevel(doc);
|
|
144756
145577
|
const retention = getEffectiveRetentionDays(doc);
|
|
144757
145578
|
const createdAt = new Date(doc.createdAt);
|
|
@@ -144823,7 +145644,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
144823
145644
|
summary: parts.join(" ; ")
|
|
144824
145645
|
};
|
|
144825
145646
|
}
|
|
144826
|
-
function toRetentionDocument(obs, accessMap) {
|
|
145647
|
+
function toRetentionDocument(obs, accessMap, feedback) {
|
|
144827
145648
|
const access3 = accessMap?.get(obs.id);
|
|
144828
145649
|
return {
|
|
144829
145650
|
id: `obs-${obs.id}`,
|
|
@@ -144845,11 +145666,12 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
144845
145666
|
sourceDetail: obs.sourceDetail ?? "",
|
|
144846
145667
|
valueCategory: obs.valueCategory ?? "",
|
|
144847
145668
|
admissionState: obs.admissionState ?? "",
|
|
144848
|
-
admissionReason: obs.admissionReason ?? ""
|
|
145669
|
+
admissionReason: obs.admissionReason ?? "",
|
|
145670
|
+
...feedback ? { feedbackWeight: feedback.weight, feedbackStatus: feedback.status } : {}
|
|
144849
145671
|
};
|
|
144850
145672
|
}
|
|
144851
145673
|
function projectObservationRetention(observation, options = {}) {
|
|
144852
|
-
const document2 = toRetentionDocument(observation, options.accessMap);
|
|
145674
|
+
const document2 = toRetentionDocument(observation, options.accessMap, options.feedback);
|
|
144853
145675
|
const relevance = calculateRelevance(document2, options.referenceTime);
|
|
144854
145676
|
const explanation = explainRetention(document2, options.referenceTime);
|
|
144855
145677
|
return {
|
|
@@ -144874,7 +145696,17 @@ function summarizeRetentionProjections(projections) {
|
|
|
144874
145696
|
}
|
|
144875
145697
|
return { active, stale, archiveCandidates, immune };
|
|
144876
145698
|
}
|
|
144877
|
-
async function
|
|
145699
|
+
async function loadFeedbackStore(dataDir) {
|
|
145700
|
+
try {
|
|
145701
|
+
const { MemoryFeedbackStore: MemoryFeedbackStore2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
|
|
145702
|
+
const store = new MemoryFeedbackStore2();
|
|
145703
|
+
await store.init(dataDir);
|
|
145704
|
+
return store;
|
|
145705
|
+
} catch {
|
|
145706
|
+
return void 0;
|
|
145707
|
+
}
|
|
145708
|
+
}
|
|
145709
|
+
async function archiveExpiredBatch(projectDir2, options) {
|
|
144878
145710
|
const store = getObservationStore();
|
|
144879
145711
|
const limit2 = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));
|
|
144880
145712
|
const afterId = Math.max(0, Math.floor(options.afterId ?? 0));
|
|
@@ -144883,11 +145715,13 @@ async function archiveExpiredBatch(_projectDir, options) {
|
|
|
144883
145715
|
afterId,
|
|
144884
145716
|
limit: limit2 + 1
|
|
144885
145717
|
});
|
|
145718
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
144886
145719
|
const hasMore = page.length > limit2;
|
|
144887
145720
|
const scanned = hasMore ? page.slice(0, limit2) : page;
|
|
144888
145721
|
const candidateIds = scanned.filter((observation) => !options.reader || canManageObservation(observation, options.reader)).filter((observation) => projectObservationRetention(observation, {
|
|
144889
145722
|
accessMap: options.accessMap,
|
|
144890
|
-
referenceTime: options.referenceTime
|
|
145723
|
+
referenceTime: options.referenceTime,
|
|
145724
|
+
...feedback ? { feedback: feedback.getState(options.projectId, "observation", String(observation.id)) } : {}
|
|
144891
145725
|
}).zone === "archive-candidate").map((observation) => observation.id);
|
|
144892
145726
|
const archived = candidateIds.length === 0 ? 0 : await store.atomic(async (tx) => {
|
|
144893
145727
|
const updates = await Promise.all(
|
|
@@ -144918,6 +145752,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
144918
145752
|
const remaining = reader2 ? remainingObservations.filter((observation) => canManageObservation(observation, reader2)).length : remainingObservations.length;
|
|
144919
145753
|
return { archived, remaining };
|
|
144920
145754
|
}
|
|
145755
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
144921
145756
|
return await store.atomic(async (tx) => {
|
|
144922
145757
|
const allObs = await tx.loadAll();
|
|
144923
145758
|
const activeObs = allObs.filter(
|
|
@@ -144925,7 +145760,11 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
144925
145760
|
);
|
|
144926
145761
|
const archivedIds = [];
|
|
144927
145762
|
for (const obs of activeObs) {
|
|
144928
|
-
const retention = projectObservationRetention(obs, {
|
|
145763
|
+
const retention = projectObservationRetention(obs, {
|
|
145764
|
+
accessMap,
|
|
145765
|
+
referenceTime,
|
|
145766
|
+
...feedback ? { feedback: feedback.getState(obs.projectId, "observation", String(obs.id)) } : {}
|
|
145767
|
+
});
|
|
144929
145768
|
if (retention.zone === "archive-candidate") {
|
|
144930
145769
|
archivedIds.push(obs.id);
|
|
144931
145770
|
}
|
|
@@ -144945,6 +145784,7 @@ var init_retention = __esm({
|
|
|
144945
145784
|
init_esm_shims();
|
|
144946
145785
|
init_obs_store();
|
|
144947
145786
|
init_visibility();
|
|
145787
|
+
init_feedback_model();
|
|
144948
145788
|
RETENTION_DAYS = {
|
|
144949
145789
|
critical: 365,
|
|
144950
145790
|
high: 180,
|
|
@@ -144985,7 +145825,7 @@ var owner_exports = {};
|
|
|
144985
145825
|
__export(owner_exports, {
|
|
144986
145826
|
resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
|
|
144987
145827
|
});
|
|
144988
|
-
import { randomUUID as
|
|
145828
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
144989
145829
|
import { promises as fs12 } from "fs";
|
|
144990
145830
|
import path20 from "path";
|
|
144991
145831
|
function ownerPath(dataDir) {
|
|
@@ -145015,7 +145855,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
|
|
|
145015
145855
|
await fs12.mkdir(path20.dirname(filePath), { recursive: true });
|
|
145016
145856
|
const created = {
|
|
145017
145857
|
version: 1,
|
|
145018
|
-
id: "local-" +
|
|
145858
|
+
id: "local-" + randomUUID8(),
|
|
145019
145859
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
145020
145860
|
};
|
|
145021
145861
|
try {
|
|
@@ -145038,7 +145878,7 @@ var init_owner = __esm({
|
|
|
145038
145878
|
});
|
|
145039
145879
|
|
|
145040
145880
|
// src/memory/long-term-store.ts
|
|
145041
|
-
import { randomUUID as
|
|
145881
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
145042
145882
|
function optionalText2(value) {
|
|
145043
145883
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
145044
145884
|
}
|
|
@@ -145089,7 +145929,7 @@ function rowToEvidence(row) {
|
|
|
145089
145929
|
createdAt: row.createdAt
|
|
145090
145930
|
};
|
|
145091
145931
|
}
|
|
145092
|
-
function
|
|
145932
|
+
function rowToEvent2(row) {
|
|
145093
145933
|
return {
|
|
145094
145934
|
id: row.id,
|
|
145095
145935
|
memoryId: row.memoryId,
|
|
@@ -145198,7 +146038,7 @@ var init_long_term_store = __esm({
|
|
|
145198
146038
|
}
|
|
145199
146039
|
insertEvidence(input) {
|
|
145200
146040
|
const evidence = {
|
|
145201
|
-
id:
|
|
146041
|
+
id: randomUUID9(),
|
|
145202
146042
|
...input,
|
|
145203
146043
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
145204
146044
|
};
|
|
@@ -145225,7 +146065,7 @@ var init_long_term_store = __esm({
|
|
|
145225
146065
|
}
|
|
145226
146066
|
recordEvent(input) {
|
|
145227
146067
|
const event = {
|
|
145228
|
-
id:
|
|
146068
|
+
id: randomUUID9(),
|
|
145229
146069
|
...input,
|
|
145230
146070
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
145231
146071
|
};
|
|
@@ -145246,7 +146086,7 @@ var init_long_term_store = __esm({
|
|
|
145246
146086
|
listEvents(memoryId) {
|
|
145247
146087
|
return this.db.prepare(`
|
|
145248
146088
|
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
145249
|
-
`).all(memoryId).map(
|
|
146089
|
+
`).all(memoryId).map(rowToEvent2);
|
|
145250
146090
|
}
|
|
145251
146091
|
markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
145252
146092
|
const unique2 = [...new Set(ids.filter(Boolean))];
|
|
@@ -145315,7 +146155,7 @@ __export(long_term_exports, {
|
|
|
145315
146155
|
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
145316
146156
|
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
145317
146157
|
});
|
|
145318
|
-
import { randomUUID as
|
|
146158
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
145319
146159
|
function isOneOf(value, values) {
|
|
145320
146160
|
return typeof value === "string" && values.includes(value);
|
|
145321
146161
|
}
|
|
@@ -145497,7 +146337,7 @@ async function createManualLongTermMemory(input) {
|
|
|
145497
146337
|
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
145498
146338
|
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
145499
146339
|
assertScope(input.scope);
|
|
145500
|
-
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" +
|
|
146340
|
+
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID10(), relation: "supports" }];
|
|
145501
146341
|
return createLongTermMemoryWithDataDir({
|
|
145502
146342
|
dataDir: input.dataDir,
|
|
145503
146343
|
originProjectId: input.projectId,
|
|
@@ -145552,7 +146392,7 @@ async function createLongTermMemoryWithDataDir(input) {
|
|
|
145552
146392
|
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
145553
146393
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
145554
146394
|
const memory = {
|
|
145555
|
-
id:
|
|
146395
|
+
id: randomUUID10(),
|
|
145556
146396
|
originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
|
|
145557
146397
|
ownerId: compactText(input.ownerId, "owner id", 160),
|
|
145558
146398
|
scope: input.scope,
|
|
@@ -145870,9 +146710,9 @@ var init_long_term = __esm({
|
|
|
145870
146710
|
});
|
|
145871
146711
|
|
|
145872
146712
|
// src/codegraph/ids.ts
|
|
145873
|
-
import { createHash as
|
|
146713
|
+
import { createHash as createHash6 } from "crypto";
|
|
145874
146714
|
function digest(input) {
|
|
145875
|
-
return
|
|
146715
|
+
return createHash6("sha256").update(input).digest("hex").slice(0, 16);
|
|
145876
146716
|
}
|
|
145877
146717
|
function normalizeCodePath(path35) {
|
|
145878
146718
|
return path35.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -145907,7 +146747,7 @@ var store_exports = {};
|
|
|
145907
146747
|
__export(store_exports, {
|
|
145908
146748
|
CodeGraphStore: () => CodeGraphStore
|
|
145909
146749
|
});
|
|
145910
|
-
import { randomUUID as
|
|
146750
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
145911
146751
|
import { posix as pathPosix } from "path";
|
|
145912
146752
|
function rowToFile(row) {
|
|
145913
146753
|
return {
|
|
@@ -146624,7 +147464,7 @@ var init_store = __esm({
|
|
|
146624
147464
|
* so an interrupted scan cannot be advertised as complete.
|
|
146625
147465
|
*/
|
|
146626
147466
|
recordCodeStateSnapshot(input) {
|
|
146627
|
-
const id =
|
|
147467
|
+
const id = randomUUID11();
|
|
146628
147468
|
let snapshot;
|
|
146629
147469
|
const tx = this.db.transaction(() => {
|
|
146630
147470
|
const previous = this.db.prepare(
|
|
@@ -146702,7 +147542,7 @@ var init_store = __esm({
|
|
|
146702
147542
|
|
|
146703
147543
|
// src/codegraph/code-state.ts
|
|
146704
147544
|
import { execFile as execFile2 } from "child_process";
|
|
146705
|
-
import { createHash as
|
|
147545
|
+
import { createHash as createHash7 } from "crypto";
|
|
146706
147546
|
import { promisify as promisify3 } from "util";
|
|
146707
147547
|
async function runGit(rootPath, args) {
|
|
146708
147548
|
try {
|
|
@@ -146731,7 +147571,7 @@ function changedPathCount(status) {
|
|
|
146731
147571
|
return count2;
|
|
146732
147572
|
}
|
|
146733
147573
|
function fingerprint(baseRevision, status) {
|
|
146734
|
-
return
|
|
147574
|
+
return createHash7("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
146735
147575
|
}
|
|
146736
147576
|
async function collectCodeStateSnapshot(input) {
|
|
146737
147577
|
const [revision, status] = await Promise.all([
|
|
@@ -146831,11 +147671,11 @@ __export(lite_provider_exports, {
|
|
|
146831
147671
|
indexProjectLite: () => indexProjectLite,
|
|
146832
147672
|
refreshProjectLite: () => refreshProjectLite
|
|
146833
147673
|
});
|
|
146834
|
-
import { createHash as
|
|
147674
|
+
import { createHash as createHash8 } from "crypto";
|
|
146835
147675
|
import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
|
|
146836
147676
|
import { join as join4, relative } from "path";
|
|
146837
147677
|
function hashText(text2) {
|
|
146838
|
-
return
|
|
147678
|
+
return createHash8("sha256").update(text2).digest("hex");
|
|
146839
147679
|
}
|
|
146840
147680
|
function extension2(path35) {
|
|
146841
147681
|
const index = path35.lastIndexOf(".");
|
|
@@ -147402,7 +148242,7 @@ var claim_store_exports = {};
|
|
|
147402
148242
|
__export(claim_store_exports, {
|
|
147403
148243
|
ClaimStore: () => ClaimStore
|
|
147404
148244
|
});
|
|
147405
|
-
import { createHash as
|
|
148245
|
+
import { createHash as createHash9, randomUUID as randomUUID12 } from "crypto";
|
|
147406
148246
|
function optionalText3(value) {
|
|
147407
148247
|
return typeof value === "string" && value ? value : void 0;
|
|
147408
148248
|
}
|
|
@@ -147441,7 +148281,7 @@ function rowToEvidence2(row) {
|
|
|
147441
148281
|
createdAt: row.createdAt
|
|
147442
148282
|
};
|
|
147443
148283
|
}
|
|
147444
|
-
function
|
|
148284
|
+
function rowToEvent3(row) {
|
|
147445
148285
|
return {
|
|
147446
148286
|
id: row.id,
|
|
147447
148287
|
projectId: row.projectId,
|
|
@@ -147455,7 +148295,7 @@ function rowToEvent2(row) {
|
|
|
147455
148295
|
};
|
|
147456
148296
|
}
|
|
147457
148297
|
function evidenceKey(input) {
|
|
147458
|
-
return
|
|
148298
|
+
return createHash9("sha256").update(JSON.stringify([
|
|
147459
148299
|
input.evidenceKind,
|
|
147460
148300
|
input.evidenceId,
|
|
147461
148301
|
input.relation,
|
|
@@ -147586,7 +148426,7 @@ var init_claim_store = __esm({
|
|
|
147586
148426
|
locator, capturedHash, evidenceKey, createdAt
|
|
147587
148427
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
147588
148428
|
`).run(
|
|
147589
|
-
|
|
148429
|
+
randomUUID12(),
|
|
147590
148430
|
input.claimId,
|
|
147591
148431
|
input.evidenceKind,
|
|
147592
148432
|
input.evidenceId,
|
|
@@ -147608,7 +148448,7 @@ var init_claim_store = __esm({
|
|
|
147608
148448
|
}
|
|
147609
148449
|
recordEvent(input) {
|
|
147610
148450
|
const event = {
|
|
147611
|
-
id:
|
|
148451
|
+
id: randomUUID12(),
|
|
147612
148452
|
...input,
|
|
147613
148453
|
...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
|
|
147614
148454
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -147636,7 +148476,7 @@ var init_claim_store = __esm({
|
|
|
147636
148476
|
SELECT * FROM knowledge_claim_events
|
|
147637
148477
|
WHERE claimId = ?
|
|
147638
148478
|
ORDER BY createdAt ASC, id
|
|
147639
|
-
`).all(claimId).map(
|
|
148479
|
+
`).all(claimId).map(rowToEvent3);
|
|
147640
148480
|
}
|
|
147641
148481
|
};
|
|
147642
148482
|
}
|
|
@@ -147653,7 +148493,7 @@ __export(claims_exports, {
|
|
|
147653
148493
|
supersedeClaim: () => supersedeClaim,
|
|
147654
148494
|
writeClaim: () => writeClaim
|
|
147655
148495
|
});
|
|
147656
|
-
import { createHash as
|
|
148496
|
+
import { createHash as createHash10, randomUUID as randomUUID13 } from "crypto";
|
|
147657
148497
|
function compactText2(value, field) {
|
|
147658
148498
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
147659
148499
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -147665,7 +148505,7 @@ function normalizedTerm(value) {
|
|
|
147665
148505
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
147666
148506
|
}
|
|
147667
148507
|
function hashIdentity(parts) {
|
|
147668
|
-
return
|
|
148508
|
+
return createHash10("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
147669
148509
|
}
|
|
147670
148510
|
function buildClaimIdentity(input) {
|
|
147671
148511
|
const subject = normalizedTerm(input.subject);
|
|
@@ -147739,7 +148579,7 @@ function normalizeClaimInput(input) {
|
|
|
147739
148579
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
147740
148580
|
return {
|
|
147741
148581
|
claim: {
|
|
147742
|
-
id:
|
|
148582
|
+
id: randomUUID13(),
|
|
147743
148583
|
projectId,
|
|
147744
148584
|
subject,
|
|
147745
148585
|
predicate,
|
|
@@ -147906,7 +148746,7 @@ function supersedeClaim(store, input) {
|
|
|
147906
148746
|
});
|
|
147907
148747
|
}
|
|
147908
148748
|
function hashObservation(observation) {
|
|
147909
|
-
return
|
|
148749
|
+
return createHash10("sha256").update(JSON.stringify([
|
|
147910
148750
|
observation.title,
|
|
147911
148751
|
observation.narrative,
|
|
147912
148752
|
observation.facts,
|
|
@@ -148150,11 +148990,11 @@ var init_frontmatter = __esm({
|
|
|
148150
148990
|
});
|
|
148151
148991
|
|
|
148152
148992
|
// src/knowledge/markdown.ts
|
|
148153
|
-
import { createHash as
|
|
148993
|
+
import { createHash as createHash11 } from "crypto";
|
|
148154
148994
|
import { promises as fs13 } from "fs";
|
|
148155
148995
|
import path21 from "path";
|
|
148156
148996
|
function hashContent(content) {
|
|
148157
|
-
return
|
|
148997
|
+
return createHash11("sha256").update(content).digest("hex");
|
|
148158
148998
|
}
|
|
148159
148999
|
function stringField(data, key) {
|
|
148160
149000
|
const value = data[key];
|
|
@@ -148280,11 +149120,11 @@ __export(wiki_exports, {
|
|
|
148280
149120
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
148281
149121
|
readKnowledgePage: () => readKnowledgePage
|
|
148282
149122
|
});
|
|
148283
|
-
import { createHash as
|
|
149123
|
+
import { createHash as createHash12 } from "crypto";
|
|
148284
149124
|
import { promises as fs14 } from "fs";
|
|
148285
149125
|
import path22 from "path";
|
|
148286
149126
|
function hash2(value) {
|
|
148287
|
-
return
|
|
149127
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
148288
149128
|
}
|
|
148289
149129
|
function now() {
|
|
148290
149130
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -148828,7 +149668,7 @@ var workflow_store_exports = {};
|
|
|
148828
149668
|
__export(workflow_store_exports, {
|
|
148829
149669
|
WorkflowStore: () => WorkflowStore
|
|
148830
149670
|
});
|
|
148831
|
-
import { randomUUID as
|
|
149671
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
148832
149672
|
function parseJson(value, fallback) {
|
|
148833
149673
|
if (typeof value !== "string" || !value) return fallback;
|
|
148834
149674
|
try {
|
|
@@ -148928,7 +149768,7 @@ var init_workflow_store = __esm({
|
|
|
148928
149768
|
}
|
|
148929
149769
|
recordRun(input) {
|
|
148930
149770
|
const run = {
|
|
148931
|
-
id:
|
|
149771
|
+
id: randomUUID14(),
|
|
148932
149772
|
workflowId: input.workflowId,
|
|
148933
149773
|
projectId: input.projectId,
|
|
148934
149774
|
task: input.task.trim(),
|
|
@@ -149006,7 +149846,7 @@ var init_outcome_types = __esm({
|
|
|
149006
149846
|
});
|
|
149007
149847
|
|
|
149008
149848
|
// src/knowledge/outcome-store.ts
|
|
149009
|
-
import { randomUUID as
|
|
149849
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
149010
149850
|
function optionalText5(value) {
|
|
149011
149851
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
149012
149852
|
}
|
|
@@ -149050,7 +149890,7 @@ var init_outcome_store = __esm({
|
|
|
149050
149890
|
}
|
|
149051
149891
|
record(input) {
|
|
149052
149892
|
const signal = {
|
|
149053
|
-
id:
|
|
149893
|
+
id: randomUUID15(),
|
|
149054
149894
|
projectId: text(input.projectId, "project id"),
|
|
149055
149895
|
candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
|
|
149056
149896
|
candidateId: text(input.candidateId, "candidate id"),
|
|
@@ -149477,11 +150317,11 @@ __export(workflows_exports, {
|
|
|
149477
150317
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
149478
150318
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
149479
150319
|
});
|
|
149480
|
-
import { createHash as
|
|
150320
|
+
import { createHash as createHash13 } from "crypto";
|
|
149481
150321
|
import { promises as fs15 } from "fs";
|
|
149482
150322
|
import path23 from "path";
|
|
149483
150323
|
function hash3(value) {
|
|
149484
|
-
return
|
|
150324
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
149485
150325
|
}
|
|
149486
150326
|
function now2() {
|
|
149487
150327
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -150878,6 +151718,16 @@ async function bindObservationCodeRefsBestEffort(observation) {
|
|
|
150878
151718
|
} catch {
|
|
150879
151719
|
}
|
|
150880
151720
|
}
|
|
151721
|
+
async function persistEvidenceCard(observation) {
|
|
151722
|
+
if (!projectDir) return;
|
|
151723
|
+
try {
|
|
151724
|
+
const evidence = new EvidenceCardStore();
|
|
151725
|
+
await evidence.init(projectDir);
|
|
151726
|
+
evidence.upsertObservation(observation);
|
|
151727
|
+
} catch (error) {
|
|
151728
|
+
console.error(`[memorix] Evidence card projection failed for obs-${observation.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
151729
|
+
}
|
|
151730
|
+
}
|
|
150881
151731
|
function queueClaimDerivation(observation) {
|
|
150882
151732
|
const dataDir = projectDir;
|
|
150883
151733
|
const isExplicit = observation.sourceDetail === "explicit";
|
|
@@ -151224,6 +152074,7 @@ async function storeObservation(input) {
|
|
|
151224
152074
|
}
|
|
151225
152075
|
if (!persistedCallbackInvoked) await input.onPersisted?.(observation);
|
|
151226
152076
|
await bindObservationCodeRefsBestEffort(observation);
|
|
152077
|
+
await persistEvidenceCard(observation);
|
|
151227
152078
|
queueObservationQualification(observation);
|
|
151228
152079
|
if (resolveObservationVisibility(observation) === "project") {
|
|
151229
152080
|
queueClaimDerivation(observation);
|
|
@@ -151316,6 +152167,7 @@ async function upsertObservation(existing, input, now3) {
|
|
|
151316
152167
|
await store.update(existing);
|
|
151317
152168
|
}
|
|
151318
152169
|
await bindObservationCodeRefsBestEffort(existing);
|
|
152170
|
+
await persistEvidenceCard(existing);
|
|
151319
152171
|
queueObservationQualification(existing);
|
|
151320
152172
|
if (resolveObservationVisibility(existing) === "project") {
|
|
151321
152173
|
queueClaimDerivation(existing);
|
|
@@ -151449,6 +152301,7 @@ async function resolveObservations(ids, status = "resolved") {
|
|
|
151449
152301
|
await Promise.all(changed.map((observation) => tx.update(observation)));
|
|
151450
152302
|
});
|
|
151451
152303
|
}
|
|
152304
|
+
for (const observation of changed) await persistEvidenceCard(observation);
|
|
151452
152305
|
return { resolved, notFound };
|
|
151453
152306
|
}
|
|
151454
152307
|
function getProjectObservations(projectId) {
|
|
@@ -151786,6 +152639,7 @@ var init_observations = __esm({
|
|
|
151786
152639
|
init_secret_filter();
|
|
151787
152640
|
init_lifecycle();
|
|
151788
152641
|
init_visibility();
|
|
152642
|
+
init_evidence_store();
|
|
151789
152643
|
observations = [];
|
|
151790
152644
|
nextId = 1;
|
|
151791
152645
|
projectDir = null;
|
|
@@ -155465,7 +156319,7 @@ var compaction_checkpoint_store_exports = {};
|
|
|
155465
156319
|
__export(compaction_checkpoint_store_exports, {
|
|
155466
156320
|
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
155467
156321
|
});
|
|
155468
|
-
import { createHash as
|
|
156322
|
+
import { createHash as createHash15, randomUUID as randomUUID16 } from "crypto";
|
|
155469
156323
|
function optionalText7(value) {
|
|
155470
156324
|
return typeof value === "string" && value ? value : void 0;
|
|
155471
156325
|
}
|
|
@@ -155507,7 +156361,7 @@ function sourceKeyFor(input, summary) {
|
|
|
155507
156361
|
input.tokensBefore ?? "",
|
|
155508
156362
|
input.firstKeptEntryId ?? ""
|
|
155509
156363
|
].join("\0");
|
|
155510
|
-
return `derived:${
|
|
156364
|
+
return `derived:${createHash15("sha256").update(material).digest("hex").slice(0, 32)}`;
|
|
155511
156365
|
}
|
|
155512
156366
|
function rowToCheckpoint(row) {
|
|
155513
156367
|
return {
|
|
@@ -155566,7 +156420,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
155566
156420
|
if (pending) return rowToCheckpoint(pending);
|
|
155567
156421
|
const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
155568
156422
|
const checkpoint = {
|
|
155569
|
-
id:
|
|
156423
|
+
id: randomUUID16(),
|
|
155570
156424
|
projectId: input.projectId,
|
|
155571
156425
|
sessionId: input.sessionId,
|
|
155572
156426
|
agent: input.agent,
|
|
@@ -155574,7 +156428,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
155574
156428
|
captureKind: "preflight",
|
|
155575
156429
|
reason: safeReason(input.reason),
|
|
155576
156430
|
sourceEvent: input.sourceEvent,
|
|
155577
|
-
sourceKey: `pre:${
|
|
156431
|
+
sourceKey: `pre:${randomUUID16()}`,
|
|
155578
156432
|
transcriptAvailable: Boolean(input.transcriptAvailable),
|
|
155579
156433
|
status: "active",
|
|
155580
156434
|
preCapturedAt: now3,
|
|
@@ -155640,7 +156494,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
155640
156494
|
return this.get(checkpoint2.id);
|
|
155641
156495
|
}
|
|
155642
156496
|
const checkpoint = {
|
|
155643
|
-
id:
|
|
156497
|
+
id: randomUUID16(),
|
|
155644
156498
|
projectId: input.projectId,
|
|
155645
156499
|
sessionId: input.sessionId,
|
|
155646
156500
|
agent: input.agent,
|
|
@@ -157004,7 +157858,7 @@ __export(team_store_exports, {
|
|
|
157004
157858
|
isTeamStoreInitialized: () => isTeamStoreInitialized,
|
|
157005
157859
|
resetTeamStore: () => resetTeamStore
|
|
157006
157860
|
});
|
|
157007
|
-
import { randomUUID as
|
|
157861
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
157008
157862
|
import path30 from "path";
|
|
157009
157863
|
import fs18 from "fs";
|
|
157010
157864
|
function getTeamStore() {
|
|
@@ -157293,7 +158147,7 @@ var init_team_store = __esm({
|
|
|
157293
158147
|
* reactivate it (preserving agent_id). Otherwise create a new one.
|
|
157294
158148
|
*/
|
|
157295
158149
|
registerAgent(input) {
|
|
157296
|
-
const instanceId = input.instanceId ||
|
|
158150
|
+
const instanceId = input.instanceId || randomUUID17();
|
|
157297
158151
|
const now3 = Date.now();
|
|
157298
158152
|
const existing = this.stmtAgentFindByInstance.get(
|
|
157299
158153
|
input.projectId,
|
|
@@ -157319,7 +158173,7 @@ var init_team_store = __esm({
|
|
|
157319
158173
|
this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
|
|
157320
158174
|
return row2;
|
|
157321
158175
|
}
|
|
157322
|
-
const agentId =
|
|
158176
|
+
const agentId = randomUUID17();
|
|
157323
158177
|
this.stmtAgentUpsert.run({
|
|
157324
158178
|
agent_id: agentId,
|
|
157325
158179
|
project_id: input.projectId,
|
|
@@ -157421,7 +158275,7 @@ var init_team_store = __esm({
|
|
|
157421
158275
|
return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
|
|
157422
158276
|
}
|
|
157423
158277
|
}
|
|
157424
|
-
const id =
|
|
158278
|
+
const id = randomUUID17();
|
|
157425
158279
|
const now3 = Date.now();
|
|
157426
158280
|
const row = {
|
|
157427
158281
|
id,
|
|
@@ -157471,7 +158325,7 @@ var init_team_store = __esm({
|
|
|
157471
158325
|
// Task Operations (with atomic claim semantics)
|
|
157472
158326
|
// ═══════════════════════════════════════════════════════════════════
|
|
157473
158327
|
createTask(input) {
|
|
157474
|
-
const taskId =
|
|
158328
|
+
const taskId = randomUUID17();
|
|
157475
158329
|
const now3 = Date.now();
|
|
157476
158330
|
const row = {
|
|
157477
158331
|
task_id: taskId,
|
|
@@ -157743,7 +158597,7 @@ var init_team_store = __esm({
|
|
|
157743
158597
|
for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
|
|
157744
158598
|
for (const msg of msgs) {
|
|
157745
158599
|
this.stmtMsgInsert.run({
|
|
157746
|
-
id: msg.id ??
|
|
158600
|
+
id: msg.id ?? randomUUID17(),
|
|
157747
158601
|
project_id: "migrated",
|
|
157748
158602
|
sender_agent_id: msg.from ?? "unknown",
|
|
157749
158603
|
recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
|
|
@@ -158614,6 +159468,23 @@ var init_maintenance = __esm({
|
|
|
158614
159468
|
}
|
|
158615
159469
|
});
|
|
158616
159470
|
|
|
159471
|
+
// src/dashboard/config-provenance.ts
|
|
159472
|
+
function resolveDashboardKeySource({ value, envKeys, configSource }) {
|
|
159473
|
+
for (const envKey of envKeys) {
|
|
159474
|
+
const envValue = process.env[envKey];
|
|
159475
|
+
if (envValue !== value) continue;
|
|
159476
|
+
return getLoadedEnvValue(envKey) === envValue ? ".env" : `env:${envKey}`;
|
|
159477
|
+
}
|
|
159478
|
+
return configSource;
|
|
159479
|
+
}
|
|
159480
|
+
var init_config_provenance = __esm({
|
|
159481
|
+
"src/dashboard/config-provenance.ts"() {
|
|
159482
|
+
"use strict";
|
|
159483
|
+
init_esm_shims();
|
|
159484
|
+
init_dotenv_loader();
|
|
159485
|
+
}
|
|
159486
|
+
});
|
|
159487
|
+
|
|
158617
159488
|
// src/dashboard/project-classification.ts
|
|
158618
159489
|
var project_classification_exports = {};
|
|
158619
159490
|
__export(project_classification_exports, {
|
|
@@ -159393,6 +160264,20 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
159393
160264
|
sendJson(res, observations2);
|
|
159394
160265
|
break;
|
|
159395
160266
|
}
|
|
160267
|
+
case "/evidence": {
|
|
160268
|
+
const observations2 = filterDashboardObservations(
|
|
160269
|
+
await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
|
|
160270
|
+
effectiveProjectId
|
|
160271
|
+
);
|
|
160272
|
+
const evidenceStore = new EvidenceCardStore();
|
|
160273
|
+
await evidenceStore.init(effectiveDataDir);
|
|
160274
|
+
evidenceStore.syncObservations(observations2);
|
|
160275
|
+
const query = url.searchParams.get("q") || "";
|
|
160276
|
+
const limit2 = Number(url.searchParams.get("limit") || 20);
|
|
160277
|
+
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()));
|
|
160278
|
+
sendJson(res, { cards, projectId: effectiveProjectId });
|
|
160279
|
+
break;
|
|
160280
|
+
}
|
|
159396
160281
|
case "/sessions": {
|
|
159397
160282
|
const allSessions = await getSessionStore().loadAll();
|
|
159398
160283
|
const sessions = filterByProject(allSessions, effectiveProjectId);
|
|
@@ -159440,8 +160325,13 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
159440
160325
|
filesModified: o.filesModified
|
|
159441
160326
|
}));
|
|
159442
160327
|
const retentionReferenceTime = new Date(now3);
|
|
160328
|
+
const feedback = new MemoryFeedbackStore();
|
|
160329
|
+
await feedback.init(effectiveDataDir).catch(() => void 0);
|
|
159443
160330
|
const retention = summarizeRetentionProjections(
|
|
159444
|
-
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
160331
|
+
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
160332
|
+
referenceTime: retentionReferenceTime,
|
|
160333
|
+
feedback: feedback.getState(effectiveProjectId, "observation", String(observation.id))
|
|
160334
|
+
}))
|
|
159445
160335
|
);
|
|
159446
160336
|
const retentionSummary = {
|
|
159447
160337
|
active: retention.active,
|
|
@@ -159535,9 +160425,14 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
159535
160425
|
effectiveProjectId
|
|
159536
160426
|
);
|
|
159537
160427
|
const referenceTime = /* @__PURE__ */ new Date();
|
|
160428
|
+
const feedback = new MemoryFeedbackStore();
|
|
160429
|
+
await feedback.init(effectiveDataDir).catch(() => void 0);
|
|
159538
160430
|
const rows = observations2.filter((observation) => observation.type !== "probe").map((observation) => ({
|
|
159539
160431
|
observation,
|
|
159540
|
-
retention: projectObservationRetention(observation, {
|
|
160432
|
+
retention: projectObservationRetention(observation, {
|
|
160433
|
+
referenceTime,
|
|
160434
|
+
feedback: feedback.getState(effectiveProjectId, "observation", String(observation.id))
|
|
160435
|
+
})
|
|
159541
160436
|
})).sort((a, b) => b.retention.displayScore - a.retention.displayScore);
|
|
159542
160437
|
const summary = summarizeRetentionProjections(rows.map((row) => row.retention));
|
|
159543
160438
|
const scored = rows.map(({ observation, retention }) => ({
|
|
@@ -159608,23 +160503,13 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
159608
160503
|
const os6 = await import("os");
|
|
159609
160504
|
const { existsSync: existsSync21 } = await import("fs");
|
|
159610
160505
|
const { join: join25 } = await import("path");
|
|
159611
|
-
let yml = {};
|
|
159612
160506
|
const configProjectRoot = effectiveProjectRoot;
|
|
159613
|
-
|
|
159614
|
-
const { loadYamlConfig: loadYamlConfig2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
|
|
159615
|
-
yml = configProjectRoot ? loadYamlConfig2(configProjectRoot) : loadYamlConfig2(null);
|
|
159616
|
-
} catch {
|
|
159617
|
-
}
|
|
159618
|
-
if (configProjectRoot) {
|
|
159619
|
-
try {
|
|
159620
|
-
const { loadDotenv: loadDotenv2 } = await Promise.resolve().then(() => (init_dotenv_loader(), dotenv_loader_exports));
|
|
159621
|
-
loadDotenv2(configProjectRoot);
|
|
159622
|
-
} catch {
|
|
159623
|
-
}
|
|
159624
|
-
}
|
|
160507
|
+
const resolved = getResolvedConfig({ projectRoot: configProjectRoot });
|
|
159625
160508
|
const files = {
|
|
159626
160509
|
"project memorix.yml": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
159627
160510
|
"user memorix.yml": { exists: false, path: "" },
|
|
160511
|
+
"project memorix.toml": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
160512
|
+
"user config.toml": { exists: false, path: "" },
|
|
159628
160513
|
"project .env": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
159629
160514
|
"user .env": { exists: false, path: "" },
|
|
159630
160515
|
"legacy config.json": { exists: false, path: "" }
|
|
@@ -159634,6 +160519,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
159634
160519
|
const paths = {
|
|
159635
160520
|
"project memorix.yml": configProjectRoot ? join25(configProjectRoot, "memorix.yml") : null,
|
|
159636
160521
|
"user memorix.yml": join25(home, ".memorix", "memorix.yml"),
|
|
160522
|
+
"project memorix.toml": configProjectRoot ? join25(configProjectRoot, "memorix.toml") : null,
|
|
160523
|
+
"user config.toml": join25(home, ".memorix", "config.toml"),
|
|
159637
160524
|
"project .env": configProjectRoot ? join25(configProjectRoot, ".env") : null,
|
|
159638
160525
|
"user .env": join25(home, ".memorix", ".env"),
|
|
159639
160526
|
"legacy config.json": join25(home, ".memorix", "config.json")
|
|
@@ -159648,67 +160535,61 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
159648
160535
|
} catch {
|
|
159649
160536
|
}
|
|
159650
160537
|
const values = [];
|
|
159651
|
-
const
|
|
159652
|
-
|
|
159653
|
-
|
|
159654
|
-
|
|
159655
|
-
|
|
159656
|
-
|
|
159657
|
-
|
|
159658
|
-
|
|
159659
|
-
|
|
159660
|
-
|
|
159661
|
-
|
|
159662
|
-
|
|
159663
|
-
|
|
159664
|
-
|
|
159665
|
-
|
|
159666
|
-
|
|
159667
|
-
|
|
160538
|
+
const tomlSource = configProjectRoot && files["project memorix.toml"].exists ? "memorix.toml" : files["user config.toml"].exists ? "config.toml" : "default";
|
|
160539
|
+
const legacySource = files["project memorix.yml"].exists || files["user memorix.yml"].exists ? "memorix.yml" : files["legacy config.json"].exists ? "config.json" : "default";
|
|
160540
|
+
const configSource = resolved.sources.toml.length > 0 ? tomlSource : resolved.sources.legacy.length > 0 ? legacySource : "default";
|
|
160541
|
+
const source = (envKey) => resolveDashboardKeySource({
|
|
160542
|
+
value: process.env[envKey] ?? "",
|
|
160543
|
+
envKeys: [envKey],
|
|
160544
|
+
configSource
|
|
160545
|
+
});
|
|
160546
|
+
if (resolved.memory.llm.provider) values.push({ key: "llm.provider", value: resolved.memory.llm.provider, source: source("MEMORIX_LLM_PROVIDER") });
|
|
160547
|
+
if (resolved.memory.llm.model) values.push({ key: "llm.model", value: resolved.memory.llm.model, source: source("MEMORIX_LLM_MODEL") });
|
|
160548
|
+
const llmKey = resolved.memory.llm.apiKey;
|
|
160549
|
+
const memoryKeyEnv = [
|
|
160550
|
+
"MEMORIX_LLM_API_KEY",
|
|
160551
|
+
"MEMORIX_API_KEY",
|
|
160552
|
+
"OPENAI_API_KEY",
|
|
160553
|
+
"ANTHROPIC_API_KEY",
|
|
160554
|
+
...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : []
|
|
160555
|
+
];
|
|
159668
160556
|
if (llmKey) {
|
|
159669
|
-
|
|
159670
|
-
if (process.env.MEMORIX_LLM_API_KEY) src = await getEnvSource("MEMORIX_LLM_API_KEY");
|
|
159671
|
-
else if (process.env.MEMORIX_API_KEY) src = await getEnvSource("MEMORIX_API_KEY");
|
|
159672
|
-
else if (yml.llm?.apiKey) src = "memorix.yml (move to .env!)";
|
|
159673
|
-
else if (process.env.OPENAI_API_KEY) src = await getEnvSource("OPENAI_API_KEY");
|
|
160557
|
+
const src = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
|
|
159674
160558
|
values.push({ key: "llm.apiKey", value: "****" + llmKey.slice(-4), source: src, sensitive: true });
|
|
159675
160559
|
} else {
|
|
159676
160560
|
values.push({ key: "llm.apiKey", value: "not set", source: "none" });
|
|
159677
160561
|
}
|
|
159678
|
-
|
|
159679
|
-
|
|
159680
|
-
|
|
159681
|
-
|
|
159682
|
-
|
|
159683
|
-
|
|
159684
|
-
|
|
159685
|
-
}
|
|
159686
|
-
const agentModel = process.env.MEMORIX_AGENT_MODEL || process.env.MEMORIX_AGENT_LLM_MODEL || yml.agent?.model;
|
|
159687
|
-
if (agentModel) {
|
|
159688
|
-
let source;
|
|
159689
|
-
if (process.env.MEMORIX_AGENT_MODEL) source = await getEnvSource("MEMORIX_AGENT_MODEL");
|
|
159690
|
-
else if (process.env.MEMORIX_AGENT_LLM_MODEL) source = `${await getEnvSource("MEMORIX_AGENT_LLM_MODEL")} (legacy)`;
|
|
159691
|
-
else source = yml.agent?.model ? "memorix.yml" : "default";
|
|
159692
|
-
values.push({ key: "agent.model", value: agentModel, source });
|
|
159693
|
-
}
|
|
159694
|
-
const agentKey = process.env.MEMORIX_AGENT_API_KEY || process.env.MEMORIX_AGENT_LLM_API_KEY || yml.agent?.apiKey;
|
|
160562
|
+
if (resolved.agent.provider) {
|
|
160563
|
+
values.push({ key: "agent.provider", value: resolved.agent.provider, source: source("MEMORIX_AGENT_PROVIDER") });
|
|
160564
|
+
}
|
|
160565
|
+
if (resolved.agent.model) {
|
|
160566
|
+
values.push({ key: "agent.model", value: resolved.agent.model, source: source("MEMORIX_AGENT_MODEL") });
|
|
160567
|
+
}
|
|
160568
|
+
const agentKey = resolved.agent.apiKey;
|
|
159695
160569
|
if (agentKey) {
|
|
159696
|
-
|
|
159697
|
-
|
|
159698
|
-
|
|
159699
|
-
|
|
160570
|
+
const src = resolveDashboardKeySource({
|
|
160571
|
+
value: agentKey,
|
|
160572
|
+
envKeys: ["MEMORIX_AGENT_API_KEY", "MEMORIX_AGENT_LLM_API_KEY"],
|
|
160573
|
+
configSource
|
|
160574
|
+
});
|
|
159700
160575
|
values.push({ key: "agent.apiKey", value: "****" + agentKey.slice(-4), source: src, sensitive: true });
|
|
159701
160576
|
} else {
|
|
159702
|
-
values.push({
|
|
159703
|
-
|
|
159704
|
-
|
|
159705
|
-
|
|
159706
|
-
|
|
159707
|
-
|
|
159708
|
-
|
|
159709
|
-
if (
|
|
159710
|
-
|
|
159711
|
-
|
|
160577
|
+
values.push({
|
|
160578
|
+
key: "agent.apiKey",
|
|
160579
|
+
value: "fallback to llm.apiKey",
|
|
160580
|
+
source: llmKey ? resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource }) : "default"
|
|
160581
|
+
});
|
|
160582
|
+
}
|
|
160583
|
+
values.push({ key: "embedding.provider", value: resolved.embedding.provider || "off", source: source("MEMORIX_EMBEDDING") });
|
|
160584
|
+
if (resolved.embedding.model) values.push({ key: "embedding.model", value: resolved.embedding.model, source: source("MEMORIX_EMBEDDING_MODEL") });
|
|
160585
|
+
if (resolved.rerank.provider !== "off") {
|
|
160586
|
+
values.push({ key: "rerank.provider", value: resolved.rerank.provider, source: source("MEMORIX_RERANK_PROVIDER") });
|
|
160587
|
+
if (resolved.rerank.model) values.push({ key: "rerank.model", value: resolved.rerank.model, source: source("MEMORIX_RERANK_MODEL") });
|
|
160588
|
+
}
|
|
160589
|
+
values.push({ key: "git.autoHook", value: String(resolved.git.autoHook ?? false), source: configSource });
|
|
160590
|
+
values.push({ key: "git.skipMergeCommits", value: String(resolved.git.skipMergeCommits ?? true), source: configSource });
|
|
160591
|
+
values.push({ key: "server.transport", value: resolved.server.transport || "stdio", source: configSource });
|
|
160592
|
+
values.push({ key: "server.dashboard", value: String(resolved.server.dashboard ?? true), source: configSource });
|
|
159712
160593
|
sendJson(res, { files, values });
|
|
159713
160594
|
break;
|
|
159714
160595
|
}
|
|
@@ -160156,10 +161037,14 @@ var init_server = __esm({
|
|
|
160156
161037
|
init_dotenv_loader();
|
|
160157
161038
|
init_yaml_loader();
|
|
160158
161039
|
init_yaml_loader();
|
|
161040
|
+
init_resolved_config();
|
|
160159
161041
|
init_graph_scope();
|
|
160160
161042
|
init_retention();
|
|
160161
161043
|
init_visibility();
|
|
161044
|
+
init_evidence_store();
|
|
161045
|
+
init_feedback();
|
|
160162
161046
|
init_maintenance();
|
|
161047
|
+
init_config_provenance();
|
|
160163
161048
|
MIME_TYPES = {
|
|
160164
161049
|
".html": "text/html; charset=utf-8",
|
|
160165
161050
|
".css": "text/css; charset=utf-8",
|
|
@@ -160627,7 +161512,7 @@ __export(planner_exports, {
|
|
|
160627
161512
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
160628
161513
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
160629
161514
|
});
|
|
160630
|
-
import { randomUUID as
|
|
161515
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
160631
161516
|
function isPlannerTask(metadata) {
|
|
160632
161517
|
if (!metadata) return null;
|
|
160633
161518
|
try {
|
|
@@ -160685,7 +161570,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
|
|
|
160685
161570
|
const maxIterations = config.maxIterations ?? 3;
|
|
160686
161571
|
const taskBudget = config.taskBudget ?? 15;
|
|
160687
161572
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
160688
|
-
const pipelineId =
|
|
161573
|
+
const pipelineId = randomUUID18();
|
|
160689
161574
|
const meta = {
|
|
160690
161575
|
plannerType: "plan",
|
|
160691
161576
|
pipelineId,
|
|
@@ -161220,8 +162105,7 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
|
|
|
161220
162105
|
if (!apiKey) {
|
|
161221
162106
|
throw new Error("No LLM API key configured for image analysis.");
|
|
161222
162107
|
}
|
|
161223
|
-
|
|
161224
|
-
if (!baseUrl.endsWith("/v1")) baseUrl += "/v1";
|
|
162108
|
+
const baseUrl = normalizeOpenAICompatibleBaseUrl(getLLMBaseUrl("https://api.openai.com/v1"));
|
|
161225
162109
|
const model = getLLMModel("gpt-4o");
|
|
161226
162110
|
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
161227
162111
|
method: "POST",
|
|
@@ -161358,8 +162242,8 @@ var init_official_skills = __esm({
|
|
|
161358
162242
|
"",
|
|
161359
162243
|
"| Situation | Prefer | CLI fallback |",
|
|
161360
162244
|
"|---|---|---|",
|
|
161361
|
-
'| 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` |',
|
|
161362
|
-
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
|
|
162245
|
+
'| 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` |',
|
|
162246
|
+
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --fallback --brief-json` |',
|
|
161363
162247
|
'| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
|
|
161364
162248
|
'| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
|
|
161365
162249
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
@@ -161372,7 +162256,7 @@ var init_official_skills = __esm({
|
|
|
161372
162256
|
"",
|
|
161373
162257
|
"- 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.",
|
|
161374
162258
|
"- 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.",
|
|
161375
|
-
'- 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.',
|
|
162259
|
+
'- 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.',
|
|
161376
162260
|
"- 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.",
|
|
161377
162261
|
"- 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.",
|
|
161378
162262
|
"- 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.",
|
|
@@ -162631,7 +163515,7 @@ alwaysApply: true
|
|
|
162631
163515
|
"",
|
|
162632
163516
|
`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.`,
|
|
162633
163517
|
"",
|
|
162634
|
-
'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.',
|
|
163518
|
+
'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.',
|
|
162635
163519
|
"",
|
|
162636
163520
|
"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.",
|
|
162637
163521
|
"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.",
|
|
@@ -162934,7 +163818,7 @@ init_freshness();
|
|
|
162934
163818
|
init_obs_store();
|
|
162935
163819
|
init_mini_skill_store();
|
|
162936
163820
|
init_session_store();
|
|
162937
|
-
import { createHash as
|
|
163821
|
+
import { createHash as createHash16 } from "crypto";
|
|
162938
163822
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
162939
163823
|
import { z as z626 } from "zod";
|
|
162940
163824
|
|
|
@@ -163414,6 +164298,8 @@ init_mini_skill_store();
|
|
|
163414
164298
|
init_mini_skills();
|
|
163415
164299
|
init_secret_filter();
|
|
163416
164300
|
init_visibility();
|
|
164301
|
+
init_persistence();
|
|
164302
|
+
init_feedback();
|
|
163417
164303
|
function normalizeMemoryBrowseQuery(query) {
|
|
163418
164304
|
const trimmed = query.trim();
|
|
163419
164305
|
if (!trimmed) return "";
|
|
@@ -163451,9 +164337,27 @@ function normalizeMemoryBrowseQuery(query) {
|
|
|
163451
164337
|
async function compactSearch(options, surface = "mcp") {
|
|
163452
164338
|
await ensureFreshIndex();
|
|
163453
164339
|
const searchOptions = { ...options, query: normalizeMemoryBrowseQuery(options.query) };
|
|
163454
|
-
|
|
164340
|
+
let entries = (await searchObservations(searchOptions)).map(
|
|
163455
164341
|
(entry) => entry.projectId || !options.projectId ? entry : { ...entry, projectId: options.projectId }
|
|
163456
164342
|
);
|
|
164343
|
+
if (options.projectId) {
|
|
164344
|
+
try {
|
|
164345
|
+
const feedback = new MemoryFeedbackStore();
|
|
164346
|
+
await feedback.init(await getProjectDataDir(options.projectId));
|
|
164347
|
+
const states = feedback.weights(options.projectId, "observation");
|
|
164348
|
+
entries = entries.map((entry) => {
|
|
164349
|
+
const state = states.get(String(entry.id));
|
|
164350
|
+
if (!state) return entry;
|
|
164351
|
+
return {
|
|
164352
|
+
...entry,
|
|
164353
|
+
score: (entry.score ?? 0) * feedbackWeightMultiplier(state.weight),
|
|
164354
|
+
feedbackWeight: state.weight,
|
|
164355
|
+
feedbackStatus: state.status
|
|
164356
|
+
};
|
|
164357
|
+
}).filter((entry) => entry.feedbackStatus !== "archived" || options.status === "all").sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
164358
|
+
} catch {
|
|
164359
|
+
}
|
|
164360
|
+
}
|
|
163457
164361
|
let formatted = formatIndexTable(entries, searchOptions.query, !options.projectId, surface);
|
|
163458
164362
|
if (entries.length === 0 && options.projectId) {
|
|
163459
164363
|
const allObservations = filterReadableObservations(getAllObservations(), options.reader);
|
|
@@ -164282,6 +165186,8 @@ init_detector();
|
|
|
164282
165186
|
init_launch_root();
|
|
164283
165187
|
init_aliases();
|
|
164284
165188
|
init_persistence();
|
|
165189
|
+
init_evidence_store();
|
|
165190
|
+
init_feedback();
|
|
164285
165191
|
|
|
164286
165192
|
// src/rules/syncer.ts
|
|
164287
165193
|
init_esm_shims();
|
|
@@ -164294,9 +165200,9 @@ init_frontmatter();
|
|
|
164294
165200
|
|
|
164295
165201
|
// src/rules/utils.ts
|
|
164296
165202
|
init_esm_shims();
|
|
164297
|
-
import { createHash as
|
|
165203
|
+
import { createHash as createHash14 } from "crypto";
|
|
164298
165204
|
function hashContent2(content) {
|
|
164299
|
-
return
|
|
165205
|
+
return createHash14("sha256").update(content.trim()).digest("hex").substring(0, 16);
|
|
164300
165206
|
}
|
|
164301
165207
|
function generateRuleId(source, filePath) {
|
|
164302
165208
|
const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
|
|
@@ -166498,6 +167404,10 @@ var TOOL_PROFILES = Object.freeze({
|
|
|
166498
167404
|
// multimodal support to one additional schema rather than enabling lite.
|
|
166499
167405
|
memorix_session_start: ["micro", "lite", "team", "full"],
|
|
166500
167406
|
memorix_media: ["micro", "lite", "team", "full"],
|
|
167407
|
+
// Evidence and feedback are deliberate operator/context-control surfaces;
|
|
167408
|
+
// keep the default micro profile at its nine-tool token budget.
|
|
167409
|
+
memorix_evidence: ["lite", "team", "full"],
|
|
167410
|
+
memorix_feedback: ["lite", "team", "full"],
|
|
166501
167411
|
// ── lite: extended solo memory surface ────────────────────────────
|
|
166502
167412
|
memorix_graph_context: ["lite", "team", "full"],
|
|
166503
167413
|
memorix_timeline: ["lite", "team", "full"],
|
|
@@ -166796,7 +167706,7 @@ function coerceObjectArray(val) {
|
|
|
166796
167706
|
return [];
|
|
166797
167707
|
}
|
|
166798
167708
|
function createDeterministicInstanceId(projectId, agentType, agentName) {
|
|
166799
|
-
const digest2 =
|
|
167709
|
+
const digest2 = createHash16("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
|
|
166800
167710
|
return `auto-${digest2}`;
|
|
166801
167711
|
}
|
|
166802
167712
|
var BOOTSTRAP_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -167097,7 +168007,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
167097
168007
|
};
|
|
167098
168008
|
const server = existingServer ?? new McpServer({
|
|
167099
168009
|
name: "memorix",
|
|
167100
|
-
version: true ? "1.
|
|
168010
|
+
version: true ? "1.8.0" : "1.0.1"
|
|
167101
168011
|
});
|
|
167102
168012
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
167103
168013
|
server.registerTool = ((name, ...args) => {
|
|
@@ -170276,7 +171186,7 @@ ${json2}
|
|
|
170276
171186
|
dashboardRunning = true;
|
|
170277
171187
|
const { exec: execCmd } = await import("child_process");
|
|
170278
171188
|
const openCmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
170279
|
-
execCmd(openCmd, () => {
|
|
171189
|
+
execCmd(openCmd, { windowsHide: true }, () => {
|
|
170280
171190
|
});
|
|
170281
171191
|
return {
|
|
170282
171192
|
content: [{
|
|
@@ -170300,6 +171210,113 @@ ${json2}
|
|
|
170300
171210
|
}
|
|
170301
171211
|
}
|
|
170302
171212
|
);
|
|
171213
|
+
server.registerTool(
|
|
171214
|
+
"memorix_evidence",
|
|
171215
|
+
{
|
|
171216
|
+
title: "Evidence Cards",
|
|
171217
|
+
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.",
|
|
171218
|
+
inputSchema: {
|
|
171219
|
+
action: z626.enum(["list", "get", "sync", "stale", "events"]).describe("Evidence operation"),
|
|
171220
|
+
candidateKind: z626.enum(["observation", "code", "git", "test", "document", "workflow", "graph"]).optional().default("observation"),
|
|
171221
|
+
candidateId: z626.string().optional().describe("Candidate id, usually an observation id"),
|
|
171222
|
+
query: z626.string().optional().describe("Optional title/source query for list"),
|
|
171223
|
+
paths: z626.array(z626.string()).max(200).optional().describe("Changed source paths for stale"),
|
|
171224
|
+
reason: z626.string().max(500).optional().describe("Why evidence became stale"),
|
|
171225
|
+
limit: z626.number().int().positive().max(100).optional().default(20)
|
|
171226
|
+
}
|
|
171227
|
+
},
|
|
171228
|
+
async ({ action, candidateKind, candidateId, query, paths, reason, limit: limit2 }) => {
|
|
171229
|
+
const unresolved = requireResolvedProject("inspect evidence cards for the current project");
|
|
171230
|
+
if (unresolved) return unresolved;
|
|
171231
|
+
const cards = new EvidenceCardStore();
|
|
171232
|
+
await cards.init(projectDir2);
|
|
171233
|
+
if (action === "sync") {
|
|
171234
|
+
const observations2 = await getObservationStore().loadByProject(project.id);
|
|
171235
|
+
const synced = cards.syncObservations(observations2);
|
|
171236
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, synced: synced.length, cards: synced.slice(0, limit2 ?? 20) }, null, 2) }] };
|
|
171237
|
+
}
|
|
171238
|
+
if (action === "stale") {
|
|
171239
|
+
const changed = cards.markStaleForPaths(project.id, paths ?? [], reason ?? "source file changed");
|
|
171240
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, staleMarked: changed, paths: paths ?? [] }, null, 2) }] };
|
|
171241
|
+
}
|
|
171242
|
+
if (action === "get") {
|
|
171243
|
+
if (!candidateId?.trim()) return { content: [{ type: "text", text: "candidateId is required for evidence get." }], isError: true };
|
|
171244
|
+
const card = cards.get(project.id, candidateKind ?? "observation", candidateId.trim());
|
|
171245
|
+
if (!card) return { content: [{ type: "text", text: "Evidence card not found." }], isError: true };
|
|
171246
|
+
return { content: [{ type: "text", text: JSON.stringify({ card, events: cards.listEvents(card.id), projectId: project.id }, null, 2) }] };
|
|
171247
|
+
}
|
|
171248
|
+
if (action === "events") {
|
|
171249
|
+
if (!candidateId?.trim()) return { content: [{ type: "text", text: "candidateId is required for evidence events." }], isError: true };
|
|
171250
|
+
const card = cards.get(project.id, candidateKind ?? "observation", candidateId.trim());
|
|
171251
|
+
if (!card) return { content: [{ type: "text", text: "Evidence card not found." }], isError: true };
|
|
171252
|
+
return { content: [{ type: "text", text: JSON.stringify(cards.listEvents(card.id, limit2), null, 2) }] };
|
|
171253
|
+
}
|
|
171254
|
+
const needle = query?.trim().toLowerCase();
|
|
171255
|
+
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);
|
|
171256
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, cards: listed }, null, 2) }] };
|
|
171257
|
+
}
|
|
171258
|
+
);
|
|
171259
|
+
server.registerTool(
|
|
171260
|
+
"memorix_feedback",
|
|
171261
|
+
{
|
|
171262
|
+
title: "Memory Feedback",
|
|
171263
|
+
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.",
|
|
171264
|
+
inputSchema: {
|
|
171265
|
+
action: z626.enum(["record", "show", "audit"]).describe("Feedback operation"),
|
|
171266
|
+
candidateKind: z626.enum(["observation", "claim", "durable-memory", "workflow"]).optional().default("observation"),
|
|
171267
|
+
candidateId: z626.string().describe("Memory or knowledge candidate id"),
|
|
171268
|
+
signal: z626.enum(["user-correction", "verification-success", "verification-failure", "code-change", "used", "not-used", "code-conflict", "strengthen", "weaken", "revoke"]).optional(),
|
|
171269
|
+
sourceRef: z626.string().max(500).optional().describe("Source of this feedback, such as test:run-42 or user:chat"),
|
|
171270
|
+
actor: z626.string().max(200).optional(),
|
|
171271
|
+
note: z626.string().max(2e3).optional(),
|
|
171272
|
+
targetEventId: z626.string().optional().describe("Existing event id when action=record and signal=revoke"),
|
|
171273
|
+
limit: z626.number().int().positive().max(200).optional().default(100)
|
|
171274
|
+
}
|
|
171275
|
+
},
|
|
171276
|
+
async ({ action, candidateKind, candidateId, signal, sourceRef, actor, note, targetEventId, limit: limit2 }) => {
|
|
171277
|
+
const unresolved = requireResolvedProject("record memory feedback for the current project");
|
|
171278
|
+
if (unresolved) return unresolved;
|
|
171279
|
+
const feedback = new MemoryFeedbackStore();
|
|
171280
|
+
await feedback.init(projectDir2);
|
|
171281
|
+
const kind = candidateKind ?? "observation";
|
|
171282
|
+
if (action === "show") {
|
|
171283
|
+
return { content: [{ type: "text", text: JSON.stringify(feedback.getState(project.id, kind, candidateId), null, 2) }] };
|
|
171284
|
+
}
|
|
171285
|
+
if (action === "audit") {
|
|
171286
|
+
return { content: [{ type: "text", text: JSON.stringify(feedback.audit(project.id, kind, candidateId, limit2), null, 2) }] };
|
|
171287
|
+
}
|
|
171288
|
+
if (!signal || !sourceRef?.trim()) {
|
|
171289
|
+
return { content: [{ type: "text", text: "record requires signal and sourceRef." }], isError: true };
|
|
171290
|
+
}
|
|
171291
|
+
try {
|
|
171292
|
+
const result = feedback.record({
|
|
171293
|
+
projectId: project.id,
|
|
171294
|
+
candidateKind: kind,
|
|
171295
|
+
candidateId,
|
|
171296
|
+
signal,
|
|
171297
|
+
sourceRef,
|
|
171298
|
+
...actor || currentAgentId ? { actor: actor ?? currentAgentId } : {},
|
|
171299
|
+
...note ? { note } : {},
|
|
171300
|
+
...targetEventId ? { targetEventId } : {}
|
|
171301
|
+
});
|
|
171302
|
+
if (kind === "observation") {
|
|
171303
|
+
const cards = new EvidenceCardStore();
|
|
171304
|
+
await cards.init(projectDir2);
|
|
171305
|
+
const card = cards.get(project.id, "observation", candidateId);
|
|
171306
|
+
if (card) {
|
|
171307
|
+
const verification = signal === "verification-success" || signal === "strengthen" ? "verified" : signal === "user-correction" || signal === "code-conflict" || signal === "weaken" ? "conflicted" : card.verification;
|
|
171308
|
+
cards.recordEvent(project.id, card.id, `feedback:${signal}`, note);
|
|
171309
|
+
if (verification !== card.verification) {
|
|
171310
|
+
cards.setVerification(project.id, card.id, verification);
|
|
171311
|
+
}
|
|
171312
|
+
}
|
|
171313
|
+
}
|
|
171314
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
171315
|
+
} catch (error) {
|
|
171316
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true };
|
|
171317
|
+
}
|
|
171318
|
+
}
|
|
171319
|
+
);
|
|
170303
171320
|
if (teamFeaturesEnabled) {
|
|
170304
171321
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
170305
171322
|
initTeamStoreForProject = initTeamStore2;
|