@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Archiver.js","sourceRoot":"","sources":["../../plugin/Archiver.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,QAAQ;IAKF;IACA;IALD,OAAO,CAAiB;IACxB,GAAG,CAAa;IAEjC,YACkB,KAAY,EACZ,aAA4B,EAC7C,OAAwB,EACxB,MAAkB,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE;QAHjB,UAAK,GAAL,KAAK,CAAO;QACZ,kBAAa,GAAb,aAAa,CAAe;QAI7C,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,GAAG;QACF,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAAE,OAAO,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACrC,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;QAExB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC;QAC5E,IAAI,CAAC,KAAK;aACR,OAAO,CACP;;;;;2BAKuB,CACvB;aACA,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,GAAG,EAE9D,CAAC;QACF,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,CAAC;IACV,CAAC;IAEO,gBAAgB;QACvB,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC;YACtE,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YACtB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAEO,iBAAiB;QACxB,OAAO,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;CACD;AAED,MAAM,mBAAmB,GAAG,IAAI,OAAO,EAAkB,CAAC;AAC1D,SAAS,uBAAuB,CAAC,KAAY;IAC5C,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"Archiver.js","sourceRoot":"","sources":["../../plugin/Archiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Store } from "./Store.js";
|
|
2
|
+
import type { Metrics } from "./metrics.js";
|
|
3
|
+
export declare const MARKER_BEGIN = "<!-- kevin:begin \u2014 curated by opencode-kevin, safe to edit -->";
|
|
4
|
+
export declare const MARKER_END = "<!-- kevin:end -->";
|
|
5
|
+
export type WriteOutcome = "written" | "noop" | "refused";
|
|
6
|
+
export interface WritePlan {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
readonly before: string;
|
|
9
|
+
readonly after: string;
|
|
10
|
+
readonly diff: string;
|
|
11
|
+
readonly outcome: WriteOutcome;
|
|
12
|
+
readonly reason?: string;
|
|
13
|
+
readonly hashBefore: string;
|
|
14
|
+
readonly hashAfter: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rule 9 (K6-009 / plan §5.1, D6-02) — three layers applied to the body
|
|
18
|
+
* before splicing:
|
|
19
|
+
* (a) the escaping discipline of `plugin/memory-format.ts`;
|
|
20
|
+
* (b) strip any line containing `kevin:begin` or `kevin:end`, in any
|
|
21
|
+
* casing, anywhere in the line;
|
|
22
|
+
* (c) strip HTML comment terminators (`-->`).
|
|
23
|
+
* Without this, a memory containing a literal `<!-- kevin:end -->` line would
|
|
24
|
+
* close the marker comment early and let subsequent content escape the
|
|
25
|
+
* curated region on the next regeneration — a marker-injection variant of the
|
|
26
|
+
* v0.1.5 prompt-injection defect (plan §3.5).
|
|
27
|
+
*/
|
|
28
|
+
export declare function sanitizeArtifactBody(body: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* v0.6.0 (K6-005 / plan §5.1) — the single write path to disk (D6-01).
|
|
31
|
+
*
|
|
32
|
+
* `plan()` is pure: it reads the target file, locates the marker pair, splices
|
|
33
|
+
* the body between the markers and returns a {@link WritePlan}. It performs no
|
|
34
|
+
* writes — rule 1. `apply()` is implemented by K6-007; until then it is a stub
|
|
35
|
+
* that throws, so no caller can accidentally write before the audit trail
|
|
36
|
+
* exists.
|
|
37
|
+
*
|
|
38
|
+
* `projectId` is a constructor argument rather than a per-call argument so that
|
|
39
|
+
* every audit row is attributed without the call site having to remember.
|
|
40
|
+
*/
|
|
41
|
+
export declare class ArtifactWriter {
|
|
42
|
+
private readonly store;
|
|
43
|
+
private readonly projectId;
|
|
44
|
+
private readonly metrics;
|
|
45
|
+
constructor(store: Store, projectId: string, metrics?: Metrics | null);
|
|
46
|
+
plan(path: string, body: string): WritePlan;
|
|
47
|
+
apply(plan: WritePlan, proposalId?: string): WriteOutcome;
|
|
48
|
+
private renameTemp;
|
|
49
|
+
private audit;
|
|
50
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { closeSync, fsyncSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from "node:fs";
|
|
3
|
+
import { unifiedDiff } from "./diff.js";
|
|
4
|
+
import { uuidv7 } from "./uuid.js";
|
|
5
|
+
// v0.6.0 (K6-005 / plan §5.1, D6-02) — the frozen marker contract. The exact
|
|
6
|
+
// byte sequences are load-bearing: README, v1.0.0 plan C-01 and the round-trip
|
|
7
|
+
// test all depend on them.
|
|
8
|
+
export const MARKER_BEGIN = "<!-- kevin:begin — curated by opencode-kevin, safe to edit -->";
|
|
9
|
+
export const MARKER_END = "<!-- kevin:end -->";
|
|
10
|
+
function sha256(text) {
|
|
11
|
+
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Rule 5 (K6-008 / plan §5.1, D6-02) — the line-ending style comes from the
|
|
15
|
+
* FIRST line ending in the existing file: CRLF if it is CRLF, otherwise LF.
|
|
16
|
+
* A CRLF file whose last line lacks a terminator, and a mixed-ending file,
|
|
17
|
+
* are both resolved by the same first-ending rule, deterministically.
|
|
18
|
+
*/
|
|
19
|
+
function detectEol(text) {
|
|
20
|
+
const nl = text.indexOf("\n");
|
|
21
|
+
if (nl === -1)
|
|
22
|
+
return "\n";
|
|
23
|
+
return nl > 0 && text[nl - 1] === "\r" ? "\r\n" : "\n";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Rule 5 (K6-008) — normalize the generated body into the file's line-ending
|
|
27
|
+
* style so a CRLF file stays CRLF everywhere, including inside the block.
|
|
28
|
+
*/
|
|
29
|
+
function normalizeEol(body, eol) {
|
|
30
|
+
return body.replace(/\r\n/g, "\n").replace(/\n/g, eol);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Rule 9, layer (a) — the escaping discipline of `plugin/memory-format.ts`
|
|
34
|
+
* (`&`, `<`, `>`) made idempotent: an ampersand that already heads a known
|
|
35
|
+
* entity (`&`, `<`, `>`, `&#NNN;`) is left alone, so sanitizing
|
|
36
|
+
* sanitized output is a fixed point. The round-trip property of the marker
|
|
37
|
+
* block depends on this: a non-idempotent escape would grow `&lt;` on
|
|
38
|
+
* every regeneration (K6-009 / plan §5.1 rule 9).
|
|
39
|
+
*/
|
|
40
|
+
function escapeIdempotent(text) {
|
|
41
|
+
return text
|
|
42
|
+
.replace(/&(?!(amp|lt|gt|#\d+);)/g, "&")
|
|
43
|
+
.replace(/</g, "<")
|
|
44
|
+
.replace(/>/g, ">");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Rule 9 (K6-009 / plan §5.1, D6-02) — three layers applied to the body
|
|
48
|
+
* before splicing:
|
|
49
|
+
* (a) the escaping discipline of `plugin/memory-format.ts`;
|
|
50
|
+
* (b) strip any line containing `kevin:begin` or `kevin:end`, in any
|
|
51
|
+
* casing, anywhere in the line;
|
|
52
|
+
* (c) strip HTML comment terminators (`-->`).
|
|
53
|
+
* Without this, a memory containing a literal `<!-- kevin:end -->` line would
|
|
54
|
+
* close the marker comment early and let subsequent content escape the
|
|
55
|
+
* curated region on the next regeneration — a marker-injection variant of the
|
|
56
|
+
* v0.1.5 prompt-injection defect (plan §3.5).
|
|
57
|
+
*/
|
|
58
|
+
export function sanitizeArtifactBody(body) {
|
|
59
|
+
const escaped = escapeIdempotent(body);
|
|
60
|
+
const kept = escaped
|
|
61
|
+
.split("\n")
|
|
62
|
+
.filter((line) => !/kevin:begin|kevin:end/i.test(line))
|
|
63
|
+
.join("\n");
|
|
64
|
+
return kept.replace(/-->/g, "");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* v0.6.0 (K6-005 / plan §5.1) — the single write path to disk (D6-01).
|
|
68
|
+
*
|
|
69
|
+
* `plan()` is pure: it reads the target file, locates the marker pair, splices
|
|
70
|
+
* the body between the markers and returns a {@link WritePlan}. It performs no
|
|
71
|
+
* writes — rule 1. `apply()` is implemented by K6-007; until then it is a stub
|
|
72
|
+
* that throws, so no caller can accidentally write before the audit trail
|
|
73
|
+
* exists.
|
|
74
|
+
*
|
|
75
|
+
* `projectId` is a constructor argument rather than a per-call argument so that
|
|
76
|
+
* every audit row is attributed without the call site having to remember.
|
|
77
|
+
*/
|
|
78
|
+
export class ArtifactWriter {
|
|
79
|
+
store;
|
|
80
|
+
projectId;
|
|
81
|
+
metrics;
|
|
82
|
+
constructor(store, projectId, metrics) {
|
|
83
|
+
this.store = store;
|
|
84
|
+
this.projectId = projectId;
|
|
85
|
+
this.metrics = metrics ?? null;
|
|
86
|
+
}
|
|
87
|
+
plan(path, body) {
|
|
88
|
+
let before;
|
|
89
|
+
try {
|
|
90
|
+
// Read as Buffer, not as utf8 text: readFileSync's text decoding
|
|
91
|
+
// strips a leading BOM, which would silently drop it on the next
|
|
92
|
+
// write. Buffer.toString keeps \uFEFF as a character of `before`.
|
|
93
|
+
before = readFileSync(path).toString("utf8");
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
97
|
+
before = "";
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const eol = detectEol(before);
|
|
104
|
+
// Rule 9 — sanitation happens in plan(), before hashing, so the hashes
|
|
105
|
+
// describe what was actually written.
|
|
106
|
+
const bodyEol = normalizeEol(sanitizeArtifactBody(body), eol);
|
|
107
|
+
const firstBegin = before.indexOf(MARKER_BEGIN);
|
|
108
|
+
const firstEnd = before.indexOf(MARKER_END);
|
|
109
|
+
let after;
|
|
110
|
+
let outcome = "written";
|
|
111
|
+
let reason;
|
|
112
|
+
if (firstBegin === -1 && firstEnd === -1) {
|
|
113
|
+
// Rule 2 — create: the block is appended at the end of the content,
|
|
114
|
+
// preceded by a blank line. For an empty file (missing file treated
|
|
115
|
+
// as "") the result is exactly: blank line, MARKER_BEGIN, body,
|
|
116
|
+
// MARKER_END, trailing newline.
|
|
117
|
+
const separator = before === "" ? eol : before.endsWith(eol) ? eol : eol + eol;
|
|
118
|
+
after =
|
|
119
|
+
before +
|
|
120
|
+
separator +
|
|
121
|
+
MARKER_BEGIN +
|
|
122
|
+
eol +
|
|
123
|
+
bodyEol +
|
|
124
|
+
eol +
|
|
125
|
+
MARKER_END +
|
|
126
|
+
eol;
|
|
127
|
+
}
|
|
128
|
+
else if (firstBegin === -1 || firstEnd === -1) {
|
|
129
|
+
// Rule 3 — exactly one marker present.
|
|
130
|
+
after = before;
|
|
131
|
+
outcome = "refused";
|
|
132
|
+
reason =
|
|
133
|
+
firstBegin === -1
|
|
134
|
+
? "kevin:end marker present without kevin:begin"
|
|
135
|
+
: "kevin:begin marker present without kevin:end";
|
|
136
|
+
}
|
|
137
|
+
else if (firstEnd < firstBegin) {
|
|
138
|
+
// Rule 3 — MARKER_END precedes MARKER_BEGIN.
|
|
139
|
+
after = before;
|
|
140
|
+
outcome = "refused";
|
|
141
|
+
reason = "kevin:end appears before kevin:begin";
|
|
142
|
+
}
|
|
143
|
+
else if (before.indexOf(MARKER_BEGIN, firstBegin + MARKER_BEGIN.length) !== -1 ||
|
|
144
|
+
before.indexOf(MARKER_END, firstEnd + MARKER_END.length) !== -1) {
|
|
145
|
+
// Rule 3 — more than one pair (any additional marker occurrence).
|
|
146
|
+
after = before;
|
|
147
|
+
outcome = "refused";
|
|
148
|
+
reason = "more than one marker pair present";
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Rule 4 — bytes outside the marker pair are byte-identical. The
|
|
152
|
+
// block between the markers (begin marker, old block, end marker)
|
|
153
|
+
// is replaced by the regenerated block.
|
|
154
|
+
const blockEnd = firstEnd + MARKER_END.length;
|
|
155
|
+
after =
|
|
156
|
+
before.slice(0, firstBegin) +
|
|
157
|
+
MARKER_BEGIN +
|
|
158
|
+
eol +
|
|
159
|
+
bodyEol +
|
|
160
|
+
eol +
|
|
161
|
+
MARKER_END +
|
|
162
|
+
before.slice(blockEnd);
|
|
163
|
+
// Rule 6 — unchanged content is a noop, never a write.
|
|
164
|
+
outcome = after === before ? "noop" : "written";
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
path,
|
|
168
|
+
before,
|
|
169
|
+
after,
|
|
170
|
+
// v0.6.0 (K6-006 / plan §5.2, D6-05) — approval prompts show bytes,
|
|
171
|
+
// never prose. Identical inputs yield "".
|
|
172
|
+
diff: unifiedDiff(path, before, after),
|
|
173
|
+
outcome,
|
|
174
|
+
...(reason !== undefined ? { reason } : {}),
|
|
175
|
+
hashBefore: sha256(before),
|
|
176
|
+
hashAfter: sha256(after),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// v0.6.0 (K6-007 / plan §5.1, rules 7–8) — atomic write + audit row.
|
|
180
|
+
apply(plan, proposalId) {
|
|
181
|
+
// Rule 8 — refusals and noops still leave an audit trail; a refusal
|
|
182
|
+
// that leaves no trace is indistinguishable from a write that never
|
|
183
|
+
// happened. Rule 6 — a noop creates no temp file and writes nothing.
|
|
184
|
+
if (plan.outcome === "noop" || plan.outcome === "refused") {
|
|
185
|
+
if (plan.outcome === "noop") {
|
|
186
|
+
this.metrics?.incr("artifact_writes_noop", 1);
|
|
187
|
+
}
|
|
188
|
+
this.audit(plan, proposalId);
|
|
189
|
+
return plan.outcome;
|
|
190
|
+
}
|
|
191
|
+
// Rule 7 — write to `<path>.kevin.tmp` in the same directory (same
|
|
192
|
+
// filesystem, so rename is atomic), fsync, close, then rename over the
|
|
193
|
+
// target. Never write the target path directly, never truncate-then-write.
|
|
194
|
+
const tmpPath = `${plan.path}.kevin.tmp`;
|
|
195
|
+
let fd;
|
|
196
|
+
try {
|
|
197
|
+
fd = openSync(tmpPath, "w");
|
|
198
|
+
writeSync(fd, plan.after, null, "utf8");
|
|
199
|
+
fsyncSync(fd);
|
|
200
|
+
closeSync(fd);
|
|
201
|
+
fd = undefined;
|
|
202
|
+
this.renameTemp(tmpPath, plan.path);
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
// Never leave .kevin.tmp litter next to the user's file.
|
|
206
|
+
if (fd !== undefined) {
|
|
207
|
+
try {
|
|
208
|
+
closeSync(fd);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// already closed or unusable; unlink below is the cleanup
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
unlinkSync(tmpPath);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// nothing to clean up
|
|
219
|
+
}
|
|
220
|
+
throw err;
|
|
221
|
+
}
|
|
222
|
+
this.metrics?.incr("artifact_writes_total", 1);
|
|
223
|
+
this.audit(plan, proposalId);
|
|
224
|
+
return "written";
|
|
225
|
+
}
|
|
226
|
+
// Fault-injection seam for the atomicity test: the rename is the point
|
|
227
|
+
// where a failure must leave the target untouched and the temp file gone.
|
|
228
|
+
renameTemp(tmpPath, target) {
|
|
229
|
+
renameSync(tmpPath, target);
|
|
230
|
+
}
|
|
231
|
+
audit(plan, proposalId) {
|
|
232
|
+
this.store
|
|
233
|
+
.prepare(`INSERT INTO artifact_writes
|
|
234
|
+
(id, proposal_id, project_id, path, bytes_before, bytes_after,
|
|
235
|
+
hash_before, hash_after, outcome, reason)
|
|
236
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
237
|
+
.run(uuidv7(), proposalId ?? null, this.projectId, plan.path, Buffer.byteLength(plan.before, "utf8"), Buffer.byteLength(plan.after, "utf8"), plan.hashBefore, plan.hashAfter, plan.outcome, plan.reason ?? null);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=ArtifactWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArtifactWriter.js","sourceRoot":"","sources":["../../plugin/ArtifactWriter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MemoryService } from "./MemoryService.js";
|
|
2
|
+
import type { RepoTruth } from "./RepoTruth.js";
|
|
3
|
+
import type { Store } from "./Store.js";
|
|
4
|
+
import type { Metrics } from "./metrics.js";
|
|
5
|
+
export type ConflictKind = "repo_truth" | "decision_pair" | "temporal";
|
|
6
|
+
export interface Conflict {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly kind: ConflictKind;
|
|
9
|
+
readonly memoryA: string;
|
|
10
|
+
readonly memoryB?: string;
|
|
11
|
+
readonly factId?: string;
|
|
12
|
+
readonly detail: string;
|
|
13
|
+
}
|
|
14
|
+
export interface RepoTruthConflictInput {
|
|
15
|
+
readonly memoryId: string;
|
|
16
|
+
readonly factId?: string | null;
|
|
17
|
+
readonly reasons: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export declare class ConflictDetector {
|
|
20
|
+
private readonly store;
|
|
21
|
+
private readonly projectId;
|
|
22
|
+
private readonly repoTruth?;
|
|
23
|
+
private readonly memoryService?;
|
|
24
|
+
private readonly metrics;
|
|
25
|
+
constructor(store: Store, projectId: string, metrics?: Metrics | null, repoTruth?: RepoTruth | undefined, memoryService?: MemoryService | undefined);
|
|
26
|
+
detect(repoTruthInput?: readonly RepoTruthConflictInput[]): Conflict[];
|
|
27
|
+
acknowledge(id: string): void;
|
|
28
|
+
/** Human-only operation. It resolves the conflict row, never a memory. */
|
|
29
|
+
resolve(id: string, keepMemoryId: string): void;
|
|
30
|
+
private detectRepoTruth;
|
|
31
|
+
private repoTruthInputs;
|
|
32
|
+
private detectDecisionPairs;
|
|
33
|
+
private detectTemporal;
|
|
34
|
+
private insertIfNew;
|
|
35
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { normalize } from "./fingerprint.js";
|
|
2
|
+
import { uuidv7 } from "./uuid.js";
|
|
3
|
+
const POLARITY_RULES = [
|
|
4
|
+
{
|
|
5
|
+
positive: ["use"],
|
|
6
|
+
negative: [
|
|
7
|
+
["do", "not", "use"],
|
|
8
|
+
["don't", "use"],
|
|
9
|
+
["never", "use"],
|
|
10
|
+
],
|
|
11
|
+
},
|
|
12
|
+
{ positive: ["always"], negative: [["never"]] },
|
|
13
|
+
{ positive: ["required"], negative: [["forbidden"], ["not", "required"]] },
|
|
14
|
+
{ positive: ["enable"], negative: [["disable"]] },
|
|
15
|
+
{ positive: ["prefer"], negative: [["avoid"]] },
|
|
16
|
+
];
|
|
17
|
+
const STOP_WORDS = new Set([
|
|
18
|
+
"a",
|
|
19
|
+
"an",
|
|
20
|
+
"and",
|
|
21
|
+
"are",
|
|
22
|
+
"as",
|
|
23
|
+
"at",
|
|
24
|
+
"be",
|
|
25
|
+
"by",
|
|
26
|
+
"for",
|
|
27
|
+
"from",
|
|
28
|
+
"in",
|
|
29
|
+
"is",
|
|
30
|
+
"it",
|
|
31
|
+
"of",
|
|
32
|
+
"on",
|
|
33
|
+
"or",
|
|
34
|
+
"that",
|
|
35
|
+
"the",
|
|
36
|
+
"this",
|
|
37
|
+
"to",
|
|
38
|
+
"with",
|
|
39
|
+
"we",
|
|
40
|
+
"when",
|
|
41
|
+
"where",
|
|
42
|
+
"you",
|
|
43
|
+
]);
|
|
44
|
+
const POLARITY_WORDS = new Set([
|
|
45
|
+
"use",
|
|
46
|
+
"do",
|
|
47
|
+
"not",
|
|
48
|
+
// "don't" tokenizes to ["don", "t"] (see tokens()); the lexicon phrase
|
|
49
|
+
// ["don't","use"] is matched by tokenizing the phrase the same way, so
|
|
50
|
+
// both fragments must be excluded from subjects() too (K7-014).
|
|
51
|
+
"don",
|
|
52
|
+
"t",
|
|
53
|
+
"never",
|
|
54
|
+
"always",
|
|
55
|
+
"required",
|
|
56
|
+
"forbidden",
|
|
57
|
+
"enable",
|
|
58
|
+
"disable",
|
|
59
|
+
"prefer",
|
|
60
|
+
"avoid",
|
|
61
|
+
]);
|
|
62
|
+
export class ConflictDetector {
|
|
63
|
+
store;
|
|
64
|
+
projectId;
|
|
65
|
+
repoTruth;
|
|
66
|
+
memoryService;
|
|
67
|
+
metrics;
|
|
68
|
+
constructor(store, projectId, metrics, repoTruth, memoryService) {
|
|
69
|
+
this.store = store;
|
|
70
|
+
this.projectId = projectId;
|
|
71
|
+
this.repoTruth = repoTruth;
|
|
72
|
+
this.memoryService = memoryService;
|
|
73
|
+
this.metrics = metrics ?? null;
|
|
74
|
+
}
|
|
75
|
+
detect(repoTruthInput) {
|
|
76
|
+
const detected = [];
|
|
77
|
+
detected.push(...this.detectRepoTruth(repoTruthInput));
|
|
78
|
+
detected.push(...this.detectDecisionPairs());
|
|
79
|
+
detected.push(...this.detectTemporal());
|
|
80
|
+
return detected;
|
|
81
|
+
}
|
|
82
|
+
acknowledge(id) {
|
|
83
|
+
this.store
|
|
84
|
+
.prepare("UPDATE memory_conflicts SET status = 'acknowledged' WHERE id = ? AND project_id = ? AND status = 'open'")
|
|
85
|
+
.run(id, this.projectId);
|
|
86
|
+
}
|
|
87
|
+
/** Human-only operation. It resolves the conflict row, never a memory. */
|
|
88
|
+
resolve(id, keepMemoryId) {
|
|
89
|
+
const row = this.store
|
|
90
|
+
.prepare(`SELECT memory_a, memory_b FROM memory_conflicts
|
|
91
|
+
WHERE id = ? AND project_id = ? AND status <> 'resolved'`)
|
|
92
|
+
.get(id, this.projectId);
|
|
93
|
+
if (!row)
|
|
94
|
+
throw new Error(`conflict not found: ${id}`);
|
|
95
|
+
if (keepMemoryId !== row.memory_a && keepMemoryId !== row.memory_b) {
|
|
96
|
+
throw new Error("keep must identify one of the conflict memories");
|
|
97
|
+
}
|
|
98
|
+
this.store
|
|
99
|
+
.prepare("UPDATE memory_conflicts SET status = 'resolved', resolved_at = datetime('now') WHERE id = ? AND project_id = ?")
|
|
100
|
+
.run(id, this.projectId);
|
|
101
|
+
}
|
|
102
|
+
detectRepoTruth(input) {
|
|
103
|
+
const items = input ?? this.repoTruthInputs();
|
|
104
|
+
const out = [];
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
for (const reason of item.reasons) {
|
|
107
|
+
this.memoryService?.applyTruthPenalty(item.memoryId, 0.5, reason);
|
|
108
|
+
const id = this.insertIfNew({
|
|
109
|
+
kind: "repo_truth",
|
|
110
|
+
memoryA: item.memoryId,
|
|
111
|
+
memoryB: null,
|
|
112
|
+
factId: item.factId ?? null,
|
|
113
|
+
detail: reason,
|
|
114
|
+
});
|
|
115
|
+
if (id)
|
|
116
|
+
out.push({
|
|
117
|
+
id,
|
|
118
|
+
kind: "repo_truth",
|
|
119
|
+
memoryA: item.memoryId,
|
|
120
|
+
factId: item.factId ?? undefined,
|
|
121
|
+
detail: reason,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// v0.7.0 (D7-03) — "recoverable by re-scanning": a memory whose
|
|
126
|
+
// contradiction has lapsed (the repo no longer contradicts it) is
|
|
127
|
+
// de-ranked no longer. The conflict row stays open — resolution is
|
|
128
|
+
// human-initiated only (D7-06) — but the score penalty lifts, so
|
|
129
|
+
// fixing the repo genuinely recovers the memory. Runs only on the
|
|
130
|
+
// production path (no explicit input): explicit-input callers control
|
|
131
|
+
// every write themselves.
|
|
132
|
+
if (!input && this.repoTruth && this.memoryService) {
|
|
133
|
+
const penalized = this.store
|
|
134
|
+
.prepare("SELECT id FROM memories WHERE project_id = ? AND truth_penalty > 0 AND status = 'active'")
|
|
135
|
+
.all(this.projectId);
|
|
136
|
+
for (const row of penalized) {
|
|
137
|
+
const memory = this.memoryService.getById(row.id);
|
|
138
|
+
if (!memory)
|
|
139
|
+
continue;
|
|
140
|
+
if ((this.repoTruth.contradictions(memory) ?? []).length === 0) {
|
|
141
|
+
this.memoryService.applyTruthPenalty(row.id, 0, "");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
repoTruthInputs() {
|
|
148
|
+
if (!this.repoTruth)
|
|
149
|
+
return [];
|
|
150
|
+
const rows = this.store
|
|
151
|
+
.prepare(`SELECT id, type, content, scope, relevance_score, source_tool,
|
|
152
|
+
source_session, metadata, created_at, updated_at, expires_at,
|
|
153
|
+
project_id, fingerprint, origin, evidence_count, last_verified_at,
|
|
154
|
+
status, fix_args, ignored, superseded_by, feedback_positive,
|
|
155
|
+
feedback_negative, curated, curated_at, inferable,
|
|
156
|
+
truth_penalty, contradicted_at
|
|
157
|
+
FROM memories WHERE project_id = ? AND status = 'active'`)
|
|
158
|
+
.all(this.projectId);
|
|
159
|
+
return rows.flatMap((row) => {
|
|
160
|
+
const memory = row;
|
|
161
|
+
const reasons = this.repoTruth?.contradictions(memory) ?? [];
|
|
162
|
+
return reasons.length > 0 ? [{ memoryId: row.id, reasons }] : [];
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
detectDecisionPairs() {
|
|
166
|
+
const rows = this.store
|
|
167
|
+
.prepare(`SELECT id, type, content, fingerprint FROM memories
|
|
168
|
+
WHERE project_id = ? AND status = 'active'
|
|
169
|
+
AND type IN ('decision', 'rule') ORDER BY id`)
|
|
170
|
+
.all(this.projectId);
|
|
171
|
+
const out = [];
|
|
172
|
+
for (let i = 0; i < rows.length; i++) {
|
|
173
|
+
for (let j = i + 1; j < rows.length; j++) {
|
|
174
|
+
const a = rows[i];
|
|
175
|
+
const b = rows[j];
|
|
176
|
+
if (!a || !b || a.fingerprint === b.fingerprint)
|
|
177
|
+
continue;
|
|
178
|
+
const pair = oppositePair(a.content, b.content);
|
|
179
|
+
if (!pair)
|
|
180
|
+
continue;
|
|
181
|
+
const id = this.insertIfNew({
|
|
182
|
+
kind: "decision_pair",
|
|
183
|
+
memoryA: a.id,
|
|
184
|
+
memoryB: b.id,
|
|
185
|
+
factId: null,
|
|
186
|
+
detail: pair,
|
|
187
|
+
});
|
|
188
|
+
if (id)
|
|
189
|
+
out.push({
|
|
190
|
+
id,
|
|
191
|
+
kind: "decision_pair",
|
|
192
|
+
memoryA: a.id,
|
|
193
|
+
memoryB: b.id,
|
|
194
|
+
detail: pair,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
detectTemporal() {
|
|
201
|
+
const rows = this.store
|
|
202
|
+
.prepare(`SELECT m.id,
|
|
203
|
+
MAX(CASE WHEN i.outcome = 'effective' THEN i.injected_at END) AS effective_at,
|
|
204
|
+
MAX(CASE WHEN i.outcome = 'ineffective' THEN i.injected_at END) AS ineffective_at
|
|
205
|
+
FROM memories m JOIN kevin_injections i ON i.memory_id = m.id
|
|
206
|
+
WHERE m.project_id = ? AND m.status = 'active'
|
|
207
|
+
GROUP BY m.id
|
|
208
|
+
HAVING effective_at IS NOT NULL AND ineffective_at IS NOT NULL
|
|
209
|
+
AND ineffective_at > effective_at`)
|
|
210
|
+
.all(this.projectId);
|
|
211
|
+
const out = [];
|
|
212
|
+
for (const row of rows) {
|
|
213
|
+
const detail = `memory was effective at ${row.effective_at} and became ineffective at ${row.ineffective_at}`;
|
|
214
|
+
const id = this.insertIfNew({
|
|
215
|
+
kind: "temporal",
|
|
216
|
+
memoryA: row.id,
|
|
217
|
+
memoryB: null,
|
|
218
|
+
factId: null,
|
|
219
|
+
detail,
|
|
220
|
+
});
|
|
221
|
+
if (id)
|
|
222
|
+
out.push({ id, kind: "temporal", memoryA: row.id, detail });
|
|
223
|
+
}
|
|
224
|
+
return out;
|
|
225
|
+
}
|
|
226
|
+
insertIfNew(input) {
|
|
227
|
+
const existing = this.store
|
|
228
|
+
.prepare(`SELECT id FROM memory_conflicts
|
|
229
|
+
WHERE project_id = ? AND kind = ? AND memory_a = ?
|
|
230
|
+
AND (memory_b IS ? OR (memory_b IS NULL AND ? IS NULL))
|
|
231
|
+
AND (fact_id IS ? OR (fact_id IS NULL AND ? IS NULL))
|
|
232
|
+
AND status = 'open' LIMIT 1`)
|
|
233
|
+
.get(this.projectId, input.kind, input.memoryA, input.memoryB, input.memoryB, input.factId, input.factId);
|
|
234
|
+
if (existing)
|
|
235
|
+
return null;
|
|
236
|
+
const id = uuidv7();
|
|
237
|
+
this.store
|
|
238
|
+
.prepare(`INSERT INTO memory_conflicts
|
|
239
|
+
(id, project_id, memory_a, memory_b, fact_id, kind, detail)
|
|
240
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
241
|
+
.run(id, this.projectId, input.memoryA, input.memoryB, input.factId, input.kind, input.detail);
|
|
242
|
+
this.metrics?.incr("conflicts_detected", 1);
|
|
243
|
+
return id;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function tokens(text) {
|
|
247
|
+
return normalize(text).match(/[a-z0-9@._/-]+/g) ?? [];
|
|
248
|
+
}
|
|
249
|
+
function hasPhrase(words, phrase) {
|
|
250
|
+
if (phrase.length === 1)
|
|
251
|
+
return words.includes(phrase[0] ?? "");
|
|
252
|
+
for (let i = 0; i <= words.length - phrase.length; i++) {
|
|
253
|
+
if (phrase.every((word, offset) => words[i + offset] === word))
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
function polarity(text, rule) {
|
|
259
|
+
const words = tokens(text);
|
|
260
|
+
// Lexicon phrases are run through the same tokenizer as the text: "don't
|
|
261
|
+
// use" → ["don","t","use"], which is exactly how the text's own apostrophe
|
|
262
|
+
// is split, so a phrase never becomes unreachable (K7-014).
|
|
263
|
+
const match = (phrase) => hasPhrase(words, tokens(phrase.join(" ")));
|
|
264
|
+
const negative = rule.negative.some(match);
|
|
265
|
+
return { positive: !negative && match(rule.positive), negative };
|
|
266
|
+
}
|
|
267
|
+
function subjects(text) {
|
|
268
|
+
return new Set(tokens(text).filter((token) => !STOP_WORDS.has(token) && !POLARITY_WORDS.has(token)));
|
|
269
|
+
}
|
|
270
|
+
function oppositePair(a, b) {
|
|
271
|
+
const shared = [...subjects(a)].some((token) => subjects(b).has(token));
|
|
272
|
+
if (!shared)
|
|
273
|
+
return null;
|
|
274
|
+
for (const rule of POLARITY_RULES) {
|
|
275
|
+
const pa = polarity(a, rule);
|
|
276
|
+
const pb = polarity(b, rule);
|
|
277
|
+
if ((pa.positive && pb.negative) || (pa.negative && pb.positive)) {
|
|
278
|
+
return `statements carry opposite ${rule.positive.join(" ")} polarity for shared subject ${shared}`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=ConflictDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConflictDetector.js","sourceRoot":"","sources":["../../plugin/ConflictDetector.ts"],"names":[],"mappings":"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"}
|