Context
scripts/loopover-config-lint.ts (exposed as npm run selfhost:config-lint -- [path]) validates a
.loopover.yml/focus-manifest file via src/selfhost/config-lint.ts's lintManifestText, which
already returns a fully machine-shaped result:
export type SelfHostConfigLintResult = {
ok: boolean;
warnings: string[];
recognizedFields: string[];
summary: string;
};
But scripts/loopover-config-lint.ts's main() only ever prints the human-formatted report via
formatLintReport() — there is no --json flag at all:
function main(): void {
const args = process.argv.slice(2);
if (args.includes("--help") || args.includes("-h")) {
console.log(usage());
return;
}
const path = args[0] ?? ".loopover.yml";
...
const result = lintManifestText(text);
console.log(formatLintReport(path, result));
if (!result.ok) process.exit(1);
}
Every sibling contributor-facing CLI in this repo that validates config or reports structured
results supports --json: loopover-mcp validate-config --file <path> [--json] (the CLI-facing
equivalent validator, see printValidateConfigHelp() in
packages/loopover-mcp/bin/loopover-mcp.js), loopover-mcp doctor [--json], loopover-mcp status [--json], and effectively every other reporting command in that same file. scripts/loopover-config-lint.ts
is the one config-validation entrypoint in the repo without a machine-readable output mode, even
though the underlying SelfHostConfigLintResult it already computes is trivially JSON-serializable
and self-hosters/CI scripts wiring this into a pre-deploy check have no way to consume it
programmatically without regex-parsing formatLintReport's plain-text output.
Requirements
- Add a
--json flag to scripts/loopover-config-lint.ts's main(). When present, print
JSON.stringify({ path, ...result }, null, 2) (or an equivalently-shaped object — path plus the
full SelfHostConfigLintResult) to stdout instead of the formatLintReport text, and keep the
same exit-code behavior (process.exit(1) when !result.ok).
- Update
usage()'s Usage: line and Options: block to document the new flag, following this
file's existing style.
- No change to the default (non-
--json) text output or to readManifestTextForLint's error
handling — the missing-file/symlink/oversize error paths should still print a plain-text error to
stderr via the existing console.error(...)\n\n${usage()} pattern (adding a --json error
contract for the file-read-failure path is out of scope for this issue if it adds ambiguity; a
future issue can align it with packages/loopover-miner/lib/cli-error.js's { ok: false, error }
convention if desired — keep this change scoped to the successful-parse path's output shape).
Deliverables
Test Coverage Requirements
scripts/loopover-config-lint.ts is under scripts/**, which is both excluded from
vitest.config.ts's coverage.include and explicitly listed in codecov.yml's ignore: block —
this change is not numerically gated by Codecov's 99% patch requirement. Regression coverage is still
required via a real subprocess/CLI-invocation test (see Deliverables) so a future edit can't silently
break --json output. Note: main() in this file already carries a
/* v8 ignore start ... v8 ignore stop */ block covering the CLI-entrypoint I/O/process.exit
plumbing (per its own comment: "formatLintReport above carries the tested logic") — the new --json
branch should either extend that same ignored block consistently (if it stays pure process/I/O
glue) or, if any new logic is added outside the ignore block, that logic needs its own direct test
coverage regardless of Codecov not gating this path. Don't silently widen the ignore block to dodge
coverage on genuinely new logic.
Expected Outcome
npm run selfhost:config-lint -- <path> --json prints a parseable JSON report of the same shape
SelfHostConfigLintResult already provides, matching the --json convention every other
config-validation-adjacent CLI entrypoint in this repo already follows.
Links & Resources
scripts/loopover-config-lint.ts — main(), usage(), formatLintReport().
src/selfhost/config-lint.ts — lintManifestText, SelfHostConfigLintResult.
packages/loopover-mcp/bin/loopover-mcp.js — validateConfigCli/printValidateConfigHelp() for
the sibling convention this aligns with.
Context
scripts/loopover-config-lint.ts(exposed asnpm run selfhost:config-lint -- [path]) validates a.loopover.yml/focus-manifest file viasrc/selfhost/config-lint.ts'slintManifestText, whichalready returns a fully machine-shaped result:
But
scripts/loopover-config-lint.ts'smain()only ever prints the human-formatted report viaformatLintReport()— there is no--jsonflag at all:Every sibling contributor-facing CLI in this repo that validates config or reports structured
results supports
--json:loopover-mcp validate-config --file <path> [--json](the CLI-facingequivalent validator, see
printValidateConfigHelp()inpackages/loopover-mcp/bin/loopover-mcp.js),loopover-mcp doctor [--json],loopover-mcp status [--json], and effectively every other reporting command in that same file.scripts/loopover-config-lint.tsis the one config-validation entrypoint in the repo without a machine-readable output mode, even
though the underlying
SelfHostConfigLintResultit already computes is trivially JSON-serializableand self-hosters/CI scripts wiring this into a pre-deploy check have no way to consume it
programmatically without regex-parsing
formatLintReport's plain-text output.Requirements
--jsonflag toscripts/loopover-config-lint.ts'smain(). When present, printJSON.stringify({ path, ...result }, null, 2)(or an equivalently-shaped object —pathplus thefull
SelfHostConfigLintResult) to stdout instead of theformatLintReporttext, and keep thesame exit-code behavior (
process.exit(1)when!result.ok).usage()'sUsage:line andOptions:block to document the new flag, following thisfile's existing style.
--json) text output or toreadManifestTextForLint's errorhandling — the missing-file/symlink/oversize error paths should still print a plain-text error to
stderr via the existing
console.error(...)\n\n${usage()}pattern (adding a--jsonerrorcontract for the file-read-failure path is out of scope for this issue if it adds ambiguity; a
future issue can align it with
packages/loopover-miner/lib/cli-error.js's{ ok: false, error }convention if desired — keep this change scoped to the successful-parse path's output shape).
Deliverables
--jsonflag support inscripts/loopover-config-lint.ts'smain().usage()text updated to document--json.scripts/loopover-config-lint.ts's existing test coverage,likely alongside
src/selfhost/config-lint.ts's test suite or a newtest/unit/loopover-config-lint-cli.test.ts) asserting--jsonoutput is valid JSON containingok,warnings,recognizedFields, andsummary, for both a clean manifest and one with anunknown top-level field.
Test Coverage Requirements
scripts/loopover-config-lint.tsis underscripts/**, which is both excluded fromvitest.config.ts'scoverage.includeand explicitly listed incodecov.yml'signore:block —this change is not numerically gated by Codecov's 99% patch requirement. Regression coverage is still
required via a real subprocess/CLI-invocation test (see Deliverables) so a future edit can't silently
break
--jsonoutput. Note:main()in this file already carries a/* v8 ignore start ... v8 ignore stop */block covering the CLI-entrypoint I/O/process.exitplumbing (per its own comment: "formatLintReport above carries the tested logic") — the new
--jsonbranch should either extend that same ignored block consistently (if it stays pure process/I/O
glue) or, if any new logic is added outside the ignore block, that logic needs its own direct test
coverage regardless of Codecov not gating this path. Don't silently widen the ignore block to dodge
coverage on genuinely new logic.
Expected Outcome
npm run selfhost:config-lint -- <path> --jsonprints a parseable JSON report of the same shapeSelfHostConfigLintResultalready provides, matching the--jsonconvention every otherconfig-validation-adjacent CLI entrypoint in this repo already follows.
Links & Resources
scripts/loopover-config-lint.ts—main(),usage(),formatLintReport().src/selfhost/config-lint.ts—lintManifestText,SelfHostConfigLintResult.packages/loopover-mcp/bin/loopover-mcp.js—validateConfigCli/printValidateConfigHelp()forthe sibling convention this aligns with.