infernoflow 0.37.1 → 0.37.3

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 (88) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/bin/infernoflow.mjs +29 -277
  3. package/dist/lib/adopters/angular.mjs +1 -128
  4. package/dist/lib/adopters/css.mjs +1 -111
  5. package/dist/lib/adopters/react.mjs +1 -104
  6. package/dist/lib/ai/ideDetection.mjs +1 -31
  7. package/dist/lib/ai/localProvider.mjs +1 -88
  8. package/dist/lib/ai/providerRouter.mjs +2 -295
  9. package/dist/lib/commands/adopt.mjs +20 -869
  10. package/dist/lib/commands/adoptWizard.mjs +9 -320
  11. package/dist/lib/commands/agent.mjs +5 -191
  12. package/dist/lib/commands/ai.mjs +2 -407
  13. package/dist/lib/commands/ask.mjs +4 -299
  14. package/dist/lib/commands/audit.mjs +13 -300
  15. package/dist/lib/commands/changelog.mjs +26 -594
  16. package/dist/lib/commands/check.mjs +3 -184
  17. package/dist/lib/commands/ci.mjs +3 -208
  18. package/dist/lib/commands/claudeMd.mjs +30 -135
  19. package/dist/lib/commands/cloud.mjs +10 -773
  20. package/dist/lib/commands/context.mjs +34 -346
  21. package/dist/lib/commands/coverage.mjs +2 -282
  22. package/dist/lib/commands/dashboard.mjs +123 -635
  23. package/dist/lib/commands/demo.mjs +8 -465
  24. package/dist/lib/commands/diff.mjs +5 -274
  25. package/dist/lib/commands/docGate.mjs +2 -81
  26. package/dist/lib/commands/doctor.mjs +3 -321
  27. package/dist/lib/commands/explain.mjs +8 -438
  28. package/dist/lib/commands/export.mjs +10 -239
  29. package/dist/lib/commands/feedback.mjs +12 -216
  30. package/dist/lib/commands/generateSkills.mjs +38 -163
  31. package/dist/lib/commands/graph.mjs +11 -378
  32. package/dist/lib/commands/health.mjs +2 -309
  33. package/dist/lib/commands/impact.mjs +2 -325
  34. package/dist/lib/commands/implement.mjs +7 -103
  35. package/dist/lib/commands/init.mjs +45 -631
  36. package/dist/lib/commands/installCursorHooks.mjs +1 -36
  37. package/dist/lib/commands/installVsCodeCopilotHooks.mjs +1 -37
  38. package/dist/lib/commands/link.mjs +2 -342
  39. package/dist/lib/commands/log.mjs +18 -248
  40. package/dist/lib/commands/monorepo.mjs +4 -428
  41. package/dist/lib/commands/notify.mjs +4 -258
  42. package/dist/lib/commands/onboard.mjs +4 -296
  43. package/dist/lib/commands/prComment.mjs +2 -361
  44. package/dist/lib/commands/prImpact.mjs +2 -157
  45. package/dist/lib/commands/publish.mjs +15 -316
  46. package/dist/lib/commands/recap.mjs +6 -380
  47. package/dist/lib/commands/report.mjs +28 -272
  48. package/dist/lib/commands/review.mjs +9 -223
  49. package/dist/lib/commands/run.mjs +8 -336
  50. package/dist/lib/commands/scaffold.mjs +54 -419
  51. package/dist/lib/commands/scan.mjs +11 -1118
  52. package/dist/lib/commands/scout.mjs +2 -291
  53. package/dist/lib/commands/setup.mjs +5 -310
  54. package/dist/lib/commands/share.mjs +13 -196
  55. package/dist/lib/commands/snapshot.mjs +3 -383
  56. package/dist/lib/commands/stability.mjs +2 -293
  57. package/dist/lib/commands/stats.mjs +5 -402
  58. package/dist/lib/commands/status.mjs +4 -172
  59. package/dist/lib/commands/suggest.mjs +21 -563
  60. package/dist/lib/commands/switch.mjs +13 -520
  61. package/dist/lib/commands/syncAuto.mjs +1 -96
  62. package/dist/lib/commands/synthesize.mjs +10 -228
  63. package/dist/lib/commands/teamSync.mjs +2 -388
  64. package/dist/lib/commands/test.mjs +6 -363
  65. package/dist/lib/commands/theme.mjs +18 -195
  66. package/dist/lib/commands/uninstall.mjs +13 -406
  67. package/dist/lib/commands/upgrade.mjs +20 -153
  68. package/dist/lib/commands/version.mjs +2 -282
  69. package/dist/lib/commands/vibe.mjs +7 -357
  70. package/dist/lib/commands/watch.mjs +4 -203
  71. package/dist/lib/commands/why.mjs +4 -358
  72. package/dist/lib/cursorHooksInstall.mjs +1 -60
  73. package/dist/lib/draftToolingInstall.mjs +7 -68
  74. package/dist/lib/git/detect-drift.mjs +4 -208
  75. package/dist/lib/learning/adapt.mjs +6 -101
  76. package/dist/lib/learning/observe.mjs +1 -119
  77. package/dist/lib/learning/patternDetector.mjs +1 -298
  78. package/dist/lib/learning/profile.mjs +2 -279
  79. package/dist/lib/learning/skillSynthesizer.mjs +24 -145
  80. package/dist/lib/telemetry.mjs +19 -269
  81. package/dist/lib/templates/index.mjs +1 -131
  82. package/dist/lib/theme/scanner.mjs +4 -343
  83. package/dist/lib/ui/errors.mjs +1 -142
  84. package/dist/lib/ui/output.mjs +6 -95
  85. package/dist/lib/ui/prompts.mjs +6 -147
  86. package/dist/lib/vsCodeCopilotHooksInstall.mjs +1 -42
  87. package/package.json +2 -4
  88. package/scripts/postinstall.js +2 -2
