@djolex999/vir-cli 0.24.3 → 0.25.1

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 (52) hide show
  1. package/README.md +30 -1
  2. package/dist/claude/updater.js +83 -7
  3. package/dist/claude/updater.js.map +1 -1
  4. package/dist/cli/connect.js +100 -0
  5. package/dist/cli/connect.js.map +1 -0
  6. package/dist/cli/initConfig.js +2 -0
  7. package/dist/cli/initConfig.js.map +1 -1
  8. package/dist/cli/insightsStatus.js +13 -0
  9. package/dist/cli/insightsStatus.js.map +1 -0
  10. package/dist/cli/reviewInsights.js +145 -0
  11. package/dist/cli/reviewInsights.js.map +1 -0
  12. package/dist/cli/syncClaude.js +101 -0
  13. package/dist/cli/syncClaude.js.map +1 -0
  14. package/dist/cli.js +43 -66
  15. package/dist/cli.js.map +1 -1
  16. package/dist/config.js +2 -0
  17. package/dist/config.js.map +1 -1
  18. package/dist/connect/calibrate.js +44 -0
  19. package/dist/connect/calibrate.js.map +1 -0
  20. package/dist/connect/cluster.js +63 -0
  21. package/dist/connect/cluster.js.map +1 -0
  22. package/dist/connect/embed.js +47 -0
  23. package/dist/connect/embed.js.map +1 -0
  24. package/dist/connect/extract.js +129 -0
  25. package/dist/connect/extract.js.map +1 -0
  26. package/dist/connect/identity.js +65 -0
  27. package/dist/connect/identity.js.map +1 -0
  28. package/dist/connect/insightFile.js +61 -0
  29. package/dist/connect/insightFile.js.map +1 -0
  30. package/dist/connect/qualify.js +39 -0
  31. package/dist/connect/qualify.js.map +1 -0
  32. package/dist/connect/run.js +199 -0
  33. package/dist/connect/run.js.map +1 -0
  34. package/dist/connect/text.js +20 -0
  35. package/dist/connect/text.js.map +1 -0
  36. package/dist/connect/types.js +2 -0
  37. package/dist/connect/types.js.map +1 -0
  38. package/dist/connect/verify.js +77 -0
  39. package/dist/connect/verify.js.map +1 -0
  40. package/dist/mcp/server.js +10 -0
  41. package/dist/mcp/server.js.map +1 -1
  42. package/dist/output/json.js +2 -0
  43. package/dist/output/json.js.map +1 -1
  44. package/dist/pipeline/run.js +6 -0
  45. package/dist/pipeline/run.js.map +1 -1
  46. package/dist/search/retriever.js +19 -0
  47. package/dist/search/retriever.js.map +1 -1
  48. package/dist/search/thresholds.js +22 -2
  49. package/dist/search/thresholds.js.map +1 -1
  50. package/dist/state/db.js +238 -0
  51. package/dist/state/db.js.map +1 -1
  52. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.js","sourceRoot":"","sources":["../../src/connect/cluster.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ // Vectors for every lesson, keyed by contentHash. Cached vectors are reused;
