bilmem 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +439 -0
- package/dist/canonical-CglQQ0xc.d.ts +262 -0
- package/dist/cli/index.js +7601 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/index.d.ts +311 -0
- package/dist/core/index.js +1975 -0
- package/dist/core/index.js.map +1 -0
- package/dist/filesystem-B3qAej0l.d.ts +69 -0
- package/dist/index.d.ts +163 -0
- package/dist/index.js +7765 -0
- package/dist/index.js.map +1 -0
- package/dist/install/index.d.ts +373 -0
- package/dist/install/index.js +6632 -0
- package/dist/install/index.js.map +1 -0
- package/dist/jev/index.d.ts +32 -0
- package/dist/jev/index.js +269 -0
- package/dist/jev/index.js.map +1 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +5479 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/rules/index.d.ts +59 -0
- package/dist/rules/index.js +388 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/scanner/index.d.ts +169 -0
- package/dist/scanner/index.js +3829 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/search/index.d.ts +44 -0
- package/dist/search/index.js +301 -0
- package/dist/search/index.js.map +1 -0
- package/dist/stats/index.d.ts +60 -0
- package/dist/stats/index.js +1373 -0
- package/dist/stats/index.js.map +1 -0
- package/dist/storage/index.d.ts +82 -0
- package/dist/storage/index.js +1748 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types-Nxq5Gzay.d.ts +390 -0
- package/package.json +71 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { S as Scope, K as Knowledge, J as JevResult } from '../types-Nxq5Gzay.js';
|
|
2
|
+
|
|
3
|
+
interface QueryContext {
|
|
4
|
+
query?: string;
|
|
5
|
+
positive?: string[];
|
|
6
|
+
negative?: string[];
|
|
7
|
+
scope?: Scope;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Evaluates JEV-style positive and negative contextual proximity for a knowledge unit.
|
|
11
|
+
*/
|
|
12
|
+
declare function evaluateJev(knowledge: Knowledge, context: QueryContext): JevResult;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Re-ranks a small set of candidate knowledge units using JEV contextual evaluation.
|
|
16
|
+
*/
|
|
17
|
+
declare function rerankCandidates(candidates: Knowledge[], context: QueryContext): JevResult[];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Formats a JevResult into a clear, inspectable explanation string.
|
|
21
|
+
*/
|
|
22
|
+
declare function formatJevExplanation(result: JevResult): string;
|
|
23
|
+
/**
|
|
24
|
+
* Formats full "bilmem why <id>" detailed output.
|
|
25
|
+
*/
|
|
26
|
+
declare function formatWhyExplanation(knowledge: Knowledge): string;
|
|
27
|
+
/**
|
|
28
|
+
* Formats lifecycle history for "bilmem why <id> --history".
|
|
29
|
+
*/
|
|
30
|
+
declare function formatWhyHistory(knowledge: Knowledge): string;
|
|
31
|
+
|
|
32
|
+
export { type QueryContext, evaluateJev, formatJevExplanation, formatWhyExplanation, formatWhyHistory, rerankCandidates };
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// src/jev/scorer.ts
|
|
2
|
+
var statementTokenCache = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function extractTokens(text) {
|
|
4
|
+
if (!text) return /* @__PURE__ */ new Set();
|
|
5
|
+
return new Set(
|
|
6
|
+
text.toLowerCase().replace(/[^a-z0-9_-]/g, " ").split(/\s+/).filter((t) => t.length > 2)
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
function getKnowledgeStatementTokens(k) {
|
|
10
|
+
let tokens = statementTokenCache.get(k);
|
|
11
|
+
if (!tokens) {
|
|
12
|
+
tokens = extractTokens(k.statement);
|
|
13
|
+
statementTokenCache.set(k, tokens);
|
|
14
|
+
}
|
|
15
|
+
return tokens;
|
|
16
|
+
}
|
|
17
|
+
function evaluateJev(knowledge, context) {
|
|
18
|
+
const queryTokens = extractTokens(context.query);
|
|
19
|
+
const contextPos = new Set((context.positive ?? []).map((p) => p.trim().toLowerCase()));
|
|
20
|
+
const contextNeg = new Set((context.negative ?? []).map((n) => n.trim().toLowerCase()));
|
|
21
|
+
const knowPos = new Set((knowledge.positive ?? []).map((p) => p.trim().toLowerCase()));
|
|
22
|
+
const knowNeg = new Set((knowledge.negative ?? []).map((n) => n.trim().toLowerCase()));
|
|
23
|
+
const negativeConflicts = [];
|
|
24
|
+
for (const n of knowNeg) {
|
|
25
|
+
if (contextPos.has(n) || queryTokens.has(n)) {
|
|
26
|
+
negativeConflicts.push(`Knowledge forbids "${n}", which was present in context`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const p of knowPos) {
|
|
30
|
+
if (contextNeg.has(p)) {
|
|
31
|
+
negativeConflicts.push(`Context forbids "${p}", which is required by knowledge`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const positiveMatches = [];
|
|
35
|
+
for (const p of knowPos) {
|
|
36
|
+
if (contextPos.has(p)) {
|
|
37
|
+
positiveMatches.push(`Context cue: ${p}`);
|
|
38
|
+
} else {
|
|
39
|
+
for (const q of queryTokens) {
|
|
40
|
+
if (p === q || p.startsWith(q) || q.startsWith(p)) {
|
|
41
|
+
positiveMatches.push(`Query term match: ${p}`);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const stmtTokens = getKnowledgeStatementTokens(knowledge);
|
|
48
|
+
let queryOverlapCount = 0;
|
|
49
|
+
for (const q of queryTokens) {
|
|
50
|
+
let matched = false;
|
|
51
|
+
for (const st of stmtTokens) {
|
|
52
|
+
if (q === st || q.startsWith(st) || st.startsWith(q)) {
|
|
53
|
+
matched = true;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (matched) {
|
|
58
|
+
queryOverlapCount++;
|
|
59
|
+
positiveMatches.push(`Statement term: ${q}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const totalCues = Math.max(1, knowPos.size);
|
|
63
|
+
const matchedCuesCount = positiveMatches.filter((m2) => m2.startsWith("Context cue") || m2.startsWith("Query term")).length;
|
|
64
|
+
const cueMatchRatio = matchedCuesCount / totalCues;
|
|
65
|
+
const tokenOverlapScore = queryTokens.size > 0 ? queryOverlapCount / Math.max(1, queryTokens.size) : 0;
|
|
66
|
+
const rawPositiveScore = 0.65 * cueMatchRatio + 0.35 * tokenOverlapScore;
|
|
67
|
+
let scopeMultiplier = 1;
|
|
68
|
+
const targetScope = (context.scope ?? "project").toLowerCase();
|
|
69
|
+
const knowScope = (knowledge.scope ?? "project").toLowerCase();
|
|
70
|
+
if (targetScope === knowScope) {
|
|
71
|
+
scopeMultiplier = 1;
|
|
72
|
+
} else if (knowScope === "global" || targetScope.startsWith(knowScope)) {
|
|
73
|
+
scopeMultiplier = 0.85;
|
|
74
|
+
} else if (knowScope === "project" && targetScope.startsWith("branch:")) {
|
|
75
|
+
scopeMultiplier = 0.9;
|
|
76
|
+
} else {
|
|
77
|
+
scopeMultiplier = 0.3;
|
|
78
|
+
}
|
|
79
|
+
const m = knowledge.metrics;
|
|
80
|
+
const evRatio = (m.support_count + 1) / (m.support_count + 2 * m.contradiction_count + 1);
|
|
81
|
+
const confidenceFactor = knowledge.confidence * evRatio;
|
|
82
|
+
let outcomeAdjustment = 0;
|
|
83
|
+
if (m.successful_outcomes > 0) {
|
|
84
|
+
outcomeAdjustment += Math.min(0.1, m.successful_outcomes * 0.03);
|
|
85
|
+
}
|
|
86
|
+
if (m.failed_outcomes > 0) {
|
|
87
|
+
outcomeAdjustment -= Math.min(0.2, m.failed_outcomes * 0.05);
|
|
88
|
+
}
|
|
89
|
+
let score = (rawPositiveScore * 0.45 + confidenceFactor * 0.4 + outcomeAdjustment) * scopeMultiplier;
|
|
90
|
+
if (knowledge.status === "stale") {
|
|
91
|
+
score *= 0.6;
|
|
92
|
+
} else if (knowledge.status === "contradicted") {
|
|
93
|
+
score *= 0.3;
|
|
94
|
+
} else if (knowledge.status === "invalid" || knowledge.status === "superseded") {
|
|
95
|
+
score *= 0.1;
|
|
96
|
+
}
|
|
97
|
+
let status = "POSSIBLE";
|
|
98
|
+
const reasons = [];
|
|
99
|
+
if (negativeConflicts.length > 0) {
|
|
100
|
+
score = Math.max(0.01, score * 0.2);
|
|
101
|
+
status = "REJECT";
|
|
102
|
+
reasons.push(`Rejected due to ${negativeConflicts.length} negative contextual conflicts.`);
|
|
103
|
+
} else if (score >= 0.45 && positiveMatches.length > 0) {
|
|
104
|
+
status = "MATCH";
|
|
105
|
+
reasons.push(`Strong contextual match with ${positiveMatches.length} matching signals.`);
|
|
106
|
+
} else if (score >= 0.25) {
|
|
107
|
+
status = "POSSIBLE";
|
|
108
|
+
reasons.push(`Potential match; partial contextual overlap.`);
|
|
109
|
+
} else {
|
|
110
|
+
status = "REJECT";
|
|
111
|
+
reasons.push(`Insufficient contextual match score (${score.toFixed(2)} < 0.25).`);
|
|
112
|
+
}
|
|
113
|
+
const finalScore = Math.round(Math.min(1, Math.max(0, score)) * 100) / 100;
|
|
114
|
+
const explanation = {
|
|
115
|
+
positiveMatches,
|
|
116
|
+
negativeConflicts,
|
|
117
|
+
score: finalScore,
|
|
118
|
+
confidence: knowledge.confidence,
|
|
119
|
+
status,
|
|
120
|
+
reasons
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
knowledge,
|
|
124
|
+
status,
|
|
125
|
+
score: finalScore,
|
|
126
|
+
explanation
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/jev/matcher.ts
|
|
131
|
+
function rerankCandidates(candidates, context) {
|
|
132
|
+
const results = [];
|
|
133
|
+
for (const candidate of candidates) {
|
|
134
|
+
const res = evaluateJev(candidate, context);
|
|
135
|
+
results.push(res);
|
|
136
|
+
}
|
|
137
|
+
const statusPriority = {
|
|
138
|
+
MATCH: 3,
|
|
139
|
+
POSSIBLE: 2,
|
|
140
|
+
REJECT: 1
|
|
141
|
+
};
|
|
142
|
+
results.sort((a, b) => {
|
|
143
|
+
const prioDiff = (statusPriority[b.status] ?? 0) - (statusPriority[a.status] ?? 0);
|
|
144
|
+
if (prioDiff !== 0) return prioDiff;
|
|
145
|
+
const scoreDiff = b.score - a.score;
|
|
146
|
+
if (Math.abs(scoreDiff) > 1e-3) return scoreDiff;
|
|
147
|
+
return b.knowledge.confidence - a.knowledge.confidence;
|
|
148
|
+
});
|
|
149
|
+
return results;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/jev/explanation.ts
|
|
153
|
+
function formatJevExplanation(result) {
|
|
154
|
+
const k = result.knowledge;
|
|
155
|
+
const exp = result.explanation;
|
|
156
|
+
const lines = [
|
|
157
|
+
`${exp.status}: ${k.id} (Score: ${exp.score.toFixed(2)})`,
|
|
158
|
+
""
|
|
159
|
+
];
|
|
160
|
+
lines.push("positive:");
|
|
161
|
+
if (exp.positiveMatches.length > 0) {
|
|
162
|
+
for (const p of exp.positiveMatches) {
|
|
163
|
+
lines.push(` + ${p}`);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
lines.push(" none");
|
|
167
|
+
}
|
|
168
|
+
lines.push("");
|
|
169
|
+
lines.push("negative conflicts:");
|
|
170
|
+
if (exp.negativeConflicts.length > 0) {
|
|
171
|
+
for (const n of exp.negativeConflicts) {
|
|
172
|
+
lines.push(` - ${n}`);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
lines.push(" none");
|
|
176
|
+
}
|
|
177
|
+
lines.push("");
|
|
178
|
+
lines.push(`confidence:`);
|
|
179
|
+
lines.push(` ${k.confidence.toFixed(2)}`);
|
|
180
|
+
if (exp.reasons.length > 0) {
|
|
181
|
+
lines.push("");
|
|
182
|
+
lines.push(`rationale:`);
|
|
183
|
+
for (const r of exp.reasons) {
|
|
184
|
+
lines.push(` \u2022 ${r}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return lines.join("\n");
|
|
188
|
+
}
|
|
189
|
+
function formatWhyExplanation(knowledge) {
|
|
190
|
+
const lines = [
|
|
191
|
+
`${knowledge.id}`,
|
|
192
|
+
"",
|
|
193
|
+
"Statement:",
|
|
194
|
+
knowledge.statement,
|
|
195
|
+
"",
|
|
196
|
+
"Evidence:"
|
|
197
|
+
];
|
|
198
|
+
if (knowledge.evidence.length > 0) {
|
|
199
|
+
for (const e of knowledge.evidence) {
|
|
200
|
+
lines.push(`- ${e}`);
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
lines.push("- (No direct source references recorded)");
|
|
204
|
+
}
|
|
205
|
+
lines.push("");
|
|
206
|
+
lines.push(`Supports: ${knowledge.metrics.support_count}`);
|
|
207
|
+
lines.push(`Contradictions: ${knowledge.metrics.contradiction_count}`);
|
|
208
|
+
lines.push(`Outcomes: ${knowledge.metrics.successful_outcomes} success, ${knowledge.metrics.failed_outcomes} failed`);
|
|
209
|
+
lines.push(`Confidence: ${knowledge.confidence.toFixed(2)}`);
|
|
210
|
+
lines.push(`Scope: ${knowledge.scope}`);
|
|
211
|
+
lines.push(`Status: ${knowledge.status}`);
|
|
212
|
+
if (knowledge.positive.length > 0) {
|
|
213
|
+
lines.push("");
|
|
214
|
+
lines.push("Applicable because (positive cues):");
|
|
215
|
+
for (const p of knowledge.positive) {
|
|
216
|
+
lines.push(`+ ${p}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (knowledge.negative.length > 0) {
|
|
220
|
+
lines.push("");
|
|
221
|
+
lines.push("Rejected contexts (negative cues):");
|
|
222
|
+
for (const n of knowledge.negative) {
|
|
223
|
+
lines.push(`- ${n}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (knowledge.relations.length > 0) {
|
|
227
|
+
lines.push("");
|
|
228
|
+
lines.push("Relations:");
|
|
229
|
+
for (const r of knowledge.relations) {
|
|
230
|
+
lines.push(`~ ${r}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (knowledge.temporal?.revision) {
|
|
234
|
+
lines.push("");
|
|
235
|
+
lines.push(`Revision: ${knowledge.temporal.revision}`);
|
|
236
|
+
}
|
|
237
|
+
return lines.join("\n");
|
|
238
|
+
}
|
|
239
|
+
function formatWhyHistory(knowledge) {
|
|
240
|
+
const lines = [knowledge.id, ""];
|
|
241
|
+
if (!knowledge.history || knowledge.history.length === 0) {
|
|
242
|
+
const date = knowledge.createdAt ? knowledge.createdAt.split("T")[0] : "unknown";
|
|
243
|
+
const stageOrStatus = (knowledge.stage || knowledge.status).toUpperCase();
|
|
244
|
+
lines.push(date);
|
|
245
|
+
lines.push(stageOrStatus);
|
|
246
|
+
lines.push(knowledge.statement);
|
|
247
|
+
return lines.join("\n");
|
|
248
|
+
}
|
|
249
|
+
for (let i = 0; i < knowledge.history.length; i++) {
|
|
250
|
+
const entry = knowledge.history[i];
|
|
251
|
+
const date = entry.timestamp ? entry.timestamp.split("T")[0] : "unknown";
|
|
252
|
+
const stageOrStatus = (entry.stage || entry.status).toUpperCase();
|
|
253
|
+
lines.push(date);
|
|
254
|
+
lines.push(stageOrStatus);
|
|
255
|
+
lines.push(entry.reason || entry.source || "Updated");
|
|
256
|
+
if (i < knowledge.history.length - 1) {
|
|
257
|
+
lines.push("");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return lines.join("\n");
|
|
261
|
+
}
|
|
262
|
+
export {
|
|
263
|
+
evaluateJev,
|
|
264
|
+
formatJevExplanation,
|
|
265
|
+
formatWhyExplanation,
|
|
266
|
+
formatWhyHistory,
|
|
267
|
+
rerankCandidates
|
|
268
|
+
};
|
|
269
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/jev/scorer.ts","../../src/jev/matcher.ts","../../src/jev/explanation.ts"],"sourcesContent":["import type {\n Knowledge,\n JevMatchStatus,\n JevExplanation,\n JevResult,\n Scope\n} from '../core/types.js';\n\nexport interface QueryContext {\n query?: string;\n positive?: string[];\n negative?: string[];\n scope?: Scope;\n}\n\nconst statementTokenCache = new WeakMap<Knowledge, Set<string>>();\n\nfunction extractTokens(text?: string): Set<string> {\n if (!text) return new Set();\n return new Set(\n text\n .toLowerCase()\n .replace(/[^a-z0-9_-]/g, ' ')\n .split(/\\s+/)\n .filter((t) => t.length > 2)\n );\n}\n\nfunction getKnowledgeStatementTokens(k: Knowledge): Set<string> {\n let tokens = statementTokenCache.get(k);\n if (!tokens) {\n tokens = extractTokens(k.statement);\n statementTokenCache.set(k, tokens);\n }\n return tokens;\n}\n\n/**\n * Evaluates JEV-style positive and negative contextual proximity for a knowledge unit.\n */\nexport function evaluateJev(\n knowledge: Knowledge,\n context: QueryContext\n): JevResult {\n const queryTokens = extractTokens(context.query);\n const contextPos = new Set((context.positive ?? []).map((p) => p.trim().toLowerCase()));\n const contextNeg = new Set((context.negative ?? []).map((n) => n.trim().toLowerCase()));\n\n const knowPos = new Set((knowledge.positive ?? []).map((p) => p.trim().toLowerCase()));\n const knowNeg = new Set((knowledge.negative ?? []).map((n) => n.trim().toLowerCase()));\n\n // 1. Negative Conflict Detection\n const negativeConflicts: string[] = [];\n\n // Knowledge forbids something present in positive context\n for (const n of knowNeg) {\n if (contextPos.has(n) || queryTokens.has(n)) {\n negativeConflicts.push(`Knowledge forbids \"${n}\", which was present in context`);\n }\n }\n\n // Context forbids something present in knowledge\n for (const p of knowPos) {\n if (contextNeg.has(p)) {\n negativeConflicts.push(`Context forbids \"${p}\", which is required by knowledge`);\n }\n }\n\n // 2. Positive Matches\n const positiveMatches: string[] = [];\n\n // Direct cue overlap\n for (const p of knowPos) {\n if (contextPos.has(p)) {\n positiveMatches.push(`Context cue: ${p}`);\n } else {\n // Check if any query token matches or stems into cue\n for (const q of queryTokens) {\n if (p === q || p.startsWith(q) || q.startsWith(p)) {\n positiveMatches.push(`Query term match: ${p}`);\n break;\n }\n }\n }\n }\n\n // Statement query token overlap\n const stmtTokens = getKnowledgeStatementTokens(knowledge);\n let queryOverlapCount = 0;\n for (const q of queryTokens) {\n let matched = false;\n for (const st of stmtTokens) {\n if (q === st || q.startsWith(st) || st.startsWith(q)) {\n matched = true;\n break;\n }\n }\n if (matched) {\n queryOverlapCount++;\n positiveMatches.push(`Statement term: ${q}`);\n }\n }\n\n // 3. Positive Score Calculation\n const totalCues = Math.max(1, knowPos.size);\n const matchedCuesCount = positiveMatches.filter((m) => m.startsWith('Context cue') || m.startsWith('Query term')).length;\n const cueMatchRatio = matchedCuesCount / totalCues;\n const tokenOverlapScore = queryTokens.size > 0 ? queryOverlapCount / Math.max(1, queryTokens.size) : 0;\n const rawPositiveScore = 0.65 * cueMatchRatio + 0.35 * tokenOverlapScore;\n\n // 4. Scope Alignment\n let scopeMultiplier = 1.0;\n const targetScope = (context.scope ?? 'project').toLowerCase();\n const knowScope = (knowledge.scope ?? 'project').toLowerCase();\n\n if (targetScope === knowScope) {\n scopeMultiplier = 1.0;\n } else if (knowScope === 'global' || targetScope.startsWith(knowScope)) {\n scopeMultiplier = 0.85;\n } else if (knowScope === 'project' && targetScope.startsWith('branch:')) {\n scopeMultiplier = 0.90;\n } else {\n // Mismatched scopes\n scopeMultiplier = 0.30;\n }\n\n // 5. Confidence and Evidence Ratio\n const m = knowledge.metrics;\n const evRatio = (m.support_count + 1) / (m.support_count + 2 * m.contradiction_count + 1);\n const confidenceFactor = knowledge.confidence * evRatio;\n\n // 6. Outcome Boost / Penalty\n let outcomeAdjustment = 0;\n if (m.successful_outcomes > 0) {\n outcomeAdjustment += Math.min(0.10, m.successful_outcomes * 0.03);\n }\n if (m.failed_outcomes > 0) {\n outcomeAdjustment -= Math.min(0.20, m.failed_outcomes * 0.05);\n }\n\n // 7. Base Combined Score\n let score = (rawPositiveScore * 0.45 + confidenceFactor * 0.40 + outcomeAdjustment) * scopeMultiplier;\n\n // Stale or Contradicted Status Penalty\n if (knowledge.status === 'stale') {\n score *= 0.6;\n } else if (knowledge.status === 'contradicted') {\n score *= 0.3;\n } else if (knowledge.status === 'invalid' || knowledge.status === 'superseded') {\n score *= 0.1;\n }\n\n // 8. Negative Conflict Penalty & Decision\n let status: JevMatchStatus = 'POSSIBLE';\n const reasons: string[] = [];\n\n if (negativeConflicts.length > 0) {\n // Severe penalty for negative conflicts\n score = Math.max(0.01, score * 0.2);\n status = 'REJECT';\n reasons.push(`Rejected due to ${negativeConflicts.length} negative contextual conflicts.`);\n } else if (score >= 0.45 && positiveMatches.length > 0) {\n status = 'MATCH';\n reasons.push(`Strong contextual match with ${positiveMatches.length} matching signals.`);\n } else if (score >= 0.25) {\n status = 'POSSIBLE';\n reasons.push(`Potential match; partial contextual overlap.`);\n } else {\n status = 'REJECT';\n reasons.push(`Insufficient contextual match score (${score.toFixed(2)} < 0.25).`);\n }\n\n const finalScore = Math.round(Math.min(1.0, Math.max(0.0, score)) * 100) / 100;\n\n const explanation: JevExplanation = {\n positiveMatches,\n negativeConflicts,\n score: finalScore,\n confidence: knowledge.confidence,\n status,\n reasons\n };\n\n return {\n knowledge,\n status,\n score: finalScore,\n explanation\n };\n}\n","import type { Knowledge, JevResult } from '../core/types.js';\nimport { evaluateJev, type QueryContext } from './scorer.js';\n\n/**\n * Re-ranks a small set of candidate knowledge units using JEV contextual evaluation.\n */\nexport function rerankCandidates(\n candidates: Knowledge[],\n context: QueryContext\n): JevResult[] {\n const results: JevResult[] = [];\n\n for (const candidate of candidates) {\n const res = evaluateJev(candidate, context);\n results.push(res);\n }\n\n // Sort: MATCH first, then POSSIBLE, then REJECT; within each group, highest score first\n const statusPriority: Record<string, number> = {\n MATCH: 3,\n POSSIBLE: 2,\n REJECT: 1\n };\n\n results.sort((a, b) => {\n const prioDiff = (statusPriority[b.status] ?? 0) - (statusPriority[a.status] ?? 0);\n if (prioDiff !== 0) return prioDiff;\n const scoreDiff = b.score - a.score;\n if (Math.abs(scoreDiff) > 0.001) return scoreDiff;\n return b.knowledge.confidence - a.knowledge.confidence;\n });\n\n return results;\n}\n","import type { JevResult, Knowledge } from '../core/types.js';\n\n/**\n * Formats a JevResult into a clear, inspectable explanation string.\n */\nexport function formatJevExplanation(result: JevResult): string {\n const k = result.knowledge;\n const exp = result.explanation;\n\n const lines: string[] = [\n `${exp.status}: ${k.id} (Score: ${exp.score.toFixed(2)})`,\n ''\n ];\n\n lines.push('positive:');\n if (exp.positiveMatches.length > 0) {\n for (const p of exp.positiveMatches) {\n lines.push(` + ${p}`);\n }\n } else {\n lines.push(' none');\n }\n\n lines.push('');\n lines.push('negative conflicts:');\n if (exp.negativeConflicts.length > 0) {\n for (const n of exp.negativeConflicts) {\n lines.push(` - ${n}`);\n }\n } else {\n lines.push(' none');\n }\n\n lines.push('');\n lines.push(`confidence:`);\n lines.push(` ${k.confidence.toFixed(2)}`);\n\n if (exp.reasons.length > 0) {\n lines.push('');\n lines.push(`rationale:`);\n for (const r of exp.reasons) {\n lines.push(` • ${r}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats full \"bilmem why <id>\" detailed output.\n */\nexport function formatWhyExplanation(knowledge: Knowledge): string {\n const lines: string[] = [\n `${knowledge.id}`,\n '',\n 'Statement:',\n knowledge.statement,\n '',\n 'Evidence:'\n ];\n\n if (knowledge.evidence.length > 0) {\n for (const e of knowledge.evidence) {\n lines.push(`- ${e}`);\n }\n } else {\n lines.push('- (No direct source references recorded)');\n }\n\n lines.push('');\n lines.push(`Supports: ${knowledge.metrics.support_count}`);\n lines.push(`Contradictions: ${knowledge.metrics.contradiction_count}`);\n lines.push(`Outcomes: ${knowledge.metrics.successful_outcomes} success, ${knowledge.metrics.failed_outcomes} failed`);\n lines.push(`Confidence: ${knowledge.confidence.toFixed(2)}`);\n lines.push(`Scope: ${knowledge.scope}`);\n lines.push(`Status: ${knowledge.status}`);\n\n if (knowledge.positive.length > 0) {\n lines.push('');\n lines.push('Applicable because (positive cues):');\n for (const p of knowledge.positive) {\n lines.push(`+ ${p}`);\n }\n }\n\n if (knowledge.negative.length > 0) {\n lines.push('');\n lines.push('Rejected contexts (negative cues):');\n for (const n of knowledge.negative) {\n lines.push(`- ${n}`);\n }\n }\n\n if (knowledge.relations.length > 0) {\n lines.push('');\n lines.push('Relations:');\n for (const r of knowledge.relations) {\n lines.push(`~ ${r}`);\n }\n }\n\n if (knowledge.temporal?.revision) {\n lines.push('');\n lines.push(`Revision: ${knowledge.temporal.revision}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats lifecycle history for \"bilmem why <id> --history\".\n */\nexport function formatWhyHistory(knowledge: Knowledge): string {\n const lines: string[] = [knowledge.id, ''];\n\n if (!knowledge.history || knowledge.history.length === 0) {\n const date = knowledge.createdAt ? knowledge.createdAt.split('T')[0] : 'unknown';\n const stageOrStatus = (knowledge.stage || knowledge.status).toUpperCase();\n lines.push(date);\n lines.push(stageOrStatus);\n lines.push(knowledge.statement);\n return lines.join('\\n');\n }\n\n for (let i = 0; i < knowledge.history.length; i++) {\n const entry = knowledge.history[i];\n const date = entry.timestamp ? entry.timestamp.split('T')[0] : 'unknown';\n const stageOrStatus = (entry.stage || entry.status).toUpperCase();\n lines.push(date);\n lines.push(stageOrStatus);\n lines.push(entry.reason || entry.source || 'Updated');\n if (i < knowledge.history.length - 1) {\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["m"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpApp } from 'mcponce';
|
|
2
|
+
|
|
3
|
+
interface CreateMcpAppOptions {
|
|
4
|
+
rootDir?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
version?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates the official McpApp for bilmem using mcponce.
|
|
10
|
+
*/
|
|
11
|
+
declare function createBilmemMcpApp(options?: CreateMcpAppOptions): McpApp;
|
|
12
|
+
|
|
13
|
+
export { type CreateMcpAppOptions, createBilmemMcpApp };
|