voyage/lib/util/autonomy-gate.mjs
Kjell Tore Guttormsen 308b149e70
refactor(gates): the autonomy gate is the --gates flag parser
lib/util/autonomy-gate.mjs keeps only gatesValue + parseGatesArgs and the
CLI ({"ok":true,"gates":true|false}; exact usage error on a bad value;
the old --state/--event arguments are a usage error). The four commands
run 'autonomy-gate.mjs --gates [value]' and read gates. Prose (README,
operations, architecture, sdlc-playbook-gap) and the S24, gates-flag
and [#1] tests follow (R9).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:37:03 +01:00

71 lines
2.3 KiB
JavaScript

// lib/util/autonomy-gate.mjs
// The --gates flag parser for /trekbrief, /trekresearch, /trekplan and
// /trekexecute: maps the flag's value to gates on or off.
//
// CLI:
// node lib/util/autonomy-gate.mjs [--gates [true|false|closed|open]]
// (bare --gates = on; true|closed = on, false|open = off; no flag = off.
// Any other value is a usage error, exit 1; case-sensitive. One token
// --gates=<value> is read as --gates <value>; an empty value is the same
// usage error. Any other argument is a usage error.)
// → JSON: { ok: true, gates: true|false } (exit 0)
// → JSON: { ok: false, error: "usage: ..." } (exit 1)
//
// Pure data; no I/O beyond the CLI's stdout.
import { isMain } from './is-main.mjs';
/**
* A --gates value: true|closed = on, false|open = off, else undefined.
*
* @param {string|undefined} v
* @returns {boolean|undefined}
*/
export function gatesValue(v) {
if (v === 'true' || v === 'closed') return true;
if (v === 'false' || v === 'open') return false;
return undefined;
}
const GATES_USAGE = 'usage: --gates takes true, false, closed or open';
const USAGE = 'usage: autonomy-gate.mjs [--gates [true|false|closed|open]]';
/**
* Parse the CLI arguments.
*
* @param {string[]} argv
* @returns {{ ok: true, gates: boolean } | { ok: false, error: string }}
*/
export function parseGatesArgs(argv) {
let gates = false;
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
let v;
if (a.startsWith('--gates=')) {
// The one-token form, read as `--gates <value>`; an empty value is no value.
v = a.slice('--gates='.length);
} else if (a === '--gates') {
// Bare `--gates` (last, or followed by another flag) means on and
// consumes nothing.
const next = argv[i + 1];
if (next === undefined || next.startsWith('--')) {
gates = true;
continue;
}
v = next;
i++;
} else {
return { ok: false, error: USAGE };
}
const g = gatesValue(v);
if (g === undefined) return { ok: false, error: GATES_USAGE };
gates = g;
}
return { ok: true, gates };
}
if (isMain(import.meta.url)) {
const result = parseGatesArgs(process.argv.slice(2));
process.stdout.write(JSON.stringify(result) + '\n');
process.exit(result.ok ? 0 : 1);
}