@anyforge/control 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +61 -8
  2. package/dist/cli.js +125 -102
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,55 +1,57 @@
1
1
  #!/usr/bin/env node
2
- var $i=Object.defineProperty;var Pi=(t,e)=>()=>(t&&(e=t(t=0)),e);var Li=(t,e)=>{for(var n in e)$i(t,n,{get:e[n],enumerable:!0})};var ir={};Li(ir,{default:()=>mc});var mc,sr=Pi(()=>{mc={name:"@anyforge/control",version:"0.6.3",description:"AnyForge CLI \u2014 hosted Oracle conversations, a governed LLM proxy, and a scriptable client for approvals, crews, work items and workflows.",license:"Apache-2.0",homepage:"https://anyforge.ai",repository:{type:"git",url:"git+https://github.com/pootonline/sovereign-engineering.git",directory:"packages/control/cli"},publishConfig:{access:"public"},type:"module",main:"dist/cli.js",bin:{anyforge:"dist/cli.js",control:"dist/cli.js"},files:["dist","README.md"],scripts:{build:"esbuild src/cli.ts --bundle --minify --platform=node --format=esm --outfile=dist/cli.js --packages=external && chmod +x dist/cli.js","type-check":"tsc --noEmit",test:"npm run build && node scripts/test.mjs",dev:"tsx src/cli.ts",prepublishOnly:"npm run build","publish:beta":"npm publish --access public --tag beta","publish:stable":"npm publish --access public"},engines:{node:">=22.19.0"},dependencies:{"@earendil-works/pi-tui":"^0.87.1",kleur:"^4.1.5",open:"^10.0.0",prompts:"^2.4.2","proper-lockfile":"^4.1.2"},devDependencies:{"@types/node":"^22.20.0","@types/prompts":"^2.4.9","@types/proper-lockfile":"^4.1.4",esbuild:"^0.25.0","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});import{red as gi,yellow as Mc,dim as kt,bold as B}from"kleur/colors";import{execFileSync as vn}from"child_process";import Wi from"open";import On from"prompts";import{green as et,dim as L,bold as Z,yellow as xe,cyan as Lt}from"kleur/colors";import{promises as _t}from"fs";import{homedir as Fi}from"os";import{join as yr,dirname as Qc}from"path";var Or=yr(Fi(),".anyforge"),hn=yr(Or,"credentials");async function vr(t){await _t.mkdir(Or,{recursive:!0,mode:448}),await _t.writeFile(hn,JSON.stringify(t,null,2),{mode:384})}async function Oe(){try{let t=await _t.readFile(hn,"utf8");return JSON.parse(t)}catch(t){if(t.code==="ENOENT")return null;throw t}}async function br(){try{return await _t.unlink(hn),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}import{promises as P}from"fs";import{execFileSync as Ni}from"child_process";import{homedir as le}from"os";import{join as M}from"path";import $t from"prompts";import{dim as X,green as yn,yellow as Pt}from"kleur/colors";var ve="# === AnyForge Control \u2014 added by `anyforge init` ===",Ze="# === end AnyForge Control ===",ke=".anyforge-bak",qi=/claude_(max|pro|team|enterprise)/i,Mi=["CLAUDE_CODE_ENABLE_TELEMETRY","OTEL_METRICS_EXPORTER","OTEL_EXPORTER_OTLP_PROTOCOL","OTEL_EXPORTER_OTLP_ENDPOINT","OTEL_EXPORTER_OTLP_HEADERS","OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"];async function Sr(t){let e=[],n=await Ui(t);if(n&&e.push(n),t.scope==="repo"){let r=await ji(t);return r&&e.push(r),e}for(let r of Bi){let o=await r.detect();if(!(!o||!(await $t({type:"confirm",name:"go",message:`Patch ${r.label} via shell rc (${X(o.path)}) ?`,initial:!0})).go))try{await r.patch(o,t),e.push({label:r.label,path:o.path}),console.log(yn(" \u2714")+" "+r.label)}catch(s){console.warn(" \u26A0 Skipped "+r.label+": "+s.message)}}return e}async function Ui(t){let e=t.scope==="repo"&&t.repoRoot?{dir:M(t.repoRoot,".claude"),file:"settings.local.json"}:{dir:M(le(),".claude"),file:"settings.json"},n=M(e.dir,e.file);if(!(await $t({type:"confirm",name:"go",message:`Patch Claude Code config at ${X(n)} ?`,initial:!0})).go)return null;await P.mkdir(e.dir,{recursive:!0});let o=await P.readFile(n,"utf8").catch(()=>"{}"),i;try{i=JSON.parse(o)}catch{i={}}let s=i.env??{},a=s.ANTHROPIC_BASE_URL;return a&&!a.includes(t.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(Pt(" \u26A0 Local LLM proxy detected: ")+X(a)),console.log(X(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(X(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(X(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(X(` from ${n}`)),console.log(),!(await $t({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await re(n)&&!await re(n+ke)&&await P.copyFile(n,n+ke),s.ANTHROPIC_BASE_URL=`${t.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=t.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await P.writeFile(n,JSON.stringify(i,null,2)+`
3
- `),console.log(yn(" \u2714")+" Claude Code"),{label:t.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function Ir(t){let e=M(le(),".claude"),n=M(e,"settings.json");await P.mkdir(e,{recursive:!0});let r=await P.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!wn(s,Er(t.endpoint))?(console.log(Pt(" \u26A0 An OpenTelemetry endpoint is already configured: ")+X(s)),console.log(X(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(X(" OTEL_EXPORTER_OTLP_ENDPOINT at "+t.endpoint+"/api/otel")),null):(await re(n)&&!await re(n+ke)&&await P.copyFile(n,n+ke),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${t.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${t.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await P.writeFile(n,JSON.stringify(o,null,2)+`
4
- `),{label:"Claude Code usage telemetry (global)",path:n})}async function ji(t){if(!t.repoRoot)return null;let e=M(t.repoRoot,".env");if(!(await $t({type:"confirm",name:"go",message:`Write AnyForge env block to ${X(e)} ?`,initial:!0})).go)return null;let r=[ve,`ANYFORGE_API_KEY=${t.apiKey}`,`ANTHROPIC_BASE_URL=${t.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${t.apiKey}`,`OPENAI_BASE_URL=${t.endpoint}/v1/openai`,`OPENAI_API_KEY=${t.apiKey}`,Ze,""].join(`
5
- `),o="";try{o=await P.readFile(e,"utf8")}catch{}let i;return o.includes(ve)?i=o.replace(new RegExp(`${ve}[\\s\\S]*?${Ze}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
2
+ var fs=Object.defineProperty;var ms=(t,e)=>()=>(t&&(e=t(t=0)),e);var gs=(t,e)=>{for(var n in e)fs(t,n,{get:e[n],enumerable:!0})};var kr={};gs(kr,{default:()=>el});var el,Ar=ms(()=>{el={name:"@anyforge/control",version:"0.7.1",description:"AnyForge CLI \u2014 hosted Oracle conversations, a governed LLM proxy, and a scriptable client for approvals, crews, work items and workflows.",license:"Apache-2.0",homepage:"https://anyforge.ai",repository:{type:"git",url:"git+https://github.com/pootonline/sovereign-engineering.git",directory:"packages/control/cli"},publishConfig:{access:"public"},type:"module",main:"dist/cli.js",bin:{anyforge:"dist/cli.js",control:"dist/cli.js"},files:["dist","README.md"],scripts:{build:"esbuild src/cli.ts --bundle --minify --platform=node --format=esm --outfile=dist/cli.js --packages=external && chmod +x dist/cli.js","type-check":"tsc --noEmit",test:"npm run build && node scripts/test.mjs",dev:"tsx src/cli.ts",prepublishOnly:"npm run build","publish:beta":"npm publish --access public --tag beta","publish:stable":"npm publish --access public"},engines:{node:">=22.19.0"},dependencies:{"@earendil-works/pi-tui":"^0.87.1",kleur:"^4.1.5",open:"^10.0.0",prompts:"^2.4.2","proper-lockfile":"^4.1.2"},devDependencies:{"@types/node":"^22.20.0","@types/prompts":"^2.4.9","@types/proper-lockfile":"^4.1.4",esbuild:"^0.25.0","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});import{red as Yi,yellow as Sl,dim as jt,bold as K}from"kleur/colors";import{execFileSync as Nn}from"child_process";import Is from"open";import Ln from"prompts";import{green as gt,dim as F,bold as oe,yellow as Le,cyan as Qt}from"kleur/colors";import{promises as Ht}from"fs";import{homedir as hs}from"os";import{join as qr,dirname as Ml}from"path";var jr=qr(hs(),".anyforge"),_n=qr(jr,"credentials");async function Mr(t){await Ht.mkdir(jr,{recursive:!0,mode:448}),await Ht.writeFile(_n,JSON.stringify(t,null,2),{mode:384})}async function Ye(){try{let t=await Ht.readFile(_n,"utf8");return JSON.parse(t)}catch(t){if(t.code==="ENOENT")return null;throw t}}async function Ur(){try{return await Ht.unlink(_n),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}import{promises as N}from"fs";import{execFileSync as ws}from"child_process";import{homedir as pe}from"os";import{join as B}from"path";import Yt from"prompts";import{dim as re,green as Pn,yellow as Jt}from"kleur/colors";var ke="# === AnyForge Control \u2014 added by `anyforge init` ===",mt="# === end AnyForge Control ===",Pe=".anyforge-bak",ys=/claude_(max|pro|team|enterprise)/i,Os=["CLAUDE_CODE_ENABLE_TELEMETRY","OTEL_METRICS_EXPORTER","OTEL_EXPORTER_OTLP_PROTOCOL","OTEL_EXPORTER_OTLP_ENDPOINT","OTEL_EXPORTER_OTLP_HEADERS","OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"];async function Kr(t){let e=[],n=await vs(t);if(n&&e.push(n),t.scope==="repo"){let r=await bs(t);return r&&e.push(r),e}for(let r of ks){let o=await r.detect();if(!(!o||!(await Yt({type:"confirm",name:"go",message:`Patch ${r.label} via shell rc (${re(o.path)}) ?`,initial:!0})).go))try{await r.patch(o,t),e.push({label:r.label,path:o.path}),console.log(Pn(" \u2714")+" "+r.label)}catch(s){console.warn(" \u26A0 Skipped "+r.label+": "+s.message)}}return e}async function vs(t){let e=t.scope==="repo"&&t.repoRoot?{dir:B(t.repoRoot,".claude"),file:"settings.local.json"}:{dir:B(pe(),".claude"),file:"settings.json"},n=B(e.dir,e.file);if(!(await Yt({type:"confirm",name:"go",message:`Patch Claude Code config at ${re(n)} ?`,initial:!0})).go)return null;await N.mkdir(e.dir,{recursive:!0});let o=await N.readFile(n,"utf8").catch(()=>"{}"),i;try{i=JSON.parse(o)}catch{i={}}let s=i.env??{},a=s.ANTHROPIC_BASE_URL;return a&&!a.includes(t.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(Jt(" \u26A0 Local LLM proxy detected: ")+re(a)),console.log(re(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(re(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(re(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(re(` from ${n}`)),console.log(),!(await Yt({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await ae(n)&&!await ae(n+Pe)&&await N.copyFile(n,n+Pe),s.ANTHROPIC_BASE_URL=`${t.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=t.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await N.writeFile(n,JSON.stringify(i,null,2)+`
3
+ `),console.log(Pn(" \u2714")+" Claude Code"),{label:t.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function zr(t){let e=B(pe(),".claude"),n=B(e,"settings.json");await N.mkdir(e,{recursive:!0});let r=await N.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!$n(s,Jr(t.endpoint))?(console.log(Jt(" \u26A0 An OpenTelemetry endpoint is already configured: ")+re(s)),console.log(re(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(re(" OTEL_EXPORTER_OTLP_ENDPOINT at "+t.endpoint+"/api/otel")),null):(await ae(n)&&!await ae(n+Pe)&&await N.copyFile(n,n+Pe),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${t.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${t.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await N.writeFile(n,JSON.stringify(o,null,2)+`
4
+ `),{label:"Claude Code usage telemetry (global)",path:n})}async function bs(t){if(!t.repoRoot)return null;let e=B(t.repoRoot,".env");if(!(await Yt({type:"confirm",name:"go",message:`Write AnyForge env block to ${re(e)} ?`,initial:!0})).go)return null;let r=[ke,`ANYFORGE_API_KEY=${t.apiKey}`,`ANTHROPIC_BASE_URL=${t.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${t.apiKey}`,`OPENAI_BASE_URL=${t.endpoint}/v1/openai`,`OPENAI_API_KEY=${t.apiKey}`,mt,""].join(`
5
+ `),o="";try{o=await N.readFile(e,"utf8")}catch{}let i;return o.includes(ke)?i=o.replace(new RegExp(`${ke}[\\s\\S]*?${mt}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
6
6
  `)?`${o}${r}`:`${o}
7
- ${r}`,i!==o&&await P.writeFile(e,i),await Di(t.repoRoot),console.log(yn(" \u2714")+" .env"),{label:".env (repo)",path:e}}async function Di(t){let e=M(t,".gitignore");try{(await P.readFile(e,"utf8")).split(`
8
- `).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(Pt(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(Pt(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}var Bi=[{label:"Cursor (shell hint)",async detect(){let t=M(le(),".cursor");return await re(t)?{path:".cursor (shell hint)"}:null},async patch(t,e){await Rr(e)}},{label:"Cline / Continue (shell hint)",async detect(){let t=await re(M(le(),".cline")),e=await re(M(le(),".continue"));return t||e?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(t,e){await Rr(e)}}];async function Rr(t){let e=[ve,`export ANYFORGE_API_KEY="${t.apiKey}"`,`export ANTHROPIC_BASE_URL="${t.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${t.apiKey}"`,`export OPENAI_BASE_URL="${t.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${t.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",Ze,""].join(`
9
- `);for(let n of[".zshrc",".bashrc"]){let r=M(le(),n);if(!await re(r))continue;let o=await P.readFile(r,"utf8"),i;o.includes(ve)?i=o.replace(new RegExp(`${ve}[\\s\\S]*?${Ze}\\n?`),e):i=o.endsWith(`
7
+ ${r}`,i!==o&&await N.writeFile(e,i),await Rs(t.repoRoot),console.log(Pn(" \u2714")+" .env"),{label:".env (repo)",path:e}}async function Rs(t){let e=B(t,".gitignore");try{(await N.readFile(e,"utf8")).split(`
8
+ `).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(Jt(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(Jt(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}var ks=[{label:"Cursor (shell hint)",async detect(){let t=B(pe(),".cursor");return await ae(t)?{path:".cursor (shell hint)"}:null},async patch(t,e){await Dr(e)}},{label:"Cline / Continue (shell hint)",async detect(){let t=await ae(B(pe(),".cline")),e=await ae(B(pe(),".continue"));return t||e?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(t,e){await Dr(e)}}];async function Dr(t){let e=[ke,`export ANYFORGE_API_KEY="${t.apiKey}"`,`export ANTHROPIC_BASE_URL="${t.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${t.apiKey}"`,`export OPENAI_BASE_URL="${t.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${t.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",mt,""].join(`
9
+ `);for(let n of[".zshrc",".bashrc"]){let r=B(pe(),n);if(!await ae(r))continue;let o=await N.readFile(r,"utf8"),i;o.includes(ke)?i=o.replace(new RegExp(`${ke}[\\s\\S]*?${mt}\\n?`),e):i=o.endsWith(`
10
10
  `)?`${o}
11
11
  ${e}`:`${o}
12
12
 
13
- ${e}`,i!==o&&await P.writeFile(r,i)}}async function re(t){try{return await P.access(t),!0}catch{return!1}}async function Cr(){try{let t=await P.readFile(M(le(),".claude.json"),"utf8"),n=JSON.parse(t).oauthAccount,r=n?.organizationType??"";if(n&&qi.test(r))return{isSubscription:!0,plan:/max/i.test(r)?"Max":/pro/i.test(r)?"Pro":/enterprise/i.test(r)?"Enterprise":/team/i.test(r)?"Team":r,email:n.emailAddress??null}}catch{}return{isSubscription:!1,plan:null,email:null}}async function Tr(t={}){let e=t.endpoint?Er(t.endpoint):null,n=[],r=M(le(),".claude","settings.json");await Ar(r,e)&&n.push(r);for(let i of[".zshrc",".bashrc"]){let s=M(le(),i);await kr(s)&&n.push(s)}let o=t.repoRoot??Gi(process.cwd());if(o){let i=M(o,".claude","settings.local.json");await Ar(i,e)&&n.push(i);let s=M(o,".env");await kr(s)&&n.push(s)}return{reverted:n}}function wn(t,e){return t?t.includes("anyforge")?!0:e?t.includes(e):!1:!1}async function Ar(t,e){if(!await re(t))return!1;if(await re(t+ke))return await P.copyFile(t+ke,t),await P.unlink(t+ke).catch(()=>{}),!0;let n;try{n=JSON.parse(await P.readFile(t,"utf8"))}catch{return!1}let r=n.env;if(!r)return!1;let o=!1,i=[["ANTHROPIC_BASE_URL","ANTHROPIC_AUTH_TOKEN"],["OPENAI_BASE_URL","OPENAI_API_KEY"]];for(let[s,a]of i)wn(r[s],e)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),wn(r.OTEL_EXPORTER_OTLP_ENDPOINT,e))for(let s of Mi)s in r&&(delete r[s],o=!0);return o?(Object.keys(r).length===0&&delete n.env,await P.writeFile(t,JSON.stringify(n,null,2)+`
14
- `),!0):!1}async function kr(t){let e;try{e=await P.readFile(t,"utf8")}catch{return!1}if(!e.includes(ve))return!1;let n=e.replace(new RegExp(`\\n?${xr(ve)}[\\s\\S]*?${xr(Ze)}\\n?`),`
13
+ ${e}`,i!==o&&await N.writeFile(r,i)}}async function ae(t){try{return await N.access(t),!0}catch{return!1}}async function Hr(){try{let t=await N.readFile(B(pe(),".claude.json"),"utf8"),n=JSON.parse(t).oauthAccount,r=n?.organizationType??"";if(n&&ys.test(r))return{isSubscription:!0,plan:/max/i.test(r)?"Max":/pro/i.test(r)?"Pro":/enterprise/i.test(r)?"Enterprise":/team/i.test(r)?"Team":r,email:n.emailAddress??null}}catch{}return{isSubscription:!1,plan:null,email:null}}async function Yr(t={}){let e=t.endpoint?Jr(t.endpoint):null,n=[],r=B(pe(),".claude","settings.json");await Br(r,e)&&n.push(r);for(let i of[".zshrc",".bashrc"]){let s=B(pe(),i);await Wr(s)&&n.push(s)}let o=t.repoRoot??As(process.cwd());if(o){let i=B(o,".claude","settings.local.json");await Br(i,e)&&n.push(i);let s=B(o,".env");await Wr(s)&&n.push(s)}return{reverted:n}}function $n(t,e){return t?t.includes("anyforge")?!0:e?t.includes(e):!1:!1}async function Br(t,e){if(!await ae(t))return!1;if(await ae(t+Pe))return await N.copyFile(t+Pe,t),await N.unlink(t+Pe).catch(()=>{}),!0;let n;try{n=JSON.parse(await N.readFile(t,"utf8"))}catch{return!1}let r=n.env;if(!r)return!1;let o=!1,i=[["ANTHROPIC_BASE_URL","ANTHROPIC_AUTH_TOKEN"],["OPENAI_BASE_URL","OPENAI_API_KEY"]];for(let[s,a]of i)$n(r[s],e)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),$n(r.OTEL_EXPORTER_OTLP_ENDPOINT,e))for(let s of Os)s in r&&(delete r[s],o=!0);return o?(Object.keys(r).length===0&&delete n.env,await N.writeFile(t,JSON.stringify(n,null,2)+`
14
+ `),!0):!1}async function Wr(t){let e;try{e=await N.readFile(t,"utf8")}catch{return!1}if(!e.includes(ke))return!1;let n=e.replace(new RegExp(`\\n?${Gr(ke)}[\\s\\S]*?${Gr(mt)}\\n?`),`
15
15
  `).replace(/\n{3,}/g,`
16
16
 
17
- `);return await P.writeFile(t,n),!0}function xr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Er(t){try{return new URL(t).host}catch{return null}}function Gi(t){try{return Ni("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var zi=2e3,Ki=900*1e3;async function $r(t){let{endpoint:e}=t;console.log(Z("AnyForge Control \u2014 device authorisation")),console.log(L(` endpoint: ${e}`));let n=process.cwd(),r=_r(n),o=r?Vi(r):null,s=await(await fetch(`${e}/api/cli/init`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({repo:o})})).json();if(!s.ok||!s.data)throw new Error(`Could not start the authorisation flow: ${s.error??"unknown error"}`);let{code:a,authUrl:c,pollUrl:p}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${Lt(c)}`),console.log(L(` Code: ${a}`)),console.log();try{await Wi(c)}catch{}let l=await Hi({pollUrl:p,endpoint:e});await vr(l),console.log(et("\u2714")+" API key saved to "+L("~/.anyforge/credentials"));let d=await Cr();if(d.isSubscription&&!t.force){await Ji(d,e,l.apiKey);return}let O=process.cwd(),x=_r(O),k=await Yi(x),b=await Sr({endpoint:e,apiKey:l.apiKey,scope:k,repoRoot:x});b.length===0?(console.log(xe("No agent configs were patched.")),console.log(L(" Set ANTHROPIC_BASE_URL="+e+"/v1/anthropic and")),console.log(L(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):Qi(b),console.log(),d.isSubscription&&t.force&&(console.log(xe(` \u26A0 --force: your Claude ${d.plan??""} subscription login is now shadowed`)),console.log(xe(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(xe(" needs an Anthropic API key on your company. Run ")+Z("anyforge logout")),console.log(xe(" to revert and restore your subscription."))),k==="repo"&&(console.log(L(" Re-run this command in another repo to patch it too,")),console.log(L(' or run from any directory and choose "global" to install system-wide.'))),console.log(Z("Done.")+" Visit "+Lt(`${e}/usage`)+" to see your traffic.")}async function Hi(t){let e=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-e<Ki;){await new Promise(i=>setTimeout(i,zi)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
18
- `),n=0);let o=await(await fetch(t.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+et("done")+`
17
+ `);return await N.writeFile(t,n),!0}function Gr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Jr(t){try{return new URL(t).host}catch{return null}}function As(t){try{return ws("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var xs=2e3,Ss=900*1e3;async function Vr(t){let{endpoint:e}=t;console.log(oe("AnyForge Control \u2014 device authorisation")),console.log(F(` endpoint: ${e}`));let n=process.cwd(),r=Qr(n),o=r?Ps(r):null,s=await(await fetch(`${e}/api/cli/init`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({repo:o})})).json();if(!s.ok||!s.data)throw new Error(`Could not start the authorisation flow: ${s.error??"unknown error"}`);let{code:a,authUrl:c,pollUrl:u}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${Qt(c)}`),console.log(F(` Code: ${a}`)),console.log();try{await Is(c)}catch{}let l=await Es({pollUrl:u,endpoint:e});await Mr(l),console.log(gt("\u2714")+" API key saved to "+F("~/.anyforge/credentials"));let p=await Hr();if(p.isSubscription&&!t.force){await Cs(p,e,l.apiKey);return}let k=process.cwd(),x=Qr(k),b=await _s(x),O=await Kr({endpoint:e,apiKey:l.apiKey,scope:b,repoRoot:x});O.length===0?(console.log(Le("No agent configs were patched.")),console.log(F(" Set ANTHROPIC_BASE_URL="+e+"/v1/anthropic and")),console.log(F(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):$s(O),console.log(),p.isSubscription&&t.force&&(console.log(Le(` \u26A0 --force: your Claude ${p.plan??""} subscription login is now shadowed`)),console.log(Le(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(Le(" needs an Anthropic API key on your company. Run ")+oe("anyforge logout")),console.log(Le(" to revert and restore your subscription."))),b==="repo"&&(console.log(F(" Re-run this command in another repo to patch it too,")),console.log(F(' or run from any directory and choose "global" to install system-wide.'))),console.log(oe("Done.")+" Run `anyforge status` to check identity, local setup and recorded activity."),console.log(" MCP access, BYOK inference and optional subscription telemetry are separate. Usage: "+Qt(`${e}/usage`))}async function Es(t){let e=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-e<Ss;){await new Promise(i=>setTimeout(i,xs)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
18
+ `),n=0);let o=await(await fetch(t.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+gt("done")+`
19
19
  `),{apiKey:o.data.apiKey,companyId:o.data.companyId,endpoint:t.endpoint,savedAt:new Date().toISOString()};if(o.status==="expired"||o.status==="not_found")throw process.stdout.write(`
20
- `),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}async function Ji(t,e,n){let r=t.email?` (${t.email})`:"";console.log(),console.log(xe(` \u26A0 Claude ${t.plan??""} subscription login detected${r}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+Z("BYOK-only")+" \u2014 it routes"),console.log(" Claude Code through your own Anthropic API key for metering and"),console.log(" governance. Pointing Claude Code at the proxy would "+Z("override and")),console.log(" "+Z("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+Z("AnyForge")),console.log(" "+Z("MCP server")+" for control (HIL approvals, work items, crews):"),console.log();let o=`claude mcp add anyforge --env ANYFORGE_API_KEY=${n} -- npx -y @anyforge/mcp-server`;if((await On({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{vn("claude",["mcp","add","anyforge","--env",`ANYFORGE_API_KEY=${n}`,"--","npx","-y","@anyforge/mcp-server"],{stdio:"inherit"}),console.log(et(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(xe(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log(L(" Add it manually:")),console.log(" "+o)}else console.log(L(" Add it later with:")),console.log(" "+o);if(console.log(),(await On({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts only \u2014 no prompt content)",initial:!0})).go){let a=await Ir({endpoint:e,apiKey:n});a&&(console.log(et(" \u2714")+" Usage telemetry enabled \u2014 view it at "+Lt(`${e}/usage`)),console.log(L(" (written to "+a.path+"; `anyforge logout` removes it)")))}else console.log(L(" Skipped \u2014 your subscription usage stays local to Claude Code."));console.log(),console.log(L(" Want the metered BYOK proxy instead? Re-run with ")+Z("--force")+L(" using an")),console.log(L(" Anthropic API key on your company (this disables your subscription in")),console.log(L(" Claude Code; ")+Z("anyforge logout")+L(" reverts it).")),console.log(),console.log(Z("Done.")+" Visit "+Lt(`${e}/usage`)+" to see your traffic.")}function _r(t){try{return vn("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function Yi(t){return t?(await On({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${t}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log(L(" Not a git repo root \u2014 installing globally.")),console.log(L(" Run this from a repo root if you want a per-repo install instead.")),"global")}function Qi(t){console.log(et("\u2714")+" Patched "+t.length+" agent config"+(t.length===1?"":"s")+":");for(let e of t)console.log(` ${L("\u2022")} ${e.label} ${L("("+e.path+")")}`)}function Vi(t){try{let e=vn("git",["remote","get-url","origin"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=e.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=e.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}import{dim as Rn,yellow as ts,bold as ns}from"kleur/colors";var m={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,INTERRUPTED:130},f=class extends Error{exitCode;hint;constructor(e,n=m.FAILURE,r){super(e),this.name="CliError",this.exitCode=n,this.hint=r}},y=class extends f{constructor(e,n){super(e,m.USAGE,n),this.name="UsageError"}},oe=class extends f{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",m.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},be=class extends f{code;status;constructor(e,n,r){super(r?`${e}: ${r}`:e,m.API_ERROR,Xi(e,n)),this.name="ControlApiError",this.code=e,this.status=n}};function Xi(t,e){if(t==="missing_api_key"||t==="invalid_api_key"||t==="invalid_token"||e===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(t==="insufficient_scope"||e===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(e===404)return"No such id in this company. Check it with the matching list command.";if(e===429)return"Rate limited. Retry after a short pause."}var Pr="https://crew.anyforge.ai";async function Fe(t){let e=process.env.ANYFORGE_API_TOKEN,n=t||process.env.ANYFORGE_API_URL;if(e)return{apiKey:e,endpoint:n||Pr};let r=await Oe();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||Pr};throw new oe}async function E(t,e,n,r){let o=`${t.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new f(`Cannot reach ${t.endpoint}: ${a instanceof Error?a.message:String(a)}`,m.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new f(`Non-JSON response from ${o} (HTTP ${i.status}).`,m.FAILURE)}if(!i.ok||s.ok===!1){let a=typeof s.error=="string"?s.error:`http_${i.status}`,c=typeof s.message=="string"?s.message:typeof s.detail=="string"?s.detail:void 0;throw new be(a,i.status,c)}return s.data}function H(t){let e=Object.entries(t).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return e.length?`?${e.join("&")}`:""}async function tt(t){return E(t,"GET","/me")}function bn(t,e,n,r){let o=t?.entityLabels?.[e]?.[n];return typeof o=="string"&&o.trim()?o:r}async function Lr(t){try{return await tt(t)}catch{return null}}function Fr(t){return[...t].length}function Ne(t,e){if(e<=0)return"";let n=[...t];return n.length<=e?t:e===1?"\u2026":`${n.slice(0,e-1).join("")}\u2026`}function W(t,e){if(t.length===0)return"";let n=t.map(i=>e.map(s=>{let a=s.value(i)??"";return s.max?Ne(a,s.max):a})),r=e.map((i,s)=>Math.max(Fr(i.header),...n.map(a=>Fr(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(e.map(i=>i.header)),...n.map(o)].join(`
21
- `)}function C(t){return JSON.stringify(t,null,2)}function Nr(t,e=Date.now()){let n=Zi(t);if(n===null)return"\u2014";let r=Math.max(0,Math.floor((e-n)/1e3));if(r<60)return`${r}s`;let o=Math.floor(r/60);if(o<60)return`${o}m`;let i=Math.floor(o/60);return i<48?`${i}h`:`${Math.floor(i/24)}d`}function Zi(t){if(typeof t=="number")return Number.isFinite(t)?t:null;if(typeof t=="string"){let e=Date.parse(t);return Number.isNaN(e)?null:e}return null}function T(t,e,n="\u2014"){let r=t[e];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function G(t,e,n="\u2014"){for(let r of e){let o=t[r];if(typeof o=="string"&&o.trim())return o}return n}function ie(t){let e=Array.isArray(t)?t:t&&typeof t=="object"?es(t):null;return e?e.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function es(t){for(let e of["items","results","rows","data"])if(Array.isArray(t[e]))return t[e];return null}function Ft(t,e,n){let r=t?`last ${t}d`:"all time";return!e||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${t?`${t}d`:"all time"} \u2014 read cap`}async function qr(t){let e=await Fe(t.endpoint),n=await tt(e);if(t.json){console.log(C(n));return}console.log(`Company: ${ns(n.companyName??n.companyId)}${n.companyName?Rn(` (${n.companyId})`):""}`),console.log(`Endpoint: ${e.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):ts("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await Oe();console.log(r?Rn(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):Rn("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}import{green as Mr,dim as Nt,yellow as rs}from"kleur/colors";async function Ur(){let t=await Oe(),e=await br(),{reverted:n}=await Tr({endpoint:t?.endpoint??null});if(console.log(e?Mr("\u2714")+" Local credentials cleared.":rs("No credentials were saved on this machine.")),n.length){console.log(Mr("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${Nt("\u2022")} ${r}`);console.log(Nt(" Your previous Claude Code login (if any) is restored."))}else console.log(Nt(" No AnyForge config patches found to revert."));console.log(Nt(" Revoke the key server-side at /settings \u2192 API keys."))}import{green as os,red as qt,yellow as is,dim as Mt}from"kleur/colors";async function jr(t){let e=await Oe();if(!e){console.log(is("Not logged in.")+" Run "+Mt("npx @anyforge/control init")+" first.");return}let n=t.endpoint||e.endpoint;console.log(`Endpoint: ${n}`),console.log(`Company: ${e.companyId}`);let r={model:"claude-3-5-haiku-20241022",max_tokens:1,messages:[{role:"user",content:"Hi"}]},o;try{o=await fetch(`${n}/v1/anthropic/v1/messages`,{method:"POST",headers:{"Content-Type":"application/json","anthropic-version":"2023-06-01",Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(r)})}catch(i){console.log(qt("\u2717 Proxy unreachable: ")+i.message),process.exit(1)}o.status===401&&(console.log(qt("\u2717 API key rejected.")+" Re-run "+Mt("npx @anyforge/control init")+"."),process.exit(1)),o.status===502&&(console.log(qt("\u2717 No BYOK Anthropic key configured for your company.")),console.log(Mt(" Add one at ")+n+Mt("/settings \u2192 API keys.")),process.exit(1)),o.ok||(console.log(qt(`\u2717 Proxy returned ${o.status}: `)+(await o.text()).slice(0,200)),process.exit(1)),console.log(os("\u2714 Proxy reachable, key valid, BYOK configured."))}import{spawn as ss}from"node:child_process";import{readFile as as}from"node:fs/promises";import{red as nt,green as An,yellow as cs,dim as rt,bold as Dr}from"kleur/colors";async function Br(t){let e=await ls(t.patchFile);e.trim()||(process.stderr.write(nt(`Empty patch \u2014 nothing to apply.
22
- `)),process.exit(1));let n=ds(e);process.stderr.write(rt(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+An(`+${n.added}`)+" "+nt(`-${n.removed}`)+`
23
- `);let r=await kn(["apply","--check"],e);if(r.code!==0){if(t.threeWay){let i=await kn(["apply","--3way"],e);i.code!==0&&(process.stderr.write(nt(`3-way apply failed:
20
+ `),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}function Ts(t,e){return["mcp","add","anyforge","--env",`ANYFORGE_API_TOKEN=${e}`,"--env",`ANYFORGE_API_URL=${t}`,"--","npx","-y","@anyforge/mcp-server"]}async function Cs(t,e,n){let r=t.email?` (${t.email})`:"";console.log(),console.log(Le(` \u26A0 Claude ${t.plan??""} subscription login detected${r}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+oe("BYOK-only")+" \u2014 it routes"),console.log(" Claude Code through your own Anthropic API key for metering and"),console.log(" governance. Pointing Claude Code at the proxy would "+oe("override and")),console.log(" "+oe("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+oe("AnyForge")),console.log(" "+oe("MCP server")+" for control (HIL approvals, work items, crews):"),console.log();let o=Ts(e,n),i="claude mcp add anyforge -- npx -y @anyforge/mcp-server";if((await Ln({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{Nn("claude",o,{stdio:"inherit"}),console.log(gt(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(Le(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log(F(" Add it manually:")),console.log(" "+i)}else console.log(F(" Add it later with:")),console.log(" "+i);if(console.log(),(await Ln({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts only \u2014 no prompt content)",initial:!0})).go){let c=await zr({endpoint:e,apiKey:n});c&&(console.log(gt(" \u2714")+" Usage telemetry enabled \u2014 view it at "+Qt(`${e}/usage`)),console.log(F(" (written to "+c.path+"; `anyforge logout` removes it)")))}else console.log(F(" Skipped \u2014 your subscription usage stays local to Claude Code."));console.log(),console.log(F(" Want the metered BYOK proxy instead? Re-run with ")+oe("--force")+F(" using an")),console.log(F(" Anthropic API key on your company (this disables your subscription in")),console.log(F(" Claude Code; ")+oe("anyforge logout")+F(" reverts it).")),console.log(),console.log(oe("Done.")+" Run `anyforge status` to check identity, local setup and recorded activity."),console.log(" MCP access, BYOK inference and optional subscription telemetry are separate. Usage: "+Qt(`${e}/usage`))}function Qr(t){try{return Nn("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function _s(t){return t?(await Ln({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${t}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log(F(" Not a git repo root \u2014 installing globally.")),console.log(F(" Run this from a repo root if you want a per-repo install instead.")),"global")}function $s(t){console.log(gt("\u2714")+" Patched "+t.length+" agent config"+(t.length===1?"":"s")+":");for(let e of t)console.log(` ${F("\u2022")} ${e.label} ${F("("+e.path+")")}`)}function Ps(t){try{let e=Nn("git",["remote","get-url","origin"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=e.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=e.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}import{dim as qn,yellow as Us,bold as Ds}from"kleur/colors";var m={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,INTERRUPTED:130},f=class extends Error{exitCode;hint;constructor(e,n=m.FAILURE,r){super(e),this.name="CliError",this.exitCode=n,this.hint=r}},y=class extends f{constructor(e,n){super(e,m.USAGE,n),this.name="UsageError"}},ce=class extends f{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",m.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},Xr=4e3,Ae=class extends f{code;status;details;constructor(e,n,r,o){super(Ls(e,r,o),m.API_ERROR,Ns(e,n)),this.name="ControlApiError",this.code=e,this.status=n,o&&(this.details=o)}};function Ls(t,e,n){let r=e?`${t}: ${e}`:t;if(!n)return r;let o=JSON.stringify(n),i=o.length>Xr?`${o.slice(0,Xr)}\u2026(truncated)`:o;return`${r}
21
+ ${i}`}function Ns(t,e){if(t==="missing_api_key"||t==="invalid_api_key"||t==="invalid_token"||e===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(t==="insufficient_scope"||e===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(e===404)return"No such id in this company. Check it with the matching list command.";if(e===429)return"Rate limited. Retry after a short pause."}var Zr="https://crew.anyforge.ai";async function Ie(t){let e=process.env.ANYFORGE_API_TOKEN,n=t||process.env.ANYFORGE_API_URL;if(e)return{apiKey:e,endpoint:n||Zr};let r=await Ye();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||Zr};throw new ce}async function T(t,e,n,r){let o=`${t.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new f(`Cannot reach ${t.endpoint}: ${a instanceof Error?a.message:String(a)}`,m.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new f(`Non-JSON response from ${o} (HTTP ${i.status}).`,m.FAILURE)}if(!i.ok||s.ok===!1){let a=typeof s.error=="string"?s.error:`http_${i.status}`,c=typeof s.message=="string"?s.message:typeof s.detail=="string"?s.detail:void 0;throw new Ae(a,i.status,c,qs(s))}return s.data}var Fs=new Set(["ok","error","message","detail"]);function qs(t){if(!t||typeof t!="object"||Array.isArray(t))return;let e=Object.entries(t).filter(([n,r])=>!Fs.has(n)&&r!==void 0);return e.length?Object.fromEntries(e):void 0}function X(t){let e=Object.entries(t).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return e.length?`?${e.join("&")}`:""}async function ht(t){return T(t,"GET","/me")}function Fn(t,e,n,r){let o=t?.entityLabels?.[e]?.[n];return typeof o=="string"&&o.trim()?o:r}async function eo(t){try{return await ht(t)}catch{return null}}function to(t){return[...t].length}function Je(t,e){if(e<=0)return"";let n=[...t];return n.length<=e?t:e===1?"\u2026":`${n.slice(0,e-1).join("")}\u2026`}function J(t,e){if(t.length===0)return"";let n=t.map(i=>e.map(s=>{let a=s.value(i)??"";return s.max?Je(a,s.max):a})),r=e.map((i,s)=>Math.max(to(i.header),...n.map(a=>to(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(e.map(i=>i.header)),...n.map(o)].join(`
22
+ `)}function S(t){return JSON.stringify(t,null,2)}function no(t,e=Date.now()){let n=js(t);if(n===null)return"\u2014";let r=Math.max(0,Math.floor((e-n)/1e3));if(r<60)return`${r}s`;let o=Math.floor(r/60);if(o<60)return`${o}m`;let i=Math.floor(o/60);return i<48?`${i}h`:`${Math.floor(i/24)}d`}function js(t){if(typeof t=="number")return Number.isFinite(t)?t:null;if(typeof t=="string"){let e=Date.parse(t);return Number.isNaN(e)?null:e}return null}function C(t,e,n="\u2014"){let r=t[e];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function Y(t,e,n="\u2014"){for(let r of e){let o=t[r];if(typeof o=="string"&&o.trim())return o}return n}function le(t){let e=Array.isArray(t)?t:t&&typeof t=="object"?Ms(t):null;return e?e.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function Ms(t){for(let e of["items","results","rows","data"])if(Array.isArray(t[e]))return t[e];return null}function Vt(t,e,n){let r=t?`last ${t}d`:"all time";return!e||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${t?`${t}d`:"all time"} \u2014 read cap`}async function ro(t){let e=await Ie(t.endpoint),n=await ht(e);if(t.json){console.log(S(n));return}console.log(`Company: ${Ds(n.companyName??n.companyId)}${n.companyName?qn(` (${n.companyId})`):""}`),console.log(`Endpoint: ${e.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):Us("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await Ye();console.log(r?qn(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):qn("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}import{green as oo,dim as Xt,yellow as Bs}from"kleur/colors";async function io(){let t=await Ye(),e=await Ur(),{reverted:n}=await Yr({endpoint:t?.endpoint??null});if(console.log(e?oo("\u2714")+" Local credentials cleared.":Bs("No credentials were saved on this machine.")),n.length){console.log(oo("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${Xt("\u2022")} ${r}`);console.log(Xt(" Your previous Claude Code login (if any) is restored."))}else console.log(Xt(" No AnyForge config patches found to revert."));console.log(Xt(" Revoke the key server-side at /settings \u2192 API keys."))}import{readFile as Zt}from"node:fs/promises";import{homedir as Ws}from"node:os";import{dirname as jn,join as fe}from"node:path";function xe(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)?t:{}}async function so(t,e={home:Ws(),cwd:process.cwd(),env:process.env}){let n=t.endpoint.replace(/\/$/,""),r=[],o={};try{o=xe(JSON.parse(await Zt(fe(e.home,".anyforge","credentials"),"utf8")))}catch{}function i(a,c){let u=xe(c),l=xe(u.env),p=Object.values(xe(u.mcpServers));r.push({source:a,readable:!0,mcp:p.some(k=>{let x=xe(k),b=xe(x.env),O=Array.isArray(x.args)?x.args:[],R=b.ANYFORGE_API_TOKEN??e.env.ANYFORGE_API_TOKEN,A=b.ANYFORGE_API_URL??e.env.ANYFORGE_API_URL,z=R??o.apiKey,j=A??(R?"https://crew.anyforge.ai":o.endpoint)??"https://crew.anyforge.ai";return O.includes("@anyforge/mcp-server")&&z===t.apiKey&&j===n}),proxy:l.ANTHROPIC_BASE_URL===`${n}/v1/anthropic`&&l.ANTHROPIC_AUTH_TOKEN===t.apiKey,subscriptionTelemetry:String(l.CLAUDE_CODE_ENABLE_TELEMETRY)==="1"&&(l.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL??l.OTEL_EXPORTER_OTLP_PROTOCOL)==="http/json"&&(l.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===void 0||l.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===`${n}/api/otel/v1/metrics`)&&l.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE==="delta"&&l.OTEL_METRICS_EXPORTER==="otlp"&&l.OTEL_EXPORTER_OTLP_ENDPOINT===`${n}/api/otel`&&(l.OTEL_EXPORTER_OTLP_METRICS_HEADERS??l.OTEL_EXPORTER_OTLP_HEADERS)===`Authorization=Bearer ${t.apiKey}`})}i("Current shell",{env:e.env});let s=e.cwd;for(;jn(s)!==s;){try{await Zt(fe(s,".git","HEAD"));break}catch{}try{await Zt(fe(s,".git"));break}catch{}s=jn(s)}jn(s)===s&&(s=e.cwd);for(let a of new Set([fe(e.home,".claude","settings.json"),fe(s,".claude","settings.json"),fe(s,".claude","settings.local.json"),fe(s,".mcp.json"),fe(e.home,".claude.json")]))try{let c=JSON.parse(await Zt(a,"utf8"));if(i(a,c),a===fe(e.home,".claude.json")){let u=xe(xe(c).projects)[s];u&&i(`${a} (project)`,u)}}catch(c){c.code!=="ENOENT"&&r.push({source:a,mcp:!1,proxy:!1,subscriptionTelemetry:!1,readable:!1})}return r}var Gs=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,Ks=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function d(t){return t.replace(Gs,"").replace(Ks,"")}function Mn(t){try{let e=new URL(t);return e.protocol!=="https:"&&e.protocol!=="http:"||!e.hostname||e.username||e.password?null:e.toString()}catch{return null}}function ao(t){return t.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(e,n)=>Mn(n)?e:"\x1B]8;;\x07")}function co(t,e){if(!e||!t.startsWith("/")||t.startsWith("//"))return t;try{return new URL(t,e).toString()}catch{return t}}function lo(t,e){return e?t.replace(/(\]\()(<?)(\/(?!\/)[^\s)>]*)/g,(n,r,o,i)=>`${r}${o}${co(i,e)}`):t}function Un(t,e){let r=d(t).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(s,a,c,u)=>{let l=co(u.startsWith("<")&&u.endsWith(">")?u.slice(1,-1):u,e),p=Mn(l);return p?`${a}[${c}](${p})`:c}),o=new Map,i=r.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(s,a,c,u,l)=>{let p=Mn(u);return o.set(c.trim().toLowerCase(),p),p?`${a}${p}${l}`:""});return o.size===0?i:i.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(s,a,c,u)=>{let l=(u||c).trim().toLowerCase();return!o.has(l)||o.get(l)?s:c})}function me(t){return typeof t=="string"?d(t):Array.isArray(t)?t.map(e=>me(e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[d(e),me(n)])):t}function uo(t){return t.state==="received"?t.lastRecordedAt??"Timestamp unavailable":t.state==="unattributed"?"Unknown: this credential has no user attribution":t.state==="unavailable"?"Unavailable: retry the check":"No recorded activity for this user in this company"}async function po(t){let e=await Ie(t.endpoint),n=await T(e,"GET","/connection"),r=await so(e),o={...n,endpoint:e.endpoint,localConfiguration:r};if(t.json)console.log(S(o));else{let i=[`Endpoint: ${e.endpoint}`,`Company: ${n.identity.companyName??n.identity.companyId} (${n.identity.companyId})`,`User: ${n.identity.userId??"Unattributed credential"}`,`Granted scopes: ${n.identity.scopes.join(", ")||"none"} (individual actions also enforce role permissions)`,`Control API: authenticated at ${n.checkedAt}`,"MCP: shared Control API verified; confirm the MCP connection in your agent client."];for(let[s,a]of[["mcp","MCP"],["proxy","Inference proxy"],["subscriptionTelemetry","Subscription telemetry"]]){let c=r.filter(u=>u[s]).map(u=>u.source);i.push(`${a} matching local settings: ${c.join(", ")||"not detected"}`)}for(let s of r.filter(a=>!a.readable))i.push(`Could not inspect: ${s.source}`);i.push("Settings are observations, not proof of effective client configuration; managed settings and other clients are not inspected.",`Latest recorded proxy usage: ${uo(n.proxy)}`,`Latest recorded subscription telemetry: ${uo(n.subscriptionTelemetry)}`,"Activity is for this user across devices, not proof that this installation is working now.","Inference forwarding was not tested. The proxy needs a company BYOK provider key.","Subscription inference stays with your provider. Optional telemetry records token counts and estimated cost, not prompts or full traces.",`Usage: ${e.endpoint.replace(/\/$/,"")}/usage`,`Traces: ${e.endpoint.replace(/\/$/,"")}/traces (MCP access alone does not create inference traces)`),console.log(i.map(d).join(`
23
+ `))}[n.proxy,n.subscriptionTelemetry].some(i=>i.state==="unavailable")&&(process.exitCode=1)}import{spawn as zs}from"node:child_process";import{readFile as Hs}from"node:fs/promises";import{red as wt,green as Dn,yellow as Ys,dim as yt,bold as fo}from"kleur/colors";async function mo(t){let e=await Js(t.patchFile);e.trim()||(process.stderr.write(wt(`Empty patch \u2014 nothing to apply.
24
+ `)),process.exit(1));let n=Qs(e);process.stderr.write(yt(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+Dn(`+${n.added}`)+" "+wt(`-${n.removed}`)+`
25
+ `);let r=await Bn(["apply","--check"],e);if(r.code!==0){if(t.threeWay){let i=await Bn(["apply","--3way"],e);i.code!==0&&(process.stderr.write(wt(`3-way apply failed:
24
26
  `)+i.stderr+`
25
- `),process.exit(1)),process.stderr.write(cs(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
26
- `));return}process.stderr.write(nt(`Patch does not apply cleanly:
27
+ `),process.exit(1)),process.stderr.write(Ys(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
28
+ `));return}process.stderr.write(wt(`Patch does not apply cleanly:
27
29
  `)+r.stderr+`
28
- `),process.stderr.write(rt("Try ")+Dr("--3way")+rt(` to attempt a 3-way merge against the index.
29
- `)),process.exit(1)}if(t.dryRun){process.stderr.write(An(`\u2713 Patch would apply cleanly.
30
- `));return}let o=await kn(["apply"],e);o.code!==0&&(process.stderr.write(nt(`git apply failed:
30
+ `),process.stderr.write(yt("Try ")+fo("--3way")+yt(` to attempt a 3-way merge against the index.
31
+ `)),process.exit(1)}if(t.dryRun){process.stderr.write(Dn(`\u2713 Patch would apply cleanly.
32
+ `));return}let o=await Bn(["apply"],e);o.code!==0&&(process.stderr.write(wt(`git apply failed:
31
33
  `)+o.stderr+`
32
- `),process.exit(1)),process.stderr.write(An(`\u2713 Applied.
33
- `)),n.files>0&&process.stderr.write(rt(" Run ")+Dr("git diff --stat")+rt(` to review.
34
- `))}async function ls(t){if(t)return await as(t,"utf8");let e=[];for await(let n of process.stdin)e.push(n);return Buffer.concat(e).toString("utf8")}function kn(t,e){return new Promise((n,r)=>{let o=ss("git",t,{stdio:["pipe","pipe","pipe"]}),i="",s="";o.stdout.on("data",a=>{i+=a.toString()}),o.stderr.on("data",a=>{s+=a.toString()}),o.on("error",r),o.on("close",a=>n({code:a??0,stdout:i,stderr:s})),o.stdin.write(e),o.stdin.end()})}function ds(t){let e=0,n=0,r=0;for(let o of t.split(`
35
- `))if(o.startsWith("diff --git"))e+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return e===0&&(n>0||r>0)&&(e=(t.match(/^\+\+\+ /gm)??[]).length),{files:e,added:n,removed:r}}import{bold as us,dim as xn,green as ps,red as fs}from"kleur/colors";async function Gr(t){let e=await E(t.creds,"GET",`/hil${H({limit:t.limit})}`);if(t.json){console.log(C(e));return}let n=ie(e);if(n.length===0){console.log(xn("No approvals pending."));return}console.log(W(n,[{header:"ID",value:r=>T(r,"id")},{header:"CREW",value:r=>T(r,"crewId"),max:24},{header:"AGE",value:r=>Nr(r.requestedAt)},{header:"SUMMARY",value:r=>G(r,["planSummary","summary","title","description"]),max:60}])),console.log(xn(`
36
- ${n.length} pending \xB7 approve with `)+us("anyforge approve <id>"))}async function Sn(t){if(!t.approvalId)throw new y(`${t.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let e=await E(t.creds,"POST",`/hil/${encodeURIComponent(t.approvalId)}`,{decision:t.decision,...t.notes?{notes:t.notes}:{}});if(t.json){console.log(C(e));return}let n=t.decision==="APPROVED"?ps("Approved"):fs("Rejected");console.log(`${n} ${t.approvalId}`);let r=e&&typeof e=="object"?e.signature:void 0;typeof r=="string"&&r&&console.log(xn(`Audit signature: ${r}`))}import{bold as ms,dim as In}from"kleur/colors";async function Wr(t){let e=await E(t.creds,"GET",`/crews${H({status:t.status,activeOnly:t.activeOnly,limit:t.limit})}`);if(t.json){console.log(C(e));return}let n=ie(e);if(n.length===0){console.log(In(t.activeOnly?"No active crews.":"No crews."));return}console.log(W(n,[{header:"ID",value:r=>T(r,"id")},{header:"STATUS",value:r=>T(r,"status")},{header:"TASK",value:r=>G(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>G(r,["errorMessage"],""),max:40}]))}async function zr(t){if(!t.crewId)throw new y("crew requires a crew id.","List them with `anyforge crews`.");let e=await E(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}${H({messages:t.messages})}`);if(t.json){console.log(C(e));return}let n=e?.crew&&typeof e.crew=="object"?e.crew:e;console.log(`${ms(gs(G(n,["taskDescription"],T(n,"id"))))}`),console.log(`Status: ${T(n,"status")}`),console.log(`Repo: ${G(n,["githubRepo"])}`);let r=T(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=T(n,"url","");o&&console.log(`Console: ${o}`);let i=ie(e?.chat);if(i.length>0){console.log(In(`
37
- Last ${i.length} messages:`));for(let s of i){let a=G(s,["agentRole","role","author","agent","type"],"?"),c=G(s,["content","body","text","summary"],"");c&&console.log(`${In(`[${a}]`)} ${Ne(c.replace(/\s+/g," "),160)}`)}}}async function Cn(t){if(!t.crewId)throw new y(`${t.action} requires a crew id.`,"List them with `anyforge crews`.");let e=await E(t.creds,"POST",`/crews/${encodeURIComponent(t.crewId)}/${t.action}`);if(t.json){console.log(C(e));return}console.log(`${t.action==="halt"?"Halted":"Resumed"} ${t.crewId}`)}function gs(t){return Ne(t.split(/\r?\n/).find(e=>e.trim())?.trim()??t,80)}import{bold as hs,dim as qe,red as Kr,yellow as Jr}from"kleur/colors";var ws=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),ys=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),Os={HIL_PENDING:"Decide it with `anyforge approvals`, or from the Slack alert.",HIL_SHIP:"Decide it with `anyforge approvals`, or from the Slack alert.",PERMISSION_PENDING:"The agent asked for a tool outside its profile. Allow or deny it in the Console.",PAUSED:"Restart it with `anyforge resume <id>`."};async function Yr(t){if(!t.workItemId)throw new y("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let e=await E(t.creds,"PATCH",`/work/${encodeURIComponent(t.workItemId)}`,{action:"dispatch",...t.profileId?{runProfileId:t.profileId}:{}});if(t.json&&!t.follow){console.log(C(e));return}let n=typeof e?.crewId=="string"?e.crewId:"";if(!n)throw new f("Dispatch was accepted but returned no crew id.",m.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of e?.warnings??[])console.error(Jr(`warning: ${r}`));if(!t.follow){console.log(`Started ${hs(n)} on ${t.workItemId}`),console.log(qe(`Follow it with \`anyforge crew follow ${n}\``));return}await Tn({creds:t.creds,json:t.json,crewId:n,intervalSeconds:t.intervalSeconds})}var vs=5,bs=10,Rs=120,Hr=30;async function Tn(t){if(!t.crewId)throw new y("crew follow requires a crew id.","List them with `anyforge crews --active`.");let e=Math.min(Math.max(t.intervalSeconds??bs,vs),Rs)*1e3,n=Date.now()+Hr*6e4,r=new Set,o="",i=!1;for(;;){let s=await E(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}?messages=50`),a=s?.crew??{},c=T(a,"status","");for(let p of s?.chat??[]){let l=T(p,"id","");!l||r.has(l)||(r.add(l),i&&!t.json&&As(p))}if(i=!0,c&&c!==o&&(t.json||console.log(qe(`\u2500\u2500 ${c}`)),o=c),ys.has(c)){if(t.json)console.log(C({crewId:t.crewId,status:c,waiting:!0,url:T(a,"url","")}));else{console.log(Jr(`
38
- ${c} \u2014 this crew is waiting on a person.`));let p=Os[c];p&&console.log(qe(p));let l=T(a,"url","");l&&console.log(qe(l))}return}if(ws.has(c)){if(t.json)console.log(C({crewId:t.crewId,status:c,waiting:!1,url:T(a,"url","")}));else{let p=`
39
- ${c}`;console.log(c==="COMPLETE"?p:Kr(p));let l=T(a,"prUrl","");l&&console.log(qe(l));let d=T(a,"errorMessage","");d&&console.log(Kr(d))}if(c!=="COMPLETE")throw new f(`Crew ${t.crewId} ended ${c}.`,m.FAILURE);return}if(Date.now()>=n)throw new f(`Still ${c||"running"} after ${Hr} minutes \u2014 giving up watching.`,m.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${t.crewId}\`.`);await xs(e)}}function As(t){let e=T(t,"agentRole","")||T(t,"type","?"),n=ks(t,["content","text","summary"]);n&&console.log(`${qe(`[${e}]`)} ${Ne(n.replace(/\s+/g," "),160)}`)}function ks(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function xs(t){return new Promise(e=>{setTimeout(e,t)})}import{dim as Ut}from"kleur/colors";var Vr=100;function Qr(t){let e=t&&typeof t=="object"?t:{};return{total:typeof e.total=="number"?e.total:null,hasMore:e.hasMore===!0,cursor:typeof e.nextCursor=="string"?e.nextCursor:null}}async function Ss(t){let e=s=>`/work${H({status:t.status,type:t.type,priority:t.priority,initiative:t.initiative,program:t.program,search:t.search,assignee:t.assignee,includeArchived:t.includeArchived,limit:t.limit,cursor:s})}`,n=await E(t.creds,"GET",e()),r=ie(n),o=Qr(n),i=1;if(!t.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<Vr;){let s=await E(t.creds,"GET",e(o.cursor));r.push(...ie(s)),o=Qr(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function Xr(t){let e=await Ss(t);if(t.json){console.log(C(t.all?{items:e.rows,total:e.total,hasMore:e.hasMore,nextCursor:null}:e.raw));return}let n=e.rows,r=await Lr(t.creds),o=bn(r,"work_item","plural","Work items");if(n.length===0){console.log(Ut(`No ${o.toLowerCase()} match that filter.`));return}console.log(W(n,[{header:"ID",value:c=>T(c,"id")},{header:"PRI",value:c=>T(c,"priority","")},{header:"TYPE",value:c=>T(c,"type","")},{header:"STATUS",value:c=>T(c,"status")},{header:"TITLE",value:c=>G(c,["title","name","summary"]),max:58}]));let i=(n.length===1?bn(r,"work_item","singular","work item"):o).toLowerCase(),s=e.total!==null&&e.total!==n.length?`${n.length} of ${e.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=e.hasMore?t.all?Ut(` \u2014 stopped after ${Vr} pages; narrow the filter`):Ut(" \u2014 pass --all for the rest"):"";console.log(`${Ut(`
40
- ${s}`)}${a}`)}import{bold as Is,dim as jt}from"kleur/colors";async function Zr(t){let e=await E(t.creds,"GET","/workflows");if(t.json){console.log(C(e));return}let n=ie(e);if(n.length===0){console.log(jt("No workflows defined."));return}console.log(W(n,[{header:"ID",value:r=>T(r,"id")},{header:"STATUS",value:r=>G(r,["status","state"],"")},{header:"NAME",value:r=>G(r,["name","title"]),max:58}])),console.log(jt(`
41
- Dispatch with `)+Is("anyforge run <id>"))}async function eo(t){if(!t.workflowId)throw new y("run requires a workflow id.","List them with `anyforge workflows`.");let e;if(t.input!==void 0){try{e=JSON.parse(t.input)}catch(o){throw new y(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!e||typeof e!="object"||Array.isArray(e))throw new y("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await E(t.creds,"POST",`/workflows/${encodeURIComponent(t.workflowId)}/run`,e===void 0?void 0:{inputs:e});if(t.json){console.log(C(n));return}let r=G(n??{},["id","runId"],"");console.log(`Queued run ${r||jt("(id not returned)")}`),console.log(jt("Runs pause at gate steps for an operator decision."))}import{dim as Cs}from"kleur/colors";async function to(t){let e=t.question?.trim();if(!e)throw new y("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!t.json&&process.stderr.isTTY&&process.stderr.write(Cs(`Asking the Oracle (this can take a few minutes)\u2026
42
- `));let n=await E(t.creds,"POST","/oracle",{question:e,...t.context?{context:t.context}:{}});if(t.json){console.log(C(n));return}let r=n&&typeof n=="object"?["answer","text","content","response"].map(o=>n[o]).find(o=>typeof o=="string"&&o.trim()):void 0;console.log(typeof r=="string"?r:C(n))}import{bold as En,dim as no,green as Ts,yellow as Es}from"kleur/colors";function _s(t){return typeof t=="number"?`${Math.round(t*100)}%`:"\u2014"}async function ro(t){let e=await E(t.creds,"GET",`/backtest-corpus${H({days:t.days})}`);if(t.json){console.log(C(e));return}let n=e.incidentsInWindow??0,r=e.backTestable??0,o=e.windowDays?`last ${e.windowDays}d`:"all time";console.log(`${En(String(r))} of ${En(String(n))} incidents are back-testable `+no(`(${_s(e.coverage)} \xB7 ${o})`)),e.viable?console.log(Ts("Enough to run a back-test.")):console.log(Es(`Not yet viable \u2014 ${e.shortfall??0} more needed.`));let i=(e.excluded??[]).filter(s=>s.count>0);i.length>0&&console.log(W(i,[{header:"EXCLUDED",value:s=>String(s.count)},{header:"REASON",value:s=>s.label,max:56}])),e.biggestGap&&console.log(no(`
43
- Biggest fixable gap: `)+En(`${e.biggestGap.label} (${e.biggestGap.count})`))}import{bold as Dt,dim as ot,green as $s,yellow as oo}from"kleur/colors";var _n=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";async function io(t){let e=await E(t.creds,"GET",`/review-interception${H({days:t.days})}`);if(t.json){console.log(C(e));return}let n=Ft(e.windowDays,e.truncated,e.oldestReviewMs),r=i=>{console.log(i)};if(r(`${Dt(String(e.seriousRaised??0))} serious findings raised across ${Dt(String(e.prsReviewed??0))} pull requests ${ot(`(${n})`)}`),e.verdict==="measured")r(`${$s(String(e.disappearedSerious??0))} no longer raised by the next round \u2014 ${Dt(_n(e.interceptionFloor))} to ${Dt(_n(e.interceptionCeiling))}`),r(ot(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${e.measurableSerious??0} that had a later round`));else{r(oo("Not enough findings had a later round to measure a rate."));for(let i of e.inconclusiveReasons??[])r(ot(` ${i}`))}let o=(e.byLens??[]).filter(i=>i.serious>0);if(o.length>0&&r(W(o,[{header:"LENS",value:i=>i.lens,max:16},{header:"RAISED",value:i=>String(i.raised)},{header:"SERIOUS",value:i=>String(i.serious)},{header:"CHECKED",value:i=>String(i.measurable)},{header:"GONE",value:i=>String(i.disappeared)}])),e.truncated){let i=e.oldestReviewMs?new Date(e.oldestReviewMs).toISOString().slice(0,10):null;r(oo(`
44
- Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}e.reviews&&e.skippedShare!=null&&e.skippedShare>0&&r(ot(`
45
- ${e.reviews.skipped} of ${e.reviews.total} reviews were skipped (${_n(e.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of e.caveats??[])r(ot(`
46
- ${i}`))}import{bold as it,dim as Se,green as Ps,red as Ls,yellow as $n}from"kleur/colors";var Fs=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";function Pn(t){if(typeof t!="number")return"\u2014";if(t<60)return`${t}m`;if(t<1440){let n=Math.floor(t/60);return`${n}h ${Math.round(t-n*60)}m`}let e=Math.floor(t/1440);return`${e}d ${Math.round((t-e*1440)/60)}h`}var Ns={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function so(t){let e=await E(t.creds,"GET",`/review-coverage${H({days:t.days})}`);if(t.json){console.log(C(e));return}let n=s=>{console.log(s)},r=Ft(e.windowDays,e.truncated,e.oldestRecordMs);n(`${it(String(e.pullRequestsReviewed??0))} of ${it(String(e.pullRequestsSeen??0))} recorded pull requests reviewed ${e.coverageRate!=null?it(`(${Fs(e.coverageRate)})`):""} ${Se(`(${r})`)}`),e.repositoriesReviewed&&n(`across ${it(String(e.repositoriesReviewed))} repositories`),n(Se("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),e.medianLatencyMinutes!=null?(n(`
47
- Feedback reached the author in ${Ps(Pn(e.medianLatencyMinutes))} median, ${it(Pn(e.p90LatencyMinutes))} at p90 ${Se(`(${e.latencySamples??0} reviews)`)}`),e.medianOnOpenLatencyMinutes!=null&&n(Se(` ${Pn(e.medianOnOpenLatencyMinutes)} median on pull-request open (${e.onOpenSamples??0} reviews, no quiet period in the way)`))):n($n(`
34
+ `),process.exit(1)),process.stderr.write(Dn(`\u2713 Applied.
35
+ `)),n.files>0&&process.stderr.write(yt(" Run ")+fo("git diff --stat")+yt(` to review.
36
+ `))}async function Js(t){if(t)return await Hs(t,"utf8");let e=[];for await(let n of process.stdin)e.push(n);return Buffer.concat(e).toString("utf8")}function Bn(t,e){return new Promise((n,r)=>{let o=zs("git",t,{stdio:["pipe","pipe","pipe"]}),i="",s="";o.stdout.on("data",a=>{i+=a.toString()}),o.stderr.on("data",a=>{s+=a.toString()}),o.on("error",r),o.on("close",a=>n({code:a??0,stdout:i,stderr:s})),o.stdin.write(e),o.stdin.end()})}function Qs(t){let e=0,n=0,r=0;for(let o of t.split(`
37
+ `))if(o.startsWith("diff --git"))e+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return e===0&&(n>0||r>0)&&(e=(t.match(/^\+\+\+ /gm)??[]).length),{files:e,added:n,removed:r}}import{bold as Vs,dim as Wn,green as Xs,red as Zs}from"kleur/colors";async function go(t){let e=await T(t.creds,"GET",`/hil${X({limit:t.limit})}`);if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(Wn("No approvals pending."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"CREW",value:r=>C(r,"crewId"),max:24},{header:"AGE",value:r=>no(r.requestedAt)},{header:"SUMMARY",value:r=>Y(r,["planSummary","summary","title","description"]),max:60}])),console.log(Wn(`
38
+ ${n.length} pending \xB7 approve with `)+Vs("anyforge approve <id>"))}async function Gn(t){if(!t.approvalId)throw new y(`${t.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let e=await T(t.creds,"POST",`/hil/${encodeURIComponent(t.approvalId)}`,{decision:t.decision,...t.notes?{notes:t.notes}:{}});if(t.json){console.log(S(e));return}let n=t.decision==="APPROVED"?Xs("Approved"):Zs("Rejected");console.log(`${n} ${t.approvalId}`);let r=e&&typeof e=="object"?e.signature:void 0;typeof r=="string"&&r&&console.log(Wn(`Audit signature: ${r}`))}import{bold as ea,dim as Kn}from"kleur/colors";async function ho(t){let e=await T(t.creds,"GET",`/crews${X({status:t.status,activeOnly:t.activeOnly,limit:t.limit})}`);if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(Kn(t.activeOnly?"No active crews.":"No crews."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>C(r,"status")},{header:"TASK",value:r=>Y(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>Y(r,["errorMessage"],""),max:40}]))}async function wo(t){if(!t.crewId)throw new y("crew requires a crew id.","List them with `anyforge crews`.");let e=await T(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}${X({messages:t.messages})}`);if(t.json){console.log(S(e));return}let n=e?.crew&&typeof e.crew=="object"?e.crew:e;console.log(`${ea(ta(Y(n,["taskDescription"],C(n,"id"))))}`),console.log(`Status: ${C(n,"status")}`),console.log(`Repo: ${Y(n,["githubRepo"])}`);let r=C(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=C(n,"url","");o&&console.log(`Console: ${o}`);let i=le(e?.chat);if(i.length>0){console.log(Kn(`
39
+ Last ${i.length} messages:`));for(let s of i){let a=Y(s,["agentRole","role","author","agent","type"],"?"),c=Y(s,["content","body","text","summary"],"");c&&console.log(`${Kn(`[${a}]`)} ${Je(c.replace(/\s+/g," "),160)}`)}}}async function zn(t){if(!t.crewId)throw new y(`${t.action} requires a crew id.`,"List them with `anyforge crews`.");let e=await T(t.creds,"POST",`/crews/${encodeURIComponent(t.crewId)}/${t.action}`);if(t.json){console.log(S(e));return}console.log(`${t.action==="halt"?"Halted":"Resumed"} ${t.crewId}`)}function ta(t){return Je(t.split(/\r?\n/).find(e=>e.trim())?.trim()??t,80)}import{bold as na,dim as Qe,red as yo,yellow as vo}from"kleur/colors";var ra=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),oa=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),ia={HIL_PENDING:"Decide it with `anyforge approvals`, or from the Slack alert.",HIL_SHIP:"Decide it with `anyforge approvals`, or from the Slack alert.",PERMISSION_PENDING:"The agent asked for a tool outside its profile. Allow or deny it in the Console.",PAUSED:"Restart it with `anyforge resume <id>`."};async function bo(t){if(!t.workItemId)throw new y("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let e=await T(t.creds,"PATCH",`/work/${encodeURIComponent(t.workItemId)}`,{action:"dispatch",...t.profileId?{runProfileId:t.profileId}:{}});if(t.json&&!t.follow){console.log(S(e));return}let n=typeof e?.crewId=="string"?e.crewId:"";if(!n)throw new f("Dispatch was accepted but returned no crew id.",m.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of e?.warnings??[])console.error(vo(`warning: ${r}`));if(!t.follow){console.log(`Started ${na(n)} on ${t.workItemId}`),console.log(Qe(`Follow it with \`anyforge crew follow ${n}\``));return}await Hn({creds:t.creds,json:t.json,crewId:n,intervalSeconds:t.intervalSeconds})}var sa=5,aa=10,ca=120,Oo=30;async function Hn(t){if(!t.crewId)throw new y("crew follow requires a crew id.","List them with `anyforge crews --active`.");let e=Math.min(Math.max(t.intervalSeconds??aa,sa),ca)*1e3,n=Date.now()+Oo*6e4,r=new Set,o="",i=!1;for(;;){let s=await T(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}?messages=50`),a=s?.crew??{},c=C(a,"status","");for(let u of s?.chat??[]){let l=C(u,"id","");!l||r.has(l)||(r.add(l),i&&!t.json&&la(u))}if(i=!0,c&&c!==o&&(t.json||console.log(Qe(`\u2500\u2500 ${c}`)),o=c),oa.has(c)){if(t.json)console.log(S({crewId:t.crewId,status:c,waiting:!0,url:C(a,"url","")}));else{console.log(vo(`
40
+ ${c} \u2014 this crew is waiting on a person.`));let u=ia[c];u&&console.log(Qe(u));let l=C(a,"url","");l&&console.log(Qe(l))}return}if(ra.has(c)){if(t.json)console.log(S({crewId:t.crewId,status:c,waiting:!1,url:C(a,"url","")}));else{let u=`
41
+ ${c}`;console.log(c==="COMPLETE"?u:yo(u));let l=C(a,"prUrl","");l&&console.log(Qe(l));let p=C(a,"errorMessage","");p&&console.log(yo(p))}if(c!=="COMPLETE")throw new f(`Crew ${t.crewId} ended ${c}.`,m.FAILURE);return}if(Date.now()>=n)throw new f(`Still ${c||"running"} after ${Oo} minutes \u2014 giving up watching.`,m.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${t.crewId}\`.`);await ua(e)}}function la(t){let e=C(t,"agentRole","")||C(t,"type","?"),n=da(t,["content","text","summary"]);n&&console.log(`${Qe(`[${e}]`)} ${Je(n.replace(/\s+/g," "),160)}`)}function da(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function ua(t){return new Promise(e=>{setTimeout(e,t)})}import{dim as en}from"kleur/colors";var ko=100;function Ro(t){let e=t&&typeof t=="object"?t:{};return{total:typeof e.total=="number"?e.total:null,hasMore:e.hasMore===!0,cursor:typeof e.nextCursor=="string"?e.nextCursor:null}}async function pa(t){let e=s=>`/work${X({status:t.status,type:t.type,priority:t.priority,initiative:t.initiative,program:t.program,search:t.search,assignee:t.assignee,includeArchived:t.includeArchived,limit:t.limit,cursor:s})}`,n=await T(t.creds,"GET",e()),r=le(n),o=Ro(n),i=1;if(!t.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<ko;){let s=await T(t.creds,"GET",e(o.cursor));r.push(...le(s)),o=Ro(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function Ao(t){let e=await pa(t);if(t.json){console.log(S(t.all?{items:e.rows,total:e.total,hasMore:e.hasMore,nextCursor:null}:e.raw));return}let n=e.rows,r=await eo(t.creds),o=Fn(r,"work_item","plural","Work items");if(n.length===0){console.log(en(`No ${o.toLowerCase()} match that filter.`));return}console.log(J(n,[{header:"ID",value:c=>C(c,"id")},{header:"PRI",value:c=>C(c,"priority","")},{header:"TYPE",value:c=>C(c,"type","")},{header:"STATUS",value:c=>C(c,"status")},{header:"TITLE",value:c=>Y(c,["title","name","summary"]),max:58}]));let i=(n.length===1?Fn(r,"work_item","singular","work item"):o).toLowerCase(),s=e.total!==null&&e.total!==n.length?`${n.length} of ${e.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=e.hasMore?t.all?en(` \u2014 stopped after ${ko} pages; narrow the filter`):en(" \u2014 pass --all for the rest"):"";console.log(`${en(`
42
+ ${s}`)}${a}`)}import{bold as fa,dim as tn}from"kleur/colors";async function Io(t){let e=await T(t.creds,"GET","/workflows");if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(tn("No workflows defined."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>Y(r,["status","state"],"")},{header:"NAME",value:r=>Y(r,["name","title"]),max:58}])),console.log(tn(`
43
+ Dispatch with `)+fa("anyforge run <id>"))}async function xo(t){if(!t.workflowId)throw new y("run requires a workflow id.","List them with `anyforge workflows`.");let e;if(t.input!==void 0){try{e=JSON.parse(t.input)}catch(o){throw new y(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!e||typeof e!="object"||Array.isArray(e))throw new y("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await T(t.creds,"POST",`/workflows/${encodeURIComponent(t.workflowId)}/run`,e===void 0?void 0:{inputs:e});if(t.json){console.log(S(n));return}let r=Y(n??{},["id","runId"],"");console.log(`Queued run ${r||tn("(id not returned)")}`),console.log(tn("Runs pause at gate steps for an operator decision."))}import{dim as ma}from"kleur/colors";async function So(t){let e=t.question?.trim();if(!e)throw new y("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!t.json&&process.stderr.isTTY&&process.stderr.write(ma(`Asking the Oracle (this can take a few minutes)\u2026
44
+ `));let n=await T(t.creds,"POST","/oracle",{question:e,...t.context?{context:t.context}:{}});if(t.json){console.log(S(n));return}let r=n&&typeof n=="object"?["answer","text","content","response"].map(o=>n[o]).find(o=>typeof o=="string"&&o.trim()):void 0;console.log(typeof r=="string"?r:S(n))}import{bold as Yn,dim as Eo,green as ga,yellow as ha}from"kleur/colors";function wa(t){return typeof t=="number"?`${Math.round(t*100)}%`:"\u2014"}async function To(t){let e=await T(t.creds,"GET",`/backtest-corpus${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=e.incidentsInWindow??0,r=e.backTestable??0,o=e.windowDays?`last ${e.windowDays}d`:"all time";console.log(`${Yn(String(r))} of ${Yn(String(n))} incidents are back-testable `+Eo(`(${wa(e.coverage)} \xB7 ${o})`)),e.viable?console.log(ga("Enough to run a back-test.")):console.log(ha(`Not yet viable \u2014 ${e.shortfall??0} more needed.`));let i=(e.excluded??[]).filter(s=>s.count>0);i.length>0&&console.log(J(i,[{header:"EXCLUDED",value:s=>String(s.count)},{header:"REASON",value:s=>s.label,max:56}])),e.biggestGap&&console.log(Eo(`
45
+ Biggest fixable gap: `)+Yn(`${e.biggestGap.label} (${e.biggestGap.count})`))}import{bold as nn,dim as Ot,green as ya,yellow as Co}from"kleur/colors";var Jn=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";async function _o(t){let e=await T(t.creds,"GET",`/review-interception${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=Vt(e.windowDays,e.truncated,e.oldestReviewMs),r=i=>{console.log(i)};if(r(`${nn(String(e.seriousRaised??0))} serious findings raised across ${nn(String(e.prsReviewed??0))} pull requests ${Ot(`(${n})`)}`),e.verdict==="measured")r(`${ya(String(e.disappearedSerious??0))} no longer raised by the next round \u2014 ${nn(Jn(e.interceptionFloor))} to ${nn(Jn(e.interceptionCeiling))}`),r(Ot(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${e.measurableSerious??0} that had a later round`));else{r(Co("Not enough findings had a later round to measure a rate."));for(let i of e.inconclusiveReasons??[])r(Ot(` ${i}`))}let o=(e.byLens??[]).filter(i=>i.serious>0);if(o.length>0&&r(J(o,[{header:"LENS",value:i=>i.lens,max:16},{header:"RAISED",value:i=>String(i.raised)},{header:"SERIOUS",value:i=>String(i.serious)},{header:"CHECKED",value:i=>String(i.measurable)},{header:"GONE",value:i=>String(i.disappeared)}])),e.truncated){let i=e.oldestReviewMs?new Date(e.oldestReviewMs).toISOString().slice(0,10):null;r(Co(`
46
+ Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}e.reviews&&e.skippedShare!=null&&e.skippedShare>0&&r(Ot(`
47
+ ${e.reviews.skipped} of ${e.reviews.total} reviews were skipped (${Jn(e.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of e.caveats??[])r(Ot(`
48
+ ${i}`))}import{bold as vt,dim as Ne,green as Oa,red as va,yellow as Qn}from"kleur/colors";var ba=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";function Vn(t){if(typeof t!="number")return"\u2014";if(t<60)return`${t}m`;if(t<1440){let n=Math.floor(t/60);return`${n}h ${Math.round(t-n*60)}m`}let e=Math.floor(t/1440);return`${e}d ${Math.round((t-e*1440)/60)}h`}var Ra={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function $o(t){let e=await T(t.creds,"GET",`/review-coverage${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=s=>{console.log(s)},r=Vt(e.windowDays,e.truncated,e.oldestRecordMs);n(`${vt(String(e.pullRequestsReviewed??0))} of ${vt(String(e.pullRequestsSeen??0))} recorded pull requests reviewed ${e.coverageRate!=null?vt(`(${ba(e.coverageRate)})`):""} ${Ne(`(${r})`)}`),e.repositoriesReviewed&&n(`across ${vt(String(e.repositoriesReviewed))} repositories`),n(Ne("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),e.medianLatencyMinutes!=null?(n(`
49
+ Feedback reached the author in ${Oa(Vn(e.medianLatencyMinutes))} median, ${vt(Vn(e.p90LatencyMinutes))} at p90 ${Ne(`(${e.latencySamples??0} reviews)`)}`),e.medianOnOpenLatencyMinutes!=null&&n(Ne(` ${Vn(e.medianOnOpenLatencyMinutes)} median on pull-request open (${e.onOpenSamples??0} reviews, no quiet period in the way)`))):n(Qn(`
48
50
  Not enough timed reviews to report a latency figure.`));let o=e.capacityGapPullRequests??0;o>0&&n(`
49
- ${Ls(String(o))} pull requests went unreviewed because a limit fired `+Se("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=e.bySkipClass??[];i.length>0&&n(W(i,[{header:"WHY UNREVIEWED",value:s=>Ns[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),e.failedOnlyPullRequests&&n(Se(`${e.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of e.inconclusiveReasons??[])n($n(`
50
- ${s}`));if(e.truncated){let s=e.oldestRecordMs?new Date(e.oldestRecordMs).toISOString().slice(0,10):null;n($n(`
51
- Read cap reached \u2014 these are the most recent records${s?` (back to ${s})`:""}, not the whole window. Every count is a lower bound.`))}for(let s of e.caveats??[])n(Se(`
52
- ${s}`))}import{promises as st}from"node:fs";import{homedir as js}from"node:os";import{dirname as co,join as Ie}from"node:path";import{dim as lo,green as Ds,yellow as Bs}from"kleur/colors";var se="anyforge-platform",qs="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",ao="anyforge://guide/platform",Ms="text/markdown";var Bt={"SKILL.md":`---
51
+ ${va(String(o))} pull requests went unreviewed because a limit fired `+Ne("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=e.bySkipClass??[];i.length>0&&n(J(i,[{header:"WHY UNREVIEWED",value:s=>Ra[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),e.failedOnlyPullRequests&&n(Ne(`${e.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of e.inconclusiveReasons??[])n(Qn(`
52
+ ${s}`));if(e.truncated){let s=e.oldestRecordMs?new Date(e.oldestRecordMs).toISOString().slice(0,10):null;n(Qn(`
53
+ Read cap reached \u2014 these are the most recent records${s?` (back to ${s})`:""}, not the whole window. Every count is a lower bound.`))}for(let s of e.caveats??[])n(Ne(`
54
+ ${s}`))}import{promises as bt}from"node:fs";import{homedir as xa}from"node:os";import{dirname as Lo,join as Fe}from"node:path";import{dim as No,green as Sa,yellow as Ea}from"kleur/colors";var de="anyforge-platform",ka="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",Po="anyforge://guide/platform",Aa="text/markdown";var rn={"SKILL.md":`---
53
55
  name: anyforge-platform
54
56
  description: >
55
57
  Orient an agent to AnyForge's structure, delivery model, surfaces, live control
@@ -256,63 +258,72 @@ these sources can grant network, filesystem, tool, or approval authority.
256
258
  Do not place API keys, tokens, credentials, private tenant records, or customer
257
259
  data in a reusable skill, prompt, log, or generated example. Use the client's
258
260
  credential mechanism and let the server enforce access.
259
- `},kd=Object.entries(Bt).map(([t,e])=>({uri:t==="SKILL.md"?ao:`${ao}/${t}`,name:t==="SKILL.md"?se:`${se}/${t.replace(/^references\//,"")}`,title:t==="SKILL.md"?"AnyForge platform guide":t,description:t==="SKILL.md"?qs:`Reference for the ${se} skill: ${t}`,mimeType:Ms,size:new TextEncoder().encode(e).byteLength}));var Us=Bt["SKILL.md"],xd=Us.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"");var uo={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills"};function Gs(t){let e=t.scope==="user"?t.homeDir??js():t.cwd??process.cwd();if(t.scope==="user"&&t.client==="codex"){let n=t.codexHome??process.env.CODEX_HOME??Ie(e,".codex");return Ie(n,"skills",se)}return Ie(e,uo[t.client],se)}function Ws(t){if(t.scope!=="project"&&t.scope!=="user")throw new y(`--scope must be project or user, got "${t.scope}".`);if(!Object.hasOwn(uo,t.client))throw new y(`--client must be agents, claude, or codex, got "${t.client}".`)}async function Ln(t){try{return(await st.lstat(t)).isSymbolicLink()}catch(e){if(e.code==="ENOENT")return!1;throw e}}async function zs(t){Ws(t);let e=Gs(t),n=Object.entries(Bt),r=n.map(([s])=>Ie(e,s));if(await Ln(e))throw new y(`Refusing to install through the symbolic link ${e}.`);let o=new Set(n.map(([s])=>co(s)).filter(s=>s!=="."));for(let s of o)if(await Ln(Ie(e,s)))throw new y(`Refusing to install through the symbolic link ${Ie(e,s)}.`);if(!t.force){let s=[];for(let a of r)try{await st.access(a),s.push(a)}catch(c){if(c.code!=="ENOENT")throw c}if(s.length>0)throw new y(`The ${se} skill already exists at ${e}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await st.mkdir(e,{recursive:!0});let i=[];for(let[s,a]of n){let c=Ie(e,s);if(await st.mkdir(co(c),{recursive:!0}),await Ln(c))throw new y(`Refusing to replace the symbolic link ${c}.`);await st.writeFile(c,a,{encoding:"utf8",mode:420}),i.push(s)}return{name:se,scope:t.scope,client:t.client,directory:e,files:i}}async function po(t){if(t.subcommand!=="install")throw new y(`Unknown skill command${t.subcommand?`: ${t.subcommand}`:""}.`,"Use `anyforge skill install anyforge-platform`.");if(t.name!==se)throw new y(`Unknown skill${t.name?`: ${t.name}`:""}.`,`The only portable platform skill is ${se}.`);let e=t.scope??"project",n=t.client??"agents";if(!["project","user"].includes(e))throw new y(`--scope must be project or user, got "${e}".`);if(!["agents","claude","codex"].includes(n))throw new y(`--client must be agents, claude, or codex, got "${n}".`);let r=await zs({scope:e,client:n,force:t.force});if(t.json){process.stdout.write(JSON.stringify(r)+`
260
- `);return}console.log(Ds("Installed ")+`${r.name} ${lo(`(${r.scope}, ${r.client})`)}`),console.log(` ${r.directory}`),console.log(lo(` ${r.files.length} files installed. Re-run with --force to refresh them.`)),r.scope==="project"&&r.client==="agents"&&console.log(Bs(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as gc}from"node:crypto";import{open as hc,realpath as wc,stat as yc}from"node:fs/promises";import{basename as Oc,join as vc,resolve as bc}from"node:path";import{bold as fi,cyan as Rc,dim as At,yellow as cn}from"kleur/colors";import{ProcessTerminal as Ac,SelectList as kc,Text as xc,TuiAltScreen as Sc}from"@earendil-works/pi-tui";var Ks=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function Hs(t){return Ks.has(t)?"querying the code graph":t==="search_code_semantic"?"searching the code index":t==="search_codebase_docs"?"searching codebase docs":null}function Gt(t){let e=Hs(t);if(e)return e;let n=/^mcp__(.+?)__(.+)$/.exec(t);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:t.replace(/_/g," ")}var Js=new Set(["ask_user","present_catch_up_decision","present_memory_candidates"]);function Me(t){return typeof t=="string"&&Js.has(t)}import{truncateToWidth as Vt,wrapTextWithAnsi as No}from"@earendil-works/pi-tui";import{cyan as qo,dim as Je,green as Mo,italic as Ia,red as Qn,yellow as Vn}from"kleur/colors";import{truncateToWidth as at,visibleWidth as qn,wrapTextWithAnsi as Vs}from"@earendil-works/pi-tui";import{bold as Xs,dim as Zs}from"kleur/colors";var Ys=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,Qs=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function u(t){return t.replace(Ys,"").replace(Qs,"")}function Fn(t){try{let e=new URL(t);return e.protocol!=="https:"&&e.protocol!=="http:"||!e.hostname||e.username||e.password?null:e.toString()}catch{return null}}function fo(t){return t.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(e,n)=>Fn(n)?e:"\x1B]8;;\x07")}function mo(t,e){if(!e||!t.startsWith("/")||t.startsWith("//"))return t;try{return new URL(t,e).toString()}catch{return t}}function go(t,e){return e?t.replace(/(\]\()(<?)(\/(?!\/)[^\s)>]*)/g,(n,r,o,i)=>`${r}${o}${mo(i,e)}`):t}function Nn(t,e){let r=u(t).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(s,a,c,p)=>{let l=mo(p.startsWith("<")&&p.endsWith(">")?p.slice(1,-1):p,e),d=Fn(l);return d?`${a}[${c}](${d})`:c}),o=new Map,i=r.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(s,a,c,p,l)=>{let d=Fn(p);return o.set(c.trim().toLowerCase(),d),d?`${a}${d}${l}`:""});return o.size===0?i:i.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(s,a,c,p)=>{let l=(p||c).trim().toLowerCase();return!o.has(l)||o.get(l)?s:c})}function de(t){return typeof t=="string"?u(t):Array.isArray(t)?t.map(e=>de(e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[u(e),de(n)])):t}function N(t){return t<1024?`${t} B`:t<1024*1024?`${ct(t/1024)} KiB`:`${ct(t/(1024*1024))} MiB`}function lt(t){let e=Math.max(0,t);if(e<1e4)return`${ct(e/1e3)}s`;let n=Math.round(e/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/3600),o=Math.floor(n%3600/60),i=n%60;return r?o?`${r}h ${o}m`:`${r}h`:i?`${o}m ${i}s`:`${o}m`}function Mn(t){let e=Math.floor(Math.max(0,t)/1e3);return e<60?`${e}s`:`${Math.floor(e/60)}m ${String(e%60).padStart(2,"0")}s`}function ee(t){return Math.abs(t)<1e3?String(Math.round(t)):Math.abs(t)<1e6?`${ct(t/1e3,t<1e5?1:0)}k`:`${ct(t/1e6)}M`}function ct(t,e=1){return t.toFixed(e).replace(/\.0+$/,"")}function ea(t){return u(t).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function ta(t,e){return typeof e=="boolean"?e?"on":"off":typeof e=="string"?u(e):/Ms$/.test(t)?lt(e):/Bytes$/.test(t)?N(e):/tokens?/i.test(t)?ee(e):String(e)}function ho(t){return t?Object.entries(t).filter(e=>e[1]!==null).map(([e,n])=>`${ea(e)} ${ta(e,n)}`):[]}function Un(t,e,n=2){let r=Math.min(16,Math.max(...t.map(([s])=>qn(s)),0)+2),o=Math.max(10,e-n-r),i=[];for(let[s,a]of t)Vs(a,o).forEach((p,l)=>{let d=l===0?Zs(at(s,r-1).padEnd(r)):" ".repeat(r);i.push(at(`${" ".repeat(n)}${d}${p}`,e))});return i}function wo(t,e,n){return[at(Xs(t),n),...Un(e,n)]}function yo(t,e,n){let r=qn(n),o=e.filter(Boolean).join(" \xB7 ");if(r+4>t)return at(o||n,t);let i=t-r-2,s=at(o,i),a=Math.max(2,t-qn(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as ut,cyan as dt,dim as Re,green as na,italic as Oo,strikethrough as ra,underline as vo,yellow as oa}from"kleur/colors";import{Markdown as ia}from"@earendil-works/pi-tui";var sa={heading:t=>ut(dt(t)),link:t=>vo(dt(t)),linkUrl:t=>Re(t),code:t=>oa(t),codeBlock:t=>t,codeBlockBorder:t=>Re(t),quote:t=>Oo(t),quoteBorder:t=>Re(t),hr:t=>Re(t),listBullet:t=>dt(t),bold:t=>ut(t),italic:t=>Oo(t),strikethrough:t=>ra(t),underline:t=>vo(t)},pt={selectedPrefix:t=>dt(t),selectedText:t=>ut(t),description:t=>Re(t),scrollInfo:t=>Re(t),noMatch:t=>Re(t)},bo={borderColor:t=>Re(t),selectList:pt};var Ue=class{constructor(e,n){this.linkOrigin=n;this.content=u(e),this.markdown=new ia(Nn(this.content,n),0,0,sa)}content;markdown;cache;getText(){return this.content}setText(e){let n=u(e);n!==this.content&&(this.content=n,this.markdown.setText(Nn(n,this.linkOrigin)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(e){let n=Math.max(12,e);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(fo):[];return this.cache={width:n,lines:r},r}};function ft(t,e){return t==="user"?`${ut(na(e?u(e):"You"))}`:`${ut(dt("Oracle"))}`}function ue(t){return t.shared||t.visibility==="company"?`Shared with the company${t.entityKey?` \xB7 ${u(t.entityKey)}`:""}`:"Private to you"}function Ro(t){return t.shared||t.visibility==="company"?"shared":"private"}import{createReadStream as va}from"node:fs";import{stat as ba}from"node:fs/promises";import{basename as Ra}from"node:path";import{setTimeout as $o}from"node:timers/promises";var Ao={txt:"text/plain",log:"text/plain",md:"text/markdown",markdown:"text/markdown",csv:"text/csv",json:"application/json",pdf:"application/pdf",ts:"text/plain",tsx:"text/plain",js:"text/plain",jsx:"text/plain",mjs:"text/plain",cjs:"text/plain",py:"text/plain",go:"text/plain",rs:"text/plain",yaml:"text/plain",yml:"text/plain",toml:"text/plain",xml:"text/plain",html:"text/plain",css:"text/plain",sh:"text/plain",sql:"text/plain",java:"text/plain",kt:"text/plain",swift:"text/plain",c:"text/plain",h:"text/plain",cpp:"text/plain",rb:"text/plain",php:"text/plain",tf:"text/plain",diff:"text/plain",patch:"text/plain",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"};function ko(t){let e=t.slice(t.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(Ao,e)?Ao[e]:null}var jn="/api/v1/oracle";function fe(t){let e;try{e=new URL(t)}catch{throw new f(`Invalid Oracle endpoint: ${t}`,m.USAGE)}if(!["http:","https:"].includes(e.protocol)||e.username||e.password)throw new f("Oracle endpoint must be an http or https URL without embedded credentials.",m.USAGE);if(e.pathname!=="/"||e.search||e.hash)throw new f("Oracle endpoint must be the workspace origin, without a path, query or fragment.",m.USAGE);return e.origin}function pe(t,e){return`${fe(t)}${jn}${e}`}function aa(t,e,n){let r;try{r=new URL(t)}catch{throw new f(`Oracle server returned an invalid ${n} endpoint.`,m.API_ERROR)}let o=new URL(fe(e));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new f(`Oracle server returned an unsafe ${n} endpoint.`,m.API_ERROR);return r.toString()}function ca(t,e){if(!t||typeof t!="object")throw new f("Oracle server omitted OAuth endpoints.",m.API_ERROR);let n=t,r=["registration","authorization","token","revocation"],o={};for(let i of r){if(typeof n[i]!="string")throw new f(`Oracle server omitted its OAuth ${i} endpoint.`,m.API_ERROR);o[i]=aa(n[i],e,i)}return o}async function We(t,e=fetch,n){let r=fe(t),o;try{o=await e(pe(r,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(l){throw new f(`Cannot reach ${r}: ${l instanceof Error?l.message:String(l)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let i=await Be(o,pe(r,"/config")),s=$(De(i,o.status)),a=`${r}${jn}`;if(s.protocolVersion!==1)throw new f(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(s.protocolVersion)}.`,m.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(s.resource!==a)throw new f("Oracle server resource does not match this workspace origin.",m.API_ERROR);let c=Array.isArray(s.scopes)?s.scopes:null;if(!c||!c.every(l=>l==="read"||l==="write"||l==="approve"))throw new f("Oracle server returned an invalid scope list.",m.API_ERROR);let p={protocolVersion:1,resource:a,scopes:c,oauth:ca(s.oauth,r)};if(s.identity!==void 0){let l=$(s.identity);if(typeof l.uid!="string"||typeof l.companyId!="string")throw new f("Oracle server returned an invalid identity.",m.API_ERROR);p.identity={uid:u(l.uid),companyId:u(l.companyId)}}if(s.capabilities!==void 0){let l=$(s.capabilities);if(![l.read,l.write,l.approve].every(d=>typeof d=="boolean"))throw new f("Oracle server returned invalid capabilities.",m.API_ERROR);p.capabilities={read:l.read,write:l.write,approve:l.approve}}if(s.model!==void 0){let l=$(s.model);if(typeof l.id!="string"||typeof l.provider!="string")throw new f("Oracle server returned invalid model metadata.",m.API_ERROR);p.model={id:u(l.id),provider:u(l.provider)}}if(s.limits!==void 0){let l=$(s.limits);if(Object.values(l).some(d=>!["string","number","boolean"].includes(typeof d)&&d!==null))throw new f("Oracle server returned invalid limits metadata.",m.API_ERROR);p.limits=Object.fromEntries(Object.entries(l).map(([d,O])=>[u(d),typeof O=="string"?u(O):O]))}return Array.isArray(s.commands)&&(p.commands=la(s.commands)),p}function la(t){let e=[];for(let n of t.slice(0,50)){let r=$(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||e.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?u(r.args).slice(0,60).trim():"";e.push({name:r.name,description:u(r.description).slice(0,200),...o?{args:o}:{}})}return e}var zt=class{endpoint;scopes;source;#e;#t;cachedConfig;constructor(e,n=fetch){this.endpoint=fe(e.endpoint),this.#e=e.getAccessToken??(async()=>e.accessToken),this.#t=n,this.scopes=new Set(e.scopes),this.source=e.source}async config(){if(!this.cachedConfig){let e=await this.#e();try{this.cachedConfig=await We(this.endpoint,this.#t,e)}catch(n){if(this.source!=="oauth"||!(n instanceof be)||n.status!==401)throw n;let r=await this.#e(e);if(r===e)throw n;this.cachedConfig=await We(this.endpoint,this.#t,r)}}return this.cachedConfig}async listSessions(){let e=await this.json("GET","/sessions"),n=Array.isArray(e)?e:$(e).sessions;if(!Array.isArray(n))throw new f("Oracle server returned an invalid sessions list.",m.API_ERROR);return n.map(Io)}async createSession(e={}){let n=await this.json("POST","/sessions",e),r=$(n);return!Array.isArray(r.messages)&&typeof r.sessionId=="string"?this.getSession(r.sessionId):xo(n)}async getSession(e){return xo(await this.json("GET",`/sessions/${encodeURIComponent(e)}`))}async submitTurn(e,n,r,o){let i,s=pe(this.endpoint,`/sessions/${encodeURIComponent(e)}/turns`),a=async p=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${p}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let p=await this.#e();if(i=await a(p),i.status===401&&this.source==="oauth"){let l=await this.#e(p);l!==p&&(i=await a(l))}}catch(p){throw p instanceof f||r?.aborted?p:new f(`Oracle connection was interrupted: ${p instanceof Error?p.message:String(p)}`,m.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await je(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let p=await Be(i,pe(this.endpoint,`/sessions/${e}/turns`)),l=De(p,i.status);throw new f(`Oracle server did not start a stream (${da(l)}).`,m.API_ERROR)}return i}async replayEvents(e,n,r){let o=[];for await(let i of this.streamReplayEvents(e,n,r))o.push(i);return o}async*streamReplayEvents(e,n,r,o){let i=`/sessions/${encodeURIComponent(e)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await je(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*mt(s,o);return}let c=De(await Be(s,pe(this.endpoint,i)),s.status),p=Array.isArray(c)?c:$(c).events;if(!Array.isArray(p))throw new f("Oracle replay response did not contain events.",m.API_ERROR);for(let l of p)yield Dn(l)}async*streamRequestEvents(e,n,r=-1,o){let i=`/sessions/${encodeURIComponent(e)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await je(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*mt(s,o);return}let c=De(await Be(s,pe(this.endpoint,i)),s.status),p=Array.isArray(c)?c:$(c).events;if(!Array.isArray(p))throw new f("Oracle request replay response did not contain events.",m.API_ERROR);for(let l of p)yield Dn(l)}async cancelTurn(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{streamId:n})}async cancelRequest(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{requestId:n})}async upload(e,n){let r=new FormData;r.set("sessionId",e),r.set("file",n,n.name);let o=await this.authenticatedFetch("POST","/uploads",{method:"POST",body:r,headers:{Accept:"application/json"}});return o.ok||await je(o),ua(De(await Be(o,pe(this.endpoint,"/uploads")),o.status))}async download(e,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(e)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await je(r),r}async json(e,n,r){let o=await this.authenticatedFetch(e,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});return o.ok||await je(o),De(await Be(o,pe(this.endpoint,n)),o.status)}async authenticatedFetch(e,n,r={},o=2e4){try{let i=pe(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=r.signal||o<=0?void 0:AbortSignal.timeout(o),c=O=>this.#t(i,{...r,method:e,headers:{...s,Authorization:`Bearer ${O}`},redirect:"error",...a?{signal:a}:{}}),p=await this.#e(),l=await c(p),d=r.body===void 0||typeof r.body=="string"||r.body===null;if(l.status===401&&this.source==="oauth"){let O=await this.#e(p);O!==p&&d&&(l=await c(O))}return l}catch(i){throw i instanceof f?i:new f(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*mt(t,e){if(!t.body)throw new f("Oracle stream has no response body.",m.FAILURE);let n=t.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,p=()=>{if(s.length===0)return null;let l=s.join(`
261
- `);if(s=[],a=0,l==="[DONE]")return null;let d;try{d=JSON.parse(l)}catch{throw new f("Oracle stream returned invalid JSON.",m.API_ERROR)}let O=Dn(d);return O.type==="finalizing"?O:O.idx<=c?null:(c=O.idx,O)};try{for(;;){let{value:d,done:O}=await n.read();d?.byteLength&&e?.();let x=r.decode(d,{stream:!O});if(o+=x,i+=Wt(x),i>2*1024*1024)throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR);let k=0,b=o.indexOf(`
262
- `,k);for(;b>=0;){let v=o.slice(k,b).replace(/\r$/,"");if(i-=Wt(o.slice(k,b+1)),k=b+1,v===""){let R=p();R&&(yield R)}else if(!v.startsWith(":")){let R=v.indexOf(":"),V=R<0?v:v.slice(0,R),K=R<0?"":v.slice(R+1).replace(/^ /,"");if(V==="data"&&(s.push(K),a+=Wt(K)+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}b=o.indexOf(`
263
- `,k)}if(o=o.slice(k),O)break}if(o.trim()){let d=o.replace(/\r$/,"");if(d.startsWith("data:")&&(s.push(d.slice(5).replace(/^ /,"")),a+=Wt(s[s.length-1]??"")+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}let l=p();l&&(yield l)}catch(l){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),l}finally{n.releaseLock()}}function Wt(t){return Buffer.byteLength(t,"utf8")}function Bn(t){let e=["program","initiative","codebase"].filter(o=>typeof t[o]=="string");if(e.length>1)throw new f("Choose only one of --program, --initiative or --codebase.",m.USAGE);let n=e[0];if(!n)return;let r=t[n];if(typeof r!="string"||!r.trim())throw new f(`--${n} needs an id.`,m.USAGE);return{kind:n,id:r.trim()}}function $(t){return!t||typeof t!="object"||Array.isArray(t)?{}:t}function da(t){if(typeof t=="string")return u(t);try{return u(JSON.stringify(t))}catch{return"unexpected response"}}function De(t,e){let n=$(t);if(n.ok===!1){let r=So(n.error,e),o=typeof n.message=="string"?u(n.message).slice(0,2e3):void 0;throw new be(r,e,o)}return n.ok===!0&&"data"in n?n.data:t}async function Be(t,e){try{return await t.json()}catch{throw new f(`Non-JSON response from ${e} (HTTP ${t.status}).`,m.FAILURE)}}async function je(t){let e;try{e=await t.clone().json()}catch{e=null}let n=$(e),r=So(n.error??n.error_description,t.status),o=typeof n.message=="string"?n.message:typeof n.error_description=="string"?n.error_description:typeof n.detail=="string"?n.detail:void 0;throw new be(r,t.status,typeof o=="string"?u(o).slice(0,2e3):void 0)}function So(t,e){if(typeof t!="string")return`http_${e}`;let n=u(t).slice(0,120);return/^[A-Za-z0-9_.-]+$/.test(n)?n:`http_${e}`}function Io(t){let e=$(t);if(typeof e.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(e.sessionId)||typeof e.title!="string"||e.visibility!=="private"&&e.visibility!=="company"||typeof e.shared!="boolean")throw new f("Oracle server returned an invalid session summary.",m.API_ERROR);return{sessionId:e.sessionId,title:u(e.title),visibility:e.visibility,shared:e.shared,...typeof e.entityKey=="string"?{entityKey:u(e.entityKey)}:{},...typeof e.updatedAt=="number"||e.updatedAt===null?{updatedAt:e.updatedAt}:{}}}function xo(t){let e=$(t),n=Io(e);if(!Array.isArray(e.messages))throw new f("Oracle server returned an invalid session transcript.",m.API_ERROR);let r=e.messages.map((o,i)=>{let s=$(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new f(`Oracle session message ${i+1} is invalid.`,m.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(ga):void 0,c=Array.isArray(s.files)?s.files.map(ha):void 0;return{role:s.role,content:u(s.content),...typeof s.id=="string"?{id:s.id}:{},...typeof s.authorName=="string"?{authorName:u(s.authorName)}:{},...s.question&&typeof s.question=="object"?{question:pa(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:fa(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof e.activeStreamId=="string"?{activeStreamId:e.activeStreamId}:{}}}function Dn(t){let e=$(t);if(e.protocolVersion!==1||typeof e.idx!="number"||!Number.isSafeInteger(e.idx)||e.idx<0||typeof e.type!="string")throw new f("Oracle stream event does not match protocol version 1.",m.API_ERROR);return de(e)}function ua(t){let e=$(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle upload response is missing file metadata.",m.API_ERROR);return{fileId:e.fileId,name:u(e.name),mediaType:u(e.mediaType),...typeof e.sizeBytes=="number"?{sizeBytes:e.sizeBytes}:{}}}function pa(t){let e=$(t);if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:u(e.id),questions:e.questions.map((n,r)=>{let o=$(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:u(o.id),header:u(o.header),question:u(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=$(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new f(`Oracle question option ${s+1} is invalid.`,m.API_ERROR);return{id:u(a.id),label:u(a.label),description:u(a.description),...typeof a.recommended=="boolean"?{recommended:a.recommended}:{},...typeof a.confirms=="boolean"?{confirms:a.confirms}:{}}})}}),optional:e.optional===!0}}function fa(t){let e=$(t);if(typeof e.questionId!="string"||!Array.isArray(e.answers))throw new f("Oracle returned an invalid question response.",m.API_ERROR);return{questionId:u(e.questionId),answers:e.answers.map(ma)}}function ma(t){let e=$(t);if(typeof e.questionId!="string"||!Array.isArray(e.optionIds)||!e.optionIds.every(n=>typeof n=="string"))throw new f("Oracle returned an invalid question answer.",m.API_ERROR);return{questionId:u(e.questionId),optionIds:e.optionIds.map(n=>u(n)),...typeof e.customText=="string"?{customText:u(e.customText).slice(0,8e3)}:{}}}function ga(t){let e=$(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle session attachment metadata is invalid.",m.API_ERROR);return{fileId:u(e.fileId),name:u(e.name),mediaType:u(e.mediaType),...typeof e.sizeBytes=="number"&&Number.isFinite(e.sizeBytes)?{sizeBytes:e.sizeBytes}:{}}}function ha(t){let e=$(t);if(typeof e.fileId!="string"||typeof e.filename!="string"||typeof e.mediaType!="string"||typeof e.sizeBytes!="number"||!Number.isFinite(e.sizeBytes))throw new f("Oracle session file metadata is invalid.",m.API_ERROR);return{fileId:u(e.fileId),filename:u(e.filename),mediaType:u(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:u(e.format)}:{}}}import{randomUUID as Co}from"node:crypto";import{promises as z}from"node:fs";import{homedir as wa}from"node:os";import{join as Gn}from"node:path";import*as To from"proper-lockfile";var gt=Gn(wa(),".anyforge"),me=Gn(gt,"oracle"),Eo=Gn(gt,"oracle.last-session");function ya(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return e.version!==1||typeof e.endpoint!="string"||typeof e.clientId!="string"||typeof e.redirectUri!="string"||typeof e.accessToken!="string"||typeof e.refreshToken!="string"||typeof e.expiresAt!="number"||!Number.isFinite(e.expiresAt)||!Array.isArray(e.scopes)||!e.scopes.every(n=>typeof n=="string")||e.lastSessionId!==void 0&&typeof e.lastSessionId!="string"?null:{version:1,endpoint:e.endpoint,clientId:e.clientId,redirectUri:e.redirectUri,accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,...typeof e.lastSessionId=="string"?{lastSessionId:e.lastSessionId}:{}}}async function Wn(t){await z.mkdir(gt,{recursive:!0,mode:448});let e=`${me}.${Co()}.tmp`;try{await z.writeFile(e,`${JSON.stringify(t,null,2)}
264
- `,{mode:384,flag:"wx"}),await z.rename(e,me),await z.chmod(me,384)}finally{await z.rm(e,{force:!0}).catch(()=>{})}}async function Kt(){let t;try{t=await z.readFile(me,"utf8")}catch(r){if(r.code==="ENOENT")return null;throw r}let e;try{e=JSON.parse(t)}catch{throw new Error(`Oracle credentials at ${me} are invalid JSON; run \`anyforge oracle logout\` and sign in again.`)}let n=ya(e);if(!n)throw new Error(`Oracle credentials at ${me} have an unsupported format; run \`anyforge oracle logout\` and sign in again.`);return n}async function ze(){try{return await z.unlink(me),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}async function _o(t,e){await Oa(Eo,{version:1,endpoint:e,sessionId:t})}async function Ht(t){let e;try{e=await z.readFile(Eo,"utf8")}catch(o){if(o.code==="ENOENT")return;throw o}let n;try{n=JSON.parse(e)}catch{return}if(!n||typeof n!="object"||Array.isArray(n))return;let r=n;return r.version===1&&r.endpoint===t&&typeof r.sessionId=="string"?r.sessionId:void 0}async function Oa(t,e){await z.mkdir(gt,{recursive:!0,mode:448});let n=`${t}.${Co()}.tmp`;try{await z.writeFile(n,`${JSON.stringify(e,null,2)}
265
- `,{mode:384,flag:"wx"}),await z.rename(n,t),await z.chmod(t,384)}finally{await z.rm(n,{force:!0}).catch(()=>{})}}async function Jt(t){await z.mkdir(gt,{recursive:!0,mode:448});let e=await To.lock(me,{realpath:!1,lockfilePath:`${me}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await t()}finally{await e()}}var zn=8192,Po=10*1048576,Aa=20*1048576,Lo=10,Fo=3;function Kn(t,e){if(t.type!=="tool_call"&&t.type!=="tool_call_start"||typeof t.spawnId=="string")return!1;let n=typeof t.id=="string"?t.id:void 0;if(n){if(e.has(n))return!1;e.add(n)}return!Me(t.name)}var Ce=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(e){return e.type==="finalizing"?!0:e.idx<=this.lastIdx?!1:(this.lastIdx=e.idx,e.type==="stream_start"&&typeof e.streamId=="string"?this.streamId=u(e.streamId):e.type==="delta"&&typeof e.content=="string"?this.answer+=e.content:Kn(e,this.toolIds)?this.answer="":e.type==="question"?this.question=Yn(e):e.type==="error"?this.error=Jn(e):e.type==="done"?this.done=e:e.type==="navigator_file_created"&&ka(this.files,e.file),!0)}get settled(){return!!(this.done||this.error)}outcome(){return{answer:this.answer,...this.question?{question:this.question}:{},...this.error?{error:this.error}:{},...this.done?{done:this.done}:{},...this.streamId?{streamId:this.streamId}:{},...this.files.length?{files:[...this.files]}:{}}}};async function Yt(t,e,n,r,o,i=new Ce){let s=async d=>{let O=i.streamId;i.accept(d)&&(i.streamId&&i.streamId!==O&&r.onStream?.(i.streamId),await r.onEvent(d))},a=()=>Hn(t,e,i,s,o,r.onActivity),c=async()=>{try{for await(let d of t.streamRequestEvents(e,n.requestId,-1,r.onActivity))await s(d)}catch(d){throw o?.aborted?d:new f("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new f("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)},p=async()=>{try{let d=await t.submitTurn(e,n,o);for await(let O of mt(d,r.onActivity))await s(O)}catch(d){if(o?.aborted||d instanceof f&&d.exitCode===m.API_ERROR)throw d;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},l;try{l=await t.submitTurn(e,n,o)}catch(d){if(o?.aborted||d instanceof f&&d.exitCode!==m.FAILURE)throw d;return p()}if(!l)throw new f("Oracle did not return a stream response.",m.FAILURE);r.onResponse?.();try{for await(let d of mt(l,r.onActivity))await s(d)}catch(d){if(o?.aborted||d instanceof f)throw d;return i.streamId?a():p()}return i.settled?i.outcome():i.streamId?a():p()}async function Hn(t,e,n,r,o,i){let s=n.streamId;if(!s)throw new f("Oracle stream replay needs a stream id.",m.FAILURE);let a=0;for(;!n.settled&&a<Fo;){if(o?.aborted)throw o.reason;try{for await(let c of t.streamReplayEvents(e,s,n.lastIdx+1,i))await r(c);if(!n.settled){if((await t.getSession(e)).activeStreamId!==s)break;await $o(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof f&&c.exitCode===m.API_ERROR||(a+=1,a>=Fo))throw c;await $o(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new f("Oracle stream could not be fully replayed; the turn was not submitted again.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the session.`);return n.outcome()}function ht(t,e){let n=e.done,r=n?.servedBy,o=Te(n?.tokens),i=U(n?.rounds),s=typeof n?.exitReason=="string"?u(n.exitReason):void 0,a=n?.exitReason==="completed"&&!e.question,c=e.files??(Array.isArray(n?.files)?n.files.map(Ke):void 0),p=e.error?"error":e.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:t,status:p,answer:u(e.answer),partial:!a,...typeof n?.messageId=="string"?{messageId:u(n.messageId)}:typeof n?.answerId=="string"?{messageId:u(n.answerId)}:{},...e.question?{question:e.question}:{},...e.error?{error:u(e.error)}:{},...e.streamId?{streamId:u(e.streamId)}:{},...r?{servedBy:de(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:de(c)}:{}}}function I(t,e){return typeof t=="string"?u(t).slice(0,e):""}function Jn(t){return typeof t.message=="string"?u(t.message).slice(0,2e3):"Oracle turn failed."}function Q(t){return u(t instanceof Error?t.message:String(t)).slice(0,2e3)}function Yn(t){let e=t.question;if(!e||typeof e!="object")throw new f("Oracle question event omitted its question card.",m.API_ERROR);return xa(e)}function Ke(t){let e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};if(typeof e.fileId!="string"||!e.fileId||typeof e.filename!="string"||!e.filename||typeof e.mediaType!="string"||!e.mediaType||typeof e.sizeBytes!="number"||!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<0)throw new f("Oracle generated-file event omitted safe file metadata.",m.API_ERROR);return{fileId:u(e.fileId),filename:u(e.filename),mediaType:u(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:u(e.format)}:{}}}function ka(t,e){let n=Ke(e);t.some(r=>r.fileId===n.fileId)||t.push(n)}function xa(t){let e=t;if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:u(e.id),optional:e.optional===!0,questions:e.questions.map((n,r)=>{let o=n&&typeof n=="object"?n:{};if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:u(o.id),header:u(o.header),question:u(o.question),multiSelect:o.multiSelect,options:o.options.map(i=>{let s=i&&typeof i=="object"?i:{};if(typeof s.id!="string"||typeof s.label!="string"||typeof s.description!="string")throw new f("Oracle question option is invalid.",m.API_ERROR);return{id:u(s.id),label:u(s.label),description:u(s.description),...typeof s.recommended=="boolean"?{recommended:s.recommended}:{},...typeof s.confirms=="boolean"?{confirms:s.confirms}:{}}})}})}}function U(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function Te(t){if(typeof t=="number"&&Number.isFinite(t))return{totalTokens:t};if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=U(e.in)??U(e.input)??U(e.inputTokens),r=U(e.cacheRead),o=U(e.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=U(e.out)??U(e.output)??U(e.outputTokens),a=U(e.total)??U(e.totalTokens)??(i!==void 0||s!==void 0?(i??0)+(s??0):void 0);if(!(i===void 0&&s===void 0&&a===void 0))return{...i!==void 0?{inputTokens:i}:{},...r?{cachedInputTokens:r}:{},...s!==void 0?{outputTokens:s}:{},...a!==void 0?{totalTokens:a}:{}}}function He(t){if(t&&typeof t=="object"){let e=t;if(typeof e.accepted=="boolean")return e.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof e.cancelled=="boolean")return e.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function wt(t,e){let n=e&&t&&(t.kind==="program"||t.kind==="initiative")?{kind:t.kind,id:t.id}:void 0;return{...!e&&t?{context:t}:{},...n?{sharedEntity:n}:{},visibility:e?"company":"private"}}async function yt(t,e){await _o(t,e).catch(()=>{})}async function Qt(t,e,n,r){if(!n.length)return[];if(n.length>Lo)throw new y(`Attach no more than ${Lo} files per turn.`);let o=0,i=[];for(let a of n){let c=await ba(a);if(!c.isFile())throw new y(`Attachment is not a file: ${a}`);if(c.size>Po)throw new y(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let p=await Sa(a,Po);if(o+=p.byteLength,o>Aa)throw new y("Attachments exceed the 20 MiB total CLI limit.");let l=Ra(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",d=ko(l)??"";if(!d)throw new y(`Unsupported attachment type: ${a}`);i.push({content:p,name:l,mediaType:d})}let s=[];for(let{content:a,name:c,mediaType:p}of i){await r(u(c),a.byteLength);let l=new ArrayBuffer(a.byteLength);new Uint8Array(l).set(a);let d=new File([l],c,{type:p});s.push(await t.upload(e,d))}return s}async function Sa(t,e){let n=[],r=0;for await(let o of va(t)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>e)throw new y(`Attachment exceeds the ${N(e)} limit: ${t}`);n.push(i)}return Buffer.concat(n)}var Ot=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Ca=2e4,Ta=6,Ea={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},_a={max_rounds:"reached the step limit",max_tokens:"reached the output limit",token_budget:"reached the token budget",deadline:"ran out of time",interrupted:"interrupted",loop_detected:"stopped a repeating loop",cancelled:"cancelled"},Xt=class{constructor(e,n){this.startedAt=e;this.sessionId=n;this.lastSignalAt=e}phase="sending";answer="";tools=[];notices=[];files=[];lastSignalAt;endedAt;end;done;upload;round;maxRounds;serverPhase;agents=new Map;toolIds=new Set;get toolCount(){return this.tools.length}get failedCount(){return this.tools.filter(e=>e.status==="failed").length}get finished(){return this.end!==void 0}setUploading(e,n,r){this.phase="uploading",this.upload=`${e} (${N(n)})`,this.lastSignalAt=r}setPhase(e,n){this.phase=e,this.lastSignalAt=n}touch(e){this.lastSignalAt=e}apply(e,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(e);switch(e.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=U(e.round),this.maxRounds=U(e.maxRounds)??this.maxRounds;for(let r=this.tools.length-1;r>=0;r--)this.tools[r]?.started&&this.tools.splice(r,1);this.phase!=="finishing"&&(this.phase="thinking");break;case"phase":this.serverPhase=typeof e.phase=="string"?e.phase:void 0;break;case"delta":this.phase!=="finishing"&&(this.phase="writing");break;case"tool_result":this.phase!=="finishing"&&(this.phase="thinking");break;case"finalizing":this.phase="finishing";break}this.record(e)}record(e){switch(e.type){case"delta":typeof e.content=="string"&&(this.answer+=e.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(e);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===e.toolUseId);n&&(n.status=e.ok===!1?"failed":"ok");break}case"subagent_start":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"running");break;case"subagent_done":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${I(e.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${I(e.filename,200)}: ${I(e.error,500)}`});break;case"attachment_notice":if(Array.isArray(e.notices))for(let n of e.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${I(r.name,160)}: ${I(r.message,500)}`})}break;case"provider_fallback":{let n=I(e.from,120),r=I(e.to,120),o=I(e.reason,40).replaceAll("_"," ");this.notices.push({tone:"info",text:`Switched model${n?` from ${n}`:""}${r?` to ${r}`:""}${o?` (${o})`:""}.`});break}case"navigator_file_created":{let n=Ke(e.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${N(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:Jn(e)});break;case"done":this.done=e;break}}recordToolCall(e){let n=typeof e.id=="string"?e.id:void 0,r=Kn(e,this.toolIds),o=typeof e.name=="string"?e.name:"";if(Me(o))return;let i=I(typeof e.label=="string"?e.label:Gt(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,e.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof e.spawnId=="string"?{spawnId:e.spawnId}:{},...e.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=u(this.answer.trim()),this.answer=""),this.tools.push(a),this.phase!=="finishing"&&(this.phase="thinking")}note(e,n){this.notices.push({tone:e,text:u(n)})}finish(e,n){this.end=e,this.endedAt=n}label(){if(this.phase==="cancelling")return"Cancelling";if(this.phase==="uploading")return`Uploading ${this.upload??"attachment"}`;if(this.phase==="sending")return"Sending";if(this.phase==="preparing")return"Preparing context";if(this.phase==="finishing")return"Finishing up";let e=[...this.agents.values()].filter(r=>r==="running").length;if(e)return`Researching (${e} agent${e===1?"":"s"})`;let n=this.tools.filter(r=>r.status==="running"&&!r.spawnId);return n.length===1?`Running ${n[0]?.label}`:n.length>1?`Running ${n.length} tools`:this.phase==="writing"?"Writing":this.serverPhase&&Ea[this.serverPhase]||"Thinking"}statusLine(e,n){let r=[this.label(),Mn(e-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=e-this.lastSignalAt;return o>=Ca&&this.phase!=="cancelling"&&r.push(`no update for ${Mn(o)}`),n&&e-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let e=[],n=lt((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=Mo("\u2713"):this.end==="awaiting_input"?o=qo("?")+" Waiting for your answer":this.end==="cancelled"?o=Vn("\u2717")+" Interrupted":this.end==="error"?o=Qn("\u2717")+" Error":o=Vn("\u2717")+` Stopped: ${r&&_a[r]||"no final answer"}`,e.push(n),this.tools.length&&e.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=Te(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&e.push(`${ee(i.inputTokens??0)} in${i.cachedInputTokens?` (${ee(i.cachedInputTokens)} cached)`:""} / ${ee(i.outputTokens??0)} out`);let s=vt(this.done?.servedBy);return s&&e.push(s),`${o} ${Je(e.join(" \xB7 "))}`}};function vt(t){if(!t||typeof t!="object")return"";let e=t,n=I(e.model??e.id,100);if(!n)return"";let r=e.fallback&&typeof e.fallback=="object"?e.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${I(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${I(r.from,100)}${o})`}return n}var Zt=class{constructor(e,n){this.activity=e;this.view=n;this.answer=new Ue("",n.linkOrigin)}answer;getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(e){let n=this.activity;this.answer.setText(n.answer);let r=[ft("assistant")];r.push(...this.renderTools(e)),r.push(...this.answer.render(e));for(let o of n.notices){let i=o.tone==="error"?Qn:o.tone==="warning"?Vn:Je;r.push(...No(i(o.text),e))}return n.finished&&r.push(Vt(n.summaryLine(),e)),r}renderTools(e){let{tools:n}=this.activity;if(!n.length)return[];if(this.activity.finished&&!this.view.expanded()){let s=this.activity.failedCount,a=`Used ${n.length} tool${n.length===1?"":"s"}${s?` \xB7 ${s} failed`:""} (ctrl+o to expand)`;return[Vt(Je(` \u23BF ${a}`),e)]}let r=this.activity.finished?n:n.slice(-Ta),o=n.length-r.length,i=[];return o&&i.push(Vt(Je(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),e)),r.forEach((s,a)=>{if(s.note)for(let d of No(s.note,Math.max(10,e-4)).slice(0,3))i.push(` ${Je(Ia(d))}`);let c=s.status==="running"?qo(Ot[this.view.frame()%Ot.length]??"*"):s.status==="ok"?Mo("\u2713"):Qn("\u2717"),p=a===0&&!o?" \u23BF ":" ",l=s.spawnId?` ${Je("agent \xB7")} `:"";i.push(Vt(`${p}${l}${c} ${s.label}`,e))}),i}};import{randomUUID as Ba}from"node:crypto";import{stat as Ga}from"node:fs/promises";import{basename as Ho}from"node:path";import{bold as Wa,cyan as Jo,dim as Yo,red as rn}from"kleur/colors";import{Container as za,Editor as Ka,ProcessTerminal as Ha,ScrollView as Ja,SelectList as Ya,TuiAltScreen as Qa,VStack as Va,getNativeClipboard as Xa,matchesKey as on,truncateToWidth as Qo,wrapTextWithAnsi as Za}from"@earendil-works/pi-tui";import{truncateToWidth as Fa,visibleWidth as Na,wrapTextWithAnsi as Bo}from"@earendil-works/pi-tui";import{bold as qa,cyan as Ma,dim as ge}from"kleur/colors";import{CombinedAutocompleteProvider as $a}from"@earendil-works/pi-tui";var bt=[{name:"help",description:"Show commands and keyboard shortcuts"},{name:"status",description:"Show session, access, model, usage and limits"},{name:"model",description:"Show the workspace model and the model that answered last"},{name:"usage",description:"Show turns and tokens used in this terminal"},{name:"new",args:"[shared]",description:"Start a new conversation",idleOnly:!0,completions:["shared"]},{name:"clear",description:"Clear the screen and start a new private conversation",idleOnly:!0},{name:"resume",args:"[session-id]",description:"Pick or open a saved conversation",idleOnly:!0},{name:"context",args:"[clear|program|initiative|codebase <id>]",description:"Show or change the context for the next message",completions:["clear","program ","initiative ","codebase "]},{name:"attach",args:"<path>",description:"Attach a file to your next message"},{name:"copy",description:"Copy the last answer as Markdown"},{name:"files",description:"List files Oracle generated in this conversation"},{name:"exit",description:"Leave the Oracle",aliases:["quit"]}],Pa=[{name:"design",args:"[topic]",description:"Talk through a technical design before anything is created"},{name:"catchup",description:"Catch up on your work: what needs you, what landed, what is running"}];function Uo(t){let e=new Set(bt.flatMap(n=>[n.name,...n.aliases??[]]));return(t??Pa).filter(n=>!e.has(n.name))}function jo(t,e){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(t.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=bt.find(a=>a.name===r||a.aliases?.includes(r));if(i)return{kind:"local",command:i,arg:o,args:o?o.split(/\s+/):[]};let s=e.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function Do(t,e){let n=[...bt.flatMap(i=>[i,...(i.aliases??[]).map(s=>({...i,name:s}))]).map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{},...i.completions?{getArgumentCompletions:s=>La(i.completions??[],s)}:{}})),...t.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new $a(n,e),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let p=(i[s]??"").slice(0,a);return s!==0||!p.trimStart().startsWith("/")?null:o.test(p)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,p){return r.applyCompletion(i,s,a,c,p)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function La(t,e){let n=t.filter(r=>r.startsWith(e.toLowerCase())&&r!==e).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function en(t,e){return t?e?"write + approve":"write":"read only"}function Ye(t){return t?`${t.kind} ${u(t.id)}`:"no context"}function Go(t,e){let n=[`${qa(Ma("AnyForge Oracle"))}${ge(` \xB7 v${u(t.version)}`)}`,`${ue(t.session)} \xB7 ${t.access} \xB7 ${Ye(t.context)}`,...t.session.messages.length?[`Resumed: ${u(t.session.title)}`]:[],ge("Only your messages and the files you attach leave this terminal."),ge("/help commands \xB7 /status details")];if(e<24)return n.flatMap(s=>Bo(s,Math.max(1,e)));let r=Math.min(e,76),o=r-4,i=[ge(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>Bo(a,o))){let a=Fa(s,o);i.push(`${ge("\u2502")} ${a}${" ".repeat(Math.max(0,o-Na(a)))} ${ge("\u2502")}`)}return i.push(ge(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function Wo(t){let e=(r,o)=>r?`${ge(r)} ${o}`:o,n=[{title:"Commands",rows:bt.map(r=>[`/${r.name}`,e(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(t.server.length){let r=t.server.map(o=>[`/${o.name}`,e(o.args,u(o.description))]);t.server.some(o=>o.name==="catchup")&&!t.canApprove&&r.push(["",ge("Acting on /catchup decisions needs a session started with `anyforge oracle --write --approve`.")]),n.push({title:"Workspace commands (answered by Oracle)",rows:r})}return n.push({title:"Keys",rows:[["Enter","Send. While Oracle works, queues one message for when it finishes"],["Shift+Enter","New line (Ctrl+J also works)"],["Esc","Interrupt the current answer"],["Ctrl+C","Interrupt the answer, or clear the input; press twice to exit"],["Ctrl+D","Exit when the input is empty"],["Ctrl+O","Show or hide tool activity for finished answers"],["Ctrl+Shift+F","Search the conversation"],["Up / Down","Recall messages sent in this terminal"],["Tab","Complete a command, or a file path after /attach"],["PgUp / PgDn","Scroll; Home and End jump to the top and bottom"]]}),n}function Xn(t){let n=[["Model",`workspace default ${t.model?`${u(t.model.provider)}/${u(t.model.id)}`:"chosen by the server"}`]],r=vt(t.lastServedBy);if(r){let o=t.lastServedBy,i=I(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function Zn(t){return[["This run",t.turns?`${t.turns} turn${t.turns===1?"":"s"} \xB7 ${t.tools} tool${t.tools===1?"":"s"} \xB7 ${ee(t.inputTokens)} in / ${ee(t.outputTokens)} out tokens`:"no turns yet"]]}function er(t){if(!t?.finished)return[];let e=[lt((t.endedAt??t.startedAt)-t.startedAt)];e.push(`${t.toolCount} tool${t.toolCount===1?"":"s"}${t.failedCount?` (${t.failedCount} failed)`:""}`);let n=U(t.done?.rounds);n!==void 0&&e.push(`${n} round${n===1?"":"s"}`);let r=Te(t.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&e.push(`${ee(r.inputTokens??0)} in${r.cachedInputTokens?` (${ee(r.cachedInputTokens)} cached)`:""} / ${ee(r.outputTokens??0)} out tokens`);let o=I(t.done?.exitReason,40);return e.push(o?o.replaceAll("_"," "):t.end??""),[["Last turn",e.filter(Boolean).join(" \xB7 ")]]}function zo(t){let e=t.capabilities?["read","write","approve"].filter(o=>t.capabilities?.[o]).join(", ")||"none":"not reported",n=t.contextText?` \xB7 note ${N(Buffer.byteLength(t.contextText,"utf8"))}`:"",r=ho(t.limits);return[["Session",`${t.session.sessionId} \xB7 ${u(t.session.title)||"Untitled"}`],["Audience",ue(t.session)],["Access",`this session ${en(t.write,t.approve)} \xB7 grant ${t.grantScopes.join(", ")||"none"} \xB7 workspace role ${e}`],["Context",`${Ye(t.context)}${n}`],...Xn(t),...er(t.lastTurn),...Zn(t.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...t.identity?[["Workspace",`company ${t.identity.companyId} \xB7 user ${t.identity.uid}`]]:[],["Endpoint",t.endpoint],["Version",`CLI ${u(t.version)} \xB7 protocol ${1}`],["Attached",t.pendingFiles.length?`${t.pendingFiles.map(u).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function Ko(t,e){return e.length?e.map((n,r)=>[`${r+1}.`,`${u(n.filename)} (${N(n.sizeBytes)}) \xB7 anyforge oracle download ${t} ${u(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{bold as Ua,cyan as tr,dim as tn,yellow as ja}from"kleur/colors";import{Input as Da,Text as Ee,matchesKey as Qe}from"@earendil-works/pi-tui";var nn=class{constructor(e,n,r){this.tui=e;this.question=n;this.onComplete=r;(n.questions[0]?.options.length??0)===0&&(this.mode="custom"),this.customInput.onSubmit=o=>{let i=o.trim().slice(0,8e3);if(!i){this.errorMessage="Enter a short answer before continuing.",this.tui.requestRender();return}this.recordCurrent(i)},this.customInput.onEscape=()=>{if(!this.question.questions[this.questionIndex]?.options.length){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.setValue(""),this.mode="select",this.tui.setFocus(this),this.tui.requestRender()}}focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new Da({prompt:`${tr("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:tn});invalidate(){}render(e){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,e-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new Ee(`${Ua(tr(u(n.header)))}${tn(o)}`,0,0).render(r),...new Ee(u(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Ee(tn(`Enter submits your text${n.options.length?" \xB7 Esc back to the choices":this.question.optional?" \xB7 Esc skip":""}`),0,0).render(r))):i.push(...new Ee(tn(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Ee(ja(this.errorMessage),0,0).render(r)),i.map(s=>`${tr("\u2502")} ${s}`)}handleInput(e){if(this.mode==="custom"){this.customInput.handleInput(e);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(Qe(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(e);return}if(Qe(e,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(Qe(e,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(Qe(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(e.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(e);if(Number.isInteger(o)&&o>=1&&o<=n.options.length){let i=n.options[o-1]?.id;i&&(this.optionIndex=o-1,n.multiSelect?r.has(i)?r.delete(i):r.add(i):(r.clear(),r.add(i)),this.tui.requestRender());return}if(Qe(e,"space")&&n.multiSelect){let i=n.options[this.optionIndex];i&&(r.has(i.id)?r.delete(i.id):r.add(i.id),this.tui.requestRender());return}if(Qe(e,"enter")){if(r.size===0){this.errorMessage="Select an option explicitly, type a custom answer, or skip if optional.",this.tui.requestRender();return}this.recordCurrent()}}renderOptions(e,n){let r=this.selectedFor(e),o=[];return e.options.forEach((i,s)=>{let a=r.has(i.id),c=e.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",p=s===this.optionIndex?"\u203A":" ",l=i.recommended?" \xB7 recommended":"",d=i.confirms?" \xB7 confirms the shown action":"",O=`${p} ${s+1}. ${c} ${u(i.label)}${l}${d}`;o.push(...new Ee(O,0,0).render(n)),o.push(...new Ee(` ${u(i.description)}`,0,0).render(n))}),o}instructions(e){return e.options.length===0?`Write a short answer${this.question.optional?" \xB7 s or Esc skip card":""}`:`\u2191/\u2193 move \xB7 1\u2013${e.options.length} ${e.multiSelect?"toggle":"select"}${e.multiSelect?" \xB7 Space toggle":""} \xB7 Enter continue \xB7 o write your own${this.question.optional?" \xB7 s or Esc skip card":""}`}requireAnswer(){let e=this.question.questions[this.questionIndex];this.errorMessage=e?.options.length?"Oracle needs an answer to continue: pick an option, or press o to write your own.":"Oracle needs an answer to continue: type it and press Enter.",this.tui.requestRender()}selectedFor(e){let n=this.selected.get(e.id);return n||(n=new Set,this.selected.set(e.id,n)),n}recordCurrent(e){let n=this.question.questions[this.questionIndex];if(!n)return;e&&this.selectedFor(n).clear();let r=[...this.selectedFor(n)],o={questionId:n.id,optionIds:r,...e?{customText:e}:{}},i=this.answers.findIndex(s=>s.questionId===n.id);if(i>=0?this.answers.splice(i,1,o):this.answers.push(o),this.customInput.setValue(""),this.mode="select",this.questionIndex<this.question.questions.length-1){this.questionIndex+=1,this.optionIndex=0,this.mode=this.question.questions[this.questionIndex]?.options.length===0?"custom":"select",this.errorMessage="",this.tui.setFocus(this),this.tui.requestRender();return}this.finish({questionId:this.question.id,answers:this.answers.map(s=>({...s}))})}finish(e){this.onComplete(e)}};var Vo=1500,ec=100,tc="\x1B]133;A\x07";function Ve(t){return{render:t,invalidate(){}}}function Xo(t,e,n,r){let o=new Ue(e,r);return{getText:()=>o.getText(),invalidate:()=>o.invalidate(),render:i=>t==="user"?["",`${tc}${ft("user",n)}`,...o.render(i)]:[ft("assistant"),...o.render(i)]}}async function Zo(t){let{client:e,config:n}=t,r=new Ha,o=new Qa(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new za,s=new Ja(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new Ka(o,bo),c=Uo(n.commands),p=typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,l=t.session,d=t.initialContext,O=t.contextText,x=t.canWrite,k=t.canApprove,b,v,R,V,K=[...t.initialFiles],ae=!1,ln=!1,xt=!1,dn=0,_e,lr=0,Ae="",St,un,$e=[],Pe={turns:0,inputTokens:0,outputTokens:0,tools:0},It=new Map,ce,yi=Ve(g=>{if(b){let w=Jo(Ot[dn%Ot.length]??"*");return[Qo(`${w} ${b.activity.statusLine(Date.now(),p)}`,g)]}return ce?[Qo(`${Jo("?")} Waiting for your answer to the question above`,g)]:[]}),Oi=Ve(g=>{let w=[en(x,k),Ye(d),Ro(l),K.length?`${K.length} file${K.length===1?"":"s"} attached`:"",v!==void 0?"1 message queued":""];return[Yo(yo(g,w,b?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new Va([{component:s,basis:0,grow:1,minSize:1},{component:yi,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:Oi,basis:"auto",shrink:0,minSize:1}]));let Y=()=>o.requestRender(),F=g=>o.flash(u(g),3e3),we=g=>{i.addChild(g),Y()},te=(g,w=Yo)=>{let h=u(g);we(Ve(A=>Za(w(h),Math.max(1,A))))},Ct=(g,w)=>{we(Ve(h=>["",...wo(g,w,h)]))},vi=()=>{_e||(_e=setInterval(()=>{dn+=1,Y()},ec),_e.unref())},pn=()=>{_e&&clearInterval(_e),_e=void 0},Xe=()=>{ae||o.hasOverlay()||o.setFocus(ce??a)},dr=g=>{R=g;let w=It.get(g.id);w&&i.removeChild(w);let h=new nn(o,g,A=>{It.delete(g.id),ce===h&&(ce=void 0),i.removeChild(h),Ai(A??{questionId:g.id,skipped:!0,answers:[]}),Xe()});It.set(g.id,h),ce=h,we(h)},fn=g=>{i.clear(),It.clear(),ce=void 0,l=g,R=void 0,V=void 0,$e=[],Ae="";let w={version:t.version,session:g,access:en(x,k),context:d};we(Ve(A=>Go(w,A)));let h;for(let A of g.messages){we(Xo(A.role,A.content,A.authorName,e.endpoint)),A.role==="assistant"&&(Ae=A.content),A.question&&(h=A.question),A.questionResponse&&(te("A stored response was recorded for this question."),h?.id===A.questionResponse.questionId&&(h=void 0));for(let S of A.files??[])$e.some(q=>q.fileId===S.fileId)||$e.push(S),te(`File: ${S.filename} (${S.mediaType}, ${N(S.sizeBytes)}) \xB7 anyforge oracle download ${g.sessionId} ${S.fileId} --output .`)}h&&dr(h),Xe(),yt(g.sessionId,e.endpoint)},ur,bi=new Promise(g=>{ur=g}),Tt=()=>{ae||(ae=!0,pn(),b?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),ur())},mn=async()=>{let g=b;if(!g||g.cancelling)return;g.cancelling=!0,g.activity.setPhase("cancelling",Date.now()),Y();let{streamId:w,requestId:h}=g;g.controller.abort(new Error("Turn cancelled by user."));let A;if(w)try{A=He(await e.cancelTurn(l.sessionId,w))}catch(S){A=`Could not confirm server cancellation: ${Q(S)}`}else if(h)try{A=He(await e.cancelRequest(l.sessionId,h))}catch(S){A=`Could not confirm server cancellation by request id: ${Q(S)}`}else A="The turn had not reached the server; nothing was sent.";g.activity.note("info",A),Y()},Le=async g=>{if(b||ae)return;if(g.kind==="submit"&&g.response){let _=R;if(!_||_.id!==g.response.questionId){F("That question is no longer active. Resume the session to refresh it.");return}te(nc(_,g.response)),R=void 0}else g.kind==="submit"&&we(Xo("user",g.text));let w=l.sessionId,h=new Xt(Date.now(),w),A=new Zt(h,{expanded:()=>xt,frame:()=>dn,linkOrigin:e.endpoint}),S={activity:h,view:A,controller:new AbortController,cancelling:!1};b=S,we(A),vi();let q=new Ce,hr=_=>{h.apply(_,Date.now()),_.type==="question"&&(dr(Yn(_)),Xe()),Y()},wr={onEvent:hr,onStream:_=>{S.streamId=_},onResponse:()=>{h.phase==="sending"&&h.setPhase("preparing",Date.now())},onActivity:()=>h.touch(Date.now())},ye="error";try{if(g.kind==="replay"){q.streamId=g.streamId,S.streamId=g.streamId,h.setPhase("thinking",Date.now());let _=await Hn(e,w,q,async ne=>{q.accept(ne)&&hr(ne)},S.controller.signal,wr.onActivity);ye=ht(w,_).status}else{let _=g.response?[]:K.splice(0),ne=await Qt(e,w,_,(gn,_i)=>{h.setUploading(gn,_i,Date.now()),Y()});S.controller.signal.throwIfAborted(),h.setPhase("sending",Date.now());let Et=Ba();S.requestId=Et;let Ti={requestId:Et,text:g.response?"":g.text,readOnly:!x,...k?{allowApprove:!0}:{},...d?{context:d}:{},...O?{contextText:O}:{},...g.response?{questionResponse:g.response}:{},...ne.length?{attachments:ne.map(gn=>({fileId:gn.fileId}))}:{}},Ei=await Yt(e,w,Ti,wr,S.controller.signal,q);ye=ht(w,Ei).status}}catch(_){if(S.controller.signal.aborted)ye="cancelled";else{ye="error";let ne=_ instanceof f&&_.hint?` ${u(_.hint)}`:"";h.note("error",`${Q(_)}${ne}`)}}finally{h.finish(ye,Date.now()),b=void 0,pn(),ae||(ln=ye==="cancelled"),St=h,h.answer.trim()&&(Ae=h.answer),h.done?.servedBy&&(un=h.done.servedBy);let _=Te(h.done?.tokens);Pe.turns+=1,Pe.tools+=h.toolCount,Pe.inputTokens+=_?.inputTokens??0,Pe.outputTokens+=_?.outputTokens??0;for(let ne of h.files)$e.some(Et=>Et.fileId===ne.fileId)||$e.push(ne);Y()}if(!ae){if(S.streamId&&ye!=="cancelled"){let _=await e.getSession(w).catch(()=>{});_&&_.sessionId===l.sessionId&&(l=_)}Ri(ye)}},Ri=g=>{if(!(ae||b)){if(V){let w=V;V=void 0,Le({kind:"submit",text:"",response:w});return}if(v!==void 0){let w=v;if(v=void 0,g==="complete"&&!ce){Le({kind:"submit",text:w});return}a.getText()||a.setText(w),F("Your queued message is back in the input; press Enter to send it.")}Xe(),Y()}},Ai=g=>{if(b){V=g,F("Answer saved; Oracle continues once the current turn settles.");return}Le({kind:"submit",text:"",response:g})},pr=async g=>{try{let w=await e.getSession(g);fn(w),w.activeStreamId&&Le({kind:"replay",streamId:w.activeStreamId}),F(`Resumed ${w.title||w.sessionId}.`)}catch(w){te(Q(w),rn)}},ki=async()=>{try{let g=await e.listSessions();if(!g.length){F("No saved conversations to resume.");return}let w=new Ya(g.map(q=>({value:q.sessionId,label:q.title,description:ue(q)})),Math.min(12,g.length),pt),h=await Ht(e.endpoint),A=h?g.findIndex(q=>q.sessionId===h):-1;A>=0&&w.setSelectedIndex(A);let S=o.showOverlay(w,{width:"85%",maxHeight:"80%",anchor:"center"});w.onSelect=q=>{S.hide(),pr(q.value)},w.onCancel=()=>{S.hide(),Xe()},S.focus()}catch(g){te(Q(g),rn)}},fr=async g=>{if(g&&(!d||d.kind!=="program"&&d.kind!=="initiative")){F("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let w=await e.createSession(wt(d,g));fn(w),F(`Started a new conversation \xB7 ${ue(w)}.`)}catch(w){te(Q(w),rn)}},xi=()=>({session:l,write:x,approve:k,grantScopes:[...e.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...d?{context:d}:{},...O?{contextText:O}:{},...n.model?{model:n.model}:{},lastServedBy:un,...St?{lastTurn:St}:{},totals:{...Pe},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},endpoint:e.endpoint,version:t.version,pendingFiles:K.map(g=>Ho(g))}),Si=async()=>{if(!Ae.trim()){F("There is no answer to copy yet.");return}try{let g=Xa();g?.setText?await g.setText(Ae):r.write(`\x1B]52;c;${Buffer.from(Ae,"utf8").toString("base64")}\x07`),F(`Copied the last answer (${Ae.length} characters).`)}catch(g){F(`Could not copy: ${Q(g)}`)}},Ii=async(g,w,h)=>{if(g.idleOnly&&b){F(`Wait for Oracle to finish, or press Esc, before /${g.name}.`);return}switch(g.name){case"help":we(Ve(A=>["",...Wo({server:c,canApprove:k}).flatMap(S=>[Wa(S.title),...Un(S.rows,A)])]));return;case"status":Ct("Status",zo(xi()));return;case"model":Ct("Model",Xn({...n.model?{model:n.model}:{},lastServedBy:un}));return;case"usage":Ct("Usage",[...er(St),...Zn(Pe)]);return;case"files":Ct("Generated files",Ko(l.sessionId,$e));return;case"copy":await Si();return;case"exit":Tt();return;case"new":if(h&&h!=="shared"){F("Usage: /new or /new shared");return}await fr(h==="shared");return;case"clear":await fr(!1);return;case"resume":h?await pr(h):await ki();return;case"context":{if(!h){te(`Context: ${Ye(d)}${O?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(h==="clear")d=void 0;else{let[A,S,...q]=w;if(!["program","initiative","codebase"].includes(A??"")||!S||q.length){F("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}d={kind:A,id:S}}te(`Context for your next message: ${Ye(d)}.`);return}case"attach":{if(!h){F("Usage: /attach <file path>");return}let A=await Ga(h).catch(()=>{});if(!A?.isFile()){F(`Not a readable file: ${h}`);return}K.push(h),te(`Attached ${Ho(h)} (${N(A.size)}). It uploads with your next message.`);return}}},mr=g=>{let w=g.trim();if(!w)return;a.addToHistory(w);let h=jo(w,c);if(h?.kind==="local"){Ii(h.command,h.args,h.arg).catch(A=>te(Q(A),rn));return}if(h?.kind==="unknown"){a.setText(w),F(`Unknown command /${h.name}. Type /help to see the commands.`);return}if(b){let A=v!==void 0;v=w,F(A?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),Y();return}Le({kind:"submit",text:w})},Ci=o.addInputListener(g=>{if(on(g,"ctrl+c")){if(b)return mn(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),Y(),{consume:!0};let w=Date.now();return w-lr<=Vo?Tt():(lr=w,o.flash("Press Ctrl+C again to exit",Vo)),{consume:!0}}if(on(g,"escape")){let w=ce!==void 0&&o.getFocusedComponent()===ce;return b&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!w?(mn(),{consume:!0}):void 0}if(on(g,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(Tt(),{consume:!0}):void 0;if(on(g,"ctrl+o"))return xt=!xt,F(xt?"Showing tool activity":"Hiding tool activity"),Y(),{consume:!0}}),gr=()=>{let g=!!b;mn().finally(()=>{g&&(ln=!0),Tt()})};process.on("SIGINT",gr),a.onSubmit=mr,a.onChange=()=>Y(),a.setAutocompleteProvider(Do(c,process.cwd())),fn(t.session),o.start(),l.activeStreamId&&Le({kind:"replay",streamId:l.activeStreamId}),t.initialPrompt&&mr(t.initialPrompt),await bi,Ci(),process.off("SIGINT",gr),pn(),b?.controller.abort(),await r.drainInput().catch(()=>{}),ln&&(process.exitCode=130)}function nc(t,e){if(e.skipped)return"Skipped the optional Oracle question.";let n=[];for(let r of e.answers){let o=t.questions.find(i=>i.id===r.questionId);for(let i of r.optionIds){let s=o?.options.find(a=>a.id===i);s&&n.push(s.label)}r.customText&&n.push(r.customText)}return`You answered: ${n.map(u).join("; ")||"no options selected"}`}import{createHash as rc,randomBytes as ei,timingSafeEqual as oc}from"node:crypto";import{createServer as ic}from"node:http";import sc from"open";var ac=6e4,cc=5*6e4,sn=new Map;async function nr(t){let e=fe(t.endpoint),n=await We(e),r=["read"];t.write&&r.push("write"),t.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=ei(32).toString("base64url"),i=await uc(o);try{let s={client_name:"AnyForge CLI",redirect_uris:[i.redirectUri],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"},a=await pc(n.oauth.registration,s);if(typeof a.client_id!="string"||!a.client_id)throw new f("OAuth registration did not return a client id.",m.API_ERROR);let c=ei(32).toString("base64url"),p=rc("sha256").update(c).digest("base64url"),l={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:p,code_challenge_method:"S256",resource:n.resource},d=new URL(n.oauth.authorization);for(let[R,V]of Object.entries(l))d.searchParams.set(R,String(V));t.onAuthorizationUrl?.(d.toString());try{t.openBrowser?await t.openBrowser(d.toString()):await sc(d.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
266
- ${d.toString()}
267
- `)}let O=await i.wait();if(!oi(O.state,o))throw new f("Oracle sign-in callback state did not match; authorization was rejected.",m.API_ERROR);if(O.error)throw new f(`Oracle authorization failed: ${u(O.error)}${O.errorDescription?` (${u(O.errorDescription)})`:""}`,m.API_ERROR);if(!O.code)throw new f("Oracle authorization callback did not include a code.",m.API_ERROR);let x={client_id:a.client_id,grant_type:"authorization_code",code:O.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},k=await ai(n.oauth.token,x);si(k);let b=ii(k.scope);if(!b.includes("read")||b.some(R=>!r.includes(R)))throw await or(n.oauth.revocation,a.client_id,k.access_token,k.refresh_token).catch(()=>{}),new f("The granted Oracle scopes are invalid for this request.",m.API_ERROR);let v={version:1,endpoint:e,clientId:a.client_id,redirectUri:i.redirectUri,accessToken:k.access_token,refreshToken:k.refresh_token,expiresAt:Date.now()+k.expires_in*1e3,scopes:b};return await Jt(()=>Wn(v)),v}finally{await i.close()}}async function ni(){let t=await Jt(async()=>{let e=await Kt();if(!e)return{hadCredentials:!1,revoked:!1,revokeFailure:void 0};try{let n=await We(e.endpoint);return await or(n.oauth.revocation,e.clientId,e.accessToken,e.refreshToken),await ze(),{hadCredentials:!0,revoked:!0,revokeFailure:void 0}}catch(n){return await ze(),{hadCredentials:!0,revoked:!1,revokeFailure:n}}});if(t.hadCredentials&&!t.revoked)throw new f(`Local Oracle credentials were cleared, but server revocation failed: ${t.revokeFailure instanceof Error?u(t.revokeFailure.message):"unknown error"}`,m.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire this access token automatically.");return{hadCredentials:t.hadCredentials,revoked:t.revoked}}async function ri(t){let e=t||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN)return ti(e);let n=await Kt();if(n&&(!e||fe(e)===n.endpoint)){let r=n.endpoint;return{endpoint:r,accessToken:n.accessToken,scopes:n.scopes.filter(rr),source:"oauth",getAccessToken:async o=>lc(r,o)}}try{return await ti(e)}catch(r){throw n&&e&&fe(e)!==n.endpoint?new oe:r instanceof oe?new oe:r}}async function ti(t){let e=await Fe(t),r=(await tt({apiKey:e.apiKey,endpoint:e.endpoint})).scopes.filter(rr);return{endpoint:e.endpoint,accessToken:e.apiKey,scopes:r,source:"control"}}async function lc(t,e){let n=fe(t),r=sn.get(n);if(r)return r;let o=Jt(()=>dc(n,e));sn.set(n,o);try{return await o}finally{sn.get(n)===o&&sn.delete(n)}}async function dc(t,e){let n=await Kt();if(!n||n.endpoint!==t)throw new oe;if(n.expiresAt>Date.now()+ac&&(!e||n.accessToken!==e))return n.accessToken;let r=await We(n.endpoint),o;try{let s={client_id:n.clientId,grant_type:"refresh_token",refresh_token:n.refreshToken,resource:r.resource};o=await ai(r.oauth.token,s)}catch(s){throw s instanceof an&&["invalid_grant","invalid_client","invalid_target"].includes(s.code)?(await ze(),new oe):s}si(o);let i;try{i=ii(o.scope)}catch(s){throw await ze(),s}if(i.some(s=>!n?.scopes.includes(s)))throw await or(r.oauth.revocation,n.clientId,o.access_token,o.refresh_token),await ze(),new f("Oracle refresh attempted to widen the saved grant; credentials were cleared.",m.API_ERROR);return n={...n,accessToken:o.access_token,refreshToken:o.refresh_token,expiresAt:Date.now()+o.expires_in*1e3,scopes:i},await Wn(n),n.accessToken}var an=class extends f{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?m.NO_CREDENTIALS:m.API_ERROR);this.code=n;this.name="OAuthResponseError"}};async function uc(t){let e,n,r=!1,o=new Promise((c,p)=>{e=c,n=p});o.catch(()=>{});let i=ic((c,p)=>{if((c.url?.length??0)>8192){p.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let l=c.url??"/";if(!l.startsWith("/callback")||l.startsWith("//")){p.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let d=new URL(l,"http://127.0.0.1");if(c.method!=="GET"||d.pathname!=="/callback"){p.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let O=d.searchParams.get("code")?.slice(0,2048)??"",x=d.searchParams.get("state")?.slice(0,256)??"",k=d.searchParams.get("error")?.slice(0,256)??void 0,b=d.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!x){p.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!oi(x,t)){p.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(r){p.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}r=!0,p.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'"}).end('<!doctype html><meta charset="utf-8"><title>AnyForge Oracle</title><p>Sign-in response received. You may close this tab.</p>'),e({code:O,state:x,...k?{error:k}:{},...b?{errorDescription:b}:{}})});await new Promise((c,p)=>{i.once("error",p),i.listen(0,"127.0.0.1",()=>{i.removeListener("error",p),c()})});let s=i.address();if(!s||typeof s=="string")throw new f("Could not bind an Oracle sign-in callback port.",m.FAILURE);let a=setTimeout(()=>{r||(r=!0,n(new f("Oracle sign-in timed out before the browser returned.",m.FAILURE)))},cc);return a.unref(),{redirectUri:`http://127.0.0.1:${s.port}/callback`,wait:()=>o,close:async()=>{clearTimeout(a),i.listening&&(i.closeAllConnections(),await new Promise(c=>i.close(()=>c())))}}}function oi(t,e){let n=Buffer.from(t),r=Buffer.from(e);return n.length===r.length&&oc(n,r)}function ii(t){let e=t.split(/[\s+]+/).filter(Boolean);if(!e.every(rr))throw new f("OAuth server returned an unknown Oracle scope.",m.API_ERROR);let n=[...new Set(e)];if(!n.includes("read"))throw new f("Oracle OAuth grant is missing the required read scope.",m.API_ERROR);return n}function rr(t){return t==="read"||t==="write"||t==="approve"}function si(t){if(!t||typeof t.access_token!="string"||!t.access_token||typeof t.refresh_token!="string"||!t.refresh_token||typeof t.token_type!="string"||t.token_type.toLowerCase()!=="bearer"||typeof t.expires_in!="number"||!Number.isFinite(t.expires_in)||t.expires_in<=0||typeof t.scope!="string")throw new f("OAuth token response did not match the supported format.",m.API_ERROR)}async function pc(t,e){return ci(t,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)})}async function ai(t,e){return ci(t,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(Object.entries(e).map(([n,r])=>[n,String(r)])).toString()})}async function ci(t,e){let n;try{n=await fetch(t,{...e,redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(o){throw new f(`OAuth request failed: ${u(o instanceof Error?o.message:String(o))}`,m.FAILURE)}let r=null;try{r=await n.json()}catch{}if(!n.ok){let o=r&&typeof r=="object"?r:{},i=typeof o.error=="string"?o.error:`http_${n.status}`,s=typeof o.error_description=="string"?u(o.error_description):i;throw new an(i,s,n.status)}if(!r||typeof r!="object"||Array.isArray(r))throw new f(`OAuth endpoint returned invalid JSON (${n.status}).`,m.API_ERROR);return r}async function or(t,e,n,r){let o=async i=>{let s=await fetch(t,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:e,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=u(c.error_description))}catch{}throw new f(`OAuth token revocation failed: ${a}`,m.API_ERROR)}};await o(r),n!==r&&await o(n)}var Ic=1048576,Cc=25*1048576;async function mi(t){let[e,...n]=t.positional,r=["exec","sessions","resume","login","logout","download"].includes(e??""),o=r?void 0:t.positional.join(" ");if(j(t.flags,"read-only")&&(j(t.flags,"write")||j(t.flags,"approve")))throw new y("--read-only cannot be combined with --write or --approve.");if(!r&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(e==="login"){if(n.length)throw new y("oracle login does not accept positional arguments.");let x=await nr({endpoint:t.endpointOverride??t.endpoint,write:j(t.flags,"write"),approve:j(t.flags,"approve")}),k=x.scopes.join(", "),v=[j(t.flags,"write")?"write":void 0,j(t.flags,"approve")?"approve":void 0].filter(R=>!!R).filter(R=>!x.scopes.includes(R));process.stdout.write(`Connected to ${x.endpoint} with scopes: ${k}.
268
- `),v.length&&process.stderr.write(`This account was granted read only; the server withheld: ${v.join(", ")}.
269
- `);return}if(e==="logout"){if(n.length)throw new y("oracle logout does not accept positional arguments.");let x=await ni();process.stdout.write(x.hadCredentials?`Oracle credentials cleared and revoked.
270
- `:`No saved Oracle credentials.
271
- `);return}let i;try{i=await di(t.endpointOverride)}catch(x){if(!r&&x instanceof f&&x.exitCode===m.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let k=(await import("prompts")).default;if((await k({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw x;let v=await nr({endpoint:t.endpointOverride??t.endpoint});process.stderr.write(`Connected to ${v.endpoint} with scopes: ${v.scopes.join(", ")}.
272
- `),i=await di(t.endpointOverride)}else throw x}if(e==="sessions"){if(n.length)throw new y("oracle sessions does not accept positional arguments.");let x=await i.listSessions();Ec(x,t.flags.json===!0);return}if(e==="download"){await Lc(i,n,t.flags);return}if(e==="exec"){if(j(t.flags,"write")||j(t.flags,"approve"))throw new y("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(t.flags.json===!0&&j(t.flags,"stream-json"))throw new y("Choose either --json or --stream-json.");let x=await Tc(n.join(" ")),k=await i.config();ui(i,k),pi(Rt(t.flags,"context"));let b=Bn(t.flags),v=await i.createSession(wt(b,!1));await yt(v.sessionId,i.endpoint);let R=await Qt(i,v.sessionId,li(t.flags),(K,ae)=>J(process.stderr,`Uploading explicit attachment ${K} (${N(ae)}).
273
- `)),V={requestId:gc(),text:x,readOnly:!0,...b?{context:b}:{},...Rt(t.flags,"context")?{contextText:Rt(t.flags,"context")}:{},...R.length?{attachments:R.map(K=>({fileId:K.fileId}))}:{}};await $c(i,v.sessionId,V,{json:t.flags.json===!0,streamJson:j(t.flags,"stream-json"),config:k});return}if(e==="resume"&&n.length>1)throw new y("oracle resume accepts at most one session id.");if(e==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("oracle resume is interactive and needs a terminal.","Use `anyforge oracle sessions` to list sessions, or run `anyforge oracle exec` for a new scripted turn.");let s=await i.config();ui(i,s);let a=Bn(t.flags),c=Rt(t.flags,"context");pi(c);let p=j(t.flags,"shared"),l=j(t.flags,"write")||j(t.flags,"approve");if(l&&(!i.scopes.has("write")||s.capabilities?.write!==!0))throw new f("This Oracle grant or current workspace role does not allow write actions.",m.API_ERROR);if(j(t.flags,"approve")&&(!i.scopes.has("approve")||s.capabilities?.approve!==!0))throw new f("This Oracle grant or current workspace role does not allow approval actions.",m.API_ERROR);if(p&&(!a||a.kind!=="program"&&a.kind!=="initiative"))throw new y("--shared requires --program or --initiative.");let d;if(e==="resume"){let k=(n[0]||void 0)??await _c(await i.listSessions(),await Ht(i.endpoint));d=await i.getSession(k)}else d=await i.createSession(wt(a,p));await yt(d.sessionId,i.endpoint);let O=await Promise.resolve().then(()=>(sr(),ir));await Zo({version:O.default.version,client:i,config:s,session:d,initialPrompt:o,initialContext:a,contextText:c,shared:p,canWrite:l,canApprove:j(t.flags,"approve"),initialFiles:li(t.flags)})}function j(t,e){return t[e]===!0}function Rt(t,e){let n=t[e];return typeof n=="string"?n:void 0}function li(t){let e=t.file;return typeof e=="string"?[e]:Array.isArray(e)?e:[]}async function di(t){try{return new zt(await ri(t))}catch(e){throw e instanceof f&&e.exitCode===m.NO_CREDENTIALS?new f("Not authenticated for the hosted Oracle.",m.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):e}}function ui(t,e){if(!t.scopes.has("read")||e.capabilities?.read===!1)throw new f("This credential does not have Oracle read access.",m.API_ERROR)}function pi(t){if(t&&Buffer.byteLength(t,"utf8")>zn)throw new y(`--context must be ${zn/1024} KiB or less.`)}async function Tc(t){let e=t.trim();if(process.stdin.isTTY){if(e)return e;throw new y("oracle exec requires a prompt when stdin is a terminal.",'Example: anyforge oracle exec "summarize this program"')}let n=[],r=0;for await(let i of process.stdin){let s=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=s.byteLength,r>Ic)throw new y("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!e&&!o)throw new y("oracle exec needs a prompt in argv or piped stdin.");return[e,o].filter(Boolean).join(`
274
-
275
- `)}function Ec(t,e){if(e){process.stdout.write(`${JSON.stringify(t,null,2)}
261
+ `},vu=Object.entries(rn).map(([t,e])=>({uri:t==="SKILL.md"?Po:`${Po}/${t}`,name:t==="SKILL.md"?de:`${de}/${t.replace(/^references\//,"")}`,title:t==="SKILL.md"?"AnyForge platform guide":t,description:t==="SKILL.md"?ka:`Reference for the ${de} skill: ${t}`,mimeType:Aa,size:new TextEncoder().encode(e).byteLength}));var Ia=rn["SKILL.md"],bu=Ia.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"");var Fo={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills"};function Ta(t){let e=t.scope==="user"?t.homeDir??xa():t.cwd??process.cwd();if(t.scope==="user"&&t.client==="codex"){let n=t.codexHome??process.env.CODEX_HOME??Fe(e,".codex");return Fe(n,"skills",de)}return Fe(e,Fo[t.client],de)}function Ca(t){if(t.scope!=="project"&&t.scope!=="user")throw new y(`--scope must be project or user, got "${t.scope}".`);if(!Object.hasOwn(Fo,t.client))throw new y(`--client must be agents, claude, or codex, got "${t.client}".`)}async function Xn(t){try{return(await bt.lstat(t)).isSymbolicLink()}catch(e){if(e.code==="ENOENT")return!1;throw e}}async function _a(t){Ca(t);let e=Ta(t),n=Object.entries(rn),r=n.map(([s])=>Fe(e,s));if(await Xn(e))throw new y(`Refusing to install through the symbolic link ${e}.`);let o=new Set(n.map(([s])=>Lo(s)).filter(s=>s!=="."));for(let s of o)if(await Xn(Fe(e,s)))throw new y(`Refusing to install through the symbolic link ${Fe(e,s)}.`);if(!t.force){let s=[];for(let a of r)try{await bt.access(a),s.push(a)}catch(c){if(c.code!=="ENOENT")throw c}if(s.length>0)throw new y(`The ${de} skill already exists at ${e}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await bt.mkdir(e,{recursive:!0});let i=[];for(let[s,a]of n){let c=Fe(e,s);if(await bt.mkdir(Lo(c),{recursive:!0}),await Xn(c))throw new y(`Refusing to replace the symbolic link ${c}.`);await bt.writeFile(c,a,{encoding:"utf8",mode:420}),i.push(s)}return{name:de,scope:t.scope,client:t.client,directory:e,files:i}}async function qo(t){if(t.subcommand!=="install")throw new y(`Unknown skill command${t.subcommand?`: ${t.subcommand}`:""}.`,"Use `anyforge skill install anyforge-platform`.");if(t.name!==de)throw new y(`Unknown skill${t.name?`: ${t.name}`:""}.`,`The only portable platform skill is ${de}.`);let e=t.scope??"project",n=t.client??"agents";if(!["project","user"].includes(e))throw new y(`--scope must be project or user, got "${e}".`);if(!["agents","claude","codex"].includes(n))throw new y(`--client must be agents, claude, or codex, got "${n}".`);let r=await _a({scope:e,client:n,force:t.force});if(t.json){process.stdout.write(JSON.stringify(r)+`
262
+ `);return}console.log(Sa("Installed ")+`${r.name} ${No(`(${r.scope}, ${r.client})`)}`),console.log(` ${r.directory}`),console.log(No(` ${r.files.length} files installed. Re-run with --force to refresh them.`)),r.scope==="project"&&r.client==="agents"&&console.log(Ea(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as tl}from"node:crypto";import{open as nl,realpath as rl,stat as ol}from"node:fs/promises";import{basename as il,join as sl,resolve as al}from"node:path";import{bold as Sr,cyan as zi,dim as ve,yellow as xn}from"kleur/colors";import{ProcessTerminal as cl,SelectList as ll,Text as dl,TuiAltScreen as ul}from"@earendil-works/pi-tui";var $a=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function Pa(t){return $a.has(t)?"querying the code graph":t==="search_code_semantic"?"searching the code index":t==="search_codebase_docs"?"searching codebase docs":null}function on(t){let e=Pa(t);if(e)return e;let n=/^mcp__(.+?)__(.+)$/.exec(t);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:t.replace(/_/g," ")}var La=new Set(["ask_user","present_catch_up_decision","present_memory_candidates"]);function Ve(t){return typeof t=="string"&&La.has(t)}import{truncateToWidth as hn,wrapTextWithAnsi as li}from"@earendil-works/pi-tui";import{cyan as di,dim as at,green as ui,italic as pc,red as pr,yellow as fr}from"kleur/colors";import{truncateToWidth as Rt,visibleWidth as Zn,wrapTextWithAnsi as Na}from"@earendil-works/pi-tui";import{bold as Fa,dim as qa}from"kleur/colors";function U(t){return t<1024?`${t} B`:t<1024*1024?`${kt(t/1024)} KiB`:`${kt(t/(1024*1024))} MiB`}function At(t){let e=Math.max(0,t);if(e<1e4)return`${kt(e/1e3)}s`;let n=Math.round(e/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/3600),o=Math.floor(n%3600/60),i=n%60;return r?o?`${r}h ${o}m`:`${r}h`:i?`${o}m ${i}s`:`${o}m`}function er(t){let e=Math.floor(Math.max(0,t)/1e3);return e<60?`${e}s`:`${Math.floor(e/60)}m ${String(e%60).padStart(2,"0")}s`}function ie(t){return Math.abs(t)<1e3?String(Math.round(t)):Math.abs(t)<1e6?`${kt(t/1e3,t<1e5?1:0)}k`:`${kt(t/1e6)}M`}function kt(t,e=1){return t.toFixed(e).replace(/\.0+$/,"")}function ja(t){return d(t).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function Ma(t,e){return typeof e=="boolean"?e?"on":"off":typeof e=="string"?d(e):/Ms$/.test(t)?At(e):/Bytes$/.test(t)?U(e):/tokens?/i.test(t)?ie(e):String(e)}function jo(t){return t?Object.entries(t).filter(e=>e[1]!==null).map(([e,n])=>`${ja(e)} ${Ma(e,n)}`):[]}function tr(t,e,n=2){let r=Math.min(16,Math.max(...t.map(([s])=>Zn(s)),0)+2),o=Math.max(10,e-n-r),i=[];for(let[s,a]of t)Na(a,o).forEach((u,l)=>{let p=l===0?qa(Rt(s,r-1).padEnd(r)):" ".repeat(r);i.push(Rt(`${" ".repeat(n)}${p}${u}`,e))});return i}function Mo(t,e,n){return[Rt(Fa(t),n),...tr(e,n)]}function Uo(t,e,n){let r=Zn(n),o=e.filter(Boolean).join(" \xB7 ");if(r+4>t)return Rt(o||n,t);let i=t-r-2,s=Rt(o,i),a=Math.max(2,t-Zn(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as xt,cyan as It,dim as Se,green as Ua,italic as Do,strikethrough as Da,underline as Bo,yellow as Ba}from"kleur/colors";import{Markdown as Wa}from"@earendil-works/pi-tui";var Ga={heading:t=>xt(It(t)),link:t=>Bo(It(t)),linkUrl:t=>Se(t),code:t=>Ba(t),codeBlock:t=>t,codeBlockBorder:t=>Se(t),quote:t=>Do(t),quoteBorder:t=>Se(t),hr:t=>Se(t),listBullet:t=>It(t),bold:t=>xt(t),italic:t=>Do(t),strikethrough:t=>Da(t),underline:t=>Bo(t)},Ze={selectedPrefix:t=>It(t),selectedText:t=>xt(t),description:t=>Se(t),scrollInfo:t=>Se(t),noMatch:t=>Se(t)},Wo={borderColor:t=>Se(t),selectList:Ze};var Xe=class{constructor(e,n){this.linkOrigin=n;this.content=d(e),this.markdown=new Wa(Un(this.content,n),0,0,Ga)}content;markdown;cache;getText(){return this.content}setText(e){let n=d(e);n!==this.content&&(this.content=n,this.markdown.setText(Un(n,this.linkOrigin)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(e){let n=Math.max(12,e);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(ao):[];return this.cache={width:n,lines:r},r}};function St(t,e){return t==="user"?`${xt(Ua(e?d(e):"You"))}`:`${xt(It("Oracle"))}`}function ge(t){return t.shared||t.visibility==="company"?`Shared with the company${t.entityKey?` \xB7 ${d(t.entityKey)}`:""}`:"Private to you"}function Go(t){return t.shared||t.visibility==="company"?"shared":"private"}import{createReadStream as ic}from"node:fs";import{stat as sc}from"node:fs/promises";import{basename as ac}from"node:path";import{setTimeout as ii}from"node:timers/promises";var Ko={txt:"text/plain",log:"text/plain",md:"text/markdown",markdown:"text/markdown",csv:"text/csv",json:"application/json",pdf:"application/pdf",ts:"text/plain",tsx:"text/plain",js:"text/plain",jsx:"text/plain",mjs:"text/plain",cjs:"text/plain",py:"text/plain",go:"text/plain",rs:"text/plain",yaml:"text/plain",yml:"text/plain",toml:"text/plain",xml:"text/plain",html:"text/plain",css:"text/plain",sh:"text/plain",sql:"text/plain",java:"text/plain",kt:"text/plain",swift:"text/plain",c:"text/plain",h:"text/plain",cpp:"text/plain",rb:"text/plain",php:"text/plain",tf:"text/plain",diff:"text/plain",patch:"text/plain",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"};function zo(t){let e=t.slice(t.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(Ko,e)?Ko[e]:null}var nr="/api/v1/oracle";var Ho="workspace";function Ee(t){let e;try{e=new URL(t)}catch{throw new f(`Invalid Oracle endpoint: ${t}`,m.USAGE)}if(!["http:","https:"].includes(e.protocol)||e.username||e.password)throw new f("Oracle endpoint must be an http or https URL without embedded credentials.",m.USAGE);if(e.pathname!=="/"||e.search||e.hash)throw new f("Oracle endpoint must be the workspace origin, without a path, query or fragment.",m.USAGE);return e.origin}function he(t,e){return`${Ee(t)}${nr}${e}`}function Ka(t,e,n){let r;try{r=new URL(t)}catch{throw new f(`Oracle server returned an invalid ${n} endpoint.`,m.API_ERROR)}let o=new URL(Ee(e));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new f(`Oracle server returned an unsafe ${n} endpoint.`,m.API_ERROR);return r.toString()}function za(t,e){if(!t||typeof t!="object")throw new f("Oracle server omitted OAuth endpoints.",m.API_ERROR);let n=t,r=["registration","authorization","token","revocation"],o={};for(let i of r){if(typeof n[i]!="string")throw new f(`Oracle server omitted its OAuth ${i} endpoint.`,m.API_ERROR);o[i]=Ka(n[i],e,i)}return o}async function qe(t,e=fetch,n){let r=Ee(t),o;try{o=await e(he(r,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(l){throw new f(`Cannot reach ${r}: ${l instanceof Error?l.message:String(l)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let i=await nt(o,he(r,"/config")),s=P(tt(i,o.status)),a=`${r}${nr}`;if(s.protocolVersion!==1)throw new f(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(s.protocolVersion)}.`,m.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(s.resource!==a)throw new f("Oracle server resource does not match this workspace origin.",m.API_ERROR);let c=Array.isArray(s.scopes)?s.scopes:null;if(!c||!c.every(l=>l==="read"||l==="write"||l==="approve"))throw new f("Oracle server returned an invalid scope list.",m.API_ERROR);let u={protocolVersion:1,resource:a,scopes:c,oauth:za(s.oauth,r)};if(s.identity!==void 0){let l=P(s.identity);if(typeof l.uid!="string"||typeof l.companyId!="string")throw new f("Oracle server returned an invalid identity.",m.API_ERROR);let p=typeof l.companyName=="string"?d(l.companyName).trim().slice(0,120):"";u.identity={uid:d(l.uid),companyId:d(l.companyId),...p?{companyName:p}:{}}}if(s.capabilities!==void 0){let l=P(s.capabilities);if(![l.read,l.write,l.approve].every(p=>typeof p=="boolean"))throw new f("Oracle server returned invalid capabilities.",m.API_ERROR);u.capabilities={read:l.read,write:l.write,approve:l.approve}}if(s.model!==void 0){let l=P(s.model);if(typeof l.id!="string"||typeof l.provider!="string")throw new f("Oracle server returned invalid model metadata.",m.API_ERROR);u.model={id:d(l.id),provider:d(l.provider)}}if(s.limits!==void 0){let l=P(s.limits);if(Object.values(l).some(p=>!["string","number","boolean"].includes(typeof p)&&p!==null))throw new f("Oracle server returned invalid limits metadata.",m.API_ERROR);u.limits=Object.fromEntries(Object.entries(l).map(([p,k])=>[d(p),typeof k=="string"?d(k):k]))}return Array.isArray(s.commands)&&(u.commands=Ha(s.commands)),u}function Ha(t){let e=[];for(let n of t.slice(0,50)){let r=P(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||e.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?d(r.args).slice(0,60).trim():"";e.push({name:r.name,description:d(r.description).slice(0,200),...o?{args:o}:{}})}return e}var je=class{endpoint;scopes;source;#e;#n;#t;cachedConfig;constructor(e,n=fetch){this.endpoint=Ee(e.endpoint),this.#e=e.getAccessToken??(async()=>e.accessToken),this.#n=e.onIdentity,this.#t=n,this.scopes=new Set(e.scopes),this.source=e.source}async config(){if(!this.cachedConfig){let e=await this.#e();try{this.cachedConfig=await qe(this.endpoint,this.#t,e)}catch(r){if(this.source!=="oauth"||!(r instanceof Ae)||r.status!==401)throw r;let o=await this.#e(e);if(o===e)throw r;this.cachedConfig=await qe(this.endpoint,this.#t,o)}let n=this.cachedConfig.identity;n&&this.#n&&await this.#n(n).catch(()=>{})}return this.cachedConfig}async listSessions(){let e=await this.json("GET","/sessions"),n=Array.isArray(e)?e:P(e).sessions;if(!Array.isArray(n))throw new f("Oracle server returned an invalid sessions list.",m.API_ERROR);return n.map(Qo)}async createSession(e={}){let n=await this.json("POST","/sessions",e),r=P(n);return!Array.isArray(r.messages)&&typeof r.sessionId=="string"?this.getSession(r.sessionId):Yo(n)}async getSession(e){return Yo(await this.json("GET",`/sessions/${encodeURIComponent(e)}`))}async submitTurn(e,n,r,o){let i,s=he(this.endpoint,`/sessions/${encodeURIComponent(e)}/turns`),a=async u=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${u}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let u=await this.#e();if(i=await a(u),i.status===401&&this.source==="oauth"){let l=await this.#e(u);l!==u&&(i=await a(l))}}catch(u){throw u instanceof f||r?.aborted?u:new f(`Oracle connection was interrupted: ${u instanceof Error?u.message:String(u)}`,m.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await et(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let u=await nt(i,he(this.endpoint,`/sessions/${e}/turns`)),l=tt(u,i.status);throw new f(`Oracle server did not start a stream (${Ya(l)}).`,m.API_ERROR)}return i}async replayEvents(e,n,r){let o=[];for await(let i of this.streamReplayEvents(e,n,r))o.push(i);return o}async*streamReplayEvents(e,n,r,o){let i=`/sessions/${encodeURIComponent(e)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await et(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*Et(s,o);return}let c=tt(await nt(s,he(this.endpoint,i)),s.status),u=Array.isArray(c)?c:P(c).events;if(!Array.isArray(u))throw new f("Oracle replay response did not contain events.",m.API_ERROR);for(let l of u)yield rr(l)}async*streamRequestEvents(e,n,r=-1,o){let i=`/sessions/${encodeURIComponent(e)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await et(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*Et(s,o);return}let c=tt(await nt(s,he(this.endpoint,i)),s.status),u=Array.isArray(c)?c:P(c).events;if(!Array.isArray(u))throw new f("Oracle request replay response did not contain events.",m.API_ERROR);for(let l of u)yield rr(l)}async cancelTurn(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{streamId:n})}async cancelRequest(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{requestId:n})}async upload(e,n){let r=new FormData;r.set("sessionId",e),r.set("file",n,n.name);let o=await this.authenticatedFetch("POST","/uploads",{method:"POST",body:r,headers:{Accept:"application/json"}});return o.ok||await et(o),Ja(tt(await nt(o,he(this.endpoint,"/uploads")),o.status))}async download(e,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(e)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await et(r),r}async json(e,n,r){let o=await this.authenticatedFetch(e,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});return o.ok||await et(o),tt(await nt(o,he(this.endpoint,n)),o.status)}async authenticatedFetch(e,n,r={},o=2e4){try{let i=he(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=r.signal||o<=0?void 0:AbortSignal.timeout(o),c=k=>this.#t(i,{...r,method:e,headers:{...s,Authorization:`Bearer ${k}`},redirect:"error",...a?{signal:a}:{}}),u=await this.#e(),l=await c(u),p=r.body===void 0||typeof r.body=="string"||r.body===null;if(l.status===401&&this.source==="oauth"){let k=await this.#e(u);k!==u&&p&&(l=await c(k))}return l}catch(i){throw i instanceof f?i:new f(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*Et(t,e){if(!t.body)throw new f("Oracle stream has no response body.",m.FAILURE);let n=t.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,u=()=>{if(s.length===0)return null;let l=s.join(`
263
+ `);if(s=[],a=0,l==="[DONE]")return null;let p;try{p=JSON.parse(l)}catch{throw new f("Oracle stream returned invalid JSON.",m.API_ERROR)}let k=rr(p);return k.type==="finalizing"?k:k.idx<=c?null:(c=k.idx,k)};try{for(;;){let{value:p,done:k}=await n.read();p?.byteLength&&e?.();let x=r.decode(p,{stream:!k});if(o+=x,i+=sn(x),i>2*1024*1024)throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR);let b=0,O=o.indexOf(`
264
+ `,b);for(;O>=0;){let R=o.slice(b,O).replace(/\r$/,"");if(i-=sn(o.slice(b,O+1)),b=O+1,R===""){let A=u();A&&(yield A)}else if(!R.startsWith(":")){let A=R.indexOf(":"),z=A<0?R:R.slice(0,A),j=A<0?"":R.slice(A+1).replace(/^ /,"");if(z==="data"&&(s.push(j),a+=sn(j)+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}O=o.indexOf(`
265
+ `,b)}if(o=o.slice(b),k)break}if(o.trim()){let p=o.replace(/\r$/,"");if(p.startsWith("data:")&&(s.push(p.slice(5).replace(/^ /,"")),a+=sn(s[s.length-1]??"")+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}let l=u();l&&(yield l)}catch(l){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),l}finally{n.releaseLock()}}function sn(t){return Buffer.byteLength(t,"utf8")}function or(t){let e=["program","initiative","codebase"].filter(o=>typeof t[o]=="string");if(e.length>1)throw new f("Choose only one of --program, --initiative or --codebase.",m.USAGE);let n=e[0];if(!n)return;let r=t[n];if(typeof r!="string"||!r.trim())throw new f(`--${n} needs an id.`,m.USAGE);return{kind:n,id:r.trim()}}function P(t){return!t||typeof t!="object"||Array.isArray(t)?{}:t}function Ya(t){if(typeof t=="string")return d(t);try{return d(JSON.stringify(t))}catch{return"unexpected response"}}function tt(t,e){let n=P(t);if(n.ok===!1){let r=Jo(n.error,e),o=typeof n.message=="string"?d(n.message).slice(0,2e3):void 0;throw new Ae(r,e,o)}return n.ok===!0&&"data"in n?n.data:t}async function nt(t,e){try{return await t.json()}catch{throw new f(`Non-JSON response from ${e} (HTTP ${t.status}).`,m.FAILURE)}}async function et(t){let e;try{e=await t.clone().json()}catch{e=null}let n=P(e),r=Jo(n.error??n.error_description,t.status),o=typeof n.message=="string"?n.message:typeof n.error_description=="string"?n.error_description:typeof n.detail=="string"?n.detail:void 0;throw new Ae(r,t.status,typeof o=="string"?d(o).slice(0,2e3):void 0)}function Jo(t,e){if(typeof t!="string")return`http_${e}`;let n=d(t).slice(0,120);return/^[A-Za-z0-9_.-]+$/.test(n)?n:`http_${e}`}function Qo(t){let e=P(t);if(typeof e.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(e.sessionId)||typeof e.title!="string"||e.visibility!=="private"&&e.visibility!=="company"||typeof e.shared!="boolean")throw new f("Oracle server returned an invalid session summary.",m.API_ERROR);return{sessionId:e.sessionId,title:d(e.title),visibility:e.visibility,shared:e.shared,...typeof e.entityKey=="string"?{entityKey:d(e.entityKey)}:{},...typeof e.updatedAt=="number"||e.updatedAt===null?{updatedAt:e.updatedAt}:{}}}function Yo(t){let e=P(t),n=Qo(e);if(!Array.isArray(e.messages))throw new f("Oracle server returned an invalid session transcript.",m.API_ERROR);let r=e.messages.map((o,i)=>{let s=P(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new f(`Oracle session message ${i+1} is invalid.`,m.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(Za):void 0,c=Array.isArray(s.files)?s.files.map(ec):void 0;return{role:s.role,content:d(s.content),...typeof s.id=="string"?{id:s.id}:{},...typeof s.authorName=="string"?{authorName:d(s.authorName)}:{},...s.question&&typeof s.question=="object"?{question:Qa(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:Va(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof e.activeStreamId=="string"?{activeStreamId:e.activeStreamId}:{}}}function rr(t){let e=P(t);if(e.protocolVersion!==1||typeof e.idx!="number"||!Number.isSafeInteger(e.idx)||e.idx<0||typeof e.type!="string")throw new f("Oracle stream event does not match protocol version 1.",m.API_ERROR);return me(e)}function Ja(t){let e=P(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle upload response is missing file metadata.",m.API_ERROR);return{fileId:e.fileId,name:d(e.name),mediaType:d(e.mediaType),...typeof e.sizeBytes=="number"?{sizeBytes:e.sizeBytes}:{}}}function Qa(t){let e=P(t);if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:d(e.id),questions:e.questions.map((n,r)=>{let o=P(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:d(o.id),header:d(o.header),question:d(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=P(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new f(`Oracle question option ${s+1} is invalid.`,m.API_ERROR);return{id:d(a.id),label:d(a.label),description:d(a.description),...typeof a.recommended=="boolean"?{recommended:a.recommended}:{},...typeof a.confirms=="boolean"?{confirms:a.confirms}:{}}})}}),optional:e.optional===!0}}function Va(t){let e=P(t);if(typeof e.questionId!="string"||!Array.isArray(e.answers))throw new f("Oracle returned an invalid question response.",m.API_ERROR);return{questionId:d(e.questionId),answers:e.answers.map(Xa)}}function Xa(t){let e=P(t);if(typeof e.questionId!="string"||!Array.isArray(e.optionIds)||!e.optionIds.every(n=>typeof n=="string"))throw new f("Oracle returned an invalid question answer.",m.API_ERROR);return{questionId:d(e.questionId),optionIds:e.optionIds.map(n=>d(n)),...typeof e.customText=="string"?{customText:d(e.customText).slice(0,8e3)}:{}}}function Za(t){let e=P(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle session attachment metadata is invalid.",m.API_ERROR);return{fileId:d(e.fileId),name:d(e.name),mediaType:d(e.mediaType),...typeof e.sizeBytes=="number"&&Number.isFinite(e.sizeBytes)?{sizeBytes:e.sizeBytes}:{}}}function ec(t){let e=P(t);if(typeof e.fileId!="string"||typeof e.filename!="string"||typeof e.mediaType!="string"||typeof e.sizeBytes!="number"||!Number.isFinite(e.sizeBytes))throw new f("Oracle session file metadata is invalid.",m.API_ERROR);return{fileId:d(e.fileId),filename:d(e.filename),mediaType:d(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:d(e.format)}:{}}}import{randomUUID as tc}from"node:crypto";import{promises as we}from"node:fs";import{homedir as nc}from"node:os";import{join as ir}from"node:path";import*as Xo from"proper-lockfile";function ln(){return ir(nc(),".anyforge")}function cn(){return ir(ln(),"oracle")}function Zo(){return ir(ln(),"oracle.last-session")}function rc(){return{version:2,active:{},logins:[]}}function an(t){return t===void 0||typeof t=="string"}function Vo(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.endpoint!="string"||typeof e.clientId!="string"||typeof e.redirectUri!="string"||typeof e.accessToken!="string"||typeof e.refreshToken!="string"||typeof e.expiresAt!="number"||!Number.isFinite(e.expiresAt)||!Array.isArray(e.scopes)||!e.scopes.every(n=>typeof n=="string")||!an(e.companyId)||!an(e.companyName)||!an(e.uid)?null:{endpoint:e.endpoint,...e.companyId?{companyId:e.companyId}:{},...e.companyName?{companyName:e.companyName}:{},...e.uid?{uid:e.uid}:{},clientId:e.clientId,redirectUri:e.redirectUri,accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes}}function oc(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;if(e.version===1){let o=Vo(e);return o?{version:2,endpoint:o.endpoint,active:{[o.endpoint]:o.clientId},logins:[o]}:null}if(e.version!==2||!Array.isArray(e.logins)||!an(e.endpoint)||!e.active||typeof e.active!="object"||Array.isArray(e.active))return null;let n=e.logins.map(Vo);if(n.some(o=>o===null))return null;let r={};for(let[o,i]of Object.entries(e.active)){if(typeof i!="string")return null;r[o]=i}return{version:2,...e.endpoint?{endpoint:e.endpoint}:{},active:r,logins:n}}async function Z(){let t=cn(),e;try{e=await we.readFile(t,"utf8")}catch(o){if(o.code==="ENOENT")return rc();throw o}let n;try{n=JSON.parse(e)}catch{throw new Error(`Oracle credentials at ${t} are invalid JSON; run \`anyforge oracle logout --all\` and sign in again.`)}let r=oc(n);if(!r)throw new Error(`Oracle credentials at ${t} have an unsupported format; run \`anyforge oracle logout --all\` and sign in again.`);return r}async function Tt(t){if(!t.logins.length){await we.rm(cn(),{force:!0});return}await oi(cn(),t)}async function dn(t){return fn(async()=>{let e=await Z(),n=await t(e);return await Tt(e),n})}function ye(t,e){return t.logins.filter(n=>n.endpoint===e)}function un(t,e){let n=ye(t,e);return n.find(r=>r.clientId===t.active[e])??n[0]}function ee(t){return t.companyName||t.companyId||"workspace not known yet"}function ei(t,e){let n=e.companyId?t.logins.find(r=>r.endpoint===e.endpoint&&r.companyId===e.companyId&&r.clientId!==e.clientId):void 0;return t.logins=[...t.logins.filter(r=>r!==n&&r.clientId!==e.clientId),e],t.active[e.endpoint]=e.clientId,t.endpoint=e.endpoint,n}function sr(t,e){t.logins=t.logins.filter(o=>!(o.endpoint===e.endpoint&&o.clientId===e.clientId));let n=ye(t,e.endpoint);if(!n.length){if(delete t.active[e.endpoint],t.endpoint===e.endpoint){let o=t.logins[0]?.endpoint;o?t.endpoint=o:delete t.endpoint}return}if(t.active[e.endpoint]!==e.clientId&&n.some(o=>o.clientId===t.active[e.endpoint]))return;let r=n[0];return t.active[e.endpoint]=r.clientId,r}function ti(t,e,n,r){let o=t.logins.find(a=>a.endpoint===e&&a.clientId===n);if(!o)return{changed:!1};let i=o.companyId!==r.companyId||r.companyName!==void 0&&o.companyName!==r.companyName||r.uid!==void 0&&o.uid!==r.uid;o.companyId=r.companyId,r.companyName!==void 0&&(o.companyName=r.companyName),r.uid!==void 0&&(o.uid=r.uid);let s=t.logins.find(a=>a!==o&&a.endpoint===e&&a.companyId===r.companyId);return s&&(t.logins=t.logins.filter(a=>a!==s),t.active[e]===s.clientId&&(t.active[e]=o.clientId)),{changed:i||!!s,...s?{duplicate:s}:{}}}function Me(t,e){let n=e.trim(),r=t.find(a=>a.companyId===n);if(r)return r;let o=t.filter(a=>a.companyName?.toLowerCase()===n.toLowerCase());if(o.length===1)return o[0];let i=t.map(a=>`${ee(a)}${a.companyId&&a.companyName?` (${a.companyId})`:""}`),s=i.length?`Saved workspaces: ${i.join(", ")}.`:"No Oracle logins are saved for this endpoint.";throw o.length>1?new y(`More than one saved workspace is named "${n}". Use its id instead.`,s):new y(`No saved Oracle login for workspace "${n}".`,`${s} Add one with \`anyforge oracle login --workspace "${n}"\`.`)}async function ni(){let t;try{t=await we.readFile(Zo(),"utf8")}catch(r){if(r.code==="ENOENT")return[];throw r}let e;try{e=JSON.parse(t)}catch{return[]}if(!e||typeof e!="object"||Array.isArray(e))return[];let n=e;return n.version!==2||!Array.isArray(n.sessions)?[]:n.sessions.filter(r=>{if(!r||typeof r!="object")return!1;let o=r;return typeof o.endpoint=="string"&&typeof o.companyId=="string"&&typeof o.sessionId=="string"})}async function ri(t,e,n=""){let r=(await ni()).filter(o=>!(o.endpoint===e&&o.companyId===n));await oi(Zo(),{version:2,sessions:[...r,{endpoint:e,companyId:n,sessionId:t}]})}async function pn(t,e=""){return(await ni()).find(n=>n.endpoint===t&&n.companyId===e)?.sessionId}async function oi(t,e){await we.mkdir(ln(),{recursive:!0,mode:448});let n=`${t}.${tc()}.tmp`;try{await we.writeFile(n,`${JSON.stringify(e,null,2)}
266
+ `,{mode:384,flag:"wx"}),await we.rename(n,t),await we.chmod(t,384)}finally{await we.rm(n,{force:!0}).catch(()=>{})}}async function fn(t){await we.mkdir(ln(),{recursive:!0,mode:448});let e=cn(),n=await Xo.lock(e,{realpath:!1,lockfilePath:`${e}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await t()}finally{await n()}}var ar=8192,si=10*1048576,cc=20*1048576,ai=10,ci=3;function cr(t,e){if(t.type!=="tool_call"&&t.type!=="tool_call_start"||typeof t.spawnId=="string")return!1;let n=typeof t.id=="string"?t.id:void 0;if(n){if(e.has(n))return!1;e.add(n)}return!Ve(t.name)}var Ue=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(e){return e.type==="finalizing"?!0:e.idx<=this.lastIdx?!1:(this.lastIdx=e.idx,e.type==="stream_start"&&typeof e.streamId=="string"?this.streamId=d(e.streamId):e.type==="delta"&&typeof e.content=="string"?this.answer+=e.content:cr(e,this.toolIds)?this.answer="":e.type==="question"?this.question=ur(e):e.type==="error"?this.error=dr(e):e.type==="done"?this.done=e:e.type==="navigator_file_created"&&lc(this.files,e.file),!0)}get settled(){return!!(this.done||this.error)}outcome(){return{answer:this.answer,...this.question?{question:this.question}:{},...this.error?{error:this.error}:{},...this.done?{done:this.done}:{},...this.streamId?{streamId:this.streamId}:{},...this.files.length?{files:[...this.files]}:{}}}};async function mn(t,e,n,r,o,i=new Ue){let s=async p=>{let k=i.streamId;i.accept(p)&&(i.streamId&&i.streamId!==k&&r.onStream?.(i.streamId),await r.onEvent(p))},a=()=>lr(t,e,i,s,o,r.onActivity),c=async()=>{try{for await(let p of t.streamRequestEvents(e,n.requestId,-1,r.onActivity))await s(p)}catch(p){throw o?.aborted?p:new f("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new f("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)},u=async()=>{try{let p=await t.submitTurn(e,n,o);for await(let k of Et(p,r.onActivity))await s(k)}catch(p){if(o?.aborted||p instanceof f&&p.exitCode===m.API_ERROR)throw p;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},l;try{l=await t.submitTurn(e,n,o)}catch(p){if(o?.aborted||p instanceof f&&p.exitCode!==m.FAILURE)throw p;return u()}if(!l)throw new f("Oracle did not return a stream response.",m.FAILURE);r.onResponse?.();try{for await(let p of Et(l,r.onActivity))await s(p)}catch(p){if(o?.aborted||p instanceof f)throw p;return i.streamId?a():u()}return i.settled?i.outcome():i.streamId?a():u()}async function lr(t,e,n,r,o,i){let s=n.streamId;if(!s)throw new f("Oracle stream replay needs a stream id.",m.FAILURE);let a=0;for(;!n.settled&&a<ci;){if(o?.aborted)throw o.reason;try{for await(let c of t.streamReplayEvents(e,s,n.lastIdx+1,i))await r(c);if(!n.settled){if((await t.getSession(e)).activeStreamId!==s)break;await ii(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof f&&c.exitCode===m.API_ERROR||(a+=1,a>=ci))throw c;await ii(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new f("Oracle stream could not be fully replayed; the turn was not submitted again.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the session.`);return n.outcome()}function Ct(t,e){let n=e.done,r=n?.servedBy,o=De(n?.tokens),i=W(n?.rounds),s=typeof n?.exitReason=="string"?d(n.exitReason):void 0,a=n?.exitReason==="completed"&&!e.question,c=e.files??(Array.isArray(n?.files)?n.files.map(ot):void 0),u=e.error?"error":e.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:t,status:u,answer:d(e.answer),partial:!a,...typeof n?.messageId=="string"?{messageId:d(n.messageId)}:typeof n?.answerId=="string"?{messageId:d(n.answerId)}:{},...e.question?{question:e.question}:{},...e.error?{error:d(e.error)}:{},...e.streamId?{streamId:d(e.streamId)}:{},...r?{servedBy:me(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:me(c)}:{}}}function E(t,e){return typeof t=="string"?d(t).slice(0,e):""}function dr(t){return typeof t.message=="string"?d(t.message).slice(0,2e3):"Oracle turn failed."}function Q(t){return d(t instanceof Error?t.message:String(t)).slice(0,2e3)}function ur(t){let e=t.question;if(!e||typeof e!="object")throw new f("Oracle question event omitted its question card.",m.API_ERROR);return dc(e)}function ot(t){let e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};if(typeof e.fileId!="string"||!e.fileId||typeof e.filename!="string"||!e.filename||typeof e.mediaType!="string"||!e.mediaType||typeof e.sizeBytes!="number"||!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<0)throw new f("Oracle generated-file event omitted safe file metadata.",m.API_ERROR);return{fileId:d(e.fileId),filename:d(e.filename),mediaType:d(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:d(e.format)}:{}}}function lc(t,e){let n=ot(e);t.some(r=>r.fileId===n.fileId)||t.push(n)}function dc(t){let e=t;if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:d(e.id),optional:e.optional===!0,questions:e.questions.map((n,r)=>{let o=n&&typeof n=="object"?n:{};if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:d(o.id),header:d(o.header),question:d(o.question),multiSelect:o.multiSelect,options:o.options.map(i=>{let s=i&&typeof i=="object"?i:{};if(typeof s.id!="string"||typeof s.label!="string"||typeof s.description!="string")throw new f("Oracle question option is invalid.",m.API_ERROR);return{id:d(s.id),label:d(s.label),description:d(s.description),...typeof s.recommended=="boolean"?{recommended:s.recommended}:{},...typeof s.confirms=="boolean"?{confirms:s.confirms}:{}}})}})}}function W(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function De(t){if(typeof t=="number"&&Number.isFinite(t))return{totalTokens:t};if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=W(e.in)??W(e.input)??W(e.inputTokens),r=W(e.cacheRead),o=W(e.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=W(e.out)??W(e.output)??W(e.outputTokens),a=W(e.total)??W(e.totalTokens)??(i!==void 0||s!==void 0?(i??0)+(s??0):void 0);if(!(i===void 0&&s===void 0&&a===void 0))return{...i!==void 0?{inputTokens:i}:{},...r?{cachedInputTokens:r}:{},...s!==void 0?{outputTokens:s}:{},...a!==void 0?{totalTokens:a}:{}}}function it(t){if(t&&typeof t=="object"){let e=t;if(typeof e.accepted=="boolean")return e.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof e.cancelled=="boolean")return e.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function st(t,e){let n=e&&t&&(t.kind==="program"||t.kind==="initiative")?{kind:t.kind,id:t.id}:void 0;return{...!e&&t?{context:t}:{},...n?{sharedEntity:n}:{},visibility:e?"company":"private"}}async function _t(t,e,n){await ri(t,e,n).catch(()=>{})}async function gn(t,e,n,r){if(!n.length)return[];if(n.length>ai)throw new y(`Attach no more than ${ai} files per turn.`);let o=0,i=[];for(let a of n){let c=await sc(a);if(!c.isFile())throw new y(`Attachment is not a file: ${a}`);if(c.size>si)throw new y(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let u=await uc(a,si);if(o+=u.byteLength,o>cc)throw new y("Attachments exceed the 20 MiB total CLI limit.");let l=ac(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",p=zo(l)??"";if(!p)throw new y(`Unsupported attachment type: ${a}`);i.push({content:u,name:l,mediaType:p})}let s=[];for(let{content:a,name:c,mediaType:u}of i){await r(d(c),a.byteLength);let l=new ArrayBuffer(a.byteLength);new Uint8Array(l).set(a);let p=new File([l],c,{type:u});s.push(await t.upload(e,p))}return s}async function uc(t,e){let n=[],r=0;for await(let o of ic(t)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>e)throw new y(`Attachment exceeds the ${U(e)} limit: ${t}`);n.push(i)}return Buffer.concat(n)}var $t=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],fc=2e4,mc=6,gc={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},hc={max_rounds:"reached the step limit",max_tokens:"reached the output limit",token_budget:"reached the token budget",deadline:"ran out of time",interrupted:"interrupted",loop_detected:"stopped a repeating loop",cancelled:"cancelled"},wn=class{constructor(e,n){this.startedAt=e;this.sessionId=n;this.lastSignalAt=e}phase="sending";answer="";tools=[];notices=[];files=[];lastSignalAt;endedAt;end;done;upload;round;maxRounds;serverPhase;agents=new Map;toolIds=new Set;get toolCount(){return this.tools.length}get failedCount(){return this.tools.filter(e=>e.status==="failed").length}get finished(){return this.end!==void 0}setUploading(e,n,r){this.phase="uploading",this.upload=`${e} (${U(n)})`,this.lastSignalAt=r}setPhase(e,n){this.phase=e,this.lastSignalAt=n}touch(e){this.lastSignalAt=e}apply(e,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(e);switch(e.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=W(e.round),this.maxRounds=W(e.maxRounds)??this.maxRounds;for(let r=this.tools.length-1;r>=0;r--)this.tools[r]?.started&&this.tools.splice(r,1);this.phase!=="finishing"&&(this.phase="thinking");break;case"phase":this.serverPhase=typeof e.phase=="string"?e.phase:void 0;break;case"delta":this.phase!=="finishing"&&(this.phase="writing");break;case"tool_result":this.phase!=="finishing"&&(this.phase="thinking");break;case"finalizing":this.phase="finishing";break}this.record(e)}record(e){switch(e.type){case"delta":typeof e.content=="string"&&(this.answer+=e.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(e);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===e.toolUseId);n&&(n.status=e.ok===!1?"failed":"ok");break}case"subagent_start":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"running");break;case"subagent_done":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${E(e.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${E(e.filename,200)}: ${E(e.error,500)}`});break;case"attachment_notice":if(Array.isArray(e.notices))for(let n of e.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${E(r.name,160)}: ${E(r.message,500)}`})}break;case"provider_fallback":{let n=E(e.from,120),r=E(e.to,120),o=E(e.reason,40).replaceAll("_"," ");this.notices.push({tone:"info",text:`Switched model${n?` from ${n}`:""}${r?` to ${r}`:""}${o?` (${o})`:""}.`});break}case"navigator_file_created":{let n=ot(e.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${U(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:dr(e)});break;case"done":this.done=e;break}}recordToolCall(e){let n=typeof e.id=="string"?e.id:void 0,r=cr(e,this.toolIds),o=typeof e.name=="string"?e.name:"";if(Ve(o))return;let i=E(typeof e.label=="string"?e.label:on(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,e.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof e.spawnId=="string"?{spawnId:e.spawnId}:{},...e.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=d(this.answer.trim()),this.answer=""),this.tools.push(a),this.phase!=="finishing"&&(this.phase="thinking")}note(e,n){this.notices.push({tone:e,text:d(n)})}finish(e,n){this.end=e,this.endedAt=n}label(){if(this.phase==="cancelling")return"Cancelling";if(this.phase==="uploading")return`Uploading ${this.upload??"attachment"}`;if(this.phase==="sending")return"Sending";if(this.phase==="preparing")return"Preparing context";if(this.phase==="finishing")return"Finishing up";let e=[...this.agents.values()].filter(r=>r==="running").length;if(e)return`Researching (${e} agent${e===1?"":"s"})`;let n=this.tools.filter(r=>r.status==="running"&&!r.spawnId);return n.length===1?`Running ${n[0]?.label}`:n.length>1?`Running ${n.length} tools`:this.phase==="writing"?"Writing":this.serverPhase&&gc[this.serverPhase]||"Thinking"}statusLine(e,n){let r=[this.label(),er(e-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=e-this.lastSignalAt;return o>=fc&&this.phase!=="cancelling"&&r.push(`no update for ${er(o)}`),n&&e-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let e=[],n=At((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=ui("\u2713"):this.end==="awaiting_input"?o=di("?")+" Waiting for your answer":this.end==="cancelled"?o=fr("\u2717")+" Interrupted":this.end==="error"?o=pr("\u2717")+" Error":o=fr("\u2717")+` Stopped: ${r&&hc[r]||"no final answer"}`,e.push(n),this.tools.length&&e.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=De(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&e.push(`${ie(i.inputTokens??0)} in${i.cachedInputTokens?` (${ie(i.cachedInputTokens)} cached)`:""} / ${ie(i.outputTokens??0)} out`);let s=Pt(this.done?.servedBy);return s&&e.push(s),`${o} ${at(e.join(" \xB7 "))}`}};function Pt(t){if(!t||typeof t!="object")return"";let e=t,n=E(e.model??e.id,100);if(!n)return"";let r=e.fallback&&typeof e.fallback=="object"?e.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${E(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${E(r.from,100)}${o})`}return n}var yn=class{constructor(e,n){this.activity=e;this.view=n;this.answer=new Xe("",n.linkOrigin)}answer;getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(e){let n=this.activity;this.answer.setText(n.answer);let r=[St("assistant")];r.push(...this.renderTools(e)),r.push(...this.answer.render(e));for(let o of n.notices){let i=o.tone==="error"?pr:o.tone==="warning"?fr:at;r.push(...li(i(o.text),e))}return n.finished&&r.push(hn(n.summaryLine(),e)),r}renderTools(e){let{tools:n}=this.activity;if(!n.length)return[];if(this.activity.finished&&!this.view.expanded()){let s=this.activity.failedCount,a=`Used ${n.length} tool${n.length===1?"":"s"}${s?` \xB7 ${s} failed`:""} (ctrl+o to expand)`;return[hn(at(` \u23BF ${a}`),e)]}let r=this.activity.finished?n:n.slice(-mc),o=n.length-r.length,i=[];return o&&i.push(hn(at(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),e)),r.forEach((s,a)=>{if(s.note)for(let p of li(s.note,Math.max(10,e-4)).slice(0,3))i.push(` ${at(pc(p))}`);let c=s.status==="running"?di($t[this.view.frame()%$t.length]??"*"):s.status==="ok"?ui("\u2713"):pr("\u2717"),u=a===0&&!o?" \u23BF ":" ",l=s.spawnId?` ${at("agent \xB7")} `:"";i.push(hn(`${u}${l}${c} ${s.label}`,e))}),i}};import{truncateToWidth as vc,visibleWidth as bc,wrapTextWithAnsi as fi}from"@earendil-works/pi-tui";import{bold as mi,cyan as Rc,dim as Oe}from"kleur/colors";import{CombinedAutocompleteProvider as wc}from"@earendil-works/pi-tui";var Lt=[{name:"help",description:"Show commands and keyboard shortcuts"},{name:"status",description:"Show session, access, model, usage and limits"},{name:"model",description:"Show the workspace model and the model that answered last"},{name:"usage",description:"Show turns and tokens used in this terminal"},{name:"new",args:"[shared]",description:"Start a new conversation",idleOnly:!0,completions:["shared"]},{name:"clear",description:"Clear the screen and start a new private conversation",idleOnly:!0},{name:"resume",args:"[session-id]",description:"Pick or open a saved conversation",idleOnly:!0},{name:"workspace",args:"[name|id]",description:"Switch to another saved workspace and start a new conversation there",idleOnly:!0},{name:"context",args:"[clear|program|initiative|codebase <id>]",description:"Show or change the context for the next message",completions:["clear","program ","initiative ","codebase "]},{name:"attach",args:"<path>",description:"Attach a file to your next message"},{name:"copy",description:"Copy the last answer as Markdown"},{name:"files",description:"List files Oracle generated in this conversation"},{name:"exit",description:"Leave the Oracle",aliases:["quit"]}],yc=[{name:"design",args:"[topic]",description:"Talk through a technical design before anything is created"},{name:"catchup",description:"Catch up on your work: what needs you, what landed, what is running"}];function mr(t){let e=new Set(Lt.flatMap(n=>[n.name,...n.aliases??[]]));return(t??yc).filter(n=>!e.has(n.name))}function pi(t,e){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(t.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=Lt.find(a=>a.name===r||a.aliases?.includes(r));if(i)return{kind:"local",command:i,arg:o,args:o?o.split(/\s+/):[]};let s=e.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function gr(t,e){let n=[...Lt.flatMap(i=>[i,...(i.aliases??[]).map(s=>({...i,name:s}))]).map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{},...i.completions?{getArgumentCompletions:s=>Oc(i.completions??[],s)}:{}})),...t.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new wc(n,e),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let u=(i[s]??"").slice(0,a);return s!==0||!u.trimStart().startsWith("/")?null:o.test(u)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,u){return r.applyCompletion(i,s,a,c,u)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function Oc(t,e){let n=t.filter(r=>r.startsWith(e.toLowerCase())&&r!==e).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function Nt(t,e){return t?e?"write + approve":"write":"read only"}function ct(t){return t?`${t.kind} ${d(t.id)}`:"no context"}function Te(t){return t?d(t.companyName||t.companyId):""}function gi(t,e){let n=[`${mi(Rc("AnyForge Oracle"))}${Oe(` \xB7 v${d(t.version)}`)}`,`${t.workspace?`${mi(t.workspace)} \xB7 `:""}${ge(t.session)} \xB7 ${t.access} \xB7 ${ct(t.context)}`,...t.session.messages.length?[`Resumed: ${d(t.session.title)}`]:[],Oe("Only your messages and the files you attach leave this terminal."),Oe("/help commands \xB7 /status details")];if(e<24)return n.flatMap(s=>fi(s,Math.max(1,e)));let r=Math.min(e,76),o=r-4,i=[Oe(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>fi(a,o))){let a=vc(s,o);i.push(`${Oe("\u2502")} ${a}${" ".repeat(Math.max(0,o-bc(a)))} ${Oe("\u2502")}`)}return i.push(Oe(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function hi(t){let e=(r,o)=>r?`${Oe(r)} ${o}`:o,n=[{title:"Commands",rows:Lt.map(r=>[`/${r.name}`,e(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(t.server.length){let r=t.server.map(o=>[`/${o.name}`,e(o.args,d(o.description))]);t.server.some(o=>o.name==="catchup")&&!t.canApprove&&r.push(["",Oe("Acting on /catchup decisions needs a session started with `anyforge oracle --write --approve`.")]),n.push({title:"Workspace commands (answered by Oracle)",rows:r})}return n.push({title:"Keys",rows:[["Enter","Send. While Oracle works, queues one message for when it finishes"],["Shift+Enter","New line (Ctrl+J also works)"],["Esc","Interrupt the current answer"],["Ctrl+C","Interrupt the answer, or clear the input; press twice to exit"],["Ctrl+D","Exit when the input is empty"],["Ctrl+O","Show or hide tool activity for finished answers"],["Ctrl+Shift+F","Search the conversation"],["Up / Down","Recall messages sent in this terminal"],["Tab","Complete a command, or a file path after /attach"],["PgUp / PgDn","Scroll; Home and End jump to the top and bottom"]]}),n}function hr(t){let n=[["Model",`workspace default ${t.model?`${d(t.model.provider)}/${d(t.model.id)}`:"chosen by the server"}`]],r=Pt(t.lastServedBy);if(r){let o=t.lastServedBy,i=E(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function wr(t){return[["This run",t.turns?`${t.turns} turn${t.turns===1?"":"s"} \xB7 ${t.tools} tool${t.tools===1?"":"s"} \xB7 ${ie(t.inputTokens)} in / ${ie(t.outputTokens)} out tokens`:"no turns yet"]]}function yr(t){if(!t?.finished)return[];let e=[At((t.endedAt??t.startedAt)-t.startedAt)];e.push(`${t.toolCount} tool${t.toolCount===1?"":"s"}${t.failedCount?` (${t.failedCount} failed)`:""}`);let n=W(t.done?.rounds);n!==void 0&&e.push(`${n} round${n===1?"":"s"}`);let r=De(t.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&e.push(`${ie(r.inputTokens??0)} in${r.cachedInputTokens?` (${ie(r.cachedInputTokens)} cached)`:""} / ${ie(r.outputTokens??0)} out tokens`);let o=E(t.done?.exitReason,40);return e.push(o?o.replaceAll("_"," "):t.end??""),[["Last turn",e.filter(Boolean).join(" \xB7 ")]]}function wi(t){let e=t.capabilities?["read","write","approve"].filter(o=>t.capabilities?.[o]).join(", ")||"none":"not reported",n=t.contextText?` \xB7 note ${U(Buffer.byteLength(t.contextText,"utf8"))}`:"",r=jo(t.limits);return[["Session",`${t.session.sessionId} \xB7 ${d(t.session.title)||"Untitled"}`],["Audience",ge(t.session)],["Access",`this session ${Nt(t.write,t.approve)} \xB7 grant ${t.grantScopes.join(", ")||"none"} \xB7 workspace role ${e}`],["Context",`${ct(t.context)}${n}`],...hr(t),...yr(t.lastTurn),...wr(t.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...t.identity?[["Workspace",kc(t.identity,t.savedWorkspaces)]]:[],["Endpoint",t.endpoint],["Version",`CLI ${d(t.version)} \xB7 protocol ${1}`],["Attached",t.pendingFiles.length?`${t.pendingFiles.map(d).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function kc(t,e){let n=t.companyName?`${d(t.companyName)} (${d(t.companyId)})`:`company ${d(t.companyId)}`,r=e!==void 0&&e>1?` \xB7 ${e} saved, /workspace to switch`:"";return`${n} \xB7 user ${d(t.uid)}${r}`}function yi(t,e){return e.length?e.map((n,r)=>[`${r+1}.`,`${d(n.filename)} (${U(n.sizeBytes)}) \xB7 anyforge oracle download ${t} ${d(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{randomUUID as Sc}from"node:crypto";import{stat as Ec}from"node:fs/promises";import{basename as Oi}from"node:path";import{bold as Tc,cyan as vi,dim as bi,red as dt,yellow as Cc}from"kleur/colors";import{Container as _c,Editor as $c,ProcessTerminal as Pc,ScrollView as Lc,SelectList as Ri,TuiAltScreen as Nc,VStack as Fc,getNativeClipboard as qc,matchesKey as bn,truncateToWidth as ki,wrapTextWithAnsi as jc}from"@earendil-works/pi-tui";import{bold as Ac,cyan as Or,dim as On,yellow as Ic}from"kleur/colors";import{Input as xc,Text as Be,matchesKey as lt}from"@earendil-works/pi-tui";var vn=class{constructor(e,n,r){this.tui=e;this.question=n;this.onComplete=r;(n.questions[0]?.options.length??0)===0&&(this.mode="custom"),this.customInput.onSubmit=o=>{let i=o.trim().slice(0,8e3);if(!i){this.errorMessage="Enter a short answer before continuing.",this.tui.requestRender();return}this.recordCurrent(i)},this.customInput.onEscape=()=>{if(!this.question.questions[this.questionIndex]?.options.length){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.setValue(""),this.mode="select",this.tui.setFocus(this),this.tui.requestRender()}}focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new xc({prompt:`${Or("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:On});invalidate(){}render(e){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,e-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new Be(`${Ac(Or(d(n.header)))}${On(o)}`,0,0).render(r),...new Be(d(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Be(On(`Enter submits your text${n.options.length?" \xB7 Esc back to the choices":this.question.optional?" \xB7 Esc skip":""}`),0,0).render(r))):i.push(...new Be(On(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Be(Ic(this.errorMessage),0,0).render(r)),i.map(s=>`${Or("\u2502")} ${s}`)}handleInput(e){if(this.mode==="custom"){this.customInput.handleInput(e);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(lt(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(e);return}if(lt(e,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(lt(e,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(lt(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(e.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(e);if(Number.isInteger(o)&&o>=1&&o<=n.options.length){let i=n.options[o-1]?.id;i&&(this.optionIndex=o-1,n.multiSelect?r.has(i)?r.delete(i):r.add(i):(r.clear(),r.add(i)),this.tui.requestRender());return}if(lt(e,"space")&&n.multiSelect){let i=n.options[this.optionIndex];i&&(r.has(i.id)?r.delete(i.id):r.add(i.id),this.tui.requestRender());return}if(lt(e,"enter")){if(r.size===0){this.errorMessage="Select an option explicitly, type a custom answer, or skip if optional.",this.tui.requestRender();return}this.recordCurrent()}}renderOptions(e,n){let r=this.selectedFor(e),o=[];return e.options.forEach((i,s)=>{let a=r.has(i.id),c=e.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",u=s===this.optionIndex?"\u203A":" ",l=i.recommended?" \xB7 recommended":"",p=i.confirms?" \xB7 confirms the shown action":"",k=`${u} ${s+1}. ${c} ${d(i.label)}${l}${p}`;o.push(...new Be(k,0,0).render(n)),o.push(...new Be(` ${d(i.description)}`,0,0).render(n))}),o}instructions(e){return e.options.length===0?`Write a short answer${this.question.optional?" \xB7 s or Esc skip card":""}`:`\u2191/\u2193 move \xB7 1\u2013${e.options.length} ${e.multiSelect?"toggle":"select"}${e.multiSelect?" \xB7 Space toggle":""} \xB7 Enter continue \xB7 o write your own${this.question.optional?" \xB7 s or Esc skip card":""}`}requireAnswer(){let e=this.question.questions[this.questionIndex];this.errorMessage=e?.options.length?"Oracle needs an answer to continue: pick an option, or press o to write your own.":"Oracle needs an answer to continue: type it and press Enter.",this.tui.requestRender()}selectedFor(e){let n=this.selected.get(e.id);return n||(n=new Set,this.selected.set(e.id,n)),n}recordCurrent(e){let n=this.question.questions[this.questionIndex];if(!n)return;e&&this.selectedFor(n).clear();let r=[...this.selectedFor(n)],o={questionId:n.id,optionIds:r,...e?{customText:e}:{}},i=this.answers.findIndex(s=>s.questionId===n.id);if(i>=0?this.answers.splice(i,1,o):this.answers.push(o),this.customInput.setValue(""),this.mode="select",this.questionIndex<this.question.questions.length-1){this.questionIndex+=1,this.optionIndex=0,this.mode=this.question.questions[this.questionIndex]?.options.length===0?"custom":"select",this.errorMessage="",this.tui.setFocus(this),this.tui.requestRender();return}this.finish({questionId:this.question.id,answers:this.answers.map(s=>({...s}))})}finish(e){this.onComplete(e)}};var Ai=1500,Mc=100,Uc="\x1B]133;A\x07";function ut(t){return{render:t,invalidate(){}}}function Ii(t,e,n,r){let o=new Xe(e,r);return{getText:()=>o.getText(),invalidate:()=>o.invalidate(),render:i=>t==="user"?["",`${Uc}${St("user",n)}`,...o.render(i)]:[St("assistant"),...o.render(i)]}}async function xi(t){let{client:e,config:n}=t,r=new Pc,o=new Nc(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new _c,s=new Lc(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new $c(o,Wo),c=mr(n.commands),u=()=>typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,l=t.session,p=t.initialContext,k=t.contextText,x=t.canWrite,b=t.canApprove,O,R,A,z,j=[...t.initialFiles],q=!1,Ce=!1,Mt=!1,Sn=0,We,Tr=0,Ut=!1,_e="",ft,Dt,Ge=[],Ke={turns:0,inputTokens:0,outputTokens:0,tools:0},Bt=new Map,ue,Vi=ut(g=>{if(O){let h=vi($t[Sn%$t.length]??"*");return[ki(`${h} ${O.activity.statusLine(Date.now(),u())}`,g)]}return ue?[ki(`${vi("?")} Waiting for your answer to the question above`,g)]:[]}),Xi=ut(g=>{let h=[Te(n.identity),Nt(x,b),ct(p),Go(l),j.length?`${j.length} file${j.length===1?"":"s"} attached`:"",R!==void 0?"1 message queued":""];return[bi(Uo(g,h,O?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new Fc([{component:s,basis:0,grow:1,minSize:1},{component:Vi,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:Xi,basis:"auto",shrink:0,minSize:1}]));let te=()=>o.requestRender(),L=g=>o.flash(d(g),3e3),Re=g=>{i.addChild(g),te()},D=(g,h=bi)=>{let w=d(g);Re(ut(v=>jc(h(w),Math.max(1,v))))},Wt=(g,h)=>{Re(ut(w=>["",...Mo(g,h,w)]))},Zi=()=>{We||(We=setInterval(()=>{Sn+=1,te()},Mc),We.unref())},En=()=>{We&&clearInterval(We),We=void 0},ze=()=>{q||o.hasOverlay()||o.setFocus(ue??a)},Cr=g=>{A=g;let h=Bt.get(g.id);h&&i.removeChild(h);let w=new vn(o,g,v=>{Bt.delete(g.id),ue===w&&(ue=void 0),i.removeChild(w),ns(v??{questionId:g.id,skipped:!0,answers:[]}),ze()});Bt.set(g.id,w),ue=w,Re(w)},Gt=g=>{i.clear(),Bt.clear(),ue=void 0,l=g,A=void 0,z=void 0,Ge=[],_e="";let h={version:t.version,workspace:Te(n.identity),session:g,access:Nt(x,b),context:p};Re(ut(v=>gi(h,v)));let w;for(let v of g.messages){Re(Ii(v.role,v.content,v.authorName,e.endpoint)),v.role==="assistant"&&(_e=v.content),v.question&&(w=v.question),v.questionResponse&&(D("A stored response was recorded for this question."),w?.id===v.questionResponse.questionId&&(w=void 0));for(let I of v.files??[])Ge.some(_=>_.fileId===I.fileId)||Ge.push(I),D(`File: ${I.filename} (${I.mediaType}, ${U(I.sizeBytes)}) \xB7 anyforge oracle download ${g.sessionId} ${I.fileId} --output .`)}w&&Cr(w),ze(),_t(g.sessionId,e.endpoint,n.identity?.companyId)},_r,es=new Promise(g=>{_r=g}),Kt=()=>{q||(q=!0,En(),O?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),_r())},Tn=async()=>{let g=O;if(!g||g.cancelling)return;g.cancelling=!0,g.activity.setPhase("cancelling",Date.now()),te();let{streamId:h,requestId:w}=g;g.controller.abort(new Error("Turn cancelled by user."));let v;if(h)try{v=it(await e.cancelTurn(l.sessionId,h))}catch(I){v=`Could not confirm server cancellation: ${Q(I)}`}else if(w)try{v=it(await e.cancelRequest(l.sessionId,w))}catch(I){v=`Could not confirm server cancellation by request id: ${Q(I)}`}else v="The turn had not reached the server; nothing was sent.";g.activity.note("info",v),te()},He=async g=>{if(O||q)return;if(g.kind==="submit"&&g.response){let $=A;if(!$||$.id!==g.response.questionId){L("That question is no longer active. Resume the session to refresh it.");return}D(Dc($,g.response)),A=void 0}else g.kind==="submit"&&Re(Ii("user",g.text));let h=l.sessionId,w=new wn(Date.now(),h),v=new yn(w,{expanded:()=>Mt,frame:()=>Sn,linkOrigin:e.endpoint}),I={activity:w,view:v,controller:new AbortController,cancelling:!1};O=I,Re(v),Zi();let _=new Ue,H=$=>{w.apply($,Date.now()),$.type==="question"&&(Cr(ur($)),ze()),te()},$e={onEvent:H,onStream:$=>{I.streamId=$},onResponse:()=>{w.phase==="sending"&&w.setPhase("preparing",Date.now())},onActivity:()=>w.touch(Date.now())},ne="error";try{if(g.kind==="replay"){_.streamId=g.streamId,I.streamId=g.streamId,w.setPhase("thinking",Date.now());let $=await lr(e,h,_,async se=>{_.accept(se)&&H(se)},I.controller.signal,$e.onActivity);ne=Ct(h,$).status}else{let $=g.response?[]:j.splice(0),se=await gn(e,h,$,(Cn,ps)=>{w.setUploading(Cn,ps,Date.now()),te()});I.controller.signal.throwIfAborted(),w.setPhase("sending",Date.now());let zt=Sc();I.requestId=zt;let ds={requestId:zt,text:g.response?"":g.text,readOnly:!x,...b?{allowApprove:!0}:{},...p?{context:p}:{},...k?{contextText:k}:{},...g.response?{questionResponse:g.response}:{},...se.length?{attachments:se.map(Cn=>({fileId:Cn.fileId}))}:{}},us=await mn(e,h,ds,$e,I.controller.signal,_);ne=Ct(h,us).status}}catch($){if(I.controller.signal.aborted)ne="cancelled";else{ne="error";let se=$ instanceof f&&$.hint?` ${d($.hint)}`:"";w.note("error",`${Q($)}${se}`)}}finally{w.finish(ne,Date.now()),O=void 0,En(),q||(Ce=ne==="cancelled"),ft=w,w.answer.trim()&&(_e=w.answer),w.done?.servedBy&&(Dt=w.done.servedBy);let $=De(w.done?.tokens);Ke.turns+=1,Ke.tools+=w.toolCount,Ke.inputTokens+=$?.inputTokens??0,Ke.outputTokens+=$?.outputTokens??0;for(let se of w.files)Ge.some(zt=>zt.fileId===se.fileId)||Ge.push(se);te()}if(!q){if(I.streamId&&ne!=="cancelled"){let $=await e.getSession(h).catch(()=>{});$&&$.sessionId===l.sessionId&&(l=$)}ts(ne)}},ts=g=>{if(!(q||O)){if(z){let h=z;z=void 0,He({kind:"submit",text:"",response:h});return}if(R!==void 0){let h=R;if(R=void 0,g==="complete"&&!ue){He({kind:"submit",text:h});return}a.getText()||a.setText(h),L("Your queued message is back in the input; press Enter to send it.")}ze(),te()}},ns=g=>{if(O){z=g,L("Answer saved; Oracle continues once the current turn settles.");return}He({kind:"submit",text:"",response:g})},$r=async g=>{try{let h=await e.getSession(g);Gt(h),h.activeStreamId&&He({kind:"replay",streamId:h.activeStreamId}),L(`Resumed ${h.title||h.sessionId}.`)}catch(h){D(Q(h),dt)}},rs=async()=>{try{let g=await e.listSessions();if(!g.length){L("No saved conversations to resume.");return}let h=new Ri(g.map(_=>({value:_.sessionId,label:_.title,description:ge(_)})),Math.min(12,g.length),Ze),w=await pn(e.endpoint,n.identity?.companyId),v=w?g.findIndex(_=>_.sessionId===w):-1;v>=0&&h.setSelectedIndex(v);let I=o.showOverlay(h,{width:"85%",maxHeight:"80%",anchor:"center"});h.onSelect=_=>{I.hide(),$r(_.value)},h.onCancel=()=>{I.hide(),ze()},I.focus()}catch(g){D(Q(g),dt)}},Pr=async g=>{if(g&&(!p||p.kind!=="program"&&p.kind!=="initiative")){L("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let h=await e.createSession(st(p,g));Gt(h),L(`Started a new conversation \xB7 ${ge(h)}.`)}catch(h){D(Q(h),dt)}},Lr=async(g,h)=>{let w=d(ee(h));if(h.companyId&&h.companyId===n.identity?.companyId){L(`Already in ${w}.`);return}Ut=!0;try{L(`Connecting to ${w}...`);let v=await g.connect(h),I=await v.client.createSession(st(void 0,!1));e=v.client,n=v.config,c=mr(n.commands),a.setAutocompleteProvider(gr(c,process.cwd()));let _=e.scopes.has("write")&&n.capabilities?.write===!0,H=e.scopes.has("approve")&&n.capabilities?.approve===!0,$e=x&&!_||b&&!H;x&&!_&&(x=!1),(!x||!H)&&(b=!1);let ne=p!==void 0;p=void 0,Dt=void 0,ft=void 0,Gt(I),D(`Switched to ${Te(n.identity)||w}. This is a new conversation in that workspace.${ne?" Context was cleared because its id belongs to the previous workspace.":""}`),$e&&D(`Access here is ${Nt(x,b)}: this workspace's login or your role there does not allow more.`,Cc)}catch(v){let I=v instanceof f&&v.hint?` ${d(v.hint)}`:"";D(`Could not switch to ${w}: ${Q(v)}${I}`,dt)}finally{Ut=!1}},os=async(g,h)=>{let w=n.identity?.companyId,v=new Ri(h.map(H=>({value:H.clientId,label:ee(H),description:[H.companyId,H.scopes.join(", "),H.companyId===w?"current":""].filter(Boolean).join(" \xB7 ")})),Math.min(12,h.length),Ze),I=h.findIndex(H=>H.companyId===w);I>=0&&v.setSelectedIndex(I);let _=o.showOverlay(v,{width:"85%",maxHeight:"80%",anchor:"center"});v.onSelect=H=>{_.hide();let $e=h.find(ne=>ne.clientId===H.value);$e&&Lr(g,$e)},v.onCancel=()=>{_.hide(),ze()},_.focus()},is=async g=>{let h=t.workspaces;if(!h){D(`This terminal signs in with ANYFORGE_API_TOKEN, which is bound to ${Te(n.identity)||"one workspace"}. To switch workspaces, unset it and sign in with \`anyforge oracle login --workspace <name>\`.`);return}let w=await h.list();if(g){let v;try{v=Me(w,g)}catch(I){let _=I instanceof f&&I.hint?` ${d(I.hint)}`:"";D(`${Q(I)}${_}`,dt);return}await Lr(h,v);return}if(w.length<=1){D(`${Te(n.identity)||"This workspace"} is the only saved workspace. To add another, run \`anyforge oracle login --workspace <name>\` in another terminal, then use /workspace here.`);return}await os(h,w)},ss=g=>({session:l,write:x,approve:b,grantScopes:[...e.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...p?{context:p}:{},...k?{contextText:k}:{},...n.model?{model:n.model}:{},lastServedBy:Dt,...ft?{lastTurn:ft}:{},totals:{...Ke},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},...g!==void 0?{savedWorkspaces:g}:{},endpoint:e.endpoint,version:t.version,pendingFiles:j.map(h=>Oi(h))}),as=async()=>{if(!_e.trim()){L("There is no answer to copy yet.");return}try{let g=qc();g?.setText?await g.setText(_e):r.write(`\x1B]52;c;${Buffer.from(_e,"utf8").toString("base64")}\x07`),L(`Copied the last answer (${_e.length} characters).`)}catch(g){L(`Could not copy: ${Q(g)}`)}},cs=async(g,h,w)=>{if(g.idleOnly&&Ut){L("Wait for the workspace switch to finish.");return}if(g.idleOnly&&O){L(`Wait for Oracle to finish, or press Esc, before /${g.name}.`);return}switch(g.name){case"help":Re(ut(v=>["",...hi({server:c,canApprove:b}).flatMap(I=>[Tc(I.title),...tr(I.rows,v)])]));return;case"status":{let v=await t.workspaces?.list().then(I=>I.length).catch(()=>{});Wt("Status",wi(ss(v)));return}case"workspace":await is(w);return;case"model":Wt("Model",hr({...n.model?{model:n.model}:{},lastServedBy:Dt}));return;case"usage":Wt("Usage",[...yr(ft),...wr(Ke)]);return;case"files":Wt("Generated files",yi(l.sessionId,Ge));return;case"copy":await as();return;case"exit":Kt();return;case"new":if(w&&w!=="shared"){L("Usage: /new or /new shared");return}await Pr(w==="shared");return;case"clear":await Pr(!1);return;case"resume":w?await $r(w):await rs();return;case"context":{if(!w){D(`Context: ${ct(p)}${k?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(w==="clear")p=void 0;else{let[v,I,..._]=h;if(!["program","initiative","codebase"].includes(v??"")||!I||_.length){L("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}p={kind:v,id:I}}D(`Context for your next message: ${ct(p)}.`);return}case"attach":{if(!w){L("Usage: /attach <file path>");return}let v=await Ec(w).catch(()=>{});if(!v?.isFile()){L(`Not a readable file: ${w}`);return}j.push(w),D(`Attached ${Oi(w)} (${U(v.size)}). It uploads with your next message.`);return}}},Nr=g=>{let h=g.trim();if(!h)return;a.addToHistory(h);let w=pi(h,c);if(w?.kind==="local"){cs(w.command,w.args,w.arg).catch(v=>D(Q(v),dt));return}if(w?.kind==="unknown"){a.setText(h),L(`Unknown command /${w.name}. Type /help to see the commands.`);return}if(Ut){a.setText(h),L("Switching workspace; send your message once it has opened.");return}if(O){let v=R!==void 0;R=h,L(v?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),te();return}He({kind:"submit",text:h})},ls=o.addInputListener(g=>{if(bn(g,"ctrl+c")){if(O)return Tn(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),te(),{consume:!0};let h=Date.now();return h-Tr<=Ai?Kt():(Tr=h,o.flash("Press Ctrl+C again to exit",Ai)),{consume:!0}}if(bn(g,"escape")){let h=ue!==void 0&&o.getFocusedComponent()===ue;return O&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!h?(Tn(),{consume:!0}):void 0}if(bn(g,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(Kt(),{consume:!0}):void 0;if(bn(g,"ctrl+o"))return Mt=!Mt,L(Mt?"Showing tool activity":"Hiding tool activity"),te(),{consume:!0}}),Fr=()=>{let g=!!O;Tn().finally(()=>{g&&(Ce=!0),Kt()})};process.on("SIGINT",Fr),a.onSubmit=Nr,a.onChange=()=>te(),a.setAutocompleteProvider(gr(c,process.cwd())),Gt(t.session),o.start(),l.activeStreamId&&He({kind:"replay",streamId:l.activeStreamId}),t.initialPrompt&&Nr(t.initialPrompt),await es,ls(),process.off("SIGINT",Fr),En(),O?.controller.abort(),await r.drainInput().catch(()=>{}),Ce&&(process.exitCode=130)}function Dc(t,e){if(e.skipped)return"Skipped the optional Oracle question.";let n=[];for(let r of e.answers){let o=t.questions.find(i=>i.id===r.questionId);for(let i of r.optionIds){let s=o?.options.find(a=>a.id===i);s&&n.push(s.label)}r.customText&&n.push(r.customText)}return`You answered: ${n.map(d).join("; ")||"no options selected"}`}import{createHash as Bc,randomBytes as Si,timingSafeEqual as Wc}from"node:crypto";import{createServer as Gc}from"node:http";import Kc from"open";var zc=6e4,Hc=5*6e4,Rn=new Map;async function vr(t){let e=Ee(t.endpoint),n=await qe(e),r=["read"];t.write&&r.push("write"),t.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=Si(32).toString("base64url"),i=await Vc(o);try{let s={client_name:"AnyForge CLI",redirect_uris:[i.redirectUri],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"},a=await Xc(n.oauth.registration,s);if(typeof a.client_id!="string"||!a.client_id)throw new f("OAuth registration did not return a client id.",m.API_ERROR);let c=Si(32).toString("base64url"),u=Bc("sha256").update(c).digest("base64url"),l={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:u,code_challenge_method:"S256",resource:n.resource},p=new URL(n.oauth.authorization);for(let[q,Ce]of Object.entries(l))p.searchParams.set(q,String(Ce));let k=t.workspace?.trim();k&&p.searchParams.set(Ho,k),t.onAuthorizationUrl?.(p.toString());try{t.openBrowser?await t.openBrowser(p.toString()):await Kc(p.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
267
+ ${p.toString()}
268
+ `)}let x=await i.wait();if(!Fi(x.state,o))throw new f("Oracle sign-in callback state did not match; authorization was rejected.",m.API_ERROR);if(x.error)throw new f(`Oracle authorization failed: ${d(x.error)}${x.errorDescription?` (${d(x.errorDescription)})`:""}`,m.API_ERROR);if(!x.code)throw new f("Oracle authorization callback did not include a code.",m.API_ERROR);let b={client_id:a.client_id,grant_type:"authorization_code",code:x.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},O=await Mi(n.oauth.token,b);ji(O);let R=qi(O.scope);if(!R.includes("read")||R.some(q=>!r.includes(q)))throw await An(n.oauth.revocation,a.client_id,O.access_token,O.refresh_token).catch(()=>{}),new f("The granted Oracle scopes are invalid for this request.",m.API_ERROR);let A=await qe(e,fetch,O.access_token).then(q=>q.identity).catch(()=>{}),z={endpoint:e,...Ti(A),clientId:a.client_id,redirectUri:i.redirectUri,accessToken:O.access_token,refreshToken:O.refresh_token,expiresAt:Date.now()+O.expires_in*1e3,scopes:R},j=await dn(q=>ei(q,z));return j&&await An(n.oauth.revocation,j.clientId,j.accessToken,j.refreshToken).catch(()=>{}),z}finally{await i.close()}}function Ti(t){return t?{companyId:t.companyId,...t.companyName?{companyName:t.companyName}:{},uid:t.uid}:{}}async function Ci(t={}){if(t.workspace&&!t.all){let n=Ft(await Z(),t.endpointOverride);n&&await br(n)}let e=await fn(async()=>{let n=await Z(),r=[];if(t.all)r=[...n.logins];else{let s=Ft(n,t.endpointOverride);t.workspace?r=[Me(s?ye(n,s):[],t.workspace)]:s&&(r=[un(n,s)].filter(a=>!!a))}let o=[],i;for(let s of r){try{await _i(s)}catch(a){o.push({login:s,error:a})}i=sr(n,s)??i}return await Tt(n),{removed:r,failures:o,...i&&!t.all?{nowActive:i}:{}}});if(e.failures.length){let n=e.failures.map(({login:r,error:o})=>{let i=o instanceof Error?d(o.message):"unknown error";return e.failures.length>1||t.all?`${d(ee(r))}: ${i}`:i});throw new f(`Local Oracle credentials were cleared, but server revocation failed for ${e.failures.length===1?"one login":`${e.failures.length} logins`}: ${n.join("; ")}`,m.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire these access tokens automatically.")}return{removed:e.removed,...e.nowActive?{nowActive:e.nowActive}:{}}}async function _i(t){let e=await qe(t.endpoint);await An(e.oauth.revocation,t.clientId,t.accessToken,t.refreshToken)}function Ft(t,e){let n=e||process.env.ANYFORGE_ENDPOINT;return n?Ee(n):t.endpoint}function $i(){return new y("ANYFORGE_API_TOKEN is set, so Oracle uses that key and its one workspace; saved Oracle logins are not used.","Unset ANYFORGE_API_TOKEN to choose between your saved workspaces.")}async function Pi(t,e){let n=t||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN){if(e)throw $i();return Ei(n)}let r=await Z(),o=Ft(r,n);if(e)return qt(await Yc(o,e));let i=o?un(r,o):void 0;if(i)return qt(i);try{return await Ei(n)}catch(s){throw r.logins.length&&n?new ce:s instanceof ce?new ce:s}}async function Yc(t,e){if(!t)return Me([],e);let n=await In(t);return Me(n,e)}function qt(t){return{endpoint:t.endpoint,accessToken:t.accessToken,scopes:t.scopes.filter(Rr),source:"oauth",getAccessToken:async e=>Jc(t.endpoint,t.clientId,e),onIdentity:async e=>{if(t.companyId===e.companyId&&(e.companyName===void 0||t.companyName===e.companyName)&&t.uid===e.uid)return;let r=await dn(i=>ti(i,t.endpoint,t.clientId,e));Object.assign(t,Ti(e));let o=r.duplicate;o&&await _i(o).catch(()=>{})}}}async function In(t){return await br(t),ye(await Z(),t)}async function br(t){let e=ye(await Z(),t).filter(n=>!n.companyId);for(let n of e)await new je(qt(n)).config().catch(()=>{})}async function Li(t){let e=Ft(await Z(),t);if(!e)return{logins:[]};let n=await In(e),r=un(await Z(),e);return{endpoint:e,logins:n,...r?{active:r}:{}}}async function Ni(t,e){if(process.env.ANYFORGE_API_TOKEN)throw $i();let n=Ft(await Z(),t);return n&&await br(n),dn(r=>{let o=Me(n?ye(r,n):[],e);return r.active[o.endpoint]=o.clientId,r.endpoint=o.endpoint,o})}async function Ei(t){let e=await Ie(t),r=(await ht({apiKey:e.apiKey,endpoint:e.endpoint})).scopes.filter(Rr);return{endpoint:e.endpoint,accessToken:e.apiKey,scopes:r,source:"control"}}async function Jc(t,e,n){let r=Ee(t),o=`${r}
269
+ ${e}`,i=Rn.get(o);if(i)return i;let s=fn(()=>Qc(r,e,n));Rn.set(o,s);try{return await s}finally{Rn.get(o)===s&&Rn.delete(o)}}async function Qc(t,e,n){let r=await Z(),o=r.logins.find(u=>u.endpoint===t&&u.clientId===e);if(!o)throw new ce;if(o.expiresAt>Date.now()+zc&&(!n||o.accessToken!==n))return o.accessToken;let i=async()=>{sr(r,o),await Tt(r)},s=await qe(o.endpoint),a;try{let u={client_id:o.clientId,grant_type:"refresh_token",refresh_token:o.refreshToken,resource:s.resource};a=await Mi(s.oauth.token,u)}catch(u){throw u instanceof kn&&["invalid_grant","invalid_client","invalid_target"].includes(u.code)?(await i(),new ce):u}ji(a);let c;try{c=qi(a.scope)}catch(u){throw await i(),u}if(c.some(u=>!o.scopes.includes(u)))throw await An(s.oauth.revocation,o.clientId,a.access_token,a.refresh_token),await i(),new f("Oracle refresh attempted to widen the saved grant; credentials were cleared.",m.API_ERROR);return o.accessToken=a.access_token,o.refreshToken=a.refresh_token,o.expiresAt=Date.now()+a.expires_in*1e3,o.scopes=c,await Tt(r),o.accessToken}var kn=class extends f{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?m.NO_CREDENTIALS:m.API_ERROR);this.code=n;this.name="OAuthResponseError"}};async function Vc(t){let e,n,r=!1,o=new Promise((c,u)=>{e=c,n=u});o.catch(()=>{});let i=Gc((c,u)=>{if((c.url?.length??0)>8192){u.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let l=c.url??"/";if(!l.startsWith("/callback")||l.startsWith("//")){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let p=new URL(l,"http://127.0.0.1");if(c.method!=="GET"||p.pathname!=="/callback"){u.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let k=p.searchParams.get("code")?.slice(0,2048)??"",x=p.searchParams.get("state")?.slice(0,256)??"",b=p.searchParams.get("error")?.slice(0,256)??void 0,O=p.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!x){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!Fi(x,t)){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(r){u.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}r=!0,u.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'"}).end('<!doctype html><meta charset="utf-8"><title>AnyForge Oracle</title><p>Sign-in response received. You may close this tab.</p>'),e({code:k,state:x,...b?{error:b}:{},...O?{errorDescription:O}:{}})});await new Promise((c,u)=>{i.once("error",u),i.listen(0,"127.0.0.1",()=>{i.removeListener("error",u),c()})});let s=i.address();if(!s||typeof s=="string")throw new f("Could not bind an Oracle sign-in callback port.",m.FAILURE);let a=setTimeout(()=>{r||(r=!0,n(new f("Oracle sign-in timed out before the browser returned.",m.FAILURE)))},Hc);return a.unref(),{redirectUri:`http://127.0.0.1:${s.port}/callback`,wait:()=>o,close:async()=>{clearTimeout(a),i.listening&&(i.closeAllConnections(),await new Promise(c=>i.close(()=>c())))}}}function Fi(t,e){let n=Buffer.from(t),r=Buffer.from(e);return n.length===r.length&&Wc(n,r)}function qi(t){let e=t.split(/[\s+]+/).filter(Boolean);if(!e.every(Rr))throw new f("OAuth server returned an unknown Oracle scope.",m.API_ERROR);let n=[...new Set(e)];if(!n.includes("read"))throw new f("Oracle OAuth grant is missing the required read scope.",m.API_ERROR);return n}function Rr(t){return t==="read"||t==="write"||t==="approve"}function ji(t){if(!t||typeof t.access_token!="string"||!t.access_token||typeof t.refresh_token!="string"||!t.refresh_token||typeof t.token_type!="string"||t.token_type.toLowerCase()!=="bearer"||typeof t.expires_in!="number"||!Number.isFinite(t.expires_in)||t.expires_in<=0||typeof t.scope!="string")throw new f("OAuth token response did not match the supported format.",m.API_ERROR)}async function Xc(t,e){return Ui(t,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)})}async function Mi(t,e){return Ui(t,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(Object.entries(e).map(([n,r])=>[n,String(r)])).toString()})}async function Ui(t,e){let n;try{n=await fetch(t,{...e,redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(o){throw new f(`OAuth request failed: ${d(o instanceof Error?o.message:String(o))}`,m.FAILURE)}let r=null;try{r=await n.json()}catch{}if(!n.ok){let o=r&&typeof r=="object"?r:{},i=typeof o.error=="string"?o.error:`http_${n.status}`,s=typeof o.error_description=="string"?d(o.error_description):i;throw new kn(i,s,n.status)}if(!r||typeof r!="object"||Array.isArray(r))throw new f(`OAuth endpoint returned invalid JSON (${n.status}).`,m.API_ERROR);return r}async function An(t,e,n,r){let o=async i=>{let s=await fetch(t,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:e,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=d(c.error_description))}catch{}throw new f(`OAuth token revocation failed: ${a}`,m.API_ERROR)}};await o(r),n!==r&&await o(n)}var pl=1048576,fl=25*1048576;async function Hi(t){let[e,...n]=t.positional,r=["exec","sessions","resume","login","logout","download","workspaces","use"].includes(e??""),o=pt(t.flags,"workspace")?.trim()||void 0,i=r?void 0:t.positional.join(" ");if(M(t.flags,"read-only")&&(M(t.flags,"write")||M(t.flags,"approve")))throw new y("--read-only cannot be combined with --write or --approve.");if(!r&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(e==="login"){if(n.length)throw new y("oracle login does not accept positional arguments.");let b=await vr({endpoint:t.endpointOverride??t.endpoint,write:M(t.flags,"write"),approve:M(t.flags,"approve"),...o?{workspace:o}:{}}),R=[M(t.flags,"write")?"write":void 0,M(t.flags,"approve")?"approve":void 0].filter(A=>!!A).filter(A=>!b.scopes.includes(A));process.stdout.write(`${Di(b)}
270
+ `),R.length&&process.stderr.write(`This account was granted read only; the server withheld: ${R.join(", ")}.
271
+ `),await gl(b,o);return}if(e==="logout"){if(n.length)throw new y("oracle logout does not accept positional arguments.");let b=M(t.flags,"all");if(b&&o)throw new y("Choose either --workspace or --all.");let O=await Ci({...t.endpointOverride?{endpointOverride:t.endpointOverride}:{},...o?{workspace:o}:{},all:b});if(!O.removed.length){process.stdout.write(`No saved Oracle login.
272
+ `);return}let R=O.removed.map(A=>d(ee(A))).join(", ");process.stdout.write(`Logged out of ${R}; ${O.removed.length===1?"its access was":"their access was"} revoked.
273
+ `),O.nowActive&&process.stdout.write(`Active workspace is now ${d(ee(O.nowActive))}.
274
+ `);return}if(e==="workspaces"){if(n.length)throw new y("oracle workspaces does not accept positional arguments.");await wl(t.endpointOverride,t.flags.json===!0);return}if(e==="use"){let b=n.join(" ").trim();if(!b)throw new y("oracle use needs a workspace name or id.","Run `anyforge oracle workspaces` to list your saved workspaces.");let O=await Ni(t.endpointOverride,b);process.stdout.write(`Now using ${d(ee(O))} (${O.scopes.join(", ")}) at ${O.endpoint}.
275
+ `);return}let s;try{s=await Gi(t.endpointOverride,o)}catch(b){if(!r&&b instanceof f&&b.exitCode===m.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let O=(await import("prompts")).default;if((await O({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw b;let A=await vr({endpoint:t.endpointOverride??t.endpoint,...o?{workspace:o}:{}});process.stderr.write(`${Di(A)}
276
+ `),s=await Gi(t.endpointOverride)}else throw b}if(e==="sessions"){if(n.length)throw new y("oracle sessions does not accept positional arguments.");let b=t.flags.json===!0;b||await Bi(await s.config().catch(()=>{}));let O=await s.listSessions();Ol(O,b);return}if(e==="download"){await kl(s,n,t.flags);return}if(e==="exec"){if(M(t.flags,"write")||M(t.flags,"approve"))throw new y("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(t.flags.json===!0&&M(t.flags,"stream-json"))throw new y("Choose either --json or --stream-json.");let b=await yl(n.join(" ")),O=await s.config();Ir(s,O),t.flags.json!==!0&&!M(t.flags,"stream-json")&&await Bi(O),Ki(pt(t.flags,"context"));let R=or(t.flags),A=await s.createSession(st(R,!1));await _t(A.sessionId,s.endpoint,O.identity?.companyId);let z=await gn(s,A.sessionId,Wi(t.flags),(q,Ce)=>V(process.stderr,`Uploading explicit attachment ${q} (${U(Ce)}).
277
+ `)),j={requestId:tl(),text:b,readOnly:!0,...R?{context:R}:{},...pt(t.flags,"context")?{contextText:pt(t.flags,"context")}:{},...z.length?{attachments:z.map(q=>({fileId:q.fileId}))}:{}};await bl(s,A.sessionId,j,{json:t.flags.json===!0,streamJson:M(t.flags,"stream-json"),config:O});return}if(e==="resume"&&n.length>1)throw new y("oracle resume accepts at most one session id.");if(e==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("oracle resume is interactive and needs a terminal.","Use `anyforge oracle sessions` to list sessions, or run `anyforge oracle exec` for a new scripted turn.");let a=await s.config();Ir(s,a);let c=or(t.flags),u=pt(t.flags,"context");Ki(u);let l=M(t.flags,"shared"),p=M(t.flags,"write")||M(t.flags,"approve");if(p&&(!s.scopes.has("write")||a.capabilities?.write!==!0))throw new f("This Oracle grant or current workspace role does not allow write actions.",m.API_ERROR);if(M(t.flags,"approve")&&(!s.scopes.has("approve")||a.capabilities?.approve!==!0))throw new f("This Oracle grant or current workspace role does not allow approval actions.",m.API_ERROR);if(l&&(!c||c.kind!=="program"&&c.kind!=="initiative"))throw new y("--shared requires --program or --initiative.");let k;if(e==="resume"){let O=(n[0]||void 0)??await vl(await s.listSessions(),await pn(s.endpoint,a.identity?.companyId));k=await s.getSession(O)}else k=await s.createSession(st(c,l));await _t(k.sessionId,s.endpoint,a.identity?.companyId);let x=await Promise.resolve().then(()=>(Ar(),kr));await xi({version:x.default.version,client:s,config:a,session:k,initialPrompt:i,initialContext:c,contextText:u,shared:l,canWrite:p,canApprove:M(t.flags,"approve"),initialFiles:Wi(t.flags),...s.source==="oauth"?{workspaces:ml(s.endpoint)}:{}})}function ml(t){return{list:()=>In(t),connect:async e=>{let n=new je(qt(e)),r=await n.config();return Ir(n,r),{client:n,config:r}}}}function Di(t){let e=t.scopes.join(", ");return t.companyId?`Connected to ${d(ee(t))} (${e}) at ${t.endpoint}.`:`Connected to ${t.endpoint} (${e}). The server did not say which workspace; \`anyforge oracle workspaces\` shows it once it does.`}async function gl(t,e){let n=d(ee(t));e&&t.companyId&&!hl(t,e)&&process.stderr.write(`You asked for "${d(e)}", but ${n} was chosen on the consent page, so this login is for ${n}.
278
+ `);let r=ye(await Z(),t.endpoint).length;r>1&&process.stderr.write(`${n} is now your active workspace (${r} saved). List them with \`anyforge oracle workspaces\`; switch with \`anyforge oracle use <name>\`.
279
+ `)}function hl(t,e){return t.companyId===e||t.companyName?.toLowerCase()===e.toLowerCase()}async function Bi(t){let e=Te(t?.identity);e&&await V(process.stderr,`${ve(`Workspace: ${e}`)}
280
+ `)}async function wl(t,e){let n=await Li(t),r=n.logins.map(o=>({name:o.companyName??null,companyId:o.companyId??null,endpoint:o.endpoint,scopes:o.scopes,active:o.clientId===n.active?.clientId}));if(e)process.stdout.write(`${JSON.stringify(r,null,2)}
281
+ `);else if(!r.length)process.stdout.write("No saved Oracle logins. Run `anyforge oracle login` to add one.\n");else{process.stdout.write(`${ve(`Oracle workspaces saved for ${n.endpoint??"this endpoint"}:`)}
282
+ `);for(let o of n.logins){let i=o.clientId===n.active?.clientId,s=d(ee(o)),a=o.companyId&&o.companyName?d(o.companyId):"",c=[i?Sr(`* ${s}`):` ${s}`,a?ve(a):"",ve(o.scopes.join(", ")),i?zi("active"):""];process.stdout.write(`${c.filter(Boolean).join(" ")}
283
+ `)}}process.env.ANYFORGE_API_TOKEN&&process.stderr.write(`ANYFORGE_API_TOKEN is set, so Oracle commands use that key and its workspace instead of these logins.
284
+ `)}function M(t,e){return t[e]===!0}function pt(t,e){let n=t[e];return typeof n=="string"?n:void 0}function Wi(t){let e=t.file;return typeof e=="string"?[e]:Array.isArray(e)?e:[]}async function Gi(t,e){try{return new je(await Pi(t,e))}catch(n){throw n instanceof f&&n.exitCode===m.NO_CREDENTIALS?new f("Not authenticated for the hosted Oracle.",m.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):n}}function Ir(t,e){if(!t.scopes.has("read")||e.capabilities?.read===!1)throw new f("This credential does not have Oracle read access.",m.API_ERROR)}function Ki(t){if(t&&Buffer.byteLength(t,"utf8")>ar)throw new y(`--context must be ${ar/1024} KiB or less.`)}async function yl(t){let e=t.trim();if(process.stdin.isTTY){if(e)return e;throw new y("oracle exec requires a prompt when stdin is a terminal.",'Example: anyforge oracle exec "summarize this program"')}let n=[],r=0;for await(let i of process.stdin){let s=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=s.byteLength,r>pl)throw new y("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!e&&!o)throw new y("oracle exec needs a prompt in argv or piped stdin.");return[e,o].filter(Boolean).join(`
285
+
286
+ `)}function Ol(t,e){if(e){process.stdout.write(`${JSON.stringify(t,null,2)}
276
287
  `);return}if(!t.length){process.stdout.write(`No Oracle sessions are available.
277
- `);return}for(let n of t){let r=ue(n);process.stdout.write(`${fi(n.sessionId)} ${u(n.title)} ${At(r)}
278
- `)}}async function _c(t,e){if(!t.length)throw new f("No accessible Oracle sessions are available.",m.API_ERROR);return new Promise((n,r)=>{let o=new Ac,i=new Sc(o),s=new xc(fi("Resume an Oracle session")),a=new kc(t.map(d=>({value:d.sessionId,label:d.title,description:ue(d)})),12,pt),c=e?t.findIndex(d=>d.sessionId===e):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=d=>{l(),n(d.value)},a.onCancel=()=>{l(),r(new f("Session selection cancelled.",m.FAILURE))};let p=()=>{l(),r(new f("Session selection interrupted.",m.INTERRUPTED))},l=()=>{process.off("SIGINT",p),i.stop()};process.once("SIGINT",p),i.start()})}async function J(t,e){t.write(e)||await new Promise(n=>t.once("drain",n))}async function $c(t,e,n,r){let o=new Ce,i=!1,s,a=new AbortController,c=()=>s??=p(),p=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let R=await t.cancelTurn(e,o.streamId);await J(process.stderr,`${He(R)}
279
- `)}catch(R){await J(process.stderr,`Could not confirm server cancellation: ${Q(R)}
280
- `)}else try{let R=await t.cancelRequest(e,n.requestId);await J(process.stderr,`${He(R)}
281
- `)}catch(R){await J(process.stderr,`Could not confirm server cancellation by request id: ${Q(R)}
282
- `)}},l=()=>{c().catch(()=>{})};process.on("SIGINT",l);let d=async R=>J(process.stdout,`${JSON.stringify(de(R))}
283
- `),O=new ar(e),x=-1,k=async R=>{if(r.streamJson){if(R.idx<=x)return;R.type!=="finalizing"&&(x=R.idx),await d({...R,sessionId:e})}else await O.emit(R)},b;try{b=await Yt(t,e,n,{onEvent:k},a.signal,o)}catch(R){if(!i)throw process.off("SIGINT",l),R;b=o.outcome()}finally{process.off("SIGINT",l),s&&await s}let v=ht(e,b);return r.streamJson?await d({protocolVersion:1,type:"result",result:v}):r.json?await J(process.stdout,`${JSON.stringify(v,null,2)}
284
- `):(v.answer&&await J(process.stdout,`${go(v.answer,t.endpoint)}
285
- `),v.status==="awaiting_input"&&await J(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
286
- `),v.status==="interrupted"&&await J(process.stderr,`Oracle turn ended without a complete final answer.
287
- `),v.status==="error"&&v.error&&await J(process.stderr,`Oracle error: ${u(v.error)}
288
- `),(v.servedBy||v.usage||v.rounds!==void 0)&&await J(process.stderr,Pc(v.servedBy,v.usage,v.rounds))),i?process.exitCode=130:v.status==="error"?process.exitCode=m.API_ERROR:v.status==="interrupted"&&(process.exitCode=m.FAILURE),v}var ar=class{constructor(e){this.sessionId=e}labels=new Map;announced=new Set;async emit(e){let n=this.describe(e);n&&await J(process.stderr,`${n}
289
- `)}describe(e){switch(e.type){case"tool_call":{if(Me(e.name))return"";let n=I(typeof e.label=="string"?e.label:Gt(I(e.name,240)),120),r=typeof e.id=="string"?e.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${At(typeof e.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${Rc(n)}`}case"tool_result":{if(e.ok!==!1)return"";let n=typeof e.toolUseId=="string"?this.labels.get(e.toolUseId):void 0;return cn(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return cn(`Warning: ${I(e.message,500)}`);case"navigator_file_error":return cn(`Could not generate ${I(e.filename,200)}: ${I(e.error,500)}`);case"navigator_file_created":{let n=Ke(e.file);return At(`Generated ${n.filename} (${N(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=I(e.from,120),r=I(e.to,120);return At(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(e.notices)?e.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${cn("Attachment")} ${I(r.name,160)}: ${I(r.message,500)}`}).join(`
290
- `):"";default:return""}}};function Pc(t,e,n){let r=[];if(t&&typeof t=="object"){let o=t,i=vt(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(I(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${I(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(I(o.provider,100))}return e?.inputTokens!==void 0||e?.outputTokens!==void 0?r.push(`${e.inputTokens??0} in${e.cachedInputTokens?` (${e.cachedInputTokens} cached)`:""} / ${e.outputTokens??0} out tokens`):e?.totalTokens!==void 0&&r.push(`${e.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${At(r.join(" \xB7 "))}
291
- `:""}async function Lc(t,e,n){if(e.length!==2)throw new y("oracle download needs exactly a session id and file id.");let[r,o]=e;if(!r||!o)throw new y("oracle download needs a session id and file id.");let i=Rt(n,"output");if(!i)throw new y("oracle download requires --output <existing-directory>.");let s=bc(i),a=await wc(s);if(!(await yc(a)).isDirectory())throw new y("--output must point to an existing directory.");let p=await t.download(r,o),l=Nc(Fc(p.headers.get("content-disposition"))),d=vc(a,l),O=await qc(p,Cc),x;try{x=await hc(d,"wx",384),await x.writeFile(O)}catch(k){throw k.code==="EEXIST"?new f(`Refusing to overwrite ${d}.`,m.FAILURE):k}finally{await x?.close()}process.stdout.write(`Downloaded ${u(l)} to ${u(d)} (${N(O.byteLength)}).
292
- `)}function Fc(t){if(!t)return"oracle-file.bin";let e=/filename\*=UTF-8''([^;]+)/i.exec(t)?.[1];if(e)try{return decodeURIComponent(e.replace(/^"|"$/g,""))}catch{return"oracle-file.bin"}let n=/filename="?([^";]+)"?/i.exec(t)?.[1];return n?n.trim():"oracle-file.bin"}function Nc(t){let e=Oc(t.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!e||e==="."||e===".."?"oracle-file.bin":e}async function qc(t,e){if(!t.body)return Buffer.alloc(0);let n=t.body.getReader(),r=[],o=0;try{for(;;){let{value:i,done:s}=await n.read();if(s)break;let a=Buffer.from(i);if(o+=a.byteLength,o>e)throw new f(`Oracle download exceeds the ${N(e)} limit.`,m.API_ERROR);r.push(a)}}catch(i){throw await n.cancel("Oracle download exceeded its byte limit.").catch(()=>{}),i}finally{n.releaseLock()}return Buffer.concat(r)}var wi="https://crew.anyforge.ai",Uc=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output"]),jc=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json"]);function Dc(t){let e={positional:[],flags:{}};for(let n=0;n<t.length;n+=1){let r=t[n];if(!r.startsWith("-")){e.command?e.positional.push(r):e.command=r;continue}let o=r==="-h"?"help":r==="-V"?"version":r==="-f"?"force":r.replace(/^--?/,""),[i,s]=o.includes("=")?[o.slice(0,o.indexOf("=")),o.slice(o.indexOf("=")+1)]:[o,void 0];if(Uc.has(i)){let a=s??t[++n];if(a===void 0)throw new y(`--${i} needs a value.`);if(i==="file"){let c=e.flags.file;e.flags.file=[...typeof c=="string"?[c]:Array.isArray(c)?c:[],a]}else e.flags[i]=a;continue}if(jc.has(i)){e.flags[i]=s===void 0?!0:s!=="false";continue}throw new y(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return e}function he(t,e){if(t===void 0||typeof t=="boolean")return;let n=Number(t);if(!Number.isFinite(n)||n<=0)throw new y(`--${e} must be a positive number, got "${t}".`);return n}function D(t){return typeof t=="string"?t:void 0}function cr(t){return t===!0?!0:void 0}function Bc(){console.log(`
293
- ${B("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
294
-
295
- ${B("USAGE")}
288
+ `);return}for(let n of t){let r=ge(n);process.stdout.write(`${Sr(n.sessionId)} ${d(n.title)} ${ve(r)}
289
+ `)}}async function vl(t,e){if(!t.length)throw new f("No accessible Oracle sessions are available.",m.API_ERROR);return new Promise((n,r)=>{let o=new cl,i=new ul(o),s=new dl(Sr("Resume an Oracle session")),a=new ll(t.map(p=>({value:p.sessionId,label:p.title,description:ge(p)})),12,Ze),c=e?t.findIndex(p=>p.sessionId===e):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=p=>{l(),n(p.value)},a.onCancel=()=>{l(),r(new f("Session selection cancelled.",m.FAILURE))};let u=()=>{l(),r(new f("Session selection interrupted.",m.INTERRUPTED))},l=()=>{process.off("SIGINT",u),i.stop()};process.once("SIGINT",u),i.start()})}async function V(t,e){t.write(e)||await new Promise(n=>t.once("drain",n))}async function bl(t,e,n,r){let o=new Ue,i=!1,s,a=new AbortController,c=()=>s??=u(),u=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let A=await t.cancelTurn(e,o.streamId);await V(process.stderr,`${it(A)}
290
+ `)}catch(A){await V(process.stderr,`Could not confirm server cancellation: ${Q(A)}
291
+ `)}else try{let A=await t.cancelRequest(e,n.requestId);await V(process.stderr,`${it(A)}
292
+ `)}catch(A){await V(process.stderr,`Could not confirm server cancellation by request id: ${Q(A)}
293
+ `)}},l=()=>{c().catch(()=>{})};process.on("SIGINT",l);let p=async A=>V(process.stdout,`${JSON.stringify(me(A))}
294
+ `),k=new xr(e),x=-1,b=async A=>{if(r.streamJson){if(A.idx<=x)return;A.type!=="finalizing"&&(x=A.idx),await p({...A,sessionId:e})}else await k.emit(A)},O;try{O=await mn(t,e,n,{onEvent:b},a.signal,o)}catch(A){if(!i)throw process.off("SIGINT",l),A;O=o.outcome()}finally{process.off("SIGINT",l),s&&await s}let R=Ct(e,O);return r.streamJson?await p({protocolVersion:1,type:"result",result:R}):r.json?await V(process.stdout,`${JSON.stringify(R,null,2)}
295
+ `):(R.answer&&await V(process.stdout,`${lo(R.answer,t.endpoint)}
296
+ `),R.status==="awaiting_input"&&await V(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
297
+ `),R.status==="interrupted"&&await V(process.stderr,`Oracle turn ended without a complete final answer.
298
+ `),R.status==="error"&&R.error&&await V(process.stderr,`Oracle error: ${d(R.error)}
299
+ `),(R.servedBy||R.usage||R.rounds!==void 0)&&await V(process.stderr,Rl(R.servedBy,R.usage,R.rounds))),i?process.exitCode=130:R.status==="error"?process.exitCode=m.API_ERROR:R.status==="interrupted"&&(process.exitCode=m.FAILURE),R}var xr=class{constructor(e){this.sessionId=e}labels=new Map;announced=new Set;async emit(e){let n=this.describe(e);n&&await V(process.stderr,`${n}
300
+ `)}describe(e){switch(e.type){case"tool_call":{if(Ve(e.name))return"";let n=E(typeof e.label=="string"?e.label:on(E(e.name,240)),120),r=typeof e.id=="string"?e.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${ve(typeof e.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${zi(n)}`}case"tool_result":{if(e.ok!==!1)return"";let n=typeof e.toolUseId=="string"?this.labels.get(e.toolUseId):void 0;return xn(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return xn(`Warning: ${E(e.message,500)}`);case"navigator_file_error":return xn(`Could not generate ${E(e.filename,200)}: ${E(e.error,500)}`);case"navigator_file_created":{let n=ot(e.file);return ve(`Generated ${n.filename} (${U(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=E(e.from,120),r=E(e.to,120);return ve(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(e.notices)?e.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${xn("Attachment")} ${E(r.name,160)}: ${E(r.message,500)}`}).join(`
301
+ `):"";default:return""}}};function Rl(t,e,n){let r=[];if(t&&typeof t=="object"){let o=t,i=Pt(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(E(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${E(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(E(o.provider,100))}return e?.inputTokens!==void 0||e?.outputTokens!==void 0?r.push(`${e.inputTokens??0} in${e.cachedInputTokens?` (${e.cachedInputTokens} cached)`:""} / ${e.outputTokens??0} out tokens`):e?.totalTokens!==void 0&&r.push(`${e.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${ve(r.join(" \xB7 "))}
302
+ `:""}async function kl(t,e,n){if(e.length!==2)throw new y("oracle download needs exactly a session id and file id.");let[r,o]=e;if(!r||!o)throw new y("oracle download needs a session id and file id.");let i=pt(n,"output");if(!i)throw new y("oracle download requires --output <existing-directory>.");let s=al(i),a=await rl(s);if(!(await ol(a)).isDirectory())throw new y("--output must point to an existing directory.");let u=await t.download(r,o),l=Il(Al(u.headers.get("content-disposition"))),p=sl(a,l),k=await xl(u,fl),x;try{x=await nl(p,"wx",384),await x.writeFile(k)}catch(b){throw b.code==="EEXIST"?new f(`Refusing to overwrite ${p}.`,m.FAILURE):b}finally{await x?.close()}process.stdout.write(`Downloaded ${d(l)} to ${d(p)} (${U(k.byteLength)}).
303
+ `)}function Al(t){if(!t)return"oracle-file.bin";let e=/filename\*=UTF-8''([^;]+)/i.exec(t)?.[1];if(e)try{return decodeURIComponent(e.replace(/^"|"$/g,""))}catch{return"oracle-file.bin"}let n=/filename="?([^";]+)"?/i.exec(t)?.[1];return n?n.trim():"oracle-file.bin"}function Il(t){let e=il(t.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!e||e==="."||e===".."?"oracle-file.bin":e}async function xl(t,e){if(!t.body)return Buffer.alloc(0);let n=t.body.getReader(),r=[],o=0;try{for(;;){let{value:i,done:s}=await n.read();if(s)break;let a=Buffer.from(i);if(o+=a.byteLength,o>e)throw new f(`Oracle download exceeds the ${U(e)} limit.`,m.API_ERROR);r.push(a)}}catch(i){throw await n.cancel("Oracle download exceeded its byte limit.").catch(()=>{}),i}finally{n.releaseLock()}return Buffer.concat(r)}var Qi="https://crew.anyforge.ai",El=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output","workspace"]),Tl=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json"]);function Cl(t){let e={positional:[],flags:{}};for(let n=0;n<t.length;n+=1){let r=t[n];if(!r.startsWith("-")){e.command?e.positional.push(r):e.command=r;continue}let o=r==="-h"?"help":r==="-V"?"version":r==="-f"?"force":r.replace(/^--?/,""),[i,s]=o.includes("=")?[o.slice(0,o.indexOf("=")),o.slice(o.indexOf("=")+1)]:[o,void 0];if(El.has(i)){let a=s??t[++n];if(a===void 0)throw new y(`--${i} needs a value.`);if(i==="file"){let c=e.flags.file;e.flags.file=[...typeof c=="string"?[c]:Array.isArray(c)?c:[],a]}else e.flags[i]=a;continue}if(Tl.has(i)){e.flags[i]=s===void 0?!0:s!=="false";continue}throw new y(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return e}function be(t,e){if(t===void 0||typeof t=="boolean")return;let n=Number(t);if(!Number.isFinite(n)||n<=0)throw new y(`--${e} must be a positive number, got "${t}".`);return n}function G(t){return typeof t=="string"?t:void 0}function Er(t){return t===!0?!0:void 0}function _l(){console.log(`
304
+ ${K("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
305
+
306
+ ${K("USAGE")}
296
307
  npx @anyforge/control <command> [options]
297
308
 
298
- ${B("SETUP")}
309
+ ${K("SETUP")}
299
310
  init Authorise this device and patch local agent configs
300
311
  whoami Show the company, scopes and endpoint this key acts as
301
- status Check connectivity to the AnyForge proxy
312
+ status Check identity, local setup and recorded activity
302
313
  logout Clear the saved API key and revert patched configs
303
314
  apply-patch [file] Apply a unified diff (file or stdin) via git apply
304
315
 
305
- ${B("SKILLS")}
316
+ ${K("SKILLS")}
306
317
  skill install anyforge-platform
307
318
  Install the portable AnyForge platform guide
308
319
  (--scope project|user, --client agents|claude|codex)
309
320
 
310
- ${B("APPROVALS")} ${kt("(the gate that blocks a human)")}
321
+ ${K("APPROVALS")} ${jt("(the gate that blocks a human)")}
311
322
  approvals List HIL approvals awaiting a decision
312
323
  approve <id> Approve one, optionally with --notes
313
324
  reject <id> Reject one, optionally with --notes
314
325
 
315
- ${B("CREWS")}
326
+ ${K("CREWS")}
316
327
  crews List crews (--active for running/paused only)
317
328
  crew <id> Show one crew, its status and recent output
318
329
  crew start <item> Dispatch a crew on a work item (--profile, --follow)
@@ -320,23 +331,25 @@ ${B("CREWS")}
320
331
  halt <id> Stop a crew
321
332
  resume <id> Resume a paused or halted crew
322
333
 
323
- ${B("WORK & WORKFLOWS")}
334
+ ${K("WORK & WORKFLOWS")}
324
335
  work List work items (--status, --type, --priority, --search).
325
336
  Paged: one page by default, --all walks every page
326
337
  workflows List operator workflows
327
338
  run <id> Dispatch a workflow run, with optional --input JSON
328
339
  ask <question> Ask the Oracle one question
329
340
 
330
- ${B("HOSTED ORACLE")}
341
+ ${K("HOSTED ORACLE")}
331
342
  oracle [prompt] Start an interactive hosted Oracle session
332
343
  oracle exec <text> Submit one read-only turn (--json or --stream-json)
333
344
  oracle resume Resume an Oracle session
334
345
  oracle sessions List Oracle sessions
335
- oracle login Connect an Oracle grant (separate from Control credentials)
336
- oracle logout Revoke and clear the saved Oracle grant
346
+ oracle login Connect an Oracle grant for a workspace (separate from Control credentials)
347
+ oracle workspaces List the workspaces you have signed in to
348
+ oracle use <name> Switch the workspace Oracle commands use
349
+ oracle logout Revoke and clear the active workspace's Oracle grant (--all for every one)
337
350
  oracle --help Show Oracle options and slash commands
338
351
 
339
- ${B("MEASUREMENT")}
352
+ ${K("MEASUREMENT")}
340
353
  backtest-corpus Can this workspace be back-tested? Counts the incidents
341
354
  that could become graded replay cases (--days 30|90|180|365)
342
355
  review-interception Serious findings the reviewer raised on your pull requests,
@@ -344,9 +357,9 @@ ${B("MEASUREMENT")}
344
357
  review-coverage How many recorded pull requests got reviewed, how fast the
345
358
  author heard back, and what a limit stopped (--days 7|30|90|180)
346
359
 
347
- ${B("OPTIONS")}
360
+ ${K("OPTIONS")}
348
361
  --json Print the raw API payload instead of a table
349
- --endpoint <url> Override the base URL (default: ${kt(wi)})
362
+ --endpoint <url> Override the base URL (default: ${jt(Qi)})
350
363
  --limit <n> Page size on list commands (work: 1-200, default 50)
351
364
  --all work: follow the cursor until the backlog is exhausted
352
365
  --notes <text> approve/reject: reviewer notes, recorded in the audit trail
@@ -364,10 +377,10 @@ ${B("OPTIONS")}
364
377
  --help, -h Show this message
365
378
  --version, -V Print CLI version
366
379
 
367
- ${B("EXIT CODES")}
380
+ ${K("EXIT CODES")}
368
381
  0 ok 1 failure 2 usage 3 not authenticated 4 API error
369
382
 
370
- ${B("EXAMPLES")}
383
+ ${K("EXAMPLES")}
371
384
  anyforge approvals
372
385
  anyforge approve hil_123 --notes "ship it"
373
386
  anyforge crews --active --json | jq -r '.[].id'
@@ -381,19 +394,23 @@ ${B("EXAMPLES")}
381
394
  anyforge review-interception --days 30
382
395
  anyforge review-coverage --days 30
383
396
  anyforge ask "which initiatives slipped this cycle?"
384
- `)}function Gc(){console.log(`
385
- ${B("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
397
+ `)}function $l(){console.log(`
398
+ ${K("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
386
399
 
387
- ${B("USAGE")}
400
+ ${K("USAGE")}
388
401
  anyforge oracle [initial prompt] [options] Start an interactive session
389
402
  anyforge oracle exec <prompt|stdin> [options] Submit one read-only turn
390
403
  anyforge oracle resume [session-id] Resume a session in the terminal
391
404
  anyforge oracle sessions [--json] List sessions you can access
392
- anyforge oracle login [--write] [--approve] Connect this CLI to Oracle
393
- anyforge oracle logout Revoke and clear Oracle login
405
+ anyforge oracle login [--workspace <name>] [--write] [--approve]
406
+ Sign in to a workspace; adds it to your saved logins
407
+ anyforge oracle workspaces [--json] List saved workspaces and which one is active
408
+ anyforge oracle use <name|id> Make a saved workspace the active one
409
+ anyforge oracle logout [--workspace <name> | --all]
410
+ Revoke and remove the active (or named, or every) login
394
411
  anyforge oracle download <session> <file> --output <directory>
395
412
 
396
- ${B("OPTIONS")}
413
+ ${K("OPTIONS")}
397
414
  --json Print one final JSON object (exec)
398
415
  --stream-json Print event JSONL followed by a final result (exec)
399
416
  --shared Share with the company (requires --program or --initiative)
@@ -405,6 +422,9 @@ ${B("OPTIONS")}
405
422
  --codebase <id> Select an authorized codebase as context
406
423
  --context <text> Add up to 8 KiB of free-text context
407
424
  --file <path> Attach one explicit file; may be repeated
425
+ --workspace <name> Use this saved workspace for one command (name or id); on
426
+ login, pre-select it on the consent page
427
+ --all logout: sign out of every saved workspace
408
428
  --endpoint <url> Use this AnyForge deployment
409
429
  --help Show this Oracle help without signing in
410
430
 
@@ -412,13 +432,14 @@ CLI attachment limits are 10 MiB per file and 20 MiB total per turn. Files are
412
432
  uploaded only when named with --file or /attach. Generated files require an
413
433
  explicit \`oracle download\` destination; existing files are never overwritten.
414
434
 
415
- ${B("IN THE CONVERSATION")}
435
+ ${K("IN THE CONVERSATION")}
416
436
  /help Commands and keys /status Session, model, limits
417
437
  /new [shared] Start a conversation /clear Clear and start afresh
418
438
  /resume [id] Open a saved conversation /usage Turns and tokens so far
419
439
  /context <kind> <id> Change context /files Generated files
420
440
  /attach <path> Attach a file /copy Copy the last answer
421
441
  /model Model details /exit Leave (also Ctrl+D)
442
+ /workspace [name] Switch to another saved workspace; starts a new conversation there
422
443
  /design [topic] Talk through a technical design with Oracle
423
444
  /catchup What needs you, what landed, what is running
424
445
  (acting on its decisions needs --write --approve)
@@ -433,9 +454,11 @@ Examples:
433
454
  anyforge oracle "Summarize the open risks"
434
455
  anyforge oracle --shared --program prog_123
435
456
  anyforge oracle exec "Summarize current risks" --json
457
+ anyforge oracle login --workspace "Acme Engineering"
458
+ anyforge oracle exec "What is blocked?" --workspace "Beta Labs"
436
459
  cat incident.log | anyforge oracle exec "Explain this log" --stream-json
437
- `)}async function Wc(t,e,n,r){let o=e.flags.json===!0,[i]=e.positional;if(t==="oracle")return mi({positional:e.positional,flags:e.flags,endpointOverride:r,endpoint:n});switch(t){case"init":return $r({endpoint:n,force:e.flags.force===!0});case"logout":return Ur();case"status":return jr({endpoint:n});case"whoami":return qr({endpoint:r,json:o});case"apply-patch":return Br({patchFile:i,threeWay:e.flags["3way"]===!0,dryRun:e.flags["dry-run"]===!0});case"proxy":console.log(Mc("Local proxy mode is coming in a future release.")),console.log(kt(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return po({subcommand:i,name:e.positional[1],scope:D(e.flags.scope),client:D(e.flags.client),force:e.flags.force===!0,json:o})}let s=await Fe(r);switch(t){case"approvals":return Gr({creds:s,json:o,limit:he(e.flags.limit,"limit")});case"approve":return Sn({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:D(e.flags.notes)});case"reject":return Sn({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:D(e.flags.notes)});case"crews":return Wr({creds:s,json:o,status:D(e.flags.status),activeOnly:cr(e.flags.active),limit:he(e.flags.limit,"limit")});case"crew":{let[a,c]=e.positional;return a==="start"?Yr({creds:s,json:o,workItemId:c,profileId:D(e.flags.profile),follow:e.flags.follow===!0,intervalSeconds:he(e.flags.interval,"interval")}):a==="follow"?Tn({creds:s,json:o,crewId:c,intervalSeconds:he(e.flags.interval,"interval")}):zr({creds:s,json:o,crewId:i,messages:he(e.flags.messages,"messages")})}case"halt":return Cn({creds:s,json:o,crewId:i,action:"halt"});case"resume":return Cn({creds:s,json:o,crewId:i,action:"resume"});case"work":return Xr({creds:s,json:o,status:D(e.flags.status),type:D(e.flags.type),priority:D(e.flags.priority),initiative:D(e.flags.initiative),program:D(e.flags.program),search:D(e.flags.search),assignee:D(e.flags.assignee),includeArchived:cr(e.flags.archived),limit:he(e.flags.limit,"limit"),all:cr(e.flags.all)});case"workflows":return Zr({creds:s,json:o});case"run":return eo({creds:s,json:o,workflowId:i,input:D(e.flags.input)});case"ask":return to({creds:s,json:o,question:e.positional.join(" "),context:D(e.flags.context)});case"backtest-corpus":return ro({creds:s,json:o,days:he(e.flags.days,"days")});case"review-interception":return io({creds:s,json:o,days:he(e.flags.days,"days")});case"review-coverage":return so({creds:s,json:o,days:he(e.flags.days,"days")});default:throw new y(`Unknown command: ${t}`,"Run `anyforge --help` for the command list.")}}async function zc(){let t;try{t=Dc(process.argv.slice(2))}catch(r){hi(r);return}if(t.flags.version===!0){let r=await Promise.resolve().then(()=>(sr(),ir));console.log(r.default.version);return}if(t.command==="oracle"&&t.flags.help===!0){Gc();return}if(t.flags.help===!0||!t.command){Bc();return}let e=D(t.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=e??wi;try{if(t.command!=="oracle"){let o=["approve","codebase","file","output","read-only","shared","stream-json","write"].find(i=>t.flags[i]!==void 0);if(o)throw new y(`--${o} is only supported by the oracle command.`)}await Wc(t.command,t,n,e)}catch(r){hi(r)}}function hi(t){t instanceof f&&(process.stderr.write(gi("Error: ")+u(t.message)+`
438
- `),t.hint?process.stderr.write(kt(u(t.hint))+`
439
- `):t instanceof y&&process.stderr.write(kt("Run `anyforge --help`.")+`
440
- `),process.exit(t.exitCode)),process.stderr.write(gi("Error: ")+u(t instanceof Error?t.message:String(t))+`
441
- `),process.exit(m.FAILURE)}zc();
460
+ `)}async function Pl(t,e,n,r){let o=e.flags.json===!0,[i]=e.positional;if(t==="oracle")return Hi({positional:e.positional,flags:e.flags,endpointOverride:r,endpoint:n});switch(t){case"init":return Vr({endpoint:n,force:e.flags.force===!0});case"logout":return io();case"status":return po({endpoint:r,json:o});case"whoami":return ro({endpoint:r,json:o});case"apply-patch":return mo({patchFile:i,threeWay:e.flags["3way"]===!0,dryRun:e.flags["dry-run"]===!0});case"proxy":console.log(Sl("Local proxy mode is coming in a future release.")),console.log(jt(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return qo({subcommand:i,name:e.positional[1],scope:G(e.flags.scope),client:G(e.flags.client),force:e.flags.force===!0,json:o})}let s=await Ie(r);switch(t){case"approvals":return go({creds:s,json:o,limit:be(e.flags.limit,"limit")});case"approve":return Gn({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:G(e.flags.notes)});case"reject":return Gn({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:G(e.flags.notes)});case"crews":return ho({creds:s,json:o,status:G(e.flags.status),activeOnly:Er(e.flags.active),limit:be(e.flags.limit,"limit")});case"crew":{let[a,c]=e.positional;return a==="start"?bo({creds:s,json:o,workItemId:c,profileId:G(e.flags.profile),follow:e.flags.follow===!0,intervalSeconds:be(e.flags.interval,"interval")}):a==="follow"?Hn({creds:s,json:o,crewId:c,intervalSeconds:be(e.flags.interval,"interval")}):wo({creds:s,json:o,crewId:i,messages:be(e.flags.messages,"messages")})}case"halt":return zn({creds:s,json:o,crewId:i,action:"halt"});case"resume":return zn({creds:s,json:o,crewId:i,action:"resume"});case"work":return Ao({creds:s,json:o,status:G(e.flags.status),type:G(e.flags.type),priority:G(e.flags.priority),initiative:G(e.flags.initiative),program:G(e.flags.program),search:G(e.flags.search),assignee:G(e.flags.assignee),includeArchived:Er(e.flags.archived),limit:be(e.flags.limit,"limit"),all:Er(e.flags.all)});case"workflows":return Io({creds:s,json:o});case"run":return xo({creds:s,json:o,workflowId:i,input:G(e.flags.input)});case"ask":return So({creds:s,json:o,question:e.positional.join(" "),context:G(e.flags.context)});case"backtest-corpus":return To({creds:s,json:o,days:be(e.flags.days,"days")});case"review-interception":return _o({creds:s,json:o,days:be(e.flags.days,"days")});case"review-coverage":return $o({creds:s,json:o,days:be(e.flags.days,"days")});default:throw new y(`Unknown command: ${t}`,"Run `anyforge --help` for the command list.")}}async function Ll(){let t;try{t=Cl(process.argv.slice(2))}catch(r){Ji(r);return}if(t.flags.version===!0){let r=await Promise.resolve().then(()=>(Ar(),kr));console.log(r.default.version);return}if(t.command==="oracle"&&t.flags.help===!0){$l();return}if(t.flags.help===!0||!t.command){_l();return}let e=G(t.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=e??Qi;try{if(t.command!=="oracle"){let o=["approve","codebase","file","output","read-only","shared","stream-json","workspace","write"].find(i=>t.flags[i]!==void 0);if(o)throw new y(`--${o} is only supported by the oracle command.`)}await Pl(t.command,t,n,e)}catch(r){Ji(r)}}function Ji(t){t instanceof f&&(process.stderr.write(Yi("Error: ")+d(t.message)+`
461
+ `),t.hint?process.stderr.write(jt(d(t.hint))+`
462
+ `):t instanceof y&&process.stderr.write(jt("Run `anyforge --help`.")+`
463
+ `),process.exit(t.exitCode)),process.stderr.write(Yi("Error: ")+d(t instanceof Error?t.message:String(t))+`
464
+ `),process.exit(m.FAILURE)}Ll();