@jmtrin/opencode-kevin 0.9.0 → 1.0.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 +558 -823
- package/dist/migrations/011_v10_proven.sql +69 -0
- package/dist/plugin/Archiver.js +0 -1
- package/dist/plugin/ArtifactWriter.d.ts +25 -10
- package/dist/plugin/ArtifactWriter.js +43 -25
- package/dist/plugin/CausalChain.js +0 -1
- package/dist/plugin/ConflictDetector.js +0 -1
- package/dist/plugin/ContextInjector.js +0 -1
- package/dist/plugin/ConventionMiner.js +0 -1
- package/dist/plugin/Curator.js +0 -1
- package/dist/plugin/Feedback.js +0 -1
- package/dist/plugin/HookLiveness.d.ts +6 -0
- package/dist/plugin/HookLiveness.js +15 -1
- package/dist/plugin/InjectionLedger.js +0 -1
- package/dist/plugin/LessonFixer.js +0 -1
- package/dist/plugin/Materializer.js +0 -1
- package/dist/plugin/MemoryService.js +0 -1
- package/dist/plugin/Migrate.d.ts +1 -1
- package/dist/plugin/Migrate.js +25 -3
- package/dist/plugin/PatternMiner.js +0 -1
- package/dist/plugin/QualityGate.js +0 -1
- package/dist/plugin/Reflector.js +0 -1
- package/dist/plugin/RepoIdentity.js +0 -1
- package/dist/plugin/RepoTruth.js +0 -1
- package/dist/plugin/Retrospective.js +7 -1
- package/dist/plugin/SharedLayer.js +0 -1
- package/dist/plugin/Store.js +0 -1
- package/dist/plugin/ToolCallObserver.js +0 -1
- package/dist/plugin/capabilities.js +0 -1
- package/dist/plugin/confidence.js +0 -1
- package/dist/plugin/contract.d.ts +46 -0
- package/dist/plugin/contract.js +368 -0
- package/dist/plugin/diff.js +0 -1
- package/dist/plugin/escape.d.ts +39 -0
- package/dist/plugin/escape.js +60 -0
- package/dist/plugin/fingerprint.js +0 -1
- package/dist/plugin/host.js +0 -1
- package/dist/plugin/index.d.ts +2 -2
- package/dist/plugin/index.js +425 -227
- package/dist/plugin/inferability.js +0 -1
- package/dist/plugin/kevin_approve.js +0 -1
- package/dist/plugin/kevin_audit.d.ts +31 -0
- package/dist/plugin/kevin_audit.js +60 -1
- package/dist/plugin/kevin_bench.d.ts +10 -0
- package/dist/plugin/kevin_bench.js +82 -0
- package/dist/plugin/kevin_conflicts.js +0 -1
- package/dist/plugin/kevin_contract.d.ts +8 -0
- package/dist/plugin/kevin_contract.js +59 -0
- package/dist/plugin/kevin_doctor.d.ts +5 -0
- package/dist/plugin/kevin_doctor.js +30 -2
- package/dist/plugin/kevin_facts.js +0 -1
- package/dist/plugin/kevin_native.js +0 -1
- package/dist/plugin/kevin_propose.js +0 -1
- package/dist/plugin/kevin_publish.js +0 -1
- package/dist/plugin/kevin_why.js +0 -1
- package/dist/plugin/memory-format.js +0 -1
- package/dist/plugin/metrics.js +0 -1
- package/dist/plugin/native.js +0 -1
- package/dist/plugin/okf-export.js +0 -1
- package/dist/plugin/okf-import.js +0 -1
- package/dist/plugin/okf.js +0 -1
- package/dist/plugin/perf.d.ts +35 -0
- package/dist/plugin/perf.js +174 -0
- package/dist/plugin/query-tokenizer.js +0 -1
- package/dist/plugin/redact.js +0 -1
- package/dist/plugin/replay-types.js +0 -1
- package/dist/plugin/replay.js +0 -1
- package/dist/plugin/sqlite-adapter.js +0 -1
- package/dist/plugin/uuid.js +0 -1
- package/package.json +21 -6
- package/dist/plugin/Archiver.js.map +0 -1
- package/dist/plugin/ArtifactWriter.js.map +0 -1
- package/dist/plugin/CausalChain.js.map +0 -1
- package/dist/plugin/ConflictDetector.js.map +0 -1
- package/dist/plugin/ContextInjector.js.map +0 -1
- package/dist/plugin/ConventionMiner.js.map +0 -1
- package/dist/plugin/Curator.js.map +0 -1
- package/dist/plugin/Feedback.js.map +0 -1
- package/dist/plugin/HookLiveness.js.map +0 -1
- package/dist/plugin/InjectionLedger.js.map +0 -1
- package/dist/plugin/LessonFixer.js.map +0 -1
- package/dist/plugin/Materializer.js.map +0 -1
- package/dist/plugin/MemoryService.js.map +0 -1
- package/dist/plugin/Migrate.js.map +0 -1
- package/dist/plugin/PatternMiner.js.map +0 -1
- package/dist/plugin/QualityGate.js.map +0 -1
- package/dist/plugin/Reflector.js.map +0 -1
- package/dist/plugin/RepoIdentity.js.map +0 -1
- package/dist/plugin/RepoTruth.js.map +0 -1
- package/dist/plugin/Retrospective.js.map +0 -1
- package/dist/plugin/SharedLayer.js.map +0 -1
- package/dist/plugin/Store.js.map +0 -1
- package/dist/plugin/ToolCallObserver.js.map +0 -1
- package/dist/plugin/capabilities.js.map +0 -1
- package/dist/plugin/confidence.js.map +0 -1
- package/dist/plugin/diff.js.map +0 -1
- package/dist/plugin/fingerprint.js.map +0 -1
- package/dist/plugin/host.js.map +0 -1
- package/dist/plugin/index.js.map +0 -1
- package/dist/plugin/inferability.js.map +0 -1
- package/dist/plugin/kevin_approve.js.map +0 -1
- package/dist/plugin/kevin_audit.js.map +0 -1
- package/dist/plugin/kevin_conflicts.js.map +0 -1
- package/dist/plugin/kevin_doctor.js.map +0 -1
- package/dist/plugin/kevin_facts.js.map +0 -1
- package/dist/plugin/kevin_native.js.map +0 -1
- package/dist/plugin/kevin_propose.js.map +0 -1
- package/dist/plugin/kevin_publish.js.map +0 -1
- package/dist/plugin/kevin_why.js.map +0 -1
- package/dist/plugin/memory-format.js.map +0 -1
- package/dist/plugin/metrics.js.map +0 -1
- package/dist/plugin/native.js.map +0 -1
- package/dist/plugin/okf-export.js.map +0 -1
- package/dist/plugin/okf-import.js.map +0 -1
- package/dist/plugin/okf.js.map +0 -1
- package/dist/plugin/query-tokenizer.js.map +0 -1
- package/dist/plugin/redact.js.map +0 -1
- package/dist/plugin/replay-types.js.map +0 -1
- package/dist/plugin/replay.js.map +0 -1
- package/dist/plugin/sqlite-adapter.js.map +0 -1
- package/dist/plugin/uuid.js.map +0 -1
- package/migrations/001_initial.sql +0 -92
- package/migrations/002_indexes.sql +0 -14
- package/migrations/003_v02_signal.sql +0 -58
- package/migrations/004_v03_knowledge.sql +0 -138
- package/migrations/005_v04_signal.sql +0 -57
- package/migrations/006_v05_glassbox.sql +0 -118
- package/migrations/007_v06_pull.sql +0 -145
- package/migrations/008_v07_truth.sql +0 -124
- package/migrations/009_v08_team.sql +0 -100
- package/migrations/010_v09_native.sql +0 -78
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
-- =============================================================
|
|
2
|
+
-- Kevin v1.0.0 "Proven" — migration 011
|
|
3
|
+
-- Adds: perf sampling, benchmark results.
|
|
4
|
+
-- No ALTER TABLE (second release running); no column is retyped.
|
|
5
|
+
-- =============================================================
|
|
6
|
+
|
|
7
|
+
-- 1. Per-scope latency aggregates, flushed at session.idle.
|
|
8
|
+
-- Machine-scoped: no project_id, for the same reason hook_liveness
|
|
9
|
+
-- has none (v0.9.0 D9-08) — latency is a property of the install.
|
|
10
|
+
CREATE TABLE IF NOT EXISTS perf_samples (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
scope TEXT NOT NULL,
|
|
13
|
+
sample_count INTEGER NOT NULL,
|
|
14
|
+
p50_ms REAL NOT NULL,
|
|
15
|
+
p95_ms REAL NOT NULL,
|
|
16
|
+
max_ms REAL NOT NULL,
|
|
17
|
+
budget_p95_ms REAL NOT NULL,
|
|
18
|
+
within_budget INTEGER NOT NULL DEFAULT 1,
|
|
19
|
+
recorded_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_perf_samples_scope
|
|
23
|
+
ON perf_samples(scope, recorded_at DESC);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_perf_samples_breach
|
|
25
|
+
ON perf_samples(within_budget) WHERE within_budget = 0;
|
|
26
|
+
|
|
27
|
+
-- 2. Benchmark results. Append-only. One row per arm per run.
|
|
28
|
+
-- arm CHECK is closed by the plan; widening requires a table rebuild (intentional friction).
|
|
29
|
+
-- scope CHECK is intentionally absent: the scope union may gain members in a 1.x minor.
|
|
30
|
+
CREATE TABLE IF NOT EXISTS bench_runs (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
corpus_digest TEXT NOT NULL,
|
|
33
|
+
contract_digest TEXT NOT NULL,
|
|
34
|
+
package_version TEXT NOT NULL,
|
|
35
|
+
runtime TEXT NOT NULL,
|
|
36
|
+
arm TEXT NOT NULL,
|
|
37
|
+
k INTEGER NOT NULL,
|
|
38
|
+
precision_at_k REAL NOT NULL,
|
|
39
|
+
recall_at_k REAL NOT NULL,
|
|
40
|
+
mrr REAL NOT NULL,
|
|
41
|
+
ran_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
42
|
+
CHECK (arm IN ('none', 'recent-k', 'random-k', 'kevin'))
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_bench_runs_corpus
|
|
46
|
+
ON bench_runs(corpus_digest, ran_at DESC);
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_bench_runs_arm
|
|
48
|
+
ON bench_runs(arm, ran_at DESC);
|
|
49
|
+
|
|
50
|
+
-- 3. Metric seeds (45 -> 51).
|
|
51
|
+
INSERT OR IGNORE INTO kevin_metrics (key, value) VALUES ('perf_samples_recorded', 0);
|
|
52
|
+
INSERT OR IGNORE INTO kevin_metrics (key, value) VALUES ('perf_budget_breaches', 0);
|
|
53
|
+
INSERT OR IGNORE INTO kevin_metrics (key, value) VALUES ('dispose_fires_total', 0);
|
|
54
|
+
INSERT OR IGNORE INTO kevin_metrics (key, value) VALUES ('dispose_misses_total', 0);
|
|
55
|
+
INSERT OR IGNORE INTO kevin_metrics (key, value) VALUES ('contract_digest_changes', 0);
|
|
56
|
+
INSERT OR IGNORE INTO kevin_metrics (key, value) VALUES ('bench_runs_total', 0);
|
|
57
|
+
|
|
58
|
+
-- 4. Setting seeds (27 -> 31). All TEXT; '0'/'1' are strings.
|
|
59
|
+
INSERT OR IGNORE INTO kevin_settings (key, value) VALUES ('perf_enabled', '1');
|
|
60
|
+
INSERT OR IGNORE INTO kevin_settings (key, value) VALUES ('perf_ring_capacity', '512');
|
|
61
|
+
INSERT OR IGNORE INTO kevin_settings (key, value) VALUES ('perf_flush_on_idle', '1');
|
|
62
|
+
INSERT OR IGNORE INTO kevin_settings (key, value) VALUES ('contract_report_enabled', '1');
|
|
63
|
+
|
|
64
|
+
-- 5. `dispose` becomes the seventh instrumented hook (v0.9.0 migration 010
|
|
65
|
+
-- seeded six rows; this is a data seed, not a schema change).
|
|
66
|
+
INSERT OR IGNORE INTO hook_liveness (hook) VALUES ('dispose');
|
|
67
|
+
|
|
68
|
+
-- 6. Schema version.
|
|
69
|
+
INSERT OR IGNORE INTO schema_version (version) VALUES ('011');
|
package/dist/plugin/Archiver.js
CHANGED
|
@@ -96,4 +96,3 @@ function formatSqliteUtc(d) {
|
|
|
96
96
|
const pad = (n) => String(n).padStart(2, "0");
|
|
97
97
|
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`;
|
|
98
98
|
}
|
|
99
|
-
//# sourceMappingURL=Archiver.js.map
|
|
@@ -35,18 +35,33 @@ export interface WritePlan {
|
|
|
35
35
|
readonly hashAfter: string;
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
* Rule 9 (
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
38
|
+
* Rule 9, layer (a) — superseded in v1.0.0 by `escapeForMarkerBlock`
|
|
39
|
+
* in `plugin/escape.ts` (K10-027), which carries the same idempotent
|
|
40
|
+
* entity discipline.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* v1.0.0 (K10-027 / plan §5.7) — the boundary functions now live in
|
|
44
|
+
* `plugin/escape.ts`; this composer applies them in fence-then-marker
|
|
45
|
+
* order. Layer (b) — strip any line containing `kevin:begin` or
|
|
46
|
+
* `kevin:end`, in any casing — is a filter rather than an escape and
|
|
47
|
+
* stays here. Without layer (b), a memory containing a literal
|
|
48
|
+
* `<!-- kevin:end -->` line would close the marker comment early and
|
|
49
|
+
* let subsequent content escape the curated region on the next
|
|
50
|
+
* regeneration — a marker-injection variant of the v0.1.5
|
|
51
|
+
* prompt-injection defect (plan §3.5). The trailing `-->` strip is kept
|
|
52
|
+
* as defence in depth although `escapeForMarkerBlock` already escapes
|
|
53
|
+
* every `>` that could form one.
|
|
48
54
|
*/
|
|
49
55
|
export declare function sanitizeArtifactBody(body: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* v1.0.0 (K10-027 / plan §5.7, rule 2) — whole-file writes escape by
|
|
58
|
+
* container. Only `.okf` files are line-oriented JSON: each line gets
|
|
59
|
+
* `escapeForOkfLine`, which is the identity on a well-formed OKF line
|
|
60
|
+
* (canonical JSON never contains raw control characters) and therefore
|
|
61
|
+
* preserves the re-render `noop`. Kevin-owned markdown paths keep their
|
|
62
|
+
* bytes — fences there are legitimate content.
|
|
63
|
+
*/
|
|
64
|
+
export declare function escapeForContainer(path: string, content: string): string;
|
|
50
65
|
/**
|
|
51
66
|
* v0.6.0 (K6-005 / plan §5.1) — the single write path to disk (D6-01).
|
|
52
67
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { closeSync, fsyncSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from "node:fs";
|
|
3
3
|
import { unifiedDiff } from "./diff.js";
|
|
4
|
+
import { escapeForFence, escapeForMarkerBlock, escapeForOkfLine, } from "./escape.js";
|
|
4
5
|
import { uuidv7 } from "./uuid.js";
|
|
5
6
|
// v0.6.0 (K6-005 / plan §5.1, D6-02) — the frozen marker contract. The exact
|
|
6
7
|
// byte sequences are load-bearing: README, v1.0.0 plan C-01 and the round-trip
|
|
@@ -30,39 +31,55 @@ function normalizeEol(body, eol) {
|
|
|
30
31
|
return body.replace(/\r\n/g, "\n").replace(/\n/g, eol);
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
|
-
* Rule 9, layer (a) —
|
|
34
|
-
*
|
|
35
|
-
* entity
|
|
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).
|
|
34
|
+
* Rule 9, layer (a) — superseded in v1.0.0 by `escapeForMarkerBlock`
|
|
35
|
+
* in `plugin/escape.ts` (K10-027), which carries the same idempotent
|
|
36
|
+
* entity discipline.
|
|
39
37
|
*/
|
|
40
|
-
function escapeIdempotent(text) {
|
|
41
|
-
return text
|
|
42
|
-
.replace(/&(?!(amp|lt|gt|#\d+);)/g, "&")
|
|
43
|
-
.replace(/</g, "<")
|
|
44
|
-
.replace(/>/g, ">");
|
|
45
|
-
}
|
|
46
38
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
39
|
+
* v1.0.0 (K10-027 / plan §5.7) — the boundary functions now live in
|
|
40
|
+
* `plugin/escape.ts`; this composer applies them in fence-then-marker
|
|
41
|
+
* order. Layer (b) — strip any line containing `kevin:begin` or
|
|
42
|
+
* `kevin:end`, in any casing — is a filter rather than an escape and
|
|
43
|
+
* stays here. Without layer (b), a memory containing a literal
|
|
44
|
+
* `<!-- kevin:end -->` line would close the marker comment early and
|
|
45
|
+
* let subsequent content escape the curated region on the next
|
|
46
|
+
* regeneration — a marker-injection variant of the v0.1.5
|
|
47
|
+
* prompt-injection defect (plan §3.5). The trailing `-->` strip is kept
|
|
48
|
+
* as defence in depth although `escapeForMarkerBlock` already escapes
|
|
49
|
+
* every `>` that could form one.
|
|
57
50
|
*/
|
|
58
51
|
export function sanitizeArtifactBody(body) {
|
|
59
|
-
const escaped =
|
|
52
|
+
const escaped = escapeForMarkerBlock(escapeForFence(body));
|
|
60
53
|
const kept = escaped
|
|
61
54
|
.split("\n")
|
|
62
55
|
.filter((line) => !/kevin:begin|kevin:end/i.test(line))
|
|
63
56
|
.join("\n");
|
|
64
57
|
return kept.replace(/-->/g, "");
|
|
65
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* v1.0.0 (K10-027 / plan §5.7, rule 2) — whole-file writes escape by
|
|
61
|
+
* container. Only `.okf` files are line-oriented JSON: each line gets
|
|
62
|
+
* `escapeForOkfLine`, which is the identity on a well-formed OKF line
|
|
63
|
+
* (canonical JSON never contains raw control characters) and therefore
|
|
64
|
+
* preserves the re-render `noop`. Kevin-owned markdown paths keep their
|
|
65
|
+
* bytes — fences there are legitimate content.
|
|
66
|
+
*/
|
|
67
|
+
export function escapeForContainer(path, content) {
|
|
68
|
+
if (!path.endsWith(".okf"))
|
|
69
|
+
return content;
|
|
70
|
+
return content
|
|
71
|
+
.split("\n")
|
|
72
|
+
.map((line) => {
|
|
73
|
+
// A CRLF file (healHeader preserves the original EOL) leaves a
|
|
74
|
+
// trailing \r on each line after the split — it is line-ending
|
|
75
|
+
// bytes, not statement content, so it must survive untouched.
|
|
76
|
+
if (line.endsWith("\r")) {
|
|
77
|
+
return `${escapeForOkfLine(line.slice(0, -1))}\r`;
|
|
78
|
+
}
|
|
79
|
+
return escapeForOkfLine(line);
|
|
80
|
+
})
|
|
81
|
+
.join("\n");
|
|
82
|
+
}
|
|
66
83
|
/**
|
|
67
84
|
* v0.6.0 (K6-005 / plan §5.1) — the single write path to disk (D6-01).
|
|
68
85
|
*
|
|
@@ -113,7 +130,9 @@ export class ArtifactWriter {
|
|
|
113
130
|
// like any other refusal: after = before, both hashes recorded.
|
|
114
131
|
const refusal = request.refusal;
|
|
115
132
|
const refused = refusal !== undefined;
|
|
116
|
-
|
|
133
|
+
// K10-027 — the container boundary: OKF lines are escaped at the
|
|
134
|
+
// single write path, never by callers.
|
|
135
|
+
const after = refused ? before : escapeForContainer(path, content);
|
|
117
136
|
return {
|
|
118
137
|
path,
|
|
119
138
|
before,
|
|
@@ -270,4 +289,3 @@ export class ArtifactWriter {
|
|
|
270
289
|
.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);
|
|
271
290
|
}
|
|
272
291
|
}
|
|
273
|
-
//# sourceMappingURL=ArtifactWriter.js.map
|
package/dist/plugin/Curator.js
CHANGED
package/dist/plugin/Feedback.js
CHANGED
|
@@ -68,6 +68,12 @@ export declare class HookLiveness {
|
|
|
68
68
|
/** Persists every counter row. Called on the metrics.flush() cadence. */
|
|
69
69
|
flush(): void;
|
|
70
70
|
private makeWrapper;
|
|
71
|
+
/**
|
|
72
|
+
* v1.0.0 (K10-013 / plan §5.3) — records the `dispose` fire and
|
|
73
|
+
* flushes immediately, from inside the dispose delegate: this is the
|
|
74
|
+
* last write of the process, and nothing after it can persist.
|
|
75
|
+
*/
|
|
76
|
+
recordDispose(): void;
|
|
71
77
|
private recordSuccess;
|
|
72
78
|
private recordError;
|
|
73
79
|
private loadFromDb;
|
|
@@ -212,6 +212,12 @@ export class HookLiveness {
|
|
|
212
212
|
}
|
|
213
213
|
makeWrapper(key, delegate) {
|
|
214
214
|
const record = () => {
|
|
215
|
+
// v1.0.0 (K10-013) — dispose is recorded inside its own delegate
|
|
216
|
+
// (via recordDispose()) rather than here: the wrapper's post-return
|
|
217
|
+
// record would land after the store is closed and could never be
|
|
218
|
+
// persisted — the event being detected is the process ending.
|
|
219
|
+
if (key === "dispose")
|
|
220
|
+
return;
|
|
215
221
|
if (HOOK_NAMES.includes(key)) {
|
|
216
222
|
this.recordSuccess(key);
|
|
217
223
|
}
|
|
@@ -258,6 +264,15 @@ export class HookLiveness {
|
|
|
258
264
|
}
|
|
259
265
|
};
|
|
260
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* v1.0.0 (K10-013 / plan §5.3) — records the `dispose` fire and
|
|
269
|
+
* flushes immediately, from inside the dispose delegate: this is the
|
|
270
|
+
* last write of the process, and nothing after it can persist.
|
|
271
|
+
*/
|
|
272
|
+
recordDispose() {
|
|
273
|
+
this.recordSuccess("dispose");
|
|
274
|
+
this.flush();
|
|
275
|
+
}
|
|
261
276
|
recordSuccess(hook) {
|
|
262
277
|
const c = this.counters.get(hook);
|
|
263
278
|
if (!c)
|
|
@@ -321,4 +336,3 @@ export function reduceVerdict(reports) {
|
|
|
321
336
|
reason: `${pending} hook(s) without checkpoint`,
|
|
322
337
|
};
|
|
323
338
|
}
|
|
324
|
-
//# sourceMappingURL=HookLiveness.js.map
|
package/dist/plugin/Migrate.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface MigrateResult {
|
|
|
5
5
|
applied: string[];
|
|
6
6
|
}
|
|
7
7
|
export type PostApplyHook = (store: Store) => void;
|
|
8
|
-
export declare const HOOK_NAMES: readonly ["tool.execute.before", "tool.execute.after", "chat.message", "experimental.chat.system.transform", "experimental.session.compacting", "event"];
|
|
8
|
+
export declare const HOOK_NAMES: readonly ["tool.execute.before", "tool.execute.after", "chat.message", "experimental.chat.system.transform", "experimental.session.compacting", "event", "dispose"];
|
|
9
9
|
export declare class Migrate {
|
|
10
10
|
private store;
|
|
11
11
|
private migrationsDir;
|
package/dist/plugin/Migrate.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { readFileSync, readdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
// v0.9.0 (K9-001 / plan §5.3, D9-08) — the six hooks Kevin registers, in
|
|
4
|
-
// hook-object order
|
|
4
|
+
// hook-object order, plus `dispose` (v1.0.0 K10-013): the seventh
|
|
5
|
+
// instrumented hook. Canonical list: the "010" post-apply hook seeds
|
|
5
6
|
// hook_liveness from it, and HookLiveness (K9-009) wraps exactly these
|
|
6
7
|
// names, so a future hook added here is visible in the table on the next
|
|
7
8
|
// migration run.
|
|
@@ -12,6 +13,7 @@ export const HOOK_NAMES = [
|
|
|
12
13
|
"experimental.chat.system.transform",
|
|
13
14
|
"experimental.session.compacting",
|
|
14
15
|
"event",
|
|
16
|
+
"dispose",
|
|
15
17
|
];
|
|
16
18
|
// Built-in post-apply hooks, keyed by migration version. Each hook runs inside
|
|
17
19
|
// the same transaction as the migration's DDL, so a hook failure rolls back the
|
|
@@ -163,6 +165,24 @@ const DEFAULT_POST_APPLY_HOOKS = {
|
|
|
163
165
|
.prepare("UPDATE hook_liveness SET experimental = CASE WHEN hook LIKE 'experimental.%' THEN 1 ELSE 0 END")
|
|
164
166
|
.run();
|
|
165
167
|
},
|
|
168
|
+
// v1.0.0 (K10-005 / plan §6.1) — Proven: four operations, all idempotent.
|
|
169
|
+
// 1. Seed dispose row defensively.
|
|
170
|
+
// 2-3. Re-derive perf_budget_breaches and bench_runs_total.
|
|
171
|
+
// 4. Normalise NULL within_budget to 1.
|
|
172
|
+
"011": (store) => {
|
|
173
|
+
store
|
|
174
|
+
.prepare("INSERT OR IGNORE INTO hook_liveness (hook) VALUES ('dispose')")
|
|
175
|
+
.run();
|
|
176
|
+
store
|
|
177
|
+
.prepare("UPDATE kevin_metrics SET value = (SELECT COUNT(*) FROM perf_samples WHERE within_budget = 0) WHERE key = 'perf_budget_breaches'")
|
|
178
|
+
.run();
|
|
179
|
+
store
|
|
180
|
+
.prepare("UPDATE kevin_metrics SET value = (SELECT COUNT(*) FROM bench_runs) WHERE key = 'bench_runs_total'")
|
|
181
|
+
.run();
|
|
182
|
+
store
|
|
183
|
+
.prepare("UPDATE perf_samples SET within_budget = 1 WHERE within_budget IS NULL")
|
|
184
|
+
.run();
|
|
185
|
+
},
|
|
166
186
|
};
|
|
167
187
|
export class Migrate {
|
|
168
188
|
store;
|
|
@@ -200,7 +220,10 @@ export class Migrate {
|
|
|
200
220
|
// updates and re-derivation, so a no-op startup can heal a
|
|
201
221
|
// crash that landed between the DDL and the hook without
|
|
202
222
|
// re-applying DDL.
|
|
203
|
-
if (from === "008" ||
|
|
223
|
+
if (from === "008" ||
|
|
224
|
+
from === "009" ||
|
|
225
|
+
from === "010" ||
|
|
226
|
+
from === "011") {
|
|
204
227
|
const repairHook = this.postApplyHooks.get(from);
|
|
205
228
|
if (repairHook)
|
|
206
229
|
this.store.transaction(() => repairHook(this.store));
|
|
@@ -241,4 +264,3 @@ export class Migrate {
|
|
|
241
264
|
.filter((m) => m !== null && m.version > current);
|
|
242
265
|
}
|
|
243
266
|
}
|
|
244
|
-
//# sourceMappingURL=Migrate.js.map
|
package/dist/plugin/Reflector.js
CHANGED
package/dist/plugin/RepoTruth.js
CHANGED
|
@@ -67,6 +67,13 @@ export const METRIC_KEY_LABELS = {
|
|
|
67
67
|
injections_suppressed_dead_hook: "Inyecciones suprimidas (hook muerto)",
|
|
68
68
|
native_registrations_total: "Registros nativos (totales)",
|
|
69
69
|
native_registration_failures: "Fallos de registro nativo",
|
|
70
|
+
// v1.0.0 (K10-005 / plan §6) — the six keys seeded by migration 011 section 3.
|
|
71
|
+
perf_samples_recorded: "Muestras de rendimiento registradas",
|
|
72
|
+
perf_budget_breaches: "Brechas de presupuesto de rendimiento",
|
|
73
|
+
dispose_fires_total: "Disparos de dispose (totales)",
|
|
74
|
+
dispose_misses_total: "Misses de dispose",
|
|
75
|
+
contract_digest_changes: "Cambios de digest de contrato",
|
|
76
|
+
bench_runs_total: "Ejecuciones de benchmark (totales)",
|
|
70
77
|
};
|
|
71
78
|
function originLabel(origin) {
|
|
72
79
|
if (origin === "reflector")
|
|
@@ -200,4 +207,3 @@ export class Retrospective {
|
|
|
200
207
|
return lines.join("\n");
|
|
201
208
|
}
|
|
202
209
|
}
|
|
203
|
-
//# sourceMappingURL=Retrospective.js.map
|
package/dist/plugin/Store.js
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const CONTRACT_VERSION = 1;
|
|
2
|
+
export type Stability = "frozen" | "forward-only";
|
|
3
|
+
export interface ContractClause {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly stability: Stability;
|
|
7
|
+
readonly since: string;
|
|
8
|
+
readonly deprecated?: string;
|
|
9
|
+
readonly replacement?: string;
|
|
10
|
+
readonly value: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface PublicContract {
|
|
13
|
+
readonly contractVersion: number;
|
|
14
|
+
readonly clauses: readonly ContractClause[];
|
|
15
|
+
}
|
|
16
|
+
export interface ContractInput {
|
|
17
|
+
readonly packageName?: string;
|
|
18
|
+
readonly packageVersion?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const CONTRACT_TOOL_NAMES: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* v1.0.0 (K10-018/K10-019 / plan §5.6) — tools added AFTER the initial
|
|
23
|
+
* freeze, each carrying the `since` the deprecation policy requires. A
|
|
24
|
+
* 1.x addition without an entry here fails the contract test as
|
|
25
|
+
* added_bare.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CONTRACT_TOOL_ADDITIONS: readonly {
|
|
28
|
+
name: string;
|
|
29
|
+
since: string;
|
|
30
|
+
}[];
|
|
31
|
+
/**
|
|
32
|
+
* v1.0.0 (K10-027 / plan §5.7) — the C-09 boundary addition. Stored is
|
|
33
|
+
* not trusted: anything reaching an artifact or a prompt is escaped at
|
|
34
|
+
* the single write path, according to its container.
|
|
35
|
+
*/
|
|
36
|
+
export declare const BOUNDARY_INVARIANT = "untrusted-input escaping at the single write path";
|
|
37
|
+
export declare function describeContract(_input?: ContractInput): PublicContract;
|
|
38
|
+
export declare function contractDigest(c: PublicContract): string;
|
|
39
|
+
export type ContractDiffKind = "removed" | "changed" | "added_ok" | "added_bare";
|
|
40
|
+
export interface ContractDiff {
|
|
41
|
+
readonly clauseId: string;
|
|
42
|
+
readonly path: string;
|
|
43
|
+
readonly kind: ContractDiffKind;
|
|
44
|
+
readonly remedy: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function diffContract(golden: PublicContract, live: PublicContract): readonly ContractDiff[];
|