infernoflow 0.32.8 → 0.32.9

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 (78) hide show
  1. package/dist/bin/infernoflow.mjs +84 -255
  2. package/dist/lib/adopters/angular.mjs +1 -128
  3. package/dist/lib/adopters/css.mjs +1 -111
  4. package/dist/lib/adopters/react.mjs +1 -104
  5. package/dist/lib/ai/ideDetection.mjs +1 -31
  6. package/dist/lib/ai/localProvider.mjs +1 -88
  7. package/dist/lib/ai/providerRouter.mjs +2 -295
  8. package/dist/lib/commands/adopt.mjs +20 -869
  9. package/dist/lib/commands/adoptWizard.mjs +9 -320
  10. package/dist/lib/commands/agent.mjs +5 -191
  11. package/dist/lib/commands/ai.mjs +2 -407
  12. package/dist/lib/commands/audit.mjs +13 -300
  13. package/dist/lib/commands/changelog.mjs +26 -594
  14. package/dist/lib/commands/check.mjs +3 -184
  15. package/dist/lib/commands/ci.mjs +3 -208
  16. package/dist/lib/commands/claudeMd.mjs +25 -130
  17. package/dist/lib/commands/cloud.mjs +5 -521
  18. package/dist/lib/commands/context.mjs +31 -287
  19. package/dist/lib/commands/coverage.mjs +2 -282
  20. package/dist/lib/commands/dashboard.mjs +123 -635
  21. package/dist/lib/commands/demo.mjs +8 -465
  22. package/dist/lib/commands/diff.mjs +5 -274
  23. package/dist/lib/commands/docGate.mjs +2 -81
  24. package/dist/lib/commands/doctor.mjs +3 -321
  25. package/dist/lib/commands/explain.mjs +8 -438
  26. package/dist/lib/commands/export.mjs +10 -239
  27. package/dist/lib/commands/generateSkills.mjs +38 -163
  28. package/dist/lib/commands/graph.mjs +203 -321
  29. package/dist/lib/commands/health.mjs +2 -309
  30. package/dist/lib/commands/impact.mjs +2 -325
  31. package/dist/lib/commands/implement.mjs +7 -103
  32. package/dist/lib/commands/init.mjs +23 -475
  33. package/dist/lib/commands/installCursorHooks.mjs +1 -36
  34. package/dist/lib/commands/installVsCodeCopilotHooks.mjs +1 -37
  35. package/dist/lib/commands/link.mjs +2 -342
  36. package/dist/lib/commands/monorepo.mjs +4 -428
  37. package/dist/lib/commands/notify.mjs +4 -258
  38. package/dist/lib/commands/onboard.mjs +4 -296
  39. package/dist/lib/commands/prComment.mjs +2 -361
  40. package/dist/lib/commands/prImpact.mjs +2 -157
  41. package/dist/lib/commands/publish.mjs +15 -316
  42. package/dist/lib/commands/report.mjs +28 -272
  43. package/dist/lib/commands/review.mjs +9 -223
  44. package/dist/lib/commands/run.mjs +8 -336
  45. package/dist/lib/commands/scaffold.mjs +54 -419
  46. package/dist/lib/commands/scan.mjs +5 -558
  47. package/dist/lib/commands/scout.mjs +2 -291
  48. package/dist/lib/commands/setup.mjs +5 -310
  49. package/dist/lib/commands/share.mjs +13 -196
  50. package/dist/lib/commands/snapshot.mjs +3 -383
  51. package/dist/lib/commands/stability.mjs +2 -293
  52. package/dist/lib/commands/status.mjs +4 -172
  53. package/dist/lib/commands/suggest.mjs +21 -563
  54. package/dist/lib/commands/syncAuto.mjs +1 -96
  55. package/dist/lib/commands/synthesize.mjs +10 -228
  56. package/dist/lib/commands/teamSync.mjs +2 -388
  57. package/dist/lib/commands/test.mjs +6 -363
  58. package/dist/lib/commands/version.mjs +2 -282
  59. package/dist/lib/commands/vibe.mjs +7 -357
  60. package/dist/lib/commands/watch.mjs +4 -203
  61. package/dist/lib/commands/why.mjs +4 -358
  62. package/dist/lib/cursorHooksInstall.mjs +1 -60
  63. package/dist/lib/draftToolingInstall.mjs +7 -68
  64. package/dist/lib/git/detect-drift.mjs +4 -208
  65. package/dist/lib/learning/adapt.mjs +6 -101
  66. package/dist/lib/learning/observe.mjs +1 -119
  67. package/dist/lib/learning/patternDetector.mjs +1 -298
  68. package/dist/lib/learning/profile.mjs +2 -279
  69. package/dist/lib/learning/skillSynthesizer.mjs +24 -145
  70. package/dist/lib/templates/index.mjs +1 -131
  71. package/dist/lib/ui/errors.mjs +1 -142
  72. package/dist/lib/ui/output.mjs +6 -72
  73. package/dist/lib/ui/prompts.mjs +6 -147
  74. package/dist/lib/vsCodeCopilotHooksInstall.mjs +1 -42
  75. package/dist/templates/cursor/inferno-mcp-server.mjs +29 -0
  76. package/dist/templates/github-app/GITHUB_APP.md +67 -0
  77. package/dist/templates/github-app/app-manifest.json +20 -0
  78. package/package.json +1 -1
