Files
gstack/bin/gstack-inventory
T
garrytanandcapy-ai[bot] 37f515bae0 inventory: the R56 evidence ledger, gstack-inventory and skill-bill EVIDENCE
docs/inventory/evidence.json holds one row per inventory key: the skill
folders discoverTemplates() finds (root skill as gstack, symlinked folders
excluded) plus seven shared parts, 71 keys. lib/inventory.ts validates each
row by its status's own fields, with named codes (LEDGER_*), and joins the
ledger with lib/context-bill.ts buildBill. bin/gstack-inventory writes
docs/inventory.md, --check validates (exit 1 with codes), --json prints.
Paid dispatches per run for /ship and /autoplan are quoted from their own
docs and found by line, so a moved citation fails --check
(INVENTORY_SOURCE_MISSING). Every current row is grandfathered and seeded
from GEVA-2's table (org-gstack-gbrain/research/gstack-part-evidence.json):
in-flight fair tests and proposed registry rows as plans, earlier unfair
results under prior with why (stub, unmasked, ceiling, ...), five safety
rows. gstack-skill-bill prints the skill's EVIDENCE line.

Evidence: plan none (owner ruling R56, GST-914); the ledger itself is the measurement record
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-11-02 05:03:32 +00:00

42 lines
2.6 KiB
TypeScript
Executable File

#!/usr/bin/env -S bun --no-env-file --config=/dev/null
// gstack-inventory — every gstack part, its load per run and its evidence (ETHOS.md: 9. Earn Its Place). Logic: lib/inventory.ts.
import { writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { buildInventory, checkInventory, DOC_PATH, LEDGER_PATH, renderInventory } from "../lib/inventory";
const USAGE = `Usage: gstack-inventory [--root <gstack checkout>] [--check | --json]
gstack-inventory --help
Joins the evidence ledger (${LEDGER_PATH}) with gstack-context-bill's sizes and writes ${DOC_PATH}:
parts ranked by load per run, each part's evidence status, a "measure next" order (largest untested
first), shared-part sizes, paid dispatches per run for /ship and /autoplan, and the key list.
--check validates the ledger (every key has one row; each row has its status's fields), the quoted
dispatch sources and the shared-part files, and writes nothing. --json prints the inventory.
Exit 0 when clean; 1 with one "<key>: <problem> (<CODE>)" line per problem; 2 on a bad argument.`;
const args = process.argv.slice(2);
if (args.includes("--help") || args.includes("-h")) { console.log(USAGE); process.exit(0); }
const rootAt = args.indexOf("--root");
const root = resolve(rootAt >= 0 ? args[rootAt + 1] ?? "" : join(import.meta.dir, ".."));
const unknown = args.find((a, i) => !["--check", "--json", "--root"].includes(a) && !(rootAt >= 0 && i === rootAt + 1));
if (unknown !== undefined || (rootAt >= 0 && !args[rootAt + 1]) || (args.includes("--check") && args.includes("--json"))) {
console.error(unknown !== undefined ? `gstack-inventory: unknown argument '${unknown}'; valid: --root <dir> --check --json --help` : USAGE);
process.exit(2);
}
const report = (problems: { key: string; code: string; message: string }[]) => {
for (const p of problems) console.error(`gstack-inventory: ${p.key}: ${p.message} (${p.code})`);
};
if (args.includes("--check")) {
const checked = checkInventory(root);
report(checked.problems);
if (checked.problems.length) process.exit(1);
console.log(`INVENTORY: ok keys=${checked.keys.length} ledger=${LEDGER_PATH} dispatch_sources=${checked.dispatches.length}`);
process.exit(0);
}
const inv = buildInventory(root);
report(inv.problems);
if (args.includes("--json")) { console.log(JSON.stringify(inv, null, 2)); process.exit(inv.problems.length ? 1 : 0); }
if (inv.problems.length) { console.error(`gstack-inventory: ${DOC_PATH} not written; fix the problems above, then rerun`); process.exit(1); }
writeFileSync(join(root, DOC_PATH), renderInventory(inv));
console.log(`INVENTORY: wrote ${DOC_PATH} keys=${inv.keys.length} commit=${inv.commit}`);