@blamejs/exceptd-skills 0.12.41 → 0.13.0

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/bin/exceptd.js +52 -44
  3. package/data/_indexes/_meta.json +47 -47
  4. package/data/_indexes/chains.json +485 -13
  5. package/data/_indexes/jurisdiction-map.json +15 -4
  6. package/data/_indexes/section-offsets.json +1244 -1244
  7. package/data/_indexes/token-budget.json +173 -173
  8. package/data/atlas-ttps.json +54 -11
  9. package/data/attack-techniques.json +113 -17
  10. package/data/cve-catalog.json +17 -24
  11. package/data/cwe-catalog.json +8 -2
  12. package/data/framework-control-gaps.json +13 -3
  13. package/data/playbooks/ai-api.json +5 -0
  14. package/data/playbooks/cicd-pipeline-compromise.json +970 -0
  15. package/data/playbooks/cloud-iam-incident.json +4 -1
  16. package/data/playbooks/cred-stores.json +10 -0
  17. package/data/playbooks/framework.json +16 -0
  18. package/data/playbooks/hardening.json +4 -0
  19. package/data/playbooks/identity-sso-compromise.json +951 -0
  20. package/data/playbooks/idp-incident.json +3 -0
  21. package/data/playbooks/kernel.json +6 -0
  22. package/data/playbooks/llm-tool-use-exfil.json +963 -0
  23. package/data/playbooks/mcp.json +6 -0
  24. package/data/playbooks/runtime.json +4 -0
  25. package/data/playbooks/sbom.json +13 -0
  26. package/data/playbooks/secrets.json +6 -0
  27. package/data/playbooks/webhook-callback-abuse.json +916 -0
  28. package/lib/cross-ref-api.js +33 -13
  29. package/lib/cve-curation.js +12 -1
  30. package/lib/exit-codes.js +29 -0
  31. package/lib/lint-skills.js +24 -2
  32. package/lib/refresh-external.js +10 -1
  33. package/lib/scoring.js +55 -0
  34. package/manifest.json +83 -83
  35. package/orchestrator/index.js +32 -24
  36. package/package.json +1 -1
  37. package/sbom.cdx.json +122 -78
  38. package/scripts/predeploy.js +7 -13
  39. package/scripts/refresh-reverse-refs.js +86 -0
  40. package/scripts/refresh-sbom.js +21 -4
  41. package/skills/age-gates-child-safety/skill.md +1 -5
  42. package/skills/ai-attack-surface/skill.md +11 -4
  43. package/skills/ai-c2-detection/skill.md +11 -2
  44. package/skills/ai-risk-management/skill.md +4 -2
  45. package/skills/api-security/skill.md +7 -8
  46. package/skills/attack-surface-pentest/skill.md +2 -2
  47. package/skills/cloud-iam-incident/skill.md +1 -5
  48. package/skills/cloud-security/skill.md +0 -4
  49. package/skills/compliance-theater/skill.md +10 -2
  50. package/skills/container-runtime-security/skill.md +1 -3
  51. package/skills/dlp-gap-analysis/skill.md +3 -4
  52. package/skills/email-security-anti-phishing/skill.md +1 -8
  53. package/skills/exploit-scoring/skill.md +7 -2
  54. package/skills/framework-gap-analysis/skill.md +1 -1
  55. package/skills/fuzz-testing-strategy/skill.md +1 -2
  56. package/skills/global-grc/skill.md +3 -2
  57. package/skills/identity-assurance/skill.md +1 -3
  58. package/skills/idp-incident-response/skill.md +1 -4
  59. package/skills/incident-response-playbook/skill.md +1 -5
  60. package/skills/kernel-lpe-triage/skill.md +2 -2
  61. package/skills/mcp-agent-trust/skill.md +13 -3
  62. package/skills/mlops-security/skill.md +2 -3
  63. package/skills/ot-ics-security/skill.md +0 -3
  64. package/skills/policy-exception-gen/skill.md +11 -3
  65. package/skills/pqc-first/skill.md +4 -2
  66. package/skills/rag-pipeline-security/skill.md +2 -0
  67. package/skills/ransomware-response/skill.md +1 -5
  68. package/skills/researcher/skill.md +4 -3
  69. package/skills/sector-energy/skill.md +0 -4
  70. package/skills/sector-federal-government/skill.md +2 -3
  71. package/skills/sector-financial/skill.md +1 -4
  72. package/skills/sector-healthcare/skill.md +0 -5
  73. package/skills/sector-telecom/skill.md +0 -4
  74. package/skills/security-maturity-tiers/skill.md +1 -2
  75. package/skills/skill-update-loop/skill.md +4 -3
  76. package/skills/supply-chain-integrity/skill.md +4 -3
  77. package/skills/threat-model-currency/skill.md +1 -1
  78. package/skills/threat-modeling-methodology/skill.md +2 -1
  79. package/skills/webapp-security/skill.md +0 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,96 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.0 — 2026-05-17
