@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.
- package/README.md +108 -33
- package/dist/migrations/003_v02_signal.sql +58 -0
- 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 +25 -1
- package/dist/plugin/ContextInjector.js +72 -15
- package/dist/plugin/ContextInjector.js.map +1 -1
- package/dist/plugin/MemoryService.d.ts +110 -3
- package/dist/plugin/MemoryService.js +432 -20
- package/dist/plugin/MemoryService.js.map +1 -1
- package/dist/plugin/Migrate.d.ts +4 -1
- package/dist/plugin/Migrate.js +40 -1
- package/dist/plugin/Migrate.js.map +1 -1
- package/dist/plugin/PatternMiner.d.ts +49 -0
- package/dist/plugin/PatternMiner.js +133 -0
- package/dist/plugin/PatternMiner.js.map +1 -0
- package/dist/plugin/Reflector.d.ts +45 -2
- package/dist/plugin/Reflector.js +134 -12
- package/dist/plugin/Reflector.js.map +1 -1
- package/dist/plugin/Retrospective.d.ts +4 -1
- package/dist/plugin/Retrospective.js +72 -5
- package/dist/plugin/Retrospective.js.map +1 -1
- package/dist/plugin/Store.d.ts +15 -0
- package/dist/plugin/Store.js +15 -0
- package/dist/plugin/Store.js.map +1 -1
- package/dist/plugin/ToolCallObserver.d.ts +4 -1
- package/dist/plugin/ToolCallObserver.js +39 -7
- package/dist/plugin/ToolCallObserver.js.map +1 -1
- package/dist/plugin/fingerprint.d.ts +27 -0
- package/dist/plugin/fingerprint.js +74 -0
- package/dist/plugin/fingerprint.js.map +1 -0
- package/dist/plugin/index.js +213 -15
- 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/memory-format.d.ts +2 -0
- package/dist/plugin/memory-format.js +6 -3
- package/dist/plugin/memory-format.js.map +1 -1
- package/dist/plugin/metrics.d.ts +60 -0
- package/dist/plugin/metrics.js +162 -0
- package/dist/plugin/metrics.js.map +1 -0
- 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/dist/plugin/redact.d.ts +1 -0
- package/dist/plugin/redact.js +7 -0
- package/dist/plugin/redact.js.map +1 -1
- package/migrations/003_v02_signal.sql +58 -0
- package/migrations/004_v03_knowledge.sql +138 -0
- 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,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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"}
|
package/dist/plugin/redact.d.ts
CHANGED
package/dist/plugin/redact.js
CHANGED
|
@@ -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"}
|