@formigio/fazemos-cli 0.10.23 → 0.10.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10,9 +10,11 @@ import { isProjectConnectionUnavailable, renderProjectConnectionUnavailableCopy,
10
10
  import { loadYaml, summarize } from './yaml/load.js';
11
11
  import { printFindings, printJson } from './yaml/format.js';
12
12
  import { validateManifest } from './manifest/checks.js';
13
+ import { validatePath as validateRunbookPath } from './runbook/checks.js';
13
14
  import { findLocalRegistry, resolveRole, buildInboxFile, writeInboxFile, writeInboxFileAtPath, buildRolesSyncPayload, findUnprocessedInboxFiles, computeFileHash, gitCommitInboxFile, } from './dispatch.js';
14
15
  import { execSync } from 'child_process';
15
16
  import { registerPauseCommands } from './pause.js';
17
+ import { registerBudgetCommands } from './budget.js';
16
18
  import { parseExecutionsJson, resolveWaitOptions, waitForPipelines, buildAwsCommand, validateExecutionEntry, } from './wait-for-pipeline.js';
17
19
  import { readFileSync, readdirSync, writeFileSync, mkdirSync, existsSync, statSync } from 'fs';
18
20
  import { fileURLToPath } from 'url';
@@ -8237,6 +8239,87 @@ Examples:
8237
8239
  if (summary.errors > 0)
8238
8240
  process.exit(1);
8239
8241
  });
