fix: close CLI term gaps — workspace rejection, stale types, quiet, placebo, help

This commit is contained in:
John Dvorak
2026-05-22 12:51:12 -07:00
parent edc2989900
commit a186146c69
6 changed files with 24 additions and 29 deletions
-21
View File
@@ -26,16 +26,6 @@ import { runDocsChecks } from './checks/docs.js';
import { renderJson } from '../../renderers/json.js'; import { renderJson } from '../../renderers/json.js';
// Deterministic string-to-seed hash (FNV-1a)
function hashStringToSeed(str: string): number {
let hash = 0x811c9dc5
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i)
hash = Math.imul(hash, 0x01000193)
}
return Math.abs(hash >>> 0)
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Types // Types
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -206,17 +196,6 @@ async function runPackageChecks(
checks.push({ ...result, package: packageName }); checks.push({ ...result, package: packageName });
} }
// 6. Determinism trust signal
const testSeed = hashStringToSeed(packageName + cwd);
checks.push({
name: 'determinism',
status: 'pass',
message: `Environment supports deterministic replay (test seed: ${testSeed})`,
detail: `Run with --seed ${testSeed} to reproduce the exact same test sequence`,
mode: 'all',
package: packageName,
});
return checks; return checks;
} }
+1 -1
View File
@@ -622,7 +622,7 @@ function parseInitOptions(args: string[], ctx: CliContext): InitOptions {
export async function handleInit(args: string[], ctx: CliContext): Promise<number> { export async function handleInit(args: string[], ctx: CliContext): Promise<number> {
const result = await initHandler(args, ctx); const result = await initHandler(args, ctx);
if (result.message) { if (result.message && !ctx.options.quiet) {
console.log(result.message); console.log(result.message);
} }
+14
View File
@@ -328,6 +328,20 @@ export async function handleObserve(
checks: result.checks, checks: result.checks,
message: result.message, message: result.message,
}) + '\n'); }) + '\n');
} else if (format === 'json-summary') {
console.log(renderJson({
exitCode: result.exitCode,
checks: result.checks,
message: result.message,
}));
} else if (format === 'ndjson-summary') {
process.stdout.write(JSON.stringify({
type: 'run.completed',
command: 'observe',
exitCode: result.exitCode,
checks: result.checks,
message: result.message,
}) + '\n');
} else { } else {
console.log(result.message); console.log(result.message);
} }
+1 -1
View File
@@ -68,7 +68,7 @@ export interface QualifyOptions {
changed?: boolean changed?: boolean
config?: string config?: string
cwd?: string cwd?: string
format?: 'human' | 'json' | 'ndjson' format?: 'human' | 'json' | 'ndjson' | 'json-summary' | 'ndjson-summary'
quiet?: boolean quiet?: boolean
verbose?: boolean verbose?: boolean
artifactDir?: string artifactDir?: string
+1 -1
View File
@@ -59,7 +59,7 @@ export interface VerifyOptions {
changed?: boolean changed?: boolean
config?: string config?: string
cwd?: string cwd?: string
format?: 'human' | 'json' | 'ndjson' format?: 'human' | 'json' | 'ndjson' | 'json-summary' | 'ndjson-summary'
quiet?: boolean quiet?: boolean
verbose?: boolean verbose?: boolean
artifactDir?: string artifactDir?: string
+6 -4
View File
@@ -54,8 +54,8 @@ function getCommandHelp(command: string): string {
apophis init [options] apophis init [options]
${pc.dim('Options:')} ${pc.dim('Options:')}
--preset <name> Preset name (e.g. safe-ci, full) --preset, -p <name> Preset name (e.g. safe-ci, full)
--force Overwrite existing files --force, -f Overwrite existing files
--noninteractive Skip all prompts, require explicit flags --noninteractive Skip all prompts, require explicit flags
${pc.dim('Examples:')} ${pc.dim('Examples:')}
@@ -116,9 +116,11 @@ function getCommandHelp(command: string): string {
${pc.dim('Options:')} ${pc.dim('Options:')}
--artifact <path> Path to failure artifact --artifact <path> Path to failure artifact
--route <filter> Select failure by route pattern
${pc.dim('Examples:')} ${pc.dim('Examples:')}
apophis replay --artifact reports/apophis/failure-*.json apophis replay --artifact reports/apophis/failure-*.json
apophis replay --artifact failure-1.json --route "POST /users"
`, `,
doctor: ` doctor: `
${pc.bold('apophis doctor')} Validate config, environment safety, docs/example correctness ${pc.bold('apophis doctor')} Validate config, environment safety, docs/example correctness
@@ -377,8 +379,8 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<numb
const commandSpecificFlags: Record<string, Set<string>> = { const commandSpecificFlags: Record<string, Set<string>> = {
init: new Set(['--preset', '-p', '--force', '-f', '--noninteractive']), init: new Set(['--preset', '-p', '--force', '-f', '--noninteractive']),
verify: new Set(['--profile', '--routes', '--seed', '--changed', '--workspace']), verify: new Set(['--profile', '--routes', '--seed', '--changed', '--workspace']),
observe: new Set(['--profile', '--check-config', '--workspace']), observe: new Set(['--profile', '--check-config']),
qualify: new Set(['--profile', '--seed', '--workspace', '--changed']), qualify: new Set(['--profile', '--seed', '--changed']),
replay: new Set(['--artifact', '--route']), replay: new Set(['--artifact', '--route']),
doctor: new Set(['--mode', '--strict', '--workspace']), doctor: new Set(['--mode', '--strict', '--workspace']),
migrate: new Set(['--check', '--dry-run', '--write']), migrate: new Set(['--check', '--dry-run', '--write']),