plumbbob 0.6.6 → 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.
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +24 -7
- package/dist/cli-core.js +7 -2
- package/dist/lib/buildlog.js +5 -2
- package/dist/lib/check.js +33 -1
- package/dist/lib/git.js +17 -0
- package/dist/lib/latch.js +97 -0
- package/dist/lib/orient.js +24 -0
- package/dist/lib/sidecar.js +116 -0
- package/dist/verbs/build.js +5 -1
- package/dist/verbs/checkpoint.js +51 -2
- package/dist/verbs/doctor.js +33 -2
- package/dist/verbs/finish.js +57 -1
- package/dist/verbs/revert.js +19 -1
- package/dist/verbs/start.js +22 -2
- package/dist/verbs/status.js +10 -3
- package/dist/verbs/turn.js +106 -0
- package/hooks/hooks.json +15 -0
- package/hooks/pre-bash-commit.sh +69 -0
- package/node_modules/checkride/CHANGELOG.md +111 -0
- package/node_modules/checkride/README.md +185 -20
- package/node_modules/checkride/dist/adapters.d.ts +9 -4
- package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
- package/node_modules/checkride/dist/adapters.js +62 -2
- package/node_modules/checkride/dist/adapters.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/hook.d.ts +63 -0
- package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/hook.js +92 -0
- package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/index.d.ts +8 -0
- package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/index.js +7 -0
- package/node_modules/checkride/dist/agent-setup/index.js.map +1 -0
- package/node_modules/checkride/dist/atomic.d.ts +13 -0
- package/node_modules/checkride/dist/atomic.d.ts.map +1 -0
- package/node_modules/checkride/dist/atomic.js +24 -0
- package/node_modules/checkride/dist/atomic.js.map +1 -0
- package/node_modules/checkride/dist/baseline/command.d.ts +42 -0
- package/node_modules/checkride/dist/baseline/command.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/command.js +58 -0
- package/node_modules/checkride/dist/baseline/command.js.map +1 -0
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts +41 -0
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/fingerprint.js +119 -0
- package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -0
- package/node_modules/checkride/dist/baseline/index.d.ts +13 -0
- package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/index.js +10 -0
- package/node_modules/checkride/dist/baseline/index.js.map +1 -0
- package/node_modules/checkride/dist/baseline/store.d.ts +67 -0
- package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/store.js +110 -0
- package/node_modules/checkride/dist/baseline/store.js.map +1 -0
- package/node_modules/checkride/dist/cli.d.ts.map +1 -1
- package/node_modules/checkride/dist/cli.js +37 -3
- package/node_modules/checkride/dist/cli.js.map +1 -1
- package/node_modules/checkride/dist/config.d.ts +43 -3
- package/node_modules/checkride/dist/config.d.ts.map +1 -1
- package/node_modules/checkride/dist/config.js +95 -22
- package/node_modules/checkride/dist/config.js.map +1 -1
- package/node_modules/checkride/dist/digest/digest.d.ts +52 -0
- package/node_modules/checkride/dist/digest/digest.d.ts.map +1 -0
- package/node_modules/checkride/dist/digest/digest.js +147 -0
- package/node_modules/checkride/dist/digest/digest.js.map +1 -0
- package/node_modules/checkride/dist/digest/index.d.ts +8 -0
- package/node_modules/checkride/dist/digest/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/digest/index.js +7 -0
- package/node_modules/checkride/dist/digest/index.js.map +1 -0
- package/node_modules/checkride/dist/doctor.d.ts +4 -0
- package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
- package/node_modules/checkride/dist/doctor.js +33 -10
- package/node_modules/checkride/dist/doctor.js.map +1 -1
- package/node_modules/checkride/dist/index.d.ts +1 -1
- package/node_modules/checkride/dist/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/index.js +1 -1
- package/node_modules/checkride/dist/index.js.map +1 -1
- package/node_modules/checkride/dist/init.d.ts +38 -0
- package/node_modules/checkride/dist/init.d.ts.map +1 -1
- package/node_modules/checkride/dist/init.js +97 -8
- package/node_modules/checkride/dist/init.js.map +1 -1
- package/node_modules/checkride/dist/orchestrator.d.ts +58 -1
- package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
- package/node_modules/checkride/dist/orchestrator.js +155 -27
- package/node_modules/checkride/dist/orchestrator.js.map +1 -1
- package/node_modules/checkride/dist/pm/detect.d.ts +21 -0
- package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/detect.js +60 -0
- package/node_modules/checkride/dist/pm/detect.js.map +1 -0
- package/node_modules/checkride/dist/pm/index.d.ts +10 -0
- package/node_modules/checkride/dist/pm/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/index.js +9 -0
- package/node_modules/checkride/dist/pm/index.js.map +1 -0
- package/node_modules/checkride/dist/pm/translate.d.ts +28 -0
- package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/translate.js +40 -0
- package/node_modules/checkride/dist/pm/translate.js.map +1 -0
- package/node_modules/checkride/package.json +20 -17
- package/node_modules/checkride/schema/checkride.config.schema.json +97 -0
- package/node_modules/checkride/schema/checkride.summary.schema.json +57 -0
- package/node_modules/checkride/templates/shared/cspell.json +1 -0
- package/node_modules/checkride/templates/shared/prettierrc.json +6 -0
- package/package.json +8 -4
- package/skills/pb-build/SKILL.md +14 -0
- package/skills/pb-plan/SKILL.md +17 -0
- package/skills/pb-verify/SKILL.md +18 -0
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
import { readFileSync, realpathSync } from 'node:fs';
|
|
13
13
|
import { parseArgs } from 'node:util';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { runBaseline } from './baseline/index.js';
|
|
15
16
|
import { runDoctor } from './doctor.js';
|
|
16
|
-
import { runInit } from './init.js';
|
|
17
|
+
import { runAgentSetup, runInit } from './init.js';
|
|
17
18
|
import { runChecks, runFix } from './orchestrator.js';
|
|
18
19
|
const RUN_OPTIONS = {
|
|
19
20
|
bail: { type: 'boolean', default: false },
|
|
@@ -23,6 +24,8 @@ const RUN_OPTIONS = {
|
|
|
23
24
|
include: { type: 'string' },
|
|
24
25
|
all: { type: 'boolean', default: false },
|
|
25
26
|
changed: { type: 'boolean', default: false },
|
|
27
|
+
digest: { type: 'boolean', default: false },
|
|
28
|
+
strict: { type: 'boolean', default: false },
|
|
26
29
|
};
|
|
27
30
|
const INIT_OPTIONS = {
|
|
28
31
|
shape: { type: 'string' },
|
|
@@ -32,6 +35,8 @@ const INIT_OPTIONS = {
|
|
|
32
35
|
author: { type: 'string' },
|
|
33
36
|
'dry-run': { type: 'boolean', default: false },
|
|
34
37
|
add: { type: 'string' },
|
|
38
|
+
baseline: { type: 'boolean', default: false },
|
|
39
|
+
'no-hook': { type: 'boolean', default: false },
|
|
35
40
|
};
|
|
36
41
|
const HELP_TEXT = `checkride — an agent harness for TypeScript repositories
|
|
37
42
|
|
|
@@ -39,18 +44,25 @@ Usage: checkride [command] [options]
|
|
|
39
44
|
|
|
40
45
|
Commands:
|
|
41
46
|
(default) Run the checks. Exit 0 pass / 1 fail / 2 error.
|
|
42
|
-
init Set up a project (new or existing — auto-detected).
|
|
47
|
+
init Set up a project (new or existing — auto-detected). Writes a
|
|
48
|
+
Claude Code Stop hook (--no-hook to skip). Existing mode:
|
|
49
|
+
--baseline grandfathers current debt.
|
|
43
50
|
doctor Verify the environment and every slot's status (read-only).
|
|
44
51
|
fix Run every active adapter's fix command.
|
|
52
|
+
baseline Record current diagnostics as a committed baseline.
|
|
53
|
+
agent-setup Add the AGENTS.md stanza + Claude Code Stop hook to an
|
|
54
|
+
existing repo (--no-hook to skip the hook).
|
|
45
55
|
|
|
46
56
|
Run options:
|
|
47
57
|
--only <a,b> Run only these slots
|
|
48
58
|
--skip <a,b> Skip these slots
|
|
49
|
-
--include <a,b> Add opt-in slots (mutation, security) to the run
|
|
59
|
+
--include <a,b> Add opt-in slots (format, mutation, security) to the run
|
|
50
60
|
--all Include every opt-in slot
|
|
51
61
|
--changed Affected-only mode (incremental)
|
|
52
62
|
--bail Stop at the first failure
|
|
53
63
|
--json Emit the summary as JSON on stdout
|
|
64
|
+
--digest Write a capped failure excerpt to .check/digest.md
|
|
65
|
+
--strict Zero checks actually running is an error (exit 2), not a pass
|
|
54
66
|
-h, --help Show this help
|
|
55
67
|
-V, --version Show the version
|
|
56
68
|
|
|
@@ -105,6 +117,8 @@ export function parseCliArgs(argv) {
|
|
|
105
117
|
json: values.json,
|
|
106
118
|
all: values.all,
|
|
107
119
|
changed: values.changed,
|
|
120
|
+
digest: values.digest,
|
|
121
|
+
strict: values.strict,
|
|
108
122
|
only: parseList(values.only),
|
|
109
123
|
skip: parseList(values.skip),
|
|
110
124
|
include: parseList(values.include),
|
|
@@ -136,6 +150,10 @@ export function parseInitArgs(argv) {
|
|
|
136
150
|
opts.author = values.author;
|
|
137
151
|
if (values['dry-run'])
|
|
138
152
|
opts.dryRun = true;
|
|
153
|
+
if (values.baseline)
|
|
154
|
+
opts.baseline = true;
|
|
155
|
+
if (values['no-hook'])
|
|
156
|
+
opts.hook = false;
|
|
139
157
|
const add = parseList(values.add);
|
|
140
158
|
if (add)
|
|
141
159
|
opts.add = add;
|
|
@@ -160,6 +178,20 @@ async function dispatchFix(argv, deps) {
|
|
|
160
178
|
const result = await runFix({ ...flags, cwd: deps.cwd, stderr: deps.stderr });
|
|
161
179
|
return result.exitCode;
|
|
162
180
|
}
|
|
181
|
+
async function dispatchBaseline(_argv, deps) {
|
|
182
|
+
const result = await runBaseline({ cwd: deps.cwd, stdout: deps.stdout, stderr: deps.stderr });
|
|
183
|
+
return result.exitCode;
|
|
184
|
+
}
|
|
185
|
+
async function dispatchAgentSetup(argv, deps) {
|
|
186
|
+
const parsed = parseInitArgs(argv);
|
|
187
|
+
const opts = { cwd: deps.cwd, stdout: deps.stdout };
|
|
188
|
+
if (parsed.hook !== undefined)
|
|
189
|
+
opts.hook = parsed.hook;
|
|
190
|
+
if (parsed.dryRun)
|
|
191
|
+
opts.dryRun = true;
|
|
192
|
+
const result = await runAgentSetup(opts);
|
|
193
|
+
return result.exitCode;
|
|
194
|
+
}
|
|
163
195
|
/** Dispatch a CLI invocation; returns the process exit code. */
|
|
164
196
|
export async function runCli(argv, deps) {
|
|
165
197
|
if (argv.includes('--help') || argv.includes('-h')) {
|
|
@@ -176,6 +208,8 @@ export async function runCli(argv, deps) {
|
|
|
176
208
|
init: dispatchInit,
|
|
177
209
|
doctor: dispatchDoctor,
|
|
178
210
|
fix: dispatchFix,
|
|
211
|
+
baseline: dispatchBaseline,
|
|
212
|
+
'agent-setup': dispatchAgentSetup,
|
|
179
213
|
};
|
|
180
214
|
const handler = dispatch[command];
|
|
181
215
|
if (!handler) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAKtD,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACzC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACxC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC5C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;CACnC,CAAC;AAEX,MAAM,YAAY,GAAG;IACnB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1B,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC9C,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACvB,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC7C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;CACtC,CAAC;AAEX,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BjB,CAAC;AAEF,SAAS,YAAY,CAAC,GAAY;IAChC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,mFAAmF;AACnF,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,GAAG,YAAY,KAAK,IAAI,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC1E,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yFAAyF;AACzF,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IAC/C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;AAChD,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAyB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5E,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAyB;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED,2EAA2E;AAC3E,SAAS,aAAa,CAAC,IAAc;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IAC3F,MAAM,KAAK,GAAa;QACtB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;KACnC,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,OAAO,CAAC,KAAyB;IACxC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjF,MAAM,IAAI,KAAK,CAAC,oBAAoB,KAAK,uCAAuC,CAAC,CAAC;AACpF,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAyB,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI;QAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzC,IAAI,MAAM,CAAC,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC5C,IAAI,MAAM,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAClD,IAAI,MAAM,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/C,IAAI,MAAM,CAAC,SAAS,CAAC;QAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IAC1C,IAAI,MAAM,CAAC,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC1C,IAAI,MAAM,CAAC,SAAS,CAAC;QAAE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACzC,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,GAAG;QAAE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAc,EAAE,IAAa;IACtD,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACtG,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAc,EAAE,IAAa;IACvD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7F,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAc,EAAE,IAAa;IACzD,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAClG,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAc,EAAE,IAAa;IACtD,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,KAAe,EAAE,IAAa;IAC5D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9F,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,IAAc,EAAE,IAAa;IAC7D,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,IAAI,GAAsB,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IACvE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACvD,IAAI,MAAM,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc,EAAE,IAAa;IACxD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,EAAE,IAAI,CAAC,CAAC;QACxC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAiE;QAC7E,GAAG,EAAE,WAAW;QAChB,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,cAAc;QACtB,GAAG,EAAE,WAAW;QAChB,QAAQ,EAAE,gBAAgB;QAC1B,aAAa,EAAE,kBAAkB;KAClC,CAAC;IACF,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,OAAO,2CAA2C,CAAC,CAAC;QACrG,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,aAAa,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,yCAAyC,CAAC,CAAC;QAC7G,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,YAAY;IACnB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,WAAW,CAAC,KAAK,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,YAAY,EAAE,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QAC/C,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC"}
|
|
@@ -21,6 +21,15 @@ export type CustomCheck = {
|
|
|
21
21
|
fixArgs?: string[];
|
|
22
22
|
timeout?: number;
|
|
23
23
|
name?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Marker files that gate a config-only custom check: it runs only when at
|
|
26
|
+
* least one listed file exists, and is skipped (`'no detect file present'`,
|
|
27
|
+
* not failed) otherwise. This keeps a shared preset safe across heterogeneous
|
|
28
|
+
* repos — a check for a tool a given repo doesn't use quietly stands down
|
|
29
|
+
* instead of lighting up red. Ignored on entries that fill a catalogue slot —
|
|
30
|
+
* those always run.
|
|
31
|
+
*/
|
|
32
|
+
detect?: string[];
|
|
24
33
|
/**
|
|
25
34
|
* Where a config-only custom check runs relative to the built-in catalogue:
|
|
26
35
|
* `'first'` (ahead of every built-in check) or `'last'` (after them, the
|
|
@@ -44,25 +53,56 @@ export type UseConfig = {
|
|
|
44
53
|
export type SlotConfig = string | false | UseConfig | CustomCheck;
|
|
45
54
|
/** Shape of `checkride.config.json`. */
|
|
46
55
|
export type CheckrideConfig = {
|
|
56
|
+
/** URL of the JSON Schema for this file, for editor validation. Ignored by the runner. */
|
|
57
|
+
$schema?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Preset(s) to inherit: a file path (`./base.json`) or a package specifier
|
|
60
|
+
* (`@acme/preset`), or an array of them. Bases merge left-to-right and the
|
|
61
|
+
* local config wins over all of them; objects deep-merge, arrays and scalars
|
|
62
|
+
* replace (arrays are not concatenated). Resolved and folded away by
|
|
63
|
+
* `loadConfig` — the runner never sees it.
|
|
64
|
+
*/
|
|
65
|
+
extends?: string | string[];
|
|
47
66
|
checks?: Record<string, SlotConfig>;
|
|
48
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Default per-check timeout in seconds. When unset, checks fall back to the
|
|
69
|
+
* built-in 600s cap (`DEFAULT_TIMEOUT_SECONDS`); `0` here or on a check
|
|
70
|
+
* disables the cap.
|
|
71
|
+
*/
|
|
49
72
|
timeout?: number;
|
|
50
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* The version-pinned URL of the published config schema, for the `$schema`
|
|
76
|
+
* pointer `init` writes into generated configs. The `v<version>` git tag must
|
|
77
|
+
* exist at release for the URL to resolve.
|
|
78
|
+
*/
|
|
79
|
+
export declare function configSchemaUrl(version: string): string;
|
|
51
80
|
/** A slot resolved to a concrete adapter, or marked skipped with a reason. */
|
|
52
81
|
export type ResolvedCheck = {
|
|
53
82
|
slot: string;
|
|
54
83
|
optIn: boolean;
|
|
55
84
|
adapter: Adapter | null;
|
|
56
85
|
skip: string | null;
|
|
86
|
+
/**
|
|
87
|
+
* True when `checks` names this slot explicitly (a non-`false` config entry).
|
|
88
|
+
* An explicit entry opts an otherwise opt-in slot into the default run — so
|
|
89
|
+
* `"format": "prettier"` runs without `--include` (see `selectChecks`).
|
|
90
|
+
*/
|
|
91
|
+
explicit?: boolean;
|
|
57
92
|
};
|
|
58
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Read and resolve `checkride.config.json` from `cwd`, or `null` when absent.
|
|
95
|
+
* Any `extends` presets (file paths or package specifiers) are resolved and
|
|
96
|
+
* merged in — local keys win, arrays replace — with `extends` folded away.
|
|
97
|
+
*/
|
|
59
98
|
export declare function loadConfig(cwd: string): CheckrideConfig | null;
|
|
60
99
|
/**
|
|
61
100
|
* Resolve every catalogue slot (in order) to an adapter or a skip reason, and
|
|
62
101
|
* fold in any config-only custom checks (an object with a `command`, keyed by a
|
|
63
102
|
* name not in the catalogue — e.g. a project's `"licenses"` check). Each custom
|
|
64
103
|
* check runs ahead of the catalogue (`order: 'first'`) or after it (`'last'`,
|
|
65
|
-
* the default); within a group, config key order is preserved.
|
|
104
|
+
* the default); within a group, config key order is preserved. A custom check
|
|
105
|
+
* that declares `detect` files is skipped when none of them are present.
|
|
66
106
|
*/
|
|
67
107
|
export declare function resolveChecks(input: {
|
|
68
108
|
slots: readonly Slot[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEnD,2DAA2D;AAC3D,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,yFAAyF;AACzF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,WAAW,CAAC;AAElE,wCAAwC;AACxC,MAAM,MAAM,eAAe,GAAG;IAC5B,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA2EF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAI9D;AAyFD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC,GAAG,aAAa,EAAE,CAwBlB"}
|
|
@@ -11,22 +11,88 @@
|
|
|
11
11
|
* 3. otherwise the slot is skipped (skipped ≠ failed).
|
|
12
12
|
*/
|
|
13
13
|
import { existsSync, readFileSync } from 'node:fs';
|
|
14
|
-
import {
|
|
14
|
+
import { createRequire } from 'node:module';
|
|
15
|
+
import { join, relative } from 'node:path';
|
|
16
|
+
/**
|
|
17
|
+
* The version-pinned URL of the published config schema, for the `$schema`
|
|
18
|
+
* pointer `init` writes into generated configs. The `v<version>` git tag must
|
|
19
|
+
* exist at release for the URL to resolve.
|
|
20
|
+
*/
|
|
21
|
+
export function configSchemaUrl(version) {
|
|
22
|
+
return `https://raw.githubusercontent.com/robmclarty/checkride/v${version}/schema/checkride.config.schema.json`;
|
|
23
|
+
}
|
|
15
24
|
const CONFIG_FILE = 'checkride.config.json';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
function isPlainObject(v) {
|
|
26
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Recursive deep-merge with local-wins semantics: plain objects merge key by
|
|
30
|
+
* key; arrays, scalars, and type mismatches from `over` replace `base` (arrays
|
|
31
|
+
* are never concatenated).
|
|
32
|
+
*/
|
|
33
|
+
function deepMerge(base, over) {
|
|
34
|
+
const out = { ...base };
|
|
35
|
+
for (const [k, v] of Object.entries(over)) {
|
|
36
|
+
const b = out[k];
|
|
37
|
+
out[k] = isPlainObject(b) && isPlainObject(v) ? deepMerge(b, v) : v;
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** Throw the friendly `invalid checkride.config.json: <reason>` error. */
|
|
42
|
+
function invalidConfig(reason, cause) {
|
|
43
|
+
throw new Error(`invalid ${CONFIG_FILE}: ${reason}`, cause ? { cause } : undefined);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Read, parse, and fully resolve a config file's `extends` chain into a single
|
|
47
|
+
* merged object. `stack` holds the absolute paths currently being resolved, so
|
|
48
|
+
* a config that (transitively) extends itself is caught as a cycle. `label`
|
|
49
|
+
* names the file in error messages — the root config's own filename for the
|
|
50
|
+
* entry point, or a repo-relative path for an inherited base.
|
|
51
|
+
*/
|
|
52
|
+
function resolveConfigFile(absPath, stack, label) {
|
|
53
|
+
if (stack.includes(absPath)) {
|
|
54
|
+
invalidConfig(`circular extends: ${[...stack, absPath].map((p) => relative(process.cwd(), p)).join(' -> ')}`);
|
|
55
|
+
}
|
|
56
|
+
let raw;
|
|
22
57
|
try {
|
|
23
|
-
|
|
24
|
-
return config;
|
|
58
|
+
raw = JSON.parse(readFileSync(absPath, 'utf8'));
|
|
25
59
|
}
|
|
26
60
|
catch (err) {
|
|
27
61
|
const reason = err instanceof Error ? err.message : String(err);
|
|
28
|
-
|
|
62
|
+
invalidConfig(label === CONFIG_FILE ? reason : `${reason} (in ${label})`, err);
|
|
29
63
|
}
|
|
64
|
+
if (!isPlainObject(raw))
|
|
65
|
+
invalidConfig(`${label} is not a JSON object`);
|
|
66
|
+
const { extends: ext, ...own } = raw;
|
|
67
|
+
const specs = ext === undefined ? [] : Array.isArray(ext) ? ext : [ext];
|
|
68
|
+
const require = createRequire(absPath);
|
|
69
|
+
let merged = {};
|
|
70
|
+
for (const spec of specs) {
|
|
71
|
+
if (typeof spec !== 'string')
|
|
72
|
+
invalidConfig(`extends entries must be strings (in ${label})`);
|
|
73
|
+
let baseAbs;
|
|
74
|
+
try {
|
|
75
|
+
baseAbs = require.resolve(spec);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
79
|
+
invalidConfig(`cannot resolve extends "${spec}" (in ${label}): ${reason}`, err);
|
|
80
|
+
}
|
|
81
|
+
const base = resolveConfigFile(baseAbs, [...stack, absPath], relative(process.cwd(), baseAbs));
|
|
82
|
+
merged = deepMerge(merged, base);
|
|
83
|
+
}
|
|
84
|
+
return deepMerge(merged, own);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Read and resolve `checkride.config.json` from `cwd`, or `null` when absent.
|
|
88
|
+
* Any `extends` presets (file paths or package specifiers) are resolved and
|
|
89
|
+
* merged in — local keys win, arrays replace — with `extends` folded away.
|
|
90
|
+
*/
|
|
91
|
+
export function loadConfig(cwd) {
|
|
92
|
+
const path = join(cwd, CONFIG_FILE);
|
|
93
|
+
if (!existsSync(path))
|
|
94
|
+
return null;
|
|
95
|
+
return resolveConfigFile(path, [], CONFIG_FILE);
|
|
30
96
|
}
|
|
31
97
|
function byName(name, adapters) {
|
|
32
98
|
return adapters.find((a) => a.name === name) ?? null;
|
|
@@ -58,7 +124,7 @@ function customAdapter(slot, c) {
|
|
|
58
124
|
name: c.name ?? `custom:${slot}`,
|
|
59
125
|
slot,
|
|
60
126
|
description: c.description ?? `Custom ${slot} check`,
|
|
61
|
-
detect: [],
|
|
127
|
+
detect: c.detect ?? [],
|
|
62
128
|
command: c.command,
|
|
63
129
|
args: c.args ?? [],
|
|
64
130
|
outputFile: c.outputFile ?? null,
|
|
@@ -68,31 +134,34 @@ function customAdapter(slot, c) {
|
|
|
68
134
|
devDeps: {},
|
|
69
135
|
};
|
|
70
136
|
}
|
|
71
|
-
function active(slot, adapter) {
|
|
72
|
-
return { slot: slot.name, optIn: slot.optIn ?? false, adapter, skip: null };
|
|
137
|
+
function active(slot, adapter, explicit = false) {
|
|
138
|
+
return { slot: slot.name, optIn: slot.optIn ?? false, adapter, skip: null, explicit };
|
|
73
139
|
}
|
|
74
|
-
function skipped(slot, reason) {
|
|
75
|
-
return { slot: slot.name, optIn: slot.optIn ?? false, adapter: null, skip: reason };
|
|
140
|
+
function skipped(slot, reason, explicit = false) {
|
|
141
|
+
return { slot: slot.name, optIn: slot.optIn ?? false, adapter: null, skip: reason, explicit };
|
|
76
142
|
}
|
|
77
143
|
function resolveOne(slot, entry, adapters, fileExists) {
|
|
144
|
+
// Any non-`false` config entry is an explicit opt-in for this slot (`false`
|
|
145
|
+
// disables it, so it never runs regardless). Detection (no entry) is not.
|
|
146
|
+
const explicit = entry !== undefined && entry !== false;
|
|
78
147
|
if (entry === false) {
|
|
79
148
|
return skipped(slot, 'disabled in checkride.config.json');
|
|
80
149
|
}
|
|
81
150
|
if (typeof entry === 'string') {
|
|
82
151
|
const adapter = byName(entry, adapters);
|
|
83
152
|
return adapter
|
|
84
|
-
? active(slot, adapter)
|
|
85
|
-
: skipped(slot, `configured adapter '${entry}' is not in the registry
|
|
153
|
+
? active(slot, adapter, explicit)
|
|
154
|
+
: skipped(slot, `configured adapter '${entry}' is not in the registry`, explicit);
|
|
86
155
|
}
|
|
87
156
|
if (entry && typeof entry === 'object') {
|
|
88
157
|
if ('use' in entry) {
|
|
89
158
|
const base = byName(entry.use, adapters);
|
|
90
159
|
return base
|
|
91
|
-
? active(slot, applyOverrides(base, entry))
|
|
92
|
-
: skipped(slot, `configured adapter '${entry.use}' is not in the registry
|
|
160
|
+
? active(slot, applyOverrides(base, entry), explicit)
|
|
161
|
+
: skipped(slot, `configured adapter '${entry.use}' is not in the registry`, explicit);
|
|
93
162
|
}
|
|
94
163
|
if ('command' in entry) {
|
|
95
|
-
return active(slot, customAdapter(slot.name, entry));
|
|
164
|
+
return active(slot, customAdapter(slot.name, entry), explicit);
|
|
96
165
|
}
|
|
97
166
|
}
|
|
98
167
|
const detected = detectAdapter(slot.name, adapters, fileExists);
|
|
@@ -103,7 +172,8 @@ function resolveOne(slot, entry, adapters, fileExists) {
|
|
|
103
172
|
* fold in any config-only custom checks (an object with a `command`, keyed by a
|
|
104
173
|
* name not in the catalogue — e.g. a project's `"licenses"` check). Each custom
|
|
105
174
|
* check runs ahead of the catalogue (`order: 'first'`) or after it (`'last'`,
|
|
106
|
-
* the default); within a group, config key order is preserved.
|
|
175
|
+
* the default); within a group, config key order is preserved. A custom check
|
|
176
|
+
* that declares `detect` files is skipped when none of them are present.
|
|
107
177
|
*/
|
|
108
178
|
export function resolveChecks(input) {
|
|
109
179
|
const cwd = input.cwd ?? process.cwd();
|
|
@@ -117,7 +187,10 @@ export function resolveChecks(input) {
|
|
|
117
187
|
if (catalogueNames.has(name))
|
|
118
188
|
continue;
|
|
119
189
|
if (entry && typeof entry === 'object' && !('use' in entry) && 'command' in entry) {
|
|
120
|
-
const
|
|
190
|
+
const detect = entry.detect ?? [];
|
|
191
|
+
const resolved = detect.length > 0 && !detect.some((f) => fileExists(f))
|
|
192
|
+
? skipped({ name }, 'no detect file present')
|
|
193
|
+
: active({ name }, customAdapter(name, entry));
|
|
121
194
|
(entry.order === 'first' ? firsts : lasts).push(resolved);
|
|
122
195
|
}
|
|
123
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-bounded failure digest (step 11).
|
|
3
|
+
*
|
|
4
|
+
* After a run, `--digest` writes a capped Markdown excerpt of the *failing*
|
|
5
|
+
* slots to `.check/digest.md` so an agent working through a big red repo spends
|
|
6
|
+
* its context on a bounded index instead of every raw `.check/<slot>.json`. The
|
|
7
|
+
* digest is an INDEX, never a replacement: it truncates (the first N findings
|
|
8
|
+
* per slot, a total byte budget) and never normalizes — each section points
|
|
9
|
+
* back at the authoritative raw file, which this module never touches.
|
|
10
|
+
*
|
|
11
|
+
* It reuses step 4's per-adapter fingerprint extractors to list a slot's
|
|
12
|
+
* findings (render the first N of the same items); a slot whose adapter has no
|
|
13
|
+
* extractor falls back to a tail of its raw text (b6). A green run has nothing
|
|
14
|
+
* to digest, so {@link writeDigest} removes any stale `.check/digest.md` — the
|
|
15
|
+
* file's presence always means "this run had failures".
|
|
16
|
+
*
|
|
17
|
+
* The `../digest` barrel (`index.ts`) is this module's only public surface (C2);
|
|
18
|
+
* siblings import from there, never from this file directly.
|
|
19
|
+
*/
|
|
20
|
+
import type { CheckRun, SummaryCheck } from '../orchestrator.js';
|
|
21
|
+
/** The digest file, beside `summary.json` under the gitignored `.check/`. */
|
|
22
|
+
export declare const DIGEST_FILE = "digest.md";
|
|
23
|
+
/** Caps that keep the digest token-bounded. Truncation, never normalization. */
|
|
24
|
+
export type DigestBudget = {
|
|
25
|
+
/** Max findings rendered per failing slot; the rest collapse to a "… N more" line. */
|
|
26
|
+
maxItemsPerSlot: number;
|
|
27
|
+
/** Max total bytes of the rendered Markdown; whole sections drop past it. */
|
|
28
|
+
maxBytes: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Conservative defaults: ~10 findings a slot and an 8 KB ceiling keep even a
|
|
32
|
+
* fully-red repo's digest to roughly two thousand tokens — small enough to read
|
|
33
|
+
* in one gulp, with the raw files a click away for the rest.
|
|
34
|
+
*/
|
|
35
|
+
export declare const DEFAULT_BUDGET: DigestBudget;
|
|
36
|
+
/**
|
|
37
|
+
* Build the Markdown digest for a completed run, or `null` when nothing failed.
|
|
38
|
+
* A check is "failing" when the summary marks it `ok: false` and not skipped —
|
|
39
|
+
* so a slot whose findings a baseline fully grandfathers (still `ok: true`) is
|
|
40
|
+
* correctly absent. Sections are added in summary (cheapest-first) order until
|
|
41
|
+
* the byte budget is spent; any remaining failing slots are named in a trailing
|
|
42
|
+
* note rather than silently dropped.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildDigest(runs: readonly CheckRun[], checks: readonly SummaryCheck[], budget?: DigestBudget): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Persist the digest for a completed run. Writes `.check/digest.md` when a slot
|
|
47
|
+
* failed; on a green run removes any stale digest so the file's presence always
|
|
48
|
+
* means "this run failed". `cwd/.check/` is assumed to exist — the orchestrator
|
|
49
|
+
* creates it before running. Returns whether a digest file now exists.
|
|
50
|
+
*/
|
|
51
|
+
export declare function writeDigest(cwd: string, runs: readonly CheckRun[], checks: readonly SummaryCheck[], budget?: DigestBudget): Promise<boolean>;
|
|
52
|
+
//# sourceMappingURL=digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../src/digest/digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AASH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjE,6EAA6E;AAC7E,eAAO,MAAM,WAAW,cAAc,CAAC;AAEvC,gFAAgF;AAChF,MAAM,MAAM,YAAY,GAAG;IACzB,sFAAsF;IACtF,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,YAAsD,CAAC;AAkEpF;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,MAAM,GAAE,YAA6B,GACpC,MAAM,GAAG,IAAI,CA+Bf;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,MAAM,GAAE,YAA6B,GACpC,OAAO,CAAC,OAAO,CAAC,CASlB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-bounded failure digest (step 11).
|
|
3
|
+
*
|
|
4
|
+
* After a run, `--digest` writes a capped Markdown excerpt of the *failing*
|
|
5
|
+
* slots to `.check/digest.md` so an agent working through a big red repo spends
|
|
6
|
+
* its context on a bounded index instead of every raw `.check/<slot>.json`. The
|
|
7
|
+
* digest is an INDEX, never a replacement: it truncates (the first N findings
|
|
8
|
+
* per slot, a total byte budget) and never normalizes — each section points
|
|
9
|
+
* back at the authoritative raw file, which this module never touches.
|
|
10
|
+
*
|
|
11
|
+
* It reuses step 4's per-adapter fingerprint extractors to list a slot's
|
|
12
|
+
* findings (render the first N of the same items); a slot whose adapter has no
|
|
13
|
+
* extractor falls back to a tail of its raw text (b6). A green run has nothing
|
|
14
|
+
* to digest, so {@link writeDigest} removes any stale `.check/digest.md` — the
|
|
15
|
+
* file's presence always means "this run had failures".
|
|
16
|
+
*
|
|
17
|
+
* The `../digest` barrel (`index.ts`) is this module's only public surface (C2);
|
|
18
|
+
* siblings import from there, never from this file directly.
|
|
19
|
+
*/
|
|
20
|
+
import { rm } from 'node:fs/promises';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { writeFileAtomic } from '../atomic.js';
|
|
23
|
+
import { fingerprint } from '../baseline/index.js';
|
|
24
|
+
/** The digest file, beside `summary.json` under the gitignored `.check/`. */
|
|
25
|
+
export const DIGEST_FILE = 'digest.md';
|
|
26
|
+
/**
|
|
27
|
+
* Conservative defaults: ~10 findings a slot and an 8 KB ceiling keep even a
|
|
28
|
+
* fully-red repo's digest to roughly two thousand tokens — small enough to read
|
|
29
|
+
* in one gulp, with the raw files a click away for the rest.
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_BUDGET = { maxItemsPerSlot: 10, maxBytes: 8000 };
|
|
32
|
+
/** Whether a string parses as JSON (mirrors the orchestrator's persist rule). */
|
|
33
|
+
function isJson(raw) {
|
|
34
|
+
try {
|
|
35
|
+
JSON.parse(raw);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The `.check/` path holding the bytes this section excerpts — matched to how
|
|
44
|
+
* {@link import('../orchestrator.js')} persisted them: an adapter's JSON output
|
|
45
|
+
* lands in `.check/<outputFile>`, everything else in `<slot>.stdout.txt` /
|
|
46
|
+
* `<slot>.stderr.txt`. Points the agent at exactly what to read for the full
|
|
47
|
+
* diagnostics.
|
|
48
|
+
*/
|
|
49
|
+
function rawPointer(adapter, outcome) {
|
|
50
|
+
if (adapter.outputFile && isJson(outcome.stdout))
|
|
51
|
+
return `.check/${adapter.outputFile}`;
|
|
52
|
+
if (outcome.stdout.trim())
|
|
53
|
+
return `.check/${adapter.slot}.stdout.txt`;
|
|
54
|
+
if (outcome.stderr.trim())
|
|
55
|
+
return `.check/${adapter.slot}.stderr.txt`;
|
|
56
|
+
return '.check/summary.json';
|
|
57
|
+
}
|
|
58
|
+
/** Non-empty lines of the raw text, used by the tail fallback. */
|
|
59
|
+
function contentLines(text) {
|
|
60
|
+
return text.split('\n').filter((line) => line.trim() !== '');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Render one failing slot's section. When the adapter can be fingerprinted, list
|
|
64
|
+
* the first N finding keys (the same items the baseline records); otherwise fall
|
|
65
|
+
* back to the last N lines of raw text — where a compiler or test runner puts
|
|
66
|
+
* its summary. Either way the section is capped and points at the raw file.
|
|
67
|
+
*/
|
|
68
|
+
function renderSection(run, maxItems) {
|
|
69
|
+
const { slot, adapter, outcome } = run;
|
|
70
|
+
const raw = rawPointer(adapter, outcome);
|
|
71
|
+
const heading = `## ${slot} — ${adapter.name}`;
|
|
72
|
+
const keys = fingerprint(adapter.name, outcome.stdout);
|
|
73
|
+
if (keys && keys.size > 0) {
|
|
74
|
+
const all = [...keys];
|
|
75
|
+
const shown = all.slice(0, maxItems);
|
|
76
|
+
const lines = shown.map((k) => `- ${k}`);
|
|
77
|
+
if (all.length > shown.length) {
|
|
78
|
+
lines.push(`- … ${all.length - shown.length} more (see \`${raw}\`)`);
|
|
79
|
+
}
|
|
80
|
+
return `${heading}\n\nRaw: \`${raw}\` — ${all.length} finding(s)\n\n${lines.join('\n')}\n`;
|
|
81
|
+
}
|
|
82
|
+
// No extractor (fallow, tsc, vitest, …) or a supported adapter that failed
|
|
83
|
+
// with no parsed findings: excerpt the tail of the raw text — truncation, not
|
|
84
|
+
// normalization — and point at the file for the rest.
|
|
85
|
+
const text = outcome.stdout.trim() ? outcome.stdout : outcome.stderr;
|
|
86
|
+
const all = contentLines(text);
|
|
87
|
+
if (all.length === 0) {
|
|
88
|
+
return `${heading}\n\nRaw: \`${raw}\` — exited ${outcome.exit_code} with no captured output\n`;
|
|
89
|
+
}
|
|
90
|
+
const tail = all.slice(-maxItems);
|
|
91
|
+
const note = tail.length < all.length ? ` — last ${tail.length} of ${all.length} lines` : '';
|
|
92
|
+
return `${heading}\n\nRaw: \`${raw}\`${note}\n\n\`\`\`\n${tail.join('\n')}\n\`\`\`\n`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build the Markdown digest for a completed run, or `null` when nothing failed.
|
|
96
|
+
* A check is "failing" when the summary marks it `ok: false` and not skipped —
|
|
97
|
+
* so a slot whose findings a baseline fully grandfathers (still `ok: true`) is
|
|
98
|
+
* correctly absent. Sections are added in summary (cheapest-first) order until
|
|
99
|
+
* the byte budget is spent; any remaining failing slots are named in a trailing
|
|
100
|
+
* note rather than silently dropped.
|
|
101
|
+
*/
|
|
102
|
+
export function buildDigest(runs, checks, budget = DEFAULT_BUDGET) {
|
|
103
|
+
const failing = checks.filter((c) => !c.ok && !c.skipped);
|
|
104
|
+
if (failing.length === 0)
|
|
105
|
+
return null;
|
|
106
|
+
const runBySlot = new Map(runs.map((r) => [r.slot, r]));
|
|
107
|
+
let out = `# checkride failure digest\n\n` +
|
|
108
|
+
`${failing.length} of ${checks.length} check(s) failed. Excerpt only — up to ` +
|
|
109
|
+
`${budget.maxItemsPerSlot} finding(s) per slot; read each linked raw file under ` +
|
|
110
|
+
`\`.check/\` for the complete, authoritative diagnostics.\n`;
|
|
111
|
+
let rendered = 0;
|
|
112
|
+
for (const check of failing) {
|
|
113
|
+
const run = runBySlot.get(check.name);
|
|
114
|
+
// A failing non-skipped check always has a run; keep a minimal fallback so a
|
|
115
|
+
// future code path that summarizes a failure without a run can't crash here.
|
|
116
|
+
const section = run
|
|
117
|
+
? `\n${renderSection(run, budget.maxItemsPerSlot)}`
|
|
118
|
+
: `\n## ${check.name} — ${check.adapter ?? 'unknown'}\n\nRaw: \`.check/summary.json\` — exited ${check.exit_code}\n`;
|
|
119
|
+
// Byte budget: once a section would overflow, stop and name what's left —
|
|
120
|
+
// but only after at least one section is in, so the digest is never empty.
|
|
121
|
+
if (rendered > 0 && Buffer.byteLength(out + section, 'utf8') > budget.maxBytes) {
|
|
122
|
+
const omitted = failing.length - rendered;
|
|
123
|
+
out += `\n_Digest truncated at ${budget.maxBytes} bytes; ${omitted} more failing slot(s) omitted — see \`.check/summary.json\`._\n`;
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
out += section;
|
|
127
|
+
rendered += 1;
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Persist the digest for a completed run. Writes `.check/digest.md` when a slot
|
|
133
|
+
* failed; on a green run removes any stale digest so the file's presence always
|
|
134
|
+
* means "this run failed". `cwd/.check/` is assumed to exist — the orchestrator
|
|
135
|
+
* creates it before running. Returns whether a digest file now exists.
|
|
136
|
+
*/
|
|
137
|
+
export async function writeDigest(cwd, runs, checks, budget = DEFAULT_BUDGET) {
|
|
138
|
+
const path = join(cwd, '.check', DIGEST_FILE);
|
|
139
|
+
const digest = buildDigest(runs, checks, budget);
|
|
140
|
+
if (digest === null) {
|
|
141
|
+
await rm(path, { force: true });
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
await writeFileAtomic(path, digest);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=digest.js.map
|