8242
+ // ── `fazemos runbook validate` — Runbook substrate validator (F39 TOOL-1) ──
8243
+ //
8244
+ // Validates Runbook step-doc frontmatter against the FROZEN schema
8245
+ // (projects/fazemos/runbooks/runbook.schema.json) + the per-template
8246
+ // flip-state ledger (projects/fazemos/runbooks/flip-state.json). Offline; no
8247
+ // API calls. A NEW command group (sibling to `yaml` / `manifest`) — a Runbook
8248
+ // doc is a different artifact (markdown-with-frontmatter, not a YAML manifest),
8249
+ // so it does not belong under `manifest validate`'s ADM contract. See the F39
8250
+ // tech spec §9. Scope: frontmatter shape + flip-state invariant ONLY — NOT
8251
+ // id→file resolution (F40), NOT contract-conformance-against-binding (F41).
8252
+ const runbookGroup = program.command('runbook').description('Runbook substrate validation (F39). A Runbook is the one reusable unit of ' +
8253
+ 'work: a declared I/O contract + a role hint + a procedure body, authored ' +
8254
+ 'as frontmatter on a step doc (steps/<Template>/<Step>.md). Offline; no API ' +
8255
+ 'calls. Run at author time, in Ollie\'s stewardship audit, or in CI on PRs ' +
8256
+ 'touching steps/** or runbooks/**.');
8257
+ runbookGroup
8258
+ .command('validate')
8259
+ .description('Validate Runbook step-doc frontmatter: frozen-schema shape + frozen enums + runbook_schema_version + F18 description contract + id shape/uniqueness + no-binding-leak + per-template flip-state invariant.')
8260
+ .argument('<path>', 'Path to a Runbook step-doc (.md) or a directory of them (e.g. "steps/Hello Fazemos/"). Absolute or relative to CWD.')
8261
+ .option('--json', 'Emit structured JSON output instead of human-readable text. See --help for shape.')
8262
+ .addHelpText('after', `
8263
+ What runs (in order, per file):
8264
+ 1. frontmatter split + js-yaml parse (rule slugs: runbook.no_frontmatter / runbook.frontmatter_parse_error / runbook.shape)
8265
+ 2. frozen schema (ajv, draft-07) (rule slugs: schema.* — required/enum/type/pattern/additionalProperties)
8266
+ 3. runbook_schema_version present/known (runbook.version_missing = ERROR; runbook.version_unknown = warning)
8267
+ 4. description (F18 contract) (runbook.description_invalid: MISSING/EMPTY/MULTILINE)
8268
+ 5. runbook id kebab shape + uniqueness (runbook.id_shape; runbook.id_duplicate across a directory run)
8269
+ 6. no binding/DAG leak (runbook.binding_leak — depends_on/source_*/step_type/template/cadence/… + top-level reviewer/eval_max_turns)
8270
+ 7. per-template flip-state invariant (runbook.flip_state_unreadable / runbook.flip_state_mismatch)
8271
+
8272
+ Schema source of truth: projects/fazemos/runbooks/runbook.schema.json (canonical;
8273
+ loaded from the workspace clone). The CLI vendors a copy as the absent-canonical
8274
+ fallback; a unit test diffs the two and fails on drift (F39 §9.2).
8275
+
8276
+ Flip-state: projects/fazemos/runbooks/flip-state.json. flipped:true => the doc is
8277
+ authoritative (empty inline sections are correct — no false EMPTY_STEP_BODY alarm);
8278
+ flipped:false/absent => inline sections are authoritative (frontmatter accepted if
8279
+ present, transitional). An unreadable ledger is a hard error.
8280
+
8281
+ Frozen enums (F39 §5.2; append-only within a major version):
8282
+ type text | number | boolean | url | filepath | json
8283
+ format text | filepath | url | commit_sha | integer | markdown | json
8284
+ source_hint upstream | pipeline_param | dispatch_param | workspace_path
8285
+
8286
+ Exit codes:
8287
+ 0 no error-severity findings (warnings + infos OK)
8288
+ 1 any error-severity finding present
8289
+
8290
+ JSON output shape (--json) — same as \`manifest validate --json\`, one object per file:
8291
+ { "source", "ok", "summary": { "errors", "warnings", "infos" }, "findings": [ … ] }
8292
+
8293
+ When to invoke:
8294
+ - Author time, before commit (catches STEP_UNRESOLVED-class defects before a render)
8295
+ - Inside Ollie's stewardship / flip audit
8296
+ - In CI on any PR touching steps/** or runbooks/**
8297
+
8298
+ Examples:
8299
+ fazemos runbook validate "projects/fazemos/steps/Hello Fazemos/Write a random fact.md"
8300
+ fazemos runbook validate "projects/fazemos/steps/Hello Fazemos/" --json | jq '.[].findings[] | select(.severity=="error")'`)
8301
+ .action((path, opts) => {
8302
+ const results = validateRunbookPath(path);
8303
+ let totalErrors = 0;
8304
+ if (opts.json) {
8305
+ const payload = results.map((r) => {
8306
+ const summary = summarize(r.findings);
8307
+ totalErrors += summary.errors;
8308
+ return { source: r.source, ok: summary.errors === 0, summary, findings: r.findings };
8309
+ });
8310
+ console.log(JSON.stringify(payload, null, 2));
8311
+ }
8312
+ else {
8313
+ for (const r of results) {
8314
+ const summary = summarize(r.findings);
8315
+ totalErrors += summary.errors;
8316
+ printFindings(r.source, r.findings, summary);
8317
+ console.log('');
8318
+ }
8319
+ }
8320
+ if (totalErrors > 0)
8321
+ process.exit(1);
8322
+ });
8240
8323
  // ── `fazemos dispatch` — role-to-role dispatch ─────────────────────
8241
8324
  //
8242
8325
  // F26 data flow (API write-through, Dex S-B):
@@ -8597,6 +8680,11 @@ program
8597
8680
  // commands and the `pause status` sub-command. All calls are org-level
8598
8681
  // (noProjectHeader: true); admin/owner required for set/clear, member for read.
8599
8682
  registerPauseCommands(program);
8683
+ // ── F33 — Token/Cost Budgets: budget set/clear/show/status ──────────────────
8684
+ // Registers `budget` top-level command with set, clear, show, and status
8685
+ // sub-commands. All calls are org-level (noProjectHeader: true);
8686
+ // admin/owner required for set/clear, any active member for show/status.
8687
+ registerBudgetCommands(program);
8600
8688
  // Skip auto-parse only when running under Vitest (which sets process.env.VITEST).
8601
8689
  // Tests import `program` and drive it via `program.parseAsync(...)` after mocking
8602
8690
  // `./api.js`. In every other context — direct invocation, npx tsx, OR the bin