infernoflow 0.32.9 → 0.33.0
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/dist/bin/infernoflow.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as d}from"node:fs";import{dirname as m,join as u}from"node:path";import{fileURLToPath as
|
|
2
|
+
import{readFileSync as d}from"node:fs";import{dirname as m,join as u}from"node:path";import{fileURLToPath as h}from"node:url";import{bold as t,gray as a,red as s}from"../lib/ui/output.mjs";const f=m(h(import.meta.url)),y=JSON.parse(d(u(f,"..","..","package.json"),"utf8")),r=y.version||"0.0.0",c={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",synthesize:"Auto-detect workflow patterns and synthesize reusable skills + agents",agent:"Manage and run auto-synthesized agents (list | run | show | delete)",version:"Smart semver bump recommendation based on capability changes (--apply to write)","pr-comment":"Post capability drift analysis as a GitHub PR comment (works in CI automatically)",dashboard:"Launch local web dashboard on localhost:7337 \u2014 live contract health, capabilities, agents","team-sync":"Sync capability contract across a team via a shared git branch (push | pull | status | init)",onboard:"Interactive onboarding wizard for new developers \u2014 explains infernoflow in 5 minutes",cloud:"Sync capability contracts via infernoflow cloud (init | push | pull | status | dashboard)",share:"Generate a public read-only HTML snapshot of your capability contract",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",report:"Generate a weekly/monthly HTML or Markdown report of capability activity",monorepo:"Manage infernoflow across monorepo packages (init | list | status | diff | sync)",link:"Link capabilities to Jira, Linear, or GitHub Issues tickets",audit:"Classify capabilities by sensitivity (auth, payment, PII, admin) and generate security surface map",scout:"Scan source files for undocumented capabilities not yet in the contract",export:"Export contract to OpenAPI, Backstage catalog-info.yaml, CSV, or Markdown",snapshot:"Save/diff/restore named snapshots of the capability contract",health:"Compute a 0\u2013100 health score across coverage, docs, freshness, completeness, drift",vibe:"Vibe coding mode \u2014 watches files, auto-syncs contract, regenerates context on every save",adopt:"Interactive wizard to adopt infernoflow in an existing project (detect \u2192 review \u2192 wire up)",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 reads actual function bodies, extracts calls, DB ops, external services",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",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"},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),synthesize:async e=>(await import("../lib/commands/synthesize.mjs")).synthesizeCommand(e),agent:async e=>(await import("../lib/commands/agent.mjs")).agentCommand(e),version:async e=>(await import("../lib/commands/version.mjs")).versionCommand(e),"pr-comment":async e=>(await import("../lib/commands/prComment.mjs")).prCommentCommand(e),dashboard:async e=>(await import("../lib/commands/dashboard.mjs")).dashboardCommand(e),"team-sync":async e=>(await import("../lib/commands/teamSync.mjs")).teamSyncCommand(e),onboard:async e=>(await import("../lib/commands/onboard.mjs")).onboardCommand(e),cloud:async e=>(await import("../lib/commands/cloud.mjs")).cloudCommand(e),share:async e=>(await import("../lib/commands/share.mjs")).shareCommand(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),report:async e=>(await import("../lib/commands/report.mjs")).reportCommand(e),monorepo:async e=>(await import("../lib/commands/monorepo.mjs")).monorepoCommand(e),link:async e=>(await import("../lib/commands/link.mjs")).linkCommand(e),audit:async e=>(await import("../lib/commands/audit.mjs")).auditCommand(e),scout:async e=>(await import("../lib/commands/scout.mjs")).scoutCommand(e),export:async e=>(await import("../lib/commands/export.mjs")).exportCommand(e),snapshot:async e=>(await import("../lib/commands/snapshot.mjs")).snapshotCommand(e),health:async e=>(await import("../lib/commands/health.mjs")).healthCommand(e),vibe:async e=>(await import("../lib/commands/vibe.mjs")).vibeCommand(e),adopt:async e=>(await import("../lib/commands/adoptWizard.mjs")).adoptWizardCommand(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)};function w(){const e=Object.keys(c),n=Math.max(...e.map(i=>i.length),8)+1;return Object.entries(c).map(([i,p])=>` ${i.padEnd(n," ")}${p}`).join(`
|
|
3
3
|
`)}const g=`
|
|
4
4
|
${t("\u{1F525} infernoflow")} ${a("v"+r)}
|
|
5
5
|
${a("The forge for liquid code \u2014 keep every AI session in sync")}
|
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
import
|
|
2
|
-
`))if(
|
|
1
|
+
import c from"node:fs";import y from"node:path";import{execSync as C}from"node:child_process";import{bold as I,gray as g,cyan as p,red as Z,green as d,yellow as _}from"../ui/output.mjs";import{buildCursorImplementPrompt as Ct,buildGenericImplementPrompt as $t}from"../ui/prompts.mjs";import{detectDrift as bt}from"../git/detect-drift.mjs";function jt(n){try{const i=process.platform;if(i==="win32")C("clip",{input:n});else if(i==="darwin")C("pbcopy",{input:n});else try{C("xclip -selection clipboard",{input:n})}catch{C("xsel --clipboard --input",{input:n})}return!0}catch{return!1}}const h="inferno",D=y.join(h,"CONTEXT.md"),tt=y.join(h,"context-state.json");function et(n){try{return JSON.parse(c.readFileSync(n,"utf8"))}catch{return null}}function E(n){try{return c.readFileSync(n,"utf8")}catch{return null}}function nt(){const n=E(tt);if(!n)return{};try{return JSON.parse(n)}catch{return{}}}function ot(n){c.writeFileSync(tt,JSON.stringify(n,null,2),"utf8")}function A(n){return n?new Date(n).toLocaleDateString("en-GB",{day:"2-digit",month:"short",year:"numeric"}):"unknown"}function Ft(n,i){if(!n)return[];const s=[];let l=null;for(const a of n.split(`
|
|
2
|
+
`))if(a.startsWith("## ")){if(l&&s.length<i&&s.push(l),s.length>=i)break;l={title:a.replace("## ","").trim(),items:[]}}else l&&a.startsWith("- ")&&l.items.push(a.replace("- ","").trim());return l&&s.length<i&&s.push(l),s.filter(a=>a.items.length>0)}async function It(n){const i=t=>n.includes(t),s=t=>{const o=n.indexOf(t);return o!==-1&&n[o+1]?n[o+1]:null},l=s("--intent")||s("-i"),a=s("--working")||s("-w"),x=s("--decision")||s("-d"),it=i("--show")||i("-s"),B=i("--copy")||i("-c"),st=i("--cursor"),rt=i("--copilot"),ct=i("--reset"),lt=i("--watch"),P=i("--auto-commit")||i("--auto-push"),L=i("--auto-push"),R=parseInt(s("--interval")||"30",10)*1e3;console.log(`
|
|
3
3
|
`+I("\uFFFD\uFFFD\uFFFD infernoflow \u2014 context")),console.log(" "+"\u2500".repeat(50)+`
|
|
4
|
-
`),
|
|
5
|
-
`)),process.exit(1));const
|
|
6
|
-
`)),process.exit(1));let
|
|
7
|
-
`))),
|
|
8
|
-
`),
|
|
9
|
-
`+
|
|
4
|
+
`),c.existsSync(h)||(console.error(Z(" \u2718 inferno/ not found")),console.error(g(` \u2192 Run: infernoflow init
|
|
5
|
+
`)),process.exit(1));const S=et(y.join(h,"contract.json")),T=et(y.join(h,"capabilities.json")),at=E(y.join(h,"CHANGELOG.md"));(!S||!T)&&(console.error(Z(` \u2718 Missing contract.json or capabilities.json
|
|
6
|
+
`)),process.exit(1));let e=nt();ct&&(e={},console.log(_(` \u26A0 State reset
|
|
7
|
+
`))),l&&(e.intent=l,e.intentUpdated=new Date().toISOString(),console.log(d(' \u2714 Intent saved: "'+l+'"'))),a&&(e.working=a,e.workingUpdated=new Date().toISOString(),console.log(d(' \u2714 Working on: "'+a+'"'))),x&&(e.decisions||(e.decisions=[]),e.decisions.push({text:x,date:new Date().toISOString()}),console.log(d(' \u2714 Decision recorded: "'+x+'"'))),(l||a||x)&&ot(e);const O=T.capabilities||[],V=O.length===(S.capabilities||[]).length,J=Ft(at,3),W=String(S.policyVersion).replace(/^v/i,""),pt=new Date().toLocaleDateString("en-GB",{day:"2-digit",month:"short",year:"numeric"}),U=V?"\u2713 validated":"\u26A0 out of sync",G=e.intent||"describe the exact task to implement",X={task:G,contract:S,caps:T,scenarios:[],state:e},dt=Ct(X),ut=$t(X),gt=O.map(t=>"- **"+t.id+"** \u2014 "+t.title).join(`
|
|
8
|
+
`),mt=J.length>0?J.map(t=>"### "+t.title+`
|
|
9
|
+
`+t.items.map(o=>" - "+o).join(`
|
|
10
10
|
`)).join(`
|
|
11
11
|
|
|
12
|
-
`):"_No recent changes_",
|
|
13
|
-
`):"_No decisions recorded_",
|
|
14
|
-
`);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
`)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`)
|
|
21
|
-
`)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
`)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
`)
|
|
28
|
-
`)
|
|
29
|
-
|
|
12
|
+
`):"_No recent changes_",ft=e.intent?e.intent+" _("+A(e.intentUpdated)+")_":'_Not set \u2014 run: infernoflow context --intent "..."_',ht=e.working?e.working+" _("+A(e.workingUpdated)+")_":'_Not set \u2014 run: infernoflow context --working "..."_',wt=e.decisions&&e.decisions.length>0?e.decisions.slice(-5).map(t=>"- "+t.text+" _("+A(t.date)+")_").join(`
|
|
13
|
+
`):"_No decisions recorded_",M=y.join(h,"sessions.jsonl");let H='_No session history yet \u2014 use: infernoflow log "<what happened>"_';if(c.existsSync(M)){const t=c.readFileSync(M,"utf8").split(`
|
|
14
|
+
`).filter(Boolean).map(o=>{try{return JSON.parse(o)}catch{return null}}).filter(Boolean).slice(-10);t.length&&(H=t.map(o=>{const f=new Date(o.ts).toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}),u=o.result?` [${o.result}]`:"";return`- **${o.type||"note"}**${u} ${o.summary} _(${f})_`}).join(`
|
|
15
|
+
`))}const K=y.join(h,"theme.json");let q="_Not scanned yet \u2014 run: infernoflow theme_";if(c.existsSync(K))try{const t=JSON.parse(c.readFileSync(K,"utf8")),o=[];if(t.fonts?.primary&&o.push(`- **Font (primary):** ${t.fonts.primary}`),t.fonts?.mono&&o.push(`- **Font (mono):** ${t.fonts.mono}`),t.colors?.mode&&o.push(`- **Color mode:** ${t.colors.mode}`),t.colors?.palette){const f=Object.entries(t.colors.palette).map(([u,k])=>`${u}=${k}`).join(" ");o.push(`- **Palette:** ${f}`)}if(t.cssVars&&Object.keys(t.cssVars).length){const f=Object.entries(t.cssVars).slice(0,8).map(([u,k])=>`${u}: ${k}`).join(" | ");o.push(`- **CSS vars:** ${f}`)}t.framework&&o.push(`- **Framework:** ${t.framework}`),o.push("","> \u26A0 Always use these exact values. Do not introduce new colors or fonts."),q=o.join(`
|
|
16
|
+
`)}catch{}const N=["# Project Context \u2014 "+S.policyId+" v"+W,"> Generated by infernoflow | "+pt+" | "+U,"","---","","## Session Memory \u2014 what AI can't infer from code","_Decisions made, failed attempts, gotchas, preferences_","",H,"","---","","## Design System","_Fonts, colors, CSS vars \u2014 always match these exactly_","",q,"","---","","## What this system does","",gt,"","---","","## Recent changes","",mt,"","---","","## Current state","","- **Capabilities:** "+O.length,"- **Version:** v"+W,"- **Sync:** "+U,"","---","","## What I am working on right now","",ht,"","---","","## Intent \u2014 what I want to build next","",ft,"","---","","## Decisions & notes","",wt,"","---","","## Implementation Prompt Seed","","Use this to start coding immediately with an agent:","","```bash",`infernoflow implement "${G}" --mode both`,"```","","### Cursor Agent Prompt","","```text",dt,"```","","### Generic Agent Prompt","","```text",ut,"```","","---","_Paste this block at the start of any new AI session._"].join(`
|
|
17
|
+
`);if(it||(c.writeFileSync(D,N,"utf8"),console.log(d(`
|
|
18
|
+
\u2714 Context written \u2192 `+D))),B){const t=jt(N);console.log(t?d(" \u2714 Copied to clipboard \u2014 paste with Ctrl+V"):_(" \u26A0 Clipboard copy failed \u2014 open inferno/CONTEXT.md manually"))}if(st&&(c.writeFileSync(".cursorrules",N,"utf8"),console.log(d(" \u2714 Written to .cursorrules \u2014 Cursor loads this automatically"))),rt&&(c.existsSync(".github")||c.mkdirSync(".github"),c.writeFileSync(".github/copilot-instructions.md",N,"utf8"),console.log(d(" \u2714 Written to .github/copilot-instructions.md \u2014 Copilot loads this automatically"))),console.log(`
|
|
19
|
+
`+I("Context Summary")),console.log(" "+"\u2500".repeat(50)),console.log(" Project "+S.policyId+" \u2014 v"+W),console.log(" Capabilities "+O.length+" registered"),console.log(" Sync "+(V?d("\u2713 in sync"):_("\u26A0 check needed"))),console.log(" Working on "+(e.working?p(e.working):g("not set"))),console.log(" Intent "+(e.intent?p(e.intent):g("not set"))),console.log(" Decisions "+(e.decisions?e.decisions.length:0)+` recorded
|
|
20
|
+
`),console.log(" "+I("Implementation Prompt")),console.log(" "+p("\u2192")+" Run "+p(`infernoflow implement "${G}" --mode both`)+`
|
|
21
|
+
`),B?(console.log(" "+I("Ready to use:")),console.log(" "+p("\u2192")+" Paste into Claude / Cursor / Copilot with "+p("Ctrl+V")+`
|
|
22
|
+
`)):(console.log(" "+I("Ready to use:")),console.log(" "+p("1.")+" Open "+p("inferno/CONTEXT.md")),console.log(" "+p("2.")+" Copy everything"),console.log(" "+p("3.")+" Paste at the start of your next AI session"),console.log(" "+g(" tip: use --copy to skip steps 1-2 automatically")+`
|
|
23
|
+
`)),lt){let u=function(m){try{return C(m,{cwd:process.cwd(),encoding:"utf8",stdio:["ignore","pipe","pipe"]}),!0}catch{return!1}},k=function(m){try{return C(`git status --porcelain "${m}"`,{cwd:process.cwd(),encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()===""}catch{return!0}},z=function(m,r,v){const b=`chore: update context [${r.length>0?r.slice(0,3).join(", "):`${v} files`}]`;return u(`git add "${m}"`)?k(m)?{ok:!1,reason:"nothing to commit"}:u(`git commit -m "${b}"`)?{ok:!0,msg:b}:{ok:!1,reason:"git commit failed (lock?)"}:{ok:!1,reason:"git add failed"}},Q=function(){return u("git push")};var _t=u,xt=k,Ot=z,Nt=Q;const t=L?"auto-push":P?"auto-commit":"watch";console.log(" "+p("\u{1F441} Watch mode active")+g(` \u2014 polling every ${R/1e3}s`+(L?" \xB7 will commit + push on change":P?" \xB7 will commit on change":""))),console.log(" "+g(`Press Ctrl+C to stop
|
|
24
|
+
`));let o="",f=null;const Y=async()=>{try{const m=process.cwd(),r=bt(m,{sinceCommits:1}),v=r.changedFiles.sort().join("|");if(v===o||(o=v,r.changedFiles.length===0))return;const $=r.affectedCapabilities.map(F=>F.id),b=$.length>0?`Working on: ${$.join(", ")} (${r.changedFiles.length} files changed)`:`${r.changedFiles.length} files changed \u2014 no capability match yet`,j=nt();if(j.working!==b){j.working=b,j.workingUpdated=new Date().toISOString(),ot(j),await It(n.filter(w=>w!=="--watch"&&w!=="--auto-commit"&&w!=="--auto-push"));const F=E(D),St=new Date().toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",second:"2-digit"});if(process.stderr.write(`
|
|
25
|
+
${d("\u2714")} [${St}] Context updated \u2014 ${$.length} capabilities affected
|
|
26
|
+
${g(r.changedFiles.slice(0,3).join(", ")+(r.changedFiles.length>3?` +${r.changedFiles.length-3} more`:""))}
|
|
27
|
+
`),P&&F!==f){f=F;const w=z(D,$,r.changedFiles.length);if(w.ok){if(process.stderr.write(` ${d("\u2714")} Committed: ${g(w.msg)}
|
|
28
|
+
`),L){const kt=Q();process.stderr.write(kt?` ${d("\u2714")} Pushed to origin
|
|
29
|
+
`:` ${_("\u26A0")} Push failed \u2014 will retry next change
|
|
30
|
+
`)}}else process.stderr.write(` ${_("\u26A0")} Commit skipped: ${g(w.reason)}
|
|
31
|
+
`)}}}catch{}};await Y();const yt=setInterval(Y,R);process.on("SIGINT",()=>{clearInterval(yt),process.stderr.write(`
|
|
32
|
+
`+g(`Watch stopped.
|
|
30
33
|
|
|
31
|
-
`)),process.exit(0)}),await new Promise(()=>{})}}export{
|
|
34
|
+
`)),process.exit(0)}),await new Promise(()=>{})}}export{It as contextCommand};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import*as l from"node:fs";import*as y from"node:path";import"node:os";import{bold as w,cyan as _,gray as n,green as $,red as h}from"../ui/output.mjs";const O="inferno",i=y.join(O,"sessions.jsonl"),N=["note","attempt","decision","gotcha","preference","theme","handoff","error"],E=["worked","failed","partial","unknown"];function j(){return l.existsSync(i)?l.readFileSync(i,"utf8").split(`
|
|
2
|
+
`).filter(Boolean).map(e=>{try{return JSON.parse(e)}catch{return null}}).filter(Boolean):[]}function D(e){l.existsSync(O)||(console.error(h(` \u2718 inferno/ not found \u2014 run: infernoflow init
|
|
3
|
+
`)),process.exit(1)),l.appendFileSync(i,JSON.stringify(e)+`
|
|
4
|
+
`,"utf8")}function R(){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 T(e,c){const r=new Date(e.ts).toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}),t=e.type||"note",d=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",m="\x1B[0m",S=e.result?` [${e.result}]`:"",a=e.agent&&e.agent!=="human"?n(` (${e.agent})`):"";return` ${n(String(c+1).padStart(3))} ${n(r)} ${d}${t}${m}${S} ${e.summary}${a}`}async function U(e){const c=o=>e.includes(o),r=(o,g)=>{const u=e.indexOf(o);return u!==-1&&e[u+1]?e[u+1]:g},t=c("--show"),d=c("--clear"),m=c("--json");if(t||m){const o=j(),g=e[e.indexOf("--show")+1],u=g&&/^\d+$/.test(g)?parseInt(g):20,p=o.slice(-u);if(m){console.log(JSON.stringify(p,null,2));return}if(console.log(`
|
|
5
|
+
`+w("\u{1F525} infernoflow \u2014 session memory")),console.log(" "+"\u2500".repeat(50)),!p.length){console.log(n(`
|
|
6
|
+
No entries yet. Start logging with: infernoflow log "<what happened>"
|
|
7
|
+
`));return}console.log(n(` Showing last ${p.length} of ${o.length} entries
|
|
8
|
+
`)),p.forEach((L,v)=>console.log(T(L,o.length-p.length+v))),console.log();return}if(d){if(!l.existsSync(i)){console.log(n(` Nothing to clear.
|
|
9
|
+
`));return}const o=i.replace(".jsonl",`-archive-${Date.now()}.jsonl`);l.renameSync(i,o),console.log($(` \u2714 Session log archived \u2192 ${y.basename(o)}
|
|
10
|
+
`));return}const a=e.filter(o=>!o.startsWith("--")&&o!==r("--type","")&&o!==r("--result","")&&o!==r("--agent","")).join(" ").trim();if(!a){console.log(`
|
|
11
|
+
`+w("\u{1F525} infernoflow log")+` \u2014 append to session memory
|
|
12
|
+
`),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
|
|
13
|
+
`));return}const f=r("--type","note"),s=r("--result",null),I=r("--agent",R());N.includes(f)||(console.error(h(` \u2718 Invalid type: ${f}. Valid: ${N.join(", ")}
|
|
14
|
+
`)),process.exit(1)),s&&!E.includes(s)&&(console.error(h(` \u2718 Invalid result: ${s}. Valid: ${E.join(", ")}
|
|
15
|
+
`)),process.exit(1));const x={ts:new Date().toISOString(),agent:I,type:f,summary:a,...s?{result:s}:{}};D(x);const b=f!=="note"?_(` [${f}]`):"",F=s?n(` \u2192 ${s}`):"";console.log($(` \u2714 Logged${b}${F}: `)+a+`
|
|
16
|
+
`)}export{U as logCommand};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import*as u from"node:fs";import*as y from"node:path";import{scanTheme as F}from"../theme/scanner.mjs";import{bold as $,cyan as h,gray as i,green as k,yellow as d,red as I}from"../ui/output.mjs";const p="inferno",S=y.join(p,"theme.json"),w=y.join(p,"sessions.jsonl");function j(e){try{return JSON.parse(u.readFileSync(e,"utf8"))}catch{return null}}function N(e){u.existsSync(w)&&u.appendFileSync(w,JSON.stringify(e)+`
|
|
2
|
+
`,"utf8")}function C(e,o){const c=[];e?.fonts?.primary!==o?.fonts?.primary&&c.push(`primary font: ${e?.fonts?.primary||"none"} \u2192 ${o?.fonts?.primary||"none"}`),e?.fonts?.mono!==o?.fonts?.mono&&c.push(`mono font: ${e?.fonts?.mono||"none"} \u2192 ${o?.fonts?.mono||"none"}`),e?.colors?.mode!==o?.colors?.mode&&c.push(`color mode: ${e?.colors?.mode||"unknown"} \u2192 ${o?.colors?.mode}`);const l=e?.colors?.palette||{},f=o?.colors?.palette||{};for(const t of new Set([...Object.keys(l),...Object.keys(f)]))l[t]!==f[t]&&c.push(`${t} color: ${l[t]||"none"} \u2192 ${f[t]||"none"}`);const a=e?.cssVars||{},r=o?.cssVars||{},n=Object.keys(r).filter(t=>!a[t]),s=Object.keys(r).filter(t=>a[t]&&a[t]!==r[t]);return n.length&&c.push(`new CSS vars: ${n.slice(0,5).join(", ")}`),s.length&&c.push(`changed CSS vars: ${s.slice(0,5).join(", ")}`),c}function O(e){const{fonts:o,colors:c,cssVars:l,framework:f,stats:a}=e;console.log(`
|
|
3
|
+
`+$("\u{1F3A8} Design System")),console.log(" "+"\u2500".repeat(50)),console.log(h(`
|
|
4
|
+
Fonts`)),o.primary&&console.log(` Primary : ${o.primary}`),o.mono&&console.log(` Mono : ${o.mono}`),o.all?.length>2&&console.log(i(` All : ${o.all.join(", ")}`)),o.sources?.length&&console.log(i(` Sources : ${o.sources.join(", ")}`)),console.log(h(`
|
|
5
|
+
Colors`)+i(` (${c.mode} mode)`));for(const[r,n]of Object.entries(c.palette)){const s=`\x1B[48;2;${parseInt(n.slice(1,3),16)};${parseInt(n.slice(3,5),16)};${parseInt(n.slice(5,7),16)}m \x1B[0m`;console.log(` ${r.padEnd(14)} ${s} ${n}`)}if(Object.keys(l).length){console.log(h(`
|
|
6
|
+
CSS Variables`)+i(` (${Object.keys(l).length} found)`));const r=Object.entries(l).slice(0,12);for(const[n,s]of r)console.log(` ${n.padEnd(24)} ${i(s)}`);Object.keys(l).length>12&&console.log(i(` \u2026 and ${Object.keys(l).length-12} more`))}console.log(h(`
|
|
7
|
+
Framework`)+` ${f}`),console.log(i(`
|
|
8
|
+
Scanned: ${a.styleFiles} style files \xB7 ${a.colorsFound} colors \xB7 ${a.varsFound} CSS vars
|
|
9
|
+
`))}async function V(e){const o=n=>e.includes(n),c=o("--dry-run"),l=o("--show")||o("-s"),f=o("--json"),a=o("--watch");if(console.log(`
|
|
10
|
+
`+$("\u{1F525} infernoflow \u2014 theme")),console.log(" "+"\u2500".repeat(50)+`
|
|
11
|
+
`),u.existsSync(p)||(console.error(I(` \u2718 inferno/ not found \u2014 run: infernoflow init
|
|
12
|
+
`)),process.exit(1)),l){const n=j(S);if(!n){console.log(d(` \u26A0 No theme.json yet \u2014 run: infernoflow theme
|
|
13
|
+
`));return}if(f){console.log(JSON.stringify(n,null,2));return}O(n);return}const r=()=>{console.log(i(" Scanning style files\u2026"));const n=process.cwd(),s=F(n);if(f){console.log(JSON.stringify(s,null,2));return}if(O(s),c){console.log(d(` \u2691 Dry run \u2014 theme.json not written
|
|
14
|
+
`));return}const t=j(S),g={...s,scannedAt:new Date().toISOString()};if(u.writeFileSync(S,JSON.stringify(g,null,2)+`
|
|
15
|
+
`,"utf8"),console.log(k(` \u2714 Written \u2192 inferno/theme.json
|
|
16
|
+
`)),t){const m=C(t,s);if(m.length){N({ts:new Date().toISOString(),agent:"infernoflow",type:"theme",summary:"Theme changed: "+m.join("; ")}),console.log(d(" \u26A1 Theme changes logged to sessions.jsonl"));for(const b of m)console.log(i(` \u2022 ${b}`));console.log()}}};if(r(),a){console.log(h(` Watching style files for changes\u2026 (Ctrl+C to stop)
|
|
17
|
+
`));const{watch:n}=await import("node:fs");let s=null;n(process.cwd(),{recursive:!0},(t,g)=>{if(!g)return;const m=y.extname(g);[".css",".scss",".sass",".less",".styl"].includes(m)&&(s&&clearTimeout(s),s=setTimeout(()=>{console.log(i(`
|
|
18
|
+
Change detected: ${g}`)),r()},1e3))}),await new Promise(()=>{})}}export{V as themeCommand};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import*as p from"node:fs";import*as d from"node:path";const k=new Set([".css",".scss",".sass",".less",".styl"]),v=new Set([".js",".mjs",".jsx",".ts",".tsx"]),L=new Set(["node_modules",".git","dist","build","out",".next","coverage",".cache"]);function T(s,c=6,n=0){if(n>c)return[];let t=[];try{for(const o of p.readdirSync(s,{withFileTypes:!0})){if(L.has(o.name))continue;const r=d.join(s,o.name);o.isDirectory()?t=t.concat(T(r,c,n+1)):o.isFile()&&t.push(r)}}catch{}return t}const P=/#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b/g,B=/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*[\d.]+)?\s*\)/g,Z=/hsla?\(\s*(\d{1,3})\s*,\s*[\d.]+%\s*,\s*[\d.]+%(?:\s*,\s*[\d.]+)?\s*\)/g,_=new Set(["#000","#000000","#fff","#ffffff","#transparent","#333","#666","#999","#ccc","#eee"]);function b(s){return s.length===4?"#"+s[1]+s[1]+s[2]+s[2]+s[3]+s[3]:s.toLowerCase()}function G(s,c,n){return"#"+[s,c,n].map(t=>parseInt(t).toString(16).padStart(2,"0")).join("")}function E(s){const c={};for(const n of s.matchAll(P)){const t=b(n[0]);_.has(t)||(c[t]=(c[t]||0)+1)}for(const n of s.matchAll(B)){const t=G(n[1],n[2],n[3]);_.has(t)||(c[t]=(c[t]||0)+1)}return c}const M=/font-family\s*:\s*([^;}{]+)/gi,D=/@font-face\s*\{[^}]*font-family\s*:\s*['"]?([^'";]+)['"]?/gi,H=/fonts\.googleapis\.com\/css[^"']*family=([^"'&]+)/gi,Q=/from\s+['"]next\/font['"]\s*.*?{\s*([A-Z][a-zA-Z_]+)\s*}/gs,X=/import\s+\{([^}]+)\}\s+from\s+['"]@fontsource\/([^'"]+)['"]/g;function $(s){return s.split(",")[0].trim().replace(/['"]/g,"").replace(/\s+/g," ").trim()}function q(s,c){const n=new Set,t=new Set;for(const o of s.matchAll(M)){const r=$(o[1]);r&&!r.includes("var(")&&r.length>2&&n.add(r)}for(const o of s.matchAll(D)){const r=o[1].trim().replace(/['"]/g,"");r&&(n.add(r),t.add("local/@font-face"))}for(const o of s.matchAll(H)){const r=decodeURIComponent(o[1]).split("|");for(const i of r){const l=i.split(":")[0].replace(/\+/g," ").trim();l&&(n.add(l),t.add("Google Fonts"))}}for(const o of s.matchAll(X)){const i=o[2].trim().split("/").pop().replace(/-/g," ").replace(/\b\w/g,l=>l.toUpperCase());n.add(i),t.add("@fontsource")}return{fonts:[...n],sources:[...t]}}const z=/--([\w-]+)\s*:\s*([^;}{]+)/g;function K(s){const c={},n=[],t=/(?::root|html)\s*\{([^}]+)\}/gi;for(const o of s.matchAll(t))n.push(o[1]);n.push(s);for(const o of n)for(const r of o.matchAll(z)){const i="--"+r[1].trim(),l=r[2].trim();l&&!l.includes("{")&&(c[i]=l)}return c}function U(s){try{const c=p.readFileSync(s,"utf8"),n={},t={},o=/colors\s*:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/g;for(const i of c.matchAll(o)){const l=i[1];for(const e of l.matchAll(/['"]?([\w-]+)['"]?\s*:\s*['"]?(#[0-9a-fA-F]{3,6})['"]?/g))n[e[1]]=b(e[2])}const r=/fontFamily\s*:\s*\{([^}]+)\}/g;for(const i of c.matchAll(r)){const l=i[1];for(const e of l.matchAll(/['"]?([\w-]+)['"]?\s*:\s*\[['"]([^'"]+)['"]/g))t[e[1]]=e[2]}return{colors:n,fonts:t}}catch{return null}}function V(s,c){const n=o=>s.some(r=>d.basename(r)===o),t=o=>c.includes(o);return n("tailwind.config.js")||n("tailwind.config.ts")||n("tailwind.config.mjs")?"tailwind":t("styled-components")||t("createGlobalStyle")?"styled-components":t("@emotion/react")||t("css`")&&t("emotion")?"emotion":t("createTheme")&&t("@mui/material")?"mui":t("ChakraProvider")||t("@chakra-ui")?"chakra":t(".module.css")||t(".module.scss")?"css-modules":s.some(o=>k.has(d.extname(o)))?"plain-css":"unknown"}function J(s,c){const t=Object.entries(s).sort((e,f)=>f[1]-e[1]).slice(0,12).map(([e])=>e),o={},r={};for(const[e,f]of Object.entries(c))/^#[0-9a-fA-F]{3,6}$/.test(f)&&(r[b(f)]=e);for(const e of t){const f=r[e];if(f){const y=f.replace(/^--/,"").replace(/-color$/,"");o[y]=e}}Object.keys(o).length<3&&t.slice(0,6).forEach((e,f)=>{Object.values(o).includes(e)||(o[`color${f+1}`]=e)});const i=Object.entries(o).filter(([e])=>/bg|background|surface|base/.test(e)).map(([,e])=>e);let l="unknown";if(i.length){const e=parseInt(i[0].slice(1),16);l=(e>>16&255)*.299+(e>>8&255)*.587+(e&255)*.114<128?"dark":"light"}return{palette:o,mode:l,raw:t}}function W(s=process.cwd()){const c=T(s),n=c.filter(a=>k.has(d.extname(a))),t=c.filter(a=>v.has(d.extname(a))),o=c.filter(a=>[".html",".htm"].includes(d.extname(a))),r=c.find(a=>/tailwind\.config\.(js|ts|mjs|cjs)$/.test(a)),i=[...n,...o].map(a=>{try{return p.readFileSync(a,"utf8")}catch{return""}}),l=t.filter(a=>{try{return p.statSync(a).size<2e5}catch{return!1}}).map(a=>{try{return p.readFileSync(a,"utf8")}catch{return""}}),e=i.join(`
|
|
2
|
+
`),f=l.join(`
|
|
3
|
+
`),y=e+`
|
|
4
|
+
`+f,u=E(e),O=E(f);for(const[a,m]of Object.entries(O))u[a]=(u[a]||0)+Math.round(m*.5);const F=K(e),h={fonts:new Set,sources:new Set};for(const a of[...i,...l]){const{fonts:m,sources:I}=q(a,"");m.forEach(S=>h.fonts.add(S)),I.forEach(S=>h.sources.add(S))}const A=V(c,y);let g=null;if(r&&(g=U(r),g)){for(const[a,m]of Object.entries(g.colors))u[m]=(u[m]||0)+5;for(const[a,m]of Object.entries(g.fonts))h.fonts.add(m)}const{palette:R,mode:x,raw:C}=J(u,F),w=[...h.fonts].filter(a=>!["inherit","initial","unset","system-ui","sans-serif","serif","monospace","-apple-system","BlinkMacSystemFont","Segoe UI"].includes(a)),j=/mono|code|courier|consol|jetbrain|fira|hack|source code/i,N=w.find(a=>j.test(a));return{fonts:{primary:w.find(a=>!j.test(a))||null,mono:N||null,all:w,sources:[...h.sources]},colors:{palette:R,mode:x,raw:C.slice(0,20)},cssVars:F,framework:A,tailwind:g,stats:{styleFiles:n.length,jsFiles:t.length,colorsFound:Object.keys(u).length,varsFound:Object.keys(F).length}}}export{W as scanTheme};
|