infernoflow 0.43.10 → 0.43.12

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.
@@ -1,12 +1,12 @@
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 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 o,cyan as a,red as u}from"../lib/ui/output.mjs";const A=S(x(import.meta.url));function O(e){for(const t of[g(e,"..","..","package.json"),g(e,"..","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",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 e=>(await import("../lib/commands/publish.mjs")).publishCommand(e),diff:async e=>(await import("../lib/commands/diff.mjs")).diffCommand(e),changelog:async e=>(await import("../lib/commands/changelog.mjs")).changelogCommand(e),setup:async e=>(await import("../lib/commands/setup.mjs")).setupCommand(e),init:async e=>(await import("../lib/commands/init.mjs")).initCommand(e),"install-cursor-hooks":async e=>(await import("../lib/commands/installCursorHooks.mjs")).installCursorHooksCommand(e),"install-vscode-copilot-hooks":async e=>(await import("../lib/commands/installVsCodeCopilotHooks.mjs")).installVsCodeCopilotHooksCommand(e),check:async e=>(await import("../lib/commands/check.mjs")).checkCommand(e),status:async e=>(await import("../lib/commands/status.mjs")).statusCommand(e),"pr-impact":async e=>(await import("../lib/commands/prImpact.mjs")).prImpactCommand(e),sync:async e=>(await import("../lib/commands/syncAuto.mjs")).syncCommand(e),run:async e=>(await import("../lib/commands/run.mjs")).runCommand(e),suggest:async e=>(await import("../lib/commands/suggest.mjs")).suggestCommand(e),implement:async e=>(await import("../lib/commands/implement.mjs")).implementCommand(e),context:async e=>(await import("../lib/commands/context.mjs")).contextCommand(e),"doc-gate":async e=>(await import("../lib/commands/docGate.mjs")).docGateCommand(e),"generate-skills":async e=>(await import("../lib/commands/generateSkills.mjs")).generateSkillsCommand(e),watch:async e=>(await import("../lib/commands/watch.mjs")).watchCommand(e),ci:async e=>(await import("../lib/commands/ci.mjs")).ciCommand(e),notify:async e=>(await import("../lib/commands/notify.mjs")).notifyCommand(e),monorepo:async e=>(await import("../lib/commands/monorepo.mjs")).monorepoCommand(e),doctor:async e=>(await import("../lib/commands/doctor.mjs")).doctorCommand(e),coverage:async e=>(await import("../lib/commands/coverage.mjs")).coverageCommand(e),review:async e=>(await import("../lib/commands/review.mjs")).reviewCommand(e),scan:async e=>(await import("../lib/commands/scan.mjs")).scanCommand(e),graph:async e=>(await import("../lib/commands/graph.mjs")).graphCommand(e),stability:async e=>(await import("../lib/commands/stability.mjs")).stabilityCommand(e),freeze:async e=>(await import("../lib/commands/stability.mjs")).freezeCommand(e),thaw:async e=>(await import("../lib/commands/stability.mjs")).thawCommand(e),why:async e=>(await import("../lib/commands/why.mjs")).whyCommand(e),impact:async e=>(await import("../lib/commands/impact.mjs")).impactCommand(e),scaffold:async e=>(await import("../lib/commands/scaffold.mjs")).scaffoldCommand(e),explain:async e=>(await import("../lib/commands/explain.mjs")).explainCommand(e),test:async e=>(await import("../lib/commands/test.mjs")).testCommand(e),ai:async e=>(await import("../lib/commands/ai.mjs")).aiCommand(e),demo:async e=>(await import("../lib/commands/demo.mjs")).demoCommand(e),log:async e=>(await import("../lib/commands/log.mjs")).logCommand(e),theme:async e=>(await import("../lib/commands/theme.mjs")).themeCommand(e),switch:async e=>(await import("../lib/commands/switch.mjs")).switchCommand(e),upgrade:async e=>(await import("../lib/commands/upgrade.mjs")).upgradeCommand(e),stats:async e=>(await import("../lib/commands/stats.mjs")).statsCommand(e),ask:async e=>(await import("../lib/commands/ask.mjs")).askCommand(e),recap:async e=>(await import("../lib/commands/recap.mjs")).recapCommand(e),uninstall:async e=>(await import("../lib/commands/uninstall.mjs")).uninstallCommand(e),feedback:async e=>(await import("../lib/commands/feedback.mjs")).feedbackCommand(e),telemetry:async e=>(await import("../lib/telemetry.mjs")).telemetryCommand(e),contract:async e=>w("contract",v,e),dev:async e=>w("dev",b,e),amp:async e=>(await import("../lib/commands/amp.mjs")).ampCommand(e)};async function w(e,t,n){const i=n[1];if(!i||i==="--help"||i==="-h"){console.log(),console.log(` ${m("\u{1F525} infernoflow "+e)} ${o("\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))} ${o(d)}`)}console.log(),console.log(` ${o("Run")} ${a(`infernoflow ${e} <verb> --help`)} ${o("for verb-specific options.")}`),console.log();return}const c=t[i];return(!c||!l[c])&&(console.error(u(`
3
- Unknown ${e} verb: ${i}`)),console.error(o(` Run: infernoflow ${e} (see all verbs)
4
- `)),process.exit(1)),l[c]([c,...n.slice(2)])}function B(){const e=Object.keys(y),t=Math.max(...e.map(n=>n.length),8)+1;return Object.entries(y).map(([n,i])=>` ${n.padEnd(t," ")}${i}`).join(`
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 r(c){const d=c.write.bind(c);c.write=function(s,...f){if(typeof s=="string")s=s.replace(n,u=>t[u]);else if(Buffer.isBuffer(s)){const u=s.toString("utf8").replace(n,k=>t[k]);s=Buffer.from(u,"utf8")}return d(s,...f)}}r(process.stdout),r(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 o,cyan as a,red as h}from"../lib/ui/output.mjs";const A=S(x(import.meta.url));function O(e){for(const t of[g(e,"..","..","package.json"),g(e,"..","package.json")])try{return JSON.parse($(t,"utf8"))}catch{}return{version:"0.0.0-source"}}const I=O(A),p=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",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 e=>(await import("../lib/commands/publish.mjs")).publishCommand(e),diff:async e=>(await import("../lib/commands/diff.mjs")).diffCommand(e),changelog:async e=>(await import("../lib/commands/changelog.mjs")).changelogCommand(e),setup:async e=>(await import("../lib/commands/setup.mjs")).setupCommand(e),init:async e=>(await import("../lib/commands/init.mjs")).initCommand(e),"install-cursor-hooks":async e=>(await import("../lib/commands/installCursorHooks.mjs")).installCursorHooksCommand(e),"install-vscode-copilot-hooks":async e=>(await import("../lib/commands/installVsCodeCopilotHooks.mjs")).installVsCodeCopilotHooksCommand(e),check:async e=>(await import("../lib/commands/check.mjs")).checkCommand(e),status:async e=>(await import("../lib/commands/status.mjs")).statusCommand(e),"pr-impact":async e=>(await import("../lib/commands/prImpact.mjs")).prImpactCommand(e),sync:async e=>(await import("../lib/commands/syncAuto.mjs")).syncCommand(e),run:async e=>(await import("../lib/commands/run.mjs")).runCommand(e),suggest:async e=>(await import("../lib/commands/suggest.mjs")).suggestCommand(e),implement:async e=>(await import("../lib/commands/implement.mjs")).implementCommand(e),context:async e=>(await import("../lib/commands/context.mjs")).contextCommand(e),"doc-gate":async e=>(await import("../lib/commands/docGate.mjs")).docGateCommand(e),"generate-skills":async e=>(await import("../lib/commands/generateSkills.mjs")).generateSkillsCommand(e),watch:async e=>(await import("../lib/commands/watch.mjs")).watchCommand(e),ci:async e=>(await import("../lib/commands/ci.mjs")).ciCommand(e),notify:async e=>(await import("../lib/commands/notify.mjs")).notifyCommand(e),monorepo:async e=>(await import("../lib/commands/monorepo.mjs")).monorepoCommand(e),doctor:async e=>(await import("../lib/commands/doctor.mjs")).doctorCommand(e),coverage:async e=>(await import("../lib/commands/coverage.mjs")).coverageCommand(e),review:async e=>(await import("../lib/commands/review.mjs")).reviewCommand(e),scan:async e=>(await import("../lib/commands/scan.mjs")).scanCommand(e),graph:async e=>(await import("../lib/commands/graph.mjs")).graphCommand(e),stability:async e=>(await import("../lib/commands/stability.mjs")).stabilityCommand(e),freeze:async e=>(await import("../lib/commands/stability.mjs")).freezeCommand(e),thaw:async e=>(await import("../lib/commands/stability.mjs")).thawCommand(e),why:async e=>(await import("../lib/commands/why.mjs")).whyCommand(e),impact:async e=>(await import("../lib/commands/impact.mjs")).impactCommand(e),scaffold:async e=>(await import("../lib/commands/scaffold.mjs")).scaffoldCommand(e),explain:async e=>(await import("../lib/commands/explain.mjs")).explainCommand(e),test:async e=>(await import("../lib/commands/test.mjs")).testCommand(e),ai:async e=>(await import("../lib/commands/ai.mjs")).aiCommand(e),demo:async e=>(await import("../lib/commands/demo.mjs")).demoCommand(e),log:async e=>(await import("../lib/commands/log.mjs")).logCommand(e),theme:async e=>(await import("../lib/commands/theme.mjs")).themeCommand(e),switch:async e=>(await import("../lib/commands/switch.mjs")).switchCommand(e),upgrade:async e=>(await import("../lib/commands/upgrade.mjs")).upgradeCommand(e),stats:async e=>(await import("../lib/commands/stats.mjs")).statsCommand(e),ask:async e=>(await import("../lib/commands/ask.mjs")).askCommand(e),recap:async e=>(await import("../lib/commands/recap.mjs")).recapCommand(e),uninstall:async e=>(await import("../lib/commands/uninstall.mjs")).uninstallCommand(e),feedback:async e=>(await import("../lib/commands/feedback.mjs")).feedbackCommand(e),telemetry:async e=>(await import("../lib/telemetry.mjs")).telemetryCommand(e),contract:async e=>w("contract",v,e),dev:async e=>w("dev",b,e),amp:async e=>(await import("../lib/commands/amp.mjs")).ampCommand(e)};async function w(e,t,n){const r=n[1];if(!r||r==="--help"||r==="-h"){console.log(),console.log(` ${m("\u{1F525} infernoflow "+e)} ${o("\u2014 available verbs:")}`),console.log();const d=Math.max(...Object.keys(t).map(s=>s.length))+2;for(const s of Object.keys(t)){const f=y[t[s]]||"";console.log(` ${a(s.padEnd(d))} ${o(f)}`)}console.log(),console.log(` ${o("Run")} ${a(`infernoflow ${e} <verb> --help`)} ${o("for verb-specific options.")}`),console.log();return}const c=t[r];return(!c||!l[c])&&(console.error(h(`
3
+ Unknown ${e} verb: ${r}`)),console.error(o(` Run: infernoflow ${e} (see all verbs)
4
+ `)),process.exit(1)),l[c]([c,...n.slice(2)])}function B(){const e=Object.keys(y),t=Math.max(...e.map(n=>n.length),8)+1;return Object.entries(y).map(([n,r])=>` ${n.padEnd(t," ")}${r}`).join(`
5
5
  `)}const v={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"},b={publish:"publish",changelog:"changelog",diff:"diff",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(v),"Dev (use: infernoflow dev <verb>)":Object.keys(b)};function R(){return Object.entries(M).map(([t,n])=>` ${m(t+":")}
6
6
  ${n.join(" ")}`).join(`
7
7
 
8
8
  `)}const C=Object.keys(l).length,j=`
9
- ${m("\u{1F525} infernoflow")} ${o("v"+h)}
9
+ ${m("\u{1F525} infernoflow")} ${o("v"+p)}
10
10
  ${o("Persistent memory for AI coding sessions")}
11
11
 
12
12
  ${m("Usage:")}
@@ -31,11 +31,11 @@
31
31
 
32
32
  ${o("Run")} ${a("infernoflow commands")} ${o("to see all "+C+" commands grouped.")}
33
33
  ${o("Run")} ${a("infernoflow <command> --help")} ${o("for command-specific options.")}
34
- `;import*as E from"node:fs";import*as P from"node:path";try{const e=P.join(process.cwd(),"inferno");if(E.existsSync(e)){const{observeCommandStart:t}=await import("../lib/learning/observe.mjs"),n=process.argv[2];n&&!n.startsWith("-")&&t(e,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
- ${m("\u{1F525} infernoflow")} ${o("v"+h)} ${o("\u2014 all "+C+" commands")}
34
+ `;import*as E from"node:fs";import*as P from"node:path";try{const e=P.join(process.cwd(),"inferno");if(E.existsSync(e)){const{observeCommandStart:t}=await import("../lib/learning/observe.mjs"),n=process.argv[2];n&&!n.startsWith("-")&&t(e,n)}}catch{}const[,,i,...D]=process.argv;(!i||i==="--help"||i==="-h")&&(console.log(j),process.exit(0)),(i==="--version"||i==="-v")&&(console.log(p),process.exit(0)),i==="commands"&&(console.log(`
35
+ ${m("\u{1F525} infernoflow")} ${o("v"+p)} ${o("\u2014 all "+C+" commands")}
36
36
  `),console.log(R()),console.log(`
37
37
  ${o("Run")} ${a("infernoflow <command> --help")} ${o("for options.")}
38
- `),process.exit(0));const T=Object.keys(l);T.includes(r)||(console.error(u(`
39
- Unknown command: ${r}`)),console.error(o("Run: infernoflow commands (see all commands)")),console.error(o(`Run: infernoflow --help (quick start)
40
- `)),process.exit(1));const G=[r,...D];l[r](G).catch(e=>{console.error(u(`
38
+ `),process.exit(0));const N=Object.keys(l);N.includes(i)||(console.error(h(`
39
+ Unknown command: ${i}`)),console.error(o("Run: infernoflow commands (see all commands)")),console.error(o(`Run: infernoflow --help (quick start)
40
+ `)),process.exit(1));const T=[i,...D];try{const{runUpgradeBackfillIfNeeded:e}=await import("../lib/upgradeCheck.mjs");await e(p,i)}catch{}l[i](T).catch(e=>{console.error(h(`
41
41
  Error: `)+e.message),process.exit(1)});
@@ -52,4 +52,4 @@ ${w.map(d=>`- \`${d.id}\`: ${d.description}`).join(`
52
52
  `),l.scripts&&(info("Suggested package.json scripts for this template:"),Object.entries(l.scripts).forEach(([d,x])=>console.log(` ${L(d)}: ${v(x)}`)),console.log()),q(`Initialised from template ${L(f(h))} \u2014 ${L(String(w.length))} capabilities`),console.log(),info(`Run ${f("infernoflow vibe")} to start vibe coding mode`),console.log();return}const S=e.includes("--cursor-hooks"),A=e.includes("--vscode-copilot-hooks"),O=e.includes("--report-json"),C=e.includes("--report-json-only"),I=e.includes("--report-human-only"),j=W(e,"--lang"),U=W(e,"--framework"),K=W(e,"--project-type"),u=C;C&&I&&(console.error("Error: --report-json-only and --report-human-only cannot be used together."),process.exit(1)),u||fe("init");const b=s.join(o,"inferno"),ee=s.join(o,".github","workflows");i.existsSync(b)&&!t&&(u&&(console.log(JSON.stringify({ok:!1,error:"inferno_exists",hint:"Use --force to overwrite"},null,2)),process.exit(1)),P("inferno/ already exists. Use --force to overwrite."),console.log(),process.exit(0));const N=M(o),Y="CreateTask, ReadTasks, UpdateTask, ToggleComplete, DeleteTask";let F=N,T=Y.split(",").map(a=>a.trim());if(r){let l=H(o,{language:j||void 0,framework:U||void 0,projectType:K||void 0});if(!n&&!C){const w=G.createInterface({input:process.stdin,output:process.stdout}),d=l.developmentProfile||{},x=d.detected||{};console.log(v(` Review inferred development stack (press Enter to accept detected values)
53
53
  `));const le=await D(w,"Language",d.language||x.language||"unknown"),ce=await D(w,"Framework",d.framework||x.framework||"unknown"),ae=await D(w,"Project type",d.projectType||x.projectType||"unknown");w.close(),l=H(o,{language:le,framework:ce,projectType:ae})}const y=l.capabilities,E=ge(y);C?console.log(JSON.stringify({mode:"adopt",policyId:N,inferredCapabilities:E,components:l.components,displayFields:l.displayFields,externalLibraries:l.externalLibraries,uiLayout:l.uiLayout,styling:l.styling,developmentProfile:l.developmentProfile,apiCalls:l.apiCalls},null,2)):(console.log(),console.log(v(ye(y))),console.log(),console.log(v(he(l))),console.log(),O&&!I&&(console.log(JSON.stringify({mode:"adopt",policyId:N,inferredCapabilities:E,components:l.components,displayFields:l.displayFields,externalLibraries:l.externalLibraries,uiLayout:l.uiLayout,styling:l.styling,developmentProfile:l.developmentProfile,apiCalls:l.apiCalls},null,2)),console.log()));const _=await ue(y,n);F=N,T=_.map(w=>w.id)}else if(!n){const a=G.createInterface({input:process.stdin,output:process.stdout});console.log(v(` Press Enter to accept defaults
54
54
  `)),F=await D(a,"Project / policy name",N),T=(await D(a,"Capabilities (comma-separated)",Y)).split(",").map(y=>y.trim()).filter(Boolean),a.close(),console.log()}if(i.mkdirSync(b,{recursive:!0}),r){const a=T.map(y=>({id:y,title:y.replace(/([A-Z])/g," $1").trim()})),l=H(o,{language:j||void 0,framework:U||void 0,projectType:K||void 0});me(b,F,a,l),u||(g("Created: "+f("inferno/contract.json")),g("Created: "+f("inferno/capabilities.json")),g("Created: "+f("inferno/scenarios/adoption_baseline.json")),g("Created: "+f("inferno/adoption_profile.json")),g("Created: "+f("inferno/CHANGELOG.md")))}else Ae(s.join(b,"contract.json"),F,T),u||g("Created: "+f("inferno/contract.json")),Te(s.join(b,"capabilities.json"),T),u||g("Created: "+f("inferno/capabilities.json")),Ee(s.join(b,"scenarios"),T),u||g("Created: "+f("inferno/scenarios/happy_path.json")),Q(s.join(b,"CHANGELOG.md"),F),u||g("Created: "+f("inferno/CHANGELOG.md"));const R=Ce(),oe=s.join(R,"scripts","inferno-doc-gate.mjs"),ne=s.join(o,"scripts","inferno-doc-gate.mjs");J(oe,ne,t,u);const te=s.join(R,"scripts","inferno-install-hooks.mjs"),ie=s.join(o,"scripts","inferno-install-hooks.mjs");J(te,ie,t,u);const se=s.join(R,"ci","github-inferno-check.yml"),re=s.join(ee,"infernoflow-check.yml");if(J(se,re,t,u),Ie(o,u),S&&we({cwd:o,templatesRoot:R,force:t,silent:u,logOk:a=>{u||g(a)},logWarn:a=>{u||P(a)}}),A&&ve({cwd:o,templatesRoot:R,force:t,silent:u,logOk:a=>{u||g(a)},logWarn:a=>{u||P(a)}}),r){const a=s.join(b,"context-state.json");let l={};try{l=JSON.parse(i.readFileSync(a,"utf8"))}catch{}const y=H(o,{language:j||void 0,framework:U||void 0,projectType:K||void 0});l.stack=y.developmentProfile,i.writeFileSync(a,JSON.stringify(l,null,2)+`
55
- `,"utf8"),u||g("Created: "+f("inferno/context-state.json"))}if(!u){q("infernoflow initialized!");const a=s.join(b,"integrations.json");!(process.env.ANTHROPIC_API_KEY||process.env.OPENAI_API_KEY||process.env.GOOGLE_AI_API_KEY||process.env.OPENROUTER_API_KEY||process.env.GEMINI_API_KEY)&&!i.existsSync(a)&&(console.log(),console.log(` ${$("\u{1F4A1}")} ${L("Tip:")} connect an AI provider for explain, why, review, and changelog AI.`),console.log(` ${f("infernoflow ai setup")} \u2014 takes 60 seconds`)),de([f("infernoflow status")+" \u2014 see your contract at a glance",f("infernoflow check")+" \u2014 validate everything",(r?"Review inferred baseline in ":"Edit ")+$("inferno/capabilities.json")+(r?" and refine IDs/titles":" to describe each capability in detail"),"Add more "+$("inferno/scenarios/*.json")+" files for edge cases","Add "+f("inferno:check")+" to your CI pipeline",...S?["Restart Cursor \u2014 hooks write assistant text to "+$("inferno/CONTEXT.draft.md"),"Promote when ready: "+f("npm run inferno:promote-draft -- --append-notes")]:[],...A?["Restart VS Code \u2014 Copilot hooks append prompts + assistant (from transcript) to "+$("inferno/CONTEXT.draft.md"),"Promote when ready: "+f("npm run inferno:promote-draft -- --append-notes")]:[],...!S&&!A?["Optional: "+f("infernoflow install-cursor-hooks")+" or "+f("infernoflow install-vscode-copilot-hooks")]:[]])}}export{Xe as initCommand};
55
+ `,"utf8"),u||g("Created: "+f("inferno/context-state.json"))}if(!u){q("infernoflow initialized!");const a=s.join(b,"integrations.json");!(process.env.ANTHROPIC_API_KEY||process.env.OPENAI_API_KEY||process.env.GOOGLE_AI_API_KEY||process.env.OPENROUTER_API_KEY||process.env.GEMINI_API_KEY)&&!i.existsSync(a)&&(console.log(),console.log(` ${$("\u{1F4A1}")} ${L("Tip:")} connect an AI provider for explain, why, review, and changelog AI.`),console.log(` ${f("infernoflow ai setup")} \u2014 takes 60 seconds`)),de([f("infernoflow status")+" \u2014 see your contract at a glance",f("infernoflow check")+" \u2014 validate everything",(r?"Review inferred baseline in ":"Edit ")+$("inferno/capabilities.json")+(r?" and refine IDs/titles":" to describe each capability in detail"),"Add more "+$("inferno/scenarios/*.json")+" files for edge cases","Add "+f("inferno:check")+" to your CI pipeline",...S?["Restart Cursor \u2014 hooks write assistant text to "+$("inferno/CONTEXT.draft.md"),"Promote when ready: "+f("npm run inferno:promote-draft -- --append-notes")]:[],...A?["Restart VS Code \u2014 Copilot hooks append prompts + assistant (from transcript) to "+$("inferno/CONTEXT.draft.md"),"Promote when ready: "+f("npm run inferno:promote-draft -- --append-notes")]:[],...!S&&!A?["Optional: "+f("infernoflow install-cursor-hooks")+" or "+f("infernoflow install-vscode-copilot-hooks")]:[]])}}export{Z as ensureGitignoreEntries,Xe as initCommand};
@@ -1,20 +1,20 @@
1
- import*as f from"node:fs";import*as m from"node:path";import"node:os";import{bold as j,cyan as A,gray as o,green as D,red as b}from"../ui/output.mjs";import{ampPaths as R,appendEntry as k,readEntries as N,AMP_MARKERS as E}from"../amp/io.mjs";function _(){return R(process.cwd())}function C(){try{const e=N(process.cwd()),l=e.filter(n=>n.type==="gotcha"),i=e.filter(n=>n.type==="decision"),s=e.filter(n=>n.type==="attempt"&&(n.result==="failed"||n.result==="partial")),t=["# Project Context (auto-generated by infernoflow)","",`> Last updated: ${new Date().toISOString()}`,""];if(l.length){t.push("## \u26A0\uFE0F Known Gotchas (Read These First)","");for(const n of l)t.push(`- ${n.summary}`);t.push("")}if(i.length){t.push("## \u2713 Decisions In Effect","");for(const n of i)t.push(`- ${n.summary}`);t.push("")}if(s.length){t.push("## \u274C Things That Don't Work (Don't Try These)","");for(const n of s)t.push(`- ${n.summary}`);t.push("")}const p=t.join(`
1
+ import*as f from"node:fs";import*as m from"node:path";import"node:os";import{bold as j,cyan as T,gray as n,green as F,red as b}from"../ui/output.mjs";import{ampPaths as A,appendEntry as k,readEntries as D,AMP_MARKERS as E}from"../amp/io.mjs";import{refreshRuleFilesFromMemory as _}from"../ruleFiles.mjs";function C(){return A(process.cwd())}function P(){try{const e=D(process.cwd()),l=e.filter(o=>o.type==="gotcha"),i=e.filter(o=>o.type==="decision"),t=e.filter(o=>o.type==="attempt"&&(o.result==="failed"||o.result==="partial")),s=["# Project Context (auto-generated by infernoflow)","",`> Last updated: ${new Date().toISOString()}`,""];if(l.length){s.push("## \u26A0\uFE0F Known Gotchas (Read These First)","");for(const o of l)s.push(`- ${o.summary}`);s.push("")}if(i.length){s.push("## \u2713 Decisions In Effect","");for(const o of i)s.push(`- ${o.summary}`);s.push("")}if(t.length){s.push("## \u274C Things That Don't Work (Don't Try These)","");for(const o of t)s.push(`- ${o.summary}`);s.push("")}const p=s.join(`
2
2
  `),g=`${E.start}
3
3
  ${p}
4
4
  ${E.end}
5
- `,a=process.cwd(),d=n=>{let c="";try{c=f.readFileSync(n,"utf8")}catch{}const w=c.indexOf(E.start),S=c.indexOf(E.end);let $;w!==-1&&S!==-1&&S>w?$=c.slice(0,w)+g+c.slice(S+E.end.length).replace(/^\n+/,""):c?$=c.replace(/\s+$/,"")+`
5
+ `,a=process.cwd(),d=o=>{let c="";try{c=f.readFileSync(o,"utf8")}catch{}const w=c.indexOf(E.start),S=c.indexOf(E.end);let $;w!==-1&&S!==-1&&S>w?$=c.slice(0,w)+g+c.slice(S+E.end.length).replace(/^\n+/,""):c?$=c.replace(/\s+$/,"")+`
6
6
 
7
- `+g:$=g,f.writeFileSync(n,$,"utf8")},O=m.join(a,"CLAUDE.md");f.existsSync(O)&&d(O);const I=m.join(a,".cursorrules");(f.existsSync(I)||f.existsSync(m.join(a,".cursor")))&&d(I);const y=m.join(a,".github","copilot-instructions.md");f.existsSync(m.join(a,".github"))&&d(y)}catch{}}const F=["note","attempt","decision","gotcha","preference","theme","handoff","error"],L=["worked","failed","partial","unknown"];function P(){return N(process.cwd())}function U(e,{auto:l=!1,quiet:i=!1}={}){const s=process.cwd(),t=m.join(s,".ai-memory"),p=m.join(s,"inferno");return l&&!f.existsSync(t)&&!f.existsSync(p)?!1:(!f.existsSync(t)&&!f.existsSync(p)&&(i||console.error(b(` \u2718 no .ai-memory/ or inferno/ \u2014 run: infernoflow init
8
- `)),process.exit(1)),k(s,e),!0)}function W(){return process.env.CURSOR_SESSION?"cursor":process.env.COPILOT_SESSION?"copilot":process.env.CLAUDE_CODE_SESSION?"claude":process.env.WINDSURF_SESSION?"windsurf":process.env.INFERNOFLOW_AGENT?process.env.INFERNOFLOW_AGENT:"human"}function V(e,l){const i=new Date(e.ts).toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}),s=e.type||"note",t=s==="gotcha"?"\x1B[33m":s==="decision"?"\x1B[36m":s==="theme"?"\x1B[35m":s==="preference"?"\x1B[34m":s==="attempt"?"\x1B[90m":s==="error"?"\x1B[31m":"\x1B[0m",p="\x1B[0m",g=e.result?` [${e.result}]`:"",a=e.agent&&e.agent!=="human"?o(` (${e.agent})`):"";return` ${o(String(l+1).padStart(3))} ${o(i)} ${t}${s}${p}${g} ${e.summary}${a}`}async function J(e){const l=r=>e.includes(r),i=(r,u)=>{const h=e.indexOf(r);return h!==-1&&e[h+1]?e[h+1]:u},s=l("--show"),t=l("--clear"),p=l("--json"),g=l("--auto"),a=l("--quiet"),d=i("--source",null);if(s||p){const r=P(),u=e[e.indexOf("--show")+1],h=u&&/^\d+$/.test(u)?parseInt(u):20,x=r.slice(-h);if(p){console.log(JSON.stringify(x,null,2));return}if(console.log(`
9
- `+j("\u{1F525} infernoflow \u2014 session memory")),console.log(" "+"\u2500".repeat(50)),!x.length){console.log(o(`
7
+ `+g:$=g,f.writeFileSync(o,$,"utf8")},O=m.join(a,"CLAUDE.md");f.existsSync(O)&&d(O);const I=m.join(a,".cursorrules");(f.existsSync(I)||f.existsSync(m.join(a,".cursor")))&&d(I);const y=m.join(a,".github","copilot-instructions.md");f.existsSync(m.join(a,".github"))&&d(y)}catch{}}const N=["note","attempt","decision","gotcha","preference","theme","handoff","error"],L=["worked","failed","partial","unknown"];function U(){return D(process.cwd())}function W(e,{auto:l=!1,quiet:i=!1}={}){const t=process.cwd(),s=m.join(t,".ai-memory"),p=m.join(t,"inferno");if(l&&!f.existsSync(s)&&!f.existsSync(p))return!1;!f.existsSync(s)&&!f.existsSync(p)&&(i||console.error(b(` \u2718 no .ai-memory/ or inferno/ \u2014 run: infernoflow init
8
+ `)),process.exit(1)),k(t,e);try{_(t)}catch{}return!0}function M(){return process.env.CURSOR_SESSION?"cursor":process.env.COPILOT_SESSION?"copilot":process.env.CLAUDE_CODE_SESSION?"claude":process.env.WINDSURF_SESSION?"windsurf":process.env.INFERNOFLOW_AGENT?process.env.INFERNOFLOW_AGENT:"human"}function V(e,l){const i=new Date(e.ts).toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}),t=e.type||"note",s=t==="gotcha"?"\x1B[33m":t==="decision"?"\x1B[36m":t==="theme"?"\x1B[35m":t==="preference"?"\x1B[34m":t==="attempt"?"\x1B[90m":t==="error"?"\x1B[31m":"\x1B[0m",p="\x1B[0m",g=e.result?` [${e.result}]`:"",a=e.agent&&e.agent!=="human"?n(` (${e.agent})`):"";return` ${n(String(l+1).padStart(3))} ${n(i)} ${s}${t}${p}${g} ${e.summary}${a}`}async function Y(e){const l=r=>e.includes(r),i=(r,u)=>{const h=e.indexOf(r);return h!==-1&&e[h+1]?e[h+1]:u},t=l("--show"),s=l("--clear"),p=l("--json"),g=l("--auto"),a=l("--quiet"),d=i("--source",null);if(t||p){const r=U(),u=e[e.indexOf("--show")+1],h=u&&/^\d+$/.test(u)?parseInt(u):20,x=r.slice(-h);if(p){console.log(JSON.stringify(x,null,2));return}if(console.log(`
9
+ `+j("\u{1F525} infernoflow \u2014 session memory")),console.log(" "+"\u2500".repeat(50)),!x.length){console.log(n(`
10
10
  No entries yet. Start logging with: infernoflow log "<what happened>"
11
- `));return}console.log(o(` Showing last ${x.length} of ${r.length} entries
12
- `)),x.forEach((v,T)=>console.log(V(v,r.length-x.length+T))),console.log();return}if(t){const{sessions:r}=_();if(!f.existsSync(r)){console.log(o(` Nothing to clear.
13
- `));return}const u=r.replace(".jsonl",`-archive-${Date.now()}.jsonl`);f.renameSync(r,u),console.log(D(` \u2714 Session log archived \u2192 ${m.basename(u)}
11
+ `));return}console.log(n(` Showing last ${x.length} of ${r.length} entries
12
+ `)),x.forEach((v,R)=>console.log(V(v,r.length-x.length+R))),console.log();return}if(s){const{sessions:r}=C();if(!f.existsSync(r)){console.log(n(` Nothing to clear.
13
+ `));return}const u=r.replace(".jsonl",`-archive-${Date.now()}.jsonl`);f.renameSync(r,u),console.log(F(` \u2714 Session log archived \u2192 ${m.basename(u)}
14
14
  `));return}const O=new Set([i("--type",""),i("--result",""),i("--agent",""),i("--source","")].filter(Boolean)),y=e.slice(1).filter(r=>!r.startsWith("--")&&!O.has(r)).join(" ").trim();if(!y){console.log(`
15
15
  `+j("\u{1F525} infernoflow log")+` \u2014 append to session memory
16
- `),console.log(o(" Usage:")),console.log(o(' infernoflow log "what happened"')),console.log(o(' infernoflow log "tried X, failed because Y" --type attempt --result failed')),console.log(o(' infernoflow log "always use multipart/form-data" --type gotcha')),console.log(o(' infernoflow log "switched to dark mode" --type theme')),console.log(o(" infernoflow log --show Print last 20 entries")),console.log(o(" infernoflow log --json Print as JSON")),console.log(),console.log(o(" Types: note \xB7 attempt \xB7 decision \xB7 gotcha \xB7 preference \xB7 theme \xB7 handoff \xB7 error")),console.log(o(" Results: worked \xB7 failed \xB7 partial \xB7 unknown")),console.log(o(` Auto-capture: --auto (silent skip if no inferno/) \xB7 --quiet \xB7 --source <name>
17
- `));return}const n=i("--type","note"),c=i("--result",null),w=i("--agent",W());F.includes(n)||(a||console.error(b(` \u2718 Invalid type: ${n}. Valid: ${F.join(", ")}
16
+ `),console.log(n(" Usage:")),console.log(n(' infernoflow log "what happened"')),console.log(n(' infernoflow log "tried X, failed because Y" --type attempt --result failed')),console.log(n(' infernoflow log "always use multipart/form-data" --type gotcha')),console.log(n(' infernoflow log "switched to dark mode" --type theme')),console.log(n(" infernoflow log --show Print last 20 entries")),console.log(n(" infernoflow log --json Print as JSON")),console.log(),console.log(n(" Types: note \xB7 attempt \xB7 decision \xB7 gotcha \xB7 preference \xB7 theme \xB7 handoff \xB7 error")),console.log(n(" Results: worked \xB7 failed \xB7 partial \xB7 unknown")),console.log(n(` Auto-capture: --auto (silent skip if no inferno/) \xB7 --quiet \xB7 --source <name>
17
+ `));return}const o=i("--type","note"),c=i("--result",null),w=i("--agent",M());N.includes(o)||(a||console.error(b(` \u2718 Invalid type: ${o}. Valid: ${N.join(", ")}
18
18
  `)),process.exit(1)),c&&!L.includes(c)&&(a||console.error(b(` \u2718 Invalid result: ${c}. Valid: ${L.join(", ")}
19
- `)),process.exit(1));const S={ts:new Date().toISOString(),agent:w,type:n,summary:y,...c?{result:c}:{},...d?{source:d}:{},...g?{auto:!0}:{}};if(U(S,{auto:g,quiet:a})&&(C(),!a)){const r=n!=="note"?A(` [${n}]`):"",u=c?o(` \u2192 ${c}`):"",h=d?o(` (via ${d})`):"";console.log(D(` \u2714 Logged${r}${u}${h}: `)+y+`
20
- `)}}export{J as logCommand};
19
+ `)),process.exit(1));const S={ts:new Date().toISOString(),agent:w,type:o,summary:y,...c?{result:c}:{},...d?{source:d}:{},...g?{auto:!0}:{}};if(W(S,{auto:g,quiet:a})&&(P(),!a)){const r=o!=="note"?T(` [${o}]`):"",u=c?n(` \u2192 ${c}`):"",h=d?n(` (via ${d})`):"";console.log(F(` \u2714 Logged${r}${u}${h}: `)+y+`
20
+ `)}}export{Y as logCommand};
@@ -1,6 +1,6 @@
1
- import*as n from"node:fs";import*as l from"node:path";import*as w from"node:os";import{fileURLToPath as C}from"node:url";import{execSync as j}from"node:child_process";import{detectIdeContext as h}from"../ai/ideDetection.mjs";import{header as _,ok as y,warn as x,info as S,done as M,cyan as f,yellow as $,bold as g,green as d}from"../ui/output.mjs";import"../cursorHooksInstall.mjs";import"../vsCodeCopilotHooksInstall.mjs";const k=l.dirname(C(import.meta.url));function v(){return l.resolve(k,"../../templates")}function J(s){try{return j(`npx infernoflow ${s}`,{encoding:"utf8",cwd:process.cwd(),timeout:6e4,stdio:["inherit","pipe","pipe"]})}catch(t){return t.stdout||t.stderr||t.message}}const P=["infernoflow_status","infernoflow_run","infernoflow_apply","infernoflow_check","infernoflow_context","infernoflow_implement","infernoflow_git_drift","infernoflow_scan_ui","infernoflow_review","amp_read","amp_write","amp_search","amp_handoff","amp_health"];function O(s){const t=l.join(w.homedir(),".claude.json");let c={};if(n.existsSync(t))try{c=JSON.parse(n.readFileSync(t,"utf8"))}catch{c={}}c.mcpServers||(c.mcpServers={});const o=c.mcpServers.infernoflow;if(o&&o.args&&o.args[0]===s)return{updated:!1};c.mcpServers.infernoflow={command:"node",args:[s]};const r=JSON.stringify(c,null,2).replace(/\u0000+/g,"");return n.writeFileSync(t,r,"utf8"),{updated:!0,path:t}}function F(s,t){const c=l.join(s,".vscode"),o=l.join(c,"mcp.json");let r={};if(n.existsSync(o))try{r=JSON.parse(n.readFileSync(o,"utf8"))}catch{r={}}r.servers||(r.servers={});const i=r.servers.infernoflow;return i&&i.args&&i.args[0]===t?{updated:!1}:(r.servers.infernoflow={type:"stdio",command:"node",args:[t]},n.mkdirSync(c,{recursive:!0}),n.writeFileSync(o,JSON.stringify(r,null,2)+`
2
- `,"utf8"),{updated:!0,path:o})}function N(s,t){const c=l.join(s,".claude"),o=l.join(c,"settings.json");let r={};if(n.existsSync(o))try{r=JSON.parse(n.readFileSync(o,"utf8"))}catch{r={}}const i=new Set(r.allowedTools||[]);for(const a of P)i.add(`mcp__infernoflow__${a}`);const p={...r,allowedTools:[...i]};return n.mkdirSync(c,{recursive:!0}),n.writeFileSync(o,JSON.stringify(p,null,2),"utf8"),o}function R(s,{silent:t=!1}={}){const c=v(),o=t?()=>{}:e=>y(e),r=t?()=>{}:e=>x(e),i={mcpServer:!1,claudeJson:!1,claudeSettings:!1},p=l.join(c,"cursor","inferno-mcp-server.mjs"),a=l.join(s,".cursor","inferno-mcp-server.mjs");try{n.existsSync(a)||(n.mkdirSync(l.dirname(a),{recursive:!0}),n.copyFileSync(p,a),i.mcpServer=!0,o("Copied MCP server \u2192 "+f(".cursor/inferno-mcp-server.mjs")))}catch(e){r("MCP server copy skipped: "+e.message)}try{O(a).updated&&(i.claudeJson=!0,o("Registered MCP server in "+f("~/.claude.json")))}catch(e){r("~/.claude.json update skipped: "+e.message)}try{F(s,a).updated&&(i.vscodeMcp=!0,o("Registered MCP server in "+f(".vscode/mcp.json")+gray(" (Copilot Chat)")))}catch(e){r(".vscode/mcp.json update skipped: "+e.message)}try{const e=l.join(s,".cursor","mcp.json");let u={};if(n.existsSync(e))try{u=JSON.parse(n.readFileSync(e,"utf8"))}catch{u={}}u.mcpServers||(u.mcpServers={});const m=u.mcpServers.infernoflow;(!m||!m.args||m.args[0]!==a)&&(u.mcpServers.infernoflow={command:"node",args:[a],env:{}},n.mkdirSync(l.dirname(e),{recursive:!0}),n.writeFileSync(e,JSON.stringify(u,null,2)+`
3
- `,"utf8"),i.cursorMcp=!0,o("Registered MCP server in "+f(".cursor/mcp.json")))}catch(e){r(".cursor/mcp.json update skipped: "+e.message)}try{N(s,!1),i.claudeSettings=!0,o("Pre-approved infernoflow tools in "+f(".claude/settings.json"))}catch(e){r(".claude/settings.json skipped: "+e.message)}return i}async function H(s){const t=process.cwd(),c=s.includes("--force")||s.includes("-f"),o=s.includes("--yes")||s.includes("-y"),r=v();_("infernoflow setup");const{ideDetected:i}=h("auto");S(`IDE detected: ${g(i==="cursor"?"Cursor":i==="vscode"?"VS Code":i==="windsurf"?"Windsurf":"unknown")}`);const a=l.join(t,".ai-memory");n.existsSync(a)?y(".ai-memory/ already exists \u2014 skipping init"):(console.log(`
1
+ import*as n from"node:fs";import*as l from"node:path";import*as w from"node:os";import{fileURLToPath as C}from"node:url";import{execSync as j}from"node:child_process";import{detectIdeContext as h}from"../ai/ideDetection.mjs";import{header as _,ok as y,warn as x,info as S,done as M,cyan as f,yellow as $,bold as g,green as d,gray as k}from"../ui/output.mjs";import"../cursorHooksInstall.mjs";import"../vsCodeCopilotHooksInstall.mjs";const J=l.dirname(C(import.meta.url));function v(){return l.resolve(J,"../../templates")}function P(s){try{return j(`npx infernoflow ${s}`,{encoding:"utf8",cwd:process.cwd(),timeout:6e4,stdio:["inherit","pipe","pipe"]})}catch(t){return t.stdout||t.stderr||t.message}}const O=["infernoflow_status","infernoflow_run","infernoflow_apply","infernoflow_check","infernoflow_context","infernoflow_implement","infernoflow_git_drift","infernoflow_scan_ui","infernoflow_review","amp_read","amp_write","amp_search","amp_handoff","amp_health"];function F(s){const t=l.join(w.homedir(),".claude.json");let c={};if(n.existsSync(t))try{c=JSON.parse(n.readFileSync(t,"utf8"))}catch{c={}}c.mcpServers||(c.mcpServers={});const o=c.mcpServers.infernoflow;if(o&&o.args&&o.args[0]===s)return{updated:!1};c.mcpServers.infernoflow={command:"node",args:[s]};const r=JSON.stringify(c,null,2).replace(/\u0000+/g,"");return n.writeFileSync(t,r,"utf8"),{updated:!0,path:t}}function N(s,t){const c=l.join(s,".vscode"),o=l.join(c,"mcp.json");let r={};if(n.existsSync(o))try{r=JSON.parse(n.readFileSync(o,"utf8"))}catch{r={}}r.servers||(r.servers={});const i=r.servers.infernoflow;return i&&i.args&&i.args[0]===t?{updated:!1}:(r.servers.infernoflow={type:"stdio",command:"node",args:[t]},n.mkdirSync(c,{recursive:!0}),n.writeFileSync(o,JSON.stringify(r,null,2)+`
2
+ `,"utf8"),{updated:!0,path:o})}function R(s,t){const c=l.join(s,".claude"),o=l.join(c,"settings.json");let r={};if(n.existsSync(o))try{r=JSON.parse(n.readFileSync(o,"utf8"))}catch{r={}}const i=new Set(r.allowedTools||[]);for(const a of O)i.add(`mcp__infernoflow__${a}`);const p={...r,allowedTools:[...i]};return n.mkdirSync(c,{recursive:!0}),n.writeFileSync(o,JSON.stringify(p,null,2),"utf8"),o}function T(s,{silent:t=!1}={}){const c=v(),o=t?()=>{}:e=>y(e),r=t?()=>{}:e=>x(e),i={mcpServer:!1,claudeJson:!1,claudeSettings:!1},p=l.join(c,"cursor","inferno-mcp-server.mjs"),a=l.join(s,".cursor","inferno-mcp-server.mjs");try{n.existsSync(a)||(n.mkdirSync(l.dirname(a),{recursive:!0}),n.copyFileSync(p,a),i.mcpServer=!0,o("Copied MCP server \u2192 "+f(".cursor/inferno-mcp-server.mjs")))}catch(e){r("MCP server copy skipped: "+e.message)}try{F(a).updated&&(i.claudeJson=!0,o("Registered MCP server in "+f("~/.claude.json")))}catch(e){r("~/.claude.json update skipped: "+e.message)}try{N(s,a).updated&&(i.vscodeMcp=!0,o("Registered MCP server in "+f(".vscode/mcp.json")+k(" (Copilot Chat)")))}catch(e){r(".vscode/mcp.json update skipped: "+e.message)}try{const e=l.join(s,".cursor","mcp.json");let u={};if(n.existsSync(e))try{u=JSON.parse(n.readFileSync(e,"utf8"))}catch{u={}}u.mcpServers||(u.mcpServers={});const m=u.mcpServers.infernoflow;(!m||!m.args||m.args[0]!==a)&&(u.mcpServers.infernoflow={command:"node",args:[a],env:{}},n.mkdirSync(l.dirname(e),{recursive:!0}),n.writeFileSync(e,JSON.stringify(u,null,2)+`
3
+ `,"utf8"),i.cursorMcp=!0,o("Registered MCP server in "+f(".cursor/mcp.json")))}catch(e){r(".cursor/mcp.json update skipped: "+e.message)}try{R(s,!1),i.claudeSettings=!0,o("Pre-approved infernoflow tools in "+f(".claude/settings.json"))}catch(e){r(".claude/settings.json skipped: "+e.message)}return i}async function E(s){const t=process.cwd(),c=s.includes("--force")||s.includes("-f"),o=s.includes("--yes")||s.includes("-y"),r=v();_("infernoflow setup");const{ideDetected:i}=h("auto");S(`IDE detected: ${g(i==="cursor"?"Cursor":i==="vscode"?"VS Code":i==="windsurf"?"Windsurf":"unknown")}`);const a=l.join(t,".ai-memory");n.existsSync(a)?y(".ai-memory/ already exists \u2014 skipping init"):(console.log(`
4
4
  ${$(".ai-memory/")} not found \u2014 running init ...
5
- `),J(o?"init --yes":"init")),console.log(),S("Wiring up MCP servers for Cursor / VS Code Copilot / Claude Code ...");const e=R(t,{silent:!1});console.log(),M("infernoflow ready"),console.log(`
6
- ${g("What was set up:")}`),console.log(` ${d("\u2714")} MCP server installed \u2192 ${f(".cursor/inferno-mcp-server.mjs")}`),e.cursorMcp&&console.log(` ${d("\u2714")} Cursor MCP config \u2192 ${f(".cursor/mcp.json")}`),e.vscodeMcp&&console.log(` ${d("\u2714")} VS Code Copilot MCP config \u2192 ${f(".vscode/mcp.json")}`),e.claudeJson&&console.log(` ${d("\u2714")} Claude Code MCP config \u2192 ${f("~/.claude.json")}`),e.claudeSettings&&console.log(` ${d("\u2714")} Auto-approved tools \u2192 ${f(".claude/settings.json")}`),console.log(),console.log(` ${g("Next step:")} Restart your AI tool. Test by asking:`),console.log(` ${f('"call the amp_write tool with a test note"')}`),console.log()}export{P as MCP_TOOLS,R as autoSetupMcp,H as setupCommand,O as updateClaudeJson,F as updateVscodeMcpJson,N as writeClaudeSettings};
5
+ `),P(o?"init --yes":"init")),console.log(),S("Wiring up MCP servers for Cursor / VS Code Copilot / Claude Code ...");const e=T(t,{silent:!1});console.log(),M("infernoflow ready"),console.log(`
6
+ ${g("What was set up:")}`),console.log(` ${d("\u2714")} MCP server installed \u2192 ${f(".cursor/inferno-mcp-server.mjs")}`),e.cursorMcp&&console.log(` ${d("\u2714")} Cursor MCP config \u2192 ${f(".cursor/mcp.json")}`),e.vscodeMcp&&console.log(` ${d("\u2714")} VS Code Copilot MCP config \u2192 ${f(".vscode/mcp.json")}`),e.claudeJson&&console.log(` ${d("\u2714")} Claude Code MCP config \u2192 ${f("~/.claude.json")}`),e.claudeSettings&&console.log(` ${d("\u2714")} Auto-approved tools \u2192 ${f(".claude/settings.json")}`),console.log(),console.log(` ${g("Next step:")} Restart your AI tool. Test by asking:`),console.log(` ${f('"call the amp_write tool with a test note"')}`),console.log()}export{O as MCP_TOOLS,T as autoSetupMcp,E as setupCommand,F as updateClaudeJson,N as updateVscodeMcpJson,R as writeClaudeSettings};
@@ -1,6 +1,9 @@
1
- import*as n from"node:fs";import*as u from"node:path";const l="<!-- infernoflow:start -->",a="<!-- infernoflow:end -->",d=[".cursorrules","CLAUDE.md",u.join(".github","copilot-instructions.md")];function m(){const e=[];return e.push("### Memory protocol \u2014 capture as you go"),e.push(""),e.push("You have the `amp_write` MCP tool. **Use it proactively** (without the user asking) whenever you detect any of these moments. Capture the lesson in one sentence so the next AI session inherits it."),e.push(""),e.push("| When you see\u2026 | Call `amp_write` with\u2026 |"),e.push("|---|---|"),e.push("| User types `!!!`, `not working`, `still broken`, `no change`, `same error`, repeated frustration | `{type: 'attempt', msg: '<one-line: what was tried and how it failed>', file: '<active file>'}` |"),e.push("| You generate a plan, numbered steps, or `Plan:` / `Approach:` block | `{type: 'note', msg: 'Plan: <one-line summary>', file: '<focus file>'}` |"),e.push("| User picks X over Y, decides an architectural approach, or you both agree on a direction | `{type: 'decision', msg: '<X> chosen over <Y> because <reason>', file: '<file>'}` |"),e.push("| Discovered non-obvious behavior, API quirk, or `aha \u2014 turns out\u2026` moment | `{type: 'gotcha', msg: '<one-line>', file: '<file>', line: <line if known>}` |"),e.push("| User says `switching` / `back to X`, or ~30 min passed without logging | `{type: 'note', msg: 'Session snapshot \u2014 worked on: <X>. Open threads: <Y>.'}` |"),e.push(""),e.push("**Do NOT log:** typos, syntax errors, obvious bugs visible in the code, anything the next AI can infer by re-reading the file."),e.push("**Do log:** anything that taught you something non-derivable from code."),e.push("**Be concise:** entries should be one sentence. Future-you will skim them."),e.join(`
2
- `)}function y(){return[l,"<!-- Auto-managed by infernoflow. Don't edit between these markers. -->","## Project memory (infernoflow)","",m(),"",'_No entries yet. They\'ll appear here as you and your AI tools log them \u2014 run `infernoflow log "..."` or call `amp_write` from any MCP-aware AI._',a].join(`
3
- `)}function g(e,s){const o=u.dirname(e);if(n.existsSync(o)||n.mkdirSync(o,{recursive:!0}),!n.existsSync(e))return n.writeFileSync(e,s+`
4
- `,"utf8"),{created:!0,updated:!1};const t=n.readFileSync(e,"utf8"),i=t.indexOf(l),r=t.indexOf(a);if(i===-1||r===-1){const f=s+`
1
+ import*as c from"node:fs";import*as l from"node:path";import{execSync as w}from"node:child_process";const m="<!-- infernoflow:start -->",h="<!-- infernoflow:end -->",d=[".cursorrules","CLAUDE.md",l.join(".github","copilot-instructions.md")];function y(){const e=[];return e.push("### Memory protocol \u2014 capture as you go"),e.push(""),e.push("You have the `amp_write` MCP tool. **Use it proactively** (without the user asking) whenever you detect any of these moments. Capture the lesson in one sentence so the next AI session inherits it."),e.push(""),e.push("| When you see\u2026 | Call `amp_write` with\u2026 |"),e.push("|---|---|"),e.push("| User types `!!!`, `not working`, `still broken`, `no change`, `same error`, repeated frustration | `{type: 'attempt', msg: '<one-line: what was tried and how it failed>', file: '<active file>'}` |"),e.push("| You generate a plan, numbered steps, or `Plan:` / `Approach:` block | `{type: 'note', msg: 'Plan: <one-line summary>', file: '<focus file>'}` |"),e.push("| User picks X over Y, decides an architectural approach, or you both agree on a direction | `{type: 'decision', msg: '<X> chosen over <Y> because <reason>', file: '<file>'}` |"),e.push("| Discovered non-obvious behavior, API quirk, or `aha \u2014 turns out\u2026` moment | `{type: 'gotcha', msg: '<one-line>', file: '<file>', line: <line if known>}` |"),e.push("| User says `switching` / `back to X`, or ~30 min passed without logging | `{type: 'note', msg: 'Session snapshot \u2014 worked on: <X>. Open threads: <Y>.'}` |"),e.push(""),e.push("**Do NOT log:** typos, syntax errors, obvious bugs visible in the code, anything the next AI can infer by re-reading the file."),e.push("**Do log:** anything that taught you something non-derivable from code."),e.push("**Be concise:** entries should be one sentence. Future-you will skim them."),e.join(`
2
+ `)}function b(){return[m,"<!-- Auto-managed by infernoflow. Don't edit between these markers. -->","## Project memory (infernoflow)","",y(),"",'_No entries yet. They\'ll appear here as you and your AI tools log them \u2014 run `infernoflow log "..."` or call `amp_write` from any MCP-aware AI._',h].join(`
3
+ `)}function g(e,u){const s=l.dirname(e);if(c.existsSync(s)||c.mkdirSync(s,{recursive:!0}),!c.existsSync(e))return c.writeFileSync(e,u+`
4
+ `,"utf8"),{created:!0,updated:!1};const t=c.readFileSync(e,"utf8"),i=t.indexOf(m),r=t.indexOf(h);if(i===-1||r===-1){const a=u+`
5
5
 
6
- `+t;return n.writeFileSync(e,f,"utf8"),{created:!1,updated:!0}}const h=t.slice(0,i),p=t.slice(r+a.length),c=h+s+p;return c===t?{created:!1,updated:!1}:(n.writeFileSync(e,c,"utf8"),{created:!1,updated:!0})}function w(e){const s=y(),o=[];for(const t of d){const i=u.join(e,t);try{const r=g(i,s);o.push({rel:t,...r})}catch(r){o.push({rel:t,error:r.message})}}return o}export{w as writeInitRuleFiles};
6
+ `+t;return c.writeFileSync(e,a,"utf8"),{created:!1,updated:!0}}const p=t.slice(0,i),o=t.slice(r+h.length),n=p+u+o;return n===t?{created:!1,updated:!1}:(c.writeFileSync(e,n,"utf8"),{created:!1,updated:!0})}function v(e){const u=b(),s=[];for(const t of d){const i=l.join(e,t);try{const r=g(i,u);s.push({rel:t,...r})}catch(r){s.push({rel:t,error:r.message})}}return s}function S(e){const u=[l.join(e,".ai-memory","sessions.jsonl"),l.join(e,"inferno","sessions.jsonl")];for(const s of u)if(c.existsSync(s))try{return c.readFileSync(s,"utf8").split(`
7
+ `).filter(Boolean).map(i=>{try{return JSON.parse(i)}catch{return null}}).filter(Boolean)}catch{}return[]}function x(e,u=10){try{return w(`git log --pretty=format:"%h%x09%ad%x09%s" --date=short -n ${u}`,{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).split(`
8
+ `).filter(Boolean).map(t=>{const[i,r,p]=t.split(" ");return{hash:(i||"").slice(0,7),date:r||"",subject:p||""}})}catch{return[]}}function j(e,u=10,s=10){const t=S(e),i=x(e,s);t.sort((n,a)=>{const f=typeof n.ts=="number"?n.ts:Date.parse(n.ts||0);return(typeof a.ts=="number"?a.ts:Date.parse(a.ts||0))-f});const r=t.slice(0,u),p={gotcha:"\u26A0",decision:"\u2713",attempt:"\u2717",note:"\xB7",detection:"\u25CB",pattern:"\u25C7"},o=[];if(o.push(m),o.push("<!-- Auto-managed by infernoflow. Don't edit between these markers. -->"),o.push("## Project memory (infernoflow)"),o.push(""),o.push(y()),o.push(""),i.length>0){o.push("### Recent commits");for(const n of i)o.push(`- \`${n.hash}\` _${n.date}_ ${n.subject}`);o.push("")}if(r.length>0){o.push("### Recent memory");for(const n of r){const a=n.file?` (\`${n.file}${n.line?":"+n.line:""}\`)`:"",f=(n.msg||n.summary||"").replace(/\n/g," ");o.push(`- ${p[n.type]||"\xB7"} **${n.type||"note"}**${a}: ${f}`)}o.push("")}return t.length===0&&i.length===0&&o.push('_No entries yet. They\'ll appear here as you and your AI tools log them \u2014 run `infernoflow log "..."` or call `amp_write` from any MCP-aware AI._'),o.push(h),o.join(`
9
+ `)}function A(e){const u=j(e),s=[];for(const t of d){const i=l.join(e,t);try{const r=g(i,u);s.push({rel:t,...r})}catch(r){s.push({rel:t,error:r.message})}}return s}export{A as refreshRuleFilesFromMemory,v as writeInitRuleFiles};
@@ -0,0 +1,3 @@
1
+ import*as o from"node:fs";import*as a from"node:path";const u=new Set(["--help","-h","--version","-v","commands","doctor","setup","init","uninstall"]);function p(t){const n=a.join(t,".ai-memory"),e=a.join(t,"inferno");return o.existsSync(n)?a.join(n,".last-cli-version"):o.existsSync(e)?a.join(e,".last-cli-version"):null}function d(t){try{return o.readFileSync(t,"utf8").trim()}catch{return""}}async function m(t,n){if(!t||n&&u.has(n))return;const e=process.cwd(),c=p(e);if(!c)return;const s=d(c);if(s===t)return;let f=!1,l=s==="";try{const{refreshRuleFilesFromMemory:i}=await import("./ruleFiles.mjs");i(e)}catch{}try{const{ensureGitignoreEntries:i}=await import("./commands/init.mjs");i(e,{silent:!0})}catch{}try{const{autoSetupMcp:i}=await import("./commands/setup.mjs"),r=i(e,{silent:!0});f=!!(r&&(r.mcpServer||r.claudeJson||r.cursorMcp||r.vscodeMcp||r.claudeSettings))}catch{}try{o.writeFileSync(c,t,"utf8")}catch{}if(f||l)try{const{gray:i}=await import("./ui/output.mjs"),r=s?`upgraded ${s} \u2192 ${t}`:`initialized for ${t}`;process.stderr.write(i(` infernoflow: ${r}, wired MCP servers + rule files
2
+ `))}catch{process.stderr.write(` infernoflow: refreshed for v${t}
3
+ `)}}export{m as runUpgradeBackfillIfNeeded};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infernoflow",
3
- "version": "0.43.10",
3
+ "version": "0.43.12",
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": {