2
+ // misses are embedded once per distinct hash and stored as they arrive, so a
3
+ // retry resumes where this run stopped. A provider failure stops the run
4
+ // (spec §10): clustering a fragment of the vault would propose rules from
5
+ // partial evidence. Over-long text is not a failure — the provider truncates.
6
+ export async function embedLessons(lessons, db, provider) {
7
+ const textByHash = new Map();
8
+ for (const l of lessons)
9
+ textByHash.set(l.contentHash, l.text);
10
+ const hashes = [...textByHash.keys()];
11
+ const out = db.getLessonEmbeddings(hashes, provider.modelName);
12
+ let embedded = 0;
13
+ for (const hash of hashes) {
14
+ if (out.has(hash))
15
+ continue;
16
+ let vec;
17
+ try {
18
+ vec = (await provider.embedDoc(textByHash.get(hash) ?? "")).embedding;
19
+ }
20
+ catch (err) {
21
+ throw new Error(`embedding provider failed after ${embedded} lesson(s) — nothing written: ${err.message}`);
22
+ }
23
+ db.storeLessonEmbedding(hash, provider.modelName, vec);
24
+ out.set(hash, vec);
25
+ embedded += 1;
26
+ }
27
+ return out;
28
+ }
29
+ // Self-heal for accepted rules: embedded at accept time, but a provider outage
30
+ // then, or a later model switch, would leave them out of embedding search.
31
+ // Best-effort — a failed embed is retried on the next sweep. Returns the count.
32
+ export async function backfillInsightEmbeddings(db, provider) {
33
+ let n = 0;
34
+ for (const t of db.listInsightEmbeddingTargets(provider.modelName)) {
35
+ let vec;
36
+ try {
37
+ vec = (await provider.embedDoc(`${t.rule}\n${t.why}`)).embedding;
38
+ }
39
+ catch {
40
+ continue;
41
+ }
42
+ db.setInsightEmbedding(t.id, vec, { model: provider.modelName, dim: vec.length });
43
+ n += 1;
44
+ }
45
+ return n;
46
+ }
47
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../src/connect/embed.ts"],"names":[],"mappings":"AAIA,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,0EAA0E;AAC1E,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAiB,EACjB,EAAW,EACX,QAA2B;IAE3B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,EAAE,CAAC,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/D,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC5B,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,mCAAmC,QAAQ,iCAAkC,GAAa,CAAC,OAAO,EAAE,CACrG,CAAC;QACJ,CAAC;QACD,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACvD,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACnB,QAAQ,IAAI,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,EAAW,EAAE,QAA2B;IACtF,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,2BAA2B,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACnE,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAClF,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,129 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { basename, join } from "node:path";
4
+ import { parseFrontmatter } from "../cli/review.js";
5
+ import { kebab } from "../pipeline/slug.js";
6
+ import { CATEGORY_DIR } from "../pipeline/writer.js";
7
+ const ITEM_RE = /^(?:[-*]|\d+\.)?\s*(?:\*\*|__)/;
8
+ const HEADING_RE = /^#{1,2}\s/;
9
+ function section(lines, title) {
10
+ const start = lines.findIndex((l) => title.test(l));
11
+ if (start === -1)
12
+ return null;
13
+ const out = [];
14
+ for (let i = start + 1; i < lines.length; i += 1) {
15
+ const line = lines[i] ?? "";
16
+ if (HEADING_RE.test(line))
17
+ break;
18
+ out.push(line);
19
+ }
20
+ return out;
21
+ }
22
+ // A lesson starts on a base-indent line beginning with an optional list marker
23
+ // and bold; its body runs to the next base-indent item or heading. Nested
24
+ // (indented) bold lines belong to their parent. Mid-line bold is not an item.
25
+ export function extractLessonTexts(markdown) {
26
+ const lines = markdown.split("\n");
27
+ const learned = section(lines, /^##\s+What Was Learned\s*$/);
28
+ if (learned === null) {
29
+ const summary = section(lines, /^##\s+Summary\s*$/);
30
+ const text = (summary ?? []).join("\n").trim();
31
+ return text.length > 0 ? [text] : [];
32
+ }
33
+ const items = [];
34
+ let cur = null;
35
+ for (const line of learned) {
36
+ // ### subheadings group lessons; they end the current item and are not text.
37
+ if (/^#{3,6}\s/.test(line)) {
38
+ cur = null;
39
+ }
40
+ else if (ITEM_RE.test(line) && !/^\s/.test(line)) {
41
+ cur = [line];
42
+ items.push(cur);
43
+ }
44
+ else if (cur) {
45
+ cur.push(line);
46
+ }
47
+ }
48
+ return items.map((l) => l.join("\n").trim()).filter((t) => t.length > 0);
49
+ }
50
+ export function normalizeLesson(raw) {
51
+ return raw
52
+ .split("\n")
53
+ .map((l) => l.replace(/^\s*(?:[-*]|\d+\.)\s+/, ""))
54
+ .join(" ")
55
+ .replace(/\*\*|__/g, "")
56
+ .replace(/\s+/g, " ")
57
+ .trim();
58
+ }
59
+ export function lessonHash(normalized) {
60
+ return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
61
+ }
62
+ export function archivedDuplicateSlugs(markdown) {
63
+ const lines = section(markdown.split("\n"), /^##\s+Archived Duplicates\s*$/) ?? [];
64
+ return lines
65
+ .map((l) => l.match(/^\s*-\s*\[\[([^\]|]+)(?:\|[^\]]*)?\]\]/)?.[1]?.trim())
66
+ .filter((s) => typeof s === "string" && s.length > 0);
67
+ }
68
+ function lessonsFromNote(path, citeSlug, archivedVia) {
69
+ let raw;
70
+ try {
71
+ raw = readFileSync(path, "utf8");
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ const fm = parseFrontmatter(raw);
77
+ const sessionId = fm.session_id ?? "";
78
+ if (sessionId.length === 0)
79
+ return [];
80
+ const noteSlug = basename(path, ".md");
81
+ return extractLessonTexts(raw).map((t, itemIndex) => {
82
+ const text = normalizeLesson(t);
83
+ return {
84
+ id: `${noteSlug}#${itemIndex}`,
85
+ noteSlug,
86
+ citeSlug,
87
+ sessionId,
88
+ noteDate: fm.date ?? "",
89
+ project: kebab(fm.project ?? ""),
90
+ category: (fm.category ?? "pattern"),
91
+ itemIndex,
92
+ text,
93
+ contentHash: lessonHash(text),
94
+ archivedVia,
95
+ };
96
+ });
97
+ }
98
+ export function collectLessons(vaultRoot) {
99
+ const out = [];
100
+ for (const dir of Object.values(CATEGORY_DIR)) {
101
+ const full = join(vaultRoot, dir);
102
+ let names;
103
+ try {
104
+ names = readdirSync(full).filter((n) => n.endsWith(".md")).sort();
105
+ }
106
+ catch {
107
+ continue;
108
+ }
109
+ for (const name of names) {
110
+ const path = join(full, name);
111
+ const slug = basename(name, ".md");
112
+ out.push(...lessonsFromNote(path, slug, null));
113
+ let raw = "";
114
+ try {
115
+ raw = readFileSync(path, "utf8");
116
+ }
117
+ catch {
118
+ continue;
119
+ }
120
+ for (const loser of archivedDuplicateSlugs(raw)) {
121
+ const lp = join(vaultRoot, "archived", `${loser}.md`);
122
+ if (existsSync(lp))
123
+ out.push(...lessonsFromNote(lp, slug, slug));
124
+ }
125
+ }
126
+ }
127
+ return out;
128
+ }
129
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/connect/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ export function jaccard(a, b) {
2
+ const sa = new Set(a);
3
+ const sb = new Set(b);
4
+ let inter = 0;
5
+ for (const x of sa)
6
+ if (sb.has(x))
7
+ inter += 1;
8
+ const union = sa.size + sb.size - inter;
9
+ return union === 0 ? 0 : inter / union;
10
+ }
11
+ export const MATCH_JACCARD = 0.5;
12
+ function cosine(a, b) {
13
+ let dot = 0;
14
+ let na = 0;
15
+ let nb = 0;
16
+ for (let i = 0; i < a.length; i += 1) {
17
+ const x = a[i] ?? 0;
18
+ const y = b[i] ?? 0;
19
+ dot += x * y;
20
+ na += x * x;
21
+ nb += y * y;
22
+ }
23
+ return na === 0 || nb === 0 ? 0 : dot / Math.sqrt(na * nb);
24
+ }
25
+ // Identity is the member SESSION set: session ids survive note rewrites
26
+ // (reconcile, run --full, dedupe winners, review edits); content hashes don't.
27
+ // Hash overlap only breaks ties. A rejected rule is also matched by its rule
28
+ // embedding, so a reworded re-discovery from new sessions stays rejected.
29
+ export function matchCandidate(candidate, insights, rejectedVectors, coreSim) {
30
+ let best = null;
31
+ let bestJ = -1;
32
+ let bestH = -1;
33
+ for (const ins of insights) {
34
+ const j = jaccard(candidate.sessionIds, ins.memberSessionIds);
35
+ if (j < MATCH_JACCARD)
36
+ continue;
37
+ const h = jaccard(candidate.hashes, ins.memberHashes);
38
+ if (j > bestJ || (j === bestJ && h > bestH)) {
39
+ best = ins;
40
+ bestJ = j;
41
+ bestH = h;
42
+ }
43
+ }
44
+ if (best === null && candidate.ruleVector !== null) {
45
+ for (const ins of insights) {
46
+ if (ins.status !== "rejected")
47
+ continue;
48
+ const v = rejectedVectors.get(ins.id);
49
+ if (v && cosine(candidate.ruleVector, v) >= coreSim)
50
+ return { kind: "skip-rejected", insight: ins };
51
+ }
52
+ }
53
+ if (best === null)
54
+ return { kind: "new" };
55
+ if (best.status === "rejected")
56
+ return { kind: "skip-rejected", insight: best };
57
+ if (best.status === "proposed")
58
+ return { kind: "update-proposed", insight: best };
59
+ const known = new Set(best.memberSessionIds);
60
+ const added = [...new Set(candidate.sessionIds)].filter((s) => !known.has(s));
61
+ return added.length === 0
62
+ ? { kind: "accepted-unchanged", insight: best }
63
+ : { kind: "accepted-additions", insight: best, addedSessions: added };
64
+ }
65
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/connect/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { mkdirSync, renameSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { kebab } from "../pipeline/slug.js";
4
+ import { ruleText } from "./text.js";
5
+ export const INSIGHTS_RULES_DIR = "insights/rules";
6
+ export function insightSlug(rule, id) {
7
+ const base = kebab(rule).slice(0, 60).replace(/-+$/, "");
8
+ const suffix = id.replace(/[^a-z0-9]/gi, "").slice(0, 8).toLowerCase();
9
+ return base.length > 0 ? `${base}-${suffix}` : `rule-${suffix}`;
10
+ }
11
+ const q = (s) => JSON.stringify(s);
12
+ export function renderInsight(row) {
13
+ const fm = [
14
+ "---",
15
+ "type: insight",
16
+ `insight_type: ${row.insightType}`,
17
+ `status: ${row.status}`,
18
+ `promotion: ${row.promotion}`,
19
+ `verified: ${row.status === "accepted"}`,
20
+ `scope: ${row.scope}`,
21
+ `sessions: ${row.sessions}`,
22
+ `projects: [${row.projects.map(q).join(", ")}]`,
23
+ `first_seen: ${row.firstSeen.slice(0, 10)}`,
24
+ `last_seen: ${row.lastSeen.slice(0, 10)}`,
25
+ "sources:",
26
+ ...row.sources.map((s) => ` - ${q(`[[${s}]]`)}`),
27
+ `generated: ${row.createdAt}`,
28
+ `model: ${row.model}`,
29
+ "---",
30
+ ];
31
+ const evidence = row.evidence.map((e) => `- [[${e.citeSlug}]] (${e.project || "-"}, ${e.date.slice(0, 10)}): ${q(e.quote)}`);
32
+ return [
33
+ ...fm,
34
+ `**Rule:** ${row.rule}`,
35
+ "",
36
+ `**Why:** ${row.why}`,
37
+ "",
38
+ "## Evidence",
39
+ "",
40
+ ...evidence,
41
+ "",
42
+ ].join("\n");
43
+ }
44
+ // The owner edits only the **Rule:** and **Why:** lines; everything else is
45
+ // re-rendered from the DB on the next state write.
46
+ export function parseRuleEdit(raw) {
47
+ const rule = ruleText(raw.match(/^\*\*Rule:\*\*[ \t]*(.+)$/m)?.[1] ?? "");
48
+ if (rule.length === 0)
49
+ return null;
50
+ const why = ruleText(raw.match(/^\*\*Why:\*\*[ \t]*(.+)$/m)?.[1] ?? "");
51
+ return { rule, why };
52
+ }
53
+ export function writeInsightFile(vaultRoot, row) {
54
+ const path = join(vaultRoot, INSIGHTS_RULES_DIR, `${row.slug}.md`);
55
+ mkdirSync(dirname(path), { recursive: true });
56
+ const tmp = `${path}.vir-${process.pid}.tmp`;
57
+ writeFileSync(tmp, renderInsight(row));
58
+ renameSync(tmp, path);
59
+ return path;
60
+ }
61
+ //# sourceMappingURL=insightFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insightFile.js","sourceRoot":"","sources":["../../src/connect/insightFile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export const MIN_SESSIONS = 3;
2
+ export const MIN_SPAN_DAYS = 7;
3
+ const DAY_MS = 86_400_000;
4
+ // Each session counts once, dated by its earliest parseable note date. A
5
+ // session with no parseable date still counts toward sessions but not the span.
6
+ export function recurrence(members) {
7
+ const earliest = new Map();
8
+ for (const m of members) {
9
+ const t = Date.parse(m.noteDate);
10
+ const prev = earliest.get(m.sessionId);
11
+ if (prev === undefined)
12
+ earliest.set(m.sessionId, Number.isFinite(t) ? t : null);
13
+ else if (Number.isFinite(t) && (prev === null || t < prev))
14
+ earliest.set(m.sessionId, t);
15
+ }
16
+ const times = [...earliest.values()].filter((t) => t !== null);
17
+ const first = times.length > 0 ? Math.min(...times) : null;
18
+ const last = times.length > 0 ? Math.max(...times) : null;
19
+ const projects = [...new Set(members.map((m) => m.project).filter((p) => p.length > 0))].sort();
20
+ return {
21
+ sessions: [...earliest.keys()],
22
+ firstSeen: first === null ? "" : new Date(first).toISOString(),
23
+ lastSeen: last === null ? "" : new Date(last).toISOString(),
24
+ projects,
25
+ spanDays: first === null || last === null ? 0 : (last - first) / DAY_MS,
26
+ };
27
+ }
28
+ export function qualifies(r) {
29
+ return r.sessions.length >= MIN_SESSIONS && r.spanDays >= MIN_SPAN_DAYS;
30
+ }
31
+ export function rankCandidates(clusters) {
32
+ return clusters
33
+ .map((members) => ({ members, rec: recurrence(members) }))
34
+ .filter((c) => qualifies(c.rec))
35
+ .sort((a, b) => b.rec.sessions.length - a.rec.sessions.length ||
36
+ b.rec.spanDays - a.rec.spanDays ||
37
+ b.rec.projects.length - a.rec.projects.length);
38
+ }
39
+ //# sourceMappingURL=qualify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qualify.js","sourceRoot":"","sources":["../../src/connect/qualify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,199 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { acquireLock, releaseLock } from "../pipeline/lock.js";
3
+ import { vaultRoot } from "../search/retriever.js";
4
+ import { embedNoteWithProvider } from "../search/provider.js";
5
+ import { thresholdsFor } from "../search/thresholds.js";
6
+ import { clusterLessons } from "./cluster.js";
7
+ import { backfillInsightEmbeddings, embedLessons } from "./embed.js";
8
+ import { collectLessons } from "./extract.js";
9
+ import { matchCandidate } from "./identity.js";
10
+ import { insightSlug, writeInsightFile } from "./insightFile.js";
11
+ import { rankCandidates, recurrence } from "./qualify.js";
12
+ import { buildVerifyPrompt, parseVerdict, validateVerdict } from "./verify.js";
13
+ const VERIFY_OUTPUT_TOKENS = 600;
14
+ function emptySummary() {
15
+ return {
16
+ lessons: 0, clusters: 0, candidates: 0, deferred: 0, proposed: 0, updated: 0, unchanged: 0,
17
+ skippedRejected: 0, unverified: 0, llmFailures: 0, additionsFlagged: 0, llmCalls: 0,
18
+ estCostUsd: null, keptRatios: [],
19
+ };
20
+ }
21
+ function evidenceOf(v) {
22
+ return v.evidence.map((e) => ({
23
+ sessionId: e.lesson.sessionId,
24
+ citeSlug: e.lesson.citeSlug,
25
+ project: e.lesson.project,
26
+ date: e.lesson.noteDate,
27
+ quote: e.quote,
28
+ }));
29
+ }
30
+ function reconsider(cfg, db, slug, now) {
31
+ const row = db.getInsightBySlug(slug);
32
+ if (row === null)
33
+ throw new Error(`no rule with slug ${slug}`);
34
+ // Spec §9: the way back for a rejected or declined rule — never a silent
35
+ // demotion of one the owner accepted and promoted.
36
+ if (row.status !== "rejected" && row.promotion !== "declined") {
37
+ throw new Error(`only a rejected or declined rule can be reconsidered — ${slug} is ${row.status}`);
38
+ }
39
+ const next = {
40
+ ...row,
41
+ status: "proposed",
42
+ promotion: "none",
43
+ evidenceChanged: false,
44
+ pending: null,
45
+ updatedAt: now.toISOString(),
46
+ };
47
+ db.upsertInsight(next);
48
+ writeInsightFile(vaultRoot(cfg), next);
49
+ return emptySummary();
50
+ }
51
+ // Find lessons the user keeps re-learning and propose them as cited rules.
52
+ // Paid: at most connectMaxCandidates LLM calls. Never run implicitly.
53
+ export async function runConnect(cfg, db, opts, deps) {
54
+ acquireLock(deps.lockPath);
55
+ try {
56
+ if (opts.reconsider !== undefined)
57
+ return reconsider(cfg, db, opts.reconsider, deps.now());
58
+ const provider = deps.provider;
59
+ if (provider === null)
60
+ throw new Error("clustering needs an embedding provider — run vir embed setup");
61
+ const summary = emptySummary();
62
+ const root = vaultRoot(cfg);
63
+ if (!opts.dryRun)
64
+ await backfillInsightEmbeddings(db, provider);
65
+ const lessons = collectLessons(root);
66
+ summary.lessons = lessons.length;
67
+ const vectors = await embedLessons(lessons, db, provider);
68
+ const { connectMinSim, connectCoreSim } = thresholdsFor(provider.modelName);
69
+ const clusters = clusterLessons(lessons, vectors, connectMinSim, connectCoreSim);
70
+ summary.clusters = clusters.length;
71
+ // Free pre-LLM triage: rejected stays rejected, and a known rule with no new
72
+ // session is unchanged — neither earns a paid call.
73
+ const insights = db.listInsights();
74
+ const todo = [];
75
+ for (const c of rankCandidates(clusters)) {
76
+ const hashes = c.members.map((m) => m.contentHash);
77
+ const pre = matchCandidate({ sessionIds: c.rec.sessions, hashes, ruleVector: null }, insights, new Map(), connectCoreSim);
78
+ if (pre.kind === "skip-rejected") {
79
+ summary.skippedRejected += 1;
80
+ continue;
81
+ }
82
+ if (pre.kind === "accepted-unchanged") {
83
+ summary.unchanged += 1;
84
+ continue;
85
+ }
86
+ if (pre.kind === "update-proposed" || pre.kind === "accepted-additions") {
87
+ // Sessions already flagged as pending additions are known too: the
88
+ // owner hasn't decided on them yet, so asking the model again is waste.
89
+ const known = new Set([
90
+ ...pre.insight.memberSessionIds,
91
+ ...(pre.insight.pending ?? []).map((e) => e.sessionId),
92
+ ]);
93
+ if (c.rec.sessions.every((s) => known.has(s))) {
94
+ summary.unchanged += 1;
95
+ continue;
96
+ }
97
+ }
98
+ todo.push(c);
99
+ }
100
+ summary.candidates = todo.length;
101
+ const batch = todo.slice(0, cfg.connectMaxCandidates);
102
+ summary.deferred = todo.length - batch.length;
103
+ if (opts.dryRun) {
104
+ let total = 0;
105
+ for (const c of batch) {
106
+ const cost = deps.estimateCostUsd(Math.ceil(buildVerifyPrompt(c.members).length / 4), VERIFY_OUTPUT_TOKENS);
107
+ total = cost === null || total === null ? null : total + cost;
108
+ }
109
+ summary.estCostUsd = total;
110
+ return summary;
111
+ }
112
+ const rejectedVectors = db.getInsightVectors("rejected");
113
+ for (const c of batch) {
114
+ summary.llmCalls += 1;
115
+ let text;
116
+ try {
117
+ text = await deps.llm(buildVerifyPrompt(c.members));
118
+ }
119
+ catch {
120
+ summary.llmFailures += 1;
121
+ continue;
122
+ }
123
+ const verdict = parseVerdict(text);
124
+ const v = verdict === null ? null : validateVerdict(c.members, verdict);
125
+ if (v === null) {
126
+ summary.unverified += 1;
127
+ continue;
128
+ }
129
+ summary.keptRatios.push(v.keptOfTotal);
130
+ const rec = recurrence(v.members);
131
+ const ruleVector = await embedNoteWithProvider(provider, `${v.rule}\n${v.why}`);
132
+ const outcome = matchCandidate({ sessionIds: rec.sessions, hashes: v.members.map((m) => m.contentHash), ruleVector }, db.listInsights(), rejectedVectors, connectCoreSim);
133
+ const now = deps.now().toISOString();
134
+ const evidence = evidenceOf(v);
135
+ const fields = {
136
+ memberSessionIds: rec.sessions,
137
+ memberHashes: v.members.map((m) => m.contentHash),
138
+ sources: [...new Set(evidence.map((e) => e.citeSlug))],
139
+ evidence,
140
+ sessions: rec.sessions.length,
141
+ projects: rec.projects,
142
+ firstSeen: rec.firstSeen,
143
+ lastSeen: rec.lastSeen,
144
+ };
145
+ if (outcome.kind === "skip-rejected") {
146
+ summary.skippedRejected += 1;
147
+ }
148
+ else if (outcome.kind === "accepted-unchanged") {
149
+ summary.unchanged += 1;
150
+ }
151
+ else if (outcome.kind === "accepted-additions") {
152
+ const added = new Set(outcome.addedSessions);
153
+ db.upsertInsight({
154
+ ...outcome.insight,
155
+ evidenceChanged: true,
156
+ pending: evidence.filter((e) => added.has(e.sessionId)),
157
+ updatedAt: now,
158
+ });
159
+ summary.additionsFlagged += 1;
160
+ }
161
+ else if (outcome.kind === "update-proposed") {
162
+ const next = { ...outcome.insight, ...fields, scope: v.scope, updatedAt: now };
163
+ db.upsertInsight(next);
164
+ writeInsightFile(root, next);
165
+ summary.updated += 1;
166
+ }
167
+ else {
168
+ const id = randomUUID();
169
+ const row = {
170
+ id,
171
+ slug: insightSlug(v.rule, id),
172
+ insightType: "recurring-rule",
173
+ status: "proposed",
174
+ promotion: "none",
175
+ scope: v.scope,
176
+ rule: v.rule,
177
+ why: v.why,
178
+ ...fields,
179
+ evidenceChanged: false,
180
+ pending: null,
181
+ model: deps.model,
182
+ createdAt: now,
183
+ updatedAt: now,
184
+ };
185
+ db.upsertInsight(row);
186
+ if (ruleVector !== null) {
187
+ db.setInsightEmbedding(id, ruleVector, { model: provider.modelName, dim: ruleVector.length });
188
+ }
189
+ writeInsightFile(root, row);
190
+ summary.proposed += 1;
191
+ }
192
+ }
193
+ return summary;
194
+ }
195
+ finally {
196
+ releaseLock(deps.lockPath);
197
+ }
198
+ }
199
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/connect/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ // Rule and why text is model-written and owner-editable, then shown in the
2
+ // terminal for approval and written into CLAUDE.md, which agents read as
3
+ // instructions. One normalization, applied at every boundary, so what the
4
+ // owner judges is byte-for-byte what gets stored and written:
5
+ // - no C0/C1 control characters (ANSI escapes could hide or recolor text)
6
+ // - no bidi overrides/isolates (could reorder what the owner reads)
7
+ // - no HTML-comment syntax (no fake VIR markers or rule ids)
8
+ // - one line (no injected headings)
9
+ const CONTROL = /[\u0000-\u001f\u007f-\u009f]/g;
10
+ const BIDI = /[\u202a-\u202e\u2066-\u2069\u200e\u200f\u061c]/g;
11
+ export function ruleText(text) {
12
+ return text
13
+ .replace(/\r\n|\r|\n|\t/g, " ")
14
+ .replace(CONTROL, "")
15
+ .replace(BIDI, "")
16
+ .replace(/<!--|-->/g, " ")
17
+ .replace(/\s+/g, " ")
18
+ .trim();
19
+ }
20
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/connect/text.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,8DAA8D;AAC9D,2EAA2E;AAC3E,qEAAqE;AACrE,8DAA8D;AAC9D,qCAAqC;AACrC,MAAM,OAAO,GAAG,+BAA+B,CAAC;AAChD,MAAM,IAAI,GAAG,iDAAiD,CAAC;AAE/D,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI;SACR,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;SACjB,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;SACzB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/connect/types.ts"],"names":[],"mappings":""}