@anyforge/control 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +154 -152
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,78 +1,22 @@
1
1
  #!/usr/bin/env node
2
- var Lc=Object.defineProperty;var Nc=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Fc=(e,t)=>{for(var n in t)Lc(e,n,{get:t[n],enumerable:!0})};var hr={};Fc(hr,{default:()=>Cp});var Cp,gr=Nc(()=>{Cp={name:"@anyforge/control",version:"0.13.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 && esbuild src/opencodePlugin/plugin.ts --bundle --platform=node --format=esm --outfile=dist/opencode-plugin.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:{"@agentclientprotocol/sdk":"^1.9.0","@earendil-works/pi-tui":"^1.0.2",kleur:"^4.1.5",open:"^11.0.4",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.28.2","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});import{red as hc,yellow as wf,dim as Ze,bold as G}from"kleur/colors";import{execFileSync as Cr}from"child_process";import Vc from"open";import ot from"prompts";import{green as it,dim as $,bold as se,yellow as Ae,cyan as on}from"kleur/colors";import{promises as Ln}from"fs";import{homedir as qc}from"os";import{join as Zo}from"path";var ei=Zo(qc(),".anyforge"),xr=Zo(ei,"credentials");async function ti(e){await Ln.mkdir(ei,{recursive:!0,mode:448}),await Ln.writeFile(xr,JSON.stringify(e,null,2),{mode:384})}async function _t(){try{let e=await Ln.readFile(xr,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT")return null;throw e}}async function ni(){try{return await Ln.unlink(xr),!0}catch(e){if(e.code==="ENOENT")return!1;throw e}}import{promises as B}from"fs";import{execFileSync as Dc}from"child_process";import{homedir as Te}from"os";import{join as X}from"path";import Et from"prompts";import{dim as H,green as Nn,yellow as nt}from"kleur/colors";import{promises as fe}from"node:fs";import{execFileSync as Mc}from"node:child_process";import{homedir as Ce}from"node:os";import{dirname as Sr,join as me}from"node:path";import{fileURLToPath as Uc}from"node:url";function Zt(e=Ce(),t=process.env){return me(t.XDG_CONFIG_HOME||me(e,".config"),"opencode")}function oi(e=Ce(),t=process.env){return me(t.XDG_DATA_HOME||me(e,".local","share"),"opencode")}async function It(e=Ce()){if(await ri(Zt(e))||await ri(oi(e)))return!0;try{return Mc("opencode",["--version"],{stdio:["ignore","pipe","pipe"],timeout:5e3}),!0}catch{return!1}}async function ii(e=Ce()){try{return JSON.parse(await fe.readFile(me(oi(e),"auth.json"),"utf8")).anthropic?.type==="oauth"}catch{return!1}}async function en(e=Ce()){let t=Zt(e);for(let n of["opencode.json","opencode.jsonc"]){let r=me(t,n),o;try{o=await fe.readFile(r,"utf8")}catch{continue}if(!o.trim())return{path:r,config:{}};try{let i=JSON.parse(o);return{path:r,config:T(i)?i:null}}catch{return{path:r,config:null}}}return{path:me(t,"opencode.json"),config:{}}}async function tn(e,t){await fe.mkdir(me(e,".."),{recursive:!0});let n=t.$schema?t:{$schema:"https://opencode.ai/config.json",...t};await fe.writeFile(e,JSON.stringify(n,null,2)+`
3
- `,{mode:384}),await fe.chmod(e,384).catch(()=>{})}function si(e){if(T(e.providers))return!0;let t=e.mcp;return T(t)&&T(t.servers)}function Rr(e){return`${e}/v1/anthropic/v1`}function ai(e,t,n){let r=Rr(t),o=`Bearer ${n}`;if(si(e)){let l=T(e.providers)?e.providers:{},d=T(l.anthropic)?l.anthropic:{},u=T(d.settings)?d.settings:{},y=T(d.headers)?d.headers:{};return{...e,providers:{...l,anthropic:{...d,settings:{...u,baseURL:r,apiKey:n},headers:{...y,Authorization:o}}}}}let i=T(e.provider)?e.provider:{},s=T(i.anthropic)?i.anthropic:{},a=T(s.options)?s.options:{},c=T(a.headers)?a.headers:{};return{...e,provider:{...i,anthropic:{...s,options:{...a,baseURL:r,apiKey:n,headers:{...c,Authorization:o}}}}}}function _r(e){let t=T(e.providers)&&T(e.providers.anthropic)&&T(e.providers.anthropic.settings)?e.providers.anthropic.settings.baseURL:void 0,n=T(e.provider)&&T(e.provider.anthropic)&&T(e.provider.anthropic.options)?e.provider.anthropic.options.baseURL:void 0,r=t??n;return typeof r=="string"?r:null}function Ir(e){let t=e.mcp;return T(t)?T(t.servers)&&T(t.servers.anyforge)||T(t.anyforge):!1}function ci(e,t){if(Ir(e))return e;let n=`${t}/api/mcp`,r=T(e.mcp)?e.mcp:{};if(si(e)){let o=T(r.servers)?r.servers:{};return{...e,mcp:{...r,servers:{...o,anyforge:{type:"remote",url:n}}}}}return{...e,mcp:{...r,anyforge:{type:"remote",url:n,enabled:!0}}}}function li(e,t){let n=_r(e);if(!n||!t(n))return null;let r={...e},o=(i,s)=>{let a=r[i];if(!T(a)||!T(a.anthropic))return;let c={...a.anthropic};if(T(c[s])){let d={...c[s]};if(typeof d.baseURL=="string"&&t(d.baseURL)&&(delete d.baseURL,delete d.apiKey,T(d.headers))){let u={...d.headers};delete u.Authorization,Object.keys(u).length?d.headers=u:delete d.headers}Object.keys(d).length?c[s]=d:delete c[s]}if(i==="providers"&&T(c.headers)){let d={...c.headers};typeof d.Authorization=="string"&&d.Authorization.startsWith("Bearer sk_anyforge")&&delete d.Authorization,Object.keys(d).length?c.headers=d:delete c.headers}let l={...a};Object.keys(c).length?l.anthropic=c:delete l.anthropic,Object.keys(l).length?r[i]=l:delete r[i]};return o("providers","settings"),o("provider","options"),r}function T(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}async function ri(e){try{return await fe.access(e),!0}catch{return!1}}function di(e=Ce()){return me(Zt(e),"plugins","anyforge-telemetry.js")}function ui(e=Ce()){return me(e,".anyforge","opencode-telemetry.json")}async function jc(){let e=Sr(Uc(import.meta.url));for(let t of[me(e,"opencode-plugin.js"),me(e,"..","..","dist","opencode-plugin.js")])try{return await fe.readFile(t,"utf8")}catch{}throw new Error("The OpenCode plugin is missing from this CLI build (dist/opencode-plugin.js).")}async function pi(e){let t=e.home??Ce(),n=di(t);await fe.mkdir(Sr(n),{recursive:!0}),await fe.writeFile(n,await jc());let r=ui(t);return await fe.mkdir(Sr(r),{recursive:!0,mode:448}),await fe.writeFile(r,JSON.stringify({sendNames:e.sendNames},null,2)+`
4
- `,{mode:384}),n}async function fi(e=Ce()){let t=[];for(let n of[di(e),ui(e)])try{await fe.unlink(n),t.push(n)}catch{}return t}var He="# === AnyForge Control \u2014 added by `anyforge init` ===",nn="# === end AnyForge Control ===",rt=".anyforge-bak",Bc=/claude_(max|pro|team|enterprise)/i,Wc=["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 yi(e){let t=[],n=await Gc(e);if(n&&t.push(n),e.scope==="repo"){let o=await zc(e);return o&&t.push(o),await It()&&(console.log(H(" OpenCode is patched only globally (a project opencode.json is usually committed).")),console.log(H(' Re-run outside a repo, or choose "global", to route OpenCode through AnyForge.'))),t}let r=await Hc(e);r&&t.push(r);for(let o of Jc){let i=await o.detect();if(!(!i||!(await Et({type:"confirm",name:"go",message:`Patch ${o.label} via shell rc (${H(i.path)}) ?`,initial:!0})).go))try{await o.patch(i,e),t.push({label:o.label,path:i.path}),console.log(Nn(" \u2714")+" "+o.label)}catch(a){console.warn(" \u26A0 Skipped "+o.label+": "+a.message)}}return t}async function Gc(e){let t=e.scope==="repo"&&e.repoRoot?{dir:X(e.repoRoot,".claude"),file:"settings.local.json"}:{dir:X(Te(),".claude"),file:"settings.json"},n=X(t.dir,t.file);if(!(await Et({type:"confirm",name:"go",message:`Patch Claude Code config at ${H(n)} ?`,initial:!0})).go)return null;await B.mkdir(t.dir,{recursive:!0});let o=await B.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(e.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(nt(" \u26A0 Local LLM proxy detected: ")+H(a)),console.log(H(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(H(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(H(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(H(` from ${n}`)),console.log(),!(await Et({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await Oe(n)&&!await Oe(n+rt)&&await B.copyFile(n,n+rt),s.ANTHROPIC_BASE_URL=`${e.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=e.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await B.writeFile(n,JSON.stringify(i,null,2)+`
5
- `),console.log(Nn(" \u2714")+" Claude Code"),{label:e.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function Hc(e){if(!await It())return null;if(await ii())return console.log(nt(" \u26A0 OpenCode is signed in to Anthropic with a Claude subscription.")),console.log(H(" Routing it through AnyForge would replace that login, so OpenCode was not patched.")),null;let t=await en();if(t.config===null)return console.log(nt(" \u26A0 "+t.path+" is not plain JSON (comments?), so it was not changed.")),console.log(H(' To route OpenCode through AnyForge, add to its "provider" section:')),console.log(H(` "anthropic": { "options": { "baseURL": "${Rr(e.endpoint)}", "apiKey": "<your AnyForge key>",`)),console.log(H(' "headers": { "Authorization": "Bearer <your AnyForge key>" } } }')),null;let n=_r(t.config);return n&&!rn(n,Er(e.endpoint))&&(console.log(nt(" \u26A0 OpenCode already sends Anthropic requests to ")+H(n)),!(await Et({type:"confirm",name:"go",message:"Replace it with the AnyForge proxy?",initial:!1})).go)||!(await Et({type:"confirm",name:"go",message:`Patch OpenCode config at ${H(t.path)} ?`,initial:!0})).go?null:(await tn(t.path,ai(t.config,e.endpoint,e.apiKey)),console.log(Nn(" \u2714")+" OpenCode"),{label:"OpenCode (global)",path:t.path})}async function vi(e){let t=X(Te(),".claude"),n=X(t,"settings.json");await B.mkdir(t,{recursive:!0});let r=await B.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!rn(s,Er(e.endpoint))?(console.log(nt(" \u26A0 An OpenTelemetry endpoint is already configured: ")+H(s)),console.log(H(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(H(" OTEL_EXPORTER_OTLP_ENDPOINT at "+e.endpoint+"/api/otel")),null):(await Oe(n)&&!await Oe(n+rt)&&await B.copyFile(n,n+rt),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_LOGS_EXPORTER===void 0&&i.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT===void 0&&(i.OTEL_LOGS_EXPORTER="otlp",e.toolDetails&&i.OTEL_LOG_TOOL_DETAILS===void 0&&(i.OTEL_LOG_TOOL_DETAILS="1")),i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${e.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${e.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await B.writeFile(n,JSON.stringify(o,null,2)+`
6
- `),{label:"Claude Code usage telemetry (global)",path:n})}async function zc(e){if(!e.repoRoot)return null;let t=X(e.repoRoot,".env");if(!(await Et({type:"confirm",name:"go",message:`Write AnyForge env block to ${H(t)} ?`,initial:!0})).go)return null;let r=[He,`ANYFORGE_API_KEY=${e.apiKey}`,`ANTHROPIC_BASE_URL=${e.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${e.apiKey}`,`OPENAI_BASE_URL=${e.endpoint}/v1/openai`,`OPENAI_API_KEY=${e.apiKey}`,nn,""].join(`
7
- `),o="";try{o=await B.readFile(t,"utf8")}catch{}let i;return o.includes(He)?i=o.replace(new RegExp(`${He}[\\s\\S]*?${nn}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
2
+ var ol=Object.defineProperty;var he=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var hi=(e,t)=>{for(var n in t)ol(e,n,{get:t[n],enumerable:!0})};import{promises as qn}from"fs";import{homedir as il}from"os";import{join as gi}from"path";async function yi(e){await qn.mkdir(wi,{recursive:!0,mode:448}),await qn.writeFile(Lr,JSON.stringify(e,null,2),{mode:384})}async function Tt(){try{let e=await qn.readFile(Lr,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT")return null;throw e}}async function vi(){try{return await qn.unlink(Lr),!0}catch(e){if(e.code==="ENOENT")return!1;throw e}}var wi,Lr,nn=he(()=>{"use strict";wi=gi(il(),".anyforge"),Lr=gi(wi,"credentials")});var bi=he(()=>{"use strict"});var sl,Nr,im,ki=he(()=>{"use strict";bi();sl=8192,Nr=[{id:"claude-sonnet-5-5",label:"Claude Sonnet 5.5",provider:"Anthropic",hint:"Best balance \u2014 fast, near-Opus coding at Sonnet cost, recommended default",maxOutput:32e3,deepAnalysis:!0},{id:"claude-sonnet-5",label:"Claude Sonnet 5",provider:"Anthropic",hint:"Prior Sonnet \u2014 superseded by Sonnet 5.5",maxOutput:32e3,deepAnalysis:!0},{id:"claude-opus-5-5",label:"Claude Opus 5.5",provider:"Anthropic",hint:"Current Opus \u2014 long-running agentic coding at a mid-tier price",maxOutput:32e3,deepAnalysis:!0},{id:"claude-opus-5",label:"Claude Opus 5",provider:"Anthropic",hint:"Prior Opus \u2014 superseded by Opus 5.5",maxOutput:32e3,deepAnalysis:!0},{id:"claude-fable-5-2",label:"Claude Fable 5.2",provider:"Anthropic",hint:"Most capable Claude \u2014 deepest reasoning, premium price",maxOutput:32e3,deepAnalysis:!0},{id:"claude-fable-5-1",label:"Claude Fable 5.1",provider:"Anthropic",hint:"Prior Fable \u2014 superseded by Fable 5.2 at a lower price",maxOutput:32e3,deepAnalysis:!0},{id:"claude-fable-5",label:"Claude Fable 5",provider:"Anthropic",hint:"Prior Fable \u2014 superseded by Fable 5.1 at the same price",maxOutput:32e3,deepAnalysis:!0},{id:"claude-sonnet-4-6",label:"Claude Sonnet 4.6",provider:"Anthropic",hint:"Older Sonnet \u2014 superseded by Sonnet 5.5",maxOutput:32e3,deepAnalysis:!0},{id:"claude-opus-4-8",label:"Claude Opus 4.8",provider:"Anthropic",hint:"Older Opus \u2014 superseded by Opus 5.5",maxOutput:32e3,deepAnalysis:!0},{id:"claude-opus-4-7",label:"Claude Opus 4.7",provider:"Anthropic",hint:"Older Opus \u2014 superseded by Opus 5.5",maxOutput:32e3,deepAnalysis:!0},{id:"claude-haiku-5-5",label:"Claude Haiku 5.5",provider:"Anthropic",hint:"Cheapest + fastest \u2014 simple edits and background work",maxOutput:32e3,deepAnalysis:!1},{id:"gpt-6.1-sol",label:"GPT-6.1 Sol",provider:"OpenAI",hint:"Recommended \u2014 strong coding and agentic work at a mid-tier price",maxOutput:128e3,deepAnalysis:!0},{id:"gpt-6-astra",label:"GPT-6 Astra",provider:"OpenAI",hint:"Most capable GPT \u2014 deepest reasoning, premium price",maxOutput:128e3,deepAnalysis:!0},{id:"gpt-6-luna",label:"GPT-6 Luna",provider:"OpenAI",hint:"Cheapest + fastest GPT \u2014 focused, high-volume tasks",maxOutput:128e3,deepAnalysis:!0},{id:"gpt-6-sol",label:"GPT-6 Sol",provider:"OpenAI",hint:"Prior Sol \u2014 superseded by GPT-6.1 Sol at the same price",maxOutput:128e3,deepAnalysis:!0},{id:"gpt-4o",label:"GPT-4o",provider:"OpenAI",hint:"Legacy \u2014 OpenAI shuts it down 2027-01-14",maxOutput:16e3,deepAnalysis:!0},{id:"gpt-4o-mini",label:"GPT-4o mini",provider:"OpenAI",hint:"Legacy \u2014 OpenAI shuts it down 2027-01-14",maxOutput:16e3,deepAnalysis:!1},{id:"gemini-4-argon",label:"Gemini 4 Argon",provider:"Google",hint:"Best Gemini reasoning \u2014 stable, 1M context",maxOutput:32e3,deepAnalysis:!0},{id:"gemini-3.1-pro-preview",label:"Gemini 3.1 Pro (preview)",provider:"Google",hint:"Preview Pro \u2014 Gemini 4 Argon is the stable choice",maxOutput:32e3,deepAnalysis:!0},{id:"gemini-3.8-flash",label:"Gemini 3.8 Flash",provider:"Google",hint:"Newest Flash \u2014 fast, cheap, 1M context",maxOutput:32e3,deepAnalysis:!0},{id:"gemini-3.6-flash",label:"Gemini 3.6 Flash",provider:"Google",hint:"Prior Flash \u2014 same rate as 3.8",maxOutput:32e3,deepAnalysis:!0},{id:"gemini-3.5-flash-lite",label:"Gemini 3.5 Flash Lite",provider:"Google",hint:"Ultra-fast, low cost",maxOutput:32e3,deepAnalysis:!1},{id:"gemini-3.1-flash-lite",label:"Gemini 3.1 Flash Lite",provider:"Google",hint:"Cheapest Gemini \u2014 simple edits",maxOutput:32e3,deepAnalysis:!1},{id:"gemma-4-31b-it",label:"Gemma 4 31B",provider:"Google",hint:"Open-weights \u2014 free-tier rate limits apply",maxOutput:sl,deepAnalysis:!1},{id:"z-ai/glm-4.6",label:"GLM-4.6",provider:"Zhipu",hint:"Strong open-weights coder \u2014 cheap, bypasses Anthropic",maxOutput:16384,deepAnalysis:!0},{id:"z-ai/glm-5.3-flash",label:"GLM-5.3 Flash",provider:"Zhipu",hint:"Lightweight GLM \u2014 fast + cheap, 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"z-ai/glm-4.5-air",label:"GLM-4.5 Air",provider:"Zhipu",hint:"Older light GLM \u2014 superseded by GLM-5.3 Flash",maxOutput:32e3,deepAnalysis:!1},{id:"z-ai/glm-5.3",label:"GLM-5.3",provider:"Zhipu",hint:"Newest GLM \u2014 strong coder, 1M context",maxOutput:32e3,deepAnalysis:!0},{id:"z-ai/glm-5.2",label:"GLM-5.2",provider:"Zhipu",hint:"Paid GLM-5.2 \u2014 the free tier's sibling without its shared rate limits",maxOutput:32e3,deepAnalysis:!0},{id:"qwen/qwen3-coder-30b-a3b-instruct",label:"Qwen3 Coder 30B A3B",provider:"Qwen",hint:"Coding-tuned MoE \u2014 very cheap for structured edits",maxOutput:32e3,deepAnalysis:!1},{id:"openai/gpt-6.1-sol",label:"GPT-6.1 Sol",provider:"OpenAI",hint:"OpenAI via OpenRouter \u2014 1M context",maxOutput:32e3,deepAnalysis:!0},{id:"openai/gpt-5.6-sol",label:"GPT-5.6 Sol",provider:"OpenAI",hint:"Older OpenAI via OpenRouter \u2014 superseded by GPT-6.1 Sol",maxOutput:32e3,deepAnalysis:!0},{id:"meta-llama/llama-3.3-70b-instruct",label:"Llama 3.3 70B",provider:"Meta",hint:"Strong open-weights coding model",maxOutput:16e3,deepAnalysis:!1},{id:"mistralai/mistral-large-4-0",label:"Mistral Large 4",provider:"Mistral",hint:"Mistral's flagship \u2014 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"deepseek/deepseek-v4-pro",label:"DeepSeek V4 Pro",provider:"DeepSeek",hint:"Strong open-weights reasoning, about a fifth of Opus per token",maxOutput:32e3,deepAnalysis:!1},{id:"deepseek/deepseek-v4.1-flash",label:"DeepSeek V4.1 Flash",provider:"DeepSeek",hint:"Very cheap + fast, 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"deepseek/deepseek-v4.1-flash-1017",label:"DeepSeek V4.1 Flash 1017",provider:"DeepSeek",hint:"The 17 Oct V4.1 Flash snapshot, pinned for reproducible runs",maxOutput:32e3,deepAnalysis:!1},{id:"deepseek/deepseek-chat",label:"DeepSeek Chat (V3)",provider:"DeepSeek",hint:"Older DeepSeek \u2014 superseded by V4.1 Flash",maxOutput:16e3,deepAnalysis:!1},{id:"deepseek/deepseek-r1",label:"DeepSeek R1",provider:"DeepSeek",hint:"Older DeepSeek reasoning \u2014 superseded by V4 Pro",maxOutput:16e3,deepAnalysis:!1},{id:"qwen/qwen3.8-27b",label:"Qwen3.8 27B",provider:"Qwen",hint:"Compact open-weights coder \u2014 cheap, 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"moonshotai/kimi-k3",label:"Kimi K3",provider:"Moonshot",hint:"Agentic open-weights coder \u2014 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"moonshotai/kimi-k3.1-pro",label:"Kimi K3.1 Pro",provider:"Moonshot",hint:"Strongest open-weights agentic coder \u2014 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"xiaomi/mimo-v2.6-pro",label:"MiMo-V2.6-Pro",provider:"Xiaomi",hint:"Near-frontier open-weights model at a very low price \u2014 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"x-ai/grok-4.7",label:"Grok 4.7",provider:"xAI",hint:"Snappy + opinionated, fewer guardrails",maxOutput:32e3,deepAnalysis:!1},{id:"meta/muse-spark-1.3",label:"Muse Spark 1.3",provider:"Meta",hint:"Meta's general model \u2014 tool calling, images, 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"meta/muse-wonder",label:"Muse Wonder (preview)",provider:"Meta",hint:"Meta's most capable model, in preview \u2014 1M context",maxOutput:32e3,deepAnalysis:!1},{id:"google/gemma-4-31b-it:free",label:"Gemma 4 31B (free)",provider:"Google \xB7 free",hint:"Capable open-weights \u2014 rate-limited",maxOutput:32e3,deepAnalysis:!1},{id:"cohere/north-mini-code:free",label:"North Mini Code (free)",provider:"Cohere \xB7 free",hint:"Compact code-tuned model \u2014 rate-limited",maxOutput:32e3,deepAnalysis:!1},{id:"nvidia/nemotron-3-ultra-550b-a55b:free",label:"Nemotron 3 Ultra (free)",provider:"NVIDIA \xB7 free",hint:"Large open-weights reasoning model \u2014 rate-limited",maxOutput:32e3,deepAnalysis:!1}],im=new Map(Nr.map(e=>[e.id.toLowerCase(),e]))});import{promises as ge}from"node:fs";import{execFileSync as al}from"node:child_process";import{homedir as Pe}from"node:os";import{dirname as Fr,join as we}from"node:path";import{fileURLToPath as cl}from"node:url";function rn(e=Pe(),t=process.env){return we(t.XDG_CONFIG_HOME||we(e,".config"),"opencode")}function Ai(e=Pe(),t=process.env){return we(t.XDG_DATA_HOME||we(e,".local","share"),"opencode")}async function st(e=Pe()){if(await Oi(rn(e))||await Oi(Ai(e)))return!0;try{return al("opencode",["--version"],{stdio:["ignore","pipe","pipe"],timeout:5e3}),!0}catch{return!1}}async function xi(e=Pe()){try{return JSON.parse(await ge.readFile(we(Ai(e),"auth.json"),"utf8")).anthropic?.type==="oauth"}catch{return!1}}async function on(e=Pe()){let t=rn(e);for(let n of["opencode.json","opencode.jsonc"]){let r=we(t,n),o;try{o=await ge.readFile(r,"utf8")}catch{continue}if(!o.trim())return{path:r,config:{}};try{let i=JSON.parse(o);return{path:r,config:C(i)?i:null}}catch{return{path:r,config:null}}}return{path:we(t,"opencode.json"),config:{}}}async function sn(e,t){await ge.mkdir(we(e,".."),{recursive:!0});let n=t.$schema?t:{$schema:"https://opencode.ai/config.json",...t};await ge.writeFile(e,JSON.stringify(n,null,2)+`
3
+ `,{mode:384}),await ge.chmod(e,384).catch(()=>{})}function Mr(e){if(C(e.providers))return!0;let t=e.mcp;return C(t)&&C(t.servers)}function qr(e){return`${e}/v1/anthropic/v1`}function _i(e,t,n){let r=qr(t),o=`Bearer ${n}`;if(Mr(e)){let l=C(e.providers)?e.providers:{},d=C(l.anthropic)?l.anthropic:{},u=C(d.settings)?d.settings:{},w=C(d.headers)?d.headers:{};return{...e,providers:{...l,anthropic:{...d,settings:{...u,baseURL:r,apiKey:n},headers:{...w,Authorization:o}}}}}let i=C(e.provider)?e.provider:{},s=C(i.anthropic)?i.anthropic:{},a=C(s.options)?s.options:{},c=C(a.headers)?a.headers:{};return{...e,provider:{...i,anthropic:{...s,options:{...a,baseURL:r,apiKey:n,headers:{...c,Authorization:o}}}}}}function Si(e){return Array.isArray(e)?Object.keys(Un).filter(t=>e.includes(t)):[]}function ul(e){return Nr.filter(t=>t.provider===Un[e].catalogue&&!t.id.includes("/")&&!/^legacy/i.test(t.hint)).map(t=>({id:t.id,name:t.label,output:t.maxOutput}))}function Ri(e,t,n,r){if(r.length===0)return e;let o=Mr(e),i=o?"providers":"provider",a={...C(e[i])?e[i]:{}};for(let c of r){let{id:l,name:d,path:u}=Un[c],w=`${t}${u}`,v=Object.fromEntries(ul(c).map(x=>[x.id,o?{name:x.name,limit:{output:x.output}}:{name:x.name}]));a[l]=o?{name:d,package:dl,settings:{baseURL:w,apiKey:n},headers:{Authorization:`Bearer ${n}`},models:v}:{name:d,npm:ll,options:{baseURL:w,apiKey:n},models:v}}return{...e,[i]:a}}function pl(e){if(!C(e))return null;let t=C(e.settings)?e.settings:C(e.options)?e.options:null;return t&&typeof t.baseURL=="string"?t.baseURL:null}function Ur(e){let t=C(e.providers)&&C(e.providers.anthropic)&&C(e.providers.anthropic.settings)?e.providers.anthropic.settings.baseURL:void 0,n=C(e.provider)&&C(e.provider.anthropic)&&C(e.provider.anthropic.options)?e.provider.anthropic.options.baseURL:void 0,r=t??n;return typeof r=="string"?r:null}function jr(e){let t=e.mcp;return C(t)?C(t.servers)&&C(t.servers.anyforge)||C(t.anyforge):!1}function Ii(e,t){if(jr(e))return e;let n=`${t}/api/mcp`,r=C(e.mcp)?e.mcp:{};if(Mr(e)){let o=C(r.servers)?r.servers:{};return{...e,mcp:{...r,servers:{...o,anyforge:{type:"remote",url:n}}}}}return{...e,mcp:{...r,anyforge:{type:"remote",url:n,enabled:!0}}}}function Ci(e,t){let n={...e},r=!1;for(let s of["providers","provider"]){let a=n[s];if(!C(a))continue;let c={...a};for(let{id:l}of Object.values(Un)){let d=pl(c[l]);d&&t(d)&&(delete c[l],r=!0)}Object.keys(c).length?n[s]=c:delete n[s]}let o=Ur(e);if(!o||!t(o))return r?n:null;let i=(s,a)=>{let c=n[s];if(!C(c)||!C(c.anthropic))return;let l={...c.anthropic};if(C(l[a])){let u={...l[a]};if(typeof u.baseURL=="string"&&t(u.baseURL)&&(delete u.baseURL,delete u.apiKey,C(u.headers))){let w={...u.headers};delete w.Authorization,Object.keys(w).length?u.headers=w:delete u.headers}Object.keys(u).length?l[a]=u:delete l[a]}if(s==="providers"&&C(l.headers)){let u={...l.headers};typeof u.Authorization=="string"&&u.Authorization.startsWith("Bearer sk_anyforge")&&delete u.Authorization,Object.keys(u).length?l.headers=u:delete l.headers}let d={...c};Object.keys(l).length?d.anthropic=l:delete d.anthropic,Object.keys(d).length?n[s]=d:delete n[s]};return i("providers","settings"),i("provider","options"),n}function C(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}async function Oi(e){try{return await ge.access(e),!0}catch{return!1}}function Ei(e=Pe()){return we(rn(e),"plugins","anyforge-telemetry.js")}function Ti(e=Pe()){return we(e,".anyforge","opencode-telemetry.json")}async function fl(){let e=Fr(cl(import.meta.url));for(let t of[we(e,"opencode-plugin.js"),we(e,"..","..","dist","opencode-plugin.js")])try{return await ge.readFile(t,"utf8")}catch{}throw new Error("The OpenCode plugin is missing from this CLI build (dist/opencode-plugin.js).")}async function $i(e){let t=e.home??Pe(),n=Ei(t);await ge.mkdir(Fr(n),{recursive:!0}),await ge.writeFile(n,await fl());let r=Ti(t);return await ge.mkdir(Fr(r),{recursive:!0,mode:448}),await ge.writeFile(r,JSON.stringify({sendNames:e.sendNames},null,2)+`
4
+ `,{mode:384}),n}async function Pi(e=Pe()){let t=[];for(let n of[Ei(e),Ti(e)])try{await ge.unlink(n),t.push(n)}catch{}return t}var Un,ll,dl,jn=he(()=>{"use strict";ki();Un={openai:{id:"anyforge-openai",name:"OpenAI via AnyForge",path:"/v1/openai",catalogue:"OpenAI"},google:{id:"anyforge-google",name:"Google via AnyForge",path:"/api/v1/google",catalogue:"Google"}},ll="@ai-sdk/openai-compatible",dl="@opencode/ai/providers/openai-compatible"});import{promises as G}from"fs";import{execFileSync as ml}from"child_process";import{homedir as Le}from"os";import{join as Z}from"path";import $t from"prompts";import{dim as H,green as Dn,yellow as at}from"kleur/colors";async function qi(e){let t=[],n=await wl(e);if(n&&t.push(n),e.scope==="repo"){let o=await vl(e);return o&&t.push(o),await st()&&(console.log(H(" OpenCode is patched only globally (a project opencode.json is usually committed).")),console.log(H(' Re-run outside a repo, or choose "global", to route OpenCode through AnyForge.'))),t}let r=await Dr(e);r&&t.push(r);for(let o of kl){let i=await o.detect();if(!(!i||!(await $t({type:"confirm",name:"go",message:`Patch ${o.label} via shell rc (${H(i.path)}) ?`,initial:!0})).go))try{await o.patch(i,e),t.push({label:o.label,path:i.path}),console.log(Dn(" \u2714")+" "+o.label)}catch(a){console.warn(" \u26A0 Skipped "+o.label+": "+a.message)}}return t}async function wl(e){let t=e.scope==="repo"&&e.repoRoot?{dir:Z(e.repoRoot,".claude"),file:"settings.local.json"}:{dir:Z(Le(),".claude"),file:"settings.json"},n=Z(t.dir,t.file);if(!(await $t({type:"confirm",name:"go",message:`Patch Claude Code config at ${H(n)} ?`,initial:!0})).go)return null;await G.mkdir(t.dir,{recursive:!0});let o=await G.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(e.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(at(" \u26A0 Local LLM proxy detected: ")+H(a)),console.log(H(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(H(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(H(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(H(` from ${n}`)),console.log(),!(await $t({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await Se(n)&&!await Se(n+ct)&&await G.copyFile(n,n+ct),s.ANTHROPIC_BASE_URL=`${e.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=e.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await G.writeFile(n,JSON.stringify(i,null,2)+`
5
+ `),console.log(Dn(" \u2714")+" Claude Code"),{label:e.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function Dr(e){if(!await st())return null;let t=e.gatewayProviders??[],n=!0;if(await xi()&&(console.log(at(" \u26A0 OpenCode is signed in to Anthropic with a Claude subscription.")),console.log(H(" Routing its Anthropic models through AnyForge would replace that login, so they stay as they are.")),n=!1,t.length===0))return null;let r=await on();if(r.config===null)return console.log(at(" \u26A0 "+r.path+" is not plain JSON (comments?), so it was not changed.")),n&&(console.log(H(' To route OpenCode through AnyForge, add to its "provider" section:')),console.log(H(` "anthropic": { "options": { "baseURL": "${qr(e.endpoint)}", "apiKey": "<your AnyForge key>",`)),console.log(H(' "headers": { "Authorization": "Bearer <your AnyForge key>" } } }'))),null;let o=Ur(r.config);n&&o&&!cn(o,Br(e.endpoint))&&(console.log(at(" \u26A0 OpenCode already sends Anthropic requests to ")+H(o)),(await $t({type:"confirm",name:"go",message:"Replace it with the AnyForge proxy?",initial:!1})).go||(n=!1));let i=[...n?["Anthropic"]:[],...t.map(c=>c==="openai"?"OpenAI":"Google")];if(i.length===0||!(await $t({type:"confirm",name:"go",message:`Route OpenCode's ${yl(i)} models through AnyForge? ${H("("+r.path+")")}`,initial:!0})).go)return null;let a=r.config;return n&&(a=_i(a,e.endpoint,e.apiKey)),a=Ri(a,e.endpoint,e.apiKey,t),await sn(r.path,a),console.log(Dn(" \u2714")+" OpenCode"+(t.length?H(` (pick ${t.map(c=>c==="openai"?'"OpenAI via AnyForge"':'"Google via AnyForge"').join(" or ")} models in /models)`):"")),{label:"OpenCode (global)",path:r.path}}function yl(e){return e.length<2?e.join(""):`${e.slice(0,-1).join(", ")} and ${e[e.length-1]}`}async function Ui(e){let t=Z(Le(),".claude"),n=Z(t,"settings.json");await G.mkdir(t,{recursive:!0});let r=await G.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!cn(s,Br(e.endpoint))?(console.log(at(" \u26A0 An OpenTelemetry endpoint is already configured: ")+H(s)),console.log(H(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(H(" OTEL_EXPORTER_OTLP_ENDPOINT at "+e.endpoint+"/api/otel")),null):(await Se(n)&&!await Se(n+ct)&&await G.copyFile(n,n+ct),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_LOGS_EXPORTER===void 0&&i.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT===void 0&&(i.OTEL_LOGS_EXPORTER="otlp",e.toolDetails&&i.OTEL_LOG_TOOL_DETAILS===void 0&&(i.OTEL_LOG_TOOL_DETAILS="1")),i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${e.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${e.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await G.writeFile(n,JSON.stringify(o,null,2)+`
6
+ `),{label:"Claude Code usage telemetry (global)",path:n})}async function vl(e){if(!e.repoRoot)return null;let t=Z(e.repoRoot,".env");if(!(await $t({type:"confirm",name:"go",message:`Write AnyForge env block to ${H(t)} ?`,initial:!0})).go)return null;let r=[Ve,`ANYFORGE_API_KEY=${e.apiKey}`,`ANTHROPIC_BASE_URL=${e.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${e.apiKey}`,`OPENAI_BASE_URL=${e.endpoint}/v1/openai`,`OPENAI_API_KEY=${e.apiKey}`,an,""].join(`
7
+ `),o="";try{o=await G.readFile(t,"utf8")}catch{}let i;return o.includes(Ve)?i=o.replace(new RegExp(`${Ve}[\\s\\S]*?${an}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
8
8
  `)?`${o}${r}`:`${o}
9
- ${r}`,i!==o&&await B.writeFile(t,i),await Kc(e.repoRoot),console.log(Nn(" \u2714")+" .env"),{label:".env (repo)",path:t}}async function Kc(e){let t=X(e,".gitignore");try{(await B.readFile(t,"utf8")).split(`
10
- `).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(nt(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(nt(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}var Jc=[{label:"Cursor (shell hint)",async detect(){let e=X(Te(),".cursor");return await Oe(e)?{path:".cursor (shell hint)"}:null},async patch(e,t){await mi(t)}},{label:"Cline / Continue (shell hint)",async detect(){let e=await Oe(X(Te(),".cline")),t=await Oe(X(Te(),".continue"));return e||t?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(e,t){await mi(t)}}];async function mi(e){let t=[He,`export ANYFORGE_API_KEY="${e.apiKey}"`,`export ANTHROPIC_BASE_URL="${e.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${e.apiKey}"`,`export OPENAI_BASE_URL="${e.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${e.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",nn,""].join(`
11
- `);for(let n of[".zshrc",".bashrc"]){let r=X(Te(),n);if(!await Oe(r))continue;let o=await B.readFile(r,"utf8"),i;o.includes(He)?i=o.replace(new RegExp(`${He}[\\s\\S]*?${nn}\\n?`),t):i=o.endsWith(`
9
+ ${r}`,i!==o&&await G.writeFile(t,i),await bl(e.repoRoot),console.log(Dn(" \u2714")+" .env"),{label:".env (repo)",path:t}}async function bl(e){let t=Z(e,".gitignore");try{(await G.readFile(t,"utf8")).split(`
10
+ `).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(at(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(at(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}async function Li(e){let t=[Ve,`export ANYFORGE_API_KEY="${e.apiKey}"`,`export ANTHROPIC_BASE_URL="${e.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${e.apiKey}"`,`export OPENAI_BASE_URL="${e.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${e.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",an,""].join(`
11
+ `);for(let n of[".zshrc",".bashrc"]){let r=Z(Le(),n);if(!await Se(r))continue;let o=await G.readFile(r,"utf8"),i;o.includes(Ve)?i=o.replace(new RegExp(`${Ve}[\\s\\S]*?${an}\\n?`),t):i=o.endsWith(`
12
12
  `)?`${o}
13
13
  ${t}`:`${o}
14
14
 
15
- ${t}`,i!==o&&await B.writeFile(r,i)}}async function Oe(e){try{return await B.access(e),!0}catch{return!1}}async function bi(){try{let e=await B.readFile(X(Te(),".claude.json"),"utf8"),n=JSON.parse(e).oauthAccount,r=n?.organizationType??"";if(n&&Bc.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 ki(e={}){let t=e.endpoint?Er(e.endpoint):null,n=[],r=X(Te(),".claude","settings.json");await hi(r,t)&&n.push(r);for(let s of[".zshrc",".bashrc"]){let a=X(Te(),s);await gi(a)&&n.push(a)}n.push(...await fi());let o=await en();if(o.config){let s=li(o.config,a=>rn(a,t));s&&(await tn(o.path,s),n.push(o.path))}let i=e.repoRoot??Yc(process.cwd());if(i){let s=X(i,".claude","settings.local.json");await hi(s,t)&&n.push(s);let a=X(i,".env");await gi(a)&&n.push(a)}return{reverted:n}}function rn(e,t){return e?e.includes("anyforge")?!0:t?e.includes(t):!1:!1}async function hi(e,t){if(!await Oe(e))return!1;if(await Oe(e+rt))return await B.copyFile(e+rt,e),await B.unlink(e+rt).catch(()=>{}),!0;let n;try{n=JSON.parse(await B.readFile(e,"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)rn(r[s],t)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),rn(r.OTEL_EXPORTER_OTLP_ENDPOINT,t)){for(let s of Wc)s in r&&(delete r[s],o=!0);r.OTEL_LOGS_EXPORTER==="otlp"&&(delete r.OTEL_LOGS_EXPORTER,r.OTEL_LOG_TOOL_DETAILS==="1"&&delete r.OTEL_LOG_TOOL_DETAILS,o=!0)}return o?(Object.keys(r).length===0&&delete n.env,await B.writeFile(e,JSON.stringify(n,null,2)+`
16
- `),!0):!1}async function gi(e){let t;try{t=await B.readFile(e,"utf8")}catch{return!1}if(!t.includes(He))return!1;let n=t.replace(new RegExp(`\\n?${wi(He)}[\\s\\S]*?${wi(nn)}\\n?`),`
15
+ ${t}`,i!==o&&await G.writeFile(r,i)}}async function Se(e){try{return await G.access(e),!0}catch{return!1}}async function ji(){try{let e=await G.readFile(Z(Le(),".claude.json"),"utf8"),n=JSON.parse(e).oauthAccount,r=n?.organizationType??"";if(n&&hl.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 Di(e={}){let t=e.endpoint?Br(e.endpoint):null,n=[],r=Z(Le(),".claude","settings.json");await Ni(r,t)&&n.push(r);for(let s of[".zshrc",".bashrc"]){let a=Z(Le(),s);await Fi(a)&&n.push(a)}n.push(...await Pi());let o=await on();if(o.config){let s=Ci(o.config,a=>cn(a,t));s&&(await sn(o.path,s),n.push(o.path))}let i=e.repoRoot??Ol(process.cwd());if(i){let s=Z(i,".claude","settings.local.json");await Ni(s,t)&&n.push(s);let a=Z(i,".env");await Fi(a)&&n.push(a)}return{reverted:n}}function cn(e,t){return e?e.includes("anyforge")?!0:t?e.includes(t):!1:!1}async function Ni(e,t){if(!await Se(e))return!1;if(await Se(e+ct))return await G.copyFile(e+ct,e),await G.unlink(e+ct).catch(()=>{}),!0;let n;try{n=JSON.parse(await G.readFile(e,"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)cn(r[s],t)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),cn(r.OTEL_EXPORTER_OTLP_ENDPOINT,t)){for(let s of gl)s in r&&(delete r[s],o=!0);r.OTEL_LOGS_EXPORTER==="otlp"&&(delete r.OTEL_LOGS_EXPORTER,r.OTEL_LOG_TOOL_DETAILS==="1"&&delete r.OTEL_LOG_TOOL_DETAILS,o=!0)}return o?(Object.keys(r).length===0&&delete n.env,await G.writeFile(e,JSON.stringify(n,null,2)+`
16
+ `),!0):!1}async function Fi(e){let t;try{t=await G.readFile(e,"utf8")}catch{return!1}if(!t.includes(Ve))return!1;let n=t.replace(new RegExp(`\\n?${Mi(Ve)}[\\s\\S]*?${Mi(an)}\\n?`),`
17
17
  `).replace(/\n{3,}/g,`
18
18
 
19
- `);return await B.writeFile(e,n),!0}function wi(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Er(e){try{return new URL(e).host}catch{return null}}function Yc(e){try{return Dc("git",["rev-parse","--show-toplevel"],{cwd:e,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var Xc=2e3,Qc=900*1e3;async function Ai(e){let{endpoint:t}=e;console.log(se("AnyForge Control \u2014 device authorisation")),console.log($(` endpoint: ${t}`));let n=process.cwd(),r=Oi(n),o=r?$r(r):null,s=await(await fetch(`${t}/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:l}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${on(c)}`),console.log($(` Code: ${a}`)),console.log();try{await Vc(c)}catch{}let{credentials:d,modelRouting:u}=await Zc({pollUrl:l,endpoint:t});if(await ti(d),console.log(it("\u2714")+" API key saved to "+$("~/.anyforge/credentials")),!u){await nl(t,d.apiKey);return}let y=await bi();if(y.isSubscription&&!e.force){await tl(y,t,d.apiKey);return}let v=process.cwd(),x=Oi(v),b=await ol(x),m=await yi({endpoint:t,apiKey:d.apiKey,scope:b,repoRoot:x});m.length===0?(console.log(Ae("No agent configs were patched.")),console.log($(" Set ANTHROPIC_BASE_URL="+t+"/v1/anthropic and")),console.log($(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):il(m),await Tr(t),console.log(),y.isSubscription&&e.force&&(console.log(Ae(` \u26A0 --force: your Claude ${y.plan??""} subscription login is now shadowed`)),console.log(Ae(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(Ae(" needs an Anthropic API key on your company. Run ")+se("anyforge logout")),console.log(Ae(" to revert and restore your subscription."))),b==="repo"&&(console.log($(" Re-run this command in another repo to patch it too,")),console.log($(' or run from any directory and choose "global" to install system-wide.'))),console.log(se("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: "+on(`${t}/usage`))}async function Zc(e){let t=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-t<Qc;){await new Promise(i=>setTimeout(i,Xc)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
20
- `),n=0);let o=await(await fetch(e.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+it("done")+`
21
- `),{credentials:{apiKey:o.data.apiKey,companyId:o.data.companyId,endpoint:e.endpoint,savedAt:new Date().toISOString()},modelRouting:o.data.modelRouting!==!1};if(o.status==="expired"||o.status==="not_found")throw process.stdout.write(`
22
- `),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}function el(e,t){return["mcp","add","anyforge","--env",`ANYFORGE_API_TOKEN=${t}`,"--env",`ANYFORGE_API_URL=${e}`,"--","npx","-y","@anyforge/mcp-server"]}async function tl(e,t,n){let r=e.email?` (${e.email})`:"";if(console.log(),console.log(Ae(` \u26A0 Claude ${e.plan??""} subscription login detected${r}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+se("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 "+se("override and")),console.log(" "+se("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+se("AnyForge")),console.log(" "+se("MCP server")+" for control (HIL approvals, work items, crews):"),console.log(),await xi(t,n),console.log(),(await ot({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts and tool, MCP and skill activity \u2014 never prompt content)",initial:!0})).go){let i=await ot({type:"confirm",name:"go",message:"Also send the names of the MCP servers and skills you use? This turns on Claude Code's tool details, which also sends Bash commands, file paths and tool input to AnyForge. AnyForge drops those on arrival and never stores them.",initial:!1}),s=await vi({endpoint:t,apiKey:n,toolDetails:i.go===!0});s&&(console.log(it(" \u2714")+" Usage telemetry enabled \u2014 view it at "+on(`${t}/usage`)),console.log($(" (written to "+s.path+"; `anyforge logout` removes it)")))}else console.log($(" Skipped \u2014 your subscription usage stays local to Claude Code."));await Tr(t),console.log(),console.log($(" Want the metered BYOK proxy instead? Re-run with ")+se("--force")+$(" using an")),console.log($(" Anthropic API key on your company (this disables your subscription in")),console.log($(" Claude Code; ")+se("anyforge logout")+$(" reverts it).")),console.log(),console.log(se("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: "+on(`${t}/usage`))}async function nl(e,t){console.log(),console.log(Ae(" This key is read-only")+$(" (Viewer role).")),console.log(" It reads programs, initiatives, work items and the strategy through the"),console.log(" "+se("AnyForge MCP server")+". Routing model calls through the company's keys"),console.log(" needs the Editor role, so your Claude Code config was "+se("not")+" patched."),console.log(),await xi(e,t),await Tr(e),console.log(),console.log(se("Done.")+" Run `anyforge status` to check identity and local setup.")}async function xi(e,t){let n=el(e,t),r="claude mcp add anyforge -- npx -y @anyforge/mcp-server";if((await ot({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{Cr("claude",n,{stdio:"inherit"}),console.log(it(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(Ae(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log($(" Add it manually:")),console.log(" "+r)}else console.log($(" Add it later with:")),console.log(" "+r);await rl(e)}async function rl(e){if(!await It())return;let t=await en(),n="opencode mcp auth anyforge";if(t.config&&Ir(t.config)){console.log($(' OpenCode already has an "anyforge" MCP server ('+t.path+")."));return}if(!(await ot({type:"confirm",name:"go",message:"Add the AnyForge MCP server to OpenCode now?",initial:!0})).go){console.log($(' Add it later under "mcp" in '+t.path+", then run: ")+n);return}if(!t.config){console.log(Ae(" "+t.path+" is not plain JSON (comments?), so it was not changed.")),console.log($(' Add under "mcp": ')+`"anyforge": { "type": "remote", "url": "${e}/api/mcp", "enabled": true }`),console.log($(" then run: ")+n);return}await tn(t.path,ci(t.config,e)),console.log(it(" \u2714")+" AnyForge MCP server added to OpenCode "+$("("+t.path+")")),console.log($(" Sign in once with: ")+n)}async function Tr(e){if(!await It())return;if(console.log(),!(await ot({type:"confirm",name:"go",message:"Send OpenCode usage to your AnyForge dashboard? (token counts and tool, MCP and skill activity \u2014 never prompt content)",initial:!0})).go){console.log($(" Skipped \u2014 OpenCode usage stays on this machine."));return}let n=await ot({type:"confirm",name:"go",message:"Also send the names of the MCP servers and skills you use in OpenCode?",initial:!1});try{let r=await pi({sendNames:n.go===!0});console.log(it(" \u2714")+" OpenCode usage telemetry enabled \u2014 view it at "+on(`${e}/usage`)),console.log($(" (plugin at "+r+"; restart OpenCode to load it; `anyforge logout` removes it)"))}catch(r){console.log(Ae(" Could not install the OpenCode plugin: ")+r.message)}}function Oi(e){try{return Cr("git",["rev-parse","--show-toplevel"],{cwd:e,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function ol(e){return e?(await ot({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${e}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log($(" Not a git repo root \u2014 installing globally.")),console.log($(" Run this from a repo root if you want a per-repo install instead.")),"global")}function il(e){console.log(it("\u2714")+" Patched "+e.length+" agent config"+(e.length===1?"":"s")+":");for(let t of e)console.log(` ${$("\u2022")} ${t.label} ${$("("+t.path+")")}`)}function $r(e){try{let t=Cr("git",["remote","get-url","origin"],{cwd:e,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=t.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=t.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}import{dim as Nr,yellow as pl,bold as fl}from"kleur/colors";var g={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,VERIFICATION_FAILED:5,INTERRUPTED:130},h=class extends Error{exitCode;hint;constructor(t,n=g.FAILURE,r){super(t),this.name="CliError",this.exitCode=n,this.hint=r}},f=class extends h{constructor(t,n){super(t,g.USAGE,n),this.name="UsageError"}},xe=class extends h{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",g.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},Si=4e3,Q=class extends h{code;status;details;constructor(t,n,r,o,i){super(sl(t,r,o),g.API_ERROR,al(t,n,i)),this.name="ControlApiError",this.code=t,this.status=n,o&&(this.details=o)}};function sl(e,t,n){let r=t?`${e}: ${t}`:e;if(!n)return r;let o=JSON.stringify(n),i=o.length>Si?`${o.slice(0,Si)}\u2026(truncated)`:o;return`${r}
23
- ${i}`}function al(e,t,n){if(e==="api_key_expired")return`This API key has expired. Mint a new key in Settings \u2192 API keys, then re-run \`npx @anyforge/control init\` or update ANYFORGE_API_TOKEN. See ${n?`${n.replace(/\/$/,"")}/docs?page=service-accounts-and-key-expiry`:'the "Service accounts and API key expiry" guide'}.`;if(e==="missing_api_key"||e==="invalid_api_key"||e==="invalid_token"||t===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(e==="insufficient_scope"||t===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(t===404)return"No such id in this company. Check it with the matching list command.";if(t===429)return"Rate limited. Retry after a short pause."}var Ri="https://crew.anyforge.ai";async function $e(e){let t=process.env.ANYFORGE_API_TOKEN,n=e||process.env.ANYFORGE_API_URL;if(t)return{apiKey:t,endpoint:n||Ri};let r=await _t();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||Ri};throw new xe}var Pr=null;function _i(e){Pr=e&&/^[a-z][a-z0-9-]*$/.test(e)?`anyforge ${e}`:null}async function R(e,t,n,r){let o=`${e.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`,"X-AnyForge-Client":"anyforge-cli",...Pr?{"X-AnyForge-Tool":Pr}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new h(`Cannot reach ${e.endpoint}: ${a instanceof Error?a.message:String(a)}`,g.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new h(`Non-JSON response from ${o} (HTTP ${i.status}).`,g.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 Q(a,i.status,c,ll(s),e.endpoint)}return s.data}var cl=new Set(["ok","error","message","detail"]);function ll(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t=Object.entries(e).filter(([n,r])=>!cl.has(n)&&r!==void 0);return t.length?Object.fromEntries(t):void 0}function M(e){let t=Object.entries(e).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return t.length?`?${t.join("&")}`:""}async function sn(e){return R(e,"GET","/me")}function Lr(e,t,n,r){let o=e?.entityLabels?.[t]?.[n];return typeof o=="string"&&o.trim()?o:r}async function Ii(e){try{return await sn(e)}catch{return null}}function Ei(e){return[...e].length}function Ct(e,t){if(t<=0)return"";let n=[...e];return n.length<=t?e:t===1?"\u2026":`${n.slice(0,t-1).join("")}\u2026`}function W(e,t){if(e.length===0)return"";let n=e.map(i=>t.map(s=>{let a=s.value(i)??"";return s.max?Ct(a,s.max):a})),r=t.map((i,s)=>Math.max(Ei(i.header),...n.map(a=>Ei(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(t.map(i=>i.header)),...n.map(o)].join(`
24
- `)}function I(e){return JSON.stringify(e,null,2)}function Ci(e,t=Date.now()){let n=dl(e);if(n===null)return"\u2014";let r=Math.max(0,Math.floor((t-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 dl(e){if(typeof e=="number")return Number.isFinite(e)?e:null;if(typeof e=="string"){let t=Date.parse(e);return Number.isNaN(t)?null:t}return null}function C(e,t,n="\u2014"){let r=e[t];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function re(e,t,n="\u2014"){for(let r of t){let o=e[r];if(typeof o=="string"&&o.trim())return o}return n}function he(e){let t=Array.isArray(e)?e:e&&typeof e=="object"?ul(e):null;return t?t.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function ul(e){for(let t of["items","results","rows","data"])if(Array.isArray(e[t]))return e[t];return null}function Fn(e,t,n){let r=e?`last ${e}d`:"all time";return!t||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${e?`${e}d`:"all time"} \u2014 read cap`}async function Ti(e){let t=await $e(e.endpoint),n=await sn(t);if(e.json){console.log(I(n));return}console.log(`Company: ${fl(n.companyName??n.companyId)}${n.companyName?Nr(` (${n.companyId})`):""}`),console.log(`Endpoint: ${t.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):pl("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await _t();console.log(r?Nr(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):Nr("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}import{green as $i,dim as qn,yellow as ml}from"kleur/colors";async function Pi(){let e=await _t(),t=await ni(),{reverted:n}=await ki({endpoint:e?.endpoint??null});if(console.log(t?$i("\u2714")+" Local credentials cleared.":ml("No credentials were saved on this machine.")),n.length){console.log($i("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${qn("\u2022")} ${r}`);console.log(qn(" Your previous Claude Code login (if any) is restored."))}else console.log(qn(" No AnyForge config patches found to revert."));console.log(qn(" Revoke the key server-side at /settings \u2192 API keys."))}import{readFile as Mn}from"node:fs/promises";import{homedir as hl}from"node:os";import{dirname as Fr,join as Pe}from"node:path";function ze(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{}}async function Li(e,t={home:hl(),cwd:process.cwd(),env:process.env}){let n=e.endpoint.replace(/\/$/,""),r=[],o={};try{o=ze(JSON.parse(await Mn(Pe(t.home,".anyforge","credentials"),"utf8")))}catch{}function i(a,c){let l=ze(c),d=ze(l.env),u=Object.values(ze(l.mcpServers));r.push({source:a,readable:!0,mcp:u.some(y=>{let v=ze(y),x=ze(v.env),b=Array.isArray(v.args)?v.args:[],m=x.ANYFORGE_API_TOKEN??t.env.ANYFORGE_API_TOKEN,A=x.ANYFORGE_API_URL??t.env.ANYFORGE_API_URL,L=m??o.apiKey,j=A??(m?"https://crew.anyforge.ai":o.endpoint)??"https://crew.anyforge.ai";return b.includes("@anyforge/mcp-server")&&L===e.apiKey&&j===n}),proxy:d.ANTHROPIC_BASE_URL===`${n}/v1/anthropic`&&d.ANTHROPIC_AUTH_TOKEN===e.apiKey,subscriptionTelemetry:String(d.CLAUDE_CODE_ENABLE_TELEMETRY)==="1"&&(d.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL??d.OTEL_EXPORTER_OTLP_PROTOCOL)==="http/json"&&(d.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===void 0||d.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===`${n}/api/otel/v1/metrics`)&&d.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE==="delta"&&d.OTEL_METRICS_EXPORTER==="otlp"&&d.OTEL_EXPORTER_OTLP_ENDPOINT===`${n}/api/otel`&&(d.OTEL_EXPORTER_OTLP_METRICS_HEADERS??d.OTEL_EXPORTER_OTLP_HEADERS)===`Authorization=Bearer ${e.apiKey}`})}i("Current shell",{env:t.env});let s=t.cwd;for(;Fr(s)!==s;){try{await Mn(Pe(s,".git","HEAD"));break}catch{}try{await Mn(Pe(s,".git"));break}catch{}s=Fr(s)}Fr(s)===s&&(s=t.cwd);for(let a of new Set([Pe(t.home,".claude","settings.json"),Pe(s,".claude","settings.json"),Pe(s,".claude","settings.local.json"),Pe(s,".mcp.json"),Pe(t.home,".claude.json")]))try{let c=JSON.parse(await Mn(a,"utf8"));if(i(a,c),a===Pe(t.home,".claude.json")){let l=ze(ze(c).projects)[s];l&&i(`${a} (project)`,l)}}catch(c){c.code!=="ENOENT"&&r.push({source:a,mcp:!1,proxy:!1,subscriptionTelemetry:!1,readable:!1})}return r}var gl=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,wl=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function p(e){return e.replace(gl,"").replace(wl,"")}function qr(e){try{let t=new URL(e);return t.protocol!=="https:"&&t.protocol!=="http:"||!t.hostname||t.username||t.password?null:t.toString()}catch{return null}}function Ni(e){return e.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(t,n)=>qr(n)?t:"\x1B]8;;\x07")}function Fi(e,t){if(!t||!e.startsWith("/")||e.startsWith("//"))return e;try{return new URL(e,t).toString()}catch{return e}}function qi(e,t){return t?e.replace(/(\]\()(<?)(\/(?!\/)[^\s)>]*)/g,(n,r,o,i)=>`${r}${o}${Fi(i,t)}`):e}function Mr(e,t){let r=p(e).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(s,a,c,l)=>{let d=Fi(l.startsWith("<")&&l.endsWith(">")?l.slice(1,-1):l,t),u=qr(d);return u?`${a}[${c}](${u})`:c}),o=new Map,i=r.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(s,a,c,l,d)=>{let u=qr(l);return o.set(c.trim().toLowerCase(),u),u?`${a}${u}${d}`:""});return o.size===0?i:i.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(s,a,c,l)=>{let d=(l||c).trim().toLowerCase();return!o.has(d)||o.get(d)?s:c})}function Le(e){return typeof e=="string"?p(e):Array.isArray(e)?e.map(t=>Le(t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([t,n])=>[p(t),Le(n)])):e}function Mi(e){return e.state==="received"?e.lastRecordedAt??"Timestamp unavailable":e.state==="unattributed"?"Unknown: this credential has no user attribution":e.state==="unavailable"?"Unavailable: retry the check":"No recorded activity for this user in this company"}async function Ui(e){let t=await $e(e.endpoint),n=await R(t,"GET","/connection"),r=await Li(t),o={...n,endpoint:t.endpoint,localConfiguration:r};if(e.json)console.log(I(o));else{let i=[`Endpoint: ${t.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(l=>l[s]).map(l=>l.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: ${Mi(n.proxy)}`,`Latest recorded subscription telemetry: ${Mi(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, estimated cost and, when your company turns it on, counts of the tools, MCP servers and skills used. Never prompts, commands, file paths or full traces.",`Usage: ${t.endpoint.replace(/\/$/,"")}/usage`,`Traces: ${t.endpoint.replace(/\/$/,"")}/traces (MCP access alone does not create inference traces)`),console.log(i.map(p).join(`
25
- `))}[n.proxy,n.subscriptionTelemetry].some(i=>i.state==="unavailable")&&(process.exitCode=1)}import{spawn as yl}from"node:child_process";import{readFile as vl}from"node:fs/promises";import{red as an,green as Ur,yellow as bl,dim as cn,bold as ji}from"kleur/colors";async function Di(e){let t=await kl(e.patchFile);t.trim()||(process.stderr.write(an(`Empty patch \u2014 nothing to apply.
26
- `)),process.exit(1));let n=Ol(t);process.stderr.write(cn(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+Ur(`+${n.added}`)+" "+an(`-${n.removed}`)+`
27
- `);let r=await jr(["apply","--check"],t);if(r.code!==0){if(e.threeWay){let i=await jr(["apply","--3way"],t);i.code!==0&&(process.stderr.write(an(`3-way apply failed:
28
- `)+i.stderr+`
29
- `),process.exit(1)),process.stderr.write(bl(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
30
- `));return}process.stderr.write(an(`Patch does not apply cleanly:
31
- `)+r.stderr+`
32
- `),process.stderr.write(cn("Try ")+ji("--3way")+cn(` to attempt a 3-way merge against the index.
33
- `)),process.exit(1)}if(e.dryRun){process.stderr.write(Ur(`\u2713 Patch would apply cleanly.
34
- `));return}let o=await jr(["apply"],t);o.code!==0&&(process.stderr.write(an(`git apply failed:
35
- `)+o.stderr+`
36
- `),process.exit(1)),process.stderr.write(Ur(`\u2713 Applied.
37
- `)),n.files>0&&process.stderr.write(cn(" Run ")+ji("git diff --stat")+cn(` to review.
38
- `))}async function kl(e){if(e)return await vl(e,"utf8");let t=[];for await(let n of process.stdin)t.push(n);return Buffer.concat(t).toString("utf8")}function jr(e,t){return new Promise((n,r)=>{let o=yl("git",e,{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(t),o.stdin.end()})}function Ol(e){let t=0,n=0,r=0;for(let o of e.split(`
39
- `))if(o.startsWith("diff --git"))t+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return t===0&&(n>0||r>0)&&(t=(e.match(/^\+\+\+ /gm)??[]).length),{files:t,added:n,removed:r}}import{bold as Al,dim as Dr,green as xl,red as Sl}from"kleur/colors";async function Bi(e){let t=await R(e.creds,"GET",`/hil${M({limit:e.limit})}`);if(e.json){console.log(I(t));return}let n=he(t);if(n.length===0){console.log(Dr("No approvals pending."));return}console.log(W(n,[{header:"ID",value:r=>C(r,"id")},{header:"CREW",value:r=>C(r,"crewId"),max:24},{header:"AGE",value:r=>Ci(r.requestedAt)},{header:"SUMMARY",value:r=>re(r,["planSummary","summary","title","description"]),max:60}])),console.log(Dr(`
40
- ${n.length} pending \xB7 approve with `)+Al("anyforge approve <id>"))}async function Br(e){if(!e.approvalId)throw new f(`${e.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let t=await R(e.creds,"POST",`/hil/${encodeURIComponent(e.approvalId)}`,{decision:e.decision,...e.notes?{notes:e.notes}:{}});if(e.json){console.log(I(t));return}let n=e.decision==="APPROVED"?xl("Approved"):Sl("Rejected");console.log(`${n} ${e.approvalId}`);let r=t&&typeof t=="object"?t.signature:void 0;typeof r=="string"&&r&&console.log(Dr(`Audit signature: ${r}`))}import{bold as Rl,dim as Wr}from"kleur/colors";async function Wi(e){let t=await R(e.creds,"GET",`/crews${M({status:e.status,activeOnly:e.activeOnly,limit:e.limit})}`);if(e.json){console.log(I(t));return}let n=he(t);if(n.length===0){console.log(Wr(e.activeOnly?"No active crews.":"No crews."));return}console.log(W(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>C(r,"status")},{header:"TASK",value:r=>re(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>re(r,["errorMessage"],""),max:40}]))}async function Gi(e){if(!e.crewId)throw new f("crew requires a crew id.","List them with `anyforge crews`.");let t=await R(e.creds,"GET",`/crews/${encodeURIComponent(e.crewId)}${M({messages:e.messages})}`);if(e.json){console.log(I(t));return}let n=t?.crew&&typeof t.crew=="object"?t.crew:t;console.log(`${Rl(_l(re(n,["taskDescription"],C(n,"id"))))}`),console.log(`Status: ${C(n,"status")}`),console.log(`Repo: ${re(n,["githubRepo"])}`);let r=C(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=C(n,"url","");o&&console.log(`Console: ${o}`);let i=he(t?.chat);if(i.length>0){console.log(Wr(`
41
- Last ${i.length} messages:`));for(let s of i){let a=re(s,["agentRole","role","author","agent","type"],"?"),c=re(s,["content","body","text","summary"],"");c&&console.log(`${Wr(`[${a}]`)} ${Ct(c.replace(/\s+/g," "),160)}`)}}}async function Gr(e){if(!e.crewId)throw new f(`${e.action} requires a crew id.`,"List them with `anyforge crews`.");let t=await R(e.creds,"POST",`/crews/${encodeURIComponent(e.crewId)}/${e.action}`);if(e.json){console.log(I(t));return}console.log(`${e.action==="halt"?"Halted":"Resumed"} ${e.crewId}`)}function _l(e){return Ct(e.split(/\r?\n/).find(t=>t.trim())?.trim()??e,80)}import{bold as Il,dim as Tt,red as Hi,yellow as Ki}from"kleur/colors";var El=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),Cl=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),Tl={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 Ji(e){if(!e.workItemId)throw new f("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let t=await R(e.creds,"PATCH",`/work/${encodeURIComponent(e.workItemId)}`,{action:"dispatch",...e.profileId?{runProfileId:e.profileId}:{}});if(e.json&&!e.follow){console.log(I(t));return}let n=typeof t?.crewId=="string"?t.crewId:"";if(!n)throw new h("Dispatch was accepted but returned no crew id.",g.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of t?.warnings??[])console.error(Ki(`warning: ${r}`));if(!e.follow){console.log(`Started ${Il(n)} on ${e.workItemId}`),console.log(Tt(`Follow it with \`anyforge crew follow ${n}\``));return}await Hr({creds:e.creds,json:e.json,crewId:n,intervalSeconds:e.intervalSeconds})}var $l=5,Pl=10,Ll=120,zi=30;async function Hr(e){if(!e.crewId)throw new f("crew follow requires a crew id.","List them with `anyforge crews --active`.");let t=Math.min(Math.max(e.intervalSeconds??Pl,$l),Ll)*1e3,n=Date.now()+zi*6e4,r=new Set,o="",i=!1;for(;;){let s=await R(e.creds,"GET",`/crews/${encodeURIComponent(e.crewId)}?messages=50`),a=s?.crew??{},c=C(a,"status","");for(let l of s?.chat??[]){let d=C(l,"id","");!d||r.has(d)||(r.add(d),i&&!e.json&&Nl(l))}if(i=!0,c&&c!==o&&(e.json||console.log(Tt(`\u2500\u2500 ${c}`)),o=c),Cl.has(c)){if(e.json)console.log(I({crewId:e.crewId,status:c,waiting:!0,url:C(a,"url","")}));else{console.log(Ki(`
42
- ${c} \u2014 this crew is waiting on a person.`));let l=Tl[c];l&&console.log(Tt(l));let d=C(a,"url","");d&&console.log(Tt(d))}return}if(El.has(c)){if(e.json)console.log(I({crewId:e.crewId,status:c,waiting:!1,url:C(a,"url","")}));else{let l=`
43
- ${c}`;console.log(c==="COMPLETE"?l:Hi(l));let d=C(a,"prUrl","");d&&console.log(Tt(d));let u=C(a,"errorMessage","");u&&console.log(Hi(u))}if(c!=="COMPLETE")throw new h(`Crew ${e.crewId} ended ${c}.`,g.FAILURE);return}if(Date.now()>=n)throw new h(`Still ${c||"running"} after ${zi} minutes \u2014 giving up watching.`,g.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${e.crewId}\`.`);await ql(t)}}function Nl(e){let t=C(e,"agentRole","")||C(e,"type","?"),n=Fl(e,["content","text","summary"]);n&&console.log(`${Tt(`[${t}]`)} ${Ct(n.replace(/\s+/g," "),160)}`)}function Fl(e,t){for(let n of t){let r=e[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function ql(e){return new Promise(t=>{setTimeout(t,e)})}import{randomUUID as Jr}from"node:crypto";import{promises as Yr}from"node:fs";import{relative as Kl,resolve as Jl,isAbsolute as Yl}from"node:path";import{execFile as Vl}from"node:child_process";import{promisify as Xl}from"node:util";import Ql from"open";import{execFile as Wl}from"node:child_process";import{promises as at}from"node:fs";import{tmpdir as Gl}from"node:os";import{join as Kr,resolve as Xi}from"node:path";var Ml=[/sk-ant-[a-zA-Z0-9_-]{20,}/,/sk-(?:proj-)?[a-zA-Z0-9_-]{20,}/,/ghp_[a-zA-Z0-9]{30,}/,/gh[sou]_[a-zA-Z0-9]{30,}/,/github_pat_[a-zA-Z0-9_]{30,}/,/AIza[0-9A-Za-z_-]{30,}/,/AKIA[0-9A-Z]{16}/,/sk_(?:live|test)_[a-zA-Z0-9]{20,}/,/xox[bpaors]-[0-9]+-[0-9]+-[a-zA-Z0-9-]{20,}/,/eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/,/-----BEGIN [A-Z ]*PRIVATE KEY-----/,/(?:api[_-]?key|secret|password|passwd|token|bearer)[\s:=]+['"]?[a-zA-Z0-9_+/=-]{16,}/i];function Ul(e,t){return t.some(n=>n.test(e))}function Yi(e){return Ul(e,Ml)}var st=100*1024,ye=(e,t)=>({ok:!1,code:e,message:t});function zr(e){if(!e.startsWith('"'))return e;if(e.length<2||!e.endsWith('"'))return null;let t=e.slice(1,-1),n=[],r={a:7,b:8,t:9,n:10,v:11,f:12,r:13,'"':34,"\\":92};for(let o=0;o<t.length;o++){let i=t[o];if(i!=="\\"){n.push(...new TextEncoder().encode(i));continue}let s=t[o+1];if(s===void 0)return null;if(/[0-7]/.test(s)){let a=t.slice(o+1,o+4);if(!/^[0-7]{3}$/.test(a))return null;n.push(parseInt(a,8)),o+=3}else if(s in r)n.push(r[s]),o+=1;else return null}try{return new TextDecoder("utf-8",{fatal:!0}).decode(new Uint8Array(n))}catch{return null}}function jl(e){return!e||e.startsWith("/")||e.includes("\0")||e.includes("\\")?!1:e.split("/").every(t=>t!==""&&t!=="."&&t!==".."&&t.toLowerCase()!==".git")}function Dl(e){if(e.startsWith('"')){let n=e.match(/^("(?:[^"\\]|\\.)*") ("(?:[^"\\]|\\.)*")$/);if(!n)return null;let[r,o]=[zr(n[1]),zr(n[2])];return r?.startsWith("a/")&&o?.startsWith("b/")&&r.slice(2)===o.slice(2)?r.slice(2):null}if((e.length-5)%2!==0)return null;let t=e.slice(2,2+(e.length-5)/2);return e===`a/${t} b/${t}`?t:null}function Bl(e,t){let n=e.slice(4).replace(/\t$/,"");if(n==="/dev/null")return n;let r=zr(n);return r?.startsWith(t)?r.slice(2):null}function Vi(e){if(typeof e!="string"||e.length===0)return ye("local_changes_empty","There are no local changes to send.");let t=new TextEncoder().encode(e).length;if(t>st)return ye("local_changes_too_large",`Your uncommitted changes are ${Math.ceil(t/1024)} KB; the limit is ${st/1024} KB. Commit and push the larger part, then send the rest.`);if(!e.startsWith("diff --git "))return ye("local_changes_invalid","The local changes must be a patch made by git diff.");let n=[],r=[],o=null,i=!1,s=0;for(let a of e.split(`
44
- `)){if(a.startsWith("diff --git ")){if(o=Dl(a.slice(11)),o===null)return ye("local_changes_invalid","The local changes contain a rename, a copy or a header this check cannot read. Commit and push those, then send the rest.");if(!jl(o))return ye("local_changes_unsafe_path",`The local changes name a path outside the repository: ${o}`);n.includes(o)||n.push(o),i=!1;continue}if(o===null)return ye("local_changes_invalid","The local changes must be a patch made by git diff.");if(i&&/^[ +\-\\]/.test(a)){a.startsWith("+")?(Yi(a.slice(1))&&r.length<5&&r.push(`${o}:${s}`),s++):a.startsWith(" ")&&s++;continue}let c=a.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);if(c){i=!0,s=Number(c[1]);continue}if(i=!1,a==="")continue;if(a.startsWith("GIT binary patch")||/^Binary files .* differ$/.test(a))return ye("local_changes_binary",`${o} is a binary file. Commit and push it, then send the rest.`);let l=a.match(/^(?:old mode|new mode|new file mode|deleted file mode) (\d+)$/)??a.match(/^index [0-9a-f]+\.\.[0-9a-f]+ (\d+)$/);if(l){if(l[1]==="120000"||l[1]==="160000")return ye("local_changes_unsupported_file",`${o} is a ${l[1]==="120000"?"symbolic link":"submodule"}. Commit and push it, then send the rest.`);continue}if(!/^(?:index [0-9a-f]+\.\.[0-9a-f]+|similarity index \d+%|dissimilarity index \d+%)$/.test(a)){if(a.startsWith("--- ")||a.startsWith("+++ ")){let d=Bl(a,a.startsWith("--- ")?"a/":"b/");if(d!=="/dev/null"&&d!==o)return ye("local_changes_invalid",`The patch headers for ${o} disagree.`);continue}return ye("local_changes_invalid",`The local changes for ${o} contain a line this check cannot read. Send a patch made by git diff without renames.`)}}return r.length?ye("local_changes_secret",`Your uncommitted changes add what looks like a credential at ${r.join(", ")}. Remove it, or move it out of the repository, then try again. Nothing was sent.`):{ok:!0,files:n,bytes:t}}var Un=class extends Error{constructor(n,r,o){super(r.trim()||`git ${n[0]} failed`);this.args=n;this.stderr=r;this.code=o}args;stderr;code};function Z(e,t){return new Promise((n,r)=>{let o=Wl("git",e,{cwd:t.cwd,encoding:"utf8",maxBuffer:t.maxBuffer??1048576,timeout:t.timeout??3e4,env:{...process.env,GIT_TERMINAL_PROMPT:"0",...t.env}},(i,s,a)=>{i?r(new Un(e,String(a??""),i.code)):n(String(s))});t.input!==void 0&&o.stdin?.end(t.input)})}var oe=(e,t)=>Z(e,t).then(n=>n.trim(),()=>null);function Qi(e){let t=e.trim().match(/^(?:https:\/\/(?:[^@/]+@)?github\.com\/|ssh:\/\/git@github\.com(?::\d+)?\/|git@github\.com:)([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/);return t?`${t[1]}/${t[2]}`:null}async function Zi(e){let t=await oe(["rev-parse","--show-toplevel"],{cwd:e});if(!t)throw new f("Run this inside a Git checkout of the repository.");return t}async function es(e){let t=await Zi(e),n=await oe(["symbolic-ref","--quiet","--short","HEAD"],{cwd:t});if(!n)throw new f("This checkout is not on a branch (detached HEAD). Check out the branch you are working on.");let r=await oe(["rev-parse","--verify","HEAD^{commit}"],{cwd:t});if(!r)throw new f(`${n} has no commits yet. Commit and push it first.`);let o=await oe(["config","--get",`branch.${n}.remote`],{cwd:t})||"origin",i=await oe(["config","--get",`remote.${o}.url`],{cwd:t}),s=i?Qi(i):null;if(!s)throw new f(`The remote "${o}" is not a GitHub repository. Code Studio works on GitHub repositories.`);let a=await oe(["config","--get",`branch.${n}.merge`],{cwd:t}),c=a?.startsWith("refs/heads/")?a.slice(11):n;return{root:t,branch:n,head:r,remote:o,remoteBranch:c,repoFullName:s}}async function ts(e){let t;try{t=await Z(["ls-remote","--heads",e.remote,`refs/heads/${e.remoteBranch}`],{cwd:e.root,timeout:6e4})}catch(o){throw new h(`Could not read ${e.remoteBranch} from ${e.remote}: ${o.message}`)}let n=t.split(`
45
- `).map(o=>o.split(" ")).find(([,o])=>o===`refs/heads/${e.remoteBranch}`)?.[0];if(!n)throw new f(`${e.remoteBranch} is not on ${e.remote} yet. Push it first: git push -u ${e.remote} ${e.branch}`);if(n===e.head)return;throw await oe(["merge-base","--is-ancestor",n,e.head],{cwd:e.root})!==null?new f(`${e.branch} has commits that are not pushed. Push them first: git push ${e.remote} ${e.branch}`):new f(`${e.remote}/${e.remoteBranch} has moved on from your checkout. Pull it, then try again.`)}async function ns(e){let{root:t}=e,n=(await Z(["ls-files","--others","--exclude-standard","-z"],{cwd:t,maxBuffer:16*1024*1024})).split("\0").filter(Boolean),r=0;for(let i of n){let s=await at.lstat(Kr(t,i));if(s.isSymbolicLink())throw new f(`${i} is a symbolic link. Commit and push it, then send the rest.`);if(!s.isFile())throw new f(`${i} is a nested repository. Commit and push it separately, then send the rest.`);if(r+=s.size,r>st)throw new f(`Your untracked files alone are over ${st/1024} KB. Commit and push the larger ones, or add them to .gitignore, then send the rest.`)}let o=await at.mkdtemp(Kr(Gl(),"anyforge-handoff-"));try{let i=Kr(o,"index"),s=Xi(t,(await Z(["rev-parse","--git-path","index"],{cwd:t})).trim()),a=await at.stat(s).catch(()=>null);a!==null&&await at.copyFile(s,i).then(()=>!0,()=>!1)?await at.utimes(i,a.atime,a.mtime):await Z(["read-tree","HEAD"],{cwd:t,env:{GIT_INDEX_FILE:i}});let l={GIT_INDEX_FILE:i};n.length&&await Z(["add","--intent-to-add","--pathspec-from-file=-","--pathspec-file-nul"],{cwd:t,env:l,input:`${n.join("\0")}\0`});let d;try{d=await Z(["-c","core.quotePath=true","diff","HEAD","--no-ext-diff","--no-textconv","--no-color","--no-renames","--ignore-submodules=none","--src-prefix=a/","--dst-prefix=b/"],{cwd:t,env:l,maxBuffer:st*4})}catch(y){throw y instanceof Un&&y.code==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"?new f(`Your uncommitted changes are over the ${st/1024} KB limit. Commit and push the larger part, then send the rest.`):y}if(!d)return{patch:"",files:[]};let u=Vi(d);if(!u.ok)throw new f(u.message);return{patch:d,files:u.files}}finally{await at.rm(o,{recursive:!0,force:!0})}}async function Hl(e,t){let n=Xi(e,(await Z(["rev-parse","--git-path",t],{cwd:e})).trim());return at.access(n).then(()=>!0,()=>!1)}async function zl(e,t){let n=(await Z(["remote"],{cwd:e})).split(`
46
- `).filter(Boolean),r=[...n.filter(o=>o==="origin"),...n.filter(o=>o!=="origin")];for(let o of r){let i=await oe(["config","--get",`remote.${o}.url`],{cwd:e});if(i&&Qi(i)?.toLowerCase()===t.toLowerCase())return o}return null}async function rs(e,t){let n=await Zi(e),r=t.repoFullName,o=t.branch;if(!r||!o)throw new f("This session has no repository branch to pick up.");if(o.startsWith("-")||await oe(["check-ref-format","--branch",o],{cwd:n})!==o)throw new h(`The session's branch name is not a valid Git branch: ${JSON.stringify(o)}`);let i=await zl(n,r);if(!i)throw new f(`This checkout is not ${r}. Run pickup from a clone of it.`);for(let m of["MERGE_HEAD","rebase-merge","rebase-apply","CHERRY_PICK_HEAD","REVERT_HEAD"])if(await Hl(n,m))throw new f("A merge, rebase, cherry-pick or revert is in progress here. Finish or abort it first.");let s=(await Z(["status","--porcelain","--untracked-files=no"],{cwd:n})).split(`
47
- `).filter(Boolean);if(s.length){let m=s.slice(0,5).map(A=>A.slice(3)).join(", ");throw new f(`You have uncommitted changes (${m}${s.length>5?", \u2026":""}). Commit or stash them first; nothing was changed.`)}let a=`refs/remotes/${i}/${o}`;try{await Z(["fetch","--no-tags",i,`+refs/heads/${o}:${a}`],{cwd:n,timeout:12e4})}catch(m){let A=m.message;throw/couldn't find remote ref|could not find remote ref/i.test(A)?new f(`The session has not pushed ${o} yet. Push it from Code Studio, or run: anyforge studio push ${t.id} --input '{"expectedHeadSha":"<head>"}'`):new h(`Could not fetch ${o} from ${i}: ${A}`)}let c=(await Z(["rev-parse","--verify",`${a}^{commit}`],{cwd:n})).trim(),l=await oe(["rev-parse","--verify","HEAD^{commit}"],{cwd:n}),d=await oe(["rev-parse","--verify","--quiet",`refs/heads/${o}^{commit}`],{cwd:n}),u=await oe(["symbolic-ref","--quiet","--short","HEAD"],{cwd:n});if(d&&d!==c&&await oe(["merge-base","--is-ancestor",d,c],{cwd:n})===null)throw new f(`Your local ${o} has commits the session's branch does not. Nothing was changed. Rebase or merge ${i}/${o} yourself.`);try{d?(u!==o&&await Z(["checkout",o,"--"],{cwd:n}),d!==c&&await Z(["merge","--ff-only","--no-edit",c],{cwd:n})):await Z(["checkout","--track","-b",o,a],{cwd:n})}catch(m){throw new h(`Git refused to check out ${o}: ${m.message}`)}let y=[t.localChanges?.baseCommit,d,l?await oe(["merge-base",l,c],{cwd:n}):null],v=null;for(let m of y)if(m&&/^[0-9a-f]{40}$/.test(m)&&await oe(["merge-base","--is-ancestor",m,c],{cwd:n})!==null){v=m;break}let b=(v&&v!==c?await Z(["log","--no-color","--format=%H%x09%s","-n","21",`${v}..${c}`],{cwd:n}):"").split(`
48
- `).filter(Boolean).map(m=>{let[A,...L]=m.split(" ");return{sha:A,subject:L.join(" ")}});return{repoFullName:r,branch:o,headSha:c,created:!d,commits:b.slice(0,20),moreCommits:b.length>20}}var Zl=Xl(Vl);function ed(e){if(!e)return{};try{let t=JSON.parse(e);if(!t||typeof t!="object"||Array.isArray(t))throw new Error("not an object");return t}catch{throw new f("--input must be a JSON object.")}}function ge(e){if(!e||!/^[A-Za-z0-9_-]+$/.test(e))throw new f("A valid Studio session or run ID is required.");return encodeURIComponent(e)}async function td(e){let[t,n]=await Promise.all([Yr.realpath(process.cwd()),Yr.realpath(Jl(e))]),r=Kl(t,n).replaceAll("\\","/");if(!r||Yl(r)||r.split("/").includes(".."))throw new f("--file must be inside the current directory, including symlink targets.");let o=await Yr.open(n,"r"),i;try{let d=await o.stat();if(!d.isFile()||d.size>2e4)throw new f("--file must be a regular file of 20 KB or smaller; select a smaller context file.");let u=Buffer.alloc(20001),y=0;for(;y<u.length;){let{bytesRead:v}=await o.read(u,y,u.length-y,y);if(!v)break;y+=v}if(y>2e4)throw new f("--file grew beyond 20 KB; select a smaller context file.");i=u.subarray(0,y).toString("utf8")}finally{await o.close()}let s=async d=>{try{return(await Zl("git",d,{cwd:process.cwd(),timeout:5e3,maxBuffer:64e3})).stdout.trim()}catch{return null}},[a,c,l]=await Promise.all([s(["branch","--show-current"]),s(["rev-parse","HEAD"]),s(["status","--porcelain","--",r])]);return{content:`Local reference file: ${r}
49
-
50
- ${i}`,localReference:{path:r,branch:a,commit:c,uncommitted:l===null||l.length>0||c===null}}}async function os(e){let t=ed(e.input),n=e.command??"list";if(e.uncommitted&&n!=="create")throw new f("--uncommitted is only supported for studio create.");if(n==="pickup")return id(e);let r="GET",o;if(n==="list")o="/studio/sessions";else if(n==="create")r="POST",o="/studio/sessions",t.idempotencyKey??=Jr(),e.repo&&(t.repoFullName=e.repo),e.branch&&(t.branch=e.branch),e.initiative&&(t.initiativeId=e.initiative),t.provenance={surface:"cli",workspace:"remote"},e.context&&(t.context=e.context);else if(n==="continue")r="POST",o=`/studio/sessions/${ge(e.id)}/context`,t.idempotencyKey??=Jr(),t.provenance={surface:"cli",workspace:"remote"},e.context&&(t.content=e.context);else if(["get","open","context","usage","changes","artifacts","runs"].includes(n))o=`/studio/sessions/${ge(e.id)}${n==="get"||n==="open"?"":`/${n}`}`;else if(n==="run")r="POST",o=`/studio/sessions/${ge(e.id)}/runs`,t.idempotencyKey??=Jr(),e.context&&(t.content=e.context);else if(n==="events")o=`/studio/runs/${ge(e.id)}/events${e.cursor?`?after=${encodeURIComponent(e.cursor)}`:""}`;else if(n==="status")o=`/studio/runs/${ge(e.id)}`;else if(["cancel","pause","resume","steer","answer"].includes(n))r="POST",o=`/studio/runs/${ge(e.id)}/control`,t.action=n,e.context&&(t.content=e.context);else if(["checkpoint","commit","stage","push"].includes(n))r="POST",o=`/studio/sessions/${ge(e.id)}/${n==="checkpoint"?"checkpoints":n}`;else throw new f(`Unknown Studio command: ${n}.`,"Use studio list, create, continue, pickup, open, get, context, usage, run, runs, status, events, pause, resume, cancel, steer, answer, changes, artifacts, checkpoint, stage, commit, or push.");if(e.file){if(!["create","continue"].includes(n))throw new f("--file is only supported for studio create or continue.");let a=await td(e.file),c=n==="create"?"context":"content";t[c]=[t[c],a.content].filter(Boolean).join(`
51
-
52
- `),t.provenance={surface:"cli",workspace:"remote",localReference:a.localReference}}let i=e.uncommitted?await nd(e,t):null,s=await R(e.creds,r,o,r==="POST"?t:void 0);i?.patch?s.localChanges=await od(e,String(s.id),i,String(t.idempotencyKey)):i&&process.stderr.write(`No uncommitted changes; the session starts from the pushed branch.
53
- `),n==="open"&&await Ql(`${e.creds.endpoint.replace(/\/$/,"")}/studio?session=${ge(e.id)}`),process.stdout.write(`${e.json?JSON.stringify(s):p(JSON.stringify(s,null,2))}
54
- `)}async function nd(e,t){let n=await es(process.cwd());if(e.repo&&e.repo.toLowerCase()!==n.repoFullName.toLowerCase())throw new f(`--repo ${e.repo} does not match this checkout (${n.repoFullName}).`);if(e.branch&&e.branch!==n.remoteBranch)throw new f(`--branch ${e.branch} does not match this checkout (${n.remoteBranch}).`);await ts(n);let r=await ns(n);if(t.repoFullName=n.repoFullName,t.branch=n.remoteBranch,r.patch){let o=`Uncommitted local changes to ${r.files.length} file${r.files.length===1?"":"s"} were applied to the workspace on top of ${n.head.slice(0,12)}. They are not committed.`;t.context=[t.context,o].filter(Boolean).join(`
55
-
56
- `)}return{...r,baseCommit:n.head}}var rd=new Set(["local_changes_empty","local_changes_too_large","local_changes_invalid","local_changes_unsafe_path","local_changes_binary","local_changes_unsupported_file","local_changes_secret","local_changes_fresh_session_required","local_changes_base_mismatch","local_changes_do_not_apply","invalid_local_changes","invalid_base_commit","invalid_patch","invalid_idempotencyKey","unknown_field","insufficient_scope","forbidden_role","turn_in_progress"]);async function od(e,t,n,r){try{return await R(e.creds,"POST",`/studio/sessions/${ge(t)}/local-changes`,{patch:n.patch,baseCommit:n.baseCommit,idempotencyKey:r})}catch(o){let i=o instanceof Error?o.message:String(o),s=o instanceof h?o.exitCode:g.FAILURE;if(!(o instanceof Q&&rd.has(o.code)))throw new h(`Could not confirm your local changes were applied: ${i}`,s,`Session ${t} was kept. Retry with --input '{"idempotencyKey":"${r}"}' to finish, or check its Changes in Code Studio.`);let a=await R(e.creds,"PATCH",`/studio/sessions/${ge(t)}`,{archived:!0}).then(()=>!0,()=>!1);throw new h(`Your local changes were not applied: ${i}`,s,a?`Session ${t} was archived; nothing in it changed.`:`Session ${t} was created without your changes. Archive it in Code Studio.`)}}async function id(e){let t=ge(e.id),n=await R(e.creds,"GET",`/studio/sessions/${t}`),r=await R(e.creds,"GET",`/studio/sessions/${t}/changes`).catch(()=>null),o=n.latestRunId?await R(e.creds,"GET",`/studio/runs/${ge(n.latestRunId)}`).catch(()=>null):null,i=!!n.latestRunId||Number(n.messageCount??0)>0,s=r?.branch||e.branch||(i?null:n.branch);if(!s)throw new h(`Could not read which branch session ${e.id} is working on; it may have moved off ${n.branch??"its starting branch"}. Nothing was changed.`,g.FAILURE,`Retry, or name the branch: anyforge studio pickup ${e.id} --branch <name>`);let a=await rs(process.cwd(),{...n,id:e.id,branch:s}),c=[];r?.exists&&r.clean===!1&&c.push("The session workspace has uncommitted changes that are not on the branch."),(!r||!r.exists&&r.latestCheckpoint)&&c.push("Could not check the session workspace for uncommitted changes. Open its Changes in Code Studio to confirm nothing is left behind."),r?.headSha&&r.headSha!==a.headSha&&c.push(`The session workspace is at ${r.headSha.slice(0,12)}, which is not what ${a.branch} holds. Push it from Code Studio, then pick up again.`),o&&["queued","running","pausing"].includes(String(o.status))&&c.push("A run is still in progress; its later work is not included.");let l={sessionId:e.id,title:n.title??null,...a,latestRun:o?{status:o.status??null,error:o.error??null,waitingOnYou:!!o.pendingQuestion}:null,warnings:c};if(e.json){process.stdout.write(`${JSON.stringify(l)}
57
- `);return}let d=[`${a.created?"Created":"Checked out"} ${a.branch} at ${a.headSha.slice(0,12)} from ${a.repoFullName}.`,`Session: ${n.title??e.id}${o?` (latest run ${o.status}${o.pendingQuestion?", waiting on you":""}${o.error?`: ${o.error}`:""})`:""}`,a.commits.length?`Commits from the session:
58
- ${a.commits.map(u=>` ${u.sha.slice(0,9)} ${u.subject}`).join(`
59
- `)}${a.moreCommits?`
60
- \u2026`:""}`:"No new commits from the session.",...c.map(u=>`Note: ${u}`)];process.stdout.write(`${p(d.join(`
61
- `))}
62
- `)}import{dim as jn}from"kleur/colors";var ss=100;function is(e){let t=e&&typeof e=="object"?e:{};return{total:typeof t.total=="number"?t.total:null,hasMore:t.hasMore===!0,cursor:typeof t.nextCursor=="string"?t.nextCursor:null}}async function sd(e){let t=s=>`/work${M({status:e.status,type:e.type,priority:e.priority,initiative:e.initiative,program:e.program,search:e.search,assignee:e.assignee,includeArchived:e.includeArchived,limit:e.limit,cursor:s})}`,n=await R(e.creds,"GET",t()),r=he(n),o=is(n),i=1;if(!e.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<ss;){let s=await R(e.creds,"GET",t(o.cursor));r.push(...he(s)),o=is(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function as(e){let t=await sd(e);if(e.json){console.log(I(e.all?{items:t.rows,total:t.total,hasMore:t.hasMore,nextCursor:null}:t.raw));return}let n=t.rows,r=await Ii(e.creds),o=Lr(r,"work_item","plural","Work items");if(n.length===0){console.log(jn(`No ${o.toLowerCase()} match that filter.`));return}console.log(W(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=>re(c,["title","name","summary"]),max:58}]));let i=(n.length===1?Lr(r,"work_item","singular","work item"):o).toLowerCase(),s=t.total!==null&&t.total!==n.length?`${n.length} of ${t.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=t.hasMore?e.all?jn(` \u2014 stopped after ${ss} pages; narrow the filter`):jn(" \u2014 pass --all for the rest"):"";console.log(`${jn(`
63
- ${s}`)}${a}`)}var ad=["edit","delete","resolve","reopen"];function cd(e){return ad.includes(e)}async function cs(e){if(!cd(e.action))throw new f("comment needs an action: edit, delete, resolve or reopen.","Usage: anyforge comment <edit|delete|resolve|reopen> <item-id> <comment-id> [--body <text>]");if(!e.itemId||!e.commentId)throw new f(`comment ${e.action} requires a work item id and a comment id.`,"Find comment ids with the anyforge_list_work_item_comments MCP tool or GET /work/<id>/comments.");let t=`/work/${encodeURIComponent(e.itemId)}/comments/${encodeURIComponent(e.commentId)}`,n,r;switch(e.action){case"edit":{if(e.body===void 0)throw new f('comment edit requires --body "<new text>".');n=await R(e.creds,"PATCH",t,{body:e.body}),r=`Edited comment ${e.commentId}`;break}case"delete":n=await R(e.creds,"DELETE",t),r=`Deleted comment ${e.commentId}`;break;default:{let o=e.action==="resolve";n=await R(e.creds,"POST",`${t}/resolve`,{resolved:o}),r=`${o?"Resolved":"Reopened"} the thread of comment ${e.commentId}`}}console.log(e.json?I(n):r)}import{bold as ld,dim as Dn}from"kleur/colors";async function ls(e){let t=await R(e.creds,"GET","/workflows");if(e.json){console.log(I(t));return}let n=he(t);if(n.length===0){console.log(Dn("No workflows defined."));return}console.log(W(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>re(r,["status","state"],"")},{header:"NAME",value:r=>re(r,["name","title"]),max:58}])),console.log(Dn(`
64
- Dispatch with `)+ld("anyforge run <id>"))}async function ds(e){if(!e.workflowId)throw new f("run requires a workflow id.","List them with `anyforge workflows`.");let t;if(e.input!==void 0){try{t=JSON.parse(e.input)}catch(o){throw new f(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!t||typeof t!="object"||Array.isArray(t))throw new f("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await R(e.creds,"POST",`/workflows/${encodeURIComponent(e.workflowId)}/run`,t===void 0?void 0:{inputs:t});if(e.json){console.log(I(n));return}let r=re(n??{},["id","runId"],"");console.log(`Queued run ${r||Dn("(id not returned)")}`),console.log(Dn("Runs pause at gate steps for an operator decision."))}import{dim as dd}from"kleur/colors";async function us(e){let t=e.question?.trim();if(!t)throw new f("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!e.json&&process.stderr.isTTY&&process.stderr.write(dd(`Asking the Oracle (this can take a few minutes)\u2026
65
- `));let n=await R(e.creds,"POST","/oracle",{question:t,...e.context?{context:e.context}:{}});if(e.json){console.log(I(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:I(n))}import{bold as Vr,dim as ps,green as ud,yellow as pd}from"kleur/colors";function fd(e){return typeof e=="number"?`${Math.round(e*100)}%`:"\u2014"}async function fs(e){let t=await R(e.creds,"GET",`/backtest-corpus${M({days:e.days})}`);if(e.json){console.log(I(t));return}let n=t.incidentsInWindow??0,r=t.backTestable??0,o=t.windowDays?`last ${t.windowDays}d`:"all time";console.log(`${Vr(String(r))} of ${Vr(String(n))} incidents are back-testable `+ps(`(${fd(t.coverage)} \xB7 ${o})`)),t.viable?console.log(ud("Enough to run a back-test.")):console.log(pd(`Not yet viable \u2014 ${t.shortfall??0} more needed.`));let i=(t.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}])),t.biggestGap&&console.log(ps(`
66
- Biggest fixable gap: `)+Vr(`${t.biggestGap.label} (${t.biggestGap.count})`))}import{bold as Bn,dim as ln,green as md,yellow as ms}from"kleur/colors";var Xr=e=>typeof e=="number"?`${Math.round(e*1e3)/10}%`:"\u2014";async function hs(e){let t=await R(e.creds,"GET",`/review-interception${M({days:e.days})}`);if(e.json){console.log(I(t));return}let n=Fn(t.windowDays,t.truncated,t.oldestReviewMs),r=i=>{console.log(i)};if(r(`${Bn(String(t.seriousRaised??0))} serious findings raised across ${Bn(String(t.prsReviewed??0))} pull requests ${ln(`(${n})`)}`),t.verdict==="measured")r(`${md(String(t.disappearedSerious??0))} no longer raised by the next round \u2014 ${Bn(Xr(t.interceptionFloor))} to ${Bn(Xr(t.interceptionCeiling))}`),r(ln(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${t.measurableSerious??0} that had a later round`));else{r(ms("Not enough findings had a later round to measure a rate."));for(let i of t.inconclusiveReasons??[])r(ln(` ${i}`))}let o=(t.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)}])),t.truncated){let i=t.oldestReviewMs?new Date(t.oldestReviewMs).toISOString().slice(0,10):null;r(ms(`
67
- Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}t.reviews&&t.skippedShare!=null&&t.skippedShare>0&&r(ln(`
68
- ${t.reviews.skipped} of ${t.reviews.total} reviews were skipped (${Xr(t.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of t.caveats??[])r(ln(`
69
- ${i}`))}import{bold as dn,dim as ct,green as hd,red as gd,yellow as Qr}from"kleur/colors";var wd=e=>typeof e=="number"?`${Math.round(e*1e3)/10}%`:"\u2014";function Zr(e){if(typeof e!="number")return"\u2014";if(e<60)return`${e}m`;if(e<1440){let n=Math.floor(e/60);return`${n}h ${Math.round(e-n*60)}m`}let t=Math.floor(e/1440);return`${t}d ${Math.round((e-t*1440)/60)}h`}var yd={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function gs(e){let t=await R(e.creds,"GET",`/review-coverage${M({days:e.days})}`);if(e.json){console.log(I(t));return}let n=s=>{console.log(s)},r=Fn(t.windowDays,t.truncated,t.oldestRecordMs);n(`${dn(String(t.pullRequestsReviewed??0))} of ${dn(String(t.pullRequestsSeen??0))} recorded pull requests reviewed ${t.coverageRate!=null?dn(`(${wd(t.coverageRate)})`):""} ${ct(`(${r})`)}`),t.repositoriesReviewed&&n(`across ${dn(String(t.repositoriesReviewed))} repositories`),n(ct("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),t.medianLatencyMinutes!=null?(n(`
70
- Feedback reached the author in ${hd(Zr(t.medianLatencyMinutes))} median, ${dn(Zr(t.p90LatencyMinutes))} at p90 ${ct(`(${t.latencySamples??0} reviews)`)}`),t.medianOnOpenLatencyMinutes!=null&&n(ct(` ${Zr(t.medianOnOpenLatencyMinutes)} median on pull-request open (${t.onOpenSamples??0} reviews, no quiet period in the way)`))):n(Qr(`
71
- Not enough timed reviews to report a latency figure.`));let o=t.capacityGapPullRequests??0;o>0&&n(`
72
- ${gd(String(o))} pull requests went unreviewed because a limit fired `+ct("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=t.bySkipClass??[];i.length>0&&n(W(i,[{header:"WHY UNREVIEWED",value:s=>yd[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),t.failedOnlyPullRequests&&n(ct(`${t.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of t.inconclusiveReasons??[])n(Qr(`
73
- ${s}`));if(t.truncated){let s=t.oldestRecordMs?new Date(t.oldestRecordMs).toISOString().slice(0,10):null;n(Qr(`
74
- 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 t.caveats??[])n(ct(`
75
- ${s}`))}import{createHash as Sd}from"node:crypto";import{dim as Os,green as Rd,red as _d,yellow as Id}from"kleur/colors";function ys(e){return vd({eventType:e.eventType,actor:e.actor,payload:e.payload,timestamp:e.timestampMs})}function vd(e){return JSON.stringify(eo(e))}function eo(e){if(Array.isArray(e))return e.map(eo);if(e===null||typeof e!="object"||Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)return e;let t=e,n={};for(let r of Object.keys(t).sort())n[r]=eo(t[r]);return n}var bd="";function vs(e,t,n){return e(`${n??""}${bd}${t}`)}function kd(e){let t=e.findIndex(n=>(n.sealVersion??1)>=2);return t===-1?e.length:t}function bs(e,t){let n=kd(e),r=n;for(let o=n;o<e.length;o++){let i=e[o];if(typeof i.hash!="string"||!i.hash)return{valid:!1,verified:o-n,unverifiable:r,brokenAt:o,brokenId:i.id,reason:"missing_hash",detail:`Row ${i.id} carries seal version ${i.sealVersion??1} but no hash.`};if(o>n){let s=e[o-1].hash??null;if((i.previousHash??null)!==s)return{valid:!1,verified:o-n,unverifiable:r,brokenAt:o,brokenId:i.id,reason:"link_mismatch",detail:`Row ${i.id} links to ${ws(i.previousHash)}, but the prior row hashes to ${ws(s)}.`}}if(i.hash!==t(i))return{valid:!1,verified:o-n,unverifiable:r,brokenAt:o,brokenId:i.id,reason:"content_mismatch",detail:`Row ${i.id} does not match its own contents.`}}return{valid:!0,verified:e.length-n,unverifiable:r}}function ws(e){return e?`${e.slice(0,12)}\u2026`:"nothing"}function Ad(e){return e?JSON.parse(JSON.stringify(e)):{}}function xd(e){return{id:e.id,eventType:e.eventType,actor:e.actor,payload:Ad(e.payload),timestampMs:e.timestampMs,hash:e.hash,previousHash:e.prevHash,...typeof e.sealVersion=="number"?{sealVersion:e.sealVersion}:{}}}function ks(e,t,n={}){let r=e.map(xd),o=e.length>0?e[e.length-1].hash??null:null,i=n.anchorHash;return i&&r.length>0&&(r[0].sealVersion??1)>=2&&(r[0].previousHash??null)!==i?{valid:!1,verified:0,unverifiable:0,brokenAt:0,brokenId:r[0].id,reason:"link_mismatch",detail:`Entry ${r[0].id} does not link onto the previous page's last hash.`,lastHash:o}:{...bs(r,a=>vs(t,ys({eventType:a.eventType,actor:a.actor,payload:a.payload,timestampMs:a.timestampMs}),a.previousHash??null)),lastHash:o}}var Ed=200,Cd=e=>Sd("sha256").update(e).digest("hex");function Td(e,t=Cd){let n=null,r=0,o=0;for(let i of e){if(i.length===0)continue;let s=ks(i,t,{anchorHash:n});if(r+=s.verified,o+=s.unverifiable,!s.valid)return{valid:!1,verified:r,unverifiable:o,brokenId:s.brokenId,reason:s.reason,detail:s.detail};n=s.lastHash}return{valid:!0,verified:r,unverifiable:o}}async function As(e){if(e.verify&&(e.eventType||e.actor))throw new f("--verify needs an unfiltered read.","Drop --event and --actor: a filtered page skips rows, so its chain links cannot meet. --from and --to are fine.");let t=c=>`/audit${M({eventType:e.eventType,actor:e.actor,from:e.from,to:e.to,limit:e.limit,cursor:c})}`,n=[],r=e.cursor;do{let c=await R(e.creds,"GET",t(r));n.push(c),r=c.hasMore&&c.nextCursor?c.nextCursor:void 0}while(e.all&&r&&n.length<Ed);let o=n.flatMap(c=>c.entries),i=n[n.length-1],s=e.verify?Td(n.map(c=>c.entries)):null,a=c=>{console.log(c)};if(e.json)a(I(n.length===1&&!s?i:{entries:o,nextCursor:i.nextCursor,hasMore:i.hasMore,chainContiguous:i.chainContiguous,pages:n.length,...s?{verification:s}:{}}));else{o.length===0?a("No audit entries match."):a(W(o,[{header:"SEQUENCE",value:l=>String(l.sequence)},{header:"TIME",value:l=>l.timestamp},{header:"EVENT",value:l=>l.eventType,max:34},{header:"ACTOR",value:l=>l.actor,max:28},{header:"HASH",value:l=>l.hash?`${l.hash.slice(0,12)}\u2026`:"\u2014"}]));let c=n.length===1?"page":"pages";a(Os(`${o.length} entries from ${n.length} ${c}.`)),i.hasMore&&i.nextCursor&&a(Id(`More entries exist. Continue with --cursor ${i.nextCursor}${e.all?"":" or pass --all"}.`)),s&&(s.valid?a(Rd(`Chain verified: ${s.verified} sealed entries link and recompute.`)+(s.unverifiable?Os(` ${s.unverifiable} earlier entries predate sealing and cannot be verified.`):"")):a(_d(`Chain break at ${s.brokenId}: ${s.reason}.`)+(s.detail?` ${s.detail}`:"")))}if(s&&!s.valid)throw new h(`Audit chain verification failed at ${s.brokenId??"an entry"} (${s.reason??"unknown"}).`,g.VERIFICATION_FAILED)}import{dim as xs}from"kleur/colors";var $d=["invite","invitations","withdraw"];function Ss(e,t){if(!e.email)throw new f(`people ${t} requires an email address.`,`Example: anyforge people ${t} person@example.com`);return e.email}function Pd(e){if(e===void 0)return;let t=e.split(",").map(n=>n.trim()).filter(Boolean);return t.length?t:void 0}function lt(e){console.log(e)}async function Rs(e){switch(e.subcommand){case"invite":{let t=Ss(e,"invite");if(!e.role)throw new f("people invite requires --role.","One of operator, editor, viewer or filer.");let n=Pd(e.team),r=await R(e.creds,"POST","/people/invitations",{email:t,role:e.role,...n?{teamIds:n}:{},...e.notify?{}:{notify:!1}});if(e.json){lt(I(r));return}let o=r.created?"Invited":"Refreshed the pending invitation for",i=r.emailSent?"Invitation email sent.":"No invitation email sent.";lt(`${o} ${r.email} as ${r.role}. ${xs(i)}`);return}case"invitations":{let t=await R(e.creds,"GET","/people/invitations");if(e.json){lt(I(t));return}let n=he(t);if(n.length===0){lt(xs("No invitations."));return}lt(W(n,[{header:"EMAIL",value:r=>C(r,"email"),max:48},{header:"ROLE",value:r=>C(r,"role")},{header:"STATUS",value:r=>C(r,"status")},{header:"TEAMS",value:r=>Array.isArray(r.teamIds)&&r.teamIds.length?r.teamIds.join(","):"\u2014",max:32}]));return}case"withdraw":{let t=Ss(e,"withdraw"),n=await R(e.creds,"DELETE",`/people/invitations${M({email:t})}`);if(e.json){lt(I(n));return}lt(`Withdrew the invitation for ${n.email}.`);return}default:throw new f(e.subcommand?`Unknown people command: ${e.subcommand}`:"people needs a command.",`One of: ${$d.join(", ")}.`)}}import{promises as _s}from"node:fs";import{dim as Wn}from"kleur/colors";var Ld=["week","book"],Gn=256e3;function dt(e){console.log(e)}function Nd(e=new Date){let t=n=>String(n).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}function Is(e){return`${Math.floor(e/60)}:${String(e%60).padStart(2,"0")}`}async function Fd(){let e=[],t=0;for await(let n of process.stdin){let r=Buffer.isBuffer(n)?n:Buffer.from(String(n));if(t+=r.length,t>Gn)throw new f(`Standard input is larger than ${Gn} bytes.`);e.push(r)}return Buffer.concat(e).toString("utf8")}function Es(e){let t;try{t=JSON.parse(e)}catch{throw new f("The entries are not valid JSON.",'Send a list: [{"initiativeId":"\u2026","date":"YYYY-MM-DD","minutes":90}]')}let n=Array.isArray(t)?t:t&&typeof t=="object"&&Array.isArray(t.entries)?t.entries:null;if(!n)throw new f('The entries must be a JSON list, or an object with an "entries" list.');return n}async function qd(e){if(!e.entries)throw new f("time book requires --entries.","Example: anyforge time book --entries week.json (or --entries - to read standard input)");if(e.entries==="-")return Es(await(e.readStdin??Fd)());let t=await _s.stat(e.entries).catch(()=>null);if(!t||!t.isFile())throw new f(`--entries ${e.entries} is not a file.`);if(t.size>Gn)throw new f(`--entries ${e.entries} is larger than ${Gn} bytes.`);return Es(await _s.readFile(e.entries,"utf8"))}async function Cs(e){let t=e.today??Nd();switch(e.subcommand){case"week":{let n=await R(e.creds,"GET",`/timesheets/week${M({date:e.date,today:t})}`);if(e.json){dt(I(n));return}let r=new Map([...n.rows,...n.addable,...n.categories].map(s=>[s.initiativeId,s.code?`${s.code} ${s.name}`:s.name]));if(dt(Wn(`Week of ${n.days[0]} to ${n.days[n.days.length-1]}`)),n.entries.length===0){dt(Wn("No time booked this week."));return}let o=[...n.entries].sort((s,a)=>s.date.localeCompare(a.date)||s.initiativeId.localeCompare(a.initiativeId));dt(W(o,[{header:"DATE",value:s=>s.date},{header:"INITIATIVE",value:s=>r.get(s.initiativeId)??s.initiativeId,max:48},{header:"ID",value:s=>s.initiativeId,max:32},{header:"HOURS",value:s=>Is(s.minutes)},{header:"SOURCE",value:s=>s.source},{header:"NOTE",value:s=>s.note??"\u2014",max:40}]));let i=o.reduce((s,a)=>s+a.minutes,0);dt(Wn(`Total ${Is(i)}`));return}case"book":{let n=await qd(e),r=await R(e.creds,"PUT","/timesheets/entries",{entries:n,today:t});if(e.json){dt(I(r));return}dt(r.written===0?Wn("Nothing to write."):`Wrote ${r.written} ${r.written===1?"cell":"cells"}.`);return}default:throw new f(e.subcommand?`Unknown time command: ${e.subcommand}`:"time needs a command.",`One of: ${Ld.join(", ")}.`)}}import{promises as pt}from"node:fs";import{homedir as Jd}from"node:os";import{dirname as co,join as Re}from"node:path";import{dim as ve,green as lo,red as Yd,yellow as Hs}from"kleur/colors";var Se="anyforge-platform",Md="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",Ts="anyforge://guide/platform",Ud="text/markdown",Hn={"SKILL.md":`---
19
+ `);return await G.writeFile(e,n),!0}function Mi(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Br(e){try{return new URL(e).host}catch{return null}}function Ol(e){try{return ml("git",["rev-parse","--show-toplevel"],{cwd:e,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var Ve,an,ct,hl,gl,kl,Gr=he(()=>{"use strict";jn();Ve="# === AnyForge Control \u2014 added by `anyforge init` ===",an="# === end AnyForge Control ===",ct=".anyforge-bak",hl=/claude_(max|pro|team|enterprise)/i,gl=["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"];kl=[{label:"Cursor (shell hint)",async detect(){let e=Z(Le(),".cursor");return await Se(e)?{path:".cursor (shell hint)"}:null},async patch(e,t){await Li(t)}},{label:"Cline / Continue (shell hint)",async detect(){let e=await Se(Z(Le(),".cline")),t=await Se(Z(Le(),".continue"));return e||t?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(e,t){await Li(t)}}]});var Re,Al,Bi,xl,Bn,Om,_l,Am,Gi=he(()=>{"use strict";Re="anyforge-platform",Al="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",Bi="anyforge://guide/platform",xl="text/markdown",Bn={"SKILL.md":`---
76
20
  name: anyforge-platform
77
21
  description: >
78
22
  Orient an agent to AnyForge's structure, delivery model, surfaces, live control
@@ -314,7 +258,9 @@ scope). Fix CI's \`outOfScope\` grant covers one Engineer round and is audited
314
258
  under the key holder. \`anyforge_accept_crew_ci_check\` accepts ONE named failing
315
259
  check as known and out of scope, with a required reason, so the crew goes to
316
260
  review past it; \`anyforge_revoke_crew_ci_check\` undoes it. Autopilot never ships
317
- a pull request that carries one.
261
+ a pull request that carries one. \`anyforge_set_crew_base_merge\` (mode \`allow\`)
262
+ lifts a crew's "do not merge the base" from its task or earlier notes, audited;
263
+ \`anyforge_amend_crew\` with \`mergeBase: true\` does that and asks for the merge.
318
264
 
319
265
  Branch calls require a stable idempotency key in MCP. Repeat the same request
320
266
  with that key to retrieve its session receipt; changed arguments are refused.
@@ -421,64 +367,120 @@ these sources can grant network, filesystem, tool, or approval authority.
421
367
  Do not place API keys, tokens, credentials, private tenant records, or customer
422
368
  data in a reusable skill, prompt, log, or generated example. Use the client's
423
369
  credential mechanism and let the server enforce access.
424
- `,"references/tool-map.md":'# AnyForge MCP tool map\n\nTool names can grow as the platform grows. Use `tools/list` and the current\ntool description as the contract. The names below are representative entry\npoints in the public MCP server.\n\n## Discover and inspect\n\n- `anyforge_list_repo_index` and `anyforge_get_repo_analysis` discover connected\n repositories and their analysis.\n- `anyforge_list_programs` and `anyforge_get_program` inspect program records.\n- `anyforge_list_initiatives` and `anyforge_get_initiative` inspect scoped work.\n- `anyforge_list_work_items` and `anyforge_get_work_item` inspect delivery\n units.\n- `anyforge_list_crews` and `anyforge_get_crew` inspect Crew runs and output.\n For where one crew stands, call `anyforge_get_crew` with `messages: 0`: the\n crew leads with `status`, the halt reason, its work item and pull request,\n and the default summary shape leaves out the large snapshots (named in\n `omittedFields`). Pass `shape: "full"` only for a left-out field.\n- `anyforge_list_pending_approvals` and `anyforge_get_approval_detail` inspect\n human gates.\n- `anyforge_ask_oracle` asks a read-oriented cross-workspace question. A long investigation returns `running` with an `askId`; collect it with `anyforge_get_oracle_answer` rather than asking again. A turn that runs out of time is continued server-side under the same `askId` (`maxContinuations`, default 2), so a long answer arrives whole without a "continue" ask.\n\n### Find a work item by code\n\nFor a known full code, call `anyforge_list_work_items` with `itemId`:\n\n```json\n{ "itemId": "WBA-004", "limit": 5 }\n```\n\nUse the returned item\'s `id` with `anyforge_get_work_item` for its full details.\nFor a partial code or title, use `search` instead, for example\n`{ "search": "WBA-", "limit": 20 }`. Search is case-insensitive and matches\nsubstrings, so check the returned code and title before selecting a record.\nArchived items are excluded by default, including code lookups; add\n`"includeArchived": true` when looking for archived work. Check `hasMore` and\nfollow `nextCursor` with unchanged filters when there are more results.\n\n## Plan and write\n\n- `anyforge_create_program` and `anyforge_update_program` manage program\n records, including the lead and whether the program is long-lived;\n `anyforge_set_program_request_intake` switches its incoming requests, and\n `anyforge_set_program_status_line` writes its status line.\n- `anyforge_create_initiative`, `anyforge_update_initiative`, and\n `anyforge_dispatch_architect` manage initiative planning and dispatch.\n- `anyforge_create_work_item` and `anyforge_update_work_item` manage concrete\n delivery units. Labels are `tags`: set them on create, and change them with\n `action: \'update\'` and `addTags` / `removeTags` (no revision needed, at any\n status, finished items included). Replacing the whole list with `tags` needs\n `ifClassificationRevision`, the item\'s `classificationRevision`.\n `anyforge_get_work_item` returns `nextActions`, every status move the key can\n make now with the arguments to send; `status` with no action moves an item\n back to BACKLOG, REFINED or READY.\n- Program Genesis also exposes tools for the structured brief and reconciling\n program delivery. Read their schemas before use.\n\n## Approve and control\n\n- `anyforge_approve_backlog` and `anyforge_approve_task_proposal` advance\n approval-gated planning.\n- `anyforge_publish_initiative_spec` publishes a pending spec submission\n when the person has read it and asks for it (hosted MCP only).\n- `anyforge_submit_approval` records a human decision when the caller has the\n required approval scope.\n- `anyforge_resume_crew`, `anyforge_halt_crew`,\n `anyforge_message_crew`, and `anyforge_amend_crew` control a Crew run.\n `anyforge_fix_crew_ci`, `anyforge_resume_crew_with_pr` and\n `anyforge_decide_crew_permission` are the Build view\'s recovery actions.\n `anyforge_accept_crew_ci_check` and `anyforge_revoke_crew_ci_check` accept\n or revoke one failing check as known and out of scope (reason required).\n Explain the effect before calling them.\n\n## Selection rules\n\n1. Prefer the narrowest read tool that answers the question.\n2. Use a detail tool after a list result when a decision depends on fields not\n present in the list.\n3. Filter and page large lists. Do not request an unbounded workspace dump.\n4. Treat names and descriptions as hints; use the tool schema for required\n fields and allowed values.\n5. Before a mutation, restate the target, change, and likely side effect.\n6. After a mutation, read the target again and report the resulting state.\n'},pg=Object.entries(Hn).map(([e,t])=>({uri:e==="SKILL.md"?Ts:`${Ts}/${e}`,name:e==="SKILL.md"?Se:`${Se}/${e.replace(/^references\//,"")}`,title:e==="SKILL.md"?"AnyForge platform guide":e,description:e==="SKILL.md"?Md:`Reference for the ${Se} skill: ${e}`,mimeType:Ud,size:new TextEncoder().encode(t).byteLength}));var jd=Hn["SKILL.md"],fg=jd.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"");import{createHash as Dd,randomBytes as Bd}from"node:crypto";import{promises as ie}from"node:fs";import{dirname as ut,isAbsolute as Wd,join as Ne,relative as Gd,sep as $s}from"node:path";var Ps=100,Ls=256*1024,Ns=1024*1024,Hd=240,zd=8,$t=".anyforge-skill.json",Kd=/^[A-Za-z0-9._@+-][A-Za-z0-9 ._@+-]*$/;function qs(e){if(typeof e!="string")return null;let t=e.startsWith("./")?e.slice(2):e;if(!t||t.length>Hd||t.startsWith("/"))return null;let n=t.split("/");if(n.length>zd)return null;for(let o of n)if(o===""||o==="."||o===".."||o==="__pycache__"||!Kd.test(o))return null;let r=t.toLowerCase();return r==="skill.md"||r===$t.toLowerCase()?null:t}function to(e){return e.startsWith("scripts/")&&e.length>8}function Je(e){return Dd("sha256").update(e,"utf8").digest("hex")}function no(e,t){let n=[`SKILL.md\0${e}\0-`];for(let r of[...t].sort((o,i)=>o.path<i.path?-1:o.path>i.path?1:0))n.push(`${r.path}\0${r.sha256}\0${r.executable?"x":"-"}`);return Je(`${n.join(`
370
+ `,"references/tool-map.md":'# AnyForge MCP tool map\n\nTool names can grow as the platform grows. Use `tools/list` and the current\ntool description as the contract. The names below are representative entry\npoints in the public MCP server.\n\n## Discover and inspect\n\n- `anyforge_list_repo_index` and `anyforge_get_repo_analysis` discover connected\n repositories and their analysis.\n- `anyforge_list_programs` and `anyforge_get_program` inspect program records.\n- `anyforge_list_initiatives` and `anyforge_get_initiative` inspect scoped work.\n- `anyforge_list_work_items` and `anyforge_get_work_item` inspect delivery\n units.\n- `anyforge_list_crews` and `anyforge_get_crew` inspect Crew runs and output.\n For where one crew stands, call `anyforge_get_crew` with `messages: 0`: the\n crew leads with `status`, the halt reason, its work item and pull request,\n and the default summary shape leaves out the large snapshots (named in\n `omittedFields`). Pass `shape: "full"` only for a left-out field.\n- `anyforge_list_pending_approvals` and `anyforge_get_approval_detail` inspect\n human gates.\n- `anyforge_ask_oracle` asks a read-oriented cross-workspace question. A long investigation returns `running` with an `askId`; collect it with `anyforge_get_oracle_answer` rather than asking again. A turn that runs out of time is continued server-side under the same `askId` (`maxContinuations`, default 2), so a long answer arrives whole without a "continue" ask.\n\n### Find a work item by code\n\nFor a known full code, call `anyforge_list_work_items` with `itemId`:\n\n```json\n{ "itemId": "WBA-004", "limit": 5 }\n```\n\nUse the returned item\'s `id` with `anyforge_get_work_item` for its full details.\nFor a partial code or title, use `search` instead, for example\n`{ "search": "WBA-", "limit": 20 }`. Search is case-insensitive and matches\nsubstrings, so check the returned code and title before selecting a record.\nArchived items are excluded by default, including code lookups; add\n`"includeArchived": true` when looking for archived work. Check `hasMore` and\nfollow `nextCursor` with unchanged filters when there are more results.\n\n## Plan and write\n\n- `anyforge_create_program` and `anyforge_update_program` manage program\n records, including the lead and whether the program is long-lived;\n `anyforge_set_program_request_intake` switches its incoming requests, and\n `anyforge_set_program_status_line` writes its status line.\n- `anyforge_create_initiative`, `anyforge_update_initiative`, and\n `anyforge_dispatch_architect` manage initiative planning and dispatch.\n- `anyforge_create_work_item` and `anyforge_update_work_item` manage concrete\n delivery units. Labels are `tags`: set them on create, and change them with\n `action: \'update\'` and `addTags` / `removeTags` (no revision needed, at any\n status, finished items included). Replacing the whole list with `tags` needs\n `ifClassificationRevision`, the item\'s `classificationRevision`.\n `anyforge_get_work_item` returns `nextActions`, every status move the key can\n make now with the arguments to send; `status` with no action moves an item\n back to BACKLOG, REFINED or READY.\n- Program Genesis also exposes tools for the structured brief and reconciling\n program delivery. Read their schemas before use.\n\n## Approve and control\n\n- `anyforge_approve_backlog` and `anyforge_approve_task_proposal` advance\n approval-gated planning.\n- `anyforge_publish_initiative_spec` publishes a pending spec submission\n when the person has read it and asks for it (hosted MCP only).\n- `anyforge_submit_approval` records a human decision when the caller has the\n required approval scope.\n- `anyforge_resume_crew`, `anyforge_halt_crew`,\n `anyforge_message_crew`, and `anyforge_amend_crew` control a Crew run.\n `anyforge_fix_crew_ci`, `anyforge_resume_crew_with_pr` and\n `anyforge_decide_crew_permission` are the Build view\'s recovery actions.\n `anyforge_accept_crew_ci_check` and `anyforge_revoke_crew_ci_check` accept\n or revoke one failing check as known and out of scope (reason required).\n `anyforge_set_crew_base_merge` allows base merges on one crew past a\n prohibition in its task or notes (`anyforge_amend_crew` with\n `mergeBase: true` also asks for the merge). Explain the effect before\n calling them.\n\n## Selection rules\n\n1. Prefer the narrowest read tool that answers the question.\n2. Use a detail tool after a list result when a decision depends on fields not\n present in the list.\n3. Filter and page large lists. Do not request an unbounded workspace dump.\n4. Treat names and descriptions as hints; use the tool schema for required\n fields and allowed values.\n5. Before a mutation, restate the target, change, and likely side effect.\n6. After a mutation, read the target again and report the resulting state.\n'},Om=Object.entries(Bn).map(([e,t])=>({uri:e==="SKILL.md"?Bi:`${Bi}/${e}`,name:e==="SKILL.md"?Re:`${Re}/${e.replace(/^references\//,"")}`,title:e==="SKILL.md"?"AnyForge platform guide":e,description:e==="SKILL.md"?Al:`Reference for the ${Re} skill: ${e}`,mimeType:xl,size:new TextEncoder().encode(t).byteLength})),_l=Bn["SKILL.md"],Am=_l.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"")});function Sl(e,t,n){let r=t?`${e}: ${t}`:e;if(!n)return r;let o=JSON.stringify(n),i=o.length>Wi?`${o.slice(0,Wi)}\u2026(truncated)`:o;return`${r}
371
+ ${i}`}function Rl(e,t,n){if(e==="api_key_expired")return`This API key has expired. Mint a new key in Settings \u2192 API keys, then re-run \`npx @anyforge/control init\` or update ANYFORGE_API_TOKEN. See ${n?`${n.replace(/\/$/,"")}/docs?page=service-accounts-and-key-expiry`:'the "Service accounts and API key expiry" guide'}.`;if(e==="missing_api_key"||e==="invalid_api_key"||e==="invalid_token"||t===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(e==="insufficient_scope"||t===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(t===404)return"No such id in this company. Check it with the matching list command.";if(t===429)return"Rate limited. Retry after a short pause."}var g,h,f,Ie,Wi,ee,q=he(()=>{"use strict";g={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,VERIFICATION_FAILED:5,INTERRUPTED:130},h=class extends Error{exitCode;hint;constructor(t,n=g.FAILURE,r){super(t),this.name="CliError",this.exitCode=n,this.hint=r}},f=class extends h{constructor(t,n){super(t,g.USAGE,n),this.name="UsageError"}},Ie=class extends h{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",g.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},Wi=4e3,ee=class extends h{code;status;details;constructor(t,n,r,o,i){super(Sl(t,r,o),g.API_ERROR,Rl(t,n,i)),this.name="ControlApiError",this.code=t,this.status=n,o&&(this.details=o)}}});async function Ne(e){let t=process.env.ANYFORGE_API_TOKEN,n=e||process.env.ANYFORGE_API_URL;if(t)return{apiKey:t,endpoint:n||Hi};let r=await Tt();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||Hi};throw new Ie}function zi(e){Wr=e&&/^[a-z][a-z0-9-]*$/.test(e)?`anyforge ${e}`:null}async function S(e,t,n,r){let o=`${e.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`,"X-AnyForge-Client":"anyforge-cli",...Wr?{"X-AnyForge-Tool":Wr}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new h(`Cannot reach ${e.endpoint}: ${a instanceof Error?a.message:String(a)}`,g.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new h(`Non-JSON response from ${o} (HTTP ${i.status}).`,g.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 ee(a,i.status,c,Cl(s),e.endpoint)}return s.data}function Cl(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t=Object.entries(e).filter(([n,r])=>!Il.has(n)&&r!==void 0);return t.length?Object.fromEntries(t):void 0}function U(e){let t=Object.entries(e).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return t.length?`?${t.join("&")}`:""}var Hi,Wr,Il,W=he(()=>{"use strict";nn();q();Hi="https://crew.anyforge.ai";Wr=null;Il=new Set(["ok","error","message","detail"])});import{createHash as El,randomBytes as Tl}from"node:crypto";import{promises as ie}from"node:fs";import{dirname as lt,isAbsolute as $l,join as Fe,relative as Pl,sep as Ki}from"node:path";function Qi(e){if(typeof e!="string")return null;let t=e.startsWith("./")?e.slice(2):e;if(!t||t.length>Ll||t.startsWith("/"))return null;let n=t.split("/");if(n.length>Nl)return null;for(let o of n)if(o===""||o==="."||o===".."||o==="__pycache__"||!Fl.test(o))return null;let r=t.toLowerCase();return r==="skill.md"||r===Pt.toLowerCase()?null:t}function Hr(e){return e.startsWith("scripts/")&&e.length>8}function Xe(e){return El("sha256").update(e,"utf8").digest("hex")}function zr(e,t){let n=[`SKILL.md\0${e}\0-`];for(let r of[...t].sort((o,i)=>o.path<i.path?-1:o.path>i.path?1:0))n.push(`${r.path}\0${r.sha256}\0${r.executable?"x":"-"}`);return Xe(`${n.join(`
425
372
  `)}
426
- `)}var ee=class extends Error{constructor(t){super(t),this.name="SkillBundleError"}};function zn(e){if(e.length>Ps)throw new ee(`The skill has ${e.length} files; at most ${Ps} are installed.`);let t=new Set,n=0;for(let r of e){if(qs(r.path)!==r.path)throw new ee(`Refusing the file path "${String(r.path)}": it is not inside the skill's folder.`);let o=r.path.toLowerCase();if(t.has(o))throw new ee(`Refusing two files named "${r.path}" that differ only by case.`);if(t.add(o),!Number.isSafeInteger(r.size)||r.size<0||r.size>Ls)throw new ee(`Refusing "${r.path}": it is larger than ${Ls} bytes.`);if(typeof r.sha256!="string"||!/^[0-9a-f]{64}$/.test(r.sha256))throw new ee(`Refusing "${r.path}": it has no valid hash.`);n+=r.size}if(n>Ns)throw new ee(`The skill's files are larger than ${Ns} bytes together.`)}function Ms(e,t,n,r){if(zn(n),no(Je(e),n)!==t)throw new ee("The skill does not match its version hash. Nothing was installed; run the command again.");let o=new Map(r.map(i=>[i.path,i]));if(o.size!==r.length||r.length!==n.length)throw new ee("The skill's files do not match its file list. Nothing was installed.");for(let i of n){let s=o.get(i.path);if(!s||typeof s.content!="string")throw new ee(`The file "${i.path}" was not sent. Nothing was installed.`);if(Je(s.content)!==i.sha256||Buffer.byteLength(s.content,"utf8")!==i.size)throw new ee(`The file "${i.path}" does not match its hash. Nothing was installed.`)}}async function ro(e){try{return(await ie.lstat(e)).isSymbolicLink()}catch(t){let n=t.code;if(n==="ENOENT"||n==="ENOTDIR")return!1;throw t}}async function Ke(e,t){let n=Gd(e,t);if(n==="")return;if(n===".."||n.startsWith(`..${$s}`)||Wd(n))throw new ee(`Refusing to write to ${t}, outside ${e}.`);let r=e;for(let o of n.split($s))if(r=Ne(r,o),await ro(r))throw new ee(`Refusing to write through the symbolic link ${r}.`)}async function oo(e){let t=Ne(e,$t);if(await ro(t))return null;let n;try{n=await ie.readFile(t,"utf8")}catch(r){if(r.code==="ENOENT")return null;throw r}try{let r=JSON.parse(n);if(r.schema!==1||r.kind!=="library"&&r.kind!=="source"||typeof r.id!="string"||typeof r.version!="string"||!r.files||typeof r.files!="object")return null;let o={};for(let[i,s]of Object.entries(r.files))(i==="SKILL.md"||qs(i)===i)&&typeof s=="string"&&(o[i]=s);return{...r,files:o}}catch{return null}}async function un(e,t){let n=[];for(let[r,o]of Object.entries(t.files)){let i=Ne(e,r);if(await ro(i)){n.push(r);continue}try{Je(await ie.readFile(i,"utf8"))!==o&&n.push(r)}catch(s){let a=s.code;if(a==="ENOENT"||a==="ENOTDIR"||a==="EISDIR")n.push(r);else throw s}}return n}async function Us(e,t,n){let r=[];for(let o of n){if(Object.hasOwn(t.files,o.path))continue;let i=Ne(e,o.path);try{(!(await ie.lstat(i)).isFile()||Je(await ie.readFile(i,"utf8"))!==o.sha256)&&r.push(o.path)}catch(s){s.code!=="ENOENT"&&r.push(o.path)}}return r}async function Fs(e,t,n){let r=Ne(ut(e),`.anyforge-${Bd(6).toString("hex")}.tmp`),o=await ie.open(r,"wx",n?493:420);try{await o.writeFile(t,"utf8")}finally{await o.close()}try{await ie.chmod(r,n?493:420),await ie.rename(r,e)}catch(i){throw await ie.rm(r,{force:!0}),i}}async function io(e){let{base:t,directory:n}=e;await Ke(t,n),await ie.mkdir(n,{recursive:!0}),await Ke(t,n);let r=new Set(e.previous?await un(n,e.previous):[]),o=[],i={};for(let l of e.files){let d=Ne(n,l.path);await Ke(n,ut(d)),await ie.mkdir(ut(d),{recursive:!0}),await Ke(n,ut(d)),await Fs(d,l.content,l.executable&&to(l.path)),i[l.path]=Je(l.content),o.push(l.path)}let s=[],a=[];for(let l of Object.keys(e.previous?.files??{}))if(!Object.hasOwn(i,l)){if(r.has(l)&&!e.force){a.push(l);continue}await js(n,l),s.push(l)}let c={...e.manifest,files:i,installedAt:new Date().toISOString()};return await Fs(Ne(n,$t),`${JSON.stringify(c,null,2)}
427
- `,!1),{written:o,removed:s,kept:a}}async function js(e,t){let n=Ne(e,t);await Ke(e,ut(n)),await ie.rm(n,{force:!0});let r=ut(n);for(;r!==e&&r.startsWith(e);){try{await ie.rmdir(r)}catch{break}r=ut(r)}}async function Ds(e,t,n,r){await Ke(e,t);let o=new Set(await un(t,n)),i=[];for(let s of Object.keys(n.files)){if(o.has(s)&&!r){i.push(s);continue}await js(t,s)}if(i.length>0)return i;await ie.rm(Ne(t,$t),{force:!0});try{await ie.rmdir(t)}catch{}return i}var po={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills",opencode:".opencode/skills"};function fo(e,t=Se){let n=e.scope==="user"?e.homeDir??Jd():e.cwd??process.cwd();if(e.scope==="user"&&e.client==="codex"){let r=e.codexHome??process.env.CODEX_HOME??Re(n,".codex");return Re(r,"skills",t)}return e.scope==="user"&&e.client==="opencode"?Re(Zt(n,e.env),"skills",t):Re(n,po[e.client],t)}function mo(e){if(e.scope!=="project"&&e.scope!=="user")throw new f(`--scope must be project or user, got "${e.scope}".`);if(!Object.hasOwn(po,e.client))throw new f(`--client must be agents, claude, codex, or opencode, got "${e.client}".`)}async function so(e){try{return(await pt.lstat(e)).isSymbolicLink()}catch(t){if(t.code==="ENOENT")return!1;throw t}}function Vd(e){return Xd(Se,Hn,e)}async function Xd(e,t,n){mo(n);let r=fo(n,e),o=Object.entries(t),i=o.map(([c])=>Re(r,c));if(await so(r))throw new f(`Refusing to install through the symbolic link ${r}.`);let s=new Set(o.map(([c])=>co(c)).filter(c=>c!=="."));for(let c of s)if(await so(Re(r,c)))throw new f(`Refusing to install through the symbolic link ${Re(r,c)}.`);if(!n.force){let c=[];for(let l of i)try{await pt.access(l),c.push(l)}catch(d){if(d.code!=="ENOENT")throw d}if(c.length>0)throw new f(`The ${e} skill already exists at ${r}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await pt.mkdir(r,{recursive:!0});let a=[];for(let[c,l]of o){let d=Re(r,c);if(await pt.mkdir(co(d),{recursive:!0}),await so(d))throw new f(`Refusing to replace the symbolic link ${d}.`);await pt.writeFile(d,l,{encoding:"utf8",mode:420}),a.push(c)}return{name:e,scope:n.scope,client:n.client,directory:r,files:a}}function uo(e){let t=e.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64).replace(/-+$/,"");if(!t)throw new f(`The skill "${e}" has no name that can be used as a folder.`);return t}function ho(e){try{return uo(e.name)}catch{return uo(`skill-${e.id}`)}}function Qd(e){let t=/^---\r?\n([\s\S]*?)\r?\n---\r?\n/.exec(e);return!!t&&/^name:[ \t]*\S/m.test(t[1])&&/^description:[ \t]*\S/m.test(t[1])}function Zd(e){let t=e.content.endsWith(`
373
+ `)}function Gn(e){if(e.length>Ji)throw new te(`The skill has ${e.length} files; at most ${Ji} are installed.`);let t=new Set,n=0;for(let r of e){if(Qi(r.path)!==r.path)throw new te(`Refusing the file path "${String(r.path)}": it is not inside the skill's folder.`);let o=r.path.toLowerCase();if(t.has(o))throw new te(`Refusing two files named "${r.path}" that differ only by case.`);if(t.add(o),!Number.isSafeInteger(r.size)||r.size<0||r.size>Vi)throw new te(`Refusing "${r.path}": it is larger than ${Vi} bytes.`);if(typeof r.sha256!="string"||!/^[0-9a-f]{64}$/.test(r.sha256))throw new te(`Refusing "${r.path}": it has no valid hash.`);n+=r.size}if(n>Yi)throw new te(`The skill's files are larger than ${Yi} bytes together.`)}function Zi(e,t,n,r){if(Gn(n),zr(Xe(e),n)!==t)throw new te("The skill does not match its version hash. Nothing was installed; run the command again.");let o=new Map(r.map(i=>[i.path,i]));if(o.size!==r.length||r.length!==n.length)throw new te("The skill's files do not match its file list. Nothing was installed.");for(let i of n){let s=o.get(i.path);if(!s||typeof s.content!="string")throw new te(`The file "${i.path}" was not sent. Nothing was installed.`);if(Xe(s.content)!==i.sha256||Buffer.byteLength(s.content,"utf8")!==i.size)throw new te(`The file "${i.path}" does not match its hash. Nothing was installed.`)}}async function Kr(e){try{return(await ie.lstat(e)).isSymbolicLink()}catch(t){let n=t.code;if(n==="ENOENT"||n==="ENOTDIR")return!1;throw t}}async function Ye(e,t){let n=Pl(e,t);if(n==="")return;if(n===".."||n.startsWith(`..${Ki}`)||$l(n))throw new te(`Refusing to write to ${t}, outside ${e}.`);let r=e;for(let o of n.split(Ki))if(r=Fe(r,o),await Kr(r))throw new te(`Refusing to write through the symbolic link ${r}.`)}async function Jr(e){let t=Fe(e,Pt);if(await Kr(t))return null;let n;try{n=await ie.readFile(t,"utf8")}catch(r){if(r.code==="ENOENT")return null;throw r}try{let r=JSON.parse(n);if(r.schema!==1||r.kind!=="library"&&r.kind!=="source"||typeof r.id!="string"||typeof r.version!="string"||!r.files||typeof r.files!="object")return null;let o={};for(let[i,s]of Object.entries(r.files))(i==="SKILL.md"||Qi(i)===i)&&typeof s=="string"&&(o[i]=s);return{...r,files:o}}catch{return null}}async function ln(e,t){let n=[];for(let[r,o]of Object.entries(t.files)){let i=Fe(e,r);if(await Kr(i)){n.push(r);continue}try{Xe(await ie.readFile(i,"utf8"))!==o&&n.push(r)}catch(s){let a=s.code;if(a==="ENOENT"||a==="ENOTDIR"||a==="EISDIR")n.push(r);else throw s}}return n}async function es(e,t,n){let r=[];for(let o of n){if(Object.hasOwn(t.files,o.path))continue;let i=Fe(e,o.path);try{(!(await ie.lstat(i)).isFile()||Xe(await ie.readFile(i,"utf8"))!==o.sha256)&&r.push(o.path)}catch(s){s.code!=="ENOENT"&&r.push(o.path)}}return r}async function Xi(e,t,n){let r=Fe(lt(e),`.anyforge-${Tl(6).toString("hex")}.tmp`),o=await ie.open(r,"wx",n?493:420);try{await o.writeFile(t,"utf8")}finally{await o.close()}try{await ie.chmod(r,n?493:420),await ie.rename(r,e)}catch(i){throw await ie.rm(r,{force:!0}),i}}async function Vr(e){let{base:t,directory:n}=e;await Ye(t,n),await ie.mkdir(n,{recursive:!0}),await Ye(t,n);let r=new Set(e.previous?await ln(n,e.previous):[]),o=[],i={};for(let l of e.files){let d=Fe(n,l.path);await Ye(n,lt(d)),await ie.mkdir(lt(d),{recursive:!0}),await Ye(n,lt(d)),await Xi(d,l.content,l.executable&&Hr(l.path)),i[l.path]=Xe(l.content),o.push(l.path)}let s=[],a=[];for(let l of Object.keys(e.previous?.files??{}))if(!Object.hasOwn(i,l)){if(r.has(l)&&!e.force){a.push(l);continue}await ts(n,l),s.push(l)}let c={...e.manifest,files:i,installedAt:new Date().toISOString()};return await Xi(Fe(n,Pt),`${JSON.stringify(c,null,2)}
374
+ `,!1),{written:o,removed:s,kept:a}}async function ts(e,t){let n=Fe(e,t);await Ye(e,lt(n)),await ie.rm(n,{force:!0});let r=lt(n);for(;r!==e&&r.startsWith(e);){try{await ie.rmdir(r)}catch{break}r=lt(r)}}async function ns(e,t,n,r){await Ye(e,t);let o=new Set(await ln(t,n)),i=[];for(let s of Object.keys(n.files)){if(o.has(s)&&!r){i.push(s);continue}await ts(t,s)}if(i.length>0)return i;await ie.rm(Fe(t,Pt),{force:!0});try{await ie.rmdir(t)}catch{}return i}var Ji,Vi,Yi,Ll,Nl,Pt,Fl,te,rs=he(()=>{"use strict";Ji=100,Vi=256*1024,Yi=1024*1024,Ll=240,Nl=8,Pt=".anyforge-skill.json",Fl=/^[A-Za-z0-9._@+-][A-Za-z0-9 ._@+-]*$/;te=class extends Error{constructor(t){super(t),this.name="SkillBundleError"}}});var ws={};hi(ws,{companySkillSlug:()=>zn,fetchCompanySkill:()=>us,installPlatformSkill:()=>as,installRemoteSkill:()=>io,installSkillFiles:()=>cs,installSlugFor:()=>Jn,renderCompanySkill:()=>ls,resolveSkillInstallDirectory:()=>Kn,resolveSkillsRoot:()=>oo,runSkill:()=>so,syncSkills:()=>eo});import{promises as dt}from"node:fs";import{homedir as Ml}from"node:os";import{dirname as Qr,join as Ce}from"node:path";import{dim as Oe,green as Zr,red as ql,yellow as ss}from"kleur/colors";function Kn(e,t=Re){let n=e.scope==="user"?e.homeDir??Ml():e.cwd??process.cwd();if(e.scope==="user"&&e.client==="codex"){let r=e.codexHome??process.env.CODEX_HOME??Ce(n,".codex");return Ce(r,"skills",t)}return e.scope==="user"&&e.client==="opencode"?Ce(rn(n,e.env),"skills",t):Ce(n,to[e.client],t)}function no(e){if(e.scope!=="project"&&e.scope!=="user")throw new f(`--scope must be project or user, got "${e.scope}".`);if(!Object.hasOwn(to,e.client))throw new f(`--client must be agents, claude, codex, or opencode, got "${e.client}".`)}async function Yr(e){try{return(await dt.lstat(e)).isSymbolicLink()}catch(t){if(t.code==="ENOENT")return!1;throw t}}function as(e){return cs(Re,Bn,e)}async function cs(e,t,n){no(n);let r=Kn(n,e),o=Object.entries(t),i=o.map(([c])=>Ce(r,c));if(await Yr(r))throw new f(`Refusing to install through the symbolic link ${r}.`);let s=new Set(o.map(([c])=>Qr(c)).filter(c=>c!=="."));for(let c of s)if(await Yr(Ce(r,c)))throw new f(`Refusing to install through the symbolic link ${Ce(r,c)}.`);if(!n.force){let c=[];for(let l of i)try{await dt.access(l),c.push(l)}catch(d){if(d.code!=="ENOENT")throw d}if(c.length>0)throw new f(`The ${e} skill already exists at ${r}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await dt.mkdir(r,{recursive:!0});let a=[];for(let[c,l]of o){let d=Ce(r,c);if(await dt.mkdir(Qr(d),{recursive:!0}),await Yr(d))throw new f(`Refusing to replace the symbolic link ${d}.`);await dt.writeFile(d,l,{encoding:"utf8",mode:420}),a.push(c)}return{name:e,scope:n.scope,client:n.client,directory:r,files:a}}function zn(e){let t=e.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64).replace(/-+$/,"");if(!t)throw new f(`The skill "${e}" has no name that can be used as a folder.`);return t}function Jn(e){try{return zn(e.name)}catch{return zn(`skill-${e.id}`)}}function Ul(e){let t=/^---\r?\n([\s\S]*?)\r?\n---\r?\n/.exec(e);return!!t&&/^name:[ \t]*\S/m.test(t[1])&&/^description:[ \t]*\S/m.test(t[1])}function ls(e){let t=e.content.endsWith(`
428
375
  `)?e.content:`${e.content}
429
- `;if(Qd(t))return{"SKILL.md":t};let n=(e.description??"").trim()||e.name;return{"SKILL.md":`---
430
- name: ${ho(e)}
376
+ `;if(Ul(t))return{"SKILL.md":t};let n=(e.description??"").trim()||e.name;return{"SKILL.md":`---
377
+ name: ${Jn(e)}
431
378
  description: ${JSON.stringify(n)}
432
379
  ---
433
380
 
434
- ${t}`}}async function zs(e){let{skills:t}=await R(e,"GET","/skills");return t}async function eu(e,t){let n=t.trim().toLowerCase(),r=await zs(e),o=s=>{try{return uo(s)}catch{return null}},i=r.find(s=>s.name.trim().toLowerCase()===n)??r.find(s=>o(s.name)===n);if(!i)throw new f(`No skill named "${t}" in your company's library.`,"Run `anyforge skill list` to see the skills you can install.");return R(e,"GET",`/skills/${encodeURIComponent(i.id)}`)}var tu=new Set(["skill_not_found","skill_no_longer_available"]);function nu(e){return e instanceof Q&&e.status===404&&tu.has(e.code)}async function Ks(e,t){let n=await R(e,"GET",`/skills/${encodeURIComponent(t)}`),r=Array.isArray(n.files)?n.files:[];return{kind:"library",id:n.id,name:n.name,description:n.description,content:n.content,files:r,version:typeof n.version?.hash=="string"?n.version.hash:no(Je(n.content),r),...typeof n.version?.revision=="number"?{revision:n.version.revision}:{}}}async function go(e,t,n){let r=await R(e,"GET",`/skill-sources/skills/${encodeURIComponent(t)}${M({repo:n??void 0})}`);return{kind:"source",id:r.id,name:r.name,description:r.description,content:r.content,files:Array.isArray(r.files)?r.files:[],version:r.version.hash,commit:r.version.commit,repo:r.repo}}function ru(e,t,n,r){return t==="library"?Ks(e,n):go(e,n,r)}async function Js(e,t,n){return R(e,"GET",`/skill-sources/skills${M({repo:t??void 0,team:n})}`)}async function Ys(e,t,n){zn(t.files);let r=[];if(t.files.length>0){let s=t.kind==="library"?`/skills/${encodeURIComponent(t.id)}/files`:`/skill-sources/skills/${encodeURIComponent(t.id)}/files${M({repo:n??void 0})}`;r=(await R(e,"GET",s)).files??[]}Ms(t.content,t.version,t.files,r);let o=t.kind==="library"?Zd(t)["SKILL.md"]:t.content,i=new Map(r.map(s=>[s.path,s]));return[{path:"SKILL.md",content:o,executable:!1},...t.files.map(s=>({path:s.path,content:i.get(s.path).content,executable:s.executable===!0&&to(s.path)}))]}function Vs(e){return{schema:1,kind:e.kind,id:e.id,name:e.name,...e.repo?{repo:e.repo}:{},...e.commit?{commit:e.commit}:{},...e.revision!==void 0?{revision:e.revision}:{},version:e.version}}function Xs(e){return co(fo(e,"x"))}function Jn(e){return e.scope==="project"?e.cwd??process.cwd():Xs(e)}async function Qs(e,t,n){mo(n);let r=ho(t),o=fo(n,r),i=await Ys(e,t,n.repo??null),s=await oo(o);if(!n.force){if(s&&s.id===t.id)throw new f(`The ${r} skill is already installed at ${o}.`,"Run `anyforge skill sync` to bring it up to date, or --force to reinstall it.");let c=[];for(let l of[...i.map(d=>d.path),$t])try{await pt.lstat(Re(o,l)),c.push(l)}catch(d){if(d.code!=="ENOENT")throw d}if(c.length>0)throw new f(`The ${r} skill already exists at ${o}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}let a=await io({base:Jn(n),directory:o,files:i,manifest:Vs(t),previous:s&&s.id===t.id?s:null,force:n.force===!0});return{name:r,scope:n.scope,client:n.client,directory:o,files:a.written,id:t.id,kind:t.kind,version:t.version,removed:a.removed}}async function ou(e){let t;try{t=await pt.readdir(e,{withFileTypes:!0})}catch(r){if(r.code==="ENOENT")return[];throw r}let n=[];for(let r of t.sort((o,i)=>o.name.localeCompare(i.name))){if(!r.isDirectory())continue;let o=Re(e,r.name),i=await oo(o);i&&n.push({directory:o,manifest:i})}return n}function Kn(e){return e instanceof Error?e.message:String(e)}async function Bs(e,t){mo(t);let n=Xs(t),r=t.repo??null,o=t.force===!0,i=t.dryRun===!0;await Ke(Jn(t),n);let s=null;if(t.team&&(s=await Js(e,r,t.team),s.sources.length===0))throw new f(`No skill source is owned by the team "${t.team}".`,"Check the team's slug on its page in the Console.");let a=new Set(s?.sources.map(y=>y.id)??[]),c=y=>{let v=y.startsWith("source:")?y.slice(7):null;return v&&v.includes(":")?v.slice(0,v.indexOf(":")):null},l=(await ou(n)).filter(({manifest:y})=>!s||y.kind==="source"&&a.has(c(y.id)??"")),d=[];for(let{directory:y,manifest:v}of l){let x={name:v.name,id:v.id,kind:v.kind},b;try{b=await ru(e,v.kind,v.id,r)}catch(m){if(!nu(m)){d.push({...x,action:"failed",reason:Kn(m)});continue}try{let A=await un(y,v);if(A.length>0&&!o){d.push({...x,action:"kept",files:A,reason:"removed upstream, but you edited it"});continue}i||await Ds(Jn(t),y,v,o),d.push({...x,action:"removed"})}catch(A){d.push({...x,action:"failed",reason:Kn(A)})}continue}try{let m=await un(y,v);if(b.version===v.version&&!(o&&m.length>0)){d.push({...x,action:"unchanged"});continue}if(m.length>0&&!o){d.push({...x,action:"kept",files:m,reason:"you edited it"});continue}let A=await Us(y,v,b.files);if(A.length>0&&!o){d.push({...x,action:"kept",files:A,reason:"the new version adds files you already have"});continue}if(i){zn(b.files),d.push({...x,action:"updated"});continue}let L=await Ys(e,b,r),j=await io({base:Jn(t),directory:y,files:L,manifest:Vs(b),previous:v,force:o});d.push({...x,action:"updated",...j.removed.length>0?{files:j.removed}:{}})}catch(m){d.push({...x,action:"failed",reason:Kn(m)})}}let u=new Set(l.map(({manifest:y})=>y.id));for(let y of s?.skills??[]){if(u.has(y.id))continue;let v={name:y.name,id:y.id,kind:"source"};try{if(i){d.push({...v,action:"added"});continue}let x=await go(e,y.id,r);await Qs(e,x,{...t,repo:r,force:!1}),d.push({...v,action:"added"})}catch(x){d.push({...v,action:"failed",reason:Kn(x)})}}return{dryRun:i,scope:t.scope,client:t.client,directory:n,results:d}}function ao(e){let t=e.scope??"project",n=e.client??"agents";if(!["project","user"].includes(t))throw new f(`--scope must be project or user, got "${t}".`);if(!Object.hasOwn(po,n))throw new f(`--client must be agents, claude, codex, or opencode, got "${n}".`);let r=e.repo!==void 0?e.repo:t==="project"?$r(e.cwd??process.cwd()):null;return{scope:t,client:n,force:e.force,...e.cwd?{cwd:e.cwd}:{},...e.homeDir?{homeDir:e.homeDir}:{},...e.codexHome?{codexHome:e.codexHome}:{},repo:r}}async function Zs(e,t,n){try{return(await Js(e,t,n)).skills}catch(r){if(!n&&r instanceof Q&&(r.status===403||r.status===404))return[];throw r}}async function iu(e,t,n,r){let o=t.trim().toLowerCase();if(!r)try{let a=await eu(e,t);return Ks(e,a.id)}catch(a){if(!(a instanceof f))throw a}let i=await Zs(e,n,r),s=i.find(a=>a.name.toLowerCase()===o)??i.find(a=>ho(a)===o);if(!s)throw new f(r?`The team "${r}" has no skill named "${t}" in its skill sources.`:`No skill named "${t}" in your company's library or skill sources.`,"Run `anyforge skill list` to see the skills you can install.");return go(e,s.id,n)}var su={added:"added",updated:"updated",unchanged:"unchanged",removed:"removed upstream",kept:"kept",failed:"failed"};function Ws(e){let t=e.dryRun?"Would sync":"Synced";console.log(`${lo(t)} ${e.results.length} ${e.results.length===1?"skill":"skills"} ${ve(`(${e.scope}, ${e.client})`)}`),console.log(` ${e.directory}`);for(let n of e.results){let r=su[n.action].padEnd(16),o=n.action==="failed"?Yd:n.action==="kept"?Hs:n.action==="unchanged"?ve:lo,i=n.action==="kept"?ve(` \u2014 ${n.reason}: ${(n.files??[]).join(", ")}. --force replaces it.`):n.action==="failed"?ve(` \u2014 ${n.reason}`):"";console.log(` ${o(r)} ${n.name}${i}`)}e.results.length===0&&console.log(ve(" No skills installed by AnyForge here. Install one with `anyforge skill install <name>`."))}async function ea(e){if(e.subcommand==="list"){let i=await e.resolveCreds(),{repo:s}=ao(e),[a,c]=await Promise.all([e.team?Promise.resolve([]):zs(i),Zs(i,s,e.team)]);if(e.json){process.stdout.write(JSON.stringify({skills:a,sourceSkills:c})+`
435
- `);return}a.length===0&&c.length===0&&console.log(ve("Your company has no skills in its library yet."));for(let l of a)console.log(`${l.name}${l.description?ve(` \u2014 ${l.description}`):""}`);for(let l of c)console.log(`${l.name} ${ve(`(${l.repo})`)}${l.description?ve(` \u2014 ${l.description}`):""}`);return}if(e.subcommand==="sync"){let i=await Bs(await e.resolveCreds(),{...ao(e),team:e.team,dryRun:e.dryRun});e.json?process.stdout.write(JSON.stringify(i)+`
436
- `):Ws(i);let s=i.results.filter(a=>a.action==="failed").length;if(s>0)throw new h(`${s} ${s===1?"skill":"skills"} could not be synced.`,g.FAILURE);return}if(e.subcommand!=="install")throw new f(`Unknown skill command${e.subcommand?`: ${e.subcommand}`:""}.`,"Use `anyforge skill list`, `anyforge skill install <name>` or `anyforge skill sync`.");if(!e.name&&!e.team)throw new f("Name the skill to install.",`Use \`anyforge skill install ${Se}\`, or \`anyforge skill list\` for your company's skills.`);let t=ao(e);if(e.name===Se&&!e.team){let i=await Vd(t);Gs(i,e.json);return}let n=await e.resolveCreds();if(!e.name&&e.team){let i=await Bs(n,{...t,team:e.team});e.json?process.stdout.write(JSON.stringify(i)+`
437
- `):Ws(i);let s=i.results.filter(a=>a.action==="failed").length;if(s>0)throw new h(`${s} ${s===1?"skill":"skills"} could not be installed.`,g.FAILURE);return}let r=await iu(n,e.name,t.repo,e.team),o;try{o=await Qs(n,r,t)}catch(i){throw i instanceof ee?new h(i.message,g.FAILURE):i}Gs(o,e.json)}function Gs(e,t){if(t){process.stdout.write(JSON.stringify(e)+`
438
- `);return}console.log(lo("Installed ")+`${e.name} ${ve(`(${e.scope}, ${e.client})`)}`),console.log(` ${e.directory}`);let n=e.name===Se?"Re-run with --force to refresh them.":"Run `anyforge skill sync` to update it.";console.log(ve(` ${e.files.length} ${e.files.length===1?"file":"files"} installed. ${n}`)),e.name===Se&&e.scope==="project"&&e.client==="agents"&&console.log(Hs(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as Tp}from"node:crypto";import{open as $p,realpath as Pp,stat as Lp}from"node:fs/promises";import{basename as Np,join as Fp,resolve as qp}from"node:path";import{bold as Wo,cyan as sc,dim as We,yellow as wr}from"kleur/colors";import{ProcessTerminal as Mp,SelectList as Up,Text as jp,TuiAltScreen as Dp}from"@earendil-works/pi-tui";var au=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function cu(e){return au.has(e)?"querying the code graph":e==="search_code_semantic"?"searching the code index":e==="search_codebase_docs"?"searching codebase docs":null}function Pt(e){let t=cu(e);if(t)return t;let n=/^mcp__(.+?)__(.+)$/.exec(e);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:e.replace(/_/g," ")}var lu=new Set(["ask_user","present_catch_up_decision","present_memory_candidates","present_skill_proposal"]);function Lt(e){return typeof e=="string"&&lu.has(e)}import{truncateToWidth as kn,wrapTextWithAnsi as Ra}from"@earendil-works/pi-tui";import{cyan as Co,dim as gt,green as _a,italic as Bu,red as To,yellow as $o}from"kleur/colors";import{truncateToWidth as pn,visibleWidth as wo,wrapTextWithAnsi as du}from"@earendil-works/pi-tui";import{bold as uu,dim as pu}from"kleur/colors";function J(e){return e<1024?`${e} B`:e<1024*1024?`${fn(e/1024)} KiB`:`${fn(e/(1024*1024))} MiB`}function mn(e){let t=Math.max(0,e);if(t<1e4)return`${fn(t/1e3)}s`;let n=Math.round(t/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 yo(e){let t=Math.floor(Math.max(0,e)/1e3);return t<60?`${t}s`:`${Math.floor(t/60)}m ${String(t%60).padStart(2,"0")}s`}function be(e){return Math.abs(e)<1e3?String(Math.round(e)):Math.abs(e)<1e6?`${fn(e/1e3,e<1e5?1:0)}k`:`${fn(e/1e6)}M`}function fn(e,t=1){return e.toFixed(t).replace(/\.0+$/,"")}function fu(e){return p(e).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function mu(e,t){return typeof t=="boolean"?t?"on":"off":typeof t=="string"?p(t):/Ms$/.test(e)?mn(t):/Bytes$/.test(e)?J(t):/tokens?/i.test(e)?be(t):String(t)}function ta(e){return e?Object.entries(e).filter(t=>t[1]!==null).map(([t,n])=>`${fu(t)} ${mu(t,n)}`):[]}function vo(e,t,n=2){let r=Math.min(16,Math.max(...e.map(([s])=>wo(s)),0)+2),o=Math.max(10,t-n-r),i=[];for(let[s,a]of e)du(a,o).forEach((l,d)=>{let u=d===0?pu(pn(s,r-1).padEnd(r)):" ".repeat(r);i.push(pn(`${" ".repeat(n)}${u}${l}`,t))});return i}function na(e,t,n){return[pn(uu(e),n),...vo(t,n)]}function ra(e,t,n){let r=wo(n),o=t.filter(Boolean).join(" \xB7 ");if(r+4>e)return pn(o||n,e);let i=e-r-2,s=pn(o,i),a=Math.max(2,e-wo(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as Ft,cyan as Nt,dim as Ye,green as hu,italic as oa,strikethrough as gu,underline as ia,yellow as wu}from"kleur/colors";import{Markdown as yu}from"@earendil-works/pi-tui";var vu={heading:e=>Ft(Nt(e)),link:e=>ia(Nt(e)),linkUrl:e=>Ye(e),code:e=>wu(e),codeBlock:e=>e,codeBlockBorder:e=>Ye(e),quote:e=>oa(e),quoteBorder:e=>Ye(e),hr:e=>Ye(e),listBullet:e=>Nt(e),bold:e=>Ft(e),italic:e=>oa(e),strikethrough:e=>gu(e),underline:e=>ia(e)},Mt={selectedPrefix:e=>Nt(e),selectedText:e=>Ft(e),description:e=>Ye(e),scrollInfo:e=>Ye(e),noMatch:e=>Ye(e)},sa={borderColor:e=>Ye(e),selectList:Mt},qt=class{constructor(t,n){this.linkOrigin=n;this.content=p(t),this.markdown=new yu(Mr(this.content,n),0,0,vu)}linkOrigin;content;markdown;cache;getText(){return this.content}setText(t){let n=p(t);n!==this.content&&(this.content=n,this.markdown.setText(Mr(n,this.linkOrigin)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(t){let n=Math.max(12,t);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(Ni):[];return this.cache={width:n,lines:r},r}};function hn(e,t){return e==="user"?`${Ft(hu(t?p(t):"You"))}`:`${Ft(Nt("Oracle"))}`}function aa(e,t,n){let r=Nt("\u2502"),o=Math.max(1,t-4);return["",`${r} ${hn("user",n)}`,...e.render(o).map(i=>`${r} ${Ft(i)}`),""]}function Fe(e){return e.shared||e.visibility==="company"?`Shared with the company${e.entityKey?` \xB7 ${p(e.entityKey)}`:""}`:"Private to you"}function ca(e){return e.shared||e.visibility==="company"?"shared":"private"}import{createReadStream as Nu}from"node:fs";import{stat as Fu}from"node:fs/promises";import{basename as qu}from"node:path";import{setTimeout as Oa}from"node:timers/promises";var la={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 da(e){let t=e.slice(e.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(la,t)?la[t]:null}var bo="/api/v1/oracle";var ua="workspace";function Ve(e){let t;try{t=new URL(e)}catch{throw new h(`Invalid Oracle endpoint: ${e}`,g.USAGE)}if(!["http:","https:"].includes(t.protocol)||t.username||t.password)throw new h("Oracle endpoint must be an http or https URL without embedded credentials.",g.USAGE);if(t.pathname!=="/"||t.search||t.hash)throw new h("Oracle endpoint must be the workspace origin, without a path, query or fragment.",g.USAGE);return t.origin}function qe(e,t){return`${Ve(e)}${bo}${t}`}function bu(e,t,n){let r;try{r=new URL(e)}catch{throw new h(`Oracle server returned an invalid ${n} endpoint.`,g.API_ERROR)}let o=new URL(Ve(t));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new h(`Oracle server returned an unsafe ${n} endpoint.`,g.API_ERROR);return r.toString()}function ku(e,t){if(!e||typeof e!="object")throw new h("Oracle server omitted OAuth endpoints.",g.API_ERROR);let n=e,r=["registration","authorization","token","revocation"],o={};for(let i of r){if(typeof n[i]!="string")throw new h(`Oracle server omitted its OAuth ${i} endpoint.`,g.API_ERROR);o[i]=bu(n[i],t,i)}return o}async function ft(e,t=fetch,n,r){let o=Ve(e),i;try{i=await t(qe(o,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:r?AbortSignal.any([r,AbortSignal.timeout(2e4)]):AbortSignal.timeout(2e4)})}catch(u){throw new h(`Cannot reach ${o}: ${u instanceof Error?u.message:String(u)}`,g.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let s=await Dt(i,qe(o,"/config")),a=q(jt(s,i.status)),c=`${o}${bo}`;if(a.protocolVersion!==1)throw new h(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(a.protocolVersion)}.`,g.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(a.resource!==c)throw new h("Oracle server resource does not match this workspace origin.",g.API_ERROR);let l=Array.isArray(a.scopes)?a.scopes:null;if(!l||!l.every(u=>u==="read"||u==="write"||u==="approve"))throw new h("Oracle server returned an invalid scope list.",g.API_ERROR);let d={protocolVersion:1,resource:c,scopes:l,oauth:ku(a.oauth,o)};if(a.identity!==void 0){let u=q(a.identity);if(typeof u.uid!="string"||typeof u.companyId!="string")throw new h("Oracle server returned an invalid identity.",g.API_ERROR);let y=typeof u.companyName=="string"?p(u.companyName).trim().slice(0,120):"";d.identity={uid:p(u.uid),companyId:p(u.companyId),...y?{companyName:y}:{}}}if(a.capabilities!==void 0){let u=q(a.capabilities);if(![u.read,u.write,u.approve].every(y=>typeof y=="boolean"))throw new h("Oracle server returned invalid capabilities.",g.API_ERROR);d.capabilities={read:u.read,write:u.write,approve:u.approve}}if(a.model!==void 0){let u=q(a.model);if(typeof u.id!="string"||typeof u.provider!="string")throw new h("Oracle server returned invalid model metadata.",g.API_ERROR);d.model={id:p(u.id),provider:p(u.provider)}}if(a.limits!==void 0){let u=q(a.limits);if(Object.values(u).some(y=>!["string","number","boolean"].includes(typeof y)&&y!==null))throw new h("Oracle server returned invalid limits metadata.",g.API_ERROR);d.limits=Object.fromEntries(Object.entries(u).map(([y,v])=>[p(y),typeof v=="string"?p(v):v]))}return Array.isArray(a.commands)&&(d.commands=Ou(a.commands)),d}function Ou(e){let t=[];for(let n of e.slice(0,50)){let r=q(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||t.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?p(r.args).slice(0,60).trim():"";t.push({name:r.name,description:p(r.description).slice(0,200),...o?{args:o}:{}})}return t}var we=class{endpoint;scopes;source;#e;#n;#t;cachedConfig;constructor(t,n=fetch){this.endpoint=Ve(t.endpoint),this.#e=t.getAccessToken??(async()=>t.accessToken),this.#n=t.onIdentity,this.#t=n,this.scopes=new Set(t.scopes),this.source=t.source}async config(t){if(!this.cachedConfig){let n=await this.#e();try{this.cachedConfig=await ft(this.endpoint,this.#t,n,t)}catch(o){if(this.source!=="oauth"||!(o instanceof Q)||o.status!==401)throw o;let i=await this.#e(n);if(i===n)throw o;this.cachedConfig=await ft(this.endpoint,this.#t,i,t)}let r=this.cachedConfig.identity;r&&this.#n&&await this.#n(r).catch(()=>{})}return this.cachedConfig}async listSessions(){let t=await this.json("GET","/sessions"),n=Array.isArray(t)?t:q(t).sessions;if(!Array.isArray(n))throw new h("Oracle server returned an invalid sessions list.",g.API_ERROR);return n.map(ma)}async createSession(t={},n){let r=await this.json("POST","/sessions",t,n),o=q(r);return!Array.isArray(o.messages)&&typeof o.sessionId=="string"?this.getSession(o.sessionId,n):pa(r)}async getSession(t,n){return pa(await this.json("GET",`/sessions/${encodeURIComponent(t)}`,void 0,n))}async submitTurn(t,n,r,o){let i,s=qe(this.endpoint,`/sessions/${encodeURIComponent(t)}/turns`),a=async l=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${l}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let l=await this.#e();if(i=await a(l),i.status===401&&this.source==="oauth"){let d=await this.#e(l);d!==l&&(i=await a(d))}}catch(l){throw l instanceof h||r?.aborted?l:new h(`Oracle connection was interrupted: ${l instanceof Error?l.message:String(l)}`,g.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await Ut(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let l=await Dt(i,qe(this.endpoint,`/sessions/${t}/turns`)),d=jt(l,i.status);throw new h(`Oracle server did not start a stream (${Au(d)}).`,g.API_ERROR)}return i}async replayEvents(t,n,r){let o=[];for await(let i of this.streamReplayEvents(t,n,r))o.push(i);return o}async*streamReplayEvents(t,n,r,o,i){let s=`/sessions/${encodeURIComponent(t)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,a=await this.authenticatedFetch("GET",s,{headers:{Accept:"text/event-stream, application/json"},signal:i},0);if(a.ok||await Ut(a),(a.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*gn(a,o);return}let l=jt(await Dt(a,qe(this.endpoint,s)),a.status),d=Array.isArray(l)?l:q(l).events;if(!Array.isArray(d))throw new h("Oracle replay response did not contain events.",g.API_ERROR);for(let u of d)yield ko(u)}async*streamRequestEvents(t,n,r=-1,o,i){let s=`/sessions/${encodeURIComponent(t)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,a=await this.authenticatedFetch("GET",s,{headers:{Accept:"text/event-stream, application/json"},signal:i},0);if(a.ok||await Ut(a),(a.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*gn(a,o);return}let l=jt(await Dt(a,qe(this.endpoint,s)),a.status),d=Array.isArray(l)?l:q(l).events;if(!Array.isArray(d))throw new h("Oracle request replay response did not contain events.",g.API_ERROR);for(let u of d)yield ko(u)}async cancelTurn(t,n){return this.json("POST",`/sessions/${encodeURIComponent(t)}/cancel`,{streamId:n})}async cancelRequest(t,n,r){return this.json("POST",`/sessions/${encodeURIComponent(t)}/cancel`,{requestId:n},r)}async upload(t,n){let r=new FormData;r.set("sessionId",t),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 Ut(o),Su(jt(await Dt(o,qe(this.endpoint,"/uploads")),o.status))}async download(t,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(t)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await Ut(r),r}async json(t,n,r,o){let i=await this.authenticatedFetch(t,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{},...o?{signal:o}:{}});return i.ok||await Ut(i),jt(await Dt(i,qe(this.endpoint,n)),i.status)}async authenticatedFetch(t,n,r={},o=2e4){try{let i=qe(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=o<=0?void 0:AbortSignal.timeout(o),c=r.signal&&a?AbortSignal.any([r.signal,a]):r.signal??a,l=v=>this.#t(i,{...r,method:t,headers:{...s,Authorization:`Bearer ${v}`},redirect:"error",...c?{signal:c}:{}}),d=await this.#e(),u=await l(d),y=r.body===void 0||typeof r.body=="string"||r.body===null;if(u.status===401&&this.source==="oauth"){let v=await this.#e(d);v!==d&&y&&(u=await l(v))}return u}catch(i){throw i instanceof h?i:new h(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,g.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*gn(e,t){if(!e.body)throw new h("Oracle stream has no response body.",g.FAILURE);let n=e.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,l=()=>{if(s.length===0)return null;let d=s.join(`
439
- `);if(s=[],a=0,d==="[DONE]")return null;let u;try{u=JSON.parse(d)}catch{throw new h("Oracle stream returned invalid JSON.",g.API_ERROR)}let y=ko(u);return y.type==="finalizing"?y:y.idx<=c?null:(c=y.idx,y)};try{for(;;){let{value:u,done:y}=await n.read();u?.byteLength&&t?.();let v=r.decode(u,{stream:!y});if(o+=v,i+=Yn(v),i>2*1024*1024)throw new h("Oracle stream event exceeded the 2 MiB protocol limit.",g.API_ERROR);let x=0,b=o.indexOf(`
440
- `,x);for(;b>=0;){let m=o.slice(x,b).replace(/\r$/,"");if(i-=Yn(o.slice(x,b+1)),x=b+1,m===""){let A=l();A&&(yield A)}else if(!m.startsWith(":")){let A=m.indexOf(":"),L=A<0?m:m.slice(0,A),j=A<0?"":m.slice(A+1).replace(/^ /,"");if(L==="data"&&(s.push(j),a+=Yn(j)+1,a>2*1024*1024))throw new h("Oracle stream event exceeded the 2 MiB protocol limit.",g.API_ERROR)}b=o.indexOf(`
441
- `,x)}if(o=o.slice(x),y)break}if(o.trim()){let u=o.replace(/\r$/,"");if(u.startsWith("data:")&&(s.push(u.slice(5).replace(/^ /,"")),a+=Yn(s[s.length-1]??"")+1,a>2*1024*1024))throw new h("Oracle stream event exceeded the 2 MiB protocol limit.",g.API_ERROR)}let d=l();d&&(yield d)}catch(d){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),d}finally{n.releaseLock()}}function Yn(e){return Buffer.byteLength(e,"utf8")}function Oo(e){let t=["program","initiative","codebase"].filter(o=>typeof e[o]=="string");if(t.length>1)throw new h("Choose only one of --program, --initiative or --codebase.",g.USAGE);let n=t[0];if(!n)return;let r=e[n];if(typeof r!="string"||!r.trim())throw new h(`--${n} needs an id.`,g.USAGE);return{kind:n,id:r.trim()}}function q(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function Au(e){if(typeof e=="string")return p(e);try{return p(JSON.stringify(e))}catch{return"unexpected response"}}function jt(e,t){let n=q(e);if(n.ok===!1){let r=fa(n.error,t),o=typeof n.message=="string"?p(n.message).slice(0,2e3):void 0;throw new Q(r,t,o)}return n.ok===!0&&"data"in n?n.data:e}async function Dt(e,t){try{return await e.json()}catch{throw new h(`Non-JSON response from ${t} (HTTP ${e.status}).`,g.FAILURE)}}async function Ut(e){let t;try{t=await e.clone().json()}catch{t=null}let n=q(t),r=fa(n.error??n.error_description,e.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 Q(r,e.status,typeof o=="string"?p(o).slice(0,2e3):void 0,void 0,xu(e))}function xu(e){try{return e.url?new URL(e.url).origin:void 0}catch{return}}function fa(e,t){if(typeof e!="string")return`http_${t}`;let n=p(e).slice(0,120);return/^[A-Za-z0-9_.-]+$/.test(n)?n:`http_${t}`}function ma(e){let t=q(e);if(typeof t.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(t.sessionId)||typeof t.title!="string"||t.visibility!=="private"&&t.visibility!=="company"||typeof t.shared!="boolean")throw new h("Oracle server returned an invalid session summary.",g.API_ERROR);return{sessionId:t.sessionId,title:p(t.title),visibility:t.visibility,shared:t.shared,...typeof t.entityKey=="string"?{entityKey:p(t.entityKey)}:{},...typeof t.updatedAt=="number"||t.updatedAt===null?{updatedAt:t.updatedAt}:{}}}function pa(e){let t=q(e),n=ma(t);if(!Array.isArray(t.messages))throw new h("Oracle server returned an invalid session transcript.",g.API_ERROR);let r=t.messages.map((o,i)=>{let s=q(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new h(`Oracle session message ${i+1} is invalid.`,g.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(Eu):void 0,c=Array.isArray(s.files)?s.files.map(Cu):void 0;return{role:s.role,content:p(s.content),...typeof s.id=="string"?{id:s.id}:{},...typeof s.authorName=="string"?{authorName:p(s.authorName)}:{},...s.question&&typeof s.question=="object"?{question:Ru(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:_u(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof t.activeStreamId=="string"?{activeStreamId:t.activeStreamId}:{}}}function ko(e){let t=q(e);if(t.protocolVersion!==1||typeof t.idx!="number"||!Number.isSafeInteger(t.idx)||t.idx<0||typeof t.type!="string")throw new h("Oracle stream event does not match protocol version 1.",g.API_ERROR);return Le(t)}function Su(e){let t=q(e);if(typeof t.fileId!="string"||typeof t.name!="string"||typeof t.mediaType!="string")throw new h("Oracle upload response is missing file metadata.",g.API_ERROR);return{fileId:t.fileId,name:p(t.name),mediaType:p(t.mediaType),...typeof t.sizeBytes=="number"?{sizeBytes:t.sizeBytes}:{}}}function Ru(e){let t=q(e);if(typeof t.id!="string"||!Array.isArray(t.questions))throw new h("Oracle returned an invalid question card.",g.API_ERROR);return{id:p(t.id),questions:t.questions.map((n,r)=>{let o=q(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new h(`Oracle question ${r+1} is invalid.`,g.API_ERROR);return{id:p(o.id),header:p(o.header),question:p(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=q(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new h(`Oracle question option ${s+1} is invalid.`,g.API_ERROR);return{id:p(a.id),label:p(a.label),description:p(a.description),...typeof a.recommended=="boolean"?{recommended:a.recommended}:{},...typeof a.confirms=="boolean"?{confirms:a.confirms}:{}}})}}),optional:t.optional===!0}}function _u(e){let t=q(e);if(typeof t.questionId!="string"||!Array.isArray(t.answers))throw new h("Oracle returned an invalid question response.",g.API_ERROR);return{questionId:p(t.questionId),answers:t.answers.map(Iu)}}function Iu(e){let t=q(e);if(typeof t.questionId!="string"||!Array.isArray(t.optionIds)||!t.optionIds.every(n=>typeof n=="string"))throw new h("Oracle returned an invalid question answer.",g.API_ERROR);return{questionId:p(t.questionId),optionIds:t.optionIds.map(n=>p(n)),...typeof t.customText=="string"?{customText:p(t.customText).slice(0,8e3)}:{}}}function Eu(e){let t=q(e);if(typeof t.fileId!="string"||typeof t.name!="string"||typeof t.mediaType!="string")throw new h("Oracle session attachment metadata is invalid.",g.API_ERROR);return{fileId:p(t.fileId),name:p(t.name),mediaType:p(t.mediaType),...typeof t.sizeBytes=="number"&&Number.isFinite(t.sizeBytes)?{sizeBytes:t.sizeBytes}:{}}}function Cu(e){let t=q(e);if(typeof t.fileId!="string"||typeof t.filename!="string"||typeof t.mediaType!="string"||typeof t.sizeBytes!="number"||!Number.isFinite(t.sizeBytes))throw new h("Oracle session file metadata is invalid.",g.API_ERROR);return{fileId:p(t.fileId),filename:p(t.filename),mediaType:p(t.mediaType),sizeBytes:t.sizeBytes,...typeof t.format=="string"?{format:p(t.format)}:{}}}import{randomUUID as Tu}from"node:crypto";import{promises as Me}from"node:fs";import{homedir as $u}from"node:os";import{join as xo}from"node:path";import*as Ao from"proper-lockfile";function Qn(){return xo($u(),".anyforge")}function Xn(){return xo(Qn(),"oracle")}function ga(){return xo(Qn(),"oracle.last-session")}function Pu(){return{version:2,active:{},logins:[]}}function Vn(e){return e===void 0||typeof e=="string"}function ha(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.endpoint!="string"||typeof t.clientId!="string"||typeof t.redirectUri!="string"||typeof t.accessToken!="string"||typeof t.refreshToken!="string"||typeof t.expiresAt!="number"||!Number.isFinite(t.expiresAt)||!Array.isArray(t.scopes)||!t.scopes.every(n=>typeof n=="string")||!Vn(t.companyId)||!Vn(t.companyName)||!Vn(t.uid)?null:{endpoint:t.endpoint,...t.companyId?{companyId:t.companyId}:{},...t.companyName?{companyName:t.companyName}:{},...t.uid?{uid:t.uid}:{},clientId:t.clientId,redirectUri:t.redirectUri,accessToken:t.accessToken,refreshToken:t.refreshToken,expiresAt:t.expiresAt,scopes:t.scopes}}function Lu(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;if(t.version===1){let o=ha(t);return o?{version:2,endpoint:o.endpoint,active:{[o.endpoint]:o.clientId},logins:[o]}:null}if(t.version!==2||!Array.isArray(t.logins)||!Vn(t.endpoint)||!t.active||typeof t.active!="object"||Array.isArray(t.active))return null;let n=t.logins.map(ha);if(n.some(o=>o===null))return null;let r={};for(let[o,i]of Object.entries(t.active)){if(typeof i!="string")return null;r[o]=i}return{version:2,...t.endpoint?{endpoint:t.endpoint}:{},active:r,logins:n}}async function le(){let e=Xn(),t;try{t=await Me.readFile(e,"utf8")}catch(o){if(o.code==="ENOENT")return Pu();throw o}let n;try{n=JSON.parse(t)}catch{throw new Error(`Oracle credentials at ${e} are invalid JSON; run \`anyforge oracle logout --all\` and sign in again.`)}let r=Lu(n);if(!r)throw new Error(`Oracle credentials at ${e} have an unsupported format; run \`anyforge oracle logout --all\` and sign in again.`);return r}async function wn(e){if(!e.logins.length){await Me.rm(Xn(),{force:!0});return}await ka(Xn(),e)}async function Zn(e){return nr(async()=>{let t=await le(),n=await e(t);return await wn(t),n})}function Ue(e,t){return e.logins.filter(n=>n.endpoint===t)}function er(e,t){let n=Ue(e,t);return n.find(r=>r.clientId===e.active[t])??n[0]}function de(e){return e.companyName||e.companyId||"workspace not known yet"}function wa(e,t){let n=t.companyId?e.logins.find(r=>r.endpoint===t.endpoint&&r.companyId===t.companyId&&r.clientId!==t.clientId):void 0;return e.logins=[...e.logins.filter(r=>r!==n&&r.clientId!==t.clientId),t],e.active[t.endpoint]=t.clientId,e.endpoint=t.endpoint,n}function So(e,t){e.logins=e.logins.filter(o=>!(o.endpoint===t.endpoint&&o.clientId===t.clientId));let n=Ue(e,t.endpoint);if(!n.length){if(delete e.active[t.endpoint],e.endpoint===t.endpoint){let o=e.logins[0]?.endpoint;o?e.endpoint=o:delete e.endpoint}return}if(e.active[t.endpoint]!==t.clientId&&n.some(o=>o.clientId===e.active[t.endpoint]))return;let r=n[0];return e.active[t.endpoint]=r.clientId,r}function ya(e,t,n,r){let o=e.logins.find(a=>a.endpoint===t&&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=e.logins.find(a=>a!==o&&a.endpoint===t&&a.companyId===r.companyId);return s&&(e.logins=e.logins.filter(a=>a!==s),e.active[t]===s.clientId&&(e.active[t]=o.clientId)),{changed:i||!!s,...s?{duplicate:s}:{}}}function mt(e,t){let n=t.trim(),r=e.find(a=>a.companyId===n);if(r)return r;let o=e.filter(a=>a.companyName?.toLowerCase()===n.toLowerCase());if(o.length===1)return o[0];let i=e.map(a=>`${de(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 f(`More than one saved workspace is named "${n}". Use its id instead.`,s):new f(`No saved Oracle login for workspace "${n}".`,`${s} Add one with \`anyforge oracle login --workspace "${n}"\`.`)}async function va(){let e;try{e=await Me.readFile(ga(),"utf8")}catch(r){if(r.code==="ENOENT")return[];throw r}let t;try{t=JSON.parse(e)}catch{return[]}if(!t||typeof t!="object"||Array.isArray(t))return[];let n=t;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 ba(e,t,n=""){let r=(await va()).filter(o=>!(o.endpoint===t&&o.companyId===n));await ka(ga(),{version:2,sessions:[...r,{endpoint:t,companyId:n,sessionId:e}]})}async function tr(e,t=""){return(await va()).find(n=>n.endpoint===e&&n.companyId===t)?.sessionId}async function ka(e,t){await Me.mkdir(Qn(),{recursive:!0,mode:448});let n=`${e}.${Tu()}.tmp`;try{await Me.writeFile(n,`${JSON.stringify(t,null,2)}
442
- `,{mode:384,flag:"wx"}),await Me.rename(n,e),await Me.chmod(e,384)}finally{await Me.rm(n,{force:!0}).catch(()=>{})}}async function nr(e){await Me.mkdir(Qn(),{recursive:!0,mode:448});let t=Xn(),n=`${t}.refresh-admission`,r;try{r=await Ao.lock(n,{realpath:!1,lockfilePath:n,stale:Number.MAX_SAFE_INTEGER,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}})}catch(o){throw o.code==="ELOCKED"?new Error(`Oracle credential access is still locked; another CLI command may be running. An abrupt exit can leave this guard behind. Stop all AnyForge CLI commands before removing the guard directory at ${n}.`,{cause:o}):o}try{let o=await Ao.lock(t,{realpath:!1,lockfilePath:`${t}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await e()}finally{await o()}}finally{await r()}}var Ro=8192,Aa=10*1048576,Mu=20*1048576,xa=10,Sa=3;function _o(e,t){if(e.type!=="tool_call"&&e.type!=="tool_call_start"||typeof e.spawnId=="string")return!1;let n=typeof e.id=="string"?e.id:void 0;if(n){if(t.has(n))return!1;t.add(n)}return!Lt(e.name)}var je=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(t){return t.type==="finalizing"?!0:t.idx<=this.lastIdx?!1:(this.lastIdx=t.idx,t.type==="stream_start"&&typeof t.streamId=="string"?this.streamId=p(t.streamId):t.type==="delta"&&typeof t.content=="string"?this.answer+=t.content:_o(t,this.toolIds)?this.answer="":t.type==="question"?this.question=vn(t):t.type==="error"?this.error=Eo(t):t.type==="done"?this.done=t:t.type==="navigator_file_created"&&Uu(this.files,t.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 Wt(e,t,n,r,o,i=new je){let s=async u=>{let y=i.streamId;i.accept(u)&&(i.streamId&&i.streamId!==y&&r.onStream?.(i.streamId),await r.onEvent(u))},a=()=>Io(e,t,i,s,o,r.onActivity),c=async()=>{try{for await(let u of e.streamRequestEvents(t,n.requestId,-1,r.onActivity,o))await s(u)}catch(u){throw o?.aborted?u:new h("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",g.FAILURE,`Run anyforge oracle resume ${t} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new h("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",g.FAILURE,`Run anyforge oracle resume ${t} to inspect the saved session.`)},l=async()=>{try{let u=await e.submitTurn(t,n,o);for await(let y of gn(u,r.onActivity))await s(y)}catch(u){if(o?.aborted||u instanceof h&&u.exitCode===g.API_ERROR)throw u;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},d;try{d=await e.submitTurn(t,n,o)}catch(u){if(o?.aborted||u instanceof h&&u.exitCode!==g.FAILURE)throw u;return l()}if(!d)throw new h("Oracle did not return a stream response.",g.FAILURE);r.onResponse?.();try{for await(let u of gn(d,r.onActivity))await s(u)}catch(u){if(o?.aborted||u instanceof h)throw u;return i.streamId?a():l()}return i.settled?i.outcome():i.streamId?a():l()}async function Io(e,t,n,r,o,i){let s=n.streamId;if(!s)throw new h("Oracle stream replay needs a stream id.",g.FAILURE);let a=0;for(;!n.settled&&a<Sa;){if(o?.aborted)throw o.reason;try{for await(let c of e.streamReplayEvents(t,s,n.lastIdx+1,i,o))await r(c);if(!n.settled){if((await e.getSession(t,o)).activeStreamId!==s)break;await Oa(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof h&&c.exitCode===g.API_ERROR||(a+=1,a>=Sa))throw c;await Oa(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new h("Oracle stream could not be fully replayed; the turn was not submitted again.",g.FAILURE,`Run anyforge oracle resume ${t} to inspect the session.`);return n.outcome()}function yn(e,t){let n=t.done,r=n?.servedBy,o=ht(n?.tokens),i=te(n?.rounds),s=typeof n?.exitReason=="string"?p(n.exitReason):void 0,a=n?.exitReason==="completed"&&!t.question,c=t.files??(Array.isArray(n?.files)?n.files.map(Xe):void 0),l=t.error?"error":t.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:e,status:l,answer:p(t.answer),partial:!a,...typeof n?.messageId=="string"?{messageId:p(n.messageId)}:typeof n?.answerId=="string"?{messageId:p(n.answerId)}:{},...t.question?{question:t.question}:{},...t.error?{error:p(t.error)}:{},...t.streamId?{streamId:p(t.streamId)}:{},...r?{servedBy:Le(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:Le(c)}:{}}}function P(e,t){return typeof e=="string"?p(e).slice(0,t):""}function Eo(e){return typeof e.message=="string"?p(e.message).slice(0,2e3):"Oracle turn failed."}function Y(e){return p(e instanceof Error?e.message:String(e)).slice(0,2e3)}function vn(e){let t=e.question;if(!t||typeof t!="object")throw new h("Oracle question event omitted its question card.",g.API_ERROR);return ju(t)}function Xe(e){let t=e&&typeof e=="object"&&!Array.isArray(e)?e:{};if(typeof t.fileId!="string"||!t.fileId||typeof t.filename!="string"||!t.filename||typeof t.mediaType!="string"||!t.mediaType||typeof t.sizeBytes!="number"||!Number.isSafeInteger(t.sizeBytes)||t.sizeBytes<0)throw new h("Oracle generated-file event omitted safe file metadata.",g.API_ERROR);return{fileId:p(t.fileId),filename:p(t.filename),mediaType:p(t.mediaType),sizeBytes:t.sizeBytes,...typeof t.format=="string"?{format:p(t.format)}:{}}}function Uu(e,t){let n=Xe(t);e.some(r=>r.fileId===n.fileId)||e.push(n)}function ju(e){let t=e;if(typeof t.id!="string"||!Array.isArray(t.questions))throw new h("Oracle returned an invalid question card.",g.API_ERROR);return{id:p(t.id),optional:t.optional===!0,questions:t.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 h(`Oracle question ${r+1} is invalid.`,g.API_ERROR);return{id:p(o.id),header:p(o.header),question:p(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 h("Oracle question option is invalid.",g.API_ERROR);return{id:p(s.id),label:p(s.label),description:p(s.description),...typeof s.recommended=="boolean"?{recommended:s.recommended}:{},...typeof s.confirms=="boolean"?{confirms:s.confirms}:{}}})}})}}function te(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function ht(e){if(typeof e=="number"&&Number.isFinite(e))return{totalTokens:e};if(!e||typeof e!="object"||Array.isArray(e))return;let t=e,n=te(t.in)??te(t.input)??te(t.inputTokens),r=te(t.cacheRead),o=te(t.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=te(t.out)??te(t.output)??te(t.outputTokens),a=te(t.total)??te(t.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 Gt(e){if(e&&typeof e=="object"){let t=e;if(typeof t.accepted=="boolean")return t.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof t.cancelled=="boolean")return t.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function Ht(e,t){let n=t&&e&&(e.kind==="program"||e.kind==="initiative")?{kind:e.kind,id:e.id}:void 0;return{...!t&&e?{context:e}:{},...n?{sharedEntity:n}:{},visibility:t?"company":"private"}}async function bn(e,t,n){await ba(e,t,n).catch(()=>{})}async function rr(e,t,n,r){if(!n.length)return[];if(n.length>xa)throw new f(`Attach no more than ${xa} files per turn.`);let o=0,i=[];for(let a of n){let c=await Fu(a);if(!c.isFile())throw new f(`Attachment is not a file: ${a}`);if(c.size>Aa)throw new f(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let l=await Du(a,Aa);if(o+=l.byteLength,o>Mu)throw new f("Attachments exceed the 20 MiB total CLI limit.");let d=qu(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",u=da(d)??"";if(!u)throw new f(`Unsupported attachment type: ${a}`);i.push({content:l,name:d,mediaType:u})}let s=[];for(let{content:a,name:c,mediaType:l}of i){await r(p(c),a.byteLength);let d=new ArrayBuffer(a.byteLength);new Uint8Array(d).set(a);let u=new File([d],c,{type:l});s.push(await e.upload(t,u))}return s}async function Du(e,t){let n=[],r=0;for await(let o of Nu(e)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>t)throw new f(`Attachment exceeds the ${J(t)} limit: ${e}`);n.push(i)}return Buffer.concat(n)}var wt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Wu=2e4,Gu=6,Hu={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},zu={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"},or=class{constructor(t,n){this.startedAt=t;this.sessionId=n;this.lastSignalAt=t}startedAt;sessionId;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(t=>t.status==="failed").length}get finished(){return this.end!==void 0}setUploading(t,n,r){this.phase="uploading",this.upload=`${t} (${J(n)})`,this.lastSignalAt=r}setPhase(t,n){this.phase=t,this.lastSignalAt=n}touch(t){this.lastSignalAt=t}apply(t,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(t);switch(t.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=te(t.round),this.maxRounds=te(t.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 t.phase=="string"?t.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(t)}record(t){switch(t.type){case"delta":typeof t.content=="string"&&(this.answer+=t.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(t);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===t.toolUseId);n&&(n.status=t.ok===!1?"failed":"ok");break}case"subagent_start":typeof t.spawnId=="string"&&this.agents.set(t.spawnId,"running");break;case"subagent_done":typeof t.spawnId=="string"&&this.agents.set(t.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${P(t.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${P(t.filename,200)}: ${P(t.error,500)}`});break;case"attachment_notice":if(Array.isArray(t.notices))for(let n of t.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${P(r.name,160)}: ${P(r.message,500)}`})}break;case"provider_fallback":{let n=P(t.from,120),r=P(t.to,120),o=P(t.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=Xe(t.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${J(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:Eo(t)});break;case"done":this.done=t;break}}recordToolCall(t){let n=typeof t.id=="string"?t.id:void 0,r=_o(t,this.toolIds),o=typeof t.name=="string"?t.name:"";if(Lt(o))return;let i=P(typeof t.label=="string"?t.label:Pt(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,t.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof t.spawnId=="string"?{spawnId:t.spawnId}:{},...t.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=p(this.answer.trim()),this.answer=""),this.tools.push(a),this.phase!=="finishing"&&(this.phase="thinking")}note(t,n){this.notices.push({tone:t,text:p(n)})}finish(t,n){this.end=t,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 t=[...this.agents.values()].filter(r=>r==="running").length;if(t)return`Researching (${t} agent${t===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&&Hu[this.serverPhase]||"Thinking"}statusLine(t,n){let r=[this.label(),yo(t-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=t-this.lastSignalAt;return o>=Wu&&this.phase!=="cancelling"&&r.push(`no update for ${yo(o)}`),n&&t-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let t=[],n=mn((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=_a("\u2713"):this.end==="awaiting_input"?o=Co("?")+" Waiting for your answer":this.end==="cancelled"?o=$o("\u2717")+" Interrupted":this.end==="error"?o=To("\u2717")+" Error":o=$o("\u2717")+` Stopped: ${r&&zu[r]||"no final answer"}`,t.push(n),this.tools.length&&t.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=ht(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&t.push(`${be(i.inputTokens??0)} in${i.cachedInputTokens?` (${be(i.cachedInputTokens)} cached)`:""} / ${be(i.outputTokens??0)} out`);let s=On(this.done?.servedBy);return s&&t.push(s),`${o} ${gt(t.join(" \xB7 "))}`}};function On(e){if(!e||typeof e!="object")return"";let t=e,n=P(t.model??t.id,100);if(!n)return"";let r=t.fallback&&typeof t.fallback=="object"?t.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${P(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${P(r.from,100)}${o})`}return n}var ir=class{constructor(t,n){this.activity=t;this.view=n;this.answer=new qt("",n.linkOrigin)}activity;view;answer;getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(t){let n=this.activity;this.answer.setText(n.answer);let r=[hn("assistant")];if(!n.finished&&!n.tools.length&&!n.answer.trim()){let o=Co(wt[this.view.frame()%wt.length]??"*");r.push(kn(` ${o} ${gt(n.label())}`,t))}r.push(...this.renderTools(t)),r.push(...this.answer.render(t));for(let o of n.notices){let i=o.tone==="error"?To:o.tone==="warning"?$o:gt;r.push(...Ra(i(o.text),t))}return n.finished&&r.push(kn(n.summaryLine(),t)),r}renderTools(t){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[kn(gt(` \u23BF ${a}`),t)]}let r=this.activity.finished?n:n.slice(-Gu),o=n.length-r.length,i=[];return o&&i.push(kn(gt(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),t)),r.forEach((s,a)=>{if(s.note)for(let u of Ra(s.note,Math.max(10,t-4)).slice(0,3))i.push(` ${gt(Bu(u))}`);let c=s.status==="running"?Co(wt[this.view.frame()%wt.length]??"*"):s.status==="ok"?_a("\u2713"):To("\u2717"),l=a===0&&!o?" \u23BF ":" ",d=s.spawnId?` ${gt("agent \xB7")} `:"";i.push(kn(`${l}${d}${c} ${s.label}`,t))}),i}};import{truncateToWidth as Vu,visibleWidth as Xu,wrapTextWithAnsi as Ea}from"@earendil-works/pi-tui";import{bold as Ca,cyan as Qu,dim as De}from"kleur/colors";import{CombinedAutocompleteProvider as Ku}from"@earendil-works/pi-tui";var An=[{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"]}],Ju=[{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 Po(e){let t=new Set(An.flatMap(n=>[n.name,...n.aliases??[]]));return(e??Ju).filter(n=>!t.has(n.name))}function Ia(e,t){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(e.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=An.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=t.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function Lo(e,t){let n=[...An.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=>Yu(i.completions??[],s)}:{}})),...e.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new Ku(n,t),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let l=(i[s]??"").slice(0,a);return s!==0||!l.trimStart().startsWith("/")?null:o.test(l)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,l){return r.applyCompletion(i,s,a,c,l)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function Yu(e,t){let n=e.filter(r=>r.startsWith(t.toLowerCase())&&r!==t).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function xn(e,t){return e?t?"write + approve":"write":"read only"}function zt(e){return e?`${e.kind} ${p(e.id)}`:"no context"}function Qe(e){return e?p(e.companyName||e.companyId):""}function Ta(e,t){let n=[`${Ca(Qu("\u26A1\uFE0E AnyForge Oracle"))}${De(` \xB7 v${p(e.version)}`)}`,`${e.workspace?`${Ca(e.workspace)} \xB7 `:""}${Fe(e.session)} \xB7 ${e.access} \xB7 ${zt(e.context)}`,...e.session.messages.length?[`Resumed: ${p(e.session.title)}`]:[],De("Only your messages and the files you attach leave this terminal."),De("/help commands \xB7 /status details")];if(t<24)return n.flatMap(s=>Ea(s,Math.max(1,t)));let r=Math.min(t,76),o=r-4,i=[De(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>Ea(a,o))){let a=Vu(s,o);i.push(`${De("\u2502")} ${a}${" ".repeat(Math.max(0,o-Xu(a)))} ${De("\u2502")}`)}return i.push(De(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function $a(e){let t=(r,o)=>r?`${De(r)} ${o}`:o,n=[{title:"Commands",rows:An.map(r=>[`/${r.name}`,t(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(e.server.length){let r=e.server.map(o=>[`/${o.name}`,t(o.args,p(o.description))]);e.server.some(o=>o.name==="catchup")&&!e.canApprove&&r.push(["",De("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 No(e){let n=[["Model",`workspace default ${e.model?`${p(e.model.provider)}/${p(e.model.id)}`:"chosen by the server"}`]],r=On(e.lastServedBy);if(r){let o=e.lastServedBy,i=P(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function Fo(e){return[["This run",e.turns?`${e.turns} turn${e.turns===1?"":"s"} \xB7 ${e.tools} tool${e.tools===1?"":"s"} \xB7 ${be(e.inputTokens)} in / ${be(e.outputTokens)} out tokens`:"no turns yet"]]}function qo(e){if(!e?.finished)return[];let t=[mn((e.endedAt??e.startedAt)-e.startedAt)];t.push(`${e.toolCount} tool${e.toolCount===1?"":"s"}${e.failedCount?` (${e.failedCount} failed)`:""}`);let n=te(e.done?.rounds);n!==void 0&&t.push(`${n} round${n===1?"":"s"}`);let r=ht(e.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&t.push(`${be(r.inputTokens??0)} in${r.cachedInputTokens?` (${be(r.cachedInputTokens)} cached)`:""} / ${be(r.outputTokens??0)} out tokens`);let o=P(e.done?.exitReason,40);return t.push(o?o.replaceAll("_"," "):e.end??""),[["Last turn",t.filter(Boolean).join(" \xB7 ")]]}function Pa(e){let t=e.capabilities?["read","write","approve"].filter(o=>e.capabilities?.[o]).join(", ")||"none":"not reported",n=e.contextText?` \xB7 note ${J(Buffer.byteLength(e.contextText,"utf8"))}`:"",r=ta(e.limits);return[["Session",`${e.session.sessionId} \xB7 ${p(e.session.title)||"Untitled"}`],["Audience",Fe(e.session)],["Access",`this session ${xn(e.write,e.approve)} \xB7 grant ${e.grantScopes.join(", ")||"none"} \xB7 workspace role ${t}`],["Context",`${zt(e.context)}${n}`],...No(e),...qo(e.lastTurn),...Fo(e.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...e.identity?[["Workspace",Zu(e.identity,e.savedWorkspaces)]]:[],["Endpoint",e.endpoint],["Version",`CLI ${p(e.version)} \xB7 protocol ${1}`],["Attached",e.pendingFiles.length?`${e.pendingFiles.map(p).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function Zu(e,t){let n=e.companyName?`${p(e.companyName)} (${p(e.companyId)})`:`company ${p(e.companyId)}`,r=t!==void 0&&t>1?` \xB7 ${t} saved, /workspace to switch`:"";return`${n} \xB7 user ${p(e.uid)}${r}`}function La(e,t){return t.length?t.map((n,r)=>[`${r+1}.`,`${p(n.filename)} (${J(n.sizeBytes)}) \xB7 anyforge oracle download ${e} ${p(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{randomUUID as rp}from"node:crypto";import{stat as op}from"node:fs/promises";import{basename as Na}from"node:path";import{bold as ip,cyan as Fa,dim as qa,red as Jt,yellow as sp}from"kleur/colors";import{Container as ap,Editor as cp,ProcessTerminal as lp,ScrollView as dp,SelectList as Ma,TuiAltScreen as up,VStack as pp,getNativeClipboard as fp,matchesKey as cr,truncateToWidth as Ua,wrapTextWithAnsi as mp}from"@earendil-works/pi-tui";import{bold as ep,cyan as Mo,dim as sr,yellow as tp}from"kleur/colors";import{Input as np,Text as yt,matchesKey as Kt}from"@earendil-works/pi-tui";var ar=class{constructor(t,n,r){this.tui=t;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()}}tui;question;onComplete;focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new np({prompt:`${Mo("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:sr});invalidate(){}render(t){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,t-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new yt(`${ep(Mo(p(n.header)))}${sr(o)}`,0,0).render(r),...new yt(p(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new yt(sr(`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 yt(sr(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new yt(tp(this.errorMessage),0,0).render(r)),i.map(s=>`${Mo("\u2502")} ${s}`)}handleInput(t){if(this.mode==="custom"){this.customInput.handleInput(t);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(t.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(Kt(t,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(t);return}if(Kt(t,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(Kt(t,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(Kt(t,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(t.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(t.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(t);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(Kt(t,"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(Kt(t,"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(t,n){let r=this.selectedFor(t),o=[];return t.options.forEach((i,s)=>{let a=r.has(i.id),c=t.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",l=s===this.optionIndex?"\u203A":" ",d=i.recommended?" \xB7 recommended":"",u=i.confirms?" \xB7 confirms the shown action":"",y=`${l} ${s+1}. ${c} ${p(i.label)}${d}${u}`;o.push(...new yt(y,0,0).render(n)),o.push(...new yt(` ${p(i.description)}`,0,0).render(n))}),o}instructions(t){return t.options.length===0?`Write a short answer${this.question.optional?" \xB7 s or Esc skip card":""}`:`\u2191/\u2193 move \xB7 1\u2013${t.options.length} ${t.multiSelect?"toggle":"select"}${t.multiSelect?" \xB7 Space toggle":""} \xB7 Enter continue \xB7 o write your own${this.question.optional?" \xB7 s or Esc skip card":""}`}requireAnswer(){let t=this.question.questions[this.questionIndex];this.errorMessage=t?.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(t){let n=this.selected.get(t.id);return n||(n=new Set,this.selected.set(t.id,n)),n}recordCurrent(t){let n=this.question.questions[this.questionIndex];if(!n)return;t&&this.selectedFor(n).clear();let r=[...this.selectedFor(n)],o={questionId:n.id,optionIds:r,...t?{customText:t}:{}},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(t){this.onComplete(t)}};var ja=1500,hp=100,gp="\x1B]133;A\x07";function Yt(e){return{render:e,invalidate(){}}}function Da(e,t,n,r){let o=new qt(t,r);return{getText:()=>o.getText(),invalidate:()=>o.invalidate(),render:i=>e==="user"?aa(o,i,n).map((s,a)=>a===1?`${gp}${s}`:s):[hn("assistant"),...o.render(i)]}}async function Ba(e){let{client:t,config:n}=e,r=new lp,o=new up(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new ap,s=new dp(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new cp(o,sa),c=Po(n.commands),l=()=>typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,d=e.session,u=e.initialContext,y=e.contextText,v=e.canWrite,x=e.canApprove,b,m,A,L,j=[...e.initialFiles],K=!1,Ie=!1,kt=!1,br=0,Ot,Ho=0,_n=!1,et="",Qt,In,At=[],xt={turns:0,inputTokens:0,outputTokens:0,tools:0},En=new Map,Ee,yc=Yt(w=>{if(b){let k=Fa(wt[br%wt.length]??"*");return[Ua(`${k} ${b.activity.statusLine(Date.now(),l())}`,w)]}return Ee?[Ua(`${Fa("?")} Waiting for your answer to the question above`,w)]:[]}),vc=Yt(w=>{let k=[Qe(n.identity),xn(v,x),zt(u),ca(d),j.length?`${j.length} file${j.length===1?"":"s"} attached`:"",m!==void 0?"1 message queued":""];return[qa(ra(w,k,b?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new pp([{component:s,basis:0,grow:1,minSize:1},{component:yc,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:vc,basis:"auto",shrink:0,minSize:1}]));let ue=()=>o.requestRender(),D=w=>o.flash(p(w),3e3),Ge=w=>{i.addChild(w),ue()},V=(w,k=qa)=>{let O=p(w);Ge(Yt(S=>mp(k(O),Math.max(1,S))))},Cn=(w,k)=>{Ge(Yt(O=>["",...na(w,k,O)]))},bc=()=>{Ot||(Ot=setInterval(()=>{br+=1,ue()},hp),Ot.unref())},kr=()=>{Ot&&clearInterval(Ot),Ot=void 0},St=()=>{K||o.hasOverlay()||o.setFocus(Ee??a)},zo=w=>{A=w;let k=En.get(w.id);k&&i.removeChild(k);let O=new ar(o,w,S=>{En.delete(w.id),Ee===O&&(Ee=void 0),i.removeChild(O),Ac(S??{questionId:w.id,skipped:!0,answers:[]}),St()});En.set(w.id,O),Ee=O,Ge(O)},Tn=w=>{i.clear(),En.clear(),Ee=void 0,d=w,A=void 0,L=void 0,At=[],et="";let k={version:e.version,workspace:Qe(n.identity),session:w,access:xn(v,x),context:u};Ge(Yt(S=>Ta(k,S)));let O;for(let S of w.messages){Ge(Da(S.role,S.content,S.authorName,t.endpoint)),S.role==="assistant"&&(et=S.content),S.question&&(O=S.question),S.questionResponse&&(V("A stored response was recorded for this question."),O?.id===S.questionResponse.questionId&&(O=void 0));for(let _ of S.files??[])At.some(N=>N.fileId===_.fileId)||At.push(_),V(`File: ${_.filename} (${_.mediaType}, ${J(_.sizeBytes)}) \xB7 anyforge oracle download ${w.sessionId} ${_.fileId} --output .`)}O&&zo(O),St(),bn(w.sessionId,t.endpoint,n.identity?.companyId)},Ko,kc=new Promise(w=>{Ko=w}),$n=()=>{K||(K=!0,kr(),b?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),Ko())},Or=async()=>{let w=b;if(!w||w.cancelling)return;w.cancelling=!0,w.activity.setPhase("cancelling",Date.now()),ue();let{streamId:k,requestId:O}=w;w.controller.abort(new Error("Turn cancelled by user."));let S;if(k)try{S=Gt(await t.cancelTurn(d.sessionId,k))}catch(_){S=`Could not confirm server cancellation: ${Y(_)}`}else if(O)try{S=Gt(await t.cancelRequest(d.sessionId,O))}catch(_){S=`Could not confirm server cancellation by request id: ${Y(_)}`}else S="The turn had not reached the server; nothing was sent.";w.activity.note("info",S),ue()},Rt=async w=>{if(b||K)return;if(w.kind==="submit"&&w.response){let F=A;if(!F||F.id!==w.response.questionId){D("That question is no longer active. Resume the session to refresh it.");return}V(wp(F,w.response)),A=void 0}else w.kind==="submit"&&Ge(Da("user",w.text));let k=d.sessionId,O=new or(Date.now(),k),S=new ir(O,{expanded:()=>kt,frame:()=>br,linkOrigin:t.endpoint}),_={activity:O,view:S,controller:new AbortController,cancelling:!1};b=_,Ge(S),bc();let N=new je,ne=F=>{O.apply(F,Date.now()),F.type==="question"&&(zo(vn(F)),St()),ue()},tt={onEvent:ne,onStream:F=>{_.streamId=F},onResponse:()=>{O.phase==="sending"&&O.setPhase("preparing",Date.now())},onActivity:()=>O.touch(Date.now())},pe="error";try{if(w.kind==="replay"){N.streamId=w.streamId,_.streamId=w.streamId,O.setPhase("thinking",Date.now());let F=await Io(t,k,N,async ke=>{N.accept(ke)&&ne(ke)},_.controller.signal,tt.onActivity);pe=yn(k,F).status}else{let F=w.response?[]:j.splice(0),ke=await rr(t,k,F,(Ar,Pc)=>{O.setUploading(Ar,Pc,Date.now()),ue()});_.controller.signal.throwIfAborted(),O.setPhase("sending",Date.now());let Pn=rp();_.requestId=Pn;let Tc={requestId:Pn,text:w.response?"":w.text,readOnly:!v,...x?{allowApprove:!0}:{},...u?{context:u}:{},...y?{contextText:y}:{},...w.response?{questionResponse:w.response}:{},...ke.length?{attachments:ke.map(Ar=>({fileId:Ar.fileId}))}:{}},$c=await Wt(t,k,Tc,tt,_.controller.signal,N);pe=yn(k,$c).status}}catch(F){if(_.controller.signal.aborted)pe="cancelled";else{pe="error";let ke=F instanceof h&&F.hint?` ${p(F.hint)}`:"";O.note("error",`${Y(F)}${ke}`)}}finally{O.finish(pe,Date.now()),b=void 0,kr(),K||(Ie=pe==="cancelled"),Qt=O,O.answer.trim()&&(et=O.answer),O.done?.servedBy&&(In=O.done.servedBy);let F=ht(O.done?.tokens);xt.turns+=1,xt.tools+=O.toolCount,xt.inputTokens+=F?.inputTokens??0,xt.outputTokens+=F?.outputTokens??0;for(let ke of O.files)At.some(Pn=>Pn.fileId===ke.fileId)||At.push(ke);ue()}if(!K){if(_.streamId&&pe!=="cancelled"){let F=await t.getSession(k).catch(()=>{});F&&F.sessionId===d.sessionId&&(d=F)}Oc(pe)}},Oc=w=>{if(!(K||b)){if(L){let k=L;L=void 0,Rt({kind:"submit",text:"",response:k});return}if(m!==void 0){let k=m;if(m=void 0,w==="complete"&&!Ee){Rt({kind:"submit",text:k});return}a.getText()||a.setText(k),D("Your queued message is back in the input; press Enter to send it.")}St(),ue()}},Ac=w=>{if(b){L=w,D("Answer saved; Oracle continues once the current turn settles.");return}Rt({kind:"submit",text:"",response:w})},Jo=async w=>{try{let k=await t.getSession(w);Tn(k),k.activeStreamId&&Rt({kind:"replay",streamId:k.activeStreamId}),D(`Resumed ${k.title||k.sessionId}.`)}catch(k){V(Y(k),Jt)}},xc=async()=>{try{let w=await t.listSessions();if(!w.length){D("No saved conversations to resume.");return}let k=new Ma(w.map(N=>({value:N.sessionId,label:N.title,description:Fe(N)})),Math.min(12,w.length),Mt),O=await tr(t.endpoint,n.identity?.companyId),S=O?w.findIndex(N=>N.sessionId===O):-1;S>=0&&k.setSelectedIndex(S);let _=o.showOverlay(k,{width:"85%",maxHeight:"80%",anchor:"center"});k.onSelect=N=>{_.hide(),Jo(N.value)},k.onCancel=()=>{_.hide(),St()},_.focus()}catch(w){V(Y(w),Jt)}},Yo=async w=>{if(w&&(!u||u.kind!=="program"&&u.kind!=="initiative")){D("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let k=await t.createSession(Ht(u,w));Tn(k),D(`Started a new conversation \xB7 ${Fe(k)}.`)}catch(k){V(Y(k),Jt)}},Vo=async(w,k)=>{let O=p(de(k));if(k.companyId&&k.companyId===n.identity?.companyId){D(`Already in ${O}.`);return}_n=!0;try{D(`Connecting to ${O}...`);let S=await w.connect(k),_=await S.client.createSession(Ht(void 0,!1));t=S.client,n=S.config,c=Po(n.commands),a.setAutocompleteProvider(Lo(c,process.cwd()));let N=t.scopes.has("write")&&n.capabilities?.write===!0,ne=t.scopes.has("approve")&&n.capabilities?.approve===!0,tt=v&&!N||x&&!ne;v&&!N&&(v=!1),(!v||!ne)&&(x=!1);let pe=u!==void 0;u=void 0,In=void 0,Qt=void 0,Tn(_),V(`Switched to ${Qe(n.identity)||O}. This is a new conversation in that workspace.${pe?" Context was cleared because its id belongs to the previous workspace.":""}`),tt&&V(`Access here is ${xn(v,x)}: this workspace's login or your role there does not allow more.`,sp)}catch(S){let _=S instanceof h&&S.hint?` ${p(S.hint)}`:"";V(`Could not switch to ${O}: ${Y(S)}${_}`,Jt)}finally{_n=!1}},Sc=async(w,k)=>{let O=n.identity?.companyId,S=new Ma(k.map(ne=>({value:ne.clientId,label:de(ne),description:[ne.companyId,ne.scopes.join(", "),ne.companyId===O?"current":""].filter(Boolean).join(" \xB7 ")})),Math.min(12,k.length),Mt),_=k.findIndex(ne=>ne.companyId===O);_>=0&&S.setSelectedIndex(_);let N=o.showOverlay(S,{width:"85%",maxHeight:"80%",anchor:"center"});S.onSelect=ne=>{N.hide();let tt=k.find(pe=>pe.clientId===ne.value);tt&&Vo(w,tt)},S.onCancel=()=>{N.hide(),St()},N.focus()},Rc=async w=>{let k=e.workspaces;if(!k){V(`This terminal signs in with ANYFORGE_API_TOKEN, which is bound to ${Qe(n.identity)||"one workspace"}. To switch workspaces, unset it and sign in with \`anyforge oracle login --workspace <name>\`.`);return}let O=await k.list();if(w){let S;try{S=mt(O,w)}catch(_){let N=_ instanceof h&&_.hint?` ${p(_.hint)}`:"";V(`${Y(_)}${N}`,Jt);return}await Vo(k,S);return}if(O.length<=1){V(`${Qe(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 Sc(k,O)},_c=w=>({session:d,write:v,approve:x,grantScopes:[...t.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...u?{context:u}:{},...y?{contextText:y}:{},...n.model?{model:n.model}:{},lastServedBy:In,...Qt?{lastTurn:Qt}:{},totals:{...xt},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},...w!==void 0?{savedWorkspaces:w}:{},endpoint:t.endpoint,version:e.version,pendingFiles:j.map(k=>Na(k))}),Ic=async()=>{if(!et.trim()){D("There is no answer to copy yet.");return}try{let w=fp();w?.setText?await w.setText(et):r.write(`\x1B]52;c;${Buffer.from(et,"utf8").toString("base64")}\x07`),D(`Copied the last answer (${et.length} characters).`)}catch(w){D(`Could not copy: ${Y(w)}`)}},Ec=async(w,k,O)=>{if(w.idleOnly&&_n){D("Wait for the workspace switch to finish.");return}if(w.idleOnly&&b){D(`Wait for Oracle to finish, or press Esc, before /${w.name}.`);return}switch(w.name){case"help":Ge(Yt(S=>["",...$a({server:c,canApprove:x}).flatMap(_=>[ip(_.title),...vo(_.rows,S)])]));return;case"status":{let S=await e.workspaces?.list().then(_=>_.length).catch(()=>{});Cn("Status",Pa(_c(S)));return}case"workspace":await Rc(O);return;case"model":Cn("Model",No({...n.model?{model:n.model}:{},lastServedBy:In}));return;case"usage":Cn("Usage",[...qo(Qt),...Fo(xt)]);return;case"files":Cn("Generated files",La(d.sessionId,At));return;case"copy":await Ic();return;case"exit":$n();return;case"new":if(O&&O!=="shared"){D("Usage: /new or /new shared");return}await Yo(O==="shared");return;case"clear":await Yo(!1);return;case"resume":O?await Jo(O):await xc();return;case"context":{if(!O){V(`Context: ${zt(u)}${y?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(O==="clear")u=void 0;else{let[S,_,...N]=k;if(!["program","initiative","codebase"].includes(S??"")||!_||N.length){D("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}u={kind:S,id:_}}V(`Context for your next message: ${zt(u)}.`);return}case"attach":{if(!O){D("Usage: /attach <file path>");return}let S=await op(O).catch(()=>{});if(!S?.isFile()){D(`Not a readable file: ${O}`);return}j.push(O),V(`Attached ${Na(O)} (${J(S.size)}). It uploads with your next message.`);return}}},Xo=w=>{let k=w.trim();if(!k)return;a.addToHistory(k);let O=Ia(k,c);if(O?.kind==="local"){Ec(O.command,O.args,O.arg).catch(S=>V(Y(S),Jt));return}if(O?.kind==="unknown"){a.setText(k),D(`Unknown command /${O.name}. Type /help to see the commands.`);return}if(_n){a.setText(k),D("Switching workspace; send your message once it has opened.");return}if(b){let S=m!==void 0;m=k,D(S?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),ue();return}Rt({kind:"submit",text:k})},Cc=o.addInputListener(w=>{if(cr(w,"ctrl+c")){if(b)return Or(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),ue(),{consume:!0};let k=Date.now();return k-Ho<=ja?$n():(Ho=k,o.flash("Press Ctrl+C again to exit",ja)),{consume:!0}}if(cr(w,"escape")){let k=Ee!==void 0&&o.getFocusedComponent()===Ee;return b&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!k?(Or(),{consume:!0}):void 0}if(cr(w,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?($n(),{consume:!0}):void 0;if(cr(w,"ctrl+o"))return kt=!kt,D(kt?"Showing tool activity":"Hiding tool activity"),ue(),{consume:!0}}),Qo=()=>{let w=!!b;Or().finally(()=>{w&&(Ie=!0),$n()})};process.on("SIGINT",Qo),a.onSubmit=Xo,a.onChange=()=>ue(),a.setAutocompleteProvider(Lo(c,process.cwd())),Tn(e.session),o.start(),d.activeStreamId&&Rt({kind:"replay",streamId:d.activeStreamId}),e.initialPrompt&&Xo(e.initialPrompt),await kc,Cc(),process.off("SIGINT",Qo),kr(),b?.controller.abort(),await r.drainInput().catch(()=>{}),Ie&&(process.exitCode=130)}function wp(e,t){if(t.skipped)return"Skipped the optional Oracle question.";let n=[];for(let r of t.answers){let o=e.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(p).join("; ")||"no options selected"}`}import{createHash as yp,randomBytes as Wa,timingSafeEqual as vp}from"node:crypto";import{createServer as bp}from"node:http";import kp from"open";var pr="https://crew.anyforge.ai",Op=6e4,Ap=5*6e4,lr=new Map;async function vt(e){e.signal?.throwIfAborted();let t=Ve(e.endpoint),n=await ft(t,fetch,void 0,e.signal),r=["read"];e.write&&r.push("write"),e.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=Wa(32).toString("base64url"),i=await _p(o,e.signal);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 Ip(n.oauth.registration,s,e.signal);if(typeof a.client_id!="string"||!a.client_id)throw new h("OAuth registration did not return a client id.",g.API_ERROR);let c=Wa(32).toString("base64url"),l=yp("sha256").update(c).digest("base64url"),d={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:l,code_challenge_method:"S256",resource:n.resource},u=new URL(n.oauth.authorization);for(let[K,Ie]of Object.entries(d))u.searchParams.set(K,String(Ie));let y=e.workspace?.trim();y&&u.searchParams.set(ua,y),e.onAuthorizationUrl?.(u.toString()),e.signal?.throwIfAborted();try{e.openBrowser?await e.openBrowser(u.toString()):await kp(u.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
381
+ ${t}`}}async function ds(e){let{skills:t}=await S(e,"GET","/skills");return t}async function us(e,t){let n=t.trim().toLowerCase(),r=await ds(e),o=s=>{try{return zn(s)}catch{return null}},i=r.find(s=>s.name.trim().toLowerCase()===n)??r.find(s=>o(s.name)===n);if(!i)throw new f(`No skill named "${t}" in your company's library.`,"Run `anyforge skill list` to see the skills you can install.");return S(e,"GET",`/skills/${encodeURIComponent(i.id)}`)}function Dl(e){return e instanceof ee&&e.status===404&&jl.has(e.code)}async function ps(e,t){let n=await S(e,"GET",`/skills/${encodeURIComponent(t)}`),r=Array.isArray(n.files)?n.files:[];return{kind:"library",id:n.id,name:n.name,description:n.description,content:n.content,files:r,version:typeof n.version?.hash=="string"?n.version.hash:zr(Xe(n.content),r),...typeof n.version?.revision=="number"?{revision:n.version.revision}:{}}}async function ro(e,t,n){let r=await S(e,"GET",`/skill-sources/skills/${encodeURIComponent(t)}${U({repo:n??void 0})}`);return{kind:"source",id:r.id,name:r.name,description:r.description,content:r.content,files:Array.isArray(r.files)?r.files:[],version:r.version.hash,commit:r.version.commit,repo:r.repo}}function Bl(e,t,n,r){return t==="library"?ps(e,n):ro(e,n,r)}async function fs(e,t,n){return S(e,"GET",`/skill-sources/skills${U({repo:t??void 0,team:n})}`)}async function ms(e,t,n){Gn(t.files);let r=[];if(t.files.length>0){let s=t.kind==="library"?`/skills/${encodeURIComponent(t.id)}/files`:`/skill-sources/skills/${encodeURIComponent(t.id)}/files${U({repo:n??void 0})}`;r=(await S(e,"GET",s)).files??[]}Zi(t.content,t.version,t.files,r);let o=t.kind==="library"?ls(t)["SKILL.md"]:t.content,i=new Map(r.map(s=>[s.path,s]));return[{path:"SKILL.md",content:o,executable:!1},...t.files.map(s=>({path:s.path,content:i.get(s.path).content,executable:s.executable===!0&&Hr(s.path)}))]}function hs(e){return{schema:1,kind:e.kind,id:e.id,name:e.name,...e.repo?{repo:e.repo}:{},...e.commit?{commit:e.commit}:{},...e.revision!==void 0?{revision:e.revision}:{},version:e.version}}function oo(e){return Qr(Kn(e,"x"))}function Hn(e){return e.scope==="project"?e.cwd??process.cwd():oo(e)}async function io(e,t,n){no(n);let r=Jn(t),o=Kn(n,r),i=await ms(e,t,n.repo??null),s=await Jr(o);if(!n.force){if(s&&s.id===t.id)throw new f(`The ${r} skill is already installed at ${o}.`,"Run `anyforge skill sync` to bring it up to date, or --force to reinstall it.");let c=[];for(let l of[...i.map(d=>d.path),Pt])try{await dt.lstat(Ce(o,l)),c.push(l)}catch(d){if(d.code!=="ENOENT")throw d}if(c.length>0)throw new f(`The ${r} skill already exists at ${o}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}let a=await Vr({base:Hn(n),directory:o,files:i,manifest:hs(t),previous:s&&s.id===t.id?s:null,force:n.force===!0});return{name:r,scope:n.scope,client:n.client,directory:o,files:a.written,id:t.id,kind:t.kind,version:t.version,removed:a.removed}}async function Gl(e){let t;try{t=await dt.readdir(e,{withFileTypes:!0})}catch(r){if(r.code==="ENOENT")return[];throw r}let n=[];for(let r of t.sort((o,i)=>o.name.localeCompare(i.name))){if(!r.isDirectory())continue;let o=Ce(e,r.name),i=await Jr(o);i&&n.push({directory:o,manifest:i})}return n}function Wn(e){return e instanceof Error?e.message:String(e)}async function eo(e,t){no(t);let n=oo(t),r=t.repo??null,o=t.force===!0,i=t.dryRun===!0;await Ye(Hn(t),n);let s=null;if(t.team&&(s=await fs(e,r,t.team),s.sources.length===0))throw new f(`No skill source is owned by the team "${t.team}".`,"Check the team's slug on its page in the Console.");let a=new Set(s?.sources.map(w=>w.id)??[]),c=w=>{let v=w.startsWith("source:")?w.slice(7):null;return v&&v.includes(":")?v.slice(0,v.indexOf(":")):null},l=(await Gl(n)).filter(({manifest:w})=>!s||w.kind==="source"&&a.has(c(w.id)??"")),d=[];for(let{directory:w,manifest:v}of l){let x={name:v.name,id:v.id,kind:v.kind},b;try{b=await Bl(e,v.kind,v.id,r)}catch(m){if(!Dl(m)){d.push({...x,action:"failed",reason:Wn(m)});continue}try{let A=await ln(w,v);if(A.length>0&&!o){d.push({...x,action:"kept",files:A,reason:"removed upstream, but you edited it"});continue}i||await ns(Hn(t),w,v,o),d.push({...x,action:"removed"})}catch(A){d.push({...x,action:"failed",reason:Wn(A)})}continue}try{let m=await ln(w,v);if(b.version===v.version&&!(o&&m.length>0)){d.push({...x,action:"unchanged"});continue}if(m.length>0&&!o){d.push({...x,action:"kept",files:m,reason:"you edited it"});continue}let A=await es(w,v,b.files);if(A.length>0&&!o){d.push({...x,action:"kept",files:A,reason:"the new version adds files you already have"});continue}if(i){Gn(b.files),d.push({...x,action:"updated"});continue}let L=await ms(e,b,r),D=await Vr({base:Hn(t),directory:w,files:L,manifest:hs(b),previous:v,force:o});d.push({...x,action:"updated",...D.removed.length>0?{files:D.removed}:{}})}catch(m){d.push({...x,action:"failed",reason:Wn(m)})}}let u=new Set(l.map(({manifest:w})=>w.id));for(let w of s?.skills??[]){if(u.has(w.id))continue;let v={name:w.name,id:w.id,kind:"source"};try{if(i){d.push({...v,action:"added"});continue}let x=await ro(e,w.id,r);await io(e,x,{...t,repo:r,force:!1}),d.push({...v,action:"added"})}catch(x){d.push({...v,action:"failed",reason:Wn(x)})}}return{dryRun:i,scope:t.scope,client:t.client,directory:n,results:d}}function Xr(e){let t=e.scope??"project",n=e.client??"agents";if(!["project","user"].includes(t))throw new f(`--scope must be project or user, got "${t}".`);if(!Object.hasOwn(to,n))throw new f(`--client must be agents, claude, codex, or opencode, got "${n}".`);let r=e.repo!==void 0?e.repo:t==="project"?co(e.cwd??process.cwd()):null;return{scope:t,client:n,force:e.force,...e.cwd?{cwd:e.cwd}:{},...e.homeDir?{homeDir:e.homeDir}:{},...e.codexHome?{codexHome:e.codexHome}:{},repo:r}}async function gs(e,t,n){try{return(await fs(e,t,n)).skills}catch(r){if(!n&&r instanceof ee&&(r.status===403||r.status===404))return[];throw r}}async function Wl(e,t,n,r){let o=t.trim().toLowerCase();if(!r)try{let a=await us(e,t);return ps(e,a.id)}catch(a){if(!(a instanceof f))throw a}let i=await gs(e,n,r),s=i.find(a=>a.name.toLowerCase()===o)??i.find(a=>Jn(a)===o);if(!s)throw new f(r?`The team "${r}" has no skill named "${t}" in its skill sources.`:`No skill named "${t}" in your company's library or skill sources.`,"Run `anyforge skill list` to see the skills you can install.");return ro(e,s.id,n)}function os(e){let t=e.dryRun?"Would sync":"Synced";console.log(`${Zr(t)} ${e.results.length} ${e.results.length===1?"skill":"skills"} ${Oe(`(${e.scope}, ${e.client})`)}`),console.log(` ${e.directory}`);for(let n of e.results){let r=Hl[n.action].padEnd(16),o=n.action==="failed"?ql:n.action==="kept"?ss:n.action==="unchanged"?Oe:Zr,i=n.action==="kept"?Oe(` \u2014 ${n.reason}: ${(n.files??[]).join(", ")}. --force replaces it.`):n.action==="failed"?Oe(` \u2014 ${n.reason}`):"";console.log(` ${o(r)} ${n.name}${i}`)}e.results.length===0&&console.log(Oe(" No skills installed by AnyForge here. Install one with `anyforge skill install <name>`."))}async function so(e){if(e.subcommand==="list"){let i=await e.resolveCreds(),{repo:s}=Xr(e),[a,c]=await Promise.all([e.team?Promise.resolve([]):ds(i),gs(i,s,e.team)]);if(e.json){process.stdout.write(JSON.stringify({skills:a,sourceSkills:c})+`
382
+ `);return}a.length===0&&c.length===0&&console.log(Oe("Your company has no skills in its library yet."));for(let l of a)console.log(`${l.name}${l.description?Oe(` \u2014 ${l.description}`):""}`);for(let l of c)console.log(`${l.name} ${Oe(`(${l.repo})`)}${l.description?Oe(` \u2014 ${l.description}`):""}`);return}if(e.subcommand==="sync"){let i=await eo(await e.resolveCreds(),{...Xr(e),team:e.team,dryRun:e.dryRun});e.json?process.stdout.write(JSON.stringify(i)+`
383
+ `):os(i);let s=i.results.filter(a=>a.action==="failed").length;if(s>0)throw new h(`${s} ${s===1?"skill":"skills"} could not be synced.`,g.FAILURE);return}if(e.subcommand!=="install")throw new f(`Unknown skill command${e.subcommand?`: ${e.subcommand}`:""}.`,"Use `anyforge skill list`, `anyforge skill install <name>` or `anyforge skill sync`.");if(!e.name&&!e.team)throw new f("Name the skill to install.",`Use \`anyforge skill install ${Re}\`, or \`anyforge skill list\` for your company's skills.`);let t=Xr(e);if(e.name===Re&&!e.team){let i=await as(t);is(i,e.json);return}let n=await e.resolveCreds();if(!e.name&&e.team){let i=await eo(n,{...t,team:e.team});e.json?process.stdout.write(JSON.stringify(i)+`
384
+ `):os(i);let s=i.results.filter(a=>a.action==="failed").length;if(s>0)throw new h(`${s} ${s===1?"skill":"skills"} could not be installed.`,g.FAILURE);return}let r=await Wl(n,e.name,t.repo,e.team),o;try{o=await io(n,r,t)}catch(i){throw i instanceof te?new h(i.message,g.FAILURE):i}is(o,e.json)}function is(e,t){if(t){process.stdout.write(JSON.stringify(e)+`
385
+ `);return}console.log(Zr("Installed ")+`${e.name} ${Oe(`(${e.scope}, ${e.client})`)}`),console.log(` ${e.directory}`);let n=e.name===Re?"Re-run with --force to refresh them.":"Run `anyforge skill sync` to update it.";console.log(Oe(` ${e.files.length} ${e.files.length===1?"file":"files"} installed. ${n}`)),e.name===Re&&e.scope==="project"&&e.client==="agents"&&console.log(ss(" This portable location is detected by AnyForge repository analysis."))}var to,jl,Hl,ao=he(()=>{"use strict";Gi();q();W();rs();lo();jn();to={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills",opencode:".opencode/skills"};jl=new Set(["skill_not_found","skill_no_longer_available"]);Hl={added:"added",updated:"updated",unchanged:"unchanged",removed:"removed upstream",kept:"kept",failed:"failed"}});import{execFileSync as Vn}from"child_process";import{stat as zl}from"fs/promises";import Kl from"open";import ut from"prompts";import{green as Me,dim as $,bold as ce,yellow as ye,cyan as dn}from"kleur/colors";async function bs(e){let{endpoint:t}=e;console.log(ce("AnyForge Control \u2014 device authorisation")),console.log($(` endpoint: ${t}`));let n=process.cwd(),r=vs(n),o=r?co(r):null,s=await(await fetch(`${t}/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:l}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${dn(c)}`),console.log($(` Code: ${a}`)),console.log();try{await Kl(c)}catch{}let{credentials:d,modelRouting:u,gatewayProviders:w}=await Yl({pollUrl:l,endpoint:t});if(await yi(d),console.log(Me("\u2714")+" API key saved to "+$("~/.anyforge/credentials")),!u){await Zl(t,d.apiKey);return}let v=await ji();if(v.isSubscription&&!e.force){await Ql(v,t,d.apiKey,w);return}let x=process.cwd(),b=vs(x),m=await rd(b),A=await qi({endpoint:t,apiKey:d.apiKey,scope:m,repoRoot:b,gatewayProviders:w});A.length===0?(console.log(ye("No agent configs were patched.")),console.log($(" Set ANTHROPIC_BASE_URL="+t+"/v1/anthropic and")),console.log($(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):od(A),await uo(t),console.log(),v.isSubscription&&e.force&&(console.log(ye(` \u26A0 --force: your Claude ${v.plan??""} subscription login is now shadowed`)),console.log(ye(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(ye(" needs an Anthropic API key on your company. Run ")+ce("anyforge logout")),console.log(ye(" to revert and restore your subscription."))),m==="repo"&&(console.log($(" Re-run this command in another repo to patch it too,")),console.log($(' or run from any directory and choose "global" to install system-wide.'))),console.log(ce("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: "+dn(`${t}/usage`))}async function Yl(e){let t=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-t<Vl;){await new Promise(i=>setTimeout(i,Jl)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
386
+ `),n=0);let o=await(await fetch(e.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+Me("done")+`
387
+ `),{credentials:{apiKey:o.data.apiKey,companyId:o.data.companyId,endpoint:e.endpoint,savedAt:new Date().toISOString()},modelRouting:o.data.modelRouting!==!1,gatewayProviders:Si(o.data.gatewayProviders)};if(o.status==="expired"||o.status==="not_found")throw process.stdout.write(`
388
+ `),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}function Xl(e,t){return["mcp","add","anyforge","--env",`ANYFORGE_API_TOKEN=${t}`,"--env",`ANYFORGE_API_URL=${e}`,"--","npx","-y","@anyforge/mcp-server"]}async function Ql(e,t,n,r){let o=e.email?` (${e.email})`:"";if(console.log(),console.log(ye(` \u26A0 Claude ${e.plan??""} subscription login detected${o}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+ce("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 "+ce("override and")),console.log(" "+ce("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+ce("AnyForge")),console.log(" "+ce("MCP server")+" for control (HIL approvals, work items, crews):"),console.log(),await ks(t,n),console.log(),(await ut({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts and tool, MCP and skill activity \u2014 never prompt content)",initial:!0})).go){let s=await ut({type:"confirm",name:"go",message:"Also send the names of the MCP servers and skills you use? This turns on Claude Code's tool details, which also sends Bash commands, file paths and tool input to AnyForge. AnyForge drops those on arrival and never stores them.",initial:!1}),a=await Ui({endpoint:t,apiKey:n,toolDetails:s.go===!0});a&&(console.log(Me(" \u2714")+" Usage telemetry enabled \u2014 view it at "+dn(`${t}/usage`)),console.log($(" (written to "+a.path+"; `anyforge logout` removes it)")))}else console.log($(" Skipped \u2014 your subscription usage stays local to Claude Code."));await st()&&(console.log(),await Dr({endpoint:t,apiKey:n,gatewayProviders:r})),await uo(t),console.log(),console.log($(" Want the metered BYOK proxy instead? Re-run with ")+ce("--force")+$(" using an")),console.log($(" Anthropic API key on your company (this disables your subscription in")),console.log($(" Claude Code; ")+ce("anyforge logout")+$(" reverts it).")),console.log(),console.log(ce("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: "+dn(`${t}/usage`))}async function Zl(e,t){console.log(),console.log(ye(" This key is read-only")+$(" (Viewer role).")),console.log(" It reads programs, initiatives, work items and the strategy through the"),console.log(" "+ce("AnyForge MCP server")+". Routing model calls through the company's keys"),console.log(" needs the Editor role, so your Claude Code config was "+ce("not")+" patched."),console.log(),await ks(e,t),await uo(e),console.log(),console.log(ce("Done.")+" Run `anyforge status` to check identity and local setup.")}async function ks(e,t){let n=Xl(e,t),r="claude mcp add anyforge -- npx -y @anyforge/mcp-server";if((await ut({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{Vn("claude",n,{stdio:"inherit"}),console.log(Me(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(ye(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log($(" Add it manually:")),console.log(" "+r)}else console.log($(" Add it later with:")),console.log(" "+r)}async function uo(e){await st()&&(await ed(e),await nd(e))}async function ed(e){console.log();let t=await on(),n=t.config!==null&&jr(t.config),r=await Promise.resolve().then(()=>(ao(),ws)),o={scope:"user",client:"opencode"},i=await td(r.resolveSkillInstallDirectory(o));if(n&&i){console.log($(" OpenCode already has the AnyForge MCP server and skill ("+t.path+")."));return}if(!(await ut({type:"confirm",name:"go",message:"Add the AnyForge tools to OpenCode? (MCP server and skill; you sign in once in the browser)",initial:!0})).go){console.log($(" Skipped \u2014 run `anyforge init` again to add them."));return}if(!i)try{let a=await r.installPlatformSkill(o);console.log(Me(" \u2714")+" AnyForge skill installed for OpenCode "+$("("+a.directory+")"))}catch(a){console.log(ye(" Could not install the AnyForge skill: ")+a.message)}if(!n){if(!t.config){console.log(ye(" "+t.path+" is not plain JSON (comments?), so it was not changed.")),console.log($(' Add under "mcp": ')+`"anyforge": { "type": "remote", "url": "${e}/api/mcp", "enabled": true }`),console.log($(" then run: ")+ys);return}await sn(t.path,Ii(t.config,e)),console.log(Me(" \u2714")+" AnyForge MCP server added to OpenCode "+$("("+t.path+")")),console.log($(" Signing OpenCode in to AnyForge \u2014 finish in the browser tab that opens."));try{Vn("opencode",["mcp","auth","anyforge"],{stdio:"inherit"}),console.log(Me(" \u2714")+" OpenCode signed in to the AnyForge tools")}catch{console.log(ye(" The sign-in did not finish. Run it again with: ")+ys)}}}async function td(e){try{return await zl(e),!0}catch{return!1}}async function nd(e){if(!await st())return;if(console.log(),!(await ut({type:"confirm",name:"go",message:"Send OpenCode usage to your AnyForge dashboard? (token counts and tool, MCP and skill activity \u2014 never prompt content)",initial:!0})).go){console.log($(" Skipped \u2014 OpenCode usage stays on this machine."));return}let n=await ut({type:"confirm",name:"go",message:"Also send the names of the MCP servers and skills you use in OpenCode?",initial:!1});try{let r=await $i({sendNames:n.go===!0});console.log(Me(" \u2714")+" OpenCode usage telemetry enabled \u2014 view it at "+dn(`${e}/usage`)),console.log($(" (plugin at "+r+"; restart OpenCode to load it; `anyforge logout` removes it)"))}catch(r){console.log(ye(" Could not install the OpenCode plugin: ")+r.message)}}function vs(e){try{return Vn("git",["rev-parse","--show-toplevel"],{cwd:e,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function rd(e){return e?(await ut({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${e}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log($(" Not a git repo root \u2014 installing globally.")),console.log($(" Run this from a repo root if you want a per-repo install instead.")),"global")}function od(e){console.log(Me("\u2714")+" Patched "+e.length+" agent config"+(e.length===1?"":"s")+":");for(let t of e)console.log(` ${$("\u2022")} ${t.label} ${$("("+t.path+")")}`)}function co(e){try{let t=Vn("git",["remote","get-url","origin"],{cwd:e,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=t.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=t.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}var Jl,Vl,ys,lo=he(()=>{"use strict";nn();Gr();jn();Jl=2e3,Vl=900*1e3;ys="opencode mcp auth anyforge"});var _r={};hi(_r,{default:()=>nf});var nf,Sr=he(()=>{nf={name:"@anyforge/control",version:"0.15.0",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 && esbuild src/opencodePlugin/plugin.ts --bundle --platform=node --format=esm --outfile=dist/opencode-plugin.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:{"@agentclientprotocol/sdk":"^1.9.0","@earendil-works/pi-tui":"^1.0.2",kleur:"^4.1.5",open:"^11.0.4",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.28.2","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});lo();import{red as Uc,yellow as Gf,dim as rt,bold as K}from"kleur/colors";nn();W();import{dim as fo,yellow as ad,bold as cd}from"kleur/colors";W();async function un(e){return S(e,"GET","/me")}function po(e,t,n,r){let o=e?.entityLabels?.[t]?.[n];return typeof o=="string"&&o.trim()?o:r}async function Os(e){try{return await un(e)}catch{return null}}function As(e){return[...e].length}function Lt(e,t){if(t<=0)return"";let n=[...e];return n.length<=t?e:t===1?"\u2026":`${n.slice(0,t-1).join("")}\u2026`}function z(e,t){if(e.length===0)return"";let n=e.map(i=>t.map(s=>{let a=s.value(i)??"";return s.max?Lt(a,s.max):a})),r=t.map((i,s)=>Math.max(As(i.header),...n.map(a=>As(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(t.map(i=>i.header)),...n.map(o)].join(`
389
+ `)}function I(e){return JSON.stringify(e,null,2)}function xs(e,t=Date.now()){let n=id(e);if(n===null)return"\u2014";let r=Math.max(0,Math.floor((t-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 id(e){if(typeof e=="number")return Number.isFinite(e)?e:null;if(typeof e=="string"){let t=Date.parse(e);return Number.isNaN(t)?null:t}return null}function T(e,t,n="\u2014"){let r=e[t];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function se(e,t,n="\u2014"){for(let r of t){let o=e[r];if(typeof o=="string"&&o.trim())return o}return n}function ve(e){let t=Array.isArray(e)?e:e&&typeof e=="object"?sd(e):null;return t?t.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function sd(e){for(let t of["items","results","rows","data"])if(Array.isArray(e[t]))return e[t];return null}function Yn(e,t,n){let r=e?`last ${e}d`:"all time";return!t||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${e?`${e}d`:"all time"} \u2014 read cap`}async function _s(e){let t=await Ne(e.endpoint),n=await un(t);if(e.json){console.log(I(n));return}console.log(`Company: ${cd(n.companyName??n.companyId)}${n.companyName?fo(` (${n.companyId})`):""}`),console.log(`Endpoint: ${t.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):ad("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await Tt();console.log(r?fo(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):fo("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}nn();Gr();import{green as Ss,dim as Xn,yellow as ld}from"kleur/colors";async function Rs(){let e=await Tt(),t=await vi(),{reverted:n}=await Di({endpoint:e?.endpoint??null});if(console.log(t?Ss("\u2714")+" Local credentials cleared.":ld("No credentials were saved on this machine.")),n.length){console.log(Ss("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${Xn("\u2022")} ${r}`);console.log(Xn(" Your previous Claude Code login (if any) is restored."))}else console.log(Xn(" No AnyForge config patches found to revert."));console.log(Xn(" Revoke the key server-side at /settings \u2192 API keys."))}W();import{readFile as Qn}from"node:fs/promises";import{homedir as dd}from"node:os";import{dirname as mo,join as qe}from"node:path";function Qe(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{}}async function Is(e,t={home:dd(),cwd:process.cwd(),env:process.env}){let n=e.endpoint.replace(/\/$/,""),r=[],o={};try{o=Qe(JSON.parse(await Qn(qe(t.home,".anyforge","credentials"),"utf8")))}catch{}function i(a,c){let l=Qe(c),d=Qe(l.env),u=Object.values(Qe(l.mcpServers));r.push({source:a,readable:!0,mcp:u.some(w=>{let v=Qe(w),x=Qe(v.env),b=Array.isArray(v.args)?v.args:[],m=x.ANYFORGE_API_TOKEN??t.env.ANYFORGE_API_TOKEN,A=x.ANYFORGE_API_URL??t.env.ANYFORGE_API_URL,L=m??o.apiKey,D=A??(m?"https://crew.anyforge.ai":o.endpoint)??"https://crew.anyforge.ai";return b.includes("@anyforge/mcp-server")&&L===e.apiKey&&D===n}),proxy:d.ANTHROPIC_BASE_URL===`${n}/v1/anthropic`&&d.ANTHROPIC_AUTH_TOKEN===e.apiKey,subscriptionTelemetry:String(d.CLAUDE_CODE_ENABLE_TELEMETRY)==="1"&&(d.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL??d.OTEL_EXPORTER_OTLP_PROTOCOL)==="http/json"&&(d.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===void 0||d.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===`${n}/api/otel/v1/metrics`)&&d.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE==="delta"&&d.OTEL_METRICS_EXPORTER==="otlp"&&d.OTEL_EXPORTER_OTLP_ENDPOINT===`${n}/api/otel`&&(d.OTEL_EXPORTER_OTLP_METRICS_HEADERS??d.OTEL_EXPORTER_OTLP_HEADERS)===`Authorization=Bearer ${e.apiKey}`})}i("Current shell",{env:t.env});let s=t.cwd;for(;mo(s)!==s;){try{await Qn(qe(s,".git","HEAD"));break}catch{}try{await Qn(qe(s,".git"));break}catch{}s=mo(s)}mo(s)===s&&(s=t.cwd);for(let a of new Set([qe(t.home,".claude","settings.json"),qe(s,".claude","settings.json"),qe(s,".claude","settings.local.json"),qe(s,".mcp.json"),qe(t.home,".claude.json")]))try{let c=JSON.parse(await Qn(a,"utf8"));if(i(a,c),a===qe(t.home,".claude.json")){let l=Qe(Qe(c).projects)[s];l&&i(`${a} (project)`,l)}}catch(c){c.code!=="ENOENT"&&r.push({source:a,mcp:!1,proxy:!1,subscriptionTelemetry:!1,readable:!1})}return r}var ud=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,pd=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function p(e){return e.replace(ud,"").replace(pd,"")}function ho(e){try{let t=new URL(e);return t.protocol!=="https:"&&t.protocol!=="http:"||!t.hostname||t.username||t.password?null:t.toString()}catch{return null}}function Cs(e){return e.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(t,n)=>ho(n)?t:"\x1B]8;;\x07")}function Es(e,t){if(!t||!e.startsWith("/")||e.startsWith("//"))return e;try{return new URL(e,t).toString()}catch{return e}}function Ts(e,t){return t?e.replace(/(\]\()(<?)(\/(?!\/)[^\s)>]*)/g,(n,r,o,i)=>`${r}${o}${Es(i,t)}`):e}function go(e,t){let r=p(e).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(s,a,c,l)=>{let d=Es(l.startsWith("<")&&l.endsWith(">")?l.slice(1,-1):l,t),u=ho(d);return u?`${a}[${c}](${u})`:c}),o=new Map,i=r.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(s,a,c,l,d)=>{let u=ho(l);return o.set(c.trim().toLowerCase(),u),u?`${a}${u}${d}`:""});return o.size===0?i:i.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(s,a,c,l)=>{let d=(l||c).trim().toLowerCase();return!o.has(d)||o.get(d)?s:c})}function Ue(e){return typeof e=="string"?p(e):Array.isArray(e)?e.map(t=>Ue(t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([t,n])=>[p(t),Ue(n)])):e}function $s(e){return e.state==="received"?e.lastRecordedAt??"Timestamp unavailable":e.state==="unattributed"?"Unknown: this credential has no user attribution":e.state==="unavailable"?"Unavailable: retry the check":"No recorded activity for this user in this company"}async function Ps(e){let t=await Ne(e.endpoint),n=await S(t,"GET","/connection"),r=await Is(t),o={...n,endpoint:t.endpoint,localConfiguration:r};if(e.json)console.log(I(o));else{let i=[`Endpoint: ${t.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(l=>l[s]).map(l=>l.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: ${$s(n.proxy)}`,`Latest recorded subscription telemetry: ${$s(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, estimated cost and, when your company turns it on, counts of the tools, MCP servers and skills used. Never prompts, commands, file paths or full traces.",`Usage: ${t.endpoint.replace(/\/$/,"")}/usage`,`Traces: ${t.endpoint.replace(/\/$/,"")}/traces (MCP access alone does not create inference traces)`),console.log(i.map(p).join(`
390
+ `))}[n.proxy,n.subscriptionTelemetry].some(i=>i.state==="unavailable")&&(process.exitCode=1)}import{spawn as fd}from"node:child_process";import{readFile as md}from"node:fs/promises";import{red as pn,green as wo,yellow as hd,dim as fn,bold as Ls}from"kleur/colors";async function Ns(e){let t=await gd(e.patchFile);t.trim()||(process.stderr.write(pn(`Empty patch \u2014 nothing to apply.
391
+ `)),process.exit(1));let n=wd(t);process.stderr.write(fn(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+wo(`+${n.added}`)+" "+pn(`-${n.removed}`)+`
392
+ `);let r=await yo(["apply","--check"],t);if(r.code!==0){if(e.threeWay){let i=await yo(["apply","--3way"],t);i.code!==0&&(process.stderr.write(pn(`3-way apply failed:
393
+ `)+i.stderr+`
394
+ `),process.exit(1)),process.stderr.write(hd(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
395
+ `));return}process.stderr.write(pn(`Patch does not apply cleanly:
396
+ `)+r.stderr+`
397
+ `),process.stderr.write(fn("Try ")+Ls("--3way")+fn(` to attempt a 3-way merge against the index.
398
+ `)),process.exit(1)}if(e.dryRun){process.stderr.write(wo(`\u2713 Patch would apply cleanly.
399
+ `));return}let o=await yo(["apply"],t);o.code!==0&&(process.stderr.write(pn(`git apply failed:
400
+ `)+o.stderr+`
401
+ `),process.exit(1)),process.stderr.write(wo(`\u2713 Applied.
402
+ `)),n.files>0&&process.stderr.write(fn(" Run ")+Ls("git diff --stat")+fn(` to review.
403
+ `))}async function gd(e){if(e)return await md(e,"utf8");let t=[];for await(let n of process.stdin)t.push(n);return Buffer.concat(t).toString("utf8")}function yo(e,t){return new Promise((n,r)=>{let o=fd("git",e,{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(t),o.stdin.end()})}function wd(e){let t=0,n=0,r=0;for(let o of e.split(`
404
+ `))if(o.startsWith("diff --git"))t+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return t===0&&(n>0||r>0)&&(t=(e.match(/^\+\+\+ /gm)??[]).length),{files:t,added:n,removed:r}}W();import{bold as yd,dim as vo,green as vd,red as bd}from"kleur/colors";q();async function Fs(e){let t=await S(e.creds,"GET",`/hil${U({limit:e.limit})}`);if(e.json){console.log(I(t));return}let n=ve(t);if(n.length===0){console.log(vo("No approvals pending."));return}console.log(z(n,[{header:"ID",value:r=>T(r,"id")},{header:"CREW",value:r=>T(r,"crewId"),max:24},{header:"AGE",value:r=>xs(r.requestedAt)},{header:"SUMMARY",value:r=>se(r,["planSummary","summary","title","description"]),max:60}])),console.log(vo(`
405
+ ${n.length} pending \xB7 approve with `)+yd("anyforge approve <id>"))}async function bo(e){if(!e.approvalId)throw new f(`${e.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let t=await S(e.creds,"POST",`/hil/${encodeURIComponent(e.approvalId)}`,{decision:e.decision,...e.notes?{notes:e.notes}:{}});if(e.json){console.log(I(t));return}let n=e.decision==="APPROVED"?vd("Approved"):bd("Rejected");console.log(`${n} ${e.approvalId}`);let r=t&&typeof t=="object"?t.signature:void 0;typeof r=="string"&&r&&console.log(vo(`Audit signature: ${r}`))}W();import{bold as kd,dim as ko}from"kleur/colors";q();async function Ms(e){let t=await S(e.creds,"GET",`/crews${U({status:e.status,activeOnly:e.activeOnly,limit:e.limit})}`);if(e.json){console.log(I(t));return}let n=ve(t);if(n.length===0){console.log(ko(e.activeOnly?"No active crews.":"No crews."));return}console.log(z(n,[{header:"ID",value:r=>T(r,"id")},{header:"STATUS",value:r=>T(r,"status")},{header:"TASK",value:r=>se(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>se(r,["errorMessage"],""),max:40}]))}async function qs(e){if(!e.crewId)throw new f("crew requires a crew id.","List them with `anyforge crews`.");let t=await S(e.creds,"GET",`/crews/${encodeURIComponent(e.crewId)}${U({messages:e.messages})}`);if(e.json){console.log(I(t));return}let n=t?.crew&&typeof t.crew=="object"?t.crew:t;console.log(`${kd(Od(se(n,["taskDescription"],T(n,"id"))))}`),console.log(`Status: ${T(n,"status")}`),console.log(`Repo: ${se(n,["githubRepo"])}`);let r=T(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=T(n,"url","");o&&console.log(`Console: ${o}`);let i=ve(t?.chat);if(i.length>0){console.log(ko(`
406
+ Last ${i.length} messages:`));for(let s of i){let a=se(s,["agentRole","role","author","agent","type"],"?"),c=se(s,["content","body","text","summary"],"");c&&console.log(`${ko(`[${a}]`)} ${Lt(c.replace(/\s+/g," "),160)}`)}}}async function Oo(e){if(!e.crewId)throw new f(`${e.action} requires a crew id.`,"List them with `anyforge crews`.");let t=await S(e.creds,"POST",`/crews/${encodeURIComponent(e.crewId)}/${e.action}`);if(e.json){console.log(I(t));return}console.log(`${e.action==="halt"?"Halted":"Resumed"} ${e.crewId}`)}function Od(e){return Lt(e.split(/\r?\n/).find(t=>t.trim())?.trim()??e,80)}W();import{bold as Ad,dim as Nt,red as Us,yellow as Ds}from"kleur/colors";q();var xd=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),_d=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),Sd={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 Bs(e){if(!e.workItemId)throw new f("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let t=await S(e.creds,"PATCH",`/work/${encodeURIComponent(e.workItemId)}`,{action:"dispatch",...e.profileId?{runProfileId:e.profileId}:{}});if(e.json&&!e.follow){console.log(I(t));return}let n=typeof t?.crewId=="string"?t.crewId:"";if(!n)throw new h("Dispatch was accepted but returned no crew id.",g.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of t?.warnings??[])console.error(Ds(`warning: ${r}`));if(!e.follow){console.log(`Started ${Ad(n)} on ${e.workItemId}`),console.log(Nt(`Follow it with \`anyforge crew follow ${n}\``));return}await Ao({creds:e.creds,json:e.json,crewId:n,intervalSeconds:e.intervalSeconds})}var Rd=5,Id=10,Cd=120,js=30;async function Ao(e){if(!e.crewId)throw new f("crew follow requires a crew id.","List them with `anyforge crews --active`.");let t=Math.min(Math.max(e.intervalSeconds??Id,Rd),Cd)*1e3,n=Date.now()+js*6e4,r=new Set,o="",i=!1;for(;;){let s=await S(e.creds,"GET",`/crews/${encodeURIComponent(e.crewId)}?messages=50`),a=s?.crew??{},c=T(a,"status","");for(let l of s?.chat??[]){let d=T(l,"id","");!d||r.has(d)||(r.add(d),i&&!e.json&&Ed(l))}if(i=!0,c&&c!==o&&(e.json||console.log(Nt(`\u2500\u2500 ${c}`)),o=c),_d.has(c)){if(e.json)console.log(I({crewId:e.crewId,status:c,waiting:!0,url:T(a,"url","")}));else{console.log(Ds(`
407
+ ${c} \u2014 this crew is waiting on a person.`));let l=Sd[c];l&&console.log(Nt(l));let d=T(a,"url","");d&&console.log(Nt(d))}return}if(xd.has(c)){if(e.json)console.log(I({crewId:e.crewId,status:c,waiting:!1,url:T(a,"url","")}));else{let l=`
408
+ ${c}`;console.log(c==="COMPLETE"?l:Us(l));let d=T(a,"prUrl","");d&&console.log(Nt(d));let u=T(a,"errorMessage","");u&&console.log(Us(u))}if(c!=="COMPLETE")throw new h(`Crew ${e.crewId} ended ${c}.`,g.FAILURE);return}if(Date.now()>=n)throw new h(`Still ${c||"running"} after ${js} minutes \u2014 giving up watching.`,g.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${e.crewId}\`.`);await $d(t)}}function Ed(e){let t=T(e,"agentRole","")||T(e,"type","?"),n=Td(e,["content","text","summary"]);n&&console.log(`${Nt(`[${t}]`)} ${Lt(n.replace(/\s+/g," "),160)}`)}function Td(e,t){for(let n of t){let r=e[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function $d(e){return new Promise(t=>{setTimeout(t,e)})}W();q();import{randomUUID as So}from"node:crypto";import{promises as Ro}from"node:fs";import{relative as Bd,resolve as Gd,isAbsolute as Wd}from"node:path";import{execFile as Hd}from"node:child_process";import{promisify as zd}from"node:util";import Kd from"open";q();import{execFile as qd}from"node:child_process";import{promises as ft}from"node:fs";import{tmpdir as Ud}from"node:os";import{join as _o,resolve as Hs}from"node:path";var Pd=[/sk-ant-[a-zA-Z0-9_-]{20,}/,/sk-(?:proj-)?[a-zA-Z0-9_-]{20,}/,/ghp_[a-zA-Z0-9]{30,}/,/gh[sou]_[a-zA-Z0-9]{30,}/,/github_pat_[a-zA-Z0-9_]{30,}/,/AIza[0-9A-Za-z_-]{30,}/,/AKIA[0-9A-Z]{16}/,/sk_(?:live|test)_[a-zA-Z0-9]{20,}/,/xox[bpaors]-[0-9]+-[0-9]+-[a-zA-Z0-9-]{20,}/,/eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/,/-----BEGIN [A-Z ]*PRIVATE KEY-----/,/(?:api[_-]?key|secret|password|passwd|token|bearer)[\s:=]+['"]?[a-zA-Z0-9_+/=-]{16,}/i];function Ld(e,t){return t.some(n=>n.test(e))}function Gs(e){return Ld(e,Pd)}var pt=100*1024,Ae=(e,t)=>({ok:!1,code:e,message:t});function xo(e){if(!e.startsWith('"'))return e;if(e.length<2||!e.endsWith('"'))return null;let t=e.slice(1,-1),n=[],r={a:7,b:8,t:9,n:10,v:11,f:12,r:13,'"':34,"\\":92};for(let o=0;o<t.length;o++){let i=t[o];if(i!=="\\"){n.push(...new TextEncoder().encode(i));continue}let s=t[o+1];if(s===void 0)return null;if(/[0-7]/.test(s)){let a=t.slice(o+1,o+4);if(!/^[0-7]{3}$/.test(a))return null;n.push(parseInt(a,8)),o+=3}else if(s in r)n.push(r[s]),o+=1;else return null}try{return new TextDecoder("utf-8",{fatal:!0}).decode(new Uint8Array(n))}catch{return null}}function Nd(e){return!e||e.startsWith("/")||e.includes("\0")||e.includes("\\")?!1:e.split("/").every(t=>t!==""&&t!=="."&&t!==".."&&t.toLowerCase()!==".git")}function Fd(e){if(e.startsWith('"')){let n=e.match(/^("(?:[^"\\]|\\.)*") ("(?:[^"\\]|\\.)*")$/);if(!n)return null;let[r,o]=[xo(n[1]),xo(n[2])];return r?.startsWith("a/")&&o?.startsWith("b/")&&r.slice(2)===o.slice(2)?r.slice(2):null}if((e.length-5)%2!==0)return null;let t=e.slice(2,2+(e.length-5)/2);return e===`a/${t} b/${t}`?t:null}function Md(e,t){let n=e.slice(4).replace(/\t$/,"");if(n==="/dev/null")return n;let r=xo(n);return r?.startsWith(t)?r.slice(2):null}function Ws(e){if(typeof e!="string"||e.length===0)return Ae("local_changes_empty","There are no local changes to send.");let t=new TextEncoder().encode(e).length;if(t>pt)return Ae("local_changes_too_large",`Your uncommitted changes are ${Math.ceil(t/1024)} KB; the limit is ${pt/1024} KB. Commit and push the larger part, then send the rest.`);if(!e.startsWith("diff --git "))return Ae("local_changes_invalid","The local changes must be a patch made by git diff.");let n=[],r=[],o=null,i=!1,s=0;for(let a of e.split(`
409
+ `)){if(a.startsWith("diff --git ")){if(o=Fd(a.slice(11)),o===null)return Ae("local_changes_invalid","The local changes contain a rename, a copy or a header this check cannot read. Commit and push those, then send the rest.");if(!Nd(o))return Ae("local_changes_unsafe_path",`The local changes name a path outside the repository: ${o}`);n.includes(o)||n.push(o),i=!1;continue}if(o===null)return Ae("local_changes_invalid","The local changes must be a patch made by git diff.");if(i&&/^[ +\-\\]/.test(a)){a.startsWith("+")?(Gs(a.slice(1))&&r.length<5&&r.push(`${o}:${s}`),s++):a.startsWith(" ")&&s++;continue}let c=a.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);if(c){i=!0,s=Number(c[1]);continue}if(i=!1,a==="")continue;if(a.startsWith("GIT binary patch")||/^Binary files .* differ$/.test(a))return Ae("local_changes_binary",`${o} is a binary file. Commit and push it, then send the rest.`);let l=a.match(/^(?:old mode|new mode|new file mode|deleted file mode) (\d+)$/)??a.match(/^index [0-9a-f]+\.\.[0-9a-f]+ (\d+)$/);if(l){if(l[1]==="120000"||l[1]==="160000")return Ae("local_changes_unsupported_file",`${o} is a ${l[1]==="120000"?"symbolic link":"submodule"}. Commit and push it, then send the rest.`);continue}if(!/^(?:index [0-9a-f]+\.\.[0-9a-f]+|similarity index \d+%|dissimilarity index \d+%)$/.test(a)){if(a.startsWith("--- ")||a.startsWith("+++ ")){let d=Md(a,a.startsWith("--- ")?"a/":"b/");if(d!=="/dev/null"&&d!==o)return Ae("local_changes_invalid",`The patch headers for ${o} disagree.`);continue}return Ae("local_changes_invalid",`The local changes for ${o} contain a line this check cannot read. Send a patch made by git diff without renames.`)}}return r.length?Ae("local_changes_secret",`Your uncommitted changes add what looks like a credential at ${r.join(", ")}. Remove it, or move it out of the repository, then try again. Nothing was sent.`):{ok:!0,files:n,bytes:t}}var Zn=class extends Error{constructor(n,r,o){super(r.trim()||`git ${n[0]} failed`);this.args=n;this.stderr=r;this.code=o}args;stderr;code};function ne(e,t){return new Promise((n,r)=>{let o=qd("git",e,{cwd:t.cwd,encoding:"utf8",maxBuffer:t.maxBuffer??1048576,timeout:t.timeout??3e4,env:{...process.env,GIT_TERMINAL_PROMPT:"0",...t.env}},(i,s,a)=>{i?r(new Zn(e,String(a??""),i.code)):n(String(s))});t.input!==void 0&&o.stdin?.end(t.input)})}var ae=(e,t)=>ne(e,t).then(n=>n.trim(),()=>null);function zs(e){let t=e.trim().match(/^(?:https:\/\/(?:[^@/]+@)?github\.com\/|ssh:\/\/git@github\.com(?::\d+)?\/|git@github\.com:)([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/);return t?`${t[1]}/${t[2]}`:null}async function Ks(e){let t=await ae(["rev-parse","--show-toplevel"],{cwd:e});if(!t)throw new f("Run this inside a Git checkout of the repository.");return t}async function Js(e){let t=await Ks(e),n=await ae(["symbolic-ref","--quiet","--short","HEAD"],{cwd:t});if(!n)throw new f("This checkout is not on a branch (detached HEAD). Check out the branch you are working on.");let r=await ae(["rev-parse","--verify","HEAD^{commit}"],{cwd:t});if(!r)throw new f(`${n} has no commits yet. Commit and push it first.`);let o=await ae(["config","--get",`branch.${n}.remote`],{cwd:t})||"origin",i=await ae(["config","--get",`remote.${o}.url`],{cwd:t}),s=i?zs(i):null;if(!s)throw new f(`The remote "${o}" is not a GitHub repository. Code Studio works on GitHub repositories.`);let a=await ae(["config","--get",`branch.${n}.merge`],{cwd:t}),c=a?.startsWith("refs/heads/")?a.slice(11):n;return{root:t,branch:n,head:r,remote:o,remoteBranch:c,repoFullName:s}}async function Vs(e){let t;try{t=await ne(["ls-remote","--heads",e.remote,`refs/heads/${e.remoteBranch}`],{cwd:e.root,timeout:6e4})}catch(o){throw new h(`Could not read ${e.remoteBranch} from ${e.remote}: ${o.message}`)}let n=t.split(`
410
+ `).map(o=>o.split(" ")).find(([,o])=>o===`refs/heads/${e.remoteBranch}`)?.[0];if(!n)throw new f(`${e.remoteBranch} is not on ${e.remote} yet. Push it first: git push -u ${e.remote} ${e.branch}`);if(n===e.head)return;throw await ae(["merge-base","--is-ancestor",n,e.head],{cwd:e.root})!==null?new f(`${e.branch} has commits that are not pushed. Push them first: git push ${e.remote} ${e.branch}`):new f(`${e.remote}/${e.remoteBranch} has moved on from your checkout. Pull it, then try again.`)}async function Ys(e){let{root:t}=e,n=(await ne(["ls-files","--others","--exclude-standard","-z"],{cwd:t,maxBuffer:16*1024*1024})).split("\0").filter(Boolean),r=0;for(let i of n){let s=await ft.lstat(_o(t,i));if(s.isSymbolicLink())throw new f(`${i} is a symbolic link. Commit and push it, then send the rest.`);if(!s.isFile())throw new f(`${i} is a nested repository. Commit and push it separately, then send the rest.`);if(r+=s.size,r>pt)throw new f(`Your untracked files alone are over ${pt/1024} KB. Commit and push the larger ones, or add them to .gitignore, then send the rest.`)}let o=await ft.mkdtemp(_o(Ud(),"anyforge-handoff-"));try{let i=_o(o,"index"),s=Hs(t,(await ne(["rev-parse","--git-path","index"],{cwd:t})).trim()),a=await ft.stat(s).catch(()=>null);a!==null&&await ft.copyFile(s,i).then(()=>!0,()=>!1)?await ft.utimes(i,a.atime,a.mtime):await ne(["read-tree","HEAD"],{cwd:t,env:{GIT_INDEX_FILE:i}});let l={GIT_INDEX_FILE:i};n.length&&await ne(["add","--intent-to-add","--pathspec-from-file=-","--pathspec-file-nul"],{cwd:t,env:l,input:`${n.join("\0")}\0`});let d;try{d=await ne(["-c","core.quotePath=true","diff","HEAD","--no-ext-diff","--no-textconv","--no-color","--no-renames","--ignore-submodules=none","--src-prefix=a/","--dst-prefix=b/"],{cwd:t,env:l,maxBuffer:pt*4})}catch(w){throw w instanceof Zn&&w.code==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"?new f(`Your uncommitted changes are over the ${pt/1024} KB limit. Commit and push the larger part, then send the rest.`):w}if(!d)return{patch:"",files:[]};let u=Ws(d);if(!u.ok)throw new f(u.message);return{patch:d,files:u.files}}finally{await ft.rm(o,{recursive:!0,force:!0})}}async function jd(e,t){let n=Hs(e,(await ne(["rev-parse","--git-path",t],{cwd:e})).trim());return ft.access(n).then(()=>!0,()=>!1)}async function Dd(e,t){let n=(await ne(["remote"],{cwd:e})).split(`
411
+ `).filter(Boolean),r=[...n.filter(o=>o==="origin"),...n.filter(o=>o!=="origin")];for(let o of r){let i=await ae(["config","--get",`remote.${o}.url`],{cwd:e});if(i&&zs(i)?.toLowerCase()===t.toLowerCase())return o}return null}async function Xs(e,t){let n=await Ks(e),r=t.repoFullName,o=t.branch;if(!r||!o)throw new f("This session has no repository branch to pick up.");if(o.startsWith("-")||await ae(["check-ref-format","--branch",o],{cwd:n})!==o)throw new h(`The session's branch name is not a valid Git branch: ${JSON.stringify(o)}`);let i=await Dd(n,r);if(!i)throw new f(`This checkout is not ${r}. Run pickup from a clone of it.`);for(let m of["MERGE_HEAD","rebase-merge","rebase-apply","CHERRY_PICK_HEAD","REVERT_HEAD"])if(await jd(n,m))throw new f("A merge, rebase, cherry-pick or revert is in progress here. Finish or abort it first.");let s=(await ne(["status","--porcelain","--untracked-files=no"],{cwd:n})).split(`
412
+ `).filter(Boolean);if(s.length){let m=s.slice(0,5).map(A=>A.slice(3)).join(", ");throw new f(`You have uncommitted changes (${m}${s.length>5?", \u2026":""}). Commit or stash them first; nothing was changed.`)}let a=`refs/remotes/${i}/${o}`;try{await ne(["fetch","--no-tags",i,`+refs/heads/${o}:${a}`],{cwd:n,timeout:12e4})}catch(m){let A=m.message;throw/couldn't find remote ref|could not find remote ref/i.test(A)?new f(`The session has not pushed ${o} yet. Push it from Code Studio, or run: anyforge studio push ${t.id} --input '{"expectedHeadSha":"<head>"}'`):new h(`Could not fetch ${o} from ${i}: ${A}`)}let c=(await ne(["rev-parse","--verify",`${a}^{commit}`],{cwd:n})).trim(),l=await ae(["rev-parse","--verify","HEAD^{commit}"],{cwd:n}),d=await ae(["rev-parse","--verify","--quiet",`refs/heads/${o}^{commit}`],{cwd:n}),u=await ae(["symbolic-ref","--quiet","--short","HEAD"],{cwd:n});if(d&&d!==c&&await ae(["merge-base","--is-ancestor",d,c],{cwd:n})===null)throw new f(`Your local ${o} has commits the session's branch does not. Nothing was changed. Rebase or merge ${i}/${o} yourself.`);try{d?(u!==o&&await ne(["checkout",o,"--"],{cwd:n}),d!==c&&await ne(["merge","--ff-only","--no-edit",c],{cwd:n})):await ne(["checkout","--track","-b",o,a],{cwd:n})}catch(m){throw new h(`Git refused to check out ${o}: ${m.message}`)}let w=[t.localChanges?.baseCommit,d,l?await ae(["merge-base",l,c],{cwd:n}):null],v=null;for(let m of w)if(m&&/^[0-9a-f]{40}$/.test(m)&&await ae(["merge-base","--is-ancestor",m,c],{cwd:n})!==null){v=m;break}let b=(v&&v!==c?await ne(["log","--no-color","--format=%H%x09%s","-n","21",`${v}..${c}`],{cwd:n}):"").split(`
413
+ `).filter(Boolean).map(m=>{let[A,...L]=m.split(" ");return{sha:A,subject:L.join(" ")}});return{repoFullName:r,branch:o,headSha:c,created:!d,commits:b.slice(0,20),moreCommits:b.length>20}}var Jd=zd(Hd);function Vd(e){if(!e)return{};try{let t=JSON.parse(e);if(!t||typeof t!="object"||Array.isArray(t))throw new Error("not an object");return t}catch{throw new f("--input must be a JSON object.")}}function be(e){if(!e||!/^[A-Za-z0-9_-]+$/.test(e))throw new f("A valid Studio session or run ID is required.");return encodeURIComponent(e)}async function Yd(e){let[t,n]=await Promise.all([Ro.realpath(process.cwd()),Ro.realpath(Gd(e))]),r=Bd(t,n).replaceAll("\\","/");if(!r||Wd(r)||r.split("/").includes(".."))throw new f("--file must be inside the current directory, including symlink targets.");let o=await Ro.open(n,"r"),i;try{let d=await o.stat();if(!d.isFile()||d.size>2e4)throw new f("--file must be a regular file of 20 KB or smaller; select a smaller context file.");let u=Buffer.alloc(20001),w=0;for(;w<u.length;){let{bytesRead:v}=await o.read(u,w,u.length-w,w);if(!v)break;w+=v}if(w>2e4)throw new f("--file grew beyond 20 KB; select a smaller context file.");i=u.subarray(0,w).toString("utf8")}finally{await o.close()}let s=async d=>{try{return(await Jd("git",d,{cwd:process.cwd(),timeout:5e3,maxBuffer:64e3})).stdout.trim()}catch{return null}},[a,c,l]=await Promise.all([s(["branch","--show-current"]),s(["rev-parse","HEAD"]),s(["status","--porcelain","--",r])]);return{content:`Local reference file: ${r}
414
+
415
+ ${i}`,localReference:{path:r,branch:a,commit:c,uncommitted:l===null||l.length>0||c===null}}}async function Qs(e){let t=Vd(e.input),n=e.command??"list";if(e.uncommitted&&n!=="create")throw new f("--uncommitted is only supported for studio create.");if(n==="pickup")return eu(e);let r="GET",o;if(n==="list")o="/studio/sessions";else if(n==="create")r="POST",o="/studio/sessions",t.idempotencyKey??=So(),e.repo&&(t.repoFullName=e.repo),e.branch&&(t.branch=e.branch),e.initiative&&(t.initiativeId=e.initiative),t.provenance={surface:"cli",workspace:"remote"},e.context&&(t.context=e.context);else if(n==="continue")r="POST",o=`/studio/sessions/${be(e.id)}/context`,t.idempotencyKey??=So(),t.provenance={surface:"cli",workspace:"remote"},e.context&&(t.content=e.context);else if(["get","open","context","usage","changes","artifacts","runs"].includes(n))o=`/studio/sessions/${be(e.id)}${n==="get"||n==="open"?"":`/${n}`}`;else if(n==="run")r="POST",o=`/studio/sessions/${be(e.id)}/runs`,t.idempotencyKey??=So(),e.context&&(t.content=e.context);else if(n==="events")o=`/studio/runs/${be(e.id)}/events${e.cursor?`?after=${encodeURIComponent(e.cursor)}`:""}`;else if(n==="status")o=`/studio/runs/${be(e.id)}`;else if(["cancel","pause","resume","steer","answer"].includes(n))r="POST",o=`/studio/runs/${be(e.id)}/control`,t.action=n,e.context&&(t.content=e.context);else if(["checkpoint","commit","stage","push"].includes(n))r="POST",o=`/studio/sessions/${be(e.id)}/${n==="checkpoint"?"checkpoints":n}`;else throw new f(`Unknown Studio command: ${n}.`,"Use studio list, create, continue, pickup, open, get, context, usage, run, runs, status, events, pause, resume, cancel, steer, answer, changes, artifacts, checkpoint, stage, commit, or push.");if(e.file){if(!["create","continue"].includes(n))throw new f("--file is only supported for studio create or continue.");let a=await Yd(e.file),c=n==="create"?"context":"content";t[c]=[t[c],a.content].filter(Boolean).join(`
416
+
417
+ `),t.provenance={surface:"cli",workspace:"remote",localReference:a.localReference}}let i=e.uncommitted?await Xd(e,t):null,s=await S(e.creds,r,o,r==="POST"?t:void 0);i?.patch?s.localChanges=await Zd(e,String(s.id),i,String(t.idempotencyKey)):i&&process.stderr.write(`No uncommitted changes; the session starts from the pushed branch.
418
+ `),n==="open"&&await Kd(`${e.creds.endpoint.replace(/\/$/,"")}/studio?session=${be(e.id)}`),process.stdout.write(`${e.json?JSON.stringify(s):p(JSON.stringify(s,null,2))}
419
+ `)}async function Xd(e,t){let n=await Js(process.cwd());if(e.repo&&e.repo.toLowerCase()!==n.repoFullName.toLowerCase())throw new f(`--repo ${e.repo} does not match this checkout (${n.repoFullName}).`);if(e.branch&&e.branch!==n.remoteBranch)throw new f(`--branch ${e.branch} does not match this checkout (${n.remoteBranch}).`);await Vs(n);let r=await Ys(n);if(t.repoFullName=n.repoFullName,t.branch=n.remoteBranch,r.patch){let o=`Uncommitted local changes to ${r.files.length} file${r.files.length===1?"":"s"} were applied to the workspace on top of ${n.head.slice(0,12)}. They are not committed.`;t.context=[t.context,o].filter(Boolean).join(`
420
+
421
+ `)}return{...r,baseCommit:n.head}}var Qd=new Set(["local_changes_empty","local_changes_too_large","local_changes_invalid","local_changes_unsafe_path","local_changes_binary","local_changes_unsupported_file","local_changes_secret","local_changes_fresh_session_required","local_changes_base_mismatch","local_changes_do_not_apply","invalid_local_changes","invalid_base_commit","invalid_patch","invalid_idempotencyKey","unknown_field","insufficient_scope","forbidden_role","turn_in_progress"]);async function Zd(e,t,n,r){try{return await S(e.creds,"POST",`/studio/sessions/${be(t)}/local-changes`,{patch:n.patch,baseCommit:n.baseCommit,idempotencyKey:r})}catch(o){let i=o instanceof Error?o.message:String(o),s=o instanceof h?o.exitCode:g.FAILURE;if(!(o instanceof ee&&Qd.has(o.code)))throw new h(`Could not confirm your local changes were applied: ${i}`,s,`Session ${t} was kept. Retry with --input '{"idempotencyKey":"${r}"}' to finish, or check its Changes in Code Studio.`);let a=await S(e.creds,"PATCH",`/studio/sessions/${be(t)}`,{archived:!0}).then(()=>!0,()=>!1);throw new h(`Your local changes were not applied: ${i}`,s,a?`Session ${t} was archived; nothing in it changed.`:`Session ${t} was created without your changes. Archive it in Code Studio.`)}}async function eu(e){let t=be(e.id),n=await S(e.creds,"GET",`/studio/sessions/${t}`),r=await S(e.creds,"GET",`/studio/sessions/${t}/changes`).catch(()=>null),o=n.latestRunId?await S(e.creds,"GET",`/studio/runs/${be(n.latestRunId)}`).catch(()=>null):null,i=!!n.latestRunId||Number(n.messageCount??0)>0,s=r?.branch||e.branch||(i?null:n.branch);if(!s)throw new h(`Could not read which branch session ${e.id} is working on; it may have moved off ${n.branch??"its starting branch"}. Nothing was changed.`,g.FAILURE,`Retry, or name the branch: anyforge studio pickup ${e.id} --branch <name>`);let a=await Xs(process.cwd(),{...n,id:e.id,branch:s}),c=[];r?.exists&&r.clean===!1&&c.push("The session workspace has uncommitted changes that are not on the branch."),(!r||!r.exists&&r.latestCheckpoint)&&c.push("Could not check the session workspace for uncommitted changes. Open its Changes in Code Studio to confirm nothing is left behind."),r?.headSha&&r.headSha!==a.headSha&&c.push(`The session workspace is at ${r.headSha.slice(0,12)}, which is not what ${a.branch} holds. Push it from Code Studio, then pick up again.`),o&&["queued","running","pausing"].includes(String(o.status))&&c.push("A run is still in progress; its later work is not included.");let l={sessionId:e.id,title:n.title??null,...a,latestRun:o?{status:o.status??null,error:o.error??null,waitingOnYou:!!o.pendingQuestion}:null,warnings:c};if(e.json){process.stdout.write(`${JSON.stringify(l)}
422
+ `);return}let d=[`${a.created?"Created":"Checked out"} ${a.branch} at ${a.headSha.slice(0,12)} from ${a.repoFullName}.`,`Session: ${n.title??e.id}${o?` (latest run ${o.status}${o.pendingQuestion?", waiting on you":""}${o.error?`: ${o.error}`:""})`:""}`,a.commits.length?`Commits from the session:
423
+ ${a.commits.map(u=>` ${u.sha.slice(0,9)} ${u.subject}`).join(`
424
+ `)}${a.moreCommits?`
425
+ \u2026`:""}`:"No new commits from the session.",...c.map(u=>`Note: ${u}`)];process.stdout.write(`${p(d.join(`
426
+ `))}
427
+ `)}W();import{dim as er}from"kleur/colors";var ea=100;function Zs(e){let t=e&&typeof e=="object"?e:{};return{total:typeof t.total=="number"?t.total:null,hasMore:t.hasMore===!0,cursor:typeof t.nextCursor=="string"?t.nextCursor:null}}async function tu(e){let t=s=>`/work${U({status:e.status,type:e.type,priority:e.priority,initiative:e.initiative,program:e.program,search:e.search,assignee:e.assignee,includeArchived:e.includeArchived,limit:e.limit,cursor:s})}`,n=await S(e.creds,"GET",t()),r=ve(n),o=Zs(n),i=1;if(!e.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<ea;){let s=await S(e.creds,"GET",t(o.cursor));r.push(...ve(s)),o=Zs(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function ta(e){let t=await tu(e);if(e.json){console.log(I(e.all?{items:t.rows,total:t.total,hasMore:t.hasMore,nextCursor:null}:t.raw));return}let n=t.rows,r=await Os(e.creds),o=po(r,"work_item","plural","Work items");if(n.length===0){console.log(er(`No ${o.toLowerCase()} match that filter.`));return}console.log(z(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=>se(c,["title","name","summary"]),max:58}]));let i=(n.length===1?po(r,"work_item","singular","work item"):o).toLowerCase(),s=t.total!==null&&t.total!==n.length?`${n.length} of ${t.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=t.hasMore?e.all?er(` \u2014 stopped after ${ea} pages; narrow the filter`):er(" \u2014 pass --all for the rest"):"";console.log(`${er(`
428
+ ${s}`)}${a}`)}W();q();var nu=["edit","delete","resolve","reopen"];function ru(e){return nu.includes(e)}async function na(e){if(!ru(e.action))throw new f("comment needs an action: edit, delete, resolve or reopen.","Usage: anyforge comment <edit|delete|resolve|reopen> <item-id> <comment-id> [--body <text>]");if(!e.itemId||!e.commentId)throw new f(`comment ${e.action} requires a work item id and a comment id.`,"Find comment ids with the anyforge_list_work_item_comments MCP tool or GET /work/<id>/comments.");let t=`/work/${encodeURIComponent(e.itemId)}/comments/${encodeURIComponent(e.commentId)}`,n,r;switch(e.action){case"edit":{if(e.body===void 0)throw new f('comment edit requires --body "<new text>".');n=await S(e.creds,"PATCH",t,{body:e.body}),r=`Edited comment ${e.commentId}`;break}case"delete":n=await S(e.creds,"DELETE",t),r=`Deleted comment ${e.commentId}`;break;default:{let o=e.action==="resolve";n=await S(e.creds,"POST",`${t}/resolve`,{resolved:o}),r=`${o?"Resolved":"Reopened"} the thread of comment ${e.commentId}`}}console.log(e.json?I(n):r)}W();import{bold as ou,dim as tr}from"kleur/colors";q();async function ra(e){let t=await S(e.creds,"GET","/workflows");if(e.json){console.log(I(t));return}let n=ve(t);if(n.length===0){console.log(tr("No workflows defined."));return}console.log(z(n,[{header:"ID",value:r=>T(r,"id")},{header:"STATUS",value:r=>se(r,["status","state"],"")},{header:"NAME",value:r=>se(r,["name","title"]),max:58}])),console.log(tr(`
429
+ Dispatch with `)+ou("anyforge run <id>"))}async function oa(e){if(!e.workflowId)throw new f("run requires a workflow id.","List them with `anyforge workflows`.");let t;if(e.input!==void 0){try{t=JSON.parse(e.input)}catch(o){throw new f(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!t||typeof t!="object"||Array.isArray(t))throw new f("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await S(e.creds,"POST",`/workflows/${encodeURIComponent(e.workflowId)}/run`,t===void 0?void 0:{inputs:t});if(e.json){console.log(I(n));return}let r=se(n??{},["id","runId"],"");console.log(`Queued run ${r||tr("(id not returned)")}`),console.log(tr("Runs pause at gate steps for an operator decision."))}W();import{dim as iu}from"kleur/colors";q();async function ia(e){let t=e.question?.trim();if(!t)throw new f("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!e.json&&process.stderr.isTTY&&process.stderr.write(iu(`Asking the Oracle (this can take a few minutes)\u2026
430
+ `));let n=await S(e.creds,"POST","/oracle",{question:t,...e.context?{context:e.context}:{}});if(e.json){console.log(I(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:I(n))}W();import{bold as Io,dim as sa,green as su,yellow as au}from"kleur/colors";function cu(e){return typeof e=="number"?`${Math.round(e*100)}%`:"\u2014"}async function aa(e){let t=await S(e.creds,"GET",`/backtest-corpus${U({days:e.days})}`);if(e.json){console.log(I(t));return}let n=t.incidentsInWindow??0,r=t.backTestable??0,o=t.windowDays?`last ${t.windowDays}d`:"all time";console.log(`${Io(String(r))} of ${Io(String(n))} incidents are back-testable `+sa(`(${cu(t.coverage)} \xB7 ${o})`)),t.viable?console.log(su("Enough to run a back-test.")):console.log(au(`Not yet viable \u2014 ${t.shortfall??0} more needed.`));let i=(t.excluded??[]).filter(s=>s.count>0);i.length>0&&console.log(z(i,[{header:"EXCLUDED",value:s=>String(s.count)},{header:"REASON",value:s=>s.label,max:56}])),t.biggestGap&&console.log(sa(`
431
+ Biggest fixable gap: `)+Io(`${t.biggestGap.label} (${t.biggestGap.count})`))}W();import{bold as nr,dim as mn,green as lu,yellow as ca}from"kleur/colors";var Co=e=>typeof e=="number"?`${Math.round(e*1e3)/10}%`:"\u2014";async function la(e){let t=await S(e.creds,"GET",`/review-interception${U({days:e.days})}`);if(e.json){console.log(I(t));return}let n=Yn(t.windowDays,t.truncated,t.oldestReviewMs),r=i=>{console.log(i)};if(r(`${nr(String(t.seriousRaised??0))} serious findings raised across ${nr(String(t.prsReviewed??0))} pull requests ${mn(`(${n})`)}`),t.verdict==="measured")r(`${lu(String(t.disappearedSerious??0))} no longer raised by the next round \u2014 ${nr(Co(t.interceptionFloor))} to ${nr(Co(t.interceptionCeiling))}`),r(mn(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${t.measurableSerious??0} that had a later round`));else{r(ca("Not enough findings had a later round to measure a rate."));for(let i of t.inconclusiveReasons??[])r(mn(` ${i}`))}let o=(t.byLens??[]).filter(i=>i.serious>0);if(o.length>0&&r(z(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)}])),t.truncated){let i=t.oldestReviewMs?new Date(t.oldestReviewMs).toISOString().slice(0,10):null;r(ca(`
432
+ Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}t.reviews&&t.skippedShare!=null&&t.skippedShare>0&&r(mn(`
433
+ ${t.reviews.skipped} of ${t.reviews.total} reviews were skipped (${Co(t.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of t.caveats??[])r(mn(`
434
+ ${i}`))}W();import{bold as hn,dim as mt,green as du,red as uu,yellow as Eo}from"kleur/colors";var pu=e=>typeof e=="number"?`${Math.round(e*1e3)/10}%`:"\u2014";function To(e){if(typeof e!="number")return"\u2014";if(e<60)return`${e}m`;if(e<1440){let n=Math.floor(e/60);return`${n}h ${Math.round(e-n*60)}m`}let t=Math.floor(e/1440);return`${t}d ${Math.round((e-t*1440)/60)}h`}var fu={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function da(e){let t=await S(e.creds,"GET",`/review-coverage${U({days:e.days})}`);if(e.json){console.log(I(t));return}let n=s=>{console.log(s)},r=Yn(t.windowDays,t.truncated,t.oldestRecordMs);n(`${hn(String(t.pullRequestsReviewed??0))} of ${hn(String(t.pullRequestsSeen??0))} recorded pull requests reviewed ${t.coverageRate!=null?hn(`(${pu(t.coverageRate)})`):""} ${mt(`(${r})`)}`),t.repositoriesReviewed&&n(`across ${hn(String(t.repositoriesReviewed))} repositories`),n(mt("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),t.medianLatencyMinutes!=null?(n(`
435
+ Feedback reached the author in ${du(To(t.medianLatencyMinutes))} median, ${hn(To(t.p90LatencyMinutes))} at p90 ${mt(`(${t.latencySamples??0} reviews)`)}`),t.medianOnOpenLatencyMinutes!=null&&n(mt(` ${To(t.medianOnOpenLatencyMinutes)} median on pull-request open (${t.onOpenSamples??0} reviews, no quiet period in the way)`))):n(Eo(`
436
+ Not enough timed reviews to report a latency figure.`));let o=t.capacityGapPullRequests??0;o>0&&n(`
437
+ ${uu(String(o))} pull requests went unreviewed because a limit fired `+mt("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=t.bySkipClass??[];i.length>0&&n(z(i,[{header:"WHY UNREVIEWED",value:s=>fu[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),t.failedOnlyPullRequests&&n(mt(`${t.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of t.inconclusiveReasons??[])n(Eo(`
438
+ ${s}`));if(t.truncated){let s=t.oldestRecordMs?new Date(t.oldestRecordMs).toISOString().slice(0,10):null;n(Eo(`
439
+ 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 t.caveats??[])n(mt(`
440
+ ${s}`))}W();import{createHash as bu}from"node:crypto";import{dim as ga,green as ku,red as Ou,yellow as Au}from"kleur/colors";q();function pa(e){return mu({eventType:e.eventType,actor:e.actor,payload:e.payload,timestamp:e.timestampMs})}function mu(e){return JSON.stringify($o(e))}function $o(e){if(Array.isArray(e))return e.map($o);if(e===null||typeof e!="object"||Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)return e;let t=e,n={};for(let r of Object.keys(t).sort())n[r]=$o(t[r]);return n}var hu="";function fa(e,t,n){return e(`${n??""}${hu}${t}`)}function gu(e){let t=e.findIndex(n=>(n.sealVersion??1)>=2);return t===-1?e.length:t}function ma(e,t){let n=gu(e),r=n;for(let o=n;o<e.length;o++){let i=e[o];if(typeof i.hash!="string"||!i.hash)return{valid:!1,verified:o-n,unverifiable:r,brokenAt:o,brokenId:i.id,reason:"missing_hash",detail:`Row ${i.id} carries seal version ${i.sealVersion??1} but no hash.`};if(o>n){let s=e[o-1].hash??null;if((i.previousHash??null)!==s)return{valid:!1,verified:o-n,unverifiable:r,brokenAt:o,brokenId:i.id,reason:"link_mismatch",detail:`Row ${i.id} links to ${ua(i.previousHash)}, but the prior row hashes to ${ua(s)}.`}}if(i.hash!==t(i))return{valid:!1,verified:o-n,unverifiable:r,brokenAt:o,brokenId:i.id,reason:"content_mismatch",detail:`Row ${i.id} does not match its own contents.`}}return{valid:!0,verified:e.length-n,unverifiable:r}}function ua(e){return e?`${e.slice(0,12)}\u2026`:"nothing"}function yu(e){return e?JSON.parse(JSON.stringify(e)):{}}function vu(e){return{id:e.id,eventType:e.eventType,actor:e.actor,payload:yu(e.payload),timestampMs:e.timestampMs,hash:e.hash,previousHash:e.prevHash,...typeof e.sealVersion=="number"?{sealVersion:e.sealVersion}:{}}}function ha(e,t,n={}){let r=e.map(vu),o=e.length>0?e[e.length-1].hash??null:null,i=n.anchorHash;return i&&r.length>0&&(r[0].sealVersion??1)>=2&&(r[0].previousHash??null)!==i?{valid:!1,verified:0,unverifiable:0,brokenAt:0,brokenId:r[0].id,reason:"link_mismatch",detail:`Entry ${r[0].id} does not link onto the previous page's last hash.`,lastHash:o}:{...ma(r,a=>fa(t,pa({eventType:a.eventType,actor:a.actor,payload:a.payload,timestampMs:a.timestampMs}),a.previousHash??null)),lastHash:o}}var xu=200,_u=e=>bu("sha256").update(e).digest("hex");function Su(e,t=_u){let n=null,r=0,o=0;for(let i of e){if(i.length===0)continue;let s=ha(i,t,{anchorHash:n});if(r+=s.verified,o+=s.unverifiable,!s.valid)return{valid:!1,verified:r,unverifiable:o,brokenId:s.brokenId,reason:s.reason,detail:s.detail};n=s.lastHash}return{valid:!0,verified:r,unverifiable:o}}async function wa(e){if(e.verify&&(e.eventType||e.actor))throw new f("--verify needs an unfiltered read.","Drop --event and --actor: a filtered page skips rows, so its chain links cannot meet. --from and --to are fine.");let t=c=>`/audit${U({eventType:e.eventType,actor:e.actor,from:e.from,to:e.to,limit:e.limit,cursor:c})}`,n=[],r=e.cursor;do{let c=await S(e.creds,"GET",t(r));n.push(c),r=c.hasMore&&c.nextCursor?c.nextCursor:void 0}while(e.all&&r&&n.length<xu);let o=n.flatMap(c=>c.entries),i=n[n.length-1],s=e.verify?Su(n.map(c=>c.entries)):null,a=c=>{console.log(c)};if(e.json)a(I(n.length===1&&!s?i:{entries:o,nextCursor:i.nextCursor,hasMore:i.hasMore,chainContiguous:i.chainContiguous,pages:n.length,...s?{verification:s}:{}}));else{o.length===0?a("No audit entries match."):a(z(o,[{header:"SEQUENCE",value:l=>String(l.sequence)},{header:"TIME",value:l=>l.timestamp},{header:"EVENT",value:l=>l.eventType,max:34},{header:"ACTOR",value:l=>l.actor,max:28},{header:"HASH",value:l=>l.hash?`${l.hash.slice(0,12)}\u2026`:"\u2014"}]));let c=n.length===1?"page":"pages";a(ga(`${o.length} entries from ${n.length} ${c}.`)),i.hasMore&&i.nextCursor&&a(Au(`More entries exist. Continue with --cursor ${i.nextCursor}${e.all?"":" or pass --all"}.`)),s&&(s.valid?a(ku(`Chain verified: ${s.verified} sealed entries link and recompute.`)+(s.unverifiable?ga(` ${s.unverifiable} earlier entries predate sealing and cannot be verified.`):"")):a(Ou(`Chain break at ${s.brokenId}: ${s.reason}.`)+(s.detail?` ${s.detail}`:"")))}if(s&&!s.valid)throw new h(`Audit chain verification failed at ${s.brokenId??"an entry"} (${s.reason??"unknown"}).`,g.VERIFICATION_FAILED)}W();import{dim as ya}from"kleur/colors";q();var Ru=["invite","invitations","withdraw"];function va(e,t){if(!e.email)throw new f(`people ${t} requires an email address.`,`Example: anyforge people ${t} person@example.com`);return e.email}function Iu(e){if(e===void 0)return;let t=e.split(",").map(n=>n.trim()).filter(Boolean);return t.length?t:void 0}function ht(e){console.log(e)}async function ba(e){switch(e.subcommand){case"invite":{let t=va(e,"invite");if(!e.role)throw new f("people invite requires --role.","One of operator, editor, viewer or filer.");let n=Iu(e.team),r=await S(e.creds,"POST","/people/invitations",{email:t,role:e.role,...n?{teamIds:n}:{},...e.notify?{}:{notify:!1}});if(e.json){ht(I(r));return}let o=r.created?"Invited":"Refreshed the pending invitation for",i=r.emailSent?"Invitation email sent.":"No invitation email sent.";ht(`${o} ${r.email} as ${r.role}. ${ya(i)}`);return}case"invitations":{let t=await S(e.creds,"GET","/people/invitations");if(e.json){ht(I(t));return}let n=ve(t);if(n.length===0){ht(ya("No invitations."));return}ht(z(n,[{header:"EMAIL",value:r=>T(r,"email"),max:48},{header:"ROLE",value:r=>T(r,"role")},{header:"STATUS",value:r=>T(r,"status")},{header:"TEAMS",value:r=>Array.isArray(r.teamIds)&&r.teamIds.length?r.teamIds.join(","):"\u2014",max:32}]));return}case"withdraw":{let t=va(e,"withdraw"),n=await S(e.creds,"DELETE",`/people/invitations${U({email:t})}`);if(e.json){ht(I(n));return}ht(`Withdrew the invitation for ${n.email}.`);return}default:throw new f(e.subcommand?`Unknown people command: ${e.subcommand}`:"people needs a command.",`One of: ${Ru.join(", ")}.`)}}W();import{promises as ka}from"node:fs";import{dim as rr}from"kleur/colors";q();var Cu=["week","book"],or=256e3;function gt(e){console.log(e)}function Eu(e=new Date){let t=n=>String(n).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}function Oa(e){return`${Math.floor(e/60)}:${String(e%60).padStart(2,"0")}`}async function Tu(){let e=[],t=0;for await(let n of process.stdin){let r=Buffer.isBuffer(n)?n:Buffer.from(String(n));if(t+=r.length,t>or)throw new f(`Standard input is larger than ${or} bytes.`);e.push(r)}return Buffer.concat(e).toString("utf8")}function Aa(e){let t;try{t=JSON.parse(e)}catch{throw new f("The entries are not valid JSON.",'Send a list: [{"initiativeId":"\u2026","date":"YYYY-MM-DD","minutes":90}]')}let n=Array.isArray(t)?t:t&&typeof t=="object"&&Array.isArray(t.entries)?t.entries:null;if(!n)throw new f('The entries must be a JSON list, or an object with an "entries" list.');return n}async function $u(e){if(!e.entries)throw new f("time book requires --entries.","Example: anyforge time book --entries week.json (or --entries - to read standard input)");if(e.entries==="-")return Aa(await(e.readStdin??Tu)());let t=await ka.stat(e.entries).catch(()=>null);if(!t||!t.isFile())throw new f(`--entries ${e.entries} is not a file.`);if(t.size>or)throw new f(`--entries ${e.entries} is larger than ${or} bytes.`);return Aa(await ka.readFile(e.entries,"utf8"))}async function xa(e){let t=e.today??Eu();switch(e.subcommand){case"week":{let n=await S(e.creds,"GET",`/timesheets/week${U({date:e.date,today:t})}`);if(e.json){gt(I(n));return}let r=new Map([...n.rows,...n.addable,...n.categories].map(s=>[s.initiativeId,s.code?`${s.code} ${s.name}`:s.name]));if(gt(rr(`Week of ${n.days[0]} to ${n.days[n.days.length-1]}`)),n.entries.length===0){gt(rr("No time booked this week."));return}let o=[...n.entries].sort((s,a)=>s.date.localeCompare(a.date)||s.initiativeId.localeCompare(a.initiativeId));gt(z(o,[{header:"DATE",value:s=>s.date},{header:"INITIATIVE",value:s=>r.get(s.initiativeId)??s.initiativeId,max:48},{header:"ID",value:s=>s.initiativeId,max:32},{header:"HOURS",value:s=>Oa(s.minutes)},{header:"SOURCE",value:s=>s.source},{header:"NOTE",value:s=>s.note??"\u2014",max:40}]));let i=o.reduce((s,a)=>s+a.minutes,0);gt(rr(`Total ${Oa(i)}`));return}case"book":{let n=await $u(e),r=await S(e.creds,"PUT","/timesheets/entries",{entries:n,today:t});if(e.json){gt(I(r));return}gt(r.written===0?rr("Nothing to write."):`Wrote ${r.written} ${r.written===1?"cell":"cells"}.`);return}default:throw new f(e.subcommand?`Unknown time command: ${e.subcommand}`:"time needs a command.",`One of: ${Cu.join(", ")}.`)}}ao();import{randomUUID as rf}from"node:crypto";import{open as of,realpath as sf,stat as af}from"node:fs/promises";import{basename as cf,join as lf,resolve as df}from"node:path";import{bold as ii,cyan as Ec,dim as Ke,yellow as Rr}from"kleur/colors";import{ProcessTerminal as uf,SelectList as pf,Text as ff,TuiAltScreen as mf}from"@earendil-works/pi-tui";var Pu=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function Lu(e){return Pu.has(e)?"querying the code graph":e==="search_code_semantic"?"searching the code index":e==="search_codebase_docs"?"searching codebase docs":null}function Ft(e){let t=Lu(e);if(t)return t;let n=/^mcp__(.+?)__(.+)$/.exec(e);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:e.replace(/_/g," ")}var Nu=new Set(["ask_user","present_catch_up_decision","present_memory_candidates","present_skill_proposal"]);function Mt(e){return typeof e=="string"&&Nu.has(e)}q();import{truncateToWidth as _n,wrapTextWithAnsi as Ya}from"@earendil-works/pi-tui";import{cyan as zo,dim as bt,green as Xa,italic as mp,red as Ko,yellow as Jo}from"kleur/colors";import{truncateToWidth as gn,visibleWidth as Po,wrapTextWithAnsi as Fu}from"@earendil-works/pi-tui";import{bold as Mu,dim as qu}from"kleur/colors";function Y(e){return e<1024?`${e} B`:e<1024*1024?`${wn(e/1024)} KiB`:`${wn(e/(1024*1024))} MiB`}function yn(e){let t=Math.max(0,e);if(t<1e4)return`${wn(t/1e3)}s`;let n=Math.round(t/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 Lo(e){let t=Math.floor(Math.max(0,e)/1e3);return t<60?`${t}s`:`${Math.floor(t/60)}m ${String(t%60).padStart(2,"0")}s`}function xe(e){return Math.abs(e)<1e3?String(Math.round(e)):Math.abs(e)<1e6?`${wn(e/1e3,e<1e5?1:0)}k`:`${wn(e/1e6)}M`}function wn(e,t=1){return e.toFixed(t).replace(/\.0+$/,"")}function Uu(e){return p(e).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function ju(e,t){return typeof t=="boolean"?t?"on":"off":typeof t=="string"?p(t):/Ms$/.test(e)?yn(t):/Bytes$/.test(e)?Y(t):/tokens?/i.test(e)?xe(t):String(t)}function _a(e){return e?Object.entries(e).filter(t=>t[1]!==null).map(([t,n])=>`${Uu(t)} ${ju(t,n)}`):[]}function No(e,t,n=2){let r=Math.min(16,Math.max(...e.map(([s])=>Po(s)),0)+2),o=Math.max(10,t-n-r),i=[];for(let[s,a]of e)Fu(a,o).forEach((l,d)=>{let u=d===0?qu(gn(s,r-1).padEnd(r)):" ".repeat(r);i.push(gn(`${" ".repeat(n)}${u}${l}`,t))});return i}function Sa(e,t,n){return[gn(Mu(e),n),...No(t,n)]}function Ra(e,t,n){let r=Po(n),o=t.filter(Boolean).join(" \xB7 ");if(r+4>e)return gn(o||n,e);let i=e-r-2,s=gn(o,i),a=Math.max(2,e-Po(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as Ut,cyan as qt,dim as Ze,green as Du,italic as Ia,strikethrough as Bu,underline as Ca,yellow as Gu}from"kleur/colors";import{Markdown as Wu}from"@earendil-works/pi-tui";var Hu={heading:e=>Ut(qt(e)),link:e=>Ca(qt(e)),linkUrl:e=>Ze(e),code:e=>Gu(e),codeBlock:e=>e,codeBlockBorder:e=>Ze(e),quote:e=>Ia(e),quoteBorder:e=>Ze(e),hr:e=>Ze(e),listBullet:e=>qt(e),bold:e=>Ut(e),italic:e=>Ia(e),strikethrough:e=>Bu(e),underline:e=>Ca(e)},Dt={selectedPrefix:e=>qt(e),selectedText:e=>Ut(e),description:e=>Ze(e),scrollInfo:e=>Ze(e),noMatch:e=>Ze(e)},Ea={borderColor:e=>Ze(e),selectList:Dt},jt=class{constructor(t,n){this.linkOrigin=n;this.content=p(t),this.markdown=new Wu(go(this.content,n),0,0,Hu)}linkOrigin;content;markdown;cache;getText(){return this.content}setText(t){let n=p(t);n!==this.content&&(this.content=n,this.markdown.setText(go(n,this.linkOrigin)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(t){let n=Math.max(12,t);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(Cs):[];return this.cache={width:n,lines:r},r}};function vn(e,t){return e==="user"?`${Ut(Du(t?p(t):"You"))}`:`${Ut(qt("Oracle"))}`}function Ta(e,t,n){let r=qt("\u2502"),o=Math.max(1,t-4);return["",`${r} ${vn("user",n)}`,...e.render(o).map(i=>`${r} ${Ut(i)}`),""]}function je(e){return e.shared||e.visibility==="company"?`Shared with the company${e.entityKey?` \xB7 ${p(e.entityKey)}`:""}`:"Private to you"}function $a(e){return e.shared||e.visibility==="company"?"shared":"private"}import{createReadStream as ap}from"node:fs";import{stat as cp}from"node:fs/promises";import{basename as lp}from"node:path";import{setTimeout as za}from"node:timers/promises";var Pa={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 La(e){let t=e.slice(e.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(Pa,t)?Pa[t]:null}q();q();var Fo="/api/v1/oracle";var Na="workspace";function et(e){let t;try{t=new URL(e)}catch{throw new h(`Invalid Oracle endpoint: ${e}`,g.USAGE)}if(!["http:","https:"].includes(t.protocol)||t.username||t.password)throw new h("Oracle endpoint must be an http or https URL without embedded credentials.",g.USAGE);if(t.pathname!=="/"||t.search||t.hash)throw new h("Oracle endpoint must be the workspace origin, without a path, query or fragment.",g.USAGE);return t.origin}function De(e,t){return`${et(e)}${Fo}${t}`}function zu(e,t,n){let r;try{r=new URL(e)}catch{throw new h(`Oracle server returned an invalid ${n} endpoint.`,g.API_ERROR)}let o=new URL(et(t));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new h(`Oracle server returned an unsafe ${n} endpoint.`,g.API_ERROR);return r.toString()}function Ku(e,t){if(!e||typeof e!="object")throw new h("Oracle server omitted OAuth endpoints.",g.API_ERROR);let n=e,r=["registration","authorization","token","revocation"],o={};for(let i of r){if(typeof n[i]!="string")throw new h(`Oracle server omitted its OAuth ${i} endpoint.`,g.API_ERROR);o[i]=zu(n[i],t,i)}return o}async function wt(e,t=fetch,n,r){let o=et(e),i;try{i=await t(De(o,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:r?AbortSignal.any([r,AbortSignal.timeout(2e4)]):AbortSignal.timeout(2e4)})}catch(u){throw new h(`Cannot reach ${o}: ${u instanceof Error?u.message:String(u)}`,g.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let s=await Wt(i,De(o,"/config")),a=M(Gt(s,i.status)),c=`${o}${Fo}`;if(a.protocolVersion!==1)throw new h(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(a.protocolVersion)}.`,g.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(a.resource!==c)throw new h("Oracle server resource does not match this workspace origin.",g.API_ERROR);let l=Array.isArray(a.scopes)?a.scopes:null;if(!l||!l.every(u=>u==="read"||u==="write"||u==="approve"))throw new h("Oracle server returned an invalid scope list.",g.API_ERROR);let d={protocolVersion:1,resource:c,scopes:l,oauth:Ku(a.oauth,o)};if(a.identity!==void 0){let u=M(a.identity);if(typeof u.uid!="string"||typeof u.companyId!="string")throw new h("Oracle server returned an invalid identity.",g.API_ERROR);let w=typeof u.companyName=="string"?p(u.companyName).trim().slice(0,120):"";d.identity={uid:p(u.uid),companyId:p(u.companyId),...w?{companyName:w}:{}}}if(a.capabilities!==void 0){let u=M(a.capabilities);if(![u.read,u.write,u.approve].every(w=>typeof w=="boolean"))throw new h("Oracle server returned invalid capabilities.",g.API_ERROR);d.capabilities={read:u.read,write:u.write,approve:u.approve}}if(a.model!==void 0){let u=M(a.model);if(typeof u.id!="string"||typeof u.provider!="string")throw new h("Oracle server returned invalid model metadata.",g.API_ERROR);d.model={id:p(u.id),provider:p(u.provider)}}if(a.limits!==void 0){let u=M(a.limits);if(Object.values(u).some(w=>!["string","number","boolean"].includes(typeof w)&&w!==null))throw new h("Oracle server returned invalid limits metadata.",g.API_ERROR);d.limits=Object.fromEntries(Object.entries(u).map(([w,v])=>[p(w),typeof v=="string"?p(v):v]))}return Array.isArray(a.commands)&&(d.commands=Ju(a.commands)),d}function Ju(e){let t=[];for(let n of e.slice(0,50)){let r=M(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||t.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?p(r.args).slice(0,60).trim():"";t.push({name:r.name,description:p(r.description).slice(0,200),...o?{args:o}:{}})}return t}var ke=class{endpoint;scopes;source;#e;#n;#t;cachedConfig;constructor(t,n=fetch){this.endpoint=et(t.endpoint),this.#e=t.getAccessToken??(async()=>t.accessToken),this.#n=t.onIdentity,this.#t=n,this.scopes=new Set(t.scopes),this.source=t.source}async config(t){if(!this.cachedConfig){let n=await this.#e();try{this.cachedConfig=await wt(this.endpoint,this.#t,n,t)}catch(o){if(this.source!=="oauth"||!(o instanceof ee)||o.status!==401)throw o;let i=await this.#e(n);if(i===n)throw o;this.cachedConfig=await wt(this.endpoint,this.#t,i,t)}let r=this.cachedConfig.identity;r&&this.#n&&await this.#n(r).catch(()=>{})}return this.cachedConfig}async listSessions(){let t=await this.json("GET","/sessions"),n=Array.isArray(t)?t:M(t).sessions;if(!Array.isArray(n))throw new h("Oracle server returned an invalid sessions list.",g.API_ERROR);return n.map(qa)}async createSession(t={},n){let r=await this.json("POST","/sessions",t,n),o=M(r);return!Array.isArray(o.messages)&&typeof o.sessionId=="string"?this.getSession(o.sessionId,n):Fa(r)}async getSession(t,n){return Fa(await this.json("GET",`/sessions/${encodeURIComponent(t)}`,void 0,n))}async submitTurn(t,n,r,o){let i,s=De(this.endpoint,`/sessions/${encodeURIComponent(t)}/turns`),a=async l=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${l}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let l=await this.#e();if(i=await a(l),i.status===401&&this.source==="oauth"){let d=await this.#e(l);d!==l&&(i=await a(d))}}catch(l){throw l instanceof h||r?.aborted?l:new h(`Oracle connection was interrupted: ${l instanceof Error?l.message:String(l)}`,g.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await Bt(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let l=await Wt(i,De(this.endpoint,`/sessions/${t}/turns`)),d=Gt(l,i.status);throw new h(`Oracle server did not start a stream (${Vu(d)}).`,g.API_ERROR)}return i}async replayEvents(t,n,r){let o=[];for await(let i of this.streamReplayEvents(t,n,r))o.push(i);return o}async*streamReplayEvents(t,n,r,o,i){let s=`/sessions/${encodeURIComponent(t)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,a=await this.authenticatedFetch("GET",s,{headers:{Accept:"text/event-stream, application/json"},signal:i},0);if(a.ok||await Bt(a),(a.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*bn(a,o);return}let l=Gt(await Wt(a,De(this.endpoint,s)),a.status),d=Array.isArray(l)?l:M(l).events;if(!Array.isArray(d))throw new h("Oracle replay response did not contain events.",g.API_ERROR);for(let u of d)yield Mo(u)}async*streamRequestEvents(t,n,r=-1,o,i){let s=`/sessions/${encodeURIComponent(t)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,a=await this.authenticatedFetch("GET",s,{headers:{Accept:"text/event-stream, application/json"},signal:i},0);if(a.ok||await Bt(a),(a.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*bn(a,o);return}let l=Gt(await Wt(a,De(this.endpoint,s)),a.status),d=Array.isArray(l)?l:M(l).events;if(!Array.isArray(d))throw new h("Oracle request replay response did not contain events.",g.API_ERROR);for(let u of d)yield Mo(u)}async cancelTurn(t,n){return this.json("POST",`/sessions/${encodeURIComponent(t)}/cancel`,{streamId:n})}async cancelRequest(t,n,r){return this.json("POST",`/sessions/${encodeURIComponent(t)}/cancel`,{requestId:n},r)}async upload(t,n){let r=new FormData;r.set("sessionId",t),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 Bt(o),Xu(Gt(await Wt(o,De(this.endpoint,"/uploads")),o.status))}async download(t,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(t)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await Bt(r),r}async json(t,n,r,o){let i=await this.authenticatedFetch(t,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{},...o?{signal:o}:{}});return i.ok||await Bt(i),Gt(await Wt(i,De(this.endpoint,n)),i.status)}async authenticatedFetch(t,n,r={},o=2e4){try{let i=De(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=o<=0?void 0:AbortSignal.timeout(o),c=r.signal&&a?AbortSignal.any([r.signal,a]):r.signal??a,l=v=>this.#t(i,{...r,method:t,headers:{...s,Authorization:`Bearer ${v}`},redirect:"error",...c?{signal:c}:{}}),d=await this.#e(),u=await l(d),w=r.body===void 0||typeof r.body=="string"||r.body===null;if(u.status===401&&this.source==="oauth"){let v=await this.#e(d);v!==d&&w&&(u=await l(v))}return u}catch(i){throw i instanceof h?i:new h(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,g.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*bn(e,t){if(!e.body)throw new h("Oracle stream has no response body.",g.FAILURE);let n=e.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,l=()=>{if(s.length===0)return null;let d=s.join(`
441
+ `);if(s=[],a=0,d==="[DONE]")return null;let u;try{u=JSON.parse(d)}catch{throw new h("Oracle stream returned invalid JSON.",g.API_ERROR)}let w=Mo(u);return w.type==="finalizing"?w:w.idx<=c?null:(c=w.idx,w)};try{for(;;){let{value:u,done:w}=await n.read();u?.byteLength&&t?.();let v=r.decode(u,{stream:!w});if(o+=v,i+=ir(v),i>2*1024*1024)throw new h("Oracle stream event exceeded the 2 MiB protocol limit.",g.API_ERROR);let x=0,b=o.indexOf(`
442
+ `,x);for(;b>=0;){let m=o.slice(x,b).replace(/\r$/,"");if(i-=ir(o.slice(x,b+1)),x=b+1,m===""){let A=l();A&&(yield A)}else if(!m.startsWith(":")){let A=m.indexOf(":"),L=A<0?m:m.slice(0,A),D=A<0?"":m.slice(A+1).replace(/^ /,"");if(L==="data"&&(s.push(D),a+=ir(D)+1,a>2*1024*1024))throw new h("Oracle stream event exceeded the 2 MiB protocol limit.",g.API_ERROR)}b=o.indexOf(`
443
+ `,x)}if(o=o.slice(x),w)break}if(o.trim()){let u=o.replace(/\r$/,"");if(u.startsWith("data:")&&(s.push(u.slice(5).replace(/^ /,"")),a+=ir(s[s.length-1]??"")+1,a>2*1024*1024))throw new h("Oracle stream event exceeded the 2 MiB protocol limit.",g.API_ERROR)}let d=l();d&&(yield d)}catch(d){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),d}finally{n.releaseLock()}}function ir(e){return Buffer.byteLength(e,"utf8")}function qo(e){let t=["program","initiative","codebase"].filter(o=>typeof e[o]=="string");if(t.length>1)throw new h("Choose only one of --program, --initiative or --codebase.",g.USAGE);let n=t[0];if(!n)return;let r=e[n];if(typeof r!="string"||!r.trim())throw new h(`--${n} needs an id.`,g.USAGE);return{kind:n,id:r.trim()}}function M(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function Vu(e){if(typeof e=="string")return p(e);try{return p(JSON.stringify(e))}catch{return"unexpected response"}}function Gt(e,t){let n=M(e);if(n.ok===!1){let r=Ma(n.error,t),o=typeof n.message=="string"?p(n.message).slice(0,2e3):void 0;throw new ee(r,t,o)}return n.ok===!0&&"data"in n?n.data:e}async function Wt(e,t){try{return await e.json()}catch{throw new h(`Non-JSON response from ${t} (HTTP ${e.status}).`,g.FAILURE)}}async function Bt(e){let t;try{t=await e.clone().json()}catch{t=null}let n=M(t),r=Ma(n.error??n.error_description,e.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 ee(r,e.status,typeof o=="string"?p(o).slice(0,2e3):void 0,void 0,Yu(e))}function Yu(e){try{return e.url?new URL(e.url).origin:void 0}catch{return}}function Ma(e,t){if(typeof e!="string")return`http_${t}`;let n=p(e).slice(0,120);return/^[A-Za-z0-9_.-]+$/.test(n)?n:`http_${t}`}function qa(e){let t=M(e);if(typeof t.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(t.sessionId)||typeof t.title!="string"||t.visibility!=="private"&&t.visibility!=="company"||typeof t.shared!="boolean")throw new h("Oracle server returned an invalid session summary.",g.API_ERROR);return{sessionId:t.sessionId,title:p(t.title),visibility:t.visibility,shared:t.shared,...typeof t.entityKey=="string"?{entityKey:p(t.entityKey)}:{},...typeof t.updatedAt=="number"||t.updatedAt===null?{updatedAt:t.updatedAt}:{}}}function Fa(e){let t=M(e),n=qa(t);if(!Array.isArray(t.messages))throw new h("Oracle server returned an invalid session transcript.",g.API_ERROR);let r=t.messages.map((o,i)=>{let s=M(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new h(`Oracle session message ${i+1} is invalid.`,g.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(tp):void 0,c=Array.isArray(s.files)?s.files.map(np):void 0;return{role:s.role,content:p(s.content),...typeof s.id=="string"?{id:s.id}:{},...typeof s.authorName=="string"?{authorName:p(s.authorName)}:{},...s.question&&typeof s.question=="object"?{question:Qu(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:Zu(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof t.activeStreamId=="string"?{activeStreamId:t.activeStreamId}:{}}}function Mo(e){let t=M(e);if(t.protocolVersion!==1||typeof t.idx!="number"||!Number.isSafeInteger(t.idx)||t.idx<0||typeof t.type!="string")throw new h("Oracle stream event does not match protocol version 1.",g.API_ERROR);return Ue(t)}function Xu(e){let t=M(e);if(typeof t.fileId!="string"||typeof t.name!="string"||typeof t.mediaType!="string")throw new h("Oracle upload response is missing file metadata.",g.API_ERROR);return{fileId:t.fileId,name:p(t.name),mediaType:p(t.mediaType),...typeof t.sizeBytes=="number"?{sizeBytes:t.sizeBytes}:{}}}function Qu(e){let t=M(e);if(typeof t.id!="string"||!Array.isArray(t.questions))throw new h("Oracle returned an invalid question card.",g.API_ERROR);return{id:p(t.id),questions:t.questions.map((n,r)=>{let o=M(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new h(`Oracle question ${r+1} is invalid.`,g.API_ERROR);return{id:p(o.id),header:p(o.header),question:p(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=M(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new h(`Oracle question option ${s+1} is invalid.`,g.API_ERROR);return{id:p(a.id),label:p(a.label),description:p(a.description),...typeof a.recommended=="boolean"?{recommended:a.recommended}:{},...typeof a.confirms=="boolean"?{confirms:a.confirms}:{}}})}}),optional:t.optional===!0}}function Zu(e){let t=M(e);if(typeof t.questionId!="string"||!Array.isArray(t.answers))throw new h("Oracle returned an invalid question response.",g.API_ERROR);return{questionId:p(t.questionId),answers:t.answers.map(ep)}}function ep(e){let t=M(e);if(typeof t.questionId!="string"||!Array.isArray(t.optionIds)||!t.optionIds.every(n=>typeof n=="string"))throw new h("Oracle returned an invalid question answer.",g.API_ERROR);return{questionId:p(t.questionId),optionIds:t.optionIds.map(n=>p(n)),...typeof t.customText=="string"?{customText:p(t.customText).slice(0,8e3)}:{}}}function tp(e){let t=M(e);if(typeof t.fileId!="string"||typeof t.name!="string"||typeof t.mediaType!="string")throw new h("Oracle session attachment metadata is invalid.",g.API_ERROR);return{fileId:p(t.fileId),name:p(t.name),mediaType:p(t.mediaType),...typeof t.sizeBytes=="number"&&Number.isFinite(t.sizeBytes)?{sizeBytes:t.sizeBytes}:{}}}function np(e){let t=M(e);if(typeof t.fileId!="string"||typeof t.filename!="string"||typeof t.mediaType!="string"||typeof t.sizeBytes!="number"||!Number.isFinite(t.sizeBytes))throw new h("Oracle session file metadata is invalid.",g.API_ERROR);return{fileId:p(t.fileId),filename:p(t.filename),mediaType:p(t.mediaType),sizeBytes:t.sizeBytes,...typeof t.format=="string"?{format:p(t.format)}:{}}}q();import{randomUUID as rp}from"node:crypto";import{promises as Be}from"node:fs";import{homedir as op}from"node:os";import{join as jo}from"node:path";import*as Uo from"proper-lockfile";function cr(){return jo(op(),".anyforge")}function ar(){return jo(cr(),"oracle")}function ja(){return jo(cr(),"oracle.last-session")}function ip(){return{version:2,active:{},logins:[]}}function sr(e){return e===void 0||typeof e=="string"}function Ua(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.endpoint!="string"||typeof t.clientId!="string"||typeof t.redirectUri!="string"||typeof t.accessToken!="string"||typeof t.refreshToken!="string"||typeof t.expiresAt!="number"||!Number.isFinite(t.expiresAt)||!Array.isArray(t.scopes)||!t.scopes.every(n=>typeof n=="string")||!sr(t.companyId)||!sr(t.companyName)||!sr(t.uid)?null:{endpoint:t.endpoint,...t.companyId?{companyId:t.companyId}:{},...t.companyName?{companyName:t.companyName}:{},...t.uid?{uid:t.uid}:{},clientId:t.clientId,redirectUri:t.redirectUri,accessToken:t.accessToken,refreshToken:t.refreshToken,expiresAt:t.expiresAt,scopes:t.scopes}}function sp(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;if(t.version===1){let o=Ua(t);return o?{version:2,endpoint:o.endpoint,active:{[o.endpoint]:o.clientId},logins:[o]}:null}if(t.version!==2||!Array.isArray(t.logins)||!sr(t.endpoint)||!t.active||typeof t.active!="object"||Array.isArray(t.active))return null;let n=t.logins.map(Ua);if(n.some(o=>o===null))return null;let r={};for(let[o,i]of Object.entries(t.active)){if(typeof i!="string")return null;r[o]=i}return{version:2,...t.endpoint?{endpoint:t.endpoint}:{},active:r,logins:n}}async function ue(){let e=ar(),t;try{t=await Be.readFile(e,"utf8")}catch(o){if(o.code==="ENOENT")return ip();throw o}let n;try{n=JSON.parse(t)}catch{throw new Error(`Oracle credentials at ${e} are invalid JSON; run \`anyforge oracle logout --all\` and sign in again.`)}let r=sp(n);if(!r)throw new Error(`Oracle credentials at ${e} have an unsupported format; run \`anyforge oracle logout --all\` and sign in again.`);return r}async function kn(e){if(!e.logins.length){await Be.rm(ar(),{force:!0});return}await Ha(ar(),e)}async function lr(e){return pr(async()=>{let t=await ue(),n=await e(t);return await kn(t),n})}function Ge(e,t){return e.logins.filter(n=>n.endpoint===t)}function dr(e,t){let n=Ge(e,t);return n.find(r=>r.clientId===e.active[t])??n[0]}function pe(e){return e.companyName||e.companyId||"workspace not known yet"}function Da(e,t){let n=t.companyId?e.logins.find(r=>r.endpoint===t.endpoint&&r.companyId===t.companyId&&r.clientId!==t.clientId):void 0;return e.logins=[...e.logins.filter(r=>r!==n&&r.clientId!==t.clientId),t],e.active[t.endpoint]=t.clientId,e.endpoint=t.endpoint,n}function Do(e,t){e.logins=e.logins.filter(o=>!(o.endpoint===t.endpoint&&o.clientId===t.clientId));let n=Ge(e,t.endpoint);if(!n.length){if(delete e.active[t.endpoint],e.endpoint===t.endpoint){let o=e.logins[0]?.endpoint;o?e.endpoint=o:delete e.endpoint}return}if(e.active[t.endpoint]!==t.clientId&&n.some(o=>o.clientId===e.active[t.endpoint]))return;let r=n[0];return e.active[t.endpoint]=r.clientId,r}function Ba(e,t,n,r){let o=e.logins.find(a=>a.endpoint===t&&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=e.logins.find(a=>a!==o&&a.endpoint===t&&a.companyId===r.companyId);return s&&(e.logins=e.logins.filter(a=>a!==s),e.active[t]===s.clientId&&(e.active[t]=o.clientId)),{changed:i||!!s,...s?{duplicate:s}:{}}}function yt(e,t){let n=t.trim(),r=e.find(a=>a.companyId===n);if(r)return r;let o=e.filter(a=>a.companyName?.toLowerCase()===n.toLowerCase());if(o.length===1)return o[0];let i=e.map(a=>`${pe(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 f(`More than one saved workspace is named "${n}". Use its id instead.`,s):new f(`No saved Oracle login for workspace "${n}".`,`${s} Add one with \`anyforge oracle login --workspace "${n}"\`.`)}async function Ga(){let e;try{e=await Be.readFile(ja(),"utf8")}catch(r){if(r.code==="ENOENT")return[];throw r}let t;try{t=JSON.parse(e)}catch{return[]}if(!t||typeof t!="object"||Array.isArray(t))return[];let n=t;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 Wa(e,t,n=""){let r=(await Ga()).filter(o=>!(o.endpoint===t&&o.companyId===n));await Ha(ja(),{version:2,sessions:[...r,{endpoint:t,companyId:n,sessionId:e}]})}async function ur(e,t=""){return(await Ga()).find(n=>n.endpoint===e&&n.companyId===t)?.sessionId}async function Ha(e,t){await Be.mkdir(cr(),{recursive:!0,mode:448});let n=`${e}.${rp()}.tmp`;try{await Be.writeFile(n,`${JSON.stringify(t,null,2)}
444
+ `,{mode:384,flag:"wx"}),await Be.rename(n,e),await Be.chmod(e,384)}finally{await Be.rm(n,{force:!0}).catch(()=>{})}}async function pr(e){await Be.mkdir(cr(),{recursive:!0,mode:448});let t=ar(),n=`${t}.refresh-admission`,r;try{r=await Uo.lock(n,{realpath:!1,lockfilePath:n,stale:Number.MAX_SAFE_INTEGER,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}})}catch(o){throw o.code==="ELOCKED"?new Error(`Oracle credential access is still locked; another CLI command may be running. An abrupt exit can leave this guard behind. Stop all AnyForge CLI commands before removing the guard directory at ${n}.`,{cause:o}):o}try{let o=await Uo.lock(t,{realpath:!1,lockfilePath:`${t}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await e()}finally{await o()}}finally{await r()}}var Bo=8192,Ka=10*1048576,dp=20*1048576,Ja=10,Va=3;function Go(e,t){if(e.type!=="tool_call"&&e.type!=="tool_call_start"||typeof e.spawnId=="string")return!1;let n=typeof e.id=="string"?e.id:void 0;if(n){if(t.has(n))return!1;t.add(n)}return!Mt(e.name)}var We=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(t){return t.type==="finalizing"?!0:t.idx<=this.lastIdx?!1:(this.lastIdx=t.idx,t.type==="stream_start"&&typeof t.streamId=="string"?this.streamId=p(t.streamId):t.type==="delta"&&typeof t.content=="string"?this.answer+=t.content:Go(t,this.toolIds)?this.answer="":t.type==="question"?this.question=An(t):t.type==="error"?this.error=Ho(t):t.type==="done"?this.done=t:t.type==="navigator_file_created"&&up(this.files,t.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 zt(e,t,n,r,o,i=new We){let s=async u=>{let w=i.streamId;i.accept(u)&&(i.streamId&&i.streamId!==w&&r.onStream?.(i.streamId),await r.onEvent(u))},a=()=>Wo(e,t,i,s,o,r.onActivity),c=async()=>{try{for await(let u of e.streamRequestEvents(t,n.requestId,-1,r.onActivity,o))await s(u)}catch(u){throw o?.aborted?u:new h("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",g.FAILURE,`Run anyforge oracle resume ${t} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new h("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",g.FAILURE,`Run anyforge oracle resume ${t} to inspect the saved session.`)},l=async()=>{try{let u=await e.submitTurn(t,n,o);for await(let w of bn(u,r.onActivity))await s(w)}catch(u){if(o?.aborted||u instanceof h&&u.exitCode===g.API_ERROR)throw u;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},d;try{d=await e.submitTurn(t,n,o)}catch(u){if(o?.aborted||u instanceof h&&u.exitCode!==g.FAILURE)throw u;return l()}if(!d)throw new h("Oracle did not return a stream response.",g.FAILURE);r.onResponse?.();try{for await(let u of bn(d,r.onActivity))await s(u)}catch(u){if(o?.aborted||u instanceof h)throw u;return i.streamId?a():l()}return i.settled?i.outcome():i.streamId?a():l()}async function Wo(e,t,n,r,o,i){let s=n.streamId;if(!s)throw new h("Oracle stream replay needs a stream id.",g.FAILURE);let a=0;for(;!n.settled&&a<Va;){if(o?.aborted)throw o.reason;try{for await(let c of e.streamReplayEvents(t,s,n.lastIdx+1,i,o))await r(c);if(!n.settled){if((await e.getSession(t,o)).activeStreamId!==s)break;await za(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof h&&c.exitCode===g.API_ERROR||(a+=1,a>=Va))throw c;await za(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new h("Oracle stream could not be fully replayed; the turn was not submitted again.",g.FAILURE,`Run anyforge oracle resume ${t} to inspect the session.`);return n.outcome()}function On(e,t){let n=t.done,r=n?.servedBy,o=vt(n?.tokens),i=re(n?.rounds),s=typeof n?.exitReason=="string"?p(n.exitReason):void 0,a=n?.exitReason==="completed"&&!t.question,c=t.files??(Array.isArray(n?.files)?n.files.map(tt):void 0),l=t.error?"error":t.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:e,status:l,answer:p(t.answer),partial:!a,...typeof n?.messageId=="string"?{messageId:p(n.messageId)}:typeof n?.answerId=="string"?{messageId:p(n.answerId)}:{},...t.question?{question:t.question}:{},...t.error?{error:p(t.error)}:{},...t.streamId?{streamId:p(t.streamId)}:{},...r?{servedBy:Ue(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:Ue(c)}:{}}}function P(e,t){return typeof e=="string"?p(e).slice(0,t):""}function Ho(e){return typeof e.message=="string"?p(e.message).slice(0,2e3):"Oracle turn failed."}function X(e){return p(e instanceof Error?e.message:String(e)).slice(0,2e3)}function An(e){let t=e.question;if(!t||typeof t!="object")throw new h("Oracle question event omitted its question card.",g.API_ERROR);return pp(t)}function tt(e){let t=e&&typeof e=="object"&&!Array.isArray(e)?e:{};if(typeof t.fileId!="string"||!t.fileId||typeof t.filename!="string"||!t.filename||typeof t.mediaType!="string"||!t.mediaType||typeof t.sizeBytes!="number"||!Number.isSafeInteger(t.sizeBytes)||t.sizeBytes<0)throw new h("Oracle generated-file event omitted safe file metadata.",g.API_ERROR);return{fileId:p(t.fileId),filename:p(t.filename),mediaType:p(t.mediaType),sizeBytes:t.sizeBytes,...typeof t.format=="string"?{format:p(t.format)}:{}}}function up(e,t){let n=tt(t);e.some(r=>r.fileId===n.fileId)||e.push(n)}function pp(e){let t=e;if(typeof t.id!="string"||!Array.isArray(t.questions))throw new h("Oracle returned an invalid question card.",g.API_ERROR);return{id:p(t.id),optional:t.optional===!0,questions:t.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 h(`Oracle question ${r+1} is invalid.`,g.API_ERROR);return{id:p(o.id),header:p(o.header),question:p(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 h("Oracle question option is invalid.",g.API_ERROR);return{id:p(s.id),label:p(s.label),description:p(s.description),...typeof s.recommended=="boolean"?{recommended:s.recommended}:{},...typeof s.confirms=="boolean"?{confirms:s.confirms}:{}}})}})}}function re(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function vt(e){if(typeof e=="number"&&Number.isFinite(e))return{totalTokens:e};if(!e||typeof e!="object"||Array.isArray(e))return;let t=e,n=re(t.in)??re(t.input)??re(t.inputTokens),r=re(t.cacheRead),o=re(t.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=re(t.out)??re(t.output)??re(t.outputTokens),a=re(t.total)??re(t.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 Kt(e){if(e&&typeof e=="object"){let t=e;if(typeof t.accepted=="boolean")return t.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof t.cancelled=="boolean")return t.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function Jt(e,t){let n=t&&e&&(e.kind==="program"||e.kind==="initiative")?{kind:e.kind,id:e.id}:void 0;return{...!t&&e?{context:e}:{},...n?{sharedEntity:n}:{},visibility:t?"company":"private"}}async function xn(e,t,n){await Wa(e,t,n).catch(()=>{})}async function fr(e,t,n,r){if(!n.length)return[];if(n.length>Ja)throw new f(`Attach no more than ${Ja} files per turn.`);let o=0,i=[];for(let a of n){let c=await cp(a);if(!c.isFile())throw new f(`Attachment is not a file: ${a}`);if(c.size>Ka)throw new f(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let l=await fp(a,Ka);if(o+=l.byteLength,o>dp)throw new f("Attachments exceed the 20 MiB total CLI limit.");let d=lp(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",u=La(d)??"";if(!u)throw new f(`Unsupported attachment type: ${a}`);i.push({content:l,name:d,mediaType:u})}let s=[];for(let{content:a,name:c,mediaType:l}of i){await r(p(c),a.byteLength);let d=new ArrayBuffer(a.byteLength);new Uint8Array(d).set(a);let u=new File([d],c,{type:l});s.push(await e.upload(t,u))}return s}async function fp(e,t){let n=[],r=0;for await(let o of ap(e)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>t)throw new f(`Attachment exceeds the ${Y(t)} limit: ${e}`);n.push(i)}return Buffer.concat(n)}var kt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],hp=2e4,gp=6,wp={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},yp={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"},mr=class{constructor(t,n){this.startedAt=t;this.sessionId=n;this.lastSignalAt=t}startedAt;sessionId;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(t=>t.status==="failed").length}get finished(){return this.end!==void 0}setUploading(t,n,r){this.phase="uploading",this.upload=`${t} (${Y(n)})`,this.lastSignalAt=r}setPhase(t,n){this.phase=t,this.lastSignalAt=n}touch(t){this.lastSignalAt=t}apply(t,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(t);switch(t.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=re(t.round),this.maxRounds=re(t.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 t.phase=="string"?t.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(t)}record(t){switch(t.type){case"delta":typeof t.content=="string"&&(this.answer+=t.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(t);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===t.toolUseId);n&&(n.status=t.ok===!1?"failed":"ok");break}case"subagent_start":typeof t.spawnId=="string"&&this.agents.set(t.spawnId,"running");break;case"subagent_done":typeof t.spawnId=="string"&&this.agents.set(t.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${P(t.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${P(t.filename,200)}: ${P(t.error,500)}`});break;case"attachment_notice":if(Array.isArray(t.notices))for(let n of t.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${P(r.name,160)}: ${P(r.message,500)}`})}break;case"provider_fallback":{let n=P(t.from,120),r=P(t.to,120),o=P(t.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=tt(t.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${Y(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:Ho(t)});break;case"done":this.done=t;break}}recordToolCall(t){let n=typeof t.id=="string"?t.id:void 0,r=Go(t,this.toolIds),o=typeof t.name=="string"?t.name:"";if(Mt(o))return;let i=P(typeof t.label=="string"?t.label:Ft(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,t.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof t.spawnId=="string"?{spawnId:t.spawnId}:{},...t.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=p(this.answer.trim()),this.answer=""),this.tools.push(a),this.phase!=="finishing"&&(this.phase="thinking")}note(t,n){this.notices.push({tone:t,text:p(n)})}finish(t,n){this.end=t,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 t=[...this.agents.values()].filter(r=>r==="running").length;if(t)return`Researching (${t} agent${t===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&&wp[this.serverPhase]||"Thinking"}statusLine(t,n){let r=[this.label(),Lo(t-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=t-this.lastSignalAt;return o>=hp&&this.phase!=="cancelling"&&r.push(`no update for ${Lo(o)}`),n&&t-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let t=[],n=yn((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=Xa("\u2713"):this.end==="awaiting_input"?o=zo("?")+" Waiting for your answer":this.end==="cancelled"?o=Jo("\u2717")+" Interrupted":this.end==="error"?o=Ko("\u2717")+" Error":o=Jo("\u2717")+` Stopped: ${r&&yp[r]||"no final answer"}`,t.push(n),this.tools.length&&t.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=vt(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&t.push(`${xe(i.inputTokens??0)} in${i.cachedInputTokens?` (${xe(i.cachedInputTokens)} cached)`:""} / ${xe(i.outputTokens??0)} out`);let s=Sn(this.done?.servedBy);return s&&t.push(s),`${o} ${bt(t.join(" \xB7 "))}`}};function Sn(e){if(!e||typeof e!="object")return"";let t=e,n=P(t.model??t.id,100);if(!n)return"";let r=t.fallback&&typeof t.fallback=="object"?t.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${P(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${P(r.from,100)}${o})`}return n}var hr=class{constructor(t,n){this.activity=t;this.view=n;this.answer=new jt("",n.linkOrigin)}activity;view;answer;getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(t){let n=this.activity;this.answer.setText(n.answer);let r=[vn("assistant")];if(!n.finished&&!n.tools.length&&!n.answer.trim()){let o=zo(kt[this.view.frame()%kt.length]??"*");r.push(_n(` ${o} ${bt(n.label())}`,t))}r.push(...this.renderTools(t)),r.push(...this.answer.render(t));for(let o of n.notices){let i=o.tone==="error"?Ko:o.tone==="warning"?Jo:bt;r.push(...Ya(i(o.text),t))}return n.finished&&r.push(_n(n.summaryLine(),t)),r}renderTools(t){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[_n(bt(` \u23BF ${a}`),t)]}let r=this.activity.finished?n:n.slice(-gp),o=n.length-r.length,i=[];return o&&i.push(_n(bt(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),t)),r.forEach((s,a)=>{if(s.note)for(let u of Ya(s.note,Math.max(10,t-4)).slice(0,3))i.push(` ${bt(mp(u))}`);let c=s.status==="running"?zo(kt[this.view.frame()%kt.length]??"*"):s.status==="ok"?Xa("\u2713"):Ko("\u2717"),l=a===0&&!o?" \u23BF ":" ",d=s.spawnId?` ${bt("agent \xB7")} `:"";i.push(_n(`${l}${d}${c} ${s.label}`,t))}),i}};import{truncateToWidth as Op,visibleWidth as Ap,wrapTextWithAnsi as Za}from"@earendil-works/pi-tui";import{bold as ec,cyan as xp,dim as He}from"kleur/colors";import{CombinedAutocompleteProvider as vp}from"@earendil-works/pi-tui";var Rn=[{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"]}],bp=[{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 Vo(e){let t=new Set(Rn.flatMap(n=>[n.name,...n.aliases??[]]));return(e??bp).filter(n=>!t.has(n.name))}function Qa(e,t){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(e.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=Rn.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=t.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function Yo(e,t){let n=[...Rn.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=>kp(i.completions??[],s)}:{}})),...e.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new vp(n,t),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let l=(i[s]??"").slice(0,a);return s!==0||!l.trimStart().startsWith("/")?null:o.test(l)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,l){return r.applyCompletion(i,s,a,c,l)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function kp(e,t){let n=e.filter(r=>r.startsWith(t.toLowerCase())&&r!==t).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function In(e,t){return e?t?"write + approve":"write":"read only"}function Vt(e){return e?`${e.kind} ${p(e.id)}`:"no context"}function nt(e){return e?p(e.companyName||e.companyId):""}function tc(e,t){let n=[`${ec(xp("\u26A1\uFE0E AnyForge Oracle"))}${He(` \xB7 v${p(e.version)}`)}`,`${e.workspace?`${ec(e.workspace)} \xB7 `:""}${je(e.session)} \xB7 ${e.access} \xB7 ${Vt(e.context)}`,...e.session.messages.length?[`Resumed: ${p(e.session.title)}`]:[],He("Only your messages and the files you attach leave this terminal."),He("/help commands \xB7 /status details")];if(t<24)return n.flatMap(s=>Za(s,Math.max(1,t)));let r=Math.min(t,76),o=r-4,i=[He(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>Za(a,o))){let a=Op(s,o);i.push(`${He("\u2502")} ${a}${" ".repeat(Math.max(0,o-Ap(a)))} ${He("\u2502")}`)}return i.push(He(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function nc(e){let t=(r,o)=>r?`${He(r)} ${o}`:o,n=[{title:"Commands",rows:Rn.map(r=>[`/${r.name}`,t(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(e.server.length){let r=e.server.map(o=>[`/${o.name}`,t(o.args,p(o.description))]);e.server.some(o=>o.name==="catchup")&&!e.canApprove&&r.push(["",He("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 Xo(e){let n=[["Model",`workspace default ${e.model?`${p(e.model.provider)}/${p(e.model.id)}`:"chosen by the server"}`]],r=Sn(e.lastServedBy);if(r){let o=e.lastServedBy,i=P(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function Qo(e){return[["This run",e.turns?`${e.turns} turn${e.turns===1?"":"s"} \xB7 ${e.tools} tool${e.tools===1?"":"s"} \xB7 ${xe(e.inputTokens)} in / ${xe(e.outputTokens)} out tokens`:"no turns yet"]]}function Zo(e){if(!e?.finished)return[];let t=[yn((e.endedAt??e.startedAt)-e.startedAt)];t.push(`${e.toolCount} tool${e.toolCount===1?"":"s"}${e.failedCount?` (${e.failedCount} failed)`:""}`);let n=re(e.done?.rounds);n!==void 0&&t.push(`${n} round${n===1?"":"s"}`);let r=vt(e.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&t.push(`${xe(r.inputTokens??0)} in${r.cachedInputTokens?` (${xe(r.cachedInputTokens)} cached)`:""} / ${xe(r.outputTokens??0)} out tokens`);let o=P(e.done?.exitReason,40);return t.push(o?o.replaceAll("_"," "):e.end??""),[["Last turn",t.filter(Boolean).join(" \xB7 ")]]}function rc(e){let t=e.capabilities?["read","write","approve"].filter(o=>e.capabilities?.[o]).join(", ")||"none":"not reported",n=e.contextText?` \xB7 note ${Y(Buffer.byteLength(e.contextText,"utf8"))}`:"",r=_a(e.limits);return[["Session",`${e.session.sessionId} \xB7 ${p(e.session.title)||"Untitled"}`],["Audience",je(e.session)],["Access",`this session ${In(e.write,e.approve)} \xB7 grant ${e.grantScopes.join(", ")||"none"} \xB7 workspace role ${t}`],["Context",`${Vt(e.context)}${n}`],...Xo(e),...Zo(e.lastTurn),...Qo(e.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...e.identity?[["Workspace",_p(e.identity,e.savedWorkspaces)]]:[],["Endpoint",e.endpoint],["Version",`CLI ${p(e.version)} \xB7 protocol ${1}`],["Attached",e.pendingFiles.length?`${e.pendingFiles.map(p).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function _p(e,t){let n=e.companyName?`${p(e.companyName)} (${p(e.companyId)})`:`company ${p(e.companyId)}`,r=t!==void 0&&t>1?` \xB7 ${t} saved, /workspace to switch`:"";return`${n} \xB7 user ${p(e.uid)}${r}`}function oc(e,t){return t.length?t.map((n,r)=>[`${r+1}.`,`${p(n.filename)} (${Y(n.sizeBytes)}) \xB7 anyforge oracle download ${e} ${p(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}q();import{randomUUID as Cp}from"node:crypto";import{stat as Ep}from"node:fs/promises";import{basename as ic}from"node:path";import{bold as Tp,cyan as sc,dim as ac,red as Xt,yellow as $p}from"kleur/colors";import{Container as Pp,Editor as Lp,ProcessTerminal as Np,ScrollView as Fp,SelectList as cc,TuiAltScreen as Mp,VStack as qp,getNativeClipboard as Up,matchesKey as yr,truncateToWidth as lc,wrapTextWithAnsi as jp}from"@earendil-works/pi-tui";import{bold as Sp,cyan as ei,dim as gr,yellow as Rp}from"kleur/colors";import{Input as Ip,Text as Ot,matchesKey as Yt}from"@earendil-works/pi-tui";var wr=class{constructor(t,n,r){this.tui=t;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()}}tui;question;onComplete;focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new Ip({prompt:`${ei("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:gr});invalidate(){}render(t){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,t-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new Ot(`${Sp(ei(p(n.header)))}${gr(o)}`,0,0).render(r),...new Ot(p(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Ot(gr(`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 Ot(gr(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Ot(Rp(this.errorMessage),0,0).render(r)),i.map(s=>`${ei("\u2502")} ${s}`)}handleInput(t){if(this.mode==="custom"){this.customInput.handleInput(t);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(t.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(Yt(t,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(t);return}if(Yt(t,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(Yt(t,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(Yt(t,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(t.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(t.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(t);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(Yt(t,"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(Yt(t,"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(t,n){let r=this.selectedFor(t),o=[];return t.options.forEach((i,s)=>{let a=r.has(i.id),c=t.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",l=s===this.optionIndex?"\u203A":" ",d=i.recommended?" \xB7 recommended":"",u=i.confirms?" \xB7 confirms the shown action":"",w=`${l} ${s+1}. ${c} ${p(i.label)}${d}${u}`;o.push(...new Ot(w,0,0).render(n)),o.push(...new Ot(` ${p(i.description)}`,0,0).render(n))}),o}instructions(t){return t.options.length===0?`Write a short answer${this.question.optional?" \xB7 s or Esc skip card":""}`:`\u2191/\u2193 move \xB7 1\u2013${t.options.length} ${t.multiSelect?"toggle":"select"}${t.multiSelect?" \xB7 Space toggle":""} \xB7 Enter continue \xB7 o write your own${this.question.optional?" \xB7 s or Esc skip card":""}`}requireAnswer(){let t=this.question.questions[this.questionIndex];this.errorMessage=t?.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(t){let n=this.selected.get(t.id);return n||(n=new Set,this.selected.set(t.id,n)),n}recordCurrent(t){let n=this.question.questions[this.questionIndex];if(!n)return;t&&this.selectedFor(n).clear();let r=[...this.selectedFor(n)],o={questionId:n.id,optionIds:r,...t?{customText:t}:{}},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(t){this.onComplete(t)}};var dc=1500,Dp=100,Bp="\x1B]133;A\x07";function Qt(e){return{render:e,invalidate(){}}}function uc(e,t,n,r){let o=new jt(t,r);return{getText:()=>o.getText(),invalidate:()=>o.invalidate(),render:i=>e==="user"?Ta(o,i,n).map((s,a)=>a===1?`${Bp}${s}`:s):[vn("assistant"),...o.render(i)]}}async function pc(e){let{client:t,config:n}=e,r=new Np,o=new Mp(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new Pp,s=new Fp(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new Lp(o,Ea),c=Vo(n.commands),l=()=>typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,d=e.session,u=e.initialContext,w=e.contextText,v=e.canWrite,x=e.canApprove,b,m,A,L,D=[...e.initialFiles],V=!1,Te=!1,_t=!1,Er=0,St,ai=0,Tn=!1,ot="",tn,$n,Rt=[],It={turns:0,inputTokens:0,outputTokens:0,tools:0},Pn=new Map,$e,Bc=Qt(y=>{if(b){let k=sc(kt[Er%kt.length]??"*");return[lc(`${k} ${b.activity.statusLine(Date.now(),l())}`,y)]}return $e?[lc(`${sc("?")} Waiting for your answer to the question above`,y)]:[]}),Gc=Qt(y=>{let k=[nt(n.identity),In(v,x),Vt(u),$a(d),D.length?`${D.length} file${D.length===1?"":"s"} attached`:"",m!==void 0?"1 message queued":""];return[ac(Ra(y,k,b?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new qp([{component:s,basis:0,grow:1,minSize:1},{component:Bc,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:Gc,basis:"auto",shrink:0,minSize:1}]));let fe=()=>o.requestRender(),B=y=>o.flash(p(y),3e3),Je=y=>{i.addChild(y),fe()},Q=(y,k=ac)=>{let O=p(y);Je(Qt(_=>jp(k(O),Math.max(1,_))))},Ln=(y,k)=>{Je(Qt(O=>["",...Sa(y,k,O)]))},Wc=()=>{St||(St=setInterval(()=>{Er+=1,fe()},Dp),St.unref())},Tr=()=>{St&&clearInterval(St),St=void 0},Ct=()=>{V||o.hasOverlay()||o.setFocus($e??a)},ci=y=>{A=y;let k=Pn.get(y.id);k&&i.removeChild(k);let O=new wr(o,y,_=>{Pn.delete(y.id),$e===O&&($e=void 0),i.removeChild(O),Kc(_??{questionId:y.id,skipped:!0,answers:[]}),Ct()});Pn.set(y.id,O),$e=O,Je(O)},Nn=y=>{i.clear(),Pn.clear(),$e=void 0,d=y,A=void 0,L=void 0,Rt=[],ot="";let k={version:e.version,workspace:nt(n.identity),session:y,access:In(v,x),context:u};Je(Qt(_=>tc(k,_)));let O;for(let _ of y.messages){Je(uc(_.role,_.content,_.authorName,t.endpoint)),_.role==="assistant"&&(ot=_.content),_.question&&(O=_.question),_.questionResponse&&(Q("A stored response was recorded for this question."),O?.id===_.questionResponse.questionId&&(O=void 0));for(let R of _.files??[])Rt.some(N=>N.fileId===R.fileId)||Rt.push(R),Q(`File: ${R.filename} (${R.mediaType}, ${Y(R.sizeBytes)}) \xB7 anyforge oracle download ${y.sessionId} ${R.fileId} --output .`)}O&&ci(O),Ct(),xn(y.sessionId,t.endpoint,n.identity?.companyId)},li,Hc=new Promise(y=>{li=y}),Fn=()=>{V||(V=!0,Tr(),b?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),li())},$r=async()=>{let y=b;if(!y||y.cancelling)return;y.cancelling=!0,y.activity.setPhase("cancelling",Date.now()),fe();let{streamId:k,requestId:O}=y;y.controller.abort(new Error("Turn cancelled by user."));let _;if(k)try{_=Kt(await t.cancelTurn(d.sessionId,k))}catch(R){_=`Could not confirm server cancellation: ${X(R)}`}else if(O)try{_=Kt(await t.cancelRequest(d.sessionId,O))}catch(R){_=`Could not confirm server cancellation by request id: ${X(R)}`}else _="The turn had not reached the server; nothing was sent.";y.activity.note("info",_),fe()},Et=async y=>{if(b||V)return;if(y.kind==="submit"&&y.response){let F=A;if(!F||F.id!==y.response.questionId){B("That question is no longer active. Resume the session to refresh it.");return}Q(Gp(F,y.response)),A=void 0}else y.kind==="submit"&&Je(uc("user",y.text));let k=d.sessionId,O=new mr(Date.now(),k),_=new hr(O,{expanded:()=>_t,frame:()=>Er,linkOrigin:t.endpoint}),R={activity:O,view:_,controller:new AbortController,cancelling:!1};b=R,Je(_),Wc();let N=new We,oe=F=>{O.apply(F,Date.now()),F.type==="question"&&(ci(An(F)),Ct()),fe()},it={onEvent:oe,onStream:F=>{R.streamId=F},onResponse:()=>{O.phase==="sending"&&O.setPhase("preparing",Date.now())},onActivity:()=>O.touch(Date.now())},me="error";try{if(y.kind==="replay"){N.streamId=y.streamId,R.streamId=y.streamId,O.setPhase("thinking",Date.now());let F=await Wo(t,k,N,async _e=>{N.accept(_e)&&oe(_e)},R.controller.signal,it.onActivity);me=On(k,F).status}else{let F=y.response?[]:D.splice(0),_e=await fr(t,k,F,(Pr,rl)=>{O.setUploading(Pr,rl,Date.now()),fe()});R.controller.signal.throwIfAborted(),O.setPhase("sending",Date.now());let Mn=Cp();R.requestId=Mn;let tl={requestId:Mn,text:y.response?"":y.text,readOnly:!v,...x?{allowApprove:!0}:{},...u?{context:u}:{},...w?{contextText:w}:{},...y.response?{questionResponse:y.response}:{},..._e.length?{attachments:_e.map(Pr=>({fileId:Pr.fileId}))}:{}},nl=await zt(t,k,tl,it,R.controller.signal,N);me=On(k,nl).status}}catch(F){if(R.controller.signal.aborted)me="cancelled";else{me="error";let _e=F instanceof h&&F.hint?` ${p(F.hint)}`:"";O.note("error",`${X(F)}${_e}`)}}finally{O.finish(me,Date.now()),b=void 0,Tr(),V||(Te=me==="cancelled"),tn=O,O.answer.trim()&&(ot=O.answer),O.done?.servedBy&&($n=O.done.servedBy);let F=vt(O.done?.tokens);It.turns+=1,It.tools+=O.toolCount,It.inputTokens+=F?.inputTokens??0,It.outputTokens+=F?.outputTokens??0;for(let _e of O.files)Rt.some(Mn=>Mn.fileId===_e.fileId)||Rt.push(_e);fe()}if(!V){if(R.streamId&&me!=="cancelled"){let F=await t.getSession(k).catch(()=>{});F&&F.sessionId===d.sessionId&&(d=F)}zc(me)}},zc=y=>{if(!(V||b)){if(L){let k=L;L=void 0,Et({kind:"submit",text:"",response:k});return}if(m!==void 0){let k=m;if(m=void 0,y==="complete"&&!$e){Et({kind:"submit",text:k});return}a.getText()||a.setText(k),B("Your queued message is back in the input; press Enter to send it.")}Ct(),fe()}},Kc=y=>{if(b){L=y,B("Answer saved; Oracle continues once the current turn settles.");return}Et({kind:"submit",text:"",response:y})},di=async y=>{try{let k=await t.getSession(y);Nn(k),k.activeStreamId&&Et({kind:"replay",streamId:k.activeStreamId}),B(`Resumed ${k.title||k.sessionId}.`)}catch(k){Q(X(k),Xt)}},Jc=async()=>{try{let y=await t.listSessions();if(!y.length){B("No saved conversations to resume.");return}let k=new cc(y.map(N=>({value:N.sessionId,label:N.title,description:je(N)})),Math.min(12,y.length),Dt),O=await ur(t.endpoint,n.identity?.companyId),_=O?y.findIndex(N=>N.sessionId===O):-1;_>=0&&k.setSelectedIndex(_);let R=o.showOverlay(k,{width:"85%",maxHeight:"80%",anchor:"center"});k.onSelect=N=>{R.hide(),di(N.value)},k.onCancel=()=>{R.hide(),Ct()},R.focus()}catch(y){Q(X(y),Xt)}},ui=async y=>{if(y&&(!u||u.kind!=="program"&&u.kind!=="initiative")){B("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let k=await t.createSession(Jt(u,y));Nn(k),B(`Started a new conversation \xB7 ${je(k)}.`)}catch(k){Q(X(k),Xt)}},pi=async(y,k)=>{let O=p(pe(k));if(k.companyId&&k.companyId===n.identity?.companyId){B(`Already in ${O}.`);return}Tn=!0;try{B(`Connecting to ${O}...`);let _=await y.connect(k),R=await _.client.createSession(Jt(void 0,!1));t=_.client,n=_.config,c=Vo(n.commands),a.setAutocompleteProvider(Yo(c,process.cwd()));let N=t.scopes.has("write")&&n.capabilities?.write===!0,oe=t.scopes.has("approve")&&n.capabilities?.approve===!0,it=v&&!N||x&&!oe;v&&!N&&(v=!1),(!v||!oe)&&(x=!1);let me=u!==void 0;u=void 0,$n=void 0,tn=void 0,Nn(R),Q(`Switched to ${nt(n.identity)||O}. This is a new conversation in that workspace.${me?" Context was cleared because its id belongs to the previous workspace.":""}`),it&&Q(`Access here is ${In(v,x)}: this workspace's login or your role there does not allow more.`,$p)}catch(_){let R=_ instanceof h&&_.hint?` ${p(_.hint)}`:"";Q(`Could not switch to ${O}: ${X(_)}${R}`,Xt)}finally{Tn=!1}},Vc=async(y,k)=>{let O=n.identity?.companyId,_=new cc(k.map(oe=>({value:oe.clientId,label:pe(oe),description:[oe.companyId,oe.scopes.join(", "),oe.companyId===O?"current":""].filter(Boolean).join(" \xB7 ")})),Math.min(12,k.length),Dt),R=k.findIndex(oe=>oe.companyId===O);R>=0&&_.setSelectedIndex(R);let N=o.showOverlay(_,{width:"85%",maxHeight:"80%",anchor:"center"});_.onSelect=oe=>{N.hide();let it=k.find(me=>me.clientId===oe.value);it&&pi(y,it)},_.onCancel=()=>{N.hide(),Ct()},N.focus()},Yc=async y=>{let k=e.workspaces;if(!k){Q(`This terminal signs in with ANYFORGE_API_TOKEN, which is bound to ${nt(n.identity)||"one workspace"}. To switch workspaces, unset it and sign in with \`anyforge oracle login --workspace <name>\`.`);return}let O=await k.list();if(y){let _;try{_=yt(O,y)}catch(R){let N=R instanceof h&&R.hint?` ${p(R.hint)}`:"";Q(`${X(R)}${N}`,Xt);return}await pi(k,_);return}if(O.length<=1){Q(`${nt(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 Vc(k,O)},Xc=y=>({session:d,write:v,approve:x,grantScopes:[...t.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...u?{context:u}:{},...w?{contextText:w}:{},...n.model?{model:n.model}:{},lastServedBy:$n,...tn?{lastTurn:tn}:{},totals:{...It},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},...y!==void 0?{savedWorkspaces:y}:{},endpoint:t.endpoint,version:e.version,pendingFiles:D.map(k=>ic(k))}),Qc=async()=>{if(!ot.trim()){B("There is no answer to copy yet.");return}try{let y=Up();y?.setText?await y.setText(ot):r.write(`\x1B]52;c;${Buffer.from(ot,"utf8").toString("base64")}\x07`),B(`Copied the last answer (${ot.length} characters).`)}catch(y){B(`Could not copy: ${X(y)}`)}},Zc=async(y,k,O)=>{if(y.idleOnly&&Tn){B("Wait for the workspace switch to finish.");return}if(y.idleOnly&&b){B(`Wait for Oracle to finish, or press Esc, before /${y.name}.`);return}switch(y.name){case"help":Je(Qt(_=>["",...nc({server:c,canApprove:x}).flatMap(R=>[Tp(R.title),...No(R.rows,_)])]));return;case"status":{let _=await e.workspaces?.list().then(R=>R.length).catch(()=>{});Ln("Status",rc(Xc(_)));return}case"workspace":await Yc(O);return;case"model":Ln("Model",Xo({...n.model?{model:n.model}:{},lastServedBy:$n}));return;case"usage":Ln("Usage",[...Zo(tn),...Qo(It)]);return;case"files":Ln("Generated files",oc(d.sessionId,Rt));return;case"copy":await Qc();return;case"exit":Fn();return;case"new":if(O&&O!=="shared"){B("Usage: /new or /new shared");return}await ui(O==="shared");return;case"clear":await ui(!1);return;case"resume":O?await di(O):await Jc();return;case"context":{if(!O){Q(`Context: ${Vt(u)}${w?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(O==="clear")u=void 0;else{let[_,R,...N]=k;if(!["program","initiative","codebase"].includes(_??"")||!R||N.length){B("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}u={kind:_,id:R}}Q(`Context for your next message: ${Vt(u)}.`);return}case"attach":{if(!O){B("Usage: /attach <file path>");return}let _=await Ep(O).catch(()=>{});if(!_?.isFile()){B(`Not a readable file: ${O}`);return}D.push(O),Q(`Attached ${ic(O)} (${Y(_.size)}). It uploads with your next message.`);return}}},fi=y=>{let k=y.trim();if(!k)return;a.addToHistory(k);let O=Qa(k,c);if(O?.kind==="local"){Zc(O.command,O.args,O.arg).catch(_=>Q(X(_),Xt));return}if(O?.kind==="unknown"){a.setText(k),B(`Unknown command /${O.name}. Type /help to see the commands.`);return}if(Tn){a.setText(k),B("Switching workspace; send your message once it has opened.");return}if(b){let _=m!==void 0;m=k,B(_?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),fe();return}Et({kind:"submit",text:k})},el=o.addInputListener(y=>{if(yr(y,"ctrl+c")){if(b)return $r(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),fe(),{consume:!0};let k=Date.now();return k-ai<=dc?Fn():(ai=k,o.flash("Press Ctrl+C again to exit",dc)),{consume:!0}}if(yr(y,"escape")){let k=$e!==void 0&&o.getFocusedComponent()===$e;return b&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!k?($r(),{consume:!0}):void 0}if(yr(y,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(Fn(),{consume:!0}):void 0;if(yr(y,"ctrl+o"))return _t=!_t,B(_t?"Showing tool activity":"Hiding tool activity"),fe(),{consume:!0}}),mi=()=>{let y=!!b;$r().finally(()=>{y&&(Te=!0),Fn()})};process.on("SIGINT",mi),a.onSubmit=fi,a.onChange=()=>fe(),a.setAutocompleteProvider(Yo(c,process.cwd())),Nn(e.session),o.start(),d.activeStreamId&&Et({kind:"replay",streamId:d.activeStreamId}),e.initialPrompt&&fi(e.initialPrompt),await Hc,el(),process.off("SIGINT",mi),Tr(),b?.controller.abort(),await r.drainInput().catch(()=>{}),Te&&(process.exitCode=130)}function Gp(e,t){if(t.skipped)return"Skipped the optional Oracle question.";let n=[];for(let r of t.answers){let o=e.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(p).join("; ")||"no options selected"}`}W();q();import{createHash as Wp,randomBytes as fc,timingSafeEqual as Hp}from"node:crypto";import{createServer as zp}from"node:http";import Kp from"open";var Or="https://crew.anyforge.ai",Jp=6e4,Vp=5*6e4,vr=new Map;async function At(e){e.signal?.throwIfAborted();let t=et(e.endpoint),n=await wt(t,fetch,void 0,e.signal),r=["read"];e.write&&r.push("write"),e.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=fc(32).toString("base64url"),i=await Zp(o,e.signal);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 ef(n.oauth.registration,s,e.signal);if(typeof a.client_id!="string"||!a.client_id)throw new h("OAuth registration did not return a client id.",g.API_ERROR);let c=fc(32).toString("base64url"),l=Wp("sha256").update(c).digest("base64url"),d={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:l,code_challenge_method:"S256",resource:n.resource},u=new URL(n.oauth.authorization);for(let[V,Te]of Object.entries(d))u.searchParams.set(V,String(Te));let w=e.workspace?.trim();w&&u.searchParams.set(Na,w),e.onAuthorizationUrl?.(u.toString()),e.signal?.throwIfAborted();try{e.openBrowser?await e.openBrowser(u.toString()):await Kp(u.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
443
445
  ${u.toString()}
444
- `)}let v=await i.wait();if(!Va(v.state,o))throw new h("Oracle sign-in callback state did not match; authorization was rejected.",g.API_ERROR);if(v.error)throw new h(`Oracle authorization failed: ${p(v.error)}${v.errorDescription?` (${p(v.errorDescription)})`:""}`,g.API_ERROR);if(!v.code)throw new h("Oracle authorization callback did not include a code.",g.API_ERROR);let x={client_id:a.client_id,grant_type:"authorization_code",code:v.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},b=await Za(n.oauth.token,x,e.signal);Qa(b);let m=Xa(b.scope);if(!m.includes("read")||m.some(K=>!r.includes(K)))throw await ur(n.oauth.revocation,a.client_id,b.access_token,b.refresh_token).catch(()=>{}),new h("The granted Oracle scopes are invalid for this request.",g.API_ERROR);let A=await ft(t,fetch,b.access_token,e.signal).then(K=>K.identity).catch(()=>{});e.signal?.throwIfAborted();let L={endpoint:t,...Ha(A),clientId:a.client_id,redirectUri:i.redirectUri,accessToken:b.access_token,refreshToken:b.refresh_token,expiresAt:Date.now()+b.expires_in*1e3,scopes:m},j=await Zn(K=>wa(K,L));return j&&await ur(n.oauth.revocation,j.clientId,j.accessToken,j.refreshToken).catch(()=>{}),L}finally{await i.close()}}function Ha(e){return e?{companyId:e.companyId,...e.companyName?{companyName:e.companyName}:{},uid:e.uid}:{}}async function za(e={}){if(e.workspace&&!e.all){let n=Sn(await le(),e.endpointOverride);n&&await Uo(n)}let t=await nr(async()=>{let n=await le(),r=[];if(e.all)r=[...n.logins];else{let s=Sn(n,e.endpointOverride);e.workspace?r=[mt(s?Ue(n,s):[],e.workspace)]:s&&(r=[er(n,s)].filter(a=>!!a))}let o=[],i;for(let s of r){try{await Ka(s)}catch(a){o.push({login:s,error:a})}i=So(n,s)??i}return await wn(n),{removed:r,failures:o,...i&&!e.all?{nowActive:i}:{}}});if(t.failures.length){let n=t.failures.map(({login:r,error:o})=>{let i=o instanceof Error?p(o.message):"unknown error";return t.failures.length>1||e.all?`${p(de(r))}: ${i}`:i});throw new h(`Local Oracle credentials were cleared, but server revocation failed for ${t.failures.length===1?"one login":`${t.failures.length} logins`}: ${n.join("; ")}`,g.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire these access tokens automatically.")}return{removed:t.removed,...t.nowActive?{nowActive:t.nowActive}:{}}}async function Ka(e){let t=await ft(e.endpoint);await ur(t.oauth.revocation,e.clientId,e.accessToken,e.refreshToken)}function Sn(e,t){let n=t||process.env.ANYFORGE_ENDPOINT;return n?Ve(n):e.endpoint}function Ja(){return new f("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 fr(e,t){let n=e||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN){if(t)throw Ja();return Ga(n)}let r=await le(),o=Sn(r,n);if(t)return Be(await xp(o,t));let i=o?er(r,o):void 0;if(i)return Be(i);try{return await Ga(n)}catch(s){throw r.logins.length&&n?new xe:s instanceof xe?new xe:s}}async function xp(e,t){if(!e)return mt([],t);let n=await mr(e);return mt(n,t)}function Be(e){return{endpoint:e.endpoint,accessToken:e.accessToken,scopes:e.scopes.filter(jo),source:"oauth",getAccessToken:async t=>Sp(e.endpoint,e.clientId,t),onIdentity:async t=>{if(e.companyId===t.companyId&&(t.companyName===void 0||e.companyName===t.companyName)&&e.uid===t.uid)return;let r=await Zn(i=>ya(i,e.endpoint,e.clientId,t));Object.assign(e,Ha(t));let o=r.duplicate;o&&await Ka(o).catch(()=>{})}}}async function mr(e){return await Uo(e),Ue(await le(),e)}async function Uo(e){let t=Ue(await le(),e).filter(n=>!n.companyId);for(let n of t)await new we(Be(n)).config().catch(()=>{})}async function Vt(e){let t=Sn(await le(),e);if(!t)return{logins:[]};let n=await mr(t),r=er(await le(),t);return{endpoint:t,logins:n,...r?{active:r}:{}}}async function Ya(e,t){if(process.env.ANYFORGE_API_TOKEN)throw Ja();let n=Sn(await le(),e);return n&&await Uo(n),Zn(r=>{let o=mt(n?Ue(r,n):[],t);return r.active[o.endpoint]=o.clientId,r.endpoint=o.endpoint,o})}async function Ga(e){let t=await $e(e),r=(await sn({apiKey:t.apiKey,endpoint:t.endpoint})).scopes.filter(jo);return{endpoint:t.endpoint,accessToken:t.apiKey,scopes:r,source:"control"}}async function Sp(e,t,n){let r=Ve(e),o=`${r}
445
- ${t}`,i=lr.get(o);if(i)return i;let s=nr(()=>Rp(r,t,n));lr.set(o,s);try{return await s}finally{lr.get(o)===s&&lr.delete(o)}}async function Rp(e,t,n){let r=await le(),o=r.logins.find(l=>l.endpoint===e&&l.clientId===t);if(!o)throw new xe;if(o.expiresAt>Date.now()+Op&&(!n||o.accessToken!==n))return o.accessToken;let i=async()=>{So(r,o),await wn(r)},s=await ft(o.endpoint),a;try{let l={client_id:o.clientId,grant_type:"refresh_token",refresh_token:o.refreshToken,resource:s.resource};a=await Za(s.oauth.token,l)}catch(l){throw l instanceof dr&&["invalid_grant","invalid_client","invalid_target"].includes(l.code)?(await i(),new xe):l}Qa(a);let c;try{c=Xa(a.scope)}catch(l){throw await i(),l}if(c.some(l=>!o.scopes.includes(l)))throw await ur(s.oauth.revocation,o.clientId,a.access_token,a.refresh_token),await i(),new h("Oracle refresh attempted to widen the saved grant; credentials were cleared.",g.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 wn(r),o.accessToken}var dr=class extends h{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?g.NO_CREDENTIALS:g.API_ERROR);this.code=n;this.name="OAuthResponseError"}code};async function _p(e,t){t?.throwIfAborted();let n,r,o=!1,i=new Promise((d,u)=>{n=d,r=u});i.catch(()=>{});let s=bp((d,u)=>{if((d.url?.length??0)>8192){u.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let y=d.url??"/";if(!y.startsWith("/callback")||y.startsWith("//")){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let v=new URL(y,"http://127.0.0.1");if(d.method!=="GET"||v.pathname!=="/callback"){u.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let x=v.searchParams.get("code")?.slice(0,2048)??"",b=v.searchParams.get("state")?.slice(0,256)??"",m=v.searchParams.get("error")?.slice(0,256)??void 0,A=v.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!b){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!Va(b,e)){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(o){u.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}o=!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>'),n({code:x,state:b,...m?{error:m}:{},...A?{errorDescription:A}:{}})});await new Promise((d,u)=>{s.once("error",u),s.listen(0,"127.0.0.1",()=>{s.removeListener("error",u),d()})});let a=s.address();if(!a||typeof a=="string")throw new h("Could not bind an Oracle sign-in callback port.",g.FAILURE);let c=setTimeout(()=>{o||(o=!0,r(new h("Oracle sign-in timed out before the browser returned.",g.FAILURE)))},Ap);c.unref();let l=()=>{o||(o=!0,r(t?.reason??new DOMException("Oracle sign-in cancelled.","AbortError"))),clearTimeout(c),s.closeAllConnections(),s.close()};return t?.addEventListener("abort",l,{once:!0}),t?.aborted&&l(),{redirectUri:`http://127.0.0.1:${a.port}/callback`,wait:()=>i,close:async()=>{t?.removeEventListener("abort",l),clearTimeout(c),s.listening&&(s.closeAllConnections(),await new Promise(d=>s.close(()=>d())))}}}function Va(e,t){let n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&vp(n,r)}function Xa(e){let t=e.split(/[\s+]+/).filter(Boolean);if(!t.every(jo))throw new h("OAuth server returned an unknown Oracle scope.",g.API_ERROR);let n=[...new Set(t)];if(!n.includes("read"))throw new h("Oracle OAuth grant is missing the required read scope.",g.API_ERROR);return n}function jo(e){return e==="read"||e==="write"||e==="approve"}function Qa(e){if(!e||typeof e.access_token!="string"||!e.access_token||typeof e.refresh_token!="string"||!e.refresh_token||typeof e.token_type!="string"||e.token_type.toLowerCase()!=="bearer"||typeof e.expires_in!="number"||!Number.isFinite(e.expires_in)||e.expires_in<=0||typeof e.scope!="string")throw new h("OAuth token response did not match the supported format.",g.API_ERROR)}async function Ip(e,t,n){return ec(e,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t),signal:n})}async function Za(e,t,n){return ec(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(Object.entries(t).map(([r,o])=>[r,String(o)])).toString(),signal:n})}async function ec(e,t){let n,r=AbortSignal.timeout(2e4);try{n=await fetch(e,{...t,redirect:"error",signal:t.signal?AbortSignal.any([t.signal,r]):r})}catch(i){throw t.signal?.throwIfAborted(),new h(`OAuth request failed: ${p(i instanceof Error?i.message:String(i))}`,g.FAILURE)}let o=null;try{o=await n.json()}catch{}if(t.signal?.throwIfAborted(),!n.ok){let i=o&&typeof o=="object"?o:{},s=typeof i.error=="string"?i.error:`http_${n.status}`,a=typeof i.error_description=="string"?p(i.error_description):s;throw new dr(s,a,n.status)}if(!o||typeof o!="object"||Array.isArray(o))throw new h(`OAuth endpoint returned invalid JSON (${n.status}).`,g.API_ERROR);return o}async function ur(e,t,n,r){let o=async i=>{let s=await fetch(e,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:t,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=p(c.error_description))}catch{}throw new h(`OAuth token revocation failed: ${a}`,g.API_ERROR)}};await o(r),n!==r&&await o(n)}var Bp=1048576,Wp=25*1048576;async function ac(e){let[t,...n]=e.positional,r=["exec","sessions","resume","login","logout","download","workspaces","use"].includes(t??""),o=bt(e.flags,"print");if(o!==void 0&&e.positional.length)throw new f("-p/--print takes the prompt as its value and cannot be combined with a subcommand or positional prompt.");let i=bt(e.flags,"workspace")?.trim()||void 0,s=r?void 0:e.positional.join(" ");if(z(e.flags,"read-only")&&(z(e.flags,"write")||z(e.flags,"approve")))throw new f("--read-only cannot be combined with --write or --approve.");if(!r&&o===void 0&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new f("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(t==="login"){if(n.length)throw new f("oracle login does not accept positional arguments.");let b=await vt({endpoint:e.endpointOverride??e.endpoint,write:z(e.flags,"write"),approve:z(e.flags,"approve"),...i?{workspace:i}:{}}),A=[z(e.flags,"write")?"write":void 0,z(e.flags,"approve")?"approve":void 0].filter(L=>!!L).filter(L=>!b.scopes.includes(L));process.stdout.write(`${tc(b)}
446
+ `)}let v=await i.wait();if(!bc(v.state,o))throw new h("Oracle sign-in callback state did not match; authorization was rejected.",g.API_ERROR);if(v.error)throw new h(`Oracle authorization failed: ${p(v.error)}${v.errorDescription?` (${p(v.errorDescription)})`:""}`,g.API_ERROR);if(!v.code)throw new h("Oracle authorization callback did not include a code.",g.API_ERROR);let x={client_id:a.client_id,grant_type:"authorization_code",code:v.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},b=await Ac(n.oauth.token,x,e.signal);Oc(b);let m=kc(b.scope);if(!m.includes("read")||m.some(V=>!r.includes(V)))throw await kr(n.oauth.revocation,a.client_id,b.access_token,b.refresh_token).catch(()=>{}),new h("The granted Oracle scopes are invalid for this request.",g.API_ERROR);let A=await wt(t,fetch,b.access_token,e.signal).then(V=>V.identity).catch(()=>{});e.signal?.throwIfAborted();let L={endpoint:t,...hc(A),clientId:a.client_id,redirectUri:i.redirectUri,accessToken:b.access_token,refreshToken:b.refresh_token,expiresAt:Date.now()+b.expires_in*1e3,scopes:m},D=await lr(V=>Da(V,L));return D&&await kr(n.oauth.revocation,D.clientId,D.accessToken,D.refreshToken).catch(()=>{}),L}finally{await i.close()}}function hc(e){return e?{companyId:e.companyId,...e.companyName?{companyName:e.companyName}:{},uid:e.uid}:{}}async function gc(e={}){if(e.workspace&&!e.all){let n=Cn(await ue(),e.endpointOverride);n&&await ti(n)}let t=await pr(async()=>{let n=await ue(),r=[];if(e.all)r=[...n.logins];else{let s=Cn(n,e.endpointOverride);e.workspace?r=[yt(s?Ge(n,s):[],e.workspace)]:s&&(r=[dr(n,s)].filter(a=>!!a))}let o=[],i;for(let s of r){try{await wc(s)}catch(a){o.push({login:s,error:a})}i=Do(n,s)??i}return await kn(n),{removed:r,failures:o,...i&&!e.all?{nowActive:i}:{}}});if(t.failures.length){let n=t.failures.map(({login:r,error:o})=>{let i=o instanceof Error?p(o.message):"unknown error";return t.failures.length>1||e.all?`${p(pe(r))}: ${i}`:i});throw new h(`Local Oracle credentials were cleared, but server revocation failed for ${t.failures.length===1?"one login":`${t.failures.length} logins`}: ${n.join("; ")}`,g.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire these access tokens automatically.")}return{removed:t.removed,...t.nowActive?{nowActive:t.nowActive}:{}}}async function wc(e){let t=await wt(e.endpoint);await kr(t.oauth.revocation,e.clientId,e.accessToken,e.refreshToken)}function Cn(e,t){let n=t||process.env.ANYFORGE_ENDPOINT;return n?et(n):e.endpoint}function yc(){return new f("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 Ar(e,t){let n=e||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN){if(t)throw yc();return mc(n)}let r=await ue(),o=Cn(r,n);if(t)return ze(await Yp(o,t));let i=o?dr(r,o):void 0;if(i)return ze(i);try{return await mc(n)}catch(s){throw r.logins.length&&n?new Ie:s instanceof Ie?new Ie:s}}async function Yp(e,t){if(!e)return yt([],t);let n=await xr(e);return yt(n,t)}function ze(e){return{endpoint:e.endpoint,accessToken:e.accessToken,scopes:e.scopes.filter(ni),source:"oauth",getAccessToken:async t=>Xp(e.endpoint,e.clientId,t),onIdentity:async t=>{if(e.companyId===t.companyId&&(t.companyName===void 0||e.companyName===t.companyName)&&e.uid===t.uid)return;let r=await lr(i=>Ba(i,e.endpoint,e.clientId,t));Object.assign(e,hc(t));let o=r.duplicate;o&&await wc(o).catch(()=>{})}}}async function xr(e){return await ti(e),Ge(await ue(),e)}async function ti(e){let t=Ge(await ue(),e).filter(n=>!n.companyId);for(let n of t)await new ke(ze(n)).config().catch(()=>{})}async function Zt(e){let t=Cn(await ue(),e);if(!t)return{logins:[]};let n=await xr(t),r=dr(await ue(),t);return{endpoint:t,logins:n,...r?{active:r}:{}}}async function vc(e,t){if(process.env.ANYFORGE_API_TOKEN)throw yc();let n=Cn(await ue(),e);return n&&await ti(n),lr(r=>{let o=yt(n?Ge(r,n):[],t);return r.active[o.endpoint]=o.clientId,r.endpoint=o.endpoint,o})}async function mc(e){let t=await Ne(e),r=(await un({apiKey:t.apiKey,endpoint:t.endpoint})).scopes.filter(ni);return{endpoint:t.endpoint,accessToken:t.apiKey,scopes:r,source:"control"}}async function Xp(e,t,n){let r=et(e),o=`${r}
447
+ ${t}`,i=vr.get(o);if(i)return i;let s=pr(()=>Qp(r,t,n));vr.set(o,s);try{return await s}finally{vr.get(o)===s&&vr.delete(o)}}async function Qp(e,t,n){let r=await ue(),o=r.logins.find(l=>l.endpoint===e&&l.clientId===t);if(!o)throw new Ie;if(o.expiresAt>Date.now()+Jp&&(!n||o.accessToken!==n))return o.accessToken;let i=async()=>{Do(r,o),await kn(r)},s=await wt(o.endpoint),a;try{let l={client_id:o.clientId,grant_type:"refresh_token",refresh_token:o.refreshToken,resource:s.resource};a=await Ac(s.oauth.token,l)}catch(l){throw l instanceof br&&["invalid_grant","invalid_client","invalid_target"].includes(l.code)?(await i(),new Ie):l}Oc(a);let c;try{c=kc(a.scope)}catch(l){throw await i(),l}if(c.some(l=>!o.scopes.includes(l)))throw await kr(s.oauth.revocation,o.clientId,a.access_token,a.refresh_token),await i(),new h("Oracle refresh attempted to widen the saved grant; credentials were cleared.",g.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 kn(r),o.accessToken}var br=class extends h{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?g.NO_CREDENTIALS:g.API_ERROR);this.code=n;this.name="OAuthResponseError"}code};async function Zp(e,t){t?.throwIfAborted();let n,r,o=!1,i=new Promise((d,u)=>{n=d,r=u});i.catch(()=>{});let s=zp((d,u)=>{if((d.url?.length??0)>8192){u.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let w=d.url??"/";if(!w.startsWith("/callback")||w.startsWith("//")){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let v=new URL(w,"http://127.0.0.1");if(d.method!=="GET"||v.pathname!=="/callback"){u.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let x=v.searchParams.get("code")?.slice(0,2048)??"",b=v.searchParams.get("state")?.slice(0,256)??"",m=v.searchParams.get("error")?.slice(0,256)??void 0,A=v.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!b){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!bc(b,e)){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(o){u.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}o=!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>'),n({code:x,state:b,...m?{error:m}:{},...A?{errorDescription:A}:{}})});await new Promise((d,u)=>{s.once("error",u),s.listen(0,"127.0.0.1",()=>{s.removeListener("error",u),d()})});let a=s.address();if(!a||typeof a=="string")throw new h("Could not bind an Oracle sign-in callback port.",g.FAILURE);let c=setTimeout(()=>{o||(o=!0,r(new h("Oracle sign-in timed out before the browser returned.",g.FAILURE)))},Vp);c.unref();let l=()=>{o||(o=!0,r(t?.reason??new DOMException("Oracle sign-in cancelled.","AbortError"))),clearTimeout(c),s.closeAllConnections(),s.close()};return t?.addEventListener("abort",l,{once:!0}),t?.aborted&&l(),{redirectUri:`http://127.0.0.1:${a.port}/callback`,wait:()=>i,close:async()=>{t?.removeEventListener("abort",l),clearTimeout(c),s.listening&&(s.closeAllConnections(),await new Promise(d=>s.close(()=>d())))}}}function bc(e,t){let n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&Hp(n,r)}function kc(e){let t=e.split(/[\s+]+/).filter(Boolean);if(!t.every(ni))throw new h("OAuth server returned an unknown Oracle scope.",g.API_ERROR);let n=[...new Set(t)];if(!n.includes("read"))throw new h("Oracle OAuth grant is missing the required read scope.",g.API_ERROR);return n}function ni(e){return e==="read"||e==="write"||e==="approve"}function Oc(e){if(!e||typeof e.access_token!="string"||!e.access_token||typeof e.refresh_token!="string"||!e.refresh_token||typeof e.token_type!="string"||e.token_type.toLowerCase()!=="bearer"||typeof e.expires_in!="number"||!Number.isFinite(e.expires_in)||e.expires_in<=0||typeof e.scope!="string")throw new h("OAuth token response did not match the supported format.",g.API_ERROR)}async function ef(e,t,n){return xc(e,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t),signal:n})}async function Ac(e,t,n){return xc(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(Object.entries(t).map(([r,o])=>[r,String(o)])).toString(),signal:n})}async function xc(e,t){let n,r=AbortSignal.timeout(2e4);try{n=await fetch(e,{...t,redirect:"error",signal:t.signal?AbortSignal.any([t.signal,r]):r})}catch(i){throw t.signal?.throwIfAborted(),new h(`OAuth request failed: ${p(i instanceof Error?i.message:String(i))}`,g.FAILURE)}let o=null;try{o=await n.json()}catch{}if(t.signal?.throwIfAborted(),!n.ok){let i=o&&typeof o=="object"?o:{},s=typeof i.error=="string"?i.error:`http_${n.status}`,a=typeof i.error_description=="string"?p(i.error_description):s;throw new br(s,a,n.status)}if(!o||typeof o!="object"||Array.isArray(o))throw new h(`OAuth endpoint returned invalid JSON (${n.status}).`,g.API_ERROR);return o}async function kr(e,t,n,r){let o=async i=>{let s=await fetch(e,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:t,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=p(c.error_description))}catch{}throw new h(`OAuth token revocation failed: ${a}`,g.API_ERROR)}};await o(r),n!==r&&await o(n)}var hf=1048576,gf=25*1048576;async function Tc(e){let[t,...n]=e.positional,r=["exec","sessions","resume","login","logout","download","workspaces","use"].includes(t??""),o=xt(e.flags,"print");if(o!==void 0&&e.positional.length)throw new f("-p/--print takes the prompt as its value and cannot be combined with a subcommand or positional prompt.");let i=xt(e.flags,"workspace")?.trim()||void 0,s=r?void 0:e.positional.join(" ");if(J(e.flags,"read-only")&&(J(e.flags,"write")||J(e.flags,"approve")))throw new f("--read-only cannot be combined with --write or --approve.");if(!r&&o===void 0&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new f("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(t==="login"){if(n.length)throw new f("oracle login does not accept positional arguments.");let b=await At({endpoint:e.endpointOverride??e.endpoint,write:J(e.flags,"write"),approve:J(e.flags,"approve"),...i?{workspace:i}:{}}),A=[J(e.flags,"write")?"write":void 0,J(e.flags,"approve")?"approve":void 0].filter(L=>!!L).filter(L=>!b.scopes.includes(L));process.stdout.write(`${_c(b)}
446
448
  `),A.length&&process.stderr.write(`This account was granted read only; the server withheld: ${A.join(", ")}.
447
- `),await Hp(b,i);return}if(t==="logout"){if(n.length)throw new f("oracle logout does not accept positional arguments.");let b=z(e.flags,"all");if(b&&i)throw new f("Choose either --workspace or --all.");let m=await za({...e.endpointOverride?{endpointOverride:e.endpointOverride}:{},...i?{workspace:i}:{},all:b});if(!m.removed.length){process.stdout.write(`No saved Oracle login.
448
- `);return}let A=m.removed.map(L=>p(de(L))).join(", ");process.stdout.write(`Logged out of ${A}; ${m.removed.length===1?"its access was":"their access was"} revoked.
449
- `),m.nowActive&&process.stdout.write(`Active workspace is now ${p(de(m.nowActive))}.
450
- `);return}if(t==="workspaces"){if(n.length)throw new f("oracle workspaces does not accept positional arguments.");await Kp(e.endpointOverride,e.flags.json===!0);return}if(t==="use"){let b=n.join(" ").trim();if(!b)throw new f("oracle use needs a workspace name or id.","Run `anyforge oracle workspaces` to list your saved workspaces.");let m=await Ya(e.endpointOverride,b);process.stdout.write(`Now using ${p(de(m))} (${m.scopes.join(", ")}) at ${m.endpoint}.
451
- `);return}let a;try{a=await oc(e.endpointOverride,i)}catch(b){if(!r&&o===void 0&&b instanceof h&&b.exitCode===g.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let m=(await import("prompts")).default;if((await m({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw b;let L=await vt({endpoint:e.endpointOverride??e.endpoint,...i?{workspace:i}:{}});process.stderr.write(`${tc(L)}
452
- `),a=await oc(e.endpointOverride)}else throw b}if(t==="sessions"){if(n.length)throw new f("oracle sessions does not accept positional arguments.");let b=e.flags.json===!0;b||await nc(await a.config().catch(()=>{}));let m=await a.listSessions();Yp(m,b);return}if(t==="download"){await Zp(a,n,e.flags);return}if(t==="exec"||o!==void 0){if(z(e.flags,"write")||z(e.flags,"approve"))throw new f("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(e.flags.json===!0&&z(e.flags,"stream-json"))throw new f("Choose either --json or --stream-json.");let b=await Jp(o??n.join(" ")),m=await a.config();Do(a,m),e.flags.json!==!0&&!z(e.flags,"stream-json")&&await nc(m),ic(bt(e.flags,"context"));let A=Oo(e.flags),L=await a.createSession(Ht(A,!1));await bn(L.sessionId,a.endpoint,m.identity?.companyId);let j=await rr(a,L.sessionId,rc(e.flags),(Ie,kt)=>ae(process.stderr,`Uploading explicit attachment ${Ie} (${J(kt)}).
453
- `)),K={requestId:Tp(),text:b,readOnly:!0,...A?{context:A}:{},...bt(e.flags,"context")?{contextText:bt(e.flags,"context")}:{},...j.length?{attachments:j.map(Ie=>({fileId:Ie.fileId}))}:{}};await Xp(a,L.sessionId,K,{json:e.flags.json===!0,streamJson:z(e.flags,"stream-json"),config:m});return}if(t==="resume"&&n.length>1)throw new f("oracle resume accepts at most one session id.");if(t==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new f("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 c=await a.config();Do(a,c);let l=Oo(e.flags),d=bt(e.flags,"context");ic(d);let u=z(e.flags,"shared"),y=z(e.flags,"write")||z(e.flags,"approve");if(y&&(!a.scopes.has("write")||c.capabilities?.write!==!0))throw new h("This Oracle grant or current workspace role does not allow write actions.",g.API_ERROR);if(z(e.flags,"approve")&&(!a.scopes.has("approve")||c.capabilities?.approve!==!0))throw new h("This Oracle grant or current workspace role does not allow approval actions.",g.API_ERROR);if(u&&(!l||l.kind!=="program"&&l.kind!=="initiative"))throw new f("--shared requires --program or --initiative.");let v;if(t==="resume"){let m=(n[0]||void 0)??await Vp(await a.listSessions(),await tr(a.endpoint,c.identity?.companyId));v=await a.getSession(m)}else v=await a.createSession(Ht(l,u));await bn(v.sessionId,a.endpoint,c.identity?.companyId);let x=await Promise.resolve().then(()=>(gr(),hr));await Ba({version:x.default.version,client:a,config:c,session:v,initialPrompt:s,initialContext:l,contextText:d,shared:u,canWrite:y,canApprove:z(e.flags,"approve"),initialFiles:rc(e.flags),...a.source==="oauth"?{workspaces:Gp(a.endpoint)}:{}})}function Gp(e){return{list:()=>mr(e),connect:async t=>{let n=new we(Be(t)),r=await n.config();return Do(n,r),{client:n,config:r}}}}function tc(e){let t=e.scopes.join(", ");return e.companyId?`Connected to ${p(de(e))} (${t}) at ${e.endpoint}.`:`Connected to ${e.endpoint} (${t}). The server did not say which workspace; \`anyforge oracle workspaces\` shows it once it does.`}async function Hp(e,t){let n=p(de(e));t&&e.companyId&&!zp(e,t)&&process.stderr.write(`You asked for "${p(t)}", but ${n} was chosen on the consent page, so this login is for ${n}.
454
- `);let r=Ue(await le(),e.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>\`.
455
- `)}function zp(e,t){return e.companyId===t||e.companyName?.toLowerCase()===t.toLowerCase()}async function nc(e){let t=Qe(e?.identity);t&&await ae(process.stderr,`${We(`Workspace: ${t}`)}
456
- `)}async function Kp(e,t){let n=await Vt(e),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(t)process.stdout.write(`${JSON.stringify(r,null,2)}
457
- `);else if(!r.length)process.stdout.write("No saved Oracle logins. Run `anyforge oracle login` to add one.\n");else{process.stdout.write(`${We(`Oracle workspaces saved for ${n.endpoint??"this endpoint"}:`)}
458
- `);for(let o of n.logins){let i=o.clientId===n.active?.clientId,s=p(de(o)),a=o.companyId&&o.companyName?p(o.companyId):"",c=[i?Wo(`* ${s}`):` ${s}`,a?We(a):"",We(o.scopes.join(", ")),i?sc("active"):""];process.stdout.write(`${c.filter(Boolean).join(" ")}
449
+ `),await yf(b,i);return}if(t==="logout"){if(n.length)throw new f("oracle logout does not accept positional arguments.");let b=J(e.flags,"all");if(b&&i)throw new f("Choose either --workspace or --all.");let m=await gc({...e.endpointOverride?{endpointOverride:e.endpointOverride}:{},...i?{workspace:i}:{},all:b});if(!m.removed.length){process.stdout.write(`No saved Oracle login.
450
+ `);return}let A=m.removed.map(L=>p(pe(L))).join(", ");process.stdout.write(`Logged out of ${A}; ${m.removed.length===1?"its access was":"their access was"} revoked.
451
+ `),m.nowActive&&process.stdout.write(`Active workspace is now ${p(pe(m.nowActive))}.
452
+ `);return}if(t==="workspaces"){if(n.length)throw new f("oracle workspaces does not accept positional arguments.");await bf(e.endpointOverride,e.flags.json===!0);return}if(t==="use"){let b=n.join(" ").trim();if(!b)throw new f("oracle use needs a workspace name or id.","Run `anyforge oracle workspaces` to list your saved workspaces.");let m=await vc(e.endpointOverride,b);process.stdout.write(`Now using ${p(pe(m))} (${m.scopes.join(", ")}) at ${m.endpoint}.
453
+ `);return}let a;try{a=await Ic(e.endpointOverride,i)}catch(b){if(!r&&o===void 0&&b instanceof h&&b.exitCode===g.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let m=(await import("prompts")).default;if((await m({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw b;let L=await At({endpoint:e.endpointOverride??e.endpoint,...i?{workspace:i}:{}});process.stderr.write(`${_c(L)}
454
+ `),a=await Ic(e.endpointOverride)}else throw b}if(t==="sessions"){if(n.length)throw new f("oracle sessions does not accept positional arguments.");let b=e.flags.json===!0;b||await Sc(await a.config().catch(()=>{}));let m=await a.listSessions();Of(m,b);return}if(t==="download"){await Sf(a,n,e.flags);return}if(t==="exec"||o!==void 0){if(J(e.flags,"write")||J(e.flags,"approve"))throw new f("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(e.flags.json===!0&&J(e.flags,"stream-json"))throw new f("Choose either --json or --stream-json.");let b=await kf(o??n.join(" ")),m=await a.config();ri(a,m),e.flags.json!==!0&&!J(e.flags,"stream-json")&&await Sc(m),Cc(xt(e.flags,"context"));let A=qo(e.flags),L=await a.createSession(Jt(A,!1));await xn(L.sessionId,a.endpoint,m.identity?.companyId);let D=await fr(a,L.sessionId,Rc(e.flags),(Te,_t)=>le(process.stderr,`Uploading explicit attachment ${Te} (${Y(_t)}).
455
+ `)),V={requestId:rf(),text:b,readOnly:!0,...A?{context:A}:{},...xt(e.flags,"context")?{contextText:xt(e.flags,"context")}:{},...D.length?{attachments:D.map(Te=>({fileId:Te.fileId}))}:{}};await xf(a,L.sessionId,V,{json:e.flags.json===!0,streamJson:J(e.flags,"stream-json"),config:m});return}if(t==="resume"&&n.length>1)throw new f("oracle resume accepts at most one session id.");if(t==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new f("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 c=await a.config();ri(a,c);let l=qo(e.flags),d=xt(e.flags,"context");Cc(d);let u=J(e.flags,"shared"),w=J(e.flags,"write")||J(e.flags,"approve");if(w&&(!a.scopes.has("write")||c.capabilities?.write!==!0))throw new h("This Oracle grant or current workspace role does not allow write actions.",g.API_ERROR);if(J(e.flags,"approve")&&(!a.scopes.has("approve")||c.capabilities?.approve!==!0))throw new h("This Oracle grant or current workspace role does not allow approval actions.",g.API_ERROR);if(u&&(!l||l.kind!=="program"&&l.kind!=="initiative"))throw new f("--shared requires --program or --initiative.");let v;if(t==="resume"){let m=(n[0]||void 0)??await Af(await a.listSessions(),await ur(a.endpoint,c.identity?.companyId));v=await a.getSession(m)}else v=await a.createSession(Jt(l,u));await xn(v.sessionId,a.endpoint,c.identity?.companyId);let x=await Promise.resolve().then(()=>(Sr(),_r));await pc({version:x.default.version,client:a,config:c,session:v,initialPrompt:s,initialContext:l,contextText:d,shared:u,canWrite:w,canApprove:J(e.flags,"approve"),initialFiles:Rc(e.flags),...a.source==="oauth"?{workspaces:wf(a.endpoint)}:{}})}function wf(e){return{list:()=>xr(e),connect:async t=>{let n=new ke(ze(t)),r=await n.config();return ri(n,r),{client:n,config:r}}}}function _c(e){let t=e.scopes.join(", ");return e.companyId?`Connected to ${p(pe(e))} (${t}) at ${e.endpoint}.`:`Connected to ${e.endpoint} (${t}). The server did not say which workspace; \`anyforge oracle workspaces\` shows it once it does.`}async function yf(e,t){let n=p(pe(e));t&&e.companyId&&!vf(e,t)&&process.stderr.write(`You asked for "${p(t)}", but ${n} was chosen on the consent page, so this login is for ${n}.
456
+ `);let r=Ge(await ue(),e.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>\`.
457
+ `)}function vf(e,t){return e.companyId===t||e.companyName?.toLowerCase()===t.toLowerCase()}async function Sc(e){let t=nt(e?.identity);t&&await le(process.stderr,`${Ke(`Workspace: ${t}`)}
458
+ `)}async function bf(e,t){let n=await Zt(e),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(t)process.stdout.write(`${JSON.stringify(r,null,2)}
459
+ `);else if(!r.length)process.stdout.write("No saved Oracle logins. Run `anyforge oracle login` to add one.\n");else{process.stdout.write(`${Ke(`Oracle workspaces saved for ${n.endpoint??"this endpoint"}:`)}
460
+ `);for(let o of n.logins){let i=o.clientId===n.active?.clientId,s=p(pe(o)),a=o.companyId&&o.companyName?p(o.companyId):"",c=[i?ii(`* ${s}`):` ${s}`,a?Ke(a):"",Ke(o.scopes.join(", ")),i?Ec("active"):""];process.stdout.write(`${c.filter(Boolean).join(" ")}
459
461
  `)}}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.
460
- `)}function z(e,t){return e[t]===!0}function bt(e,t){let n=e[t];return typeof n=="string"?n:void 0}function rc(e){let t=e.file;return typeof t=="string"?[t]:Array.isArray(t)?t:[]}async function oc(e,t){try{return new we(await fr(e,t))}catch(n){throw n instanceof h&&n.exitCode===g.NO_CREDENTIALS?new h("Not authenticated for the hosted Oracle.",g.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):n}}function Do(e,t){if(!e.scopes.has("read")||t.capabilities?.read===!1)throw new h("This credential does not have Oracle read access.",g.API_ERROR)}function ic(e){if(e&&Buffer.byteLength(e,"utf8")>Ro)throw new f(`--context must be ${Ro/1024} KiB or less.`)}async function Jp(e){let t=e.trim();if(process.stdin.isTTY){if(t)return t;throw new f("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>Bp)throw new f("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!t&&!o)throw new f("oracle exec needs a prompt in argv or piped stdin.");return[t,o].filter(Boolean).join(`
462
+ `)}function J(e,t){return e[t]===!0}function xt(e,t){let n=e[t];return typeof n=="string"?n:void 0}function Rc(e){let t=e.file;return typeof t=="string"?[t]:Array.isArray(t)?t:[]}async function Ic(e,t){try{return new ke(await Ar(e,t))}catch(n){throw n instanceof h&&n.exitCode===g.NO_CREDENTIALS?new h("Not authenticated for the hosted Oracle.",g.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):n}}function ri(e,t){if(!e.scopes.has("read")||t.capabilities?.read===!1)throw new h("This credential does not have Oracle read access.",g.API_ERROR)}function Cc(e){if(e&&Buffer.byteLength(e,"utf8")>Bo)throw new f(`--context must be ${Bo/1024} KiB or less.`)}async function kf(e){let t=e.trim();if(process.stdin.isTTY){if(t)return t;throw new f("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>hf)throw new f("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!t&&!o)throw new f("oracle exec needs a prompt in argv or piped stdin.");return[t,o].filter(Boolean).join(`
461
463
 
462
- `)}function Yp(e,t){if(t){process.stdout.write(`${JSON.stringify(e,null,2)}
464
+ `)}function Of(e,t){if(t){process.stdout.write(`${JSON.stringify(e,null,2)}
463
465
  `);return}if(!e.length){process.stdout.write(`No Oracle sessions are available.
464
- `);return}for(let n of e){let r=Fe(n);process.stdout.write(`${Wo(n.sessionId)} ${p(n.title)} ${We(r)}
465
- `)}}async function Vp(e,t){if(!e.length)throw new h("No accessible Oracle sessions are available.",g.API_ERROR);return new Promise((n,r)=>{let o=new Mp,i=new Dp(o),s=new jp(Wo("Resume an Oracle session")),a=new Up(e.map(u=>({value:u.sessionId,label:u.title,description:Fe(u)})),12,Mt),c=t?e.findIndex(u=>u.sessionId===t):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=u=>{d(),n(u.value)},a.onCancel=()=>{d(),r(new h("Session selection cancelled.",g.FAILURE))};let l=()=>{d(),r(new h("Session selection interrupted.",g.INTERRUPTED))},d=()=>{process.off("SIGINT",l),i.stop()};process.once("SIGINT",l),i.start()})}async function ae(e,t){e.write(t)||await new Promise(n=>e.once("drain",n))}async function Xp(e,t,n,r){let o=new je,i=!1,s,a=new AbortController,c=()=>s??=l(),l=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let A=await e.cancelTurn(t,o.streamId);await ae(process.stderr,`${Gt(A)}
466
- `)}catch(A){await ae(process.stderr,`Could not confirm server cancellation: ${Y(A)}
467
- `)}else try{let A=await e.cancelRequest(t,n.requestId);await ae(process.stderr,`${Gt(A)}
468
- `)}catch(A){await ae(process.stderr,`Could not confirm server cancellation by request id: ${Y(A)}
469
- `)}},d=()=>{c().catch(()=>{})};process.on("SIGINT",d);let u=async A=>ae(process.stdout,`${JSON.stringify(Le(A))}
470
- `),y=new Bo(t),v=-1,x=async A=>{if(r.streamJson){if(A.idx<=v)return;A.type!=="finalizing"&&(v=A.idx),await u({...A,sessionId:t})}else await y.emit(A)},b;try{b=await Wt(e,t,n,{onEvent:x},a.signal,o)}catch(A){if(!i)throw process.off("SIGINT",d),A;b=o.outcome()}finally{process.off("SIGINT",d),s&&await s}let m=yn(t,b);return r.streamJson?await u({protocolVersion:1,type:"result",result:m}):r.json?await ae(process.stdout,`${JSON.stringify(m,null,2)}
471
- `):(m.answer&&await ae(process.stdout,`${qi(m.answer,e.endpoint)}
472
- `),m.status==="awaiting_input"&&await ae(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
473
- `),m.status==="interrupted"&&await ae(process.stderr,`Oracle turn ended without a complete final answer.
474
- `),m.status==="error"&&m.error&&await ae(process.stderr,`Oracle error: ${p(m.error)}
475
- `),(m.servedBy||m.usage||m.rounds!==void 0)&&await ae(process.stderr,Qp(m.servedBy,m.usage,m.rounds))),i?process.exitCode=130:m.status==="error"?process.exitCode=g.API_ERROR:m.status==="interrupted"&&(process.exitCode=g.FAILURE),m}var Bo=class{constructor(t){this.sessionId=t}sessionId;labels=new Map;announced=new Set;async emit(t){let n=this.describe(t);n&&await ae(process.stderr,`${n}
476
- `)}describe(t){switch(t.type){case"tool_call":{if(Lt(t.name))return"";let n=P(typeof t.label=="string"?t.label:Pt(P(t.name,240)),120),r=typeof t.id=="string"?t.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${We(typeof t.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${sc(n)}`}case"tool_result":{if(t.ok!==!1)return"";let n=typeof t.toolUseId=="string"?this.labels.get(t.toolUseId):void 0;return wr(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return wr(`Warning: ${P(t.message,500)}`);case"navigator_file_error":return wr(`Could not generate ${P(t.filename,200)}: ${P(t.error,500)}`);case"navigator_file_created":{let n=Xe(t.file);return We(`Generated ${n.filename} (${J(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=P(t.from,120),r=P(t.to,120);return We(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(t.notices)?t.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${wr("Attachment")} ${P(r.name,160)}: ${P(r.message,500)}`}).join(`
477
- `):"";default:return""}}};function Qp(e,t,n){let r=[];if(e&&typeof e=="object"){let o=e,i=On(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(P(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${P(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(P(o.provider,100))}return t?.inputTokens!==void 0||t?.outputTokens!==void 0?r.push(`${t.inputTokens??0} in${t.cachedInputTokens?` (${t.cachedInputTokens} cached)`:""} / ${t.outputTokens??0} out tokens`):t?.totalTokens!==void 0&&r.push(`${t.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${We(r.join(" \xB7 "))}
478
- `:""}async function Zp(e,t,n){if(t.length!==2)throw new f("oracle download needs exactly a session id and file id.");let[r,o]=t;if(!r||!o)throw new f("oracle download needs a session id and file id.");let i=bt(n,"output");if(!i)throw new f("oracle download requires --output <existing-directory>.");let s=qp(i),a=await Pp(s);if(!(await Lp(a)).isDirectory())throw new f("--output must point to an existing directory.");let l=await e.download(r,o),d=tf(ef(l.headers.get("content-disposition"))),u=Fp(a,d),y=await nf(l,Wp),v;try{v=await $p(u,"wx",384),await v.writeFile(y)}catch(x){throw x.code==="EEXIST"?new h(`Refusing to overwrite ${u}.`,g.FAILURE):x}finally{await v?.close()}process.stdout.write(`Downloaded ${p(d)} to ${p(u)} (${J(y.byteLength)}).
479
- `)}function ef(e){if(!e)return"oracle-file.bin";let t=/filename\*=UTF-8''([^;]+)/i.exec(e)?.[1];if(t)try{return decodeURIComponent(t.replace(/^"|"$/g,""))}catch{return"oracle-file.bin"}let n=/filename="?([^";]+)"?/i.exec(e)?.[1];return n?n.trim():"oracle-file.bin"}function tf(e){let t=Np(e.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!t||t==="."||t===".."?"oracle-file.bin":t}async function nf(e,t){if(!e.body)return Buffer.alloc(0);let n=e.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>t)throw new h(`Oracle download exceeds the ${J(t)} limit.`,g.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)}import{Readable as pf,Writable as ff}from"node:stream";import{ndJsonStream as mf}from"@agentclientprotocol/sdk";import{randomUUID as rf}from"node:crypto";import{isAbsolute as of}from"node:path";import{setTimeout as sf}from"node:timers/promises";import{agent as af,RequestError as U}from"@agentclientprotocol/sdk";import{RequestError as yr}from"@agentclientprotocol/sdk";var cc=65536;function lc(e){if(e.length>100)throw yr.invalidParams(void 0,"At most 100 prompt blocks are supported.");let n=e.map(r=>{if(r.type==="text")return r.text;if(r.type==="resource_link")return`[Untrusted resource reference; content has not been read]
480
- ${JSON.stringify({name:r.name,uri:r.uri,description:r.description})}`;throw yr.invalidParams(void 0,"Hosted Oracle accepts text and resource references only. Paste file contents as text; local files, embedded resources, images and audio are unsupported.")}).join(`
481
- `);if(!n.trim()||Buffer.byteLength(n,"utf8")>cc)throw yr.invalidParams(void 0,`Prompt must contain text and fit within ${cc} UTF-8 bytes.`);return n}function ce(){throw yr.invalidParams(void 0,"Answer must match the pending question and its option ids. Use the displayed /answer JSON or /skip command; ordinary prose cannot confirm actions.")}function Go(e,t){if(!t||typeof t!="object"||Array.isArray(t))return ce();let n=t;if(n.questionId!==e.id||Object.keys(n).some(i=>!["questionId","answers","skipped"].includes(i)))return ce();if(n.skipped===!0)return!e.optional||!Array.isArray(n.answers)||n.answers.length?ce():{questionId:e.id,answers:[],skipped:!0};if(n.skipped!==void 0||!Array.isArray(n.answers)||n.answers.length!==e.questions.length)return ce();let r=new Set,o=n.answers.map(i=>{if(!i||typeof i!="object"||Array.isArray(i))return ce();let s=i;if(Object.keys(s).some(l=>!["questionId","optionIds","customText"].includes(l)))return ce();let a=e.questions.find(l=>l.id===s.questionId);if(!a||r.has(a.id)||!Array.isArray(s.optionIds))return ce();r.add(a.id);let c=s.optionIds;return c.some(l=>typeof l!="string"||!a.options.some(d=>d.id===l))||new Set(c).size!==c.length||!a.multiSelect&&c.length>1||s.customText!==void 0&&(typeof s.customText!="string"||!s.customText.trim()||Buffer.byteLength(s.customText)>8192)||!c.length&&s.customText===void 0?ce():{questionId:a.id,optionIds:c,...typeof s.customText=="string"?{customText:s.customText}:{}}});return{questionId:e.id,answers:o}}function dc(e,t){if(t===`/skip ${e.id}`)return Go(e,{questionId:e.id,answers:[],skipped:!0});if(!t.startsWith("/answer "))return ce();let n;try{n=JSON.parse(t.slice(8))}catch{return ce()}return Go(e,n)}function Xt(e){let t=e.questions.map(r=>`${r.header}: ${r.question}
466
+ `);return}for(let n of e){let r=je(n);process.stdout.write(`${ii(n.sessionId)} ${p(n.title)} ${Ke(r)}
467
+ `)}}async function Af(e,t){if(!e.length)throw new h("No accessible Oracle sessions are available.",g.API_ERROR);return new Promise((n,r)=>{let o=new uf,i=new mf(o),s=new ff(ii("Resume an Oracle session")),a=new pf(e.map(u=>({value:u.sessionId,label:u.title,description:je(u)})),12,Dt),c=t?e.findIndex(u=>u.sessionId===t):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=u=>{d(),n(u.value)},a.onCancel=()=>{d(),r(new h("Session selection cancelled.",g.FAILURE))};let l=()=>{d(),r(new h("Session selection interrupted.",g.INTERRUPTED))},d=()=>{process.off("SIGINT",l),i.stop()};process.once("SIGINT",l),i.start()})}async function le(e,t){e.write(t)||await new Promise(n=>e.once("drain",n))}async function xf(e,t,n,r){let o=new We,i=!1,s,a=new AbortController,c=()=>s??=l(),l=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let A=await e.cancelTurn(t,o.streamId);await le(process.stderr,`${Kt(A)}
468
+ `)}catch(A){await le(process.stderr,`Could not confirm server cancellation: ${X(A)}
469
+ `)}else try{let A=await e.cancelRequest(t,n.requestId);await le(process.stderr,`${Kt(A)}
470
+ `)}catch(A){await le(process.stderr,`Could not confirm server cancellation by request id: ${X(A)}
471
+ `)}},d=()=>{c().catch(()=>{})};process.on("SIGINT",d);let u=async A=>le(process.stdout,`${JSON.stringify(Ue(A))}
472
+ `),w=new oi(t),v=-1,x=async A=>{if(r.streamJson){if(A.idx<=v)return;A.type!=="finalizing"&&(v=A.idx),await u({...A,sessionId:t})}else await w.emit(A)},b;try{b=await zt(e,t,n,{onEvent:x},a.signal,o)}catch(A){if(!i)throw process.off("SIGINT",d),A;b=o.outcome()}finally{process.off("SIGINT",d),s&&await s}let m=On(t,b);return r.streamJson?await u({protocolVersion:1,type:"result",result:m}):r.json?await le(process.stdout,`${JSON.stringify(m,null,2)}
473
+ `):(m.answer&&await le(process.stdout,`${Ts(m.answer,e.endpoint)}
474
+ `),m.status==="awaiting_input"&&await le(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
475
+ `),m.status==="interrupted"&&await le(process.stderr,`Oracle turn ended without a complete final answer.
476
+ `),m.status==="error"&&m.error&&await le(process.stderr,`Oracle error: ${p(m.error)}
477
+ `),(m.servedBy||m.usage||m.rounds!==void 0)&&await le(process.stderr,_f(m.servedBy,m.usage,m.rounds))),i?process.exitCode=130:m.status==="error"?process.exitCode=g.API_ERROR:m.status==="interrupted"&&(process.exitCode=g.FAILURE),m}var oi=class{constructor(t){this.sessionId=t}sessionId;labels=new Map;announced=new Set;async emit(t){let n=this.describe(t);n&&await le(process.stderr,`${n}
478
+ `)}describe(t){switch(t.type){case"tool_call":{if(Mt(t.name))return"";let n=P(typeof t.label=="string"?t.label:Ft(P(t.name,240)),120),r=typeof t.id=="string"?t.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${Ke(typeof t.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${Ec(n)}`}case"tool_result":{if(t.ok!==!1)return"";let n=typeof t.toolUseId=="string"?this.labels.get(t.toolUseId):void 0;return Rr(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return Rr(`Warning: ${P(t.message,500)}`);case"navigator_file_error":return Rr(`Could not generate ${P(t.filename,200)}: ${P(t.error,500)}`);case"navigator_file_created":{let n=tt(t.file);return Ke(`Generated ${n.filename} (${Y(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=P(t.from,120),r=P(t.to,120);return Ke(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(t.notices)?t.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${Rr("Attachment")} ${P(r.name,160)}: ${P(r.message,500)}`}).join(`
479
+ `):"";default:return""}}};function _f(e,t,n){let r=[];if(e&&typeof e=="object"){let o=e,i=Sn(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(P(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${P(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(P(o.provider,100))}return t?.inputTokens!==void 0||t?.outputTokens!==void 0?r.push(`${t.inputTokens??0} in${t.cachedInputTokens?` (${t.cachedInputTokens} cached)`:""} / ${t.outputTokens??0} out tokens`):t?.totalTokens!==void 0&&r.push(`${t.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${Ke(r.join(" \xB7 "))}
480
+ `:""}async function Sf(e,t,n){if(t.length!==2)throw new f("oracle download needs exactly a session id and file id.");let[r,o]=t;if(!r||!o)throw new f("oracle download needs a session id and file id.");let i=xt(n,"output");if(!i)throw new f("oracle download requires --output <existing-directory>.");let s=df(i),a=await sf(s);if(!(await af(a)).isDirectory())throw new f("--output must point to an existing directory.");let l=await e.download(r,o),d=If(Rf(l.headers.get("content-disposition"))),u=lf(a,d),w=await Cf(l,gf),v;try{v=await of(u,"wx",384),await v.writeFile(w)}catch(x){throw x.code==="EEXIST"?new h(`Refusing to overwrite ${u}.`,g.FAILURE):x}finally{await v?.close()}process.stdout.write(`Downloaded ${p(d)} to ${p(u)} (${Y(w.byteLength)}).
481
+ `)}function Rf(e){if(!e)return"oracle-file.bin";let t=/filename\*=UTF-8''([^;]+)/i.exec(e)?.[1];if(t)try{return decodeURIComponent(t.replace(/^"|"$/g,""))}catch{return"oracle-file.bin"}let n=/filename="?([^";]+)"?/i.exec(e)?.[1];return n?n.trim():"oracle-file.bin"}function If(e){let t=cf(e.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!t||t==="."||t===".."?"oracle-file.bin":t}async function Cf(e,t){if(!e.body)return Buffer.alloc(0);let n=e.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>t)throw new h(`Oracle download exceeds the ${Y(t)} limit.`,g.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)}q();import{Readable as qf,Writable as Uf}from"node:stream";import{ndJsonStream as jf}from"@agentclientprotocol/sdk";import{randomUUID as Ef}from"node:crypto";import{isAbsolute as Tf}from"node:path";import{setTimeout as $f}from"node:timers/promises";import{agent as Pf,RequestError as j}from"@agentclientprotocol/sdk";q();import{RequestError as Ir}from"@agentclientprotocol/sdk";var $c=65536;function Pc(e){if(e.length>100)throw Ir.invalidParams(void 0,"At most 100 prompt blocks are supported.");let n=e.map(r=>{if(r.type==="text")return r.text;if(r.type==="resource_link")return`[Untrusted resource reference; content has not been read]
482
+ ${JSON.stringify({name:r.name,uri:r.uri,description:r.description})}`;throw Ir.invalidParams(void 0,"Hosted Oracle accepts text and resource references only. Paste file contents as text; local files, embedded resources, images and audio are unsupported.")}).join(`
483
+ `);if(!n.trim()||Buffer.byteLength(n,"utf8")>$c)throw Ir.invalidParams(void 0,`Prompt must contain text and fit within ${$c} UTF-8 bytes.`);return n}function de(){throw Ir.invalidParams(void 0,"Answer must match the pending question and its option ids. Use the displayed /answer JSON or /skip command; ordinary prose cannot confirm actions.")}function si(e,t){if(!t||typeof t!="object"||Array.isArray(t))return de();let n=t;if(n.questionId!==e.id||Object.keys(n).some(i=>!["questionId","answers","skipped"].includes(i)))return de();if(n.skipped===!0)return!e.optional||!Array.isArray(n.answers)||n.answers.length?de():{questionId:e.id,answers:[],skipped:!0};if(n.skipped!==void 0||!Array.isArray(n.answers)||n.answers.length!==e.questions.length)return de();let r=new Set,o=n.answers.map(i=>{if(!i||typeof i!="object"||Array.isArray(i))return de();let s=i;if(Object.keys(s).some(l=>!["questionId","optionIds","customText"].includes(l)))return de();let a=e.questions.find(l=>l.id===s.questionId);if(!a||r.has(a.id)||!Array.isArray(s.optionIds))return de();r.add(a.id);let c=s.optionIds;return c.some(l=>typeof l!="string"||!a.options.some(d=>d.id===l))||new Set(c).size!==c.length||!a.multiSelect&&c.length>1||s.customText!==void 0&&(typeof s.customText!="string"||!s.customText.trim()||Buffer.byteLength(s.customText)>8192)||!c.length&&s.customText===void 0?de():{questionId:a.id,optionIds:c,...typeof s.customText=="string"?{customText:s.customText}:{}}});return{questionId:e.id,answers:o}}function Lc(e,t){if(t===`/skip ${e.id}`)return si(e,{questionId:e.id,answers:[],skipped:!0});if(!t.startsWith("/answer "))return de();let n;try{n=JSON.parse(t.slice(8))}catch{return de()}return si(e,n)}function en(e){let t=e.questions.map(r=>`${r.header}: ${r.question}
482
484
  ${r.options.map(o=>` ${JSON.stringify(o.id)}: ${o.label} \u2014 ${o.description}${o.confirms?" (confirms an action)":""}`).join(`
483
485
  `)}`).join(`
484
486
 
@@ -486,13 +488,13 @@ ${r.options.map(o=>` ${JSON.stringify(o.id)}: ${o.label} \u2014 ${o.description
486
488
 
487
489
  Reply with explicit option ids:
488
490
  /answer ${JSON.stringify(n)}${e.optional?`
489
- Or skip: /skip ${e.id}`:""}`}function uc(e){return{type:"object",properties:Object.fromEntries(e.questions.map((t,n)=>[`answer_${n}`,t.multiSelect?{type:"array",title:t.header,description:t.question,items:{type:"string",enum:t.options.map(r=>r.id)},minItems:1}:{type:"string",title:t.header,description:`${t.question}
491
+ Or skip: /skip ${e.id}`:""}`}function Nc(e){return{type:"object",properties:Object.fromEntries(e.questions.map((t,n)=>[`answer_${n}`,t.multiSelect?{type:"array",title:t.header,description:t.question,items:{type:"string",enum:t.options.map(r=>r.id)},minItems:1}:{type:"string",title:t.header,description:`${t.question}
490
492
  ${t.options.map(r=>`${r.id}: ${r.label} \u2014 ${r.description}${r.confirms?" (confirms an action)":""}`).join(`
491
- `)}`,enum:t.options.map(r=>r.id),enumNames:t.options.map(r=>r.label)}])),required:e.questions.map((t,n)=>`answer_${n}`)}}function pc(e,t){if(!t||typeof t!="object"||Array.isArray(t))return ce();let n=t;return Object.keys(n).length!==e.questions.length?ce():Go(e,{questionId:e.id,answers:e.questions.map((r,o)=>{let i=n[`answer_${o}`];return typeof i=="string"&&(r.multiSelect||!r.options.some(s=>s.id===i))?{questionId:r.id,optionIds:[],customText:i}:{questionId:r.id,optionIds:r.multiSelect?i:[i]}})})}function cf(e){return{client:async()=>new we(await fr(e.endpointOverride,e.workspace)),login:async t=>{let n=await Vt(e.endpointOverride),r=await vt({endpoint:n.endpoint??pr,workspace:e.workspace,write:e.write,approve:e.approve,signal:t,onAuthorizationUrl:o=>process.stderr.write(`Authorize AnyForge Oracle in your browser:
493
+ `)}`,enum:t.options.map(r=>r.id),enumNames:t.options.map(r=>r.label)}])),required:e.questions.map((t,n)=>`answer_${n}`)}}function Fc(e,t){if(!t||typeof t!="object"||Array.isArray(t))return de();let n=t;return Object.keys(n).length!==e.questions.length?de():si(e,{questionId:e.id,answers:e.questions.map((r,o)=>{let i=n[`answer_${o}`];return typeof i=="string"&&(r.multiSelect||!r.options.some(s=>s.id===i))?{questionId:r.id,optionIds:[],customText:i}:{questionId:r.id,optionIds:r.multiSelect?i:[i]}})})}function Lf(e){return{client:async()=>new ke(await Ar(e.endpointOverride,e.workspace)),login:async t=>{let n=await Zt(e.endpointOverride),r=await At({endpoint:n.endpoint??Or,workspace:e.workspace,write:e.write,approve:e.approve,signal:t,onAuthorizationUrl:o=>process.stderr.write(`Authorize AnyForge Oracle in your browser:
492
494
  ${o}
493
- `)});return new we(Be(r))}}}var vr=class{constructor(t,n=cf(t)){this.options=t;this.dependencies=n}options;dependencies;initialized=!1;formSupported=!1;sessions=new Map;loading=new Set;pendingSetups=0;clientPromise;loginPromise;stopping=!1;lifetime=new AbortController;app(){let t=async n=>{try{return await n()}catch(r){throw df(r)}};return af({name:"anyforge"}).onRequest("initialize",({params:n})=>this.initialize(n)).onRequest("authenticate",({params:n})=>t(async()=>{if(this.ready(),n.methodId!=="oracle-browser")throw U.invalidParams(void 0,"Unknown authentication method. Terminal authentication runs as a separate command.");return await this.authenticate(),{}})).onRequest("session/new",({params:n,client:r})=>t(()=>this.newSession(n,r))).onRequest("session/load",({params:n,client:r})=>t(()=>this.loadSession(n,r))).onRequest("session/prompt",({params:n,client:r})=>t(()=>this.prompt(n,r))).onNotification("session/cancel",({params:n})=>this.cancel(n.sessionId))}initialize(t){if(this.initialized)throw U.invalidRequest(void 0,"This connection is already initialized.");if(!Number.isSafeInteger(t.protocolVersion)||t.protocolVersion<1)throw U.unsupportedProtocolVersion(t.protocolVersion,[1]);return this.initialized=!0,this.formSupported=t.clientCapabilities?.elicitation?.form!=null,{protocolVersion:1,agentInfo:{name:"anyforge",title:"AnyForge Hosted Oracle",version:this.options.version},agentCapabilities:{loadSession:!0,promptCapabilities:{image:!1,audio:!1,embeddedContext:!1},mcpCapabilities:{http:!1,sse:!1}},authMethods:[{id:"oracle-browser",name:"Sign in to AnyForge",description:"Authorize a workspace-scoped Oracle grant in your browser."},...t.clientCapabilities?.auth?.terminal===!0?[{id:"oracle-terminal",name:"Sign in from a terminal",type:"terminal",args:["--login"]}]:[]]}}ready(){if(!this.initialized)throw U.invalidRequest(void 0,"Initialize the ACP connection first.");if(this.stopping)throw U.requestCancelled()}client(){return this.clientPromise??=this.dependencies.client().catch(t=>{throw this.clientPromise=void 0,t}),this.clientPromise}async authenticate(){if(this.sessions.size||this.pendingSetups)throw U.invalidRequest(void 0,"Restart this ACP process to change authentication after opening a session.");return this.loginPromise||(this.loginPromise=this.dependencies.login(this.lifetime.signal).then(async t=>{await t.config(this.lifetime.signal),this.clientPromise=Promise.resolve(t)}).finally(()=>{this.loginPromise=void 0})),this.loginPromise}validateSetup(t){if(this.ready(),!of(t.cwd))throw U.invalidParams(void 0,"ACP cwd must be an absolute path. Hosted mode does not read this directory.");if(this.loginPromise)throw U.invalidRequest(void 0,"Wait for authentication to finish.");if(this.sessions.size+this.pendingSetups>=128&&(!("sessionId"in t)||!this.sessions.has(t.sessionId)))throw U.invalidRequest(void 0,"This ACP process has reached its 128-session limit. Restart it to open more sessions.")}async newSession(t,n){this.validateSetup(t),this.pendingSetups+=1;try{let r=await this.client();await r.config(this.lifetime.signal);let o=await r.createSession({visibility:"private",...this.options.context?{context:this.options.context}:{}},this.lifetime.signal);if(this.stopping)throw U.requestCancelled();return this.sessions.set(o.sessionId,{client:r,mcpNoticePending:t.mcpServers.length>0}),t.mcpServers.length&&await this.mcpNotice(n,o.sessionId),{sessionId:o.sessionId}}finally{this.pendingSetups-=1}}async loadSession(t,n){if(this.validateSetup(t),this.sessions.get(t.sessionId)?.active||this.loading.has(t.sessionId))throw U.invalidRequest(void 0,"Cannot load a session during an active prompt or load.");this.loading.add(t.sessionId),this.pendingSetups+=1;try{let r=await this.client(),o=await r.getSession(t.sessionId,this.lifetime.signal);if(o.activeStreamId)throw U.invalidRequest(void 0,"The hosted session is still running. Wait for it to settle before loading it.");if(this.stopping)throw U.requestCancelled();this.sessions.set(t.sessionId,{client:r,question:lf(o),mcpNoticePending:t.mcpServers.length>0}),t.mcpServers.length&&await this.mcpNotice(n,t.sessionId);for(let i of o.messages)i.content&&await this.update(n,t.sessionId,{sessionUpdate:i.role==="user"?"user_message_chunk":"agent_message_chunk",content:{type:"text",text:p(i.content)}}),i.question&&await this.text(n,t.sessionId,Xt(i.question));return{}}finally{this.loading.delete(t.sessionId),this.pendingSetups-=1}}prompt(t,n){this.ready();let r=this.sessions.get(t.sessionId);if(!r)throw U.invalidParams(void 0,"Load or create this session before prompting it.");if(r.active||this.loading.has(t.sessionId))throw U.invalidRequest(void 0,"A prompt or load is already running in this session. Wait for it to settle.");let o=lc(t.prompt),i=r.question?dc(r.question,o):void 0;if(!r.question&&(o.startsWith("/answer ")||o.startsWith("/skip ")))throw U.invalidParams(void 0,"There is no pending question in this session.");let s={cancelled:!1,abort:new AbortController,interaction:new AbortController,done:Promise.resolve({stopReason:"end_turn"})};return r.active=s,s.done=this.runPrompt(r,s,t.sessionId,i?"":o,i,n).finally(()=>{s.requestId=void 0,s.interaction.abort(),s.abort.abort(),s.deadline&&clearTimeout(s.deadline),r.active=void 0}),s.done}async runPrompt(t,n,r,o,i,s){t.mcpNoticePending&&(await this.mcpNotice(s,r),t.mcpNoticePending=!1);let a=await t.client.config(this.lifetime.signal);if(n.cancelled)return{stopReason:"cancelled"};let c=this.options.write&&t.client.scopes.has("write")&&a.capabilities?.write===!0,l=c&&this.options.approve&&t.client.scopes.has("approve")&&a.capabilities?.approve===!0;for(let d=0;d<20;d+=1){if(n.cancelled)return{stopReason:"cancelled"};n.requestId=rf();let u={requestId:n.requestId,text:o,readOnly:!c,...l?{allowApprove:!0}:{},...this.options.context?{context:this.options.context}:{},...this.options.contextText?{contextText:this.options.contextText}:{},...i?{questionResponse:i}:{}},y=new je,v=new Set,x=await Wt(t.client,r,u,{onEvent:async m=>{if(m.type==="delta"&&typeof m.content=="string")await this.text(s,r,p(m.content));else if((m.type==="tool_call"||m.type==="tool_call_start")&&typeof m.id=="string"&&!v.has(m.id))v.add(m.id),await this.update(s,r,{sessionUpdate:"tool_call",toolCallId:m.id,title:typeof m.label=="string"?p(m.label).slice(0,200):Pt(typeof m.name=="string"?m.name:""),status:"in_progress"});else if(m.type==="tool_result"&&typeof m.toolUseId=="string"&&v.has(m.toolUseId))await this.update(s,r,{sessionUpdate:"tool_call_update",toolCallId:m.toolUseId,status:m.ok===!1?"failed":"completed"});else if(m.type==="question")t.question=vn(m);else if(m.type==="navigator_file_created"){let A=Xe(m.file);await this.text(s,r,`Generated file: ${A.filename} (${A.mediaType}, ${A.sizeBytes} bytes). Session id: ${r}; file id: ${A.fileId}. Download using anyforge oracle download with an explicit output directory.`)}}},n.abort.signal,y);if(n.requestId=void 0,x.error)throw U.internalError(void 0,x.error);if(i&&(t.question=x.question),n.cancelled||x.done?.exitReason==="cancelled")return{stopReason:"cancelled"};if(!x.question){let m=x.done?.exitReason;if(m==="completed")return{stopReason:"end_turn"};if(m==="max_tokens"||m==="token_budget")return{stopReason:"max_tokens"};if(m==="max_rounds")return{stopReason:"max_turn_requests"};throw U.internalError(void 0,`Oracle stopped before completion (${typeof m=="string"?p(m):"unknown reason"}). Resume the hosted session to inspect it.`)}if(t.question=x.question,!this.formSupported)return await this.text(s,r,Xt(x.question)),{stopReason:"end_turn"};let b;try{b=await uf(s.request("elicitation/create",{mode:"form",sessionId:r,message:Xt(x.question),requestedSchema:uc(x.question)},{cancellationSignal:n.interaction.signal}),n.interaction.signal)}catch(m){if(n.cancelled)return{stopReason:"cancelled"};if(!(m instanceof U)||m.code!==-32601)throw m;return await this.text(s,r,Xt(x.question)),{stopReason:"end_turn"}}if(n.cancelled)return{stopReason:"cancelled"};if(b.action!=="accept")return await this.text(s,r,`No answer was submitted. The question remains pending.
494
- `+Xt(x.question)),{stopReason:"end_turn"};i=pc(x.question,b.content),o=""}return{stopReason:"max_turn_requests"}}async cancel(t){let n=this.sessions.get(t),r=n?.active;if(!n||!r||(r.cancelled=!0,r.interaction.abort(),!r.requestId))return;r.deadline??=setTimeout(()=>r.abort.abort(new Error("Oracle cancellation did not settle within 15 seconds. Inspect the hosted session before retrying.")),15e3);let o=r.requestId;r.cancel??=this.cancelUntilClaimed(n.client,t,o,r).catch(i=>{r.requestId&&(process.stderr.write(`Oracle cancellation request failed: ${Y(i)}
495
- `),r.abort.abort(new Error("Oracle cancellation could not be confirmed. Inspect the hosted session before retrying.")))}),await r.cancel}async cancelUntilClaimed(t,n,r,o){for(;o.requestId===r&&!o.abort.signal.aborted;)try{await t.cancelRequest(n,r,o.abort.signal);return}catch(i){if(!(i instanceof Q)||i.status!==404)throw i;await sf(100,void 0,{signal:o.abort.signal})}}async shutdown(){if(this.stopping)return;this.stopping=!0,this.lifetime.abort();let t=[...this.sessions.entries()].filter(([,o])=>o.active),n=Promise.allSettled(t.map(async([o,i])=>{await this.cancel(o),await i.active?.done})),r;await Promise.race([n,new Promise(o=>{r=setTimeout(o,3e3)})]),r&&clearTimeout(r);for(let[,o]of t)o.active?.abort.abort();this.sessions.clear()}update(t,n,r){return t.notify("session/update",{sessionId:n,update:r})}text(t,n,r){return this.update(t,n,{sessionUpdate:"agent_message_chunk",content:{type:"text",text:r}})}mcpNotice(t,n){return this.text(t,n,"AnyForge is running in hosted mode. Client MCP servers and local tools are omitted: their commands, environment and connections are never used or forwarded. Your authorized AnyForge server tools remain available. Local files and terminals are unavailable.")}};function lf(e){let t=e.messages.at(-1);return t?.role==="assistant"?t.question:void 0}function df(e){return e instanceof U?e:e instanceof h&&e.exitCode===g.NO_CREDENTIALS||e instanceof Q&&e.status===401?U.authRequired(void 0,"Sign in with authenticate or run anyforge oracle login, then retry."):U.internalError(void 0,Y(e))}function uf(e,t){return new Promise((n,r)=>{let o=()=>r(U.requestCancelled());t.addEventListener("abort",o,{once:!0}),e.then(n,r).finally(()=>t.removeEventListener("abort",o)).catch(()=>{}),t.aborted&&o()})}var hf=new Set(["endpoint","workspace","write","approve","read-only","program","initiative","codebase","context","login","help"]);function fc(){return`AnyForge ACP \u2014 hosted Oracle over ACP v1 JSON-RPC stdio.
495
+ `)});return new ke(ze(r))}}}var Cr=class{constructor(t,n=Lf(t)){this.options=t;this.dependencies=n}options;dependencies;initialized=!1;formSupported=!1;sessions=new Map;loading=new Set;pendingSetups=0;clientPromise;loginPromise;stopping=!1;lifetime=new AbortController;app(){let t=async n=>{try{return await n()}catch(r){throw Ff(r)}};return Pf({name:"anyforge"}).onRequest("initialize",({params:n})=>this.initialize(n)).onRequest("authenticate",({params:n})=>t(async()=>{if(this.ready(),n.methodId!=="oracle-browser")throw j.invalidParams(void 0,"Unknown authentication method. Terminal authentication runs as a separate command.");return await this.authenticate(),{}})).onRequest("session/new",({params:n,client:r})=>t(()=>this.newSession(n,r))).onRequest("session/load",({params:n,client:r})=>t(()=>this.loadSession(n,r))).onRequest("session/prompt",({params:n,client:r})=>t(()=>this.prompt(n,r))).onNotification("session/cancel",({params:n})=>this.cancel(n.sessionId))}initialize(t){if(this.initialized)throw j.invalidRequest(void 0,"This connection is already initialized.");if(!Number.isSafeInteger(t.protocolVersion)||t.protocolVersion<1)throw j.unsupportedProtocolVersion(t.protocolVersion,[1]);return this.initialized=!0,this.formSupported=t.clientCapabilities?.elicitation?.form!=null,{protocolVersion:1,agentInfo:{name:"anyforge",title:"AnyForge Hosted Oracle",version:this.options.version},agentCapabilities:{loadSession:!0,promptCapabilities:{image:!1,audio:!1,embeddedContext:!1},mcpCapabilities:{http:!1,sse:!1}},authMethods:[{id:"oracle-browser",name:"Sign in to AnyForge",description:"Authorize a workspace-scoped Oracle grant in your browser."},...t.clientCapabilities?.auth?.terminal===!0?[{id:"oracle-terminal",name:"Sign in from a terminal",type:"terminal",args:["--login"]}]:[]]}}ready(){if(!this.initialized)throw j.invalidRequest(void 0,"Initialize the ACP connection first.");if(this.stopping)throw j.requestCancelled()}client(){return this.clientPromise??=this.dependencies.client().catch(t=>{throw this.clientPromise=void 0,t}),this.clientPromise}async authenticate(){if(this.sessions.size||this.pendingSetups)throw j.invalidRequest(void 0,"Restart this ACP process to change authentication after opening a session.");return this.loginPromise||(this.loginPromise=this.dependencies.login(this.lifetime.signal).then(async t=>{await t.config(this.lifetime.signal),this.clientPromise=Promise.resolve(t)}).finally(()=>{this.loginPromise=void 0})),this.loginPromise}validateSetup(t){if(this.ready(),!Tf(t.cwd))throw j.invalidParams(void 0,"ACP cwd must be an absolute path. Hosted mode does not read this directory.");if(this.loginPromise)throw j.invalidRequest(void 0,"Wait for authentication to finish.");if(this.sessions.size+this.pendingSetups>=128&&(!("sessionId"in t)||!this.sessions.has(t.sessionId)))throw j.invalidRequest(void 0,"This ACP process has reached its 128-session limit. Restart it to open more sessions.")}async newSession(t,n){this.validateSetup(t),this.pendingSetups+=1;try{let r=await this.client();await r.config(this.lifetime.signal);let o=await r.createSession({visibility:"private",...this.options.context?{context:this.options.context}:{}},this.lifetime.signal);if(this.stopping)throw j.requestCancelled();return this.sessions.set(o.sessionId,{client:r,mcpNoticePending:t.mcpServers.length>0}),t.mcpServers.length&&await this.mcpNotice(n,o.sessionId),{sessionId:o.sessionId}}finally{this.pendingSetups-=1}}async loadSession(t,n){if(this.validateSetup(t),this.sessions.get(t.sessionId)?.active||this.loading.has(t.sessionId))throw j.invalidRequest(void 0,"Cannot load a session during an active prompt or load.");this.loading.add(t.sessionId),this.pendingSetups+=1;try{let r=await this.client(),o=await r.getSession(t.sessionId,this.lifetime.signal);if(o.activeStreamId)throw j.invalidRequest(void 0,"The hosted session is still running. Wait for it to settle before loading it.");if(this.stopping)throw j.requestCancelled();this.sessions.set(t.sessionId,{client:r,question:Nf(o),mcpNoticePending:t.mcpServers.length>0}),t.mcpServers.length&&await this.mcpNotice(n,t.sessionId);for(let i of o.messages)i.content&&await this.update(n,t.sessionId,{sessionUpdate:i.role==="user"?"user_message_chunk":"agent_message_chunk",content:{type:"text",text:p(i.content)}}),i.question&&await this.text(n,t.sessionId,en(i.question));return{}}finally{this.loading.delete(t.sessionId),this.pendingSetups-=1}}prompt(t,n){this.ready();let r=this.sessions.get(t.sessionId);if(!r)throw j.invalidParams(void 0,"Load or create this session before prompting it.");if(r.active||this.loading.has(t.sessionId))throw j.invalidRequest(void 0,"A prompt or load is already running in this session. Wait for it to settle.");let o=Pc(t.prompt),i=r.question?Lc(r.question,o):void 0;if(!r.question&&(o.startsWith("/answer ")||o.startsWith("/skip ")))throw j.invalidParams(void 0,"There is no pending question in this session.");let s={cancelled:!1,abort:new AbortController,interaction:new AbortController,done:Promise.resolve({stopReason:"end_turn"})};return r.active=s,s.done=this.runPrompt(r,s,t.sessionId,i?"":o,i,n).finally(()=>{s.requestId=void 0,s.interaction.abort(),s.abort.abort(),s.deadline&&clearTimeout(s.deadline),r.active=void 0}),s.done}async runPrompt(t,n,r,o,i,s){t.mcpNoticePending&&(await this.mcpNotice(s,r),t.mcpNoticePending=!1);let a=await t.client.config(this.lifetime.signal);if(n.cancelled)return{stopReason:"cancelled"};let c=this.options.write&&t.client.scopes.has("write")&&a.capabilities?.write===!0,l=c&&this.options.approve&&t.client.scopes.has("approve")&&a.capabilities?.approve===!0;for(let d=0;d<20;d+=1){if(n.cancelled)return{stopReason:"cancelled"};n.requestId=Ef();let u={requestId:n.requestId,text:o,readOnly:!c,...l?{allowApprove:!0}:{},...this.options.context?{context:this.options.context}:{},...this.options.contextText?{contextText:this.options.contextText}:{},...i?{questionResponse:i}:{}},w=new We,v=new Set,x=await zt(t.client,r,u,{onEvent:async m=>{if(m.type==="delta"&&typeof m.content=="string")await this.text(s,r,p(m.content));else if((m.type==="tool_call"||m.type==="tool_call_start")&&typeof m.id=="string"&&!v.has(m.id))v.add(m.id),await this.update(s,r,{sessionUpdate:"tool_call",toolCallId:m.id,title:typeof m.label=="string"?p(m.label).slice(0,200):Ft(typeof m.name=="string"?m.name:""),status:"in_progress"});else if(m.type==="tool_result"&&typeof m.toolUseId=="string"&&v.has(m.toolUseId))await this.update(s,r,{sessionUpdate:"tool_call_update",toolCallId:m.toolUseId,status:m.ok===!1?"failed":"completed"});else if(m.type==="question")t.question=An(m);else if(m.type==="navigator_file_created"){let A=tt(m.file);await this.text(s,r,`Generated file: ${A.filename} (${A.mediaType}, ${A.sizeBytes} bytes). Session id: ${r}; file id: ${A.fileId}. Download using anyforge oracle download with an explicit output directory.`)}}},n.abort.signal,w);if(n.requestId=void 0,x.error)throw j.internalError(void 0,x.error);if(i&&(t.question=x.question),n.cancelled||x.done?.exitReason==="cancelled")return{stopReason:"cancelled"};if(!x.question){let m=x.done?.exitReason;if(m==="completed")return{stopReason:"end_turn"};if(m==="max_tokens"||m==="token_budget")return{stopReason:"max_tokens"};if(m==="max_rounds")return{stopReason:"max_turn_requests"};throw j.internalError(void 0,`Oracle stopped before completion (${typeof m=="string"?p(m):"unknown reason"}). Resume the hosted session to inspect it.`)}if(t.question=x.question,!this.formSupported)return await this.text(s,r,en(x.question)),{stopReason:"end_turn"};let b;try{b=await Mf(s.request("elicitation/create",{mode:"form",sessionId:r,message:en(x.question),requestedSchema:Nc(x.question)},{cancellationSignal:n.interaction.signal}),n.interaction.signal)}catch(m){if(n.cancelled)return{stopReason:"cancelled"};if(!(m instanceof j)||m.code!==-32601)throw m;return await this.text(s,r,en(x.question)),{stopReason:"end_turn"}}if(n.cancelled)return{stopReason:"cancelled"};if(b.action!=="accept")return await this.text(s,r,`No answer was submitted. The question remains pending.
496
+ `+en(x.question)),{stopReason:"end_turn"};i=Fc(x.question,b.content),o=""}return{stopReason:"max_turn_requests"}}async cancel(t){let n=this.sessions.get(t),r=n?.active;if(!n||!r||(r.cancelled=!0,r.interaction.abort(),!r.requestId))return;r.deadline??=setTimeout(()=>r.abort.abort(new Error("Oracle cancellation did not settle within 15 seconds. Inspect the hosted session before retrying.")),15e3);let o=r.requestId;r.cancel??=this.cancelUntilClaimed(n.client,t,o,r).catch(i=>{r.requestId&&(process.stderr.write(`Oracle cancellation request failed: ${X(i)}
497
+ `),r.abort.abort(new Error("Oracle cancellation could not be confirmed. Inspect the hosted session before retrying.")))}),await r.cancel}async cancelUntilClaimed(t,n,r,o){for(;o.requestId===r&&!o.abort.signal.aborted;)try{await t.cancelRequest(n,r,o.abort.signal);return}catch(i){if(!(i instanceof ee)||i.status!==404)throw i;await $f(100,void 0,{signal:o.abort.signal})}}async shutdown(){if(this.stopping)return;this.stopping=!0,this.lifetime.abort();let t=[...this.sessions.entries()].filter(([,o])=>o.active),n=Promise.allSettled(t.map(async([o,i])=>{await this.cancel(o),await i.active?.done})),r;await Promise.race([n,new Promise(o=>{r=setTimeout(o,3e3)})]),r&&clearTimeout(r);for(let[,o]of t)o.active?.abort.abort();this.sessions.clear()}update(t,n,r){return t.notify("session/update",{sessionId:n,update:r})}text(t,n,r){return this.update(t,n,{sessionUpdate:"agent_message_chunk",content:{type:"text",text:r}})}mcpNotice(t,n){return this.text(t,n,"AnyForge is running in hosted mode. Client MCP servers and local tools are omitted: their commands, environment and connections are never used or forwarded. Your authorized AnyForge server tools remain available. Local files and terminals are unavailable.")}};function Nf(e){let t=e.messages.at(-1);return t?.role==="assistant"?t.question:void 0}function Ff(e){return e instanceof j?e:e instanceof h&&e.exitCode===g.NO_CREDENTIALS||e instanceof ee&&e.status===401?j.authRequired(void 0,"Sign in with authenticate or run anyforge oracle login, then retry."):j.internalError(void 0,X(e))}function Mf(e,t){return new Promise((n,r)=>{let o=()=>r(j.requestCancelled());t.addEventListener("abort",o,{once:!0}),e.then(n,r).finally(()=>t.removeEventListener("abort",o)).catch(()=>{}),t.aborted&&o()})}var Df=new Set(["endpoint","workspace","write","approve","read-only","program","initiative","codebase","context","login","help"]);function Mc(){return`AnyForge ACP \u2014 hosted Oracle over ACP v1 JSON-RPC stdio.
496
498
 
497
499
  Usage: anyforge acp [options]
498
500
 
@@ -529,16 +531,16 @@ with the displayed /answer JSON command. Ordinary prose never confirms actions.
529
531
  Sessions support new, load, text/tool progress and cancellation. Local modes,
530
532
  model selection, session list/fork/delete and local tool execution are not offered.
531
533
  Protocol traffic uses stdout; diagnostics use stderr.
532
- `}function gf(e,t){if(e.positional.length)throw new f("acp does not accept positional arguments. Prompts arrive over ACP stdio.");let n=Object.keys(e.flags).find(l=>!hf.has(l));if(n)throw new f(`--${n} is not supported by acp. Run anyforge acp --help.`);let r=e.flags.write===!0||e.flags.approve===!0;if(e.flags["read-only"]===!0&&r)throw new f("--read-only cannot be combined with --write or --approve.");let o=["program","initiative","codebase"].filter(l=>e.flags[l]!==void 0);if(o.length>1)throw new f("Choose only one of --program, --initiative or --codebase.");let i=o[0],s=i?e.flags[i]:void 0;if(i&&(typeof s!="string"||!s.trim()||Buffer.byteLength(s)>256))throw new f("Context id must contain 1\u2013256 UTF-8 bytes.");let a=e.flags.context;if(a!==void 0&&(typeof a!="string"||Buffer.byteLength(a)>8192))throw new f("--context must fit within 8 KiB.");let c=e.flags.workspace;if(c!==void 0&&(typeof c!="string"||!c.trim()||Buffer.byteLength(c)>256))throw new f("--workspace must contain 1\u2013256 UTF-8 bytes.");return{version:t,endpointOverride:e.endpointOverride,...typeof c=="string"?{workspace:c}:{},write:r,approve:e.flags.approve===!0,...i&&typeof s=="string"?{context:{kind:i,id:s}}:{},...typeof a=="string"?{contextText:a}:{}}}async function mc(e,t){let n=gf(e,t);if(e.flags.login===!0){let a=new AbortController,c=()=>a.abort();process.once("SIGTERM",c),process.once("SIGINT",c);try{let l=await Vt(n.endpointOverride),d=await vt({endpoint:l.endpoint??pr,workspace:n.workspace,write:n.write,approve:n.approve,signal:a.signal,onAuthorizationUrl:u=>process.stderr.write(`Authorize AnyForge Oracle in your browser:
534
+ `}function Bf(e,t){if(e.positional.length)throw new f("acp does not accept positional arguments. Prompts arrive over ACP stdio.");let n=Object.keys(e.flags).find(l=>!Df.has(l));if(n)throw new f(`--${n} is not supported by acp. Run anyforge acp --help.`);let r=e.flags.write===!0||e.flags.approve===!0;if(e.flags["read-only"]===!0&&r)throw new f("--read-only cannot be combined with --write or --approve.");let o=["program","initiative","codebase"].filter(l=>e.flags[l]!==void 0);if(o.length>1)throw new f("Choose only one of --program, --initiative or --codebase.");let i=o[0],s=i?e.flags[i]:void 0;if(i&&(typeof s!="string"||!s.trim()||Buffer.byteLength(s)>256))throw new f("Context id must contain 1\u2013256 UTF-8 bytes.");let a=e.flags.context;if(a!==void 0&&(typeof a!="string"||Buffer.byteLength(a)>8192))throw new f("--context must fit within 8 KiB.");let c=e.flags.workspace;if(c!==void 0&&(typeof c!="string"||!c.trim()||Buffer.byteLength(c)>256))throw new f("--workspace must contain 1\u2013256 UTF-8 bytes.");return{version:t,endpointOverride:e.endpointOverride,...typeof c=="string"?{workspace:c}:{},write:r,approve:e.flags.approve===!0,...i&&typeof s=="string"?{context:{kind:i,id:s}}:{},...typeof a=="string"?{contextText:a}:{}}}async function qc(e,t){let n=Bf(e,t);if(e.flags.login===!0){let a=new AbortController,c=()=>a.abort();process.once("SIGTERM",c),process.once("SIGINT",c);try{let l=await Zt(n.endpointOverride),d=await At({endpoint:l.endpoint??Or,workspace:n.workspace,write:n.write,approve:n.approve,signal:a.signal,onAuthorizationUrl:u=>process.stderr.write(`Authorize AnyForge Oracle in your browser:
533
535
  ${u}
534
- `)});await new we(Be(d)).config(),process.stderr.write(`AnyForge Oracle login saved. Restart or retry your ACP session.
535
- `)}finally{process.removeListener("SIGTERM",c),process.removeListener("SIGINT",c)}return}let r=new vr(n),o=mf(ff.toWeb(process.stdout),pf.toWeb(process.stdin),{maxMessageBytes:1048576}),i=r.app().connect(o),s=()=>i.close();process.once("SIGTERM",s),process.once("SIGINT",s);try{await i.closed}finally{process.removeListener("SIGTERM",s),process.removeListener("SIGINT",s),await r.shutdown(),process.stdin.destroy()}}var wc="https://crew.anyforge.ai",yf=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output","workspace","repo","branch","print","event","actor","from","to","cursor","role","team","body","date","entries"]),vf=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json","verify","no-email","login","uncommitted"]);function bf(e){let t={positional:[],flags:{}};for(let n=0;n<e.length;n+=1){let r=e[n];if(!r.startsWith("-")){t.command?t.positional.push(r):t.command=r;continue}let o=r==="-h"?"help":r==="-V"?"version":r==="-f"?"force":r==="-p"||r.startsWith("-p=")?r.replace(/^-p/,"print"):r.replace(/^--?/,""),[i,s]=o.includes("=")?[o.slice(0,o.indexOf("=")),o.slice(o.indexOf("=")+1)]:[o,void 0];if(yf.has(i)){let a=s??e[++n];if(a===void 0)throw new f(`--${i} needs a value.`);if(i==="file"){let c=t.flags.file;t.flags.file=[...typeof c=="string"?[c]:Array.isArray(c)?c:[],a]}else t.flags[i]=a;continue}if(vf.has(i)){t.flags[i]=s===void 0?!0:s!=="false";continue}throw new f(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return t}function _e(e,t){if(e===void 0||typeof e=="boolean")return;let n=Number(e);if(!Number.isFinite(n)||n<=0)throw new f(`--${t} must be a positive number, got "${e}".`);return n}function E(e){return typeof e=="string"?e:void 0}function Rn(e){return e===!0?!0:void 0}function kf(){console.log(`
536
- ${G("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
536
+ `)});await new ke(ze(d)).config(),process.stderr.write(`AnyForge Oracle login saved. Restart or retry your ACP session.
537
+ `)}finally{process.removeListener("SIGTERM",c),process.removeListener("SIGINT",c)}return}let r=new Cr(n),o=jf(Uf.toWeb(process.stdout),qf.toWeb(process.stdin),{maxMessageBytes:1048576}),i=r.app().connect(o),s=()=>i.close();process.once("SIGTERM",s),process.once("SIGINT",s);try{await i.closed}finally{process.removeListener("SIGTERM",s),process.removeListener("SIGINT",s),await r.shutdown(),process.stdin.destroy()}}W();q();var Dc="https://crew.anyforge.ai",Wf=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output","workspace","repo","branch","print","event","actor","from","to","cursor","role","team","body","date","entries"]),Hf=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json","verify","no-email","login","uncommitted"]);function zf(e){let t={positional:[],flags:{}};for(let n=0;n<e.length;n+=1){let r=e[n];if(!r.startsWith("-")){t.command?t.positional.push(r):t.command=r;continue}let o=r==="-h"?"help":r==="-V"?"version":r==="-f"?"force":r==="-p"||r.startsWith("-p=")?r.replace(/^-p/,"print"):r.replace(/^--?/,""),[i,s]=o.includes("=")?[o.slice(0,o.indexOf("=")),o.slice(o.indexOf("=")+1)]:[o,void 0];if(Wf.has(i)){let a=s??e[++n];if(a===void 0)throw new f(`--${i} needs a value.`);if(i==="file"){let c=t.flags.file;t.flags.file=[...typeof c=="string"?[c]:Array.isArray(c)?c:[],a]}else t.flags[i]=a;continue}if(Hf.has(i)){t.flags[i]=s===void 0?!0:s!=="false";continue}throw new f(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return t}function Ee(e,t){if(e===void 0||typeof e=="boolean")return;let n=Number(e);if(!Number.isFinite(n)||n<=0)throw new f(`--${t} must be a positive number, got "${e}".`);return n}function E(e){return typeof e=="string"?e:void 0}function En(e){return e===!0?!0:void 0}function Kf(){console.log(`
538
+ ${K("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
537
539
 
538
- ${G("USAGE")}
540
+ ${K("USAGE")}
539
541
  npx @anyforge/control <command> [options]
540
542
 
541
- ${G("CODE STUDIO")}
543
+ ${K("CODE STUDIO")}
542
544
  studio list List your owned coding sessions
543
545
  studio create --repo owner/repo Prepare a direct remote session
544
546
  studio create --uncommitted Hand this checkout's branch and uncommitted
@@ -553,14 +555,14 @@ ${G("CODE STUDIO")}
553
555
  studio changes|artifacts <id> Inspect remote results
554
556
  studio stage|commit|push <id> Explicit Git action with --input JSON
555
557
 
556
- ${G("SETUP")}
558
+ ${K("SETUP")}
557
559
  init Authorise this device and patch local agent configs
558
560
  whoami Show the company, scopes and endpoint this key acts as
559
561
  status Check identity, local setup and recorded activity
560
562
  logout Clear the saved API key and revert patched configs
561
563
  apply-patch [file] Apply a unified diff (file or stdin) via git apply
562
564
 
563
- ${G("SKILLS")}
565
+ ${K("SKILLS")}
564
566
  skill list List your company's skills and skill-source skills
565
567
  skill install <name> Install a skill's whole folder (scripts and references
566
568
  included) into a local agent, or anyforge-platform for
@@ -569,12 +571,12 @@ ${G("SKILLS")}
569
571
  skill sync Update installed skills to their current version; keeps
570
572
  local edits unless --force (--dry-run, --team <slug>)
571
573
 
572
- ${G("APPROVALS")} ${Ze("(the gate that blocks a human)")}
574
+ ${K("APPROVALS")} ${rt("(the gate that blocks a human)")}
573
575
  approvals List HIL approvals awaiting a decision
574
576
  approve <id> Approve one, optionally with --notes
575
577
  reject <id> Reject one, optionally with --notes
576
578
 
577
- ${G("CREWS")}
579
+ ${K("CREWS")}
578
580
  crews List crews (--active for running/paused only)
579
581
  crew <id> Show one crew, its status and recent output
580
582
  crew start <item> Dispatch a crew on a work item (--profile, --follow)
@@ -582,7 +584,7 @@ ${G("CREWS")}
582
584
  halt <id> Stop a crew
583
585
  resume <id> Resume a paused or halted crew
584
586
 
585
- ${G("WORK & WORKFLOWS")}
587
+ ${K("WORK & WORKFLOWS")}
586
588
  work List work items (--status, --type, --priority, --search).
587
589
  Paged: one page by default, --all walks every page
588
590
  comment <action> <item> <comment>
@@ -591,7 +593,7 @@ ${G("WORK & WORKFLOWS")}
591
593
  run <id> Dispatch a workflow run, with optional --input JSON
592
594
  ask <question> Ask the Oracle one question
593
595
 
594
- ${G("HOSTED ORACLE")}
596
+ ${K("HOSTED ORACLE")}
595
597
  acp Serve the hosted Oracle over ACP v1 stdio (T3 Code and editors)
596
598
  acp --help Show hosted ACP capabilities, limits and options
597
599
  oracle [prompt] Start an interactive hosted Oracle session
@@ -604,7 +606,7 @@ ${G("HOSTED ORACLE")}
604
606
  oracle logout Revoke and clear the active workspace's Oracle grant (--all for every one)
605
607
  oracle --help Show Oracle options and slash commands
606
608
 
607
- ${G("MEASUREMENT")}
609
+ ${K("MEASUREMENT")}
608
610
  backtest-corpus Can this workspace be back-tested? Counts the incidents
609
611
  that could become graded replay cases (--days 30|90|180|365)
610
612
  review-interception Serious findings the reviewer raised on your pull requests,
@@ -612,18 +614,18 @@ ${G("MEASUREMENT")}
612
614
  review-coverage How many recorded pull requests got reviewed, how fast the
613
615
  author heard back, and what a limit stopped (--days 7|30|90|180)
614
616
 
615
- ${G("AUDIT LOG")} ${Ze("(needs a key with the audit:read scope)")}
617
+ ${K("AUDIT LOG")} ${rt("(needs a key with the audit:read scope)")}
616
618
  audit Page through the hash-chained audit trail, oldest first
617
619
  (--event, --actor, --from, --to, --limit, --cursor, --all).
618
620
  --verify recomputes every hash and link across the pages read
619
621
 
620
- ${G("TIMESHEET")} ${Ze("(your own time; book needs the write scope)")}
622
+ ${K("TIMESHEET")} ${rt("(your own time; book needs the write scope)")}
621
623
  time week Your timesheet for this week (--date <day> for another)
622
624
  time book --entries <f>
623
625
  Book cells from a JSON list, all or nothing (--entries - reads stdin):
624
626
  [{"initiativeId":"\u2026","date":"YYYY-MM-DD","minutes":90,"note":"\u2026"}]
625
627
 
626
- ${G("PEOPLE")} ${Ze("(needs a key with the people:invite scope, minted by an owner)")}
628
+ ${K("PEOPLE")} ${rt("(needs a key with the people:invite scope, minted by an owner)")}
627
629
  people invite <email> --role <role>
628
630
  Invite one person: operator, editor, viewer or filer, on a
629
631
  verified company domain (--team <ids>, --no-email)
@@ -631,9 +633,9 @@ ${G("PEOPLE")} ${Ze("(needs a key with the people:invite scope, minted by an ow
631
633
  people withdraw <email>
632
634
  Withdraw a pending invitation
633
635
 
634
- ${G("OPTIONS")}
636
+ ${K("OPTIONS")}
635
637
  --json Print the raw API payload instead of a table
636
- --endpoint <url> Override the base URL (default: ${Ze(wc)})
638
+ --endpoint <url> Override the base URL (default: ${rt(Dc)})
637
639
  --limit <n> Page size on list commands (work: 1-200, default 50)
638
640
  --all work: follow the cursor until the backlog is exhausted
639
641
  --notes <text> approve/reject: reviewer notes, recorded in the audit trail
@@ -664,10 +666,10 @@ ${G("OPTIONS")}
664
666
  --help, -h Show this message
665
667
  --version, -V Print CLI version
666
668
 
667
- ${G("EXIT CODES")}
669
+ ${K("EXIT CODES")}
668
670
  0 ok 1 failure 2 usage 3 not authenticated 4 API error 5 audit verification failed
669
671
 
670
- ${G("EXAMPLES")}
672
+ ${K("EXAMPLES")}
671
673
  anyforge approvals
672
674
  anyforge approve hil_123 --notes "ship it"
673
675
  anyforge crews --active --json | jq -r '.[].id'
@@ -689,10 +691,10 @@ ${G("EXAMPLES")}
689
691
  anyforge people withdraw person@example.com
690
692
  anyforge skill install secret-guard --client claude
691
693
  anyforge skill sync --client claude --dry-run
692
- `)}function Of(){console.log(`
693
- ${G("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
694
+ `)}function Jf(){console.log(`
695
+ ${K("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
694
696
 
695
- ${G("USAGE")}
697
+ ${K("USAGE")}
696
698
  anyforge oracle [initial prompt] [options] Start an interactive session
697
699
  anyforge oracle -p <prompt> [options] Print one read-only answer and exit
698
700
  anyforge oracle exec <prompt|stdin> [options] Submit one read-only turn
@@ -706,7 +708,7 @@ ${G("USAGE")}
706
708
  Revoke and remove the active (or named, or every) login
707
709
  anyforge oracle download <session> <file> --output <directory>
708
710
 
709
- ${G("OPTIONS")}
711
+ ${K("OPTIONS")}
710
712
  -p, --print <prompt> Print one answer to stdout and exit (like oracle exec)
711
713
  --json Print one final JSON object (exec)
712
714
  --stream-json Print event JSONL followed by a final result (exec)
@@ -729,7 +731,7 @@ CLI attachment limits are 10 MiB per file and 20 MiB total per turn. Files are
729
731
  uploaded only when named with --file or /attach. Generated files require an
730
732
  explicit \`oracle download\` destination; existing files are never overwritten.
731
733
 
732
- ${G("IN THE CONVERSATION")}
734
+ ${K("IN THE CONVERSATION")}
733
735
  /help Commands and keys /status Session, model, limits
734
736
  /new [shared] Start a conversation /clear Clear and start afresh
735
737
  /resume [id] Open a saved conversation /usage Turns and tokens so far
@@ -755,8 +757,8 @@ Examples:
755
757
  anyforge oracle login --workspace "Acme Engineering"
756
758
  anyforge oracle exec "What is blocked?" --workspace "Beta Labs"
757
759
  cat incident.log | anyforge oracle exec "Explain this log" --stream-json
758
- `)}async function Af(e,t,n,r){let o=t.flags.json===!0,[i]=t.positional;if(e==="oracle")return ac({positional:t.positional,flags:t.flags,endpointOverride:r,endpoint:n});if(e==="acp"){let a=await Promise.resolve().then(()=>(gr(),hr));return mc({positional:t.positional,flags:t.flags,endpointOverride:r},a.default.version)}switch(e){case"init":return Ai({endpoint:n,force:t.flags.force===!0});case"logout":return Pi();case"status":return Ui({endpoint:r,json:o});case"whoami":return Ti({endpoint:r,json:o});case"apply-patch":return Di({patchFile:i,threeWay:t.flags["3way"]===!0,dryRun:t.flags["dry-run"]===!0});case"proxy":console.log(wf("Local proxy mode is coming in a future release.")),console.log(Ze(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return ea({subcommand:i,name:t.positional[1],scope:E(t.flags.scope),client:E(t.flags.client),team:E(t.flags.team),force:t.flags.force===!0,dryRun:t.flags["dry-run"]===!0,json:o,resolveCreds:()=>$e(r)})}let s=await $e(r);switch(e){case"approvals":return Bi({creds:s,json:o,limit:_e(t.flags.limit,"limit")});case"approve":return Br({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:E(t.flags.notes)});case"reject":return Br({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:E(t.flags.notes)});case"crews":return Wi({creds:s,json:o,status:E(t.flags.status),activeOnly:Rn(t.flags.active),limit:_e(t.flags.limit,"limit")});case"crew":{let[a,c]=t.positional;return a==="start"?Ji({creds:s,json:o,workItemId:c,profileId:E(t.flags.profile),follow:t.flags.follow===!0,intervalSeconds:_e(t.flags.interval,"interval")}):a==="follow"?Hr({creds:s,json:o,crewId:c,intervalSeconds:_e(t.flags.interval,"interval")}):Gi({creds:s,json:o,crewId:i,messages:_e(t.flags.messages,"messages")})}case"halt":return Gr({creds:s,json:o,crewId:i,action:"halt"});case"resume":return Gr({creds:s,json:o,crewId:i,action:"resume"});case"studio":return os({creds:s,json:o,command:i,id:t.positional[1],input:E(t.flags.input),context:E(t.flags.context),file:E(t.flags.file),repo:E(t.flags.repo),branch:E(t.flags.branch),initiative:E(t.flags.initiative),cursor:E(t.flags.cursor),uncommitted:Rn(t.flags.uncommitted)});case"work":return as({creds:s,json:o,status:E(t.flags.status),type:E(t.flags.type),priority:E(t.flags.priority),initiative:E(t.flags.initiative),program:E(t.flags.program),search:E(t.flags.search),assignee:E(t.flags.assignee),includeArchived:Rn(t.flags.archived),limit:_e(t.flags.limit,"limit"),all:Rn(t.flags.all)});case"comment":return cs({creds:s,json:o,action:i,itemId:t.positional[1],commentId:t.positional[2],body:E(t.flags.body)});case"workflows":return ls({creds:s,json:o});case"run":return ds({creds:s,json:o,workflowId:i,input:E(t.flags.input)});case"ask":return us({creds:s,json:o,question:t.positional.join(" "),context:E(t.flags.context)});case"backtest-corpus":return fs({creds:s,json:o,days:_e(t.flags.days,"days")});case"review-interception":return hs({creds:s,json:o,days:_e(t.flags.days,"days")});case"review-coverage":return gs({creds:s,json:o,days:_e(t.flags.days,"days")});case"audit":return As({creds:s,json:o,eventType:E(t.flags.event),actor:E(t.flags.actor),from:E(t.flags.from),to:E(t.flags.to),limit:_e(t.flags.limit,"limit"),cursor:E(t.flags.cursor),all:Rn(t.flags.all),verify:t.flags.verify===!0});case"time":return Cs({creds:s,json:o,subcommand:i,date:E(t.flags.date),entries:E(t.flags.entries)});case"people":return Rs({creds:s,json:o,subcommand:i,email:t.positional[1],role:E(t.flags.role),team:E(t.flags.team),notify:t.flags["no-email"]!==!0});default:throw new f(`Unknown command: ${e}`,"Run `anyforge --help` for the command list.")}}async function xf(){let e;try{e=bf(process.argv.slice(2))}catch(r){gc(r);return}if(!e.command&&e.flags.login===!0&&(e.command="acp"),e.flags.version===!0){let r=await Promise.resolve().then(()=>(gr(),hr));console.log(r.default.version);return}if(e.command==="oracle"&&e.flags.help===!0){Of();return}if(e.command==="acp"&&e.flags.help===!0){console.log(fc());return}if(e.flags.help===!0||!e.command){kf();return}let t=E(e.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=t??wc;try{if(e.command!=="oracle"&&e.command!=="acp"){let o=["approve","codebase","file","output","print","read-only","shared","stream-json","workspace","write"].find(i=>e.flags[i]!==void 0);if(o)throw new f(`--${o} is only supported by the oracle command.`)}if(e.command!=="acp"&&e.flags.login!==void 0)throw new f("--login is only supported by the acp command.");_i(e.command),await Af(e.command,e,n,t)}catch(r){gc(r)}}function gc(e){e instanceof h&&(process.stderr.write(hc("Error: ")+p(e.message)+`
759
- `),e.hint?process.stderr.write(Ze(p(e.hint))+`
760
- `):e instanceof f&&process.stderr.write(Ze("Run `anyforge --help`.")+`
761
- `),process.exit(e.exitCode)),process.stderr.write(hc("Error: ")+p(e instanceof Error?e.message:String(e))+`
762
- `),process.exit(g.FAILURE)}xf();
760
+ `)}async function Vf(e,t,n,r){let o=t.flags.json===!0,[i]=t.positional;if(e==="oracle")return Tc({positional:t.positional,flags:t.flags,endpointOverride:r,endpoint:n});if(e==="acp"){let a=await Promise.resolve().then(()=>(Sr(),_r));return qc({positional:t.positional,flags:t.flags,endpointOverride:r},a.default.version)}switch(e){case"init":return bs({endpoint:n,force:t.flags.force===!0});case"logout":return Rs();case"status":return Ps({endpoint:r,json:o});case"whoami":return _s({endpoint:r,json:o});case"apply-patch":return Ns({patchFile:i,threeWay:t.flags["3way"]===!0,dryRun:t.flags["dry-run"]===!0});case"proxy":console.log(Gf("Local proxy mode is coming in a future release.")),console.log(rt(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return so({subcommand:i,name:t.positional[1],scope:E(t.flags.scope),client:E(t.flags.client),team:E(t.flags.team),force:t.flags.force===!0,dryRun:t.flags["dry-run"]===!0,json:o,resolveCreds:()=>Ne(r)})}let s=await Ne(r);switch(e){case"approvals":return Fs({creds:s,json:o,limit:Ee(t.flags.limit,"limit")});case"approve":return bo({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:E(t.flags.notes)});case"reject":return bo({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:E(t.flags.notes)});case"crews":return Ms({creds:s,json:o,status:E(t.flags.status),activeOnly:En(t.flags.active),limit:Ee(t.flags.limit,"limit")});case"crew":{let[a,c]=t.positional;return a==="start"?Bs({creds:s,json:o,workItemId:c,profileId:E(t.flags.profile),follow:t.flags.follow===!0,intervalSeconds:Ee(t.flags.interval,"interval")}):a==="follow"?Ao({creds:s,json:o,crewId:c,intervalSeconds:Ee(t.flags.interval,"interval")}):qs({creds:s,json:o,crewId:i,messages:Ee(t.flags.messages,"messages")})}case"halt":return Oo({creds:s,json:o,crewId:i,action:"halt"});case"resume":return Oo({creds:s,json:o,crewId:i,action:"resume"});case"studio":return Qs({creds:s,json:o,command:i,id:t.positional[1],input:E(t.flags.input),context:E(t.flags.context),file:E(t.flags.file),repo:E(t.flags.repo),branch:E(t.flags.branch),initiative:E(t.flags.initiative),cursor:E(t.flags.cursor),uncommitted:En(t.flags.uncommitted)});case"work":return ta({creds:s,json:o,status:E(t.flags.status),type:E(t.flags.type),priority:E(t.flags.priority),initiative:E(t.flags.initiative),program:E(t.flags.program),search:E(t.flags.search),assignee:E(t.flags.assignee),includeArchived:En(t.flags.archived),limit:Ee(t.flags.limit,"limit"),all:En(t.flags.all)});case"comment":return na({creds:s,json:o,action:i,itemId:t.positional[1],commentId:t.positional[2],body:E(t.flags.body)});case"workflows":return ra({creds:s,json:o});case"run":return oa({creds:s,json:o,workflowId:i,input:E(t.flags.input)});case"ask":return ia({creds:s,json:o,question:t.positional.join(" "),context:E(t.flags.context)});case"backtest-corpus":return aa({creds:s,json:o,days:Ee(t.flags.days,"days")});case"review-interception":return la({creds:s,json:o,days:Ee(t.flags.days,"days")});case"review-coverage":return da({creds:s,json:o,days:Ee(t.flags.days,"days")});case"audit":return wa({creds:s,json:o,eventType:E(t.flags.event),actor:E(t.flags.actor),from:E(t.flags.from),to:E(t.flags.to),limit:Ee(t.flags.limit,"limit"),cursor:E(t.flags.cursor),all:En(t.flags.all),verify:t.flags.verify===!0});case"time":return xa({creds:s,json:o,subcommand:i,date:E(t.flags.date),entries:E(t.flags.entries)});case"people":return ba({creds:s,json:o,subcommand:i,email:t.positional[1],role:E(t.flags.role),team:E(t.flags.team),notify:t.flags["no-email"]!==!0});default:throw new f(`Unknown command: ${e}`,"Run `anyforge --help` for the command list.")}}async function Yf(){let e;try{e=zf(process.argv.slice(2))}catch(r){jc(r);return}if(!e.command&&e.flags.login===!0&&(e.command="acp"),e.flags.version===!0){let r=await Promise.resolve().then(()=>(Sr(),_r));console.log(r.default.version);return}if(e.command==="oracle"&&e.flags.help===!0){Jf();return}if(e.command==="acp"&&e.flags.help===!0){console.log(Mc());return}if(e.flags.help===!0||!e.command){Kf();return}let t=E(e.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=t??Dc;try{if(e.command!=="oracle"&&e.command!=="acp"){let o=["approve","codebase","file","output","print","read-only","shared","stream-json","workspace","write"].find(i=>e.flags[i]!==void 0);if(o)throw new f(`--${o} is only supported by the oracle command.`)}if(e.command!=="acp"&&e.flags.login!==void 0)throw new f("--login is only supported by the acp command.");zi(e.command),await Vf(e.command,e,n,t)}catch(r){jc(r)}}function jc(e){e instanceof h&&(process.stderr.write(Uc("Error: ")+p(e.message)+`
761
+ `),e.hint?process.stderr.write(rt(p(e.hint))+`
762
+ `):e instanceof f&&process.stderr.write(rt("Run `anyforge --help`.")+`
763
+ `),process.exit(e.exitCode)),process.stderr.write(Uc("Error: ")+p(e instanceof Error?e.message:String(e))+`
764
+ `),process.exit(g.FAILURE)}Yf();