@jmtrin/opencode-kevin 0.5.0 → 0.7.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 (90) hide show
  1. package/README.md +268 -122
  2. package/dist/migrations/001_initial.sql +91 -91
  3. package/dist/migrations/003_v02_signal.sql +57 -57
  4. package/dist/migrations/004_v03_knowledge.sql +138 -138
  5. package/dist/migrations/005_v04_signal.sql +57 -57
  6. package/dist/migrations/006_v05_glassbox.sql +118 -118
  7. package/dist/migrations/007_v06_pull.sql +145 -0
  8. package/dist/migrations/008_v07_truth.sql +124 -0
  9. package/dist/plugin/Archiver.js +4 -3
  10. package/dist/plugin/Archiver.js.map +1 -1
  11. package/dist/plugin/ArtifactWriter.d.ts +50 -0
  12. package/dist/plugin/ArtifactWriter.js +240 -0
  13. package/dist/plugin/ArtifactWriter.js.map +1 -0
  14. package/dist/plugin/ConflictDetector.d.ts +35 -0
  15. package/dist/plugin/ConflictDetector.js +283 -0
  16. package/dist/plugin/ConflictDetector.js.map +1 -0
  17. package/dist/plugin/ContextInjector.d.ts +15 -0
  18. package/dist/plugin/ContextInjector.js +46 -11
  19. package/dist/plugin/ContextInjector.js.map +1 -1
  20. package/dist/plugin/ConventionMiner.d.ts +35 -0
  21. package/dist/plugin/ConventionMiner.js +243 -0
  22. package/dist/plugin/ConventionMiner.js.map +1 -0
  23. package/dist/plugin/Curator.d.ts +96 -0
  24. package/dist/plugin/Curator.js +283 -0
  25. package/dist/plugin/Curator.js.map +1 -0
  26. package/dist/plugin/Feedback.js +4 -3
  27. package/dist/plugin/Feedback.js.map +1 -1
  28. package/dist/plugin/Materializer.d.ts +59 -0
  29. package/dist/plugin/Materializer.js +237 -0
  30. package/dist/plugin/Materializer.js.map +1 -0
  31. package/dist/plugin/MemoryService.d.ts +37 -0
  32. package/dist/plugin/MemoryService.js +241 -20
  33. package/dist/plugin/MemoryService.js.map +1 -1
  34. package/dist/plugin/Migrate.js +51 -2
  35. package/dist/plugin/Migrate.js.map +1 -1
  36. package/dist/plugin/QualityGate.d.ts +15 -1
  37. package/dist/plugin/QualityGate.js +12 -0
  38. package/dist/plugin/QualityGate.js.map +1 -1
  39. package/dist/plugin/Reflector.js +13 -0
  40. package/dist/plugin/Reflector.js.map +1 -1
  41. package/dist/plugin/RepoTruth.d.ts +80 -0
  42. package/dist/plugin/RepoTruth.js +600 -0
  43. package/dist/plugin/RepoTruth.js.map +1 -0
  44. package/dist/plugin/Retrospective.d.ts +1 -0
  45. package/dist/plugin/Retrospective.js +20 -1
  46. package/dist/plugin/Retrospective.js.map +1 -1
  47. package/dist/plugin/capabilities.d.ts +15 -0
  48. package/dist/plugin/capabilities.js +42 -0
  49. package/dist/plugin/capabilities.js.map +1 -0
  50. package/dist/plugin/diff.d.ts +8 -0
  51. package/dist/plugin/diff.js +183 -0
  52. package/dist/plugin/diff.js.map +1 -0
  53. package/dist/plugin/index.d.ts +8 -1
  54. package/dist/plugin/index.js +354 -2
  55. package/dist/plugin/index.js.map +1 -1
  56. package/dist/plugin/inferability.d.ts +32 -0
  57. package/dist/plugin/inferability.js +89 -0
  58. package/dist/plugin/inferability.js.map +1 -0
  59. package/dist/plugin/kevin_approve.d.ts +34 -0
  60. package/dist/plugin/kevin_approve.js +50 -0
  61. package/dist/plugin/kevin_approve.js.map +1 -0
  62. package/dist/plugin/kevin_audit.d.ts +87 -1
  63. package/dist/plugin/kevin_audit.js +190 -3
  64. package/dist/plugin/kevin_audit.js.map +1 -1
  65. package/dist/plugin/kevin_conflicts.d.ts +9 -0
  66. package/dist/plugin/kevin_conflicts.js +51 -0
  67. package/dist/plugin/kevin_conflicts.js.map +1 -0
  68. package/dist/plugin/kevin_facts.d.ts +42 -0
  69. package/dist/plugin/kevin_facts.js +37 -0
  70. package/dist/plugin/kevin_facts.js.map +1 -0
  71. package/dist/plugin/kevin_propose.d.ts +23 -0
  72. package/dist/plugin/kevin_propose.js +15 -0
  73. package/dist/plugin/kevin_propose.js.map +1 -0
  74. package/dist/plugin/kevin_publish.d.ts +38 -0
  75. package/dist/plugin/kevin_publish.js +19 -0
  76. package/dist/plugin/kevin_publish.js.map +1 -0
  77. package/dist/plugin/metrics.d.ts +12 -1
  78. package/dist/plugin/metrics.js +49 -0
  79. package/dist/plugin/metrics.js.map +1 -1
  80. package/dist/plugin/replay-types.d.ts +8 -8
  81. package/dist/plugin/replay.js +10 -0
  82. package/dist/plugin/replay.js.map +1 -1
  83. package/migrations/001_initial.sql +91 -91
  84. package/migrations/003_v02_signal.sql +57 -57
  85. package/migrations/004_v03_knowledge.sql +138 -138
  86. package/migrations/005_v04_signal.sql +57 -57
  87. package/migrations/006_v05_glassbox.sql +118 -118
  88. package/migrations/007_v06_pull.sql +145 -0
  89. package/migrations/008_v07_truth.sql +124 -0
  90. package/package.json +3 -2
