plumbbob 0.6.5 → 0.8.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 (113) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/README.md +24 -7
  3. package/dist/cli-core.js +7 -2
  4. package/dist/lib/buildlog.js +5 -2
  5. package/dist/lib/check.js +33 -1
  6. package/dist/lib/git.js +17 -0
  7. package/dist/lib/intent.js +3 -2
  8. package/dist/lib/latch.js +97 -0
  9. package/dist/lib/orient.js +31 -1
  10. package/dist/lib/sidecar.js +116 -0
  11. package/dist/verbs/build.js +5 -1
  12. package/dist/verbs/checkpoint.js +61 -7
  13. package/dist/verbs/doctor.js +33 -2
  14. package/dist/verbs/finish.js +57 -1
  15. package/dist/verbs/revert.js +19 -1
  16. package/dist/verbs/start.js +22 -2
  17. package/dist/verbs/status.js +10 -3
  18. package/dist/verbs/turn.js +106 -0
  19. package/hooks/hooks.json +15 -0
  20. package/hooks/pre-bash-commit.sh +69 -0
  21. package/node_modules/checkride/CHANGELOG.md +111 -0
  22. package/node_modules/checkride/README.md +185 -20
  23. package/node_modules/checkride/dist/adapters.d.ts +9 -4
  24. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  25. package/node_modules/checkride/dist/adapters.js +62 -2
  26. package/node_modules/checkride/dist/adapters.js.map +1 -1
  27. package/node_modules/checkride/dist/agent-setup/hook.d.ts +63 -0
  28. package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -0
  29. package/node_modules/checkride/dist/agent-setup/hook.js +92 -0
  30. package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -0
  31. package/node_modules/checkride/dist/agent-setup/index.d.ts +8 -0
  32. package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -0
  33. package/node_modules/checkride/dist/agent-setup/index.js +7 -0
  34. package/node_modules/checkride/dist/agent-setup/index.js.map +1 -0
  35. package/node_modules/checkride/dist/atomic.d.ts +13 -0
  36. package/node_modules/checkride/dist/atomic.d.ts.map +1 -0
  37. package/node_modules/checkride/dist/atomic.js +24 -0
  38. package/node_modules/checkride/dist/atomic.js.map +1 -0
  39. package/node_modules/checkride/dist/baseline/command.d.ts +42 -0
  40. package/node_modules/checkride/dist/baseline/command.d.ts.map +1 -0
  41. package/node_modules/checkride/dist/baseline/command.js +58 -0
  42. package/node_modules/checkride/dist/baseline/command.js.map +1 -0
  43. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +41 -0
  44. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -0
  45. package/node_modules/checkride/dist/baseline/fingerprint.js +119 -0
  46. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -0
  47. package/node_modules/checkride/dist/baseline/index.d.ts +13 -0
  48. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -0
  49. package/node_modules/checkride/dist/baseline/index.js +10 -0
  50. package/node_modules/checkride/dist/baseline/index.js.map +1 -0
  51. package/node_modules/checkride/dist/baseline/store.d.ts +67 -0
  52. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -0
  53. package/node_modules/checkride/dist/baseline/store.js +110 -0
  54. package/node_modules/checkride/dist/baseline/store.js.map +1 -0
  55. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  56. package/node_modules/checkride/dist/cli.js +37 -3
  57. package/node_modules/checkride/dist/cli.js.map +1 -1
  58. package/node_modules/checkride/dist/config.d.ts +43 -3
  59. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  60. package/node_modules/checkride/dist/config.js +95 -22
  61. package/node_modules/checkride/dist/config.js.map +1 -1
  62. package/node_modules/checkride/dist/digest/digest.d.ts +52 -0
  63. package/node_modules/checkride/dist/digest/digest.d.ts.map +1 -0
  64. package/node_modules/checkride/dist/digest/digest.js +147 -0
  65. package/node_modules/checkride/dist/digest/digest.js.map +1 -0
  66. package/node_modules/checkride/dist/digest/index.d.ts +8 -0
  67. package/node_modules/checkride/dist/digest/index.d.ts.map +1 -0
  68. package/node_modules/checkride/dist/digest/index.js +7 -0
  69. package/node_modules/checkride/dist/digest/index.js.map +1 -0
  70. package/node_modules/checkride/dist/doctor.d.ts +4 -0
  71. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  72. package/node_modules/checkride/dist/doctor.js +33 -10
  73. package/node_modules/checkride/dist/doctor.js.map +1 -1
  74. package/node_modules/checkride/dist/index.d.ts +1 -1
  75. package/node_modules/checkride/dist/index.d.ts.map +1 -1
  76. package/node_modules/checkride/dist/index.js +1 -1
  77. package/node_modules/checkride/dist/index.js.map +1 -1
  78. package/node_modules/checkride/dist/init.d.ts +38 -0
  79. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  80. package/node_modules/checkride/dist/init.js +97 -8
  81. package/node_modules/checkride/dist/init.js.map +1 -1
  82. package/node_modules/checkride/dist/orchestrator.d.ts +58 -1
  83. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  84. package/node_modules/checkride/dist/orchestrator.js +155 -27
  85. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  86. package/node_modules/checkride/dist/pm/detect.d.ts +21 -0
  87. package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -0
  88. package/node_modules/checkride/dist/pm/detect.js +60 -0
  89. package/node_modules/checkride/dist/pm/detect.js.map +1 -0
  90. package/node_modules/checkride/dist/pm/index.d.ts +10 -0
  91. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -0
  92. package/node_modules/checkride/dist/pm/index.js +9 -0
  93. package/node_modules/checkride/dist/pm/index.js.map +1 -0
  94. package/node_modules/checkride/dist/pm/translate.d.ts +28 -0
  95. package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -0
  96. package/node_modules/checkride/dist/pm/translate.js +40 -0
  97. package/node_modules/checkride/dist/pm/translate.js.map +1 -0
  98. package/node_modules/checkride/package.json +20 -17
  99. package/node_modules/checkride/schema/checkride.config.schema.json +97 -0
  100. package/node_modules/checkride/schema/checkride.summary.schema.json +57 -0
  101. package/node_modules/checkride/templates/shared/cspell.json +1 -0
  102. package/node_modules/checkride/templates/shared/prettierrc.json +6 -0
  103. package/package.json +8 -4
  104. package/skills/pb-build/SKILL.md +32 -14
  105. package/skills/pb-finish/SKILL.md +5 -6
  106. package/skills/pb-harvest/SKILL.md +1 -2
  107. package/skills/pb-park/SKILL.md +1 -1
  108. package/skills/pb-plan/SKILL.md +37 -5
  109. package/skills/pb-refine/SKILL.md +0 -1
  110. package/skills/pb-status/SKILL.md +5 -1
  111. package/skills/pb-step/SKILL.md +5 -4
  112. package/skills/pb-verify/SKILL.md +26 -9
  113. package/templates/intent.md +4 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Claude Code Stop hook — the mechanical half of the agent contract.
