@jmtrin/opencode-kevin 0.1.5 → 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.
Files changed (56) hide show
  1. package/README.md +108 -33
  2. package/dist/migrations/003_v02_signal.sql +58 -0
  3. package/dist/migrations/004_v03_knowledge.sql +138 -0
  4. package/dist/plugin/CausalChain.d.ts +11 -0
  5. package/dist/plugin/CausalChain.js +109 -0
  6. package/dist/plugin/CausalChain.js.map +1 -0
  7. package/dist/plugin/ContextInjector.d.ts +25 -1
  8. package/dist/plugin/ContextInjector.js +72 -15
  9. package/dist/plugin/ContextInjector.js.map +1 -1
  10. package/dist/plugin/MemoryService.d.ts +110 -3
  11. package/dist/plugin/MemoryService.js +432 -20
  12. package/dist/plugin/MemoryService.js.map +1 -1
  13. package/dist/plugin/Migrate.d.ts +4 -1
  14. package/dist/plugin/Migrate.js +40 -1
  15. package/dist/plugin/Migrate.js.map +1 -1
  16. package/dist/plugin/PatternMiner.d.ts +49 -0
  17. package/dist/plugin/PatternMiner.js +133 -0
  18. package/dist/plugin/PatternMiner.js.map +1 -0
  19. package/dist/plugin/Reflector.d.ts +45 -2
  20. package/dist/plugin/Reflector.js +134 -12
  21. package/dist/plugin/Reflector.js.map +1 -1
  22. package/dist/plugin/Retrospective.d.ts +4 -1
  23. package/dist/plugin/Retrospective.js +72 -5
  24. package/dist/plugin/Retrospective.js.map +1 -1
  25. package/dist/plugin/Store.d.ts +15 -0
  26. package/dist/plugin/Store.js +15 -0
  27. package/dist/plugin/Store.js.map +1 -1
  28. package/dist/plugin/ToolCallObserver.d.ts +4 -1
  29. package/dist/plugin/ToolCallObserver.js +39 -7
  30. package/dist/plugin/ToolCallObserver.js.map +1 -1
  31. package/dist/plugin/fingerprint.d.ts +27 -0
  32. package/dist/plugin/fingerprint.js +74 -0
  33. package/dist/plugin/fingerprint.js.map +1 -0
  34. package/dist/plugin/index.js +213 -15
  35. package/dist/plugin/index.js.map +1 -1
  36. package/dist/plugin/kevin_why.d.ts +19 -0
  37. package/dist/plugin/kevin_why.js +92 -0
  38. package/dist/plugin/kevin_why.js.map +1 -0
  39. package/dist/plugin/memory-format.d.ts +2 -0
  40. package/dist/plugin/memory-format.js +6 -3
  41. package/dist/plugin/memory-format.js.map +1 -1
  42. package/dist/plugin/metrics.d.ts +60 -0
  43. package/dist/plugin/metrics.js +162 -0
  44. package/dist/plugin/metrics.js.map +1 -0
  45. package/dist/plugin/okf-export.d.ts +3 -0
  46. package/dist/plugin/okf-export.js +86 -0
  47. package/dist/plugin/okf-export.js.map +1 -0
  48. package/dist/plugin/okf-import.d.ts +73 -0
  49. package/dist/plugin/okf-import.js +239 -0
  50. package/dist/plugin/okf-import.js.map +1 -0
  51. package/dist/plugin/redact.d.ts +1 -0
  52. package/dist/plugin/redact.js +7 -0
  53. package/dist/plugin/redact.js.map +1 -1
  54. package/migrations/003_v02_signal.sql +58 -0
  55. package/migrations/004_v03_knowledge.sql +138 -0
  56. package/package.json +48 -48
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Seeded metric keys defined by migration 003_v02_signal.sql.
3
+ * The order here MUST match the migration's INSERT OR IGNORE block, since
4
+ * snapshot() relies on those keys being present in the cache even when the
5
+ * underlying table is empty (e.g., before 003 is applied, on a fresh
6
+ * :memory: test DB, or after a manual wipe).
7
+ */
8
+ export const METRIC_KEYS = [
9
+ "tokens_injected_pre_prompt",
10
+ "tokens_injected_compacting",
11
+ "reflections_throttled",
12
+ "duplicate_suppressions",
13
+ "tool_calls_deduped",
14
+ "patterns_mined",
15
+ "patterns_causal",
16
+ "causal_links",
17
+ "memories_superseded",
18
+ ];
19
+ const DEFAULT_FLUSH_MS = 1000;
20
+ function zeroCache() {
21
+ const m = new Map();
22
+ for (const k of METRIC_KEYS)
23
+ m.set(k, 0);
24
+ return m;
25
+ }
26
+ /**
27
+ * Cheap token estimate used when bumping the `tokens_injected_*` counters.
28
+ * Per plan §B6.2: heuristic = block.length / 4, floored to 1 so empty strings
29
+ * don't contribute zero tokens (avoids losing signal on whitespace-only
30
+ * blocks).
31
+ */
32
+ export function estimateTokens(text) {
33
+ return Math.max(1, Math.round(text.length / 4));
34
+ }
35
+ /**
36
+ * In-memory mirror of the `kevin_metrics` table with debounced writes.
37
+ *
38
+ * The cache is seeded from `kevin_metrics` on construction (or zeros if the
39
+ * table is missing — graceful degradation for unit tests and pre-003 DBs).
40
+ * `incr()` updates the cache and schedules a debounced `flush()` (1 s by
41
+ * default). `flush()` writes every dirty key in a single transaction and
42
+ * clears the timer, so the call site can also force a flush on `session.idle`
43
+ * and on plugin dispose.
44
+ */
45
+ export class Metrics {
46
+ store;
47
+ cache;
48
+ dirty = new Set();
49
+ flushTimer = null;
50
+ flushMs;
51
+ closed = false;
52
+ constructor(store, flushMs = DEFAULT_FLUSH_MS) {
53
+ this.store = store;
54
+ this.flushMs = flushMs;
55
+ this.cache = zeroCache();
56
+ this.loadFromDb();
57
+ }
58
+ loadFromDb() {
59
+ // Graceful: kevin_metrics only exists after migration 003. If a caller
60
+ // instantiates Metrics against a fresh / pre-003 DB, leave the zeros
61
+ // seeded in memory; the eventual flush() will create the rows.
62
+ let rows = [];
63
+ try {
64
+ rows = this.store
65
+ .prepare("SELECT key, value FROM kevin_metrics")
66
+ .all();
67
+ }
68
+ catch {
69
+ rows = [];
70
+ }
71
+ for (const row of rows) {
72
+ if (this.cache.has(row.key)) {
73
+ this.cache.set(row.key, row.value);
74
+ }
75
+ }
76
+ }
77
+ incr(key, by = 1) {
78
+ if (this.closed)
79
+ return;
80
+ const current = this.cache.get(key) ?? 0;
81
+ this.cache.set(key, current + by);
82
+ this.dirty.add(key);
83
+ this.scheduleFlush();
84
+ }
85
+ /**
86
+ * Returns a snapshot of the cache. The returned object always contains all
87
+ * METRIC_KEYS, even if the DB has no rows yet. Does NOT flush.
88
+ */
89
+ snapshot() {
90
+ const out = {};
91
+ for (const k of METRIC_KEYS)
92
+ out[k] = this.cache.get(k) ?? 0;
93
+ return out;
94
+ }
95
+ /**
96
+ * Returns the cached value for a single key. Does NOT flush.
97
+ */
98
+ get(key) {
99
+ return this.cache.get(key) ?? 0;
100
+ }
101
+ /** True iff a debounced flush is scheduled. Useful for tests. */
102
+ isFlushScheduled() {
103
+ return this.flushTimer !== null;
104
+ }
105
+ /**
106
+ * Writes every dirty key to `kevin_metrics` in one transaction. Clears
107
+ * the debounce timer. Safe to call repeatedly; no-op when nothing is
108
+ * dirty or when the object is closed. Missing rows are inserted, present
109
+ * rows are updated. The table is created lazily on first flush so this
110
+ * works against pre-003 DBs too.
111
+ */
112
+ flush() {
113
+ if (this.closed || this.dirty.size === 0) {
114
+ this.clearTimer();
115
+ return;
116
+ }
117
+ this.clearTimer();
118
+ const dirtyKeys = Array.from(this.dirty);
119
+ this.dirty.clear();
120
+ const store = this.store;
121
+ store.transaction(() => {
122
+ store.exec(`CREATE TABLE IF NOT EXISTS kevin_metrics (
123
+ key TEXT PRIMARY KEY,
124
+ value INTEGER NOT NULL DEFAULT 0,
125
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
126
+ )`);
127
+ const upsert = store.prepare(`INSERT INTO kevin_metrics (key, value, updated_at)
128
+ VALUES (?, ?, datetime('now'))
129
+ ON CONFLICT(key) DO UPDATE SET
130
+ value = excluded.value,
131
+ updated_at = datetime('now')`);
132
+ for (const k of dirtyKeys) {
133
+ upsert.run(k, this.cache.get(k) ?? 0);
134
+ }
135
+ });
136
+ }
137
+ close() {
138
+ if (this.closed)
139
+ return;
140
+ this.flush();
141
+ this.closed = true;
142
+ this.clearTimer();
143
+ }
144
+ scheduleFlush() {
145
+ if (this.flushTimer !== null)
146
+ return;
147
+ this.flushTimer = setTimeout(() => {
148
+ this.flushTimer = null;
149
+ this.flush();
150
+ }, this.flushMs);
151
+ // unref so the timer never keeps a Node process alive on its own.
152
+ const t = this.flushTimer;
153
+ t.unref?.();
154
+ }
155
+ clearTimer() {
156
+ if (this.flushTimer !== null) {
157
+ clearTimeout(this.flushTimer);
158
+ this.flushTimer = null;
159
+ }
160
+ }
161
+ }
162
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../plugin/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Store } from "./Store.js";
2
+ export declare function exportOkf(store: Store): string;
3
+ export declare function exportMarkdown(store: Store): string;
@@ -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":"AACA,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,MAAM,OAAO,GAAG,sBAAsB,CAAC;AACvC,MAAM,KAAK,GAAG,iEAAiE,CAAC;AAiBhF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,EAAE,GAAkC,IAAI,CAAC;IAC7C,IAAI,IAAI,GAAa,EAAE,CAAC;IAExB,gEAAgE;IAChE,sDAAsD;IACtD,MAAM,OAAO,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAE3E,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,yBAAyB;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YAC3B,CAAC,EAAE,CAAC;YACJ,SAAS;QACV,CAAC;QACD,mEAAmE;QACnE,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YACpC,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACV,CAAC;QACD,gCAAgC;QAChC,EAAE,GAAG,EAAE,CAAC;QACR,IAAI,GAAG,EAAE,CAAC;QACV,CAAC,EAAE,CAAC;QACJ,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1B,MAAM,GAAG,IAAI,CAAC;gBACd,CAAC,EAAE,CAAC;gBACJ,MAAM;YACP,CAAC;YACD,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,CAAC,EAAE,CAAC;gBACP,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,CAAC;YACD,CAAC,EAAE,CAAC;QACL,CAAC;QACD,IAAI,CAAC,MAAM;YAAE,MAAM;QACnB,IAAI,CAAC,EAAE,CAAC,EAAE;YAAE,SAAS;QAErB,iEAAiE;QACjE,iEAAiE;QACjE,gEAAgE;QAChE,+DAA+D;QAC/D,wBAAwB;QACxB,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1B,0DAA0D;gBAC1D,2DAA2D;gBAC3D,0BAA0B;gBAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;oBAAE,CAAC,EAAE,CAAC;gBACvD,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrE,MAAM;gBACP,CAAC;gBACD,yDAAyD;gBACzD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACf,CAAC,EAAE,CAAC;gBACJ,SAAS;YACV,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,EAAE,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClD,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChD,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,IAAI,IAAI,CAAC;QAClC,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACzE,MAAM,YAAY,GAAG,EAAE,CAAC,gBAAgB,IAAI,IAAI,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC;YACZ,EAAE;YACF,IAAI;YACJ,OAAO;YACP,WAAW,EAAE,EAAE;YACf,cAAc,EAAE,aAAa;YAC7B,gBAAgB,EAAE,YAAY;SAC9B,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/C,iEAAiE;IACjE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAEhE,MAAM,EAAE,GAA2B,EAAE,CAAC;QACtC,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YACxD,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;YACtE,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;YAChE,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;YAC/D,IAAI,QAAQ;gBAAE,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;iBAC7B,IAAI,QAAQ;gBAAE,EAAE,CAAC,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;iBAC3C,IAAI,QAAQ;gBAAE,EAAE,CAAC,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;iBAC9C,IAAI,QAAQ;gBAAE,EAAE,CAAC,gBAAgB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACvD,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBAC3B,0DAA0D;gBAC1D,IAAI,SAAS,GAAG,CAAC;oBAAE,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC;gBACrC,MAAM;YACP,CAAC;QACF,CAAC;QACD,IAAI,SAAS,GAAG,CAAC;YAAE,SAAS,GAAG,CAAC,CAAC;QAEjC,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK;gBAAE,MAAM;YAC/B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;QACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC;YACZ,EAAE;YACF,IAAI;YACJ,OAAO;YACP,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,IAAI;YACnC,cAAc,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC;YAClE,gBAAgB,EAAE,EAAE,CAAC,gBAAgB,IAAI,IAAI;SAC7C,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAOD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACpC,UAAU;IACV,MAAM;IACN,SAAS;IACT,SAAS;CACT,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CACxB,MAAc,EACd,aAA4B;IAE5B,IAAI,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QACpD,MAAM,EAAE,GACP,KAAK,CAAC,WAAW,IAAI,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEnE,MAAM,mBAAmB,GACxB,KAAK,CAAC,cAAc,GAAG,CAAC;YACvB,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,gCAAgC,KAAK,CAAC,cAAc,GACpE,KAAK,CAAC,gBAAgB;gBACrB,CAAC,CAAC,sBAAsB,KAAK,CAAC,gBAAgB,EAAE;gBAChD,CAAC,CAAC,EACJ,GAAG;YACJ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAElB,gEAAgE;QAChE,+DAA+D;QAC/D,gEAAgE;QAChE,2CAA2C;QAC3C,UAAU,IAAI,aAAa,CAAC,wBAAwB,CACnD,KAAK,CAAC,IAA2B,EACjC,EAAE,EACF,IAAI,CACJ,CAAC;QAEF,aAAa,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,KAAK,CAAC,IAAmD;YAC/D,OAAO,EAAE,mBAAmB;YAC5B,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,EAAE;YACf,aAAa,EACZ,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;YAC5D,cAAc,EAAE,KAAK,CAAC,gBAAgB,IAAI,SAAS;SACnD,CAAC,CAAC;QACH,QAAQ,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC"}
@@ -1 +1,2 @@
1
1
  export declare function redactPaths(text: string): string;
2
+ export declare function stripPrivate(text: string): string;
@@ -9,4 +9,11 @@ export function redactPaths(text) {
9
9
  }
10
10
  return out;
11
11
  }
12
+ const PRIVATE_BLOCK_RE = /<private\b[^>]*>([\s\S]*?)<\/private>/gi;
13
+ export function stripPrivate(text) {
14
+ return text.replace(PRIVATE_BLOCK_RE, (_match, inner) => {
15
+ const n = inner.length;
16
+ return `<private: redacted ${n} chars>`;
17
+ });
18
+ }
12
19
  //# sourceMappingURL=redact.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../plugin/redact.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAa;IAC/B,0BAA0B;IAC1B,+KAA+K;CAC/K,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QACjC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../plugin/redact.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAa;IAC/B,0BAA0B;IAC1B,+KAA+K;CAC/K,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QACjC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,MAAM,gBAAgB,GAAG,yCAAyC,CAAC;AAEnE,MAAM,UAAU,YAAY,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,KAAa,EAAE,EAAE;QAC/D,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACvB,OAAO,sBAAsB,CAAC,SAAS,CAAC;IACzC,CAAC,CAAC,CAAC;AACJ,CAAC"}