@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.
- package/README.md +268 -122
- package/dist/migrations/001_initial.sql +91 -91
- package/dist/migrations/003_v02_signal.sql +57 -57
- package/dist/migrations/004_v03_knowledge.sql +138 -138
- package/dist/migrations/005_v04_signal.sql +57 -57
- package/dist/migrations/006_v05_glassbox.sql +118 -118
- package/dist/migrations/007_v06_pull.sql +145 -0
- package/dist/migrations/008_v07_truth.sql +124 -0
- package/dist/plugin/Archiver.js +4 -3
- package/dist/plugin/Archiver.js.map +1 -1
- package/dist/plugin/ArtifactWriter.d.ts +50 -0
- package/dist/plugin/ArtifactWriter.js +240 -0
- package/dist/plugin/ArtifactWriter.js.map +1 -0
- package/dist/plugin/ConflictDetector.d.ts +35 -0
- package/dist/plugin/ConflictDetector.js +283 -0
- package/dist/plugin/ConflictDetector.js.map +1 -0
- package/dist/plugin/ContextInjector.d.ts +15 -0
- package/dist/plugin/ContextInjector.js +46 -11
- package/dist/plugin/ContextInjector.js.map +1 -1
- package/dist/plugin/ConventionMiner.d.ts +35 -0
- package/dist/plugin/ConventionMiner.js +243 -0
- package/dist/plugin/ConventionMiner.js.map +1 -0
- package/dist/plugin/Curator.d.ts +96 -0
- package/dist/plugin/Curator.js +283 -0
- package/dist/plugin/Curator.js.map +1 -0
- package/dist/plugin/Feedback.js +4 -3
- package/dist/plugin/Feedback.js.map +1 -1
- package/dist/plugin/Materializer.d.ts +59 -0
- package/dist/plugin/Materializer.js +237 -0
- package/dist/plugin/Materializer.js.map +1 -0
- package/dist/plugin/MemoryService.d.ts +37 -0
- package/dist/plugin/MemoryService.js +241 -20
- package/dist/plugin/MemoryService.js.map +1 -1
- package/dist/plugin/Migrate.js +51 -2
- package/dist/plugin/Migrate.js.map +1 -1
- package/dist/plugin/QualityGate.d.ts +15 -1
- package/dist/plugin/QualityGate.js +12 -0
- package/dist/plugin/QualityGate.js.map +1 -1
- package/dist/plugin/Reflector.js +13 -0
- package/dist/plugin/Reflector.js.map +1 -1
- package/dist/plugin/RepoTruth.d.ts +80 -0
- package/dist/plugin/RepoTruth.js +600 -0
- package/dist/plugin/RepoTruth.js.map +1 -0
- package/dist/plugin/Retrospective.d.ts +1 -0
- package/dist/plugin/Retrospective.js +20 -1
- package/dist/plugin/Retrospective.js.map +1 -1
- package/dist/plugin/capabilities.d.ts +15 -0
- package/dist/plugin/capabilities.js +42 -0
- package/dist/plugin/capabilities.js.map +1 -0
- package/dist/plugin/diff.d.ts +8 -0
- package/dist/plugin/diff.js +183 -0
- package/dist/plugin/diff.js.map +1 -0
- package/dist/plugin/index.d.ts +8 -1
- package/dist/plugin/index.js +354 -2
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/inferability.d.ts +32 -0
- package/dist/plugin/inferability.js +89 -0
- package/dist/plugin/inferability.js.map +1 -0
- package/dist/plugin/kevin_approve.d.ts +34 -0
- package/dist/plugin/kevin_approve.js +50 -0
- package/dist/plugin/kevin_approve.js.map +1 -0
- package/dist/plugin/kevin_audit.d.ts +87 -1
- package/dist/plugin/kevin_audit.js +190 -3
- package/dist/plugin/kevin_audit.js.map +1 -1
- package/dist/plugin/kevin_conflicts.d.ts +9 -0
- package/dist/plugin/kevin_conflicts.js +51 -0
- package/dist/plugin/kevin_conflicts.js.map +1 -0
- package/dist/plugin/kevin_facts.d.ts +42 -0
- package/dist/plugin/kevin_facts.js +37 -0
- package/dist/plugin/kevin_facts.js.map +1 -0
- package/dist/plugin/kevin_propose.d.ts +23 -0
- package/dist/plugin/kevin_propose.js +15 -0
- package/dist/plugin/kevin_propose.js.map +1 -0
- package/dist/plugin/kevin_publish.d.ts +38 -0
- package/dist/plugin/kevin_publish.js +19 -0
- package/dist/plugin/kevin_publish.js.map +1 -0
- package/dist/plugin/metrics.d.ts +12 -1
- package/dist/plugin/metrics.js +49 -0
- package/dist/plugin/metrics.js.map +1 -1
- package/dist/plugin/replay-types.d.ts +8 -8
- package/dist/plugin/replay.js +10 -0
- package/dist/plugin/replay.js.map +1 -1
- package/migrations/001_initial.sql +91 -91
- package/migrations/003_v02_signal.sql +57 -57
- package/migrations/004_v03_knowledge.sql +138 -138
- package/migrations/005_v04_signal.sql +57 -57
- package/migrations/006_v05_glassbox.sql +118 -118
- package/migrations/007_v06_pull.sql +145 -0
- package/migrations/008_v07_truth.sql +124 -0
- 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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"}
|
package/dist/plugin/Feedback.js
CHANGED
|
@@ -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
|
|
15
|
-
return
|
|
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":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AA4CnC,MAAM,iBAAiB,GAA+B,CAAC,QAAQ,CAAC,CAAC;AACjE,MAAM,iBAAiB,GAA+B;IACrD,OAAO;IACP,UAAU;IACV,QAAQ;CACR,CAAC;AAEF,4EAA4E;AAC5E,4EAA4E;AAC5E,+BAA+B;AAC/B,MAAM,kBAAkB,GAAG,IAAI,OAAO,EAAkB,CAAC;AACzD,SAAS,gBAAgB,CAAC,KAAY;IACrC,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,MAAM,KAAK,
|
|
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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"}
|