@isaacriehm/cairn-core 0.18.2 → 0.19.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.
@@ -66,3 +66,27 @@ export declare function findDuplicateClusters(args: {
66
66
  thresholdFloor?: number;
67
67
  thresholdDefinite?: number;
68
68
  }): DedupResult;
69
+ export interface AcceptedDuplicate {
70
+ dup: boolean;
71
+ /** Matched accepted DEC id, present only when `dup`. */
72
+ matchId?: string;
73
+ /** Matched accepted DEC title, present only when `dup`. */
74
+ matchTitle?: string;
75
+ /** Title-Jaccard similarity of the match, present only when `dup`. */
76
+ similarity?: number;
77
+ }
78
+ /**
79
+ * Is a candidate decision a near-duplicate of one ALREADY accepted in the
80
+ * ledger? This is the dedup half of the auto-accept verify gate: a fresh
81
+ * DEC that merely restates an accepted one should NOT silently re-land —
82
+ * it falls back to an `_inbox/` draft for human eyes instead.
83
+ *
84
+ * Title-token Jaccard against the accepted (non-superseded) ledger, at the
85
+ * same `definite` threshold the inbox clusterer uses. Title-vs-title keeps
86
+ * it symmetric (the ledger only carries titles); deterministic, no LLM.
87
+ */
88
+ export declare function isDuplicateOfAccepted(args: {
89
+ repoRoot: string;
90
+ title: string;
91
+ threshold?: number;
92
+ }): AcceptedDuplicate;
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
21
21
  import { join } from "node:path";
22
- import { decisionsDir } from "@isaacriehm/cairn-state";
22
+ import { buildDecisionsLedger, decisionsDir } from "@isaacriehm/cairn-state";
23
23
  import { jaccard, tokenize } from "../text/jaccard.js";
24
24
  /** Default char window of body to fold into the token bag. */
25
25
  const BODY_CHAR_WINDOW = 500;
@@ -214,4 +214,45 @@ export function findDuplicateClusters(args) {
214
214
  thresholdDefinite,
215
215
  };
216
216
  }
217
+ /**
218
+ * Is a candidate decision a near-duplicate of one ALREADY accepted in the
219
+ * ledger? This is the dedup half of the auto-accept verify gate: a fresh
220
+ * DEC that merely restates an accepted one should NOT silently re-land —
221
+ * it falls back to an `_inbox/` draft for human eyes instead.
222
+ *
223
+ * Title-token Jaccard against the accepted (non-superseded) ledger, at the
224
+ * same `definite` threshold the inbox clusterer uses. Title-vs-title keeps
225
+ * it symmetric (the ledger only carries titles); deterministic, no LLM.
226
+ */
227
+ export function isDuplicateOfAccepted(args) {
228
+ const threshold = args.threshold ?? DEFAULT_THRESHOLD_DEFINITE;
229
+ const candidate = tokenize(args.title);
230
+ if (candidate.size === 0)
231
+ return { dup: false };
232
+ let entries;
233
+ try {
234
+ entries = buildDecisionsLedger({ repoRoot: args.repoRoot });
235
+ }
236
+ catch {
237
+ return { dup: false };
238
+ }
239
+ let best = { sim: 0, id: "", title: "" };
240
+ for (const e of entries) {
241
+ const t = tokenize(e.title);
242
+ if (t.size === 0)
243
+ continue;
244
+ const sim = jaccard(candidate, t);
245
+ if (sim > best.sim)
246
+ best = { sim, id: e.id, title: e.title };
247
+ }
248
+ if (best.sim >= threshold) {
249
+ return {
250
+ dup: true,
251
+ matchId: best.id,
252
+ matchTitle: best.title,
253
+ similarity: Math.round(best.sim * 100) / 100,
254
+ };
255
+ }
256
+ return { dup: false };
257
+ }
217
258
  //# sourceMappingURL=dedup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/attention/dedup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/attention/dedup.ts"],"names":[],"mappings":"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"}
@@ -5,12 +5,23 @@
5
5
  * 1. Probable inline rebuilds — `className` lists in non-component code
6
6
  * whose Tailwind utility ROOTS closely match an indexed component's
7
7
  * (max-w-2xl ≈ max-w-4xl, so value-tweaked copies still match).
