infernoflow 0.42.2 → 0.42.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog — infernoflow
2
2
 
3
+ ## 0.42.5 — 2026-05-05
4
+
5
+ ### Added
6
+ - **VS Code extension Phase 1 — memory-first MVP rewrite** (`vscode-extension/` source, ships separately to the Marketplace, not via npm). The extension is now built around `.ai-memory/sessions.jsonl` instead of the old contract-system views. Five new TypeScript modules:
7
+ - `src/amp.ts` — wraps the `infernoflow-amp` npm package, single source of truth for memory I/O. File-watcher over both `.ai-memory/` and legacy `inferno/` so any CLI write triggers a refresh.
8
+ - `src/treeProvider.ts` — sidebar TreeView with Session Health, Gotchas, Decisions, Failed Attempts, and Quick Actions sections. Click an entry → jump to file:line.
9
+ - `src/statusBar.ts` — `🔥 B 65 · ⚠3 · ✓2 · ❌1 · 📋 Switch` with click-to-open-sidebar and click-to-copy-handoff. Colour-coded by health grade.
10
+ - `src/diagnostics.ts` — gotchas surface as Warnings in the Problems panel (Copilot reads them, so AI knows about gotchas before repeating mistakes).
11
+ - `src/commands.ts` — log gotcha/decision/attempt/note, ask (search), switch, recap, refresh, openPanel, migrateAmp. All with Ctrl+Alt+G/D/A/S/R bindings.
12
+ - **Right-click editor menu** — log gotcha or decision for the current line directly from the editor context menu (file/line auto-captured).
13
+ - **Extension settings** — `cliPath`, `showStatusBar`, `showDiagnostics`, `notifications` (all/important/none).
14
+ - **`vscode-extension/README.md`** rewritten to lead with "AI Session Memory" instead of contract-first framing.
15
+
16
+ ### Changed
17
+ - `vscode-extension/package.json` — replaced contracts views (Capabilities/Scenarios/Changelog) with a single Session Memory view. Replaced the 7 contracts commands with 10 memory-focused ones. Added 5 keybindings + right-click menu items. Added `infernoflow-amp@^1.0.0` as a runtime dependency.
18
+
19
+ ### Internal
20
+ - TypeScript compile clean (~850 lines across 6 files). Phase 2 (gutter icons + CodeLens + auto-capture), Phase 3 (Copilot Chat participant), and Phase 4 (cloud sync UI) deferred per the locked plan in `docs/EXTENSION_PLAN.md`.
21
+ - Marketplace publish itself stays manual: `cd vscode-extension && npm install && npx vsce package && npx vsce publish` after `vsce login infernoflow` is set up. See `vscode-extension/PUBLISH.md`.
22
+
23
+ ## 0.42.4 — 2026-05-05
24
+
25
+ ### Added
26
+ - **Cross-platform CI matrix** — `.github/workflows/ci.yml` now runs the smoke suite on **ubuntu-latest + windows-latest + macos-latest** across Node 18/20/22 (7 cells total). Catches Windows path / line-ending / shell-quoting bugs at PR time, not after a release.
27
+ - **Production audit job in CI** — `npm audit --omit=dev --audit-level=high` runs on every push so any introduced vulnerability fails the build.
28
+ - **VS Code extension shipped to v0.7.0** — `vscode-extension/package.json` modernised: leads with "Persistent memory for AI coding sessions", expanded keywords (ai-memory, amp, copilot/cursor/claude/windsurf), AI Marketplace category, gallery banner. Activates on the AMP layout (`.ai-memory/sessions.jsonl`) AND on the legacy `inferno/` layout.
29
+ - **`vscode-extension/PUBLISH.md`** — one-time setup walkthrough (Azure DevOps PAT + `vsce login`) and recurring `npx vsce publish` workflow for shipping the extension to the VS Code Marketplace.
30
+ - **`vscode-extension/CHANGELOG.md`** — Marketplace renders it on the listing page.
31
+
32
+ ### Internal
33
+ - Marketplace publish itself is a manual step (needs the maintainer's Azure DevOps PAT). All the prep — version, README, CHANGELOG, manifest fields, gallery banner — is in place; `npx vsce publish` from `vscode-extension/` ships it.
34
+
35
+ ## 0.42.3 — 2026-05-05
36
+
37
+ ### Added
38
+ - **`infernoflow amp` subsystem** — first-class verbs (status / migrate / validate / version) for the AI Memory Protocol. Already surfaced via the `amp` namespace dispatcher.
39
+ - **AMP MCP tool aliases** — `amp_read`, `amp_write`, `amp_handoff`, `amp_search`, `amp_health` exposed alongside the existing `infernoflow_*` tools in the bundled MCP server.
40
+ - **`switch` output redesign** — handoff is now screenshot-worthy:
41
+ - `## ⚠️ STOP — Read These Before Doing Anything (N gotchas)` banner
42
+ - Numbered lists for gotchas, decisions, attempts (not bullets)
43
+ - File paths shown inline next to gotchas (`→ File: src/api.js`)
44
+ - Session health score in header (`Health: A (90/100)`)
45
+ - Dropped redundant "Open threads" and "Recent session log" sections
46
+ - **Trust badges in README** — `dependencies-0` and `npm-audit-0-vulnerabilities`. Backed by `npm audit` returning clean.
47
+ - **Demo GIF recording guide** at `docs/DEMO_GIF.md` — 30-second shot list with timings.
48
+
49
+ ### Fixed
50
+ - `switch` health-score computation referenced an undefined `notes` filter; corrected so it builds against the actual gotcha/decision/attempt counts (max 90 instead of 100, since notes don't materialise here).
51
+ - Smoke test's gotcha-section assertion updated to match the new "STOP" header.
52
+
3
53
  ## 0.42.2 — 2026-05-03
4
54
 
5
55
  ### Added
package/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/infernoflow.svg?color=orange)](https://www.npmjs.com/package/infernoflow)
8
8
  [![npm downloads](https://img.shields.io/npm/dw/infernoflow.svg?color=orange)](https://www.npmjs.com/package/infernoflow)
9
+ [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](./package.json)
10
+ [![npm audit](https://img.shields.io/badge/npm%20audit-0%20vulnerabilities-brightgreen)](https://docs.npmjs.com/cli/v10/commands/npm-audit)
9
11
 
10
12
  ## The 60-second pitch
11
13
 
@@ -1,11 +1,11 @@
1
- import*as E from"node:fs";import*as g from"node:path";import"node:os";import{execSync as w}from"node:child_process";import{bold as W,cyan as S,gray as et,green as ot,yellow as B,red as it}from"../ui/output.mjs";import{ampPaths as rt,readEntries as ct,appendEntry as lt}from"../amp/io.mjs";const I="inferno";function V(){return rt(process.cwd())}const at=g.join(I,"HANDOFF.md"),wt=g.join(I,"sessions.jsonl"),J=g.join(I,"context-state.json"),z=g.join(I,"contract.json"),K=g.join(I,"theme.json"),X=g.join(I,"adoption_profile.json");function f(o){try{return JSON.parse(E.readFileSync(o,"utf8"))}catch{return null}}function pt(o){try{return E.readFileSync(o,"utf8")}catch{return null}}function F(o){return o?new Date(o).toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}):"unknown"}function q(o){if(o<0)return"unknown";const i=Math.floor(o/36e5),l=Math.floor(o%36e5/6e4);return i>0?`${i}h ${l}m`:`${l}m`}function Q(){return ct(process.cwd())}function Y(o,i,l){if(l)return new Date(0);if(i){const n=i.match(/^(\d+)h$/i),c=i.match(/^(\d+)d$/i);if(n)return new Date(Date.now()-parseInt(n[1])*36e5);if(c)return new Date(Date.now()-parseInt(c[1])*864e5);const s=new Date(i);if(!isNaN(s))return s}for(let n=o.length-1;n>=0;n--)if(o[n].type==="handoff"){const c=new Date(o[n].ts||0),s=new Date(Date.now()-864e5);return c>s?c:s}return new Date(Date.now()-864e5)}function ft(o){try{const i=process.platform;if(i==="win32")w("clip",{input:o});else if(i==="darwin")w("pbcopy",{input:o});else try{w("xclip -selection clipboard",{input:o})}catch{w("xsel --clipboard --input",{input:o})}return!0}catch{return!1}}function Z(){if(process.env.CURSOR_SESSION)return"Cursor";if(process.env.COPILOT_SESSION)return"GitHub Copilot";if(process.env.CLAUDE_CODE_SESSION)return"Claude Code";if(process.env.WINDSURF_SESSION)return"Windsurf";if(process.env.TERM_PROGRAM==="vscode")return"VS Code";const o=f(X);return o?.ide?o.ide:null}function ut(){try{const o=w("git diff --stat HEAD 2>/dev/null || git diff --cached --stat 2>/dev/null",{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim();return o||w("git log --stat -1 --pretty= 2>/dev/null",{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function nt(o){try{const i=o&&o.getTime()>0?`--after="${o.toISOString()}"`:"-10",l=w(`git log ${i} --name-only --pretty=format: 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim();if(!l)return[];const n={};for(const c of l.split(`
2
- `)){const s=c.trim();s&&(n[s]=(n[s]||0)+1)}return Object.entries(n).sort((c,s)=>s[1]-c[1]).slice(0,5).map(([c,s])=>({file:c,edits:s}))}catch{return[]}}function tt(o){try{const i=o?`--after="${o.toISOString()}"`:"-5",l=w(`git log ${i} --pretty=format:"%h %s" 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim();return l?l.split(`
3
- `).filter(Boolean):[]}catch{return[]}}function st(o){const i=[],l=o.filter(n=>n.type==="attempt"&&(n.result==="failed"||n.result==="partial"||!n.result));for(const n of l)o.find(s=>s.type==="attempt"&&s.result==="worked"&&new Date(s.ts)>new Date(n.ts)&&s.summary.toLowerCase().includes(n.summary.split(" ")[0].toLowerCase()))||i.push({text:n.summary,ts:n.ts,kind:"unresolved-attempt"});for(const n of o)/\b(TODO|WIP|FIXME|BLOCKED|pending)\b/i.test(n.summary)&&(i.find(c=>c.text===n.summary)||i.push({text:n.summary,ts:n.ts,kind:"flagged"}));return i.slice(0,8)}function dt(o,i,l){const n=f(J)||{},c=f(z)||{},s=f(K),b=f(X),$=Q(),a=Y($,i,l),k=$.filter(e=>new Date(e.ts||0)>a),H=$.slice(-5),D=new Date,u=D.toLocaleString("en-GB",{day:"2-digit",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"}),_=c.policyId||g.basename(process.cwd()),j=c.policyVersion||"?",O=(c.capabilities||[]).slice(0,20),x=Z(),R=a.getTime()>0?D-a:-1,N=q(R),A=a.getTime()>0?a.getTime().toString(16).slice(-6).toUpperCase():"ALL",T=tt(a.getTime()>0?a:null),C=ut(),G=nt(a.getTime()>0?a:null),m=k.length>0?k:H,r=m.filter(e=>e.type==="gotcha"),h=m.filter(e=>e.type==="decision"),M=m.filter(e=>e.type==="attempt").filter(e=>e.result==="failed"||e.result==="partial"),P=m.filter(e=>e.type==="preference"),L=m.slice(-8),d=st(m),U=a.getTime()===0?"all time":a.toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}),y=["sessions.jsonl"];(n.working||n.intent)&&y.push("context-state.json"),s&&y.push("theme.json"),c.capabilities?.length&&y.push("contract.json"),b&&y.push("adoption_profile.json"),T.length&&y.push("git log");const t=[`# \u{1F525} infernoflow Handoff \u2014 ${_}`,`> Generated: ${u}${o?` | Handing off to: **${o}**`:""}`,`> Session: **#${A}** \xB7 ${N} \xB7 **${k.length} entries** since ${U}`,`> Sources: ${y.join(" \xB7 ")}${x?` \xB7 IDE: ${x}`:""}`,"","---","","## Pick up here",""];if(n.working||n.intent?(n.working&&t.push(`**Working on:** ${n.working} _(${F(n.workingUpdated)})_`),n.intent&&t.push(`**Intent:** ${n.intent} _(${F(n.intentUpdated)})_`),t.push("")):t.push('_No working state set. Run: `infernoflow context --working "..."` to set it._',""),d.length){t.push("## \u{1F513} Open threads \u2014 not yet resolved","");for(const e of d){const p=e.kind==="flagged"?"[flagged]":"[unresolved]";t.push(`- ${p} ${e.text} _(${F(e.ts)})_`)}t.push("")}if(r.length){t.push("## \u26A0 Gotchas \u2014 read these first","");for(const e of r)t.push(`- ${e.summary} _(${F(e.ts)})_`);t.push("")}if(h.length){t.push("## Decisions made","");for(const e of h){const p=e.result?` \u2192 **${e.result}**`:"";t.push(`- ${e.summary}${p} _(${F(e.ts)})_`)}t.push("")}if(M.length){t.push("## \u2717 Already tried \u2014 don't repeat","");for(const e of M)t.push(`- ${e.summary} _(${F(e.ts)})_`);t.push("")}if(G.length){t.push("## \u{1F4C1} Hot Files This Session","");for(const{file:e,edits:p}of G)t.push(`- \`${e}\` \u2014 ${p} edit${p!==1?"s":""}`);t.push("")}if(P.length){t.push("## Developer preferences","");for(const e of P)t.push(`- ${e.summary}`);t.push("")}if(T.length||C){if(t.push("## Git activity this session",""),T.length){t.push("**Commits:**");for(const e of T)t.push(`- \`${e}\``);t.push("")}C&&(t.push("**Uncommitted changes:**"),t.push("```"),t.push(C.split(`
1
+ import*as b from"node:fs";import*as m from"node:path";import"node:os";import{execSync as S}from"node:child_process";import{bold as V,cyan as $,gray as it,green as rt,yellow as J,red as pt}from"../ui/output.mjs";import{ampPaths as ut,readEntries as dt,appendEntry as ht}from"../amp/io.mjs";const T="inferno";function z(){return ut(process.cwd())}const gt=m.join(T,"HANDOFF.md"),Ft=m.join(T,"sessions.jsonl"),K=m.join(T,"context-state.json"),X=m.join(T,"contract.json"),q=m.join(T,"theme.json"),Q=m.join(T,"adoption_profile.json");function u(t){try{return JSON.parse(b.readFileSync(t,"utf8"))}catch{return null}}function mt(t){try{return b.readFileSync(t,"utf8")}catch{return null}}function Y(t){return t?new Date(t).toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}):"unknown"}function Z(t){if(t<0)return"unknown";const i=Math.floor(t/36e5),l=Math.floor(t%36e5/6e4);return i>0?`${i}h ${l}m`:`${l}m`}function tt(){return dt(process.cwd())}function et(t,i,l){if(l)return new Date(0);if(i){const o=i.match(/^(\d+)h$/i),c=i.match(/^(\d+)d$/i);if(o)return new Date(Date.now()-parseInt(o[1])*36e5);if(c)return new Date(Date.now()-parseInt(c[1])*864e5);const s=new Date(i);if(!isNaN(s))return s}for(let o=t.length-1;o>=0;o--)if(t[o].type==="handoff"){const c=new Date(t[o].ts||0),s=new Date(Date.now()-864e5);return c>s?c:s}return new Date(Date.now()-864e5)}function yt(t){try{const i=process.platform;if(i==="win32")S("clip",{input:t});else if(i==="darwin")S("pbcopy",{input:t});else try{S("xclip -selection clipboard",{input:t})}catch{S("xsel --clipboard --input",{input:t})}return!0}catch{return!1}}function ot(){if(process.env.CURSOR_SESSION)return"Cursor";if(process.env.COPILOT_SESSION)return"GitHub Copilot";if(process.env.CLAUDE_CODE_SESSION)return"Claude Code";if(process.env.WINDSURF_SESSION)return"Windsurf";if(process.env.TERM_PROGRAM==="vscode")return"VS Code";const t=u(Q);return t?.ide?t.ide:null}function wt(){try{const t=S("git diff --stat HEAD 2>/dev/null || git diff --cached --stat 2>/dev/null",{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim();return t||S("git log --stat -1 --pretty= 2>/dev/null",{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function ct(t){try{const i=t&&t.getTime()>0?`--after="${t.toISOString()}"`:"-10",l=S(`git log ${i} --name-only --pretty=format: 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim();if(!l)return[];const o={};for(const c of l.split(`
2
+ `)){const s=c.trim();s&&(o[s]=(o[s]||0)+1)}return Object.entries(o).sort((c,s)=>s[1]-c[1]).slice(0,5).map(([c,s])=>({file:c,edits:s}))}catch{return[]}}function nt(t){try{const i=t?`--after="${t.toISOString()}"`:"-5",l=S(`git log ${i} --pretty=format:"%h %s" 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim();return l?l.split(`
3
+ `).filter(Boolean):[]}catch{return[]}}function lt(t){const i=[],l=t.filter(o=>o.type==="attempt"&&(o.result==="failed"||o.result==="partial"||!o.result));for(const o of l)t.find(s=>s.type==="attempt"&&s.result==="worked"&&new Date(s.ts)>new Date(o.ts)&&s.summary.toLowerCase().includes(o.summary.split(" ")[0].toLowerCase()))||i.push({text:o.summary,ts:o.ts,kind:"unresolved-attempt"});for(const o of t)/\b(TODO|WIP|FIXME|BLOCKED|pending)\b/i.test(o.summary)&&(i.find(c=>c.text===o.summary)||i.push({text:o.summary,ts:o.ts,kind:"flagged"}));return i.slice(0,8)}function St(t,i,l){const o=u(K)||{},c=u(X)||{},s=u(q),A=u(Q),D=tt(),a=et(D,i,l),N=D.filter(n=>new Date(n.ts||0)>a),H=D.slice(-5),I=new Date,d=I.toLocaleString("en-GB",{day:"2-digit",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"}),j=c.policyId||m.basename(process.cwd()),E=c.policyVersion||"?",O=(c.capabilities||[]).slice(0,20),x=ot(),M=a.getTime()>0?I-a:-1,k=Z(M),L=a.getTime()>0?a.getTime().toString(16).slice(-6).toUpperCase():"ALL",C=nt(a.getTime()>0?a:null),_=wt(),R=ct(a.getTime()>0?a:null),y=N.length>0?N:H,r=y.filter(n=>n.type==="gotcha"),h=y.filter(n=>n.type==="decision"),v=y.filter(n=>n.type==="attempt").filter(n=>n.result==="failed"||n.result==="partial"),G=y.filter(n=>n.type==="preference"),W=y.slice(-8),g=lt(y),st=a.getTime()===0?"all time":a.toLocaleString("en-GB",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}),w=["sessions.jsonl"];(o.working||o.intent)&&w.push("context-state.json"),s&&w.push("theme.json"),c.capabilities?.length&&w.push("contract.json"),A&&w.push("adoption_profile.json"),C.length&&w.push("git log");const B=r.length,P=h.length,at=v.length;let F=Math.min(B*20,40)+Math.min(P*15,30)+Math.min(at*15,20);F=Math.min(F,100);const ft=F>=80?"A":F>=60?"B":F>=40?"C":F>=20?"D":"F",e=[`# \u{1F525} infernoflow Handoff \u2014 ${j}`,`> Generated: ${d}${t?` | Handing off to: **${t}**`:""}`,`> Session: **#${L}** \xB7 ${k} \xB7 **${N.length} entries** \xB7 Health: **${ft}** (${F}/100)`,`> Sources: ${w.join(" \xB7 ")}${x?` \xB7 IDE: ${x}`:""}`,"","---",""];if((o.working||o.intent)&&(e.push("## \u{1F3AF} Working on",""),o.working&&e.push(`**${o.working}** _(${Y(o.workingUpdated)})_`),o.intent&&e.push(`Intent: ${o.intent} _(${Y(o.intentUpdated)})_`),e.push("")),r.length&&(e.push(`## \u26A0\uFE0F STOP \u2014 Read These Before Doing Anything (${r.length} gotcha${r.length===1?"":"s"})`,""),r.forEach((n,p)=>{e.push(`${p+1}. **${n.summary}**`);const f=n.file||n.source;if(f&&/[\\/.]/.test(f)){const U=n.line?`${f}:${n.line}`:f;e.push(` \u2192 File: \`${U}\``)}}),e.push("")),h.length&&(e.push("## \u2713 Decisions In Effect \u2014 Follow These",""),h.forEach((n,p)=>{const f=n.result?` \u2192 **${n.result}**`:"";e.push(`${p+1}. ${n.summary}${f}`)}),e.push("")),v.length&&(e.push("## \u274C Already Tried \u2014 Don't Repeat",""),v.forEach((n,p)=>{const f=n.file||n.source,U=f&&/[\\/.]/.test(f)?` (\`${f}\`)`:"";e.push(`${p+1}. ${n.summary}${U} _(${Y(n.ts)})_`)}),e.push("")),R.length){e.push("## \u{1F4C1} Hot Files This Session","");for(const{file:n,edits:p}of R)e.push(`- \`${n}\` \u2014 ${p} edit${p!==1?"s":""}`);e.push("")}if(G.length){e.push("## Developer preferences","");for(const n of G)e.push(`- ${n.summary}`);e.push("")}if(C.length||_){if(e.push("## Git activity this session",""),C.length){e.push("**Commits:**");for(const n of C)e.push(`- \`${n}\``);e.push("")}_&&(e.push("**Uncommitted changes:**"),e.push("```"),e.push(_.split(`
4
4
  `).slice(0,15).join(`
5
- `)),t.push("```"),t.push(""))}if(s){if(t.push("## Design system",""),s.fonts?.primary&&t.push(`- **Font:** ${s.fonts.primary}${s.fonts.mono?` \xB7 mono: ${s.fonts.mono}`:""}`),s.colors?.mode&&t.push(`- **Mode:** ${s.colors.mode}`),s.colors?.palette){const e=Object.entries(s.colors.palette).map(([p,v])=>`${p}=${v}`).join(" ");t.push(`- **Palette:** ${e}`)}if(s.cssVars&&Object.keys(s.cssVars).length){const e=Object.entries(s.cssVars).slice(0,6).map(([p,v])=>`${p}: ${v}`).join(" | ");t.push(`- **CSS vars:** ${e}`)}s.framework&&t.push(`- **Framework:** ${s.framework}`),t.push("","> \u26A0 Always match these exactly. Do not introduce new colors or fonts.","")}if(O.length&&(t.push("## Capability contract",""),t.push(`Project: **${_}** v${j}`),t.push(`Capabilities: ${O.join(", ")}`),t.push("")),L.length){t.push("## Recent session log","");for(const e of L){const p=e.result?` [${e.result}]`:"",v=e.source?` {${e.source}}`:"";t.push(`- **${e.type}**${p}${v}: ${e.summary} _(${F(e.ts)})_`)}t.push("")}return t.push("---"),t.push(`_Session #${A} \xB7 ${N} \xB7 Generated by infernoflow._`),t.join(`
6
- `)}async function St(o){const i=r=>o.includes(r),l=r=>{const h=o.indexOf(r);return h!==-1&&o[h+1]?o[h+1]:null},n=i("--show")||i("-s"),c=i("--copy")||i("-c"),s=i("--json"),b=i("--all"),$=l("--since"),a=l("--to")||o.find(r=>!r.startsWith("-")&&!["switch"].includes(r))||null;console.log(`
7
- `+W("\u{1F525} infernoflow \u2014 switch")),console.log(" "+"\u2500".repeat(50)+`
8
- `);const k=g.join(process.cwd(),".ai-memory");if(!E.existsSync(I)&&!E.existsSync(k)&&(console.error(it(` \u2718 not initialized \u2014 run: infernoflow init
9
- `)),process.exit(1)),n){const r=pt(at);if(!r){console.log(B(` \u26A0 No HANDOFF.md yet \u2014 run: infernoflow switch
10
- `));return}console.log(r);return}const H=dt(a,$,b);if(s){const r=f(J)||{},h=f(z)||{},M=f(K),P=f(X),L=Q(),d=Y(L,$,b),U=L.filter(e=>new Date(e.ts||0)>d),y=tt(d.getTime()>0?d:null),t=Z();console.log(JSON.stringify({state:r,contract:{policyId:h.policyId,policyVersion:h.policyVersion,capabilities:h.capabilities},theme:M,adoption:P,sessions:U,commits:y,ide:t,sessionStart:d.toISOString(),sessionId:d.getTime()>0?d.getTime().toString(16).slice(-6).toUpperCase():"ALL",sessionDuration:q(d.getTime()>0?Date.now()-d.getTime():-1),generatedAt:new Date().toISOString()},null,2));return}E.writeFileSync(V().handoff,H,"utf8"),console.log(ot(" \u2714 Written \u2192 "+g.relative(process.cwd(),V().handoff)+`
11
- `));const D=Q(),u=Y(D,$,b),_=D.filter(r=>new Date(r.ts||0)>u),j=f(J)||{},O=f(K),x=f(z)||{},R=tt(u.getTime()>0?u:null),N=nt(u.getTime()>0?u:null),A=Z(),T=_.length>0?_:D.slice(-5),C=st(T),G=q(u.getTime()>0?Date.now()-u.getTime():-1),m=u.getTime()>0?u.getTime().toString(16).slice(-6).toUpperCase():"ALL";if(console.log(" "+W("Handoff ready")),console.log(" "+"\u2500".repeat(50)),console.log(" "+et("Session #"+m+" \xB7 "+G)),j.working&&console.log(" Working on "+S(j.working)),j.intent&&console.log(" Intent "+S(j.intent)),console.log(" Memory "+_.length+" entries this session (total: "+D.length+")"),C.length&&console.log(" Open threads "+B(C.length+" unresolved")),R.length&&console.log(" Git commits "+R.length+" this session"),N.length&&console.log(" Hot files "+N.map(r=>S(r.file)).join(", ")),console.log(" Capabilities "+(x.capabilities||[]).length+" registered"),O?.fonts?.primary&&console.log(" Font "+O.fonts.primary),O?.colors?.mode&&console.log(" Color mode "+O.colors.mode),A&&console.log(" IDE "+A),a&&console.log(" Handing off \u2192 "+S(a)),console.log(),c){const r=ft(H);console.log(r?ot(" \u2714 Copied to clipboard \u2014 paste at the start of your next AI session"):B(" \u26A0 Clipboard failed \u2014 open inferno/HANDOFF.md manually"))}else console.log(" "+W("Ready to use:")),console.log(" "+S("1.")+" Open "+S("inferno/HANDOFF.md")),console.log(" "+S("2.")+" Copy all"),console.log(" "+S("3.")+" Paste at the start of your next AI session"),console.log(" "+et(" tip: use --copy to skip steps 1-2 automatically"));if(console.log(),E.existsSync(V().sessions)){const r={ts:new Date().toISOString(),agent:"infernoflow",type:"handoff",summary:a?`Handed off to ${a}`:"Handoff generated"};lt(process.cwd(),r)}}export{St as switchCommand};
5
+ `)),e.push("```"),e.push(""))}if(s){if(e.push("## Design system",""),s.fonts?.primary&&e.push(`- **Font:** ${s.fonts.primary}${s.fonts.mono?` \xB7 mono: ${s.fonts.mono}`:""}`),s.colors?.mode&&e.push(`- **Mode:** ${s.colors.mode}`),s.colors?.palette){const n=Object.entries(s.colors.palette).map(([p,f])=>`${p}=${f}`).join(" ");e.push(`- **Palette:** ${n}`)}if(s.cssVars&&Object.keys(s.cssVars).length){const n=Object.entries(s.cssVars).slice(0,6).map(([p,f])=>`${p}: ${f}`).join(" | ");e.push(`- **CSS vars:** ${n}`)}s.framework&&e.push(`- **Framework:** ${s.framework}`),e.push("","> \u26A0 Always match these exactly. Do not introduce new colors or fonts.","")}return O.length&&(e.push("## Capability contract",""),e.push(`Project: **${j}** v${E}`),e.push(`Capabilities: ${O.join(", ")}`),e.push("")),e.push("---"),e.push(`_Session #${L} \xB7 ${k} \xB7 Generated by infernoflow._`),e.join(`
6
+ `)}async function Tt(t){const i=r=>t.includes(r),l=r=>{const h=t.indexOf(r);return h!==-1&&t[h+1]?t[h+1]:null},o=i("--show")||i("-s"),c=i("--copy")||i("-c"),s=i("--json"),A=i("--all"),D=l("--since"),a=l("--to")||t.find(r=>!r.startsWith("-")&&!["switch"].includes(r))||null;console.log(`
7
+ `+V("\u{1F525} infernoflow \u2014 switch")),console.log(" "+"\u2500".repeat(50)+`
8
+ `);const N=m.join(process.cwd(),".ai-memory");if(!b.existsSync(T)&&!b.existsSync(N)&&(console.error(pt(` \u2718 not initialized \u2014 run: infernoflow init
9
+ `)),process.exit(1)),o){const r=mt(gt);if(!r){console.log(J(` \u26A0 No HANDOFF.md yet \u2014 run: infernoflow switch
10
+ `));return}console.log(r);return}const H=St(a,D,A);if(s){const r=u(K)||{},h=u(X)||{},v=u(q),G=u(Q),W=tt(),g=et(W,D,A),st=W.filter(P=>new Date(P.ts||0)>g),w=nt(g.getTime()>0?g:null),B=ot();console.log(JSON.stringify({state:r,contract:{policyId:h.policyId,policyVersion:h.policyVersion,capabilities:h.capabilities},theme:v,adoption:G,sessions:st,commits:w,ide:B,sessionStart:g.toISOString(),sessionId:g.getTime()>0?g.getTime().toString(16).slice(-6).toUpperCase():"ALL",sessionDuration:Z(g.getTime()>0?Date.now()-g.getTime():-1),generatedAt:new Date().toISOString()},null,2));return}b.writeFileSync(z().handoff,H,"utf8"),console.log(rt(" \u2714 Written \u2192 "+m.relative(process.cwd(),z().handoff)+`
11
+ `));const I=tt(),d=et(I,D,A),j=I.filter(r=>new Date(r.ts||0)>d),E=u(K)||{},O=u(q),x=u(X)||{},M=nt(d.getTime()>0?d:null),k=ct(d.getTime()>0?d:null),L=ot(),C=j.length>0?j:I.slice(-5),_=lt(C),R=Z(d.getTime()>0?Date.now()-d.getTime():-1),y=d.getTime()>0?d.getTime().toString(16).slice(-6).toUpperCase():"ALL";if(console.log(" "+V("Handoff ready")),console.log(" "+"\u2500".repeat(50)),console.log(" "+it("Session #"+y+" \xB7 "+R)),E.working&&console.log(" Working on "+$(E.working)),E.intent&&console.log(" Intent "+$(E.intent)),console.log(" Memory "+j.length+" entries this session (total: "+I.length+")"),_.length&&console.log(" Open threads "+J(_.length+" unresolved")),M.length&&console.log(" Git commits "+M.length+" this session"),k.length&&console.log(" Hot files "+k.map(r=>$(r.file)).join(", ")),console.log(" Capabilities "+(x.capabilities||[]).length+" registered"),O?.fonts?.primary&&console.log(" Font "+O.fonts.primary),O?.colors?.mode&&console.log(" Color mode "+O.colors.mode),L&&console.log(" IDE "+L),a&&console.log(" Handing off \u2192 "+$(a)),console.log(),c){const r=yt(H);console.log(r?rt(" \u2714 Copied to clipboard \u2014 paste at the start of your next AI session"):J(" \u26A0 Clipboard failed \u2014 open inferno/HANDOFF.md manually"))}else console.log(" "+V("Ready to use:")),console.log(" "+$("1.")+" Open "+$("inferno/HANDOFF.md")),console.log(" "+$("2.")+" Copy all"),console.log(" "+$("3.")+" Paste at the start of your next AI session"),console.log(" "+it(" tip: use --copy to skip steps 1-2 automatically"));if(console.log(),b.existsSync(z().sessions)){const r={ts:new Date().toISOString(),agent:"infernoflow",type:"handoff",summary:a?`Handed off to ${a}`:"Handoff generated"};ht(process.cwd(),r)}}export{Tt as switchCommand};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infernoflow",
3
- "version": "0.42.2",
3
+ "version": "0.42.5",
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": {