infernoflow 0.42.0 → 0.42.1
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/CHANGELOG.md +14 -0
- package/README.md +30 -1
- package/dist/bin/infernoflow.mjs +22 -21
- package/dist/lib/commands/amp.mjs +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog — infernoflow
|
|
2
2
|
|
|
3
|
+
## 0.42.1 — 2026-05-03
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`infernoflow amp` subsystem** — first-class verbs for the AI Memory Protocol:
|
|
7
|
+
- `infernoflow amp` (or `amp status`) — prints AMP conformance level, layout state (.ai-memory/ vs legacy inferno/), and entry breakdown by type.
|
|
8
|
+
- `infernoflow amp migrate` — copies legacy `inferno/sessions.jsonl` into `.ai-memory/sessions.jsonl` with AMP-shape translation. Idempotent. Leaves the original untouched.
|
|
9
|
+
- `infernoflow amp validate` — schema-checks every entry in `sessions.jsonl` against AMP v1.0 (type enum, msg ≤ 500 chars, ts as Unix-ms integer, ULID format, tool enum, confidence range). Surfaces parse errors and schema violations with line numbers.
|
|
10
|
+
- `infernoflow amp version` — prints the AMP spec version (1.0).
|
|
11
|
+
- **README repositioned** — leads with "infernoflow is the reference CLI for AMP". New "AI Memory Protocol" section explaining `.ai-memory/` layout, wire format, and the migration path.
|
|
12
|
+
- **`amp` namespace added to `--help`** — joins contract / cloud / dev as the four subsystem dispatchers.
|
|
13
|
+
|
|
14
|
+
### Internal
|
|
15
|
+
- Verified end-to-end: legacy `inferno/sessions.jsonl` with `summary` / `agent` / `result` / non-AMP types → `infernoflow amp migrate` → AMP-shape entries on disk → `infernoflow amp validate` reports 3/3 conform → `infernoflow ask` finds them via the normalization layer.
|
|
16
|
+
|
|
3
17
|
## 0.42.0 — 2026-05-03
|
|
4
18
|
|
|
5
19
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# 🔥 infernoflow
|
|
2
2
|
|
|
3
|
-
> Persistent memory for AI coding sessions. Captures what agents can't infer from code: gotchas, decisions, dead ends. Replays it into your next AI chat so you stop re-
|
|
3
|
+
> Persistent memory for AI coding sessions. Captures what agents can't infer from code: gotchas, decisions, dead ends. Replays it into your next AI chat so you stop re-deriving context every time.
|
|
4
|
+
>
|
|
5
|
+
> infernoflow is the reference CLI for [**AMP — the AI Memory Protocol**](docs/protocol/PROTOCOL.md). Any AMP-compatible tool can read your `.ai-memory/sessions.jsonl` — Cursor, Copilot, Claude, Windsurf, future agents. Vendor-neutral, file-based, zero deps.
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/infernoflow)
|
|
6
8
|
[](https://www.npmjs.com/package/infernoflow)
|
|
@@ -45,6 +47,33 @@ These five cover 90% of usage:
|
|
|
45
47
|
|
|
46
48
|
Run `infernoflow commands` for the full grouped list (51 commands across Session Memory, Code Analysis, Workflow, Cloud, Setup, Advanced).
|
|
47
49
|
|
|
50
|
+
## The AI Memory Protocol (AMP)
|
|
51
|
+
|
|
52
|
+
infernoflow stores memory in the AMP-canonical layout:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
.ai-memory/
|
|
56
|
+
├── sessions.jsonl # one AMP entry per line (gotchas, decisions, attempts, notes…)
|
|
57
|
+
├── amp.json # project metadata
|
|
58
|
+
└── handoff.md # generated handoff for AI agents
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Each entry on disk is AMP wire format:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{"type":"gotcha","msg":"API returns 202 not 200","ts":1714704000000,"id":"amp_01HXYZ...","file":"src/api.js","line":42}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The full spec is in [docs/protocol/PROTOCOL.md](docs/protocol/PROTOCOL.md). Any tool that can parse JSONL can read your memory — that's the whole point. infernoflow is currently the **AMP Full** reference implementation: read + write + handoff + injection across CLAUDE.md / .cursorrules / copilot-instructions.md.
|
|
68
|
+
|
|
69
|
+
If you have a project on the legacy `inferno/sessions.jsonl` layout, migrate with one command:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
infernoflow amp migrate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The original `inferno/sessions.jsonl` is left in place — nothing is overwritten.
|
|
76
|
+
|
|
48
77
|
## Auto-context for AI agents
|
|
49
78
|
|
|
50
79
|
When you run `infernoflow log`, infernoflow silently keeps these files up to date so any AI agent reading them gets your latest gotchas/decisions automatically:
|
package/dist/bin/infernoflow.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
(function(){if(process.platform!=="win32"||process.env.WT_SESSION||process.env.ConEmuPID||process.env.TERM_PROGRAM==="vscode")return;const a={"\u2500":"-","\u2501":"-","\u2550":"=","\u2502":"|","\u2503":"|","\u2551":"|","\u250C":"+","\u2510":"+","\u2514":"+","\u2518":"+","\u251C":"+","\u2524":"+","\u252C":"+","\u2534":"+","\u253C":"+","\xB7":"*","\u2192":"->","\u2190":"<-","\u2714":"[OK]","\u2713":"[OK]","\u2718":"[X]","\u2717":"[X]","\u26A0":"[!]",\u2139:"[i]"},n=new RegExp(Object.keys(a).join("|"),"g");function i(c){const d=c.write.bind(c);c.write=function(s,...p){if(typeof s=="string")s=s.replace(n,f=>a[f]);else if(Buffer.isBuffer(s)){const f=s.toString("utf8").replace(n,k=>a[k]);s=Buffer.from(f,"utf8")}return d(s,...p)}}i(process.stdout),i(process.stderr)})();import{readFileSync as $}from"node:fs";import{dirname as S,join as g}from"node:path";import{fileURLToPath as x}from"node:url";import{bold as m,gray as e,cyan as t,red as u}from"../lib/ui/output.mjs";const O=S(x(import.meta.url));function A(o){for(const a of[g(o,"..","..","package.json"),g(o,"..","package.json")])try{return JSON.parse($(a,"utf8"))}catch{}return{version:"0.0.0-source"}}const R=A(O),h=R.version||"0.0.0",y={publish:"Bump version, update changelog, build, npm publish, git commit + push in one shot",diff:"Show what capabilities changed since the last git tag (or any ref)",changelog:"Draft a changelog entry from commits since the last tag",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",dashboard:"Launch local web dashboard on localhost:7337 \u2014 live contract health, capabilities, agents",login:"Sign in with GitHub \u2014 syncs session memory to the cloud on every log",logout:"Sign out and remove local credentials",whoami:"Show currently logged-in user",cloud:"Sync capability contracts via infernoflow cloud (init | push | pull | status | dashboard)",watch:"Watch source files and run suggest automatically on save",ci:"CI-native check: GitHub Actions annotations, GitLab code quality, exit codes",notify:"Post capability drift summary to Slack or Discord",monorepo:"Manage infernoflow across monorepo packages (init | list | status | diff | sync)",doctor:"Diagnose your infernoflow setup \u2014 checks Node, git, contract, AI providers, MCP, hooks",coverage:"Map test files to capabilities \u2014 show which caps have test coverage and which don't",review:"AI-powered capability impact review for staged or recent git changes",scan:"Deep AST scan \u2014 route discovery, entry point detection, HTTP URL extraction, capability suggestions",graph:"Build capability dependency graph \u2014 shows which caps call which, detects breaking changes",stability:"Show solid/liquid stability level for every capability (frozen/stable/experimental)",freeze:"Mark a capability as frozen (solid) \u2014 AI will not modify it without explicit instruction",thaw:"Reset a capability to experimental (liquid) \u2014 free to evolve",why:"Given a file or function name \u2014 show which capability it serves, scenarios, stability, and git history",impact:"Blast radius analysis \u2014 see every cap, scenario, and risk level affected before you change anything",scaffold:"Generate a new capability \u2014 source skeleton, contract registration, and placeholder scenario in one command",explain:"AI narrative about a capability \u2014 what it does, why it exists, what's risky, and what to test",test:"Run registered scenarios for a capability \u2014 auto-generates a smoke harness if no test runner is configured",ai:"Manage AI providers \u2014 setup, status, test connection (subcommands: setup | status | test | clear)",demo:"Interactive walkthrough \u2014 scaffolds a sample project and runs the full capability chain end-to-end",feedback:"60-second CLI survey about how you use infernoflow (--form to open web form)",telemetry:"Manage anonymous usage telemetry (on | off | status) \u2014 opt-in, command names only",log:"Append to session memory (decisions, gotchas, failed attempts, theme changes) \u2014 what AI can't infer from code",theme:"Scan fonts, colors, and CSS variables \u2014 write inferno/theme.json so AI always matches the design system",switch:"Generate a handoff summary when switching AI agents \u2014 paste into the next session so nothing is lost",upgrade:"Upgrade a lite infernoflow setup to the full structure (scenarios, changelog, scripts)",stats:"Value dashboard \u2014 session memory, tokens injected per session, coverage %, estimated savings",ask:"Query session memory \u2014 search gotchas, decisions, and failed attempts by keyword or type",recap:"End-of-session summary \u2014 what was captured, what git changes weren't logged, session health score",uninstall:"Remove infernoflow from a project \u2014 inferno/, CLAUDE.md, MCP server, git hooks (--dry-run to preview)",contract:"Capability contracts \u2014 scan, freeze, impact, graph, scaffold, etc. (run: infernoflow contract)",dev:"Maintenance & integration \u2014 publish, changelog, dashboard, ai, ci, sync, etc. (run: infernoflow dev)"},l={publish:async o=>(await import("../lib/commands/publish.mjs")).publishCommand(o),diff:async o=>(await import("../lib/commands/diff.mjs")).diffCommand(o),changelog:async o=>(await import("../lib/commands/changelog.mjs")).changelogCommand(o),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),dashboard:async o=>(await import("../lib/commands/dashboard.mjs")).dashboardCommand(o),login:async o=>(await import("../lib/commands/login.mjs")).loginCommand(o),logout:async()=>(await import("../lib/commands/login.mjs")).logoutCommand(),whoami:async()=>(await import("../lib/commands/login.mjs")).whoamiCommand(),cloud:async o=>(await import("../lib/commands/cloud.mjs")).cloudCommand(o),watch:async o=>(await import("../lib/commands/watch.mjs")).watchCommand(o),ci:async o=>(await import("../lib/commands/ci.mjs")).ciCommand(o),notify:async o=>(await import("../lib/commands/notify.mjs")).notifyCommand(o),monorepo:async o=>(await import("../lib/commands/monorepo.mjs")).monorepoCommand(o),doctor:async o=>(await import("../lib/commands/doctor.mjs")).doctorCommand(o),coverage:async o=>(await import("../lib/commands/coverage.mjs")).coverageCommand(o),review:async o=>(await import("../lib/commands/review.mjs")).reviewCommand(o),scan:async o=>(await import("../lib/commands/scan.mjs")).scanCommand(o),graph:async o=>(await import("../lib/commands/graph.mjs")).graphCommand(o),stability:async o=>(await import("../lib/commands/stability.mjs")).stabilityCommand(o),freeze:async o=>(await import("../lib/commands/stability.mjs")).freezeCommand(o),thaw:async o=>(await import("../lib/commands/stability.mjs")).thawCommand(o),why:async o=>(await import("../lib/commands/why.mjs")).whyCommand(o),impact:async o=>(await import("../lib/commands/impact.mjs")).impactCommand(o),scaffold:async o=>(await import("../lib/commands/scaffold.mjs")).scaffoldCommand(o),explain:async o=>(await import("../lib/commands/explain.mjs")).explainCommand(o),test:async o=>(await import("../lib/commands/test.mjs")).testCommand(o),ai:async o=>(await import("../lib/commands/ai.mjs")).aiCommand(o),demo:async o=>(await import("../lib/commands/demo.mjs")).demoCommand(o),log:async o=>(await import("../lib/commands/log.mjs")).logCommand(o),theme:async o=>(await import("../lib/commands/theme.mjs")).themeCommand(o),switch:async o=>(await import("../lib/commands/switch.mjs")).switchCommand(o),upgrade:async o=>(await import("../lib/commands/upgrade.mjs")).upgradeCommand(o),stats:async o=>(await import("../lib/commands/stats.mjs")).statsCommand(o),ask:async o=>(await import("../lib/commands/ask.mjs")).askCommand(o),recap:async o=>(await import("../lib/commands/recap.mjs")).recapCommand(o),uninstall:async o=>(await import("../lib/commands/uninstall.mjs")).uninstallCommand(o),feedback:async o=>(await import("../lib/commands/feedback.mjs")).feedbackCommand(o),telemetry:async o=>(await import("../lib/telemetry.mjs")).telemetryCommand(o),contract:async o=>w("contract",b,o),dev:async o=>w("dev",v,o)};async function w(o,a,n){const i=n[1];if(!i||i==="--help"||i==="-h"){console.log(),console.log(` ${m("\u{1F525} infernoflow "+o)} ${e("\u2014 available verbs:")}`),console.log();const d=Math.max(...Object.keys(a).map(s=>s.length))+2;for(const s of Object.keys(a)){const p=y[a[s]]||"";console.log(` ${t(s.padEnd(d))} ${e(p)}`)}console.log(),console.log(` ${e("Run")} ${t(`infernoflow ${o} <verb> --help`)} ${e("for verb-specific options.")}`),console.log();return}const c=a[i];return(!c||!l[c])&&(console.error(u(`
|
|
2
|
+
(function(){if(process.platform!=="win32"||process.env.WT_SESSION||process.env.ConEmuPID||process.env.TERM_PROGRAM==="vscode")return;const t={"\u2500":"-","\u2501":"-","\u2550":"=","\u2502":"|","\u2503":"|","\u2551":"|","\u250C":"+","\u2510":"+","\u2514":"+","\u2518":"+","\u251C":"+","\u2524":"+","\u252C":"+","\u2534":"+","\u253C":"+","\xB7":"*","\u2192":"->","\u2190":"<-","\u2714":"[OK]","\u2713":"[OK]","\u2718":"[X]","\u2717":"[X]","\u26A0":"[!]",\u2139:"[i]"},n=new RegExp(Object.keys(t).join("|"),"g");function i(c){const p=c.write.bind(c);c.write=function(s,...d){if(typeof s=="string")s=s.replace(n,f=>t[f]);else if(Buffer.isBuffer(s)){const f=s.toString("utf8").replace(n,k=>t[k]);s=Buffer.from(f,"utf8")}return p(s,...d)}}i(process.stdout),i(process.stderr)})();import{readFileSync as $}from"node:fs";import{dirname as S,join as g}from"node:path";import{fileURLToPath as x}from"node:url";import{bold as m,gray as e,cyan as a,red as u}from"../lib/ui/output.mjs";const A=S(x(import.meta.url));function O(o){for(const t of[g(o,"..","..","package.json"),g(o,"..","package.json")])try{return JSON.parse($(t,"utf8"))}catch{}return{version:"0.0.0-source"}}const I=O(A),h=I.version||"0.0.0",y={publish:"Bump version, update changelog, build, npm publish, git commit + push in one shot",diff:"Show what capabilities changed since the last git tag (or any ref)",changelog:"Draft a changelog entry from commits since the last tag",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",dashboard:"Launch local web dashboard on localhost:7337 \u2014 live contract health, capabilities, agents",login:"Sign in with GitHub \u2014 syncs session memory to the cloud on every log",logout:"Sign out and remove local credentials",whoami:"Show currently logged-in user",cloud:"Sync capability contracts via infernoflow cloud (init | push | pull | status | dashboard)",watch:"Watch source files and run suggest automatically on save",ci:"CI-native check: GitHub Actions annotations, GitLab code quality, exit codes",notify:"Post capability drift summary to Slack or Discord",monorepo:"Manage infernoflow across monorepo packages (init | list | status | diff | sync)",doctor:"Diagnose your infernoflow setup \u2014 checks Node, git, contract, AI providers, MCP, hooks",coverage:"Map test files to capabilities \u2014 show which caps have test coverage and which don't",review:"AI-powered capability impact review for staged or recent git changes",scan:"Deep AST scan \u2014 route discovery, entry point detection, HTTP URL extraction, capability suggestions",graph:"Build capability dependency graph \u2014 shows which caps call which, detects breaking changes",stability:"Show solid/liquid stability level for every capability (frozen/stable/experimental)",freeze:"Mark a capability as frozen (solid) \u2014 AI will not modify it without explicit instruction",thaw:"Reset a capability to experimental (liquid) \u2014 free to evolve",why:"Given a file or function name \u2014 show which capability it serves, scenarios, stability, and git history",impact:"Blast radius analysis \u2014 see every cap, scenario, and risk level affected before you change anything",scaffold:"Generate a new capability \u2014 source skeleton, contract registration, and placeholder scenario in one command",explain:"AI narrative about a capability \u2014 what it does, why it exists, what's risky, and what to test",test:"Run registered scenarios for a capability \u2014 auto-generates a smoke harness if no test runner is configured",ai:"Manage AI providers \u2014 setup, status, test connection (subcommands: setup | status | test | clear)",demo:"Interactive walkthrough \u2014 scaffolds a sample project and runs the full capability chain end-to-end",feedback:"60-second CLI survey about how you use infernoflow (--form to open web form)",telemetry:"Manage anonymous usage telemetry (on | off | status) \u2014 opt-in, command names only",log:"Append to session memory (decisions, gotchas, failed attempts, theme changes) \u2014 what AI can't infer from code",theme:"Scan fonts, colors, and CSS variables \u2014 write inferno/theme.json so AI always matches the design system",switch:"Generate a handoff summary when switching AI agents \u2014 paste into the next session so nothing is lost",upgrade:"Upgrade a lite infernoflow setup to the full structure (scenarios, changelog, scripts)",stats:"Value dashboard \u2014 session memory, tokens injected per session, coverage %, estimated savings",ask:"Query session memory \u2014 search gotchas, decisions, and failed attempts by keyword or type",recap:"End-of-session summary \u2014 what was captured, what git changes weren't logged, session health score",uninstall:"Remove infernoflow from a project \u2014 inferno/, CLAUDE.md, MCP server, git hooks (--dry-run to preview)",contract:"Capability contracts \u2014 scan, freeze, impact, graph, scaffold, etc. (run: infernoflow contract)",dev:"Maintenance & integration \u2014 publish, changelog, dashboard, ai, ci, sync, etc. (run: infernoflow dev)",amp:"AI Memory Protocol \u2014 status, migrate from legacy, validate (run: infernoflow amp)"},l={publish:async o=>(await import("../lib/commands/publish.mjs")).publishCommand(o),diff:async o=>(await import("../lib/commands/diff.mjs")).diffCommand(o),changelog:async o=>(await import("../lib/commands/changelog.mjs")).changelogCommand(o),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),dashboard:async o=>(await import("../lib/commands/dashboard.mjs")).dashboardCommand(o),login:async o=>(await import("../lib/commands/login.mjs")).loginCommand(o),logout:async()=>(await import("../lib/commands/login.mjs")).logoutCommand(),whoami:async()=>(await import("../lib/commands/login.mjs")).whoamiCommand(),cloud:async o=>(await import("../lib/commands/cloud.mjs")).cloudCommand(o),watch:async o=>(await import("../lib/commands/watch.mjs")).watchCommand(o),ci:async o=>(await import("../lib/commands/ci.mjs")).ciCommand(o),notify:async o=>(await import("../lib/commands/notify.mjs")).notifyCommand(o),monorepo:async o=>(await import("../lib/commands/monorepo.mjs")).monorepoCommand(o),doctor:async o=>(await import("../lib/commands/doctor.mjs")).doctorCommand(o),coverage:async o=>(await import("../lib/commands/coverage.mjs")).coverageCommand(o),review:async o=>(await import("../lib/commands/review.mjs")).reviewCommand(o),scan:async o=>(await import("../lib/commands/scan.mjs")).scanCommand(o),graph:async o=>(await import("../lib/commands/graph.mjs")).graphCommand(o),stability:async o=>(await import("../lib/commands/stability.mjs")).stabilityCommand(o),freeze:async o=>(await import("../lib/commands/stability.mjs")).freezeCommand(o),thaw:async o=>(await import("../lib/commands/stability.mjs")).thawCommand(o),why:async o=>(await import("../lib/commands/why.mjs")).whyCommand(o),impact:async o=>(await import("../lib/commands/impact.mjs")).impactCommand(o),scaffold:async o=>(await import("../lib/commands/scaffold.mjs")).scaffoldCommand(o),explain:async o=>(await import("../lib/commands/explain.mjs")).explainCommand(o),test:async o=>(await import("../lib/commands/test.mjs")).testCommand(o),ai:async o=>(await import("../lib/commands/ai.mjs")).aiCommand(o),demo:async o=>(await import("../lib/commands/demo.mjs")).demoCommand(o),log:async o=>(await import("../lib/commands/log.mjs")).logCommand(o),theme:async o=>(await import("../lib/commands/theme.mjs")).themeCommand(o),switch:async o=>(await import("../lib/commands/switch.mjs")).switchCommand(o),upgrade:async o=>(await import("../lib/commands/upgrade.mjs")).upgradeCommand(o),stats:async o=>(await import("../lib/commands/stats.mjs")).statsCommand(o),ask:async o=>(await import("../lib/commands/ask.mjs")).askCommand(o),recap:async o=>(await import("../lib/commands/recap.mjs")).recapCommand(o),uninstall:async o=>(await import("../lib/commands/uninstall.mjs")).uninstallCommand(o),feedback:async o=>(await import("../lib/commands/feedback.mjs")).feedbackCommand(o),telemetry:async o=>(await import("../lib/telemetry.mjs")).telemetryCommand(o),contract:async o=>w("contract",b,o),dev:async o=>w("dev",v,o),amp:async o=>(await import("../lib/commands/amp.mjs")).ampCommand(o)};async function w(o,t,n){const i=n[1];if(!i||i==="--help"||i==="-h"){console.log(),console.log(` ${m("\u{1F525} infernoflow "+o)} ${e("\u2014 available verbs:")}`),console.log();const p=Math.max(...Object.keys(t).map(s=>s.length))+2;for(const s of Object.keys(t)){const d=y[t[s]]||"";console.log(` ${a(s.padEnd(p))} ${e(d)}`)}console.log(),console.log(` ${e("Run")} ${a(`infernoflow ${o} <verb> --help`)} ${e("for verb-specific options.")}`),console.log();return}const c=t[i];return(!c||!l[c])&&(console.error(u(`
|
|
3
3
|
Unknown ${o} verb: ${i}`)),console.error(e(` Run: infernoflow ${o} (see all verbs)
|
|
4
|
-
`)),process.exit(1)),l[c]([c,...n.slice(2)])}function U(){const o=Object.keys(y),
|
|
5
|
-
`)}const b={scan:"scan",check:"check",status:"status",freeze:"freeze",thaw:"thaw",why:"why",impact:"impact",graph:"graph",stability:"stability",scaffold:"scaffold",explain:"explain",test:"test",coverage:"coverage",suggest:"suggest",run:"run",implement:"implement","doc-gate":"doc-gate","pr-impact":"pr-impact",review:"review",demo:"demo",upgrade:"upgrade",context:"context",sync:"sync"},v={publish:"publish",changelog:"changelog",diff:"diff",dashboard:"dashboard",monorepo:"monorepo",ci:"ci",ai:"ai",theme:"theme",stats:"stats",feedback:"feedback",telemetry:"telemetry",uninstall:"uninstall","generate-skills":"generate-skills","install-cursor-hooks":"install-cursor-hooks","install-vscode-copilot-hooks":"install-vscode-copilot-hooks",setup:"setup"},
|
|
4
|
+
`)),process.exit(1)),l[c]([c,...n.slice(2)])}function U(){const o=Object.keys(y),t=Math.max(...o.map(n=>n.length),8)+1;return Object.entries(y).map(([n,i])=>` ${n.padEnd(t," ")}${i}`).join(`
|
|
5
|
+
`)}const b={scan:"scan",check:"check",status:"status",freeze:"freeze",thaw:"thaw",why:"why",impact:"impact",graph:"graph",stability:"stability",scaffold:"scaffold",explain:"explain",test:"test",coverage:"coverage",suggest:"suggest",run:"run",implement:"implement","doc-gate":"doc-gate","pr-impact":"pr-impact",review:"review",demo:"demo",upgrade:"upgrade",context:"context",sync:"sync"},v={publish:"publish",changelog:"changelog",diff:"diff",dashboard:"dashboard",monorepo:"monorepo",ci:"ci",ai:"ai",theme:"theme",stats:"stats",feedback:"feedback",telemetry:"telemetry",uninstall:"uninstall","generate-skills":"generate-skills","install-cursor-hooks":"install-cursor-hooks","install-vscode-copilot-hooks":"install-vscode-copilot-hooks",setup:"setup"},M={"Memory (top-level)":["log","ask","switch","recap","status"],"Watch (top-level)":["watch"],"Setup (top-level)":["init","doctor"],"AMP (use: infernoflow amp <verb>)":["status","migrate","validate","version"],"Contract (use: infernoflow contract <verb>)":Object.keys(b),"Cloud (use: infernoflow cloud <verb>)":["login","logout","whoami","cloud","notify"],"Dev (use: infernoflow dev <verb>)":Object.keys(v)};function R(){return Object.entries(M).map(([t,n])=>` ${m(t+":")}
|
|
6
6
|
${n.join(" ")}`).join(`
|
|
7
7
|
|
|
8
|
-
`)}const C=Object.keys(l).length,
|
|
8
|
+
`)}const C=Object.keys(l).length,j=`
|
|
9
9
|
${m("\u{1F525} infernoflow")} ${e("v"+h)}
|
|
10
10
|
${e("Persistent memory for AI coding sessions")}
|
|
11
11
|
|
|
@@ -13,29 +13,30 @@
|
|
|
13
13
|
infernoflow [command] [options]
|
|
14
14
|
|
|
15
15
|
${m("Memory")} ${e("\u2014 the 5-command core")}
|
|
16
|
-
${
|
|
17
|
-
${
|
|
18
|
-
${
|
|
19
|
-
${
|
|
20
|
-
${
|
|
16
|
+
${a("log")} ${e('"..."')} Add to session memory ${e("(--type gotcha|decision|attempt)")}
|
|
17
|
+
${a("ask")} ${e('"..."')} Search your memory by keyword ${e("(gotchas surface first)")}
|
|
18
|
+
${a("switch")} Generate handoff for next AI agent
|
|
19
|
+
${a("recap")} End-of-session health score + unlogged changes
|
|
20
|
+
${a("status")} Quick health check
|
|
21
21
|
|
|
22
22
|
${m("Setup")}
|
|
23
|
-
${
|
|
24
|
-
${
|
|
25
|
-
${
|
|
23
|
+
${a("init")} 60-second setup ${e("(memory mode by default)")}
|
|
24
|
+
${a("watch")} Auto-capture mode ${e("(stuck-loops, dep changes, test removals)")}
|
|
25
|
+
${a("doctor")} Diagnose your setup
|
|
26
26
|
|
|
27
27
|
${m("Subsystems")} ${e("\u2014 grouped, run for verbs:")}
|
|
28
|
-
${
|
|
29
|
-
${
|
|
30
|
-
${
|
|
28
|
+
${a("amp")} AI Memory Protocol ${e("(status, migrate, validate)")}
|
|
29
|
+
${a("contract")} Capability contracts ${e("(scan, freeze, impact, scaffold, \u2026)")}
|
|
30
|
+
${a("cloud")} Cloud sync + accounts ${e("(login, push, pull, status, \u2026)")}
|
|
31
|
+
${a("dev")} Publishing, dashboards, AI providers ${e("(publish, ai, ci, \u2026)")}
|
|
31
32
|
|
|
32
|
-
${e("Run")} ${
|
|
33
|
-
${e("Run")} ${
|
|
34
|
-
`;import*as E from"node:fs";import*as
|
|
33
|
+
${e("Run")} ${a("infernoflow commands")} ${e("to see all "+C+" commands grouped.")}
|
|
34
|
+
${e("Run")} ${a("infernoflow <command> --help")} ${e("for command-specific options.")}
|
|
35
|
+
`;import*as E from"node:fs";import*as P from"node:path";try{const o=P.join(process.cwd(),"inferno");if(E.existsSync(o)){const{observeCommandStart:t}=await import("../lib/learning/observe.mjs"),n=process.argv[2];n&&!n.startsWith("-")&&t(o,n)}}catch{}const[,,r,...D]=process.argv;(!r||r==="--help"||r==="-h")&&(console.log(j),process.exit(0)),(r==="--version"||r==="-v")&&(console.log(h),process.exit(0)),r==="commands"&&(console.log(`
|
|
35
36
|
${m("\u{1F525} infernoflow")} ${e("v"+h)} ${e("\u2014 all "+C+" commands")}
|
|
36
|
-
`),console.log(
|
|
37
|
-
${e("Run")} ${
|
|
37
|
+
`),console.log(R()),console.log(`
|
|
38
|
+
${e("Run")} ${a("infernoflow <command> --help")} ${e("for options.")}
|
|
38
39
|
`),process.exit(0));const G=Object.keys(l);G.includes(r)||(console.error(u(`
|
|
39
40
|
Unknown command: ${r}`)),console.error(e("Run: infernoflow commands (see all commands)")),console.error(e(`Run: infernoflow --help (quick start)
|
|
40
|
-
`)),process.exit(1));const T=[r,...
|
|
41
|
+
`)),process.exit(1));const T=[r,...D];l[r](T).catch(o=>{console.error(u(`
|
|
41
42
|
Error: `)+o.message),process.exit(1)});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import*as m from"node:fs";import*as u from"node:path";import{bold as l,cyan as d,gray as s,green as h,yellow as S,red as v}from"../ui/output.mjs";import{AMP_VERSION as y,ampPaths as M,readEntries as A,migrateLegacy as b}from"../amp/io.mjs";const j=new Set(["gotcha","decision","attempt","note","detection","pattern"]),x=new Set(["copilot","cursor","claude","windsurf","other"]);function k(o,n){const e=[];return(!o||typeof o!="object")&&e.push("not an object"),o.type?j.has(o.type)||e.push(`type "${o.type}" not in AMP enum`):e.push("missing required field: type"),o.msg?typeof o.msg!="string"?e.push("msg must be a string"):o.msg.length>500&&e.push(`msg too long (${o.msg.length} > 500)`):e.push("missing required field: msg"),o.ts==null?e.push("missing required field: ts"):(typeof o.ts!="number"||!Number.isFinite(o.ts))&&e.push("ts must be a Unix-ms integer"),o.id&&!/^amp_[0-9A-Z]{26}$/.test(o.id)&&e.push(`id "${o.id}" not in amp_ULID format`),o.tool&&!x.has(o.tool)&&e.push(`tool "${o.tool}" not in AMP enum`),o.confidence!=null&&(o.confidence<0||o.confidence>1)&&e.push("confidence out of range [0,1]"),e}function E(o){const{sessions:n}=M(o);if(!m.existsSync(n))return{sessions:n,entries:[],lines:[]};const e=m.readFileSync(n,"utf8").split(`
|
|
2
|
+
`).filter(Boolean),a=e.map((c,r)=>{try{return{ok:!0,line:r+1,value:JSON.parse(c)}}catch(t){return{ok:!1,line:r+1,value:null,error:t.message}}});return{sessions:n,entries:a,lines:e}}function P(o){const{sessions:n,isAmp:e,root:a}=M(o),c=u.join(o,".ai-memory"),r=u.join(o,"inferno"),t=m.existsSync(c),g=m.existsSync(r)&&m.existsSync(u.join(r,"sessions.jsonl"));if(console.log(),console.log(` ${l("\u{1F525} infernoflow amp")} ${s("\u2014 AI Memory Protocol status")}`),console.log(),console.log(` Spec version ${l(y)}`),console.log(` Conformance level ${l("AMP Full")} ${s("(read + write + handoff + injection)")}`),console.log(),!t&&!g){console.log(` ${S("\u26A0")} ${s("Project not initialised \u2014 run:")} ${d("infernoflow init")}`),console.log();return}if(console.log(` ${l("Layout:")}`),console.log(` .ai-memory/ ${t?h("\u2714 present")+(e?s(" (active)"):""):s("\u2014")}`),console.log(` inferno/ ${g?S("\u26A0 legacy")+(e?"":s(" (active)")):s("\u2014")}`),console.log(),m.existsSync(n)){const f=A(o);if(console.log(` ${l("Memory:")}`),console.log(` file ${s(u.relative(o,n))}`),console.log(` entries ${l(String(f.length))}`),f.length){const i=new Map;for(const $ of f)i.set($.type,(i.get($.type)||0)+1);const p=[...i.entries()].map(([$,w])=>`${$}:${w}`).join(" ");console.log(` breakdown ${s(p)}`)}}g&&!t&&(console.log(),console.log(` ${s("Tip:")} ${d("infernoflow amp migrate")} ${s("copies legacy memory into the AMP layout.")}`)),console.log()}function N(o){console.log(),console.log(` ${l("\u{1F525} infernoflow amp migrate")}`),console.log();const n=b(o);n.migrated>0?(console.log(` ${h("\u2714")} Migrated ${l(String(n.migrated))} entr${n.migrated===1?"y":"ies"} \u2192 ${d(".ai-memory/sessions.jsonl")}`),console.log(` ${s("The original inferno/sessions.jsonl is untouched. See .ai-memory/MIGRATED.md for details.")}`)):console.log(` ${s("Nothing migrated \u2014 ")}${n.reason}${s(".")}`),console.log()}function O(o){console.log(),console.log(` ${l("\u{1F525} infernoflow amp validate")}`),console.log();const{sessions:n,entries:e}=E(o);if(!e.length){console.log(` ${s("No entries to validate at")} ${d(u.relative(o,n))}`),console.log();return}let a=0,c=0,r=0;const t=[];for(const i of e){if(!i.ok){c++,t.push({line:i.line,error:`parse error: ${i.error}`});continue}const p=k(i.value,i.line);p.length?(r++,t.push({line:i.line,error:p.join("; ")})):a++}for(const i of t.slice(0,10))console.log(` ${v("\u2718")} line ${i.line} ${s(i.error)}`);t.length>10&&console.log(` ${s(`\u2026 ${t.length-10} more`)}`),t.length&&console.log();const g=e.length,f=c===0&&r===0;console.log(f?` ${h("\u2714")} ${l(`${a}/${g}`)} entries conform to AMP v${y}.`:` ${v("\u2718")} ${l(`${a}/${g}`)} entries OK \xB7 ${c} parse \xB7 ${r} schema`),console.log(),f||process.exit(1)}function T(){console.log(y)}async function I(o){const n=o[1],e=process.cwd();if(!n||n==="status")return P(e);if(n==="migrate")return N(e);if(n==="validate")return O(e);if(n==="version")return T();if(n==="--help"||n==="-h")return P(e);console.error(v(`
|
|
3
|
+
Unknown amp verb: ${n}`)),console.error(s(` Try: infernoflow amp (status | migrate | validate | version)
|
|
4
|
+
`)),process.exit(1)}export{I as ampCommand};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infernoflow",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.1",
|
|
4
4
|
"description": "Persistent memory for AI coding sessions \u2014 captures what agents can't infer from code alone. Works with Copilot, Cursor, Claude, and Windsurf.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|