infernoflow 0.10.16 → 0.10.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -363
- package/dist/bin/infernoflow.mjs +37 -27
- package/dist/lib/adopters/angular.mjs +1 -0
- package/dist/lib/adopters/css.mjs +1 -0
- package/dist/lib/adopters/react.mjs +1 -0
- package/dist/lib/commands/adopt.mjs +11 -11
- package/dist/lib/commands/context.mjs +25 -18
- package/dist/lib/commands/generateSkills.mjs +114 -0
- package/dist/lib/commands/setup.mjs +4 -0
- package/dist/lib/commands/suggest.mjs +13 -13
- package/dist/lib/git/detect-drift.mjs +4 -0
- package/dist/lib/learning/adapt.mjs +9 -0
- package/dist/lib/learning/observe.mjs +1 -0
- package/dist/lib/learning/profile.mjs +2 -0
- package/dist/templates/cursor/inferno-mcp-server.mjs +378 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,408 +1,97 @@
|
|
|
1
1
|
# 🔥 infernoflow
|
|
2
|
-
|
|
3
2
|
> The forge for liquid code — keep capabilities, contracts, and docs in sync with your codebase.
|
|
4
3
|
|
|
5
4
|
## What it does
|
|
6
|
-
|
|
7
|
-
infernoflow ensures that when your code changes, your **capability contracts** and **documentation** stay in sync. It prevents "semantic drift" — where code evolves but no one knows what the system can actually do.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
inferno/
|
|
11
|
-
├── contract.json ← what your system promises to do
|
|
12
|
-
├── capabilities.json ← registry of each capability
|
|
13
|
-
├── scenarios/ ← test scenarios covering each capability
|
|
14
|
-
└── CHANGELOG.md ← history of capability changes
|
|
15
|
-
```
|
|
5
|
+
infernoflow ensures that when your code changes, your **capability contracts** and **documentation** stay in sync. It prevents semantic drift — where code evolves but no one knows what the system can actually do.
|
|
16
6
|
|
|
17
7
|
## Install
|
|
18
|
-
|
|
19
8
|
```bash
|
|
20
9
|
npm install -g infernoflow
|
|
21
|
-
# or
|
|
10
|
+
# or:
|
|
22
11
|
npx infernoflow init
|
|
23
12
|
```
|
|
24
13
|
|
|
25
14
|
## Quick Start
|
|
26
|
-
|
|
27
15
|
```bash
|
|
28
|
-
# 1. Scaffold in your project root:
|
|
29
16
|
npx infernoflow init
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
# to inferno/CONTEXT.draft.md (gitignored). Promote with npm run inferno:promote-draft.
|
|
33
|
-
npx infernoflow init --yes --cursor-hooks
|
|
34
|
-
|
|
35
|
-
# Optional: VS Code + GitHub Copilot agent hooks (Preview) — same draft file + promote flow
|
|
36
|
-
npx infernoflow init --yes --vscode-copilot-hooks
|
|
37
|
-
|
|
38
|
-
# Or add hooks to an existing infernoflow project:
|
|
39
|
-
npx infernoflow install-cursor-hooks
|
|
40
|
-
npx infernoflow install-vscode-copilot-hooks
|
|
41
|
-
|
|
42
|
-
# 2. See your contract health:
|
|
17
|
+
npx infernoflow install-cursor-hooks # installs MCP server + .cursor/mcp.json
|
|
18
|
+
# Restart Cursor → Settings → MCP → infernoflow: 4 tools enabled
|
|
43
19
|
infernoflow status
|
|
44
|
-
|
|
45
|
-
# 3. When you add a feature, let AI update the docs:
|
|
46
|
-
infernoflow suggest "added email notifications and user profiles"
|
|
47
|
-
|
|
48
|
-
# 4. Validate everything:
|
|
20
|
+
infernoflow suggest "added email notifications"
|
|
49
21
|
infernoflow check
|
|
50
|
-
|
|
51
|
-
# 5. In CI / pre-push hook:
|
|
52
|
-
infernoflow doc-gate
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Adopt Existing Project
|
|
56
|
-
|
|
57
|
-
Use this when your project already has code and you want InfernoFlow to bootstrap from current behavior.
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
# from existing project root
|
|
61
|
-
infernoflow init --adopt
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Non-interactive adoption:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
infernoflow init --adopt --yes
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Override detected stack during adoption:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
infernoflow init --adopt --lang ts --framework angular --project-type frontend
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
C# / ASP.NET example:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
infernoflow init --adopt --lang cs --framework aspnet --project-type backend --report-human-only
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
JSON report for CI/logging:
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
infernoflow init --adopt --yes --report-json
|
|
86
22
|
```
|
|
87
23
|
|
|
88
|
-
|
|
24
|
+
## Cursor MCP Integration (recommended)
|
|
89
25
|
|
|
90
|
-
|
|
91
|
-
infernoflow init --adopt --yes --report-json-only
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Human-only output (visual report only, no JSON block):
|
|
26
|
+
After running `install-cursor-hooks`, infernoflow registers as an MCP server inside Cursor. No copy/paste — Cursor calls infernoflow tools directly in chat.
|
|
95
27
|
|
|
28
|
+
### Setup
|
|
96
29
|
```bash
|
|
97
|
-
infernoflow
|
|
30
|
+
infernoflow install-cursor-hooks
|
|
31
|
+
# Restart Cursor
|
|
32
|
+
# Settings → MCP → infernoflow: 4 tools enabled
|
|
98
33
|
```
|
|
99
34
|
|
|
100
|
-
|
|
101
|
-
- `inferno/contract.json` (inferred capability baseline)
|
|
102
|
-
- `inferno/capabilities.json` (inferred registry)
|
|
103
|
-
- `inferno/scenarios/adoption_baseline.json` (coverage baseline)
|
|
104
|
-
- `inferno/adoption_profile.json` (detected components, display fields, external libraries, UI layout, styling hints)
|
|
105
|
-
- `inferno/adoption_profile.json` (detected components, display fields, external libraries, UI layout, styling hints, API call map)
|
|
106
|
-
- `inferno/context-state.json` (saved development profile: language/framework/project type)
|
|
107
|
-
- `inferno/CHANGELOG.md` (adoption entry)
|
|
108
|
-
|
|
109
|
-
Safety:
|
|
110
|
-
- Existing `inferno/` is not overwritten unless `--force` is provided.
|
|
111
|
-
- Adoption prints an inferred capability report with source-file hints and confidence.
|
|
112
|
-
|
|
113
|
-
## Recommended Workflow
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
# start a feature
|
|
117
|
-
infernoflow context --intent "add search to tasks" --working "frontend search UX"
|
|
118
|
-
|
|
119
|
-
# generate implementation prompt(s) for coding agent
|
|
120
|
-
infernoflow implement "add server-side task search endpoint" --mode both
|
|
121
|
-
|
|
122
|
-
# build code changes
|
|
123
|
-
|
|
124
|
-
# sync inferno contract with AI assistance
|
|
125
|
-
infernoflow suggest "added task search by title and due date"
|
|
126
|
-
|
|
127
|
-
# verify no drift
|
|
128
|
-
infernoflow status
|
|
129
|
-
infernoflow check
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Team SOP (Developer Workflow)
|
|
133
|
-
|
|
134
|
-
Use this checklist for every feature branch:
|
|
35
|
+
### MCP tools
|
|
135
36
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- Implement UI/API/tests as usual.
|
|
37
|
+
| Tool | What it does |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `infernoflow_run` | Generates a task prompt from your contract |
|
|
40
|
+
| `infernoflow_apply` | Applies the JSON response — updates contract + CHANGELOG |
|
|
41
|
+
| `infernoflow_check` | Validates contract sync |
|
|
42
|
+
| `infernoflow_status` | Shows contract health |
|
|
143
43
|
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
infernoflow suggest "plain-language description of what changed"
|
|
44
|
+
### Workflow in Cursor chat
|
|
147
45
|
```
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
infernoflow status
|
|
155
|
-
infernoflow check
|
|
46
|
+
You: Use infernoflow_run with task "add search functionality"
|
|
47
|
+
Cursor: [calls infernoflow_run → returns prompt]
|
|
48
|
+
Cursor: [generates JSON]
|
|
49
|
+
Cursor: [calls infernoflow_apply]
|
|
50
|
+
→ contract.json, capabilities.json, CHANGELOG.md updated + validated
|
|
156
51
|
```
|
|
157
52
|
|
|
158
|
-
|
|
53
|
+
### Terminal fallback (without MCP)
|
|
159
54
|
```bash
|
|
160
|
-
infernoflow
|
|
161
|
-
|
|
162
|
-
|
|
55
|
+
infernoflow run "add search functionality"
|
|
56
|
+
# writes inferno/agent-prompt.md and waits
|
|
57
|
+
# paste prompt into Cursor/Claude → save JSON to inferno/agent-response.json
|
|
58
|
+
# infernoflow picks it up and applies automatically
|
|
163
59
|
```
|
|
164
60
|
|
|
165
|
-
6) **Definition of done**
|
|
166
|
-
- Capability changes are reflected in `inferno/contract.json`.
|
|
167
|
-
- New/changed capabilities exist in `inferno/capabilities.json`.
|
|
168
|
-
- Scenario coverage updated under `inferno/scenarios/`.
|
|
169
|
-
- `inferno/CHANGELOG.md` updated under `## Unreleased`.
|
|
170
|
-
- `infernoflow check` passes.
|
|
171
|
-
|
|
172
61
|
## Commands
|
|
173
62
|
|
|
174
63
|
| Command | Description |
|
|
175
64
|
|---|---|
|
|
176
|
-
| `infernoflow init` |
|
|
177
|
-
| `infernoflow
|
|
178
|
-
| `infernoflow
|
|
179
|
-
| `infernoflow
|
|
180
|
-
| `infernoflow
|
|
181
|
-
| `infernoflow
|
|
182
|
-
| `infernoflow
|
|
183
|
-
| `infernoflow
|
|
184
|
-
| `infernoflow
|
|
185
|
-
| `infernoflow
|
|
186
|
-
| `infernoflow
|
|
187
|
-
| `infernoflow install-vscode-copilot-hooks` | Install `.github/hooks` for VS Code + Copilot (Preview) + same promote script |
|
|
188
|
-
|
|
189
|
-
### Cursor hooks (draft → promote)
|
|
190
|
-
|
|
191
|
-
[Cursor hooks](https://cursor.com/docs/agent/hooks) can run a small Node script after each assistant message. infernoflow can install:
|
|
192
|
-
|
|
193
|
-
- **`.cursor/hooks.json`** — `afterAgentResponse` and `stop` events
|
|
194
|
-
- **`.cursor/hooks/inferno-session-draft.mjs`** — appends assistant `text` to **`inferno/CONTEXT.draft.md`** (never overwrites `CONTEXT.md` automatically)
|
|
195
|
-
- **`scripts/inferno-promote-draft.mjs`** + **`npm run inferno:promote-draft`** — preview, `--append-notes` (merge under `## Decisions & notes` in `inferno/CONTEXT.md`), or `--clear`
|
|
196
|
-
- **`.gitignore`** entry for `inferno/CONTEXT.draft.md` when possible
|
|
197
|
-
|
|
198
|
-
Install with **`infernoflow install-cursor-hooks`** or **`infernoflow init --cursor-hooks`**. Restart Cursor after install. Review the draft before promoting; treat chat as **input**, not product truth.
|
|
199
|
-
|
|
200
|
-
### VS Code + GitHub Copilot hooks (draft → promote, Preview)
|
|
201
|
-
|
|
202
|
-
VS Code can run [Agent hooks](https://code.visualstudio.com/docs/copilot/customization/hooks) from **`.github/hooks/*.json`**. infernoflow installs:
|
|
203
|
-
|
|
204
|
-
- **`.github/hooks/infernoflow-drafts.json`** — wires **`UserPromptSubmit`** (your prompt) and **`Stop`** (end of agent turn)
|
|
205
|
-
- **`scripts/inferno-vscode-copilot-hook.mjs`** — appends the user prompt on submit; on **Stop**, reads **`transcript_path`** from stdin (when present), parses **JSONL** or session **JSON**, and appends the **last assistant text** it can infer (format varies by VS Code / Copilot version — if parsing fails, a short marker is still appended)
|
|
206
|
-
- The same **`inferno:promote-draft`** script and **`.gitignore`** entry for **`inferno/CONTEXT.draft.md`** as the Cursor flow
|
|
207
|
-
|
|
208
|
-
Install with **`infernoflow install-vscode-copilot-hooks`** or **`infernoflow init --vscode-copilot-hooks`**. Restart VS Code, confirm your org allows hooks, and use the **GitHub Copilot Chat Hooks** output channel for diagnostics.
|
|
209
|
-
|
|
210
|
-
**Limitations:** Hooks are **Preview**; `transcript_path` / JSONL shape may differ by build; some hook events omit `transcript_path` ([vscode#300583](https://github.com/microsoft/vscode/issues/300583)). You still have the full **`infernoflow`** CLI in the terminal when hooks are not enough.
|
|
211
|
-
|
|
212
|
-
### Options
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
infernoflow init --force # overwrite existing files
|
|
216
|
-
infernoflow init --cursor-hooks # with init: install Cursor draft hooks (see above)
|
|
217
|
-
infernoflow init --vscode-copilot-hooks # with init: install VS Code + Copilot draft hooks (Preview)
|
|
218
|
-
infernoflow init --yes # skip prompts, use defaults
|
|
219
|
-
infernoflow init --adopt # infer baseline from existing project
|
|
220
|
-
infernoflow init --adopt --lang ts --framework react --project-type frontend
|
|
221
|
-
infernoflow init --adopt --report-human-only
|
|
222
|
-
infernoflow suggest "..." # describe what changed
|
|
223
|
-
infernoflow implement "..." --mode both
|
|
224
|
-
infernoflow implement "..." --mode cursor
|
|
225
|
-
infernoflow implement "..." --mode generic
|
|
226
|
-
infernoflow implement "..." --mode both --copy
|
|
227
|
-
infernoflow run "add favorite badge to tasks"
|
|
228
|
-
infernoflow run "sync check" --dry-run
|
|
229
|
-
infernoflow run "sync check" --json
|
|
230
|
-
infernoflow pr-impact
|
|
231
|
-
infernoflow pr-impact --json
|
|
232
|
-
infernoflow sync --auto
|
|
233
|
-
infernoflow sync --auto --json
|
|
234
|
-
npm run inferno:hooks # install local git hooks (after init)
|
|
235
|
-
infernoflow install-cursor-hooks --force # overwrite hook files if present
|
|
236
|
-
infernoflow install-vscode-copilot-hooks --force
|
|
237
|
-
infernoflow check --json # machine-readable output for CI
|
|
238
|
-
infernoflow check --skip-doc-gate
|
|
239
|
-
infernoflow status --json # machine-readable status summary
|
|
240
|
-
infernoflow doc-gate --json # machine-readable doc-gate result
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## `infernoflow suggest` — AI-powered updates
|
|
244
|
-
|
|
245
|
-
When you add a feature, just describe it in plain language. infernoflow generates a prompt you can paste into **any AI** (Claude, ChatGPT, Copilot, Cursor, etc.), then applies the suggested changes automatically.
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
infernoflow suggest "added payment processing and invoice generation"
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
**What happens:**
|
|
252
|
-
1. infernoflow reads your current contract state
|
|
253
|
-
2. Generates a structured prompt with full context
|
|
254
|
-
3. You paste it into your AI of choice
|
|
255
|
-
4. Paste the JSON response back
|
|
256
|
-
5. infernoflow previews the changes and asks for confirmation
|
|
257
|
-
6. On approval — updates `contract.json`, `capabilities.json`, `scenarios/`, and `CHANGELOG.md`
|
|
258
|
-
|
|
259
|
-
**Example output:**
|
|
260
|
-
```
|
|
261
|
-
Proposed Changes
|
|
262
|
-
|
|
263
|
-
Summary: Added payment processing and invoice generation functionality.
|
|
264
|
-
|
|
265
|
-
+ New capabilities:
|
|
266
|
-
ProcessPayment — Process Payment
|
|
267
|
-
GenerateInvoice — Generate Invoice
|
|
268
|
-
|
|
269
|
-
~ Scenario updates:
|
|
270
|
-
[update] happy_path.json
|
|
271
|
-
|
|
272
|
-
📝 Changelog: - Add payment processing and invoice generation capabilities.
|
|
273
|
-
|
|
274
|
-
Apply these changes? (y/n)
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Works with any AI — Claude, ChatGPT, GitHub Copilot, Cursor, or your own setup.
|
|
278
|
-
|
|
279
|
-
## `infernoflow run` — zero copy/paste flow
|
|
280
|
-
|
|
281
|
-
Run one command and infernoflow will:
|
|
282
|
-
1. Detect drift (`pr-impact`)
|
|
283
|
-
2. Resolve provider (`auto` defaults to IDE agent)
|
|
284
|
-
3. Generate suggestion
|
|
285
|
-
4. Apply inferno updates
|
|
286
|
-
5. Validate with `check`
|
|
287
|
-
6. Roll back automatically if validation fails
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
infernoflow run "add favorite badge to tasks and filter by favorite"
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Machine mode:
|
|
294
|
-
|
|
295
|
-
```bash
|
|
296
|
-
infernoflow run "sync check" --json
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
Provider options:
|
|
300
|
-
|
|
301
|
-
```bash
|
|
302
|
-
infernoflow run "task" --provider auto # default (IDE agent first)
|
|
303
|
-
infernoflow run "task" --provider agent --ide cursor # require IDE agent
|
|
304
|
-
infernoflow run "task" --provider local # explicit local model
|
|
305
|
-
infernoflow run "task" --provider prompt # deterministic prompt fallback
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
IDE routing behavior:
|
|
309
|
-
- `auto` + agent available -> uses IDE agent
|
|
310
|
-
- `auto` + no agent -> falls back to prompt mode (`FALLBACK_PROMPT_MODE`)
|
|
311
|
-
- `agent` + no agent -> exits with `EXPLICIT_AGENT_REQUIRED`
|
|
312
|
-
|
|
313
|
-
Local model configuration (optional):
|
|
314
|
-
|
|
315
|
-
```bash
|
|
316
|
-
# local provider example: ollama
|
|
317
|
-
set INFERNO_LOCAL_PROVIDER=ollama
|
|
318
|
-
set INFERNO_LOCAL_ENDPOINT=http://127.0.0.1:11434/api/generate
|
|
319
|
-
set INFERNO_LOCAL_MODEL=llama3.1:8b
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
Optional OpenAI-compatible local server:
|
|
323
|
-
|
|
324
|
-
```bash
|
|
325
|
-
set INFERNO_LOCAL_PROVIDER=openai
|
|
326
|
-
set INFERNO_LOCAL_ENDPOINT=http://127.0.0.1:1234/v1/chat/completions
|
|
327
|
-
set INFERNO_LOCAL_MODEL=local-model
|
|
328
|
-
set INFERNO_LOCAL_API_KEY=local
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## `infernoflow implement` — code-agent execution prompts
|
|
332
|
-
|
|
333
|
-
Generate coding prompts from your project context and inferno contract:
|
|
334
|
-
|
|
335
|
-
```bash
|
|
336
|
-
infernoflow implement "add pagination to tasks" --mode both
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
Modes:
|
|
340
|
-
- `--mode cursor`: Cursor-specific coding prompt
|
|
341
|
-
- `--mode generic`: generic prompt for any coding agent
|
|
342
|
-
- `--mode both`: print both sections (default)
|
|
343
|
-
- `--copy`: copy selected prompt output to clipboard
|
|
344
|
-
|
|
345
|
-
Recommended chain:
|
|
346
|
-
1) `infernoflow context --intent "..."`
|
|
347
|
-
2) `infernoflow implement "..."`
|
|
348
|
-
3) run the coding agent and apply code changes
|
|
349
|
-
4) `infernoflow suggest "..."`
|
|
350
|
-
5) `infernoflow check`
|
|
351
|
-
|
|
352
|
-
## Troubleshooting
|
|
353
|
-
|
|
354
|
-
- `Unknown command: suggest`:
|
|
355
|
-
- Run `infernoflow --help` and confirm `suggest` appears.
|
|
356
|
-
- If using `npx`, force a specific version: `npx infernoflow@latest --help`.
|
|
357
|
-
- `infernoflow: command not found`:
|
|
358
|
-
- Use `npx infernoflow ...` or install globally: `npm install -g infernoflow`.
|
|
359
|
-
- `npm publish` fails with existing version:
|
|
360
|
-
- Bump version first (`npm version patch|minor|major`) then publish.
|
|
361
|
-
- `status` or `check` fails due to missing inferno files:
|
|
362
|
-
- Run `infernoflow init` at project root.
|
|
363
|
-
- Windows/Git Bash path confusion:
|
|
364
|
-
- Prefer `node bin/infernoflow.mjs --help` from package root for local debugging.
|
|
365
|
-
|
|
366
|
-
## Why infernoflow?
|
|
367
|
-
|
|
368
|
-
**The problem:** AI-assisted development moves fast. Code changes daily. But what does the system *actually do*? What changed? What's covered?
|
|
369
|
-
|
|
370
|
-
**The metaphor:** A forge (כיבשן). Metal becomes liquid — flexible, shapeable. The forge is the controlled environment where that change happens safely, with molds (contracts) and tempering (validation).
|
|
371
|
-
|
|
372
|
-
**The principle:** Liquid where you want flexibility. Solid where you need safety.
|
|
65
|
+
| `infernoflow init` | Scaffold inferno/ in your project |
|
|
66
|
+
| `infernoflow install-cursor-hooks` | MCP server + hooks + .cursor/mcp.json |
|
|
67
|
+
| `infernoflow install-vscode-copilot-hooks` | VS Code + Copilot hooks (Preview) |
|
|
68
|
+
| `infernoflow status` | Contract health at a glance |
|
|
69
|
+
| `infernoflow check` | Full validation |
|
|
70
|
+
| `infernoflow suggest` | AI-powered contract update |
|
|
71
|
+
| `infernoflow run` | One-command flow with rollback |
|
|
72
|
+
| `infernoflow implement` | Generate coding agent prompts |
|
|
73
|
+
| `infernoflow context` | Build AI session context |
|
|
74
|
+
| `infernoflow doc-gate` | Fail if docs not updated |
|
|
75
|
+
| `infernoflow pr-impact` | Analyze PR capability drift |
|
|
373
76
|
|
|
374
77
|
## CI Integration
|
|
375
|
-
|
|
376
78
|
```yaml
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
382
|
-
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
79
|
+
- name: infernoflow check
|
|
80
|
+
run: npx infernoflow check --json
|
|
81
|
+
- name: infernoflow doc-gate
|
|
82
|
+
run: npx infernoflow doc-gate --json
|
|
383
83
|
```
|
|
384
84
|
|
|
385
|
-
|
|
386
|
-
- `scripts/inferno-install-hooks.mjs`
|
|
387
|
-
- `.github/workflows/infernoflow-check.yml`
|
|
388
|
-
|
|
389
|
-
Install local hooks once per clone:
|
|
390
|
-
|
|
391
|
-
```bash
|
|
392
|
-
npm run inferno:hooks
|
|
393
|
-
```
|
|
85
|
+
## Troubleshooting
|
|
394
86
|
|
|
395
|
-
|
|
87
|
+
- **MCP not showing in Cursor** — restart Cursor completely after install-cursor-hooks
|
|
88
|
+
- `ide_agent_bridge_not_configured` — use MCP tools in Cursor chat instead
|
|
89
|
+
- **infernoflow not found** — use `npx infernoflow` or install globally
|
|
90
|
+
- **PowerShell scripts disabled** — run `Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass`
|
|
396
91
|
|
|
397
|
-
|
|
398
|
-
npm test
|
|
399
|
-
npm pack --dry-run
|
|
400
|
-
node bin/infernoflow.mjs --help
|
|
401
|
-
node bin/infernoflow.mjs check --help
|
|
402
|
-
```
|
|
92
|
+
## Why infernoflow?
|
|
403
93
|
|
|
404
|
-
|
|
94
|
+
AI-assisted development moves fast. Code changes daily. But what does the system *actually do*? infernoflow keeps the answer current — automatically.
|
|
405
95
|
|
|
406
96
|
## License
|
|
407
|
-
|
|
408
|
-
MIT
|
|
97
|
+
MIT
|
package/dist/bin/infernoflow.mjs
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as d}from"node:fs";import{dirname as m,join as f}from"node:path";import{fileURLToPath as u}from"node:url";import{bold as
|
|
2
|
+
import{readFileSync as d}from"node:fs";import{dirname as m,join as f}from"node:path";import{fileURLToPath as u}from"node:url";import{bold as t,gray as e,red as a}from"../lib/ui/output.mjs";const h=m(u(import.meta.url)),y=JSON.parse(d(f(h,"..","package.json"),"utf8")),i=y.version||"0.0.0",c={setup:"One command to get fully operational \u2014 detects IDE, inits, installs hooks + MCP",init:"Scaffold inferno/ in your project (or adopt existing project)","install-cursor-hooks":"Install Cursor hooks: draft agent replies to inferno/CONTEXT.draft.md","install-vscode-copilot-hooks":"Install VS Code + Copilot agent hooks (Preview): draft to inferno/CONTEXT.draft.md",check:"Validate contract, capabilities, scenarios, changelog",status:"Show contract health at a glance","pr-impact":"Summarize PR impact on capabilities and docs",sync:"Run deterministic inferno sync flow",run:"One-command detect/propose/apply/validate flow","doc-gate":"Fail if code changed but docs were not updated",suggest:"Generate AI prompt + apply capability updates",implement:"Generate code-agent implementation prompt(s)",context:"Generate AI-ready context for new sessions","generate-skills":"Generate personalised Cursor rules + skill files from your developer profile"},l={setup:async o=>(await import("../lib/commands/setup.mjs")).setupCommand(o),init:async o=>(await import("../lib/commands/init.mjs")).initCommand(o),"install-cursor-hooks":async o=>(await import("../lib/commands/installCursorHooks.mjs")).installCursorHooksCommand(o),"install-vscode-copilot-hooks":async o=>(await import("../lib/commands/installVsCodeCopilotHooks.mjs")).installVsCodeCopilotHooksCommand(o),check:async o=>(await import("../lib/commands/check.mjs")).checkCommand(o),status:async o=>(await import("../lib/commands/status.mjs")).statusCommand(o),"pr-impact":async o=>(await import("../lib/commands/prImpact.mjs")).prImpactCommand(o),sync:async o=>(await import("../lib/commands/syncAuto.mjs")).syncCommand(o),run:async o=>(await import("../lib/commands/run.mjs")).runCommand(o),suggest:async o=>(await import("../lib/commands/suggest.mjs")).suggestCommand(o),implement:async o=>(await import("../lib/commands/implement.mjs")).implementCommand(o),context:async o=>(await import("../lib/commands/context.mjs")).contextCommand(o),"doc-gate":async o=>(await import("../lib/commands/docGate.mjs")).docGateCommand(o),"generate-skills":async o=>(await import("../lib/commands/generateSkills.mjs")).generateSkillsCommand(o)};function g(){const o=Object.keys(c),s=Math.max(...o.map(r=>r.length),8)+1;return Object.entries(c).map(([r,p])=>` ${r.padEnd(s," ")}${p}`).join(`
|
|
3
3
|
`)}const w=`
|
|
4
|
-
${
|
|
5
|
-
${
|
|
4
|
+
${t("\u{1F525} infernoflow")} ${e("v"+i)}
|
|
5
|
+
${e("The forge for liquid code \u2014 keep every AI session in sync")}
|
|
6
6
|
|
|
7
|
-
${
|
|
7
|
+
${t("Usage:")}
|
|
8
8
|
infernoflow <command> [options]
|
|
9
9
|
|
|
10
|
-
${
|
|
10
|
+
${t("Commands:")}
|
|
11
11
|
${g()}
|
|
12
12
|
|
|
13
|
-
${
|
|
13
|
+
${t("setup options:")}
|
|
14
|
+
--yes, -y Skip prompts (non-interactive)
|
|
15
|
+
--force, -f Overwrite existing hook files
|
|
16
|
+
|
|
17
|
+
${t("init options:")}
|
|
14
18
|
--cursor-hooks Also install Cursor hooks (draft \u2192 inferno/CONTEXT.draft.md)
|
|
15
19
|
--vscode-copilot-hooks Also install VS Code + Copilot hooks (.github/hooks \u2014 Preview)
|
|
16
20
|
--adopt Infer capabilities from an existing codebase
|
|
@@ -23,46 +27,52 @@ ${g()}
|
|
|
23
27
|
--yes, -y Skip prompts and accept inferred/default values
|
|
24
28
|
--force, -f Overwrite existing inferno/ files
|
|
25
29
|
|
|
26
|
-
${
|
|
30
|
+
${t("install-cursor-hooks options:")}
|
|
27
31
|
--force, -f Overwrite .cursor/hooks.json and hook scripts if they exist
|
|
28
32
|
|
|
29
|
-
${
|
|
33
|
+
${t("install-vscode-copilot-hooks options:")}
|
|
30
34
|
--force, -f Overwrite .github/hooks/infernoflow-drafts.json and scripts if they exist
|
|
31
35
|
|
|
32
|
-
${
|
|
36
|
+
${t("context options:")}
|
|
33
37
|
--intent "..." What you plan to build next
|
|
34
38
|
--working "..." What you are building right now
|
|
35
39
|
--decision "..." Record a decision or note
|
|
36
40
|
--show Print context without writing file
|
|
37
41
|
--copy, -c Copy context to clipboard instantly
|
|
38
42
|
--reset Clear all stored state
|
|
43
|
+
--watch Poll git diff every 30s and auto-update CONTEXT.md (living context)
|
|
44
|
+
--interval <secs> Watch poll interval in seconds (default: 30)
|
|
45
|
+
|
|
46
|
+
${t("generate-skills options:")}
|
|
47
|
+
--cursor Also install rules to .cursor/rules/infernoflow.md
|
|
48
|
+
--force, -f Overwrite existing generated skill files
|
|
39
49
|
|
|
40
|
-
${
|
|
50
|
+
${t("implement options:")}
|
|
41
51
|
--mode <type> cursor | generic | both (default: both)
|
|
42
52
|
--copy, -c Copy generated prompt(s) to clipboard
|
|
43
53
|
|
|
44
|
-
${
|
|
54
|
+
${t("run options:")}
|
|
45
55
|
--dry-run Execute full flow without writing files
|
|
46
56
|
--json Emit machine-readable events and result payload
|
|
47
57
|
--no-rollback Keep changes even if validation fails
|
|
48
58
|
--provider <type> auto | agent | local | prompt (default: auto)
|
|
49
59
|
--ide <name> auto | cursor | vscode | windsurf (default: auto)
|
|
50
60
|
|
|
51
|
-
${
|
|
52
|
-
${
|
|
53
|
-
${
|
|
54
|
-
${
|
|
55
|
-
${
|
|
56
|
-
${
|
|
61
|
+
${t("Typical workflow:")}
|
|
62
|
+
${e('1. infernoflow context --intent "what I want to build"')}
|
|
63
|
+
${e("2. [paste inferno/CONTEXT.md into Claude / Cursor / Copilot]")}
|
|
64
|
+
${e("3. [build the feature]")}
|
|
65
|
+
${e('4. infernoflow suggest "what I built"')}
|
|
66
|
+
${e("5. infernoflow check")}
|
|
57
67
|
|
|
58
|
-
${
|
|
59
|
-
${
|
|
60
|
-
${
|
|
61
|
-
${
|
|
62
|
-
${
|
|
63
|
-
${
|
|
64
|
-
${
|
|
65
|
-
|
|
66
|
-
Unknown command: ${n}`)),console.error(
|
|
67
|
-
`)),process.exit(1));const
|
|
68
|
+
${t("Machine output:")}
|
|
69
|
+
${e("status --json")}
|
|
70
|
+
${e("check --json")}
|
|
71
|
+
${e("doc-gate --json")}
|
|
72
|
+
${e("pr-impact --json")}
|
|
73
|
+
${e("sync --auto --json")}
|
|
74
|
+
${e('run "task" --json')}
|
|
75
|
+
`;import*as k from"node:fs";import*as C from"node:path";try{const o=C.join(process.cwd(),"inferno");if(k.existsSync(o)){const{observeCommandStart:s}=await import("../lib/learning/observe.mjs"),r=process.argv[2];r&&!r.startsWith("-")&&s(o,r)}}catch{}const[,,n,...v]=process.argv;(!n||n==="--help"||n==="-h")&&(console.log(w),process.exit(0)),(n==="--version"||n==="-v")&&(console.log(i),process.exit(0));const b=Object.keys(l);b.includes(n)||(console.error(a(`
|
|
76
|
+
Unknown command: ${n}`)),console.error(e(`Run: infernoflow --help
|
|
77
|
+
`)),process.exit(1));const $=[n,...v];l[n]($).catch(o=>{console.error(a(`
|
|
68
78
|
Error: `)+o.message),process.exit(1)});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as z from"node:fs";import*as w from"node:path";function S(m){try{return z.readFileSync(m,"utf8")}catch{return""}}function v(m,y){const d=new Set,p=new Set,h=new Set,u=new Set,A=new Set,f=new Map,c=(t,n,o,a)=>{f.has(t)||f.set(t,{id:t,title:n,reason:o,sourceFiles:new Set}),f.get(t).sourceFiles.add(w.relative(m,a))};for(const t of y){const n=w.relative(m,t).replace(/\\/g,"/"),o=S(t);if(o){if(/\.(ts)$/.test(t)){const a=o.matchAll(/@Component\s*\([^)]*\)[\s\S]*?class\s+([A-Z][A-Za-z0-9_]*Component)/g);for(const e of a){const s=e[1].replace(/Component$/,"");d.add(s);const i=s.endsWith("Page")||s.endsWith("View")?`View${s.replace(/(Page|View)$/,"")}`:`View${s}`;c(i,`View ${s.replace(/([A-Z])/g," $1").trim()}`,`@Component class detected: ${e[1]}`,t)}const l=o.matchAll(/@Injectable[\s\S]*?class\s+([A-Z][A-Za-z0-9_]*Service)/g);for(const e of l)h.add(e[1]);if([...o.matchAll(/FormBuilder|FormGroup|FormControl/g)].length>0){const e=o.matchAll(/['"]([a-zA-Z][a-zA-Z0-9_]*)['"]:\s*(?:this\.\w+\.control|new FormControl|\[)/g);for(const s of e)A.add(s[1])}}if(n.includes("routing")||n.includes("routes")||n.endsWith("app.routes.ts")){const a=o.matchAll(/\bpath\s*:\s*['"`]([^'"`]+)['"`]/g);for(const r of a){const e=r[1].trim();if(e&&e!=="**"&&!e.startsWith(":")){p.add(e);const s=e.split("/").filter(Boolean);if(s.length>=1){const i=s[s.length-1],C="View"+i.charAt(0).toUpperCase()+i.slice(1).replace(/-([a-z])/g,(g,F)=>F.toUpperCase()),$="View "+i.replace(/-/g," ").replace(/\b\w/g,g=>g.toUpperCase());c(C,$,`Route detected: /${e}`,t)}}}const l=o.matchAll(/loadChildren\s*:\s*\(\s*\)\s*=>\s*import\s*\(['"`]([^'"`]+)['"`]\)/g);for(const r of l)u.add(r[1])}if(/\.html$/.test(t)){const a=o.matchAll(/routerLink\s*=\s*['"`]([^'"`]+)['"`]/g);for(const r of a)p.add(r[1].replace(/^\//,""));const l=o.matchAll(/\(click\)\s*=\s*["']([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g);for(const r of l){const e=r[1];/delete|remove/i.test(e)&&c("DeleteItem","Delete Item",`(click) handler: ${e}`,t),/create|add|new/i.test(e)&&c("CreateItem","Create Item",`(click) handler: ${e}`,t),/submit|save/i.test(e)&&c("UpdateItem","Update Item",`(click) handler: ${e}`,t)}}}}return{components:Array.from(d).sort(),routes:Array.from(p).sort(),services:Array.from(h).sort(),lazyModules:Array.from(u).sort(),formFields:Array.from(A).sort(),capabilities:Array.from(f.values()).map(t=>({...t,sourceFiles:Array.from(t.sourceFiles)}))}}export{v as scanAngular};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as h from"node:fs";import"node:path";function g(c){try{return h.readFileSync(c,"utf8")}catch{return""}}function w(c,l){const t=new Set,a=new Set,s=new Set,d=new Set,f=new Set,m=l.filter(o=>/\.(css|scss|sass|less|styl)$/.test(o)||/\.(ts|tsx|js|jsx)$/.test(o)&&!o.includes("node_modules"));for(const o of m){const i=g(o);if(!i)continue;const u=i.matchAll(/--([a-zA-Z][a-zA-Z0-9_-]*)\s*:/g);for(const e of u){const r=`--${e[1]}`;t.add(r),/color|colour|bg|background|text|border|shadow|fill|stroke/i.test(e[1])?a.add(r):/space|spacing|gap|padding|margin|size|radius|width|height/i.test(e[1])?s.add(r):/theme|primary|secondary|accent|brand|dark|light/i.test(e[1])&&f.add(r)}if(/\.(css|scss|sass|less)$/.test(o)){const e=i.matchAll(/^\s*\.([a-zA-Z][a-zA-Z0-9_-]*)[\s{,]/gm);for(const r of e){const n=r[1];n.length<4||/^(flex|grid|block|hidden|text|font|bg|border|p-|m-|w-|h-)/.test(n)||/^(active|disabled|hover|focus|error|success|warning)$/.test(n)||d.add(n)}}if(/\.(ts|tsx|js|jsx)$/.test(o)){const e=i.matchAll(/(?:styled|css)`[^`]*--([a-zA-Z][a-zA-Z0-9_-]*)\s*:/g);for(const n of e)t.add(`--${n[1]}`);const r=i.matchAll(/\[--([a-zA-Z][a-zA-Z0-9_-]*)\]/g);for(const n of r)t.add(`--${n[1]}`)}}return{designTokens:Array.from(t).sort().slice(0,40),colorTokens:Array.from(a).sort().slice(0,20),spacingTokens:Array.from(s).sort().slice(0,15),componentClasses:Array.from(d).sort().slice(0,30),themeVars:Array.from(f).sort().slice(0,15)}}function y(c,l=[]){const t=s=>l.includes(s),a=s=>s.test(c);return t("tailwindcss")||a(/\b(?:flex|grid|px-\d|py-\d|text-\w+|bg-\w+|rounded)/)?"tailwind":t("bootstrap")||a(/\b(?:container|row|col-|btn btn-|navbar|card)/)?"bootstrap":l.some(s=>s.startsWith("@angular/material"))?"angular-material":t("antd")||a(/\bant-/)?"ant-design":t("@mui/material")||t("@material-ui/core")?"mui":t("styled-components")?"styled-components":t("@emotion/react")||t("@emotion/styled")?"emotion":t("@chakra-ui/react")?"chakra-ui":t("@radix-ui/react-primitive")?"radix-ui":"unknown"}export{y as detectCSSFramework,w as scanCSS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as w from"node:fs";import*as C from"node:path";function k(c){try{return w.readFileSync(c,"utf8")}catch{return""}}function I(c,d){const n=new Set,l=new Set,i=new Set,r=new Map,a=(t,s,m,f)=>{r.has(t)||r.set(t,{id:t,title:s,reason:m,sourceFiles:new Set}),r.get(t).sourceFiles.add(C.relative(c,f))};for(const t of d){if(!/\.(tsx?|jsx?)$/.test(t))continue;const s=k(t);if(!s)continue;const m=s.matchAll(/export\s+(?:default\s+)?function\s+([A-Z][A-Za-z0-9_]*)\s*\(/g);for(const o of m)if(n.add(o[1]),/Page|View|Screen|Dashboard|Panel|Modal|Dialog/i.test(o[1])){const e="View"+o[1].replace(/(Page|View|Screen|Dashboard|Panel|Modal|Dialog)$/,"");a(e,`View ${o[1].replace(/([A-Z])/g," $1").trim()}`,`React component: ${o[1]}`,t)}const f=s.matchAll(/(?:export\s+)?const\s+([A-Z][A-Za-z0-9_]*)\s*=\s*(?:React\.memo\()?(?:\([^)]*\)|[a-zA-Z_]\w*)\s*=>/g);for(const o of f)n.add(o[1]);const p=s.matchAll(/export\s+(?:default\s+)?function\s+(use[A-Z][A-Za-z0-9_]*)\s*\(/g);for(const o of p)l.add(o[1]);const h=s.matchAll(/(?:export\s+)?const\s+(use[A-Z][A-Za-z0-9_]*)\s*=/g);for(const o of h)l.add(o[1]);const u=s.matchAll(/<Route[^>]+path\s*=\s*["'`]([^"'`]+)["'`]/g);for(const o of u){const e=o[1].replace(/^\//,"").replace(/:[\w]+/g,"{id}");e&&i.add(e)}const g=s.matchAll(/path\s*:\s*["'`]([^"'`]+)["'`]/g);for(const o of g){const e=o[1].replace(/^\//,"").replace(/:[\w]+/g,"{id}");e&&e!=="*"&&e.length<60&&i.add(e)}const A=s.matchAll(/onClick\s*=\s*\{(?:[^}]*\b(delete|remove|create|add|submit|save|search|filter|toggle|update|edit)\b[^}]*)\}/gi);for(const o of A){const e=o[1].toLowerCase();(e==="delete"||e==="remove")&&a("DeleteItem","Delete Item",`onClick handler contains "${e}"`,t),(e==="create"||e==="add")&&a("CreateItem","Create Item",`onClick handler contains "${e}"`,t),(e==="submit"||e==="save"||e==="update"||e==="edit")&&a("UpdateItem","Update Item",`onClick handler contains "${e}"`,t),e==="search"&&a("SearchItems","Search Items",'onClick handler contains "search"',t),e==="filter"&&a("FilterItems","Filter Items",'onClick handler contains "filter"',t),e==="toggle"&&a("ToggleComplete","Toggle Complete",'onClick handler contains "toggle"',t)}}return{components:Array.from(n).sort(),customHooks:Array.from(l).sort(),routes:Array.from(i).sort(),capabilities:Array.from(r.values()).map(t=>({...t,sourceFiles:Array.from(t.sourceFiles)}))}}export{I as scanReact};
|