memorix 1.0.2 → 1.0.3
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 +17 -0
- package/README.md +7 -6
- package/README.zh-CN.md +8 -7
- package/dist/cli/index.js +753 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +693 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -42046,6 +42046,10 @@ var init_graph = __esm({
|
|
|
42046
42046
|
);
|
|
42047
42047
|
await this.save();
|
|
42048
42048
|
}
|
|
42049
|
+
/** Get all entity names (for Formation Pipeline entity resolution) */
|
|
42050
|
+
getEntityNames() {
|
|
42051
|
+
return this.entities.map((e3) => e3.name);
|
|
42052
|
+
}
|
|
42049
42053
|
/** Read the entire graph */
|
|
42050
42054
|
async readGraph() {
|
|
42051
42055
|
await this.init();
|
|
@@ -43813,6 +43817,624 @@ Respond in JSON only:
|
|
|
43813
43817
|
}
|
|
43814
43818
|
});
|
|
43815
43819
|
|
|
43820
|
+
// src/memory/formation/extract.ts
|
|
43821
|
+
function extractFacts(narrative, existingFacts) {
|
|
43822
|
+
const existingLower = new Set(existingFacts.map((f4) => f4.toLowerCase().trim()));
|
|
43823
|
+
const extracted = [];
|
|
43824
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43825
|
+
for (const { pattern, format } of FACT_PATTERNS) {
|
|
43826
|
+
pattern.lastIndex = 0;
|
|
43827
|
+
let match;
|
|
43828
|
+
while ((match = pattern.exec(narrative)) !== null) {
|
|
43829
|
+
const fact = format(match);
|
|
43830
|
+
const normalized = fact.toLowerCase().trim();
|
|
43831
|
+
if (existingLower.has(normalized) || seen.has(normalized)) continue;
|
|
43832
|
+
if (fact.length < 5 || fact.length > 120) continue;
|
|
43833
|
+
seen.add(normalized);
|
|
43834
|
+
extracted.push(fact);
|
|
43835
|
+
}
|
|
43836
|
+
}
|
|
43837
|
+
return extracted.slice(0, 10);
|
|
43838
|
+
}
|
|
43839
|
+
function improveTitle(title, narrative) {
|
|
43840
|
+
const isGeneric = GENERIC_TITLE_PATTERNS.some((p2) => p2.test(title));
|
|
43841
|
+
if (!isGeneric) return { title, improved: false };
|
|
43842
|
+
const sentences = narrative.replace(/```[\s\S]*?```/g, "").split(/[.。!!?\n]/).map((s2) => s2.trim()).filter((s2) => s2.length >= 15);
|
|
43843
|
+
if (sentences.length > 0) {
|
|
43844
|
+
return { title: sentences[0].slice(0, 60), improved: true };
|
|
43845
|
+
}
|
|
43846
|
+
return { title, improved: false };
|
|
43847
|
+
}
|
|
43848
|
+
function resolveEntity(entityName, existingEntities) {
|
|
43849
|
+
if (existingEntities.length === 0) return { entityName, resolved: false };
|
|
43850
|
+
const lower = entityName.toLowerCase().replace(/[-_]/g, "");
|
|
43851
|
+
for (const existing of existingEntities) {
|
|
43852
|
+
const existingLower = existing.toLowerCase().replace(/[-_]/g, "");
|
|
43853
|
+
if (lower === existingLower) {
|
|
43854
|
+
return { entityName: existing, resolved: existing !== entityName };
|
|
43855
|
+
}
|
|
43856
|
+
if (lower.length >= 3 && existingLower.length >= 3) {
|
|
43857
|
+
if (existingLower.includes(lower) || lower.includes(existingLower)) {
|
|
43858
|
+
const canonical = existing.length >= entityName.length ? existing : entityName;
|
|
43859
|
+
return { entityName: canonical, resolved: canonical !== entityName };
|
|
43860
|
+
}
|
|
43861
|
+
}
|
|
43862
|
+
}
|
|
43863
|
+
return { entityName, resolved: false };
|
|
43864
|
+
}
|
|
43865
|
+
function verifyType(declaredType, narrative, title) {
|
|
43866
|
+
const content = `${title} ${narrative}`;
|
|
43867
|
+
const scores = [];
|
|
43868
|
+
for (const { type, patterns } of TYPE_SIGNALS) {
|
|
43869
|
+
let score = 0;
|
|
43870
|
+
for (const p2 of patterns) {
|
|
43871
|
+
const regex2 = new RegExp(p2.source, p2.flags.includes("g") ? p2.flags : p2.flags + "g");
|
|
43872
|
+
const matches = [...content.matchAll(regex2)];
|
|
43873
|
+
score += matches.length;
|
|
43874
|
+
}
|
|
43875
|
+
if (score > 0) scores.push({ type, score });
|
|
43876
|
+
}
|
|
43877
|
+
if (scores.length === 0) return { type: declaredType, corrected: false };
|
|
43878
|
+
scores.sort((a3, b3) => b3.score - a3.score);
|
|
43879
|
+
const best = scores[0];
|
|
43880
|
+
if (best.type !== declaredType && best.score >= 2) {
|
|
43881
|
+
const declaredScore = scores.find((s2) => s2.type === declaredType)?.score ?? 0;
|
|
43882
|
+
if (declaredScore === 0) {
|
|
43883
|
+
return { type: best.type, corrected: true };
|
|
43884
|
+
}
|
|
43885
|
+
}
|
|
43886
|
+
return { type: declaredType, corrected: false };
|
|
43887
|
+
}
|
|
43888
|
+
function runExtract(input, existingEntities) {
|
|
43889
|
+
const callerFacts = input.facts ?? [];
|
|
43890
|
+
const extractedFacts = extractFacts(input.narrative, callerFacts);
|
|
43891
|
+
const allFacts = [...callerFacts, ...extractedFacts];
|
|
43892
|
+
const { title, improved: titleImproved } = improveTitle(input.title, input.narrative);
|
|
43893
|
+
const { entityName, resolved: entityResolved } = resolveEntity(
|
|
43894
|
+
input.entityName,
|
|
43895
|
+
existingEntities
|
|
43896
|
+
);
|
|
43897
|
+
const { type, corrected: typeCorrected } = verifyType(
|
|
43898
|
+
input.type,
|
|
43899
|
+
input.narrative,
|
|
43900
|
+
input.title
|
|
43901
|
+
);
|
|
43902
|
+
return {
|
|
43903
|
+
title,
|
|
43904
|
+
titleImproved,
|
|
43905
|
+
narrative: input.narrative,
|
|
43906
|
+
facts: allFacts,
|
|
43907
|
+
extractedFacts,
|
|
43908
|
+
entityName,
|
|
43909
|
+
entityResolved,
|
|
43910
|
+
type,
|
|
43911
|
+
typeCorrected
|
|
43912
|
+
};
|
|
43913
|
+
}
|
|
43914
|
+
var FACT_PATTERNS, GENERIC_TITLE_PATTERNS, TYPE_SIGNALS;
|
|
43915
|
+
var init_extract = __esm({
|
|
43916
|
+
"src/memory/formation/extract.ts"() {
|
|
43917
|
+
"use strict";
|
|
43918
|
+
init_esm_shims();
|
|
43919
|
+
FACT_PATTERNS = [
|
|
43920
|
+
// Key: Value pairs (e.g., "Port: 3000", "Timeout = 60s")
|
|
43921
|
+
{
|
|
43922
|
+
pattern: /\b([A-Z][a-zA-Z_-]{2,30})\s*[:=]\s*([^\n,;]{2,60})/g,
|
|
43923
|
+
format: (m4) => `${m4[1]}: ${m4[2].trim()}`
|
|
43924
|
+
},
|
|
43925
|
+
// Arrow notation (e.g., "MySQL → PostgreSQL", "v1.0 → v2.0")
|
|
43926
|
+
{
|
|
43927
|
+
pattern: /\b(\S{2,30})\s*[→➜\->]+\s*(\S{2,30})/g,
|
|
43928
|
+
format: (m4) => `${m4[1]} \u2192 ${m4[2]}`
|
|
43929
|
+
},
|
|
43930
|
+
// Version numbers (e.g., "v1.2.3", "version 2.0")
|
|
43931
|
+
{
|
|
43932
|
+
pattern: /\b(?:v(?:ersion)?\s*)(\d+\.\d+(?:\.\d+)?(?:-[\w.]+)?)\b/gi,
|
|
43933
|
+
format: (m4) => `Version: ${m4[1]}`
|
|
43934
|
+
},
|
|
43935
|
+
// Error messages (e.g., "Error: ...", "ERR_...")
|
|
43936
|
+
{
|
|
43937
|
+
pattern: /\b(?:Error|ERR|ENOENT|ECONNREFUSED|TypeError|RangeError|SyntaxError|ReferenceError)[:\s]+([^\n]{5,80})/gi,
|
|
43938
|
+
format: (m4) => `Error: ${m4[1].trim()}`
|
|
43939
|
+
},
|
|
43940
|
+
// Port numbers in context
|
|
43941
|
+
{
|
|
43942
|
+
pattern: /\b(?:port|PORT)\s*[:=]?\s*(\d{2,5})\b/gi,
|
|
43943
|
+
format: (m4) => `Port: ${m4[1]}`
|
|
43944
|
+
},
|
|
43945
|
+
// Environment variables
|
|
43946
|
+
{
|
|
43947
|
+
pattern: /\b([A-Z][A-Z0-9_]{3,30})\s*=\s*(\S{1,60})/g,
|
|
43948
|
+
format: (m4) => `${m4[1]}=${m4[2]}`
|
|
43949
|
+
},
|
|
43950
|
+
// npm/package versions (e.g., "react@18.2.0")
|
|
43951
|
+
{
|
|
43952
|
+
pattern: /\b([@a-z][\w./-]+)@(\d+\.\d+\.\d+(?:-[\w.]+)?)\b/g,
|
|
43953
|
+
format: (m4) => `${m4[1]}@${m4[2]}`
|
|
43954
|
+
}
|
|
43955
|
+
];
|
|
43956
|
+
GENERIC_TITLE_PATTERNS = [
|
|
43957
|
+
/^Updated \S+\.\w+$/i,
|
|
43958
|
+
/^Created \S+\.\w+$/i,
|
|
43959
|
+
/^Deleted \S+\.\w+$/i,
|
|
43960
|
+
/^Modified \S+\.\w+$/i,
|
|
43961
|
+
/^Changed \S+\.\w+$/i,
|
|
43962
|
+
/^Session activity/i,
|
|
43963
|
+
/^Activity \(/i,
|
|
43964
|
+
/^Used \w+$/i,
|
|
43965
|
+
/^Ran: /i
|
|
43966
|
+
];
|
|
43967
|
+
TYPE_SIGNALS = [
|
|
43968
|
+
{
|
|
43969
|
+
type: "problem-solution",
|
|
43970
|
+
patterns: [
|
|
43971
|
+
/\b(fix|fixed|bug|error|issue|crash|broken|resolved|workaround|patch)\b/i,
|
|
43972
|
+
/\b(修复|修正|解决|报错|崩溃|异常)\b/
|
|
43973
|
+
]
|
|
43974
|
+
},
|
|
43975
|
+
{
|
|
43976
|
+
type: "gotcha",
|
|
43977
|
+
patterns: [
|
|
43978
|
+
/\b(gotcha|pitfall|trap|careful|warning|caveat|footgun|unexpected|beware)\b/i,
|
|
43979
|
+
/\b(坑|陷阱|注意|小心|踩坑)\b/
|
|
43980
|
+
]
|
|
43981
|
+
},
|
|
43982
|
+
{
|
|
43983
|
+
type: "decision",
|
|
43984
|
+
patterns: [
|
|
43985
|
+
/\b(decided|chose|chosen|selected|adopted|rejected|evaluated|compared)\b/i,
|
|
43986
|
+
/\b(决定|选择|采用|弃用|对比|评估)\b/
|
|
43987
|
+
]
|
|
43988
|
+
},
|
|
43989
|
+
{
|
|
43990
|
+
type: "what-changed",
|
|
43991
|
+
patterns: [
|
|
43992
|
+
/\b(changed|migrated|upgraded|refactored|replaced|renamed|moved|removed|added)\b/i,
|
|
43993
|
+
/\b(改|迁移|升级|重构|替换|重命名|删除|新增)\b/
|
|
43994
|
+
]
|
|
43995
|
+
},
|
|
43996
|
+
{
|
|
43997
|
+
type: "how-it-works",
|
|
43998
|
+
patterns: [
|
|
43999
|
+
/\b(works by|architecture|mechanism|pipeline|flow|under the hood|internally)\b/i,
|
|
44000
|
+
/\b(原理|机制|流程|架构|内部)\b/
|
|
44001
|
+
]
|
|
44002
|
+
},
|
|
44003
|
+
{
|
|
44004
|
+
type: "trade-off",
|
|
44005
|
+
patterns: [
|
|
44006
|
+
/\b(trade.?off|compromise|downside|cost|benefit|pro|con|versus|vs)\b/i,
|
|
44007
|
+
/\b(权衡|折中|代价|收益|优缺点)\b/
|
|
44008
|
+
]
|
|
44009
|
+
}
|
|
44010
|
+
];
|
|
44011
|
+
}
|
|
44012
|
+
});
|
|
44013
|
+
|
|
44014
|
+
// src/memory/formation/resolve.ts
|
|
44015
|
+
function wordOverlap(a3, b3) {
|
|
44016
|
+
const wordsA = new Set(a3.toLowerCase().split(/\s+/).filter((w3) => w3.length > 2));
|
|
44017
|
+
const wordsB = new Set(b3.toLowerCase().split(/\s+/).filter((w3) => w3.length > 2));
|
|
44018
|
+
if (wordsA.size === 0 || wordsB.size === 0) return 0;
|
|
44019
|
+
let intersection2 = 0;
|
|
44020
|
+
for (const w3 of wordsA) {
|
|
44021
|
+
if (wordsB.has(w3)) intersection2++;
|
|
44022
|
+
}
|
|
44023
|
+
return intersection2 / Math.max(wordsA.size, wordsB.size);
|
|
44024
|
+
}
|
|
44025
|
+
function entitiesMatch(a3, b3) {
|
|
44026
|
+
const na = a3.toLowerCase().replace(/[-_]/g, "");
|
|
44027
|
+
const nb = b3.toLowerCase().replace(/[-_]/g, "");
|
|
44028
|
+
if (na === nb) return true;
|
|
44029
|
+
if (na.length >= 3 && nb.length >= 3) {
|
|
44030
|
+
if (na.includes(nb) || nb.includes(na)) return true;
|
|
44031
|
+
}
|
|
44032
|
+
return false;
|
|
44033
|
+
}
|
|
44034
|
+
function hasContradiction(oldText, newText) {
|
|
44035
|
+
const negationPatterns = [
|
|
44036
|
+
/\bnot\s+(\w+)/gi,
|
|
44037
|
+
/\bno longer\b/i,
|
|
44038
|
+
/\binstead of\b/i,
|
|
44039
|
+
/\breplaced\b.*\bwith\b/i,
|
|
44040
|
+
/\bremoved\b/i,
|
|
44041
|
+
/\bdeprecated\b/i,
|
|
44042
|
+
/\bobsolete\b/i,
|
|
44043
|
+
/不再/,
|
|
44044
|
+
/已弃用/,
|
|
44045
|
+
/替换为/,
|
|
44046
|
+
/改为/
|
|
44047
|
+
];
|
|
44048
|
+
return negationPatterns.some((p2) => p2.test(newText));
|
|
44049
|
+
}
|
|
44050
|
+
function mergeNarratives(oldNarrative, newNarrative) {
|
|
44051
|
+
if (newNarrative.length > oldNarrative.length * 1.5) return newNarrative;
|
|
44052
|
+
if (oldNarrative.length > newNarrative.length * 1.5) return oldNarrative;
|
|
44053
|
+
return `${newNarrative}
|
|
44054
|
+
|
|
44055
|
+
[Previous context]: ${oldNarrative}`;
|
|
44056
|
+
}
|
|
44057
|
+
function mergeFacts2(oldFacts, newFacts) {
|
|
44058
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44059
|
+
const merged = [];
|
|
44060
|
+
for (const f4 of newFacts) {
|
|
44061
|
+
const norm = f4.toLowerCase().trim();
|
|
44062
|
+
if (!seen.has(norm) && f4.trim().length > 0) {
|
|
44063
|
+
seen.add(norm);
|
|
44064
|
+
merged.push(f4);
|
|
44065
|
+
}
|
|
44066
|
+
}
|
|
44067
|
+
for (const f4 of oldFacts) {
|
|
44068
|
+
const norm = f4.toLowerCase().trim();
|
|
44069
|
+
if (!seen.has(norm) && f4.trim().length > 0) {
|
|
44070
|
+
seen.add(norm);
|
|
44071
|
+
merged.push(f4);
|
|
44072
|
+
}
|
|
44073
|
+
}
|
|
44074
|
+
return merged;
|
|
44075
|
+
}
|
|
44076
|
+
function scoreCandidate(extracted, candidate) {
|
|
44077
|
+
const entityMatch = entitiesMatch(extracted.entityName, candidate.entityName);
|
|
44078
|
+
const contentOverlap = wordOverlap(
|
|
44079
|
+
`${extracted.title} ${extracted.narrative}`,
|
|
44080
|
+
`${candidate.title} ${candidate.narrative}`
|
|
44081
|
+
);
|
|
44082
|
+
const score = candidate.score * 0.6 + (entityMatch ? 0.2 : 0) + contentOverlap * 0.2;
|
|
44083
|
+
const newLength = extracted.narrative.length + extracted.facts.join(" ").length;
|
|
44084
|
+
const oldLength = candidate.narrative.length + candidate.facts.length;
|
|
44085
|
+
const richer = newLength > oldLength * 1.15;
|
|
44086
|
+
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
44087
|
+
return { score, entityMatch, richer, contradiction };
|
|
44088
|
+
}
|
|
44089
|
+
async function runResolve(extracted, projectId, searchMemories, getObservation2) {
|
|
44090
|
+
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
44091
|
+
let hits;
|
|
44092
|
+
try {
|
|
44093
|
+
hits = await searchMemories(query, 5, projectId);
|
|
44094
|
+
} catch {
|
|
44095
|
+
return { action: "new", reason: "Search unavailable, defaulting to new" };
|
|
44096
|
+
}
|
|
44097
|
+
if (hits.length === 0) {
|
|
44098
|
+
return { action: "new", reason: "No similar existing memories found" };
|
|
44099
|
+
}
|
|
44100
|
+
const scored = hits.map((hit) => ({
|
|
44101
|
+
hit,
|
|
44102
|
+
...scoreCandidate(extracted, hit)
|
|
44103
|
+
}));
|
|
44104
|
+
scored.sort((a3, b3) => b3.score - a3.score);
|
|
44105
|
+
const best = scored[0];
|
|
44106
|
+
if (best.hit.score >= SIMILARITY_DUPLICATE) {
|
|
44107
|
+
if (best.richer) {
|
|
44108
|
+
const existing = getObservation2(best.hit.observationId);
|
|
44109
|
+
const oldFacts = existing?.facts ?? best.hit.facts.split("\n").filter(Boolean);
|
|
44110
|
+
return {
|
|
44111
|
+
action: "evolve",
|
|
44112
|
+
targetId: best.hit.observationId,
|
|
44113
|
+
reason: `Near-duplicate of #${best.hit.observationId} but richer content (score: ${best.score.toFixed(2)})`,
|
|
44114
|
+
mergedNarrative: mergeNarratives(best.hit.narrative, extracted.narrative),
|
|
44115
|
+
mergedFacts: mergeFacts2(oldFacts, extracted.facts)
|
|
44116
|
+
};
|
|
44117
|
+
}
|
|
44118
|
+
return {
|
|
44119
|
+
action: "discard",
|
|
44120
|
+
targetId: best.hit.observationId,
|
|
44121
|
+
reason: `Duplicate of #${best.hit.observationId} (score: ${best.score.toFixed(2)})`
|
|
44122
|
+
};
|
|
44123
|
+
}
|
|
44124
|
+
if (best.score >= SIMILARITY_HIGH2) {
|
|
44125
|
+
if (best.contradiction) {
|
|
44126
|
+
const existing = getObservation2(best.hit.observationId);
|
|
44127
|
+
const oldFacts = existing?.facts ?? best.hit.facts.split("\n").filter(Boolean);
|
|
44128
|
+
return {
|
|
44129
|
+
action: "evolve",
|
|
44130
|
+
targetId: best.hit.observationId,
|
|
44131
|
+
reason: `Supersedes #${best.hit.observationId}: contradiction detected (score: ${best.score.toFixed(2)})`,
|
|
44132
|
+
mergedNarrative: extracted.narrative,
|
|
44133
|
+
mergedFacts: mergeFacts2(oldFacts, extracted.facts)
|
|
44134
|
+
};
|
|
44135
|
+
}
|
|
44136
|
+
if (best.richer) {
|
|
44137
|
+
const existing = getObservation2(best.hit.observationId);
|
|
44138
|
+
const oldFacts = existing?.facts ?? best.hit.facts.split("\n").filter(Boolean);
|
|
44139
|
+
return {
|
|
44140
|
+
action: "merge",
|
|
44141
|
+
targetId: best.hit.observationId,
|
|
44142
|
+
reason: `Merging with #${best.hit.observationId}: same topic, new content is richer (score: ${best.score.toFixed(2)})`,
|
|
44143
|
+
mergedNarrative: mergeNarratives(best.hit.narrative, extracted.narrative),
|
|
44144
|
+
mergedFacts: mergeFacts2(oldFacts, extracted.facts)
|
|
44145
|
+
};
|
|
44146
|
+
}
|
|
44147
|
+
return {
|
|
44148
|
+
action: "discard",
|
|
44149
|
+
targetId: best.hit.observationId,
|
|
44150
|
+
reason: `Already covered by #${best.hit.observationId} (score: ${best.score.toFixed(2)})`
|
|
44151
|
+
};
|
|
44152
|
+
}
|
|
44153
|
+
if (best.score >= SIMILARITY_MEDIUM2 && best.entityMatch) {
|
|
44154
|
+
const existing = getObservation2(best.hit.observationId);
|
|
44155
|
+
const oldFacts = existing?.facts ?? best.hit.facts.split("\n").filter(Boolean);
|
|
44156
|
+
const newFactCount = extracted.facts.length;
|
|
44157
|
+
const oldFactCount = oldFacts.length;
|
|
44158
|
+
if (newFactCount > oldFactCount) {
|
|
44159
|
+
return {
|
|
44160
|
+
action: "merge",
|
|
44161
|
+
targetId: best.hit.observationId,
|
|
44162
|
+
reason: `Same entity "${extracted.entityName}", new memory has more facts (${newFactCount} > ${oldFactCount})`,
|
|
44163
|
+
mergedNarrative: mergeNarratives(best.hit.narrative, extracted.narrative),
|
|
44164
|
+
mergedFacts: mergeFacts2(oldFacts, extracted.facts)
|
|
44165
|
+
};
|
|
44166
|
+
}
|
|
44167
|
+
}
|
|
44168
|
+
return { action: "new", reason: `Different from existing memories (best score: ${best.score.toFixed(2)})` };
|
|
44169
|
+
}
|
|
44170
|
+
var SIMILARITY_HIGH2, SIMILARITY_MEDIUM2, SIMILARITY_DUPLICATE;
|
|
44171
|
+
var init_resolve = __esm({
|
|
44172
|
+
"src/memory/formation/resolve.ts"() {
|
|
44173
|
+
"use strict";
|
|
44174
|
+
init_esm_shims();
|
|
44175
|
+
SIMILARITY_HIGH2 = 0.75;
|
|
44176
|
+
SIMILARITY_MEDIUM2 = 0.5;
|
|
44177
|
+
SIMILARITY_DUPLICATE = 0.9;
|
|
44178
|
+
}
|
|
44179
|
+
});
|
|
44180
|
+
|
|
44181
|
+
// src/memory/formation/evaluate.ts
|
|
44182
|
+
function factDensity(facts, narrativeLength) {
|
|
44183
|
+
if (narrativeLength === 0) return 0;
|
|
44184
|
+
const structuredChars = facts.reduce((sum, f4) => sum + f4.length, 0);
|
|
44185
|
+
return Math.min(1, structuredChars / Math.max(narrativeLength, 100));
|
|
44186
|
+
}
|
|
44187
|
+
function specificityScore(content) {
|
|
44188
|
+
let count3 = 0;
|
|
44189
|
+
for (const p2 of SPECIFICITY_PATTERNS) {
|
|
44190
|
+
p2.lastIndex = 0;
|
|
44191
|
+
if (p2.test(content)) count3++;
|
|
44192
|
+
}
|
|
44193
|
+
return Math.min(1, count3 / 3);
|
|
44194
|
+
}
|
|
44195
|
+
function causalScore(content) {
|
|
44196
|
+
let count3 = 0;
|
|
44197
|
+
for (const p2 of CAUSAL_PATTERNS) {
|
|
44198
|
+
p2.lastIndex = 0;
|
|
44199
|
+
if (p2.test(content)) count3++;
|
|
44200
|
+
}
|
|
44201
|
+
return Math.min(1, count3 / 2);
|
|
44202
|
+
}
|
|
44203
|
+
function noiseScore(title, narrative) {
|
|
44204
|
+
let noisiness = 0;
|
|
44205
|
+
for (const p2 of NOISE_PATTERNS) {
|
|
44206
|
+
if (p2.test(title)) {
|
|
44207
|
+
noisiness += 0.3;
|
|
44208
|
+
break;
|
|
44209
|
+
}
|
|
44210
|
+
}
|
|
44211
|
+
const lines = narrative.split("\n").filter((l3) => l3.trim().length > 0);
|
|
44212
|
+
let toolOutputLines = 0;
|
|
44213
|
+
for (const line of lines) {
|
|
44214
|
+
for (const p2 of TOOL_OUTPUT_PATTERNS) {
|
|
44215
|
+
if (p2.test(line)) {
|
|
44216
|
+
toolOutputLines++;
|
|
44217
|
+
break;
|
|
44218
|
+
}
|
|
44219
|
+
}
|
|
44220
|
+
}
|
|
44221
|
+
if (lines.length > 0) {
|
|
44222
|
+
noisiness += toolOutputLines / lines.length * 0.5;
|
|
44223
|
+
}
|
|
44224
|
+
if (narrative.length < 50) noisiness += 0.2;
|
|
44225
|
+
return Math.min(1, noisiness);
|
|
44226
|
+
}
|
|
44227
|
+
function categorize(score) {
|
|
44228
|
+
if (score >= 0.6) return "core";
|
|
44229
|
+
if (score >= 0.35) return "contextual";
|
|
44230
|
+
return "ephemeral";
|
|
44231
|
+
}
|
|
44232
|
+
function buildReason(typeWeight, factDens, specificity, causal, noise, category) {
|
|
44233
|
+
const parts = [];
|
|
44234
|
+
if (typeWeight >= 0.7) parts.push("high-value type");
|
|
44235
|
+
else if (typeWeight <= 0.45) parts.push("low-value type");
|
|
44236
|
+
if (factDens > 0.3) parts.push("fact-dense");
|
|
44237
|
+
if (specificity > 0.3) parts.push("specific (versions/codes/paths)");
|
|
44238
|
+
if (causal > 0.3) parts.push("causal reasoning");
|
|
44239
|
+
if (noise > 0.3) parts.push("noisy content");
|
|
44240
|
+
const detail = parts.length > 0 ? parts.join(", ") : "average content";
|
|
44241
|
+
return `${category}: ${detail}`;
|
|
44242
|
+
}
|
|
44243
|
+
function runEvaluate(extracted) {
|
|
44244
|
+
const content = `${extracted.title} ${extracted.narrative} ${extracted.facts.join(" ")}`;
|
|
44245
|
+
const typeWeight = TYPE_WEIGHTS[extracted.type] ?? 0.5;
|
|
44246
|
+
const factDens = factDensity(extracted.facts, extracted.narrative.length);
|
|
44247
|
+
const specificity = specificityScore(content);
|
|
44248
|
+
const causal = causalScore(content);
|
|
44249
|
+
const noise = noiseScore(extracted.title, extracted.narrative);
|
|
44250
|
+
const rawScore = typeWeight * 0.5 + factDens * 0.12 + specificity * 0.12 + causal * 0.12 - noise * 0.14;
|
|
44251
|
+
const extractionBonus = extracted.extractedFacts.length > 0 ? 0.05 : 0;
|
|
44252
|
+
const titlePenalty = extracted.titleImproved ? -0.03 : 0;
|
|
44253
|
+
const correctionBonus = extracted.typeCorrected ? 0.03 : 0;
|
|
44254
|
+
const score = Math.max(0, Math.min(1, rawScore + extractionBonus + titlePenalty + correctionBonus));
|
|
44255
|
+
const category = categorize(score);
|
|
44256
|
+
const reason = buildReason(typeWeight, factDens, specificity, causal, noise, category);
|
|
44257
|
+
return { score, category, reason };
|
|
44258
|
+
}
|
|
44259
|
+
var TYPE_WEIGHTS, SPECIFICITY_PATTERNS, CAUSAL_PATTERNS, NOISE_PATTERNS, TOOL_OUTPUT_PATTERNS;
|
|
44260
|
+
var init_evaluate = __esm({
|
|
44261
|
+
"src/memory/formation/evaluate.ts"() {
|
|
44262
|
+
"use strict";
|
|
44263
|
+
init_esm_shims();
|
|
44264
|
+
TYPE_WEIGHTS = {
|
|
44265
|
+
"gotcha": 0.85,
|
|
44266
|
+
"decision": 0.8,
|
|
44267
|
+
"problem-solution": 0.75,
|
|
44268
|
+
"trade-off": 0.7,
|
|
44269
|
+
"why-it-exists": 0.65,
|
|
44270
|
+
"how-it-works": 0.6,
|
|
44271
|
+
"discovery": 0.55,
|
|
44272
|
+
"what-changed": 0.45,
|
|
44273
|
+
"session-request": 0.4
|
|
44274
|
+
};
|
|
44275
|
+
SPECIFICITY_PATTERNS = [
|
|
44276
|
+
/\b\d+\.\d+\.\d+\b/,
|
|
44277
|
+
// Semantic version numbers
|
|
44278
|
+
/\b(ERR_|ENOENT|ECONNREFUSED|E[A-Z]{3,})\b/,
|
|
44279
|
+
// Error codes
|
|
44280
|
+
/\b(port|PORT)\s*[:=]?\s*\d{2,5}\b/i,
|
|
44281
|
+
// Port numbers
|
|
44282
|
+
/\bhttps?:\/\/\S+/,
|
|
44283
|
+
// URLs
|
|
44284
|
+
/`[^`]{3,60}`/,
|
|
44285
|
+
// Inline code references
|
|
44286
|
+
/\b[A-Z][A-Z0-9_]{3,}\b/,
|
|
44287
|
+
// Constants (e.g., MAX_RETRIES)
|
|
44288
|
+
/\b\d+\s*(ms|s|sec|min|MB|GB|KB)\b/i
|
|
44289
|
+
// Measurements with units
|
|
44290
|
+
];
|
|
44291
|
+
CAUSAL_PATTERNS = [
|
|
44292
|
+
/\b(because|therefore|due to|caused by|as a result|fixed by|resolved by)\b/i,
|
|
44293
|
+
/\b(so that|in order to|leads to|results in|prevents)\b/i,
|
|
44294
|
+
/(?:因为|所以|由于|导致|造成|因此|为了|解决)/
|
|
44295
|
+
];
|
|
44296
|
+
NOISE_PATTERNS = [
|
|
44297
|
+
/^Session activity/i,
|
|
44298
|
+
/^Updated \S+\.\w+$/i,
|
|
44299
|
+
/^Created \S+\.\w+$/i,
|
|
44300
|
+
/^Deleted \S+\.\w+$/i,
|
|
44301
|
+
/^File written successfully/i,
|
|
44302
|
+
/^Command executed/i,
|
|
44303
|
+
/^Tool: (read_file|list_dir|find_by_name)/i,
|
|
44304
|
+
/^\s*$/
|
|
44305
|
+
];
|
|
44306
|
+
TOOL_OUTPUT_PATTERNS = [
|
|
44307
|
+
/^(file|directory|folder)\s+(created|deleted|moved|copied)/i,
|
|
44308
|
+
/^Successfully\s+(installed|updated|removed)/i,
|
|
44309
|
+
/^\d+ files? changed/i,
|
|
44310
|
+
/^npm (WARN|notice)/i,
|
|
44311
|
+
/^\s*at\s+\S+\s+\(/
|
|
44312
|
+
// Stack trace lines
|
|
44313
|
+
];
|
|
44314
|
+
}
|
|
44315
|
+
});
|
|
44316
|
+
|
|
44317
|
+
// src/memory/formation/index.ts
|
|
44318
|
+
var formation_exports = {};
|
|
44319
|
+
__export(formation_exports, {
|
|
44320
|
+
clearFormationMetrics: () => clearFormationMetrics,
|
|
44321
|
+
getFormationMetrics: () => getFormationMetrics,
|
|
44322
|
+
getMetricsSummary: () => getMetricsSummary,
|
|
44323
|
+
runFormation: () => runFormation
|
|
44324
|
+
});
|
|
44325
|
+
function getFormationMetrics() {
|
|
44326
|
+
return metricsBuffer;
|
|
44327
|
+
}
|
|
44328
|
+
function clearFormationMetrics() {
|
|
44329
|
+
metricsBuffer.length = 0;
|
|
44330
|
+
}
|
|
44331
|
+
function getMetricsSummary() {
|
|
44332
|
+
const total = metricsBuffer.length;
|
|
44333
|
+
if (total === 0) {
|
|
44334
|
+
return {
|
|
44335
|
+
total: 0,
|
|
44336
|
+
avgValueScore: 0,
|
|
44337
|
+
avgExtractedFacts: 0,
|
|
44338
|
+
titleImprovedRate: 0,
|
|
44339
|
+
entityResolvedRate: 0,
|
|
44340
|
+
typeCorectedRate: 0,
|
|
44341
|
+
resolutionBreakdown: {},
|
|
44342
|
+
categoryBreakdown: {},
|
|
44343
|
+
avgDurationMs: 0
|
|
44344
|
+
};
|
|
44345
|
+
}
|
|
44346
|
+
const sum = (fn) => metricsBuffer.reduce((s2, m4) => s2 + fn(m4), 0);
|
|
44347
|
+
const resolutionBreakdown = {};
|
|
44348
|
+
const categoryBreakdown = {};
|
|
44349
|
+
for (const m4 of metricsBuffer) {
|
|
44350
|
+
resolutionBreakdown[m4.resolutionAction] = (resolutionBreakdown[m4.resolutionAction] ?? 0) + 1;
|
|
44351
|
+
categoryBreakdown[m4.valueCategory] = (categoryBreakdown[m4.valueCategory] ?? 0) + 1;
|
|
44352
|
+
}
|
|
44353
|
+
return {
|
|
44354
|
+
total,
|
|
44355
|
+
avgValueScore: sum((m4) => m4.valueScore) / total,
|
|
44356
|
+
avgExtractedFacts: sum((m4) => m4.systemExtractedFacts) / total,
|
|
44357
|
+
titleImprovedRate: sum((m4) => m4.titleImproved ? 1 : 0) / total,
|
|
44358
|
+
entityResolvedRate: sum((m4) => m4.entityResolved ? 1 : 0) / total,
|
|
44359
|
+
typeCorectedRate: sum((m4) => m4.typeCorrected ? 1 : 0) / total,
|
|
44360
|
+
resolutionBreakdown,
|
|
44361
|
+
categoryBreakdown,
|
|
44362
|
+
avgDurationMs: sum((m4) => m4.durationMs) / total
|
|
44363
|
+
};
|
|
44364
|
+
}
|
|
44365
|
+
async function runFormation(input, config2) {
|
|
44366
|
+
const startTime = Date.now();
|
|
44367
|
+
let stagesCompleted = 0;
|
|
44368
|
+
const existingEntities = config2.getEntityNames();
|
|
44369
|
+
const extraction = runExtract(input, existingEntities);
|
|
44370
|
+
stagesCompleted = 1;
|
|
44371
|
+
let resolution;
|
|
44372
|
+
if (input.topicKey) {
|
|
44373
|
+
resolution = {
|
|
44374
|
+
action: "new",
|
|
44375
|
+
reason: "TopicKey upsert \u2014 bypasses resolve stage"
|
|
44376
|
+
};
|
|
44377
|
+
} else {
|
|
44378
|
+
resolution = await runResolve(
|
|
44379
|
+
extraction,
|
|
44380
|
+
input.projectId,
|
|
44381
|
+
config2.searchMemories,
|
|
44382
|
+
config2.getObservation
|
|
44383
|
+
);
|
|
44384
|
+
}
|
|
44385
|
+
stagesCompleted = 2;
|
|
44386
|
+
const evaluation = runEvaluate(extraction);
|
|
44387
|
+
stagesCompleted = 3;
|
|
44388
|
+
const durationMs = Date.now() - startTime;
|
|
44389
|
+
const formed = {
|
|
44390
|
+
// Final enriched data
|
|
44391
|
+
entityName: extraction.entityName,
|
|
44392
|
+
type: extraction.type,
|
|
44393
|
+
title: extraction.title,
|
|
44394
|
+
narrative: resolution.mergedNarrative ?? extraction.narrative,
|
|
44395
|
+
facts: resolution.mergedFacts ?? extraction.facts,
|
|
44396
|
+
// Stage results
|
|
44397
|
+
extraction,
|
|
44398
|
+
resolution,
|
|
44399
|
+
evaluation,
|
|
44400
|
+
// Pipeline metadata
|
|
44401
|
+
pipeline: {
|
|
44402
|
+
mode: "rules",
|
|
44403
|
+
durationMs,
|
|
44404
|
+
stagesCompleted,
|
|
44405
|
+
shadow: config2.shadow
|
|
44406
|
+
}
|
|
44407
|
+
};
|
|
44408
|
+
const metrics = {
|
|
44409
|
+
systemExtractedFacts: extraction.extractedFacts.length,
|
|
44410
|
+
titleImproved: extraction.titleImproved,
|
|
44411
|
+
entityResolved: extraction.entityResolved,
|
|
44412
|
+
typeCorrected: extraction.typeCorrected,
|
|
44413
|
+
resolutionAction: resolution.action,
|
|
44414
|
+
valueScore: evaluation.score,
|
|
44415
|
+
valueCategory: evaluation.category,
|
|
44416
|
+
durationMs,
|
|
44417
|
+
mode: "rules"
|
|
44418
|
+
};
|
|
44419
|
+
if (metricsBuffer.length >= MAX_METRICS_BUFFER) {
|
|
44420
|
+
metricsBuffer.shift();
|
|
44421
|
+
}
|
|
44422
|
+
metricsBuffer.push(metrics);
|
|
44423
|
+
return formed;
|
|
44424
|
+
}
|
|
44425
|
+
var metricsBuffer, MAX_METRICS_BUFFER;
|
|
44426
|
+
var init_formation = __esm({
|
|
44427
|
+
"src/memory/formation/index.ts"() {
|
|
44428
|
+
"use strict";
|
|
44429
|
+
init_esm_shims();
|
|
44430
|
+
init_extract();
|
|
44431
|
+
init_resolve();
|
|
44432
|
+
init_evaluate();
|
|
44433
|
+
metricsBuffer = [];
|
|
44434
|
+
MAX_METRICS_BUFFER = 500;
|
|
44435
|
+
}
|
|
44436
|
+
});
|
|
44437
|
+
|
|
43816
44438
|
// src/memory/session.ts
|
|
43817
44439
|
var session_exports = {};
|
|
43818
44440
|
__export(session_exports, {
|
|
@@ -44451,7 +45073,7 @@ async function promoteToMiniSkill(projectDir2, projectId, observations2, options
|
|
|
44451
45073
|
const title = generateTitle(observations2);
|
|
44452
45074
|
const instruction = options2?.instruction || generateInstruction(observations2);
|
|
44453
45075
|
const trigger = options2?.trigger || generateTrigger(observations2);
|
|
44454
|
-
const facts =
|
|
45076
|
+
const facts = extractFacts2(observations2);
|
|
44455
45077
|
const tags = [
|
|
44456
45078
|
...options2?.tags || [],
|
|
44457
45079
|
...extractTags(observations2)
|
|
@@ -44559,7 +45181,7 @@ function generateTrigger(observations2) {
|
|
|
44559
45181
|
}
|
|
44560
45182
|
return parts.length > 0 ? parts.join("; ") : `Related to ${obs.title}`;
|
|
44561
45183
|
}
|
|
44562
|
-
function
|
|
45184
|
+
function extractFacts2(observations2) {
|
|
44563
45185
|
const facts = /* @__PURE__ */ new Set();
|
|
44564
45186
|
for (const obs of observations2) {
|
|
44565
45187
|
for (const f4 of obs.facts) {
|
|
@@ -45662,7 +46284,7 @@ async function createMemorixServer(cwd, existingServer, sharedTeam) {
|
|
|
45662
46284
|
let syncAdvisory = null;
|
|
45663
46285
|
const server = existingServer ?? new McpServer({
|
|
45664
46286
|
name: "memorix",
|
|
45665
|
-
version: true ? "1.0.
|
|
46287
|
+
version: true ? "1.0.3" : "1.0.1"
|
|
45666
46288
|
});
|
|
45667
46289
|
server.registerTool(
|
|
45668
46290
|
"memorix_store",
|
|
@@ -45818,12 +46440,68 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
|
|
|
45818
46440
|
const enrichment = enrichmentParts.length > 0 ? `
|
|
45819
46441
|
Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
45820
46442
|
const action = upserted ? "\u{1F504} Updated" : "\u2705 Stored";
|
|
46443
|
+
let formationNote = "";
|
|
46444
|
+
try {
|
|
46445
|
+
const formationConfig = {
|
|
46446
|
+
shadow: true,
|
|
46447
|
+
useLLM: false,
|
|
46448
|
+
minValueScore: 0.3,
|
|
46449
|
+
searchMemories: async (q3, limit, pid) => {
|
|
46450
|
+
const result = await compactSearch({ query: q3, limit, projectId: pid, status: "active" });
|
|
46451
|
+
if (result.entries.length === 0) return [];
|
|
46452
|
+
const details = await compactDetail(result.entries.map((e3) => e3.id));
|
|
46453
|
+
return details.documents.map((d3, i2) => ({
|
|
46454
|
+
id: Number(d3.id.replace("obs-", "")),
|
|
46455
|
+
observationId: d3.observationId,
|
|
46456
|
+
title: d3.title,
|
|
46457
|
+
narrative: d3.narrative,
|
|
46458
|
+
facts: d3.facts,
|
|
46459
|
+
entityName: d3.entityName,
|
|
46460
|
+
type: d3.type,
|
|
46461
|
+
score: result.entries[i2]?.score ?? 0
|
|
46462
|
+
}));
|
|
46463
|
+
},
|
|
46464
|
+
getObservation: (id) => {
|
|
46465
|
+
const o3 = getObservation(id);
|
|
46466
|
+
if (!o3) return null;
|
|
46467
|
+
return {
|
|
46468
|
+
id: o3.id,
|
|
46469
|
+
entityName: o3.entityName,
|
|
46470
|
+
type: o3.type,
|
|
46471
|
+
title: o3.title,
|
|
46472
|
+
narrative: o3.narrative,
|
|
46473
|
+
facts: o3.facts,
|
|
46474
|
+
topicKey: o3.topicKey
|
|
46475
|
+
};
|
|
46476
|
+
},
|
|
46477
|
+
getEntityNames: () => graphManager.getEntityNames()
|
|
46478
|
+
};
|
|
46479
|
+
const formed = await runFormation({
|
|
46480
|
+
entityName,
|
|
46481
|
+
type,
|
|
46482
|
+
title,
|
|
46483
|
+
narrative,
|
|
46484
|
+
facts: safeFacts,
|
|
46485
|
+
projectId: project.id,
|
|
46486
|
+
source: "explicit",
|
|
46487
|
+
topicKey
|
|
46488
|
+
}, formationConfig);
|
|
46489
|
+
formationNote = `
|
|
46490
|
+
\u{1F52C} Formation[shadow]: ${formed.evaluation.category} (${formed.evaluation.score.toFixed(2)}) | ${formed.resolution.action} | ${formed.pipeline.durationMs}ms`;
|
|
46491
|
+
if (formed.extraction.extractedFacts.length > 0) {
|
|
46492
|
+
formationNote += ` | +${formed.extraction.extractedFacts.length} facts`;
|
|
46493
|
+
}
|
|
46494
|
+
if (formed.extraction.titleImproved) formationNote += " | title\u2191";
|
|
46495
|
+
if (formed.extraction.entityResolved) formationNote += ` | entity\u2192${formed.entityName}`;
|
|
46496
|
+
if (formed.extraction.typeCorrected) formationNote += ` | type\u2192${formed.type}`;
|
|
46497
|
+
} catch {
|
|
46498
|
+
}
|
|
45821
46499
|
return {
|
|
45822
46500
|
content: [
|
|
45823
46501
|
{
|
|
45824
46502
|
type: "text",
|
|
45825
46503
|
text: `${action} observation #${obs.id} "${title}" (~${obs.tokens} tokens)
|
|
45826
|
-
Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ""}${compactAction}${compressionNote}${enrichment}`
|
|
46504
|
+
Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ""}${compactAction}${compressionNote}${enrichment}${formationNote}`
|
|
45827
46505
|
}
|
|
45828
46506
|
]
|
|
45829
46507
|
};
|
|
@@ -46178,6 +46856,53 @@ Archived memories can be restored manually if needed.` }]
|
|
|
46178
46856
|
};
|
|
46179
46857
|
}
|
|
46180
46858
|
);
|
|
46859
|
+
server.registerTool(
|
|
46860
|
+
"memorix_formation_metrics",
|
|
46861
|
+
{
|
|
46862
|
+
title: "Formation Pipeline Metrics",
|
|
46863
|
+
description: "Show aggregated metrics from the Memory Formation Pipeline running in shadow mode. Reports value scores, resolution actions, fact extraction rates, and processing times.",
|
|
46864
|
+
inputSchema: {}
|
|
46865
|
+
},
|
|
46866
|
+
async () => {
|
|
46867
|
+
const summary = getMetricsSummary();
|
|
46868
|
+
if (summary.total === 0) {
|
|
46869
|
+
return {
|
|
46870
|
+
content: [{
|
|
46871
|
+
type: "text",
|
|
46872
|
+
text: "\u{1F4CA} Formation Pipeline: No metrics collected yet.\nStore some observations to start collecting shadow mode data."
|
|
46873
|
+
}]
|
|
46874
|
+
};
|
|
46875
|
+
}
|
|
46876
|
+
const lines = [
|
|
46877
|
+
"\u{1F4CA} **Formation Pipeline Metrics** (shadow mode)",
|
|
46878
|
+
"",
|
|
46879
|
+
`**Total observations processed:** ${summary.total}`,
|
|
46880
|
+
`**Average value score:** ${summary.avgValueScore.toFixed(3)}`,
|
|
46881
|
+
`**Average processing time:** ${summary.avgDurationMs.toFixed(1)}ms`,
|
|
46882
|
+
"",
|
|
46883
|
+
"### Quality Indicators",
|
|
46884
|
+
`- **Avg system-extracted facts:** ${summary.avgExtractedFacts.toFixed(1)} per observation`,
|
|
46885
|
+
`- **Title improved rate:** ${(summary.titleImprovedRate * 100).toFixed(1)}%`,
|
|
46886
|
+
`- **Entity resolved rate:** ${(summary.entityResolvedRate * 100).toFixed(1)}%`,
|
|
46887
|
+
`- **Type corrected rate:** ${(summary.typeCorectedRate * 100).toFixed(1)}%`,
|
|
46888
|
+
"",
|
|
46889
|
+
"### Value Categories"
|
|
46890
|
+
];
|
|
46891
|
+
for (const [cat, count3] of Object.entries(summary.categoryBreakdown)) {
|
|
46892
|
+
const pct = (count3 / summary.total * 100).toFixed(1);
|
|
46893
|
+
const icon = cat === "core" ? "\u{1F7E2}" : cat === "contextual" ? "\u{1F7E1}" : "\u{1F534}";
|
|
46894
|
+
lines.push(`- ${icon} **${cat}:** ${count3} (${pct}%)`);
|
|
46895
|
+
}
|
|
46896
|
+
lines.push("", "### Resolution Actions");
|
|
46897
|
+
for (const [action, count3] of Object.entries(summary.resolutionBreakdown)) {
|
|
46898
|
+
const pct = (count3 / summary.total * 100).toFixed(1);
|
|
46899
|
+
lines.push(`- **${action}:** ${count3} (${pct}%)`);
|
|
46900
|
+
}
|
|
46901
|
+
return {
|
|
46902
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
46903
|
+
};
|
|
46904
|
+
}
|
|
46905
|
+
);
|
|
46181
46906
|
let enableKG = false;
|
|
46182
46907
|
try {
|
|
46183
46908
|
const { homedir: homedir17 } = await import("os");
|
|
@@ -47491,6 +48216,7 @@ var init_server4 = __esm({
|
|
|
47491
48216
|
init_engine2();
|
|
47492
48217
|
init_provider2();
|
|
47493
48218
|
init_memory_manager();
|
|
48219
|
+
init_formation();
|
|
47494
48220
|
lastInternalWriteMs = 0;
|
|
47495
48221
|
markInternalWrite = () => {
|
|
47496
48222
|
lastInternalWriteMs = Date.now();
|
|
@@ -47698,7 +48424,7 @@ var init_serve = __esm({
|
|
|
47698
48424
|
});
|
|
47699
48425
|
} else {
|
|
47700
48426
|
console.error(`[memorix] cwd may not be a valid project, trying MCP roots protocol...`);
|
|
47701
|
-
const mcpServer = new McpServer2({ name: "memorix", version: true ? "1.0.
|
|
48427
|
+
const mcpServer = new McpServer2({ name: "memorix", version: true ? "1.0.3" : "1.0.1" });
|
|
47702
48428
|
mcpServer.registerTool("_memorix_loading", {
|
|
47703
48429
|
description: "Memorix is initializing, detecting project root...",
|
|
47704
48430
|
inputSchema: {}
|
|
@@ -50448,6 +51174,28 @@ async function runHook() {
|
|
|
50448
51174
|
const projectId = canonicalId;
|
|
50449
51175
|
await initObservations2(dataDir);
|
|
50450
51176
|
await storeObservation2({ ...observation, projectId });
|
|
51177
|
+
try {
|
|
51178
|
+
const { runFormation: runFormation2 } = await Promise.resolve().then(() => (init_formation(), formation_exports));
|
|
51179
|
+
runFormation2({
|
|
51180
|
+
entityName: observation.entityName,
|
|
51181
|
+
type: observation.type,
|
|
51182
|
+
title: observation.title,
|
|
51183
|
+
narrative: observation.narrative,
|
|
51184
|
+
facts: observation.facts,
|
|
51185
|
+
projectId,
|
|
51186
|
+
source: "hook"
|
|
51187
|
+
}, {
|
|
51188
|
+
shadow: true,
|
|
51189
|
+
useLLM: false,
|
|
51190
|
+
minValueScore: 0.3,
|
|
51191
|
+
searchMemories: async () => [],
|
|
51192
|
+
// Skip search in hooks for speed
|
|
51193
|
+
getObservation: () => null,
|
|
51194
|
+
getEntityNames: () => []
|
|
51195
|
+
}).catch(() => {
|
|
51196
|
+
});
|
|
51197
|
+
} catch {
|
|
51198
|
+
}
|
|
50451
51199
|
const emoji2 = TYPE_EMOJI[observation.type] ?? "\u{1F4DD}";
|
|
50452
51200
|
output.systemMessage = (output.systemMessage ?? "") + `
|
|
50453
51201
|
${emoji2} Memorix saved: ${observation.title} [${observation.type}]`;
|