@@ -1,103 +1,4 @@
1
- /**
2
- * infernoflow demo
3
- *
4
- * A self-contained, narrated walkthrough of infernoflow's core capabilities.
5
- * Scaffolds a temp sample project, runs the full chain, and shows real output.
6
- *
7
- * Usage:
8
- * infernoflow demo Run the full interactive demo
9
- * infernoflow demo --fast Skip pauses (CI/recording mode)
10
- * infernoflow demo --no-cleanup Keep the temp project after the demo
11
- *
12
- * What it demonstrates:
13
- * 1. Project structure — a mini e-commerce API with real capabilities
14
- * 2. infernoflow scan — AST analysis: functions, services, throws
15
- * 3. infernoflow graph — dependency graph
16
- * 4. infernoflow stability — frozen/stable/experimental breakdown
17
- * 5. infernoflow impact — blast radius for payment-process
18
- * 6. infernoflow explain — narrative (structural or AI)
19
- * 7. infernoflow why — file → capability correlation
20
- * 8. The money shot: trying to modify a frozen cap and getting warned
21
- */
22
-
23
- import * as fs from "node:fs";
24
- import * as path from "node:path";
25
- import * as os from "node:os";
26
- import { fileURLToPath } from "node:url";
27
- import { execSync, spawnSync } from "node:child_process";
28
- import { bold, cyan, gray, green, yellow, red } from "../ui/output.mjs";
29
-
30
- // ── helpers ───────────────────────────────────────────────────────────────────
31
-
32
- function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
33
-
34
- async function pause(fast, ms = 900) {
35
- if (!fast) await sleep(ms);
36
- }
37
-
38
- function hr(char = "─", len = 60) {
39
- return gray(char.repeat(len));
40
- }
41
-
42
- function run(cmd, cwd) {
43
- try {
44
- return spawnSync(cmd, {
45
- shell: true, cwd, encoding: "utf8", timeout: 30_000,
46
- });
47
- } catch { return { stdout: "", stderr: "", status: 1 }; }
48
- }
49
-
50
- // ── sample project scaffold ───────────────────────────────────────────────────
51
-
52
- const SAMPLE_FILES = {
53
- // Capability definitions
54
- "inferno/capabilities.json": JSON.stringify([
55
- {
56
- id: "user-auth",
57
- name: "User Authentication",
58
- description: "Handles login, session management, and token validation",
59
- stability: "frozen",
60
- owner: "auth-team",
61
- },
62
- {
63
- id: "payment-process",
64
- name: "Payment Processing",
65
- description: "Charges cards via Stripe, handles retries and webhook events",
66
- stability: "stable",
67
- owner: "payments-team",
68
- },
69
- {
70
- id: "order-create",
71
- name: "Order Creation",
72
- description: "Validates cart, reserves inventory, creates order records",
73
- stability: "experimental",
74
- owner: "core-team",
75
- },
76
- {
77
- id: "email-notify",
78
- name: "Email Notifications",
79
- description: "Sends transactional emails via SendGrid for orders and auth events",
80
- stability: "experimental",
81
- owner: "core-team",
82
- },
83
- ], null, 2),
84
-
85
- // Dependency graph
86
- "inferno/graph.json": JSON.stringify({
87
- deps: {
88
- "order-create": ["user-auth", "payment-process"],
89
- "email-notify": ["order-create"],
90
- "payment-process": ["user-auth"],
91
- },
92
- dependents: {
93
- "user-auth": ["payment-process", "order-create"],
94
- "payment-process": ["order-create"],
95
- "order-create": ["email-notify"],
96
- },
97
- }, null, 2),
98
-
99
- // Source files
100
- "src/auth.js": `// User Authentication
1
+ import*as b from"node:fs";import*as u from"node:path";import*as A from"node:os";import{fileURLToPath as E}from"node:url";import{spawnSync as C}from"node:child_process";import{bold as y,cyan as o,gray as a,green as r,yellow as v,red as h}from"../ui/output.mjs";function T(e){return new Promise(t=>setTimeout(t,e))}async function d(e,t=900){e||await T(t)}function J(e="\u2500",t=60){return a(e.repeat(t))}function q(e,t){try{return C(e,{shell:!0,cwd:t,encoding:"utf8",timeout:3e4})}catch{return{stdout:"",stderr:"",status:1}}}const P={"inferno/capabilities.json":JSON.stringify([{id:"user-auth",name:"User Authentication",description:"Handles login, session management, and token validation",stability:"frozen",owner:"auth-team"},{id:"payment-process",name:"Payment Processing",description:"Charges cards via Stripe, handles retries and webhook events",stability:"stable",owner:"payments-team"},{id:"order-create",name:"Order Creation",description:"Validates cart, reserves inventory, creates order records",stability:"experimental",owner:"core-team"},{id:"email-notify",name:"Email Notifications",description:"Sends transactional emails via SendGrid for orders and auth events",stability:"experimental",owner:"core-team"}],null,2),"inferno/graph.json":JSON.stringify({deps:{"order-create":["user-auth","payment-process"],"email-notify":["order-create"],"payment-process":["user-auth"]},dependents:{"user-auth":["payment-process","order-create"],"payment-process":["order-create"],"order-create":["email-notify"]}},null,2),"src/auth.js":`// User Authentication
101
2
  const jwt = require('jsonwebtoken');
102
3
  const bcrypt = require('bcrypt');
103
4
 
@@ -128,9 +29,7 @@ function validateToken(req, res, next) {
128
29
  }
129
30
 
130
31
  module.exports = { authenticateUser, validateToken };
131
- `,
132
-
133
- "src/payment.js": `// Payment Processing
32
+ `,"src/payment.js":`// Payment Processing
134
33
  const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
135
34
 
136
35
  /**
@@ -169,9 +68,7 @@ async function handleWebhook(event) {
169
68
  }
170
69
 
171
70
  module.exports = { processPayment, handleWebhook };
172
- `,
173
-
174
- "src/order.js": `// Order Creation
71
+ `,"src/order.js":`// Order Creation
175
72
  const { validateToken } = require('./auth');
176
73
  const { processPayment } = require('./payment');
177
74
 
@@ -195,9 +92,7 @@ async function createOrder(userId, cart, paymentMethodId) {
195
92
  }
196
93
 
197
94
  module.exports = { createOrder };
198
- `,
199
-
200
- "src/email.js": `// Email Notifications
95
+ `,"src/email.js":`// Email Notifications
201
96
  const sgMail = require('@sendgrid/mail');
202
97
  sgMail.setApiKey(process.env.SENDGRID_API_KEY);
203
98
 
@@ -208,363 +103,11 @@ async function sendOrderConfirmation(order, user) {
208
103
  await sgMail.send({
209
104
  to: user.email,
210
105
  from: 'noreply@shop.com',
211
- subject: \`Order confirmed #\${order.id}\`,
212
- text: \`Your order for \$\${order.total} has been confirmed.\`,
106
+ subject: \`Order confirmed \u2014 #\${order.id}\`,
107
+ text: \`Your order for $\${order.total} has been confirmed.\`,
213
108
  });
214
109
  }
215
110
 
216
111
  module.exports = { sendOrderConfirmation };
217
- `,
218
-
219
- // Scenarios
220
- "inferno/scenarios/auth-happy-path.json": JSON.stringify({
221
- scenarioId: "auth-happy-path",
222
- description: "User logs in with valid credentials and receives a JWT",
223
- capabilitiesCovered: ["user-auth"],
224
- steps: [
225
- "POST /auth/login with valid email + password",
226
- "Expect 200 with { token: '...' }",
227
- "Use token in Authorization header for subsequent requests",
228
- ],
229
- expects: [
230
- "Token is a valid JWT signed with JWT_SECRET",
231
- "Token expires in 24 hours",
232
- ],
233
- }, null, 2),
234
-
235
- "inferno/scenarios/payment-charge.json": JSON.stringify({
236
- scenarioId: "payment-charge",
237
- description: "Successful card charge via Stripe",
238
- capabilitiesCovered: ["payment-process"],
239
- steps: [
240
- "Create order with valid cart",
241
- "Call processPayment with valid Stripe test PM",
242
- "Expect payment record in db with status: paid",
243
- ],
244
- }, null, 2),
245
-
246
- "package.json": JSON.stringify({
247
- name: "demo-shop-api",
248
- version: "1.0.0",
249
- description: "Demo e-commerce API for infernoflow walkthrough",
250
- }, null, 2),
251
-
252
- // Pre-built scan so `why` works without running AST scan
253
- "inferno/scan.json": JSON.stringify({
254
- scannedAt: new Date().toISOString(),
255
- capabilities: [
256
- {
257
- id: "user-auth",
258
- codeAnalysis: {
259
- sourceFiles: ["src/auth.js"],
260
- functions: ["authenticateUser", "validateToken"],
261
- services: [],
262
- calls: ["db.users.findByEmail", "bcrypt.compare", "jwt.sign", "jwt.verify"],
263
- throws: ["AuthError"],
264
- },
265
- },
266
- {
267
- id: "payment-process",
268
- codeAnalysis: {
269
- sourceFiles: ["src/payment.js"],
270
- functions: ["processPayment", "handleWebhook"],
271
- services: ["stripe"],
272
- calls: ["stripe.paymentIntents.create", "db.payments.create", "db.orders.updateStatus"],
273
- throws: ["PaymentError"],
274
- },
275
- },
276
- {
277
- id: "order-create",
278
- codeAnalysis: {
279
- sourceFiles: ["src/order.js"],
280
- functions: ["createOrder"],
281
- services: [],
282
- calls: ["db.users.findById", "db.inventory.reserve", "db.orders.create", "processPayment"],
283
- throws: [],
284
- },
285
- },
286
- {
287
- id: "email-notify",
288
- codeAnalysis: {
289
- sourceFiles: ["src/email.js"],
290
- functions: ["sendOrderConfirmation"],
291
- services: ["sendgrid"],
292
- calls: ["sgMail.send"],
293
- throws: [],
294
- },
295
- },
296
- ],
297
- }, null, 2),
298
-
299
- // Capability map for file → cap lookups
300
- "inferno/capability-map.json": JSON.stringify({
301
- "src/auth.js": ["user-auth"],
302
- "src/payment.js": ["payment-process"],
303
- "src/order.js": ["order-create"],
304
- "src/email.js": ["email-notify"],
305
- }, null, 2),
306
- };
307
-
308
- function scaffoldProject(dir) {
309
- fs.mkdirSync(dir, { recursive: true });
310
- for (const [relPath, content] of Object.entries(SAMPLE_FILES)) {
311
- const full = path.join(dir, relPath);
312
- fs.mkdirSync(path.dirname(full), { recursive: true });
313
- fs.writeFileSync(full, content);
314
- }
315
- }
316
-
317
- // ── narrated steps ────────────────────────────────────────────────────────────
318
-
319
- function header(title) {
320
- console.log();
321
- console.log(bold(` ── ${title}`));
322
- console.log();
323
- }
324
-
325
- function narrate(text) {
326
- console.log(` ${gray(text)}`);
327
- }
328
-
329
- function cmd(text) {
330
- console.log(` ${cyan("$")} ${bold(text)}`);
331
- }
332
-
333
- function out(lines) {
334
- for (const l of lines) console.log(` ${l}`);
335
- }
336
-
337
- // ── demo runner ───────────────────────────────────────────────────────────────
338
-
339
- function runInferno(command, args, demoDir, ifBin) {
340
- const r = spawnSync(process.execPath, [ifBin, command, ...args], {
341
- cwd: demoDir, encoding: "utf8", timeout: 30_000,
342
- env: { ...process.env, NO_COLOR: "1" }
343
- });
344
- return (r.stdout || "") + (r.stderr || "");
345
- }
346
-
347
- function printOutput(raw, maxLines = 20) {
348
- const lines = raw.split("\n").filter(l => l.trim()).slice(0, maxLines);
349
- for (const l of lines) console.log(` ${gray("│")} ${l}`);
350
- }
351
-
352
- export async function demoCommand(rawArgs) {
353
- const args = (rawArgs || []).slice(1);
354
- const fast = args.includes("--fast");
355
- const noCleanup = args.includes("--no-cleanup");
356
-
357
- // Find infernoflow bin
358
- const ifBin = path.resolve(
359
- path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url)))),
360
- "bin", "infernoflow.mjs"
361
- );
362
-
363
- const demoDir = path.join(os.tmpdir(), `infernoflow-demo-${Date.now()}`);
364
-
365
- console.clear();
366
- console.log();
367
- console.log(bold(" 🔥 infernoflow — interactive demo"));
368
- console.log(gray(" ─────────────────────────────────────────────────────────────"));
369
- console.log();
370
- console.log(gray(" We'll build a mini e-commerce API and show infernoflow's full"));
371
- console.log(gray(" capability chain — from AST scan to blast radius analysis."));
372
- console.log();
373
- if (!fast) {
374
- console.log(gray(" Press Enter to advance each step, or run with --fast to skip pauses."));
375
- }
376
- console.log();
377
-
378
- // ── Step 1: The project ─────────────────────────────────────────────────────
379
- await pause(fast, 1200);
380
- header("Step 1 of 7 — The project");
381
- narrate("A small e-commerce API: auth, payments, orders, email.");
382
- narrate(`Scaffolded in: ${demoDir}`);
383
- console.log();
384
-
385
- scaffoldProject(demoDir);
386
-
387
- out([
388
- `${green("src/")}`,
389
- ` ${cyan("auth.js")} ← user-auth capability`,
390
- ` ${cyan("payment.js")} ← payment-process capability`,
391
- ` ${cyan("order.js")} ← order-create capability`,
392
- ` ${cyan("email.js")} ← email-notify capability`,
393
- ``,
394
- `${green("inferno/")}`,
395
- ` ${cyan("capabilities.json")} ← 4 capabilities registered`,
396
- ` ${cyan("graph.json")} ← dependency graph`,
397
- ` ${cyan("scenarios/")} ← 2 test scenarios`,
398
- ]);
399
-
400
- await pause(fast, 1000);
401
-
402
- // ── Step 2: Stability ───────────────────────────────────────────────────────
403
- header("Step 2 of 7 — Capability stability");
404
- cmd("infernoflow stability");
405
- console.log();
406
-
407
- const stabOut = runInferno("stability", [], demoDir, ifBin);
408
- if (stabOut.trim()) {
409
- printOutput(stabOut, 12);
410
- } else {
411
- // Manual fallback display
412
- out([
413
- `🧊 ${red("user-auth")} frozen Auth team owns this — no changes without approval`,
414
- `〰️ ${yellow("payment-process")} stable Stripe integration — additive changes only`,
415
- `🌊 ${green("order-create")} experimental Free to refactor`,
416
- `🌊 ${green("email-notify")} experimental Free to refactor`,
417
- ]);
418
- }
419
-
420
- console.log();
421
- narrate("user-auth is FROZEN — it's the most critical cap and must never break silently.");
422
- narrate("payment-process is STABLE — changes must be additive.");
423
-
424
- await pause(fast, 1000);
425
-
426
- // ── Step 3: Impact analysis ─────────────────────────────────────────────────
427
- header("Step 3 of 7 — Blast radius: what breaks if user-auth changes?");
428
- cmd("infernoflow impact user-auth");
429
- console.log();
430
-
431
- const impactOut = runInferno("impact", ["user-auth"], demoDir, ifBin);
432
- if (impactOut.trim()) {
433
- printOutput(impactOut, 18);
434
- } else {
435
- out([
436
- `🧊 ${red("user-auth")} → risk: ${red("CRITICAL")}`,
437
- ``,
438
- ` Direct dependents (1):`,
439
- ` payment-process ${yellow("stable")}`,
440
- ``,
441
- ` Transitive dependents (2):`,
442
- ` order-create ${green("experimental")}`,
443
- ` email-notify ${green("experimental")}`,
444
- ``,
445
- ` ${red("CRITICAL")} — frozen capability with dependents.`,
446
- ` Any change risks breaking 3 downstream capabilities.`,
447
- ]);
448
- }
449
-
450
- console.log();
451
- narrate("Change user-auth and you risk breaking payments, orders, and email.");
452
- narrate("This is the blast radius — measured before you write a single line.");
453
-
454
- await pause(fast, 1200);
455
-
456
- // ── Step 4: explain ─────────────────────────────────────────────────────────
457
- header("Step 4 of 7 — What is this capability, exactly?");
458
- cmd("infernoflow explain user-auth");
459
- console.log();
460
-
461
- const explainOut = runInferno("explain", ["user-auth"], demoDir, ifBin);
462
- if (explainOut.trim()) {
463
- printOutput(explainOut, 14);
464
- } else {
465
- out([
466
- `🧊 ${red("user-auth")}`,
467
- ` User Authentication`,
468
- ``,
469
- ` Handles login, session management, and token validation.`,
470
- ` This capability is FROZEN — do not modify without explicit instruction.`,
471
- ` payment-process, order-create depend on this capability.`,
472
- ` Before shipping changes, run: auth-happy-path scenario.`,
473
- ``,
474
- ` ${yellow("💡")} For richer AI narratives: infernoflow ai setup`,
475
- ]);
476
- }
477
-
478
- await pause(fast, 1000);
479
-
480
- // ── Step 5: why ─────────────────────────────────────────────────────────────
481
- header("Step 5 of 7 — File → capability correlation");
482
- cmd("infernoflow why src/payment.js");
483
- console.log();
484
-
485
- const whyOut = runInferno("why", ["src/payment.js"], demoDir, ifBin);
486
- if (whyOut.trim()) {
487
- printOutput(whyOut, 14);
488
- } else {
489
- out([
490
- ` src/payment.js → ${yellow("payment-process")} (stable)`,
491
- ``,
492
- ` Name: Payment Processing`,
493
- ` Description: Charges cards via Stripe, handles retries and webhook events`,
494
- ` Stability: 〰️ stable — additive changes only`,
495
- ``,
496
- ` Scenarios: payment-charge`,
497
- ` Depended on by: order-create (experimental)`,
498
- ]);
499
- }
500
-
501
- console.log();
502
- narrate("Any developer can instantly see what capability owns a given file.");
503
- narrate("No guessing. No digging through wikis.");
504
-
505
- await pause(fast, 1000);
506
-
507
- // ── Step 6: test ─────────────────────────────────────────────────────────────
508
- header("Step 6 of 7 — Run registered scenarios");
509
- cmd("infernoflow test");
510
- console.log();
511
-
512
- const testOut = runInferno("test", [], demoDir, ifBin);
513
- if (testOut.trim()) {
514
- printOutput(testOut, 12);
515
- } else {
516
- out([
517
- ` ${green("✓")} user-auth [frozen]`,
518
- ` ${green("✓")} auth-happy-path (generated)`,
519
- ``,
520
- ` ${green("✓")} payment-process [stable]`,
521
- ` ${green("✓")} payment-charge (generated)`,
522
- ``,
523
- ` ${green("2")} passed 0 failed 0 skipped`,
524
- ]);
525
- }
526
-
527
- await pause(fast, 800);
528
-
529
- // ── Step 7: the money shot ──────────────────────────────────────────────────
530
- header("Step 7 of 7 — The money shot: CI gate on a frozen capability");
531
- cmd("infernoflow impact user-auth --check");
532
- console.log();
533
- narrate("--check exits with code 1 if risk is HIGH or CRITICAL.");
534
- narrate("Add this to your CI pipeline before any PR that touches auth.");
535
- console.log();
536
-
537
- out([
538
- ` ${red("CRITICAL")} — user-auth is frozen with 3 dependents`,
539
- ` Exit code: 1`,
540
- ``,
541
- ` Your CI pipeline just stopped a risky change from reaching production.`,
542
- ]);
543
-
544
- await pause(fast, 600);
545
-
546
- // ── Summary ─────────────────────────────────────────────────────────────────
547
- console.log();
548
- console.log(gray(" ─────────────────────────────────────────────────────────────"));
549
- console.log();
550
- console.log(bold(" That's infernoflow."));
551
- console.log();
552
- console.log(` ${green("✓")} Capability contracts tracked in code, not in Confluence`);
553
- console.log(` ${green("✓")} Blast radius measured before you change anything`);
554
- console.log(` ${green("✓")} Every file knows what capability it serves`);
555
- console.log(` ${green("✓")} CI gates on frozen capabilities — broken things don't ship`);
556
- console.log(` ${green("✓")} Zero-touch with CLAUDE.md: your AI sessions stay in sync automatically`);
557
- console.log();
558
- console.log(` ${bold("Get started:")} ${cyan("npm install -g infernoflow")} → ${cyan("infernoflow setup")}`);
559
- console.log();
560
- console.log(gray(" ─────────────────────────────────────────────────────────────"));
561
- console.log();
562
-
563
- if (noCleanup) {
564
- console.log(gray(` Demo project kept at: ${demoDir}`));
565
- } else {
566
- try { fs.rmSync(demoDir, { recursive: true, force: true }); } catch {}
567
- }
568
-
569
- console.log();
570
- }
112
+ `,"inferno/scenarios/auth-happy-path.json":JSON.stringify({scenarioId:"auth-happy-path",description:"User logs in with valid credentials and receives a JWT",capabilitiesCovered:["user-auth"],steps:["POST /auth/login with valid email + password","Expect 200 with { token: '...' }","Use token in Authorization header for subsequent requests"],expects:["Token is a valid JWT signed with JWT_SECRET","Token expires in 24 hours"]},null,2),"inferno/scenarios/payment-charge.json":JSON.stringify({scenarioId:"payment-charge",description:"Successful card charge via Stripe",capabilitiesCovered:["payment-process"],steps:["Create order with valid cart","Call processPayment with valid Stripe test PM","Expect payment record in db with status: paid"]},null,2),"package.json":JSON.stringify({name:"demo-shop-api",version:"1.0.0",description:"Demo e-commerce API for infernoflow walkthrough"},null,2),"inferno/scan.json":JSON.stringify({scannedAt:new Date().toISOString(),capabilities:[{id:"user-auth",codeAnalysis:{sourceFiles:["src/auth.js"],functions:["authenticateUser","validateToken"],services:[],calls:["db.users.findByEmail","bcrypt.compare","jwt.sign","jwt.verify"],throws:["AuthError"]}},{id:"payment-process",codeAnalysis:{sourceFiles:["src/payment.js"],functions:["processPayment","handleWebhook"],services:["stripe"],calls:["stripe.paymentIntents.create","db.payments.create","db.orders.updateStatus"],throws:["PaymentError"]}},{id:"order-create",codeAnalysis:{sourceFiles:["src/order.js"],functions:["createOrder"],services:[],calls:["db.users.findById","db.inventory.reserve","db.orders.create","processPayment"],throws:[]}},{id:"email-notify",codeAnalysis:{sourceFiles:["src/email.js"],functions:["sendOrderConfirmation"],services:["sendgrid"],calls:["sgMail.send"],throws:[]}}]},null,2),"inferno/capability-map.json":JSON.stringify({"src/auth.js":["user-auth"],"src/payment.js":["payment-process"],"src/order.js":["order-create"],"src/email.js":["email-notify"]},null,2)};function x(e){b.mkdirSync(e,{recursive:!0});for(const[t,n]of Object.entries(P)){const s=u.join(e,t);b.mkdirSync(u.dirname(s),{recursive:!0}),b.writeFileSync(s,n)}}function p(e){console.log(),console.log(y(` \u2500\u2500 ${e}`)),console.log()}function i(e){console.log(` ${a(e)}`)}function f(e){console.log(` ${o("$")} ${y(e)}`)}function m(e){for(const t of e)console.log(` ${t}`)}function g(e,t,n,s){const l=C(process.execPath,[s,e,...t],{cwd:n,encoding:"utf8",timeout:3e4,env:{...process.env,NO_COLOR:"1"}});return(l.stdout||"")+(l.stderr||"")}function w(e,t=20){const n=e.split(`
113
+ `).filter(s=>s.trim()).slice(0,t);for(const s of n)console.log(` ${a("\u2502")} ${s}`)}async function F(e){const t=(e||[]).slice(1),n=t.includes("--fast"),s=t.includes("--no-cleanup"),l=u.resolve(u.dirname(u.dirname(u.dirname(E(import.meta.url)))),"bin","infernoflow.mjs"),c=u.join(A.tmpdir(),`infernoflow-demo-${Date.now()}`);console.clear(),console.log(),console.log(y(" \u{1F525} infernoflow \u2014 interactive demo")),console.log(a(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),console.log(a(" We'll build a mini e-commerce API and show infernoflow's full")),console.log(a(" capability chain \u2014 from AST scan to blast radius analysis.")),console.log(),n||console.log(a(" Press Enter to advance each step, or run with --fast to skip pauses.")),console.log(),await d(n,1200),p("Step 1 of 7 \u2014 The project"),i("A small e-commerce API: auth, payments, orders, email."),i(`Scaffolded in: ${c}`),console.log(),x(c),m([`${r("src/")}`,` ${o("auth.js")} \u2190 user-auth capability`,` ${o("payment.js")} \u2190 payment-process capability`,` ${o("order.js")} \u2190 order-create capability`,` ${o("email.js")} \u2190 email-notify capability`,"",`${r("inferno/")}`,` ${o("capabilities.json")} \u2190 4 capabilities registered`,` ${o("graph.json")} \u2190 dependency graph`,` ${o("scenarios/")} \u2190 2 test scenarios`]),await d(n,1e3),p("Step 2 of 7 \u2014 Capability stability"),f("infernoflow stability"),console.log();const S=g("stability",[],c,l);S.trim()?w(S,12):m([`\u{1F9CA} ${h("user-auth")} frozen Auth team owns this \u2014 no changes without approval`,`\u3030\uFE0F ${v("payment-process")} stable Stripe integration \u2014 additive changes only`,`\u{1F30A} ${r("order-create")} experimental Free to refactor`,`\u{1F30A} ${r("email-notify")} experimental Free to refactor`]),console.log(),i("user-auth is FROZEN \u2014 it's the most critical cap and must never break silently."),i("payment-process is STABLE \u2014 changes must be additive."),await d(n,1e3),p("Step 3 of 7 \u2014 Blast radius: what breaks if user-auth changes?"),f("infernoflow impact user-auth"),console.log();const $=g("impact",["user-auth"],c,l);$.trim()?w($,18):m([`\u{1F9CA} ${h("user-auth")} \u2192 risk: ${h("CRITICAL")}`,""," Direct dependents (1):",` payment-process ${v("stable")}`,""," Transitive dependents (2):",` order-create ${r("experimental")}`,` email-notify ${r("experimental")}`,"",` ${h("CRITICAL")} \u2014 frozen capability with dependents.`," Any change risks breaking 3 downstream capabilities."]),console.log(),i("Change user-auth and you risk breaking payments, orders, and email."),i("This is the blast radius \u2014 measured before you write a single line."),await d(n,1200),p("Step 4 of 7 \u2014 What is this capability, exactly?"),f("infernoflow explain user-auth"),console.log();const I=g("explain",["user-auth"],c,l);I.trim()?w(I,14):m([`\u{1F9CA} ${h("user-auth")}`," User Authentication",""," Handles login, session management, and token validation."," This capability is FROZEN \u2014 do not modify without explicit instruction."," payment-process, order-create depend on this capability."," Before shipping changes, run: auth-happy-path scenario.","",` ${v("\u{1F4A1}")} For richer AI narratives: infernoflow ai setup`]),await d(n,1e3),p("Step 5 of 7 \u2014 File \u2192 capability correlation"),f("infernoflow why src/payment.js"),console.log();const j=g("why",["src/payment.js"],c,l);j.trim()?w(j,14):m([` src/payment.js \u2192 ${v("payment-process")} (stable)`,""," Name: Payment Processing"," Description: Charges cards via Stripe, handles retries and webhook events"," Stability: \u3030\uFE0F stable \u2014 additive changes only",""," Scenarios: payment-charge"," Depended on by: order-create (experimental)"]),console.log(),i("Any developer can instantly see what capability owns a given file."),i("No guessing. No digging through wikis."),await d(n,1e3),p("Step 6 of 7 \u2014 Run registered scenarios"),f("infernoflow test"),console.log();const k=g("test",[],c,l);if(k.trim()?w(k,12):m([` ${r("\u2713")} user-auth [frozen]`,` ${r("\u2713")} auth-happy-path (generated)`,"",` ${r("\u2713")} payment-process [stable]`,` ${r("\u2713")} payment-charge (generated)`,"",` ${r("2")} passed 0 failed 0 skipped`]),await d(n,800),p("Step 7 of 7 \u2014 The money shot: CI gate on a frozen capability"),f("infernoflow impact user-auth --check"),console.log(),i("--check exits with code 1 if risk is HIGH or CRITICAL."),i("Add this to your CI pipeline before any PR that touches auth."),console.log(),m([` ${h("CRITICAL")} \u2014 user-auth is frozen with 3 dependents`," Exit code: 1",""," Your CI pipeline just stopped a risky change from reaching production."]),await d(n,600),console.log(),console.log(a(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),console.log(y(" That's infernoflow.")),console.log(),console.log(` ${r("\u2713")} Capability contracts tracked in code, not in Confluence`),console.log(` ${r("\u2713")} Blast radius measured before you change anything`),console.log(` ${r("\u2713")} Every file knows what capability it serves`),console.log(` ${r("\u2713")} CI gates on frozen capabilities \u2014 broken things don't ship`),console.log(` ${r("\u2713")} Zero-touch with CLAUDE.md: your AI sessions stay in sync automatically`),console.log(),console.log(` ${y("Get started:")} ${o("npm install -g infernoflow")} \u2192 ${o("infernoflow setup")}`),console.log(),console.log(a(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),s)console.log(a(` Demo project kept at: ${c}`));else try{b.rmSync(c,{recursive:!0,force:!0})}catch{}console.log()}export{F as demoCommand};