memorix 1.7.3 → 1.8.1
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 +41 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/cli/index.js +1488 -270
- package/dist/dashboard/static/app.js +125 -27
- package/dist/dashboard/static/index.html +11 -1
- package/dist/dashboard/static/style.css +86 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +927 -240
- package/dist/maintenance-runner.js +607 -68
- package/dist/media-audio-runner.js +602 -63
- package/dist/media-video-runner.js +607 -68
- package/dist/memcode-runtime/CHANGELOG.md +41 -0
- package/dist/sdk.js +926 -239
- package/dist/types.d.ts +8 -0
- package/dist/vector-backfill-runner.js +607 -68
- 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 +39 -1
- package/docs/ARCHITECTURE.md +3 -1
- package/docs/DASHBOARD.md +16 -0
- package/docs/DEVELOPMENT.md +3 -2
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/README.md +15 -2
- 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/context.ts +11 -0
- package/src/cli/commands/dashboard.ts +1 -1
- package/src/cli/commands/evidence.ts +56 -0
- package/src/cli/commands/feedback.ts +58 -0
- package/src/cli/commands/resume.ts +2 -0
- package/src/cli/commands/serve-http.ts +229 -13
- 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/dashboard/config-provenance.ts +17 -0
- package/src/dashboard/evidence.ts +63 -0
- package/src/dashboard/server.ts +178 -154
- package/src/dashboard/static/index.html +11 -1
- 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/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/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 +125 -5
- package/src/store/evidence-store.ts +261 -0
- package/src/store/sqlite-db.ts +104 -0
- package/src/types.ts +8 -0
package/dist/cli/index.js
CHANGED
|
@@ -3232,7 +3232,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
|
|
|
3232
3232
|
|
|
3233
3233
|
// src/cli/version.ts
|
|
3234
3234
|
function getCliVersion() {
|
|
3235
|
-
return true ? "1.
|
|
3235
|
+
return true ? "1.8.1" : pkg.version;
|
|
3236
3236
|
}
|
|
3237
3237
|
var init_version = __esm({
|
|
3238
3238
|
"src/cli/version.ts"() {
|
|
@@ -9465,7 +9465,7 @@ function closeAllDatabases() {
|
|
|
9465
9465
|
_dbCache.delete(key);
|
|
9466
9466
|
}
|
|
9467
9467
|
}
|
|
9468
|
-
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;
|
|
9468
|
+
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;
|
|
9469
9469
|
var init_sqlite_db = __esm({
|
|
9470
9470
|
"src/store/sqlite-db.ts"() {
|
|
9471
9471
|
"use strict";
|
|
@@ -10111,6 +10111,79 @@ CREATE TABLE IF NOT EXISTS compaction_checkpoints (
|
|
|
10111
10111
|
created_at TEXT NOT NULL,
|
|
10112
10112
|
updated_at TEXT NOT NULL
|
|
10113
10113
|
);
|
|
10114
|
+
`;
|
|
10115
|
+
CREATE_EVIDENCE_CARDS_TABLE = `
|
|
10116
|
+
CREATE TABLE IF NOT EXISTS evidence_cards (
|
|
10117
|
+
id TEXT PRIMARY KEY,
|
|
10118
|
+
project_id TEXT NOT NULL,
|
|
10119
|
+
candidate_kind TEXT NOT NULL,
|
|
10120
|
+
candidate_id TEXT NOT NULL,
|
|
10121
|
+
title TEXT NOT NULL,
|
|
10122
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
10123
|
+
entity_name TEXT,
|
|
10124
|
+
source_kind TEXT NOT NULL,
|
|
10125
|
+
source_ref TEXT NOT NULL,
|
|
10126
|
+
locator TEXT,
|
|
10127
|
+
captured_hash TEXT,
|
|
10128
|
+
session_id TEXT,
|
|
10129
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
10130
|
+
verification TEXT NOT NULL DEFAULT 'unverified',
|
|
10131
|
+
freshness TEXT NOT NULL DEFAULT 'current',
|
|
10132
|
+
stale_reason TEXT,
|
|
10133
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
10134
|
+
related_entities_json TEXT NOT NULL DEFAULT '[]',
|
|
10135
|
+
created_at TEXT NOT NULL,
|
|
10136
|
+
updated_at TEXT NOT NULL,
|
|
10137
|
+
UNIQUE(project_id, candidate_kind, candidate_id)
|
|
10138
|
+
);
|
|
10139
|
+
`;
|
|
10140
|
+
CREATE_EVIDENCE_CARD_EVENTS_TABLE = `
|
|
10141
|
+
CREATE TABLE IF NOT EXISTS evidence_card_events (
|
|
10142
|
+
id TEXT PRIMARY KEY,
|
|
10143
|
+
project_id TEXT NOT NULL,
|
|
10144
|
+
card_id TEXT NOT NULL,
|
|
10145
|
+
kind TEXT NOT NULL,
|
|
10146
|
+
detail TEXT,
|
|
10147
|
+
created_at TEXT NOT NULL,
|
|
10148
|
+
FOREIGN KEY (card_id) REFERENCES evidence_cards(id) ON DELETE CASCADE
|
|
10149
|
+
);
|
|
10150
|
+
`;
|
|
10151
|
+
CREATE_MEMORY_FEEDBACK_STATES_TABLE = `
|
|
10152
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_states (
|
|
10153
|
+
project_id TEXT NOT NULL,
|
|
10154
|
+
candidate_kind TEXT NOT NULL,
|
|
10155
|
+
candidate_id TEXT NOT NULL,
|
|
10156
|
+
weight REAL NOT NULL DEFAULT 1.0,
|
|
10157
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'active',
|
|
10158
|
+
updated_at TEXT NOT NULL,
|
|
10159
|
+
PRIMARY KEY (project_id, candidate_kind, candidate_id)
|
|
10160
|
+
);
|
|
10161
|
+
`;
|
|
10162
|
+
CREATE_MEMORY_FEEDBACK_EVENTS_TABLE = `
|
|
10163
|
+
CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
10164
|
+
id TEXT PRIMARY KEY,
|
|
10165
|
+
project_id TEXT NOT NULL,
|
|
10166
|
+
candidate_kind TEXT NOT NULL,
|
|
10167
|
+
candidate_id TEXT NOT NULL,
|
|
10168
|
+
signal TEXT NOT NULL,
|
|
10169
|
+
actor TEXT,
|
|
10170
|
+
note TEXT,
|
|
10171
|
+
source_ref TEXT NOT NULL,
|
|
10172
|
+
target_event_id TEXT,
|
|
10173
|
+
delta REAL NOT NULL DEFAULT 0,
|
|
10174
|
+
observed_at TEXT NOT NULL
|
|
10175
|
+
);
|
|
10176
|
+
`;
|
|
10177
|
+
CREATE_MCP_BINDINGS_TABLE = `
|
|
10178
|
+
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
10179
|
+
handle_id TEXT PRIMARY KEY,
|
|
10180
|
+
project_id TEXT NOT NULL,
|
|
10181
|
+
project_root TEXT NOT NULL,
|
|
10182
|
+
data_dir TEXT NOT NULL,
|
|
10183
|
+
created_at TEXT NOT NULL,
|
|
10184
|
+
last_used_at TEXT NOT NULL,
|
|
10185
|
+
expires_at TEXT
|
|
10186
|
+
);
|
|
10114
10187
|
`;
|
|
10115
10188
|
CREATE_INDEXES = `
|
|
10116
10189
|
CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
|
|
@@ -10173,6 +10246,12 @@ CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_target
|
|
|
10173
10246
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
|
|
10174
10247
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
|
|
10175
10248
|
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
|
|
10249
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC);
|
|
10250
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id);
|
|
10251
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
10252
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
10253
|
+
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
10254
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
10176
10255
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
10177
10256
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
10178
10257
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -10328,6 +10407,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
10328
10407
|
}
|
|
10329
10408
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_media_jobs_source_asset ON media_jobs(project_id, source_asset_id, status)");
|
|
10330
10409
|
}
|
|
10410
|
+
},
|
|
10411
|
+
{
|
|
10412
|
+
id: "1.8-context-control-plane",
|
|
10413
|
+
apply: (db2) => {
|
|
10414
|
+
db2.exec(CREATE_EVIDENCE_CARDS_TABLE);
|
|
10415
|
+
db2.exec(CREATE_EVIDENCE_CARD_EVENTS_TABLE);
|
|
10416
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_STATES_TABLE);
|
|
10417
|
+
db2.exec(CREATE_MEMORY_FEEDBACK_EVENTS_TABLE);
|
|
10418
|
+
db2.exec(CREATE_MCP_BINDINGS_TABLE);
|
|
10419
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC)");
|
|
10420
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id)");
|
|
10421
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at)");
|
|
10422
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
10423
|
+
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)");
|
|
10424
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
10425
|
+
}
|
|
10331
10426
|
}
|
|
10332
10427
|
];
|
|
10333
10428
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -21514,6 +21609,8 @@ var require_main = __commonJS({
|
|
|
21514
21609
|
var dotenv_loader_exports = {};
|
|
21515
21610
|
__export(dotenv_loader_exports, {
|
|
21516
21611
|
getLoadedEnvFiles: () => getLoadedEnvFiles,
|
|
21612
|
+
getLoadedEnvKeys: () => getLoadedEnvKeys,
|
|
21613
|
+
getLoadedEnvValue: () => getLoadedEnvValue,
|
|
21517
21614
|
loadDotenv: () => loadDotenv,
|
|
21518
21615
|
resetDotenv: () => resetDotenv
|
|
21519
21616
|
});
|
|
@@ -21524,6 +21621,8 @@ function loadEnvFile(filePath) {
|
|
|
21524
21621
|
const parsed = (0, import_dotenv.parse)(readFileSync7(filePath, "utf-8"));
|
|
21525
21622
|
for (const [key, value] of Object.entries(parsed)) {
|
|
21526
21623
|
if (!(key in process.env)) {
|
|
21624
|
+
loadedEnvKeys.add(key);
|
|
21625
|
+
loadedEnvValues.set(key, value);
|
|
21527
21626
|
process.env[key] = value;
|
|
21528
21627
|
injectedKeys.add(key);
|
|
21529
21628
|
}
|
|
@@ -21536,6 +21635,8 @@ function loadDotenv(projectRoot, options = {}) {
|
|
|
21536
21635
|
resetDotenv();
|
|
21537
21636
|
}
|
|
21538
21637
|
loadedEnvFiles.length = 0;
|
|
21638
|
+
loadedEnvKeys.clear();
|
|
21639
|
+
loadedEnvValues.clear();
|
|
21539
21640
|
if (projectRoot) {
|
|
21540
21641
|
loadEnvFile(getProjectDotenvPath(projectRoot));
|
|
21541
21642
|
}
|
|
@@ -21551,11 +21652,18 @@ function resetDotenv() {
|
|
|
21551
21652
|
dotenvLoaded = false;
|
|
21552
21653
|
dotenvProjectRoot = null;
|
|
21553
21654
|
loadedEnvFiles.length = 0;
|
|
21655
|
+
loadedEnvKeys.clear();
|
|
21554
21656
|
}
|
|
21555
21657
|
function getLoadedEnvFiles() {
|
|
21556
21658
|
return loadedEnvFiles;
|
|
21557
21659
|
}
|
|
21558
|
-
|
|
21660
|
+
function getLoadedEnvKeys() {
|
|
21661
|
+
return loadedEnvKeys;
|
|
21662
|
+
}
|
|
21663
|
+
function getLoadedEnvValue(key) {
|
|
21664
|
+
return loadedEnvValues.get(key);
|
|
21665
|
+
}
|
|
21666
|
+
var import_dotenv, dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
|
|
21559
21667
|
var init_dotenv_loader = __esm({
|
|
21560
21668
|
"src/config/dotenv-loader.ts"() {
|
|
21561
21669
|
"use strict";
|
|
@@ -21565,6 +21673,8 @@ var init_dotenv_loader = __esm({
|
|
|
21565
21673
|
dotenvLoaded = false;
|
|
21566
21674
|
dotenvProjectRoot = null;
|
|
21567
21675
|
loadedEnvFiles = [];
|
|
21676
|
+
loadedEnvKeys = /* @__PURE__ */ new Set();
|
|
21677
|
+
loadedEnvValues = /* @__PURE__ */ new Map();
|
|
21568
21678
|
injectedKeys = /* @__PURE__ */ new Set();
|
|
21569
21679
|
}
|
|
21570
21680
|
});
|
|
@@ -26608,6 +26718,234 @@ var init_lifecycle = __esm({
|
|
|
26608
26718
|
}
|
|
26609
26719
|
});
|
|
26610
26720
|
|
|
26721
|
+
// src/store/evidence-store.ts
|
|
26722
|
+
var evidence_store_exports = {};
|
|
26723
|
+
__export(evidence_store_exports, {
|
|
26724
|
+
EvidenceCardStore: () => EvidenceCardStore,
|
|
26725
|
+
buildEvidenceCardId: () => buildEvidenceCardId
|
|
26726
|
+
});
|
|
26727
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
26728
|
+
function safeJson(value, fallback) {
|
|
26729
|
+
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
26730
|
+
try {
|
|
26731
|
+
return JSON.parse(value);
|
|
26732
|
+
} catch {
|
|
26733
|
+
return fallback;
|
|
26734
|
+
}
|
|
26735
|
+
}
|
|
26736
|
+
function rowToCard(row) {
|
|
26737
|
+
return {
|
|
26738
|
+
id: String(row.id),
|
|
26739
|
+
projectId: String(row.project_id),
|
|
26740
|
+
candidateKind: row.candidate_kind,
|
|
26741
|
+
candidateId: String(row.candidate_id),
|
|
26742
|
+
title: String(row.title),
|
|
26743
|
+
summary: String(row.summary ?? ""),
|
|
26744
|
+
...row.entity_name ? { entityName: String(row.entity_name) } : {},
|
|
26745
|
+
sourceKind: String(row.source_kind),
|
|
26746
|
+
sourceRef: String(row.source_ref),
|
|
26747
|
+
...row.locator ? { locator: String(row.locator) } : {},
|
|
26748
|
+
...row.captured_hash ? { capturedHash: String(row.captured_hash) } : {},
|
|
26749
|
+
...row.session_id ? { sessionId: String(row.session_id) } : {},
|
|
26750
|
+
status: String(row.status ?? "active"),
|
|
26751
|
+
verification: row.verification,
|
|
26752
|
+
freshness: row.freshness,
|
|
26753
|
+
...row.stale_reason ? { staleReason: String(row.stale_reason) } : {},
|
|
26754
|
+
files: safeJson(row.files_json, []),
|
|
26755
|
+
relatedEntities: safeJson(row.related_entities_json, []),
|
|
26756
|
+
createdAt: String(row.created_at),
|
|
26757
|
+
updatedAt: String(row.updated_at)
|
|
26758
|
+
};
|
|
26759
|
+
}
|
|
26760
|
+
function observationHash(observation) {
|
|
26761
|
+
return createHash3("sha256").update(JSON.stringify({
|
|
26762
|
+
projectId: observation.projectId,
|
|
26763
|
+
id: observation.id,
|
|
26764
|
+
title: observation.title,
|
|
26765
|
+
narrative: observation.narrative,
|
|
26766
|
+
facts: observation.facts,
|
|
26767
|
+
files: observation.filesModified,
|
|
26768
|
+
relatedEntities: observation.relatedEntities
|
|
26769
|
+
})).digest("hex");
|
|
26770
|
+
}
|
|
26771
|
+
function sourceKind(observation) {
|
|
26772
|
+
if (observation.source === "git" || observation.sourceDetail === "git-ingest") return "git";
|
|
26773
|
+
if (observation.sourceDetail === "hook") return "hook";
|
|
26774
|
+
return observation.source ?? "agent";
|
|
26775
|
+
}
|
|
26776
|
+
function buildEvidenceCardId(projectId, candidateKind, candidateId) {
|
|
26777
|
+
return `evidence:${candidateKind}:${projectId}:${candidateId}`;
|
|
26778
|
+
}
|
|
26779
|
+
var EvidenceCardStore;
|
|
26780
|
+
var init_evidence_store = __esm({
|
|
26781
|
+
"src/store/evidence-store.ts"() {
|
|
26782
|
+
"use strict";
|
|
26783
|
+
init_esm_shims();
|
|
26784
|
+
init_sqlite_db();
|
|
26785
|
+
EvidenceCardStore = class {
|
|
26786
|
+
db = null;
|
|
26787
|
+
async init(dataDir) {
|
|
26788
|
+
this.db = getDatabase(dataDir);
|
|
26789
|
+
}
|
|
26790
|
+
requireDb() {
|
|
26791
|
+
if (!this.db) throw new Error("EvidenceCardStore is not initialized.");
|
|
26792
|
+
return this.db;
|
|
26793
|
+
}
|
|
26794
|
+
upsertObservation(observation) {
|
|
26795
|
+
const db2 = this.requireDb();
|
|
26796
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
26797
|
+
const card = {
|
|
26798
|
+
id: `evidence:observation:${observation.projectId}:${observation.id}`,
|
|
26799
|
+
projectId: observation.projectId,
|
|
26800
|
+
candidateKind: "observation",
|
|
26801
|
+
candidateId: String(observation.id),
|
|
26802
|
+
title: observation.title,
|
|
26803
|
+
summary: observation.narrative.slice(0, 500),
|
|
26804
|
+
entityName: observation.entityName,
|
|
26805
|
+
sourceKind: sourceKind(observation),
|
|
26806
|
+
sourceRef: `observation:${observation.id}`,
|
|
26807
|
+
locator: observation.filesModified?.join(", ") || `observation:${observation.id}`,
|
|
26808
|
+
capturedHash: observationHash(observation),
|
|
26809
|
+
...observation.sessionId ? { sessionId: observation.sessionId } : {},
|
|
26810
|
+
status: observation.status ?? "active",
|
|
26811
|
+
verification: observation.status === "resolved" ? "verified" : "unverified",
|
|
26812
|
+
freshness: "current",
|
|
26813
|
+
files: observation.filesModified ?? [],
|
|
26814
|
+
relatedEntities: observation.relatedEntities ?? [],
|
|
26815
|
+
createdAt: observation.createdAt,
|
|
26816
|
+
updatedAt: now3
|
|
26817
|
+
};
|
|
26818
|
+
db2.prepare(`
|
|
26819
|
+
INSERT INTO evidence_cards (
|
|
26820
|
+
id, project_id, candidate_kind, candidate_id, title, summary, entity_name,
|
|
26821
|
+
source_kind, source_ref, locator, captured_hash, session_id, status,
|
|
26822
|
+
verification, freshness, stale_reason, files_json, related_entities_json,
|
|
26823
|
+
created_at, updated_at
|
|
26824
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?)
|
|
26825
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
26826
|
+
title = excluded.title,
|
|
26827
|
+
summary = excluded.summary,
|
|
26828
|
+
entity_name = excluded.entity_name,
|
|
26829
|
+
source_kind = excluded.source_kind,
|
|
26830
|
+
source_ref = excluded.source_ref,
|
|
26831
|
+
locator = excluded.locator,
|
|
26832
|
+
captured_hash = excluded.captured_hash,
|
|
26833
|
+
session_id = excluded.session_id,
|
|
26834
|
+
status = excluded.status,
|
|
26835
|
+
freshness = 'current',
|
|
26836
|
+
stale_reason = NULL,
|
|
26837
|
+
files_json = excluded.files_json,
|
|
26838
|
+
related_entities_json = excluded.related_entities_json,
|
|
26839
|
+
updated_at = excluded.updated_at
|
|
26840
|
+
`).run(
|
|
26841
|
+
card.id,
|
|
26842
|
+
card.projectId,
|
|
26843
|
+
card.candidateKind,
|
|
26844
|
+
card.candidateId,
|
|
26845
|
+
card.title,
|
|
26846
|
+
card.summary,
|
|
26847
|
+
card.entityName ?? null,
|
|
26848
|
+
card.sourceKind,
|
|
26849
|
+
card.sourceRef,
|
|
26850
|
+
card.locator ?? null,
|
|
26851
|
+
card.capturedHash ?? null,
|
|
26852
|
+
card.sessionId ?? null,
|
|
26853
|
+
card.status,
|
|
26854
|
+
card.verification,
|
|
26855
|
+
card.freshness,
|
|
26856
|
+
JSON.stringify(card.files),
|
|
26857
|
+
JSON.stringify(card.relatedEntities),
|
|
26858
|
+
card.createdAt,
|
|
26859
|
+
card.updatedAt
|
|
26860
|
+
);
|
|
26861
|
+
return this.get(card.projectId, card.candidateKind, card.candidateId) ?? card;
|
|
26862
|
+
}
|
|
26863
|
+
get(projectId, candidateKind, candidateId) {
|
|
26864
|
+
const row = this.requireDb().prepare(`
|
|
26865
|
+
SELECT * FROM evidence_cards WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
26866
|
+
`).get(projectId, candidateKind, candidateId);
|
|
26867
|
+
return row ? rowToCard(row) : void 0;
|
|
26868
|
+
}
|
|
26869
|
+
list(projectId, options = {}) {
|
|
26870
|
+
const limit2 = Math.min(100, Math.max(1, Math.floor(options.limit ?? 20)));
|
|
26871
|
+
const clauses = ["project_id = ?"];
|
|
26872
|
+
const args = [projectId];
|
|
26873
|
+
if (options.freshness) {
|
|
26874
|
+
clauses.push("freshness = ?");
|
|
26875
|
+
args.push(options.freshness);
|
|
26876
|
+
}
|
|
26877
|
+
if (options.status) {
|
|
26878
|
+
clauses.push("status = ?");
|
|
26879
|
+
args.push(options.status);
|
|
26880
|
+
}
|
|
26881
|
+
args.push(limit2);
|
|
26882
|
+
const rows = this.requireDb().prepare(`
|
|
26883
|
+
SELECT * FROM evidence_cards WHERE ${clauses.join(" AND ")} ORDER BY updated_at DESC, id DESC LIMIT ?
|
|
26884
|
+
`).all(...args);
|
|
26885
|
+
return rows.map(rowToCard);
|
|
26886
|
+
}
|
|
26887
|
+
syncObservations(observations2) {
|
|
26888
|
+
return observations2.map((observation) => this.upsertObservation(observation));
|
|
26889
|
+
}
|
|
26890
|
+
markStaleForPaths(projectId, paths, reason = "source file changed") {
|
|
26891
|
+
const normalized = new Set(paths.map((value) => value.replace(/\\/g, "/").toLowerCase()));
|
|
26892
|
+
if (normalized.size === 0) return 0;
|
|
26893
|
+
const db2 = this.requireDb();
|
|
26894
|
+
const rows = db2.prepare(`SELECT * FROM evidence_cards WHERE project_id = ? AND freshness != 'stale'`).all(projectId);
|
|
26895
|
+
const update2 = db2.prepare(`
|
|
26896
|
+
UPDATE evidence_cards SET freshness = 'stale', stale_reason = ?, updated_at = ?
|
|
26897
|
+
WHERE id = ?
|
|
26898
|
+
`);
|
|
26899
|
+
let changed = 0;
|
|
26900
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
26901
|
+
const run = db2.transaction(() => {
|
|
26902
|
+
for (const row of rows) {
|
|
26903
|
+
const files = safeJson(row.files_json, []);
|
|
26904
|
+
if (!files.some((file2) => normalized.has(file2.replace(/\\/g, "/").toLowerCase()))) continue;
|
|
26905
|
+
update2.run(reason, now3, row.id);
|
|
26906
|
+
changed++;
|
|
26907
|
+
}
|
|
26908
|
+
});
|
|
26909
|
+
run();
|
|
26910
|
+
return changed;
|
|
26911
|
+
}
|
|
26912
|
+
setVerification(projectId, cardId, verification) {
|
|
26913
|
+
this.requireDb().prepare(`
|
|
26914
|
+
UPDATE evidence_cards SET verification = ?, updated_at = ? WHERE project_id = ? AND id = ?
|
|
26915
|
+
`).run(verification, (/* @__PURE__ */ new Date()).toISOString(), projectId, cardId);
|
|
26916
|
+
}
|
|
26917
|
+
recordEvent(projectId, cardId, kind, detail) {
|
|
26918
|
+
const event = {
|
|
26919
|
+
id: randomUUID3(),
|
|
26920
|
+
projectId,
|
|
26921
|
+
cardId,
|
|
26922
|
+
kind,
|
|
26923
|
+
...detail ? { detail: detail.slice(0, 2e3) } : {},
|
|
26924
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26925
|
+
};
|
|
26926
|
+
this.requireDb().prepare(`
|
|
26927
|
+
INSERT INTO evidence_card_events (id, project_id, card_id, kind, detail, created_at)
|
|
26928
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
26929
|
+
`).run(event.id, event.projectId, event.cardId, event.kind, event.detail ?? null, event.createdAt);
|
|
26930
|
+
return event;
|
|
26931
|
+
}
|
|
26932
|
+
listEvents(cardId, limit2 = 50) {
|
|
26933
|
+
const rows = this.requireDb().prepare(`
|
|
26934
|
+
SELECT * FROM evidence_card_events WHERE card_id = ? ORDER BY created_at DESC LIMIT ?
|
|
26935
|
+
`).all(cardId, Math.min(200, Math.max(1, Math.floor(limit2))));
|
|
26936
|
+
return rows.map((row) => ({
|
|
26937
|
+
id: String(row.id),
|
|
26938
|
+
projectId: String(row.project_id),
|
|
26939
|
+
cardId: String(row.card_id),
|
|
26940
|
+
kind: String(row.kind),
|
|
26941
|
+
...row.detail ? { detail: String(row.detail) } : {},
|
|
26942
|
+
createdAt: String(row.created_at)
|
|
26943
|
+
}));
|
|
26944
|
+
}
|
|
26945
|
+
};
|
|
26946
|
+
}
|
|
26947
|
+
});
|
|
26948
|
+
|
|
26611
26949
|
// src/runtime/isolated-maintenance.ts
|
|
26612
26950
|
import { spawn } from "child_process";
|
|
26613
26951
|
import { existsSync as existsSync10 } from "fs";
|
|
@@ -26769,7 +27107,7 @@ var workspace_store_exports = {};
|
|
|
26769
27107
|
__export(workspace_store_exports, {
|
|
26770
27108
|
KnowledgeWorkspaceStore: () => KnowledgeWorkspaceStore
|
|
26771
27109
|
});
|
|
26772
|
-
import { randomUUID as
|
|
27110
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
26773
27111
|
function arrayValue(raw) {
|
|
26774
27112
|
if (typeof raw !== "string" || !raw) return [];
|
|
26775
27113
|
try {
|
|
@@ -26910,7 +27248,7 @@ var init_workspace_store = __esm({
|
|
|
26910
27248
|
}
|
|
26911
27249
|
createProposal(input) {
|
|
26912
27250
|
const proposal = {
|
|
26913
|
-
id: input.id ??
|
|
27251
|
+
id: input.id ?? randomUUID4(),
|
|
26914
27252
|
...input,
|
|
26915
27253
|
status: input.status ?? "pending",
|
|
26916
27254
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -26963,13 +27301,13 @@ __export(workspace_exports, {
|
|
|
26963
27301
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
26964
27302
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
26965
27303
|
});
|
|
26966
|
-
import { createHash as
|
|
27304
|
+
import { createHash as createHash4 } from "crypto";
|
|
26967
27305
|
import { execFile } from "child_process";
|
|
26968
27306
|
import { promises as fs8 } from "fs";
|
|
26969
27307
|
import path12 from "path";
|
|
26970
27308
|
import { promisify } from "util";
|
|
26971
27309
|
function hash(value) {
|
|
26972
|
-
return
|
|
27310
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
26973
27311
|
}
|
|
26974
27312
|
function workspaceId(projectId, mode) {
|
|
26975
27313
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -27569,7 +27907,7 @@ var media_store_exports = {};
|
|
|
27569
27907
|
__export(media_store_exports, {
|
|
27570
27908
|
MediaStore: () => MediaStore
|
|
27571
27909
|
});
|
|
27572
|
-
import { randomUUID as
|
|
27910
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
27573
27911
|
function asOptionalText(value) {
|
|
27574
27912
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
27575
27913
|
}
|
|
@@ -27739,7 +28077,7 @@ var init_media_store = __esm({
|
|
|
27739
28077
|
return { asset: this.getAsset(input.projectId, existing.id), deduplicated: true };
|
|
27740
28078
|
}
|
|
27741
28079
|
const asset = {
|
|
27742
|
-
id:
|
|
28080
|
+
id: randomUUID5(),
|
|
27743
28081
|
...input,
|
|
27744
28082
|
createdAt: now3,
|
|
27745
28083
|
updatedAt: now3
|
|
@@ -27819,7 +28157,7 @@ var init_media_store = __esm({
|
|
|
27819
28157
|
`).get(input.assetId, input.observationId ?? null, input.role);
|
|
27820
28158
|
if (existing) return rowToLink(existing);
|
|
27821
28159
|
const link = {
|
|
27822
|
-
id:
|
|
28160
|
+
id: randomUUID5(),
|
|
27823
28161
|
assetId: input.assetId,
|
|
27824
28162
|
projectId: input.projectId,
|
|
27825
28163
|
...input.observationId !== void 0 ? { observationId: input.observationId } : {},
|
|
@@ -27858,7 +28196,7 @@ var init_media_store = __esm({
|
|
|
27858
28196
|
return rowToDerivation(this.db.prepare("SELECT * FROM media_derivations WHERE id = ?").get(existing.id));
|
|
27859
28197
|
}
|
|
27860
28198
|
const derivation = {
|
|
27861
|
-
id:
|
|
28199
|
+
id: randomUUID5(),
|
|
27862
28200
|
...input,
|
|
27863
28201
|
content,
|
|
27864
28202
|
...error40 ? { error: error40 } : {},
|
|
@@ -27945,7 +28283,7 @@ var init_media_store = __esm({
|
|
|
27945
28283
|
createJob(input) {
|
|
27946
28284
|
const now3 = Date.now();
|
|
27947
28285
|
const job = {
|
|
27948
|
-
id:
|
|
28286
|
+
id: randomUUID5(),
|
|
27949
28287
|
projectId: input.projectId,
|
|
27950
28288
|
kind: input.kind,
|
|
27951
28289
|
status: "queued",
|
|
@@ -28121,14 +28459,14 @@ __export(asset_store_exports, {
|
|
|
28121
28459
|
readMediaAsset: () => readMediaAsset,
|
|
28122
28460
|
removeMediaAsset: () => removeMediaAsset
|
|
28123
28461
|
});
|
|
28124
|
-
import { createHash as
|
|
28462
|
+
import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
|
|
28125
28463
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
28126
28464
|
import path13 from "path";
|
|
28127
28465
|
function mediaRoot(dataDir) {
|
|
28128
28466
|
return path13.resolve(dataDir, "media");
|
|
28129
28467
|
}
|
|
28130
28468
|
function projectStorageKey(projectId) {
|
|
28131
|
-
return
|
|
28469
|
+
return createHash5("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
28132
28470
|
}
|
|
28133
28471
|
function validateUnderRoot(root, candidate2) {
|
|
28134
28472
|
const resolved = path13.resolve(candidate2);
|
|
@@ -28188,14 +28526,14 @@ async function readHeader(filePath, bytes = 32) {
|
|
|
28188
28526
|
}
|
|
28189
28527
|
async function sha256File(filePath) {
|
|
28190
28528
|
const bytes = await readFile3(filePath);
|
|
28191
|
-
return
|
|
28529
|
+
return createHash5("sha256").update(bytes).digest("hex");
|
|
28192
28530
|
}
|
|
28193
28531
|
function destinationFor(root, projectId, sha2562, extension3) {
|
|
28194
28532
|
const relative3 = path13.join("assets", projectStorageKey(projectId), sha2562.slice(0, 2), `${sha2562}${extension3}`);
|
|
28195
28533
|
return { relative: relative3, absolute: validateUnderRoot(root, path13.join(root, relative3)) };
|
|
28196
28534
|
}
|
|
28197
28535
|
function deletionStagingPath(root, assetId) {
|
|
28198
|
-
return validateUnderRoot(root, path13.join(root, ".trash", `${assetId}.${
|
|
28536
|
+
return validateUnderRoot(root, path13.join(root, ".trash", `${assetId}.${randomUUID6()}.pending-delete`));
|
|
28199
28537
|
}
|
|
28200
28538
|
async function destinationExists(destination) {
|
|
28201
28539
|
try {
|
|
@@ -28209,7 +28547,7 @@ async function destinationExists(destination) {
|
|
|
28209
28547
|
async function persistFile(source, destination) {
|
|
28210
28548
|
await mkdir3(path13.dirname(destination), { recursive: true });
|
|
28211
28549
|
if (await destinationExists(destination)) return false;
|
|
28212
|
-
const temporary = `${destination}.${
|
|
28550
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
28213
28551
|
try {
|
|
28214
28552
|
await copyFile(source, temporary);
|
|
28215
28553
|
await rename2(temporary, destination);
|
|
@@ -28225,7 +28563,7 @@ async function persistFile(source, destination) {
|
|
|
28225
28563
|
async function persistBuffer(bytes, destination) {
|
|
28226
28564
|
await mkdir3(path13.dirname(destination), { recursive: true });
|
|
28227
28565
|
if (await destinationExists(destination)) return false;
|
|
28228
|
-
const temporary = `${destination}.${
|
|
28566
|
+
const temporary = `${destination}.${randomUUID6()}.tmp`;
|
|
28229
28567
|
try {
|
|
28230
28568
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
28231
28569
|
await rename2(temporary, destination);
|
|
@@ -28294,7 +28632,7 @@ async function importMediaBuffer(input) {
|
|
|
28294
28632
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
28295
28633
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
28296
28634
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
28297
|
-
const sha2562 =
|
|
28635
|
+
const sha2562 = createHash5("sha256").update(input.bytes).digest("hex");
|
|
28298
28636
|
return importKnownMedia({
|
|
28299
28637
|
dataDir: input.dataDir,
|
|
28300
28638
|
projectId: input.projectId,
|
|
@@ -28312,7 +28650,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
28312
28650
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
28313
28651
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
28314
28652
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
28315
|
-
const sha2562 =
|
|
28653
|
+
const sha2562 = createHash5("sha256").update(bytes).digest("hex");
|
|
28316
28654
|
if (sha2562 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
28317
28655
|
return bytes;
|
|
28318
28656
|
}
|
|
@@ -81182,7 +81520,7 @@ var require_gaxios = __commonJS({
|
|
|
81182
81520
|
var retry_js_1 = require_retry3();
|
|
81183
81521
|
var stream_1 = __require("stream");
|
|
81184
81522
|
var interceptor_js_1 = require_interceptor();
|
|
81185
|
-
var
|
|
81523
|
+
var randomUUID20 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
81186
81524
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
81187
81525
|
var Gaxios = class {
|
|
81188
81526
|
agentCache = /* @__PURE__ */ new Map();
|
|
@@ -81455,7 +81793,7 @@ var require_gaxios = __commonJS({
|
|
|
81455
81793
|
*/
|
|
81456
81794
|
["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
81457
81795
|
if (opts.multipart?.length) {
|
|
81458
|
-
const boundary = await
|
|
81796
|
+
const boundary = await randomUUID20();
|
|
81459
81797
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
81460
81798
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
81461
81799
|
} else if (shouldDirectlyPassData) {
|
|
@@ -93682,7 +94020,7 @@ var require_websocket = __commonJS({
|
|
|
93682
94020
|
var http3 = __require("http");
|
|
93683
94021
|
var net = __require("net");
|
|
93684
94022
|
var tls = __require("tls");
|
|
93685
|
-
var { randomBytes: randomBytes3, createHash:
|
|
94023
|
+
var { randomBytes: randomBytes3, createHash: createHash22 } = __require("crypto");
|
|
93686
94024
|
var { Duplex, Readable: Readable3 } = __require("stream");
|
|
93687
94025
|
var { URL: URL2 } = __require("url");
|
|
93688
94026
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -94350,7 +94688,7 @@ var require_websocket = __commonJS({
|
|
|
94350
94688
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
94351
94689
|
return;
|
|
94352
94690
|
}
|
|
94353
|
-
const digest2 =
|
|
94691
|
+
const digest2 = createHash22("sha1").update(key + GUID).digest("base64");
|
|
94354
94692
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
94355
94693
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
94356
94694
|
return;
|
|
@@ -94722,7 +95060,7 @@ var require_websocket_server = __commonJS({
|
|
|
94722
95060
|
var EventEmitter2 = __require("events");
|
|
94723
95061
|
var http3 = __require("http");
|
|
94724
95062
|
var { Duplex } = __require("stream");
|
|
94725
|
-
var { createHash:
|
|
95063
|
+
var { createHash: createHash22 } = __require("crypto");
|
|
94726
95064
|
var extension3 = require_extension();
|
|
94727
95065
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
94728
95066
|
var subprotocol2 = require_subprotocol();
|
|
@@ -95029,7 +95367,7 @@ var require_websocket_server = __commonJS({
|
|
|
95029
95367
|
);
|
|
95030
95368
|
}
|
|
95031
95369
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
95032
|
-
const digest2 =
|
|
95370
|
+
const digest2 = createHash22("sha1").update(key + GUID).digest("base64");
|
|
95033
95371
|
const headers = [
|
|
95034
95372
|
"HTTP/1.1 101 Switching Protocols",
|
|
95035
95373
|
"Upgrade: websocket",
|
|
@@ -168432,8 +168770,8 @@ var init_session_resources = __esm({
|
|
|
168432
168770
|
});
|
|
168433
168771
|
|
|
168434
168772
|
// packages/ai/dist/utils/abort-signals.js
|
|
168435
|
-
function combineAbortSignals(
|
|
168436
|
-
const activeSignals =
|
|
168773
|
+
function combineAbortSignals(signals2) {
|
|
168774
|
+
const activeSignals = signals2.filter((signal) => signal !== void 0);
|
|
168437
168775
|
if (activeSignals.length === 0) {
|
|
168438
168776
|
return { cleanup: () => {
|
|
168439
168777
|
} };
|
|
@@ -178146,6 +178484,186 @@ var init_audio_jobs = __esm({
|
|
|
178146
178484
|
}
|
|
178147
178485
|
});
|
|
178148
178486
|
|
|
178487
|
+
// src/memory/feedback-model.ts
|
|
178488
|
+
function feedbackWeightMultiplier(weight) {
|
|
178489
|
+
return Math.max(0.35, Math.min(1.4, 0.35 + Math.max(0, Math.min(2, weight)) * 0.525));
|
|
178490
|
+
}
|
|
178491
|
+
var init_feedback_model = __esm({
|
|
178492
|
+
"src/memory/feedback-model.ts"() {
|
|
178493
|
+
"use strict";
|
|
178494
|
+
init_esm_shims();
|
|
178495
|
+
}
|
|
178496
|
+
});
|
|
178497
|
+
|
|
178498
|
+
// src/memory/feedback.ts
|
|
178499
|
+
var feedback_exports = {};
|
|
178500
|
+
__export(feedback_exports, {
|
|
178501
|
+
FEEDBACK_DELTAS: () => FEEDBACK_DELTAS,
|
|
178502
|
+
MemoryFeedbackStore: () => MemoryFeedbackStore,
|
|
178503
|
+
applyMemoryFeedback: () => applyMemoryFeedback,
|
|
178504
|
+
feedbackWeightMultiplier: () => feedbackWeightMultiplier
|
|
178505
|
+
});
|
|
178506
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
178507
|
+
function applyMemoryFeedback(current, event) {
|
|
178508
|
+
const delta = event.signal === "revoke" ? 0 : FEEDBACK_DELTAS[event.signal];
|
|
178509
|
+
const weight = Math.max(0, Math.min(2, current.weight + delta));
|
|
178510
|
+
const status = (event.signal === "code-conflict" || event.signal === "user-correction" || event.signal === "weaken") && weight < 0.5 ? "archived" : current.status;
|
|
178511
|
+
return { weight, status, audit: [...current.audit, { ...event }] };
|
|
178512
|
+
}
|
|
178513
|
+
function rowToEvent(row) {
|
|
178514
|
+
return {
|
|
178515
|
+
id: String(row.id),
|
|
178516
|
+
projectId: String(row.project_id),
|
|
178517
|
+
candidateKind: row.candidate_kind,
|
|
178518
|
+
candidateId: String(row.candidate_id),
|
|
178519
|
+
signal: row.signal,
|
|
178520
|
+
...row.observed_at ? { at: String(row.observed_at) } : { at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
178521
|
+
...row.actor ? { actor: String(row.actor) } : {},
|
|
178522
|
+
...row.note ? { note: String(row.note) } : {},
|
|
178523
|
+
...row.source_ref ? { sourceRef: String(row.source_ref) } : {},
|
|
178524
|
+
...row.target_event_id ? { targetEventId: String(row.target_event_id) } : {},
|
|
178525
|
+
delta: Number(row.delta ?? 0)
|
|
178526
|
+
};
|
|
178527
|
+
}
|
|
178528
|
+
var FEEDBACK_DELTAS, MemoryFeedbackStore;
|
|
178529
|
+
var init_feedback = __esm({
|
|
178530
|
+
"src/memory/feedback.ts"() {
|
|
178531
|
+
"use strict";
|
|
178532
|
+
init_esm_shims();
|
|
178533
|
+
init_sqlite_db();
|
|
178534
|
+
init_feedback_model();
|
|
178535
|
+
FEEDBACK_DELTAS = {
|
|
178536
|
+
"user-correction": -0.35,
|
|
178537
|
+
"verification-success": 0.25,
|
|
178538
|
+
"verification-failure": -0.25,
|
|
178539
|
+
"code-change": -0.15,
|
|
178540
|
+
used: 0.1,
|
|
178541
|
+
"not-used": -0.05,
|
|
178542
|
+
"code-conflict": -0.4,
|
|
178543
|
+
strengthen: 0.2,
|
|
178544
|
+
weaken: -0.2
|
|
178545
|
+
};
|
|
178546
|
+
MemoryFeedbackStore = class {
|
|
178547
|
+
db = null;
|
|
178548
|
+
async init(dataDir) {
|
|
178549
|
+
this.db = getDatabase(dataDir);
|
|
178550
|
+
}
|
|
178551
|
+
requireDb() {
|
|
178552
|
+
if (!this.db) throw new Error("MemoryFeedbackStore is not initialized.");
|
|
178553
|
+
return this.db;
|
|
178554
|
+
}
|
|
178555
|
+
loadEvents(projectId, candidateKind, candidateId) {
|
|
178556
|
+
return this.requireDb().prepare(`
|
|
178557
|
+
SELECT * FROM memory_feedback_events
|
|
178558
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
178559
|
+
ORDER BY observed_at ASC, rowid ASC
|
|
178560
|
+
`).all(projectId, candidateKind, candidateId).map(rowToEvent);
|
|
178561
|
+
}
|
|
178562
|
+
rebuild(projectId, candidateKind, candidateId) {
|
|
178563
|
+
const events = this.loadEvents(projectId, candidateKind, candidateId);
|
|
178564
|
+
const revoked = new Set(events.filter((event) => event.signal === "revoke" && event.targetEventId).map((event) => event.targetEventId));
|
|
178565
|
+
let state = { weight: 1, status: "active", audit: [] };
|
|
178566
|
+
for (const event of events) {
|
|
178567
|
+
if (event.signal === "revoke" || revoked.has(event.id)) {
|
|
178568
|
+
state.audit.push(event);
|
|
178569
|
+
continue;
|
|
178570
|
+
}
|
|
178571
|
+
state = applyMemoryFeedback(state, event);
|
|
178572
|
+
}
|
|
178573
|
+
this.requireDb().prepare(`
|
|
178574
|
+
INSERT INTO memory_feedback_states (project_id, candidate_kind, candidate_id, weight, lifecycle_status, updated_at)
|
|
178575
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
178576
|
+
ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
|
|
178577
|
+
weight = excluded.weight, lifecycle_status = excluded.lifecycle_status, updated_at = excluded.updated_at
|
|
178578
|
+
`).run(projectId, candidateKind, candidateId, state.weight, state.status, (/* @__PURE__ */ new Date()).toISOString());
|
|
178579
|
+
return state;
|
|
178580
|
+
}
|
|
178581
|
+
getState(projectId, candidateKind, candidateId) {
|
|
178582
|
+
const row = this.requireDb().prepare(`
|
|
178583
|
+
SELECT weight, lifecycle_status FROM memory_feedback_states
|
|
178584
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
178585
|
+
`).get(projectId, candidateKind, candidateId);
|
|
178586
|
+
if (!row) return { weight: 1, status: "active", audit: [] };
|
|
178587
|
+
return {
|
|
178588
|
+
weight: Number(row.weight ?? 1),
|
|
178589
|
+
status: row.lifecycle_status ?? "active",
|
|
178590
|
+
audit: this.loadEvents(projectId, candidateKind, candidateId)
|
|
178591
|
+
};
|
|
178592
|
+
}
|
|
178593
|
+
listStates(projectId, candidateKind = "observation") {
|
|
178594
|
+
return this.requireDb().prepare(`
|
|
178595
|
+
SELECT candidate_id, weight, lifecycle_status, updated_at
|
|
178596
|
+
FROM memory_feedback_states WHERE project_id = ? AND candidate_kind = ?
|
|
178597
|
+
ORDER BY updated_at DESC
|
|
178598
|
+
`).all(projectId, candidateKind).map((row) => ({
|
|
178599
|
+
candidateId: String(row.candidate_id),
|
|
178600
|
+
weight: Number(row.weight),
|
|
178601
|
+
status: row.lifecycle_status,
|
|
178602
|
+
updatedAt: String(row.updated_at)
|
|
178603
|
+
}));
|
|
178604
|
+
}
|
|
178605
|
+
weights(projectId, candidateKind = "observation") {
|
|
178606
|
+
const states = /* @__PURE__ */ new Map();
|
|
178607
|
+
for (const row of this.listStates(projectId, candidateKind)) {
|
|
178608
|
+
states.set(row.candidateId, this.getState(projectId, candidateKind, row.candidateId));
|
|
178609
|
+
}
|
|
178610
|
+
return states;
|
|
178611
|
+
}
|
|
178612
|
+
record(input) {
|
|
178613
|
+
if (input.signal === "revoke" && !input.targetEventId) {
|
|
178614
|
+
throw new Error("A revoke feedback event requires targetEventId.");
|
|
178615
|
+
}
|
|
178616
|
+
if (input.signal === "revoke") {
|
|
178617
|
+
const target = this.requireDb().prepare(`
|
|
178618
|
+
SELECT 1 FROM memory_feedback_events
|
|
178619
|
+
WHERE id = ? AND project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
178620
|
+
`).get(input.targetEventId, input.projectId, input.candidateKind, input.candidateId);
|
|
178621
|
+
if (!target) throw new Error("The feedback event to revoke was not found in the same candidate scope.");
|
|
178622
|
+
}
|
|
178623
|
+
const event = {
|
|
178624
|
+
id: randomUUID7(),
|
|
178625
|
+
projectId: input.projectId,
|
|
178626
|
+
candidateKind: input.candidateKind,
|
|
178627
|
+
candidateId: input.candidateId,
|
|
178628
|
+
signal: input.signal,
|
|
178629
|
+
sourceRef: input.sourceRef,
|
|
178630
|
+
...input.actor ? { actor: input.actor } : {},
|
|
178631
|
+
...input.note ? { note: input.note.slice(0, 2e3) } : {},
|
|
178632
|
+
...input.targetEventId ? { targetEventId: input.targetEventId } : {},
|
|
178633
|
+
at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
178634
|
+
delta: input.signal === "revoke" ? 0 : FEEDBACK_DELTAS[input.signal]
|
|
178635
|
+
};
|
|
178636
|
+
this.requireDb().prepare(`
|
|
178637
|
+
INSERT INTO memory_feedback_events (
|
|
178638
|
+
id, project_id, candidate_kind, candidate_id, signal, actor, note,
|
|
178639
|
+
source_ref, target_event_id, delta, observed_at
|
|
178640
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
178641
|
+
`).run(
|
|
178642
|
+
event.id,
|
|
178643
|
+
event.projectId,
|
|
178644
|
+
event.candidateKind,
|
|
178645
|
+
event.candidateId,
|
|
178646
|
+
event.signal,
|
|
178647
|
+
event.actor ?? null,
|
|
178648
|
+
event.note ?? null,
|
|
178649
|
+
event.sourceRef,
|
|
178650
|
+
event.targetEventId ?? null,
|
|
178651
|
+
event.delta,
|
|
178652
|
+
event.at
|
|
178653
|
+
);
|
|
178654
|
+
return { event, state: this.rebuild(input.projectId, input.candidateKind, input.candidateId) };
|
|
178655
|
+
}
|
|
178656
|
+
audit(projectId, candidateKind, candidateId, limit2 = 100) {
|
|
178657
|
+
return this.requireDb().prepare(`
|
|
178658
|
+
SELECT * FROM memory_feedback_events
|
|
178659
|
+
WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
|
|
178660
|
+
ORDER BY observed_at DESC, rowid DESC LIMIT ?
|
|
178661
|
+
`).all(projectId, candidateKind, candidateId, Math.min(200, Math.max(1, Math.floor(limit2)))).map(rowToEvent);
|
|
178662
|
+
}
|
|
178663
|
+
};
|
|
178664
|
+
}
|
|
178665
|
+
});
|
|
178666
|
+
|
|
178149
178667
|
// src/memory/retention.ts
|
|
178150
178668
|
var retention_exports = {};
|
|
178151
178669
|
__export(retention_exports, {
|
|
@@ -178187,6 +178705,7 @@ function getEffectiveRetentionDays(doc) {
|
|
|
178187
178705
|
}
|
|
178188
178706
|
function isImmune(doc) {
|
|
178189
178707
|
if (doc.type === "probe") return false;
|
|
178708
|
+
if (doc.feedbackStatus === "archived") return false;
|
|
178190
178709
|
if (doc.admissionState === "candidate" || doc.admissionState === "ephemeral") return false;
|
|
178191
178710
|
if (doc.valueCategory === "core") return true;
|
|
178192
178711
|
const importance = getImportanceLevel(doc);
|
|
@@ -178219,7 +178738,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
178219
178738
|
const decayFactor = Math.exp(-ageDays / retention);
|
|
178220
178739
|
const accessCount = doc.accessCount ?? 0;
|
|
178221
178740
|
const accessBoost = Math.min(2, 1 + 0.1 * accessCount);
|
|
178222
|
-
|
|
178741
|
+
const feedbackMultiplier = doc.feedbackWeight === void 0 ? 1 : feedbackWeightMultiplier(doc.feedbackWeight);
|
|
178742
|
+
let totalScore = base * decayFactor * accessBoost * feedbackMultiplier;
|
|
178223
178743
|
const immune = isImmune(doc);
|
|
178224
178744
|
if (immune) {
|
|
178225
178745
|
totalScore = Math.max(totalScore, 0.5);
|
|
@@ -178231,7 +178751,8 @@ function calculateRelevance(doc, referenceTime) {
|
|
|
178231
178751
|
decayFactor,
|
|
178232
178752
|
accessBoost,
|
|
178233
178753
|
ageDays,
|
|
178234
|
-
isImmune: immune
|
|
178754
|
+
isImmune: immune,
|
|
178755
|
+
feedbackMultiplier
|
|
178235
178756
|
};
|
|
178236
178757
|
}
|
|
178237
178758
|
function rankByRelevance(docs, referenceTime) {
|
|
@@ -178239,6 +178760,7 @@ function rankByRelevance(docs, referenceTime) {
|
|
|
178239
178760
|
}
|
|
178240
178761
|
function getRetentionZone(doc, referenceTime) {
|
|
178241
178762
|
const now3 = referenceTime ?? /* @__PURE__ */ new Date();
|
|
178763
|
+
if (doc.feedbackStatus === "archived") return "archive-candidate";
|
|
178242
178764
|
const importance = getImportanceLevel(doc);
|
|
178243
178765
|
const retention = getEffectiveRetentionDays(doc);
|
|
178244
178766
|
const createdAt = new Date(doc.createdAt);
|
|
@@ -178310,7 +178832,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
178310
178832
|
summary: parts.join(" ; ")
|
|
178311
178833
|
};
|
|
178312
178834
|
}
|
|
178313
|
-
function toRetentionDocument(obs, accessMap) {
|
|
178835
|
+
function toRetentionDocument(obs, accessMap, feedback) {
|
|
178314
178836
|
const access4 = accessMap?.get(obs.id);
|
|
178315
178837
|
return {
|
|
178316
178838
|
id: `obs-${obs.id}`,
|
|
@@ -178332,11 +178854,12 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
178332
178854
|
sourceDetail: obs.sourceDetail ?? "",
|
|
178333
178855
|
valueCategory: obs.valueCategory ?? "",
|
|
178334
178856
|
admissionState: obs.admissionState ?? "",
|
|
178335
|
-
admissionReason: obs.admissionReason ?? ""
|
|
178857
|
+
admissionReason: obs.admissionReason ?? "",
|
|
178858
|
+
...feedback ? { feedbackWeight: feedback.weight, feedbackStatus: feedback.status } : {}
|
|
178336
178859
|
};
|
|
178337
178860
|
}
|
|
178338
178861
|
function projectObservationRetention(observation, options = {}) {
|
|
178339
|
-
const document2 = toRetentionDocument(observation, options.accessMap);
|
|
178862
|
+
const document2 = toRetentionDocument(observation, options.accessMap, options.feedback);
|
|
178340
178863
|
const relevance = calculateRelevance(document2, options.referenceTime);
|
|
178341
178864
|
const explanation = explainRetention(document2, options.referenceTime);
|
|
178342
178865
|
return {
|
|
@@ -178361,7 +178884,17 @@ function summarizeRetentionProjections(projections) {
|
|
|
178361
178884
|
}
|
|
178362
178885
|
return { active, stale, archiveCandidates, immune };
|
|
178363
178886
|
}
|
|
178364
|
-
async function
|
|
178887
|
+
async function loadFeedbackStore(dataDir) {
|
|
178888
|
+
try {
|
|
178889
|
+
const { MemoryFeedbackStore: MemoryFeedbackStore2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
|
|
178890
|
+
const store2 = new MemoryFeedbackStore2();
|
|
178891
|
+
await store2.init(dataDir);
|
|
178892
|
+
return store2;
|
|
178893
|
+
} catch {
|
|
178894
|
+
return void 0;
|
|
178895
|
+
}
|
|
178896
|
+
}
|
|
178897
|
+
async function archiveExpiredBatch(projectDir2, options) {
|
|
178365
178898
|
const store2 = getObservationStore();
|
|
178366
178899
|
const limit2 = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));
|
|
178367
178900
|
const afterId = Math.max(0, Math.floor(options.afterId ?? 0));
|
|
@@ -178370,11 +178903,13 @@ async function archiveExpiredBatch(_projectDir, options) {
|
|
|
178370
178903
|
afterId,
|
|
178371
178904
|
limit: limit2 + 1
|
|
178372
178905
|
});
|
|
178906
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
178373
178907
|
const hasMore = page.length > limit2;
|
|
178374
178908
|
const scanned = hasMore ? page.slice(0, limit2) : page;
|
|
178375
178909
|
const candidateIds = scanned.filter((observation) => !options.reader || canManageObservation(observation, options.reader)).filter((observation) => projectObservationRetention(observation, {
|
|
178376
178910
|
accessMap: options.accessMap,
|
|
178377
|
-
referenceTime: options.referenceTime
|
|
178911
|
+
referenceTime: options.referenceTime,
|
|
178912
|
+
...feedback ? { feedback: feedback.getState(options.projectId, "observation", String(observation.id)) } : {}
|
|
178378
178913
|
}).zone === "archive-candidate").map((observation) => observation.id);
|
|
178379
178914
|
const archived = candidateIds.length === 0 ? 0 : await store2.atomic(async (tx) => {
|
|
178380
178915
|
const updates = await Promise.all(
|
|
@@ -178405,6 +178940,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
178405
178940
|
const remaining = reader2 ? remainingObservations.filter((observation) => canManageObservation(observation, reader2)).length : remainingObservations.length;
|
|
178406
178941
|
return { archived, remaining };
|
|
178407
178942
|
}
|
|
178943
|
+
const feedback = await loadFeedbackStore(projectDir2);
|
|
178408
178944
|
return await store2.atomic(async (tx) => {
|
|
178409
178945
|
const allObs = await tx.loadAll();
|
|
178410
178946
|
const activeObs = allObs.filter(
|
|
@@ -178412,7 +178948,11 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
|
|
|
178412
178948
|
);
|
|
178413
178949
|
const archivedIds = [];
|
|
178414
178950
|
for (const obs of activeObs) {
|
|
178415
|
-
const retention = projectObservationRetention(obs, {
|
|
178951
|
+
const retention = projectObservationRetention(obs, {
|
|
178952
|
+
accessMap,
|
|
178953
|
+
referenceTime,
|
|
178954
|
+
...feedback ? { feedback: feedback.getState(obs.projectId, "observation", String(obs.id)) } : {}
|
|
178955
|
+
});
|
|
178416
178956
|
if (retention.zone === "archive-candidate") {
|
|
178417
178957
|
archivedIds.push(obs.id);
|
|
178418
178958
|
}
|
|
@@ -178432,6 +178972,7 @@ var init_retention = __esm({
|
|
|
178432
178972
|
init_esm_shims();
|
|
178433
178973
|
init_obs_store();
|
|
178434
178974
|
init_visibility();
|
|
178975
|
+
init_feedback_model();
|
|
178435
178976
|
RETENTION_DAYS = {
|
|
178436
178977
|
critical: 365,
|
|
178437
178978
|
high: 180,
|
|
@@ -178472,7 +179013,7 @@ var owner_exports = {};
|
|
|
178472
179013
|
__export(owner_exports, {
|
|
178473
179014
|
resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
|
|
178474
179015
|
});
|
|
178475
|
-
import { randomUUID as
|
|
179016
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
178476
179017
|
import { promises as fs11 } from "fs";
|
|
178477
179018
|
import path19 from "path";
|
|
178478
179019
|
function ownerPath(dataDir) {
|
|
@@ -178502,7 +179043,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
|
|
|
178502
179043
|
await fs11.mkdir(path19.dirname(filePath), { recursive: true });
|
|
178503
179044
|
const created = {
|
|
178504
179045
|
version: 1,
|
|
178505
|
-
id: "local-" +
|
|
179046
|
+
id: "local-" + randomUUID8(),
|
|
178506
179047
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
178507
179048
|
};
|
|
178508
179049
|
try {
|
|
@@ -178529,7 +179070,7 @@ var long_term_store_exports = {};
|
|
|
178529
179070
|
__export(long_term_store_exports, {
|
|
178530
179071
|
LongTermMemoryStore: () => LongTermMemoryStore
|
|
178531
179072
|
});
|
|
178532
|
-
import { randomUUID as
|
|
179073
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
178533
179074
|
function optionalText2(value) {
|
|
178534
179075
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
178535
179076
|
}
|
|
@@ -178580,7 +179121,7 @@ function rowToEvidence(row) {
|
|
|
178580
179121
|
createdAt: row.createdAt
|
|
178581
179122
|
};
|
|
178582
179123
|
}
|
|
178583
|
-
function
|
|
179124
|
+
function rowToEvent2(row) {
|
|
178584
179125
|
return {
|
|
178585
179126
|
id: row.id,
|
|
178586
179127
|
memoryId: row.memoryId,
|
|
@@ -178689,7 +179230,7 @@ var init_long_term_store = __esm({
|
|
|
178689
179230
|
}
|
|
178690
179231
|
insertEvidence(input) {
|
|
178691
179232
|
const evidence = {
|
|
178692
|
-
id:
|
|
179233
|
+
id: randomUUID9(),
|
|
178693
179234
|
...input,
|
|
178694
179235
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
178695
179236
|
};
|
|
@@ -178716,7 +179257,7 @@ var init_long_term_store = __esm({
|
|
|
178716
179257
|
}
|
|
178717
179258
|
recordEvent(input) {
|
|
178718
179259
|
const event = {
|
|
178719
|
-
id:
|
|
179260
|
+
id: randomUUID9(),
|
|
178720
179261
|
...input,
|
|
178721
179262
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
178722
179263
|
};
|
|
@@ -178737,7 +179278,7 @@ var init_long_term_store = __esm({
|
|
|
178737
179278
|
listEvents(memoryId) {
|
|
178738
179279
|
return this.db.prepare(`
|
|
178739
179280
|
SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
|
|
178740
|
-
`).all(memoryId).map(
|
|
179281
|
+
`).all(memoryId).map(rowToEvent2);
|
|
178741
179282
|
}
|
|
178742
179283
|
markAccess(ids, at2 = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
178743
179284
|
const unique3 = [...new Set(ids.filter(Boolean))];
|
|
@@ -178806,7 +179347,7 @@ __export(long_term_exports, {
|
|
|
178806
179347
|
selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
|
|
178807
179348
|
supersedeLongTermMemory: () => supersedeLongTermMemory
|
|
178808
179349
|
});
|
|
178809
|
-
import { randomUUID as
|
|
179350
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
178810
179351
|
function isOneOf(value, values) {
|
|
178811
179352
|
return typeof value === "string" && values.includes(value);
|
|
178812
179353
|
}
|
|
@@ -178988,7 +179529,7 @@ async function createManualLongTermMemory(input) {
|
|
|
178988
179529
|
const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
|
|
178989
179530
|
if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
|
|
178990
179531
|
assertScope(input.scope);
|
|
178991
|
-
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" +
|
|
179532
|
+
const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID10(), relation: "supports" }];
|
|
178992
179533
|
return createLongTermMemoryWithDataDir({
|
|
178993
179534
|
dataDir: input.dataDir,
|
|
178994
179535
|
originProjectId: input.projectId,
|
|
@@ -179043,7 +179584,7 @@ async function createLongTermMemoryWithDataDir(input) {
|
|
|
179043
179584
|
assertPortableEvidence(input.scope, portability, evidenceInputs);
|
|
179044
179585
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
179045
179586
|
const memory = {
|
|
179046
|
-
id:
|
|
179587
|
+
id: randomUUID10(),
|
|
179047
179588
|
originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
|
|
179048
179589
|
ownerId: compactText(input.ownerId, "owner id", 160),
|
|
179049
179590
|
scope: input.scope,
|
|
@@ -179361,9 +179902,9 @@ var init_long_term = __esm({
|
|
|
179361
179902
|
});
|
|
179362
179903
|
|
|
179363
179904
|
// src/codegraph/ids.ts
|
|
179364
|
-
import { createHash as
|
|
179905
|
+
import { createHash as createHash6 } from "crypto";
|
|
179365
179906
|
function digest(input) {
|
|
179366
|
-
return
|
|
179907
|
+
return createHash6("sha256").update(input).digest("hex").slice(0, 16);
|
|
179367
179908
|
}
|
|
179368
179909
|
function normalizeCodePath(path48) {
|
|
179369
179910
|
return path48.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -179398,7 +179939,7 @@ var store_exports = {};
|
|
|
179398
179939
|
__export(store_exports, {
|
|
179399
179940
|
CodeGraphStore: () => CodeGraphStore
|
|
179400
179941
|
});
|
|
179401
|
-
import { randomUUID as
|
|
179942
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
179402
179943
|
import { posix as pathPosix } from "path";
|
|
179403
179944
|
function rowToFile(row) {
|
|
179404
179945
|
return {
|
|
@@ -180115,7 +180656,7 @@ var init_store = __esm({
|
|
|
180115
180656
|
* so an interrupted scan cannot be advertised as complete.
|
|
180116
180657
|
*/
|
|
180117
180658
|
recordCodeStateSnapshot(input) {
|
|
180118
|
-
const id =
|
|
180659
|
+
const id = randomUUID11();
|
|
180119
180660
|
let snapshot;
|
|
180120
180661
|
const tx = this.db.transaction(() => {
|
|
180121
180662
|
const previous = this.db.prepare(
|
|
@@ -180193,7 +180734,7 @@ var init_store = __esm({
|
|
|
180193
180734
|
|
|
180194
180735
|
// src/codegraph/code-state.ts
|
|
180195
180736
|
import { execFile as execFile2 } from "child_process";
|
|
180196
|
-
import { createHash as
|
|
180737
|
+
import { createHash as createHash7 } from "crypto";
|
|
180197
180738
|
import { promisify as promisify3 } from "util";
|
|
180198
180739
|
async function runGit(rootPath, args) {
|
|
180199
180740
|
try {
|
|
@@ -180222,7 +180763,7 @@ function changedPathCount(status) {
|
|
|
180222
180763
|
return count3;
|
|
180223
180764
|
}
|
|
180224
180765
|
function fingerprint(baseRevision, status) {
|
|
180225
|
-
return
|
|
180766
|
+
return createHash7("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
180226
180767
|
}
|
|
180227
180768
|
async function collectCodeStateSnapshot(input) {
|
|
180228
180769
|
const [revision, status] = await Promise.all([
|
|
@@ -180322,11 +180863,11 @@ __export(lite_provider_exports, {
|
|
|
180322
180863
|
indexProjectLite: () => indexProjectLite,
|
|
180323
180864
|
refreshProjectLite: () => refreshProjectLite
|
|
180324
180865
|
});
|
|
180325
|
-
import { createHash as
|
|
180866
|
+
import { createHash as createHash8 } from "crypto";
|
|
180326
180867
|
import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
|
|
180327
180868
|
import { join as join5, relative } from "path";
|
|
180328
180869
|
function hashText(text2) {
|
|
180329
|
-
return
|
|
180870
|
+
return createHash8("sha256").update(text2).digest("hex");
|
|
180330
180871
|
}
|
|
180331
180872
|
function extension2(path48) {
|
|
180332
180873
|
const index = path48.lastIndexOf(".");
|
|
@@ -180893,7 +181434,7 @@ var claim_store_exports = {};
|
|
|
180893
181434
|
__export(claim_store_exports, {
|
|
180894
181435
|
ClaimStore: () => ClaimStore
|
|
180895
181436
|
});
|
|
180896
|
-
import { createHash as
|
|
181437
|
+
import { createHash as createHash9, randomUUID as randomUUID12 } from "crypto";
|
|
180897
181438
|
function optionalText3(value) {
|
|
180898
181439
|
return typeof value === "string" && value ? value : void 0;
|
|
180899
181440
|
}
|
|
@@ -180932,7 +181473,7 @@ function rowToEvidence2(row) {
|
|
|
180932
181473
|
createdAt: row.createdAt
|
|
180933
181474
|
};
|
|
180934
181475
|
}
|
|
180935
|
-
function
|
|
181476
|
+
function rowToEvent3(row) {
|
|
180936
181477
|
return {
|
|
180937
181478
|
id: row.id,
|
|
180938
181479
|
projectId: row.projectId,
|
|
@@ -180946,7 +181487,7 @@ function rowToEvent2(row) {
|
|
|
180946
181487
|
};
|
|
180947
181488
|
}
|
|
180948
181489
|
function evidenceKey(input) {
|
|
180949
|
-
return
|
|
181490
|
+
return createHash9("sha256").update(JSON.stringify([
|
|
180950
181491
|
input.evidenceKind,
|
|
180951
181492
|
input.evidenceId,
|
|
180952
181493
|
input.relation,
|
|
@@ -181077,7 +181618,7 @@ var init_claim_store = __esm({
|
|
|
181077
181618
|
locator, capturedHash, evidenceKey, createdAt
|
|
181078
181619
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
181079
181620
|
`).run(
|
|
181080
|
-
|
|
181621
|
+
randomUUID12(),
|
|
181081
181622
|
input.claimId,
|
|
181082
181623
|
input.evidenceKind,
|
|
181083
181624
|
input.evidenceId,
|
|
@@ -181099,7 +181640,7 @@ var init_claim_store = __esm({
|
|
|
181099
181640
|
}
|
|
181100
181641
|
recordEvent(input) {
|
|
181101
181642
|
const event = {
|
|
181102
|
-
id:
|
|
181643
|
+
id: randomUUID12(),
|
|
181103
181644
|
...input,
|
|
181104
181645
|
...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
|
|
181105
181646
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -181127,7 +181668,7 @@ var init_claim_store = __esm({
|
|
|
181127
181668
|
SELECT * FROM knowledge_claim_events
|
|
181128
181669
|
WHERE claimId = ?
|
|
181129
181670
|
ORDER BY createdAt ASC, id
|
|
181130
|
-
`).all(claimId).map(
|
|
181671
|
+
`).all(claimId).map(rowToEvent3);
|
|
181131
181672
|
}
|
|
181132
181673
|
};
|
|
181133
181674
|
}
|
|
@@ -181144,7 +181685,7 @@ __export(claims_exports, {
|
|
|
181144
181685
|
supersedeClaim: () => supersedeClaim,
|
|
181145
181686
|
writeClaim: () => writeClaim
|
|
181146
181687
|
});
|
|
181147
|
-
import { createHash as
|
|
181688
|
+
import { createHash as createHash10, randomUUID as randomUUID13 } from "crypto";
|
|
181148
181689
|
function compactText2(value, field) {
|
|
181149
181690
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
181150
181691
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -181156,7 +181697,7 @@ function normalizedTerm(value) {
|
|
|
181156
181697
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
181157
181698
|
}
|
|
181158
181699
|
function hashIdentity(parts) {
|
|
181159
|
-
return
|
|
181700
|
+
return createHash10("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
181160
181701
|
}
|
|
181161
181702
|
function buildClaimIdentity(input) {
|
|
181162
181703
|
const subject = normalizedTerm(input.subject);
|
|
@@ -181230,7 +181771,7 @@ function normalizeClaimInput(input) {
|
|
|
181230
181771
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
181231
181772
|
return {
|
|
181232
181773
|
claim: {
|
|
181233
|
-
id:
|
|
181774
|
+
id: randomUUID13(),
|
|
181234
181775
|
projectId,
|
|
181235
181776
|
subject,
|
|
181236
181777
|
predicate,
|
|
@@ -181397,7 +181938,7 @@ function supersedeClaim(store2, input) {
|
|
|
181397
181938
|
});
|
|
181398
181939
|
}
|
|
181399
181940
|
function hashObservation(observation) {
|
|
181400
|
-
return
|
|
181941
|
+
return createHash10("sha256").update(JSON.stringify([
|
|
181401
181942
|
observation.title,
|
|
181402
181943
|
observation.narrative,
|
|
181403
181944
|
observation.facts,
|
|
@@ -181641,11 +182182,11 @@ var init_frontmatter = __esm({
|
|
|
181641
182182
|
});
|
|
181642
182183
|
|
|
181643
182184
|
// src/knowledge/markdown.ts
|
|
181644
|
-
import { createHash as
|
|
182185
|
+
import { createHash as createHash11 } from "crypto";
|
|
181645
182186
|
import { promises as fs12 } from "fs";
|
|
181646
182187
|
import path20 from "path";
|
|
181647
182188
|
function hashContent(content) {
|
|
181648
|
-
return
|
|
182189
|
+
return createHash11("sha256").update(content).digest("hex");
|
|
181649
182190
|
}
|
|
181650
182191
|
function stringField(data, key) {
|
|
181651
182192
|
const value = data[key];
|
|
@@ -181771,11 +182312,11 @@ __export(wiki_exports, {
|
|
|
181771
182312
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
181772
182313
|
readKnowledgePage: () => readKnowledgePage
|
|
181773
182314
|
});
|
|
181774
|
-
import { createHash as
|
|
182315
|
+
import { createHash as createHash12 } from "crypto";
|
|
181775
182316
|
import { promises as fs13 } from "fs";
|
|
181776
182317
|
import path21 from "path";
|
|
181777
182318
|
function hash2(value) {
|
|
181778
|
-
return
|
|
182319
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
181779
182320
|
}
|
|
181780
182321
|
function now() {
|
|
181781
182322
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -182319,7 +182860,7 @@ var workflow_store_exports = {};
|
|
|
182319
182860
|
__export(workflow_store_exports, {
|
|
182320
182861
|
WorkflowStore: () => WorkflowStore
|
|
182321
182862
|
});
|
|
182322
|
-
import { randomUUID as
|
|
182863
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
182323
182864
|
function parseJson(value, fallback) {
|
|
182324
182865
|
if (typeof value !== "string" || !value) return fallback;
|
|
182325
182866
|
try {
|
|
@@ -182419,7 +182960,7 @@ var init_workflow_store = __esm({
|
|
|
182419
182960
|
}
|
|
182420
182961
|
recordRun(input) {
|
|
182421
182962
|
const run = {
|
|
182422
|
-
id:
|
|
182963
|
+
id: randomUUID14(),
|
|
182423
182964
|
workflowId: input.workflowId,
|
|
182424
182965
|
projectId: input.projectId,
|
|
182425
182966
|
task: input.task.trim(),
|
|
@@ -182497,7 +183038,7 @@ var init_outcome_types = __esm({
|
|
|
182497
183038
|
});
|
|
182498
183039
|
|
|
182499
183040
|
// src/knowledge/outcome-store.ts
|
|
182500
|
-
import { randomUUID as
|
|
183041
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
182501
183042
|
function optionalText5(value) {
|
|
182502
183043
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
182503
183044
|
}
|
|
@@ -182541,7 +183082,7 @@ var init_outcome_store = __esm({
|
|
|
182541
183082
|
}
|
|
182542
183083
|
record(input) {
|
|
182543
183084
|
const signal = {
|
|
182544
|
-
id:
|
|
183085
|
+
id: randomUUID15(),
|
|
182545
183086
|
projectId: text(input.projectId, "project id"),
|
|
182546
183087
|
candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
|
|
182547
183088
|
candidateId: text(input.candidateId, "candidate id"),
|
|
@@ -182968,11 +183509,11 @@ __export(workflows_exports, {
|
|
|
182968
183509
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
182969
183510
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
182970
183511
|
});
|
|
182971
|
-
import { createHash as
|
|
183512
|
+
import { createHash as createHash13 } from "crypto";
|
|
182972
183513
|
import { promises as fs14 } from "fs";
|
|
182973
183514
|
import path22 from "path";
|
|
182974
183515
|
function hash3(value) {
|
|
182975
|
-
return
|
|
183516
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
182976
183517
|
}
|
|
182977
183518
|
function now2() {
|
|
182978
183519
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -184369,6 +184910,16 @@ async function bindObservationCodeRefsBestEffort(observation) {
|
|
|
184369
184910
|
} catch {
|
|
184370
184911
|
}
|
|
184371
184912
|
}
|
|
184913
|
+
async function persistEvidenceCard(observation) {
|
|
184914
|
+
if (!projectDir) return;
|
|
184915
|
+
try {
|
|
184916
|
+
const evidence = new EvidenceCardStore();
|
|
184917
|
+
await evidence.init(projectDir);
|
|
184918
|
+
evidence.upsertObservation(observation);
|
|
184919
|
+
} catch (error40) {
|
|
184920
|
+
console.error(`[memorix] Evidence card projection failed for obs-${observation.id}: ${error40 instanceof Error ? error40.message : String(error40)}`);
|
|
184921
|
+
}
|
|
184922
|
+
}
|
|
184372
184923
|
function queueClaimDerivation(observation) {
|
|
184373
184924
|
const dataDir = projectDir;
|
|
184374
184925
|
const isExplicit = observation.sourceDetail === "explicit";
|
|
@@ -184715,6 +185266,7 @@ async function storeObservation(input) {
|
|
|
184715
185266
|
}
|
|
184716
185267
|
if (!persistedCallbackInvoked) await input.onPersisted?.(observation);
|
|
184717
185268
|
await bindObservationCodeRefsBestEffort(observation);
|
|
185269
|
+
await persistEvidenceCard(observation);
|
|
184718
185270
|
queueObservationQualification(observation);
|
|
184719
185271
|
if (resolveObservationVisibility(observation) === "project") {
|
|
184720
185272
|
queueClaimDerivation(observation);
|
|
@@ -184807,6 +185359,7 @@ async function upsertObservation(existing, input, now3) {
|
|
|
184807
185359
|
await store2.update(existing);
|
|
184808
185360
|
}
|
|
184809
185361
|
await bindObservationCodeRefsBestEffort(existing);
|
|
185362
|
+
await persistEvidenceCard(existing);
|
|
184810
185363
|
queueObservationQualification(existing);
|
|
184811
185364
|
if (resolveObservationVisibility(existing) === "project") {
|
|
184812
185365
|
queueClaimDerivation(existing);
|
|
@@ -184940,6 +185493,7 @@ async function resolveObservations(ids, status = "resolved") {
|
|
|
184940
185493
|
await Promise.all(changed.map((observation) => tx.update(observation)));
|
|
184941
185494
|
});
|
|
184942
185495
|
}
|
|
185496
|
+
for (const observation of changed) await persistEvidenceCard(observation);
|
|
184943
185497
|
return { resolved, notFound };
|
|
184944
185498
|
}
|
|
184945
185499
|
function getProjectObservations(projectId) {
|
|
@@ -185277,6 +185831,7 @@ var init_observations = __esm({
|
|
|
185277
185831
|
init_secret_filter();
|
|
185278
185832
|
init_lifecycle();
|
|
185279
185833
|
init_visibility();
|
|
185834
|
+
init_evidence_store();
|
|
185280
185835
|
observations = [];
|
|
185281
185836
|
nextId = 1;
|
|
185282
185837
|
projectDir = null;
|
|
@@ -186709,9 +187264,27 @@ function normalizeMemoryBrowseQuery(query) {
|
|
|
186709
187264
|
async function compactSearch(options, surface = "mcp") {
|
|
186710
187265
|
await ensureFreshIndex();
|
|
186711
187266
|
const searchOptions = { ...options, query: normalizeMemoryBrowseQuery(options.query) };
|
|
186712
|
-
|
|
187267
|
+
let entries = (await searchObservations(searchOptions)).map(
|
|
186713
187268
|
(entry) => entry.projectId || !options.projectId ? entry : { ...entry, projectId: options.projectId }
|
|
186714
187269
|
);
|
|
187270
|
+
if (options.projectId) {
|
|
187271
|
+
try {
|
|
187272
|
+
const feedback = new MemoryFeedbackStore();
|
|
187273
|
+
await feedback.init(await getProjectDataDir(options.projectId));
|
|
187274
|
+
const states = feedback.weights(options.projectId, "observation");
|
|
187275
|
+
entries = entries.map((entry) => {
|
|
187276
|
+
const state = states.get(String(entry.id));
|
|
187277
|
+
if (!state) return entry;
|
|
187278
|
+
return {
|
|
187279
|
+
...entry,
|
|
187280
|
+
score: (entry.score ?? 0) * feedbackWeightMultiplier(state.weight),
|
|
187281
|
+
feedbackWeight: state.weight,
|
|
187282
|
+
feedbackStatus: state.status
|
|
187283
|
+
};
|
|
187284
|
+
}).filter((entry) => entry.feedbackStatus !== "archived" || options.status === "all").sort((a4, b4) => (b4.score ?? 0) - (a4.score ?? 0));
|
|
187285
|
+
} catch {
|
|
187286
|
+
}
|
|
187287
|
+
}
|
|
186715
187288
|
let formatted = formatIndexTable(entries, searchOptions.query, !options.projectId, surface);
|
|
186716
187289
|
if (entries.length === 0 && options.projectId) {
|
|
186717
187290
|
const allObservations = filterReadableObservations(getAllObservations(), options.reader);
|
|
@@ -187030,6 +187603,8 @@ var init_engine3 = __esm({
|
|
|
187030
187603
|
init_mini_skills();
|
|
187031
187604
|
init_secret_filter();
|
|
187032
187605
|
init_visibility();
|
|
187606
|
+
init_persistence();
|
|
187607
|
+
init_feedback();
|
|
187033
187608
|
}
|
|
187034
187609
|
});
|
|
187035
187610
|
|
|
@@ -187044,7 +187619,7 @@ __export(team_store_exports, {
|
|
|
187044
187619
|
isTeamStoreInitialized: () => isTeamStoreInitialized,
|
|
187045
187620
|
resetTeamStore: () => resetTeamStore
|
|
187046
187621
|
});
|
|
187047
|
-
import { randomUUID as
|
|
187622
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
187048
187623
|
import path24 from "path";
|
|
187049
187624
|
import fs15 from "fs";
|
|
187050
187625
|
function getTeamStore() {
|
|
@@ -187333,7 +187908,7 @@ var init_team_store = __esm({
|
|
|
187333
187908
|
* reactivate it (preserving agent_id). Otherwise create a new one.
|
|
187334
187909
|
*/
|
|
187335
187910
|
registerAgent(input) {
|
|
187336
|
-
const instanceId = input.instanceId ||
|
|
187911
|
+
const instanceId = input.instanceId || randomUUID16();
|
|
187337
187912
|
const now3 = Date.now();
|
|
187338
187913
|
const existing = this.stmtAgentFindByInstance.get(
|
|
187339
187914
|
input.projectId,
|
|
@@ -187359,7 +187934,7 @@ var init_team_store = __esm({
|
|
|
187359
187934
|
this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
|
|
187360
187935
|
return row2;
|
|
187361
187936
|
}
|
|
187362
|
-
const agentId =
|
|
187937
|
+
const agentId = randomUUID16();
|
|
187363
187938
|
this.stmtAgentUpsert.run({
|
|
187364
187939
|
agent_id: agentId,
|
|
187365
187940
|
project_id: input.projectId,
|
|
@@ -187461,7 +188036,7 @@ var init_team_store = __esm({
|
|
|
187461
188036
|
return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
|
|
187462
188037
|
}
|
|
187463
188038
|
}
|
|
187464
|
-
const id =
|
|
188039
|
+
const id = randomUUID16();
|
|
187465
188040
|
const now3 = Date.now();
|
|
187466
188041
|
const row = {
|
|
187467
188042
|
id,
|
|
@@ -187511,7 +188086,7 @@ var init_team_store = __esm({
|
|
|
187511
188086
|
// Task Operations (with atomic claim semantics)
|
|
187512
188087
|
// ═══════════════════════════════════════════════════════════════════
|
|
187513
188088
|
createTask(input) {
|
|
187514
|
-
const taskId =
|
|
188089
|
+
const taskId = randomUUID16();
|
|
187515
188090
|
const now3 = Date.now();
|
|
187516
188091
|
const row = {
|
|
187517
188092
|
task_id: taskId,
|
|
@@ -187783,7 +188358,7 @@ var init_team_store = __esm({
|
|
|
187783
188358
|
for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
|
|
187784
188359
|
for (const msg of msgs) {
|
|
187785
188360
|
this.stmtMsgInsert.run({
|
|
187786
|
-
id: msg.id ??
|
|
188361
|
+
id: msg.id ?? randomUUID16(),
|
|
187787
188362
|
project_id: "migrated",
|
|
187788
188363
|
sender_agent_id: msg.from ?? "unknown",
|
|
187789
188364
|
recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
|
|
@@ -192216,8 +192791,8 @@ var init_official_skills = __esm({
|
|
|
192216
192791
|
"",
|
|
192217
192792
|
"| Situation | Prefer | CLI fallback |",
|
|
192218
192793
|
"|---|---|---|",
|
|
192219
|
-
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --brief-json` |',
|
|
192220
|
-
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
|
|
192794
|
+
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --fallback --brief-json` |',
|
|
192795
|
+
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --fallback --brief-json` |',
|
|
192221
192796
|
'| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
|
|
192222
192797
|
'| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
|
|
192223
192798
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
@@ -192230,7 +192805,7 @@ var init_official_skills = __esm({
|
|
|
192230
192805
|
"",
|
|
192231
192806
|
"- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user's actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.",
|
|
192232
192807
|
"- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client's tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.",
|
|
192233
|
-
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
192808
|
+
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --fallback --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --fallback --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
192234
192809
|
"- After a successful `memorix_project_context`, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use Context Pack, search, or detail only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
192235
192810
|
"- If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
192236
192811
|
"- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer. Fetch detail only for a result you still need after the brief.",
|
|
@@ -193489,7 +194064,7 @@ alwaysApply: true
|
|
|
193489
194064
|
"",
|
|
193490
194065
|
`Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). When the task is continuing prior work, the same brief also includes a bounded prior-work projection. Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
193491
194066
|
"",
|
|
193492
|
-
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --brief-json`. For a new task, use `memorix context "<task>" --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
194067
|
+
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --fallback --brief-json`. For a new task, use `memorix context "<task>" --fallback --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
193493
194068
|
"",
|
|
193494
194069
|
"After a successful `memorix_project_context` result, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use `memorix_context_pack`, `memorix_search`, or `memorix_detail` only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
193495
194070
|
"If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
@@ -197997,7 +198572,7 @@ var compaction_checkpoint_store_exports = {};
|
|
|
197997
198572
|
__export(compaction_checkpoint_store_exports, {
|
|
197998
198573
|
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
197999
198574
|
});
|
|
198000
|
-
import { createHash as
|
|
198575
|
+
import { createHash as createHash14, randomUUID as randomUUID17 } from "crypto";
|
|
198001
198576
|
function optionalText7(value) {
|
|
198002
198577
|
return typeof value === "string" && value ? value : void 0;
|
|
198003
198578
|
}
|
|
@@ -198039,7 +198614,7 @@ function sourceKeyFor(input, summary) {
|
|
|
198039
198614
|
input.tokensBefore ?? "",
|
|
198040
198615
|
input.firstKeptEntryId ?? ""
|
|
198041
198616
|
].join("\0");
|
|
198042
|
-
return `derived:${
|
|
198617
|
+
return `derived:${createHash14("sha256").update(material).digest("hex").slice(0, 32)}`;
|
|
198043
198618
|
}
|
|
198044
198619
|
function rowToCheckpoint(row) {
|
|
198045
198620
|
return {
|
|
@@ -198098,7 +198673,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
198098
198673
|
if (pending) return rowToCheckpoint(pending);
|
|
198099
198674
|
const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
198100
198675
|
const checkpoint = {
|
|
198101
|
-
id:
|
|
198676
|
+
id: randomUUID17(),
|
|
198102
198677
|
projectId: input.projectId,
|
|
198103
198678
|
sessionId: input.sessionId,
|
|
198104
198679
|
agent: input.agent,
|
|
@@ -198106,7 +198681,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
198106
198681
|
captureKind: "preflight",
|
|
198107
198682
|
reason: safeReason(input.reason),
|
|
198108
198683
|
sourceEvent: input.sourceEvent,
|
|
198109
|
-
sourceKey: `pre:${
|
|
198684
|
+
sourceKey: `pre:${randomUUID17()}`,
|
|
198110
198685
|
transcriptAvailable: Boolean(input.transcriptAvailable),
|
|
198111
198686
|
status: "active",
|
|
198112
198687
|
preCapturedAt: now3,
|
|
@@ -198172,7 +198747,7 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
198172
198747
|
return this.get(checkpoint2.id);
|
|
198173
198748
|
}
|
|
198174
198749
|
const checkpoint = {
|
|
198175
|
-
id:
|
|
198750
|
+
id: randomUUID17(),
|
|
198176
198751
|
projectId: input.projectId,
|
|
198177
198752
|
sessionId: input.sessionId,
|
|
198178
198753
|
agent: input.agent,
|
|
@@ -198920,6 +199495,59 @@ var init_context_receipt = __esm({
|
|
|
198920
199495
|
}
|
|
198921
199496
|
});
|
|
198922
199497
|
|
|
199498
|
+
// src/cli/fallback-budget.ts
|
|
199499
|
+
import { createHash as createHash15 } from "crypto";
|
|
199500
|
+
function fallbackRequestKey(projectId, task) {
|
|
199501
|
+
const normalized = (task ?? "").trim().toLowerCase().replace(/\s+/g, " ");
|
|
199502
|
+
return createHash15("sha256").update(`${projectId}
|
|
199503
|
+
${normalized}`).digest("hex").slice(0, 32);
|
|
199504
|
+
}
|
|
199505
|
+
var DEFAULT_FALLBACK_TTL_MS, CliFallbackBudget;
|
|
199506
|
+
var init_fallback_budget = __esm({
|
|
199507
|
+
"src/cli/fallback-budget.ts"() {
|
|
199508
|
+
"use strict";
|
|
199509
|
+
init_esm_shims();
|
|
199510
|
+
init_sqlite_db();
|
|
199511
|
+
DEFAULT_FALLBACK_TTL_MS = 10 * 60 * 1e3;
|
|
199512
|
+
CliFallbackBudget = class {
|
|
199513
|
+
db = null;
|
|
199514
|
+
async init(dataDir) {
|
|
199515
|
+
this.db = getDatabase(dataDir);
|
|
199516
|
+
this.db.exec(`
|
|
199517
|
+
CREATE TABLE IF NOT EXISTS cli_fallback_attempts (
|
|
199518
|
+
project_id TEXT NOT NULL,
|
|
199519
|
+
request_key TEXT NOT NULL,
|
|
199520
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
199521
|
+
last_attempt_at INTEGER NOT NULL,
|
|
199522
|
+
expires_at INTEGER NOT NULL,
|
|
199523
|
+
PRIMARY KEY (project_id, request_key)
|
|
199524
|
+
)
|
|
199525
|
+
`);
|
|
199526
|
+
}
|
|
199527
|
+
claim(projectId, task, now3 = Date.now(), ttlMs = DEFAULT_FALLBACK_TTL_MS) {
|
|
199528
|
+
if (!this.db) throw new Error("CliFallbackBudget is not initialized.");
|
|
199529
|
+
const key = fallbackRequestKey(projectId, task);
|
|
199530
|
+
const current = this.db.prepare(`
|
|
199531
|
+
SELECT count, expires_at FROM cli_fallback_attempts WHERE project_id = ? AND request_key = ?
|
|
199532
|
+
`).get(projectId, key);
|
|
199533
|
+
const count3 = Number(current?.count ?? 0);
|
|
199534
|
+
if (current && Number(current.expires_at) > now3 && count3 >= 1) {
|
|
199535
|
+
return { allowed: false, key, count: count3, reason: "Fallback budget exhausted for this task. Stop probing and continue with the current project files." };
|
|
199536
|
+
}
|
|
199537
|
+
this.db.prepare(`
|
|
199538
|
+
INSERT INTO cli_fallback_attempts (project_id, request_key, count, last_attempt_at, expires_at)
|
|
199539
|
+
VALUES (?, ?, 1, ?, ?)
|
|
199540
|
+
ON CONFLICT(project_id, request_key) DO UPDATE SET
|
|
199541
|
+
count = CASE WHEN excluded.expires_at > cli_fallback_attempts.expires_at THEN 1 ELSE cli_fallback_attempts.count + 1 END,
|
|
199542
|
+
last_attempt_at = excluded.last_attempt_at,
|
|
199543
|
+
expires_at = CASE WHEN excluded.expires_at > cli_fallback_attempts.expires_at THEN excluded.expires_at ELSE cli_fallback_attempts.expires_at END
|
|
199544
|
+
`).run(projectId, key, now3, now3 + Math.max(1e3, ttlMs));
|
|
199545
|
+
return { allowed: true, key, count: 1 };
|
|
199546
|
+
}
|
|
199547
|
+
};
|
|
199548
|
+
}
|
|
199549
|
+
});
|
|
199550
|
+
|
|
198923
199551
|
// src/cli/commands/context.ts
|
|
198924
199552
|
var context_exports = {};
|
|
198925
199553
|
__export(context_exports, {
|
|
@@ -198948,6 +199576,7 @@ var init_context2 = __esm({
|
|
|
198948
199576
|
init_context_receipt();
|
|
198949
199577
|
init_workflows2();
|
|
198950
199578
|
init_operator_shared();
|
|
199579
|
+
init_fallback_budget();
|
|
198951
199580
|
context_default = defineCommand({
|
|
198952
199581
|
meta: {
|
|
198953
199582
|
name: "context",
|
|
@@ -198964,13 +199593,23 @@ var init_context2 = __esm({
|
|
|
198964
199593
|
refresh: { type: "string", description: "Project scan policy: auto, always, or never" },
|
|
198965
199594
|
agent: { type: "string", description: "Optional target agent for compatible workflow selection" },
|
|
198966
199595
|
json: { type: "boolean", description: "Emit machine-readable JSON output" },
|
|
198967
|
-
briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON" }
|
|
199596
|
+
briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON" },
|
|
199597
|
+
fallback: { type: "boolean", description: "Mark this as the one-shot MCP-unavailable fallback for the task" }
|
|
198968
199598
|
},
|
|
198969
199599
|
run: async ({ args }) => {
|
|
198970
199600
|
const asJson = !!args.json || !!args.briefJson;
|
|
198971
199601
|
const task = args.task?.trim() || args.input?.trim() || void 0;
|
|
198972
199602
|
try {
|
|
198973
199603
|
const { project, dataDir, reader: reader2 } = await getCliProjectContext();
|
|
199604
|
+
if (args.fallback) {
|
|
199605
|
+
const budget = new CliFallbackBudget();
|
|
199606
|
+
await budget.init(dataDir);
|
|
199607
|
+
const claim = budget.claim(project.id, task);
|
|
199608
|
+
if (!claim.allowed) {
|
|
199609
|
+
emitError(claim.reason ?? "CLI fallback budget exhausted for this task.", asJson);
|
|
199610
|
+
return;
|
|
199611
|
+
}
|
|
199612
|
+
}
|
|
198974
199613
|
const context = await buildAutoProjectContext({
|
|
198975
199614
|
project,
|
|
198976
199615
|
dataDir,
|
|
@@ -199028,7 +199667,8 @@ var init_resume = __esm({
|
|
|
199028
199667
|
refresh: { type: "string", description: "Project scan policy: auto, always, or never" },
|
|
199029
199668
|
agent: { type: "string", description: "Optional target agent for compatible workflow selection" },
|
|
199030
199669
|
json: { type: "boolean", description: "Emit machine-readable JSON output" },
|
|
199031
|
-
briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON" }
|
|
199670
|
+
briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON" },
|
|
199671
|
+
fallback: { type: "boolean", description: "Mark this as the one-shot MCP-unavailable fallback for the task" }
|
|
199032
199672
|
},
|
|
199033
199673
|
async run({ args }) {
|
|
199034
199674
|
await context_default.run?.({
|
|
@@ -199039,6 +199679,7 @@ var init_resume = __esm({
|
|
|
199039
199679
|
agent: args.agent,
|
|
199040
199680
|
json: args.json,
|
|
199041
199681
|
briefJson: args.briefJson,
|
|
199682
|
+
fallback: args.fallback,
|
|
199042
199683
|
resume: true
|
|
199043
199684
|
},
|
|
199044
199685
|
rawArgs: [],
|
|
@@ -200294,6 +200935,166 @@ var init_knowledge = __esm({
|
|
|
200294
200935
|
}
|
|
200295
200936
|
});
|
|
200296
200937
|
|
|
200938
|
+
// src/cli/commands/evidence.ts
|
|
200939
|
+
var evidence_exports = {};
|
|
200940
|
+
__export(evidence_exports, {
|
|
200941
|
+
default: () => evidence_default
|
|
200942
|
+
});
|
|
200943
|
+
var evidence_default;
|
|
200944
|
+
var init_evidence = __esm({
|
|
200945
|
+
"src/cli/commands/evidence.ts"() {
|
|
200946
|
+
"use strict";
|
|
200947
|
+
init_esm_shims();
|
|
200948
|
+
init_dist2();
|
|
200949
|
+
init_obs_store();
|
|
200950
|
+
init_evidence_store();
|
|
200951
|
+
init_operator_shared();
|
|
200952
|
+
evidence_default = defineCommand({
|
|
200953
|
+
meta: { name: "evidence", description: "Inspect project-scoped evidence cards and provenance" },
|
|
200954
|
+
args: {
|
|
200955
|
+
action: { type: "positional", description: "list, get, sync, stale, or events", required: false },
|
|
200956
|
+
id: { type: "string", description: "Candidate id, usually an observation id" },
|
|
200957
|
+
paths: { type: "string", description: "Comma-separated changed paths for stale" },
|
|
200958
|
+
reason: { type: "string", description: "Why the source became stale" },
|
|
200959
|
+
query: { type: "string", description: "Search title/source fields" },
|
|
200960
|
+
limit: { type: "string", description: "Maximum cards/events" },
|
|
200961
|
+
json: { type: "boolean", description: "Emit JSON" }
|
|
200962
|
+
},
|
|
200963
|
+
async run({ args }) {
|
|
200964
|
+
const action = args.action || "list";
|
|
200965
|
+
const asJson = !!args.json;
|
|
200966
|
+
try {
|
|
200967
|
+
const context = action === "list" || action === "get" || action === "events" ? await getCliReadContext() : await getCliProjectContext({ searchIndex: false });
|
|
200968
|
+
const { project, dataDir } = context;
|
|
200969
|
+
const store2 = new EvidenceCardStore();
|
|
200970
|
+
await store2.init(dataDir);
|
|
200971
|
+
const limit2 = Math.min(100, Math.max(1, Number(args.limit || 20)));
|
|
200972
|
+
if (action === "sync") {
|
|
200973
|
+
const synced = store2.syncObservations(await getObservationStore().loadByProject(project.id));
|
|
200974
|
+
emitResult({ project, synced: synced.length }, `Synced ${synced.length} evidence card(s).`, asJson);
|
|
200975
|
+
return;
|
|
200976
|
+
}
|
|
200977
|
+
if (action === "stale") {
|
|
200978
|
+
const paths = String(args.paths || "").split(",").map((value) => value.trim()).filter(Boolean);
|
|
200979
|
+
const changed = store2.markStaleForPaths(project.id, paths, String(args.reason || "source file changed"));
|
|
200980
|
+
emitResult({ project, staleMarked: changed, paths }, `Marked ${changed} evidence card(s) stale.`, asJson);
|
|
200981
|
+
return;
|
|
200982
|
+
}
|
|
200983
|
+
const id = String(args.id || "").trim();
|
|
200984
|
+
if (action === "get" || action === "events") {
|
|
200985
|
+
if (!id) {
|
|
200986
|
+
emitError(`--id is required for evidence ${action}.`, asJson);
|
|
200987
|
+
return;
|
|
200988
|
+
}
|
|
200989
|
+
const card = store2.get(project.id, "observation", id);
|
|
200990
|
+
if (!card) {
|
|
200991
|
+
emitError(`Evidence card for observation ${id} was not found.`, asJson);
|
|
200992
|
+
return;
|
|
200993
|
+
}
|
|
200994
|
+
const result = action === "events" ? store2.listEvents(card.id, limit2) : { card, events: store2.listEvents(card.id) };
|
|
200995
|
+
emitResult({ project, result }, JSON.stringify(result, null, 2), asJson);
|
|
200996
|
+
return;
|
|
200997
|
+
}
|
|
200998
|
+
if (action !== "list") {
|
|
200999
|
+
emitError("action must be list, get, sync, stale, or events.", asJson);
|
|
201000
|
+
return;
|
|
201001
|
+
}
|
|
201002
|
+
const query = String(args.query || "").trim().toLowerCase();
|
|
201003
|
+
const cards = store2.list(project.id, { limit: 100 }).filter((card) => !query || [card.title, card.summary, card.sourceRef, card.locator || ""].join(" ").toLowerCase().includes(query)).slice(0, limit2);
|
|
201004
|
+
emitResult({ project, cards }, cards.length === 0 ? "No evidence cards found." : cards.map((card) => `- ${card.candidateId} ${card.title} [${card.freshness}] ${card.sourceRef}`).join("\n"), asJson);
|
|
201005
|
+
} catch (error40) {
|
|
201006
|
+
emitError(error40 instanceof Error ? error40.message : String(error40), asJson);
|
|
201007
|
+
}
|
|
201008
|
+
}
|
|
201009
|
+
});
|
|
201010
|
+
}
|
|
201011
|
+
});
|
|
201012
|
+
|
|
201013
|
+
// src/cli/commands/feedback.ts
|
|
201014
|
+
var feedback_exports2 = {};
|
|
201015
|
+
__export(feedback_exports2, {
|
|
201016
|
+
default: () => feedback_default
|
|
201017
|
+
});
|
|
201018
|
+
var signals, feedback_default;
|
|
201019
|
+
var init_feedback2 = __esm({
|
|
201020
|
+
"src/cli/commands/feedback.ts"() {
|
|
201021
|
+
"use strict";
|
|
201022
|
+
init_esm_shims();
|
|
201023
|
+
init_dist2();
|
|
201024
|
+
init_feedback();
|
|
201025
|
+
init_operator_shared();
|
|
201026
|
+
signals = ["user-correction", "verification-success", "verification-failure", "code-change", "used", "not-used", "code-conflict", "strengthen", "weaken", "revoke"];
|
|
201027
|
+
feedback_default = defineCommand({
|
|
201028
|
+
meta: { name: "feedback", description: "Record and audit memory feedback" },
|
|
201029
|
+
args: {
|
|
201030
|
+
action: { type: "positional", description: "record, show, or audit", required: false },
|
|
201031
|
+
id: { type: "string", description: "Candidate id" },
|
|
201032
|
+
kind: { type: "string", description: "observation, claim, durable-memory, or workflow" },
|
|
201033
|
+
signal: { type: "string", description: "Feedback signal" },
|
|
201034
|
+
source: { type: "string", description: "Source reference for the feedback" },
|
|
201035
|
+
actor: { type: "string", description: "Actor id or human label" },
|
|
201036
|
+
note: { type: "string", description: "Short audit note" },
|
|
201037
|
+
targetEventId: { type: "string", description: "Event id to revoke" },
|
|
201038
|
+
limit: { type: "string", description: "Maximum audit rows" },
|
|
201039
|
+
json: { type: "boolean", description: "Emit JSON" }
|
|
201040
|
+
},
|
|
201041
|
+
async run({ args }) {
|
|
201042
|
+
const action = args.action || "show";
|
|
201043
|
+
const asJson = !!args.json;
|
|
201044
|
+
try {
|
|
201045
|
+
const context = action === "show" || action === "audit" ? await getCliReadContext() : await getCliProjectContext({ searchIndex: false });
|
|
201046
|
+
const { project, dataDir } = context;
|
|
201047
|
+
const id = String(args.id || "").trim();
|
|
201048
|
+
const kind = String(args.kind || "observation").trim() || "observation";
|
|
201049
|
+
if (!id) {
|
|
201050
|
+
emitError("--id is required.", asJson);
|
|
201051
|
+
return;
|
|
201052
|
+
}
|
|
201053
|
+
if (!["observation", "claim", "durable-memory", "workflow"].includes(kind)) {
|
|
201054
|
+
emitError("Invalid --kind.", asJson);
|
|
201055
|
+
return;
|
|
201056
|
+
}
|
|
201057
|
+
const store2 = new MemoryFeedbackStore();
|
|
201058
|
+
await store2.init(dataDir);
|
|
201059
|
+
if (action === "show") {
|
|
201060
|
+
const result2 = store2.getState(project.id, kind, id);
|
|
201061
|
+
emitResult({ project, result: result2 }, JSON.stringify(result2, null, 2), asJson);
|
|
201062
|
+
return;
|
|
201063
|
+
}
|
|
201064
|
+
if (action === "audit") {
|
|
201065
|
+
const result2 = store2.audit(project.id, kind, id, Number(args.limit || 100));
|
|
201066
|
+
emitResult({ project, result: result2 }, JSON.stringify(result2, null, 2), asJson);
|
|
201067
|
+
return;
|
|
201068
|
+
}
|
|
201069
|
+
if (action !== "record") {
|
|
201070
|
+
emitError("action must be record, show, or audit.", asJson);
|
|
201071
|
+
return;
|
|
201072
|
+
}
|
|
201073
|
+
const signal = String(args.signal || "").trim();
|
|
201074
|
+
const sourceRef = String(args.source || "").trim();
|
|
201075
|
+
if (!signals.includes(signal) || !sourceRef) {
|
|
201076
|
+
emitError(`record requires --signal (${signals.join(", ")}) and --source.`, asJson);
|
|
201077
|
+
return;
|
|
201078
|
+
}
|
|
201079
|
+
const result = store2.record({
|
|
201080
|
+
projectId: project.id,
|
|
201081
|
+
candidateKind: kind,
|
|
201082
|
+
candidateId: id,
|
|
201083
|
+
signal,
|
|
201084
|
+
sourceRef,
|
|
201085
|
+
...args.actor ? { actor: String(args.actor) } : {},
|
|
201086
|
+
...args.note ? { note: String(args.note) } : {},
|
|
201087
|
+
...args.targetEventId ? { targetEventId: String(args.targetEventId) } : {}
|
|
201088
|
+
});
|
|
201089
|
+
emitResult({ project, result }, `Recorded ${signal} for ${kind}:${id}; weight=${result.state.weight.toFixed(2)}.`, asJson);
|
|
201090
|
+
} catch (error40) {
|
|
201091
|
+
emitError(error40 instanceof Error ? error40.message : String(error40), asJson);
|
|
201092
|
+
}
|
|
201093
|
+
}
|
|
201094
|
+
});
|
|
201095
|
+
}
|
|
201096
|
+
});
|
|
201097
|
+
|
|
200297
201098
|
// src/cli/commands/reasoning.ts
|
|
200298
201099
|
var reasoning_exports = {};
|
|
200299
201100
|
__export(reasoning_exports, {
|
|
@@ -203494,7 +204295,7 @@ __export(planner_exports, {
|
|
|
203494
204295
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
203495
204296
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
203496
204297
|
});
|
|
203497
|
-
import { randomUUID as
|
|
204298
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
203498
204299
|
function isPlannerTask(metadata) {
|
|
203499
204300
|
if (!metadata) return null;
|
|
203500
204301
|
try {
|
|
@@ -203552,7 +204353,7 @@ function seedAutonomousPipeline(teamStore, projectId, config2, opts) {
|
|
|
203552
204353
|
const maxIterations = config2.maxIterations ?? 3;
|
|
203553
204354
|
const taskBudget = config2.taskBudget ?? 15;
|
|
203554
204355
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
203555
|
-
const pipelineId =
|
|
204356
|
+
const pipelineId = randomUUID18();
|
|
203556
204357
|
const meta = {
|
|
203557
204358
|
plannerType: "plan",
|
|
203558
204359
|
pipelineId,
|
|
@@ -204471,11 +205272,11 @@ __export(receipt_service_exports, {
|
|
|
204471
205272
|
buildHandoffReceipt: () => buildHandoffReceipt,
|
|
204472
205273
|
formatHandoffReceipt: () => formatHandoffReceipt
|
|
204473
205274
|
});
|
|
204474
|
-
import { createHash as
|
|
205275
|
+
import { createHash as createHash16 } from "crypto";
|
|
204475
205276
|
import { existsSync as existsSync21, readFileSync as readFileSync13 } from "fs";
|
|
204476
205277
|
import path36 from "path";
|
|
204477
205278
|
function sha256(value) {
|
|
204478
|
-
return `sha256:${
|
|
205279
|
+
return `sha256:${createHash16("sha256").update(value).digest("hex")}`;
|
|
204479
205280
|
}
|
|
204480
205281
|
function hashId(projectId, id) {
|
|
204481
205282
|
return sha256(`${projectId}:obs:${id}`);
|
|
@@ -204696,6 +205497,10 @@ var init_tool_profile = __esm({
|
|
|
204696
205497
|
// multimodal support to one additional schema rather than enabling lite.
|
|
204697
205498
|
memorix_session_start: ["micro", "lite", "team", "full"],
|
|
204698
205499
|
memorix_media: ["micro", "lite", "team", "full"],
|
|
205500
|
+
// Evidence and feedback are deliberate operator/context-control surfaces;
|
|
205501
|
+
// keep the default micro profile at its nine-tool token budget.
|
|
205502
|
+
memorix_evidence: ["lite", "team", "full"],
|
|
205503
|
+
memorix_feedback: ["lite", "team", "full"],
|
|
204699
205504
|
// ── lite: extended solo memory surface ────────────────────────────
|
|
204700
205505
|
memorix_graph_context: ["lite", "team", "full"],
|
|
204701
205506
|
memorix_timeline: ["lite", "team", "full"],
|
|
@@ -216650,9 +217455,9 @@ var init_graph_scope = __esm({
|
|
|
216650
217455
|
});
|
|
216651
217456
|
|
|
216652
217457
|
// src/rules/utils.ts
|
|
216653
|
-
import { createHash as
|
|
217458
|
+
import { createHash as createHash17 } from "crypto";
|
|
216654
217459
|
function hashContent2(content) {
|
|
216655
|
-
return
|
|
217460
|
+
return createHash17("sha256").update(content.trim()).digest("hex").substring(0, 16);
|
|
216656
217461
|
}
|
|
216657
217462
|
function generateRuleId(source, filePath) {
|
|
216658
217463
|
const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
|
|
@@ -218356,6 +219161,18 @@ var init_cleanup = __esm({
|
|
|
218356
219161
|
});
|
|
218357
219162
|
|
|
218358
219163
|
// src/dashboard/maintenance.ts
|
|
219164
|
+
var maintenance_exports = {};
|
|
219165
|
+
__export(maintenance_exports, {
|
|
219166
|
+
DashboardMaintenanceError: () => DashboardMaintenanceError,
|
|
219167
|
+
executeCleanup: () => executeCleanup,
|
|
219168
|
+
executeConsolidate: () => executeConsolidate,
|
|
219169
|
+
executeDeduplicate: () => executeDeduplicate,
|
|
219170
|
+
executeRetentionArchive: () => executeRetentionArchive,
|
|
219171
|
+
previewCleanup: () => previewCleanup,
|
|
219172
|
+
previewConsolidate: () => previewConsolidate,
|
|
219173
|
+
previewDeduplicate: () => previewDeduplicate,
|
|
219174
|
+
previewRetentionArchive: () => previewRetentionArchive
|
|
219175
|
+
});
|
|
218359
219176
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
218360
219177
|
function reader(projectId) {
|
|
218361
219178
|
return { projectId };
|
|
@@ -218597,6 +219414,23 @@ var init_maintenance = __esm({
|
|
|
218597
219414
|
}
|
|
218598
219415
|
});
|
|
218599
219416
|
|
|
219417
|
+
// src/dashboard/config-provenance.ts
|
|
219418
|
+
function resolveDashboardKeySource({ value, envKeys, configSource }) {
|
|
219419
|
+
for (const envKey of envKeys) {
|
|
219420
|
+
const envValue = process.env[envKey];
|
|
219421
|
+
if (envValue !== value) continue;
|
|
219422
|
+
return getLoadedEnvValue(envKey) === envValue ? ".env" : `env:${envKey}`;
|
|
219423
|
+
}
|
|
219424
|
+
return configSource;
|
|
219425
|
+
}
|
|
219426
|
+
var init_config_provenance = __esm({
|
|
219427
|
+
"src/dashboard/config-provenance.ts"() {
|
|
219428
|
+
"use strict";
|
|
219429
|
+
init_esm_shims();
|
|
219430
|
+
init_dotenv_loader();
|
|
219431
|
+
}
|
|
219432
|
+
});
|
|
219433
|
+
|
|
218600
219434
|
// src/dashboard/project-classification.ts
|
|
218601
219435
|
var project_classification_exports = {};
|
|
218602
219436
|
__export(project_classification_exports, {
|
|
@@ -219376,6 +220210,20 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
219376
220210
|
sendJson(res, observations2);
|
|
219377
220211
|
break;
|
|
219378
220212
|
}
|
|
220213
|
+
case "/evidence": {
|
|
220214
|
+
const observations2 = filterDashboardObservations(
|
|
220215
|
+
await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
|
|
220216
|
+
effectiveProjectId
|
|
220217
|
+
);
|
|
220218
|
+
const evidenceStore = new EvidenceCardStore();
|
|
220219
|
+
await evidenceStore.init(effectiveDataDir);
|
|
220220
|
+
evidenceStore.syncObservations(observations2);
|
|
220221
|
+
const query = url2.searchParams.get("q") || "";
|
|
220222
|
+
const limit2 = Number(url2.searchParams.get("limit") || 20);
|
|
220223
|
+
const cards = evidenceStore.list(effectiveProjectId, { limit: Math.min(100, Math.max(1, limit2)) }).filter((card) => !query || [card.title, card.summary, card.sourceRef, card.locator ?? ""].join(" ").toLowerCase().includes(query.toLowerCase()));
|
|
220224
|
+
sendJson(res, { cards, projectId: effectiveProjectId });
|
|
220225
|
+
break;
|
|
220226
|
+
}
|
|
219379
220227
|
case "/sessions": {
|
|
219380
220228
|
const allSessions = await getSessionStore().loadAll();
|
|
219381
220229
|
const sessions = filterByProject(allSessions, effectiveProjectId);
|
|
@@ -219423,8 +220271,13 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
219423
220271
|
filesModified: o4.filesModified
|
|
219424
220272
|
}));
|
|
219425
220273
|
const retentionReferenceTime = new Date(now3);
|
|
220274
|
+
const feedback = new MemoryFeedbackStore();
|
|
220275
|
+
await feedback.init(effectiveDataDir).catch(() => void 0);
|
|
219426
220276
|
const retention = summarizeRetentionProjections(
|
|
219427
|
-
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
220277
|
+
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
220278
|
+
referenceTime: retentionReferenceTime,
|
|
220279
|
+
feedback: feedback.getState(effectiveProjectId, "observation", String(observation.id))
|
|
220280
|
+
}))
|
|
219428
220281
|
);
|
|
219429
220282
|
const retentionSummary = {
|
|
219430
220283
|
active: retention.active,
|
|
@@ -219518,9 +220371,14 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
219518
220371
|
effectiveProjectId
|
|
219519
220372
|
);
|
|
219520
220373
|
const referenceTime = /* @__PURE__ */ new Date();
|
|
220374
|
+
const feedback = new MemoryFeedbackStore();
|
|
220375
|
+
await feedback.init(effectiveDataDir).catch(() => void 0);
|
|
219521
220376
|
const rows = observations2.filter((observation) => observation.type !== "probe").map((observation) => ({
|
|
219522
220377
|
observation,
|
|
219523
|
-
retention: projectObservationRetention(observation, {
|
|
220378
|
+
retention: projectObservationRetention(observation, {
|
|
220379
|
+
referenceTime,
|
|
220380
|
+
feedback: feedback.getState(effectiveProjectId, "observation", String(observation.id))
|
|
220381
|
+
})
|
|
219524
220382
|
})).sort((a4, b4) => b4.retention.displayScore - a4.retention.displayScore);
|
|
219525
220383
|
const summary = summarizeRetentionProjections(rows.map((row) => row.retention));
|
|
219526
220384
|
const scored = rows.map(({ observation, retention }) => ({
|
|
@@ -219591,23 +220449,13 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
219591
220449
|
const os9 = await import("os");
|
|
219592
220450
|
const { existsSync: existsSync34 } = await import("fs");
|
|
219593
220451
|
const { join: join34 } = await import("path");
|
|
219594
|
-
let yml = {};
|
|
219595
220452
|
const configProjectRoot = effectiveProjectRoot;
|
|
219596
|
-
|
|
219597
|
-
const { loadYamlConfig: loadYamlConfig2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
|
|
219598
|
-
yml = configProjectRoot ? loadYamlConfig2(configProjectRoot) : loadYamlConfig2(null);
|
|
219599
|
-
} catch {
|
|
219600
|
-
}
|
|
219601
|
-
if (configProjectRoot) {
|
|
219602
|
-
try {
|
|
219603
|
-
const { loadDotenv: loadDotenv2 } = await Promise.resolve().then(() => (init_dotenv_loader(), dotenv_loader_exports));
|
|
219604
|
-
loadDotenv2(configProjectRoot);
|
|
219605
|
-
} catch {
|
|
219606
|
-
}
|
|
219607
|
-
}
|
|
220453
|
+
const resolved = getResolvedConfig({ projectRoot: configProjectRoot });
|
|
219608
220454
|
const files = {
|
|
219609
220455
|
"project memorix.yml": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
219610
220456
|
"user memorix.yml": { exists: false, path: "" },
|
|
220457
|
+
"project memorix.toml": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
220458
|
+
"user config.toml": { exists: false, path: "" },
|
|
219611
220459
|
"project .env": { exists: false, path: "", unavailable: !configProjectRoot },
|
|
219612
220460
|
"user .env": { exists: false, path: "" },
|
|
219613
220461
|
"legacy config.json": { exists: false, path: "" }
|
|
@@ -219617,6 +220465,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
219617
220465
|
const paths = {
|
|
219618
220466
|
"project memorix.yml": configProjectRoot ? join34(configProjectRoot, "memorix.yml") : null,
|
|
219619
220467
|
"user memorix.yml": join34(home, ".memorix", "memorix.yml"),
|
|
220468
|
+
"project memorix.toml": configProjectRoot ? join34(configProjectRoot, "memorix.toml") : null,
|
|
220469
|
+
"user config.toml": join34(home, ".memorix", "config.toml"),
|
|
219620
220470
|
"project .env": configProjectRoot ? join34(configProjectRoot, ".env") : null,
|
|
219621
220471
|
"user .env": join34(home, ".memorix", ".env"),
|
|
219622
220472
|
"legacy config.json": join34(home, ".memorix", "config.json")
|
|
@@ -219631,67 +220481,61 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
219631
220481
|
} catch {
|
|
219632
220482
|
}
|
|
219633
220483
|
const values = [];
|
|
219634
|
-
const
|
|
219635
|
-
|
|
219636
|
-
|
|
219637
|
-
|
|
219638
|
-
|
|
219639
|
-
|
|
219640
|
-
|
|
219641
|
-
|
|
219642
|
-
|
|
219643
|
-
|
|
219644
|
-
|
|
219645
|
-
|
|
219646
|
-
|
|
219647
|
-
|
|
219648
|
-
|
|
219649
|
-
|
|
219650
|
-
|
|
220484
|
+
const tomlSource = configProjectRoot && files["project memorix.toml"].exists ? "memorix.toml" : files["user config.toml"].exists ? "config.toml" : "default";
|
|
220485
|
+
const legacySource = files["project memorix.yml"].exists || files["user memorix.yml"].exists ? "memorix.yml" : files["legacy config.json"].exists ? "config.json" : "default";
|
|
220486
|
+
const configSource = resolved.sources.toml.length > 0 ? tomlSource : resolved.sources.legacy.length > 0 ? legacySource : "default";
|
|
220487
|
+
const source = (envKey) => resolveDashboardKeySource({
|
|
220488
|
+
value: process.env[envKey] ?? "",
|
|
220489
|
+
envKeys: [envKey],
|
|
220490
|
+
configSource
|
|
220491
|
+
});
|
|
220492
|
+
if (resolved.memory.llm.provider) values.push({ key: "llm.provider", value: resolved.memory.llm.provider, source: source("MEMORIX_LLM_PROVIDER") });
|
|
220493
|
+
if (resolved.memory.llm.model) values.push({ key: "llm.model", value: resolved.memory.llm.model, source: source("MEMORIX_LLM_MODEL") });
|
|
220494
|
+
const llmKey = resolved.memory.llm.apiKey;
|
|
220495
|
+
const memoryKeyEnv = [
|
|
220496
|
+
"MEMORIX_LLM_API_KEY",
|
|
220497
|
+
"MEMORIX_API_KEY",
|
|
220498
|
+
"OPENAI_API_KEY",
|
|
220499
|
+
"ANTHROPIC_API_KEY",
|
|
220500
|
+
...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : []
|
|
220501
|
+
];
|
|
219651
220502
|
if (llmKey) {
|
|
219652
|
-
|
|
219653
|
-
if (process.env.MEMORIX_LLM_API_KEY) src2 = await getEnvSource("MEMORIX_LLM_API_KEY");
|
|
219654
|
-
else if (process.env.MEMORIX_API_KEY) src2 = await getEnvSource("MEMORIX_API_KEY");
|
|
219655
|
-
else if (yml.llm?.apiKey) src2 = "memorix.yml (move to .env!)";
|
|
219656
|
-
else if (process.env.OPENAI_API_KEY) src2 = await getEnvSource("OPENAI_API_KEY");
|
|
220503
|
+
const src2 = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
|
|
219657
220504
|
values.push({ key: "llm.apiKey", value: "****" + llmKey.slice(-4), source: src2, sensitive: true });
|
|
219658
220505
|
} else {
|
|
219659
220506
|
values.push({ key: "llm.apiKey", value: "not set", source: "none" });
|
|
219660
220507
|
}
|
|
219661
|
-
|
|
219662
|
-
|
|
219663
|
-
|
|
219664
|
-
|
|
219665
|
-
|
|
219666
|
-
|
|
219667
|
-
|
|
219668
|
-
}
|
|
219669
|
-
const agentModel = process.env.MEMORIX_AGENT_MODEL || process.env.MEMORIX_AGENT_LLM_MODEL || yml.agent?.model;
|
|
219670
|
-
if (agentModel) {
|
|
219671
|
-
let source;
|
|
219672
|
-
if (process.env.MEMORIX_AGENT_MODEL) source = await getEnvSource("MEMORIX_AGENT_MODEL");
|
|
219673
|
-
else if (process.env.MEMORIX_AGENT_LLM_MODEL) source = `${await getEnvSource("MEMORIX_AGENT_LLM_MODEL")} (legacy)`;
|
|
219674
|
-
else source = yml.agent?.model ? "memorix.yml" : "default";
|
|
219675
|
-
values.push({ key: "agent.model", value: agentModel, source });
|
|
219676
|
-
}
|
|
219677
|
-
const agentKey = process.env.MEMORIX_AGENT_API_KEY || process.env.MEMORIX_AGENT_LLM_API_KEY || yml.agent?.apiKey;
|
|
220508
|
+
if (resolved.agent.provider) {
|
|
220509
|
+
values.push({ key: "agent.provider", value: resolved.agent.provider, source: source("MEMORIX_AGENT_PROVIDER") });
|
|
220510
|
+
}
|
|
220511
|
+
if (resolved.agent.model) {
|
|
220512
|
+
values.push({ key: "agent.model", value: resolved.agent.model, source: source("MEMORIX_AGENT_MODEL") });
|
|
220513
|
+
}
|
|
220514
|
+
const agentKey = resolved.agent.apiKey;
|
|
219678
220515
|
if (agentKey) {
|
|
219679
|
-
|
|
219680
|
-
|
|
219681
|
-
|
|
219682
|
-
|
|
220516
|
+
const src2 = resolveDashboardKeySource({
|
|
220517
|
+
value: agentKey,
|
|
220518
|
+
envKeys: ["MEMORIX_AGENT_API_KEY", "MEMORIX_AGENT_LLM_API_KEY"],
|
|
220519
|
+
configSource
|
|
220520
|
+
});
|
|
219683
220521
|
values.push({ key: "agent.apiKey", value: "****" + agentKey.slice(-4), source: src2, sensitive: true });
|
|
219684
220522
|
} else {
|
|
219685
|
-
values.push({
|
|
219686
|
-
|
|
219687
|
-
|
|
219688
|
-
|
|
219689
|
-
|
|
219690
|
-
|
|
219691
|
-
|
|
219692
|
-
if (
|
|
219693
|
-
|
|
219694
|
-
|
|
220523
|
+
values.push({
|
|
220524
|
+
key: "agent.apiKey",
|
|
220525
|
+
value: "fallback to llm.apiKey",
|
|
220526
|
+
source: llmKey ? resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource }) : "default"
|
|
220527
|
+
});
|
|
220528
|
+
}
|
|
220529
|
+
values.push({ key: "embedding.provider", value: resolved.embedding.provider || "off", source: source("MEMORIX_EMBEDDING") });
|
|
220530
|
+
if (resolved.embedding.model) values.push({ key: "embedding.model", value: resolved.embedding.model, source: source("MEMORIX_EMBEDDING_MODEL") });
|
|
220531
|
+
if (resolved.rerank.provider !== "off") {
|
|
220532
|
+
values.push({ key: "rerank.provider", value: resolved.rerank.provider, source: source("MEMORIX_RERANK_PROVIDER") });
|
|
220533
|
+
if (resolved.rerank.model) values.push({ key: "rerank.model", value: resolved.rerank.model, source: source("MEMORIX_RERANK_MODEL") });
|
|
220534
|
+
}
|
|
220535
|
+
values.push({ key: "git.autoHook", value: String(resolved.git.autoHook ?? false), source: configSource });
|
|
220536
|
+
values.push({ key: "git.skipMergeCommits", value: String(resolved.git.skipMergeCommits ?? true), source: configSource });
|
|
220537
|
+
values.push({ key: "server.transport", value: resolved.server.transport || "stdio", source: configSource });
|
|
220538
|
+
values.push({ key: "server.dashboard", value: String(resolved.server.dashboard ?? true), source: configSource });
|
|
219695
220539
|
sendJson(res, { files, values });
|
|
219696
220540
|
break;
|
|
219697
220541
|
}
|
|
@@ -219926,6 +220770,37 @@ function normalizeDashboardTask(task) {
|
|
|
219926
220770
|
preferredRole: task.preferred_role ?? task.preferredRole ?? null
|
|
219927
220771
|
};
|
|
219928
220772
|
}
|
|
220773
|
+
function emptyTeamSnapshot(mode, scope, status) {
|
|
220774
|
+
return {
|
|
220775
|
+
status,
|
|
220776
|
+
mode,
|
|
220777
|
+
readOnly: true,
|
|
220778
|
+
scope,
|
|
220779
|
+
agents: [],
|
|
220780
|
+
activeCount: 0,
|
|
220781
|
+
recentCount: 0,
|
|
220782
|
+
historicalCount: 0,
|
|
220783
|
+
totalAgents: 0,
|
|
220784
|
+
recentWindowDays: 7,
|
|
220785
|
+
locks: [],
|
|
220786
|
+
tasks: [],
|
|
220787
|
+
availableTasks: 0,
|
|
220788
|
+
sessions: 0,
|
|
220789
|
+
roles: [],
|
|
220790
|
+
roleOccupancy: [],
|
|
220791
|
+
handoffs: [],
|
|
220792
|
+
openTasks: 0,
|
|
220793
|
+
openHandoffs: 0,
|
|
220794
|
+
totalUnread: 0,
|
|
220795
|
+
activeSessions: 0,
|
|
220796
|
+
error: status === "error" ? "Coordination state unavailable" : "Coordination state is incomplete",
|
|
220797
|
+
errorCode: status === "error" ? "COORDINATION_STATE_UNAVAILABLE" : "COORDINATION_STATE_DEGRADED"
|
|
220798
|
+
};
|
|
220799
|
+
}
|
|
220800
|
+
function logTeamSnapshotFailure(scope, status) {
|
|
220801
|
+
const safeScope = scope === "global" ? "global" : "project";
|
|
220802
|
+
console.error("[dashboard] coordination snapshot unavailable", { status, scope: safeScope });
|
|
220803
|
+
}
|
|
219929
220804
|
async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
219930
220805
|
try {
|
|
219931
220806
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
@@ -219952,8 +220827,9 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
|
219952
220827
|
const roleOccupancy = effectiveProjectId ? teamStore.getRoleOccupancy(effectiveProjectId) : [];
|
|
219953
220828
|
const handoffs = effectiveProjectId ? teamStore.listHandoffs(effectiveProjectId) : [];
|
|
219954
220829
|
return {
|
|
220830
|
+
status: "ok",
|
|
219955
220831
|
mode,
|
|
219956
|
-
readOnly:
|
|
220832
|
+
readOnly: true,
|
|
219957
220833
|
scope,
|
|
219958
220834
|
agents: withTier,
|
|
219959
220835
|
activeCount,
|
|
@@ -219974,28 +220850,8 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
|
219974
220850
|
activeSessions: activeCount
|
|
219975
220851
|
};
|
|
219976
220852
|
} catch {
|
|
219977
|
-
|
|
219978
|
-
|
|
219979
|
-
readOnly: mode === "standalone",
|
|
219980
|
-
scope,
|
|
219981
|
-
agents: [],
|
|
219982
|
-
activeCount: 0,
|
|
219983
|
-
recentCount: 0,
|
|
219984
|
-
historicalCount: 0,
|
|
219985
|
-
totalAgents: 0,
|
|
219986
|
-
recentWindowDays: 7,
|
|
219987
|
-
locks: [],
|
|
219988
|
-
tasks: [],
|
|
219989
|
-
availableTasks: 0,
|
|
219990
|
-
sessions: 0,
|
|
219991
|
-
roles: [],
|
|
219992
|
-
roleOccupancy: [],
|
|
219993
|
-
handoffs: [],
|
|
219994
|
-
openTasks: 0,
|
|
219995
|
-
openHandoffs: 0,
|
|
219996
|
-
totalUnread: 0,
|
|
219997
|
-
activeSessions: 0
|
|
219998
|
-
};
|
|
220853
|
+
logTeamSnapshotFailure(scope, "error");
|
|
220854
|
+
return emptyTeamSnapshot(mode, scope, "error");
|
|
219999
220855
|
}
|
|
220000
220856
|
}
|
|
220001
220857
|
function readBody(req) {
|
|
@@ -220014,13 +220870,12 @@ function readBody(req) {
|
|
|
220014
220870
|
req.on("error", reject);
|
|
220015
220871
|
});
|
|
220016
220872
|
}
|
|
220017
|
-
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true,
|
|
220873
|
+
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true, projectRoot = null, projectResolved = true) {
|
|
220018
220874
|
await initObservationStore(dataDir);
|
|
220019
220875
|
await initSessionStore(dataDir);
|
|
220020
220876
|
const resolvedStaticDir = staticDir;
|
|
220021
220877
|
const baseDir = getBaseDataDir();
|
|
220022
|
-
const
|
|
220023
|
-
const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: isControlPlane ? "control-plane" : "standalone", port };
|
|
220878
|
+
const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: "standalone", port };
|
|
220024
220879
|
const server = createServer(async (req, res) => {
|
|
220025
220880
|
const url2 = req.url || "/";
|
|
220026
220881
|
if (url2.startsWith("/api/set-current-project") && req.method === "POST") {
|
|
@@ -220042,54 +220897,20 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
220042
220897
|
}
|
|
220043
220898
|
return;
|
|
220044
220899
|
}
|
|
220045
|
-
|
|
220046
|
-
|
|
220047
|
-
|
|
220048
|
-
const scope = parsedUrl.searchParams.get("scope") || "project";
|
|
220049
|
-
sendJson(res, await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode));
|
|
220050
|
-
return;
|
|
220051
|
-
}
|
|
220052
|
-
try {
|
|
220053
|
-
teamInstances.fileLocks.cleanExpired();
|
|
220054
|
-
const agents = teamInstances.registry.listAgents();
|
|
220055
|
-
const locks = teamInstances.fileLocks.listLocks();
|
|
220056
|
-
const tasks = teamInstances.taskManager.list();
|
|
220057
|
-
const available = teamInstances.taskManager.getAvailable();
|
|
220058
|
-
let roles = [];
|
|
220059
|
-
let roleOccupancy = [];
|
|
220060
|
-
let handoffs = [];
|
|
220061
|
-
try {
|
|
220062
|
-
const { getTeamStore: getTeamStore2, isTeamStoreInitialized: isTeamStoreInitialized2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
220063
|
-
if (isTeamStoreInitialized2()) {
|
|
220064
|
-
const teamStore = getTeamStore2();
|
|
220065
|
-
const projectId2 = state.projectId;
|
|
220066
|
-
roles = teamStore.listRoles(projectId2);
|
|
220067
|
-
roleOccupancy = teamStore.getRoleOccupancy(projectId2);
|
|
220068
|
-
handoffs = teamStore.listHandoffs(projectId2);
|
|
220069
|
-
}
|
|
220070
|
-
} catch {
|
|
220071
|
-
}
|
|
220900
|
+
const parsedUrl = new URL(url2, `http://127.0.0.1:${port}`);
|
|
220901
|
+
if (parsedUrl.pathname === "/api/team") {
|
|
220902
|
+
if (req.method !== "GET") {
|
|
220072
220903
|
sendJson(res, {
|
|
220073
|
-
|
|
220074
|
-
|
|
220075
|
-
|
|
220076
|
-
|
|
220077
|
-
|
|
220078
|
-
|
|
220079
|
-
tasks,
|
|
220080
|
-
availableTasks: available.length,
|
|
220081
|
-
roles,
|
|
220082
|
-
roleOccupancy,
|
|
220083
|
-
handoffs,
|
|
220084
|
-
// Resume data for "Continue this project" area
|
|
220085
|
-
openTasks: tasks.filter((t4) => t4.status === "pending" || t4.status === "in_progress").length,
|
|
220086
|
-
openHandoffs: handoffs.filter((h5) => h5.handoff_status === "open" || h5.handoffStatus === "open").length,
|
|
220087
|
-
totalUnread: agents.reduce((sum, a4) => sum + teamInstances.messageBus.getUnreadCount(a4.id), 0),
|
|
220088
|
-
activeSessions: agents.filter((a4) => a4.status === "active").length
|
|
220089
|
-
});
|
|
220090
|
-
} catch {
|
|
220091
|
-
sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0, roles: [], roleOccupancy: [], handoffs: [] });
|
|
220904
|
+
status: "error",
|
|
220905
|
+
readOnly: true,
|
|
220906
|
+
error: "Coordination status is read-only",
|
|
220907
|
+
errorCode: "COORDINATION_STATUS_READ_ONLY"
|
|
220908
|
+
}, 405);
|
|
220909
|
+
return;
|
|
220092
220910
|
}
|
|
220911
|
+
const scope = parsedUrl.searchParams.get("scope") || "project";
|
|
220912
|
+
const snapshot = await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode);
|
|
220913
|
+
sendJson(res, snapshot, snapshot.status === "error" ? 503 : 200);
|
|
220093
220914
|
return;
|
|
220094
220915
|
}
|
|
220095
220916
|
if (url2.startsWith("/api/")) {
|
|
@@ -220110,13 +220931,12 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
220110
220931
|
server.listen(port, "127.0.0.1", () => {
|
|
220111
220932
|
const url2 = `http://127.0.0.1:${port}`;
|
|
220112
220933
|
const resolvedLabel = projectResolved ? "resolved" : "unresolved";
|
|
220113
|
-
const modeLabel =
|
|
220934
|
+
const modeLabel = "Standalone";
|
|
220114
220935
|
console.error(` Memorix Dashboard [${modeLabel}]`);
|
|
220115
220936
|
console.error(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
220116
220937
|
console.error(` Mode: ${modeLabel}`);
|
|
220117
220938
|
console.error(` Project: ${projectName} (${projectId}) [${resolvedLabel}]`);
|
|
220118
220939
|
console.error(` Local: ${url2}`);
|
|
220119
|
-
if (isControlPlane) console.error(` MCP: ${url2}/mcp`);
|
|
220120
220940
|
console.error(` Data dir: ${dataDir}`);
|
|
220121
220941
|
console.error(`
|
|
220122
220942
|
Press Ctrl+C to stop
|
|
@@ -220139,10 +220959,14 @@ var init_server3 = __esm({
|
|
|
220139
220959
|
init_dotenv_loader();
|
|
220140
220960
|
init_yaml_loader();
|
|
220141
220961
|
init_yaml_loader();
|
|
220962
|
+
init_resolved_config();
|
|
220142
220963
|
init_graph_scope();
|
|
220143
220964
|
init_retention();
|
|
220144
220965
|
init_visibility();
|
|
220966
|
+
init_evidence_store();
|
|
220967
|
+
init_feedback();
|
|
220145
220968
|
init_maintenance();
|
|
220969
|
+
init_config_provenance();
|
|
220146
220970
|
MIME_TYPES = {
|
|
220147
220971
|
".html": "text/html; charset=utf-8",
|
|
220148
220972
|
".css": "text/css; charset=utf-8",
|
|
@@ -260174,7 +260998,7 @@ __export(server_exports2, {
|
|
|
260174
260998
|
createMemorixServer: () => createMemorixServer,
|
|
260175
260999
|
shouldAwaitProjectRuntime: () => shouldAwaitProjectRuntime
|
|
260176
261000
|
});
|
|
260177
|
-
import { createHash as
|
|
261001
|
+
import { createHash as createHash18 } from "crypto";
|
|
260178
261002
|
function formatFormationStageDurations(stageDurationsMs) {
|
|
260179
261003
|
const orderedStages = ["extract", "resolve", "evaluate"];
|
|
260180
261004
|
const parts = orderedStages.filter((stage) => stageDurationsMs[stage] !== void 0).map((stage) => `${stage}=${stageDurationsMs[stage]}ms`);
|
|
@@ -260256,7 +261080,7 @@ function coerceObjectArray(val) {
|
|
|
260256
261080
|
return [];
|
|
260257
261081
|
}
|
|
260258
261082
|
function createDeterministicInstanceId(projectId, agentType, agentName) {
|
|
260259
|
-
const digest2 =
|
|
261083
|
+
const digest2 = createHash18("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
|
|
260260
261084
|
return `auto-${digest2}`;
|
|
260261
261085
|
}
|
|
260262
261086
|
function shouldAwaitProjectRuntime(toolName) {
|
|
@@ -260548,7 +261372,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
260548
261372
|
};
|
|
260549
261373
|
const server = existingServer ?? new McpServer({
|
|
260550
261374
|
name: "memorix",
|
|
260551
|
-
version: true ? "1.
|
|
261375
|
+
version: true ? "1.8.1" : "1.0.1"
|
|
260552
261376
|
});
|
|
260553
261377
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
260554
261378
|
server.registerTool = ((name, ...args) => {
|
|
@@ -263701,7 +264525,7 @@ ${json4}
|
|
|
263701
264525
|
}
|
|
263702
264526
|
}
|
|
263703
264527
|
console.error(`[memorix] Dashboard staticDir: ${staticDir}`);
|
|
263704
|
-
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false,
|
|
264528
|
+
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false, project.rootPath, projectResolved).then(() => {
|
|
263705
264529
|
dashboardRunning = true;
|
|
263706
264530
|
}).catch((err) => {
|
|
263707
264531
|
console.error("[memorix] Dashboard error:", err);
|
|
@@ -263727,7 +264551,7 @@ ${json4}
|
|
|
263727
264551
|
dashboardRunning = true;
|
|
263728
264552
|
const { exec: execCmd } = await import("child_process");
|
|
263729
264553
|
const openCmd = process.platform === "win32" ? `start "" "${url2}"` : process.platform === "darwin" ? `open "${url2}"` : `xdg-open "${url2}"`;
|
|
263730
|
-
execCmd(openCmd, () => {
|
|
264554
|
+
execCmd(openCmd, { windowsHide: true }, () => {
|
|
263731
264555
|
});
|
|
263732
264556
|
return {
|
|
263733
264557
|
content: [{
|
|
@@ -263751,6 +264575,113 @@ ${json4}
|
|
|
263751
264575
|
}
|
|
263752
264576
|
}
|
|
263753
264577
|
);
|
|
264578
|
+
server.registerTool(
|
|
264579
|
+
"memorix_evidence",
|
|
264580
|
+
{
|
|
264581
|
+
title: "Evidence Cards",
|
|
264582
|
+
description: "Inspect the bounded, project-scoped provenance cards behind Memorix context. Use list for a compact index, get/events for one source, sync to repair the projection, and stale when known source files changed. Cards expose sourceRef, locator, capturedHash, and freshness.",
|
|
264583
|
+
inputSchema: {
|
|
264584
|
+
action: external_exports2.enum(["list", "get", "sync", "stale", "events"]).describe("Evidence operation"),
|
|
264585
|
+
candidateKind: external_exports2.enum(["observation", "code", "git", "test", "document", "workflow", "graph"]).optional().default("observation"),
|
|
264586
|
+
candidateId: external_exports2.string().optional().describe("Candidate id, usually an observation id"),
|
|
264587
|
+
query: external_exports2.string().optional().describe("Optional title/source query for list"),
|
|
264588
|
+
paths: external_exports2.array(external_exports2.string()).max(200).optional().describe("Changed source paths for stale"),
|
|
264589
|
+
reason: external_exports2.string().max(500).optional().describe("Why evidence became stale"),
|
|
264590
|
+
limit: external_exports2.number().int().positive().max(100).optional().default(20)
|
|
264591
|
+
}
|
|
264592
|
+
},
|
|
264593
|
+
async ({ action, candidateKind, candidateId, query, paths, reason, limit: limit2 }) => {
|
|
264594
|
+
const unresolved = requireResolvedProject("inspect evidence cards for the current project");
|
|
264595
|
+
if (unresolved) return unresolved;
|
|
264596
|
+
const cards = new EvidenceCardStore();
|
|
264597
|
+
await cards.init(projectDir2);
|
|
264598
|
+
if (action === "sync") {
|
|
264599
|
+
const observations2 = await getObservationStore().loadByProject(project.id);
|
|
264600
|
+
const synced = cards.syncObservations(observations2);
|
|
264601
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, synced: synced.length, cards: synced.slice(0, limit2 ?? 20) }, null, 2) }] };
|
|
264602
|
+
}
|
|
264603
|
+
if (action === "stale") {
|
|
264604
|
+
const changed = cards.markStaleForPaths(project.id, paths ?? [], reason ?? "source file changed");
|
|
264605
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, staleMarked: changed, paths: paths ?? [] }, null, 2) }] };
|
|
264606
|
+
}
|
|
264607
|
+
if (action === "get") {
|
|
264608
|
+
if (!candidateId?.trim()) return { content: [{ type: "text", text: "candidateId is required for evidence get." }], isError: true };
|
|
264609
|
+
const card = cards.get(project.id, candidateKind ?? "observation", candidateId.trim());
|
|
264610
|
+
if (!card) return { content: [{ type: "text", text: "Evidence card not found." }], isError: true };
|
|
264611
|
+
return { content: [{ type: "text", text: JSON.stringify({ card, events: cards.listEvents(card.id), projectId: project.id }, null, 2) }] };
|
|
264612
|
+
}
|
|
264613
|
+
if (action === "events") {
|
|
264614
|
+
if (!candidateId?.trim()) return { content: [{ type: "text", text: "candidateId is required for evidence events." }], isError: true };
|
|
264615
|
+
const card = cards.get(project.id, candidateKind ?? "observation", candidateId.trim());
|
|
264616
|
+
if (!card) return { content: [{ type: "text", text: "Evidence card not found." }], isError: true };
|
|
264617
|
+
return { content: [{ type: "text", text: JSON.stringify(cards.listEvents(card.id, limit2), null, 2) }] };
|
|
264618
|
+
}
|
|
264619
|
+
const needle = query?.trim().toLowerCase();
|
|
264620
|
+
const listed = cards.list(project.id, { limit: Math.max(limit2 ?? 20, 100) }).filter((card) => !needle || [card.title, card.summary, card.sourceRef, card.locator ?? ""].join(" ").toLowerCase().includes(needle)).slice(0, limit2 ?? 20);
|
|
264621
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, cards: listed }, null, 2) }] };
|
|
264622
|
+
}
|
|
264623
|
+
);
|
|
264624
|
+
server.registerTool(
|
|
264625
|
+
"memorix_feedback",
|
|
264626
|
+
{
|
|
264627
|
+
title: "Memory Feedback",
|
|
264628
|
+
description: "Record or inspect auditable memory outcomes. Positive verification/use strengthens recall; correction, conflict, source change, or weaken lowers it. Use revoke with targetEventId to undo one prior signal without deleting audit history.",
|
|
264629
|
+
inputSchema: {
|
|
264630
|
+
action: external_exports2.enum(["record", "show", "audit"]).describe("Feedback operation"),
|
|
264631
|
+
candidateKind: external_exports2.enum(["observation", "claim", "durable-memory", "workflow"]).optional().default("observation"),
|
|
264632
|
+
candidateId: external_exports2.string().describe("Memory or knowledge candidate id"),
|
|
264633
|
+
signal: external_exports2.enum(["user-correction", "verification-success", "verification-failure", "code-change", "used", "not-used", "code-conflict", "strengthen", "weaken", "revoke"]).optional(),
|
|
264634
|
+
sourceRef: external_exports2.string().max(500).optional().describe("Source of this feedback, such as test:run-42 or user:chat"),
|
|
264635
|
+
actor: external_exports2.string().max(200).optional(),
|
|
264636
|
+
note: external_exports2.string().max(2e3).optional(),
|
|
264637
|
+
targetEventId: external_exports2.string().optional().describe("Existing event id when action=record and signal=revoke"),
|
|
264638
|
+
limit: external_exports2.number().int().positive().max(200).optional().default(100)
|
|
264639
|
+
}
|
|
264640
|
+
},
|
|
264641
|
+
async ({ action, candidateKind, candidateId, signal, sourceRef, actor, note, targetEventId, limit: limit2 }) => {
|
|
264642
|
+
const unresolved = requireResolvedProject("record memory feedback for the current project");
|
|
264643
|
+
if (unresolved) return unresolved;
|
|
264644
|
+
const feedback = new MemoryFeedbackStore();
|
|
264645
|
+
await feedback.init(projectDir2);
|
|
264646
|
+
const kind = candidateKind ?? "observation";
|
|
264647
|
+
if (action === "show") {
|
|
264648
|
+
return { content: [{ type: "text", text: JSON.stringify(feedback.getState(project.id, kind, candidateId), null, 2) }] };
|
|
264649
|
+
}
|
|
264650
|
+
if (action === "audit") {
|
|
264651
|
+
return { content: [{ type: "text", text: JSON.stringify(feedback.audit(project.id, kind, candidateId, limit2), null, 2) }] };
|
|
264652
|
+
}
|
|
264653
|
+
if (!signal || !sourceRef?.trim()) {
|
|
264654
|
+
return { content: [{ type: "text", text: "record requires signal and sourceRef." }], isError: true };
|
|
264655
|
+
}
|
|
264656
|
+
try {
|
|
264657
|
+
const result = feedback.record({
|
|
264658
|
+
projectId: project.id,
|
|
264659
|
+
candidateKind: kind,
|
|
264660
|
+
candidateId,
|
|
264661
|
+
signal,
|
|
264662
|
+
sourceRef,
|
|
264663
|
+
...actor || currentAgentId ? { actor: actor ?? currentAgentId } : {},
|
|
264664
|
+
...note ? { note } : {},
|
|
264665
|
+
...targetEventId ? { targetEventId } : {}
|
|
264666
|
+
});
|
|
264667
|
+
if (kind === "observation") {
|
|
264668
|
+
const cards = new EvidenceCardStore();
|
|
264669
|
+
await cards.init(projectDir2);
|
|
264670
|
+
const card = cards.get(project.id, "observation", candidateId);
|
|
264671
|
+
if (card) {
|
|
264672
|
+
const verification = signal === "verification-success" || signal === "strengthen" ? "verified" : signal === "user-correction" || signal === "code-conflict" || signal === "weaken" ? "conflicted" : card.verification;
|
|
264673
|
+
cards.recordEvent(project.id, card.id, `feedback:${signal}`, note);
|
|
264674
|
+
if (verification !== card.verification) {
|
|
264675
|
+
cards.setVerification(project.id, card.id, verification);
|
|
264676
|
+
}
|
|
264677
|
+
}
|
|
264678
|
+
}
|
|
264679
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
264680
|
+
} catch (error40) {
|
|
264681
|
+
return { content: [{ type: "text", text: error40 instanceof Error ? error40.message : String(error40) }], isError: true };
|
|
264682
|
+
}
|
|
264683
|
+
}
|
|
264684
|
+
);
|
|
263754
264685
|
if (teamFeaturesEnabled) {
|
|
263755
264686
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
263756
264687
|
initTeamStoreForProject = initTeamStore2;
|
|
@@ -263936,7 +264867,7 @@ ${lines.join("\n")}` }] };
|
|
|
263936
264867
|
server.registerTool(
|
|
263937
264868
|
"team_task",
|
|
263938
264869
|
{
|
|
263939
|
-
title: "Task
|
|
264870
|
+
title: "Task Status",
|
|
263940
264871
|
description: 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. Action "create": create a task. Action "claim": assign to yourself (atomic, race-safe). Action "complete": mark done with result. Action "list": show tasks.',
|
|
263941
264872
|
inputSchema: {
|
|
263942
264873
|
action: external_exports2.enum(["create", "claim", "complete", "list"]).describe("Operation to perform"),
|
|
@@ -264806,6 +265737,8 @@ var init_server4 = __esm({
|
|
|
264806
265737
|
init_launch_root();
|
|
264807
265738
|
init_aliases();
|
|
264808
265739
|
init_persistence();
|
|
265740
|
+
init_evidence_store();
|
|
265741
|
+
init_feedback();
|
|
264809
265742
|
init_syncer();
|
|
264810
265743
|
init_engine5();
|
|
264811
265744
|
init_tool_profile();
|
|
@@ -265292,6 +266225,35 @@ var init_serve = __esm({
|
|
|
265292
266225
|
}
|
|
265293
266226
|
});
|
|
265294
266227
|
|
|
266228
|
+
// src/server/mcp-diagnostics.ts
|
|
266229
|
+
function getMcpDiagnostics() {
|
|
266230
|
+
return {
|
|
266231
|
+
serverName: MCP_SERVER_NAME,
|
|
266232
|
+
protocol: {
|
|
266233
|
+
current: CURRENT_MCP_PROTOCOL_VERSION,
|
|
266234
|
+
legacy: LEGACY_MCP_PROTOCOL_VERSION,
|
|
266235
|
+
statelessRequests: "supported",
|
|
266236
|
+
statefulStreamableHttp: "supported"
|
|
266237
|
+
},
|
|
266238
|
+
capabilities: {
|
|
266239
|
+
tasks: "unsupported",
|
|
266240
|
+
polling: "unsupported",
|
|
266241
|
+
listCache: "supported",
|
|
266242
|
+
explicitProjectHandle: "supported"
|
|
266243
|
+
}
|
|
266244
|
+
};
|
|
266245
|
+
}
|
|
266246
|
+
var CURRENT_MCP_PROTOCOL_VERSION, LEGACY_MCP_PROTOCOL_VERSION, MCP_SERVER_NAME;
|
|
266247
|
+
var init_mcp_diagnostics = __esm({
|
|
266248
|
+
"src/server/mcp-diagnostics.ts"() {
|
|
266249
|
+
"use strict";
|
|
266250
|
+
init_esm_shims();
|
|
266251
|
+
CURRENT_MCP_PROTOCOL_VERSION = "2026-07-28";
|
|
266252
|
+
LEGACY_MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
266253
|
+
MCP_SERVER_NAME = "io.github.AVIDS2/memorix";
|
|
266254
|
+
}
|
|
266255
|
+
});
|
|
266256
|
+
|
|
265295
266257
|
// src/cli/port.ts
|
|
265296
266258
|
function parseTcpPort(value, defaultPort) {
|
|
265297
266259
|
const raw = value?.trim() || String(defaultPort);
|
|
@@ -267388,6 +268350,79 @@ var init_streamableHttp = __esm({
|
|
|
267388
268350
|
}
|
|
267389
268351
|
});
|
|
267390
268352
|
|
|
268353
|
+
// src/server/mcp-binding-store.ts
|
|
268354
|
+
var mcp_binding_store_exports = {};
|
|
268355
|
+
__export(mcp_binding_store_exports, {
|
|
268356
|
+
McpBindingStore: () => McpBindingStore
|
|
268357
|
+
});
|
|
268358
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
268359
|
+
function rowToBinding(row) {
|
|
268360
|
+
return {
|
|
268361
|
+
handleId: String(row.handle_id),
|
|
268362
|
+
projectId: String(row.project_id),
|
|
268363
|
+
projectRoot: String(row.project_root),
|
|
268364
|
+
dataDir: String(row.data_dir),
|
|
268365
|
+
createdAt: String(row.created_at),
|
|
268366
|
+
lastUsedAt: String(row.last_used_at),
|
|
268367
|
+
...row.expires_at ? { expiresAt: String(row.expires_at) } : {}
|
|
268368
|
+
};
|
|
268369
|
+
}
|
|
268370
|
+
var McpBindingStore;
|
|
268371
|
+
var init_mcp_binding_store = __esm({
|
|
268372
|
+
"src/server/mcp-binding-store.ts"() {
|
|
268373
|
+
"use strict";
|
|
268374
|
+
init_esm_shims();
|
|
268375
|
+
init_sqlite_db();
|
|
268376
|
+
McpBindingStore = class {
|
|
268377
|
+
db = null;
|
|
268378
|
+
async init(dataDir) {
|
|
268379
|
+
this.db = getDatabase(dataDir);
|
|
268380
|
+
}
|
|
268381
|
+
requireDb() {
|
|
268382
|
+
if (!this.db) throw new Error("McpBindingStore is not initialized.");
|
|
268383
|
+
return this.db;
|
|
268384
|
+
}
|
|
268385
|
+
create(input) {
|
|
268386
|
+
const now3 = /* @__PURE__ */ new Date();
|
|
268387
|
+
const binding = {
|
|
268388
|
+
handleId: `mxh_${randomUUID19().replace(/-/g, "")}`,
|
|
268389
|
+
projectId: input.projectId,
|
|
268390
|
+
projectRoot: input.projectRoot,
|
|
268391
|
+
dataDir: input.dataDir,
|
|
268392
|
+
createdAt: now3.toISOString(),
|
|
268393
|
+
lastUsedAt: now3.toISOString(),
|
|
268394
|
+
...input.ttlMs && input.ttlMs > 0 ? { expiresAt: new Date(now3.getTime() + input.ttlMs).toISOString() } : {}
|
|
268395
|
+
};
|
|
268396
|
+
this.requireDb().prepare(`
|
|
268397
|
+
INSERT INTO mcp_bindings (handle_id, project_id, project_root, data_dir, created_at, last_used_at, expires_at)
|
|
268398
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
268399
|
+
`).run(binding.handleId, binding.projectId, binding.projectRoot, binding.dataDir, binding.createdAt, binding.lastUsedAt, binding.expiresAt ?? null);
|
|
268400
|
+
return binding;
|
|
268401
|
+
}
|
|
268402
|
+
get(handleId) {
|
|
268403
|
+
const row = this.requireDb().prepare(`SELECT * FROM mcp_bindings WHERE handle_id = ?`).get(handleId);
|
|
268404
|
+
if (!row) return void 0;
|
|
268405
|
+
const binding = rowToBinding(row);
|
|
268406
|
+
if (binding.expiresAt && Date.parse(binding.expiresAt) <= Date.now()) {
|
|
268407
|
+
this.delete(handleId);
|
|
268408
|
+
return void 0;
|
|
268409
|
+
}
|
|
268410
|
+
return binding;
|
|
268411
|
+
}
|
|
268412
|
+
touch(handleId) {
|
|
268413
|
+
const binding = this.get(handleId);
|
|
268414
|
+
if (!binding) return void 0;
|
|
268415
|
+
const lastUsedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
268416
|
+
this.requireDb().prepare(`UPDATE mcp_bindings SET last_used_at = ? WHERE handle_id = ?`).run(lastUsedAt, handleId);
|
|
268417
|
+
return { ...binding, lastUsedAt };
|
|
268418
|
+
}
|
|
268419
|
+
delete(handleId) {
|
|
268420
|
+
this.requireDb().prepare(`DELETE FROM mcp_bindings WHERE handle_id = ?`).run(handleId);
|
|
268421
|
+
}
|
|
268422
|
+
};
|
|
268423
|
+
}
|
|
268424
|
+
});
|
|
268425
|
+
|
|
267391
268426
|
// src/runtime/control-plane-maintenance.ts
|
|
267392
268427
|
var control_plane_maintenance_exports = {};
|
|
267393
268428
|
__export(control_plane_maintenance_exports, {
|
|
@@ -267455,6 +268490,7 @@ var serve_http_exports = {};
|
|
|
267455
268490
|
__export(serve_http_exports, {
|
|
267456
268491
|
DEFAULT_SESSION_TIMEOUT_MS: () => DEFAULT_SESSION_TIMEOUT_MS,
|
|
267457
268492
|
EXPIRED_SESSION_TTL_MS: () => EXPIRED_SESSION_TTL_MS,
|
|
268493
|
+
MCP_SDK_COMPAT_PROTOCOL_VERSION: () => MCP_SDK_COMPAT_PROTOCOL_VERSION,
|
|
267458
268494
|
_testing: () => _testing2,
|
|
267459
268495
|
default: () => serve_http_default,
|
|
267460
268496
|
parseSessionTimeoutMs: () => parseSessionTimeoutMs,
|
|
@@ -267476,7 +268512,7 @@ function resolveServeHttpDefaults(argsPort, configured) {
|
|
|
267476
268512
|
const transportNotice = configured.transport === "stdio" ? '[memorix] config server.transport = "stdio"; serve-http continues on HTTP (the explicit command wins).' : void 0;
|
|
267477
268513
|
return { port, transportNotice };
|
|
267478
268514
|
}
|
|
267479
|
-
var DEFAULT_SESSION_TIMEOUT_MS, EXPIRED_SESSION_TTL_MS, serve_http_default, _testing2;
|
|
268515
|
+
var DEFAULT_SESSION_TIMEOUT_MS, EXPIRED_SESSION_TTL_MS, MCP_SDK_COMPAT_PROTOCOL_VERSION, serve_http_default, _testing2;
|
|
267480
268516
|
var init_serve_http = __esm({
|
|
267481
268517
|
"src/cli/commands/serve-http.ts"() {
|
|
267482
268518
|
"use strict";
|
|
@@ -267486,10 +268522,12 @@ var init_serve_http = __esm({
|
|
|
267486
268522
|
init_graph_scope();
|
|
267487
268523
|
init_retention();
|
|
267488
268524
|
init_visibility();
|
|
268525
|
+
init_mcp_diagnostics();
|
|
267489
268526
|
init_port();
|
|
267490
268527
|
init_mcp_root_path();
|
|
267491
268528
|
DEFAULT_SESSION_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
|
|
267492
268529
|
EXPIRED_SESSION_TTL_MS = 10 * 60 * 1e3;
|
|
268530
|
+
MCP_SDK_COMPAT_PROTOCOL_VERSION = "2025-11-25";
|
|
267493
268531
|
serve_http_default = defineCommand({
|
|
267494
268532
|
meta: {
|
|
267495
268533
|
name: "serve-http",
|
|
@@ -267519,7 +268557,7 @@ var init_serve_http = __esm({
|
|
|
267519
268557
|
},
|
|
267520
268558
|
run: async ({ args }) => {
|
|
267521
268559
|
const { createServer: createServer3 } = await import("http");
|
|
267522
|
-
const { randomUUID:
|
|
268560
|
+
const { randomUUID: randomUUID20 } = await import("crypto");
|
|
267523
268561
|
const { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 } = await Promise.resolve().then(() => (init_streamableHttp(), streamableHttp_exports));
|
|
267524
268562
|
const { isInitializeRequest: isInitializeRequest2 } = await Promise.resolve().then(() => (init_types8(), types_exports3));
|
|
267525
268563
|
const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
|
|
@@ -267527,6 +268565,8 @@ var init_serve_http = __esm({
|
|
|
267527
268565
|
const { findGitInSubdirs: findGitInSubdirs2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
|
|
267528
268566
|
const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync12 } = await import("fs");
|
|
267529
268567
|
const { homedir: homedir36 } = await import("os");
|
|
268568
|
+
const { McpBindingStore: McpBindingStore2 } = await Promise.resolve().then(() => (init_mcp_binding_store(), mcp_binding_store_exports));
|
|
268569
|
+
const { MemoryFeedbackStore: MemoryFeedbackStore2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
|
|
267530
268570
|
let configuredDefaults = {};
|
|
267531
268571
|
try {
|
|
267532
268572
|
const { getServerConfig: getServerConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -267579,9 +268619,8 @@ var init_serve_http = __esm({
|
|
|
267579
268619
|
teamStoreCache.set(dataDir, store2);
|
|
267580
268620
|
return store2;
|
|
267581
268621
|
}
|
|
267582
|
-
const
|
|
267583
|
-
|
|
267584
|
-
const sharedTeamStore = await getTeamStore2(teamDataDir);
|
|
268622
|
+
const statelessBindingStore = new McpBindingStore2();
|
|
268623
|
+
await statelessBindingStore.init(persistMod.getBaseDataDir());
|
|
267585
268624
|
const sessions = /* @__PURE__ */ new Map();
|
|
267586
268625
|
const sessionLastActivity = /* @__PURE__ */ new Map();
|
|
267587
268626
|
const expiredSessions = /* @__PURE__ */ new Map();
|
|
@@ -267721,12 +268760,91 @@ var init_serve_http = __esm({
|
|
|
267721
268760
|
res.setHeader("Vary", "Origin");
|
|
267722
268761
|
}
|
|
267723
268762
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
267724
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Mcp-Session-Id, Last-Event-Id");
|
|
267725
|
-
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
|
|
268763
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Mcp-Session-Id, Mcp-Project-Handle, Mcp-Project-Root, Mcp-Stateless, Last-Event-Id");
|
|
268764
|
+
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id, Mcp-Project-Handle, Mcp-Protocol-Version, Mcp-Method, Mcp-Name");
|
|
268765
|
+
res.setHeader("Mcp-Protocol-Version", req.headers["mcp-protocol-version"] || CURRENT_MCP_PROTOCOL_VERSION);
|
|
268766
|
+
res.setHeader("Mcp-Method", req.method || "UNKNOWN");
|
|
268767
|
+
res.setHeader("Mcp-Name", MCP_SERVER_NAME);
|
|
268768
|
+
}
|
|
268769
|
+
async function handleStatelessPost(req, res, body) {
|
|
268770
|
+
const handleId = typeof req.headers["mcp-project-handle"] === "string" ? req.headers["mcp-project-handle"] : void 0;
|
|
268771
|
+
const persisted = handleId ? statelessBindingStore.touch(handleId) : void 0;
|
|
268772
|
+
if (handleId && !persisted) {
|
|
268773
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
268774
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32001, message: "MCP project handle not found or expired; initialize again." }, id: null }));
|
|
268775
|
+
return;
|
|
268776
|
+
}
|
|
268777
|
+
const requestedRoot = typeof req.headers["mcp-project-root"] === "string" ? req.headers["mcp-project-root"] : void 0;
|
|
268778
|
+
const root = persisted?.projectRoot ?? requestedRoot ?? projectRoot;
|
|
268779
|
+
if (!persisted && !isInitializeRequest2(body)) {
|
|
268780
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
268781
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32e3, message: "Stateless MCP requests require Mcp-Project-Handle; initialize first." }, id: null }));
|
|
268782
|
+
return;
|
|
268783
|
+
}
|
|
268784
|
+
const { createMemorixServer: createMemorixServer3 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
|
|
268785
|
+
const { createProjectBindingController: createProjectBindingController3 } = await Promise.resolve().then(() => (init_request_context(), request_context_exports));
|
|
268786
|
+
const binding = createProjectBindingController3(root);
|
|
268787
|
+
const { server, projectId, handleTransportClose } = await createMemorixServer3(
|
|
268788
|
+
root,
|
|
268789
|
+
void 0,
|
|
268790
|
+
void 0,
|
|
268791
|
+
{
|
|
268792
|
+
allowUntrackedFallback: false,
|
|
268793
|
+
deferProjectInitUntilBound: true,
|
|
268794
|
+
deferProjectRuntimeInit: true,
|
|
268795
|
+
dashboardMode: "control-plane",
|
|
268796
|
+
dashboardPort: port,
|
|
268797
|
+
toolProfile,
|
|
268798
|
+
projectBinding: binding
|
|
268799
|
+
}
|
|
268800
|
+
);
|
|
268801
|
+
const transport = new StreamableHTTPServerTransport2({
|
|
268802
|
+
// No Mcp-Session-Id: the protocol state is carried by our explicit
|
|
268803
|
+
// durable project handle and reconstructed on every request.
|
|
268804
|
+
sessionIdGenerator: void 0,
|
|
268805
|
+
enableJsonResponse: true
|
|
268806
|
+
});
|
|
268807
|
+
try {
|
|
268808
|
+
await server.connect(transport);
|
|
268809
|
+
let effectiveHandle = persisted;
|
|
268810
|
+
if (!effectiveHandle && projectId !== "__unresolved__") {
|
|
268811
|
+
effectiveHandle = statelessBindingStore.create({
|
|
268812
|
+
projectId,
|
|
268813
|
+
projectRoot: root,
|
|
268814
|
+
dataDir: await persistMod.getProjectDataDir(projectId)
|
|
268815
|
+
});
|
|
268816
|
+
}
|
|
268817
|
+
if (effectiveHandle) res.setHeader("Mcp-Project-Handle", effectiveHandle.handleId);
|
|
268818
|
+
const sdkBody = body && typeof body === "object" ? JSON.parse(JSON.stringify(body)) : body;
|
|
268819
|
+
const sdkRequest = sdkBody;
|
|
268820
|
+
if (sdkRequest && typeof sdkRequest === "object" && sdkRequest.method === "initialize" && sdkRequest.params) {
|
|
268821
|
+
sdkRequest.params.protocolVersion = MCP_SDK_COMPAT_PROTOCOL_VERSION;
|
|
268822
|
+
}
|
|
268823
|
+
if (req.headers["mcp-protocol-version"]) {
|
|
268824
|
+
req.headers["mcp-protocol-version"] = MCP_SDK_COMPAT_PROTOCOL_VERSION;
|
|
268825
|
+
for (let i4 = 0; i4 < req.rawHeaders.length; i4 += 2) {
|
|
268826
|
+
if (req.rawHeaders[i4].toLowerCase() === "mcp-protocol-version") {
|
|
268827
|
+
req.rawHeaders[i4 + 1] = MCP_SDK_COMPAT_PROTOCOL_VERSION;
|
|
268828
|
+
break;
|
|
268829
|
+
}
|
|
268830
|
+
}
|
|
268831
|
+
}
|
|
268832
|
+
patchMcpResponse(res);
|
|
268833
|
+
await transport.handleRequest(req, res, sdkBody);
|
|
268834
|
+
} finally {
|
|
268835
|
+
handleTransportClose();
|
|
268836
|
+
await transport.close().catch(() => void 0);
|
|
268837
|
+
}
|
|
267726
268838
|
}
|
|
267727
268839
|
async function handlePost(req, res) {
|
|
267728
268840
|
const sessionId = req.headers["mcp-session-id"];
|
|
267729
268841
|
const body = await parseBody(req);
|
|
268842
|
+
const requestedProtocol = req.headers["mcp-protocol-version"];
|
|
268843
|
+
const statelessRequested = req.headers["mcp-stateless"] === "true" || requestedProtocol === CURRENT_MCP_PROTOCOL_VERSION;
|
|
268844
|
+
if (!sessionId && statelessRequested) {
|
|
268845
|
+
await handleStatelessPost(req, res, body);
|
|
268846
|
+
return;
|
|
268847
|
+
}
|
|
267730
268848
|
if (sessionId && sessions.has(sessionId)) {
|
|
267731
268849
|
sessionLastActivity.set(sessionId, Date.now());
|
|
267732
268850
|
patchMcpResponse(res);
|
|
@@ -267740,7 +268858,7 @@ var init_serve_http = __esm({
|
|
|
267740
268858
|
if (!sessionId && isInitializeRequest2(body)) {
|
|
267741
268859
|
let createdState = null;
|
|
267742
268860
|
const transport = new StreamableHTTPServerTransport2({
|
|
267743
|
-
sessionIdGenerator: () =>
|
|
268861
|
+
sessionIdGenerator: () => randomUUID20(),
|
|
267744
268862
|
enableJsonResponse: true,
|
|
267745
268863
|
onsessioninitialized: (sid) => {
|
|
267746
268864
|
if (createdState) sessions.set(sid, createdState);
|
|
@@ -267773,7 +268891,7 @@ var init_serve_http = __esm({
|
|
|
267773
268891
|
const { server, switchProject, handleTransportClose } = await createMemorixServer2(
|
|
267774
268892
|
projectRoot,
|
|
267775
268893
|
void 0,
|
|
267776
|
-
|
|
268894
|
+
void 0,
|
|
267777
268895
|
{
|
|
267778
268896
|
allowUntrackedFallback: false,
|
|
267779
268897
|
deferProjectInitUntilBound: true,
|
|
@@ -267915,6 +269033,18 @@ var init_serve_http = __esm({
|
|
|
267915
269033
|
{ projectId }
|
|
267916
269034
|
);
|
|
267917
269035
|
}
|
|
269036
|
+
async function loadProjectFeedback(dataDir, projectId) {
|
|
269037
|
+
const result = /* @__PURE__ */ new Map();
|
|
269038
|
+
try {
|
|
269039
|
+
const feedback = new MemoryFeedbackStore2();
|
|
269040
|
+
await feedback.init(dataDir);
|
|
269041
|
+
for (const state of feedback.listStates(projectId, "observation")) {
|
|
269042
|
+
result.set(state.candidateId, { weight: state.weight, status: state.status });
|
|
269043
|
+
}
|
|
269044
|
+
} catch {
|
|
269045
|
+
}
|
|
269046
|
+
return result;
|
|
269047
|
+
}
|
|
267918
269048
|
const cliDir = pathModule.default.dirname(fileURLToPath10(import.meta.url));
|
|
267919
269049
|
const dashStaticDir = pathModule.default.join(cliDir, "..", "dashboard", "static");
|
|
267920
269050
|
const MIME_TYPES2 = {
|
|
@@ -267973,9 +269103,50 @@ var init_serve_http = __esm({
|
|
|
267973
269103
|
sendJson2({ ok: true, scope: "per-request" });
|
|
267974
269104
|
return;
|
|
267975
269105
|
}
|
|
269106
|
+
const maintenanceMatch = apiPath.match(/^\/maintenance\/(cleanup|deduplicate|consolidate|retention)\/(preview|execute)$/);
|
|
269107
|
+
if (maintenanceMatch) {
|
|
269108
|
+
if (req.method !== "POST") {
|
|
269109
|
+
sendJson2({ error: "Maintenance actions require POST." }, 405);
|
|
269110
|
+
return;
|
|
269111
|
+
}
|
|
269112
|
+
const bodyValue = await parseBody(req);
|
|
269113
|
+
const body = bodyValue && typeof bodyValue === "object" && !Array.isArray(bodyValue) ? bodyValue : {};
|
|
269114
|
+
const { projectId: maintenanceProjectId, dataDir: maintenanceDataDir } = await resolveRequestProject(url2);
|
|
269115
|
+
const maintenanceStore = await getDashboardObservationStore(maintenanceDataDir);
|
|
269116
|
+
const context = {
|
|
269117
|
+
dataDir: maintenanceDataDir,
|
|
269118
|
+
projectId: maintenanceProjectId,
|
|
269119
|
+
projectRoot: maintenanceProjectId === defaultProject.id ? projectRoot : null,
|
|
269120
|
+
store: maintenanceStore
|
|
269121
|
+
};
|
|
269122
|
+
const maintenance = await Promise.resolve().then(() => (init_maintenance(), maintenance_exports));
|
|
269123
|
+
const action = maintenanceMatch[1];
|
|
269124
|
+
const phase = maintenanceMatch[2];
|
|
269125
|
+
let result;
|
|
269126
|
+
if (action === "cleanup") {
|
|
269127
|
+
result = phase === "preview" ? await maintenance.previewCleanup(context, body.includeNoise === true) : await maintenance.executeCleanup(context, body.payload, body.token);
|
|
269128
|
+
} else if (action === "deduplicate") {
|
|
269129
|
+
result = phase === "preview" ? await maintenance.previewDeduplicate(context) : await maintenance.executeDeduplicate(context, body.payload, body.token);
|
|
269130
|
+
} else if (action === "consolidate") {
|
|
269131
|
+
result = phase === "preview" ? await maintenance.previewConsolidate(context) : await maintenance.executeConsolidate(context, body.payload, body.token);
|
|
269132
|
+
} else {
|
|
269133
|
+
result = phase === "preview" ? await maintenance.previewRetentionArchive(context) : await maintenance.executeRetentionArchive(context, body.payload, body.token);
|
|
269134
|
+
}
|
|
269135
|
+
sendJson2(result);
|
|
269136
|
+
return;
|
|
269137
|
+
}
|
|
267976
269138
|
if (apiPath === "/team") {
|
|
267977
|
-
|
|
267978
|
-
|
|
269139
|
+
if (req.method !== "GET") {
|
|
269140
|
+
sendJson2({
|
|
269141
|
+
status: "error",
|
|
269142
|
+
readOnly: true,
|
|
269143
|
+
error: "Coordination status is read-only",
|
|
269144
|
+
errorCode: "COORDINATION_STATUS_READ_ONLY"
|
|
269145
|
+
}, 405);
|
|
269146
|
+
return;
|
|
269147
|
+
}
|
|
269148
|
+
const { projectId: teamProjectId, dataDir: teamDataDir } = await resolveRequestProject(url2);
|
|
269149
|
+
const ts2 = await getTeamStore2(teamDataDir);
|
|
267979
269150
|
const scope = url2.searchParams.get("scope") || "project";
|
|
267980
269151
|
const effectiveTeamProjectId = scope === "global" ? void 0 : teamProjectId;
|
|
267981
269152
|
const agents = effectiveTeamProjectId ? ts2.listAgents(effectiveTeamProjectId) : ts2.listAllAgents();
|
|
@@ -268038,8 +269209,9 @@ var init_serve_http = __esm({
|
|
|
268038
269209
|
const handoffs = effectiveTeamProjectId ? ts2.listHandoffs(effectiveTeamProjectId) : [];
|
|
268039
269210
|
const openHandoffs = handoffs.filter((handoff) => handoff.status !== "completed").length;
|
|
268040
269211
|
sendJson2({
|
|
269212
|
+
status: "ok",
|
|
268041
269213
|
mode: "control-plane",
|
|
268042
|
-
readOnly:
|
|
269214
|
+
readOnly: true,
|
|
268043
269215
|
scope,
|
|
268044
269216
|
agents: withTier,
|
|
268045
269217
|
// Primary headline number
|
|
@@ -268076,6 +269248,7 @@ var init_serve_http = __esm({
|
|
|
268076
269248
|
await initGraphStore2(statsDataDir);
|
|
268077
269249
|
const graph = { entities: getGraphStore2().loadEntities(), relations: getGraphStore2().loadRelations() };
|
|
268078
269250
|
const observations2 = await loadDashboardProjectObservations(statsDataDir, statsProjectId, "active");
|
|
269251
|
+
const feedback = await loadProjectFeedback(statsDataDir, statsProjectId);
|
|
268079
269252
|
const statsStore = await getDashboardObservationStore(statsDataDir);
|
|
268080
269253
|
const nextId2 = await statsStore.loadIdCounter();
|
|
268081
269254
|
const typeCounts = {};
|
|
@@ -268110,7 +269283,10 @@ var init_serve_http = __esm({
|
|
|
268110
269283
|
filesModified: o4.filesModified
|
|
268111
269284
|
}));
|
|
268112
269285
|
const retention = summarizeRetentionProjections(
|
|
268113
|
-
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
269286
|
+
observations2.filter((observation) => observation.type !== "probe").map((observation) => projectObservationRetention(observation, {
|
|
269287
|
+
referenceTime: new Date(now3),
|
|
269288
|
+
feedback: feedback.get(String(observation.id))
|
|
269289
|
+
}))
|
|
268114
269290
|
);
|
|
268115
269291
|
const retentionSummary = {
|
|
268116
269292
|
active: retention.active,
|
|
@@ -268217,6 +269393,19 @@ var init_serve_http = __esm({
|
|
|
268217
269393
|
sendJson2(await loadDashboardProjectObservations(obsDataDir, obsProjectId, "active"));
|
|
268218
269394
|
return;
|
|
268219
269395
|
}
|
|
269396
|
+
if (apiPath === "/evidence") {
|
|
269397
|
+
const { projectId: evidenceProjectId, dataDir: evidenceDataDir } = await resolveRequestProject(url2);
|
|
269398
|
+
const { EvidenceCardStore: EvidenceCardStore2 } = await Promise.resolve().then(() => (init_evidence_store(), evidence_store_exports));
|
|
269399
|
+
const evidenceStore = new EvidenceCardStore2();
|
|
269400
|
+
await evidenceStore.init(evidenceDataDir);
|
|
269401
|
+
const observations2 = await loadDashboardProjectObservations(evidenceDataDir, evidenceProjectId, "active");
|
|
269402
|
+
evidenceStore.syncObservations(observations2);
|
|
269403
|
+
const query = (url2.searchParams.get("q") || "").trim().toLowerCase();
|
|
269404
|
+
const limit2 = Math.min(100, Math.max(1, Number(url2.searchParams.get("limit") || 20)));
|
|
269405
|
+
const cards = evidenceStore.list(evidenceProjectId, { limit: 100 }).filter((card) => !query || [card.title, card.summary, card.sourceRef, card.locator ?? ""].join(" ").toLowerCase().includes(query)).slice(0, limit2).map((card) => ({ ...card, events: evidenceStore.listEvents(card.id, 8) }));
|
|
269406
|
+
sendJson2({ projectId: evidenceProjectId, cards });
|
|
269407
|
+
return;
|
|
269408
|
+
}
|
|
268220
269409
|
if (apiPath === "/graph") {
|
|
268221
269410
|
const { projectId: graphProjectId, dataDir: graphDataDir } = await resolveRequestProject(url2);
|
|
268222
269411
|
const { initGraphStore: initGraphStore2, getGraphStore: getGraphStore2 } = await Promise.resolve().then(() => (init_graph_store(), graph_store_exports));
|
|
@@ -268238,10 +269427,11 @@ var init_serve_http = __esm({
|
|
|
268238
269427
|
if (apiPath === "/retention") {
|
|
268239
269428
|
const { projectId: retProjectId, dataDir: retDataDir } = await resolveRequestProject(url2);
|
|
268240
269429
|
const observations2 = await loadDashboardProjectObservations(retDataDir, retProjectId, "active");
|
|
269430
|
+
const feedback = await loadProjectFeedback(retDataDir, retProjectId);
|
|
268241
269431
|
const referenceTime = /* @__PURE__ */ new Date();
|
|
268242
269432
|
const rows = observations2.filter((observation) => observation.type !== "probe").map((observation) => ({
|
|
268243
269433
|
observation,
|
|
268244
|
-
retention: projectObservationRetention(observation, { referenceTime })
|
|
269434
|
+
retention: projectObservationRetention(observation, { referenceTime, feedback: feedback.get(String(observation.id)) })
|
|
268245
269435
|
})).sort((a4, b4) => b4.retention.displayScore - a4.retention.displayScore);
|
|
268246
269436
|
const summary = summarizeRetentionProjections(rows.map((row) => row.retention));
|
|
268247
269437
|
const items = rows.map(({ observation, retention }) => ({
|
|
@@ -268594,6 +269784,23 @@ var init_serve_http = __esm({
|
|
|
268594
269784
|
}
|
|
268595
269785
|
sendJson2({ error: "Not found" }, 404);
|
|
268596
269786
|
} catch (err) {
|
|
269787
|
+
if (apiPath === "/team") {
|
|
269788
|
+
const scope = url2.searchParams.get("scope") === "global" ? "global" : "project";
|
|
269789
|
+
console.error("[memorix] coordination snapshot unavailable", { status: "error", scope });
|
|
269790
|
+
sendJson2({
|
|
269791
|
+
status: "error",
|
|
269792
|
+
mode: "control-plane",
|
|
269793
|
+
readOnly: true,
|
|
269794
|
+
scope,
|
|
269795
|
+
agents: [],
|
|
269796
|
+
locks: [],
|
|
269797
|
+
tasks: [],
|
|
269798
|
+
handoffs: [],
|
|
269799
|
+
error: "Coordination state unavailable",
|
|
269800
|
+
errorCode: "COORDINATION_STATE_UNAVAILABLE"
|
|
269801
|
+
}, 503);
|
|
269802
|
+
return;
|
|
269803
|
+
}
|
|
268597
269804
|
sendJson2({ error: err instanceof Error ? err.message : "Unknown error" }, 500);
|
|
268598
269805
|
}
|
|
268599
269806
|
}
|
|
@@ -268618,6 +269825,11 @@ var init_serve_http = __esm({
|
|
|
268618
269825
|
}));
|
|
268619
269826
|
return;
|
|
268620
269827
|
}
|
|
269828
|
+
if (url2.pathname === "/protocol-diagnostics") {
|
|
269829
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "public, max-age=60" });
|
|
269830
|
+
res.end(JSON.stringify(getMcpDiagnostics()));
|
|
269831
|
+
return;
|
|
269832
|
+
}
|
|
268621
269833
|
if (url2.pathname === "/mcp") {
|
|
268622
269834
|
const accept = req.headers["accept"] || "";
|
|
268623
269835
|
const needs = [];
|
|
@@ -270492,10 +271704,10 @@ __export(handler_exports, {
|
|
|
270492
271704
|
resetCooldowns: () => resetCooldowns,
|
|
270493
271705
|
runHook: () => runHook
|
|
270494
271706
|
});
|
|
270495
|
-
import { createHash as
|
|
271707
|
+
import { createHash as createHash19 } from "crypto";
|
|
270496
271708
|
function deriveHookActorId(input) {
|
|
270497
271709
|
const material = `${input.agent ?? "unknown"}\0${input.sessionId ?? "unknown"}`;
|
|
270498
|
-
return `hook:${
|
|
271710
|
+
return `hook:${createHash19("sha256").update(material).digest("hex").slice(0, 24)}`;
|
|
270499
271711
|
}
|
|
270500
271712
|
function classifyTool(input) {
|
|
270501
271713
|
if (input.event === "post_edit") return "file_modify";
|
|
@@ -272440,10 +273652,10 @@ var init_ingest = __esm({
|
|
|
272440
273652
|
});
|
|
272441
273653
|
|
|
272442
273654
|
// src/media/embedding.ts
|
|
272443
|
-
import { createHash as
|
|
273655
|
+
import { createHash as createHash20 } from "crypto";
|
|
272444
273656
|
function profileKey(provider2, asset) {
|
|
272445
273657
|
const identity = `${provider2.name}\0${provider2.dimensions}\0${asset.kind}`;
|
|
272446
|
-
return `media:${
|
|
273658
|
+
return `media:${createHash20("sha256").update(identity).digest("hex").slice(0, 20)}`;
|
|
272447
273659
|
}
|
|
272448
273660
|
function supportsAsset(provider2, asset) {
|
|
272449
273661
|
return !!provider2.embedInput && (provider2.supportedModalities?.includes(asset.kind) ?? false);
|
|
@@ -275475,7 +276687,7 @@ var init_dashboard = __esm({
|
|
|
275475
276687
|
}
|
|
275476
276688
|
const cliDir = path45.dirname(fileURLToPath9(import.meta.url));
|
|
275477
276689
|
const staticDir = path45.join(cliDir, "..", "dashboard", "static");
|
|
275478
|
-
await startDashboard2(dataDir, port, staticDir, project.id, project.name, true,
|
|
276690
|
+
await startDashboard2(dataDir, port, staticDir, project.id, project.name, true, project.rootPath, true);
|
|
275479
276691
|
await new Promise(() => {
|
|
275480
276692
|
});
|
|
275481
276693
|
}
|
|
@@ -278056,7 +279268,7 @@ function safeWrite(path48, content) {
|
|
|
278056
279268
|
} catch {
|
|
278057
279269
|
}
|
|
278058
279270
|
}
|
|
278059
|
-
var
|
|
279271
|
+
var init_evidence2 = __esm({
|
|
278060
279272
|
"src/orchestrate/evidence.ts"() {
|
|
278061
279273
|
"use strict";
|
|
278062
279274
|
init_esm_shims();
|
|
@@ -278182,7 +279394,7 @@ var init_permission = __esm({
|
|
|
278182
279394
|
});
|
|
278183
279395
|
|
|
278184
279396
|
// src/orchestrate/memorix-bridge.ts
|
|
278185
|
-
import { createHash as
|
|
279397
|
+
import { createHash as createHash21 } from "crypto";
|
|
278186
279398
|
async function getStoreObservation() {
|
|
278187
279399
|
if (!_storeObservation) {
|
|
278188
279400
|
const mod = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
@@ -278198,7 +279410,7 @@ async function getSearchObservations() {
|
|
|
278198
279410
|
return _searchObservations;
|
|
278199
279411
|
}
|
|
278200
279412
|
function automaticActorId(...parts) {
|
|
278201
|
-
return `orchestrator:${
|
|
279413
|
+
return `orchestrator:${createHash21("sha256").update(parts.join("\0")).digest("hex").slice(0, 24)}`;
|
|
278202
279414
|
}
|
|
278203
279415
|
function isEligibleAutomaticLesson(entry) {
|
|
278204
279416
|
return entry.admissionState !== "candidate" && entry.admissionState !== "ephemeral";
|
|
@@ -278345,7 +279557,7 @@ function sanitizeErrorPattern(text2) {
|
|
|
278345
279557
|
}
|
|
278346
279558
|
function hashErrorPattern(errorOutput) {
|
|
278347
279559
|
const sanitized = sanitizeErrorPattern(errorOutput).slice(0, 500);
|
|
278348
|
-
return
|
|
279560
|
+
return createHash21("sha256").update(sanitized).digest("hex").slice(0, 12);
|
|
278349
279561
|
}
|
|
278350
279562
|
function sleep6(ms2) {
|
|
278351
279563
|
return new Promise((resolve6) => setTimeout(() => resolve6([]), ms2));
|
|
@@ -279351,7 +280563,7 @@ var init_coordinator = __esm({
|
|
|
279351
280563
|
init_verify_gate();
|
|
279352
280564
|
init_error_recovery();
|
|
279353
280565
|
init_cost_tracker();
|
|
279354
|
-
|
|
280566
|
+
init_evidence2();
|
|
279355
280567
|
init_permission();
|
|
279356
280568
|
init_memorix_bridge();
|
|
279357
280569
|
}
|
|
@@ -284602,6 +285814,8 @@ var main2 = defineCommand({
|
|
|
284602
285814
|
codegraph: () => Promise.resolve().then(() => (init_codegraph(), codegraph_exports)).then((m6) => m6.default),
|
|
284603
285815
|
checkpoint: () => Promise.resolve().then(() => (init_checkpoint2(), checkpoint_exports)).then((m6) => m6.default),
|
|
284604
285816
|
knowledge: () => Promise.resolve().then(() => (init_knowledge(), knowledge_exports)).then((m6) => m6.default),
|
|
285817
|
+
evidence: () => Promise.resolve().then(() => (init_evidence(), evidence_exports)).then((m6) => m6.default),
|
|
285818
|
+
feedback: () => Promise.resolve().then(() => (init_feedback2(), feedback_exports2)).then((m6) => m6.default),
|
|
284605
285819
|
reasoning: () => Promise.resolve().then(() => (init_reasoning(), reasoning_exports)).then((m6) => m6.default),
|
|
284606
285820
|
retention: () => Promise.resolve().then(() => (init_retention2(), retention_exports2)).then((m6) => m6.default),
|
|
284607
285821
|
formation: () => Promise.resolve().then(() => (init_formation2(), formation_exports2)).then((m6) => m6.default),
|
|
@@ -284700,6 +285914,8 @@ var main2 = defineCommand({
|
|
|
284700
285914
|
"lock",
|
|
284701
285915
|
"handoff",
|
|
284702
285916
|
"poll",
|
|
285917
|
+
"evidence",
|
|
285918
|
+
"feedback",
|
|
284703
285919
|
"receipt",
|
|
284704
285920
|
"serve",
|
|
284705
285921
|
"serve-http",
|
|
@@ -284757,6 +285973,8 @@ var main2 = defineCommand({
|
|
|
284757
285973
|
console.error(" codegraph Refresh/status/context-pack for CodeGraph Memory");
|
|
284758
285974
|
console.error(" checkpoint Inspect native compact continuity checkpoints");
|
|
284759
285975
|
console.error(" knowledge Review source-backed knowledge pages and project workflows");
|
|
285976
|
+
console.error(" evidence Inspect source-backed evidence cards");
|
|
285977
|
+
console.error(" feedback Record or audit memory feedback");
|
|
284760
285978
|
console.error(" reasoning Store/search decision rationale");
|
|
284761
285979
|
console.error(" retention Inspect stale/archive status");
|
|
284762
285980
|
console.error(" formation Inspect Memory Formation metrics");
|