@@ -0,0 +1,283 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import { MARKER_BEGIN, MARKER_END, } from "./ArtifactWriter.js";
4
+ import { computeConfidence } from "./confidence.js";
5
+ import { normalize } from "./fingerprint.js";
6
+ import { uuidv7 } from "./uuid.js";
7
+ const MAX_CANDIDATE_LINES = 20;
8
+ const MAX_CANDIDATE_CHARS = 4000;
9
+ const CONFIDENCE_FLOOR = 0.6;
10
+ const MAX_SENTENCE_CHARS = 160;
11
+ export function firstSentence(content) {
12
+ const match = content.match(/^[\s\S]*?(?=[.!?](?:\s|$)|\r?\n|$)/);
13
+ const sentence = (match ? match[0] : content).trim();
14
+ return sentence.slice(0, MAX_SENTENCE_CHARS);
15
+ }
16
+ function evidenceString(row) {
17
+ const parts = [];
18
+ if (row.evidence_count >= 2) {
19
+ const last = row.last_verified_at
20
+ ? `, last ${row.last_verified_at.slice(0, 10)}`
21
+ : "";
22
+ parts.push(`verified ${row.evidence_count}×${last}`);
23
+ }
24
+ if (row.feedback_positive >= 1) {
25
+ parts.push(`feedback ${row.feedback_positive}×`);
26
+ }
27
+ return parts.join(", ");
28
+ }
29
+ export class Curator {
30
+ store;
31
+ memoryService;
32
+ projectId;
33
+ metrics;
34
+ constructor(store, memoryService, projectId, metrics) {
35
+ this.store = store;
36
+ this.memoryService = memoryService;
37
+ this.projectId = projectId;
38
+ this.metrics = metrics ?? null;
39
+ }
40
+ /**
41
+ * Plan §5.4 selection predicate — all clauses must hold, evaluated
42
+ * verbatim. The confidence floor cannot be expressed in SQL (it is the
43
+ * two-sided formula of `computeConfidence`), so the cheap clauses run
44
+ * in SQL and confidence is computed and filtered per row in JS.
45
+ *
46
+ * The floor is `confidence >= 0.6` where the feedback arm of D6-09 also
47
+ * clears it: `computeConfidence` credits one positive human verdict at
48
+ * 0.05 (K5-010), so a row with `feedback_positive = 1` and no causal
49
+ * evidence scores 0.55 — yet D6-09's warrant is "either the world
50
+ * verified it twice, or a human verified it once". The disjunction
51
+ * (K6-012 acceptance) is the floor's complement for the feedback arm.
52
+ *
53
+ * Ordered by `confidence DESC, updated_at DESC`, capped at 20 lines and
54
+ * 4000 characters of content, whichever binds first. The char budget
55
+ * counts the raw content length: rendered lines are truncated to 160
56
+ * chars, so a rendered-line budget could never bind before the line cap.
57
+ */
58
+ candidates(limit) {
59
+ const rows = this.store
60
+ .prepare(`SELECT id, content, evidence_count, recurrence_count,
61
+ feedback_positive, feedback_negative,
62
+ last_verified_at, updated_at
63
+ FROM memories
64
+ WHERE status = 'active'
65
+ AND ignored = 0
66
+ AND curated = 0
67
+ AND (inferable IS NULL OR inferable != 1)
68
+ AND (evidence_count >= 2 OR feedback_positive >= 1)`)
69
+ .all();
70
+ const scored = rows
71
+ .map((row) => ({
72
+ row,
73
+ confidence: computeConfidence(row.evidence_count ?? 0, row.recurrence_count ?? 0, row.feedback_positive ?? 0, row.feedback_negative ?? 0),
74
+ }))
75
+ .filter((s) => s.confidence >= CONFIDENCE_FLOOR || s.row.feedback_positive >= 1)
76
+ .sort((a, b) => b.confidence - a.confidence ||
77
+ b.row.updated_at.localeCompare(a.row.updated_at));
78
+ const maxLines = limit ?? MAX_CANDIDATE_LINES;
79
+ const result = [];
80
+ let totalChars = 0;
81
+ for (const s of scored) {
82
+ if (result.length >= maxLines)
83
+ break;
84
+ if (totalChars + s.row.content.length > MAX_CANDIDATE_CHARS)
85
+ break;
86
+ const evidence = evidenceString(s.row);
87
+ result.push({
88
+ memoryId: s.row.id,
89
+ line: `- ${firstSentence(s.row.content)} (${evidence})`,
90
+ confidence: s.confidence,
91
+ evidence,
92
+ });
93
+ totalChars += s.row.content.length;
94
+ }
95
+ return result;
96
+ }
97
+ /**
98
+ * Renders the block sorted by memory id (D6-10): confidence orders
99
+ * selection, id orders output. Adding one candidate to a set of ten
100
+ * must change exactly one line of the rendered block.
101
+ */
102
+ renderBlock(candidates) {
103
+ const sorted = [...candidates].sort((a, b) => a.memoryId.localeCompare(b.memoryId));
104
+ return `${sorted.map((c) => c.line).join("\n")}\n`;
105
+ }
106
+ /**
107
+ * Plan §5.4 — strict dry run (D5-08): plan only, never write. Returns a
108
+ * pending proposal per call, or [] when no candidate clears the floor.
109
+ *
110
+ * The proposal is a whole-block proposal: the persisted `proposed_text`
111
+ * is the merged block (current block in the file + new candidate lines),
112
+ * so approving it replaces the file block with exactly what was reviewed.
113
+ * The current block is learned from `plan().before` — the Curator has no
114
+ * fs capability, the writer reads (D6-01). Both plan calls are
115
+ * deterministic, so a second propose() with unchanged inputs reproduces
116
+ * the persisted diff byte-identically.
117
+ *
118
+ * A new proposal supersedes prior pending (or rejected) rows for the
119
+ * same (project_id, kind, target_path) triple — §5.5's regeneration
120
+ * arrow. Rows are never deleted (the audit trail is append-only).
121
+ *
122
+ * The schema's `memory_id` column is singular while a whole-block
123
+ * proposal carries several ids; the contributing ids are stored joined
124
+ * by "," (uuidv7 ids contain no comma) and split on read.
125
+ */
126
+ propose(kind, writer) {
127
+ const targetPath = this.targetPathFor(kind);
128
+ const candidates = this.candidates();
129
+ if (candidates.length === 0)
130
+ return [];
131
+ const readPlan = writer.plan(targetPath, this.renderBlock(candidates));
132
+ const currentBlock = extractBlock(readPlan.before);
133
+ // v0.7.0 (K7-013 / plan §4, D6-09) — de-duplicate against the WHOLE
134
+ // file, not just the region between Kevin's markers. A convention the
135
+ // user already wrote in their own words in their own section must not
136
+ // be proposed back to them. The comparison is over the same normalized
137
+ // tokens the fingerprint uses — no new similarity metric (D7-11).
138
+ const entireFile = wholeFileLines(readPlan.before);
139
+ const freshCandidates = candidates.filter((candidate) => !entireFile.has(normalizeBullet(candidate.line)));
140
+ if (freshCandidates.length === 0 && currentBlock === "")
141
+ return [];
142
+ const newBlock = this.renderBlock(freshCandidates);
143
+ const newLines = newBlock.split("\n").filter((l) => l !== "");
144
+ const mergedBlock = newLines.length === 0
145
+ ? currentBlock
146
+ : currentBlock === ""
147
+ ? `${newLines.join("\n")}\n`
148
+ : `${currentBlock}${currentBlock.endsWith("\n") ? "" : "\n"}${newLines.join("\n")}\n`;
149
+ // v0.7.0 (K7-013) — nothing new to propose: every candidate is already
150
+ // in the file (inside or outside the markers). A vacuous proposal would
151
+ // be noise; return none.
152
+ const plan = writer.plan(targetPath, mergedBlock);
153
+ const prior = this.store
154
+ .prepare(`SELECT id FROM curation_proposals
155
+ WHERE project_id = ? AND kind = ? AND target_path = ?
156
+ AND status IN ('pending', 'rejected')`)
157
+ .all(this.projectId, kind, targetPath);
158
+ for (const row of prior) {
159
+ this.transition(row.id, "supersede");
160
+ }
161
+ const memoryIds = freshCandidates.map((c) => c.memoryId);
162
+ const id = uuidv7();
163
+ this.store
164
+ .prepare(`INSERT INTO curation_proposals
165
+ (id, project_id, memory_id, kind, target_path,
166
+ proposed_text, diff, status)
167
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')`)
168
+ .run(id, this.projectId, memoryIds.join(","), kind, targetPath, mergedBlock, plan.diff);
169
+ this.metrics?.incr("proposals_created", 1);
170
+ const row = this.store
171
+ .prepare("SELECT created_at FROM curation_proposals WHERE id = ?")
172
+ .get(id);
173
+ return [
174
+ {
175
+ id,
176
+ kind,
177
+ targetPath,
178
+ memoryIds,
179
+ proposedText: mergedBlock,
180
+ diff: plan.diff,
181
+ status: "pending",
182
+ createdAt: row.created_at,
183
+ },
184
+ ];
185
+ }
186
+ /**
187
+ * Plan §5.5 state machine, as explicit transitions with an exhaustive
188
+ * switch — an unknown transition or an illegal source state throws
189
+ * rather than silently no-oping. `decided_at` stamps approve/reject/
190
+ * supersede, `applied_at` stamps apply.
191
+ */
192
+ transition(proposalId, transition) {
193
+ const row = this.store
194
+ .prepare("SELECT status FROM curation_proposals WHERE id = ?")
195
+ .get(proposalId);
196
+ if (!row) {
197
+ throw new Error(`proposal not found: ${proposalId}`);
198
+ }
199
+ const status = row.status;
200
+ let next = null;
201
+ switch (transition) {
202
+ case "approve":
203
+ if (status === "pending")
204
+ next = "approved";
205
+ break;
206
+ case "reject":
207
+ if (status === "pending")
208
+ next = "rejected";
209
+ break;
210
+ case "apply":
211
+ if (status === "approved")
212
+ next = "applied";
213
+ break;
214
+ case "supersede":
215
+ if (status === "pending" || status === "rejected") {
216
+ next = "superseded";
217
+ }
218
+ break;
219
+ default:
220
+ throw new Error(`unknown transition: ${transition}`);
221
+ }
222
+ if (next === null) {
223
+ throw new Error(`illegal transition: ${status} -> ${transition}`);
224
+ }
225
+ if (next === "applied") {
226
+ this.store
227
+ .prepare("UPDATE curation_proposals SET status = 'applied', applied_at = datetime('now') WHERE id = ?")
228
+ .run(proposalId);
229
+ }
230
+ else {
231
+ this.store
232
+ .prepare("UPDATE curation_proposals SET status = ?, decided_at = datetime('now') WHERE id = ?")
233
+ .run(next, proposalId);
234
+ }
235
+ return next;
236
+ }
237
+ /** Plan §5.6 target paths. agents_md is a setting; skill/reference live under ~/.opencode-kevin. */
238
+ targetPathFor(kind) {
239
+ switch (kind) {
240
+ case "agents_md":
241
+ return this.memoryService.getSetting("agents_md_path", "AGENTS.md");
242
+ case "skill":
243
+ return join(homedir(), ".opencode-kevin", "skills", "project-knowledge.md");
244
+ case "reference":
245
+ return join(homedir(), ".opencode-kevin", "refs", "project-knowledge.md");
246
+ }
247
+ }
248
+ }
249
+ /** The block content currently between the markers, "" when absent or malformed. */
250
+ function extractBlock(before) {
251
+ const begin = before.indexOf(MARKER_BEGIN);
252
+ const end = before.indexOf(MARKER_END);
253
+ if (begin === -1 || end === -1 || end < begin)
254
+ return "";
255
+ return before
256
+ .slice(begin + MARKER_BEGIN.length, end)
257
+ .replace(/^\r?\n/, "")
258
+ .replace(/\r?\n$/, "");
259
+ }
260
+ /**
261
+ * v0.7.0 (K7-013 / plan §4) — the normalized set of bullet statements across
262
+ * the WHOLE file, including any the user wrote outside Kevin's markers. Only
263
+ * markdown bullets (`- ...`) are considered: prose and the marker lines are
264
+ * never a candidate to propose back.
265
+ */
266
+ function wholeFileLines(before) {
267
+ const set = new Set();
268
+ for (const line of before.split(/\r?\n/)) {
269
+ if (line.trim().startsWith("-")) {
270
+ set.add(normalizeBullet(line));
271
+ }
272
+ }
273
+ return set;
274
+ }
275
+ /** Normalize a rendered bullet for de-duplication — strip the marker prefix. */
276
+ function normalizeBullet(line) {
277
+ const statement = line
278
+ .replace(/^\s*-\s+/, "")
279
+ .trim()
280
+ .replace(/\s+\((?:verified|feedback)[^)]*\)\s*$/i, "");
281
+ return normalize(statement);
282
+ }
283
+ //# sourceMappingURL=Curator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Curator.js","sourceRoot":"","sources":["../../plugin/Curator.ts"],"names":[],"mappings":"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"}
@@ -8,18 +8,19 @@ const NEGATIVE_VERDICTS = [
8
8
  // v0.5.0 — pre-006 DBs lack `memory_feedback`; record() fails loudly with a
9
9
  // descriptive error instead of a bare "no such table" (the tool layer turns
10
10
  // it into a graceful message).
11
+ // v0.6.0 (K6-001a) — positive-only caching: a successful probe is cached,
12
+ // a failed probe is NOT. A Store migrated in place heals on the next call.
11
13
  const feedbackTableCache = new WeakMap();
12
14
  function hasFeedbackTable(store) {
13
15
  const cached = feedbackTableCache.get(store);
14
- if (cached !== undefined)
15
- return cached;
16
+ if (cached === true)
17
+ return true;
16
18
  try {
17
19
  store.prepare("SELECT COUNT(*) FROM memory_feedback").get();
18
20
  feedbackTableCache.set(store, true);
19
21
  return true;
20
22
  }
21
23
  catch {
22
- feedbackTableCache.set(store, false);
23
24
  return false;
24
25
  }
25
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Feedback.js","sourceRoot":"","sources":["../../plugin/Feedback.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Feedback.js","sourceRoot":"","sources":["../../plugin/Feedback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { ArtifactWriter, WriteOutcome } from "./ArtifactWriter.js";
2
+ import type { Store } from "./Store.js";
3
+ /**
4
+ * K6-017 — v0.6.0 pull — topic bundles for the pull channels (plan §5.6).
5
+ *
6
+ * Writes `~/.opencode-kevin/refs/<topic>.md` (one file per topic) and
7
+ * `~/.opencode-kevin/skills/project-knowledge.md` (one file). Both go
8
+ * through the `ArtifactWriter` — marker-scoped, atomic, hash-audited.
9
+ * There is no direct raw file-write anywhere in this module (D6-01).
10
+ *
11
+ * Topic derivation is deterministic and semantic (D6-14): a topic is
12
+ * `<type>-<dominant token>`, where the dominant token is the
13
+ * highest-frequency non-stop-word token of the fingerprint-normalized
14
+ * content across the memories in the group, ties broken lexicographically.
15
+ * Topics are NEVER derived from a fingerprint prefix, and hash-like tokens
16
+ * (hex-only, length >= 8) are excluded from the race entirely.
17
+ *
18
+ * Output ordering within each bundle is by memory id, matching §5.4.
19
+ * Regeneration with unchanged inputs is a `noop` at the ArtifactWriter
20
+ * level, so the "run twice, compare bytes" criterion holds for every
21
+ * bundle.
22
+ */
23
+ export interface MaterializedBundle {
24
+ readonly topic: string;
25
+ readonly path: string;
26
+ readonly outcome: WriteOutcome;
27
+ }
28
+ export interface BundleTarget {
29
+ readonly topic: string;
30
+ readonly path: string;
31
+ }
32
+ export declare const SKILL_TOPIC = "project-knowledge";
33
+ export declare class Materializer {
34
+ private readonly store;
35
+ /** `root` is injectable for tests; production defaults to ~/.opencode-kevin. */
36
+ private readonly root;
37
+ constructor(store: Store, options?: {
38
+ root?: string;
39
+ });
40
+ /** The curated, active memories — the knowledge the pull channels publish. */
41
+ private curatedRows;
42
+ /** The rendered skill body over all curated memories; "" when empty. */
43
+ skillBody(): string;
44
+ /** Group rows by type, deriving each type's topic from its own content. */
45
+ private groupByTopic;
46
+ /**
47
+ * The pull-channel targets: the skill file plus one ref file per topic.
48
+ * The order is deterministic (skill first, refs by topic).
49
+ */
50
+ bundleTargets(): BundleTarget[];
51
+ /**
52
+ * Regenerate every bundle through the ArtifactWriter (plan + apply).
53
+ * The only call site of `apply()` outside `kevin_approve` — D6-01's
54
+ * single write FUNCTION with two constrained targets: `kevin_approve`
55
+ * reaches `agents_md_path`, this module reaches `~/.opencode-kevin`
56
+ * only (D6-07; enforced by K6-020).
57
+ */
58
+ materialize(writer: ArtifactWriter): MaterializedBundle[];
59
+ }
@@ -0,0 +1,237 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import { firstSentence } from "./Curator.js";
4
+ import { normalize } from "./fingerprint.js";
5
+ export const SKILL_TOPIC = "project-knowledge";
6
+ /** Hash-like noise: FNV-1a output is 16 lowercase hex chars; an 8+ hex
7
+ * token is indistinguishable from a fingerprint prefix and must never
8
+ * become a topic (D6-14). */
9
+ const HEX_LIKE_RE = /^[0-9a-f]{8,}$/;
10
+ const TOKEN_RE = /[^a-z0-9]+/;
11
+ /** Conservative English function words; code-adjacent meaning-bearing
12
+ * words (npm, ts2304, cargo...) are deliberately NOT stop-words. */
13
+ const STOP_WORDS = new Set([
14
+ "a",
15
+ "about",
16
+ "after",
17
+ "again",
18
+ "all",
19
+ "also",
20
+ "an",
21
+ "and",
22
+ "any",
23
+ "are",
24
+ "as",
25
+ "at",
26
+ "be",
27
+ "been",
28
+ "before",
29
+ "being",
30
+ "but",
31
+ "by",
32
+ "can",
33
+ "could",
34
+ "did",
35
+ "do",
36
+ "does",
37
+ "for",
38
+ "from",
39
+ "had",
40
+ "has",
41
+ "have",
42
+ "he",
43
+ "her",
44
+ "his",
45
+ "if",
46
+ "in",
47
+ "into",
48
+ "is",
49
+ "it",
50
+ "its",
51
+ "may",
52
+ "might",
53
+ "more",
54
+ "most",
55
+ "must",
56
+ "not",
57
+ "of",
58
+ "on",
59
+ "one",
60
+ "or",
61
+ "our",
62
+ "per",
63
+ "shall",
64
+ "she",
65
+ "so",
66
+ "than",
67
+ "that",
68
+ "the",
69
+ "their",
70
+ "them",
71
+ "then",
72
+ "there",
73
+ "these",
74
+ "they",
75
+ "this",
76
+ "those",
77
+ "through",
78
+ "to",
79
+ "too",
80
+ "under",
81
+ "up",
82
+ "us",
83
+ "via",
84
+ "was",
85
+ "we",
86
+ "were",
87
+ "what",
88
+ "when",
89
+ "where",
90
+ "which",
91
+ "while",
92
+ "who",
93
+ "will",
94
+ "with",
95
+ "would",
96
+ "you",
97
+ "your",
98
+ ]);
99
+ /** Sanitize a memory type into a filesystem-safe topic prefix. */
100
+ function sanitizeType(type) {
101
+ const cleaned = type
102
+ .toLowerCase()
103
+ .replace(/[^a-z0-9]+/g, "-")
104
+ .replace(/-+/g, "-")
105
+ .replace(/^-|-$/g, "");
106
+ return cleaned === "" ? "memory" : cleaned;
107
+ }
108
+ function tokensOf(content) {
109
+ return normalize(content)
110
+ .split(TOKEN_RE)
111
+ .filter((t) => t !== "" && !STOP_WORDS.has(t) && !HEX_LIKE_RE.test(t));
112
+ }
113
+ /** Highest-frequency non-stop-word token, ties broken lexicographically
114
+ * (smallest wins) so the result is stable. "" when every token is a
115
+ * stop-word or hash-like noise. */
116
+ function dominantToken(rows) {
117
+ const counts = new Map();
118
+ for (const row of rows) {
119
+ for (const token of tokensOf(row.content)) {
120
+ counts.set(token, (counts.get(token) ?? 0) + 1);
121
+ }
122
+ }
123
+ let best = "";
124
+ let bestCount = 0;
125
+ for (const [token, count] of counts) {
126
+ if (count > bestCount || (count === bestCount && token < best)) {
127
+ best = token;
128
+ bestCount = count;
129
+ }
130
+ }
131
+ return best;
132
+ }
133
+ function renderRows(rows) {
134
+ const sorted = [...rows].sort((a, b) => a.id.localeCompare(b.id));
135
+ const lines = sorted
136
+ .map((row) => `- ${firstSentence(row.content)}`)
137
+ .filter((line) => line !== "- ");
138
+ return lines.length === 0 ? "" : `${lines.join("\n")}\n`;
139
+ }
140
+ export class Materializer {
141
+ store;
142
+ /** `root` is injectable for tests; production defaults to ~/.opencode-kevin. */
143
+ root;
144
+ constructor(store, options = {}) {
145
+ this.store = store;
146
+ this.root = options.root ?? join(homedir(), ".opencode-kevin");
147
+ }
148
+ /** The curated, active memories — the knowledge the pull channels publish. */
149
+ curatedRows() {
150
+ return this.store
151
+ .prepare(`SELECT id, type, content FROM memories
152
+ WHERE status = 'active' AND curated = 1`)
153
+ .all();
154
+ }
155
+ /** The rendered skill body over all curated memories; "" when empty. */
156
+ skillBody() {
157
+ return renderRows(this.curatedRows());
158
+ }
159
+ /** Group rows by type, deriving each type's topic from its own content. */
160
+ groupByTopic(rows) {
161
+ const byType = new Map();
162
+ for (const row of rows) {
163
+ const list = byType.get(row.type) ?? [];
164
+ list.push(row);
165
+ byType.set(row.type, list);
166
+ }
167
+ const groups = [];
168
+ for (const [type, typeRows] of byType) {
169
+ const token = dominantToken(typeRows);
170
+ if (token === "")
171
+ continue;
172
+ groups.push({
173
+ topic: `${sanitizeType(type)}-${token}`,
174
+ rows: typeRows,
175
+ });
176
+ }
177
+ return groups.sort((a, b) => a.topic.localeCompare(b.topic));
178
+ }
179
+ /**
180
+ * The pull-channel targets: the skill file plus one ref file per topic.
181
+ * The order is deterministic (skill first, refs by topic).
182
+ */
183
+ bundleTargets() {
184
+ const rows = this.curatedRows();
185
+ const targets = [];
186
+ if (rows.length > 0 && renderRows(rows) !== "") {
187
+ targets.push({
188
+ topic: SKILL_TOPIC,
189
+ path: join(this.root, "skills", "project-knowledge.md"),
190
+ });
191
+ }
192
+ for (const group of this.groupByTopic(rows)) {
193
+ if (renderRows(group.rows) === "")
194
+ continue;
195
+ targets.push({
196
+ topic: group.topic,
197
+ path: join(this.root, "refs", `${group.topic}.md`),
198
+ });
199
+ }
200
+ return targets;
201
+ }
202
+ /**
203
+ * Regenerate every bundle through the ArtifactWriter (plan + apply).
204
+ * The only call site of `apply()` outside `kevin_approve` — D6-01's
205
+ * single write FUNCTION with two constrained targets: `kevin_approve`
206
+ * reaches `agents_md_path`, this module reaches `~/.opencode-kevin`
207
+ * only (D6-07; enforced by K6-020).
208
+ */
209
+ materialize(writer) {
210
+ const pending = [];
211
+ const rows = this.curatedRows();
212
+ const skillBody = renderRows(rows);
213
+ if (skillBody !== "") {
214
+ pending.push({
215
+ topic: SKILL_TOPIC,
216
+ path: join(this.root, "skills", "project-knowledge.md"),
217
+ body: skillBody,
218
+ });
219
+ }
220
+ for (const group of this.groupByTopic(rows)) {
221
+ const body = renderRows(group.rows);
222
+ if (body === "")
223
+ continue;
224
+ pending.push({
225
+ topic: group.topic,
226
+ path: join(this.root, "refs", `${group.topic}.md`),
227
+ body,
228
+ });
229
+ }
230
+ return pending.map((bundle) => ({
231
+ topic: bundle.topic,
232
+ path: bundle.path,
233
+ outcome: writer.apply(writer.plan(bundle.path, bundle.body)),
234
+ }));
235
+ }
236
+ }
237
+ //# sourceMappingURL=Materializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Materializer.js","sourceRoot":"","sources":["../../plugin/Materializer.ts"],"names":[],"mappings":"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"}