@jmtrin/kevin-core 1.4.0 → 2.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 +711 -667
- package/dist/ArtifactWriter.js +1 -1
- package/dist/InjectionLedger.js +112 -110
- package/dist/Materializer.d.ts +5 -0
- package/dist/Materializer.js +11 -0
- package/dist/MemoryService.js +93 -91
- package/dist/RepoIdentity.js +1 -1
- package/dist/Retrospective.js +8 -0
- package/dist/Store.d.ts +1 -0
- package/dist/Store.js +14 -2
- package/dist/contract.d.ts +58 -1
- package/dist/contract.js +215 -3
- package/dist/import-host.d.ts +41 -0
- package/dist/import-host.js +286 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +16 -1
- package/dist/kevin_audit.d.ts +16 -0
- package/dist/kevin_audit.js +37 -0
- package/dist/metrics.d.ts +1 -1
- package/dist/metrics.js +22 -0
- package/dist/mif.d.ts +32 -0
- package/dist/mif.js +112 -0
- package/dist/migrations/014_v2_commonwealth.sql +50 -0
- package/dist/okf-shards.d.ts +10 -0
- package/dist/okf-shards.js +103 -0
- package/dist/okf.d.ts +5 -1
- package/dist/okf.js +11 -3
- package/dist/skills-emit.d.ts +38 -0
- package/dist/skills-emit.js +421 -0
- package/dist/skills-validate.d.ts +7 -0
- package/dist/skills-validate.js +236 -0
- package/dist/sources/ClaudeMemorySource.d.ts +10 -0
- package/dist/sources/ClaudeMemorySource.js +36 -0
- package/dist/sources/CodexMemoriesSource.d.ts +10 -0
- package/dist/sources/CodexMemoriesSource.js +37 -0
- package/dist/sources/IdleSync.d.ts +10 -0
- package/dist/sources/IdleSync.js +49 -0
- package/dist/sources/MemorySource.d.ts +19 -0
- package/dist/sources/MemorySource.js +1 -0
- package/dist/sources/OpencodeNativeSource.d.ts +10 -0
- package/dist/sources/OpencodeNativeSource.js +33 -0
- package/dist/sources/OpencodePluginSource.d.ts +9 -0
- package/dist/sources/OpencodePluginSource.js +13 -0
- package/dist/sqlite-adapter.js +1 -1
- package/package.json +24 -26
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// K16-014 — ClaudeMemorySource (read-only mirror of ~/.claude/memory)
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
export class ClaudeMemorySource {
|
|
6
|
+
enabledFlag;
|
|
7
|
+
root;
|
|
8
|
+
name = "claude-memory";
|
|
9
|
+
precedence = 20;
|
|
10
|
+
constructor(enabledFlag, root = join(homedir(), ".claude")) {
|
|
11
|
+
this.enabledFlag = enabledFlag;
|
|
12
|
+
this.root = root;
|
|
13
|
+
}
|
|
14
|
+
enabled() { return this.enabledFlag(); }
|
|
15
|
+
async fetch() {
|
|
16
|
+
if (!this.enabled())
|
|
17
|
+
return [];
|
|
18
|
+
const memPath = join(this.root, "memory");
|
|
19
|
+
// Could be directory of markdown files or single file — best-effort
|
|
20
|
+
if (!existsSync(memPath))
|
|
21
|
+
return [];
|
|
22
|
+
try {
|
|
23
|
+
const txt = readFileSync(memPath, "utf8");
|
|
24
|
+
// naive: split lines non-empty as statements
|
|
25
|
+
return txt.split("\n").map(s => s.trim()).filter(Boolean).slice(0, 100).map(statement => ({
|
|
26
|
+
statement,
|
|
27
|
+
type: "rule",
|
|
28
|
+
scope: null,
|
|
29
|
+
source: this.name,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MemorySource, SourceEntry } from "./MemorySource.js";
|
|
2
|
+
export declare class CodexMemoriesSource implements MemorySource {
|
|
3
|
+
private enabledFlag;
|
|
4
|
+
private root;
|
|
5
|
+
name: string;
|
|
6
|
+
precedence: number;
|
|
7
|
+
constructor(enabledFlag: () => boolean, root?: string);
|
|
8
|
+
enabled(): boolean;
|
|
9
|
+
fetch(): Promise<SourceEntry[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// K16-015 — CodexMemoriesSource (mirror of ~/.codex/memories)
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
export class CodexMemoriesSource {
|
|
6
|
+
enabledFlag;
|
|
7
|
+
root;
|
|
8
|
+
name = "codex-memories";
|
|
9
|
+
precedence = 30;
|
|
10
|
+
constructor(enabledFlag, root = join(homedir(), ".codex", "memories")) {
|
|
11
|
+
this.enabledFlag = enabledFlag;
|
|
12
|
+
this.root = root;
|
|
13
|
+
}
|
|
14
|
+
enabled() { return this.enabledFlag(); }
|
|
15
|
+
async fetch() {
|
|
16
|
+
if (!this.enabled())
|
|
17
|
+
return [];
|
|
18
|
+
if (!existsSync(this.root))
|
|
19
|
+
return [];
|
|
20
|
+
const out = [];
|
|
21
|
+
try {
|
|
22
|
+
for (const f of readdirSync(this.root)) {
|
|
23
|
+
if (!f.endsWith(".md") && !f.endsWith(".txt"))
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
const txt = readFileSync(join(this.root, f), "utf8");
|
|
27
|
+
for (const line of txt.split("\n").map(s => s.trim()).filter(Boolean).slice(0, 50)) {
|
|
28
|
+
out.push({ statement: line, type: "rule", scope: null, source: this.name });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch { }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch { }
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Store } from "../Store.js";
|
|
2
|
+
import type { MemorySource, SourceSyncResult } from "./MemorySource.js";
|
|
3
|
+
export interface SyncDeps {
|
|
4
|
+
store: Store;
|
|
5
|
+
sources: MemorySource[];
|
|
6
|
+
metrics?: {
|
|
7
|
+
incr(key: string, by?: number): void;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare function idleSync(deps: SyncDeps): Promise<SourceSyncResult[]>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { fingerprint } from "../fingerprint.js";
|
|
2
|
+
function dedupKey(e) {
|
|
3
|
+
// lower precedence wins attribution: fingerprint over normalized statement + scope
|
|
4
|
+
return fingerprint(`${e.type}\0${e.statement}\0${e.scope ?? ""}`);
|
|
5
|
+
}
|
|
6
|
+
export async function idleSync(deps) {
|
|
7
|
+
const results = [];
|
|
8
|
+
const seen = new Set();
|
|
9
|
+
// Pre-populate dedup with existing memories fingerprints (lowest precedence already wins)
|
|
10
|
+
try {
|
|
11
|
+
const rows = deps.store.prepare("SELECT fingerprint FROM memories").all();
|
|
12
|
+
for (const r of rows)
|
|
13
|
+
if (r.fingerprint)
|
|
14
|
+
seen.add(r.fingerprint);
|
|
15
|
+
}
|
|
16
|
+
catch { }
|
|
17
|
+
for (const src of deps.sources.sort((a, b) => a.precedence - b.precedence)) {
|
|
18
|
+
if (!src.enabled()) {
|
|
19
|
+
results.push({ source: src.name, fetched: 0, dedupSkipped: 0, inserted: 0 });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const entries = await src.fetch().catch(() => []);
|
|
23
|
+
let dedupSkipped = 0;
|
|
24
|
+
let inserted = 0;
|
|
25
|
+
for (const e of entries) {
|
|
26
|
+
const fp = dedupKey(e);
|
|
27
|
+
if (seen.has(fp)) {
|
|
28
|
+
dedupSkipped++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
seen.add(fp);
|
|
32
|
+
// Insert as memory with source provenance (simplified)
|
|
33
|
+
try {
|
|
34
|
+
deps.store.prepare(`INSERT OR IGNORE INTO memories (id, project_id, type, content, scope, fingerprint, confidence, origin, source, created_at)
|
|
35
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`).run(`src-${fp.slice(0, 12)}-${src.name}`, "default", e.type, e.statement, e.scope, fp, 0.5, src.name, src.name);
|
|
36
|
+
inserted++;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
dedupSkipped++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (dedupSkipped > 0)
|
|
43
|
+
deps.metrics?.incr("source_dedup_skips_total", dedupSkipped);
|
|
44
|
+
if (inserted > 0)
|
|
45
|
+
deps.metrics?.incr("source_syncs_total", 1);
|
|
46
|
+
results.push({ source: src.name, fetched: entries.length, dedupSkipped, inserted });
|
|
47
|
+
}
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface MemorySource {
|
|
2
|
+
name: string;
|
|
3
|
+
precedence: number;
|
|
4
|
+
enabled(): boolean;
|
|
5
|
+
fetch(): Promise<SourceEntry[]>;
|
|
6
|
+
}
|
|
7
|
+
export interface SourceEntry {
|
|
8
|
+
statement: string;
|
|
9
|
+
type: "decision" | "rule" | "pattern" | "solution";
|
|
10
|
+
scope: string | null;
|
|
11
|
+
source: string;
|
|
12
|
+
updatedAt?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SourceSyncResult {
|
|
15
|
+
source: string;
|
|
16
|
+
fetched: number;
|
|
17
|
+
dedupSkipped: number;
|
|
18
|
+
inserted: number;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MemorySource, SourceEntry } from "./MemorySource.js";
|
|
2
|
+
export declare class OpencodeNativeSource implements MemorySource {
|
|
3
|
+
private enabledFlag;
|
|
4
|
+
private projectRoot;
|
|
5
|
+
name: string;
|
|
6
|
+
precedence: number;
|
|
7
|
+
constructor(enabledFlag: () => boolean, projectRoot?: string);
|
|
8
|
+
enabled(): boolean;
|
|
9
|
+
fetch(): Promise<SourceEntry[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// K16-016 — OpencodeNativeSource (native opencode memories, e.g. .opencode/memory)
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export class OpencodeNativeSource {
|
|
5
|
+
enabledFlag;
|
|
6
|
+
projectRoot;
|
|
7
|
+
name = "opencode-native";
|
|
8
|
+
precedence = 40;
|
|
9
|
+
constructor(enabledFlag, projectRoot = process.cwd()) {
|
|
10
|
+
this.enabledFlag = enabledFlag;
|
|
11
|
+
this.projectRoot = projectRoot;
|
|
12
|
+
}
|
|
13
|
+
enabled() { return this.enabledFlag(); }
|
|
14
|
+
async fetch() {
|
|
15
|
+
if (!this.enabled())
|
|
16
|
+
return [];
|
|
17
|
+
const p = join(this.projectRoot, ".opencode", "memory");
|
|
18
|
+
if (!existsSync(p))
|
|
19
|
+
return [];
|
|
20
|
+
try {
|
|
21
|
+
const txt = readFileSync(p, "utf8");
|
|
22
|
+
return txt.split("\n").map(s => s.trim()).filter(Boolean).slice(0, 100).map(statement => ({
|
|
23
|
+
statement,
|
|
24
|
+
type: "rule",
|
|
25
|
+
scope: null,
|
|
26
|
+
source: this.name,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MemorySource, SourceEntry } from "./MemorySource.js";
|
|
2
|
+
export declare class OpencodePluginSource implements MemorySource {
|
|
3
|
+
private enabledFlag;
|
|
4
|
+
name: string;
|
|
5
|
+
precedence: number;
|
|
6
|
+
constructor(enabledFlag: () => boolean);
|
|
7
|
+
enabled(): boolean;
|
|
8
|
+
fetch(): Promise<SourceEntry[]>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class OpencodePluginSource {
|
|
2
|
+
enabledFlag;
|
|
3
|
+
name = "opencode-plugin";
|
|
4
|
+
precedence = 10;
|
|
5
|
+
constructor(enabledFlag) {
|
|
6
|
+
this.enabledFlag = enabledFlag;
|
|
7
|
+
}
|
|
8
|
+
enabled() { return this.enabledFlag(); }
|
|
9
|
+
async fetch() {
|
|
10
|
+
// Plugin source is the local DB itself — no fetch, handled elsewhere
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/sqlite-adapter.js
CHANGED
package/package.json
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
"license": "MIT"
|
|
2
|
+
"name": "@jmtrin/kevin-core",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Kevin core — host-agnostic deterministic brain (Bedrock)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.json && node ./scripts/copy-migrations.mjs",
|
|
17
|
+
"typecheck": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.5.0"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"license": "MIT"
|
|
28
26
|
}
|