Skip to content

feat(selfhost): scripts/loopover-config-lint.ts has no --json output mode, unlike sibling validators #5931

Description

@JSONbored

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

  • --json flag support in scripts/loopover-config-lint.ts's main().
  • usage() text updated to document --json.
  • Regression test (new or extending scripts/loopover-config-lint.ts's existing test coverage,
    likely alongside src/selfhost/config-lint.ts's test suite or a new
    test/unit/loopover-config-lint-cli.test.ts) asserting --json output is valid JSON containing
    ok, warnings, recognizedFields, and summary, for both a clean manifest and one with an
    unknown top-level field.

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.tsmain(), usage(), formatLintReport().
  • src/selfhost/config-lint.tslintManifestText, SelfHostConfigLintResult.
  • packages/loopover-mcp/bin/loopover-mcp.jsvalidateConfigCli/printValidateConfigHelp() for
    the sibling convention this aligns with.

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:featureGittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions