@jmtrin/opencode-kevin 0.2.0 → 0.3.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 +76 -35
- package/dist/migrations/004_v03_knowledge.sql +138 -0
- package/dist/plugin/CausalChain.d.ts +11 -0
- package/dist/plugin/CausalChain.js +109 -0
- package/dist/plugin/CausalChain.js.map +1 -0
- package/dist/plugin/ContextInjector.d.ts +12 -0
- package/dist/plugin/ContextInjector.js +31 -0
- package/dist/plugin/ContextInjector.js.map +1 -1
- package/dist/plugin/MemoryService.d.ts +62 -2
- package/dist/plugin/MemoryService.js +260 -15
- package/dist/plugin/MemoryService.js.map +1 -1
- package/dist/plugin/Migrate.js +12 -0
- package/dist/plugin/Migrate.js.map +1 -1
- package/dist/plugin/Reflector.d.ts +16 -0
- package/dist/plugin/Reflector.js +58 -19
- package/dist/plugin/Reflector.js.map +1 -1
- package/dist/plugin/ToolCallObserver.js +1 -1
- package/dist/plugin/ToolCallObserver.js.map +1 -1
- package/dist/plugin/index.js +130 -10
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/kevin_why.d.ts +19 -0
- package/dist/plugin/kevin_why.js +92 -0
- package/dist/plugin/kevin_why.js.map +1 -0
- package/dist/plugin/metrics.d.ts +1 -1
- package/dist/plugin/metrics.js +3 -0
- package/dist/plugin/metrics.js.map +1 -1
- package/dist/plugin/okf-export.d.ts +3 -0
- package/dist/plugin/okf-export.js +86 -0
- package/dist/plugin/okf-export.js.map +1 -0
- package/dist/plugin/okf-import.d.ts +73 -0
- package/dist/plugin/okf-import.js +239 -0
- package/dist/plugin/okf-import.js.map +1 -0
- package/migrations/004_v03_knowledge.sql +138 -0
- package/package.json +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { TS_CODE_RULES } from "./Reflector.js";
|
|
2
|
+
export function kevinWhy(store, query) {
|
|
3
|
+
// v0.3.0 fix (bug #7) — the old code wrapped the WHOLE query in a
|
|
4
|
+
// single quoted phrase, so it only matched the exact full-string
|
|
5
|
+
// sequence. Tokenize like MemoryService.queryRelevant: quote each
|
|
6
|
+
// word (escaping inner quotes) and AND them together, so partial or
|
|
7
|
+
// multi-word queries still hit the FTS index.
|
|
8
|
+
const tokens = query
|
|
9
|
+
.trim()
|
|
10
|
+
.split(/\s+/)
|
|
11
|
+
.filter((t) => t.length > 0)
|
|
12
|
+
.map((t) => `"${t.replace(/"/g, '""')}"`);
|
|
13
|
+
if (tokens.length === 0)
|
|
14
|
+
return null;
|
|
15
|
+
const match = tokens.join(" AND ");
|
|
16
|
+
const patternRows = store
|
|
17
|
+
.prepare(`SELECT m.id, m.content, m.fingerprint, m.evidence_count,
|
|
18
|
+
m.last_verified_at, m.created_at
|
|
19
|
+
FROM memories_fts
|
|
20
|
+
JOIN memories m ON m.rowid = memories_fts.rowid
|
|
21
|
+
WHERE memories_fts MATCH ?
|
|
22
|
+
AND m.type = 'pattern'
|
|
23
|
+
AND m.origin IN ('causal', 'pattern')
|
|
24
|
+
AND m.status = 'active'
|
|
25
|
+
ORDER BY m.evidence_count DESC, m.created_at DESC
|
|
26
|
+
LIMIT 1`)
|
|
27
|
+
.all(match);
|
|
28
|
+
if (patternRows.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
const pattern = patternRows[0];
|
|
31
|
+
const fp = pattern.fingerprint;
|
|
32
|
+
const confidence = Math.min(1.0, 0.5 + 0.1 * (pattern.evidence_count ?? 0));
|
|
33
|
+
const traceRows = store
|
|
34
|
+
.prepare(`SELECT tc.session_id, tc.ts, tc.success,
|
|
35
|
+
m.id as memory_id, m.type as memory_type, m.created_at as memory_created_at
|
|
36
|
+
FROM tool_calls tc
|
|
37
|
+
LEFT JOIN memories m ON m.fingerprint = tc.fix_for_fingerprint
|
|
38
|
+
AND m.type = 'error' AND m.origin = 'reflector'
|
|
39
|
+
WHERE (tc.fix_for_fingerprint = ? OR tc.fingerprint LIKE ?)
|
|
40
|
+
AND tc.session_id IN (
|
|
41
|
+
SELECT DISTINCT source_session FROM memories
|
|
42
|
+
WHERE fingerprint = ? AND type = 'error'
|
|
43
|
+
)
|
|
44
|
+
ORDER BY tc.ts ASC
|
|
45
|
+
LIMIT 20`)
|
|
46
|
+
.all(fp, `%${fp.slice(0, 8)}%`, fp);
|
|
47
|
+
const trace = [];
|
|
48
|
+
const errorSessions = store
|
|
49
|
+
.prepare(`SELECT DISTINCT source_session, fingerprint, created_at
|
|
50
|
+
FROM memories
|
|
51
|
+
WHERE fingerprint = ? AND type = 'error' AND origin = 'reflector'
|
|
52
|
+
ORDER BY created_at ASC`)
|
|
53
|
+
.all(fp);
|
|
54
|
+
for (const err of errorSessions) {
|
|
55
|
+
trace.push({
|
|
56
|
+
event: "failure",
|
|
57
|
+
fingerprint: err.fingerprint,
|
|
58
|
+
session: err.source_session ?? "unknown",
|
|
59
|
+
ts: err.created_at,
|
|
60
|
+
});
|
|
61
|
+
const fixRow = store
|
|
62
|
+
.prepare(`SELECT session_id, ts FROM tool_calls
|
|
63
|
+
WHERE fix_for_fingerprint = ?
|
|
64
|
+
AND session_id = ?
|
|
65
|
+
ORDER BY ts ASC LIMIT 1`)
|
|
66
|
+
.get(fp, err.source_session);
|
|
67
|
+
if (fixRow) {
|
|
68
|
+
trace.push({
|
|
69
|
+
event: "fix",
|
|
70
|
+
fingerprint: fp,
|
|
71
|
+
session: fixRow.session_id,
|
|
72
|
+
ts: fixRow.ts,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const relatedRules = [];
|
|
77
|
+
const tsCodeMatch = query.match(/TS(\d{4,5})/);
|
|
78
|
+
if (tsCodeMatch) {
|
|
79
|
+
const hint = TS_CODE_RULES[tsCodeMatch[1]] ?? `review TS${tsCodeMatch[1]}`;
|
|
80
|
+
relatedRules.push(hint);
|
|
81
|
+
}
|
|
82
|
+
const summary = `When tool fails with ${query}: ${confidence >= 0.7 ? "consistently" : "often"} resolved by fixing ${relatedRules.length > 0 ? relatedRules.join(", ") : "the underlying issue"}.`;
|
|
83
|
+
return {
|
|
84
|
+
summary,
|
|
85
|
+
confidence,
|
|
86
|
+
evidence_count: pattern.evidence_count ?? 0,
|
|
87
|
+
last_verified: pattern.last_verified_at ?? null,
|
|
88
|
+
trace,
|
|
89
|
+
related_rules: relatedRules,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=kevin_why.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kevin_why.js","sourceRoot":"","sources":["../../plugin/kevin_why.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAuB/C,MAAM,UAAU,QAAQ,CAAC,KAAY,EAAE,KAAa;IACnD,kEAAkE;IAClE,iEAAiE;IACjE,kEAAkE;IAClE,oEAAoE;IACpE,8CAA8C;IAC9C,MAAM,MAAM,GAAG,KAAK;SAClB,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,WAAW,GAAG,KAAK;SACvB,OAAO,CACP;;;;;;;;;YASS,CACT;SACA,GAAG,CAAC,KAAK,CAOR,CAAC;IAEJ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,CAAC;IAE5E,MAAM,SAAS,GAAG,KAAK;SACrB,OAAO,CACP;;;;;;;;;;;aAWU,CACV;SACA,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,CAOhC,CAAC;IAEJ,MAAM,KAAK,GAAoB,EAAE,CAAC;IAElC,MAAM,aAAa,GAAG,KAAK;SACzB,OAAO,CACP;;;4BAGyB,CACzB;SACA,GAAG,CAAC,EAAE,CAIL,CAAC;IAEJ,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC;YACV,KAAK,EAAE,SAAS;YAChB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,OAAO,EAAE,GAAG,CAAC,cAAc,IAAI,SAAS;YACxC,EAAE,EAAE,GAAG,CAAC,UAAU;SAClB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,KAAK;aAClB,OAAO,CACP;;;6BAGyB,CACzB;aACA,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,cAAc,CAEhB,CAAC;QAEb,IAAI,MAAM,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC;gBACV,KAAK,EAAE,KAAK;gBACZ,WAAW,EAAE,EAAE;gBACf,OAAO,EAAE,MAAM,CAAC,UAAU;gBAC1B,EAAE,EAAE,MAAM,CAAC,EAAE;aACb,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC/C,IAAI,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,YAAY,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,OAAO,GAAG,wBAAwB,KAAK,KAAK,UAAU,IAAI,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,uBAAuB,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,sBAAsB,GAAG,CAAC;IAEnM,OAAO;QACN,OAAO;QACP,UAAU;QACV,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC;QAC3C,aAAa,EAAE,OAAO,CAAC,gBAAgB,IAAI,IAAI;QAC/C,KAAK;QACL,aAAa,EAAE,YAAY;KAC3B,CAAC;AACH,CAAC"}
|
package/dist/plugin/metrics.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { Store } from "./Store.js";
|
|
|
6
6
|
* underlying table is empty (e.g., before 003 is applied, on a fresh
|
|
7
7
|
* :memory: test DB, or after a manual wipe).
|
|
8
8
|
*/
|
|
9
|
-
export declare const METRIC_KEYS: readonly ["tokens_injected_pre_prompt", "tokens_injected_compacting", "reflections_throttled", "duplicate_suppressions", "tool_calls_deduped", "patterns_mined"];
|
|
9
|
+
export declare const METRIC_KEYS: readonly ["tokens_injected_pre_prompt", "tokens_injected_compacting", "reflections_throttled", "duplicate_suppressions", "tool_calls_deduped", "patterns_mined", "patterns_causal", "causal_links", "memories_superseded"];
|
|
10
10
|
export type MetricKey = (typeof METRIC_KEYS)[number];
|
|
11
11
|
/**
|
|
12
12
|
* Cheap token estimate used when bumping the `tokens_injected_*` counters.
|
package/dist/plugin/metrics.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../plugin/metrics.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,4BAA4B;IAC5B,4BAA4B;IAC5B,uBAAuB;IACvB,wBAAwB;IACxB,oBAAoB;IACpB,gBAAgB;
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../plugin/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const EXPORT_TYPES = new Set(["decision", "rule", "pattern"]);
|
|
2
|
+
function formatTimestamp(ts) {
|
|
3
|
+
try {
|
|
4
|
+
return new Date(ts).toISOString().replace("T", " ").slice(0, 19);
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return ts;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function exportOkf(store) {
|
|
11
|
+
const rows = store
|
|
12
|
+
.prepare(`SELECT id, type, content, scope, relevance_score, fingerprint,
|
|
13
|
+
evidence_count, last_verified_at, status,
|
|
14
|
+
source_tool, source_session, created_at, updated_at
|
|
15
|
+
FROM memories
|
|
16
|
+
WHERE status = 'active'
|
|
17
|
+
ORDER BY type, created_at DESC`)
|
|
18
|
+
.all();
|
|
19
|
+
const filtered = rows.filter((r) => EXPORT_TYPES.has(r.type));
|
|
20
|
+
if (filtered.length === 0)
|
|
21
|
+
return "<!-- No exportable memories found. -->\n";
|
|
22
|
+
const blocks = [];
|
|
23
|
+
for (const m of filtered) {
|
|
24
|
+
const fm = [];
|
|
25
|
+
fm.push("---");
|
|
26
|
+
fm.push(`id: ${m.id}`);
|
|
27
|
+
fm.push(`type: ${m.type}`);
|
|
28
|
+
fm.push(`confidence: ${Math.min(1, 0.5 + 0.1 * m.evidence_count).toFixed(2)}`);
|
|
29
|
+
fm.push(`evidence_count: ${m.evidence_count}`);
|
|
30
|
+
if (m.last_verified_at) {
|
|
31
|
+
fm.push(`last_verified_at: ${formatTimestamp(m.last_verified_at)}`);
|
|
32
|
+
}
|
|
33
|
+
if (m.fingerprint) {
|
|
34
|
+
fm.push(`fingerprint: ${m.fingerprint}`);
|
|
35
|
+
}
|
|
36
|
+
fm.push(`created: ${formatTimestamp(m.created_at)}`);
|
|
37
|
+
fm.push(`scope: ${m.scope}`);
|
|
38
|
+
fm.push("---");
|
|
39
|
+
fm.push("");
|
|
40
|
+
fm.push(m.content);
|
|
41
|
+
blocks.push(fm.join("\n"));
|
|
42
|
+
}
|
|
43
|
+
return `${blocks.join("\n\n")}\n`;
|
|
44
|
+
}
|
|
45
|
+
export function exportMarkdown(store) {
|
|
46
|
+
const rows = store
|
|
47
|
+
.prepare(`SELECT id, type, content, scope, relevance_score, fingerprint,
|
|
48
|
+
evidence_count, last_verified_at, status,
|
|
49
|
+
created_at, updated_at
|
|
50
|
+
FROM memories
|
|
51
|
+
WHERE status = 'active'
|
|
52
|
+
ORDER BY type, created_at DESC`)
|
|
53
|
+
.all();
|
|
54
|
+
const filtered = rows.filter((r) => EXPORT_TYPES.has(r.type));
|
|
55
|
+
if (filtered.length === 0)
|
|
56
|
+
return "# Kevin Knowledge Export\n\n_No exportable memories found._\n";
|
|
57
|
+
const lines = [];
|
|
58
|
+
lines.push("# Kevin Knowledge Export");
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push(`Exported: ${new Date().toISOString().replace("T", " ").slice(0, 19)}`);
|
|
61
|
+
lines.push(`Total entries: ${filtered.length}`);
|
|
62
|
+
lines.push("");
|
|
63
|
+
for (const m of filtered) {
|
|
64
|
+
const conf = Math.min(1, 0.5 + 0.1 * m.evidence_count);
|
|
65
|
+
lines.push(`## ${m.type}: \`${m.fingerprint ?? m.id.slice(0, 8)}\``);
|
|
66
|
+
lines.push("");
|
|
67
|
+
lines.push(`- **ID:** \`${m.id}\``);
|
|
68
|
+
lines.push(`- **Confidence:** ${conf.toFixed(2)}`);
|
|
69
|
+
lines.push(`- **Evidence count:** ${m.evidence_count}`);
|
|
70
|
+
if (m.last_verified_at) {
|
|
71
|
+
lines.push(`- **Last verified:** ${formatTimestamp(m.last_verified_at)}`);
|
|
72
|
+
}
|
|
73
|
+
if (m.fingerprint) {
|
|
74
|
+
lines.push(`- **Fingerprint:** \`${m.fingerprint}\``);
|
|
75
|
+
}
|
|
76
|
+
lines.push(`- **Scope:** ${m.scope}`);
|
|
77
|
+
lines.push(`- **Created:** ${formatTimestamp(m.created_at)}`);
|
|
78
|
+
lines.push("");
|
|
79
|
+
lines.push(m.content);
|
|
80
|
+
lines.push("");
|
|
81
|
+
lines.push("---");
|
|
82
|
+
lines.push("");
|
|
83
|
+
}
|
|
84
|
+
return lines.join("\n");
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=okf-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okf-export.js","sourceRoot":"","sources":["../../plugin/okf-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { MemoryService } from "./MemoryService.js";
|
|
2
|
+
/**
|
|
3
|
+
* v0.3.0 fix — A single parsed bundle entry. `evidence_count` and
|
|
4
|
+
* `last_verified_at` are preserved across round-trips (export → import)
|
|
5
|
+
* so causal confidence is not lost when knowledge is shared between
|
|
6
|
+
* projects.
|
|
7
|
+
*/
|
|
8
|
+
export interface ParsedEntry {
|
|
9
|
+
id: string;
|
|
10
|
+
type: string;
|
|
11
|
+
content: string;
|
|
12
|
+
fingerprint: string | null;
|
|
13
|
+
evidence_count: number;
|
|
14
|
+
last_verified_at: string | null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* v0.3.0 fix — Clean state-machine parser for the frontmatter bundle
|
|
18
|
+
* format produced by `okf-export.ts::exportOkf`. Each entry is:
|
|
19
|
+
*
|
|
20
|
+
* ---
|
|
21
|
+
* id: <uuid>
|
|
22
|
+
* type: <decision|rule|pattern>
|
|
23
|
+
* confidence: 0.70
|
|
24
|
+
* evidence_count: 2
|
|
25
|
+
* last_verified_at: 2026-07-25 12:34:56
|
|
26
|
+
* fingerprint: <hex>
|
|
27
|
+
* created: 2026-07-25 12:00:00
|
|
28
|
+
* scope: project
|
|
29
|
+
* ---
|
|
30
|
+
*
|
|
31
|
+
* <content body, may span multiple lines, may include `---` lines
|
|
32
|
+
* within — the body terminator is the NEXT top-level `---` followed
|
|
33
|
+
* by an `id:` line, or EOF>
|
|
34
|
+
*
|
|
35
|
+
* The previous implementation only ever flagged `inFm = true` once and
|
|
36
|
+
* never reset `contentStarted` between entries, so 2..N entries were
|
|
37
|
+
* silently dropped (bug #1). This rewrite handles arbitrary numbers of
|
|
38
|
+
* consecutive frontmatter sections.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseMarkdownBundle(text: string): ParsedEntry[];
|
|
41
|
+
/**
|
|
42
|
+
* v0.3.0 fix — Fallback parser for the markdown-style `##` heading
|
|
43
|
+
* format produced by `okf-export.ts::exportMarkdown`. The previous
|
|
44
|
+
* version extracted `fingerprint: null` for every entry (regex was
|
|
45
|
+
* pinned to 16 hex chars while actual fingerprints are variable
|
|
46
|
+
* length) and contaminated `content` with the heading line and
|
|
47
|
+
* metadata bullets. This version cleanly separates metadata bullets
|
|
48
|
+
* (looking for `**ID:**`, `**Fingerprint:**`, `**Evidence count:**`,
|
|
49
|
+
* `**Last verified:**`, `**Scope:**` prefixes) from the content
|
|
50
|
+
* body, which starts after the first blank line following the bullet
|
|
51
|
+
* block and runs until the trailing `---` separator (or EOF).
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseMarkdownHeadings(text: string): ParsedEntry[];
|
|
54
|
+
export interface ImportResult {
|
|
55
|
+
imported: number;
|
|
56
|
+
superseded: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* v0.3.0 fix — Ingest a bundle (frontmatter OR markdown) into the
|
|
60
|
+
* local SQLite store as `context` memories with `origin='imported'`.
|
|
61
|
+
*
|
|
62
|
+
* Fixes over the v0.3.0 baseline:
|
|
63
|
+
* * Multi-entry bundles now produce N imports instead of N=1 — the
|
|
64
|
+
* parser bug is closed.
|
|
65
|
+
* * `ParsedEntry.evidence_count` and `last_verified_at` are
|
|
66
|
+
* threaded through so causal confidence survives a round-trip.
|
|
67
|
+
* * `ImportResult.superseded` is populated using
|
|
68
|
+
* `countSupersedeCandidates`, which mirrors the supersede logic
|
|
69
|
+
* in `MemoryService.save()`. Previously it was hard-coded to 0.
|
|
70
|
+
* * Generated ids use `uuidv7()` (the project's id generator)
|
|
71
|
+
* instead of `crypto.randomUUID()` for consistency.
|
|
72
|
+
*/
|
|
73
|
+
export declare function importOkf(bundle: string, memoryService: MemoryService): ImportResult;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { fingerprint as computeFingerprint } from "./fingerprint.js";
|
|
2
|
+
import { uuidv7 } from "./uuid.js";
|
|
3
|
+
const PAIR_RE = /^([a-z_]+):\s*(.*)$/i;
|
|
4
|
+
const ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5
|
+
/**
|
|
6
|
+
* v0.3.0 fix — Clean state-machine parser for the frontmatter bundle
|
|
7
|
+
* format produced by `okf-export.ts::exportOkf`. Each entry is:
|
|
8
|
+
*
|
|
9
|
+
* ---
|
|
10
|
+
* id: <uuid>
|
|
11
|
+
* type: <decision|rule|pattern>
|
|
12
|
+
* confidence: 0.70
|
|
13
|
+
* evidence_count: 2
|
|
14
|
+
* last_verified_at: 2026-07-25 12:34:56
|
|
15
|
+
* fingerprint: <hex>
|
|
16
|
+
* created: 2026-07-25 12:00:00
|
|
17
|
+
* scope: project
|
|
18
|
+
* ---
|
|
19
|
+
*
|
|
20
|
+
* <content body, may span multiple lines, may include `---` lines
|
|
21
|
+
* within — the body terminator is the NEXT top-level `---` followed
|
|
22
|
+
* by an `id:` line, or EOF>
|
|
23
|
+
*
|
|
24
|
+
* The previous implementation only ever flagged `inFm = true` once and
|
|
25
|
+
* never reset `contentStarted` between entries, so 2..N entries were
|
|
26
|
+
* silently dropped (bug #1). This rewrite handles arbitrary numbers of
|
|
27
|
+
* consecutive frontmatter sections.
|
|
28
|
+
*/
|
|
29
|
+
export function parseMarkdownBundle(text) {
|
|
30
|
+
const lines = text.replace(/\r\n/g, "\n").split("\n");
|
|
31
|
+
const entries = [];
|
|
32
|
+
let i = 0;
|
|
33
|
+
let fm = null;
|
|
34
|
+
let body = [];
|
|
35
|
+
// True when we have just seen a `---` opener and are collecting
|
|
36
|
+
// `key: value` pairs until the matching `---` closer.
|
|
37
|
+
const isFmKey = (s) => PAIR_RE.test(s) || s.trim() === "";
|
|
38
|
+
while (i < lines.length) {
|
|
39
|
+
const line = lines[i];
|
|
40
|
+
// Seek an opening `---`.
|
|
41
|
+
if (line.trim() !== "---") {
|
|
42
|
+
i++;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
// Trivially empty bundle (just opener/closer with no keys) — skip.
|
|
46
|
+
if (lines[i + 1]?.trim() === "---") {
|
|
47
|
+
i += 2;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Begin frontmatter collection.
|
|
51
|
+
fm = {};
|
|
52
|
+
body = [];
|
|
53
|
+
i++;
|
|
54
|
+
let closed = false;
|
|
55
|
+
while (i < lines.length) {
|
|
56
|
+
const cur = lines[i];
|
|
57
|
+
if (cur.trim() === "---") {
|
|
58
|
+
closed = true;
|
|
59
|
+
i++;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
const m = cur.match(PAIR_RE);
|
|
63
|
+
if (m) {
|
|
64
|
+
fm[m[1].toLowerCase()] = m[2].trim();
|
|
65
|
+
}
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
if (!closed)
|
|
69
|
+
break;
|
|
70
|
+
if (!fm.id)
|
|
71
|
+
continue;
|
|
72
|
+
// Collect body until the next top-level `---` opener. The opener
|
|
73
|
+
// is recognizable as `---` followed by an `id:` pair in the next
|
|
74
|
+
// frontmatter block; we look ahead conservatively: a `---` line
|
|
75
|
+
// immediately followed by a `key:` line is an opener, anything
|
|
76
|
+
// else is body content.
|
|
77
|
+
while (i < lines.length) {
|
|
78
|
+
const cur = lines[i];
|
|
79
|
+
if (cur.trim() === "---") {
|
|
80
|
+
// peek the NEXT non-empty line — if it looks like a PAIR,
|
|
81
|
+
// this `---` is an opener for the next entry, so stop body
|
|
82
|
+
// here without consuming.
|
|
83
|
+
let j = i + 1;
|
|
84
|
+
while (j < lines.length && lines[j].trim() === "")
|
|
85
|
+
j++;
|
|
86
|
+
if (j < lines.length && isFmKey(lines[j]) && PAIR_RE.test(lines[j])) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
// Otherwise treat as body content (e.g. thematic break).
|
|
90
|
+
body.push(cur);
|
|
91
|
+
i++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
body.push(cur);
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
const content = body.join("\n").trim();
|
|
98
|
+
if (!content)
|
|
99
|
+
continue;
|
|
100
|
+
const type = (fm.type ?? "context").toLowerCase();
|
|
101
|
+
const id = ID_RE.test(fm.id) ? fm.id : uuidv7();
|
|
102
|
+
const fp = fm.fingerprint ?? null;
|
|
103
|
+
const evidenceCount = Number.parseInt(fm.evidence_count ?? "0", 10) || 0;
|
|
104
|
+
const lastVerified = fm.last_verified_at ?? null;
|
|
105
|
+
entries.push({
|
|
106
|
+
id,
|
|
107
|
+
type,
|
|
108
|
+
content,
|
|
109
|
+
fingerprint: fp,
|
|
110
|
+
evidence_count: evidenceCount,
|
|
111
|
+
last_verified_at: lastVerified,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return entries;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* v0.3.0 fix — Fallback parser for the markdown-style `##` heading
|
|
118
|
+
* format produced by `okf-export.ts::exportMarkdown`. The previous
|
|
119
|
+
* version extracted `fingerprint: null` for every entry (regex was
|
|
120
|
+
* pinned to 16 hex chars while actual fingerprints are variable
|
|
121
|
+
* length) and contaminated `content` with the heading line and
|
|
122
|
+
* metadata bullets. This version cleanly separates metadata bullets
|
|
123
|
+
* (looking for `**ID:**`, `**Fingerprint:**`, `**Evidence count:**`,
|
|
124
|
+
* `**Last verified:**`, `**Scope:**` prefixes) from the content
|
|
125
|
+
* body, which starts after the first blank line following the bullet
|
|
126
|
+
* block and runs until the trailing `---` separator (or EOF).
|
|
127
|
+
*/
|
|
128
|
+
export function parseMarkdownHeadings(text) {
|
|
129
|
+
const normalized = text.replace(/\r\n/g, "\n");
|
|
130
|
+
// Split on `## ` headings; first chunk is the document preamble.
|
|
131
|
+
const chunks = normalized.split(/^##\s+/m).slice(1);
|
|
132
|
+
const entries = [];
|
|
133
|
+
for (const chunk of chunks) {
|
|
134
|
+
const lines = chunk.split("\n");
|
|
135
|
+
const typeMatch = lines[0]?.match(/^([A-Za-z]+):\s*/);
|
|
136
|
+
const type = typeMatch ? typeMatch[1].toLowerCase() : "context";
|
|
137
|
+
const fm = {};
|
|
138
|
+
let bodyStart = -1;
|
|
139
|
+
for (let k = 1; k < lines.length; k++) {
|
|
140
|
+
const ln = lines[k];
|
|
141
|
+
const bulletId = ln.match(/^- \*\*ID:\*\*\s*`([^`]+)`/);
|
|
142
|
+
const bulletFp = ln.match(/^- \*\*Fingerprint:\*\*\s*`([a-f0-9]+)`/i);
|
|
143
|
+
const bulletEv = ln.match(/^- \*\*Evidence count:\*\*\s*(\d+)/);
|
|
144
|
+
const bulletLv = ln.match(/^- \*\*Last verified:\*\*\s*(.+)$/);
|
|
145
|
+
if (bulletId)
|
|
146
|
+
fm.id = bulletId[1];
|
|
147
|
+
else if (bulletFp)
|
|
148
|
+
fm.fingerprint = bulletFp[1];
|
|
149
|
+
else if (bulletEv)
|
|
150
|
+
fm.evidence_count = bulletEv[1];
|
|
151
|
+
else if (bulletLv)
|
|
152
|
+
fm.last_verified_at = bulletLv[1].trim();
|
|
153
|
+
else if (ln.trim() === "") {
|
|
154
|
+
// First blank line after bullet block — body starts here.
|
|
155
|
+
if (bodyStart < 0)
|
|
156
|
+
bodyStart = k + 1;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (bodyStart < 0)
|
|
161
|
+
bodyStart = 1;
|
|
162
|
+
const bodyLines = [];
|
|
163
|
+
for (let k = bodyStart; k < lines.length; k++) {
|
|
164
|
+
const ln = lines[k];
|
|
165
|
+
if (ln.trim() === "---")
|
|
166
|
+
break;
|
|
167
|
+
bodyLines.push(ln);
|
|
168
|
+
}
|
|
169
|
+
const content = bodyLines.join("\n").trim();
|
|
170
|
+
if (!content)
|
|
171
|
+
continue;
|
|
172
|
+
const id = fm.id && ID_RE.test(fm.id) ? fm.id : uuidv7();
|
|
173
|
+
entries.push({
|
|
174
|
+
id,
|
|
175
|
+
type,
|
|
176
|
+
content,
|
|
177
|
+
fingerprint: fm.fingerprint ?? null,
|
|
178
|
+
evidence_count: Number.parseInt(fm.evidence_count ?? "0", 10) || 0,
|
|
179
|
+
last_verified_at: fm.last_verified_at ?? null,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return entries;
|
|
183
|
+
}
|
|
184
|
+
const IMPORT_ALLOWED_TYPES = new Set([
|
|
185
|
+
"decision",
|
|
186
|
+
"rule",
|
|
187
|
+
"pattern",
|
|
188
|
+
"context",
|
|
189
|
+
]);
|
|
190
|
+
/**
|
|
191
|
+
* v0.3.0 fix — Ingest a bundle (frontmatter OR markdown) into the
|
|
192
|
+
* local SQLite store as `context` memories with `origin='imported'`.
|
|
193
|
+
*
|
|
194
|
+
* Fixes over the v0.3.0 baseline:
|
|
195
|
+
* * Multi-entry bundles now produce N imports instead of N=1 — the
|
|
196
|
+
* parser bug is closed.
|
|
197
|
+
* * `ParsedEntry.evidence_count` and `last_verified_at` are
|
|
198
|
+
* threaded through so causal confidence survives a round-trip.
|
|
199
|
+
* * `ImportResult.superseded` is populated using
|
|
200
|
+
* `countSupersedeCandidates`, which mirrors the supersede logic
|
|
201
|
+
* in `MemoryService.save()`. Previously it was hard-coded to 0.
|
|
202
|
+
* * Generated ids use `uuidv7()` (the project's id generator)
|
|
203
|
+
* instead of `crypto.randomUUID()` for consistency.
|
|
204
|
+
*/
|
|
205
|
+
export function importOkf(bundle, memoryService) {
|
|
206
|
+
let entries = parseMarkdownBundle(bundle);
|
|
207
|
+
if (entries.length === 0) {
|
|
208
|
+
entries = parseMarkdownHeadings(bundle);
|
|
209
|
+
}
|
|
210
|
+
let imported = 0;
|
|
211
|
+
let superseded = 0;
|
|
212
|
+
for (const entry of entries) {
|
|
213
|
+
if (!IMPORT_ALLOWED_TYPES.has(entry.type))
|
|
214
|
+
continue;
|
|
215
|
+
const fp = entry.fingerprint ?? computeFingerprint(entry.content, undefined);
|
|
216
|
+
const contentWithEvidence = entry.evidence_count > 0
|
|
217
|
+
? `${entry.content}\n\n[imported evidence_count=${entry.evidence_count}${entry.last_verified_at
|
|
218
|
+
? `, last_verified_at=${entry.last_verified_at}`
|
|
219
|
+
: ""}]`
|
|
220
|
+
: entry.content;
|
|
221
|
+
// Count rows that save() will mark as superseded (decision/rule
|
|
222
|
+
// with the same fingerprint). The supersede update itself runs
|
|
223
|
+
// inside MemoryService.save() in a single transaction; we count
|
|
224
|
+
// here to surface the value to the caller.
|
|
225
|
+
superseded += memoryService.countSupersedeCandidates(entry.type, fp, null);
|
|
226
|
+
memoryService.save({
|
|
227
|
+
type: entry.type,
|
|
228
|
+
content: contentWithEvidence,
|
|
229
|
+
scope: "project",
|
|
230
|
+
origin: "imported",
|
|
231
|
+
fingerprint: fp,
|
|
232
|
+
evidenceCount: entry.evidence_count > 0 ? entry.evidence_count : undefined,
|
|
233
|
+
lastVerifiedAt: entry.last_verified_at ?? undefined,
|
|
234
|
+
});
|
|
235
|
+
imported++;
|
|
236
|
+
}
|
|
237
|
+
return { imported, superseded };
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=okf-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okf-import.js","sourceRoot":"","sources":["../../plugin/okf-import.ts"],"names":[],"mappings":"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"}
|