infernoflow 0.37.1 → 0.37.4

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 +71 -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,90 +1,40 @@
1
- /**
2
- * infernoflow generate-skills
3
- *
4
- * Reads inferno/developer-profile.json and generates personalised skill files:
5
- * - inferno/generated-skills/cursor-rules.md → copy to .cursor/rules/infernoflow.md
6
- * - inferno/generated-skills/quick-restore.md → session startup skill
7
- * - inferno/generated-skills/naming-guide.md → detected naming conventions
8
- * - inferno/generated-skills/feature-scaffold.md → personal feature checklist
9
- *
10
- * Run: infernoflow generate-skills [--cursor] [--force]
11
- * --cursor Also copy generated rules to .cursor/rules/infernoflow.md
12
- * --force Overwrite existing generated files
13
- */
14
-
15
- import * as fs from "node:fs";
16
- import * as path from "node:path";
17
- import { readProfile } from "../learning/profile.mjs";
18
- import { header, ok, warn, done, nextSteps, cyan, yellow, bold, gray } from "../ui/output.mjs";
19
-
20
- const SKILLS_DIR = path.join("inferno", "generated-skills");
21
-
22
- function write(filePath, content, force) {
23
- if (fs.existsSync(filePath) && !force) {
24
- warn(`Already exists (use --force to overwrite): ${path.relative(process.cwd(), filePath)}`);
25
- return false;
26
- }
27
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
28
- fs.writeFileSync(filePath, content, "utf8");
29
- ok(`Generated: ${path.relative(process.cwd(), filePath)}`);
30
- return true;
31
- }
32
-
33
- function buildCursorRules(profile, contract) {
34
- const naming = profile.namingStyle !== "unknown" ? profile.namingStyle : "PascalCase";
35
- const verbs = profile.preferredVerbs.length > 0 ? profile.preferredVerbs.slice(0, 5).join(", ") : "Add, Update, Remove";
36
- const framework = profile.stack?.framework || "unknown";
37
- const clusters = profile.featureClusters.slice(0, 3);
38
- const sessionStyle = profile.sessionCount >= 20 ? "experienced" : profile.sessionCount >= 5 ? "intermediate" : "new";
39
-
40
- const clusterRules = clusters.map(cluster =>
41
- `- When touching [${cluster.slice(0, 3).join(", ")}], check whether related capabilities also need updating`
42
- ).join("\n");
43
-
44
- return `# infernoflow — Cursor Rules (auto-generated)
45
- # Project: ${contract?.policyId || "unknown"} | Stack: ${framework}
1
+ import*as l from"node:fs";import*as s from"node:path";import{readProfile as k}from"../learning/profile.mjs";import{header as y,ok as w,warn as b,done as $,nextSteps as C,cyan as m,yellow as j}from"../ui/output.mjs";const p=s.join("inferno","generated-skills");function f(e,n,i){return l.existsSync(e)&&!i?(b(`Already exists (use --force to overwrite): ${s.relative(process.cwd(),e)}`),!1):(l.mkdirSync(s.dirname(e),{recursive:!0}),l.writeFileSync(e,n,"utf8"),w(`Generated: ${s.relative(process.cwd(),e)}`),!0)}function S(e,n){const i=e.namingStyle!=="unknown"?e.namingStyle:"PascalCase",r=e.preferredVerbs.length>0?e.preferredVerbs.slice(0,5).join(", "):"Add, Update, Remove",t=e.stack?.framework||"unknown",o=e.featureClusters.slice(0,3),a=e.sessionCount>=20?"experienced":e.sessionCount>=5?"intermediate":"new",c=o.map(u=>`- When touching [${u.slice(0,3).join(", ")}], check whether related capabilities also need updating`).join(`
2
+ `);return`# infernoflow \u2014 Cursor Rules (auto-generated)
3
+ # Project: ${n?.policyId||"unknown"} | Stack: ${t}
46
4
  # Regenerate with: infernoflow generate-skills --cursor
47
5
 
48
6
  ## Contract awareness
49
7
  - This project uses infernoflow to track capability contracts
50
8
  - After implementing any feature, always call \`infernoflow_run\` then \`infernoflow_apply\`
51
9
  - Run \`infernoflow_check\` before every commit
52
- - Current capabilities: [${(contract?.capabilities || []).join(", ")}]
10
+ - Current capabilities: [${(n?.capabilities||[]).join(", ")}]
53
11
 
54
12
  ## Naming conventions (detected from this developer's history)
55
- - Capability IDs use **${naming}** (e.g. ${verbs.split(", ").slice(0, 2).map(v => v + "Item").join(", ")})
56
- - Preferred action verbs: ${verbs}
13
+ - Capability IDs use **${i}** (e.g. ${r.split(", ").slice(0,2).map(u=>u+"Item").join(", ")})
14
+ - Preferred action verbs: ${r}
57
15
  - Match this style when suggesting new capability names
58
16
 
59
17
  ## Feature clusters (capabilities this developer adds together)
60
- ${clusterRules || "- No clusters detected yet build more features to train this"}
18
+ ${c||"- No clusters detected yet \u2014 build more features to train this"}
61
19
 
62
- ## Session style (${sessionStyle})
63
- ${sessionStyle === "experienced"
64
- ? "- Skip basic explanations this developer knows the codebase well\n- Be direct and minimal in responses"
65
- : "- Include brief context for non-obvious decisions\n- Explain infernoflow commands when used"}
20
+ ## Session style (${a})
21
+ ${a==="experienced"?`- Skip basic explanations \u2014 this developer knows the codebase well
22
+ - Be direct and minimal in responses`:`- Include brief context for non-obvious decisions
23
+ - Explain infernoflow commands when used`}
66
24
 
67
25
  ## Workflow reminders
68
26
  - Start sessions with: \`infernoflow context --show\`
69
27
  - Use \`infernoflow_git_drift\` to check what's changed before starting work
70
28
  - Use \`infernoflow_implement\` to get a structured coding prompt before writing code
71
- - Changelog entries should be ${profile.changelogVerbosity === "detailed" ? "detailed (include context and impact)" : "brief (one line, action-focused)"}
72
- `;
73
- }
74
-
75
- function buildQuickRestore(profile, contract) {
76
- const working = ""; // will be filled at runtime from context-state.json
77
- const framework = profile.stack?.framework || "unknown";
78
- const capabilities = (contract?.capabilities || []).slice(0, 6);
79
-
80
- return `# Quick Restore — ${contract?.policyId || "this project"}
29
+ - Changelog entries should be ${e.changelogVerbosity==="detailed"?"detailed (include context and impact)":"brief (one line, action-focused)"}
30
+ `}function R(e,n){const r=e.stack?.framework||"unknown",t=(n?.capabilities||[]).slice(0,6);return`# Quick Restore \u2014 ${n?.policyId||"this project"}
81
31
  # Paste this at the start of any new AI session to restore context instantly.
82
32
  # Regenerate with: infernoflow generate-skills
83
33
 
84
34
  ## Project snapshot
85
- - **Project:** ${contract?.policyId || "unknown"}
86
- - **Stack:** ${framework} / ${profile.stack?.language || "unknown"} (${profile.stack?.projectType || "unknown"})
87
- - **Capabilities:** ${capabilities.join(", ")}${(contract?.capabilities || []).length > 6 ? ` +${(contract?.capabilities || []).length - 6} more` : ""}
35
+ - **Project:** ${n?.policyId||"unknown"}
36
+ - **Stack:** ${r} / ${e.stack?.language||"unknown"} (${e.stack?.projectType||"unknown"})
37
+ - **Capabilities:** ${t.join(", ")}${(n?.capabilities||[]).length>6?` +${(n?.capabilities||[]).length-6} more`:""}
88
38
 
89
39
  ## How to start a session
90
40
  1. Run: \`infernoflow context --show\`
@@ -93,64 +43,42 @@ function buildQuickRestore(profile, contract) {
93
43
  4. Pick up where you left off
94
44
 
95
45
  ## infernoflow tools available (in Cursor / VS Code Agent mode)
96
- - \`infernoflow_run\` generate a contract update prompt
97
- - \`infernoflow_apply\` apply a JSON response
98
- - \`infernoflow_implement\` get a structured coding prompt
99
- - \`infernoflow_git_drift\` see what capabilities may have drifted
100
- - \`infernoflow_check\` validate contract is in sync
101
- - \`infernoflow_status\` quick health check
46
+ - \`infernoflow_run\` \u2014 generate a contract update prompt
47
+ - \`infernoflow_apply\` \u2014 apply a JSON response
48
+ - \`infernoflow_implement\` \u2014 get a structured coding prompt
49
+ - \`infernoflow_git_drift\` \u2014 see what capabilities may have drifted
50
+ - \`infernoflow_check\` \u2014 validate contract is in sync
51
+ - \`infernoflow_status\` \u2014 quick health check
102
52
 
103
53
  ## Definition of done (every feature branch)
104
54
  - [ ] Code works as intended
105
- - [ ] \`infernoflow_run\` \`infernoflow_apply\` completed
55
+ - [ ] \`infernoflow_run\` \u2192 \`infernoflow_apply\` completed
106
56
  - [ ] \`infernoflow_check\` passes
107
57
  - [ ] Commit message references the capability changed
108
- `;
109
- }
110
-
111
- function buildNamingGuide(profile) {
112
- const naming = profile.namingStyle !== "unknown" ? profile.namingStyle : "PascalCase";
113
- const verbs = profile.preferredVerbs.length > 0 ? profile.preferredVerbs : ["Create", "Read", "Update", "Delete", "Search"];
114
-
115
- const examples = verbs.slice(0, 5).map(v => {
116
- if (naming === "PascalCase") return ` - ${v}Item, ${v}Task, ${v}User`;
117
- if (naming === "camelCase") return ` - ${v.toLowerCase()}Item, ${v.toLowerCase()}Task`;
118
- return ` - ${v.toLowerCase()}-item, ${v.toLowerCase()}-task`;
119
- }).join("\n");
58
+ `}function _(e){const n=e.namingStyle!=="unknown"?e.namingStyle:"PascalCase",i=e.preferredVerbs.length>0?e.preferredVerbs:["Create","Read","Update","Delete","Search"],r=i.slice(0,5).map(t=>n==="PascalCase"?` - ${t}Item, ${t}Task, ${t}User`:n==="camelCase"?` - ${t.toLowerCase()}Item, ${t.toLowerCase()}Task`:` - ${t.toLowerCase()}-item, ${t.toLowerCase()}-task`).join(`
59
+ `);return`# Naming Guide \u2014 auto-generated from your capability history
120
60
 
121
- return `# Naming Guide — auto-generated from your capability history
122
-
123
- ## Detected style: ${naming}
61
+ ## Detected style: ${n}
124
62
 
125
63
  ### Your preferred action verbs
126
- ${verbs.map(v => `- **${v}**`).join("\n")}
64
+ ${i.map(t=>`- **${t}**`).join(`
65
+ `)}
127
66
 
128
67
  ### Examples matching your style
129
- ${examples}
68
+ ${r}
130
69
 
131
70
  ### Rules
132
71
  - All capability IDs in \`inferno/contract.json\` must follow this style
133
- - New capabilities suggested by AI should match reject any that don't
72
+ - New capabilities suggested by AI should match \u2014 reject any that don't
134
73
  - If you rename a capability, update contract.json + capabilities.json + any scenarios
135
74
 
136
75
  ### When naming a new capability, ask:
137
76
  1. Does it describe a single, discrete behavior? (If not, split it)
138
77
  2. Does it start with one of your preferred verbs?
139
- 3. Is it in ${naming}?
140
- 4. Is it unique not already in contract.json?
141
- `;
142
- }
143
-
144
- function buildFeatureScaffold(profile, contract) {
145
- const clusters = profile.featureClusters.slice(0, 2);
146
- const topCluster = clusters[0] || [];
147
- const framework = profile.stack?.framework || "unknown";
148
-
149
- const clusterChecks = topCluster.slice(0, 4).map(id =>
150
- `- [ ] Does **${id}** need updating? (check inferno/capabilities.json)`
151
- ).join("\n");
152
-
153
- return `# Feature Scaffold — ${framework} project
78
+ 3. Is it in ${n}?
79
+ 4. Is it unique \u2014 not already in contract.json?
80
+ `}function I(e,n){const r=e.featureClusters.slice(0,2)[0]||[],t=e.stack?.framework||"unknown",o=r.slice(0,4).map(a=>`- [ ] Does **${a}** need updating? (check inferno/capabilities.json)`).join(`
81
+ `);return`# Feature Scaffold \u2014 ${t} project
154
82
  # Use this checklist whenever starting a new feature.
155
83
  # Regenerate with: infernoflow generate-skills
156
84
 
@@ -166,13 +94,13 @@ function buildFeatureScaffold(profile, contract) {
166
94
  - [ ] Verify it works end-to-end
167
95
 
168
96
  ## Capability cluster check
169
- ${clusterChecks || "- [ ] Review existing capabilities do any need updating?"}
97
+ ${o||"- [ ] Review existing capabilities \u2014 do any need updating?"}
170
98
 
171
99
  ## Contract update (required before merge)
172
100
  - [ ] Run \`infernoflow_run\` with a description of what changed
173
101
  - [ ] Review the suggested JSON
174
102
  - [ ] Run \`infernoflow_apply\` with the JSON
175
- - [ ] Run \`infernoflow_check\` must pass
103
+ - [ ] Run \`infernoflow_check\` \u2014 must pass
176
104
 
177
105
  ## Commit message
178
106
  - Reference the capability: "feat: add SearchItems endpoint (#42)"
@@ -182,58 +110,5 @@ ${clusterChecks || "- [ ] Review existing capabilities — do any need updating?
182
110
  - [ ] Feature works
183
111
  - [ ] \`infernoflow_check\` passes
184
112
  - [ ] PR description mentions which capabilities changed
185
- `;
186
- }
187
-
188
- export async function generateSkillsCommand(args) {
189
- const cwd = process.cwd();
190
- const force = args.includes("--force") || args.includes("-f");
191
- const installCursor = args.includes("--cursor");
192
-
193
- header("generate-skills");
194
-
195
- const infernoDir = path.join(cwd, "inferno");
196
- if (!fs.existsSync(infernoDir)) {
197
- console.error(" ✘ inferno/ not found — run: infernoflow init\n");
198
- process.exit(1);
199
- }
200
-
201
- const profile = readProfile(infernoDir);
202
- let contract = null;
203
- try { contract = JSON.parse(fs.readFileSync(path.join(infernoDir, "contract.json"), "utf8")); } catch {}
204
-
205
- const skillsDir = path.join(cwd, SKILLS_DIR);
206
-
207
- // Generate all four skill files
208
- write(path.join(skillsDir, "cursor-rules.md"), buildCursorRules(profile, contract), force);
209
- write(path.join(skillsDir, "quick-restore.md"), buildQuickRestore(profile, contract), force);
210
- write(path.join(skillsDir, "naming-guide.md"), buildNamingGuide(profile), force);
211
- write(path.join(skillsDir, "feature-scaffold.md"), buildFeatureScaffold(profile, contract), force);
212
-
213
- // Optionally install cursor rules
214
- if (installCursor) {
215
- const rulesDir = path.join(cwd, ".cursor", "rules");
216
- fs.mkdirSync(rulesDir, { recursive: true });
217
- const src = path.join(skillsDir, "cursor-rules.md");
218
- const dst = path.join(rulesDir, "infernoflow.md");
219
- fs.copyFileSync(src, dst);
220
- ok(`Installed to: .cursor/rules/infernoflow.md`);
221
- }
222
-
223
- const profileSummary = [
224
- profile.namingStyle !== "unknown" ? `naming: ${profile.namingStyle}` : null,
225
- profile.stack?.framework !== "unknown" ? `stack: ${profile.stack.framework}` : null,
226
- profile.sessionCount > 0 ? `sessions: ${profile.sessionCount}` : null,
227
- ].filter(Boolean).join(" · ");
228
-
229
- done(`Skills generated${profileSummary ? ` (${profileSummary})` : ""}`);
230
-
231
- nextSteps([
232
- `Review files in ${yellow(SKILLS_DIR + "/")}`,
233
- `Copy to Cursor: ${cyan("infernoflow generate-skills --cursor")}`,
234
- `Re-run any time to refresh after more sessions: ${cyan("infernoflow generate-skills --force")}`,
235
- profile.sessionCount < 5
236
- ? `Run more commands to improve personalisation (${profile.sessionCount} sessions so far)`
237
- : `Profile has ${profile.sessionCount} sessions — personalisation is well-trained`,
238
- ]);
239
- }
113
+ `}async function A(e){const n=process.cwd(),i=e.includes("--force")||e.includes("-f"),r=e.includes("--cursor");y("generate-skills");const t=s.join(n,"inferno");l.existsSync(t)||(console.error(` \u2718 inferno/ not found \u2014 run: infernoflow init
114
+ `),process.exit(1));const o=k(t);let a=null;try{a=JSON.parse(l.readFileSync(s.join(t,"contract.json"),"utf8"))}catch{}const c=s.join(n,p);if(f(s.join(c,"cursor-rules.md"),S(o,a),i),f(s.join(c,"quick-restore.md"),R(o,a),i),f(s.join(c,"naming-guide.md"),_(o),i),f(s.join(c,"feature-scaffold.md"),I(o,a),i),r){const d=s.join(n,".cursor","rules");l.mkdirSync(d,{recursive:!0});const h=s.join(c,"cursor-rules.md"),g=s.join(d,"infernoflow.md");l.copyFileSync(h,g),w("Installed to: .cursor/rules/infernoflow.md")}const u=[o.namingStyle!=="unknown"?`naming: ${o.namingStyle}`:null,o.stack?.framework!=="unknown"?`stack: ${o.stack.framework}`:null,o.sessionCount>0?`sessions: ${o.sessionCount}`:null].filter(Boolean).join(" \xB7 ");$(`Skills generated${u?` (${u})`:""}`),C([`Review files in ${j(p+"/")}`,`Copy to Cursor: ${m("infernoflow generate-skills --cursor")}`,`Re-run any time to refresh after more sessions: ${m("infernoflow generate-skills --force")}`,o.sessionCount<5?`Run more commands to improve personalisation (${o.sessionCount} sessions so far)`:`Profile has ${o.sessionCount} sessions \u2014 personalisation is well-trained`])}export{A as generateSkillsCommand};