@jmtrin/opencode-kevin 0.1.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +108 -33
  2. package/dist/migrations/003_v02_signal.sql +58 -0
  3. package/dist/migrations/004_v03_knowledge.sql +138 -0
  4. package/dist/plugin/CausalChain.d.ts +11 -0
  5. package/dist/plugin/CausalChain.js +109 -0
  6. package/dist/plugin/CausalChain.js.map +1 -0
  7. package/dist/plugin/ContextInjector.d.ts +25 -1
  8. package/dist/plugin/ContextInjector.js +72 -15
  9. package/dist/plugin/ContextInjector.js.map +1 -1
  10. package/dist/plugin/MemoryService.d.ts +110 -3
  11. package/dist/plugin/MemoryService.js +432 -20
  12. package/dist/plugin/MemoryService.js.map +1 -1
  13. package/dist/plugin/Migrate.d.ts +4 -1
  14. package/dist/plugin/Migrate.js +40 -1
  15. package/dist/plugin/Migrate.js.map +1 -1
  16. package/dist/plugin/PatternMiner.d.ts +49 -0
  17. package/dist/plugin/PatternMiner.js +133 -0
  18. package/dist/plugin/PatternMiner.js.map +1 -0
  19. package/dist/plugin/Reflector.d.ts +45 -2
  20. package/dist/plugin/Reflector.js +134 -12
  21. package/dist/plugin/Reflector.js.map +1 -1
  22. package/dist/plugin/Retrospective.d.ts +4 -1
  23. package/dist/plugin/Retrospective.js +72 -5
  24. package/dist/plugin/Retrospective.js.map +1 -1
  25. package/dist/plugin/Store.d.ts +15 -0
  26. package/dist/plugin/Store.js +15 -0
  27. package/dist/plugin/Store.js.map +1 -1
  28. package/dist/plugin/ToolCallObserver.d.ts +4 -1
  29. package/dist/plugin/ToolCallObserver.js +39 -7
  30. package/dist/plugin/ToolCallObserver.js.map +1 -1
  31. package/dist/plugin/fingerprint.d.ts +27 -0
  32. package/dist/plugin/fingerprint.js +74 -0
  33. package/dist/plugin/fingerprint.js.map +1 -0
  34. package/dist/plugin/index.js +213 -15
  35. package/dist/plugin/index.js.map +1 -1
  36. package/dist/plugin/kevin_why.d.ts +19 -0
  37. package/dist/plugin/kevin_why.js +92 -0
  38. package/dist/plugin/kevin_why.js.map +1 -0
  39. package/dist/plugin/memory-format.d.ts +2 -0
  40. package/dist/plugin/memory-format.js +6 -3
  41. package/dist/plugin/memory-format.js.map +1 -1
  42. package/dist/plugin/metrics.d.ts +60 -0
  43. package/dist/plugin/metrics.js +162 -0
  44. package/dist/plugin/metrics.js.map +1 -0
  45. package/dist/plugin/okf-export.d.ts +3 -0
  46. package/dist/plugin/okf-export.js +86 -0
  47. package/dist/plugin/okf-export.js.map +1 -0
  48. package/dist/plugin/okf-import.d.ts +73 -0
  49. package/dist/plugin/okf-import.js +239 -0
  50. package/dist/plugin/okf-import.js.map +1 -0
  51. package/dist/plugin/redact.d.ts +1 -0
  52. package/dist/plugin/redact.js +7 -0
  53. package/dist/plugin/redact.js.map +1 -1
  54. package/migrations/003_v02_signal.sql +58 -0
  55. package/migrations/004_v03_knowledge.sql +138 -0
  56. package/package.json +48 -48
