ktg-plugin-marketplace/plugins/config-audit/scanners/whats-active.mjs
Kjell Tore Guttormsen 5eecb968d8 feat(humanizer): wire humanizer into 6 remaining CLIs with --raw
Adds --raw flag to all 6 remaining CLIs and wires humanization into the
default rendering path. --json and --raw both bypass humanization for
v5.0.0 byte-equal output; default mode humanizes findings/diff/prose.

  token-hotspots-cli: humanizes payload.findings before stdout JSON write.
  plugin-health-scanner: humanizes finding titles in stderr brief summary;
    --json/--raw write byte-identical v5.0.0-shape result to stdout.
  drift-cli: humanizes diff.{newFindings,resolvedFindings,unchangedFindings,
    movedFindings} before formatDiffReport; --raw applies to save and list
    modes too. Baselines remain raw v5.0.0 on disk.
  fix-cli: humanizes manual-finding titles in stderr fix-plan prose; both
    --json and --raw produce identical machine-readable JSON to stdout.
  manifest, whats-active: --raw is a no-op (no findings, inventory only)
    but parsed for CLI surface consistency.

Decision on missing --output-file flag for drift-cli/fix-cli/plugin-health:
deferred. SC-6/SC-7 tests in Wave 4 will use stdout-redirect (the simpler
Alt B path) since these CLIs already write JSON to stdout in machine modes.

Test cli-humanizer.test.mjs covers all 6 CLIs. Three CLIs that read
environment state (plugin-health, manifest, whats-active) verify
mode-equivalence (--json == --raw) instead of frozen-snapshot byte-equal,
because their output reflects current marketplace state which drifts as
plugins are added since the Wave 0 capture.

Wave 3 / Step 7 of v5.1.0 humanizer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 17:47:09 +02:00

69 lines
2.1 KiB
JavaScript

#!/usr/bin/env node
/**
* whats-active CLI — produce a read-only inventory of everything Claude Code
* loads for a given repo path. Thin shim over scanners/lib/active-config-reader.mjs.
*
* Usage:
* node whats-active.mjs [path] [--json] [--output-file <path>]
* [--verbose] [--suggest-disables]
*
* Exit codes: 0=ok, 3=unrecoverable error.
* Zero external dependencies.
*/
import { resolve } from 'node:path';
import { writeFile, stat } from 'node:fs/promises';
import { readActiveConfig } from './lib/active-config-reader.mjs';
async function main() {
const args = process.argv.slice(2);
let targetPath = '.';
let outputFile = null;
let jsonMode = false;
// --raw is accepted for CLI surface consistency but is a no-op here:
// whats-active produces an inventory snapshot, not findings.
let rawMode = false;
let verbose = false;
let suggestDisables = false;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--json') jsonMode = true;
else if (args[i] === '--raw') rawMode = true;
else if (args[i] === '--verbose') verbose = true;
else if (args[i] === '--suggest-disables') suggestDisables = true;
else if (args[i] === '--output-file' && args[i + 1]) outputFile = args[++i];
else if (!args[i].startsWith('-')) targetPath = args[i];
}
const absPath = resolve(targetPath);
try {
const s = await stat(absPath);
if (!s.isDirectory()) {
process.stderr.write(`Error: ${absPath} is not a directory\n`);
process.exit(3);
}
} catch {
process.stderr.write(`Error: path does not exist: ${absPath}\n`);
process.exit(3);
}
const result = await readActiveConfig(absPath, { verbose, suggestDisables });
const json = JSON.stringify(result, null, 2);
if (outputFile) {
await writeFile(outputFile, json, 'utf-8');
}
if (jsonMode || rawMode || !outputFile) {
process.stdout.write(json + '\n');
}
}
const isDirectRun = process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname);
if (isDirectRun) {
main().catch(err => {
process.stderr.write(`Fatal: ${err.message}\n`);
process.exit(3);
});
}