From d6f2007723df166109804a8038ede440546ec2e1 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:36:03 +0000 Subject: [PATCH] build: shorten local validation loops --- .husky/pre-push | 2 +- AGENTS.md | 4 +++- CONTRIBUTING.md | 11 ++++++----- package.json | 16 ++++++++++------ scripts/scan-todos.mjs | 4 ++-- tests/identity.test.ts | 8 ++++---- tests/scanTodos.test.ts | 33 +++++++++++++++++++++++++++++++++ turbo.json | 33 ++++++++++++++++++++++++++++++--- 8 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 tests/scanTodos.test.ts diff --git a/.husky/pre-push b/.husky/pre-push index 0ad376d97..e2a8fa839 100644 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1 +1 @@ -npm run check +npm run check:fast diff --git a/AGENTS.md b/AGENTS.md index 6a143b947..6e27eee99 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -63,6 +63,7 @@ See [docs/architecture.mermaid](docs/architecture.mermaid) for a visual architec - `npm run lint:fix`: auto-fix oxlint violations where possible. - `npm run format:check`: verify Prettier formatting. - `npm run check`: run cached typecheck, lint, format:check, knip, and package-metadata freshness tasks. +- `npm run check:fast`: run only cached typecheck and lint for rapid local and pre-push feedback. - `npm run check:ci`: run the static gate plus duplicate-code and debt-marker scans. - `npm run check:test`: run the cached static tasks plus the uncached complete test suite. - `npm run check:pr`: run the test gate plus uncached generated-document validation for PR preparation. @@ -79,12 +80,13 @@ See [docs/architecture.mermaid](docs/architecture.mermaid) for a visual architec - `npm run verify:replay`: build and run the real Linux Bubblewrap/seccomp/cgroup verifier against source-owned replay fixtures; set `REA_REPLAY_INPUT_PATH` to verify an operator-local manifest. - `npm run verify:package`: pack and test the CLI, setup transaction, skill, and canonical target-free MCP catalog in an isolated environment. - `npm run docs:api`: render uncommitted API documentation from JSDoc comments into `build/api-docs/` using TypeDoc. +- `npm run docs:api:cached`: render API documentation through Turbo or restore a valid local result. - `npm run docs:generate`: refresh committed metadata and render the uncommitted API documentation. - `npm run docs:check`: verify generated package metadata, the canonical product catalog, caller-visible documentation facts, TypeDoc rendering, and the error JSON schema. - `npm run config:print -- /path/to/binary`: print an MCP server config with absolute paths. - `HOPPER_TARGET_PATH=/path/to/binary npm start`: launch Hopper and run the built stdio MCP server. -Pre-commit hooks via Husky format and lint staged files. Pre-push runs `npm run check`. Use `npm run lint:fix` to auto-correct violations locally. +Pre-commit hooks via Husky format then lint staged source files. Pre-push runs `npm run check:fast`; CI owns the broader static and generated-document gates. Use `npm run lint:fix` to auto-correct violations locally. ## Configuration & Environment Variables diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e92be536..40bc35c6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,11 +28,12 @@ npm run verify:package npm pack --dry-run ``` -`npm run check` runs cached typecheck, lint, formatting, dead-code, and package -metadata freshness tasks; `check:fast` remains as an alias. Use `npm run -check:test` when the complete test suite is relevant. Pre-commit formats and -lints only staged files, and pre-push runs `check`. `check:pr` additionally -renders API documentation and checks all committed generated metadata. Real +`npm run check:fast` runs cached typecheck and lint for rapid local feedback. +`npm run check` adds formatting, dead-code, and package-metadata freshness +checks; use `npm run check:test` when the complete test suite is relevant. +Pre-commit formats then lints staged source files, and pre-push runs +`check:fast`. `check:pr` additionally renders API documentation and checks all +committed generated metadata. Real provider and replay execution remains uncached, but their deterministic build prerequisite uses Turbo. CI uploads the rendered TypeDoc site as an `api-docs` artifact; the generated HTML is not committed. diff --git a/package.json b/package.json index 5e23ef1c8..aa7fa5f18 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "build": "tsc -p tsconfig.build.json", "precheck": "npm run deps:check", "check": "turbo run typecheck lint format:check knip metadata:check", - "check:fast": "npm run check", + "precheck:fast": "npm run deps:check", + "check:fast": "turbo run typecheck lint", "precheck:test": "npm run deps:check", "check:test": "turbo run typecheck lint format:check knip metadata:check test:run", "precheck:pr": "npm run deps:check", @@ -116,17 +117,20 @@ "evidence:generate": "npm run build:cached && node scripts/generate-completion-ledger.mjs", "evidence:check": "npm run build:cached && node scripts/generate-completion-ledger.mjs --check", "docs:api": "typedoc", - "docs:generate": "npm run metadata:generate && npm run build:cached && node scripts/generate-skill-metadata.mjs && node scripts/generate-product-catalog.mjs && node scripts/generate-completion-ledger.mjs && npm run docs:api && node scripts/generate-error-schema.mjs", + "docs:api:cached": "turbo run docs:api", + "docs:generate": "npm run metadata:generate && npm run build:cached && node scripts/generate-skill-metadata.mjs && node scripts/generate-product-catalog.mjs && node scripts/generate-completion-ledger.mjs && npm run docs:api:cached && node scripts/generate-error-schema.mjs", "docs:check": "turbo run docs:check:built", - "docs:check:built": "node scripts/generate-package-metadata.mjs --check && node scripts/generate-skill-metadata.mjs --check && node scripts/generate-product-catalog.mjs --check && node scripts/generate-completion-ledger.mjs --check && node scripts/check-doc-facts.mjs && npm run docs:api && node scripts/generate-error-schema.mjs --check", + "docs:check:built": "node scripts/generate-package-metadata.mjs --check && node scripts/generate-skill-metadata.mjs --check && node scripts/generate-product-catalog.mjs --check && node scripts/generate-completion-ledger.mjs --check && node scripts/check-doc-facts.mjs && node scripts/generate-error-schema.mjs --check", "docs:error-schema": "npm run build:cached && node scripts/generate-error-schema.mjs", "prepack": "node scripts/prepack.mjs", - "prepublishOnly": "npm run deps:check && node scripts/generate-skill-metadata.mjs --check", "prepare": "node scripts/prepare.mjs" }, "lint-staged": { - "*.{ts,mjs,json,md,yml,yaml}": "prettier --write", - "*.ts": "oxlint --fix" + "*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}": [ + "prettier --write", + "oxlint --fix" + ], + "*.{json,md,yml,yaml}": "prettier --write" }, "dependencies": { "@babel/parser": "8.0.4", diff --git a/scripts/scan-todos.mjs b/scripts/scan-todos.mjs index 44e3dae04..4990f6c92 100644 --- a/scripts/scan-todos.mjs +++ b/scripts/scan-todos.mjs @@ -12,7 +12,7 @@ const sourceFiles = globSync( [ "src/**/*.ts", "tests/**/*.ts", - "scripts/**/*.mjs", + "scripts/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}", "bridge/**/*.py", "bridge/**/*.java", ], @@ -46,7 +46,7 @@ for (const file of sourceFiles) { if (count > 0) { console.log(`\n${count} tech-debt marker(s) found.`); - process.exitCode = 0; + process.exitCode = 1; } else { console.log("No tech-debt markers found."); } diff --git a/tests/identity.test.ts b/tests/identity.test.ts index db3f43b8d..87f3234f5 100644 --- a/tests/identity.test.ts +++ b/tests/identity.test.ts @@ -15,9 +15,10 @@ describe("package identity", () => { start: z.string(), "metadata:check": z.string(), prebuild: z.string(), + "precheck:fast": z.string(), + "check:fast": z.string(), prepare: z.string(), prepack: z.string(), - prepublishOnly: z.string(), }), }) .parse( @@ -49,10 +50,9 @@ describe("package identity", () => { expect(packageJson.scripts.prebuild).toBe( "npm run deps:check && npm run metadata:check", ); + expect(packageJson.scripts["precheck:fast"]).toBe("npm run deps:check"); + expect(packageJson.scripts["check:fast"]).toBe("turbo run typecheck lint"); expect(packageJson.scripts.prepare).toBe("node scripts/prepare.mjs"); expect(packageJson.scripts.prepack).toBe("node scripts/prepack.mjs"); - expect(packageJson.scripts.prepublishOnly).toBe( - "npm run deps:check && node scripts/generate-skill-metadata.mjs --check", - ); }); }); diff --git a/tests/scanTodos.test.ts b/tests/scanTodos.test.ts new file mode 100644 index 000000000..2ab1da7d7 --- /dev/null +++ b/tests/scanTodos.test.ts @@ -0,0 +1,33 @@ +import { execFile } from "node:child_process"; +import { copyFile, mkdir, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { promisify } from "node:util"; + +import { describe, expect, it } from "vitest"; + +import { createTestTempDirectory } from "./fixtures/temporaryDirectory.js"; + +const execute = promisify(execFile); + +describe("tech-debt marker scan", () => { + it("passes a clean tree and rejects a tree containing a marker", async () => { + const root = await createTestTempDirectory("rea-scan-todos-"); + const scripts = join(root, "scripts"); + const source = join(root, "src"); + await Promise.all([mkdir(scripts), mkdir(source)]); + const scanner = join(scripts, "scan-todos.mjs"); + await copyFile(join(process.cwd(), "scripts/scan-todos.mjs"), scanner); + await writeFile(join(source, "clean.ts"), "export const clean = true;\n"); + + await expect(execute(process.execPath, [scanner])).resolves.toMatchObject({ + stdout: "No tech-debt markers found.\n", + }); + + const marker = `TO${"DO"}`; + await writeFile(join(scripts, "debt.mts"), `// ${marker}: close the gap\n`); + await expect(execute(process.execPath, [scanner])).rejects.toMatchObject({ + code: 1, + stdout: expect.stringContaining(`${marker} - close the gap`), + }); + }); +}); diff --git a/turbo.json b/turbo.json index edd4091f1..1556c8413 100644 --- a/turbo.json +++ b/turbo.json @@ -41,14 +41,41 @@ "lint": {}, "format:check": {}, "knip": {}, - "jscpd": {}, - "scan:todos": {}, + "jscpd": { + "inputs": [ + ".gitignore", + ".jscpd.json", + "package.json", + "package-lock.json", + "src/**", + "tests/**" + ] + }, + "scan:todos": { + "inputs": [ + "bridge/**/*.{java,py}", + "scripts/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}", + "src/**/*.ts", + "tests/**/*.ts" + ] + }, + "docs:api": { + "inputs": [ + "package.json", + "package-lock.json", + "src/**/*.ts", + "tsconfig.json", + "typedoc.json" + ], + "outputs": ["build/api-docs/**"], + "outputLogs": "new-only" + }, "test:run": { "dependsOn": ["build"], "cache": false }, "docs:check:built": { - "dependsOn": ["build"], + "dependsOn": ["build", "docs:api"], "cache": false } }