4
+
5
+ Minor release. Breaking-change bundle for the v0.10.x legacy-verb removal that has been deprecation-bannered since v0.11.0; envelope harmonization across every JSON-emitting verb; 4 new playbooks expanding the canonical set to 20; engine hardening (factor-shape validation, cache invalidation, fsync-on-rename, deterministic SBOM); schema reverse fields on ATLAS, ATT&CK, and the playbook chain.
6
+
7
+ ### Breaking changes — migration required
8
+
9
+ **Five v0.10.x legacy verbs hard-removed: `plan`, `govern`, `direct`, `look`, `ingest`.** They were deprecation-bannered since v0.11.0 and slated-for-removal-in-v0.13 since v0.12.0. Operators on v0.10.x → v0.13.0 now get a structured `ok:false` refusal with the v0.11+ replacement command. Each removal is a pure rename — same underlying capability is reachable via the replacement. Refusal body shape:
10
+
11
+ ```json
12
+ {
13
+ "ok": false,
14
+ "error": "'plan' was removed in v0.13.0. Use `exceptd brief --all` instead.",
15
+ "verb": "plan",
16
+ "removed_in": "0.13.0",
17
+ "replacement": "brief --all",
18
+ "deprecation_history": "Deprecated in v0.11.0 ... removed in v0.13.0."
19
+ }
20
+ ```
21
+
22
+ Replacements:
23
+ - `exceptd plan` → `exceptd brief --all`
24
+ - `exceptd govern <pb>` → `exceptd brief <pb> --phase govern`
25
+ - `exceptd direct <pb>` → `exceptd brief <pb> --phase direct`
26
+ - `exceptd look <pb>` → `exceptd brief <pb> --phase look`
27
+ - `exceptd ingest <args>` → `exceptd run <args>`
28
+
29
+ `reattest` and `list-attestations` were also deprecation-bannered but are PRESERVED — they remain canonical short-form routings of `attest diff` / `attest list` and stay functional.
30
+
31
+ The deprecation-banner + tempdir-marker mechanism (added v0.11.0, persisted via `EXCEPTD_DEPRECATION_SHOWN` env var + `exceptd-deprecation-shown-v<X.Y.Z>` tempdir marker) is removed. Pre-v0.13 scripts that pinned the banner shape should remove those assertions.
32
+
33
+ **Orchestrator exit-code class change: usage errors exit 1 (`GENERIC_FAILURE`), not 2 (`DETECTED_ESCALATE`).** Affected verbs: `framework-gap` (missing args), `report <format>` (unknown format), `validate-cves` / `validate-rfcs` (catalog-read failure), `watchlist` (manifest-read failure), `skill <name>` (skill-not-found). Pre-v0.13 these exited 2, colliding with the canonical CI contract where exit 2 means "verb ran and detected an escalation-worthy finding." CI gates wired to branch on exit 2 will need to also accept exit 1 for these verbs, OR pre-validate inputs before invocation.
34
+
35
+ **Envelope harmonization: every JSON-emitting verb now carries top-level `ok` and (where applicable) `verb`.** Pre-v0.13 `brief --all`, `watchlist`, `ci`, `doctor`, `discover`, `attest show`, `attest export`, and `cmdRunMulti` omitted one or both fields inconsistently. `emit()` now defaults `ok: true` when not set (symmetric to the existing `ok: false → exit 1` fallback), and per-verb call sites set `verb: "..."` explicitly. Consumers that parsed bodies for the absence of these fields will break; consumers reading specific known fields are unaffected.
36
+
37
+ **Orchestrator `ok:false` bodies now land on stdout (not stderr).** Aligns with the bin/exceptd.js convention so a single consumer can parse the verb's envelope without splitting across two streams. Advisory text (`[verb] hint: ...`) still goes to stderr.
38
+
39
+ ### Security
40
+
41
+ **`lib/sign.js` `generateKeypair()` ACL-hardening status surfaces in CLI output.** `restrictWindowsAcl()` now returns a boolean; the verdict line announces `Windows ACL hardened: yes|NO` rather than silently warning.
42
+
43
+ **`lib/cve-curation.js` + `lib/refresh-external.js` `writeJsonAtomic()` fsync before rename.** Pre-v0.13 a power loss between the tmp-write and the rename could leave the renamed destination zero-length / partial. The open + write + fsync + close + rename idiom closes the durability gap on both atomic-write helpers.
44
+
45
+ ### Features
46
+
47
+ **4 new playbooks expand the canonical set to 20.**
48
+ - `webhook-callback-abuse` — OAuth callback hijack, inbound-webhook signature validation, Slack/Teams/Discord webhook leakage, the Snowflake-class long-lived-callback-token-in-CI-log pattern.
49
+ - `cicd-pipeline-compromise` — self-hosted runner takeover, workflow-injection (the `${{ inputs.* }}` class), third-party Action SHA-pin discipline, OIDC trust-policy abuse, runner-scoped signing keys. Distinct from `sbom` (package-registry supply chain).
50
+ - `identity-sso-compromise` — in-progress IdP-plane detection (Salt Typhoon / Scattered Spider / Okta-2023 / golden-SAML / PRT theft patterns). Detect-side counterpart to the existing `idp-incident` (response playbook).
51
+ - `llm-tool-use-exfil` — agentic-AI tool abuse via prompt injection. Auto-approve-on-high-impact-tool, instruction-coercion grammar in tool responses, unprompted tool chains, credential-shadow in tool args. Distinct from `dlp-exfiltration` (enterprise DLP) and `mcp` (install-time tool trust).
52
+
53
+ Each new playbook carries `threat_currency_score >= 90`, full air-gap alternatives on look artifacts, substantive theater_test blocks on framework gaps, and `feeds_into[]` chains into the existing playbook set.
54
+
55
+ **Schema reverse fields populated across 3 catalogs + playbooks.**
56
+ - ATLAS TTPs now carry `cve_refs[]` (11 entries populated with 21 back-edges from `cve.atlas_refs`).
57
+ - ATT&CK techniques now carry `cve_refs[]` (20 entries populated with 56 back-edges from `cve.attack_refs`).
58
+ - Every playbook now carries `_meta.fed_by[]` (11 playbooks populated with 54 back-edges from `_meta.feeds_into[].playbook_id`). Operators reading a playbook can see what chains INTO it without grepping every other playbook.
59
+
60
+ `scripts/refresh-reverse-refs.js` extends to 8 reverse-direction passes (4 manifest-driven, 2 CVE-driven, 2 catalog-back-edge, 1 playbook-back-edge); `npm run refresh-reverse-refs` rebuilds the full set in one pass.
61
+
62
+ **`lib/scoring.js validate()` refuses mixed Shape A / Shape B factor sets.** The catalog historically stored `rwep_factors` in two distinct shapes (raw booleans + post-weight integers). Mixing shapes inside one entry silently broke the sum invariant — a CVE with `cisa_kev: true, blast_radius: 30` reported rwep 30 instead of the operator-intended 55. The new `detectFactorShape()` helper detects mixed entries and emits a structured error pointing at the affected CVE id.
63
+
64
+ **`lib/cross-ref-api.js` cache invalidation uses (mtime, size) tier.** Pre-v0.13 cache invalidation was mtime-only; on filesystems with 1-2s mtime granularity (FAT32, HFS+ pre-APFS, NFSv3, Docker bind-mounts that proxy mtime) a rapid refresh-then-reload within the same second served stale data. Adding `size` catches every content change that affects byte count.
65
+
66
+ **`lib/lint-skills.js` enforces `last_threat_review` staleness gate.** Warn at >180 days; hard fail at >365 days. Operators with stale skills get a structured warning naming the affected file + the exact day count; year-stale skills fail the lint outright. The forcing function for Hard Rule #8 (which was policy-only pre-v0.13).
67
+
68
+ **`scripts/refresh-sbom.js` produces a deterministic bundle.** `metadata.timestamp` and `serialNumber` are derived from the content-hash seed (`<name>@<version>@<bundleSha>`) instead of wall-clock. Identical content → identical SBOM across re-runs. The SBOM-currency predeploy gate can now rely on byte-identity for the no-change case.
69
+
70
+ **`exceptd doctor --fix` second remediation branch: post-rotate stale signatures.** Continues the v0.12.41 fix. When the private key IS present but the signatures check fails (the `generate-keypair --rotate` followup state), `doctor --fix` runs `sign-all` to re-sign skills + manifest against the current keypair. Without this branch the rotation flow would converge to a broken-but-not-self-healing state.
71
+
72
+ ### Bugs
73
+
74
+ **3 catalogs got `last_threat_review` fields backfilled.** `exploit-availability.json`, `global-frameworks.json`, `zeroday-lessons.json` carried `last_updated` but lacked the threat-review timestamp the other 8 catalogs use. All 11 now follow the same shape.
75
+
76
+ **`active_exploitation` field vocabulary now declared in `cve-catalog.json._meta`.** Pre-v0.13 the field accepted free-form values; 10 entries used `"unknown"` which wasn't documented. The new `_meta.active_exploitation_vocabulary` block enumerates `confirmed | suspected | theoretical | none | unknown` with per-value definitions.
77
+
78
+ **4 CVEs flipped `_draft: false` (verified).** `CVE-2024-3094` (xz-utils backdoor), `CVE-2024-21626` (Leaky Vessels), `CVE-2026-42945` (NGINX Rift), `MAL-2026-TANSTACK-MINI`. 1 quarantined (`MAL-2026-ANTHROPIC-MCP-STDIO` — duplicate of `CVE-2026-30623`). The remaining 15 draft CVEs are now marked with a structured `_draft_reason` ("blocked on missing zeroday-lessons entry" in all 14 cases except the GTIG embargoed placeholder).
79
+
80
+ **Hard Rule #5 regional-framework backfill on 7 skills.** `policy-exception-gen`, `compliance-theater`, `exploit-scoring`, `ai-c2-detection`, `ai-attack-surface`, `mcp-agent-trust`, `api-security` previously cited NIST without one or more of EU/UK/AU/ISO equivalents. Each now carries substantive references to NIS2/DORA/EU AI Act, NCSC CAF, ASD ISM/Essential 8, and ISO 27001:2022 controls as appropriate.
81
+
82
+ **39 of 42 skills got `data_deps` arrays regenerated** from body content references. Pre-v0.13 the array drifted whenever a skill body added or removed a `data/<file>.json` reference without the frontmatter being updated. `api-security` and `email-security-anti-phishing` ended up with empty `data_deps` — their bodies reference no catalog file by name; flagged for v0.14 body-content review.
83
+
84
+ **`scripts/refresh-reverse-refs.js` orphan detection caught 8 framework-gap forward-orphan references introduced by the Hard Rule #5 backfill.** `NIST-800-53-SC-39`, `ISO-27001-2022-A.8.22`, `CIS-Kubernetes-Benchmark-5.7`, `NIST-800-218-SSDF-PW.4`, `NIST-800-53-SR-3`, `SLSA-v1.0-Source-L3`, `NIST-AI-RMF-MAP-3.4`, `OWASP-Top-10-2021-A06`. These are real framework controls cited by the new skill content but absent from the gap catalog; tracked for v0.14 gap-catalog expansion.
85
+
86
+ ### Internal
87
+
88
+ - `lib/exit-codes.js` exports `safeExit(code)` — sets `process.exitCode` without calling `process.exit()`. Dispatch surface (`bin/exceptd.js`, `orchestrator/index.js`) converted from `process.exit(N)` to `safeExit(EXIT_CODES.X)` for non-zero codes; `tests/safe-exit-grep.test.js` refuses regressions.
89
+ - `validate-playbooks` predeploy gate flipped from informational to required. 20/20 playbooks validate cleanly.
90
+ - 7 new pinning tests in `tests/v0_12_41-fixes.test.js`, `tests/safe-exit-grep.test.js`, `tests/atlas-version-canonical.test.js`, `tests/operator-leak-grep.test.js`, `tests/verify-shipped-tarball-wrapper.test.js`.
91
+ - Test suite: 1179 total, 1173 pass, 6 skipped (POSIX-only / no-privkey gates), 0 fail.
92
+ - `release.yml` publish-job split (id-token:write vs contents:write separation) and `refresh.yml` split-checkout pattern remain in v0.14 backlog; they're workflow-security hardening with no operator-facing surface change.
93
+
3
94
  ## 0.12.41 — 2026-05-17