@@ -1,204 +1,6 @@
1
- /**
2
- * infernoflow audit
3
- *
4
- * Classify capabilities by security sensitivity and generate a surface map.
5
- * Tags each capability with one or more sensitivity labels:
6
- * auth — authentication / authorization / sessions / tokens
7
- * payment — billing, subscriptions, pricing, invoices
8
- * pii — personal data, email, address, phone, GDPR scope
9
- * admin — privileged operations, configuration, user management
10
- * public — read-only, no auth required
11
- *
12
- * Stores results in inferno/audit.json (git-trackable).
13
- *
14
- * Usage:
15
- * infernoflow audit Run audit, print summary
16
- * infernoflow audit --format json Machine-readable JSON to stdout
17
- * infernoflow audit --format html Write HTML report
18
- * infernoflow audit --out audit.html Custom output path
19
- * infernoflow audit --fail-on high Exit 1 if any HIGH caps are unreviewed
20
- * infernoflow audit --json Alias for --format json
21
- */
22
-
23
- import * as fs from "node:fs";
24
- import * as path from "node:path";
25
- import { done, warn, info, bold, cyan, gray, green, yellow, red } from "../ui/output.mjs";
26
-
27
- const AUDIT_FILE = "audit.json";
28
-
29
- // ── Sensitivity keyword maps ──────────────────────────────────────────────────
30
-
31
- const SENSITIVITY_RULES = [
32
- {
33
- tag: "auth",
34
- severity: "high",
35
- label: "Authentication / Authorization",
36
- keywords: [
37
- "auth", "login", "logout", "signin", "signout", "signup",
38
- "password", "credential", "token", "session", "oauth",
39
- "jwt", "permission", "role", "access", "privilege", "2fa",
40
- "mfa", "sso", "saml", "openid", "verify", "authenticate",
41
- ],
42
- },
43
- {
44
- tag: "payment",
45
- severity: "high",
46
- label: "Payment / Billing",
47
- keywords: [
48
- "payment", "billing", "invoice", "charge", "subscription",
49
- "checkout", "stripe", "card", "credit", "debit", "price",
50
- "plan", "tier", "coupon", "refund", "transaction", "purchase",
51
- "order", "cart", "paypal", "wallet",
52
- ],
53
- },
54
- {
55
- tag: "pii",
56
- severity: "high",
57
- label: "Personal / PII Data",
58
- keywords: [
59
- "pii", "personal", "profile", "email", "phone", "address",
60
- "name", "user", "account", "gdpr", "privacy", "data",
61
- "export", "download", "delete account", "identity", "dob",
62
- "birthday", "ssn", "passport", "tax",
63
- ],
64
- },
65
- {
66
- tag: "admin",
67
- severity: "medium",
68
- label: "Admin / Privileged",
69
- keywords: [
70
- "admin", "manage", "config", "setting", "system", "deploy",
71
- "migration", "seed", "reset", "purge", "archive", "batch",
72
- "bulk", "impersonate", "override", "feature flag",
73
- ],
74
- },
75
- {
76
- tag: "public",
77
- severity: "low",
78
- label: "Public / Read-only",
79
- keywords: [
80
- "list", "search", "view", "read", "fetch", "get", "show",
81
- "display", "browse", "filter", "sort", "paginate",
82
- ],
83
- },
84
- ];
85
-
86
- const SEVERITY_ORDER = { high: 3, medium: 2, low: 1, unknown: 0 };
87
-
88
- // ── Classification ────────────────────────────────────────────────────────────
89
-
90
- function classifyCapability(cap) {
91
- const text = [
92
- typeof cap === "string" ? cap : "",
93
- cap?.id || "",
94
- cap?.name || "",
95
- cap?.description || "",
96
- (cap?.tags || []).join(" "),
97
- ].join(" ").toLowerCase();
98
-
99
- const matched = [];
100
- for (const rule of SENSITIVITY_RULES) {
101
- if (rule.keywords.some(kw => text.includes(kw))) {
102
- matched.push(rule);
103
- }
104
- }
105
-
106
- // Remove "public" if any higher-severity tag also matched
107
- const hasHigher = matched.some(r => r.tag !== "public" && r.severity !== "low");
108
- const filtered = hasHigher ? matched.filter(r => r.tag !== "public") : matched;
109
-
110
- if (!filtered.length) {
111
- return { tags: ["unknown"], severity: "unknown", labels: ["Unclassified"] };
112
- }
113
-
114
- const severity = filtered.reduce((best, r) => {
115
- return SEVERITY_ORDER[r.severity] > SEVERITY_ORDER[best] ? r.severity : best;
116
- }, "low");
117
-
118
- return {
119
- tags: filtered.map(r => r.tag),
120
- severity,
121
- labels: filtered.map(r => r.label),
122
- };
123
- }
124
-
125
- // ── Storage ───────────────────────────────────────────────────────────────────
126
-
127
- function readAudit(infernoDir) {
128
- const p = path.join(infernoDir, AUDIT_FILE);
129
- if (!fs.existsSync(p)) return {};
130
- try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch { return {}; }
131
- }
132
-
133
- function writeAudit(infernoDir, data) {
134
- fs.writeFileSync(path.join(infernoDir, AUDIT_FILE), JSON.stringify(data, null, 2) + "\n");
135
- }
136
-
137
- function readContract(infernoDir) {
138
- for (const f of ["contract.json", "capabilities.json"]) {
139
- const p = path.join(infernoDir, f);
140
- if (fs.existsSync(p)) {
141
- try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch {}
142
- }
143
- }
144
- return null;
145
- }
146
-
147
- // ── Formatters ────────────────────────────────────────────────────────────────
148
-
149
- function severityColor(sev) {
150
- if (sev === "high") return red;
151
- if (sev === "medium") return yellow;
152
- if (sev === "low") return green;
153
- return gray;
154
- }
155
-
156
- function severityIcon(sev) {
157
- if (sev === "high") return "🔴";
158
- if (sev === "medium") return "🟡";
159
- if (sev === "low") return "🟢";
160
- return "⚪";
161
- }
162
-
163
- function printTextReport(results, stats) {
164
- const bySeverity = { high: [], medium: [], low: [], unknown: [] };
165
- for (const r of results) (bySeverity[r.severity] || bySeverity.unknown).push(r);
166
-
167
- console.log();
168
- console.log(` ${bold("🔥 infernoflow audit — Security Surface Map")}`);
169
- console.log();
170
- console.log(` ${bold(String(results.length))} capabilities scanned`);
171
- console.log(` ${red(String(stats.high))} high · ${yellow(String(stats.medium))} medium · ${green(String(stats.low))} low · ${gray(String(stats.unknown))} unclassified`);
172
- console.log();
173
-
174
- for (const [sev, items] of Object.entries(bySeverity)) {
175
- if (!items.length) continue;
176
- const col = severityColor(sev);
177
- console.log(` ${col(bold(`${sev.toUpperCase()} (${items.length})`))}`);
178
- for (const item of items) {
179
- const tagStr = item.tags.join(", ");
180
- console.log(` ${col("▸")} ${bold(item.id.padEnd(30))} ${gray(tagStr)}`);
181
- if (item.description) console.log(` ${gray(item.description.slice(0, 72))}`);
182
- }
183
- console.log();
184
- }
185
-
186
- if (stats.unknown > 0) {
187
- console.log(` ${gray("Tip: Add descriptions to unclassified capabilities for better detection.")}`);
188
- console.log();
189
- }
190
- }
191
-
192
- function buildHtmlReport(results, stats, runAt) {
193
- const rows = results.map(r => {
194
- const sev = r.severity;
195
- const cls = sev === "high" ? "high" : sev === "medium" ? "med" : sev === "low" ? "low" : "unk";
196
- const tags = r.tags.join(", ");
197
- const icon = severityIcon(sev);
198
- return `<tr class="${cls}"><td>${icon} ${sev}</td><td><strong>${escHtml(r.id)}</strong></td><td>${escHtml(tags)}</td><td>${escHtml(r.description || "")}</td></tr>`;
199
- }).join("\n");
200
-
201
- return `<!DOCTYPE html>
1
+ import*as d from"node:fs";import*as u from"node:path";import{done as I,warn as N,bold as g,gray as m,green as T,yellow as C,red as b}from"../ui/output.mjs";const x="audit.json",A=[{tag:"auth",severity:"high",label:"Authentication / Authorization",keywords:["auth","login","logout","signin","signout","signup","password","credential","token","session","oauth","jwt","permission","role","access","privilege","2fa","mfa","sso","saml","openid","verify","authenticate"]},{tag:"payment",severity:"high",label:"Payment / Billing",keywords:["payment","billing","invoice","charge","subscription","checkout","stripe","card","credit","debit","price","plan","tier","coupon","refund","transaction","purchase","order","cart","paypal","wallet"]},{tag:"pii",severity:"high",label:"Personal / PII Data",keywords:["pii","personal","profile","email","phone","address","name","user","account","gdpr","privacy","data","export","download","delete account","identity","dob","birthday","ssn","passport","tax"]},{tag:"admin",severity:"medium",label:"Admin / Privileged",keywords:["admin","manage","config","setting","system","deploy","migration","seed","reset","purge","archive","batch","bulk","impersonate","override","feature flag"]},{tag:"public",severity:"low",label:"Public / Read-only",keywords:["list","search","view","read","fetch","get","show","display","browse","filter","sort","paginate"]}],p={high:3,medium:2,low:1,unknown:0};function R(o){const t=[typeof o=="string"?o:"",o?.id||"",o?.name||"",o?.description||"",(o?.tags||[]).join(" ")].join(" ").toLowerCase(),n=[];for(const e of A)e.keywords.some(l=>t.includes(l))&&n.push(e);const s=n.some(e=>e.tag!=="public"&&e.severity!=="low")?n.filter(e=>e.tag!=="public"):n;if(!s.length)return{tags:["unknown"],severity:"unknown",labels:["Unclassified"]};const r=s.reduce((e,l)=>p[l.severity]>p[e]?l.severity:e,"low");return{tags:s.map(e=>e.tag),severity:r,labels:s.map(e=>e.label)}}function _(o){const t=u.join(o,x);if(!d.existsSync(t))return{};try{return JSON.parse(d.readFileSync(t,"utf8"))}catch{return{}}}function H(o,t){d.writeFileSync(u.join(o,x),JSON.stringify(t,null,2)+`
2
+ `)}function P(o){for(const t of["contract.json","capabilities.json"]){const n=u.join(o,t);if(d.existsSync(n))try{return JSON.parse(d.readFileSync(n,"utf8"))}catch{}}return null}function U(o){return o==="high"?b:o==="medium"?C:o==="low"?T:m}function F(o){return o==="high"?"\u{1F534}":o==="medium"?"\u{1F7E1}":o==="low"?"\u{1F7E2}":"\u26AA"}function J(o,t){const n={high:[],medium:[],low:[],unknown:[]};for(const c of o)(n[c.severity]||n.unknown).push(c);console.log(),console.log(` ${g("\u{1F525} infernoflow audit \u2014 Security Surface Map")}`),console.log(),console.log(` ${g(String(o.length))} capabilities scanned`),console.log(` ${b(String(t.high))} high \xB7 ${C(String(t.medium))} medium \xB7 ${T(String(t.low))} low \xB7 ${m(String(t.unknown))} unclassified`),console.log();for(const[c,s]of Object.entries(n)){if(!s.length)continue;const r=U(c);console.log(` ${r(g(`${c.toUpperCase()} (${s.length})`))}`);for(const e of s){const l=e.tags.join(", ");console.log(` ${r("\u25B8")} ${g(e.id.padEnd(30))} ${m(l)}`),e.description&&console.log(` ${m(e.description.slice(0,72))}`)}console.log()}t.unknown>0&&(console.log(` ${m("Tip: Add descriptions to unclassified capabilities for better detection.")}`),console.log())}function z(o,t,n){const c=o.map(s=>{const r=s.severity,e=r==="high"?"high":r==="medium"?"med":r==="low"?"low":"unk",l=s.tags.join(", "),y=F(r);return`<tr class="${e}"><td>${y} ${r}</td><td><strong>${k(s.id)}</strong></td><td>${k(l)}</td><td>${k(s.description||"")}</td></tr>`}).join(`
3
+ `);return`<!DOCTYPE html>
202
4
  <html lang="en">
203
5
  <head>
204
6
  <meta charset="UTF-8">
@@ -226,110 +28,21 @@ function buildHtmlReport(results, stats, runAt) {
226
28
  </style>
227
29
  </head>
228
30
  <body>
229
- <h1>🔥 infernoflow audit</h1>
230
- <p class="meta">Generated ${runAt}</p>
31
+ <h1>\u{1F525} infernoflow audit</h1>
32
+ <p class="meta">Generated ${n}</p>
231
33
  <div class="stats">
232
- <div class="stat high"><div class="n">${stats.high}</div><div class="l">HIGH</div></div>
233
- <div class="stat med"><div class="n">${stats.medium}</div><div class="l">MEDIUM</div></div>
234
- <div class="stat low"><div class="n">${stats.low}</div><div class="l">LOW</div></div>
235
- <div class="stat unk"><div class="n">${stats.unknown}</div><div class="l">UNKNOWN</div></div>
34
+ <div class="stat high"><div class="n">${t.high}</div><div class="l">HIGH</div></div>
35
+ <div class="stat med"><div class="n">${t.medium}</div><div class="l">MEDIUM</div></div>
36
+ <div class="stat low"><div class="n">${t.low}</div><div class="l">LOW</div></div>
37
+ <div class="stat unk"><div class="n">${t.unknown}</div><div class="l">UNKNOWN</div></div>
236
38
  </div>
237
39
  <table>
238
40
  <thead><tr><th>Severity</th><th>Capability</th><th>Tags</th><th>Description</th></tr></thead>
239
41
  <tbody>
240
- ${rows}
42
+ ${c}
241
43
  </tbody>
242
44
  </table>
243
45
  </body>
244
- </html>`;
245
- }
246
-
247
- function escHtml(str) {
248
- return String(str).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
249
- }
250
-
251
- // ── Entry ─────────────────────────────────────────────────────────────────────
252
-
253
- export async function auditCommand(rawArgs) {
254
- const args = rawArgs.slice(1);
255
- const jsonMode = args.includes("--json") || args.includes("--format") && args[args.indexOf("--format") + 1] === "json";
256
- const cwd = process.cwd();
257
- const infernoDir = path.join(cwd, "inferno");
258
-
259
- if (!fs.existsSync(infernoDir)) {
260
- const msg = "inferno/ not found. Run: infernoflow init";
261
- if (jsonMode) { console.log(JSON.stringify({ ok: false, error: msg })); }
262
- else { warn(msg); }
263
- process.exit(1);
264
- }
265
-
266
- // Parse flags
267
- const fmtIdx = args.indexOf("--format");
268
- const format = fmtIdx !== -1 ? args[fmtIdx + 1] : (jsonMode ? "json" : "text");
269
- const outIdx = args.indexOf("--out");
270
- const outPath = outIdx !== -1 ? args[outIdx + 1] : null;
271
- const failOnIdx = args.indexOf("--fail-on");
272
- const failOn = failOnIdx !== -1 ? args[failOnIdx + 1] : null;
273
-
274
- const contract = readContract(infernoDir);
275
- if (!contract) {
276
- const msg = "No contract.json or capabilities.json found.";
277
- if (jsonMode) { console.log(JSON.stringify({ ok: false, error: msg })); }
278
- else { warn(msg); }
279
- process.exit(1);
280
- }
281
-
282
- const rawCaps = contract.capabilities || [];
283
- const runAt = new Date().toISOString();
284
-
285
- // Classify every capability
286
- const results = rawCaps.map(cap => {
287
- const id = typeof cap === "string" ? cap : (cap.id || cap.name || "unknown");
288
- const description = typeof cap === "string" ? "" : (cap.description || "");
289
- const cls = classifyCapability(cap);
290
- return { id, description, ...cls };
291
- });
292
-
293
- // Sort by severity descending
294
- results.sort((a, b) => (SEVERITY_ORDER[b.severity] || 0) - (SEVERITY_ORDER[a.severity] || 0));
295
-
296
- // Stats
297
- const stats = { high: 0, medium: 0, low: 0, unknown: 0 };
298
- for (const r of results) {
299
- const key = r.severity in stats ? r.severity : "unknown";
300
- stats[key]++;
301
- }
302
-
303
- // Persist to audit.json
304
- const auditData = {
305
- runAt,
306
- stats,
307
- capabilities: results,
308
- };
309
- writeAudit(infernoDir, auditData);
310
-
311
- // Output
312
- if (format === "json" || jsonMode) {
313
- console.log(JSON.stringify({ ok: true, ...auditData }));
314
- } else if (format === "html") {
315
- const html = buildHtmlReport(results, stats, runAt);
316
- const dest = outPath || path.join(infernoDir, "audit.html");
317
- fs.writeFileSync(dest, html);
318
- if (!jsonMode) done(`HTML audit report written to ${bold(dest)}`);
319
- } else {
320
- printTextReport(results, stats);
321
- if (!jsonMode) done(`Saved to ${bold(path.join(infernoDir, AUDIT_FILE))}`);
322
- }
323
-
324
- // Exit code enforcement
325
- if (failOn) {
326
- const threshold = SEVERITY_ORDER[failOn] || 0;
327
- const violations = results.filter(r => (SEVERITY_ORDER[r.severity] || 0) >= threshold);
328
- if (violations.length > 0) {
329
- if (!jsonMode) {
330
- console.error(red(`\n ✗ ${violations.length} capability/capabilities at or above "${failOn}" severity — review required.\n`));
331
- }
332
- process.exit(1);
333
- }
334
- }
335
- }
46
+ </html>`}function k(o){return String(o).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async function G(o){const t=o.slice(1),n=t.includes("--json")||t.includes("--format")&&t[t.indexOf("--format")+1]==="json",c=process.cwd(),s=u.join(c,"inferno");if(!d.existsSync(s)){const i="inferno/ not found. Run: infernoflow init";n?console.log(JSON.stringify({ok:!1,error:i})):N(i),process.exit(1)}const r=t.indexOf("--format"),e=r!==-1?t[r+1]:n?"json":"text",l=t.indexOf("--out"),y=l!==-1?t[l+1]:null,S=t.indexOf("--fail-on"),v=S!==-1?t[S+1]:null,$=P(s);if(!$){const i="No contract.json or capabilities.json found.";n?console.log(JSON.stringify({ok:!1,error:i})):N(i),process.exit(1)}const D=$.capabilities||[],j=new Date().toISOString(),f=D.map(i=>{const a=typeof i=="string"?i:i.id||i.name||"unknown",w=typeof i=="string"?"":i.description||"",E=R(i);return{id:a,description:w,...E}});f.sort((i,a)=>(p[a.severity]||0)-(p[i.severity]||0));const h={high:0,medium:0,low:0,unknown:0};for(const i of f){const a=i.severity in h?i.severity:"unknown";h[a]++}const O={runAt:j,stats:h,capabilities:f};if(H(s,O),e==="json"||n)console.log(JSON.stringify({ok:!0,...O}));else if(e==="html"){const i=z(f,h,j),a=y||u.join(s,"audit.html");d.writeFileSync(a,i),n||I(`HTML audit report written to ${g(a)}`)}else J(f,h),n||I(`Saved to ${g(u.join(s,x))}`);if(v){const i=p[v]||0,a=f.filter(w=>(p[w.severity]||0)>=i);a.length>0&&(n||console.error(b(`
47
+ \u2717 ${a.length} capability/capabilities at or above "${v}" severity \u2014 review required.
48
+ `)),process.exit(1))}}export{G as auditCommand};