8
+ * Similarity is IDF-weighted over the component corpus: a utility root
9
+ * that nearly every component uses (`flex`, `gap`, `mx`, `px`) carries
10
+ * almost no weight, so a page sharing only generic layout scaffolding
11
+ * does NOT match — only overlap on DISTINCTIVE class roots counts. This
12
+ * is self-tuning to the project's own CSS; no hardcoded utility list.
8
13
  * 2. Name collisions — `@cairn` names colliding with a type/interface name.
14
+ * 3. Unregistered components — a component-shaped file (PascalCase
15
+ * basename, real exports, JSX markup) sitting OUTSIDE the declared
16
+ * component dirs. These are co-located components the registry can't
17
+ * see; route entry files (page.tsx/layout.tsx — lowercase) are
18
+ * naturally excluded, so no framework convention list is hardcoded.
19
+ * Surfaced as an offer to relocate or register the dir — never moved.
9
20
  *
10
21
  * Findings are triage input surfaced to the attention queue with EXTEND /
11
- * rename recommendations; never auto-fixed.
22
+ * rename / register recommendations; never auto-fixed.
12
23
  */
13
- export type ComponentAuditKind = "inline-rebuild" | "name-collision";
24
+ export type ComponentAuditKind = "inline-rebuild" | "name-collision" | "unregistered-component";
14
25
  export interface ComponentAuditFinding {
15
26
  kind: ComponentAuditKind;
16
27
  /** Where the probable violation lives (repo-relative POSIX). */
@@ -5,18 +5,34 @@
5
5
  * 1. Probable inline rebuilds — `className` lists in non-component code
6
6
  * whose Tailwind utility ROOTS closely match an indexed component's
7
7
  * (max-w-2xl ≈ max-w-4xl, so value-tweaked copies still match).
8
+ * Similarity is IDF-weighted over the component corpus: a utility root
9
+ * that nearly every component uses (`flex`, `gap`, `mx`, `px`) carries
10
+ * almost no weight, so a page sharing only generic layout scaffolding
11
+ * does NOT match — only overlap on DISTINCTIVE class roots counts. This
12
+ * is self-tuning to the project's own CSS; no hardcoded utility list.
8
13
  * 2. Name collisions — `@cairn` names colliding with a type/interface name.
14
+ * 3. Unregistered components — a component-shaped file (PascalCase
15
+ * basename, real exports, JSX markup) sitting OUTSIDE the declared
16
+ * component dirs. These are co-located components the registry can't
17
+ * see; route entry files (page.tsx/layout.tsx — lowercase) are
18
+ * naturally excluded, so no framework convention list is hardcoded.
19
+ * Surfaced as an offer to relocate or register the dir — never moved.
9
20
  *
10
21
  * Findings are triage input surfaced to the attention queue with EXTEND /
11
- * rename recommendations; never auto-fixed.
22
+ * rename / register recommendations; never auto-fixed.
12
23
  */
13
24
  import { readFileSync } from "node:fs";
14
25
  import { join } from "node:path";
15
- import { collectComponents, hasComponentConfig, loadComponentsConfig, walkFs, } from "@isaacriehm/cairn-state";
16
- import { jaccard } from "../text/jaccard.js";
26
+ import { collectComponents, extractExportName, extractExportNames, hasComponentConfig, loadComponentsConfig, walkFs, } from "@isaacriehm/cairn-state";
17
27
  const SIMILARITY_THRESHOLD = 0.7;
18
28
  const MIN_SHARED_ROOTS = 3;
19
29
  const MIN_CLASSES = 3;
30
+ /**
31
+ * A shared root only counts toward MIN_SHARED_ROOTS if it is distinctive —
32
+ * idf ≥ ln(2), i.e. the root appears in fewer than ~half of all components.
33
+ * Ubiquitous layout utilities fall below this and never satisfy the gate.
34
+ */
35
+ const IDF_DISTINCTIVE_FLOOR = Math.log(2);
20
36
  const CLASS_ATTR_RE = /className\s*=\s*(?:"([^"]+)"|'([^']+)'|\{`([^`]+)`\})/g;
21
37
  const VALUE_SUFFIX = /-(?:\d[^-]*|xs|sm|md|lg|xl|\dxl|auto|full|none|screen|px)$/;