3
+ *
4
+ * `init` and `checkride agent-setup` write an idempotent Stop hook into
5
+ * `.claude/settings.json`. It runs the project's `check` script as a hard gate:
6
+ * exit 2 blocks the agent from finishing while the pipeline is red, so "exit 0 =
7
+ * done" becomes enforcement, not just advice. The command uses the *detected*
8
+ * package manager's run form (`pnpm run check`, `npm run check`, `yarn run
9
+ * check`, `bun run check`) so the hook works in any repo, not only pnpm ones
10
+ * (b7). Merging is surgical: unrelated hooks, other Stop groups, and every other
11
+ * settings key are preserved, and re-applying with the same PM is a no-op.
12
+ *
13
+ * This module owns only the hook; the AGENTS.md stanza and the higher-level
14
+ * `agent-setup` command live in `init.ts`, which imports the writer here — a
15
+ * single direction, so there is no cycle.
16
+ */
17
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
18
+ import { dirname, join } from 'node:path';
19
+ import { detectPackageManager } from '../pm/index.js';
20
+ /** Project-shared Claude Code settings (committed), relative to the repo root. */
21
+ export const CLAUDE_SETTINGS_FILE = '.claude/settings.json';
22
+ /**
23
+ * Stable, package-manager-independent marker identifying checkride's Stop hook
24
+ * inside a settings file. The run prefix varies by PM, so identity keys on the
25
+ * guidance message, which does not.
26
+ */
27
+ const HOOK_SENTINEL = 'checkride: the gate is red';
28
+ /** True when a hook entry is checkride's (matched by the PM-independent sentinel). */
29
+ function isCheckrideHook(hook) {
30
+ return hook.type === 'command' && typeof hook.command === 'string' && hook.command.includes(HOOK_SENTINEL);
31
+ }
32
+ /**
33
+ * The Stop-hook command for `pm`: run the gate, and on red print guidance and
34
+ * exit 2 (the blocking code — a plain exit 1 lets the agent stop anyway).
35
+ */
36
+ export function stopHookCommand(pm) {
37
+ const run = `${pm} run check`;
38
+ const guidance = `${HOOK_SENTINEL} — read .check/summary.json, fix the failing slot, then finish (do not stop while checkride is red).`;
39
+ return `${run} || { echo '${guidance}' >&2; exit 2; }`;
40
+ }
41
+ /**
42
+ * Merge checkride's Stop hook into parsed settings, idempotently. An existing
43
+ * checkride hook (found by its sentinel) has its command refreshed in place;
44
+ * otherwise a new Stop group is appended. Sibling hooks in the same group, other
45
+ * Stop groups, and every unrelated settings key are left untouched, so applying
46
+ * twice with the same command yields deep-equal settings.
47
+ */
48
+ export function applyStopHook(settings, command) {
49
+ const hooks = { ...settings.hooks };
50
+ const stop = Array.isArray(hooks.Stop) ? hooks.Stop.map((g) => ({ ...g })) : [];
51
+ const idx = stop.findIndex((g) => (g.hooks ?? []).some(isCheckrideHook));
52
+ const existing = idx >= 0 ? stop[idx] : undefined;
53
+ if (existing) {
54
+ stop[idx] = {
55
+ ...existing,
56
+ hooks: (existing.hooks ?? []).map((h) => (isCheckrideHook(h) ? { ...h, command } : h)),
57
+ };
58
+ }
59
+ else {
60
+ stop.push({ hooks: [{ type: 'command', command }] });
61
+ }
62
+ return { ...settings, hooks: { ...hooks, Stop: stop } };
63
+ }
64
+ async function readIfExists(path) {
65
+ try {
66
+ return await readFile(path, 'utf8');
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ /**
73
+ * Write or refresh the Stop hook in `cwd/.claude/settings.json` for the detected
74
+ * (or provided) package manager, preserving any other settings. Returns whether
75
+ * the file changed: a second run with the same PM leaves it byte-identical, so
76
+ * `changed` is `false`. `dryRun` computes the result without writing.
77
+ */
78
+ export async function writeStopHook(cwd, opts = {}) {
79
+ const path = join(cwd, CLAUDE_SETTINGS_FILE);
80
+ const pm = opts.pm ?? detectPackageManager({ cwd });
81
+ const raw = await readIfExists(path);
82
+ const settings = raw ? JSON.parse(raw) : {};
83
+ const next = applyStopHook(settings, stopHookCommand(pm));
84
+ const nextRaw = `${JSON.stringify(next, null, 2)}\n`;
85
+ const changed = raw !== nextRaw;
86
+ if (changed && !opts.dryRun) {
87
+ await mkdir(dirname(path), { recursive: true });
88
+ await writeFile(path, nextRaw);
89
+ }
90
+ return { path: CLAUDE_SETTINGS_FILE, changed };
91
+ }
92
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/agent-setup/hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Agent-setup module — the Claude Code Stop hook (step 12). This barrel is the
3
+ * module's only public surface (C2): siblings import from `../agent-setup`,
4
+ * never from `./hook.js` directly.
5
+ */
6
+ export type { StopHookResult } from './hook.js';
7
+ export { applyStopHook, CLAUDE_SETTINGS_FILE, stopHookCommand, writeStopHook } from './hook.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent-setup/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Agent-setup module — the Claude Code Stop hook (step 12). This barrel is the
3
+ * module's only public surface (C2): siblings import from `../agent-setup`,
4
+ * never from `./hook.js` directly.
5
+ */
6
+ export { applyStopHook, CLAUDE_SETTINGS_FILE, stopHookCommand, writeStopHook } from './hook.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent-setup/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Crash-consistent artifact writes.
3
+ *
4
+ * Consumers parse `.check/summary.json` (and the digest, the raw slot files,
5
+ * and the committed baseline) as machine input; a run killed mid-write must
6
+ * never leave them a half-written file to read. Writing to a temp sibling
7
+ * and renaming into place makes each artifact either the previous complete
8
+ * version or the new complete version — `rename(2)` is atomic within a
9
+ * directory — never torn.
10
+ */
11
+ /** Write `data` to `path` atomically: temp sibling first, then rename over. */
12
+ export declare function writeFileAtomic(path: string, data: string): Promise<void>;
13
+ //# sourceMappingURL=atomic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic.d.ts","sourceRoot":"","sources":["../src/atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,+EAA+E;AAC/E,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/E"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Crash-consistent artifact writes.
3
+ *
4
+ * Consumers parse `.check/summary.json` (and the digest, the raw slot files,
5
+ * and the committed baseline) as machine input; a run killed mid-write must
6
+ * never leave them a half-written file to read. Writing to a temp sibling
7
+ * and renaming into place makes each artifact either the previous complete
8
+ * version or the new complete version — `rename(2)` is atomic within a
9
+ * directory — never torn.
10
+ */
11
+ import { rename, rm, writeFile } from 'node:fs/promises';
12
+ /** Write `data` to `path` atomically: temp sibling first, then rename over. */
13
+ export async function writeFileAtomic(path, data) {
14
+ const tmp = `${path}.${process.pid}.tmp`;
15
+ try {
16
+ await writeFile(tmp, data);
17
+ await rename(tmp, path);
18
+ }
19
+ catch (err) {
20
+ await rm(tmp, { force: true });
21
+ throw err;
22
+ }
23
+ }
24
+ //# sourceMappingURL=atomic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../src/atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEzD,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,IAAY;IAC9D,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC3B,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The `checkride baseline` command (baseline part 2).
3
+ *
4
+ * Runs the normal pipeline, fingerprints every fingerprintable slot's raw output
5
+ * (step 4's per-adapter extractors), and writes the result to
6
+ * `checkride.baseline.json` at repo root — beside `checkride.config.json`,
7
+ * committed, NOT under the gitignored `.check/` (D9). The file grandfathers a
8
+ * legacy repo's existing diagnostics so a later baseline-aware run (step 6) can
9
+ * subtract them and fail only on genuinely new findings.
10
+ *
11
+ * Only slots whose adapter has an extractor participate: a supported-but-clean
12
+ * slot records an empty array (it opted in and had nothing to grandfather),
13
+ * while a slot with no extractor (fallow, tsc, links, …) simply never appears —
14
+ * exactly the "supported vs. unsupported" distinction the fingerprint contract
15
+ * draws. Running each check under the resolved package manager and capturing raw
16
+ * output is delegated to {@link runChecks}, so baseline fingerprints precisely
17
+ * the bytes a normal run would.
18
+ */
19
+ import type { Adapter, Slot } from '../adapters.js';
20
+ import type { CheckrideConfig } from '../config.js';
21
+ import type { CheckRunner, Out } from '../orchestrator.js';
22
+ import type { PackageManager } from '../pm/index.js';
23
+ import type { Baseline } from './store.js';
24
+ export type BaselineOptions = {
25
+ cwd?: string;
26
+ slots?: readonly Slot[];
27
+ adapters?: readonly Adapter[];
28
+ config?: CheckrideConfig | null;
29
+ stdout?: Out;
30
+ stderr?: Out;
31
+ runner?: CheckRunner;
32
+ /** Package manager to run under; detected from `cwd` when omitted. */
33
+ pm?: PackageManager;
34
+ };
35
+ export type BaselineResult = {
36
+ ok: boolean;
37
+ exitCode: number;
38
+ baseline: Baseline;
39
+ };
40
+ /** Run the pipeline and write the per-adapter fingerprint baseline to `cwd`. */
41
+ export declare function runBaseline(options: BaselineOptions): Promise<BaselineResult>;
42
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/baseline/command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,GAAG,EAAc,MAAM,oBAAoB,CAAC;AAEvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sEAAsE;IACtE,EAAE,CAAC,EAAE,cAAc,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEnF,gFAAgF;AAChF,wBAAsB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAsCnF"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The `checkride baseline` command (baseline part 2).
3
+ *
4
+ * Runs the normal pipeline, fingerprints every fingerprintable slot's raw output
5
+ * (step 4's per-adapter extractors), and writes the result to
6
+ * `checkride.baseline.json` at repo root — beside `checkride.config.json`,
7
+ * committed, NOT under the gitignored `.check/` (D9). The file grandfathers a
8
+ * legacy repo's existing diagnostics so a later baseline-aware run (step 6) can
9
+ * subtract them and fail only on genuinely new findings.
10
+ *
11
+ * Only slots whose adapter has an extractor participate: a supported-but-clean
12
+ * slot records an empty array (it opted in and had nothing to grandfather),
13
+ * while a slot with no extractor (fallow, tsc, links, …) simply never appears —
14
+ * exactly the "supported vs. unsupported" distinction the fingerprint contract
15
+ * draws. Running each check under the resolved package manager and capturing raw
16
+ * output is delegated to {@link runChecks}, so baseline fingerprints precisely
17
+ * the bytes a normal run would.
18
+ */
19
+ import { runChecks } from '../orchestrator.js';
20
+ import { fingerprint } from './fingerprint.js';
21
+ import { BASELINE_FILE, BASELINE_SCHEMA_VERSION, writeBaseline } from './store.js';
22
+ /** Run the pipeline and write the per-adapter fingerprint baseline to `cwd`. */
23
+ export async function runBaseline(options) {
24
+ const cwd = options.cwd ?? process.cwd();
25
+ const stderr = options.stderr ?? process.stderr;
26
+ // json:false so the run reports progress on stderr and nothing on stdout; the
27
+ // baseline artifact is the file, so stdout stays clean (C5). baseline:null so a
28
+ // re-capture records the raw current diagnostics — never masked or pruned by an
29
+ // existing baseline the run would otherwise pick up (step 6).
30
+ const runOptions = {
31
+ cwd,
32
+ json: false,
33
+ stderr,
34
+ baseline: null,
35
+ ...(options.slots !== undefined ? { slots: options.slots } : {}),
36
+ ...(options.adapters !== undefined ? { adapters: options.adapters } : {}),
37
+ ...(options.config !== undefined ? { config: options.config } : {}),
38
+ ...(options.runner !== undefined ? { runner: options.runner } : {}),
39
+ ...(options.pm !== undefined ? { pm: options.pm } : {}),
40
+ ...(options.stdout !== undefined ? { stdout: options.stdout } : {}),
41
+ };
42
+ const result = await runChecks(runOptions);
43
+ const slots = {};
44
+ for (const run of result.runs) {
45
+ const keys = fingerprint(run.adapter.name, run.outcome.stdout);
46
+ if (keys === null)
47
+ continue;
48
+ slots[run.slot] = [...keys].toSorted();
49
+ }
50
+ const baseline = { schema_version: BASELINE_SCHEMA_VERSION, slots };
51
+ await writeBaseline(cwd, baseline);
52
+ const slotNames = Object.keys(slots);
53
+ const total = Object.values(slots).reduce((n, keys) => n + keys.length, 0);
54
+ const where = slotNames.length > 0 ? slotNames.join(', ') : '(no fingerprintable slots)';
55
+ stderr.write(`\nbaseline: wrote ${BASELINE_FILE} — ${total} diagnostic(s) across ${where}\n`);
56
+ return { ok: true, exitCode: 0, baseline };
57
+ }
58
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/baseline/command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Per-adapter diagnostic fingerprints (baseline part 1).
3
+ *
4
+ * A *fingerprint* is a stable, order-independent set of key strings extracted
5
+ * from one adapter's raw output. Each key names a single finding by what it is
6
+ * (`<file>:<rule>:<message>`) rather than where it sits, so a finding keeps its
7
+ * key when unrelated edits shift its line and column — that is what later lets
8
+ * the baseline (steps 5–6) subtract already-known findings without re-flagging
9
+ * them every time surrounding code moves.
10
+ *
11
+ * This is deliberately NOT a normalized diagnostic schema (D3): each adapter
12
+ * owns its own key string, the raw `.check/<slot>.json` stays authoritative, and
13
+ * an adapter whose output isn't a stable diagnostic set simply has no extractor
14
+ * and returns `null` — baseline is unsupported for that slot, decided
15
+ * per-adapter against real fixtures (D12), not from an up-front list. Step 4
16
+ * ships extractors for the blessed lint/struct/spell adapters (oxlint, ast-grep,
17
+ * cspell); fallow's cross-file findings (cycles, duplication) sit out for now
18
+ * (a4) and can gain a composite-key extractor later without touching this seam.
19
+ */
20
+ /** A stable, order-independent set of diagnostic keys for one adapter's output. */
21
+ export type Fingerprint = ReadonlySet<string>;
22
+ /** Turns one adapter's raw output (JSON or text) into a fingerprint. */
23
+ export type Extractor = (raw: string) => Fingerprint;
24
+ /**
25
+ * Fingerprint one adapter's raw output, or `null` when the adapter has no
26
+ * extractor (baseline unsupported for that slot). Keyed on adapter name, so an
27
+ * alternate tool that shares a slot with a supported default (biome/eslint for
28
+ * `lint`, knip for `dead`) opts out until it grows its own extractor. A
29
+ * supported adapter with zero findings returns an empty set, never `null` —
30
+ * "supported but clean" and "unsupported" are distinct, and steps 5–6 depend on
31
+ * the difference.
32
+ */
33
+ export declare function fingerprint(adapter: string, raw: string): Fingerprint | null;
34
+ /**
35
+ * Whether an adapter can be fingerprinted (has an extractor), decided by name
36
+ * without needing its output. `init --baseline` uses this to tell which failing
37
+ * slots the baseline can grandfather from those that must still fall back to a
38
+ * `false` disable.
39
+ */
40
+ export declare function isFingerprintable(adapter: string): boolean;
41
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAE9C,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,WAAW,CAAC;AAmFrD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAG5E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Per-adapter diagnostic fingerprints (baseline part 1).
3
+ *
4
+ * A *fingerprint* is a stable, order-independent set of key strings extracted
5
+ * from one adapter's raw output. Each key names a single finding by what it is
6
+ * (`<file>:<rule>:<message>`) rather than where it sits, so a finding keeps its
7
+ * key when unrelated edits shift its line and column — that is what later lets
8
+ * the baseline (steps 5–6) subtract already-known findings without re-flagging
9
+ * them every time surrounding code moves.
10
+ *
11
+ * This is deliberately NOT a normalized diagnostic schema (D3): each adapter
12
+ * owns its own key string, the raw `.check/<slot>.json` stays authoritative, and
13
+ * an adapter whose output isn't a stable diagnostic set simply has no extractor
14
+ * and returns `null` — baseline is unsupported for that slot, decided
15
+ * per-adapter against real fixtures (D12), not from an up-front list. Step 4
16
+ * ships extractors for the blessed lint/struct/spell adapters (oxlint, ast-grep,
17
+ * cspell); fallow's cross-file findings (cycles, duplication) sit out for now
18
+ * (a4) and can gain a composite-key extractor later without touching this seam.
19
+ */
20
+ /**
21
+ * Build a finding's key from its identity. Line and column are intentionally
22
+ * excluded so the key survives edits that only move the code; the message is
23
+ * whitespace-collapsed so cosmetic wrapping differences don't split one finding
24
+ * into two. `rule` is empty for tools (cspell) that don't name a rule.
25
+ */
26
+ function key(file, rule, message) {
27
+ return `${file}:${rule}:${message.replace(/\s+/g, ' ').trim()}`;
28
+ }
29
+ /** Parse JSON output defensively; malformed input yields `null`, never a throw. */
30
+ function parseJson(raw) {
31
+ try {
32
+ const parsed = JSON.parse(raw);
33
+ return parsed;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ /** Narrow to a plain object so string fields can be read without assertions. */
40
+ function isRecord(value) {
41
+ return typeof value === 'object' && value !== null;
42
+ }
43
+ /** Read a field as a string, or `''` when it is missing or not a string. */
44
+ function str(value) {
45
+ return typeof value === 'string' ? value : '';
46
+ }
47
+ /** Coerce an unknown to an array of unknowns (non-arrays become empty). */
48
+ function asArray(value) {
49
+ return Array.isArray(value) ? value : [];
50
+ }
51
+ /** oxlint `--format=json`: `{ diagnostics: [{ filename, code, message }] }`. */
52
+ const extractOxlint = (raw) => {
53
+ const keys = new Set();
54
+ const payload = parseJson(raw);
55
+ const diagnostics = isRecord(payload) ? asArray(payload['diagnostics']) : [];
56
+ for (const d of diagnostics) {
57
+ if (!isRecord(d))
58
+ continue;
59
+ const file = str(d['filename']);
60
+ const message = str(d['message']);
61
+ if (file && message)
62
+ keys.add(key(file, str(d['code']), message));
63
+ }
64
+ return keys;
65
+ };
66
+ /** ast-grep `--json=compact`: an array of `{ file, ruleId, message }`. */
67
+ const extractAstGrep = (raw) => {
68
+ const keys = new Set();
69
+ for (const m of asArray(parseJson(raw))) {
70
+ if (!isRecord(m))
71
+ continue;
72
+ const file = str(m['file']);
73
+ const message = str(m['message']);
74
+ if (file && message)
75
+ keys.add(key(file, str(m['ruleId']), message));
76
+ }
77
+ return keys;
78
+ };
79
+ /** cspell default reporter line: `<file>:<line>:<col> - <message>`. */
80
+ const CSPELL_LINE = /^(.+?):\d+:\d+ - (.+)$/;
81
+ /** cspell has no rule id, so its key is `<file>::<message>` (empty rule slot). */
82
+ const extractCspell = (raw) => {
83
+ const keys = new Set();
84
+ for (const line of raw.split('\n')) {
85
+ const m = CSPELL_LINE.exec(line.trim());
86
+ if (m)
87
+ keys.add(key(m[1] ?? '', '', m[2] ?? ''));
88
+ }
89
+ return keys;
90
+ };
91
+ /** Extractors keyed by adapter name (not slot); everything else sits out. */
92
+ const EXTRACTORS = {
93
+ oxlint: extractOxlint,
94
+ 'ast-grep': extractAstGrep,
95
+ cspell: extractCspell,
96
+ };
97
+ /**
98
+ * Fingerprint one adapter's raw output, or `null` when the adapter has no
99
+ * extractor (baseline unsupported for that slot). Keyed on adapter name, so an
100
+ * alternate tool that shares a slot with a supported default (biome/eslint for
101
+ * `lint`, knip for `dead`) opts out until it grows its own extractor. A
102
+ * supported adapter with zero findings returns an empty set, never `null` —
103
+ * "supported but clean" and "unsupported" are distinct, and steps 5–6 depend on
104
+ * the difference.
105
+ */
106
+ export function fingerprint(adapter, raw) {
107
+ const extractor = EXTRACTORS[adapter];
108
+ return extractor ? extractor(raw) : null;
109
+ }
110
+ /**
111
+ * Whether an adapter can be fingerprinted (has an extractor), decided by name
112
+ * without needing its output. `init --baseline` uses this to tell which failing
113
+ * slots the baseline can grandfather from those that must still fall back to a
114
+ * `false` disable.
115
+ */
116
+ export function isFingerprintable(adapter) {
117
+ return EXTRACTORS[adapter] !== undefined;
118
+ }
119
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Baseline module — per-adapter diagnostic fingerprints (step 4) and, in later
3
+ * steps, the baseline read/write/ratchet built on top of them. This barrel is
4
+ * the module's only public surface (C2): siblings import from `../baseline`,
5
+ * never from `./fingerprint.js` directly.
6
+ */
7
+ export type { Extractor, Fingerprint } from './fingerprint.js';
8
+ export { fingerprint, isFingerprintable } from './fingerprint.js';
9
+ export type { Baseline, BaselineAdjustment } from './store.js';
10
+ export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, ratchet, writeBaseline, } from './store.js';
11
+ export type { BaselineOptions, BaselineResult } from './command.js';
12
+ export { runBaseline } from './command.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Baseline module — per-adapter diagnostic fingerprints (step 4) and, in later
3
+ * steps, the baseline read/write/ratchet built on top of them. This barrel is
4
+ * the module's only public surface (C2): siblings import from `../baseline`,
5
+ * never from `./fingerprint.js` directly.
6
+ */
7
+ export { fingerprint, isFingerprintable } from './fingerprint.js';
8
+ export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, ratchet, writeBaseline, } from './store.js';
9
+ export { runBaseline } from './command.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The baseline artifact: its on-disk shape and the pure read / write / apply /
3
+ * ratchet operations a baseline-aware run (step 6) is built from.
4
+ *
5
+ * This file imports nothing from the orchestrator on purpose: the `baseline`
6
+ * command (command.ts) bridges to the run pipeline, but a *run* only needs to
7
+ * mask and ratchet an already-captured baseline, so the orchestrator can depend
8
+ * on these helpers without a load-order cycle. Keeping the file I/O and the
9
+ * set algebra here (not in the orchestrator) also preserves the orchestrator's
10
+ * "never parse diagnostics" thesis — fingerprinting stays inside this module.
11
+ */
12
+ import type { Fingerprint } from './fingerprint.js';
13
+ /** The committed baseline artifact, at repo root beside `checkride.config.json`. */
14
+ export declare const BASELINE_FILE = "checkride.baseline.json";
15
+ /** Schema version of the baseline file; independent of the summary schema (D8). */
16
+ export declare const BASELINE_SCHEMA_VERSION = 1;
17
+ /** Shape of `checkride.baseline.json`: per-slot sets of grandfathered keys. */
18
+ export type Baseline = {
19
+ schema_version: number;
20
+ slots: Record<string, string[]>;
21
+ };
22
+ /** The result of masking one slot's current fingerprint with its baseline. */
23
+ export type BaselineAdjustment = {
24
+ /** Grandfathered-adjusted pass: the failure is fully explained by known debt. */
25
+ ok: boolean;
26
+ /** How many current diagnostics the baseline suppressed (the `baselined` count). */
27
+ baselined: number;
28
+ /** Sorted diagnostics present now that the baseline does NOT grandfather. */
29
+ newKeys: string[];
30
+ };
31
+ /**
32
+ * Read `checkride.baseline.json` from `cwd`; `null` when absent or unusable. The
33
+ * baseline is a committed file a run reads on every invocation, so a malformed
34
+ * one is coerced into a clean shape (or dropped) rather than thrown — a corrupt
35
+ * baseline must never break `checkride`.
36
+ */
37
+ export declare function loadBaseline(cwd: string): Baseline | null;
38
+ /** Serialize and write the baseline to `cwd` (pretty-printed, trailing newline, atomic). */
39
+ export declare function writeBaseline(cwd: string, baseline: Baseline): Promise<void>;
40
+ /**
41
+ * Mask one slot's current fingerprint with its grandfathered keys. Masking is
42
+ * pure set subtraction: `newKeys` are the current diagnostics the baseline does
43
+ * not cover, `baselined` counts the ones it does.
44
+ *
45
+ * The failure flips to a pass *only* when there are current diagnostics and none
46
+ * of them are new — a tool that produced no parseable diagnostics (a crash, empty
47
+ * output that fingerprints to the empty set) is never masked, so a genuine
48
+ * breakage still fails even while a baseline is active. Correctness beats
49
+ * precision: better to re-surface a masked finding than to silently green a crash.
50
+ */
51
+ export declare function applyBaseline(current: Fingerprint, baselinedKeys: readonly string[], rawOk: boolean): BaselineAdjustment;
52
+ /**
53
+ * Ratchet the baseline against a fully-observed run: for every slot observed this
54
+ * run, keep only the grandfathered keys still present (a fixed diagnostic is
55
+ * dropped); a slot absent from `observed` — disabled, without an extractor, or
56
+ * not run — is preserved untouched. The result never grows: genuinely new findings
57
+ * are the run's failures, not new debt, so only a `checkride baseline` capture
58
+ * ever adds keys. Callers gate this on a full run (no `--only`/`--skip`/
59
+ * `--changed`, no early `--bail` break) so a partial run can't prune keys it
60
+ * simply didn't observe (a1).
61
+ */
62
+ export declare function ratchet(baseline: Baseline, observed: ReadonlyMap<string, Fingerprint>): Baseline;
63
+ /** Total grandfathered diagnostics across every slot. */
64
+ export declare function countBaselineKeys(baseline: Baseline): number;
65
+ /** Order-independent structural equality, so an unchanged ratchet skips its write. */
66
+ export declare function baselinesEqual(a: Baseline, b: Baseline): boolean;
67
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/baseline/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,oFAAoF;AACpF,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAEvD,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,+EAA+E;AAC/E,MAAM,MAAM,QAAQ,GAAG;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iFAAiF;IACjF,EAAE,EAAE,OAAO,CAAC;IACZ,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAOF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAezD;AAED,4FAA4F;AAC5F,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,KAAK,EAAE,OAAO,GACb,kBAAkB,CAUpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,QAAQ,CAOhG;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE5D;AASD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEhE"}