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
|
@@ -95,6 +95,8 @@ function loadEnvFile(filePath) {
|
|
|
95
95
|
const parsed = parse(readFileSync(filePath, "utf-8"));
|
|
96
96
|
for (const [key, value] of Object.entries(parsed)) {
|
|
97
97
|
if (!(key in process.env)) {
|
|
98
|
+
loadedEnvKeys.add(key);
|
|
99
|
+
loadedEnvValues.set(key, value);
|
|
98
100
|
process.env[key] = value;
|
|
99
101
|
injectedKeys.add(key);
|
|
100
102
|
}
|
|
@@ -107,6 +109,8 @@ function loadDotenv(projectRoot, options = {}) {
|
|
|
107
109
|
resetDotenv();
|
|
108
110
|
}
|
|
109
111
|
loadedEnvFiles.length = 0;
|
|
112
|
+
loadedEnvKeys.clear();
|
|
113
|
+
loadedEnvValues.clear();
|
|
110
114
|
if (projectRoot) {
|
|
111
115
|
loadEnvFile(getProjectDotenvPath(projectRoot));
|
|
112
116
|
}
|
|
@@ -122,11 +126,12 @@ function resetDotenv() {
|
|
|
122
126
|
dotenvLoaded = false;
|
|
123
127
|
dotenvProjectRoot = null;
|
|
124
128
|
loadedEnvFiles.length = 0;
|
|
129
|
+
loadedEnvKeys.clear();
|
|
125
130
|
}
|
|
126
131
|
function getLoadedEnvFiles() {
|
|
127
132
|
return loadedEnvFiles;
|
|
128
133
|
}
|
|
129
|
-
var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, injectedKeys;
|
|
134
|
+
var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
|
|
130
135
|
var init_dotenv_loader = __esm({
|
|
131
136
|
"src/config/dotenv-loader.ts"() {
|
|
132
137
|
"use strict";
|
|
@@ -135,6 +140,8 @@ var init_dotenv_loader = __esm({
|
|
|
135
140
|
dotenvLoaded = false;
|
|
136
141
|
dotenvProjectRoot = null;
|
|
137
142
|
loadedEnvFiles = [];
|
|
143
|
+
loadedEnvKeys = /* @__PURE__ */ new Set();
|
|
144
|
+
loadedEnvValues = /* @__PURE__ */ new Map();
|
|
138
145
|
injectedKeys = /* @__PURE__ */ new Set();
|
|
139
146
|
}
|
|
140
147
|
});
|
|
@@ -176,6 +183,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
176
183
|
llm: { ...userConfig.llm, ...projectConfig.llm },
|
|
177
184
|
agent: { ...userConfig.agent, ...projectConfig.agent },
|
|
178
185
|
embedding: { ...userConfig.embedding, ...projectConfig.embedding },
|
|
186
|
+
rerank: { ...userConfig.rerank, ...projectConfig.rerank },
|
|
179
187
|
git: { ...userConfig.git, ...projectConfig.git },
|
|
180
188
|
codegraph: { ...userConfig.codegraph, ...projectConfig.codegraph },
|
|
181
189
|
behavior: { ...userConfig.behavior, ...projectConfig.behavior },
|
|
@@ -517,7 +525,7 @@ function closeAllDatabases() {
|
|
|
517
525
|
_dbCache.delete(key);
|
|
518
526
|
}
|
|
519
527
|
}
|
|
520
|
-
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;
|
|
528
|
+
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;
|
|
521
529
|
var init_sqlite_db = __esm({
|
|
522
530
|
"src/store/sqlite-db.ts"() {
|
|
523
531
|
"use strict";
|
|
@@ -1163,6 +1171,79 @@ CREATE TABLE IF NOT EXISTS compaction_checkpoints (
|
|
|
1163
1171
|
created_at TEXT NOT NULL,
|
|
1164
1172
|
updated_at TEXT NOT NULL
|
|
1165
1173
|
);
|
|
1174
|
+
`;
|
|
1175
|
+
CREATE_EVIDENCE_CARDS_TABLE = `
|
|
1176
|
+
CREATE TABLE IF NOT EXISTS evidence_cards (
|
|
1177
|
+
id TEXT PRIMARY KEY,
|
|
1178
|
+
project_id TEXT NOT NULL,
|
|
1179
|
+
candidate_kind TEXT NOT NULL,
|
|
1180
|
+
candidate_id TEXT NOT NULL,
|
|
1181
|
+
title TEXT NOT NULL,
|
|
1182
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
1183
|
+
entity_name TEXT,
|
|
1184
|
+
source_kind TEXT NOT NULL,
|
|
1185
|
+
source_ref TEXT NOT NULL,
|
|
1186
|
+
locator TEXT,
|
|
1187
|
+
captured_hash TEXT,
|
|
1188
|
+
session_id TEXT,
|
|
1189
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
1190
|
+
verification TEXT NOT NULL DEFAULT 'unverified',
|
|
1191
|
+
freshness TEXT NOT NULL DEFAULT 'current',
|
|
1192
|
+
stale_reason TEXT,
|
|
1193
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
1194
|
+
related_entities_json TEXT NOT NULL DEFAULT '[]',
|
|
1195
|
+
created_at TEXT NOT NULL,
|
|
1196
|
+
updated_at TEXT NOT NULL,
|
|
1197
|
+
UNIQUE(project_id, candidate_kind, candidate_id)
|
|
1198
|
+
);
|
|
1199
|
+
`;
|
|
1200
|
+
CREATE_EVIDENCE_CARD_EVENTS_TABLE = `
|
|
1201
|
+
CREATE TABLE IF NOT EXISTS evidence_card_events (
|
|
1202
|
+
id TEXT PRIMARY KEY,
|
|
1203
|
+
project_id TEXT NOT NULL,
|
|
1204
|
+
card_id TEXT NOT NULL,
|
|
1205
|
+
kind TEXT NOT NULL,
|
|
1206
|
+
detail TEXT,
|
|
1207
|
+
created_at TEXT NOT NULL,
|
|
1208
|
+
FOREIGN KEY (card_id) REFERENCES evidence_cards(id) ON DELETE CASCADE
|
|
1209
|
+
);
|
|
1210
|
+
`;
|
|
1211
|
+
CREATE_MEMORY_FEEDBACK_STATES_TABLE = `
|
|
1212
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_states (
|
|
1213
|
+
project_id TEXT NOT NULL,
|
|
1214
|
+
candidate_kind TEXT NOT NULL,
|
|
1215
|
+
candidate_id TEXT NOT NULL,
|
|
1216
|
+
weight REAL NOT NULL DEFAULT 1.0,
|
|
1217
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'active',
|
|
1218
|
+
updated_at TEXT NOT NULL,
|
|
1219
|
+
PRIMARY KEY (project_id, candidate_kind, candidate_id)
|
|
1220
|
+
);
|
|
1221
|
+
`;
|
|
1222
|
+
CREATE_MEMORY_FEEDBACK_EVENTS_TABLE = `
|
|
1223
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
1224
|
+
id TEXT PRIMARY KEY,
|
|
1225
|
+
project_id TEXT NOT NULL,
|
|
1226
|
+
candidate_kind TEXT NOT NULL,
|
|
1227
|
+
candidate_id TEXT NOT NULL,
|
|
1228
|
+
signal TEXT NOT NULL,
|
|
1229
|
+
actor TEXT,
|
|
1230
|
+
note TEXT,
|
|
1231
|
+
source_ref TEXT NOT NULL,
|
|
1232
|
+
target_event_id TEXT,
|
|
1233
|
+
delta REAL NOT NULL DEFAULT 0,
|
|
1234
|
+
observed_at TEXT NOT NULL
|
|
1235
|
+
);
|
|
1236
|
+
`;
|
|
1237
|
+
CREATE_MCP_BINDINGS_TABLE = `
|
|
1238
|
+
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
1239
|
+
handle_id TEXT PRIMARY KEY,
|
|
1240
|
+
project_id TEXT NOT NULL,
|
|
1241
|
+
project_root TEXT NOT NULL,
|
|
1242
|
+
data_dir TEXT NOT NULL,
|
|
1243
|
+
created_at TEXT NOT NULL,
|
|
1244
|
+
last_used_at TEXT NOT NULL,
|
|
1245
|
+
expires_at TEXT
|
|
1246
|
+
);
|
|
1166
1247
|
`;
|
|
1167
1248
|
CREATE_INDEXES = `
|
|
1168
1249
|
CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
|
|
@@ -1225,6 +1306,12 @@ CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_target
|
|
|
1225
1306
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
|
|
1226
1307
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
|
|
1227
1308
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
|
|
1309
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC);
|
|
1310
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id);
|
|
1311
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1312
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1313
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1314
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1228
1315
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1229
1316
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1230
1317
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1380,6 +1467,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1380
1467
|
}
|
|
1381
1468
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_media_jobs_source_asset ON media_jobs(project_id, source_asset_id, status)");
|
|
1382
1469
|
}
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
id: "1.8-context-control-plane",
|
|
1473
|
+
apply: (db2) => {
|
|
1474
|
+
db2.exec(CREATE_EVIDENCE_CARDS_TABLE);
|
|
1475
|
+
db2.exec(CREATE_EVIDENCE_CARD_EVENTS_TABLE);
|
|
1476
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_STATES_TABLE);
|
|
1477
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_EVENTS_TABLE);
|
|
1478
|
+
db2.exec(CREATE_MCP_BINDINGS_TABLE);
|
|
1479
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC)");
|
|
1480
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id)");
|
|
1481
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at)");
|
|
1482
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1483
|
+
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)");
|
|
1484
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1485
|
+
}
|
|
1383
1486
|
}
|
|
1384
1487
|
];
|
|
1385
1488
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -1836,6 +1939,7 @@ function mergeTomlConfig(base, override) {
|
|
|
1836
1939
|
llm: { ...base.memory?.llm, ...override.memory?.llm }
|
|
1837
1940
|
},
|
|
1838
1941
|
embedding: { ...base.embedding, ...override.embedding },
|
|
1942
|
+
rerank: { ...base.rerank, ...override.rerank },
|
|
1839
1943
|
hooks: { ...base.hooks, ...override.hooks },
|
|
1840
1944
|
git: { ...base.git, ...override.git },
|
|
1841
1945
|
codegraph: { ...base.codegraph, ...override.codegraph },
|
|
@@ -1932,6 +2036,7 @@ __export(resolved_config_exports, {
|
|
|
1932
2036
|
getResolvedConfigForCwd: () => getResolvedConfigForCwd,
|
|
1933
2037
|
getResolvedEmbeddingLane: () => getResolvedEmbeddingLane,
|
|
1934
2038
|
getResolvedMemoryLane: () => getResolvedMemoryLane,
|
|
2039
|
+
getResolvedRerankLane: () => getResolvedRerankLane,
|
|
1935
2040
|
resetResolvedConfigCache: () => resetResolvedConfigCache
|
|
1936
2041
|
});
|
|
1937
2042
|
import { homedir as homedir5 } from "os";
|
|
@@ -1964,6 +2069,16 @@ function getResolvedConfig(options = {}) {
|
|
|
1964
2069
|
legacy.llm?.baseUrl
|
|
1965
2070
|
);
|
|
1966
2071
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
2072
|
+
const memoryLlmApiKey = first(
|
|
2073
|
+
process.env.MEMORIX_LLM_API_KEY,
|
|
2074
|
+
process.env.MEMORIX_API_KEY,
|
|
2075
|
+
toml.memory?.llm?.api_key,
|
|
2076
|
+
yaml.llm?.apiKey,
|
|
2077
|
+
legacy.llm?.apiKey,
|
|
2078
|
+
process.env.OPENAI_API_KEY,
|
|
2079
|
+
process.env.ANTHROPIC_API_KEY,
|
|
2080
|
+
openRouterMemoryLlmApiKey
|
|
2081
|
+
);
|
|
1967
2082
|
const resolved = {
|
|
1968
2083
|
agent: {
|
|
1969
2084
|
provider: first(
|
|
@@ -2004,16 +2119,7 @@ function getResolvedConfig(options = {}) {
|
|
|
2004
2119
|
provider: memoryLlmProvider,
|
|
2005
2120
|
model: memoryLlmModel,
|
|
2006
2121
|
baseUrl: memoryLlmBaseUrl,
|
|
2007
|
-
apiKey:
|
|
2008
|
-
process.env.MEMORIX_LLM_API_KEY,
|
|
2009
|
-
process.env.MEMORIX_API_KEY,
|
|
2010
|
-
toml.memory?.llm?.api_key,
|
|
2011
|
-
yaml.llm?.apiKey,
|
|
2012
|
-
legacy.llm?.apiKey,
|
|
2013
|
-
process.env.OPENAI_API_KEY,
|
|
2014
|
-
process.env.ANTHROPIC_API_KEY,
|
|
2015
|
-
openRouterMemoryLlmApiKey
|
|
2016
|
-
)
|
|
2122
|
+
apiKey: memoryLlmApiKey
|
|
2017
2123
|
}
|
|
2018
2124
|
},
|
|
2019
2125
|
embedding: {
|
|
@@ -2023,6 +2129,12 @@ function getResolvedConfig(options = {}) {
|
|
|
2023
2129
|
apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
|
|
2024
2130
|
dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
|
|
2025
2131
|
},
|
|
2132
|
+
rerank: resolveRerankLane({
|
|
2133
|
+
toml,
|
|
2134
|
+
yaml,
|
|
2135
|
+
memoryLlmApiKey,
|
|
2136
|
+
memoryLlmBaseUrl
|
|
2137
|
+
}),
|
|
2026
2138
|
git: {
|
|
2027
2139
|
autoHook: firstBool(toml.git?.auto_hook, yaml.git?.autoHook),
|
|
2028
2140
|
ingestOnCommit: firstBool(toml.git?.ingest_on_commit, yaml.git?.ingestOnCommit),
|
|
@@ -2092,6 +2204,9 @@ function getResolvedMemoryLane(options = {}) {
|
|
|
2092
2204
|
function getResolvedEmbeddingLane(options = {}) {
|
|
2093
2205
|
return getResolvedConfig(options).embedding;
|
|
2094
2206
|
}
|
|
2207
|
+
function getResolvedRerankLane(options = {}) {
|
|
2208
|
+
return getResolvedConfig(options).rerank;
|
|
2209
|
+
}
|
|
2095
2210
|
function resetResolvedConfigCache() {
|
|
2096
2211
|
}
|
|
2097
2212
|
function first(...values) {
|
|
@@ -2134,6 +2249,10 @@ function getEnvSourceNames() {
|
|
|
2134
2249
|
"MEMORIX_EMBEDDING_BASE_URL",
|
|
2135
2250
|
"MEMORIX_EMBEDDING_MODEL",
|
|
2136
2251
|
"MEMORIX_EMBEDDING_DIMENSIONS",
|
|
2252
|
+
"MEMORIX_RERANK_PROVIDER",
|
|
2253
|
+
"MEMORIX_RERANK_MODEL",
|
|
2254
|
+
"MEMORIX_RERANK_BASE_URL",
|
|
2255
|
+
"MEMORIX_RERANK_API_KEY",
|
|
2137
2256
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
2138
2257
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
2139
2258
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
@@ -2157,6 +2276,63 @@ function normalizeExternalContext(value) {
|
|
|
2157
2276
|
if (normalized === "auto" || normalized === "off") return normalized;
|
|
2158
2277
|
return void 0;
|
|
2159
2278
|
}
|
|
2279
|
+
function normalizeRerankProvider(value) {
|
|
2280
|
+
const normalized = value?.trim().toLowerCase();
|
|
2281
|
+
if (normalized === "http") return "http";
|
|
2282
|
+
return "off";
|
|
2283
|
+
}
|
|
2284
|
+
function resolveRerankLane(args) {
|
|
2285
|
+
const provider2 = normalizeRerankProvider(first(
|
|
2286
|
+
process.env.MEMORIX_RERANK_PROVIDER,
|
|
2287
|
+
args.toml.rerank?.provider,
|
|
2288
|
+
args.yaml.rerank?.provider,
|
|
2289
|
+
"off"
|
|
2290
|
+
));
|
|
2291
|
+
const model = first(
|
|
2292
|
+
process.env.MEMORIX_RERANK_MODEL,
|
|
2293
|
+
args.toml.rerank?.model,
|
|
2294
|
+
args.yaml.rerank?.model
|
|
2295
|
+
);
|
|
2296
|
+
const explicitBaseUrl = first(
|
|
2297
|
+
process.env.MEMORIX_RERANK_BASE_URL,
|
|
2298
|
+
args.toml.rerank?.base_url,
|
|
2299
|
+
args.yaml.rerank?.baseUrl
|
|
2300
|
+
);
|
|
2301
|
+
const baseUrl = provider2 === "http" ? first(explicitBaseUrl, args.memoryLlmBaseUrl) : explicitBaseUrl;
|
|
2302
|
+
const dedicatedApiKey = first(
|
|
2303
|
+
process.env.MEMORIX_RERANK_API_KEY,
|
|
2304
|
+
args.toml.rerank?.api_key,
|
|
2305
|
+
args.yaml.rerank?.apiKey
|
|
2306
|
+
);
|
|
2307
|
+
const sameEndpoint = provider2 === "http" && sameTrustedEndpoint(baseUrl, args.memoryLlmBaseUrl);
|
|
2308
|
+
const inheritedApiKey = sameEndpoint ? args.memoryLlmApiKey : void 0;
|
|
2309
|
+
const apiKey = first(dedicatedApiKey, inheritedApiKey);
|
|
2310
|
+
const canSendRequest = provider2 === "http" && Boolean(baseUrl) && (Boolean(apiKey) || !args.memoryLlmApiKey || sameEndpoint);
|
|
2311
|
+
return { provider: provider2, model, baseUrl, apiKey, canSendRequest };
|
|
2312
|
+
}
|
|
2313
|
+
function sameTrustedEndpoint(left, right) {
|
|
2314
|
+
const a = normalizeTrustedEndpoint(left);
|
|
2315
|
+
const b = normalizeTrustedEndpoint(right);
|
|
2316
|
+
return Boolean(a && b && a === b);
|
|
2317
|
+
}
|
|
2318
|
+
function normalizeTrustedEndpoint(value) {
|
|
2319
|
+
const trimmed = value?.trim();
|
|
2320
|
+
if (!trimmed) return void 0;
|
|
2321
|
+
try {
|
|
2322
|
+
const url = new URL(trimmed);
|
|
2323
|
+
const protocol = url.protocol.toLowerCase();
|
|
2324
|
+
const hostname = url.hostname.toLowerCase();
|
|
2325
|
+
const port = url.port;
|
|
2326
|
+
let pathname = url.pathname.replace(/\/+$/, "");
|
|
2327
|
+
if (pathname.toLowerCase().endsWith("/rerank")) {
|
|
2328
|
+
pathname = pathname.slice(0, -"/rerank".length).replace(/\/+$/, "");
|
|
2329
|
+
}
|
|
2330
|
+
return `${protocol}//${hostname}${port ? `:${port}` : ""}${pathname}`;
|
|
2331
|
+
} catch {
|
|
2332
|
+
const fallback = trimmed.replace(/\/+$/, "").replace(/\/rerank$/i, "").replace(/\/+$/, "");
|
|
2333
|
+
return fallback.toLowerCase() || void 0;
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2160
2336
|
var init_resolved_config = __esm({
|
|
2161
2337
|
"src/config/resolved-config.ts"() {
|
|
2162
2338
|
"use strict";
|
|
@@ -4392,9 +4568,27 @@ __export(provider_exports2, {
|
|
|
4392
4568
|
getLLMConfig: () => getLLMConfig,
|
|
4393
4569
|
initLLM: () => initLLM,
|
|
4394
4570
|
isLLMEnabled: () => isLLMEnabled,
|
|
4571
|
+
normalizeOpenAICompatibleBaseUrl: () => normalizeOpenAICompatibleBaseUrl,
|
|
4395
4572
|
parseLLMTimeoutMs: () => parseLLMTimeoutMs,
|
|
4396
4573
|
setLLMConfig: () => setLLMConfig
|
|
4397
4574
|
});
|
|
4575
|
+
function normalizeOpenAICompatibleBaseUrl(baseUrl) {
|
|
4576
|
+
const base = baseUrl.trim().replace(/\/+$/, "");
|
|
4577
|
+
if (!base) return base;
|
|
4578
|
+
let pathname = "";
|
|
4579
|
+
try {
|
|
4580
|
+
pathname = new URL(base).pathname.replace(/\/+$/, "");
|
|
4581
|
+
} catch {
|
|
4582
|
+
pathname = base.split(/[?#]/, 1)[0].replace(/\/+$/, "");
|
|
4583
|
+
}
|
|
4584
|
+
const lastSegment = pathname.split("/").filter(Boolean).at(-1);
|
|
4585
|
+
if (lastSegment && OPENAI_API_VERSION_SEGMENT.test(lastSegment)) {
|
|
4586
|
+
return base;
|
|
4587
|
+
}
|
|
4588
|
+
const queryOrHash = base.match(/[?#].*$/)?.[0] ?? "";
|
|
4589
|
+
const pathWithoutQuery = base.slice(0, base.length - queryOrHash.length).replace(/\/+$/, "");
|
|
4590
|
+
return `${pathWithoutQuery}/v1${queryOrHash}`;
|
|
4591
|
+
}
|
|
4398
4592
|
function parseLLMTimeoutMs(raw) {
|
|
4399
4593
|
if (raw === void 0 || raw.trim() === "") return LLM_TIMEOUT_DEFAULT_MS;
|
|
4400
4594
|
const parsed = Number(raw);
|
|
@@ -4498,8 +4692,7 @@ async function callLLM(systemPrompt, userMessage, signal) {
|
|
|
4498
4692
|
}
|
|
4499
4693
|
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
4500
4694
|
const config = currentConfig;
|
|
4501
|
-
|
|
4502
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
4695
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
4503
4696
|
const url = `${base}/chat/completions`;
|
|
4504
4697
|
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
4505
4698
|
const response = await fetch(url, {
|
|
@@ -4578,8 +4771,7 @@ async function callLLMWithTools(messages, tools, signal) {
|
|
|
4578
4771
|
}
|
|
4579
4772
|
async function callOpenAIWithTools(messages, tools, signal) {
|
|
4580
4773
|
const config = currentConfig;
|
|
4581
|
-
|
|
4582
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
4774
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
4583
4775
|
const url = `${base}/chat/completions`;
|
|
4584
4776
|
const openaiMessages = messages.map((msg) => {
|
|
4585
4777
|
if (msg.role === "tool") {
|
|
@@ -4729,8 +4921,7 @@ async function callAnthropicWithTools(messages, tools, signal) {
|
|
|
4729
4921
|
}
|
|
4730
4922
|
async function* callOpenAIWithToolsStream(messages, tools) {
|
|
4731
4923
|
const config = currentConfig;
|
|
4732
|
-
|
|
4733
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
4924
|
+
const base = normalizeOpenAICompatibleBaseUrl(config.baseUrl);
|
|
4734
4925
|
const url = `${base}/chat/completions`;
|
|
4735
4926
|
const openaiMessages = messages.map((msg) => {
|
|
4736
4927
|
if (msg.role === "tool") {
|
|
@@ -4978,7 +5169,7 @@ async function* callAnthropicWithToolsStream(messages, tools) {
|
|
|
4978
5169
|
}
|
|
4979
5170
|
};
|
|
4980
5171
|
}
|
|
4981
|
-
var LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_MIN_MS, LLM_TIMEOUT_MAX_MS, MAX_LLM_RESPONSE_BYTES, LLM_CALL_TIMEOUT_MS, PROVIDER_DEFAULTS, currentConfig;
|
|
5172
|
+
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;
|
|
4982
5173
|
var init_provider2 = __esm({
|
|
4983
5174
|
"src/llm/provider.ts"() {
|
|
4984
5175
|
"use strict";
|
|
@@ -4988,6 +5179,7 @@ var init_provider2 = __esm({
|
|
|
4988
5179
|
LLM_TIMEOUT_MIN_MS = 1e3;
|
|
4989
5180
|
LLM_TIMEOUT_MAX_MS = 3e5;
|
|
4990
5181
|
MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
5182
|
+
OPENAI_API_VERSION_SEGMENT = /^v\d+(?:[a-z][a-z0-9-]*)?$/i;
|
|
4991
5183
|
LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);
|
|
4992
5184
|
PROVIDER_DEFAULTS = {
|
|
4993
5185
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
@@ -5047,6 +5239,48 @@ Rules:
|
|
|
5047
5239
|
}
|
|
5048
5240
|
});
|
|
5049
5241
|
|
|
5242
|
+
// src/rerank/policy.ts
|
|
5243
|
+
function parseRerankTimeoutMs(raw) {
|
|
5244
|
+
const value = raw?.trim();
|
|
5245
|
+
if (!value) return DEFAULT_RERANK_TIMEOUT_MS;
|
|
5246
|
+
const parsed = Number(value);
|
|
5247
|
+
if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {
|
|
5248
|
+
console.warn(
|
|
5249
|
+
`[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.`
|
|
5250
|
+
);
|
|
5251
|
+
return DEFAULT_RERANK_TIMEOUT_MS;
|
|
5252
|
+
}
|
|
5253
|
+
if (parsed < RERANK_TIMEOUT_MIN_MS) return RERANK_TIMEOUT_MIN_MS;
|
|
5254
|
+
if (parsed > RERANK_TIMEOUT_MAX_MS) return RERANK_TIMEOUT_MAX_MS;
|
|
5255
|
+
return parsed;
|
|
5256
|
+
}
|
|
5257
|
+
function resolveRerankTimeoutMs(explicitTimeoutMs) {
|
|
5258
|
+
if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
|
|
5259
|
+
return explicitTimeoutMs;
|
|
5260
|
+
}
|
|
5261
|
+
return parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
5262
|
+
}
|
|
5263
|
+
function shouldAttemptHttpRerank(input) {
|
|
5264
|
+
return input.quality === "thorough" && input.hasQuery && input.candidateCount >= MIN_RERANK_CANDIDATES;
|
|
5265
|
+
}
|
|
5266
|
+
function shouldAttemptLlmRerank(input) {
|
|
5267
|
+
if (input.httpRerankConfigured) return false;
|
|
5268
|
+
if (input.quality !== "thorough" || input.tier !== "heavy" || !input.hasQuery) return false;
|
|
5269
|
+
if (input.candidateCount < MIN_RERANK_CANDIDATES) return false;
|
|
5270
|
+
return input.topScore > 0 && input.secondScore / input.topScore > 0.7;
|
|
5271
|
+
}
|
|
5272
|
+
var DEFAULT_RERANK_TIMEOUT_MS, RERANK_TIMEOUT_MIN_MS, RERANK_TIMEOUT_MAX_MS, MIN_RERANK_CANDIDATES;
|
|
5273
|
+
var init_policy = __esm({
|
|
5274
|
+
"src/rerank/policy.ts"() {
|
|
5275
|
+
"use strict";
|
|
5276
|
+
init_esm_shims();
|
|
5277
|
+
DEFAULT_RERANK_TIMEOUT_MS = 3e4;
|
|
5278
|
+
RERANK_TIMEOUT_MIN_MS = 1e3;
|
|
5279
|
+
RERANK_TIMEOUT_MAX_MS = 3e5;
|
|
5280
|
+
MIN_RERANK_CANDIDATES = 3;
|
|
5281
|
+
}
|
|
5282
|
+
});
|
|
5283
|
+
|
|
5050
5284
|
// src/timeout.ts
|
|
5051
5285
|
function withTimeout(promise, ms, label) {
|
|
5052
5286
|
return new Promise((resolve, reject) => {
|
|
@@ -5332,6 +5566,148 @@ var init_aliases = __esm({
|
|
|
5332
5566
|
}
|
|
5333
5567
|
});
|
|
5334
5568
|
|
|
5569
|
+
// src/rerank/http-provider.ts
|
|
5570
|
+
function buildRerankUrl(baseUrl) {
|
|
5571
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
5572
|
+
if (trimmed.endsWith("/rerank")) return trimmed;
|
|
5573
|
+
return `${trimmed}/rerank`;
|
|
5574
|
+
}
|
|
5575
|
+
function parseRerankResponse(payload) {
|
|
5576
|
+
const rows = extractRows(payload);
|
|
5577
|
+
if (rows.length === 0) {
|
|
5578
|
+
throw new Error("Neural rerank response contained no ranked results");
|
|
5579
|
+
}
|
|
5580
|
+
return rows.sort((a, b) => b.score - a.score);
|
|
5581
|
+
}
|
|
5582
|
+
function extractRows(payload) {
|
|
5583
|
+
if (Array.isArray(payload)) {
|
|
5584
|
+
return payload.map(rowFromUnknown).filter((row) => row !== null);
|
|
5585
|
+
}
|
|
5586
|
+
if (payload && typeof payload === "object" && "results" in payload) {
|
|
5587
|
+
const results = payload.results;
|
|
5588
|
+
if (Array.isArray(results)) {
|
|
5589
|
+
return results.map(rowFromUnknown).filter((row) => row !== null);
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5592
|
+
throw new Error("Neural rerank response was not Cohere or TEI shaped");
|
|
5593
|
+
}
|
|
5594
|
+
function rowFromUnknown(value) {
|
|
5595
|
+
if (!value || typeof value !== "object") return null;
|
|
5596
|
+
const row = value;
|
|
5597
|
+
if (typeof row.index !== "number" || !Number.isFinite(row.index)) return null;
|
|
5598
|
+
const score = typeof row.relevance_score === "number" ? row.relevance_score : typeof row.score === "number" ? row.score : null;
|
|
5599
|
+
if (score === null || !Number.isFinite(score)) return null;
|
|
5600
|
+
return { index: row.index, score };
|
|
5601
|
+
}
|
|
5602
|
+
function buildRerankBody(query, documents, model) {
|
|
5603
|
+
const body = {
|
|
5604
|
+
query,
|
|
5605
|
+
documents,
|
|
5606
|
+
top_n: documents.length,
|
|
5607
|
+
return_documents: false
|
|
5608
|
+
};
|
|
5609
|
+
const trimmed = model?.trim();
|
|
5610
|
+
if (trimmed) body.model = trimmed;
|
|
5611
|
+
return body;
|
|
5612
|
+
}
|
|
5613
|
+
async function rerankViaHttp(query, documents, config) {
|
|
5614
|
+
if (documents.length === 0) return [];
|
|
5615
|
+
const url = buildRerankUrl(config.baseUrl);
|
|
5616
|
+
const headers = {
|
|
5617
|
+
"content-type": "application/json"
|
|
5618
|
+
};
|
|
5619
|
+
if (config.apiKey) {
|
|
5620
|
+
headers.authorization = `Bearer ${config.apiKey}`;
|
|
5621
|
+
}
|
|
5622
|
+
const controller = new AbortController();
|
|
5623
|
+
const timeoutMs = resolveRerankTimeoutMs(config.timeoutMs);
|
|
5624
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
5625
|
+
try {
|
|
5626
|
+
const fetchImpl = config.fetchImpl ?? fetch;
|
|
5627
|
+
const response = await fetchImpl(url, {
|
|
5628
|
+
method: "POST",
|
|
5629
|
+
headers,
|
|
5630
|
+
signal: controller.signal,
|
|
5631
|
+
body: JSON.stringify(buildRerankBody(query, documents, config.model))
|
|
5632
|
+
});
|
|
5633
|
+
if (!response.ok) {
|
|
5634
|
+
throw new Error(`Neural rerank HTTP ${response.status} from ${url}`);
|
|
5635
|
+
}
|
|
5636
|
+
return parseRerankResponse(await response.json());
|
|
5637
|
+
} finally {
|
|
5638
|
+
clearTimeout(timer);
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
var init_http_provider = __esm({
|
|
5642
|
+
"src/rerank/http-provider.ts"() {
|
|
5643
|
+
"use strict";
|
|
5644
|
+
init_esm_shims();
|
|
5645
|
+
init_policy();
|
|
5646
|
+
}
|
|
5647
|
+
});
|
|
5648
|
+
|
|
5649
|
+
// src/rerank/index.ts
|
|
5650
|
+
var rerank_exports = {};
|
|
5651
|
+
__export(rerank_exports, {
|
|
5652
|
+
DEFAULT_RERANK_TIMEOUT_MS: () => DEFAULT_RERANK_TIMEOUT_MS,
|
|
5653
|
+
MIN_RERANK_CANDIDATES: () => MIN_RERANK_CANDIDATES,
|
|
5654
|
+
isNeuralRerankEnabled: () => isNeuralRerankEnabled,
|
|
5655
|
+
neuralRerankCandidates: () => neuralRerankCandidates,
|
|
5656
|
+
parseRerankTimeoutMs: () => parseRerankTimeoutMs,
|
|
5657
|
+
resolveRerankTimeoutMs: () => resolveRerankTimeoutMs,
|
|
5658
|
+
shouldAttemptHttpRerank: () => shouldAttemptHttpRerank,
|
|
5659
|
+
shouldAttemptLlmRerank: () => shouldAttemptLlmRerank
|
|
5660
|
+
});
|
|
5661
|
+
function isNeuralRerankEnabled(options = {}) {
|
|
5662
|
+
const lane = getResolvedRerankLane(options);
|
|
5663
|
+
return lane.provider === "http" && Boolean(lane.baseUrl);
|
|
5664
|
+
}
|
|
5665
|
+
async function neuralRerankCandidates(query, candidates, options = {}) {
|
|
5666
|
+
if (!isNeuralRerankEnabled(options) || candidates.length === 0) return null;
|
|
5667
|
+
const lane = getResolvedRerankLane(options);
|
|
5668
|
+
if (!lane.canSendRequest || !lane.baseUrl) return null;
|
|
5669
|
+
const toRerank = candidates.slice(0, MAX_RERANK);
|
|
5670
|
+
const rest = candidates.slice(MAX_RERANK);
|
|
5671
|
+
const documents = toRerank.map((candidate) => candidateText(candidate));
|
|
5672
|
+
const ranked = await rerankViaHttp(query, documents, {
|
|
5673
|
+
provider: "http",
|
|
5674
|
+
model: lane.model,
|
|
5675
|
+
baseUrl: lane.baseUrl,
|
|
5676
|
+
apiKey: lane.apiKey,
|
|
5677
|
+
timeoutMs: resolveRerankTimeoutMs()
|
|
5678
|
+
});
|
|
5679
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5680
|
+
const reranked = [];
|
|
5681
|
+
for (const row of ranked) {
|
|
5682
|
+
const candidate = toRerank[row.index];
|
|
5683
|
+
if (!candidate || seen.has(row.index)) continue;
|
|
5684
|
+
reranked.push(candidate);
|
|
5685
|
+
seen.add(row.index);
|
|
5686
|
+
}
|
|
5687
|
+
for (const [index, candidate] of toRerank.entries()) {
|
|
5688
|
+
if (!seen.has(index)) reranked.push(candidate);
|
|
5689
|
+
}
|
|
5690
|
+
reranked.push(...rest);
|
|
5691
|
+
return reranked;
|
|
5692
|
+
}
|
|
5693
|
+
function candidateText(candidate) {
|
|
5694
|
+
const narrative = candidate.narrative?.trim();
|
|
5695
|
+
if (narrative) return `${candidate.title} \u2014 ${narrative.slice(0, 200)}`;
|
|
5696
|
+
return candidate.title;
|
|
5697
|
+
}
|
|
5698
|
+
var MAX_RERANK;
|
|
5699
|
+
var init_rerank = __esm({
|
|
5700
|
+
"src/rerank/index.ts"() {
|
|
5701
|
+
"use strict";
|
|
5702
|
+
init_esm_shims();
|
|
5703
|
+
init_resolved_config();
|
|
5704
|
+
init_http_provider();
|
|
5705
|
+
init_policy();
|
|
5706
|
+
init_policy();
|
|
5707
|
+
MAX_RERANK = 10;
|
|
5708
|
+
}
|
|
5709
|
+
});
|
|
5710
|
+
|
|
5335
5711
|
// src/llm/quality.ts
|
|
5336
5712
|
var quality_exports = {};
|
|
5337
5713
|
__export(quality_exports, {
|
|
@@ -5371,9 +5747,9 @@ async function rerankResults(query, candidates) {
|
|
|
5371
5747
|
if (!isLLMEnabled() || candidates.length <= 2) {
|
|
5372
5748
|
return { reranked: candidates, usedLLM: false };
|
|
5373
5749
|
}
|
|
5374
|
-
const
|
|
5375
|
-
const toRerank = candidates.slice(0,
|
|
5376
|
-
const rest = candidates.slice(
|
|
5750
|
+
const MAX_RERANK2 = 10;
|
|
5751
|
+
const toRerank = candidates.slice(0, MAX_RERANK2);
|
|
5752
|
+
const rest = candidates.slice(MAX_RERANK2);
|
|
5377
5753
|
try {
|
|
5378
5754
|
const candidateList = toRerank.map(
|
|
5379
5755
|
(c) => `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` \u2014 ${c.narrative.substring(0, 100)}` : ""}`
|
|
@@ -6266,46 +6642,78 @@ async function searchObservations(options) {
|
|
|
6266
6642
|
}
|
|
6267
6643
|
}
|
|
6268
6644
|
}
|
|
6269
|
-
const
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
})
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6645
|
+
const httpGate = shouldAttemptHttpRerank({
|
|
6646
|
+
quality,
|
|
6647
|
+
hasQuery: Boolean(hasQuery),
|
|
6648
|
+
candidateCount: intermediate.length
|
|
6649
|
+
});
|
|
6650
|
+
const llmGateWithoutHttp = shouldAttemptLlmRerank({
|
|
6651
|
+
quality,
|
|
6652
|
+
tier,
|
|
6653
|
+
hasQuery: Boolean(hasQuery),
|
|
6654
|
+
candidateCount: intermediate.length,
|
|
6655
|
+
topScore: intermediate[0]?.score ?? 0,
|
|
6656
|
+
secondScore: intermediate[1]?.score ?? 0,
|
|
6657
|
+
httpRerankConfigured: false
|
|
6658
|
+
});
|
|
6659
|
+
if (httpGate || llmGateWithoutHttp) {
|
|
6660
|
+
const narrativeMap = /* @__PURE__ */ new Map();
|
|
6661
|
+
for (const hit of results.hits) {
|
|
6662
|
+
const doc = hit.document;
|
|
6663
|
+
narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);
|
|
6664
|
+
}
|
|
6665
|
+
const RERANK_TOP_K = 5;
|
|
6666
|
+
const toRerank = intermediate.slice(0, RERANK_TOP_K);
|
|
6667
|
+
const candidates = toRerank.map((e2, index) => ({
|
|
6668
|
+
id: `r${index + 1}`,
|
|
6669
|
+
title: e2.title,
|
|
6670
|
+
type: e2.type,
|
|
6671
|
+
score: e2.score,
|
|
6672
|
+
narrative: narrativeMap.get(makeEntryKey(e2.projectId, e2.id))
|
|
6673
|
+
}));
|
|
6674
|
+
const RERANK_TIMEOUT_MS = parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
6675
|
+
const candidateMap = new Map(candidates.map((candidate, index) => [candidate.id, toRerank[index]]));
|
|
6676
|
+
const { isNeuralRerankEnabled: isNeuralRerankEnabled2, neuralRerankCandidates: neuralRerankCandidates2 } = await Promise.resolve().then(() => (init_rerank(), rerank_exports));
|
|
6677
|
+
const httpConfigured = isNeuralRerankEnabled2();
|
|
6678
|
+
if (httpConfigured && httpGate) {
|
|
6679
|
+
try {
|
|
6680
|
+
const neural = await withTimeout(
|
|
6681
|
+
neuralRerankCandidates2(originalQuery, candidates),
|
|
6682
|
+
RERANK_TIMEOUT_MS,
|
|
6683
|
+
"neural rerank"
|
|
6684
|
+
);
|
|
6685
|
+
if (neural && neural.length > 0) {
|
|
6686
|
+
const rerankedTop = neural.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
6687
|
+
if (rerankedTop.length > 0) {
|
|
6688
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
6689
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + neural rerank");
|
|
6690
|
+
mark("rerank(usedNeural=true)");
|
|
6691
|
+
}
|
|
6305
6692
|
}
|
|
6693
|
+
} catch {
|
|
6694
|
+
console.error("[memorix] neural rerank failed or timed out; keeping original order");
|
|
6306
6695
|
}
|
|
6307
|
-
}
|
|
6308
|
-
|
|
6696
|
+
} else if (!httpConfigured && llmGateWithoutHttp) {
|
|
6697
|
+
try {
|
|
6698
|
+
const { rerankResults: rerankResults2 } = await Promise.resolve().then(() => (init_quality(), quality_exports));
|
|
6699
|
+
const { reranked, usedLLM } = await withTimeout(
|
|
6700
|
+
rerankResults2(originalQuery, candidates),
|
|
6701
|
+
RERANK_TIMEOUT_MS,
|
|
6702
|
+
"LLM rerank"
|
|
6703
|
+
);
|
|
6704
|
+
mark(`rerank(usedLLM=${usedLLM})`);
|
|
6705
|
+
if (usedLLM) {
|
|
6706
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
6707
|
+
const rerankedTop = reranked.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
6708
|
+
if (rerankedTop.length > 0) {
|
|
6709
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
6710
|
+
}
|
|
6711
|
+
}
|
|
6712
|
+
} catch {
|
|
6713
|
+
console.error("[memorix] LLM rerank failed or timed out, using original order");
|
|
6714
|
+
}
|
|
6715
|
+
} else {
|
|
6716
|
+
mark(`rerank(skipped,tier=${tier})`);
|
|
6309
6717
|
}
|
|
6310
6718
|
} else {
|
|
6311
6719
|
mark(`rerank(skipped,tier=${tier})`);
|
|
@@ -6486,6 +6894,7 @@ var init_orama_store = __esm({
|
|
|
6486
6894
|
init_project_affinity();
|
|
6487
6895
|
init_intent_detector();
|
|
6488
6896
|
init_query_expansion();
|
|
6897
|
+
init_policy();
|
|
6489
6898
|
init_timeout();
|
|
6490
6899
|
db = null;
|
|
6491
6900
|
dbInitPromise = null;
|
|
@@ -7674,8 +8083,228 @@ var init_lifecycle = __esm({
|
|
|
7674
8083
|
}
|
|
7675
8084
|
});
|
|
7676
8085
|
|
|
8086
|
+
// src/store/evidence-store.ts
|
|
8087
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
8088
|
+
function safeJson(value, fallback) {
|
|
8089
|
+
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
8090
|
+
try {
|
|
8091
|
+
return JSON.parse(value);
|
|
8092
|
+
} catch {
|
|
8093
|
+
return fallback;
|
|
8094
|
+
}
|
|
8095
|
+
}
|
|
8096
|
+
function rowToCard(row) {
|
|
8097
|
+
return {
|
|
8098
|
+
id: String(row.id),
|
|
8099
|
+
projectId: String(row.project_id),
|
|
8100
|
+
candidateKind: row.candidate_kind,
|
|
8101
|
+
candidateId: String(row.candidate_id),
|
|
8102
|
+
title: String(row.title),
|
|
8103
|
+
summary: String(row.summary ?? ""),
|
|
8104
|
+
...row.entity_name ? { entityName: String(row.entity_name) } : {},
|
|
8105
|
+
sourceKind: String(row.source_kind),
|
|
8106
|
+
sourceRef: String(row.source_ref),
|
|
8107
|
+
...row.locator ? { locator: String(row.locator) } : {},
|
|
8108
|
+
...row.captured_hash ? { capturedHash: String(row.captured_hash) } : {},
|
|
8109
|
+
...row.session_id ? { sessionId: String(row.session_id) } : {},
|
|
8110
|
+
status: String(row.status ?? "active"),
|
|
8111
|
+
verification: row.verification,
|
|
8112
|
+
freshness: row.freshness,
|
|
8113
|
+
...row.stale_reason ? { staleReason: String(row.stale_reason) } : {},
|
|
8114
|
+
files: safeJson(row.files_json, []),
|
|
8115
|
+
relatedEntities: safeJson(row.related_entities_json, []),
|
|
8116
|
+
createdAt: String(row.created_at),
|
|
8117
|
+
updatedAt: String(row.updated_at)
|
|
8118
|
+
};
|
|
8119
|
+
}
|
|
8120
|
+
function observationHash(observation) {
|
|
8121
|
+
return createHash3("sha256").update(JSON.stringify({
|
|
8122
|
+
projectId: observation.projectId,
|
|
8123
|
+
id: observation.id,
|
|
8124
|
+
title: observation.title,
|
|
8125
|
+
narrative: observation.narrative,
|
|
8126
|
+
facts: observation.facts,
|
|
8127
|
+
files: observation.filesModified,
|
|
8128
|
+
relatedEntities: observation.relatedEntities
|
|
8129
|
+
})).digest("hex");
|
|
8130
|
+
}
|
|
8131
|
+
function sourceKind(observation) {
|
|
8132
|
+
if (observation.source === "git" || observation.sourceDetail === "git-ingest") return "git";
|
|
8133
|
+
if (observation.sourceDetail === "hook") return "hook";
|
|
8134
|
+
return observation.source ?? "agent";
|
|
8135
|
+
}
|
|
8136
|
+
var EvidenceCardStore;
|
|
8137
|
+
var init_evidence_store = __esm({
|
|
8138
|
+
"src/store/evidence-store.ts"() {
|
|
8139
|
+
"use strict";
|
|
8140
|
+
init_esm_shims();
|
|
8141
|
+
init_sqlite_db();
|
|
8142
|
+
EvidenceCardStore = class {
|
|
8143
|
+
db = null;
|
|
8144
|
+
async init(dataDir) {
|
|
8145
|
+
this.db = getDatabase(dataDir);
|
|
8146
|
+
}
|
|
8147
|
+
requireDb() {
|
|
8148
|
+
if (!this.db) throw new Error("EvidenceCardStore is not initialized.");
|
|
8149
|
+
return this.db;
|
|
8150
|
+
}
|
|
8151
|
+
upsertObservation(observation) {
|
|
8152
|
+
const db2 = this.requireDb();
|
|
8153
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
8154
|
+
const card = {
|
|
8155
|
+
id: `evidence:observation:${observation.projectId}:${observation.id}`,
|
|
8156
|
+
projectId: observation.projectId,
|
|
8157
|
+
candidateKind: "observation",
|
|
8158
|
+
candidateId: String(observation.id),
|
|
8159
|
+
title: observation.title,
|
|
8160
|
+
summary: observation.narrative.slice(0, 500),
|
|
8161
|
+
entityName: observation.entityName,
|
|
8162
|
+
sourceKind: sourceKind(observation),
|
|
8163
|
+
sourceRef: `observation:${observation.id}`,
|
|
8164
|
+
locator: observation.filesModified?.join(", ") || `observation:${observation.id}`,
|
|
8165
|
+
capturedHash: observationHash(observation),
|
|
8166
|
+
...observation.sessionId ? { sessionId: observation.sessionId } : {},
|
|
8167
|
+
status: observation.status ?? "active",
|
|
8168
|
+
verification: observation.status === "resolved" ? "verified" : "unverified",
|
|
8169
|
+
freshness: "current",
|
|
8170
|
+
files: observation.filesModified ?? [],
|
|
8171
|
+
relatedEntities: observation.relatedEntities ?? [],
|
|
8172
|
+
createdAt: observation.createdAt,
|
|
8173
|
+
updatedAt: now3
|
|
8174
|
+
};
|
|
8175
|
+
db2.prepare(`
|
|
8176
|
+
INSERT INTO evidence_cards (
|
|
8177
|
+
id, project_id, candidate_kind, candidate_id, title, summary, entity_name,
|
|
8178
|
+
source_kind, source_ref, locator, captured_hash, session_id, status,
|
|
8179
|
+
verification, freshness, stale_reason, files_json, related_entities_json,
|
|
8180
|
+
created_at, updated_at
|
|
8181
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?)
|
|
8182
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
8183
|
+
title = excluded.title,
|
|
8184
|
+
summary = excluded.summary,
|
|
8185
|
+
entity_name = excluded.entity_name,
|
|
8186
|
+
source_kind = excluded.source_kind,
|
|
8187
|
+
source_ref = excluded.source_ref,
|
|
8188
|
+
locator = excluded.locator,
|
|
8189
|
+
captured_hash = excluded.captured_hash,
|
|
8190
|
+
session_id = excluded.session_id,
|
|
8191
|
+
status = excluded.status,
|
|
8192
|
+
freshness = 'current',
|
|
8193
|
+
stale_reason = NULL,
|
|
8194
|
+
files_json = excluded.files_json,
|
|
8195
|
+
related_entities_json = excluded.related_entities_json,
|
|
8196
|
+
updated_at = excluded.updated_at
|
|
8197
|
+
`).run(
|
|
8198
|
+
card.id,
|
|
8199
|
+
card.projectId,
|
|
8200
|
+
card.candidateKind,
|
|
8201
|
+
card.candidateId,
|
|
8202
|
+
card.title,
|
|
8203
|
+
card.summary,
|
|
8204
|
+
card.entityName ?? null,
|
|
8205
|
+
card.sourceKind,
|
|
8206
|
+
card.sourceRef,
|
|
8207
|
+
card.locator ?? null,
|
|
8208
|
+
card.capturedHash ?? null,
|
|
8209
|
+
card.sessionId ?? null,
|
|
8210
|
+
card.status,
|
|
8211
|
+
card.verification,
|
|
8212
|
+
card.freshness,
|
|
8213
|
+
JSON.stringify(card.files),
|
|
8214
|
+
JSON.stringify(card.relatedEntities),
|
|
8215
|
+
card.createdAt,
|
|
8216
|
+
card.updatedAt
|
|
8217
|
+
);
|
|
8218
|
+
return this.get(card.projectId, card.candidateKind, card.candidateId) ?? card;
|
|
8219
|
+
}
|
|
8220
|
+
get(projectId, candidateKind, candidateId) {
|
|
8221
|
+
const row = this.requireDb().prepare(`
|
|
8222
|
+
SELECT * FROM evidence_cards WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
8223
|
+
`).get(projectId, candidateKind, candidateId);
|
|
8224
|
+
return row ? rowToCard(row) : void 0;
|
|
8225
|
+
}
|
|
8226
|
+
list(projectId, options = {}) {
|
|
8227
|
+
const limit2 = Math.min(100, Math.max(1, Math.floor(options.limit ?? 20)));
|
|
8228
|
+
const clauses = ["project_id = ?"];
|
|
8229
|
+
const args = [projectId];
|
|
8230
|
+
if (options.freshness) {
|
|
8231
|
+
clauses.push("freshness = ?");
|
|
8232
|
+
args.push(options.freshness);
|
|
8233
|
+
}
|
|
8234
|
+
if (options.status) {
|
|
8235
|
+
clauses.push("status = ?");
|
|
8236
|
+
args.push(options.status);
|
|
8237
|
+
}
|
|
8238
|
+
args.push(limit2);
|
|
8239
|
+
const rows = this.requireDb().prepare(`
|
|
8240
|
+
SELECT * FROM evidence_cards WHERE ${clauses.join(" AND ")} ORDER BY updated_at DESC, id DESC LIMIT ?
|
|
8241
|
+
`).all(...args);
|
|
8242
|
+
return rows.map(rowToCard);
|
|
8243
|
+
}
|
|
8244
|
+
syncObservations(observations2) {
|
|
8245
|
+
return observations2.map((observation) => this.upsertObservation(observation));
|
|
8246
|
+
}
|
|
8247
|
+
markStaleForPaths(projectId, paths, reason = "source file changed") {
|
|
8248
|
+
const normalized = new Set(paths.map((value) => value.replace(/\\/g, "/").toLowerCase()));
|
|
8249
|
+
if (normalized.size === 0) return 0;
|
|
8250
|
+
const db2 = this.requireDb();
|
|
8251
|
+
const rows = db2.prepare(`SELECT * FROM evidence_cards WHERE project_id = ? AND freshness != 'stale'`).all(projectId);
|
|
8252
|
+
const update2 = db2.prepare(`
|
|
8253
|
+
UPDATE evidence_cards SET freshness = 'stale', stale_reason = ?, updated_at = ?
|
|
8254
|
+
WHERE id = ?
|
|
8255
|
+
`);
|
|
8256
|
+
let changed = 0;
|
|
8257
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
8258
|
+
const run = db2.transaction(() => {
|
|
8259
|
+
for (const row of rows) {
|
|
8260
|
+
const files = safeJson(row.files_json, []);
|
|
8261
|
+
if (!files.some((file) => normalized.has(file.replace(/\\/g, "/").toLowerCase()))) continue;
|
|
8262
|
+
update2.run(reason, now3, row.id);
|
|
8263
|
+
changed++;
|
|
8264
|
+
}
|
|
8265
|
+
});
|
|
8266
|
+
run();
|
|
8267
|
+
return changed;
|
|
8268
|
+
}
|
|
8269
|
+
setVerification(projectId, cardId, verification) {
|
|
8270
|
+
this.requireDb().prepare(`
|
|
8271
|
+
UPDATE evidence_cards SET verification = ?, updated_at = ? WHERE project_id = ? AND id = ?
|
|
8272
|
+
`).run(verification, (/* @__PURE__ */ new Date()).toISOString(), projectId, cardId);
|
|
8273
|
+
}
|
|
8274
|
+
recordEvent(projectId, cardId, kind, detail) {
|
|
8275
|
+
const event = {
|
|
8276
|
+
id: randomUUID3(),
|
|
8277
|
+
projectId,
|
|
8278
|
+
cardId,
|
|
8279
|
+
kind,
|
|
8280
|
+
...detail ? { detail: detail.slice(0, 2e3) } : {},
|
|
8281
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8282
|
+
};
|
|
8283
|
+
this.requireDb().prepare(`
|
|
8284
|
+
INSERT INTO evidence_card_events (id, project_id, card_id, kind, detail, created_at)
|
|
8285
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
8286
|
+
`).run(event.id, event.projectId, event.cardId, event.kind, event.detail ?? null, event.createdAt);
|
|
8287
|
+
return event;
|
|
8288
|
+
}
|
|
8289
|
+
listEvents(cardId, limit2 = 50) {
|
|
8290
|
+
const rows = this.requireDb().prepare(`
|
|
8291
|
+
SELECT * FROM evidence_card_events WHERE card_id = ? ORDER BY created_at DESC LIMIT ?
|
|
8292
|
+
`).all(cardId, Math.min(200, Math.max(1, Math.floor(limit2))));
|
|
8293
|
+
return rows.map((row) => ({
|
|
8294
|
+
id: String(row.id),
|
|
8295
|
+
projectId: String(row.project_id),
|
|
8296
|
+
cardId: String(row.card_id),
|
|
8297
|
+
kind: String(row.kind),
|
|
8298
|
+
...row.detail ? { detail: String(row.detail) } : {},
|
|
8299
|
+
createdAt: String(row.created_at)
|
|
8300
|
+
}));
|
|
8301
|
+
}
|
|
8302
|
+
};
|
|
8303
|
+
}
|
|
8304
|
+
});
|
|
8305
|
+
|
|
7677
8306
|
// src/knowledge/workspace-store.ts
|
|
7678
|
-
import { randomUUID as
|
|
8307
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
7679
8308
|
function arrayValue(raw) {
|
|
7680
8309
|
if (typeof raw !== "string" || !raw) return [];
|
|
7681
8310
|
try {
|
|
@@ -7816,7 +8445,7 @@ var init_workspace_store = __esm({
|
|
|
7816
8445
|
}
|
|
7817
8446
|
createProposal(input) {
|
|
7818
8447
|
const proposal = {
|
|
7819
|
-
id: input.id ??
|
|
8448
|
+
id: input.id ?? randomUUID4(),
|
|
7820
8449
|
...input,
|
|
7821
8450
|
status: input.status ?? "pending",
|
|
7822
8451
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7869,13 +8498,13 @@ __export(workspace_exports, {
|
|
|
7869
8498
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
7870
8499
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
7871
8500
|
});
|
|
7872
|
-
import { createHash as
|
|
8501
|
+
import { createHash as createHash4 } from "crypto";
|
|
7873
8502
|
import { execFile } from "child_process";
|
|
7874
8503
|
import { promises as fs6 } from "fs";
|
|
7875
8504
|
import path9 from "path";
|
|
7876
8505
|
import { promisify } from "util";
|
|
7877
8506
|
function hash(value) {
|
|
7878
|
-
return
|
|
8507
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
7879
8508
|
}
|
|
7880
8509
|
function workspaceId(projectId, mode) {
|
|
7881
8510
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -8471,7 +9100,7 @@ Respond in JSON only:
|
|
|
8471
9100
|
});
|
|
8472
9101
|
|
|
8473
9102
|
// src/media/media-store.ts
|
|
8474
|
-
import { randomUUID as
|
|
9103
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
8475
9104
|
function asOptionalText(value) {
|
|
8476
9105
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
8477
9106
|
}
|
|
@@ -8641,7 +9270,7 @@ var init_media_store = __esm({
|
|
|
8641
9270
|
return { asset: this.getAsset(input.projectId, existing.id), deduplicated: true };
|
|
8642
9271
|
}
|
|
8643
9272
|
const asset = {
|
|
8644
|
-
id:
|
|
9273
|
+
id: randomUUID5(),
|
|
8645
9274
|
...input,
|
|
8646
9275
|
createdAt: now3,
|
|
8647
9276
|
updatedAt: now3
|
|
@@ -8721,7 +9350,7 @@ var init_media_store = __esm({
|
|
|
8721
9350
|
`).get(input.assetId, input.observationId ?? null, input.role);
|
|
8722
9351
|
if (existing) return rowToLink(existing);
|
|
8723
9352
|
const link = {
|
|
8724
|
-
id:
|
|
9353
|
+
id: randomUUID5(),
|
|
8725
9354
|
assetId: input.assetId,
|
|
8726
9355
|
projectId: input.projectId,
|
|
8727
9356
|
...input.observationId !== void 0 ? { observationId: input.observationId } : {},
|
|
@@ -8760,7 +9389,7 @@ var init_media_store = __esm({
|
|
|
8760
9389
|
return rowToDerivation(this.db.prepare("SELECT * FROM media_derivations WHERE id = ?").get(existing.id));
|
|
8761
9390
|
}
|
|
8762
9391
|
const derivation = {
|
|
8763
|
-
id:
|
|
9392
|
+
id: randomUUID5(),
|
|
8764
9393
|
...input,
|
|
8765
9394
|
content,
|
|
8766
9395
|
...error ? { error } : {},
|
|
@@ -8847,7 +9476,7 @@ var init_media_store = __esm({
|
|
|
8847
9476
|
createJob(input) {
|
|
8848
9477
|
const now3 = Date.now();
|
|
8849
9478
|
const job = {
|
|
8850
|
-
id:
|
|
9479
|
+
id: randomUUID5(),
|
|
8851
9480
|
projectId: input.projectId,
|
|
8852
9481
|
kind: input.kind,
|
|
8853
9482
|
status: "queued",
|
|
@@ -9009,14 +9638,14 @@ var init_types2 = __esm({
|
|
|
9009
9638
|
});
|
|
9010
9639
|
|
|
9011
9640
|
// src/media/asset-store.ts
|
|
9012
|
-
import { createHash as
|
|
9641
|
+
import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
|
|
9013
9642
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
9014
9643
|
import path10 from "path";
|
|
9015
9644
|
function mediaRoot(dataDir) {
|
|
9016
9645
|
return path10.resolve(dataDir, "media");
|
|
9017
9646
|
}
|
|
9018
9647
|
function projectStorageKey(projectId) {
|
|
9019
|
-
return
|
|
9648
|
+
return createHash5("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
9020
9649
|
}
|
|
9021
9650
|
function validateUnderRoot(root, candidate) {
|
|
9022
9651
|
const resolved = path10.resolve(candidate);
|
|
@@ -9080,7 +9709,7 @@ async function destinationExists(destination) {
|
|
|
9080
9709
|
async function persistBuffer(bytes, destination) {
|
|
9081
9710
|
await mkdir3(path10.dirname(destination), { recursive: true });
|
|
9082
9711
|
if (await destinationExists(destination)) return false;
|
|
9083
|
-
const temporary = `${destination}.${
|
|
9712
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
9084
9713
|
try {
|
|
9085
9714
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
9086
9715
|
await rename2(temporary, destination);
|
|
@@ -9125,7 +9754,7 @@ async function importMediaBuffer(input) {
|
|
|
9125
9754
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
9126
9755
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
9127
9756
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
9128
|
-
const sha256 =
|
|
9757
|
+
const sha256 = createHash5("sha256").update(input.bytes).digest("hex");
|
|
9129
9758
|
return importKnownMedia({
|
|
9130
9759
|
dataDir: input.dataDir,
|
|
9131
9760
|
projectId: input.projectId,
|
|
@@ -9143,7 +9772,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
9143
9772
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
9144
9773
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
9145
9774
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
9146
|
-
const sha256 =
|
|
9775
|
+
const sha256 = createHash5("sha256").update(bytes).digest("hex");
|
|
9147
9776
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
9148
9777
|
return bytes;
|
|
9149
9778
|
}
|
|
@@ -61894,7 +62523,7 @@ var require_gaxios = __commonJS({
|
|
|
61894
62523
|
var retry_js_1 = require_retry3();
|
|
61895
62524
|
var stream_1 = __require("stream");
|
|
61896
62525
|
var interceptor_js_1 = require_interceptor();
|
|
61897
|
-
var
|
|
62526
|
+
var randomUUID16 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
61898
62527
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
61899
62528
|
var Gaxios = class {
|
|
61900
62529
|
agentCache = /* @__PURE__ */ new Map();
|
|
@@ -62167,7 +62796,7 @@ var require_gaxios = __commonJS({
|
|
|
62167
62796
|
*/
|
|
62168
62797
|
["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
62169
62798
|
if (opts.multipart?.length) {
|
|
62170
|
-
const boundary = await
|
|
62799
|
+
const boundary = await randomUUID16();
|
|
62171
62800
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
62172
62801
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
62173
62802
|
} else if (shouldDirectlyPassData) {
|
|
@@ -74394,7 +75023,7 @@ var require_websocket = __commonJS({
|
|
|
74394
75023
|
var http3 = __require("http");
|
|
74395
75024
|
var net = __require("net");
|
|
74396
75025
|
var tls = __require("tls");
|
|
74397
|
-
var { randomBytes, createHash:
|
|
75026
|
+
var { randomBytes, createHash: createHash14 } = __require("crypto");
|
|
74398
75027
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
74399
75028
|
var { URL: URL2 } = __require("url");
|
|
74400
75029
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -75062,7 +75691,7 @@ var require_websocket = __commonJS({
|
|
|
75062
75691
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
75063
75692
|
return;
|
|
75064
75693
|
}
|
|
75065
|
-
const digest2 =
|
|
75694
|
+
const digest2 = createHash14("sha1").update(key + GUID).digest("base64");
|
|
75066
75695
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
75067
75696
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
75068
75697
|
return;
|
|
@@ -75434,7 +76063,7 @@ var require_websocket_server = __commonJS({
|
|
|
75434
76063
|
var EventEmitter = __require("events");
|
|
75435
76064
|
var http3 = __require("http");
|
|
75436
76065
|
var { Duplex } = __require("stream");
|
|
75437
|
-
var { createHash:
|
|
76066
|
+
var { createHash: createHash14 } = __require("crypto");
|
|
75438
76067
|
var extension3 = require_extension();
|
|
75439
76068
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
75440
76069
|
var subprotocol2 = require_subprotocol();
|
|
@@ -75741,7 +76370,7 @@ var require_websocket_server = __commonJS({
|
|
|
75741
76370
|
);
|
|
75742
76371
|
}
|
|
75743
76372
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
75744
|
-
const digest2 =
|
|
76373
|
+
const digest2 = createHash14("sha1").update(key + GUID).digest("base64");
|
|
75745
76374
|
const headers = [
|
|
75746
76375
|
"HTTP/1.1 101 Switching Protocols",
|
|
75747
76376
|
"Upgrade: websocket",
|
|
@@ -142879,6 +143508,186 @@ var init_audio_jobs = __esm({
|
|
|
142879
143508
|
}
|
|
142880
143509
|
});
|
|
142881
143510
|
|
|
143511
|
+
// src/memory/feedback-model.ts
|
|
143512
|
+
function feedbackWeightMultiplier(weight) {
|
|
143513
|
+
return Math.max(0.35, Math.min(1.4, 0.35 + Math.max(0, Math.min(2, weight)) * 0.525));
|
|
143514
|
+
}
|
|
143515
|
+
var init_feedback_model = __esm({
|
|
143516
|
+
"src/memory/feedback-model.ts"() {
|
|
143517
|
+
"use strict";
|
|
143518
|
+
init_esm_shims();
|
|
143519
|
+
}
|
|
143520
|
+
});
|
|
143521
|
+
|
|
143522
|
+
// src/memory/feedback.ts
|
|
143523
|
+
var feedback_exports = {};
|
|
143524
|
+
__export(feedback_exports, {
|
|
143525
|
+
FEEDBACK_DELTAS: () => FEEDBACK_DELTAS,
|
|
143526
|
+
MemoryFeedbackStore: () => MemoryFeedbackStore,
|
|
143527
|
+
applyMemoryFeedback: () => applyMemoryFeedback,
|
|
143528
|
+
feedbackWeightMultiplier: () => feedbackWeightMultiplier
|
|
143529
|
+
});
|
|
143530
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
143531
|
+
function applyMemoryFeedback(current, event) {
|
|
143532
|
+
const delta = event.signal === "revoke" ? 0 : FEEDBACK_DELTAS[event.signal];
|
|
143533
|
+
const weight = Math.max(0, Math.min(2, current.weight + delta));
|
|
143534
|
+
const status = (event.signal === "code-conflict" || event.signal === "user-correction" || event.signal === "weaken") && weight < 0.5 ? "archived" : current.status;
|
|
143535
|
+
return { weight, status, audit: [...current.audit, { ...event }] };
|
|
143536
|
+
}
|
|
143537
|
+
function rowToEvent(row) {
|
|
143538
|
+
return {
|
|
143539
|
+
id: String(row.id),
|
|
143540
|
+
projectId: String(row.project_id),
|
|
143541
|
+
candidateKind: row.candidate_kind,
|
|
143542
|
+
candidateId: String(row.candidate_id),
|
|
143543
|
+
signal: row.signal,
|
|
143544
|
+
...row.observed_at ? { at: String(row.observed_at) } : { at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
143545
|
+
...row.actor ? { actor: String(row.actor) } : {},
|
|
143546
|
+
...row.note ? { note: String(row.note) } : {},
|
|
143547
|
+
...row.source_ref ? { sourceRef: String(row.source_ref) } : {},
|
|
143548
|
+
...row.target_event_id ? { targetEventId: String(row.target_event_id) } : {},
|
|
143549
|
+
delta: Number(row.delta ?? 0)
|
|
143550
|
+
};
|
|
143551
|
+
}
|
|
143552
|
+
var FEEDBACK_DELTAS, MemoryFeedbackStore;
|
|
143553
|
+
var init_feedback = __esm({
|
|
143554
|
+
"src/memory/feedback.ts"() {
|
|
143555
|
+
"use strict";
|
|
143556
|
+
init_esm_shims();
|
|
143557
|
+
init_sqlite_db();
|
|
143558
|
+
init_feedback_model();
|
|
143559
|
+
FEEDBACK_DELTAS = {
|
|
143560
|
+
"user-correction": -0.35,
|
|
143561
|
+
"verification-success": 0.25,
|
|
143562
|
+
"verification-failure": -0.25,
|
|
143563
|
+
"code-change": -0.15,
|
|
143564
|
+
used: 0.1,
|
|
143565
|
+
"not-used": -0.05,
|
|
143566
|
+
"code-conflict": -0.4,
|
|
143567
|
+
strengthen: 0.2,
|
|
143568
|
+
weaken: -0.2
|
|
143569
|
+
};
|
|
143570
|
+
MemoryFeedbackStore = class {
|
|
143571
|
+
db = null;
|
|
143572
|
+
async init(dataDir) {
|
|
143573
|
+
this.db = getDatabase(dataDir);
|
|
143574
|
+
}
|
|
143575
|
+
requireDb() {
|
|
143576
|
+
if (!this.db) throw new Error("MemoryFeedbackStore is not initialized.");
|
|
143577
|
+
return this.db;
|
|
143578
|
+
}
|
|
143579
|
+
loadEvents(projectId, candidateKind, candidateId) {
|
|
143580
|
+
return this.requireDb().prepare(`
|
|
143581
|
+
SELECT * FROM memory_feedback_events
|
|
143582
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
143583
|
+
ORDER BY observed_at ASC, rowid ASC
|
|
143584
|
+
`).all(projectId, candidateKind, candidateId).map(rowToEvent);
|
|
143585
|
+
}
|
|
143586
|
+
rebuild(projectId, candidateKind, candidateId) {
|
|
143587
|
+
const events = this.loadEvents(projectId, candidateKind, candidateId);
|
|
143588
|
+
const revoked = new Set(events.filter((event) => event.signal === "revoke" && event.targetEventId).map((event) => event.targetEventId));
|
|
143589
|
+
let state = { weight: 1, status: "active", audit: [] };
|
|
143590
|
+
for (const event of events) {
|
|
143591
|
+
if (event.signal === "revoke" || revoked.has(event.id)) {
|
|
143592
|
+
state.audit.push(event);
|
|
143593
|
+
continue;
|
|
143594
|
+
}
|
|
143595
|
+
state = applyMemoryFeedback(state, event);
|
|
143596
|
+
}
|
|
143597
|
+
this.requireDb().prepare(`
|
|
143598
|
+
INSERT INTO memory_feedback_states (project_id, candidate_kind, candidate_id, weight, lifecycle_status, updated_at)
|
|
143599
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
143600
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
143601
|
+
weight = excluded.weight, lifecycle_status = excluded.lifecycle_status, updated_at = excluded.updated_at
|
|
143602
|
+
`).run(projectId, candidateKind, candidateId, state.weight, state.status, (/* @__PURE__ */ new Date()).toISOString());
|
|
143603
|
+
return state;
|
|
143604
|
+
}
|
|
143605
|
+
getState(projectId, candidateKind, candidateId) {
|
|
143606
|
+
const row = this.requireDb().prepare(`
|
|
143607
|
+
SELECT weight, lifecycle_status FROM memory_feedback_states
|
|
143608
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
143609
|
+
`).get(projectId, candidateKind, candidateId);
|
|
143610
|
+
if (!row) return { weight: 1, status: "active", audit: [] };
|
|
143611
|
+
return {
|
|
143612
|
+
weight: Number(row.weight ?? 1),
|
|
143613
|
+
status: row.lifecycle_status ?? "active",
|
|
143614
|
+
audit: this.loadEvents(projectId, candidateKind, candidateId)
|
|
143615
|
+
};
|
|
143616
|
+
}
|
|
143617
|
+
listStates(projectId, candidateKind = "observation") {
|
|
143618
|
+
return this.requireDb().prepare(`
|
|
143619
|
+
SELECT candidate_id, weight, lifecycle_status, updated_at
|
|
143620
|
+
FROM memory_feedback_states WHERE project_id = ? AND candidate_kind = ?
|
|
143621
|
+
ORDER BY updated_at DESC
|
|
143622
|
+
`).all(projectId, candidateKind).map((row) => ({
|
|
143623
|
+
candidateId: String(row.candidate_id),
|
|
143624
|
+
weight: Number(row.weight),
|
|
143625
|
+
status: row.lifecycle_status,
|
|
143626
|
+
updatedAt: String(row.updated_at)
|
|
143627
|
+
}));
|
|
143628
|
+
}
|
|
143629
|
+
weights(projectId, candidateKind = "observation") {
|
|
143630
|
+
const states = /* @__PURE__ */ new Map();
|
|
143631
|
+
for (const row of this.listStates(projectId, candidateKind)) {
|
|
143632
|
+
states.set(row.candidateId, this.getState(projectId, candidateKind, row.candidateId));
|
|
143633
|
+
}
|
|
143634
|
+
return states;
|
|
143635
|
+
}
|
|
143636
|
+
record(input) {
|
|
143637
|
+
if (input.signal === "revoke" && !input.targetEventId) {
|
|
143638
|
+
throw new Error("A revoke feedback event requires targetEventId.");
|
|
143639
|
+
}
|
|
143640
|
+
if (input.signal === "revoke") {
|
|
143641
|
+
const target = this.requireDb().prepare(`
|
|
143642
|
+
SELECT 1 FROM memory_feedback_events
|
|
143643
|
+
WHERE id = ? AND project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
143644
|
+
`).get(input.targetEventId, input.projectId, input.candidateKind, input.candidateId);
|
|
143645
|
+
if (!target) throw new Error("The feedback event to revoke was not found in the same candidate scope.");
|
|
143646
|
+
}
|
|
143647
|
+
const event = {
|
|
143648
|
+
id: randomUUID7(),
|
|
143649
|
+
projectId: input.projectId,
|
|
143650
|
+
candidateKind: input.candidateKind,
|
|
143651
|
+
candidateId: input.candidateId,
|
|
143652
|
+
signal: input.signal,
|
|
143653
|
+
sourceRef: input.sourceRef,
|
|
143654
|
+
...input.actor ? { actor: input.actor } : {},
|
|
143655
|
+
...input.note ? { note: input.note.slice(0, 2e3) } : {},
|
|
143656
|
+
...input.targetEventId ? { targetEventId: input.targetEventId } : {},
|
|
143657
|
+
at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
143658
|
+
delta: input.signal === "revoke" ? 0 : FEEDBACK_DELTAS[input.signal]
|
|
143659
|
+
};
|
|
143660
|
+
this.requireDb().prepare(`
|
|
143661
|
+
INSERT INTO memory_feedback_events (
|
|
143662
|
+
id, project_id, candidate_kind, candidate_id, signal, actor, note,
|
|
143663
|
+
source_ref, target_event_id, delta, observed_at
|
|
143664
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
143665
|
+
`).run(
|
|
143666
|
+
event.id,
|
|
143667
|
+
event.projectId,
|
|
143668
|
+
event.candidateKind,
|
|
143669
|
+
event.candidateId,
|
|
143670
|
+
event.signal,
|
|
143671
|
+
event.actor ?? null,
|
|
143672
|
+
event.note ?? null,
|
|
143673
|
+
event.sourceRef,
|
|
143674
|
+
event.targetEventId ?? null,
|
|
143675
|
+
event.delta,
|
|
143676
|
+
event.at
|
|
143677
|
+
);
|
|
143678
|
+
return { event, state: this.rebuild(input.projectId, input.candidateKind, input.candidateId) };
|
|
143679
|
+
}
|
|
143680
|
+
audit(projectId, candidateKind, candidateId, limit2 = 100) {
|
|
143681
|
+
return this.requireDb().prepare(`
|
|
143682
|
+
SELECT * FROM memory_feedback_events
|
|
143683
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
143684
|
+
ORDER BY observed_at DESC, rowid DESC LIMIT ?
|
|
143685
|
+
`).all(projectId, candidateKind, candidateId, Math.min(200, Math.max(1, Math.floor(limit2)))).map(rowToEvent);
|
|
143686
|
+
}
|
|
143687
|
+
};
|
|
143688
|
+
}
|
|
143689
|
+
});
|
|
143690
|
+
|
|
142882
143691
|
// src/memory/retention.ts
|
|
142883
143692
|
var retention_exports = {};
|
|
142884
143693
|
__export(retention_exports, {
|
|
@@ -142920,6 +143729,7 @@ function getEffectiveRetentionDays(doc) {
|
|
|
142920
143729
|
}
|
|
142921
143730
|
function isImmune(doc) {
|
|
142922
143731
|
if (doc.type === "probe") return false;
|
|
143732
|
+
if (doc.feedbackStatus === "archived") return false;
|
|
142923
143733
|
if (doc.admissionState === "candidate" || doc.admissionState === "ephemeral") return false;
|
|
142924
143734
|
if (doc.valueCategory === "core") return true;
|
|
142925
143735
|
const importance = getImportanceLevel(doc);
|
|
@@ -142952,7 +143762,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
142952
143762
|
const decayFactor = Math.exp(-ageDays / retention);
|
|
142953
143763
|
const accessCount = doc.accessCount ?? 0;
|
|
142954
143764
|
const accessBoost = Math.min(2, 1 + 0.1 * accessCount);
|
|
142955
|
-
|
|
143765
|
+
const feedbackMultiplier = doc.feedbackWeight === void 0 ? 1 : feedbackWeightMultiplier(doc.feedbackWeight);
|
|
143766
|
+
let totalScore = base * decayFactor * accessBoost * feedbackMultiplier;
|
|
142956
143767
|
const immune = isImmune(doc);
|
|
142957
143768
|
if (immune) {
|
|
142958
143769
|
totalScore = Math.max(totalScore, 0.5);
|
|
@@ -142964,7 +143775,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
142964
143775
|
decayFactor,
|
|
142965
143776
|
accessBoost,
|
|
142966
143777
|
ageDays,
|
|
142967
|
-
isImmune: immune
|
|
143778
|
+
isImmune: immune,
|
|
143779
|
+
feedbackMultiplier
|
|
142968
143780
|
};
|
|
142969
143781
|
}
|
|
142970
143782
|
function rankByRelevance(docs, referenceTime) {
|
|
@@ -142972,6 +143784,7 @@ function rankByRelevance(docs, referenceTime) {
|
|
|
142972
143784
|
}
|
|
142973
143785
|
function getRetentionZone(doc, referenceTime) {
|
|
142974
143786
|
const now3 = referenceTime ?? /* @__PURE__ */ new Date();
|
|
143787
|
+
if (doc.feedbackStatus === "archived") return "archive-candidate";
|
|
142975
143788
|
const importance = getImportanceLevel(doc);
|
|
142976
143789
|
const retention = getEffectiveRetentionDays(doc);
|
|
142977
143790
|
const createdAt = new Date(doc.createdAt);
|
|
@@ -143043,7 +143856,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
143043
143856
|
summary: parts.join(" ; ")
|
|
143044
143857
|
};
|
|
143045
143858
|
}
|
|
143046
|
-
function toRetentionDocument(obs, accessMap) {
|
|
143859
|
+
function toRetentionDocument(obs, accessMap, feedback) {
|
|
143047
143860
|
const access2 = accessMap?.get(obs.id);
|
|
143048
143861
|
return {
|
|
143049
143862
|
id: `obs-${obs.id}`,
|
|
@@ -143065,11 +143878,12 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
143065
143878
|
sourceDetail: obs.sourceDetail ?? "",
|
|
143066
143879
|
valueCategory: obs.valueCategory ?? "",
|
|
143067
143880
|
admissionState: obs.admissionState ?? "",
|
|
143068
|
-
admissionReason: obs.admissionReason ?? ""
|
|
143881
|
+
admissionReason: obs.admissionReason ?? "",
|
|
143882
|
+
...feedback ? { feedbackWeight: feedback.weight, feedbackStatus: feedback.status } : {}
|
|
143069
143883
|
};
|
|
143070
143884
|
}
|
|
143071
143885
|
function projectObservationRetention(observation, options = {}) {
|
|
143072
|
-
const document2 = toRetentionDocument(observation, options.accessMap);
|
|
143886
|
+
const document2 = toRetentionDocument(observation, options.accessMap, options.feedback);
|
|
143073
143887
|
const relevance = calculateRelevance(document2, options.referenceTime);
|
|
143074
143888
|
const explanation = explainRetention(document2, options.referenceTime);
|
|
143075
143889
|
return {
|
|
@@ -143094,7 +143908,17 @@ function summarizeRetentionProjections(projections) {
|
|
|
143094
143908
|
}
|
|
143095
143909
|
return { active, stale, archiveCandidates, immune };
|
|
143096
143910
|
}
|
|
143097
|
-
async function
|
|
143911
|
+
async function loadFeedbackStore(dataDir) {
|
|
143912
|
+
try {
|
|
143913
|
+
const { MemoryFeedbackStore: MemoryFeedbackStore2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
|
|
143914
|
+
const store = new MemoryFeedbackStore2();
|
|
143915
|
+
await store.init(dataDir);
|
|
143916
|
+
return store;
|
|
143917
|
+
} catch {
|
|
143918
|
+
return void 0;
|
|
143919
|
+
}
|
|
143920
|
+
}
|
|
143921
|
+
async function archiveExpiredBatch(projectDir2, options) {
|
|
143098
143922
|
const store = getObservationStore();
|
|
143099
143923
|
const limit2 = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));
|
|
143100
143924
|
const afterId = Math.max(0, Math.floor(options.afterId ?? 0));
|
|
@@ -143103,11 +143927,13 @@ async function archiveExpiredBatch(_projectDir, options) {
|
|
|
143103
143927
|
afterId,
|
|
143104
143928
|
limit: limit2 + 1
|
|
143105
143929
|
});
|
|
143930
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
143106
143931
|
const hasMore = page.length > limit2;
|
|
143107
143932
|
const scanned = hasMore ? page.slice(0, limit2) : page;
|
|
143108
143933
|
const candidateIds = scanned.filter((observation) => !options.reader || canManageObservation(observation, options.reader)).filter((observation) => projectObservationRetention(observation, {
|
|
143109
143934
|
accessMap: options.accessMap,
|
|
143110
|
-
referenceTime: options.referenceTime
|
|
143935
|
+
referenceTime: options.referenceTime,
|
|
143936
|
+
...feedback ? { feedback: feedback.getState(options.projectId, "observation", String(observation.id)) } : {}
|
|
143111
143937
|
}).zone === "archive-candidate").map((observation) => observation.id);
|
|
143112
143938
|
const archived = candidateIds.length === 0 ? 0 : await store.atomic(async (tx) => {
|
|
143113
143939
|
const updates = await Promise.all(
|
|
@@ -143138,6 +143964,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
143138
143964
|
const remaining = reader ? remainingObservations.filter((observation) => canManageObservation(observation, reader)).length : remainingObservations.length;
|
|
143139
143965
|
return { archived, remaining };
|
|
143140
143966
|
}
|
|
143967
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
143141
143968
|
return await store.atomic(async (tx) => {
|
|
143142
143969
|
const allObs = await tx.loadAll();
|
|
143143
143970
|
const activeObs = allObs.filter(
|
|
@@ -143145,7 +143972,11 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
143145
143972
|
);
|
|
143146
143973
|
const archivedIds = [];
|
|
143147
143974
|
for (const obs of activeObs) {
|
|
143148
|
-
const retention = projectObservationRetention(obs, {
|
|
143975
|
+
const retention = projectObservationRetention(obs, {
|
|
143976
|
+
accessMap,
|
|
143977
|
+
referenceTime,
|
|
143978
|
+
...feedback ? { feedback: feedback.getState(obs.projectId, "observation", String(obs.id)) } : {}
|
|
143979
|
+
});
|
|
143149
143980
|
if (retention.zone === "archive-candidate") {
|
|
143150
143981
|
archivedIds.push(obs.id);
|
|
143151
143982
|
}
|
|
@@ -143165,6 +143996,7 @@ var init_retention = __esm({
|
|
|
143165
143996
|
init_esm_shims();
|
|
143166
143997
|
init_obs_store();
|
|
143167
143998
|
init_visibility();
|
|
143999
|
+
init_feedback_model();
|
|
143168
144000
|
RETENTION_DAYS = {
|
|
143169
144001
|
critical: 365,
|
|
143170
144002
|
high: 180,
|
|
@@ -143201,7 +144033,7 @@ var init_retention = __esm({
|
|
|
143201
144033
|
});
|
|
143202
144034
|
|
|
143203
144035
|
// src/memory/owner.ts
|
|
143204
|
-
import { randomUUID as
|
|
144036
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
143205
144037
|
import { promises as fs9 } from "fs";
|
|
143206
144038
|
import path16 from "path";
|
|
143207
144039
|
function ownerPath(dataDir) {
|
|
@@ -143231,7 +144063,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
|
|
|
143231
144063
|
await fs9.mkdir(path16.dirname(filePath), { recursive: true });
|
|
143232
144064
|
const created = {
|
|
143233
144065
|
version: 1,
|
|
143234
|
-
id: "local-" +
|
|
144066
|
+
id: "local-" + randomUUID8(),
|
|
143235
144067
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
143236
144068
|
};
|
|
143237
144069
|
try {
|
|
@@ -143254,7 +144086,7 @@ var init_owner = __esm({
|
|
|
143254
144086
|
});
|
|
143255
144087
|
|
|
143256
144088
|
// src/memory/long-term-store.ts
|
|
143257
|
-
import { randomUUID as
|
|
144089
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
143258
144090
|
function optionalText2(value) {
|
|
143259
144091
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
143260
144092
|
}
|
|
@@ -143305,7 +144137,7 @@ function rowToEvidence(row) {
|
|
|
143305
144137
|
createdAt: row.createdAt
|
|
143306
144138
|
};
|
|
143307
144139
|
}
|
|
143308
|
-
function
|
|
144140
|
+
function rowToEvent2(row) {
|
|
143309
144141
|
return {
|
|
143310
144142
|
id: row.id,
|
|
143311
144143
|
memoryId: row.memoryId,
|
|
@@ -143414,7 +144246,7 @@ var init_long_term_store = __esm({
|
|
|
143414
144246
|
}
|
|
143415
144247
|
insertEvidence(input) {
|
|
143416
144248
|
const evidence = {
|
|
143417
|
-
id:
|
|
144249
|
+
id: randomUUID9(),
|
|
143418
144250
|
...input,
|
|
143419
144251
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
143420
144252
|
};
|
|
@@ -143441,7 +144273,7 @@ var init_long_term_store = __esm({
|
|
|
143441
144273
|
}
|
|
143442
144274
|
recordEvent(input) {
|
|
143443
144275
|
const event = {
|
|
143444
|
-
id:
|
|
144276
|
+
id: randomUUID9(),
|
|
143445
144277
|
...input,
|
|
143446
144278
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
143447
144279
|
};
|
|
@@ -143462,7 +144294,7 @@ var init_long_term_store = __esm({
|
|
|
143462
144294
|
listEvents(memoryId) {
|
|
143463
144295
|
return this.db.prepare(`
|
|
143464
144296
|
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
143465
|
-
`).all(memoryId).map(
|
|
144297
|
+
`).all(memoryId).map(rowToEvent2);
|
|
143466
144298
|
}
|
|
143467
144299
|
markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
143468
144300
|
const unique = [...new Set(ids.filter(Boolean))];
|
|
@@ -143531,7 +144363,7 @@ __export(long_term_exports, {
|
|
|
143531
144363
|
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
143532
144364
|
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
143533
144365
|
});
|
|
143534
|
-
import { randomUUID as
|
|
144366
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
143535
144367
|
function isOneOf(value, values) {
|
|
143536
144368
|
return typeof value === "string" && values.includes(value);
|
|
143537
144369
|
}
|
|
@@ -143713,7 +144545,7 @@ async function createManualLongTermMemory(input) {
|
|
|
143713
144545
|
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
143714
144546
|
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
143715
144547
|
assertScope(input.scope);
|
|
143716
|
-
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" +
|
|
144548
|
+
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID10(), relation: "supports" }];
|
|
143717
144549
|
return createLongTermMemoryWithDataDir({
|
|
143718
144550
|
dataDir: input.dataDir,
|
|
143719
144551
|
originProjectId: input.projectId,
|
|
@@ -143768,7 +144600,7 @@ async function createLongTermMemoryWithDataDir(input) {
|
|
|
143768
144600
|
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
143769
144601
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
143770
144602
|
const memory = {
|
|
143771
|
-
id:
|
|
144603
|
+
id: randomUUID10(),
|
|
143772
144604
|
originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
|
|
143773
144605
|
ownerId: compactText(input.ownerId, "owner id", 160),
|
|
143774
144606
|
scope: input.scope,
|
|
@@ -144086,9 +144918,9 @@ var init_long_term = __esm({
|
|
|
144086
144918
|
});
|
|
144087
144919
|
|
|
144088
144920
|
// src/codegraph/ids.ts
|
|
144089
|
-
import { createHash as
|
|
144921
|
+
import { createHash as createHash6 } from "crypto";
|
|
144090
144922
|
function digest(input) {
|
|
144091
|
-
return
|
|
144923
|
+
return createHash6("sha256").update(input).digest("hex").slice(0, 16);
|
|
144092
144924
|
}
|
|
144093
144925
|
function normalizeCodePath(path22) {
|
|
144094
144926
|
return path22.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -144123,7 +144955,7 @@ var store_exports = {};
|
|
|
144123
144955
|
__export(store_exports, {
|
|
144124
144956
|
CodeGraphStore: () => CodeGraphStore
|
|
144125
144957
|
});
|
|
144126
|
-
import { randomUUID as
|
|
144958
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
144127
144959
|
import { posix as pathPosix } from "path";
|
|
144128
144960
|
function rowToFile(row) {
|
|
144129
144961
|
return {
|
|
@@ -144840,7 +145672,7 @@ var init_store = __esm({
|
|
|
144840
145672
|
* so an interrupted scan cannot be advertised as complete.
|
|
144841
145673
|
*/
|
|
144842
145674
|
recordCodeStateSnapshot(input) {
|
|
144843
|
-
const id =
|
|
145675
|
+
const id = randomUUID11();
|
|
144844
145676
|
let snapshot;
|
|
144845
145677
|
const tx = this.db.transaction(() => {
|
|
144846
145678
|
const previous = this.db.prepare(
|
|
@@ -144918,7 +145750,7 @@ var init_store = __esm({
|
|
|
144918
145750
|
|
|
144919
145751
|
// src/codegraph/code-state.ts
|
|
144920
145752
|
import { execFile as execFile2 } from "child_process";
|
|
144921
|
-
import { createHash as
|
|
145753
|
+
import { createHash as createHash7 } from "crypto";
|
|
144922
145754
|
import { promisify as promisify3 } from "util";
|
|
144923
145755
|
async function runGit(rootPath, args) {
|
|
144924
145756
|
try {
|
|
@@ -144947,7 +145779,7 @@ function changedPathCount(status) {
|
|
|
144947
145779
|
return count2;
|
|
144948
145780
|
}
|
|
144949
145781
|
function fingerprint(baseRevision, status) {
|
|
144950
|
-
return
|
|
145782
|
+
return createHash7("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
144951
145783
|
}
|
|
144952
145784
|
async function collectCodeStateSnapshot(input) {
|
|
144953
145785
|
const [revision, status] = await Promise.all([
|
|
@@ -145047,11 +145879,11 @@ __export(lite_provider_exports, {
|
|
|
145047
145879
|
indexProjectLite: () => indexProjectLite,
|
|
145048
145880
|
refreshProjectLite: () => refreshProjectLite
|
|
145049
145881
|
});
|
|
145050
|
-
import { createHash as
|
|
145882
|
+
import { createHash as createHash8 } from "crypto";
|
|
145051
145883
|
import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
|
|
145052
145884
|
import { join as join4, relative } from "path";
|
|
145053
145885
|
function hashText(text2) {
|
|
145054
|
-
return
|
|
145886
|
+
return createHash8("sha256").update(text2).digest("hex");
|
|
145055
145887
|
}
|
|
145056
145888
|
function extension2(path22) {
|
|
145057
145889
|
const index = path22.lastIndexOf(".");
|
|
@@ -145618,7 +146450,7 @@ var claim_store_exports = {};
|
|
|
145618
146450
|
__export(claim_store_exports, {
|
|
145619
146451
|
ClaimStore: () => ClaimStore
|
|
145620
146452
|
});
|
|
145621
|
-
import { createHash as
|
|
146453
|
+
import { createHash as createHash9, randomUUID as randomUUID12 } from "crypto";
|
|
145622
146454
|
function optionalText3(value) {
|
|
145623
146455
|
return typeof value === "string" && value ? value : void 0;
|
|
145624
146456
|
}
|
|
@@ -145657,7 +146489,7 @@ function rowToEvidence2(row) {
|
|
|
145657
146489
|
createdAt: row.createdAt
|
|
145658
146490
|
};
|
|
145659
146491
|
}
|
|
145660
|
-
function
|
|
146492
|
+
function rowToEvent3(row) {
|
|
145661
146493
|
return {
|
|
145662
146494
|
id: row.id,
|
|
145663
146495
|
projectId: row.projectId,
|
|
@@ -145671,7 +146503,7 @@ function rowToEvent2(row) {
|
|
|
145671
146503
|
};
|
|
145672
146504
|
}
|
|
145673
146505
|
function evidenceKey(input) {
|
|
145674
|
-
return
|
|
146506
|
+
return createHash9("sha256").update(JSON.stringify([
|
|
145675
146507
|
input.evidenceKind,
|
|
145676
146508
|
input.evidenceId,
|
|
145677
146509
|
input.relation,
|
|
@@ -145802,7 +146634,7 @@ var init_claim_store = __esm({
|
|
|
145802
146634
|
locator, capturedHash, evidenceKey, createdAt
|
|
145803
146635
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
145804
146636
|
`).run(
|
|
145805
|
-
|
|
146637
|
+
randomUUID12(),
|
|
145806
146638
|
input.claimId,
|
|
145807
146639
|
input.evidenceKind,
|
|
145808
146640
|
input.evidenceId,
|
|
@@ -145824,7 +146656,7 @@ var init_claim_store = __esm({
|
|
|
145824
146656
|
}
|
|
145825
146657
|
recordEvent(input) {
|
|
145826
146658
|
const event = {
|
|
145827
|
-
id:
|
|
146659
|
+
id: randomUUID12(),
|
|
145828
146660
|
...input,
|
|
145829
146661
|
...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
|
|
145830
146662
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -145852,7 +146684,7 @@ var init_claim_store = __esm({
|
|
|
145852
146684
|
SELECT * FROM knowledge_claim_events
|
|
145853
146685
|
WHERE claimId = ?
|
|
145854
146686
|
ORDER BY createdAt ASC, id
|
|
145855
|
-
`).all(claimId).map(
|
|
146687
|
+
`).all(claimId).map(rowToEvent3);
|
|
145856
146688
|
}
|
|
145857
146689
|
};
|
|
145858
146690
|
}
|
|
@@ -145869,7 +146701,7 @@ __export(claims_exports, {
|
|
|
145869
146701
|
supersedeClaim: () => supersedeClaim,
|
|
145870
146702
|
writeClaim: () => writeClaim
|
|
145871
146703
|
});
|
|
145872
|
-
import { createHash as
|
|
146704
|
+
import { createHash as createHash10, randomUUID as randomUUID13 } from "crypto";
|
|
145873
146705
|
function compactText2(value, field) {
|
|
145874
146706
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
145875
146707
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -145881,7 +146713,7 @@ function normalizedTerm(value) {
|
|
|
145881
146713
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
145882
146714
|
}
|
|
145883
146715
|
function hashIdentity(parts) {
|
|
145884
|
-
return
|
|
146716
|
+
return createHash10("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
145885
146717
|
}
|
|
145886
146718
|
function buildClaimIdentity(input) {
|
|
145887
146719
|
const subject = normalizedTerm(input.subject);
|
|
@@ -145955,7 +146787,7 @@ function normalizeClaimInput(input) {
|
|
|
145955
146787
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
145956
146788
|
return {
|
|
145957
146789
|
claim: {
|
|
145958
|
-
id:
|
|
146790
|
+
id: randomUUID13(),
|
|
145959
146791
|
projectId,
|
|
145960
146792
|
subject,
|
|
145961
146793
|
predicate,
|
|
@@ -146122,7 +146954,7 @@ function supersedeClaim(store, input) {
|
|
|
146122
146954
|
});
|
|
146123
146955
|
}
|
|
146124
146956
|
function hashObservation(observation) {
|
|
146125
|
-
return
|
|
146957
|
+
return createHash10("sha256").update(JSON.stringify([
|
|
146126
146958
|
observation.title,
|
|
146127
146959
|
observation.narrative,
|
|
146128
146960
|
observation.facts,
|
|
@@ -146366,11 +147198,11 @@ var init_frontmatter = __esm({
|
|
|
146366
147198
|
});
|
|
146367
147199
|
|
|
146368
147200
|
// src/knowledge/markdown.ts
|
|
146369
|
-
import { createHash as
|
|
147201
|
+
import { createHash as createHash11 } from "crypto";
|
|
146370
147202
|
import { promises as fs10 } from "fs";
|
|
146371
147203
|
import path17 from "path";
|
|
146372
147204
|
function hashContent(content) {
|
|
146373
|
-
return
|
|
147205
|
+
return createHash11("sha256").update(content).digest("hex");
|
|
146374
147206
|
}
|
|
146375
147207
|
function stringField(data, key) {
|
|
146376
147208
|
const value = data[key];
|
|
@@ -146496,11 +147328,11 @@ __export(wiki_exports, {
|
|
|
146496
147328
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
146497
147329
|
readKnowledgePage: () => readKnowledgePage
|
|
146498
147330
|
});
|
|
146499
|
-
import { createHash as
|
|
147331
|
+
import { createHash as createHash12 } from "crypto";
|
|
146500
147332
|
import { promises as fs11 } from "fs";
|
|
146501
147333
|
import path18 from "path";
|
|
146502
147334
|
function hash2(value) {
|
|
146503
|
-
return
|
|
147335
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
146504
147336
|
}
|
|
146505
147337
|
function now() {
|
|
146506
147338
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -147040,7 +147872,7 @@ var init_workflow_sync = __esm({
|
|
|
147040
147872
|
});
|
|
147041
147873
|
|
|
147042
147874
|
// src/knowledge/workflow-store.ts
|
|
147043
|
-
import { randomUUID as
|
|
147875
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
147044
147876
|
function parseJson(value, fallback) {
|
|
147045
147877
|
if (typeof value !== "string" || !value) return fallback;
|
|
147046
147878
|
try {
|
|
@@ -147140,7 +147972,7 @@ var init_workflow_store = __esm({
|
|
|
147140
147972
|
}
|
|
147141
147973
|
recordRun(input) {
|
|
147142
147974
|
const run = {
|
|
147143
|
-
id:
|
|
147975
|
+
id: randomUUID14(),
|
|
147144
147976
|
workflowId: input.workflowId,
|
|
147145
147977
|
projectId: input.projectId,
|
|
147146
147978
|
task: input.task.trim(),
|
|
@@ -147208,7 +148040,7 @@ var init_outcome_types = __esm({
|
|
|
147208
148040
|
});
|
|
147209
148041
|
|
|
147210
148042
|
// src/knowledge/outcome-store.ts
|
|
147211
|
-
import { randomUUID as
|
|
148043
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
147212
148044
|
function optionalText5(value) {
|
|
147213
148045
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
147214
148046
|
}
|
|
@@ -147252,7 +148084,7 @@ var init_outcome_store = __esm({
|
|
|
147252
148084
|
}
|
|
147253
148085
|
record(input) {
|
|
147254
148086
|
const signal = {
|
|
147255
|
-
id:
|
|
148087
|
+
id: randomUUID15(),
|
|
147256
148088
|
projectId: text(input.projectId, "project id"),
|
|
147257
148089
|
candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
|
|
147258
148090
|
candidateId: text(input.candidateId, "candidate id"),
|
|
@@ -147357,11 +148189,11 @@ __export(workflows_exports, {
|
|
|
147357
148189
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
147358
148190
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
147359
148191
|
});
|
|
147360
|
-
import { createHash as
|
|
148192
|
+
import { createHash as createHash13 } from "crypto";
|
|
147361
148193
|
import { promises as fs12 } from "fs";
|
|
147362
148194
|
import path19 from "path";
|
|
147363
148195
|
function hash3(value) {
|
|
147364
|
-
return
|
|
148196
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
147365
148197
|
}
|
|
147366
148198
|
function now2() {
|
|
147367
148199
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -148743,6 +149575,16 @@ async function bindObservationCodeRefsBestEffort(observation) {
|
|
|
148743
149575
|
} catch {
|
|
148744
149576
|
}
|
|
148745
149577
|
}
|
|
149578
|
+
async function persistEvidenceCard(observation) {
|
|
149579
|
+
if (!projectDir) return;
|
|
149580
|
+
try {
|
|
149581
|
+
const evidence = new EvidenceCardStore();
|
|
149582
|
+
await evidence.init(projectDir);
|
|
149583
|
+
evidence.upsertObservation(observation);
|
|
149584
|
+
} catch (error) {
|
|
149585
|
+
console.error(`[memorix] Evidence card projection failed for obs-${observation.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
149586
|
+
}
|
|
149587
|
+
}
|
|
148746
149588
|
function queueClaimDerivation(observation) {
|
|
148747
149589
|
const dataDir = projectDir;
|
|
148748
149590
|
const isExplicit = observation.sourceDetail === "explicit";
|
|
@@ -149089,6 +149931,7 @@ async function storeObservation(input) {
|
|
|
149089
149931
|
}
|
|
149090
149932
|
if (!persistedCallbackInvoked) await input.onPersisted?.(observation);
|
|
149091
149933
|
await bindObservationCodeRefsBestEffort(observation);
|
|
149934
|
+
await persistEvidenceCard(observation);
|
|
149092
149935
|
queueObservationQualification(observation);
|
|
149093
149936
|
if (resolveObservationVisibility(observation) === "project") {
|
|
149094
149937
|
queueClaimDerivation(observation);
|
|
@@ -149181,6 +150024,7 @@ async function upsertObservation(existing, input, now3) {
|
|
|
149181
150024
|
await store.update(existing);
|
|
149182
150025
|
}
|
|
149183
150026
|
await bindObservationCodeRefsBestEffort(existing);
|
|
150027
|
+
await persistEvidenceCard(existing);
|
|
149184
150028
|
queueObservationQualification(existing);
|
|
149185
150029
|
if (resolveObservationVisibility(existing) === "project") {
|
|
149186
150030
|
queueClaimDerivation(existing);
|
|
@@ -149314,6 +150158,7 @@ async function resolveObservations(ids, status = "resolved") {
|
|
|
149314
150158
|
await Promise.all(changed.map((observation) => tx.update(observation)));
|
|
149315
150159
|
});
|
|
149316
150160
|
}
|
|
150161
|
+
for (const observation of changed) await persistEvidenceCard(observation);
|
|
149317
150162
|
return { resolved, notFound };
|
|
149318
150163
|
}
|
|
149319
150164
|
function getProjectObservations(projectId) {
|
|
@@ -149651,6 +150496,7 @@ var init_observations = __esm({
|
|
|
149651
150496
|
init_secret_filter();
|
|
149652
150497
|
init_lifecycle();
|
|
149653
150498
|
init_visibility();
|
|
150499
|
+
init_evidence_store();
|
|
149654
150500
|
observations = [];
|
|
149655
150501
|
nextId = 1;
|
|
149656
150502
|
projectDir = null;
|