plumbbob 0.9.3 → 0.9.5
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 +15 -13
- package/dist/cli-core.js +19 -2
- package/dist/lib/check.js +46 -13
- package/dist/lib/intent.js +1 -1
- package/dist/lib/latch.js +3 -3
- package/dist/lib/reentry.js +70 -0
- package/dist/verbs/agent.js +2 -2
- package/dist/verbs/doctor.js +4 -4
- package/dist/verbs/finish.js +1 -1
- package/dist/verbs/recover.js +297 -0
- package/dist/verbs/revert.js +2 -2
- package/dist/verbs/spike.js +8 -2
- package/hooks/post-edit.sh +4 -4
- package/hooks/pre-bash-commit.sh +3 -3
- package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
- package/node_modules/checkride/CHANGELOG.md +1003 -0
- package/node_modules/checkride/LICENSE +201 -21
- package/node_modules/checkride/README.md +171 -30
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
- package/node_modules/checkride/dist/adapters.d.ts +18 -6
- package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
- package/node_modules/checkride/dist/adapters.js +42 -23
- package/node_modules/checkride/dist/adapters.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
- package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
- package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
- package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/command.js +77 -0
- package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts +61 -0
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/cursor.js +189 -0
- package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
- package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/files.js +80 -0
- package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
- package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/harness.js +84 -0
- package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
- package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
- package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
- package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/index.js +9 -4
- package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts +58 -0
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/scripts.js +299 -0
- package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
- package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
- package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
- package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/configured.js +45 -0
- package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
- package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/format.js +56 -0
- package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
- package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
- package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
- package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/index.js +19 -0
- package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
- package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/json.js +47 -0
- package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
- package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/raw.js +91 -0
- package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
- package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/summary.js +108 -0
- package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
- package/node_modules/checkride/dist/atomic.d.ts +16 -1
- package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
- package/node_modules/checkride/dist/atomic.js +25 -3
- package/node_modules/checkride/dist/atomic.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
- package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fallow.js +161 -58
- package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts +7 -7
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.js +16 -19
- package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
- package/node_modules/checkride/dist/baseline/index.d.ts +4 -4
- package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/index.js +4 -4
- package/node_modules/checkride/dist/baseline/index.js.map +1 -1
- package/node_modules/checkride/dist/baseline/store.d.ts +12 -4
- package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/store.js +16 -9
- package/node_modules/checkride/dist/baseline/store.js.map +1 -1
- package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
- package/node_modules/checkride/dist/baseline-command.js +7 -7
- package/node_modules/checkride/dist/baseline-command.js.map +1 -1
- package/node_modules/checkride/dist/cli.d.ts +17 -4
- package/node_modules/checkride/dist/cli.d.ts.map +1 -1
- package/node_modules/checkride/dist/cli.js +259 -18
- package/node_modules/checkride/dist/cli.js.map +1 -1
- package/node_modules/checkride/dist/config.d.ts +84 -8
- package/node_modules/checkride/dist/config.d.ts.map +1 -1
- package/node_modules/checkride/dist/config.js +122 -18
- package/node_modules/checkride/dist/config.js.map +1 -1
- package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
- package/node_modules/checkride/dist/digest/digest.js +5 -5
- package/node_modules/checkride/dist/digest/index.d.ts +2 -2
- package/node_modules/checkride/dist/digest/index.js +2 -2
- package/node_modules/checkride/dist/doctor.d.ts +25 -6
- package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
- package/node_modules/checkride/dist/doctor.js +193 -27
- package/node_modules/checkride/dist/doctor.js.map +1 -1
- package/node_modules/checkride/dist/gate.d.ts +135 -0
- package/node_modules/checkride/dist/gate.d.ts.map +1 -0
- package/node_modules/checkride/dist/gate.js +490 -0
- package/node_modules/checkride/dist/gate.js.map +1 -0
- package/node_modules/checkride/dist/init.d.ts +72 -12
- package/node_modules/checkride/dist/init.d.ts.map +1 -1
- package/node_modules/checkride/dist/init.js +324 -81
- package/node_modules/checkride/dist/init.js.map +1 -1
- package/node_modules/checkride/dist/json.d.ts +21 -0
- package/node_modules/checkride/dist/json.d.ts.map +1 -0
- package/node_modules/checkride/dist/json.js +21 -0
- package/node_modules/checkride/dist/json.js.map +1 -0
- package/node_modules/checkride/dist/links.d.ts +31 -5
- package/node_modules/checkride/dist/links.d.ts.map +1 -1
- package/node_modules/checkride/dist/links.js +141 -32
- package/node_modules/checkride/dist/links.js.map +1 -1
- package/node_modules/checkride/dist/node-pin.d.ts +129 -0
- package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
- package/node_modules/checkride/dist/node-pin.js +211 -0
- package/node_modules/checkride/dist/node-pin.js.map +1 -0
- package/node_modules/checkride/dist/orchestrator.d.ts +40 -10
- package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
- package/node_modules/checkride/dist/orchestrator.js +196 -102
- package/node_modules/checkride/dist/orchestrator.js.map +1 -1
- package/node_modules/checkride/dist/pack.d.ts +8 -9
- package/node_modules/checkride/dist/pack.d.ts.map +1 -1
- package/node_modules/checkride/dist/pack.js +53 -17
- package/node_modules/checkride/dist/pack.js.map +1 -1
- package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
- package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/detect.js +6 -1
- package/node_modules/checkride/dist/pm/detect.js.map +1 -1
- package/node_modules/checkride/dist/pm/index.d.ts +6 -2
- package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/index.js +6 -2
- package/node_modules/checkride/dist/pm/index.js.map +1 -1
- package/node_modules/checkride/dist/pm/launch.d.ts +51 -0
- package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/launch.js +92 -0
- package/node_modules/checkride/dist/pm/launch.js.map +1 -0
- package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
- package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/tools.js +124 -0
- package/node_modules/checkride/dist/pm/tools.js.map +1 -0
- package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
- package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/translate.js +78 -18
- package/node_modules/checkride/dist/pm/translate.js.map +1 -1
- package/node_modules/checkride/dist/proc.d.ts +30 -0
- package/node_modules/checkride/dist/proc.d.ts.map +1 -0
- package/node_modules/checkride/dist/proc.js +42 -0
- package/node_modules/checkride/dist/proc.js.map +1 -0
- package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
- package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/cli.js +24 -0
- package/node_modules/checkride/dist/qa/cli.js.map +1 -0
- package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
- package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/dead.js +88 -0
- package/node_modules/checkride/dist/qa/dead.js.map +1 -0
- package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
- package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/dupes.js +62 -0
- package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
- package/node_modules/checkride/dist/qa/health.d.ts +85 -0
- package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/health.js +109 -0
- package/node_modules/checkride/dist/qa/health.js.map +1 -0
- package/node_modules/checkride/dist/qa/index.d.ts +23 -0
- package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/index.js +22 -0
- package/node_modules/checkride/dist/qa/index.js.map +1 -0
- package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
- package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/mutation.js +195 -0
- package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
- package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
- package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/qa.js +158 -0
- package/node_modules/checkride/dist/qa/qa.js.map +1 -0
- package/node_modules/checkride/dist/qa/read.d.ts +40 -0
- package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/read.js +47 -0
- package/node_modules/checkride/dist/qa/read.js.map +1 -0
- package/node_modules/checkride/dist/qa/render.d.ts +26 -0
- package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/render.js +310 -0
- package/node_modules/checkride/dist/qa/render.js.map +1 -0
- package/node_modules/checkride/dist/security.d.ts +45 -0
- package/node_modules/checkride/dist/security.d.ts.map +1 -0
- package/node_modules/checkride/dist/security.js +86 -0
- package/node_modules/checkride/dist/security.js.map +1 -0
- package/node_modules/checkride/dist/smoke.d.ts +5 -5
- package/node_modules/checkride/dist/smoke.js +5 -5
- package/node_modules/checkride/dist/snippets.d.ts +26 -29
- package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
- package/node_modules/checkride/dist/snippets.js +26 -30
- package/node_modules/checkride/dist/snippets.js.map +1 -1
- package/node_modules/checkride/dist/tool-json.d.ts +33 -0
- package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
- package/node_modules/checkride/dist/tool-json.js +58 -0
- package/node_modules/checkride/dist/tool-json.js.map +1 -0
- package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
- package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/cli.js +26 -0
- package/node_modules/checkride/dist/triage/cli.js.map +1 -0
- package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
- package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
- package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
- package/node_modules/checkride/dist/triage/env.d.ts +54 -0
- package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/env.js +81 -0
- package/node_modules/checkride/dist/triage/env.js.map +1 -0
- package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
- package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/gate.js +121 -0
- package/node_modules/checkride/dist/triage/gate.js.map +1 -0
- package/node_modules/checkride/dist/triage/index.d.ts +22 -0
- package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/index.js +20 -0
- package/node_modules/checkride/dist/triage/index.js.map +1 -0
- package/node_modules/checkride/dist/triage/render.d.ts +19 -0
- package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/render.js +419 -0
- package/node_modules/checkride/dist/triage/render.js.map +1 -0
- package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
- package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/triage.js +131 -0
- package/node_modules/checkride/dist/triage/triage.js.map +1 -0
- package/node_modules/checkride/package.json +17 -15
- package/node_modules/checkride/schema/checkride.config.schema.json +62 -5
- package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
- package/node_modules/checkride/skills/check/SKILL.md +257 -0
- package/node_modules/checkride/skills/qa/SKILL.md +231 -0
- package/node_modules/checkride/templates/shared/cspell.json +1 -0
- package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
- package/package.json +2 -2
- package/skills/build/SKILL.md +23 -19
- package/skills/finish/SKILL.md +3 -1
- package/skills/harvest/SKILL.md +2 -1
- package/skills/plan/SKILL.md +8 -7
- package/skills/recover/SKILL.md +28 -0
- package/skills/refine/SKILL.md +5 -4
- package/skills/spike/SKILL.md +1 -1
- package/skills/step/SKILL.md +4 -4
- package/skills/verify/SKILL.md +19 -14
- package/templates/intent.md +8 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,18 +11,19 @@
|
|
|
11
11
|
* Generation, not transformation: every file is written once; the project owns
|
|
12
12
|
* it afterward.
|
|
13
13
|
*/
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
14
15
|
import { existsSync, readFileSync } from 'node:fs';
|
|
15
16
|
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
16
17
|
import { basename, dirname, join } from 'node:path';
|
|
17
18
|
import { fileURLToPath } from 'node:url';
|
|
18
19
|
import { ADAPTERS, SLOTS } from './adapters.js';
|
|
19
20
|
import { planSnippets, selectDocFiles } from './snippets.js';
|
|
20
|
-
import {
|
|
21
|
+
import { detectHarnesses, writeCursorSkills, writeHooks } from './agent-setup/index.js';
|
|
21
22
|
import { BASELINE_FILE, isFingerprintable } from './baseline/index.js';
|
|
22
23
|
import { runBaseline } from './baseline-command.js';
|
|
23
|
-
import { configSchemaUrl, resolveChecks } from './config.js';
|
|
24
|
-
import { runChecks } from './orchestrator.js';
|
|
25
|
-
import { detectPackageManager } from './pm/index.js';
|
|
24
|
+
import { configSchemaUrl, loadConfig, resolveChecks } from './config.js';
|
|
25
|
+
import { runChecks, selectChecks } from './orchestrator.js';
|
|
26
|
+
import { detectPackageManager, execCommand, runScript } from './pm/index.js';
|
|
26
27
|
const NULL_OUT = { write: () => true };
|
|
27
28
|
/** Run the adopted checks once; a failing (non-skipped) check marks its slot. */
|
|
28
29
|
async function defaultProbe(slots, cwd) {
|
|
@@ -33,22 +34,131 @@ async function defaultProbe(slots, cwd) {
|
|
|
33
34
|
}
|
|
34
35
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
35
36
|
const TEMPLATES_DIR = join(HERE, '..', 'templates');
|
|
36
|
-
const
|
|
37
|
+
const STANZA_BEGIN_PREFIX = '<!-- checkride:begin';
|
|
37
38
|
const STANZA_END = '<!-- checkride:end -->';
|
|
39
|
+
/** The block, capturing its stamp (absent on stanzas written before v0.10.1) and its body. */
|
|
40
|
+
const STANZA_RE = /<!-- checkride:begin(?: hash=([0-9a-z]+))? -->([\s\S]*?)<!-- checkride:end -->/;
|
|
41
|
+
const STANZA_BEGIN_RE = /<!-- checkride:begin(?: hash=[0-9a-z]+)? -->/;
|
|
38
42
|
// ----------------------------------------------------------------------------
|
|
39
43
|
// AGENTS.md stanza (gate: idempotent)
|
|
40
44
|
// ----------------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Compare two stanza bodies the way a reader would: line endings and trailing
|
|
47
|
+
* whitespace are not edits. Deliberately minimal — one checkride version stamps
|
|
48
|
+
* a block and a later one verifies that stamp, so every rule here has to keep
|
|
49
|
+
* holding across versions or a pristine stanza starts reading as an edited one.
|
|
50
|
+
*/
|
|
51
|
+
function normalizeStanza(text) {
|
|
52
|
+
return text.replace(/\r\n/g, '\n').replace(/[ \t]+$/gm, '').trim();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The stamp written into the begin marker: a digest of the body checkride
|
|
56
|
+
* generated. A later run recomputes it from what is on disk — a match means the
|
|
57
|
+
* block is still checkride's own output and is safe to refresh; a mismatch means
|
|
58
|
+
* someone edited it and refreshing would destroy their work.
|
|
59
|
+
*
|
|
60
|
+
* The `v1` prefix earns its place twice: it dates the normalization rules above
|
|
61
|
+
* (change them and bump it, so old stamps read as unverifiable rather than
|
|
62
|
+
* edited), and it guarantees the token contains a digit. cspell ignores words
|
|
63
|
+
* with digits, so a digest that happened to come up all `a`-`f` cannot fail the
|
|
64
|
+
* `spell` check of the repo checkride wrote it into.
|
|
65
|
+
*/
|
|
66
|
+
function stanzaStamp(body) {
|
|
67
|
+
return `v1${createHash('sha256').update(normalizeStanza(body)).digest('hex').slice(0, 16)}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A stanza body without its trailing generated `Active checks in this repo: …`
|
|
71
|
+
* line — the part that is pure wording, identical in every repo running a given
|
|
72
|
+
* checkride version.
|
|
73
|
+
*
|
|
74
|
+
* The active-checks line is what makes two stanzas from the same release differ,
|
|
75
|
+
* so a registry of released wordings has to compare everything but that. If the
|
|
76
|
+
* line is missing, or something follows it inside the markers, nothing is
|
|
77
|
+
* stripped and the digest simply fails to match — which is the safe answer.
|
|
78
|
+
*/
|
|
79
|
+
function stanzaPreamble(body) {
|
|
80
|
+
return normalizeStanza(normalizeStanza(body).replace(/\nActive checks in this repo:[^\n]*$/, ''));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The wording of every stanza checkride released before it stamped them, keyed
|
|
84
|
+
* by {@link stanzaPreamble} digest. Four distinct texts across v0.1.1–v0.10.0.
|
|
85
|
+
*
|
|
86
|
+
* This is what makes the stamp's arrival a non-event for repos that never
|
|
87
|
+
* touched their stanza. Without it, every upgrading repo looked `unstamped` —
|
|
88
|
+
* an older version's wording is not distinguishable from a customization by
|
|
89
|
+
* comparison alone — so the first run after upgrading refused and wrote
|
|
90
|
+
* *nothing*, hooks and config included. That is how the 0.10.1 gate-timeout fix
|
|
91
|
+
* failed to reach the repos that most needed it: the guard protecting AGENTS.md
|
|
92
|
+
* prose was also withholding a fix for a gate that had silently stopped gating.
|
|
93
|
+
*
|
|
94
|
+
* Recognizing the wording collapses that to the case it was always meant to
|
|
95
|
+
* cover. A pre-stamp stanza whose preamble is one of these is checkride's own
|
|
96
|
+
* output, untouched, and refreshing it loses nothing; one that has been edited
|
|
97
|
+
* still fails to match and is still refused.
|
|
98
|
+
*
|
|
99
|
+
* The list is closed. Every release from 0.10.1 stamps what it writes, so no
|
|
100
|
+
* future version can add an unstamped wording — nothing here needs maintaining.
|
|
101
|
+
*/
|
|
102
|
+
const LEGACY_STANZA_PREAMBLES = new Set([
|
|
103
|
+
'v16da2ec6a25e24085', // v0.1.1–v0.1.6
|
|
104
|
+
'v190c2d48a280ff92c', // v0.2.0–v0.7.0
|
|
105
|
+
'v1d4b4eaeeccb5faa2', // v0.8.0–v0.9.6
|
|
106
|
+
'v17a3a1a85e3c3123e', // v0.10.0 (0.10.1 shares the wording but stamps it)
|
|
107
|
+
]);
|
|
108
|
+
/** Classify the stanza in `content` against the `body` checkride would write. */
|
|
109
|
+
export function inspectStanza(content, body) {
|
|
110
|
+
const match = STANZA_RE.exec(content);
|
|
111
|
+
if (!match) {
|
|
112
|
+
// A begin marker with no end is a stanza someone edited badly, not an absent
|
|
113
|
+
// one: appending a second block would be the same data loss in another form.
|
|
114
|
+
return content.includes(STANZA_BEGIN_PREFIX) ? 'edited' : 'absent';
|
|
115
|
+
}
|
|
116
|
+
const [, stamp, found = ''] = match;
|
|
117
|
+
if (stamp === undefined) {
|
|
118
|
+
if (normalizeStanza(found) === normalizeStanza(body))
|
|
119
|
+
return 'pristine';
|
|
120
|
+
return LEGACY_STANZA_PREAMBLES.has(stanzaStamp(stanzaPreamble(found))) ? 'pristine' : 'unstamped';
|
|
121
|
+
}
|
|
122
|
+
return stamp === stanzaStamp(found) ? 'pristine' : 'edited';
|
|
43
123
|
}
|
|
44
|
-
/**
|
|
45
|
-
|
|
124
|
+
/**
|
|
125
|
+
* The `struct` slot's section: where the boundary rules live, not what they say.
|
|
126
|
+
*
|
|
127
|
+
* checkride ships opinionated ast-grep defaults (`no-class.yml` and friends),
|
|
128
|
+
* but it does not own the repo's architecture, and the stanza is the one place
|
|
129
|
+
* a repo cannot talk back — editing it blocks the next refresh. So this points
|
|
130
|
+
* at the rule files and stops. A repo that allows classes, default exports, or
|
|
131
|
+
* bundler-style extensionless imports deletes those rules and this stays true.
|
|
132
|
+
*/
|
|
133
|
+
function structSection() {
|
|
134
|
+
return [
|
|
135
|
+
'### Module boundaries',
|
|
136
|
+
'',
|
|
137
|
+
'The `struct` check runs whatever ast-grep rules `sgconfig.yml` points at',
|
|
138
|
+
"(`rules/` by default). Those files are this repo's boundary convention —",
|
|
139
|
+
'read them rather than assuming one.',
|
|
140
|
+
'',
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The agent-facing contract block, parameterized by the active checks and the
|
|
145
|
+
* repo's package manager.
|
|
146
|
+
*
|
|
147
|
+
* `pm` is not cosmetic. The stanza is a list of commands an agent is told to
|
|
148
|
+
* run, and `pnpm check` in an npm repo is an instruction that cannot succeed —
|
|
149
|
+
* the agent either invents a substitute or reports the pipeline as broken.
|
|
150
|
+
* Everything here routes through {@link runScript}/{@link execCommand} for that
|
|
151
|
+
* reason; nothing spells a launcher literally.
|
|
152
|
+
*/
|
|
153
|
+
export function buildStanza(activeSlots, pm = 'pnpm') {
|
|
154
|
+
const check = runScript(pm, 'check');
|
|
155
|
+
const triage = execCommand(pm, ['checkride', 'triage']);
|
|
46
156
|
return [
|
|
47
157
|
'## Checkride: the definition of done',
|
|
48
158
|
'',
|
|
49
|
-
|
|
159
|
+
`\`${check}\` is the single source of truth for "done". Exit 0 means the work is`,
|
|
50
160
|
'complete; any other exit code means it is not. Never claim a task is finished while',
|
|
51
|
-
|
|
161
|
+
`\`${check}\` is red.`,
|
|
52
162
|
'',
|
|
53
163
|
'When it fails:',
|
|
54
164
|
'',
|
|
@@ -56,13 +166,16 @@ export function buildStanza(activeSlots) {
|
|
|
56
166
|
"2. Read that check's raw output (`.check/<slot>.json` or `.check/<slot>.stdout.txt`).",
|
|
57
167
|
'3. Fix the root cause, then re-run.',
|
|
58
168
|
'',
|
|
59
|
-
|
|
60
|
-
'`
|
|
169
|
+
`\`${triage}\` runs this procedure in full and reads \`.check/\` for you`,
|
|
170
|
+
'(`/checkride:check` and `/checkride-check` are the same thing as a skill).',
|
|
61
171
|
'',
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
'
|
|
65
|
-
'
|
|
172
|
+
`Tight feedback loops: \`${check} --bail\`, \`${check} --only types,lint\`, and`,
|
|
173
|
+
`\`${check} --changed\`.`,
|
|
174
|
+
'',
|
|
175
|
+
'If a stop-gate hook is configured (`.claude/settings.json` or `.cursor/hooks.json`),',
|
|
176
|
+
`it runs the full \`${check}\` as the final gate — so while iterating, prefer the narrow`,
|
|
177
|
+
'commands above and let the hook run the authoritative pipeline once at the end rather',
|
|
178
|
+
'than running the full check yourself every loop.',
|
|
66
179
|
'',
|
|
67
180
|
'### Baseline',
|
|
68
181
|
'',
|
|
@@ -72,27 +185,28 @@ export function buildStanza(activeSlots) {
|
|
|
72
185
|
'the ratchet, so the baseline only ever shrinks. Never add to the baseline to make a',
|
|
73
186
|
'check pass; fix the finding.',
|
|
74
187
|
'',
|
|
75
|
-
'
|
|
76
|
-
'',
|
|
77
|
-
'A module is a unit of encapsulation. A single file is a module; promote it to a',
|
|
78
|
-
'folder with a barrel `index.ts` when it grows internals worth hiding. A folder',
|
|
79
|
-
"module's `index.ts` is its only public surface — re-exports only, no logic. Import",
|
|
80
|
-
"siblings through `'../<sibling>/index.js'`, never their internals.",
|
|
81
|
-
'',
|
|
82
|
-
'Named exports only; no classes; `.js` extensions on relative imports.',
|
|
83
|
-
'',
|
|
188
|
+
...(activeSlots.includes('struct') ? structSection() : []),
|
|
84
189
|
`Active checks in this repo: ${activeSlots.join(', ')}.`,
|
|
85
190
|
].join('\n');
|
|
86
191
|
}
|
|
87
192
|
/**
|
|
88
193
|
* Insert or refresh the checkride stanza in an AGENTS.md body. Idempotent:
|
|
89
|
-
* applying twice yields identical output.
|
|
194
|
+
* applying twice yields identical output. It rewrites the marked region without
|
|
195
|
+
* looking at what was there — callers gate on {@link inspectStanza} first.
|
|
90
196
|
*/
|
|
91
197
|
export function applyStanza(content, body) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
198
|
+
// A replacer function, not the string: a `$&` in the stanza would otherwise be
|
|
199
|
+
// read as a backreference.
|
|
200
|
+
const block = `${STANZA_BEGIN_PREFIX} hash=${stanzaStamp(body)} -->\n\n${body}\n\n${STANZA_END}`;
|
|
201
|
+
if (STANZA_RE.test(content)) {
|
|
202
|
+
return content.replace(STANZA_RE, () => block);
|
|
203
|
+
}
|
|
204
|
+
if (STANZA_BEGIN_RE.test(content)) {
|
|
205
|
+
// A begin marker with no end: replace the marker in place rather than
|
|
206
|
+
// appending a second block, which would leave two begins and make the next
|
|
207
|
+
// refresh swallow everything between them. What followed the orphaned marker
|
|
208
|
+
// stays where it is — now outside the markers, so nothing rewrites it again.
|
|
209
|
+
return content.replace(STANZA_BEGIN_RE, () => block);
|
|
96
210
|
}
|
|
97
211
|
if (content.trim().length === 0) {
|
|
98
212
|
return `${block}\n`;
|
|
@@ -312,18 +426,57 @@ async function writePackage(w, dir, pkgName, value) {
|
|
|
312
426
|
await put(w, join(dir, 'src', 'index.test.ts'), smokeTest(value));
|
|
313
427
|
}
|
|
314
428
|
/**
|
|
315
|
-
* Write/refresh the
|
|
316
|
-
*
|
|
317
|
-
*
|
|
429
|
+
* Write/refresh the agent hooks unless opted out (`hook === false`), remove any
|
|
430
|
+
* named for removal, for the selected harnesses (default: detected) and the
|
|
431
|
+
* repo's detected package manager. Records each file when it changed, else a
|
|
432
|
+
* no-op note in `skipped` when one is provided.
|
|
433
|
+
*
|
|
434
|
+
* `--no-hook` and `--remove-hook` compose rather than conflict: the first says
|
|
435
|
+
* "write nothing", the second "take this one out", and together they mean
|
|
436
|
+
* "remove the gate and leave the rest of the setup untouched" — which is the
|
|
437
|
+
* whole point of being able to drop a hook after the fact.
|
|
438
|
+
*/
|
|
439
|
+
async function writeHook(w, options, skipped) {
|
|
440
|
+
const remove = options.removeHooks ?? [];
|
|
441
|
+
if (options.hook === false && remove.length === 0)
|
|
442
|
+
return;
|
|
443
|
+
const hooks = options.hook === false ? [] : options.hooks;
|
|
444
|
+
const result = await writeHooks(w.cwd, {
|
|
445
|
+
dryRun: w.dryRun,
|
|
446
|
+
...(hooks ? { hooks } : {}),
|
|
447
|
+
...(remove.length > 0 ? { remove } : {}),
|
|
448
|
+
...(options.harnesses ? { harnesses: options.harnesses } : {}),
|
|
449
|
+
});
|
|
450
|
+
record(w, result.files, skipped);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Write the bundled skills for every selected harness that cannot install them
|
|
454
|
+
* as a plugin. Only Cursor needs this today; Claude Code gets the same two
|
|
455
|
+
* skills from `.claude-plugin/`, installed once for every repo.
|
|
456
|
+
*
|
|
457
|
+
* Unlike the hooks this is not covered by `--no-hook`: that flag turns off the
|
|
458
|
+
* mechanical gate, and a skill gates nothing.
|
|
318
459
|
*/
|
|
319
|
-
async function
|
|
320
|
-
|
|
460
|
+
async function writeSkills(w, options, skipped) {
|
|
461
|
+
const harnesses = options.harnesses ?? detectHarnesses(w.cwd);
|
|
462
|
+
if (!harnesses.includes('cursor'))
|
|
321
463
|
return;
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
464
|
+
record(w, await writeCursorSkills(w.cwd, { dryRun: w.dryRun }), skipped);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Fold a writer's file list into the run's written/removed/skipped report. A
|
|
468
|
+
* deleted file is a change, but not a *write* — counting it as one would have
|
|
469
|
+
* `--remove-hook gate` report that it wrote a file it actually took away.
|
|
470
|
+
*/
|
|
471
|
+
function record(w, files, skipped) {
|
|
472
|
+
for (const f of files) {
|
|
473
|
+
if (!f.changed)
|
|
474
|
+
skipped?.push(`${f.path} (${f.removed === true ? 'absent' : 'unchanged'})`);
|
|
475
|
+
else if (f.removed === true)
|
|
476
|
+
w.removed.push(f.path);
|
|
477
|
+
else
|
|
478
|
+
w.written.push(f.path);
|
|
479
|
+
}
|
|
327
480
|
}
|
|
328
481
|
// ----------------------------------------------------------------------------
|
|
329
482
|
// New-project mode
|
|
@@ -361,7 +514,7 @@ async function writeNewScaffold(w, s) {
|
|
|
361
514
|
* into `.claude/settings.json` idempotently rather than overwriting.
|
|
362
515
|
*/
|
|
363
516
|
async function planCollisions(s, cwd) {
|
|
364
|
-
const plan = { cwd, dryRun: true, written: [] };
|
|
517
|
+
const plan = { cwd, dryRun: true, written: [], removed: [] };
|
|
365
518
|
await writeNewScaffold(plan, s);
|
|
366
519
|
return plan.written.filter((rel) => existsSync(join(cwd, rel)));
|
|
367
520
|
}
|
|
@@ -388,7 +541,7 @@ function resolveNewScaffold(options, cwd) {
|
|
|
388
541
|
};
|
|
389
542
|
}
|
|
390
543
|
/**
|
|
391
|
-
* Overwrite protection
|
|
544
|
+
* Overwrite protection: unless `force`, refuse rather than clobber any file
|
|
392
545
|
* the scaffold would write. Planning on a dry writer first means a collision
|
|
393
546
|
* bails before a single real byte is written — the refusal writes nothing.
|
|
394
547
|
*/
|
|
@@ -412,14 +565,24 @@ function reportNew(stdout, shape, w, cwd) {
|
|
|
412
565
|
async function initNew(options, cwd) {
|
|
413
566
|
const scaffold = resolveNewScaffold(options, cwd);
|
|
414
567
|
await assertNoCollisions(scaffold, cwd, options.force ?? false);
|
|
415
|
-
const w = { cwd, dryRun: options.dryRun ?? false, written: [] };
|
|
568
|
+
const w = { cwd, dryRun: options.dryRun ?? false, written: [], removed: [] };
|
|
416
569
|
await writeNewScaffold(w, scaffold);
|
|
417
|
-
// Claude Code Stop hook (opt-out
|
|
570
|
+
// Claude Code Stop hook (opt-out). A fresh project has no PM lockfile
|
|
418
571
|
// yet, so it resolves to the `pnpm` default — matching the generated scripts.
|
|
419
|
-
await writeHook(w, options
|
|
572
|
+
await writeHook(w, options);
|
|
573
|
+
await writeSkills(w, options);
|
|
420
574
|
if (options.stdout)
|
|
421
575
|
reportNew(options.stdout, scaffold.shape, w, cwd);
|
|
422
|
-
return {
|
|
576
|
+
return {
|
|
577
|
+
mode: 'new',
|
|
578
|
+
shape: scaffold.shape,
|
|
579
|
+
written: w.written,
|
|
580
|
+
removed: w.removed,
|
|
581
|
+
skipped: [],
|
|
582
|
+
disabled: [],
|
|
583
|
+
grandfathered: [],
|
|
584
|
+
exitCode: 0,
|
|
585
|
+
};
|
|
423
586
|
}
|
|
424
587
|
// ----------------------------------------------------------------------------
|
|
425
588
|
// Existing-project mode
|
|
@@ -433,9 +596,9 @@ async function readIfExists(path) {
|
|
|
433
596
|
}
|
|
434
597
|
}
|
|
435
598
|
// ----------------------------------------------------------------------------
|
|
436
|
-
// Publish-ready bundle
|
|
599
|
+
// Publish-ready bundle: the library path scaffolds the opt-in artifact
|
|
437
600
|
// checks into `checkride.config.json` so a buildable library orders itself out
|
|
438
|
-
// of the box (build → pack/smoke/attw/publint/snippets
|
|
601
|
+
// of the box (build → pack/smoke/attw/publint/snippets).
|
|
439
602
|
// ----------------------------------------------------------------------------
|
|
440
603
|
/**
|
|
441
604
|
* The publish-ready bundle, in wave order. Each slot's value is the adapter
|
|
@@ -446,7 +609,7 @@ async function readIfExists(path) {
|
|
|
446
609
|
const PUBLISH_BUNDLE_SLOTS = ['build', 'publint', 'attw', 'pack', 'smoke', 'snippets'];
|
|
447
610
|
/** `--add` values that expand to the whole bundle. */
|
|
448
611
|
const PUBLISH_BUNDLE_ALIASES = new Set(['publish', 'bundle']);
|
|
449
|
-
/** Printed (and recorded in `skipped`) when snippets is requested but no tagged fence exists
|
|
612
|
+
/** Printed (and recorded in `skipped`) when snippets is requested but no tagged fence exists. */
|
|
450
613
|
const SNIPPETS_POINTER = 'snippets-dist: no tagged fences found — add a `<!-- snippet: check -->` marker above a ' +
|
|
451
614
|
'ts/typescript fence in README.md or docs/*.md to enable the doc-snippet typecheck';
|
|
452
615
|
/**
|
|
@@ -465,9 +628,9 @@ function readInitManifest(cwd) {
|
|
|
465
628
|
}
|
|
466
629
|
/**
|
|
467
630
|
* True when README.md or a non-recursive docs/*.md carries at least one tagged
|
|
468
|
-
* snippet fence — the signal that gates scaffolding `snippets-dist
|
|
469
|
-
* Reuses
|
|
470
|
-
* the slot itself checks.
|
|
631
|
+
* snippet fence — the signal that gates scaffolding `snippets-dist`.
|
|
632
|
+
* Reuses the snippets module's pure discovery/plan primitives so the detection
|
|
633
|
+
* matches what the slot itself checks.
|
|
471
634
|
*/
|
|
472
635
|
async function hasTaggedSnippets(cwd) {
|
|
473
636
|
let docsEntries = [];
|
|
@@ -488,7 +651,7 @@ async function hasTaggedSnippets(cwd) {
|
|
|
488
651
|
}
|
|
489
652
|
/**
|
|
490
653
|
* Fold the requested publish slots into config entries, gating `build` on a
|
|
491
|
-
* build script and `snippets` (→ `snippets-dist`) on a tagged fence
|
|
654
|
+
* build script and `snippets` (→ `snippets-dist`) on a tagged fence — the
|
|
492
655
|
* two slots that would otherwise stand down as a skip (`build`) or hard-error on
|
|
493
656
|
* zero snippets (`snippets`).
|
|
494
657
|
*/
|
|
@@ -540,16 +703,67 @@ function splitAdd(add, manifest) {
|
|
|
540
703
|
}
|
|
541
704
|
return { publishRequested, fileAdds };
|
|
542
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* The stanza's active-check list: the selection a default `checkride` run
|
|
708
|
+
* makes, resolved config-aware from disk. `inventory()` is the wrong input
|
|
709
|
+
* here — it has detection semantics and never reads checkride.config.json, so
|
|
710
|
+
* it under-reports the gate (opt-in slots the config opts in, custom checks)
|
|
711
|
+
* to the exact audience the stanza exists to inform. Mirrors `doctor`'s
|
|
712
|
+
* `defaultActive` derivation.
|
|
713
|
+
*/
|
|
714
|
+
function activeCheckSlots(cwd, slots, adapters) {
|
|
715
|
+
const resolved = resolveChecks({ slots, adapters, config: loadConfig(cwd), cwd });
|
|
716
|
+
return selectChecks(resolved, {})
|
|
717
|
+
.filter((r) => r.adapter !== null)
|
|
718
|
+
.map((r) => r.slot);
|
|
719
|
+
}
|
|
720
|
+
const STANZA_REFUSALS = {
|
|
721
|
+
edited: 'it has been edited since checkride wrote it',
|
|
722
|
+
unstamped: 'it predates the stanza stamp and matches no wording checkride has released, so it has been changed since it was written',
|
|
723
|
+
};
|
|
724
|
+
/**
|
|
725
|
+
* Refuse to refresh a stanza that is not checkride's own output, so a repo's
|
|
726
|
+
* edge-case additions survive the next `init`/`agent-setup` instead of being
|
|
727
|
+
* silently overwritten. `opts.force` overrides.
|
|
728
|
+
*
|
|
729
|
+
* Called before either entry point writes anything, so a refusal leaves the repo
|
|
730
|
+
* exactly as it found it (the same rule `assertNoCollisions` follows in new
|
|
731
|
+
* mode). In existing mode that puts it ahead of the config write, so `body` here
|
|
732
|
+
* reflects the config as it is on disk now rather than as this run will leave
|
|
733
|
+
* it — which no longer costs anything: a stamped stanza is checked against its
|
|
734
|
+
* own stamp, and an unstamped one against a registry of released wordings that
|
|
735
|
+
* ignores the active-checks line entirely. Neither reads `body`'s slot list.
|
|
736
|
+
*
|
|
737
|
+
* Hook management deliberately does not come through here — see the `hooks`
|
|
738
|
+
* command, which never touches AGENTS.md and so has nothing to refuse.
|
|
739
|
+
*/
|
|
740
|
+
async function assertStanzaUnedited(cwd, body, opts) {
|
|
741
|
+
if (opts.force === true)
|
|
742
|
+
return;
|
|
743
|
+
const existing = await readIfExists(join(cwd, 'AGENTS.md'));
|
|
744
|
+
if (existing === null)
|
|
745
|
+
return;
|
|
746
|
+
const state = inspectStanza(existing, body);
|
|
747
|
+
if (state === 'absent' || state === 'pristine')
|
|
748
|
+
return;
|
|
749
|
+
const remedy = state === 'edited'
|
|
750
|
+
? 'Move your additions outside the markers — checkride never rewrites what is outside them — or re-run with --force to discard them and refresh.'
|
|
751
|
+
: 'If you have not edited it, re-run with --force: the refreshed stanza carries a stamp, and later runs tell an edit from a refresh on their own.';
|
|
752
|
+
throw new Error(`refusing to overwrite the checkride stanza in AGENTS.md: ${STANZA_REFUSALS[state]}.\n ${remedy}`);
|
|
753
|
+
}
|
|
543
754
|
/**
|
|
544
755
|
* Write (or refresh) the AGENTS.md stanza for `slots`, idempotently: it writes
|
|
545
756
|
* only when the applied stanza differs from the current file, records the outcome
|
|
546
757
|
* on `w`/`skipped`, and honours dry-run. Shared by `initExisting` and
|
|
547
758
|
* `runAgentSetup` (both create-or-refresh the same stanza).
|
|
759
|
+
*
|
|
760
|
+
* It rewrites the marked region unconditionally; whether that is allowed is
|
|
761
|
+
* {@link assertStanzaUnedited}'s call, made before either caller writes anything.
|
|
548
762
|
*/
|
|
549
|
-
async function writeAgentsStanza(w, cwd, slots, skipped) {
|
|
763
|
+
async function writeAgentsStanza(w, cwd, slots, pm, skipped) {
|
|
550
764
|
const agentsPath = join(cwd, 'AGENTS.md');
|
|
551
765
|
const existing = await readIfExists(agentsPath);
|
|
552
|
-
const nextAgents = applyStanza(existing ?? '', buildStanza(slots));
|
|
766
|
+
const nextAgents = applyStanza(existing ?? '', buildStanza(slots, pm));
|
|
553
767
|
if (nextAgents !== existing) {
|
|
554
768
|
if (!w.dryRun)
|
|
555
769
|
await writeFile(agentsPath, nextAgents);
|
|
@@ -566,12 +780,19 @@ const ADD_CONFIGS = {
|
|
|
566
780
|
types: [['shared/tsconfig.base.json', 'tsconfig.base.json'], ['flat/tsconfig.json', 'tsconfig.json']],
|
|
567
781
|
format: [['shared/prettierrc.json', '.prettierrc.json']],
|
|
568
782
|
lint: [['shared/oxlintrc.json', '.oxlintrc.json']],
|
|
783
|
+
// `struct` scaffolds the boundary rule and stops. New-mode `init` writes all
|
|
784
|
+
// four (`writeSharedStatic`), and that is a different bargain: there checkride
|
|
785
|
+
// is creating the package, so its house style has nobody to override. Here the
|
|
786
|
+
// repo already exists and has already decided. `no-class`, `no-default-export`
|
|
787
|
+
// and `require-js-extension` are style and module-system opinions — a repo
|
|
788
|
+
// with classes, default exports, or bundler resolution goes red on adoption
|
|
789
|
+
// for writing the code it always wrote, which reads as checkride being broken.
|
|
790
|
+
// `no-deep-sibling-import` is the one that makes `struct` the slot it is, and
|
|
791
|
+
// failing it means what it says. The other three stay one copy away, in
|
|
792
|
+
// `docs/deep-modules.md`.
|
|
569
793
|
struct: [
|
|
570
794
|
['shared/sgconfig.yml', 'sgconfig.yml'],
|
|
571
|
-
['shared/rules/no-class.yml', 'rules/no-class.yml'],
|
|
572
|
-
['shared/rules/no-default-export.yml', 'rules/no-default-export.yml'],
|
|
573
795
|
['shared/rules/no-deep-sibling-import.yml', 'rules/no-deep-sibling-import.yml'],
|
|
574
|
-
['shared/rules/require-js-extension.yml', 'rules/require-js-extension.yml'],
|
|
575
796
|
],
|
|
576
797
|
dead: [['flat/fallow.toml', 'fallow.toml']],
|
|
577
798
|
// dupes/health are the same fallow tool + config as `dead`, just other slots.
|
|
@@ -625,7 +846,7 @@ async function addCheckAlias(w, skipped) {
|
|
|
625
846
|
w.written.push('package.json (added check script)');
|
|
626
847
|
}
|
|
627
848
|
/**
|
|
628
|
-
* Classify each failing adopted slot. `--baseline`
|
|
849
|
+
* Classify each failing adopted slot. `--baseline` grandfathers a
|
|
629
850
|
* failing *fingerprintable* slot (kept enabled; the baseline masks its debt and
|
|
630
851
|
* the ratchet carries the cleanup); a failing slot with no extractor can't be
|
|
631
852
|
* grandfathered, so it still falls back to a `false` disable. Without
|
|
@@ -652,7 +873,7 @@ async function captureBaselineIfNeeded(options, cwd, grandfathered, dryRun) {
|
|
|
652
873
|
}
|
|
653
874
|
/**
|
|
654
875
|
* Write checkride.config.json for the adopted tools (disabled failures as
|
|
655
|
-
* `false`) plus the publish-ready bundle
|
|
876
|
+
* `false`) plus the publish-ready bundle; never clobber an existing one.
|
|
656
877
|
*/
|
|
657
878
|
async function writeExistingConfig(w, cwd, adopted, disabledSet, bundleChecks, skipped) {
|
|
658
879
|
if (existsSync(join(cwd, 'checkride.config.json'))) {
|
|
@@ -667,7 +888,7 @@ async function writeExistingConfig(w, cwd, adopted, disabledSet, bundleChecks, s
|
|
|
667
888
|
checks[i.slot] = i.adapter;
|
|
668
889
|
}
|
|
669
890
|
// The opt-in publish bundle follows the adopted default slots; explicit
|
|
670
|
-
// entries opt these slots into the run (
|
|
891
|
+
// entries opt these slots into the run (the library orders itself).
|
|
671
892
|
for (const [slot, adapter] of Object.entries(bundleChecks))
|
|
672
893
|
checks[slot] = adapter;
|
|
673
894
|
const config = { $schema: configSchemaUrl(productVersion()), checks };
|
|
@@ -708,7 +929,7 @@ function reportExisting(stdout, adopted, w, grandfathered, disabled) {
|
|
|
708
929
|
}
|
|
709
930
|
}
|
|
710
931
|
/**
|
|
711
|
-
* Plan the publish-ready bundle
|
|
932
|
+
* Plan the publish-ready bundle for existing-repo init. Only meaningful
|
|
712
933
|
* when a config will actually be written: `writeExistingConfig` never clobbers an
|
|
713
934
|
* existing `checkride.config.json`, so an existing config means the bundle has
|
|
714
935
|
* nowhere to land. The bundle is scaffolded *enabled* — not probed/disabled like
|
|
@@ -733,8 +954,12 @@ async function initExisting(options, cwd) {
|
|
|
733
954
|
const adapters = options.adapters ?? ADAPTERS;
|
|
734
955
|
const slots = options.slots ?? SLOTS;
|
|
735
956
|
const manifest = readInitManifest(cwd);
|
|
736
|
-
const w = { cwd, dryRun: options.dryRun ?? false, written: [] };
|
|
957
|
+
const w = { cwd, dryRun: options.dryRun ?? false, written: [], removed: [] };
|
|
737
958
|
const skipped = [];
|
|
959
|
+
const pm = detectPackageManager({ cwd });
|
|
960
|
+
// Before the first write: a stanza this repo has customized stops the run
|
|
961
|
+
// rather than being clobbered by the refresh below.
|
|
962
|
+
await assertStanzaUnedited(cwd, buildStanza(activeCheckSlots(cwd, slots, adapters), pm), options);
|
|
738
963
|
// Route --add: publish slots (and the library path) opt into the bundle; the
|
|
739
964
|
// rest scaffold blessed configs before inventory, so they're detected this run.
|
|
740
965
|
const { publishRequested, fileAdds } = splitAdd(options.add ?? [], manifest);
|
|
@@ -746,24 +971,35 @@ async function initExisting(options, cwd) {
|
|
|
746
971
|
const failing = new Set(await probe(adopted.map((i) => i.slot), cwd));
|
|
747
972
|
const { grandfathered, disabled } = resolveAdoptionPlan(adopted, failing, options.baseline ?? false);
|
|
748
973
|
await captureBaselineIfNeeded(options, cwd, grandfathered, w.dryRun);
|
|
749
|
-
// Publish-ready bundle
|
|
974
|
+
// Publish-ready bundle: planned only when a config will be written.
|
|
750
975
|
const bundle = await planInitBundle(publishRequested, manifest, cwd);
|
|
751
976
|
if (bundle.snippetsPointer)
|
|
752
977
|
skipped.push(bundle.snippetsPointer);
|
|
753
978
|
await writeExistingConfig(w, cwd, adopted, new Set(disabled), bundle.checks, skipped);
|
|
754
979
|
await ensureGitignore(w, cwd, skipped);
|
|
755
|
-
// package.json: add the `check: checkride` alias
|
|
980
|
+
// package.json: add the `check: checkride` alias if missing.
|
|
756
981
|
await addCheckAlias(w, skipped);
|
|
757
|
-
// AGENTS.md stanza (create or refresh, idempotent)
|
|
758
|
-
|
|
982
|
+
// AGENTS.md stanza (create or refresh, idempotent), derived from the config
|
|
983
|
+
// written above so it reports the gate as configured, not as detected.
|
|
984
|
+
await writeAgentsStanza(w, cwd, activeCheckSlots(cwd, slots, adapters), pm, skipped);
|
|
759
985
|
await writeClaudePointer(w, cwd, skipped);
|
|
760
|
-
// Claude Code Stop hook (opt-out
|
|
761
|
-
await writeHook(w, options
|
|
986
|
+
// Claude Code Stop hook (opt-out), using the repo's detected PM.
|
|
987
|
+
await writeHook(w, options, skipped);
|
|
988
|
+
await writeSkills(w, options, skipped);
|
|
762
989
|
if (options.stdout) {
|
|
763
990
|
reportExisting(options.stdout, adopted, w, grandfathered, disabled);
|
|
764
991
|
reportInitBundle(options.stdout, bundle);
|
|
765
992
|
}
|
|
766
|
-
return {
|
|
993
|
+
return {
|
|
994
|
+
mode: 'existing',
|
|
995
|
+
shape: null,
|
|
996
|
+
written: w.written,
|
|
997
|
+
removed: w.removed,
|
|
998
|
+
skipped,
|
|
999
|
+
disabled,
|
|
1000
|
+
grandfathered,
|
|
1001
|
+
exitCode: 0,
|
|
1002
|
+
};
|
|
767
1003
|
}
|
|
768
1004
|
// ----------------------------------------------------------------------------
|
|
769
1005
|
// Entry
|
|
@@ -780,25 +1016,32 @@ export async function runInit(options) {
|
|
|
780
1016
|
/**
|
|
781
1017
|
* `checkride agent-setup` — wire the agent contract into an *existing* repo
|
|
782
1018
|
* without a full `init`: the `check` alias the hook resolves to, the AGENTS.md
|
|
783
|
-
* stanza (the human-readable contract),
|
|
784
|
-
* mechanical gate)
|
|
785
|
-
*
|
|
1019
|
+
* stanza (the human-readable contract), the stop-gate hooks for every detected
|
|
1020
|
+
* harness (the mechanical gate), and the skills a harness cannot get from the
|
|
1021
|
+
* bundled plugin. Every write is additive and idempotent — a second run is a
|
|
1022
|
+
* no-op — and the hooks are opt-out (`hook: false`).
|
|
786
1023
|
*/
|
|
787
1024
|
export async function runAgentSetup(options) {
|
|
788
1025
|
const cwd = options.cwd ?? process.cwd();
|
|
789
1026
|
const slots = options.slots ?? SLOTS;
|
|
790
1027
|
const adapters = options.adapters ?? ADAPTERS;
|
|
791
|
-
const w = { cwd, dryRun: options.dryRun ?? false, written: [] };
|
|
1028
|
+
const w = { cwd, dryRun: options.dryRun ?? false, written: [], removed: [] };
|
|
792
1029
|
const skipped = [];
|
|
1030
|
+
const stanzaSlots = activeCheckSlots(cwd, slots, adapters);
|
|
1031
|
+
const pm = detectPackageManager({ cwd });
|
|
1032
|
+
// Before the first write: a stanza this repo has customized stops the run
|
|
1033
|
+
// rather than being clobbered by the refresh below.
|
|
1034
|
+
await assertStanzaUnedited(cwd, buildStanza(stanzaSlots, pm), options);
|
|
793
1035
|
// The `check` alias the hook's `<pm> run check` resolves to (never clobbers).
|
|
794
1036
|
await addCheckAlias(w, skipped);
|
|
795
|
-
// AGENTS.md stanza for the
|
|
796
|
-
|
|
797
|
-
await
|
|
798
|
-
await
|
|
1037
|
+
// AGENTS.md stanza for the checks the default run selects (create or refresh).
|
|
1038
|
+
await writeAgentsStanza(w, cwd, stanzaSlots, pm, skipped);
|
|
1039
|
+
await writeHook(w, options, skipped);
|
|
1040
|
+
await writeSkills(w, options, skipped);
|
|
799
1041
|
if (options.stdout) {
|
|
800
|
-
|
|
1042
|
+
const removed = w.removed.length > 0 ? `, removed ${w.removed.length}` : '';
|
|
1043
|
+
options.stdout.write(`checkride agent-setup: wrote ${w.written.length} file(s)${removed}${w.dryRun ? ' [dry run]' : ''}.\n`);
|
|
801
1044
|
}
|
|
802
|
-
return { written: w.written, skipped, exitCode: 0 };
|
|
1045
|
+
return { written: w.written, removed: w.removed, skipped, exitCode: 0 };
|
|
803
1046
|
}
|
|
804
1047
|
//# sourceMappingURL=init.js.map
|