diff --git a/README.md b/README.md index 5cbe7d8..b82a7f4 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ Code hygiene for [omp](https://github.com/oh-my-pi) — isolated sub-agent checks that scan a target, apply fixes, and emit a findings + changes -report. Port of the pi extension (was `~/.pi/agent/extensions/pygienium/`); -inspired by piolium's sub-agent loops. +report. Inspired by piolium's sub-agent loops. Pygienium runs **highly-structured hygiene passes** over a repo to clean up the common quality issues LLM-generated code accumulates: restating comments, @@ -70,9 +69,9 @@ resumable — progress is persisted to `/.pygienium/run-state.json`. ## Checks -The five shipped checks live in [`src/checks/`](./src/checks/) and are -auto-discovered on load. `/pygienium-help` lists whichever checks are currently -registered, so this table and the live help always agree on the registered set. +The five shipped checks live in [`src/checks/`](./src/checks/) and self-register +on load. `/pygienium-help` lists whichever checks are currently registered, so +this table and the live help always agree on the registered set. | Command | Check | Agent | What it fixes | | --- | --- | --- | --- | @@ -99,27 +98,20 @@ git (opt out with `--no-gitignore`). ## Adding a check -One file exporting a `check` definition. **No `index.ts` command-wiring changes.** +One file + one `registerCheck()` call. **No `index.ts` command-wiring changes.** `index.ts` auto-discovers every `checks/*.ts` (except the registry barrel) at -startup, registers each file's `check` export, and `/pygienium-` appears +startup, so a new file self-registers and `/pygienium-` appears automatically. -Check files are **pure data modules** — they export a definition and never -import the registry at runtime. Registration happens in `index.ts` from the -entry's own registry instance, which keeps a single registry even under omp's -extension loader (it cache-busts lazily imported graph modules with an -`?mtime` suffix, which would otherwise split the registry into two module -instances). - 1. Create `src/checks/.ts` from the template below. 2. Edit the `name`, `label`, `description`, the rubric in the scan/fix task builders, and the `gate` precondition. -3. Export it as `check`. Done. +3. Keep the trailing `registerCheck(Check)`. Done. ```ts -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { registerCheck, type CheckScope } from "./registry.js"; -export const check = { +export const myCheck = { name: "my-check", label: "My check", description: "What it fixes (shown in /pygienium-help).", @@ -129,7 +121,9 @@ export const check = { buildScanTask: (_cwd: string, scope: CheckScope) => `# Task: my-check scan\n…`, buildFixTask: (_cwd: string, scope: CheckScope, findings: string) => `# Task: my-check fix\n…`, gate: (cwd: string) => undefined, -} as const satisfies CheckDefinition; +} as const; + +registerCheck(myCheck); ``` Reload omp (or `/reload`) and run `/pygienium-help` — `/pygienium-my-check` is @@ -142,7 +136,7 @@ touches command plumbing. Each check is a "mode" running a fixed phase pipeline: ``` -registerCheck(def) ← index.ts discovers checks/*.ts `check` exports +registerCheck(def) ← checks/*.ts self-register on load │ ▼ /pygienium- ─► runCheck(def) (src/modes/check-runner.ts) @@ -171,10 +165,9 @@ registerCheck(def) ← index.ts discovers checks/*.ts `check` exports `/pygienium-export` are pure reads over it; `/pygienium-all` shares one `RunState` across every check so phases accumulate in one record. - **The registry** (`src/checks/registry.ts`) is the extensibility seam: a - module-level `Map` of `CheckDefinition`s. `index.ts` discovers every - `checks/*.ts` file, registers its `check` export, then iterates the map and - binds one `/pygienium-` command per entry — adding a check is a file - with a `check` export, nothing else. + module-level `Map` of `CheckDefinition`s. `index.ts` iterates it and binds + one `/pygienium-` command per entry, so adding a check is a file + + one `registerCheck()` line. - **The footer** (`src/footer.ts`) is the piolium-style pipeline-overview status strip: a single static line in the TUI footer (via `ui.setStatus(key, text)`) listing the full ordered pipeline with the cursor @@ -202,7 +195,7 @@ pygienium/ │ ├─ phases.ts ← live chat progress widget + completion-tree helpers │ ├─ footer.ts ← pipeline-overview status strip (TUI footer) │ ├─ modes/check-runner.ts ← the per-check phase pipeline -│ └─ checks/ ← one file per check, exporting `check` +│ └─ checks/ ← one file per check, self-registering │ ├─ registry.ts ← CheckDefinition + registerCheck │ ├─ comments.ts deep-modules.ts dead-code.ts │ ├─ defensive-guards.ts diff --git a/package.json b/package.json index 60aab3d..ef72ef4 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@mikefreno/omp-pygenium", + "name": "@mikefreno/omp-pygienium", "version": "0.1.0", "description": "Code hygiene extension for omp (port of the pi extension) — isolated sub-agent checks that scan a target, apply fixes, and emit a findings+changes report.", "keywords": [ @@ -30,4 +30,4 @@ "typecheck": "tsc --noEmit", "test": "bun test" } -} \ No newline at end of file +} diff --git a/src/checks/all.ts b/src/checks/all.ts new file mode 100644 index 0000000..95e6301 --- /dev/null +++ b/src/checks/all.ts @@ -0,0 +1,15 @@ +/** + * Static barrel for shipped checks. + * + * Every check module self-registers on import (top-level `registerCheck`), so + * importing all of them here — once, statically, from the entry graph — + * registers every check before commands bind. Adding a check means dropping + * the file in and adding one import line here. + */ +import "./comments.js"; +import "./complexity.js"; +import "./dead-code.js"; +import "./deep-modules.js"; +import "./defensive-guards.js"; +import "./scope.js"; +import "./todos.js"; diff --git a/src/checks/comments.ts b/src/checks/comments.ts index d776f2f..9a735f1 100644 --- a/src/checks/comments.ts +++ b/src/checks/comments.ts @@ -20,7 +20,7 @@ * @module pygienium/checks/comments */ -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { registerCheck, type CheckScope } from "./registry.js"; import { scopeRulesMarkdown } from "./scope.js"; /** Phase-strip phase this check belongs to. */ @@ -215,7 +215,7 @@ async function commentsVerify(scope: CheckScope): Promise { } /** The comments hygiene check definition. */ -export const check = { +export const commentsCheck = { name: "comments", label: "Comments", description: @@ -227,7 +227,7 @@ export const check = { buildFixTask: buildCommentsFixTask, gate: commentsGate, verify: commentsVerify, -} as const satisfies CheckDefinition; +} as const; -// No self-registration here: `index.ts` auto-discovers every `checks/*.ts` -// that exports `check` and registers it — a new check is still one file. +// Self-register on import so index.ts auto-discovery picks it up. +registerCheck(commentsCheck); diff --git a/src/checks/complexity.ts b/src/checks/complexity.ts index 09d8b5f..204bff3 100644 --- a/src/checks/complexity.ts +++ b/src/checks/complexity.ts @@ -21,7 +21,7 @@ * @module pygienium/checks/complexity */ -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { registerCheck, type CheckScope } from "./registry.js"; import { scopeRulesMarkdown } from "./scope.js"; /** Phase-strip phase this check belongs to. */ @@ -299,7 +299,7 @@ async function complexityVerify( } /** The excessive complexity check definition. */ -export const check = { +export const complexityCheck = { name: "complexity", label: "Complexity", description: @@ -311,7 +311,7 @@ export const check = { buildFixTask: buildComplexityFixTask, gate: complexityGate, verify: complexityVerify, -} as const satisfies CheckDefinition; +} as const; -// No self-registration here: `index.ts` auto-discovers every `checks/*.ts` -// that exports `check` and registers it — a new check is still one file. +// Self-register on import so index.ts auto-discovery picks it up. +registerCheck(complexityCheck); diff --git a/src/checks/dead-code.ts b/src/checks/dead-code.ts index 57c9c82..546a7ec 100644 --- a/src/checks/dead-code.ts +++ b/src/checks/dead-code.ts @@ -29,7 +29,11 @@ import { rm, } from "node:fs/promises"; import { basename, dirname, join, relative, resolve } from "node:path"; -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { + registerCheck, + type CheckDefinition, + type CheckScope, +} from "./registry.js"; import { isScopeSource, SCOPE_EXCLUDE_DIRS, @@ -1126,7 +1130,7 @@ async function deadCodeVerify(scope: CheckScope): Promise { } /** The registered `CheckDefinition` (module self-registers on import). */ -export const check: CheckDefinition = { +export const deadCodeCheck: CheckDefinition = { name: "dead-code", label: "Dead code", description: @@ -1140,5 +1144,5 @@ export const check: CheckDefinition = { verify: deadCodeVerify, }; -// No self-registration here: `index.ts` auto-discovers every `checks/*.ts` -// that exports `check` and registers it. +// Self-register so `index.ts` auto-discovers this check with zero wiring edits. +registerCheck(deadCodeCheck); diff --git a/src/checks/deep-modules.ts b/src/checks/deep-modules.ts index e8e3b10..72038c4 100644 --- a/src/checks/deep-modules.ts +++ b/src/checks/deep-modules.ts @@ -23,7 +23,11 @@ import { readdirSync } from "node:fs"; import { join } from "node:path"; -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { + registerCheck, + type CheckDefinition, + type CheckScope, +} from "./registry.js"; import { isScopeSource, scopeRulesMarkdown } from "./scope.js"; /** Output directory for this check's persistent reports. */ @@ -168,7 +172,7 @@ function buildDeepFixTask( } /** The check definition; registers itself on import. */ -export const check: CheckDefinition = { +const deepModulesCheck: CheckDefinition = { name: "deep-modules", label: "Deep modules", description: @@ -181,5 +185,6 @@ export const check: CheckDefinition = { verify: deepModulesVerify, }; -// No self-registration here: `index.ts` auto-discovers every `checks/*.ts` -// that exports `check` and registers it. +registerCheck(deepModulesCheck); + +export { deepModulesCheck }; diff --git a/src/checks/defensive-guards.ts b/src/checks/defensive-guards.ts index 9ea0bf5..66c7631 100644 --- a/src/checks/defensive-guards.ts +++ b/src/checks/defensive-guards.ts @@ -43,7 +43,11 @@ import { readdirSync } from "node:fs"; import { join } from "node:path"; -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { + registerCheck, + type CheckDefinition, + type CheckScope, +} from "./registry.js"; import { isScopeSource, scopeRulesMarkdown } from "./scope.js"; /** Output directory for this check's persistent reports. */ @@ -198,7 +202,7 @@ function buildDefensiveGuardsFixTask( } /** The check definition; registers itself on import. */ -export const check: CheckDefinition = { +const defensiveGuardsCheck: CheckDefinition = { name: "defensive-guards", label: "Defensive guards", description: @@ -211,5 +215,6 @@ export const check: CheckDefinition = { verify: defensiveGuardsVerify, }; -// No self-registration here: `index.ts` auto-discovers every `checks/*.ts` -// that exports `check` and registers it. +registerCheck(defensiveGuardsCheck); + +export { defensiveGuardsCheck }; diff --git a/src/checks/scope.ts b/src/checks/scope.ts index c89d8c8..e81d9d8 100644 --- a/src/checks/scope.ts +++ b/src/checks/scope.ts @@ -39,7 +39,7 @@ export const SCOPE_EXTENSIONS: ReadonlySet = new Set([ /** * Directories pygienium never descends into — build output, dependency caches, - * tooling state, and VCS metadata. When walking the tree with `glob`/`grep`/ + * tooling state, and VCS metadata. When walking the tree with `find`/`grep`/ * `readdir`, skip these by name to avoid wasting tokens on vendored code and * generated artifacts the user can't act on. */ @@ -104,7 +104,7 @@ export function isScopeSource(path: string): boolean { * exactly what to inspect and what to skip — stated once here, not copy-pasted * into each task builder. * - * Agents that use `glob`/`grep`/`readdir` for their own file discovery read + * Agents that use `find`/`grep`/`readdir` for their own file discovery read * this before exploring, so the exclusion list governs their search too. */ export function scopeRulesMarkdown(): string { @@ -139,7 +139,7 @@ noise the user cannot act on. exists — it is the authoritative source inventory (git-tracked, extension- filtered, exclude-aware). Read its \`fileCounts\` for the quick picture. 2. Otherwise enumerate files yourself, applying the rules above. -3. When using \`glob\`/\`grep\`, add ignore patterns for the skip directories - (e.g. exclude \`**/node_modules/**\` from your scans). +3. When using \`find\`/\`grep\`, add prune clauses for the skip directories + (e.g. \`find . -type d -name node_modules -prune -o -name '*.ts' -print\`). `; } diff --git a/src/checks/todos.ts b/src/checks/todos.ts index 7ffae08..6cbe949 100644 --- a/src/checks/todos.ts +++ b/src/checks/todos.ts @@ -40,7 +40,11 @@ import { readdirSync } from "node:fs"; import { readFile, readdir, stat } from "node:fs/promises"; import { join, relative } from "node:path"; import { loadRunState } from "../run-state.js"; -import type { CheckDefinition, CheckScope } from "./registry.js"; +import { + registerCheck, + type CheckDefinition, + type CheckScope, +} from "./registry.js"; import { isScopeSource, SCOPE_EXCLUDE_DIRS, @@ -541,7 +545,7 @@ async function todosVerify(scope: CheckScope): Promise { } /** The todos check definition; registers itself on import. */ -export const check: CheckDefinition = { +const todosCheck: CheckDefinition = { name: "todos", label: "TODOs & stubs", description: @@ -554,5 +558,6 @@ export const check: CheckDefinition = { verify: todosVerify, }; -// No self-registration here: `index.ts` auto-discovers every `checks/*.ts` -// that exports `check` and registers it. +registerCheck(todosCheck); + +export { todosCheck }; diff --git a/src/index.ts b/src/index.ts index 94edccd..6b56719 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,11 +3,15 @@ * * Entry point. Registers `/pygienium-help`, auto-registers one * `/pygienium-` command per registered `CheckDefinition`, plus the - * `all`/`resume`/`status`/`export` commands. Adding a check requires ONLY a new - * file in `src/checks/` plus one `registerCheck(def)` call — no changes here. + * `all`/`resume`/`status`/`export` commands. Adding a check requires a new + * file in `src/checks/` plus one import line in `src/checks/all.ts` — no + * changes here. * - * Check files in `src/checks/` are auto-discovered (every `.ts` except the - * registry barrel), so they self-register at load time before commands bind. + * Check modules self-register on import (top-level `registerCheck`); the + * static barrel `src/checks/all.ts` imports every shipped check so they all + * register before commands bind. A static import list (rather than readdir + + * dynamic import) keeps the whole check graph resolvable up front, which + * matters for bundlers and module-loaders that tag extension graphs. * * Pi loads this file via jiti at runtime (see `pi.extensions` in package.json). * The default export runs once per session; the factory is async so check @@ -16,10 +20,9 @@ * @module pygienium/index */ -import { readdir, readFile } from "node:fs/promises"; -import { dirname, join } from "node:path"; +import { readFile } from "node:fs/promises"; +import { join } from "node:path"; import { homedir } from "node:os"; -import { fileURLToPath } from "node:url"; import type { ExtensionAPI, ExtensionCommandContext, @@ -28,7 +31,7 @@ import type { SessionStartEvent, } from "@oh-my-pi/pi-coding-agent"; import { Box, Text } from "@oh-my-pi/pi-tui"; -import { registerCheck, type CheckDefinition } from "./checks/registry.js"; +import "./checks/all.js"; import { registerPygieniumCommands, type PygieniumCtx } from "./commands.js"; import { type SendChatMessage, @@ -244,34 +247,6 @@ function makeStreamForwarder(pi: ExtensionAPI): StreamForwarder { return { onAgentEvent, sendPhaseLine }; } -/** - * Import every `checks/*.ts` module (except the registry barrel) and register - * each file's `check` export. Check files are pure data modules — they no - * longer self-register on import, because omp's extension loader cache-busts - * lazily imported graph modules with an `?mtime` suffix, which would split - * the registry into two module instances (static entry-graph imports resolve - * to the clean file, lazy imports to the `?mtime` copy). Registering here — - * from the entry's own registry instance — keeps one registry and still makes - * adding a check a drop-a-file operation. - */ -async function loadCheckModules(): Promise { - const dir = join(dirname(fileURLToPath(import.meta.url)), "checks"); - let entries: string[]; - try { - entries = await readdir(dir); - } catch { - return; // no checks dir (e.g. minimal install) - } - for (const entry of entries) { - if (!entry.endsWith(".ts")) continue; - if (entry === "registry.ts" || entry === "load.ts") continue; - const mod = (await import(`./checks/${entry}`)) as { - check?: CheckDefinition; - }; - if (mod.check) registerCheck(mod.check); - } -} - /** * Create a callback to send completion messages to the main chat window. */ @@ -291,9 +266,8 @@ function makeSendChatMessage(pi: ExtensionAPI): SendChatMessage { export default async function pygieniumExtension( pi: ExtensionAPI, ): Promise { - // Self-register every shipped check before wiring commands. - await loadCheckModules(); - + // Checks self-register on import (see ./checks/all.js), which runs before + // this factory — commands below bind against a fully populated registry. const sendChatMessage = makeSendChatMessage(pi); // Register custom message renderer for pygienium progress messages. diff --git a/tests/all-integration.test.ts b/tests/all-integration.test.ts index d9fed12..e54999d 100644 --- a/tests/all-integration.test.ts +++ b/tests/all-integration.test.ts @@ -43,7 +43,7 @@ function fakeCheck(name: string): CheckDefinition { } function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** Capture process.stdout.write lines for the duration of `fn`. */ diff --git a/tests/all.test.ts b/tests/all.test.ts index 87664ae..8965fdb 100644 --- a/tests/all.test.ts +++ b/tests/all.test.ts @@ -65,7 +65,7 @@ function fakeCheck(name: string): CheckDefinition { } function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** Tracker: records dispatched agent tasks then delegates to the fake runner. */ diff --git a/tests/check-runner.test.ts b/tests/check-runner.test.ts index f029dfb..a02c2e1 100644 --- a/tests/check-runner.test.ts +++ b/tests/check-runner.test.ts @@ -41,7 +41,7 @@ function smokeCheck(): CheckDefinition { } function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } describe("check-runner integration", () => { diff --git a/tests/comments.test.ts b/tests/comments.test.ts index 705a25a..1a70c4a 100644 --- a/tests/comments.test.ts +++ b/tests/comments.test.ts @@ -27,7 +27,7 @@ import { import { handleCheckCommand, type PygieniumCtx } from "../src/commands.js"; import { loadRunState } from "../src/run-state.js"; import { - check as commentsCheck, + commentsCheck, findingsPath, changesPath, } from "../src/checks/comments.js"; @@ -48,6 +48,7 @@ const FILENAME = "sample.ts"; function stubCtx(cwd: string): PygieniumCtx { return { cwd, + mode: "print", hasUI: false, ui: undefined, } as PygieniumCtx; diff --git a/tests/complexity.test.ts b/tests/complexity.test.ts index e6a976f..8e4689f 100644 --- a/tests/complexity.test.ts +++ b/tests/complexity.test.ts @@ -19,7 +19,7 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; import { tmpdir } from "node:os"; import { - check as complexityCheck, + complexityCheck, buildComplexityScanTask, buildComplexityFixTask, } from "../src/checks/complexity.js"; diff --git a/tests/dead-code.test.ts b/tests/dead-code.test.ts index dd6bd2a..3607660 100644 --- a/tests/dead-code.test.ts +++ b/tests/dead-code.test.ts @@ -22,7 +22,7 @@ import { getCheck, } from "../src/checks/registry.js"; import { - check as deadCodeCheck, + deadCodeCheck, detectDeadCode, findingsPath, changesPath, @@ -39,7 +39,7 @@ import { handleCheckCommand, type PygieniumCtx } from "../src/commands.js"; import { loadRunState } from "../src/run-state.js"; function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } async function writeFixture(root: string): Promise { diff --git a/tests/deep-modules.test.ts b/tests/deep-modules.test.ts index f02cf14..ae34688 100644 --- a/tests/deep-modules.test.ts +++ b/tests/deep-modules.test.ts @@ -30,11 +30,11 @@ import { loadRunState } from "../src/run-state.js"; import { findingsPath, changesPath, - check as deepModulesCheck, + deepModulesCheck, } from "../src/checks/deep-modules.js"; function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** Drop a pass-through wrapper module that forwards a single lib call. */ diff --git a/tests/defensive-guards.test.ts b/tests/defensive-guards.test.ts index 68efd8f..f8b2529 100644 --- a/tests/defensive-guards.test.ts +++ b/tests/defensive-guards.test.ts @@ -35,11 +35,11 @@ import { loadRunState } from "../src/run-state.js"; import { findingsPath, changesPath, - check as defensiveGuardsCheck, + defensiveGuardsCheck, } from "../src/checks/defensive-guards.js"; function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** diff --git a/tests/per-check-resume.test.ts b/tests/per-check-resume.test.ts index 6638197..a603da9 100644 --- a/tests/per-check-resume.test.ts +++ b/tests/per-check-resume.test.ts @@ -30,7 +30,7 @@ import { handleCheckCommand, type PygieniumCtx } from "../src/commands.js"; import { loadRunState } from "../src/run-state.js"; function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** Capture process.stdout.write lines for the duration of `fn`. */ diff --git a/tests/status-resume-export.test.ts b/tests/status-resume-export.test.ts index 1153e99..0eff4bd 100644 --- a/tests/status-resume-export.test.ts +++ b/tests/status-resume-export.test.ts @@ -79,7 +79,7 @@ function fakeCheck(name: string): CheckDefinition { } function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** Tracker: records dispatched agent tasks then delegates to the fake runner. */ diff --git a/tests/todos.test.ts b/tests/todos.test.ts index 67ccb3e..7470e2c 100644 --- a/tests/todos.test.ts +++ b/tests/todos.test.ts @@ -32,14 +32,14 @@ import { loadRunState } from "../src/run-state.js"; import { findingsPath, changesPath, - check as todosCheck, + todosCheck, detectTodoStubs, todosPriorCounts, buildTodosScanTask, } from "../src/checks/todos.js"; function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } /** diff --git a/tests/verify-hooks.test.ts b/tests/verify-hooks.test.ts index 7878e54..24f9129 100644 --- a/tests/verify-hooks.test.ts +++ b/tests/verify-hooks.test.ts @@ -29,10 +29,10 @@ import { } from "../src/agent-runner.js"; import { handleCheckCommand, type PygieniumCtx } from "../src/commands.js"; import { loadRunState } from "../src/run-state.js"; -import { check as complexityCheck } from "../src/checks/complexity.js"; -import { check as deadCodeCheck } from "../src/checks/dead-code.js"; -import { check as deepModulesCheck } from "../src/checks/deep-modules.js"; -import { check as defensiveGuardsCheck } from "../src/checks/defensive-guards.js"; +import { complexityCheck } from "../src/checks/complexity.js"; +import { deadCodeCheck } from "../src/checks/dead-code.js"; +import { deepModulesCheck } from "../src/checks/deep-modules.js"; +import { defensiveGuardsCheck } from "../src/checks/defensive-guards.js"; /** Agent runner that simulates the MagniFluo bug: ok, empty, no writes. */ const noopRunner: AgentRunner = async () => ({ @@ -41,7 +41,7 @@ const noopRunner: AgentRunner = async () => ({ }); function stubCtx(cwd: string): PygieniumCtx { - return { cwd, hasUI: false, ui: undefined } as PygieniumCtx; + return { cwd, mode: "print", hasUI: false, ui: undefined } as PygieniumCtx; } describe("verify hooks fail loudly on empty agent output", () => {