22
38
  const SKIP_DIRS = new Set([".git", ".cairn", "node_modules", "dist", ".next", "build", "coverage"]);
@@ -43,18 +59,38 @@ function classLists(source) {
43
59
  }
44
60
  return lists;
45
61
  }
46
- function rootSimilarity(a, b) {
47
- const ra = new Set(a.map(utilityRoot));
48
- const rb = new Set(b.map(utilityRoot));
49
- let shared = 0;
50
- for (const r of ra)
51
- if (rb.has(r))
52
- shared += 1;
53
- return { score: jaccard(ra, rb), shared };
62
+ /** Distinct utility roots of a class list. */
63
+ function rootSet(classes) {
64
+ return new Set(classes.map(utilityRoot));
54
65
  }
55
66
  function inComponentDirs(rel, config) {
56
67
  return config.workspaces.some((ws) => ws.componentDirs.some((d) => rel === d || rel.startsWith(`${d}/`)));
57
68
  }
69
+ /** JSX markup signal — a tag or a className attribute. */
70
+ const JSX_RE = /<[A-Za-z][^>]*\/?>|className\s*=/;
71
+ /**
72
+ * If a file outside the component dirs looks like a misplaced COMPONENT
73
+ * (rather than a hook/context/util, or markup duplicated inside
74
+ * non-component code), return its exported names; otherwise null. Three
75
+ * convention-based signals, no framework list:
76
+ * 1. PascalCase basename — named component files are `FeaturedShell.tsx`;
77
+ * framework route entry files are lowercase (`page.tsx`, `layout.tsx`).
78
+ * 2. Exports a PascalCase symbol — a component-like export exists (a file
79
+ * exporting only `useThing` / consts is a hook/util, not a component).
80
+ * 3. Renders JSX — excludes type-only / pure-logic files.
81
+ */
82
+ function misplacedComponentExports(rel, source) {
83
+ const base = rel.slice(rel.lastIndexOf("/") + 1);
84
+ const stem = base.includes(".") ? base.slice(0, base.indexOf(".")) : base;
85
+ if (!/^[A-Z][a-z]/.test(stem))
86
+ return null;
87
+ const names = extractExportNames(source);
88
+ if (!names.some((n) => /^[A-Z][a-z]/.test(n)))
89
+ return null;
90
+ if (!JSX_RE.test(source))
91
+ return null;
92
+ return names;
93
+ }
58
94
  export function runComponentAudit(repoRoot) {
59
95
  const config = loadComponentsConfig(repoRoot);
60
96
  if (!hasComponentConfig(config))
@@ -66,6 +102,7 @@ export function runComponentAudit(repoRoot) {
66
102
  const findings = [];
67
103
  let scanned = 0;
68
104
  // ── 1. Inline-rebuild scan ────────────────────────────────────────────
105
+ // Each component's className lists, with utility roots precomputed.
69
106
  const signatures = components
70
107
  .map((c) => {
71
108
  let src = "";
@@ -75,9 +112,48 @@ export function runComponentAudit(repoRoot) {
75
112
  catch {
76
113
  /* skip unreadable */
77
114
  }
78
- return { name: c.tags.cairn ?? "?", file: c.file, lists: classLists(src) };
115
+ const lists = classLists(src).map((l) => ({
116
+ line: l.line,
117
+ roots: rootSet(l.classes),
118
+ }));
119
+ return { name: c.tags.cairn ?? "?", file: c.file, lists };
79
120
  })
80
121
  .filter((c) => c.lists.length > 0);
122
+ // Corpus IDF: how distinctive each utility root is. A root present in many
123
+ // components (df → N) gets idf → 0; a rare root gets a high weight. Document
124
+ // = one component (union of its lists' roots), so repetition within a file
125
+ // doesn't inflate frequency.
126
+ const corpusN = signatures.length;
127
+ const docFreq = new Map();
128
+ for (const c of signatures) {
129
+ const compRoots = new Set();
130
+ for (const l of c.lists)
131
+ for (const r of l.roots)
132
+ compRoots.add(r);
133
+ for (const r of compRoots)
134
+ docFreq.set(r, (docFreq.get(r) ?? 0) + 1);
135
+ }
136
+ const idf = (root) => Math.log((corpusN + 1) / ((docFreq.get(root) ?? 0) + 1));
137
+ // IDF-weighted Jaccard between two root sets, plus the count of shared
138
+ // DISTINCTIVE roots (ubiquitous roots don't count toward the gate).
139
+ const weightedSimilarity = (target, comp) => {
140
+ let inter = 0;
141
+ let union = 0;
142
+ let shared = 0;
143
+ for (const r of target) {
144
+ const w = idf(r);
145
+ union += w;
146
+ if (comp.has(r)) {
147
+ inter += w;
148
+ if (w >= IDF_DISTINCTIVE_FLOOR)
149
+ shared += 1;
150
+ }
151
+ }
152
+ for (const r of comp)
153
+ if (!target.has(r))
154
+ union += idf(r);
155
+ return { score: union > 0 ? inter / union : 0, shared };
156
+ };
81
157
  // ── 2. Name-collision prep ────────────────────────────────────────────
82
158
  const nameToComponent = new Map();
83
159
  for (const c of components)
@@ -105,14 +181,35 @@ export function runComponentAudit(repoRoot) {
105
181
  scanned += 1;
106
182
  // Inline rebuild — only in non-component code with a UI extension.
107
183
  if (extensions.has(ext) && !inComponentDirs(rel, config)) {
184
+ // A component-shaped file outside the component dirs is not a
185
+ // rebuild — it is a co-located component the registry can't see.
186
+ // Surface it (with its export names + file) as an offer to
187
+ // relocate/register; skip the rebuild scan for it.
188
+ const exports = misplacedComponentExports(rel, source);
189
+ if (exports !== null) {
190
+ const primary = extractExportName(source) ?? exports[0];
191
+ const others = exports.filter((n) => n !== primary);
192
+ const dirs = config.workspaces.flatMap((w) => w.componentDirs).join(", ");
193
+ findings.push({
194
+ kind: "unregistered-component",
195
+ file: rel,
196
+ component: primary,
197
+ componentFile: rel,
198
+ message: `${primary} (${rel})${others.length > 0 ? ` — also exports ${others.join(", ")}` : ""} ` +
199
+ `looks like a component but lives outside the declared component dir(s) (${dirs}); the registry can't see it`,
200
+ recommendation: `move ${rel} into a component dir, or add its directory to the workspace's componentDirs — then header + index ${primary}`,
201
+ });
202
+ return;
203
+ }
108
204
  for (const target of classLists(source)) {
205
+ const troots = rootSet(target.classes);
109
206
  let best = null;
110
207
  for (const comp of signatures) {
111
208
  for (const list of comp.lists) {
112
- const { score, shared } = rootSimilarity(target.classes, list.classes);
209
+ const { score, shared } = weightedSimilarity(troots, list.roots);
113
210
  if (score >= SIMILARITY_THRESHOLD && shared >= MIN_SHARED_ROOTS) {
114
211
  if (best === null || score > best.score) {
115
- best = { name: comp.name, file: comp.file, classes: list.classes, score };
212
+ best = { name: comp.name, file: comp.file, score };
116
213
  }
117
214
  }
118
215
  }
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/components/audit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/components/audit.ts"],"names":[],"mappings":"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"}
@@ -1,36 +1,42 @@
1
1
  /**
2
- * Deterministic component-dir detection for adoption (Phase 4-seed).
2
+ * LLM-driven, convention-agnostic component-layout detection.
3
3
  *
4
- * No LLM. Probes conventional component directories that actually
5
- * exist on disk and proposes a `components:` block for
6
- * `.cairn/config.yaml`. Returns `null` when the project has no
7
- * recognizable component layout (non-UI repos stay untouched).
4
+ * Cairn adoption ALWAYS runs inside an LLM coding agent, so detection
5
+ * leans on a model rather than a hardcoded convention list — there is no
6
+ * `src/components` / `packages/*` assumption baked in. A Sonnet call reads
7
+ * the repo's structural digest (per-directory file-extension histogram,
8
+ * the dirs that hold a `package.json`, and any workspace-manifest files)
9
+ * and returns the `components:` config: which workspaces carry reusable
10
+ * UI, where their component dirs live, the extensions in play, and a
11
+ * taxonomy that fits THAT workspace. A non-UI repo (a backend with no
12
+ * components) returns null and is left untouched.
8
13
  *
9
- * Isolation invariant (port invariant 3): a monorepo workspace is
10
- * NEVER guessed as `shared`. We omit the flag entirely — it normalizes
11
- * to isolated and leave the opt-in to the operator (manual config
12
- * edit or the future annotate step).
14
+ * Only mechanical, repo-agnostic facts stay deterministic: the file walk
15
+ * and the universal build-output exclude list. Everything that requires
16
+ * understanding "what is this directory for" is the model's job — naming,
17
+ * monorepo tooling, framework, and taxonomy are all inferred, never
18
+ * assumed.
19
+ *
20
+ * Isolation invariant (port invariant 3): a workspace is NEVER emitted as
21
+ * `shared`. The flag is omitted (it normalizes to isolated); the operator
22
+ * opts in afterward (the skill asks).
13
23
  */
14
24
  import { type ComponentsConfig } from "@isaacriehm/cairn-state";
15
- import type { DetectionResult } from "./types.js";
16
25
  /**
17
- * Probe `repoRoot` for a component layout and return a `components:`
18
- * config block (raw yaml shape), or `null` when nothing is found.
19
- *
20
- * - 2+ monorepo packages with component dirs `workspaces` form.
21
- * - Exactly one package, or root-level dirs flat single-app form.
22
- *
23
- * `detection` is reserved for future stack-aware tuning; extension
24
- * detection is presence-driven so the result holds even when stack
25
- * signatures are absent (e.g. a Vue repo with no tsconfig).
26
+ * Detect the repo's component layout via the model and return a
27
+ * `components:` config block (raw yaml shape), or `null` when the repo
28
+ * carries no reusable UI components. Retries the model call once before
29
+ * giving up. There is no deterministic fallback by design: detection only
30
+ * ever runs inside an LLM coding agent, so "no model" means adoption is
31
+ * not happening at all.
26
32
  */
27
- export declare function detectComponentsConfig(repoRoot: string, _detection: DetectionResult): ComponentsConfig | null;
33
+ export declare function detectComponentsConfig(repoRoot: string): Promise<ComponentsConfig | null>;
28
34
  export type EnsureComponentsStatus =
29
35
  /** No `.cairn/config.yaml` — the repo isn't adopted; run `/cairn-adopt` first. */
30
36
  "not-adopted"
31
37
  /** A `components:` block already exists — left untouched (idempotent). */
32
38
  | "exists"
33
- /** No recognizable component layout on disk — nothing written (non-UI repo). */
39
+ /** No reusable UI components on disk — nothing written (non-UI repo). */
34
40
  | "none"
35
41
  /** A `components:` block was detected and merged into the config. */
36
42
  | "written";
@@ -43,9 +49,9 @@ export interface EnsureComponentsConfigResult {
43
49
  }
44
50
  /**
45
51
  * Backfill a `components:` block into an already-adopted repo's
46
- * `.cairn/config.yaml`. The same deterministic FS probe adoption Phase
47
- * 4-seed runs, but applied to a config that already exists — so it MERGES
48
- * the key in (preserving every other key) rather than writing a fresh file.
52
+ * `.cairn/config.yaml`. Runs the same LLM detection adoption Phase 4-seed
53
+ * runs, but MERGES the key into a config that already exists (preserving
54
+ * every other key) rather than writing a fresh file.
49
55
  *
50
56
  * Idempotent: a repo that already carries a `components:` block is left
51
57
  * untouched ("exists"). The standalone backfill path
@@ -53,7 +59,7 @@ export interface EnsureComponentsConfigResult {
53
59
  * is the only caller; adoption keeps using `detectComponentsConfig`
54
60
  * directly inside 4-seed.
55
61
  *
56
- * Isolation invariant (port invariant 3): monorepo workspaces are never
57
- * guessed as `shared` — the operator opts in afterward (the skill asks).
62
+ * Isolation invariant (port invariant 3): workspaces are never emitted as
63
+ * `shared` — the operator opts in afterward (the skill asks).
58
64
  */
59
- export declare function ensureComponentsConfig(repoRoot: string): EnsureComponentsConfigResult;
65
+ export declare function ensureComponentsConfig(repoRoot: string): Promise<EnsureComponentsConfigResult>;