@@ -1,11 +1,47 @@
1
1
  import { readFileSync, readdirSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ // Built-in post-apply hooks, keyed by migration version. Each hook runs inside
4
+ // the same transaction as the migration's DDL, so a hook failure rolls back the
5
+ // whole migration. Hooks are only invoked when their version is being applied
6
+ // (i.e., not already present in schema_version).
7
+ const DEFAULT_POST_APPLY_HOOKS = {
8
+ // v0.2.0 Signal Quality: defensive backfill of memories.origin for legacy
9
+ // rows. The column is NOT NULL DEFAULT 'agent', so SQLite already populates
10
+ // pre-existing rows with 'agent' on ALTER TABLE. This hook is a belt-and-
11
+ // braces UPDATE that coerces any NULL/empty stragglers (which would only
12
+ // exist if a partial DB skipped the DEFAULT) back to 'agent'.
13
+ "003": (store) => {
14
+ store
15
+ .prepare("UPDATE memories SET origin = 'agent' WHERE origin IS NULL OR origin = ''")
16
+ .run();
17
+ },
18
+ // v0.3.0 Knowledge + Causality: backfill evidence_count and status for
19
+ // legacy rows. Columns have NOT NULL DEFAULT, so SQLite already populates
20
+ // pre-existing rows. This hook is belt-and-braces in case a partial DB
21
+ // skipped the defaults.
22
+ "004": (store) => {
23
+ store
24
+ .prepare("UPDATE memories SET evidence_count = 0 WHERE evidence_count IS NULL")
25
+ .run();
26
+ store
27
+ .prepare("UPDATE memories SET status = 'active' WHERE status IS NULL OR status = ''")
28
+ .run();
29
+ },
30
+ };
3
31
  export class Migrate {
4
32
  store;
5
33
  migrationsDir;
6
- constructor(store, migrationsDir) {
34
+ postApplyHooks;
35
+ constructor(store, migrationsDir, postApplyHooks) {
7
36
  this.store = store;
8
37
  this.migrationsDir = migrationsDir;
38
+ this.postApplyHooks = new Map(Object.entries({
39
+ ...DEFAULT_POST_APPLY_HOOKS,
40
+ ...(postApplyHooks ?? {}),
41
+ }));
42
+ }
43
+ registerPostApply(version, hook) {
44
+ this.postApplyHooks.set(version, hook);
9
45
  }
10
46
  async run() {
11
47
  this.store.exec(`CREATE TABLE IF NOT EXISTS schema_version (
@@ -25,6 +61,9 @@ export class Migrate {
25
61
  const sql = readFileSync(join(this.migrationsDir, migration.file), "utf8");
26
62
  this.store.transaction(() => {
27
63
  this.store.exec(sql);
64
+ const hook = this.postApplyHooks.get(migration.version);
65
+ if (hook)
66
+ hook(this.store);
28
67
  insertVersion.run(migration.version);
29
68
  });
30
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Migrate.js","sourceRoot":"","sources":["../../plugin/Migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,OAAO,OAAO;IAEV;IACA;IAFT,YACS,KAAY,EACZ,aAAqB;QADrB,UAAK,GAAL,KAAK,CAAO;QACZ,kBAAa,GAAb,aAAa,CAAQ;IAC3B,CAAC;IAEJ,KAAK,CAAC,GAAG;QACR,IAAI,CAAC,KAAK,CAAC,IAAI,CACd;;;UAGO,CACP,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK;aAC3B,OAAO,CACP,kEAAkE,CAClE;aACA,GAAG,EAAqC,CAAC;QAE3C,MAAM,IAAI,GAAG,UAAU,EAAE,OAAO,IAAI,KAAK,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAEvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACxC,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CACvC,2DAA2D,CAC3D,CAAC;QAEF,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,YAAY,CACvB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,IAAI,CAAC,EACxC,MAAM,CACN,CAAC;YACF,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;gBAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACrB,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;QACJ,CAAC;QAED,OAAO;YACN,IAAI;YACJ,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO;YACvC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;SACtC,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,OAAe;QAClC,IAAI,KAAK,GAAa,EAAE,CAAC;QACzB,IAAI,CAAC;YACJ,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC;QACX,CAAC;QACD,KAAK,CAAC,IAAI,EAAE,CAAC;QACb,OAAO,KAAK;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACrC,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACnD,CAAC,CAAC;aACD,MAAM,CACN,CAAC,CAAC,EAA0C,EAAE,CAC7C,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,GAAG,OAAO,CAClC,CAAC;IACJ,CAAC;CACD"}
1
+ {"version":3,"file":"Migrate.js","sourceRoot":"","sources":["../../plugin/Migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { MemoryService } from "./MemoryService.js";
2
+ import type { Store } from "./Store.js";
3
+ import type { Metrics } from "./metrics.js";
4
+ /**
5
+ * v0.2.0 PatternMiner (K2-021, plan §B6.10 / D2-08).
6
+ *
7
+ * Opt-in deterministic pattern miner. Reads recent `tool_calls` for a given
8
+ * project, groups consecutive ordered 2-grams of `(tool_name)` and 3-grams
9
+ * where the *middle* tool was a failure, and when a group reaches the
10
+ * threshold (default `N ≥ 5` distinct sessions), emits a single
11
+ * `type='pattern'`, `origin='pattern'` memory describing the pattern.
12
+ *
13
+ * Default OFF — must be enabled by setting `kevin_settings.patternminer_enabled`
14
+ * to `'1'`. Idempotent via SELECT-before-INSERT keyed on
15
+ * `(project_id, fingerprint, type='pattern', origin='pattern')`. Migration 003's
16
+ * partial UNIQUE index only covers `type='error' AND origin='reflector'`, so
17
+ * pattern memories cannot rely on a database uniqueness constraint — the
18
+ * SELECT check inside `mine()` is the single idempotency mechanism.
19
+ *
20
+ * NO LLM hop (D2-08). The emitted suggestion is a deterministic template built
21
+ * from the captured tool names.
22
+ */
23
+ export interface PatternMinerOptions {
24
+ /** Minimum distinct sessions a pattern must appear in before emission.
25
+ * Default 5 (D2-08). */
26
+ threshold?: number;
27
+ }
28
+ export declare class PatternMiner {
29
+ private readonly store;
30
+ private readonly memoryService;
31
+ private readonly metrics;
32
+ private readonly threshold;
33
+ constructor(store: Store, memoryService: MemoryService, metrics?: Metrics | null, options?: PatternMinerOptions);
34
+ /**
35
+ * Mine patterns observed in `tool_calls` for the given project. Returns the
36
+ * number of NEW `pattern` memories emitted this cycle.
37
+ *
38
+ * When the opt-in flag `kevin_settings.patternminer_enabled` is not set to
39
+ * `'1'` (default), this is a no-op and returns 0.
40
+ *
41
+ * When `projectId` is null/undefined, mines tool_calls whose `project_id`
42
+ * IS NULL (legacy / opt-out flow). When `projectId` is a string, mines
43
+ * tool_calls scoped to that project only.
44
+ */
45
+ mine(projectId?: string | null): number;
46
+ private isEnabled;
47
+ private fetchToolCalls;
48
+ private collectCandidates;
49
+ }
@@ -0,0 +1,133 @@
1
+ import { fingerprint as computeFingerprint } from "./fingerprint.js";
2
+ const DEFAULT_THRESHOLD = 5;
3
+ const SETTING_KEY = "patternminer_enabled";
4
+ export class PatternMiner {
5
+ store;
6
+ memoryService;
7
+ metrics;
8
+ threshold;
9
+ constructor(store, memoryService, metrics, options) {
10
+ this.store = store;
11
+ this.memoryService = memoryService;
12
+ this.metrics = metrics ?? null;
13
+ this.threshold = options?.threshold ?? DEFAULT_THRESHOLD;
14
+ }
15
+ /**
16
+ * Mine patterns observed in `tool_calls` for the given project. Returns the
17
+ * number of NEW `pattern` memories emitted this cycle.
18
+ *
19
+ * When the opt-in flag `kevin_settings.patternminer_enabled` is not set to
20
+ * `'1'` (default), this is a no-op and returns 0.
21
+ *
22
+ * When `projectId` is null/undefined, mines tool_calls whose `project_id`
23
+ * IS NULL (legacy / opt-out flow). When `projectId` is a string, mines
24
+ * tool_calls scoped to that project only.
25
+ */
26
+ mine(projectId) {
27
+ if (!this.isEnabled())
28
+ return 0;
29
+ const rows = this.fetchToolCalls(projectId ?? null);
30
+ if (rows.length === 0)
31
+ return 0;
32
+ const candidates = this.collectCandidates(rows);
33
+ if (candidates.length === 0)
34
+ return 0;
35
+ let emitted = 0;
36
+ for (const c of candidates) {
37
+ if (c.sessions.size < this.threshold)
38
+ continue;
39
+ const fp = computeFingerprint(c.content, projectId ?? undefined);
40
+ // Idempotency: migration 003's partial unique only covers
41
+ // (type='error', origin='reflector'). For pattern memories we
42
+ // SELECT to detect a prior emission with the same
43
+ // (project_id, fingerprint, type='pattern', origin='pattern').
44
+ const existing = this.store
45
+ .prepare(`SELECT id FROM memories
46
+ WHERE type = 'pattern' AND origin = 'pattern'
47
+ AND fingerprint = ?
48
+ AND (project_id IS ? OR (project_id IS NULL AND ? IS NULL))
49
+ LIMIT 1`)
50
+ .get(fp, projectId ?? null, projectId ?? null);
51
+ if (existing)
52
+ continue;
53
+ this.memoryService.save({
54
+ type: "pattern",
55
+ origin: "pattern",
56
+ fingerprint: fp,
57
+ content: c.content,
58
+ scope: "project",
59
+ projectId: projectId ?? undefined,
60
+ relevanceScore: 0.5,
61
+ sourceTool: "PatternMiner",
62
+ });
63
+ this.metrics?.incr("patterns_mined", 1);
64
+ emitted += 1;
65
+ }
66
+ return emitted;
67
+ }
68
+ isEnabled() {
69
+ const row = this.store
70
+ .prepare("SELECT value FROM kevin_settings WHERE key = ?")
71
+ .get(SETTING_KEY);
72
+ return row?.value === "1";
73
+ }
74
+ fetchToolCalls(projectId) {
75
+ const nullPid = projectId === null || projectId === undefined;
76
+ const sql = nullPid
77
+ ? `SELECT id, session_id, ts, tool, success FROM tool_calls
78
+ WHERE project_id IS NULL
79
+ ORDER BY session_id ASC, ts ASC`
80
+ : `SELECT id, session_id, ts, tool, success FROM tool_calls
81
+ WHERE project_id = ?
82
+ ORDER BY session_id ASC, ts ASC`;
83
+ const stmt = this.store.prepare(sql);
84
+ const rows = (nullPid ? stmt.all() : stmt.all(projectId));
85
+ return rows;
86
+ }
87
+ collectCandidates(rows) {
88
+ // Group rows by session_id preserving arrival order. The SQL already
89
+ // orders by (session_id ASC, ts ASC), so a sequential scan yields each
90
+ // session's tool_calls in execution order.
91
+ const bySession = new Map();
92
+ for (const r of rows) {
93
+ let list = bySession.get(r.session_id);
94
+ if (!list) {
95
+ list = [];
96
+ bySession.set(r.session_id, list);
97
+ }
98
+ list.push(r);
99
+ }
100
+ // 2-grams: ordered pair (a, b) of consecutive tool names per session.
101
+ // 3-grams: ordered triple (a, b, c) where the middle tool b failed
102
+ // (success = 0). These capture the "X→Y fails then Z" lifecycle that
103
+ // the plan §B6.10 calls out.
104
+ const map = new Map();
105
+ const record = (key, content, sessionId) => {
106
+ let cand = map.get(key);
107
+ if (!cand) {
108
+ cand = { key, content, sessions: new Set() };
109
+ map.set(key, cand);
110
+ }
111
+ cand.sessions.add(sessionId);
112
+ };
113
+ for (const [sessionId, list] of bySession) {
114
+ for (let i = 0; i < list.length - 1; i++) {
115
+ const a = list[i];
116
+ const b = list[i + 1];
117
+ const key2 = `2g::${a.tool}::${b.tool}`;
118
+ const content2 = `Pattern: tool "${a.tool}" followed by tool "${b.tool}". Review the ${a.tool}→${b.tool} contract before retrying.`;
119
+ record(key2, content2, sessionId);
120
+ if (i + 2 < list.length) {
121
+ const c = list[i + 2];
122
+ if (b.success === 0) {
123
+ const key3 = `3g::${a.tool}::${b.tool}::${c.tool}`;
124
+ const content3 = `Pattern: tool "${a.tool}" followed by failing tool "${b.tool}" then tool "${c.tool}". Review the ${a.tool}→${b.tool}(failed)→${c.tool} contract before retrying.`;
125
+ record(key3, content3, sessionId);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ return Array.from(map.values());
131
+ }
132
+ }
133
+ //# sourceMappingURL=PatternMiner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PatternMiner.js","sourceRoot":"","sources":["../../plugin/PatternMiner.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { MemoryService } from "./MemoryService.js";
2
+ import type { Metrics } from "./metrics.js";
2
3
  export interface ReflectionInput {
3
4
  toolName: string;
4
5
  argsSummary: string;
@@ -7,24 +8,66 @@ export interface ReflectionInput {
7
8
  exitCode?: number;
8
9
  errorType: string;
9
10
  sessionId: string;
11
+ /** Optional project scope for v0.2.0 dedup + per-fingerprint throttle. */
12
+ projectId?: string | null;
13
+ /** v0.3.0 fix — callID of the failing tool_call. Used by onLinkError
14
+ * (see ReflectorOptions) to stamp tool_calls.error_fingerprint so the
15
+ * feedback loop can match recurrences by the SAME identity dimension
16
+ * the error memory uses. */
17
+ callID?: string;
10
18
  }
11
19
  export interface ReflectorOptions {
12
20
  throttleMs?: number;
21
+ /** v0.3.0 (K3-018) — optional LLM enrichment callback. Default no-op. */
22
+ enrich?: (lesson: string, stderr: string, stdout: string) => Promise<string | null>;
23
+ /** v0.3.0 fix — link a failing tool_call to the stderr-based fingerprint
24
+ * the matching error memory uses. Default no-op. The caller (index.ts)
25
+ * provides an implementation that UPDATEs tool_calls.error_fingerprint
26
+ * for the given callID, so boost/penalize feedback queries stop missing
27
+ * recurrences by fingerprint mismatch. */
28
+ onLinkError?: (callID: string, fingerprint: string) => void;
13
29
  }
14
30
  export interface HeuristicLessonInput {
15
31
  toolName: string;
16
32
  errorType: string;
17
33
  firstErrorLine: string;
34
+ /** v0.2.0 (K2-018) — optional pre-computed dispatch result. When absent,
35
+ * dispatch is performed on `firstErrorLine` alone. */
36
+ dispatched?: DispatchedLesson | null;
37
+ }
38
+ /** Result of the per-error-code deterministic rule dispatch (K2-018 / D2-09). */
39
+ export interface DispatchedLesson {
40
+ /** Stable short code captured from the source output (e.g. `TS2304`,
41
+ * `EADDRINUSE`, `F401`, the captured `Error: <Name>` class, the failing
42
+ * command string). `null` when no rule matches (fallback path). */
43
+ code: string | null;
44
+ /** Short deterministic hint, e.g. `import or typo`, `review syscall:
45
+ * EADDRINUSE`. `null` when `code` is null (the v0.1.x fallback path). */
46
+ hint: string | null;
18
47
  }
19
48
  export declare const ERROR_LINE_RE: RegExp;
20
49
  export declare const STRONG_ERROR_RE: RegExp;
50
+ export declare const TS_CODE_RULES: Record<string, string>;
21
51
  export declare class Reflector {
22
52
  private memoryService;
23
- private lastReflectionTs;
53
+ private lastReflectionByFp;
24
54
  private throttleMs;
25
- constructor(memoryService: MemoryService, options?: ReflectorOptions);
55
+ private metrics;
56
+ private enrichFn;
57
+ private onLinkErrorFn;
58
+ constructor(memoryService: MemoryService, options?: ReflectorOptions, metrics?: Metrics | null);
26
59
  invoke(input: ReflectionInput): Promise<string | null>;
27
60
  generateHeuristicLesson(input: HeuristicLessonInput): string;
61
+ /**
62
+ * v0.2.0 (K2-018 / D2-09) — deterministic per-error-code rule dispatch.
63
+ * Pure regex sweep over `stderr + '\n' + stdout` with NO LLM hop. Returns
64
+ * a short stable `code` + `hint` pair when a known rule matches, or
65
+ * `{ code: null, hint: null }` for the v0.1.x fallback path (which keeps
66
+ * the v0.1.x `SUGGESTIONS[errorType]` suggestion verbatim).
67
+ *
68
+ * Exported for unit testing (K2-019).
69
+ */
70
+ dispatchLesson(stderr: string, stdout: string, errorType: string): DispatchedLesson;
28
71
  redactPaths(text: string): string;
29
72
  redactSecrets(text: string): string;
30
73
  private extractFirstErrorLine;
@@ -1,3 +1,4 @@
1
+ import { fingerprint as computeFingerprint } from "./fingerprint.js";
1
2
  import { redactPaths as redactPathsText } from "./redact.js";
2
3
  const DEFAULT_THROTTLE_MS = 60_000;
3
4
  const MAX_CONTENT_CHARS = 4096;
@@ -6,6 +7,12 @@ const TRUNC_SUFFIX = "... [truncated]";
6
7
  const CONTEXT_PREFIX = "\n\nContext:\n";
7
8
  export const ERROR_LINE_RE = /\b(error|failed|fail|cannot find|cannot resolve|TS\d{4,}|exception|traceback|panic|fatal|referenceerror|typeerror|syntaxerror|command failed|non-zero exit)\b/i;
8
9
  export const STRONG_ERROR_RE = /\b(cannot find|cannot resolve|TS\d{4,}|error TS\d|command failed|non-zero exit|exit code [1-9]\d*|traceback|referenceerror|typeerror|syntaxerror|fatal error|exception|failed to compile|build failed|compilation failed)\b/i;
10
+ /** v0.1.x fallback table — keyed by `errorType`. RETAINED in v0.2.0 as the
11
+ * fallback for memos whose output does not match a deterministic code rule.
12
+ * The v0.2.0 per-error-code rule table below layers ON TOP of this fallback:
13
+ * when a code is matched, the hint is appended to the v0.1.x suggestion as a
14
+ * 'Likely cause:' line; when no code is matched, output is identical to v0.1.x.
15
+ */
9
16
  const SUGGESTIONS = {
10
17
  typecheck: "Verify types and imports before running.",
11
18
  lint: "Run linter and fix warnings before committing.",
@@ -14,6 +21,25 @@ const SUGGESTIONS = {
14
21
  timeout: "Check for infinite loops or long-running operations.",
15
22
  unknown: "Review the error output for details.",
16
23
  };
24
+ // --- v0.2.0 (K2-018) lesson v2 — per-error-code deterministic dispatch (D2-09).
25
+ // Pure TS, NO LLM hop. Order of dispatch matches the plan §B6.4 priority list:
26
+ // (1) TS\d{4,5} > (2) Python lint > (3) syscall > (4) generic `Error: <Name>` >
27
+ // (5) `Command "<cmd>" failed` > (6) v0.1.x SUGGESTIONS fallback.
28
+ // v0.2.0 (K2-018) — shared per-error-code rule table. Exported so
29
+ // kevin_why.ts reuses the SAME hints instead of duplicating them
30
+ // (bug #6).
31
+ export const TS_CODE_RULES = {
32
+ "2304": "import or typo",
33
+ "2322": "type mismatch",
34
+ "2740": "missing or wrong property",
35
+ "2552": "undefined identifier",
36
+ "18047": "possibly null",
37
+ };
38
+ const TS_CODE_RE = /\bTS(\d{4,5})\b/;
39
+ const PY_LINT_RE = /\b(ELIF\d{0,4})\b|\b(F\d{3,4})\b|flake8:\s+(\S+)/;
40
+ const SYSCALL_RE = /\b(EADDRINUSE|ENOENT|EACCES|EPERM)\b/;
41
+ const GENERIC_ERROR_RE = /\bError:\s+(\w+)/;
42
+ const COMMAND_FAILED_RE = /Command\s+"([^"]+)"\s+failed/;
17
43
  const SECRET_PATTERNS = [
18
44
  /(API_KEY|SECRET|PASSWORD|TOKEN)\s*[=:]\s*\S+/gi,
19
45
  /\bBearer\s+\S+/gi,
@@ -23,18 +49,20 @@ const SECRET_VALUE_PATTERN = /\s*=\s*\S+(.*)$/;
23
49
  const PATH_PATTERNS_DEPRECATED = null;
24
50
  export class Reflector {
25
51
  memoryService;
26
- lastReflectionTs = 0;
52
+ lastReflectionByFp = new Map();
27
53
  throttleMs;
28
- constructor(memoryService, options) {
54
+ metrics;
55
+ enrichFn;
56
+ onLinkErrorFn;
57
+ constructor(memoryService, options, metrics) {
29
58
  this.memoryService = memoryService;
30
59
  this.throttleMs = options?.throttleMs ?? DEFAULT_THROTTLE_MS;
60
+ this.metrics = metrics ?? null;
61
+ this.enrichFn = options?.enrich ?? (async () => null);
62
+ this.onLinkErrorFn = options?.onLinkError ?? (() => { });
31
63
  }
32
64
  async invoke(input) {
33
65
  const now = Date.now();
34
- if (now - this.lastReflectionTs < this.throttleMs) {
35
- return null;
36
- }
37
- this.lastReflectionTs = now;
38
66
  const redactedStderr = this.redactSecrets(this.redactPaths(input.stderr));
39
67
  const redactedStdout = this.redactSecrets(this.redactPaths(input.stdout));
40
68
  const sourceOutput = redactedStderr.length > 0 ? redactedStderr : redactedStdout;
@@ -43,27 +71,60 @@ export class Reflector {
43
71
  toolName: input.toolName,
44
72
  errorType: input.errorType,
45
73
  firstErrorLine,
74
+ dispatched: this.dispatchLesson(redactedStderr, redactedStdout, input.errorType),
46
75
  });
76
+ // v0.3.0 fix (bug #5) — the per-fingerprint throttle check runs
77
+ // BEFORE the optional LLM enrichment, so throttled repeats never
78
+ // waste an LLM call. The fingerprint is computed from the source
79
+ // output when present, otherwise from the PRE-enrichment lesson,
80
+ // keeping the identity stable and identical to the saved memory's.
81
+ const projectId = input.projectId ?? null;
82
+ const fpContent = sourceOutput.length > 0 ? sourceOutput : lesson;
83
+ const fp = computeFingerprint(fpContent, projectId ?? undefined);
84
+ const last = this.lastReflectionByFp.get(fp) ?? 0;
85
+ if (now - last < this.throttleMs) {
86
+ this.metrics?.incr("reflections_throttled", 1);
87
+ return null;
88
+ }
89
+ this.lastReflectionByFp.set(fp, now);
90
+ // v0.3.0 (K3-018): optional LLM enrichment opt-in. Runs only when
91
+ // the throttle check passed (bug #5).
92
+ let enrichedLesson = lesson;
93
+ try {
94
+ const enrichment = await this.enrichFn(lesson, redactedStderr, redactedStdout);
95
+ if (enrichment) {
96
+ enrichedLesson = `${lesson}\n${enrichment}`;
97
+ }
98
+ }
99
+ catch {
100
+ // enrichment failures are non-blocking
101
+ }
47
102
  const metadata = {};
103
+ if (input.callID) {
104
+ metadata.origin_call_id = input.callID;
105
+ }
48
106
  let finalContent;
49
107
  if (sourceOutput.length > 0) {
50
- const fullLen = lesson.length + CONTEXT_PREFIX.length + sourceOutput.length;
108
+ const fullLen = enrichedLesson.length + CONTEXT_PREFIX.length + sourceOutput.length;
51
109
  if (fullLen <= MAX_CONTENT_CHARS) {
52
- finalContent = `${lesson}${CONTEXT_PREFIX}${sourceOutput}`;
110
+ finalContent = `${enrichedLesson}${CONTEXT_PREFIX}${sourceOutput}`;
53
111
  }
54
112
  else {
55
113
  const budget = MAX_CONTENT_CHARS -
56
- lesson.length -
114
+ enrichedLesson.length -
57
115
  CONTEXT_PREFIX.length -
58
116
  TRUNC_SUFFIX.length;
59
117
  const truncated = sourceOutput.slice(0, Math.max(0, budget));
60
- finalContent = `${lesson}${CONTEXT_PREFIX}${truncated}${TRUNC_SUFFIX}`;
118
+ finalContent = `${enrichedLesson}${CONTEXT_PREFIX}${truncated}${TRUNC_SUFFIX}`;
61
119
  metadata.truncated = true;
62
120
  }
63
121
  }
64
122
  else {
65
- finalContent = lesson;
123
+ finalContent = enrichedLesson;
66
124
  }
125
+ // K2-007: the per-fingerprint throttle check ran above (before
126
+ // enrichment); `fp` is reused here so dedup/throttle and the saved
127
+ // memory agree on identity.
67
128
  const id = this.memoryService.save({
68
129
  type: "error",
69
130
  content: finalContent,
@@ -71,15 +132,76 @@ export class Reflector {
71
132
  sourceTool: input.toolName,
72
133
  sourceSession: input.sessionId,
73
134
  metadata,
135
+ origin: "reflector",
136
+ projectId: projectId ?? undefined,
137
+ fingerprint: fp,
74
138
  });
139
+ // v0.3.0 fix — stamp the failing tool_call with the stderr-based
140
+ // fingerprint so the feedback loop's recurrence queries can match
141
+ // it (closes the fingerprint-mismatch bug). Fires even after the
142
+ // dedup path returned an existing memory id, since the current
143
+ // call IS a new occurrence of the same error.
144
+ if (input.callID && this.onLinkErrorFn) {
145
+ try {
146
+ this.onLinkErrorFn(input.callID, fp);
147
+ }
148
+ catch {
149
+ // linking failure is non-blocking
150
+ }
151
+ }
75
152
  return id;
76
153
  }
77
154
  generateHeuristicLesson(input) {
155
+ const dispatched = input.dispatched ??
156
+ this.dispatchLesson(input.firstErrorLine, "", input.errorType);
78
157
  const suggestion = SUGGESTIONS[input.errorType] ?? SUGGESTIONS.unknown;
79
158
  const line = input.firstErrorLine.length > MAX_ERROR_LINE_CHARS
80
159
  ? `${input.firstErrorLine.slice(0, MAX_ERROR_LINE_CHARS)}...`
81
160
  : input.firstErrorLine;
82
- return `When ${input.toolName} fails with ${input.errorType}: ${line}\nSuggestion: ${suggestion}`;
161
+ let lesson = `When ${input.toolName} fails with ${input.errorType}: ${line}\nSuggestion: ${suggestion}`;
162
+ if (dispatched.code && dispatched.hint) {
163
+ lesson += `\nLikely cause: ${dispatched.hint} (code ${dispatched.code})`;
164
+ }
165
+ return lesson;
166
+ }
167
+ /**
168
+ * v0.2.0 (K2-018 / D2-09) — deterministic per-error-code rule dispatch.
169
+ * Pure regex sweep over `stderr + '\n' + stdout` with NO LLM hop. Returns
170
+ * a short stable `code` + `hint` pair when a known rule matches, or
171
+ * `{ code: null, hint: null }` for the v0.1.x fallback path (which keeps
172
+ * the v0.1.x `SUGGESTIONS[errorType]` suggestion verbatim).
173
+ *
174
+ * Exported for unit testing (K2-019).
175
+ */
176
+ dispatchLesson(stderr, stdout, errorType) {
177
+ const combined = `${stderr}\n${stdout}`;
178
+ const tsMatch = combined.match(TS_CODE_RE);
179
+ if (tsMatch) {
180
+ const num = tsMatch[1];
181
+ const hint = TS_CODE_RULES[num] ?? `review TS${num}`;
182
+ return { code: `TS${num}`, hint };
183
+ }
184
+ const pyMatch = combined.match(PY_LINT_RE);
185
+ if (pyMatch) {
186
+ const rule = pyMatch[1] || pyMatch[2] || pyMatch[3] || "unknown";
187
+ return { code: rule, hint: `review python lint: ${rule}` };
188
+ }
189
+ const sysMatch = combined.match(SYSCALL_RE);
190
+ if (sysMatch) {
191
+ const code = sysMatch[1];
192
+ return { code, hint: `review syscall: ${code}` };
193
+ }
194
+ const errMatch = combined.match(GENERIC_ERROR_RE);
195
+ if (errMatch) {
196
+ const name = errMatch[1];
197
+ return { code: name, hint: `review error class: ${name}` };
198
+ }
199
+ const cmdMatch = combined.match(COMMAND_FAILED_RE);
200
+ if (cmdMatch) {
201
+ const cmd = cmdMatch[1];
202
+ return { code: cmd, hint: `review failing command: ${cmd}` };
203
+ }
204
+ return { code: null, hint: null };
83
205
  }
84
206
  redactPaths(text) {
85
207
  return redactPathsText(text);
@@ -1 +1 @@
1
- {"version":3,"file":"Reflector.js","sourceRoot":"","sources":["../../plugin/Reflector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Reflector.js","sourceRoot":"","sources":["../../plugin/Reflector.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { MemoryService } from "./MemoryService.js";
2
2
  import type { Store } from "./Store.js";
3
+ import type { Metrics } from "./metrics.js";
3
4
  export interface RetrospectiveOptions {
4
5
  dir?: string;
5
6
  }
@@ -7,7 +8,9 @@ export declare class Retrospective {
7
8
  private store;
8
9
  private memoryService;
9
10
  private retrospectivesDir;
10
- constructor(store: Store, memoryService: MemoryService, options?: RetrospectiveOptions);
11
+ private metrics;
12
+ constructor(store: Store, memoryService: MemoryService, options?: RetrospectiveOptions, metrics?: Metrics | null);
11
13
  generate(sessionId: string): Promise<string | null>;
14
+ private collectFalsePositives;
12
15
  private buildMarkdown;
13
16
  }