4
95
 
5
96
  Cross-domain hygiene pass: signature-regression class fix, sidecar hardening, attestation UX, ATLAS pin reconciliation, operator-narrative scrub, and structural test pins to lock the class fixes against future drift.
package/bin/exceptd.js CHANGED
@@ -207,31 +207,46 @@ function suggestVerb(cmd, known) {
207
207
  // v0.11.0 introduces: brief (collapses plan/govern/direct/look), discover (scan + dispatch),
208
208
  // doctor (currency + verify + validate-cves + validate-rfcs), ci (CI gate),
209
209
  // ai-run (streaming JSONL), ask (plain-English routing).
210
+ //
211
+ // v0.13.0 removed the v0.10.x phase-name aliases (plan, govern, direct,
212
+ // look, ingest). They were deprecation-bannered since v0.11.0 and
213
+ // slated-for-removal-in-v0.13 since v0.12.0; v0.13 honors that contract.
214
+ // REMOVED_VERBS below carries the rename map for operator-facing refusal
215
+ // hints. `reattest` and `list-attestations` are preserved as canonical
216
+ // routings — they're short forms of `attest diff` / `attest list` that
217
+ // remain operationally useful and have substantial test coverage.
210
218
  const PLAYBOOK_VERBS = new Set([
211
- // v0.11.0 canonical surface:
212
219
  "brief", "run", "ai-run", "attest", "discover", "doctor", "ci", "ask",
213
220
  "verify-attestation", "run-all", "lint",
214
- // v0.10.x legacy verbs — kept as aliases with deprecation banner, scheduled for removal in v0.13:
215
- "plan", "govern", "direct", "look", "ingest", "reattest", "list-attestations",
221
+ "reattest", "list-attestations",
216
222
  ]);
217
223
 
218
- // Map legacy verb names to their v0.11.0 replacement so the dispatcher can
219
- // emit a single deprecation banner per session.
220
- const LEGACY_VERB_REPLACEMENTS = {
224
+ // v0.13.0: hard-removed legacy verbs. The dispatcher refuses the verb
225
+ // with an actionable replacement hint instead of routing it. Pre-v0.13
226
+ // these were soft-deprecated (banner + still functional); v0.13 removes
227
+ // the routing entirely. Operators upgrading from v0.10.x → v0.13 see
228
+ // the same hint that the deprecation banner previously surfaced, but
229
+ // non-zero exit so scripts noticing pinned-name use fail loudly instead
230
+ // of silently invoking the alias.
231
+ const REMOVED_VERBS = {
221
232
  plan: "brief --all",
222
233
  govern: "brief <pb> --phase govern",
223
234
  direct: "brief <pb> --phase direct",
224
235
  look: "brief <pb> --phase look",
225
236
  ingest: "run",
226
- reattest: "attest diff",
227
- "list-attestations": "attest list",
237
+ };
238
+
239
+ // Renamed but functionally-routed verbs (orchestrator-side dispatch still
240
+ // handles them as of v0.13). Distinct from REMOVED_VERBS — these aren't
241
+ // refused; they're just a soft hint that the rename happened. No banner
242
+ // is emitted post-v0.13.
243
+ const RENAMED_VERBS_HINT = {
228
244
  scan: "discover --scan-only",
229
245
  dispatch: "discover",
230
246
  currency: "doctor --currency",
231
247
  verify: "doctor --signatures",
232
248
  "validate-cves": "doctor --cves",
233
249
  "validate-rfcs": "doctor --rfcs",
234
- watchlist: "watch",
235
250
  prefetch: "refresh --no-network",
236
251
  "build-indexes": "refresh --indexes-only",
237
252
  };
@@ -498,40 +513,23 @@ function main() {
498
513
  process.exit(0);
499
514
  }
500
515
 
501
- // v0.12.8: emit the deprecation banner BEFORE branching on PLAYBOOK_VERBS
502
- // so that legacy aliases routed through STANDALONE_VERBS or the orchestrator
503
- // (scan, dispatch, currency, verify, validate-cves, validate-rfcs,
504
- // watchlist, prefetch, build-indexes) also surface the rename.
505
- // Previously the banner only fired for PLAYBOOK_VERBS-resident aliases
506
- // (plan, govern, direct, look, ingest, reattest, list-attestations).
507
- if (LEGACY_VERB_REPLACEMENTS[cmd] && !process.env.EXCEPTD_DEPRECATION_SHOWN) {
508
- const ver = readPkgVersion();
509
- // Cycle 11 F7 (v0.12.32): persist the suppression across invocations via
510
- // an OS-tempdir marker keyed by exceptd version. Pre-fix the env-var
511
- // guard reset every fresh node process so operators saw the same banner
512
- // on every `exceptd plan` invocation, even after they'd already read it.
513
- // Per-version key means a new version (legitimate new content) shows the
514
- // banner once; subsequent runs within the same version stay quiet. The
515
- // explicit EXCEPTD_DEPRECATION_SHOWN=1 env-var opt-out still suppresses
516
- // even the first display, matching the documented contract.
517
- const markerDir = require("os").tmpdir();
518
- const markerFile = path.join(markerDir, `exceptd-deprecation-shown-v${ver}`);
519
- let alreadyShown = false;
520
- try { alreadyShown = fs.existsSync(markerFile); } catch { /* tmpdir unwritable; degrade to per-process */ }
521
- if (!alreadyShown) {
522
- const haveBrief = ver !== "unknown" && ver.match(/^(\d+)\.(\d+)/) && (parseInt(RegExp.$1, 10) > 0 || parseInt(RegExp.$2, 10) >= 11);
523
- process.stderr.write(
524
- `[exceptd] DEPRECATION: \`${cmd}\` is a v0.10.x verb. ` +
525
- (haveBrief
526
- ? `Prefer \`${LEGACY_VERB_REPLACEMENTS[cmd]}\` (available in this install, v${ver}). `
527
- : `Upgrade to v0.11.0+ then use \`${LEGACY_VERB_REPLACEMENTS[cmd]}\` (currently installed: v${ver}). `) +
528
- `Legacy verbs remain functional through this release; they will be removed in v0.13. ` +
529
- `This banner shows once per exceptd version per host (re-shown on upgrade). Permanent suppress: export EXCEPTD_DEPRECATION_SHOWN=1.\n`
530
- );
531
- try { fs.writeFileSync(markerFile, `shown_at=${new Date().toISOString()}\nversion=${ver}\n`, { mode: 0o600 }); }
532
- catch { /* tmpdir unwritable; the env-var guard below keeps the per-process suppression intact */ }
533
- }
534
- process.env.EXCEPTD_DEPRECATION_SHOWN = "1";
516
+ // v0.13.0: hard-refuse the v0.10.x legacy verbs that were
517
+ // deprecation-bannered since v0.11.0. Pre-v0.13 these silently routed
518
+ // to their v0.11+ replacements with a soft banner; v0.13 honors the
519
+ // long-advertised removal. Operators upgrading from v0.10.x get a
520
+ // structured error with the replacement command, suitable for
521
+ // grep / scripted handling.
522
+ if (REMOVED_VERBS[cmd]) {
523
+ emitError(
524
+ `'${cmd}' was removed in v0.13.0. Use \`exceptd ${REMOVED_VERBS[cmd]}\` instead.`,
525
+ {
526
+ verb: cmd,
527
+ removed_in: "0.13.0",
528
+ replacement: REMOVED_VERBS[cmd],
529
+ deprecation_history: "Deprecated in v0.11.0 with a soft banner; slated-for-removal-in-v0.13 announced in v0.12.0; removed in v0.13.0.",
530
+ }
531
+ );
532
+ return;
535
533
  }
536
534
 
537
535
  // Seven-phase playbook verbs run in-process — they emit JSON to stdout
@@ -714,6 +712,16 @@ function emit(obj, pretty, humanRenderer) {
714
712
  if (obj && obj.ok === false && !process.exitCode) {
715
713
  process.exitCode = EXIT_CODES.GENERIC_FAILURE;
716
714
  }
715
+ // v0.13.0 envelope harmonization: every emitted body has a top-level
716
+ // `ok` field — defaults to true when not set, matching the symmetric
717
+ // ok:false → exitCode=1 fallback above. Consumers that parse stdout
718
+ // can now assume the envelope shape regardless of which verb produced
719
+ // the body. Per-site `verb: "<name>"` is set at the call site; this
720
+ // helper guarantees the `ok` field's presence but does not synthesize
721
+ // verb (the caller knows its own name).
722
+ if (obj && typeof obj === 'object' && !('ok' in obj)) {
723
+ obj = { ok: true, ...obj };
724
+ }
717
725
  const wantJson = !!global.__exceptdWantJson || !!process.env.EXCEPTD_RAW_JSON;
718
726
  if (humanRenderer && !wantJson && !pretty) {
719
727
  process.stdout.write(humanRenderer(obj) + "\n");
@@ -4544,7 +4552,7 @@ function cmdAttest(runner, args, runOpts, pretty) {
4544
4552
  }
4545
4553
 
4546
4554
  if (subverb === "show") {
4547
- emit({ session_id: sessionId, attestations, attestation_replays: replays }, pretty);
4555
+ emit({ verb: "attest show", session_id: sessionId, attestations, attestation_replays: replays }, pretty);
4548
4556
  return;
4549
4557
  }
4550
4558
 
@@ -1,63 +1,63 @@
1
1
  {
2
2
  "schema_version": "1.1.0",
3
- "generated_at": "2026-05-17T20:21:35.517Z",
3
+ "generated_at": "2026-05-17T23:47:25.094Z",
4
4
  "generator": "scripts/build-indexes.js",
5
5
  "source_count": 54,
6
6
  "source_hashes": {
7
- "manifest.json": "adcee350ac3e4ffc9a6edd5003735df10503bffcd7474e298d1ecddb1e948224",
8
- "data/atlas-ttps.json": "259e76e4252c7a56c17bbe96982a5e37ac89131c2d37a547fe38d64dcacfd763",
9
- "data/attack-techniques.json": "51f60819aef36e960fd768e44dcc725e137781534fbbb028e5ef6baa21defa1d",
10
- "data/cve-catalog.json": "415384660f879d26491a612e579943092135acb676cbb95327f309c921ff69ed",
11
- "data/cwe-catalog.json": "6e7349a0fac39bdf9c4cb4598e101e51400f67d64c5d653bbca462f28bc1a0cb",
7
+ "manifest.json": "e4db72d2b307adb316fad1af15322392587c50c4de5b7592c015b93631f6f26b",
8
+ "data/atlas-ttps.json": "1301e6d053be91ac41ec38e64c72ac726e478b7fd6482884c3e2219c8fa16173",
9
+ "data/attack-techniques.json": "4afc226cc7359771a54aab1a1ff53c5530d1ef54eabc1d2fbd3b1caeda2f64a6",
10
+ "data/cve-catalog.json": "d4d2ecc24a0b010d5e83fea9850130278bea120ef130c99dcbb03eff64008f2d",
11
+ "data/cwe-catalog.json": "7a8e01c6f5538125b81ddb29f1b658f0fd407682bc2998aafc6b759e3b1afe48",
12
12
  "data/d3fend-catalog.json": "a1fc2827ceb344669e148d55197dbf1b0e5b20bcc618e90517639c17d67ee82d",
13
13
  "data/dlp-controls.json": "d2406c482dddd30e49203879999dc4b3a7fd4d0494d6a61d86b91ee76415df19",
14
14
  "data/exploit-availability.json": "003a400f5ae5b15527589571679ccdb9b3a62e60073627b5fbdeb2a9fe330a7a",
15
- "data/framework-control-gaps.json": "45d4b461a733fc31ce5a02b0462d0e23aa5d7469d937d77ad69417eb5293f189",
15
+ "data/framework-control-gaps.json": "2c37446ad38270ebe51c0eaf340b26f19367c4eae47886d6310f16a4185354bf",
16
16
  "data/global-frameworks.json": "9ba563a85f7f8d6c3c957de64945e20925a89d0ed6ea6fc561cf093811acf558",
17
17
  "data/rfc-references.json": "e253a548c8a829d178d5aea601e268724b85c936ccbfa51c2e5d80c5f8efe2b0",
18
18
  "data/zeroday-lessons.json": "27d46a0e09a3edbe97dfbb070c3991348567cf93c86a3e94c767c5ad2dfb653e",
19
- "skills/kernel-lpe-triage/skill.md": "8e94bfd38d6db47342fbbe95a0c8df8f7c38743982c13e9de6a1c59cd3783d33",
20
- "skills/ai-attack-surface/skill.md": "853ea46b500fa60b5f5db1137629f8b64447b5df2c8346c15c6cbd1e59285532",
21
- "skills/mcp-agent-trust/skill.md": "b09a33e71a0cc13ec70e7e750ac4b91887b657d293d92c3cdb49a4e094adcfea",
22
- "skills/framework-gap-analysis/skill.md": "4994b47c2618d24e5557f2a23de21960f6f12a6d66d1b8780b4de6d9d3735dfe",
23
- "skills/compliance-theater/skill.md": "5fa6207256d002c42a28a90d15b9a9ef0503ae7dba9b55b4098e2e52607377f4",
24
- "skills/exploit-scoring/skill.md": "91bab353257383bd21e49005c1c8188b98b46642184dea29729ad45fc732d698",
25
- "skills/rag-pipeline-security/skill.md": "96d26b90539bda836032c2fc2935e0d5736f40bcd286165979c0ed34f47f3ce6",
26
- "skills/ai-c2-detection/skill.md": "4f986ac65d4cba36ef9173d204acaf81646a9f7c42623ebba0973ea0108133c0",
27
- "skills/policy-exception-gen/skill.md": "78a8623700eab1801387e4792611529089b6248ff3faef15d70c0093609ec323",
28
- "skills/threat-model-currency/skill.md": "9fcddaa06334d104cb160bace92c92cdcb6b2881f579b82970e42fbd3d213a05",
29
- "skills/global-grc/skill.md": "e0487de49679172347653d8c191d1f269193de6f444f6b0c6396d326e45bd72e",
19
+ "skills/kernel-lpe-triage/skill.md": "ae4a0af924d0078ffc6cd051a3ef9fce75a6a3f9c0c15d1c07900ae5faf80502",
20
+ "skills/ai-attack-surface/skill.md": "dcca7d92a1ab4d1e4c46356b614a138b1c1f79b65a6a290eccf2095d8d443993",
21
+ "skills/mcp-agent-trust/skill.md": "6821f6d38f6e23bbed953f8f86a279597b0b95a2d0548b5383e851bca7442531",
22
+ "skills/framework-gap-analysis/skill.md": "3b139eaefbedd36b2379cfe22dceef71e97d0e34404b0009b7afbfe0a8dc39e6",
23
+ "skills/compliance-theater/skill.md": "a1387c523f7aa2481a199f6288e0152b94aa5a6644600eb39dbb3ea9ee9af6bd",
24
+ "skills/exploit-scoring/skill.md": "fba9e27722d361cc6ed5992d9aaeaa397598b417fc5a0d6fe0bee2993942e7e8",
25
+ "skills/rag-pipeline-security/skill.md": "ff07e48918090247aef71def4150b0df372a24bcdaa34eb6e11d246b9e71e1ee",
26
+ "skills/ai-c2-detection/skill.md": "3da9f549f5c62e6163cddd70c8edccbef7be622d5a45fa89c90c6550e68c6b2e",
27
+ "skills/policy-exception-gen/skill.md": "a7d886f7fa99a150b040f158b09045ba45e107439315389aea785311b0013395",
28
+ "skills/threat-model-currency/skill.md": "ecc6441cb47ef2bc24547e47be018098228c956a41d61ddb50de7e7b37114a37",
29
+ "skills/global-grc/skill.md": "1dca534cce7612c1d26a7b1bfd088a811081555ecfa25b1f68cff2ca2ba28c98",
30
30
  "skills/zeroday-gap-learn/skill.md": "59a0d7cd85b923b3f5633bdc15c1a88eef7dea6332480d93b0bb0ae93a4cd0fe",
31
- "skills/pqc-first/skill.md": "a5eb776e1ea3bb422a4c18a3bdf39ad2ec1651b3c25e65c89428ba319141b275",
32
- "skills/skill-update-loop/skill.md": "0d5b08f71e4853a634344eaf260da90bd7a29d4df48200ee75be878dce3467e2",
33
- "skills/security-maturity-tiers/skill.md": "2027161ab0a3382ba506cca7be1966e11367bbdf861de316facd54e25fef5761",
34
- "skills/researcher/skill.md": "51d03d9eaea52d2bbbdd67709035db494d44819ce58931ca025cab3025c9fad7",
35
- "skills/attack-surface-pentest/skill.md": "9cb02d9d428ef674ba8af8c935f86ddca197f0ba1f7d216d76ce1b268ae4bb6a",
36
- "skills/fuzz-testing-strategy/skill.md": "eaab866236c8cb8a6c8ddc5e65d786ee6d598682de6014ed4e83c6cd163a2128",
37
- "skills/dlp-gap-analysis/skill.md": "ee9fd4928d96b2e9957d8db9dec90c844443fbcf2a292e69040bfa47c78a4f4b",
38
- "skills/supply-chain-integrity/skill.md": "497f1ef20f3e506ce1bec5ec65730ffc58300054ff3e8e563e0862838164491a",
31
+ "skills/pqc-first/skill.md": "a7131b65d0ceee47887b16679ee4e4b065d32d8751fe59921762388703662913",
32
+ "skills/skill-update-loop/skill.md": "cf2b996cb18a5146614c06e3a50f4734a07d02b5be36bbdf492583f9cdcfed4d",
33
+ "skills/security-maturity-tiers/skill.md": "ed962937c45f3d95f325f231b787d272fe45c4cb91d4c5a2d982493d722c2acf",
34
+ "skills/researcher/skill.md": "b47daaa26fdac07aa23e7becaa18487c5302e65c654f99fecab3689f23ec1bd2",
35
+ "skills/attack-surface-pentest/skill.md": "0d301beb9fb8e247ec80256a7e647804b5f9a41c7156e5724555ca9f93ccb986",
36
+ "skills/fuzz-testing-strategy/skill.md": "51acb746cd63366ca62567588c700a9eb3f37c43250bd9ae4e1477ccb71c5b6d",
37
+ "skills/dlp-gap-analysis/skill.md": "1c4e1d7da2421b82f202eaf2c9e21876af34ab5c76ce1359166842ee473f02dd",
38
+ "skills/supply-chain-integrity/skill.md": "ad69b72f5c5df095f8618b977fbc8f0fbff396eebd4a8448b44c3f93309f63f9",
39
39
  "skills/defensive-countermeasure-mapping/skill.md": "e62c71ba3be2b4d0f7dfa529fec007cba6bee3013f76b93756e3e6310f2d22ab",
40
- "skills/identity-assurance/skill.md": "6fd734d5cf8eed031537c9ccb1ad11c09ec4e88d31c45d86046a2154a6770990",
41
- "skills/ot-ics-security/skill.md": "258003e15bd4e939a1ec1f71c22ffa4dccd6d3194411281f4685abfe840d7cd3",
40
+ "skills/identity-assurance/skill.md": "4ee7096fd82997c66b0f9e825ea3c04c3aa84768b74e6f668c1a9104104138cf",
41
+ "skills/ot-ics-security/skill.md": "9ece7b1fb7f24e37dbdd8618b94b2a4434e182e3426e15f17e26464c0a1fdfd1",
42
42
  "skills/coordinated-vuln-disclosure/skill.md": "0e875953bb8a38a89c8ec5d2a9ef967b12e9a9f166dc9356723f10304fd0535e",
43
- "skills/threat-modeling-methodology/skill.md": "bb34933a1eee2cd1da98da5a5dada2c7fc7ebb0bddf5afb39e1f6ee26064d151",
44
- "skills/webapp-security/skill.md": "6fdae41856963df0f8655fb52df7cd26b6b47031f55dfe897003ed9647a73ab5",
45
- "skills/ai-risk-management/skill.md": "10d31ca594449e1fef4c34ea45448ab30a6ffdc2fe1faf4ccaf0a1dd05d67774",
46
- "skills/sector-healthcare/skill.md": "217066e5961fbc3fcd1b5e3df42f299d7aeaf3b5f25e913152836b77f211f96d",
47
- "skills/sector-financial/skill.md": "77f6355eb7672f2157bf3d18bfe1d6042efe302468ebddd48ffc385655bf4d10",
48
- "skills/sector-federal-government/skill.md": "981bd7aea1b3ba7875d1222f077126d4eb9462bed46e3e6f5cfed5f94378b152",
49
- "skills/sector-energy/skill.md": "44b635b9c52bb10ee2f8d786400926e018c7581387324f59ee3a815de4929c9c",
50
- "skills/sector-telecom/skill.md": "3489410b0905cbf6b392ea7f7cde35ccd4b03de0d22d2d1b0c671e46d70962c9",
51
- "skills/api-security/skill.md": "75dcb1b9395de2be4ca60e53f900692721b7ef66ded3e510a20d17f35daf982d",
52
- "skills/cloud-security/skill.md": "56f0d5d6cf182d347e84baa95a04c39be51e82da3360dac48fcf5d8c4e56a9c3",
53
- "skills/container-runtime-security/skill.md": "7e0806b9e13db120f9b65d5f48b33db9f1026c4c2d719838ef0f0c8778ec4365",
54
- "skills/mlops-security/skill.md": "a7bf448527e15bb0c6936217c69f3e18cc823f534e0c7f749966cde32039c63e",
55
- "skills/incident-response-playbook/skill.md": "0695ee43881527459f657a90276748922347f16dd494ae2b98e2a9396c570a44",
56
- "skills/ransomware-response/skill.md": "15de039c5679215b7ceb9a55494f614b06fe618aa0f69ce8aff004dc9a841fa4",
57
- "skills/email-security-anti-phishing/skill.md": "b5a7693b3ddbd6cd83303d092bc5e324db431245d25c4945d9f65fcffa1995e7",
58
- "skills/age-gates-child-safety/skill.md": "66c7f6537077e4e949214ebf3864cb75de0f50f80fa25d25365c6d7fe485dc7a",
59
- "skills/cloud-iam-incident/skill.md": "f124d1170cffb490ddd093ad6fc9876591515643fb2f51379023a08548c7290d",
60
- "skills/idp-incident-response/skill.md": "3d75d7a0fc5b9a3c584ac5c6510f8b6bd63b7b780488541eb193250ae795b4e2"
43
+ "skills/threat-modeling-methodology/skill.md": "ac623f61585de66c9ef5ed63e9c6059faef77e525abc672ac6d435c616a7268f",
44
+ "skills/webapp-security/skill.md": "fdb07324b69a3a724e3eaba17bf687d72d4bd9d5c4f440be816bc9b08b8aef04",
45
+ "skills/ai-risk-management/skill.md": "67e62791f60231f2ff53408922fa7137a9060de72097769c630f838a1c227c45",
46
+ "skills/sector-healthcare/skill.md": "a18e11d25524cdbf40df3798f4c2aa3cb51a4db1b088242ea53fa2885e86b64c",
47
+ "skills/sector-financial/skill.md": "023b5440d614e6b83ba7294219bcac3cdbffd28fdfdd5f0ec23abbeea71b8230",
48
+ "skills/sector-federal-government/skill.md": "c63cf1c7c98e920f968cfe60f14e718ea71b120c1b01616af22f64a796963bbe",
49
+ "skills/sector-energy/skill.md": "643fd951359c2602d9b029a244fe66c1e23f726e711141a06c09cc760a479534",
50
+ "skills/sector-telecom/skill.md": "862f9482af88e5409e011a6981a5d719863deeb646e41cd4df63e5d6597c50b1",
51
+ "skills/api-security/skill.md": "2bdfa3dbe534efa3df245e0da37998ad7ab2da4a3171d5000d3346513c10bceb",
52
+ "skills/cloud-security/skill.md": "c9fad9ed3663cf2faec74ad8f06d62eb86e6636f79933560d8c8d50e0e82d1da",
53
+ "skills/container-runtime-security/skill.md": "605a8e8eb1af09835b967ec7179456015ec116c6b9051af3a8d225866cc2f7af",
54
+ "skills/mlops-security/skill.md": "ca3fd922b43fc57aeb5e65c2d5a2823e6bc438167d6afa3a767cee83e4af1f96",
55
+ "skills/incident-response-playbook/skill.md": "2017515d899c1b2bcb878bc6731e4059623ac52345b2cebbd92204583657bf60",
56
+ "skills/ransomware-response/skill.md": "2e4fc488f86ed1ba7791ab0e7021160d8ca5ad33a02cdf92a5b916c8afecaa54",
57
+ "skills/email-security-anti-phishing/skill.md": "e4e9e5a820c0ed3fde9483282e7a0ecaf79284cd2e9923ce66f2b0fb1fc44626",
58
+ "skills/age-gates-child-safety/skill.md": "66e7773d29c179ab62f409007c05e05993e04a19273225a1e520f2481fd9a90d",
59
+ "skills/cloud-iam-incident/skill.md": "6494ee3856edeb212e65fe5cdb208357c1a832eb8ac374b26055586bfc71f629",
60
+ "skills/idp-incident-response/skill.md": "e67a2576e7f1c3bf89f499f5c977bc470ef29e8b3e3e45f4cb5bd45a82674282"
61
61
  },
62
62
  "skill_count": 42,
63
63
  "catalog_count": 11,
@@ -78,7 +78,7 @@
78
78
  "handoff_dag_nodes": 42,
79
79
  "summary_cards": 42,
80
80
  "section_offsets_skills": 42,
81
- "token_budget_total_approx": 397775,
81
+ "token_budget_total_approx": 402643,
82
82
  "recipes": 8,
83
83
  "jurisdiction_clocks": 29,
84
84
  "did_ladders": 8,