plumbbob 0.9.5 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +87 -86
- package/dist/cli-core.js +8 -8
- package/dist/cli.js +1 -1
- package/dist/lib/agents.js +26 -26
- package/dist/lib/buildlog.js +11 -11
- package/dist/lib/buildlogsync.js +8 -8
- package/dist/lib/check.js +14 -14
- package/dist/lib/commitbody.js +72 -0
- package/dist/lib/commitmsg.js +7 -7
- package/dist/lib/git.js +44 -15
- package/dist/lib/intent.js +20 -19
- package/dist/lib/latch.js +16 -16
- package/dist/lib/orient.js +36 -17
- package/dist/lib/reentry.js +3 -3
- package/dist/lib/settings.js +16 -16
- package/dist/lib/sidecar.js +54 -54
- package/dist/lib/templates.js +1 -1
- package/dist/verbs/agent.js +25 -25
- package/dist/verbs/build.js +9 -9
- package/dist/verbs/check.js +6 -6
- package/dist/verbs/checkpoint.js +48 -47
- package/dist/verbs/doctor.js +27 -26
- package/dist/verbs/finish.js +27 -40
- package/dist/verbs/handoff.js +9 -8
- package/dist/verbs/init.js +9 -9
- package/dist/verbs/park.js +3 -3
- package/dist/verbs/recover.js +11 -11
- package/dist/verbs/revert.js +12 -12
- package/dist/verbs/spike.js +17 -17
- package/dist/verbs/start.js +49 -19
- package/dist/verbs/status.js +8 -8
- package/dist/verbs/turn.js +16 -16
- package/dist/verbs/use.js +4 -4
- package/node_modules/checkride/.claude-plugin/plugin.json +1 -1
- package/node_modules/checkride/CHANGELOG.md +401 -0
- package/node_modules/checkride/README.md +27 -9
- package/node_modules/checkride/dist/adapters.d.ts +12 -4
- package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
- package/node_modules/checkride/dist/adapters.js +21 -1
- package/node_modules/checkride/dist/adapters.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts +9 -1
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/cursor.js +59 -1
- package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/harness.d.ts +1 -1
- package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/harness.js +10 -1
- package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts +23 -0
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/scripts.js +387 -82
- package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fallow.js +2 -2
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts +14 -5
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.js +58 -5
- package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
- package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
- package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/history.js +232 -0
- package/node_modules/checkride/dist/baseline/history.js.map +1 -0
- package/node_modules/checkride/dist/baseline/index.d.ts +4 -2
- package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/index.js +2 -1
- package/node_modules/checkride/dist/baseline/index.js.map +1 -1
- package/node_modules/checkride/dist/baseline/store.d.ts +30 -7
- package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/store.js +50 -16
- package/node_modules/checkride/dist/baseline/store.js.map +1 -1
- package/node_modules/checkride/dist/cli.d.ts +5 -1
- package/node_modules/checkride/dist/cli.d.ts.map +1 -1
- package/node_modules/checkride/dist/cli.js +98 -25
- package/node_modules/checkride/dist/cli.js.map +1 -1
- package/node_modules/checkride/dist/config.d.ts +33 -4
- package/node_modules/checkride/dist/config.d.ts.map +1 -1
- package/node_modules/checkride/dist/config.js +21 -6
- package/node_modules/checkride/dist/config.js.map +1 -1
- package/node_modules/checkride/dist/digest/digest.js +1 -1
- package/node_modules/checkride/dist/doctor.d.ts +2 -0
- package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
- package/node_modules/checkride/dist/doctor.js +39 -1
- package/node_modules/checkride/dist/doctor.js.map +1 -1
- package/node_modules/checkride/dist/gate.d.ts +49 -4
- package/node_modules/checkride/dist/gate.d.ts.map +1 -1
- package/node_modules/checkride/dist/gate.js +143 -16
- package/node_modules/checkride/dist/gate.js.map +1 -1
- package/node_modules/checkride/dist/init.d.ts +8 -1
- package/node_modules/checkride/dist/init.d.ts.map +1 -1
- package/node_modules/checkride/dist/init.js +68 -7
- package/node_modules/checkride/dist/init.js.map +1 -1
- package/node_modules/checkride/dist/node-pin.d.ts +1 -1
- package/node_modules/checkride/dist/node-pin.js +1 -1
- package/node_modules/checkride/dist/orchestrator.d.ts +13 -0
- package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
- package/node_modules/checkride/dist/orchestrator.js +118 -13
- package/node_modules/checkride/dist/orchestrator.js.map +1 -1
- package/node_modules/checkride/dist/pm/index.d.ts +1 -0
- package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/index.js.map +1 -1
- package/node_modules/checkride/dist/pm/launch.d.ts +23 -2
- package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/launch.js +16 -0
- package/node_modules/checkride/dist/pm/launch.js.map +1 -1
- package/node_modules/checkride/dist/pm/translate.js +1 -1
- package/node_modules/checkride/dist/pm/translate.js.map +1 -1
- package/node_modules/checkride/dist/qa/mutation.d.ts +4 -4
- package/node_modules/checkride/dist/qa/mutation.js +4 -4
- package/node_modules/checkride/dist/recover.d.ts +48 -0
- package/node_modules/checkride/dist/recover.d.ts.map +1 -0
- package/node_modules/checkride/dist/recover.js +220 -0
- package/node_modules/checkride/dist/recover.js.map +1 -0
- package/node_modules/checkride/dist/smoke.d.ts +1 -1
- package/node_modules/checkride/dist/smoke.js +1 -1
- package/node_modules/checkride/dist/snippets.d.ts +1 -1
- package/node_modules/checkride/package.json +3 -2
- package/node_modules/checkride/schema/checkride.config.schema.json +9 -1
- package/node_modules/checkride/skills/check/SKILL.md +9 -1
- package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
- package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
- package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
- package/node_modules/checkride/templates/shared/vale.ini +34 -0
- package/package.json +10 -9
- package/skills/build/SKILL.md +69 -64
- package/skills/doctor/SKILL.md +11 -11
- package/skills/finish/SKILL.md +20 -19
- package/skills/harvest/SKILL.md +13 -12
- package/skills/park/SKILL.md +10 -10
- package/skills/plan/SKILL.md +63 -54
- package/skills/recover/SKILL.md +6 -6
- package/skills/refine/SKILL.md +18 -16
- package/skills/revert/SKILL.md +6 -6
- package/skills/spike/SKILL.md +9 -9
- package/skills/status/SKILL.md +5 -5
- package/skills/step/SKILL.md +17 -12
- package/skills/verify/SKILL.md +45 -40
- package/templates/build-log.md +7 -7
- package/templates/intent.md +49 -39
- package/templates/spike-report.md +10 -10
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* an adapter whose output isn't a stable diagnostic set simply has no extractor
|
|
14
14
|
* and returns `null` — baseline is unsupported for that slot, decided
|
|
15
15
|
* per-adapter against real fixtures, not from an up-front list. Extractors
|
|
16
|
-
* ship for the blessed lint/struct/spell adapters (oxlint, ast-grep,
|
|
17
|
-
* for fallow's three analyses (dead-code, dupes, health — see
|
|
18
|
-
* which also owns fallow's gating verdict).
|
|
16
|
+
* ship for the blessed lint/struct/spell/prose adapters (oxlint, ast-grep,
|
|
17
|
+
* cspell, vale) and for fallow's three analyses (dead-code, dupes, health — see
|
|
18
|
+
* `./fallow.ts`, which also owns fallow's gating verdict).
|
|
19
19
|
*/
|
|
20
20
|
/** A stable, order-independent set of diagnostic keys for one adapter's output. */
|
|
21
21
|
export type Fingerprint = ReadonlySet<string>;
|
|
@@ -25,15 +25,24 @@ export type Fingerprint = ReadonlySet<string>;
|
|
|
25
25
|
* alternate tool that shares a slot with a supported default (biome/eslint for
|
|
26
26
|
* `lint`, knip for `dead`) opts out until it grows its own extractor. A
|
|
27
27
|
* supported adapter with zero findings returns an empty set, never `null` —
|
|
28
|
-
* "supported but clean" and "
|
|
28
|
+
* "supported but clean" and "not observed" are distinct, and masking and the
|
|
29
29
|
* ratchet depend on the difference.
|
|
30
|
+
*
|
|
31
|
+
* `null` therefore has two readings, and callers treat them the same way: no
|
|
32
|
+
* extractor for this adapter (decided by name, before any output), or an
|
|
33
|
+
* extractor that read its output and could not trust it — vale's runtime-error
|
|
34
|
+
* report being the one case a format can say that about (see
|
|
35
|
+
* {@link extractVale}). Either way the run contributes nothing to the baseline
|
|
36
|
+
* and prunes nothing from it.
|
|
30
37
|
*/
|
|
31
38
|
export declare function fingerprint(adapter: string, raw: string): Fingerprint | null;
|
|
32
39
|
/**
|
|
33
40
|
* Whether an adapter can be fingerprinted (has an extractor), decided by name
|
|
34
41
|
* without needing its output. `init --baseline` uses this to tell which failing
|
|
35
42
|
* slots the baseline can grandfather from those that must still fall back to a
|
|
36
|
-
* `false` disable.
|
|
43
|
+
* `false` disable. It answers for the adapter, not for a particular run: a
|
|
44
|
+
* fingerprintable adapter can still yield `null` on output it can't trust, in
|
|
45
|
+
* which case that run simply grandfathers nothing.
|
|
37
46
|
*/
|
|
38
47
|
export declare function isFingerprintable(adapter: string): boolean;
|
|
39
48
|
//# sourceMappingURL=fingerprint.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAyI9C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAG5E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D"}
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* an adapter whose output isn't a stable diagnostic set simply has no extractor
|
|
14
14
|
* and returns `null` — baseline is unsupported for that slot, decided
|
|
15
15
|
* per-adapter against real fixtures, not from an up-front list. Extractors
|
|
16
|
-
* ship for the blessed lint/struct/spell adapters (oxlint, ast-grep,
|
|
17
|
-
* for fallow's three analyses (dead-code, dupes, health — see
|
|
18
|
-
* which also owns fallow's gating verdict).
|
|
16
|
+
* ship for the blessed lint/struct/spell/prose adapters (oxlint, ast-grep,
|
|
17
|
+
* cspell, vale) and for fallow's three analyses (dead-code, dupes, health — see
|
|
18
|
+
* `./fallow.ts`, which also owns fallow's gating verdict).
|
|
19
19
|
*/
|
|
20
20
|
import { isRecord } from '../json.js';
|
|
21
21
|
import { parseToolJson } from '../tool-json.js';
|
|
@@ -86,11 +86,55 @@ const extractCspell = (raw) => {
|
|
|
86
86
|
}
|
|
87
87
|
return keys;
|
|
88
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* Whether a parsed vale payload is an *alert report* — the `{ "<path>": [alert,
|
|
91
|
+
* …] }` shape a lint run emits — rather than one of the flat runtime-error
|
|
92
|
+
* objects (`{ Code: "E100" | "E201", Text, Path, Line, Span }`) it emits instead
|
|
93
|
+
* when the config won't load. Every value of an alert report is an array of
|
|
94
|
+
* alerts; an error report's are scalars, so the two never look alike. A clean
|
|
95
|
+
* run's `{}` passes vacuously, which is the point: "clean" must stay
|
|
96
|
+
* distinguishable from "broken".
|
|
97
|
+
*/
|
|
98
|
+
function isValeAlertReport(payload) {
|
|
99
|
+
return (isRecord(payload) && Object.values(payload).every((alerts) => Array.isArray(alerts) && alerts.every(isRecord)));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* vale `--output=JSON`: `{ "<path>": [{ Check, Message, Severity }] }`.
|
|
103
|
+
*
|
|
104
|
+
* Only error-severity alerts are keyed. Vale's exit code — the `prose` slot's
|
|
105
|
+
* whole verdict — is 1 iff an error-severity alert exists, so a warning can
|
|
106
|
+
* never fail a check; fingerprinting one would hand an advisory alert gating
|
|
107
|
+
* power in a baselined repo (a new warning key blocks masking on an otherwise
|
|
108
|
+
* grandfathered red run) and churn the ratchet with keys no verdict can use.
|
|
109
|
+
*
|
|
110
|
+
* Returns `null` — never the empty set — for anything that is not an alert
|
|
111
|
+
* report. A runtime error (`E100` no config, `E201` bad config) is a flat object
|
|
112
|
+
* that an alert-shaped reader would happily see as zero findings, and one such
|
|
113
|
+
* run would prune every grandfathered prose key out of the baseline on the next
|
|
114
|
+
* ratchet. `null` means "not observed", which leaves the baseline standing.
|
|
115
|
+
*/
|
|
116
|
+
const extractVale = (raw) => {
|
|
117
|
+
const payload = parseJson(raw);
|
|
118
|
+
if (!isValeAlertReport(payload))
|
|
119
|
+
return null;
|
|
120
|
+
const keys = new Set();
|
|
121
|
+
for (const [file, alerts] of Object.entries(payload)) {
|
|
122
|
+
for (const a of alerts) {
|
|
123
|
+
if (str(a['Severity']) !== 'error')
|
|
124
|
+
continue;
|
|
125
|
+
const message = str(a['Message']);
|
|
126
|
+
if (file && message)
|
|
127
|
+
keys.add(key(file, str(a['Check']), message));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return keys;
|
|
131
|
+
};
|
|
89
132
|
/** Extractors keyed by adapter name (not slot); everything else sits out. */
|
|
90
133
|
const EXTRACTORS = {
|
|
91
134
|
oxlint: extractOxlint,
|
|
92
135
|
'ast-grep': extractAstGrep,
|
|
93
136
|
cspell: extractCspell,
|
|
137
|
+
vale: extractVale,
|
|
94
138
|
// One `fallow` adapter fills all three fallow slots (dead/dupes/health); its
|
|
95
139
|
// extractor dispatches on the report's `kind`, so a single registration serves
|
|
96
140
|
// every slot. See `./fallow.ts`.
|
|
@@ -102,8 +146,15 @@ const EXTRACTORS = {
|
|
|
102
146
|
* alternate tool that shares a slot with a supported default (biome/eslint for
|
|
103
147
|
* `lint`, knip for `dead`) opts out until it grows its own extractor. A
|
|
104
148
|
* supported adapter with zero findings returns an empty set, never `null` —
|
|
105
|
-
* "supported but clean" and "
|
|
149
|
+
* "supported but clean" and "not observed" are distinct, and masking and the
|
|
106
150
|
* ratchet depend on the difference.
|
|
151
|
+
*
|
|
152
|
+
* `null` therefore has two readings, and callers treat them the same way: no
|
|
153
|
+
* extractor for this adapter (decided by name, before any output), or an
|
|
154
|
+
* extractor that read its output and could not trust it — vale's runtime-error
|
|
155
|
+
* report being the one case a format can say that about (see
|
|
156
|
+
* {@link extractVale}). Either way the run contributes nothing to the baseline
|
|
157
|
+
* and prunes nothing from it.
|
|
107
158
|
*/
|
|
108
159
|
export function fingerprint(adapter, raw) {
|
|
109
160
|
const extractor = EXTRACTORS[adapter];
|
|
@@ -113,7 +164,9 @@ export function fingerprint(adapter, raw) {
|
|
|
113
164
|
* Whether an adapter can be fingerprinted (has an extractor), decided by name
|
|
114
165
|
* without needing its output. `init --baseline` uses this to tell which failing
|
|
115
166
|
* slots the baseline can grandfather from those that must still fall back to a
|
|
116
|
-
* `false` disable.
|
|
167
|
+
* `false` disable. It answers for the adapter, not for a particular run: a
|
|
168
|
+
* fingerprintable adapter can still yield `null` on output it can't trust, in
|
|
169
|
+
* which case that run simply grandfathers nothing.
|
|
117
170
|
*/
|
|
118
171
|
export function isFingerprintable(adapter) {
|
|
119
172
|
return EXTRACTORS[adapter] !== undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/baseline/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAe7C;;;;;GAKG;AACH,SAAS,GAAG,CAAC,IAAY,EAAE,IAAY,EAAE,OAAe;IACtD,OAAO,GAAG,IAAI,IAAI,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AAC3C,CAAC;AAED,4EAA4E;AAC5E,SAAS,GAAG,CAAC,KAAc;IACzB,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC;AAED,2EAA2E;AAC3E,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,gFAAgF;AAChF,MAAM,aAAa,GAAc,CAAC,GAAG,EAAE,EAAE;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAClC,IAAI,IAAI,IAAI,OAAO;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,cAAc,GAAc,CAAC,GAAG,EAAE,EAAE;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAClC,IAAI,IAAI,IAAI,OAAO;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,uEAAuE;AACvE,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAE7C,kFAAkF;AAClF,MAAM,aAAa,GAAc,CAAC,GAAG,EAAE,EAAE;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,SAAS,iBAAiB,CAAC,OAAgB;IACzC,OAAO,CACL,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAC/G,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,GAAc,CAAC,GAAG,EAAE,EAAE;IACrC,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,OAAO;gBAAE,SAAS;YAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YAClC,IAAI,IAAI,IAAI,OAAO;gBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,6EAA6E;AAC7E,MAAM,UAAU,GAAwC;IACtD,MAAM,EAAE,aAAa;IACrB,UAAU,EAAE,cAAc;IAC1B,MAAM,EAAE,aAAa;IACrB,IAAI,EAAE,WAAW;IACjB,6EAA6E;IAC7E,+EAA+E;IAC/E,iCAAiC;IACjC,MAAM,EAAE,cAAc;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,GAAW;IACtD,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git plumbing for baseline recovery: reconstruct recent committed states of
|
|
3
|
+
* `checkride.baseline.json` so a clobbered file (a botched merge, an agent
|
|
4
|
+
* resolving a conflict by deleting the "problem" lines) can be restored without
|
|
5
|
+
* manual archaeology. Everything here is read-only toward git — recovery writes
|
|
6
|
+
* the file through `writeBaseline`, never `git checkout`, so a restore lands as
|
|
7
|
+
* an ordinary reviewable working-tree edit.
|
|
8
|
+
*
|
|
9
|
+
* `git log --follow` is deliberately not used: the baseline's name and location
|
|
10
|
+
* are constants ({@link BASELINE_FILE}), so history beyond a rename boundary
|
|
11
|
+
* would describe a different file — and a repo that renamed the baseline is not
|
|
12
|
+
* running stock checkride anyway.
|
|
13
|
+
*/
|
|
14
|
+
import type { Baseline } from './store.js';
|
|
15
|
+
/** Why a git invocation failed, classified for user-facing messages. */
|
|
16
|
+
export type GitFailure = 'missing' | 'not-a-repo' | 'timeout' | 'failed';
|
|
17
|
+
export type GitResult = {
|
|
18
|
+
ok: true;
|
|
19
|
+
stdout: string;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
error: GitFailure;
|
|
23
|
+
detail: string;
|
|
24
|
+
};
|
|
25
|
+
/** Runs `git <args>`; injectable so history logic is testable without a repo. */
|
|
26
|
+
export type GitRunner = (args: readonly string[]) => Promise<GitResult>;
|
|
27
|
+
/** Commits of file history walked when `--depth` is not given. */
|
|
28
|
+
export declare const DEFAULT_DEPTH = 25;
|
|
29
|
+
/** The real runner: `git` under `cwd`, with a timeout so recovery can't hang. */
|
|
30
|
+
export declare function realGit(cwd: string, timeoutMs?: number): GitRunner;
|
|
31
|
+
/** The user-facing error for a failed git invocation; `runCli` renders it as exit 2. */
|
|
32
|
+
export declare function gitFailureError(result: {
|
|
33
|
+
error: GitFailure;
|
|
34
|
+
detail: string;
|
|
35
|
+
}): Error;
|
|
36
|
+
/** One commit that touched the baseline file. */
|
|
37
|
+
export type BaselineRevision = {
|
|
38
|
+
sha: string;
|
|
39
|
+
shortSha: string;
|
|
40
|
+
date: string;
|
|
41
|
+
author: string;
|
|
42
|
+
subject: string;
|
|
43
|
+
};
|
|
44
|
+
export type Candidate = {
|
|
45
|
+
kind: 'snapshot';
|
|
46
|
+
rev: BaselineRevision;
|
|
47
|
+
baseline: Baseline;
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'union';
|
|
50
|
+
baseline: Baseline;
|
|
51
|
+
folded: number;
|
|
52
|
+
};
|
|
53
|
+
export type HistoryScan = {
|
|
54
|
+
/** Union first (when it adds anything), then distinct snapshots newest-first. */
|
|
55
|
+
candidates: Candidate[];
|
|
56
|
+
/** Commits whose snapshot was actually examined (≤ the log's length). */
|
|
57
|
+
walked: number;
|
|
58
|
+
/** Short shas whose blob was unreadable or unparseable — skipped, never fatal. */
|
|
59
|
+
skipped: string[];
|
|
60
|
+
/** A shallow clone's log is truncated; said in the report, never an error. */
|
|
61
|
+
shallow: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** Whether the working-tree baseline carries uncommitted changes. */
|
|
64
|
+
export declare function baselineDirty(git: GitRunner): Promise<boolean>;
|
|
65
|
+
export declare function collectCandidates(git: GitRunner, current: Baseline | null, depth: number): Promise<HistoryScan>;
|
|
66
|
+
/** Per-slot key union of every part, canonical (sorted slots and keys). */
|
|
67
|
+
export declare function unionBaselines(parts: readonly Baseline[]): Baseline;
|
|
68
|
+
/** What the red-run probe found: `matched` of `total` new keys were grandfathered at `shortSha`. */
|
|
69
|
+
export type HistoricalHint = {
|
|
70
|
+
matched: number;
|
|
71
|
+
total: number;
|
|
72
|
+
shortSha: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The red-run detection probe: were these "new" findings grandfathered in a
|
|
76
|
+
* recent committed baseline? The difference between "a wall of new debt" and
|
|
77
|
+
* "a merge dropped baseline entries" is a diagnosis the run output alone
|
|
78
|
+
* cannot make. Strictly best-effort: the whole probe races a
|
|
79
|
+
* {@link HINT_BUDGET_MS} budget, its git children carry the same short
|
|
80
|
+
* timeout, and any failure — git absent, not a repository, shallow miss,
|
|
81
|
+
* mangled blobs — resolves to `null`, never a thrown error or a slow run.
|
|
82
|
+
*/
|
|
83
|
+
export declare function historicalHint(cwd: string, newKeys: readonly string[], git?: GitRunner, budgetMs?: number): Promise<HistoricalHint | null>;
|
|
84
|
+
/** What applying `to` over `from` changes, per slot: keys gained and keys lost. */
|
|
85
|
+
export type BaselineDelta = {
|
|
86
|
+
restored: Record<string, string[]>;
|
|
87
|
+
absent: Record<string, string[]>;
|
|
88
|
+
restoredCount: number;
|
|
89
|
+
absentCount: number;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* `restored` is what an apply adds; `absent` is what only an `--exact` apply
|
|
93
|
+
* would drop (the default union write never removes a key, so its `absent` side
|
|
94
|
+
* is empty by construction — the renderer still shows it so `--exact`'s cost is
|
|
95
|
+
* visible before it is paid).
|
|
96
|
+
*/
|
|
97
|
+
export declare function diffBaselines(from: Baseline | null, to: Baseline): BaselineDelta;
|
|
98
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/baseline/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git plumbing for baseline recovery: reconstruct recent committed states of
|
|
3
|
+
* `checkride.baseline.json` so a clobbered file (a botched merge, an agent
|
|
4
|
+
* resolving a conflict by deleting the "problem" lines) can be restored without
|
|
5
|
+
* manual archaeology. Everything here is read-only toward git — recovery writes
|
|
6
|
+
* the file through `writeBaseline`, never `git checkout`, so a restore lands as
|
|
7
|
+
* an ordinary reviewable working-tree edit.
|
|
8
|
+
*
|
|
9
|
+
* `git log --follow` is deliberately not used: the baseline's name and location
|
|
10
|
+
* are constants ({@link BASELINE_FILE}), so history beyond a rename boundary
|
|
11
|
+
* would describe a different file — and a repo that renamed the baseline is not
|
|
12
|
+
* running stock checkride anyway.
|
|
13
|
+
*/
|
|
14
|
+
import { execFile } from 'node:child_process';
|
|
15
|
+
import { promisify } from 'node:util';
|
|
16
|
+
import { BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, parseBaseline } from './store.js';
|
|
17
|
+
const execFileP = promisify(execFile);
|
|
18
|
+
const GIT_TIMEOUT_MS = 10_000;
|
|
19
|
+
/** A monorepo baseline can be large; a `git show` must not be truncated mid-blob. */
|
|
20
|
+
const GIT_MAX_BUFFER = 64 * 1024 * 1024;
|
|
21
|
+
/** At most this many distinct snapshots are presented — a small set to choose from. */
|
|
22
|
+
const MAX_SNAPSHOTS = 5;
|
|
23
|
+
/** Commits of file history walked when `--depth` is not given. */
|
|
24
|
+
export const DEFAULT_DEPTH = 25;
|
|
25
|
+
/** The `code`/`killed`/`stderr` shape of a rejected `execFile`, checked not cast. */
|
|
26
|
+
function rejection(err) {
|
|
27
|
+
if (typeof err !== 'object' || err === null)
|
|
28
|
+
return {};
|
|
29
|
+
const out = {};
|
|
30
|
+
if ('code' in err && typeof err.code === 'string')
|
|
31
|
+
out.code = err.code;
|
|
32
|
+
if ('killed' in err && typeof err.killed === 'boolean')
|
|
33
|
+
out.killed = err.killed;
|
|
34
|
+
if ('stderr' in err && typeof err.stderr === 'string')
|
|
35
|
+
out.stderr = err.stderr;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** The real runner: `git` under `cwd`, with a timeout so recovery can't hang. */
|
|
39
|
+
export function realGit(cwd, timeoutMs = GIT_TIMEOUT_MS) {
|
|
40
|
+
return async (args) => {
|
|
41
|
+
try {
|
|
42
|
+
const { stdout } = await execFileP('git', [...args], { cwd, timeout: timeoutMs, maxBuffer: GIT_MAX_BUFFER });
|
|
43
|
+
return { ok: true, stdout };
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const e = rejection(err);
|
|
47
|
+
if (e.code === 'ENOENT')
|
|
48
|
+
return { ok: false, error: 'missing', detail: 'git not found on PATH' };
|
|
49
|
+
if (e.killed === true)
|
|
50
|
+
return { ok: false, error: 'timeout', detail: `git ${args[0]} timed out (>${GIT_TIMEOUT_MS / 1000}s)` };
|
|
51
|
+
const stderr = (e.stderr ?? '').trim();
|
|
52
|
+
if (stderr.includes('not a git repository'))
|
|
53
|
+
return { ok: false, error: 'not-a-repo', detail: stderr };
|
|
54
|
+
return { ok: false, error: 'failed', detail: stderr.length > 0 ? stderr : `git ${args[0]} failed` };
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** The user-facing error for a failed git invocation; `runCli` renders it as exit 2. */
|
|
59
|
+
export function gitFailureError(result) {
|
|
60
|
+
if (result.error === 'missing')
|
|
61
|
+
return new Error('recover: git is required but was not found on PATH');
|
|
62
|
+
if (result.error === 'not-a-repo')
|
|
63
|
+
return new Error('recover: not inside a git repository');
|
|
64
|
+
return new Error(`recover: ${result.detail}`);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Field/record separators keep `git log` parsing exact: a subject line may
|
|
68
|
+
* contain anything printable, but never the unit or record separator bytes.
|
|
69
|
+
*/
|
|
70
|
+
const LOG_FORMAT = '%H%x1f%h%x1f%cI%x1f%an%x1f%s%x1e';
|
|
71
|
+
function parseLog(stdout) {
|
|
72
|
+
return stdout
|
|
73
|
+
.split('\x1e')
|
|
74
|
+
.map((record) => record.replace(/^\n/, ''))
|
|
75
|
+
.filter((record) => record.length > 0)
|
|
76
|
+
.map((record) => {
|
|
77
|
+
const [sha = '', shortSha = '', date = '', author = '', subject = ''] = record.split('\x1f');
|
|
78
|
+
return { sha, shortSha, date, author, subject };
|
|
79
|
+
})
|
|
80
|
+
.filter((rev) => rev.sha.length > 0);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Where the baseline lives relative to the *git* root — in a monorepo the
|
|
84
|
+
* checkride root is often a subdirectory, and `git show <sha>:<path>` resolves
|
|
85
|
+
* `<path>` from the repository root, not from cwd.
|
|
86
|
+
*/
|
|
87
|
+
async function locate(git) {
|
|
88
|
+
const result = await git(['rev-parse', '--show-toplevel', '--show-prefix', '--is-shallow-repository']);
|
|
89
|
+
if (!result.ok)
|
|
90
|
+
throw gitFailureError(result);
|
|
91
|
+
const [, prefix = '', shallowWord = ''] = result.stdout.split('\n');
|
|
92
|
+
return { path: `${prefix}${BASELINE_FILE}`, shallow: shallowWord.trim() === 'true' };
|
|
93
|
+
}
|
|
94
|
+
/** Whether the working-tree baseline carries uncommitted changes. */
|
|
95
|
+
export async function baselineDirty(git) {
|
|
96
|
+
const result = await git(['status', '--porcelain', '--', BASELINE_FILE]);
|
|
97
|
+
if (!result.ok)
|
|
98
|
+
throw gitFailureError(result);
|
|
99
|
+
return result.stdout.trim().length > 0;
|
|
100
|
+
}
|
|
101
|
+
/** Is this state worth presenting — different from current and from everything kept? */
|
|
102
|
+
function isNewState(baseline, current, kept) {
|
|
103
|
+
if (current !== null && baselinesEqual(baseline, current))
|
|
104
|
+
return false;
|
|
105
|
+
return !kept.some((s) => baselinesEqual(s.baseline, baseline));
|
|
106
|
+
}
|
|
107
|
+
async function walkSnapshots(git, path, revisions, current) {
|
|
108
|
+
const walk = { snapshots: [], parsed: [], skipped: [], walked: 0 };
|
|
109
|
+
for (const rev of revisions) {
|
|
110
|
+
if (walk.snapshots.length >= MAX_SNAPSHOTS)
|
|
111
|
+
break;
|
|
112
|
+
walk.walked += 1;
|
|
113
|
+
// oxlint-disable-next-line no-await-in-loop -- sequential on purpose: the early-stop above only saves `git show` calls if they run one at a time.
|
|
114
|
+
const show = await git(['show', `${rev.sha}:${path}`]);
|
|
115
|
+
const baseline = show.ok ? parseBaseline(show.stdout) : null;
|
|
116
|
+
if (baseline === null) {
|
|
117
|
+
walk.skipped.push(rev.shortSha);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
walk.parsed.push(baseline);
|
|
121
|
+
if (isNewState(baseline, current, walk.snapshots))
|
|
122
|
+
walk.snapshots.push({ kind: 'snapshot', rev, baseline });
|
|
123
|
+
}
|
|
124
|
+
return walk;
|
|
125
|
+
}
|
|
126
|
+
export async function collectCandidates(git, current, depth) {
|
|
127
|
+
const located = await locate(git);
|
|
128
|
+
const log = await git(['log', '-n', String(depth), `--format=${LOG_FORMAT}`, '--', located.path]);
|
|
129
|
+
if (!log.ok)
|
|
130
|
+
throw gitFailureError(log);
|
|
131
|
+
const walk = await walkSnapshots(git, located.path, parseLog(log.stdout), current);
|
|
132
|
+
const union = unionBaselines(current === null ? walk.parsed : [current, ...walk.parsed]);
|
|
133
|
+
const unionAddsAnything = current === null ? walk.parsed.length > 0 : !baselinesEqual(union, current);
|
|
134
|
+
const candidates = [
|
|
135
|
+
...(unionAddsAnything ? [{ kind: 'union', baseline: union, folded: walk.parsed.length }] : []),
|
|
136
|
+
...walk.snapshots,
|
|
137
|
+
];
|
|
138
|
+
return { candidates, walked: walk.walked, skipped: walk.skipped, shallow: located.shallow };
|
|
139
|
+
}
|
|
140
|
+
/** Per-slot key union of every part, canonical (sorted slots and keys). */
|
|
141
|
+
export function unionBaselines(parts) {
|
|
142
|
+
const merged = new Map();
|
|
143
|
+
for (const part of parts) {
|
|
144
|
+
for (const [slot, keys] of Object.entries(part.slots)) {
|
|
145
|
+
const set = merged.get(slot) ?? new Set();
|
|
146
|
+
for (const key of keys)
|
|
147
|
+
set.add(key);
|
|
148
|
+
merged.set(slot, set);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const slots = {};
|
|
152
|
+
for (const slot of [...merged.keys()].toSorted())
|
|
153
|
+
slots[slot] = [...(merged.get(slot) ?? [])].toSorted();
|
|
154
|
+
return { schema_version: BASELINE_SCHEMA_VERSION, slots };
|
|
155
|
+
}
|
|
156
|
+
/** The probe's whole budget — a hint must never make a red run noticeably slower. */
|
|
157
|
+
const HINT_BUDGET_MS = 750;
|
|
158
|
+
const HINT_LOG_DEPTH = 5;
|
|
159
|
+
const HINT_SNAPSHOTS = 3;
|
|
160
|
+
/** Resolves `null` when the budget expires; unref'd so it never holds the process open. */
|
|
161
|
+
function budget(ms) {
|
|
162
|
+
return new Promise((resolve) => {
|
|
163
|
+
setTimeout(() => resolve(null), ms).unref();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async function probeHistory(git, newKeys) {
|
|
167
|
+
const located = await locate(git);
|
|
168
|
+
const log = await git(['log', '-n', String(HINT_LOG_DEPTH), `--format=${LOG_FORMAT}`, '--', located.path]);
|
|
169
|
+
if (!log.ok)
|
|
170
|
+
return null;
|
|
171
|
+
const keys = new Set(newKeys);
|
|
172
|
+
for (const rev of parseLog(log.stdout).slice(0, HINT_SNAPSHOTS)) {
|
|
173
|
+
// oxlint-disable-next-line no-await-in-loop -- at most three probes, and the newest match wins — later shows are only paid for when earlier ones miss.
|
|
174
|
+
const show = await git(['show', `${rev.sha}:${located.path}`]);
|
|
175
|
+
const baseline = show.ok ? parseBaseline(show.stdout) : null;
|
|
176
|
+
if (baseline === null)
|
|
177
|
+
continue;
|
|
178
|
+
const grandfathered = new Set(Object.values(baseline.slots).flat());
|
|
179
|
+
const matched = [...keys].filter((k) => grandfathered.has(k)).length;
|
|
180
|
+
if (matched > 0)
|
|
181
|
+
return { matched, total: newKeys.length, shortSha: rev.shortSha };
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The red-run detection probe: were these "new" findings grandfathered in a
|
|
187
|
+
* recent committed baseline? The difference between "a wall of new debt" and
|
|
188
|
+
* "a merge dropped baseline entries" is a diagnosis the run output alone
|
|
189
|
+
* cannot make. Strictly best-effort: the whole probe races a
|
|
190
|
+
* {@link HINT_BUDGET_MS} budget, its git children carry the same short
|
|
191
|
+
* timeout, and any failure — git absent, not a repository, shallow miss,
|
|
192
|
+
* mangled blobs — resolves to `null`, never a thrown error or a slow run.
|
|
193
|
+
*/
|
|
194
|
+
export async function historicalHint(cwd, newKeys, git, budgetMs = HINT_BUDGET_MS) {
|
|
195
|
+
if (newKeys.length === 0)
|
|
196
|
+
return null;
|
|
197
|
+
try {
|
|
198
|
+
return await Promise.race([probeHistory(git ?? realGit(cwd, budgetMs), newKeys), budget(budgetMs)]);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* `restored` is what an apply adds; `absent` is what only an `--exact` apply
|
|
206
|
+
* would drop (the default union write never removes a key, so its `absent` side
|
|
207
|
+
* is empty by construction — the renderer still shows it so `--exact`'s cost is
|
|
208
|
+
* visible before it is paid).
|
|
209
|
+
*/
|
|
210
|
+
export function diffBaselines(from, to) {
|
|
211
|
+
const restored = {};
|
|
212
|
+
const absent = {};
|
|
213
|
+
let restoredCount = 0;
|
|
214
|
+
let absentCount = 0;
|
|
215
|
+
const slots = new Set([...Object.keys(from?.slots ?? {}), ...Object.keys(to.slots)]);
|
|
216
|
+
for (const slot of [...slots].toSorted()) {
|
|
217
|
+
const fromKeys = new Set(from?.slots[slot] ?? []);
|
|
218
|
+
const toKeys = new Set(to.slots[slot] ?? []);
|
|
219
|
+
const gained = [...toKeys].filter((k) => !fromKeys.has(k)).toSorted();
|
|
220
|
+
const lost = [...fromKeys].filter((k) => !toKeys.has(k)).toSorted();
|
|
221
|
+
if (gained.length > 0) {
|
|
222
|
+
restored[slot] = gained;
|
|
223
|
+
restoredCount += gained.length;
|
|
224
|
+
}
|
|
225
|
+
if (lost.length > 0) {
|
|
226
|
+
absent[slot] = lost;
|
|
227
|
+
absentCount += lost.length;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return { restored, absent, restoredCount, absentCount };
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/baseline/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
export type { Fingerprint } from './fingerprint.js';
|
|
8
8
|
export { fingerprint, isFingerprintable } from './fingerprint.js';
|
|
9
9
|
export { fallowVerdict } from './fallow.js';
|
|
10
|
-
export type {
|
|
11
|
-
export {
|
|
10
|
+
export type { BaselineDelta, Candidate, GitResult, GitRunner, HistoryScan } from './history.js';
|
|
11
|
+
export { baselineDirty, collectCandidates, DEFAULT_DEPTH, diffBaselines, gitFailureError, historicalHint, realGit, unionBaselines, } from './history.js';
|
|
12
|
+
export type { Baseline, BaselineRead } from './store.js';
|
|
13
|
+
export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, parseBaseline, ratchet, readBaselineStatus, writeBaseline, } from './store.js';
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/baseline/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChG,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
|
@@ -6,5 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { fingerprint, isFingerprintable } from './fingerprint.js';
|
|
8
8
|
export { fallowVerdict } from './fallow.js';
|
|
9
|
-
export {
|
|
9
|
+
export { baselineDirty, collectCandidates, DEFAULT_DEPTH, diffBaselines, gitFailureError, historicalHint, realGit, unionBaselines, } from './history.js';
|
|
10
|
+
export { applyBaseline, BASELINE_FILE, BASELINE_SCHEMA_VERSION, baselinesEqual, countBaselineKeys, loadBaseline, parseBaseline, ratchet, readBaselineStatus, writeBaseline, } from './store.js';
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +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;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC"}
|
|
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;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
|
@@ -29,12 +29,13 @@ export type BaselineAdjustment = {
|
|
|
29
29
|
newKeys: string[];
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* Parse baseline file content; `null` when unusable. The baseline is a
|
|
33
|
+
* committed file a run reads on every invocation, so a malformed one is coerced
|
|
34
|
+
* into a clean shape (or dropped) rather than thrown — a corrupt baseline must
|
|
35
|
+
* never break `checkride`. Takes raw text rather than a path so historical
|
|
36
|
+
* copies (a `git show` blob during recovery) parse under the same tolerance.
|
|
36
37
|
*
|
|
37
|
-
*
|
|
38
|
+
* Content from a *newer* schema is dropped rather than read optimistically. The
|
|
38
39
|
* fields it does not have yet are the ones that would say which findings are
|
|
39
40
|
* masked and why, so guessing means either masking findings it never
|
|
40
41
|
* grandfathered or claiming ones it did. Dropping it fails closed: the run
|
|
@@ -42,8 +43,30 @@ export type BaselineAdjustment = {
|
|
|
42
43
|
* intended, never a green that was not earned. Same direction as
|
|
43
44
|
* {@link applyBaseline}'s refusal to mask an unparseable run.
|
|
44
45
|
*/
|
|
46
|
+
export declare function parseBaseline(raw: string): Baseline | null;
|
|
47
|
+
/** How reading `checkride.baseline.json` went — see {@link readBaselineStatus}. */
|
|
48
|
+
export type BaselineRead = {
|
|
49
|
+
baseline: Baseline | null;
|
|
50
|
+
state: 'absent' | 'ok' | 'unparseable';
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Read the baseline and say *why* it is missing when it is. Absent and
|
|
54
|
+
* unparseable both mask nothing, but they mean different things to the person
|
|
55
|
+
* staring at the resulting red: absent is a repo that never adopted a baseline,
|
|
56
|
+
* unparseable is a file somebody (often a merge) mangled — the run warns about
|
|
57
|
+
* the second so the damage is diagnosed at the moment it bites, not archaeology
|
|
58
|
+
* later.
|
|
59
|
+
*/
|
|
60
|
+
export declare function readBaselineStatus(cwd: string): BaselineRead;
|
|
61
|
+
/** Read `checkride.baseline.json` from `cwd`; `null` when absent or unusable. */
|
|
45
62
|
export declare function loadBaseline(cwd: string): Baseline | null;
|
|
46
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Serialize and write the baseline to `cwd` (canonical, pretty-printed,
|
|
65
|
+
* trailing newline, atomic). Written canonical — sorted slots, sorted keys — so
|
|
66
|
+
* the committed file diffs deterministically: two branches that grandfather the
|
|
67
|
+
* same debt produce byte-identical files instead of a spurious merge conflict
|
|
68
|
+
* over insertion order.
|
|
69
|
+
*/
|
|
47
70
|
export declare function writeBaseline(cwd: string, baseline: Baseline): Promise<void>;
|
|
48
71
|
/**
|
|
49
72
|
* Mask one slot's current fingerprint with its grandfathered keys. Masking is
|
|
@@ -58,7 +81,7 @@ export declare function writeBaseline(cwd: string, baseline: Baseline): Promise<
|
|
|
58
81
|
*/
|
|
59
82
|
export declare function applyBaseline(current: Fingerprint, baselinedKeys: readonly string[], rawOk: boolean): BaselineAdjustment;
|
|
60
83
|
/**
|
|
61
|
-
* Ratchet the baseline against a fully
|
|
84
|
+
* Ratchet the baseline against a fully observed run: for every slot observed this
|
|
62
85
|
* run, keep only the grandfathered keys still present (a fixed diagnostic is
|
|
63
86
|
* dropped); a slot absent from `observed` — disabled, without an extractor, or
|
|
64
87
|
* not run — is preserved untouched. The result never grows: genuinely new findings
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/baseline/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,oFAAoF;AACpF,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAEvD,8EAA8E;AAC9E,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;AAEF
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/baseline/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,oFAAoF;AACpF,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAEvD,8EAA8E;AAC9E,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;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAc1D;AAED,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,aAAa,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAW5D;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAEzD;AAED;;;;;;GAMG;AACH,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;AAcD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEhE"}
|