@anyforge/control 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +6 -5
  2. package/dist/cli.js +103 -100
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -64,6 +64,7 @@ start a conversation or submit a read-only turn from a script:
64
64
  ```bash
65
65
  anyforge oracle login
66
66
  anyforge oracle
67
+ anyforge oracle -p "Summarize current risks"
67
68
  anyforge oracle --program prog_123
68
69
  anyforge oracle exec "Summarize current risks" --json
69
70
  cat incident.log | anyforge oracle exec "Explain this log" --stream-json
@@ -98,8 +99,8 @@ with an explanation.
98
99
  Interactive conversations are read only by default. Use `oracle login --write`
99
100
  and start with `oracle --write` to enable workspace edits. Consequential edits
100
101
  require a later explicit confirmation of the proposed action. Operator actions
101
- and external MCP writes additionally require `--approve`. `oracle exec` always
102
- remains read only.
102
+ and external MCP writes additionally require `--approve`. `oracle exec` and
103
+ `oracle -p` always remain read only.
103
104
 
104
105
  Use Shift+Enter for multiline input. Type `/` for the command palette:
105
106
  `/help`, `/status` (session, workspace, access, model, last turn, usage and
@@ -108,8 +109,8 @@ limits), `/new`, `/clear`, `/resume`, `/workspace`, `/context`, `/attach`,
108
109
  `/remember [what]` are answered by the Oracle itself, as in the web widget;
109
110
  acting on `/catchup` decisions needs a session started with `--write --approve`.
110
111
 
111
- While Oracle works, a status line shows what it is doing, how long it has
112
- taken and which step it is on, and each tool appears as it runs. Enter queues
112
+ While Oracle works, an indicator appears under its name immediately. A status
113
+ line shows elapsed time and the current step, and each tool appears as it runs. Enter queues
113
114
  one follow-up message. Esc or Ctrl+C cancels the current run and keeps the
114
115
  conversation open; press Ctrl+C twice, or Ctrl+D on an empty line, to exit.
115
116
  Ctrl+O shows or hides finished tool activity; Ctrl+Shift+F searches the
@@ -169,7 +170,7 @@ CI gates on these, so they are a contract:
169
170
  | `1` | Network or unexpected failure (retryable) — and a `crew follow` whose run ended `HALTED` / `REJECTED` / `CANCELLED`, which is not |
170
171
  | `2` | Usage error |
171
172
  | `3` | Not authenticated — run `init`, or set `ANYFORGE_API_TOKEN` |
172
- | `4` | The API refused; its error code prints to stderr |
173
+ | `4` | The API refused; its error code, and any details the API sent with it, print to stderr |
173
174
  | `130` | An Oracle run was interrupted: `exec` was cancelled with Ctrl+C, or you left an interactive session whose last answer you cancelled |
174
175
 
175
176
  Errors and progress go to stderr, so a `--json` pipe stays parseable under a failure.
package/dist/cli.js CHANGED
@@ -1,56 +1,57 @@
1
1
  #!/usr/bin/env node
2
- var ps=Object.defineProperty;var fs=(t,e)=>()=>(t&&(e=t(t=0)),e);var ms=(t,e)=>{for(var n in e)ps(t,n,{get:e[n],enumerable:!0})};var kr={};ms(kr,{default:()=>Qc});var Qc,Ar=fs(()=>{Qc={name:"@anyforge/control",version:"0.7.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","type-check":"tsc --noEmit",test:"npm run build && node scripts/test.mjs",dev:"tsx src/cli.ts",prepublishOnly:"npm run build","publish:beta":"npm publish --access public --tag beta","publish:stable":"npm publish --access public"},engines:{node:">=22.19.0"},dependencies:{"@earendil-works/pi-tui":"^0.87.1",kleur:"^4.1.5",open:"^10.0.0",prompts:"^2.4.2","proper-lockfile":"^4.1.2"},devDependencies:{"@types/node":"^22.20.0","@types/prompts":"^2.4.9","@types/proper-lockfile":"^4.1.4",esbuild:"^0.25.0","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});import{red as Hi,yellow as kl,dim as jt,bold as K}from"kleur/colors";import{execFileSync as Nn}from"child_process";import As from"open";import Ln from"prompts";import{green as gt,dim as F,bold as oe,yellow as Le,cyan as Qt}from"kleur/colors";import{promises as Ht}from"fs";import{homedir as gs}from"os";import{join as qr,dirname as Nl}from"path";var jr=qr(gs(),".anyforge"),_n=qr(jr,"credentials");async function Mr(t){await Ht.mkdir(jr,{recursive:!0,mode:448}),await Ht.writeFile(_n,JSON.stringify(t,null,2),{mode:384})}async function Ye(){try{let t=await Ht.readFile(_n,"utf8");return JSON.parse(t)}catch(t){if(t.code==="ENOENT")return null;throw t}}async function Ur(){try{return await Ht.unlink(_n),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}import{promises as N}from"fs";import{execFileSync as hs}from"child_process";import{homedir as pe}from"os";import{join as B}from"path";import Yt from"prompts";import{dim as re,green as Pn,yellow as Jt}from"kleur/colors";var ke="# === AnyForge Control \u2014 added by `anyforge init` ===",mt="# === end AnyForge Control ===",Pe=".anyforge-bak",ws=/claude_(max|pro|team|enterprise)/i,ys=["CLAUDE_CODE_ENABLE_TELEMETRY","OTEL_METRICS_EXPORTER","OTEL_EXPORTER_OTLP_PROTOCOL","OTEL_EXPORTER_OTLP_ENDPOINT","OTEL_EXPORTER_OTLP_HEADERS","OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"];async function Kr(t){let e=[],n=await Os(t);if(n&&e.push(n),t.scope==="repo"){let r=await vs(t);return r&&e.push(r),e}for(let r of Rs){let o=await r.detect();if(!(!o||!(await Yt({type:"confirm",name:"go",message:`Patch ${r.label} via shell rc (${re(o.path)}) ?`,initial:!0})).go))try{await r.patch(o,t),e.push({label:r.label,path:o.path}),console.log(Pn(" \u2714")+" "+r.label)}catch(s){console.warn(" \u26A0 Skipped "+r.label+": "+s.message)}}return e}async function Os(t){let e=t.scope==="repo"&&t.repoRoot?{dir:B(t.repoRoot,".claude"),file:"settings.local.json"}:{dir:B(pe(),".claude"),file:"settings.json"},n=B(e.dir,e.file);if(!(await Yt({type:"confirm",name:"go",message:`Patch Claude Code config at ${re(n)} ?`,initial:!0})).go)return null;await N.mkdir(e.dir,{recursive:!0});let o=await N.readFile(n,"utf8").catch(()=>"{}"),i;try{i=JSON.parse(o)}catch{i={}}let s=i.env??{},a=s.ANTHROPIC_BASE_URL;return a&&!a.includes(t.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(Jt(" \u26A0 Local LLM proxy detected: ")+re(a)),console.log(re(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(re(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(re(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(re(` from ${n}`)),console.log(),!(await Yt({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await ae(n)&&!await ae(n+Pe)&&await N.copyFile(n,n+Pe),s.ANTHROPIC_BASE_URL=`${t.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=t.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await N.writeFile(n,JSON.stringify(i,null,2)+`
3
- `),console.log(Pn(" \u2714")+" Claude Code"),{label:t.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function zr(t){let e=B(pe(),".claude"),n=B(e,"settings.json");await N.mkdir(e,{recursive:!0});let r=await N.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!$n(s,Jr(t.endpoint))?(console.log(Jt(" \u26A0 An OpenTelemetry endpoint is already configured: ")+re(s)),console.log(re(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(re(" OTEL_EXPORTER_OTLP_ENDPOINT at "+t.endpoint+"/api/otel")),null):(await ae(n)&&!await ae(n+Pe)&&await N.copyFile(n,n+Pe),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${t.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${t.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await N.writeFile(n,JSON.stringify(o,null,2)+`
4
- `),{label:"Claude Code usage telemetry (global)",path:n})}async function vs(t){if(!t.repoRoot)return null;let e=B(t.repoRoot,".env");if(!(await Yt({type:"confirm",name:"go",message:`Write AnyForge env block to ${re(e)} ?`,initial:!0})).go)return null;let r=[ke,`ANYFORGE_API_KEY=${t.apiKey}`,`ANTHROPIC_BASE_URL=${t.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${t.apiKey}`,`OPENAI_BASE_URL=${t.endpoint}/v1/openai`,`OPENAI_API_KEY=${t.apiKey}`,mt,""].join(`
5
- `),o="";try{o=await N.readFile(e,"utf8")}catch{}let i;return o.includes(ke)?i=o.replace(new RegExp(`${ke}[\\s\\S]*?${mt}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
2
+ var ms=Object.defineProperty;var gs=(t,e)=>()=>(t&&(e=t(t=0)),e);var hs=(t,e)=>{for(var n in e)ms(t,n,{get:e[n],enumerable:!0})};var Ar={};hs(Ar,{default:()=>tl});var tl,Ir=gs(()=>{tl={name:"@anyforge/control",version:"0.7.2",description:"AnyForge CLI \u2014 hosted Oracle conversations, a governed LLM proxy, and a scriptable client for approvals, crews, work items and workflows.",license:"Apache-2.0",homepage:"https://anyforge.ai",repository:{type:"git",url:"git+https://github.com/pootonline/sovereign-engineering.git",directory:"packages/control/cli"},publishConfig:{access:"public"},type:"module",main:"dist/cli.js",bin:{anyforge:"dist/cli.js",control:"dist/cli.js"},files:["dist","README.md"],scripts:{build:"esbuild src/cli.ts --bundle --minify --platform=node --format=esm --outfile=dist/cli.js --packages=external && chmod +x dist/cli.js","type-check":"tsc --noEmit",test:"npm run build && node scripts/test.mjs",dev:"tsx src/cli.ts",prepublishOnly:"npm run build","publish:beta":"npm publish --access public --tag beta","publish:stable":"npm publish --access public"},engines:{node:">=22.19.0"},dependencies:{"@earendil-works/pi-tui":"^0.87.1",kleur:"^4.1.5",open:"^10.0.0",prompts:"^2.4.2","proper-lockfile":"^4.1.2"},devDependencies:{"@types/node":"^22.20.0","@types/prompts":"^2.4.9","@types/proper-lockfile":"^4.1.4",esbuild:"^0.25.0","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});import{red as Ji,yellow as El,dim as Ut,bold as z}from"kleur/colors";import{execFileSync as Nn}from"child_process";import xs from"open";import Ln from"prompts";import{green as Ot,dim as q,bold as oe,yellow as Le,cyan as Vt}from"kleur/colors";import{promises as Yt}from"fs";import{homedir as ws}from"os";import{join as jr,dirname as Ul}from"path";var Mr=jr(ws(),".anyforge"),_n=jr(Mr,"credentials");async function Ur(t){await Yt.mkdir(Mr,{recursive:!0,mode:448}),await Yt.writeFile(_n,JSON.stringify(t,null,2),{mode:384})}async function Xe(){try{let t=await Yt.readFile(_n,"utf8");return JSON.parse(t)}catch(t){if(t.code==="ENOENT")return null;throw t}}async function Dr(){try{return await Yt.unlink(_n),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}import{promises as F}from"fs";import{execFileSync as ys}from"child_process";import{homedir as fe}from"os";import{join as W}from"path";import Jt from"prompts";import{dim as re,green as Pn,yellow as Qt}from"kleur/colors";var Ae="# === AnyForge Control \u2014 added by `anyforge init` ===",yt="# === end AnyForge Control ===",Pe=".anyforge-bak",Os=/claude_(max|pro|team|enterprise)/i,vs=["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 zr(t){let e=[],n=await bs(t);if(n&&e.push(n),t.scope==="repo"){let r=await Rs(t);return r&&e.push(r),e}for(let r of As){let o=await r.detect();if(!(!o||!(await Jt({type:"confirm",name:"go",message:`Patch ${r.label} via shell rc (${re(o.path)}) ?`,initial:!0})).go))try{await r.patch(o,t),e.push({label:r.label,path:o.path}),console.log(Pn(" \u2714")+" "+r.label)}catch(s){console.warn(" \u26A0 Skipped "+r.label+": "+s.message)}}return e}async function bs(t){let e=t.scope==="repo"&&t.repoRoot?{dir:W(t.repoRoot,".claude"),file:"settings.local.json"}:{dir:W(fe(),".claude"),file:"settings.json"},n=W(e.dir,e.file);if(!(await Jt({type:"confirm",name:"go",message:`Patch Claude Code config at ${re(n)} ?`,initial:!0})).go)return null;await F.mkdir(e.dir,{recursive:!0});let o=await F.readFile(n,"utf8").catch(()=>"{}"),i;try{i=JSON.parse(o)}catch{i={}}let s=i.env??{},a=s.ANTHROPIC_BASE_URL;return a&&!a.includes(t.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(Qt(" \u26A0 Local LLM proxy detected: ")+re(a)),console.log(re(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(re(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(re(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(re(` from ${n}`)),console.log(),!(await Jt({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await ae(n)&&!await ae(n+Pe)&&await F.copyFile(n,n+Pe),s.ANTHROPIC_BASE_URL=`${t.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=t.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await F.writeFile(n,JSON.stringify(i,null,2)+`
3
+ `),console.log(Pn(" \u2714")+" Claude Code"),{label:t.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function Hr(t){let e=W(fe(),".claude"),n=W(e,"settings.json");await F.mkdir(e,{recursive:!0});let r=await F.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!$n(s,Qr(t.endpoint))?(console.log(Qt(" \u26A0 An OpenTelemetry endpoint is already configured: ")+re(s)),console.log(re(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(re(" OTEL_EXPORTER_OTLP_ENDPOINT at "+t.endpoint+"/api/otel")),null):(await ae(n)&&!await ae(n+Pe)&&await F.copyFile(n,n+Pe),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${t.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${t.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await F.writeFile(n,JSON.stringify(o,null,2)+`
4
+ `),{label:"Claude Code usage telemetry (global)",path:n})}async function Rs(t){if(!t.repoRoot)return null;let e=W(t.repoRoot,".env");if(!(await Jt({type:"confirm",name:"go",message:`Write AnyForge env block to ${re(e)} ?`,initial:!0})).go)return null;let r=[Ae,`ANYFORGE_API_KEY=${t.apiKey}`,`ANTHROPIC_BASE_URL=${t.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${t.apiKey}`,`OPENAI_BASE_URL=${t.endpoint}/v1/openai`,`OPENAI_API_KEY=${t.apiKey}`,yt,""].join(`
5
+ `),o="";try{o=await F.readFile(e,"utf8")}catch{}let i;return o.includes(Ae)?i=o.replace(new RegExp(`${Ae}[\\s\\S]*?${yt}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
6
6
  `)?`${o}${r}`:`${o}
7
- ${r}`,i!==o&&await N.writeFile(e,i),await bs(t.repoRoot),console.log(Pn(" \u2714")+" .env"),{label:".env (repo)",path:e}}async function bs(t){let e=B(t,".gitignore");try{(await N.readFile(e,"utf8")).split(`
8
- `).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(Jt(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(Jt(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}var Rs=[{label:"Cursor (shell hint)",async detect(){let t=B(pe(),".cursor");return await ae(t)?{path:".cursor (shell hint)"}:null},async patch(t,e){await Dr(e)}},{label:"Cline / Continue (shell hint)",async detect(){let t=await ae(B(pe(),".cline")),e=await ae(B(pe(),".continue"));return t||e?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(t,e){await Dr(e)}}];async function Dr(t){let e=[ke,`export ANYFORGE_API_KEY="${t.apiKey}"`,`export ANTHROPIC_BASE_URL="${t.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${t.apiKey}"`,`export OPENAI_BASE_URL="${t.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${t.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",mt,""].join(`
9
- `);for(let n of[".zshrc",".bashrc"]){let r=B(pe(),n);if(!await ae(r))continue;let o=await N.readFile(r,"utf8"),i;o.includes(ke)?i=o.replace(new RegExp(`${ke}[\\s\\S]*?${mt}\\n?`),e):i=o.endsWith(`
7
+ ${r}`,i!==o&&await F.writeFile(e,i),await ks(t.repoRoot),console.log(Pn(" \u2714")+" .env"),{label:".env (repo)",path:e}}async function ks(t){let e=W(t,".gitignore");try{(await F.readFile(e,"utf8")).split(`
8
+ `).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(Qt(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(Qt(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}var As=[{label:"Cursor (shell hint)",async detect(){let t=W(fe(),".cursor");return await ae(t)?{path:".cursor (shell hint)"}:null},async patch(t,e){await Br(e)}},{label:"Cline / Continue (shell hint)",async detect(){let t=await ae(W(fe(),".cline")),e=await ae(W(fe(),".continue"));return t||e?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(t,e){await Br(e)}}];async function Br(t){let e=[Ae,`export ANYFORGE_API_KEY="${t.apiKey}"`,`export ANTHROPIC_BASE_URL="${t.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${t.apiKey}"`,`export OPENAI_BASE_URL="${t.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${t.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",yt,""].join(`
9
+ `);for(let n of[".zshrc",".bashrc"]){let r=W(fe(),n);if(!await ae(r))continue;let o=await F.readFile(r,"utf8"),i;o.includes(Ae)?i=o.replace(new RegExp(`${Ae}[\\s\\S]*?${yt}\\n?`),e):i=o.endsWith(`
10
10
  `)?`${o}
11
11
  ${e}`:`${o}
12
12
 
13
- ${e}`,i!==o&&await N.writeFile(r,i)}}async function ae(t){try{return await N.access(t),!0}catch{return!1}}async function Hr(){try{let t=await N.readFile(B(pe(),".claude.json"),"utf8"),n=JSON.parse(t).oauthAccount,r=n?.organizationType??"";if(n&&ws.test(r))return{isSubscription:!0,plan:/max/i.test(r)?"Max":/pro/i.test(r)?"Pro":/enterprise/i.test(r)?"Enterprise":/team/i.test(r)?"Team":r,email:n.emailAddress??null}}catch{}return{isSubscription:!1,plan:null,email:null}}async function Yr(t={}){let e=t.endpoint?Jr(t.endpoint):null,n=[],r=B(pe(),".claude","settings.json");await Br(r,e)&&n.push(r);for(let i of[".zshrc",".bashrc"]){let s=B(pe(),i);await Wr(s)&&n.push(s)}let o=t.repoRoot??ks(process.cwd());if(o){let i=B(o,".claude","settings.local.json");await Br(i,e)&&n.push(i);let s=B(o,".env");await Wr(s)&&n.push(s)}return{reverted:n}}function $n(t,e){return t?t.includes("anyforge")?!0:e?t.includes(e):!1:!1}async function Br(t,e){if(!await ae(t))return!1;if(await ae(t+Pe))return await N.copyFile(t+Pe,t),await N.unlink(t+Pe).catch(()=>{}),!0;let n;try{n=JSON.parse(await N.readFile(t,"utf8"))}catch{return!1}let r=n.env;if(!r)return!1;let o=!1,i=[["ANTHROPIC_BASE_URL","ANTHROPIC_AUTH_TOKEN"],["OPENAI_BASE_URL","OPENAI_API_KEY"]];for(let[s,a]of i)$n(r[s],e)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),$n(r.OTEL_EXPORTER_OTLP_ENDPOINT,e))for(let s of ys)s in r&&(delete r[s],o=!0);return o?(Object.keys(r).length===0&&delete n.env,await N.writeFile(t,JSON.stringify(n,null,2)+`
14
- `),!0):!1}async function Wr(t){let e;try{e=await N.readFile(t,"utf8")}catch{return!1}if(!e.includes(ke))return!1;let n=e.replace(new RegExp(`\\n?${Gr(ke)}[\\s\\S]*?${Gr(mt)}\\n?`),`
13
+ ${e}`,i!==o&&await F.writeFile(r,i)}}async function ae(t){try{return await F.access(t),!0}catch{return!1}}async function Yr(){try{let t=await F.readFile(W(fe(),".claude.json"),"utf8"),n=JSON.parse(t).oauthAccount,r=n?.organizationType??"";if(n&&Os.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 Jr(t={}){let e=t.endpoint?Qr(t.endpoint):null,n=[],r=W(fe(),".claude","settings.json");await Wr(r,e)&&n.push(r);for(let i of[".zshrc",".bashrc"]){let s=W(fe(),i);await Gr(s)&&n.push(s)}let o=t.repoRoot??Is(process.cwd());if(o){let i=W(o,".claude","settings.local.json");await Wr(i,e)&&n.push(i);let s=W(o,".env");await Gr(s)&&n.push(s)}return{reverted:n}}function $n(t,e){return t?t.includes("anyforge")?!0:e?t.includes(e):!1:!1}async function Wr(t,e){if(!await ae(t))return!1;if(await ae(t+Pe))return await F.copyFile(t+Pe,t),await F.unlink(t+Pe).catch(()=>{}),!0;let n;try{n=JSON.parse(await F.readFile(t,"utf8"))}catch{return!1}let r=n.env;if(!r)return!1;let o=!1,i=[["ANTHROPIC_BASE_URL","ANTHROPIC_AUTH_TOKEN"],["OPENAI_BASE_URL","OPENAI_API_KEY"]];for(let[s,a]of i)$n(r[s],e)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),$n(r.OTEL_EXPORTER_OTLP_ENDPOINT,e))for(let s of vs)s in r&&(delete r[s],o=!0);return o?(Object.keys(r).length===0&&delete n.env,await F.writeFile(t,JSON.stringify(n,null,2)+`
14
+ `),!0):!1}async function Gr(t){let e;try{e=await F.readFile(t,"utf8")}catch{return!1}if(!e.includes(Ae))return!1;let n=e.replace(new RegExp(`\\n?${Kr(Ae)}[\\s\\S]*?${Kr(yt)}\\n?`),`
15
15
  `).replace(/\n{3,}/g,`
16
16
 
17
- `);return await N.writeFile(t,n),!0}function Gr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Jr(t){try{return new URL(t).host}catch{return null}}function ks(t){try{return hs("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var Is=2e3,xs=900*1e3;async function Vr(t){let{endpoint:e}=t;console.log(oe("AnyForge Control \u2014 device authorisation")),console.log(F(` endpoint: ${e}`));let n=process.cwd(),r=Qr(n),o=r?$s(r):null,s=await(await fetch(`${e}/api/cli/init`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({repo:o})})).json();if(!s.ok||!s.data)throw new Error(`Could not start the authorisation flow: ${s.error??"unknown error"}`);let{code:a,authUrl:c,pollUrl:u}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${Qt(c)}`),console.log(F(` Code: ${a}`)),console.log();try{await As(c)}catch{}let l=await Ss({pollUrl:u,endpoint:e});await Mr(l),console.log(gt("\u2714")+" API key saved to "+F("~/.anyforge/credentials"));let p=await Hr();if(p.isSubscription&&!t.force){await Ts(p,e,l.apiKey);return}let k=process.cwd(),x=Qr(k),b=await Cs(x),O=await Kr({endpoint:e,apiKey:l.apiKey,scope:b,repoRoot:x});O.length===0?(console.log(Le("No agent configs were patched.")),console.log(F(" Set ANTHROPIC_BASE_URL="+e+"/v1/anthropic and")),console.log(F(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):_s(O),console.log(),p.isSubscription&&t.force&&(console.log(Le(` \u26A0 --force: your Claude ${p.plan??""} subscription login is now shadowed`)),console.log(Le(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(Le(" needs an Anthropic API key on your company. Run ")+oe("anyforge logout")),console.log(Le(" to revert and restore your subscription."))),b==="repo"&&(console.log(F(" Re-run this command in another repo to patch it too,")),console.log(F(' or run from any directory and choose "global" to install system-wide.'))),console.log(oe("Done.")+" Run `anyforge status` to check identity, local setup and recorded activity."),console.log(" MCP access, BYOK inference and optional subscription telemetry are separate. Usage: "+Qt(`${e}/usage`))}async function Ss(t){let e=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-e<xs;){await new Promise(i=>setTimeout(i,Is)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
18
- `),n=0);let o=await(await fetch(t.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+gt("done")+`
17
+ `);return await F.writeFile(t,n),!0}function Kr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Qr(t){try{return new URL(t).host}catch{return null}}function Is(t){try{return ys("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var Ss=2e3,Es=900*1e3;async function Xr(t){let{endpoint:e}=t;console.log(oe("AnyForge Control \u2014 device authorisation")),console.log(q(` endpoint: ${e}`));let n=process.cwd(),r=Vr(n),o=r?Ls(r):null,s=await(await fetch(`${e}/api/cli/init`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({repo:o})})).json();if(!s.ok||!s.data)throw new Error(`Could not start the authorisation flow: ${s.error??"unknown error"}`);let{code:a,authUrl:c,pollUrl:u}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${Vt(c)}`),console.log(q(` Code: ${a}`)),console.log();try{await xs(c)}catch{}let d=await Ts({pollUrl:u,endpoint:e});await Ur(d),console.log(Ot("\u2714")+" API key saved to "+q("~/.anyforge/credentials"));let p=await Yr();if(p.isSubscription&&!t.force){await _s(p,e,d.apiKey);return}let R=process.cwd(),I=Vr(R),x=await $s(I),O=await zr({endpoint:e,apiKey:d.apiKey,scope:x,repoRoot:I});O.length===0?(console.log(Le("No agent configs were patched.")),console.log(q(" Set ANTHROPIC_BASE_URL="+e+"/v1/anthropic and")),console.log(q(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):Ps(O),console.log(),p.isSubscription&&t.force&&(console.log(Le(` \u26A0 --force: your Claude ${p.plan??""} subscription login is now shadowed`)),console.log(Le(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(Le(" needs an Anthropic API key on your company. Run ")+oe("anyforge logout")),console.log(Le(" to revert and restore your subscription."))),x==="repo"&&(console.log(q(" Re-run this command in another repo to patch it too,")),console.log(q(' or run from any directory and choose "global" to install system-wide.'))),console.log(oe("Done.")+" Run `anyforge status` to check identity, local setup and recorded activity."),console.log(" MCP access, BYOK inference and optional subscription telemetry are separate. Usage: "+Vt(`${e}/usage`))}async function Ts(t){let e=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-e<Es;){await new Promise(i=>setTimeout(i,Ss)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
18
+ `),n=0);let o=await(await fetch(t.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+Ot("done")+`
19
19
  `),{apiKey:o.data.apiKey,companyId:o.data.companyId,endpoint:t.endpoint,savedAt:new Date().toISOString()};if(o.status==="expired"||o.status==="not_found")throw process.stdout.write(`
20
- `),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}function Es(t,e){return["mcp","add","anyforge","--env",`ANYFORGE_API_TOKEN=${e}`,"--env",`ANYFORGE_API_URL=${t}`,"--","npx","-y","@anyforge/mcp-server"]}async function Ts(t,e,n){let r=t.email?` (${t.email})`:"";console.log(),console.log(Le(` \u26A0 Claude ${t.plan??""} subscription login detected${r}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+oe("BYOK-only")+" \u2014 it routes"),console.log(" Claude Code through your own Anthropic API key for metering and"),console.log(" governance. Pointing Claude Code at the proxy would "+oe("override and")),console.log(" "+oe("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+oe("AnyForge")),console.log(" "+oe("MCP server")+" for control (HIL approvals, work items, crews):"),console.log();let o=Es(e,n),i="claude mcp add anyforge -- npx -y @anyforge/mcp-server";if((await Ln({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{Nn("claude",o,{stdio:"inherit"}),console.log(gt(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(Le(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log(F(" Add it manually:")),console.log(" "+i)}else console.log(F(" Add it later with:")),console.log(" "+i);if(console.log(),(await Ln({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts only \u2014 no prompt content)",initial:!0})).go){let c=await zr({endpoint:e,apiKey:n});c&&(console.log(gt(" \u2714")+" Usage telemetry enabled \u2014 view it at "+Qt(`${e}/usage`)),console.log(F(" (written to "+c.path+"; `anyforge logout` removes it)")))}else console.log(F(" Skipped \u2014 your subscription usage stays local to Claude Code."));console.log(),console.log(F(" Want the metered BYOK proxy instead? Re-run with ")+oe("--force")+F(" using an")),console.log(F(" Anthropic API key on your company (this disables your subscription in")),console.log(F(" Claude Code; ")+oe("anyforge logout")+F(" reverts it).")),console.log(),console.log(oe("Done.")+" Run `anyforge status` to check identity, local setup and recorded activity."),console.log(" MCP access, BYOK inference and optional subscription telemetry are separate. Usage: "+Qt(`${e}/usage`))}function Qr(t){try{return Nn("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function Cs(t){return t?(await Ln({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${t}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log(F(" Not a git repo root \u2014 installing globally.")),console.log(F(" Run this from a repo root if you want a per-repo install instead.")),"global")}function _s(t){console.log(gt("\u2714")+" Patched "+t.length+" agent config"+(t.length===1?"":"s")+":");for(let e of t)console.log(` ${F("\u2022")} ${e.label} ${F("("+e.path+")")}`)}function $s(t){try{let e=Nn("git",["remote","get-url","origin"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=e.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=e.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}import{dim as qn,yellow as Fs,bold as qs}from"kleur/colors";var m={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,INTERRUPTED:130},f=class extends Error{exitCode;hint;constructor(e,n=m.FAILURE,r){super(e),this.name="CliError",this.exitCode=n,this.hint=r}},y=class extends f{constructor(e,n){super(e,m.USAGE,n),this.name="UsageError"}},ce=class extends f{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",m.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},Ae=class extends f{code;status;constructor(e,n,r){super(r?`${e}: ${r}`:e,m.API_ERROR,Ps(e,n)),this.name="ControlApiError",this.code=e,this.status=n}};function Ps(t,e){if(t==="missing_api_key"||t==="invalid_api_key"||t==="invalid_token"||e===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(t==="insufficient_scope"||e===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(e===404)return"No such id in this company. Check it with the matching list command.";if(e===429)return"Rate limited. Retry after a short pause."}var Xr="https://crew.anyforge.ai";async function Ie(t){let e=process.env.ANYFORGE_API_TOKEN,n=t||process.env.ANYFORGE_API_URL;if(e)return{apiKey:e,endpoint:n||Xr};let r=await Ye();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||Xr};throw new ce}async function T(t,e,n,r){let o=`${t.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new f(`Cannot reach ${t.endpoint}: ${a instanceof Error?a.message:String(a)}`,m.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new f(`Non-JSON response from ${o} (HTTP ${i.status}).`,m.FAILURE)}if(!i.ok||s.ok===!1){let a=typeof s.error=="string"?s.error:`http_${i.status}`,c=typeof s.message=="string"?s.message:typeof s.detail=="string"?s.detail:void 0;throw new Ae(a,i.status,c)}return s.data}function X(t){let e=Object.entries(t).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return e.length?`?${e.join("&")}`:""}async function ht(t){return T(t,"GET","/me")}function Fn(t,e,n,r){let o=t?.entityLabels?.[e]?.[n];return typeof o=="string"&&o.trim()?o:r}async function Zr(t){try{return await ht(t)}catch{return null}}function eo(t){return[...t].length}function Je(t,e){if(e<=0)return"";let n=[...t];return n.length<=e?t:e===1?"\u2026":`${n.slice(0,e-1).join("")}\u2026`}function J(t,e){if(t.length===0)return"";let n=t.map(i=>e.map(s=>{let a=s.value(i)??"";return s.max?Je(a,s.max):a})),r=e.map((i,s)=>Math.max(eo(i.header),...n.map(a=>eo(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(e.map(i=>i.header)),...n.map(o)].join(`
21
- `)}function S(t){return JSON.stringify(t,null,2)}function to(t,e=Date.now()){let n=Ls(t);if(n===null)return"\u2014";let r=Math.max(0,Math.floor((e-n)/1e3));if(r<60)return`${r}s`;let o=Math.floor(r/60);if(o<60)return`${o}m`;let i=Math.floor(o/60);return i<48?`${i}h`:`${Math.floor(i/24)}d`}function Ls(t){if(typeof t=="number")return Number.isFinite(t)?t:null;if(typeof t=="string"){let e=Date.parse(t);return Number.isNaN(e)?null:e}return null}function C(t,e,n="\u2014"){let r=t[e];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function Y(t,e,n="\u2014"){for(let r of e){let o=t[r];if(typeof o=="string"&&o.trim())return o}return n}function le(t){let e=Array.isArray(t)?t:t&&typeof t=="object"?Ns(t):null;return e?e.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function Ns(t){for(let e of["items","results","rows","data"])if(Array.isArray(t[e]))return t[e];return null}function Vt(t,e,n){let r=t?`last ${t}d`:"all time";return!e||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${t?`${t}d`:"all time"} \u2014 read cap`}async function no(t){let e=await Ie(t.endpoint),n=await ht(e);if(t.json){console.log(S(n));return}console.log(`Company: ${qs(n.companyName??n.companyId)}${n.companyName?qn(` (${n.companyId})`):""}`),console.log(`Endpoint: ${e.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):Fs("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await Ye();console.log(r?qn(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):qn("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}import{green as ro,dim as Xt,yellow as js}from"kleur/colors";async function oo(){let t=await Ye(),e=await Ur(),{reverted:n}=await Yr({endpoint:t?.endpoint??null});if(console.log(e?ro("\u2714")+" Local credentials cleared.":js("No credentials were saved on this machine.")),n.length){console.log(ro("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${Xt("\u2022")} ${r}`);console.log(Xt(" Your previous Claude Code login (if any) is restored."))}else console.log(Xt(" No AnyForge config patches found to revert."));console.log(Xt(" Revoke the key server-side at /settings \u2192 API keys."))}import{readFile as Zt}from"node:fs/promises";import{homedir as Ms}from"node:os";import{dirname as jn,join as fe}from"node:path";function xe(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)?t:{}}async function io(t,e={home:Ms(),cwd:process.cwd(),env:process.env}){let n=t.endpoint.replace(/\/$/,""),r=[],o={};try{o=xe(JSON.parse(await Zt(fe(e.home,".anyforge","credentials"),"utf8")))}catch{}function i(a,c){let u=xe(c),l=xe(u.env),p=Object.values(xe(u.mcpServers));r.push({source:a,readable:!0,mcp:p.some(k=>{let x=xe(k),b=xe(x.env),O=Array.isArray(x.args)?x.args:[],R=b.ANYFORGE_API_TOKEN??e.env.ANYFORGE_API_TOKEN,A=b.ANYFORGE_API_URL??e.env.ANYFORGE_API_URL,z=R??o.apiKey,j=A??(R?"https://crew.anyforge.ai":o.endpoint)??"https://crew.anyforge.ai";return O.includes("@anyforge/mcp-server")&&z===t.apiKey&&j===n}),proxy:l.ANTHROPIC_BASE_URL===`${n}/v1/anthropic`&&l.ANTHROPIC_AUTH_TOKEN===t.apiKey,subscriptionTelemetry:String(l.CLAUDE_CODE_ENABLE_TELEMETRY)==="1"&&(l.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL??l.OTEL_EXPORTER_OTLP_PROTOCOL)==="http/json"&&(l.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===void 0||l.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT===`${n}/api/otel/v1/metrics`)&&l.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE==="delta"&&l.OTEL_METRICS_EXPORTER==="otlp"&&l.OTEL_EXPORTER_OTLP_ENDPOINT===`${n}/api/otel`&&(l.OTEL_EXPORTER_OTLP_METRICS_HEADERS??l.OTEL_EXPORTER_OTLP_HEADERS)===`Authorization=Bearer ${t.apiKey}`})}i("Current shell",{env:e.env});let s=e.cwd;for(;jn(s)!==s;){try{await Zt(fe(s,".git","HEAD"));break}catch{}try{await Zt(fe(s,".git"));break}catch{}s=jn(s)}jn(s)===s&&(s=e.cwd);for(let a of new Set([fe(e.home,".claude","settings.json"),fe(s,".claude","settings.json"),fe(s,".claude","settings.local.json"),fe(s,".mcp.json"),fe(e.home,".claude.json")]))try{let c=JSON.parse(await Zt(a,"utf8"));if(i(a,c),a===fe(e.home,".claude.json")){let u=xe(xe(c).projects)[s];u&&i(`${a} (project)`,u)}}catch(c){c.code!=="ENOENT"&&r.push({source:a,mcp:!1,proxy:!1,subscriptionTelemetry:!1,readable:!1})}return r}var Us=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,Ds=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function d(t){return t.replace(Us,"").replace(Ds,"")}function Mn(t){try{let e=new URL(t);return e.protocol!=="https:"&&e.protocol!=="http:"||!e.hostname||e.username||e.password?null:e.toString()}catch{return null}}function so(t){return t.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(e,n)=>Mn(n)?e:"\x1B]8;;\x07")}function ao(t,e){if(!e||!t.startsWith("/")||t.startsWith("//"))return t;try{return new URL(t,e).toString()}catch{return t}}function co(t,e){return e?t.replace(/(\]\()(<?)(\/(?!\/)[^\s)>]*)/g,(n,r,o,i)=>`${r}${o}${ao(i,e)}`):t}function Un(t,e){let r=d(t).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(s,a,c,u)=>{let l=ao(u.startsWith("<")&&u.endsWith(">")?u.slice(1,-1):u,e),p=Mn(l);return p?`${a}[${c}](${p})`:c}),o=new Map,i=r.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(s,a,c,u,l)=>{let p=Mn(u);return o.set(c.trim().toLowerCase(),p),p?`${a}${p}${l}`:""});return o.size===0?i:i.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(s,a,c,u)=>{let l=(u||c).trim().toLowerCase();return!o.has(l)||o.get(l)?s:c})}function me(t){return typeof t=="string"?d(t):Array.isArray(t)?t.map(e=>me(e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[d(e),me(n)])):t}function lo(t){return t.state==="received"?t.lastRecordedAt??"Timestamp unavailable":t.state==="unattributed"?"Unknown: this credential has no user attribution":t.state==="unavailable"?"Unavailable: retry the check":"No recorded activity for this user in this company"}async function uo(t){let e=await Ie(t.endpoint),n=await T(e,"GET","/connection"),r=await io(e),o={...n,endpoint:e.endpoint,localConfiguration:r};if(t.json)console.log(S(o));else{let i=[`Endpoint: ${e.endpoint}`,`Company: ${n.identity.companyName??n.identity.companyId} (${n.identity.companyId})`,`User: ${n.identity.userId??"Unattributed credential"}`,`Granted scopes: ${n.identity.scopes.join(", ")||"none"} (individual actions also enforce role permissions)`,`Control API: authenticated at ${n.checkedAt}`,"MCP: shared Control API verified; confirm the MCP connection in your agent client."];for(let[s,a]of[["mcp","MCP"],["proxy","Inference proxy"],["subscriptionTelemetry","Subscription telemetry"]]){let c=r.filter(u=>u[s]).map(u=>u.source);i.push(`${a} matching local settings: ${c.join(", ")||"not detected"}`)}for(let s of r.filter(a=>!a.readable))i.push(`Could not inspect: ${s.source}`);i.push("Settings are observations, not proof of effective client configuration; managed settings and other clients are not inspected.",`Latest recorded proxy usage: ${lo(n.proxy)}`,`Latest recorded subscription telemetry: ${lo(n.subscriptionTelemetry)}`,"Activity is for this user across devices, not proof that this installation is working now.","Inference forwarding was not tested. The proxy needs a company BYOK provider key.","Subscription inference stays with your provider. Optional telemetry records token counts and estimated cost, not prompts or full traces.",`Usage: ${e.endpoint.replace(/\/$/,"")}/usage`,`Traces: ${e.endpoint.replace(/\/$/,"")}/traces (MCP access alone does not create inference traces)`),console.log(i.map(d).join(`
22
- `))}[n.proxy,n.subscriptionTelemetry].some(i=>i.state==="unavailable")&&(process.exitCode=1)}import{spawn as Bs}from"node:child_process";import{readFile as Ws}from"node:fs/promises";import{red as wt,green as Dn,yellow as Gs,dim as yt,bold as po}from"kleur/colors";async function fo(t){let e=await Ks(t.patchFile);e.trim()||(process.stderr.write(wt(`Empty patch \u2014 nothing to apply.
23
- `)),process.exit(1));let n=zs(e);process.stderr.write(yt(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+Dn(`+${n.added}`)+" "+wt(`-${n.removed}`)+`
24
- `);let r=await Bn(["apply","--check"],e);if(r.code!==0){if(t.threeWay){let i=await Bn(["apply","--3way"],e);i.code!==0&&(process.stderr.write(wt(`3-way apply failed:
20
+ `),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}function Cs(t,e){return["mcp","add","anyforge","--env",`ANYFORGE_API_TOKEN=${e}`,"--env",`ANYFORGE_API_URL=${t}`,"--","npx","-y","@anyforge/mcp-server"]}async function _s(t,e,n){let r=t.email?` (${t.email})`:"";console.log(),console.log(Le(` \u26A0 Claude ${t.plan??""} subscription login detected${r}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+oe("BYOK-only")+" \u2014 it routes"),console.log(" Claude Code through your own Anthropic API key for metering and"),console.log(" governance. Pointing Claude Code at the proxy would "+oe("override and")),console.log(" "+oe("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+oe("AnyForge")),console.log(" "+oe("MCP server")+" for control (HIL approvals, work items, crews):"),console.log();let o=Cs(e,n),i="claude mcp add anyforge -- npx -y @anyforge/mcp-server";if((await Ln({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{Nn("claude",o,{stdio:"inherit"}),console.log(Ot(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(Le(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log(q(" Add it manually:")),console.log(" "+i)}else console.log(q(" Add it later with:")),console.log(" "+i);if(console.log(),(await Ln({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts only \u2014 no prompt content)",initial:!0})).go){let c=await Hr({endpoint:e,apiKey:n});c&&(console.log(Ot(" \u2714")+" Usage telemetry enabled \u2014 view it at "+Vt(`${e}/usage`)),console.log(q(" (written to "+c.path+"; `anyforge logout` removes it)")))}else console.log(q(" Skipped \u2014 your subscription usage stays local to Claude Code."));console.log(),console.log(q(" Want the metered BYOK proxy instead? Re-run with ")+oe("--force")+q(" using an")),console.log(q(" Anthropic API key on your company (this disables your subscription in")),console.log(q(" Claude Code; ")+oe("anyforge logout")+q(" reverts it).")),console.log(),console.log(oe("Done.")+" Run `anyforge status` to check identity, local setup and recorded activity."),console.log(" MCP access, BYOK inference and optional subscription telemetry are separate. Usage: "+Vt(`${e}/usage`))}function Vr(t){try{return Nn("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function $s(t){return t?(await Ln({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${t}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log(q(" Not a git repo root \u2014 installing globally.")),console.log(q(" Run this from a repo root if you want a per-repo install instead.")),"global")}function Ps(t){console.log(Ot("\u2714")+" Patched "+t.length+" agent config"+(t.length===1?"":"s")+":");for(let e of t)console.log(` ${q("\u2022")} ${e.label} ${q("("+e.path+")")}`)}function Ls(t){try{let e=Nn("git",["remote","get-url","origin"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=e.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=e.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}import{dim as qn,yellow as Ds,bold as Bs}from"kleur/colors";var m={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,INTERRUPTED:130},f=class extends Error{exitCode;hint;constructor(e,n=m.FAILURE,r){super(e),this.name="CliError",this.exitCode=n,this.hint=r}},y=class extends f{constructor(e,n){super(e,m.USAGE,n),this.name="UsageError"}},ce=class extends f{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",m.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},Zr=4e3,Ie=class extends f{code;status;details;constructor(e,n,r,o){super(Ns(e,r,o),m.API_ERROR,Fs(e,n)),this.name="ControlApiError",this.code=e,this.status=n,o&&(this.details=o)}};function Ns(t,e,n){let r=e?`${t}: ${e}`:t;if(!n)return r;let o=JSON.stringify(n),i=o.length>Zr?`${o.slice(0,Zr)}\u2026(truncated)`:o;return`${r}
21
+ ${i}`}function Fs(t,e){if(t==="missing_api_key"||t==="invalid_api_key"||t==="invalid_token"||e===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(t==="insufficient_scope"||e===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(e===404)return"No such id in this company. Check it with the matching list command.";if(e===429)return"Rate limited. Retry after a short pause."}var eo="https://crew.anyforge.ai";async function xe(t){let e=process.env.ANYFORGE_API_TOKEN,n=t||process.env.ANYFORGE_API_URL;if(e)return{apiKey:e,endpoint:n||eo};let r=await Xe();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||eo};throw new ce}async function T(t,e,n,r){let o=`${t.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new f(`Cannot reach ${t.endpoint}: ${a instanceof Error?a.message:String(a)}`,m.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new f(`Non-JSON response from ${o} (HTTP ${i.status}).`,m.FAILURE)}if(!i.ok||s.ok===!1){let a=typeof s.error=="string"?s.error:`http_${i.status}`,c=typeof s.message=="string"?s.message:typeof s.detail=="string"?s.detail:void 0;throw new Ie(a,i.status,c,js(s))}return s.data}var qs=new Set(["ok","error","message","detail"]);function js(t){if(!t||typeof t!="object"||Array.isArray(t))return;let e=Object.entries(t).filter(([n,r])=>!qs.has(n)&&r!==void 0);return e.length?Object.fromEntries(e):void 0}function X(t){let e=Object.entries(t).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return e.length?`?${e.join("&")}`:""}async function vt(t){return T(t,"GET","/me")}function Fn(t,e,n,r){let o=t?.entityLabels?.[e]?.[n];return typeof o=="string"&&o.trim()?o:r}async function to(t){try{return await vt(t)}catch{return null}}function no(t){return[...t].length}function Ze(t,e){if(e<=0)return"";let n=[...t];return n.length<=e?t:e===1?"\u2026":`${n.slice(0,e-1).join("")}\u2026`}function J(t,e){if(t.length===0)return"";let n=t.map(i=>e.map(s=>{let a=s.value(i)??"";return s.max?Ze(a,s.max):a})),r=e.map((i,s)=>Math.max(no(i.header),...n.map(a=>no(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(e.map(i=>i.header)),...n.map(o)].join(`
22
+ `)}function S(t){return JSON.stringify(t,null,2)}function ro(t,e=Date.now()){let n=Ms(t);if(n===null)return"\u2014";let r=Math.max(0,Math.floor((e-n)/1e3));if(r<60)return`${r}s`;let o=Math.floor(r/60);if(o<60)return`${o}m`;let i=Math.floor(o/60);return i<48?`${i}h`:`${Math.floor(i/24)}d`}function Ms(t){if(typeof t=="number")return Number.isFinite(t)?t:null;if(typeof t=="string"){let e=Date.parse(t);return Number.isNaN(e)?null:e}return null}function C(t,e,n="\u2014"){let r=t[e];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function Y(t,e,n="\u2014"){for(let r of e){let o=t[r];if(typeof o=="string"&&o.trim())return o}return n}function le(t){let e=Array.isArray(t)?t:t&&typeof t=="object"?Us(t):null;return e?e.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function Us(t){for(let e of["items","results","rows","data"])if(Array.isArray(t[e]))return t[e];return null}function Xt(t,e,n){let r=t?`last ${t}d`:"all time";return!e||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${t?`${t}d`:"all time"} \u2014 read cap`}async function oo(t){let e=await xe(t.endpoint),n=await vt(e);if(t.json){console.log(S(n));return}console.log(`Company: ${Bs(n.companyName??n.companyId)}${n.companyName?qn(` (${n.companyId})`):""}`),console.log(`Endpoint: ${e.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):Ds("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await Xe();console.log(r?qn(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):qn("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}import{green as io,dim as Zt,yellow as Ws}from"kleur/colors";async function so(){let t=await Xe(),e=await Dr(),{reverted:n}=await Jr({endpoint:t?.endpoint??null});if(console.log(e?io("\u2714")+" Local credentials cleared.":Ws("No credentials were saved on this machine.")),n.length){console.log(io("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${Zt("\u2022")} ${r}`);console.log(Zt(" Your previous Claude Code login (if any) is restored."))}else console.log(Zt(" No AnyForge config patches found to revert."));console.log(Zt(" Revoke the key server-side at /settings \u2192 API keys."))}import{readFile as en}from"node:fs/promises";import{homedir as Gs}from"node:os";import{dirname as jn,join as me}from"node:path";function Se(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)?t:{}}async function ao(t,e={home:Gs(),cwd:process.cwd(),env:process.env}){let n=t.endpoint.replace(/\/$/,""),r=[],o={};try{o=Se(JSON.parse(await en(me(e.home,".anyforge","credentials"),"utf8")))}catch{}function i(a,c){let u=Se(c),d=Se(u.env),p=Object.values(Se(u.mcpServers));r.push({source:a,readable:!0,mcp:p.some(R=>{let I=Se(R),x=Se(I.env),O=Array.isArray(I.args)?I.args:[],v=x.ANYFORGE_API_TOKEN??e.env.ANYFORGE_API_TOKEN,k=x.ANYFORGE_API_URL??e.env.ANYFORGE_API_URL,P=v??o.apiKey,j=k??(v?"https://crew.anyforge.ai":o.endpoint)??"https://crew.anyforge.ai";return O.includes("@anyforge/mcp-server")&&P===t.apiKey&&j===n}),proxy:d.ANTHROPIC_BASE_URL===`${n}/v1/anthropic`&&d.ANTHROPIC_AUTH_TOKEN===t.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 ${t.apiKey}`})}i("Current shell",{env:e.env});let s=e.cwd;for(;jn(s)!==s;){try{await en(me(s,".git","HEAD"));break}catch{}try{await en(me(s,".git"));break}catch{}s=jn(s)}jn(s)===s&&(s=e.cwd);for(let a of new Set([me(e.home,".claude","settings.json"),me(s,".claude","settings.json"),me(s,".claude","settings.local.json"),me(s,".mcp.json"),me(e.home,".claude.json")]))try{let c=JSON.parse(await en(a,"utf8"));if(i(a,c),a===me(e.home,".claude.json")){let u=Se(Se(c).projects)[s];u&&i(`${a} (project)`,u)}}catch(c){c.code!=="ENOENT"&&r.push({source:a,mcp:!1,proxy:!1,subscriptionTelemetry:!1,readable:!1})}return r}var Ks=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,zs=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function l(t){return t.replace(Ks,"").replace(zs,"")}function Mn(t){try{let e=new URL(t);return e.protocol!=="https:"&&e.protocol!=="http:"||!e.hostname||e.username||e.password?null:e.toString()}catch{return null}}function co(t){return t.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(e,n)=>Mn(n)?e:"\x1B]8;;\x07")}function lo(t,e){if(!e||!t.startsWith("/")||t.startsWith("//"))return t;try{return new URL(t,e).toString()}catch{return t}}function uo(t,e){return e?t.replace(/(\]\()(<?)(\/(?!\/)[^\s)>]*)/g,(n,r,o,i)=>`${r}${o}${lo(i,e)}`):t}function Un(t,e){let r=l(t).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(s,a,c,u)=>{let d=lo(u.startsWith("<")&&u.endsWith(">")?u.slice(1,-1):u,e),p=Mn(d);return p?`${a}[${c}](${p})`:c}),o=new Map,i=r.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(s,a,c,u,d)=>{let p=Mn(u);return o.set(c.trim().toLowerCase(),p),p?`${a}${p}${d}`:""});return o.size===0?i:i.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(s,a,c,u)=>{let d=(u||c).trim().toLowerCase();return!o.has(d)||o.get(d)?s:c})}function ge(t){return typeof t=="string"?l(t):Array.isArray(t)?t.map(e=>ge(e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[l(e),ge(n)])):t}function po(t){return t.state==="received"?t.lastRecordedAt??"Timestamp unavailable":t.state==="unattributed"?"Unknown: this credential has no user attribution":t.state==="unavailable"?"Unavailable: retry the check":"No recorded activity for this user in this company"}async function fo(t){let e=await xe(t.endpoint),n=await T(e,"GET","/connection"),r=await ao(e),o={...n,endpoint:e.endpoint,localConfiguration:r};if(t.json)console.log(S(o));else{let i=[`Endpoint: ${e.endpoint}`,`Company: ${n.identity.companyName??n.identity.companyId} (${n.identity.companyId})`,`User: ${n.identity.userId??"Unattributed credential"}`,`Granted scopes: ${n.identity.scopes.join(", ")||"none"} (individual actions also enforce role permissions)`,`Control API: authenticated at ${n.checkedAt}`,"MCP: shared Control API verified; confirm the MCP connection in your agent client."];for(let[s,a]of[["mcp","MCP"],["proxy","Inference proxy"],["subscriptionTelemetry","Subscription telemetry"]]){let c=r.filter(u=>u[s]).map(u=>u.source);i.push(`${a} matching local settings: ${c.join(", ")||"not detected"}`)}for(let s of r.filter(a=>!a.readable))i.push(`Could not inspect: ${s.source}`);i.push("Settings are observations, not proof of effective client configuration; managed settings and other clients are not inspected.",`Latest recorded proxy usage: ${po(n.proxy)}`,`Latest recorded subscription telemetry: ${po(n.subscriptionTelemetry)}`,"Activity is for this user across devices, not proof that this installation is working now.","Inference forwarding was not tested. The proxy needs a company BYOK provider key.","Subscription inference stays with your provider. Optional telemetry records token counts and estimated cost, not prompts or full traces.",`Usage: ${e.endpoint.replace(/\/$/,"")}/usage`,`Traces: ${e.endpoint.replace(/\/$/,"")}/traces (MCP access alone does not create inference traces)`),console.log(i.map(l).join(`
23
+ `))}[n.proxy,n.subscriptionTelemetry].some(i=>i.state==="unavailable")&&(process.exitCode=1)}import{spawn as Hs}from"node:child_process";import{readFile as Ys}from"node:fs/promises";import{red as bt,green as Dn,yellow as Js,dim as Rt,bold as mo}from"kleur/colors";async function go(t){let e=await Qs(t.patchFile);e.trim()||(process.stderr.write(bt(`Empty patch \u2014 nothing to apply.
24
+ `)),process.exit(1));let n=Vs(e);process.stderr.write(Rt(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+Dn(`+${n.added}`)+" "+bt(`-${n.removed}`)+`
25
+ `);let r=await Bn(["apply","--check"],e);if(r.code!==0){if(t.threeWay){let i=await Bn(["apply","--3way"],e);i.code!==0&&(process.stderr.write(bt(`3-way apply failed:
25
26
  `)+i.stderr+`
26
- `),process.exit(1)),process.stderr.write(Gs(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
27
- `));return}process.stderr.write(wt(`Patch does not apply cleanly:
27
+ `),process.exit(1)),process.stderr.write(Js(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
28
+ `));return}process.stderr.write(bt(`Patch does not apply cleanly:
28
29
  `)+r.stderr+`
29
- `),process.stderr.write(yt("Try ")+po("--3way")+yt(` to attempt a 3-way merge against the index.
30
+ `),process.stderr.write(Rt("Try ")+mo("--3way")+Rt(` to attempt a 3-way merge against the index.
30
31
  `)),process.exit(1)}if(t.dryRun){process.stderr.write(Dn(`\u2713 Patch would apply cleanly.
31
- `));return}let o=await Bn(["apply"],e);o.code!==0&&(process.stderr.write(wt(`git apply failed:
32
+ `));return}let o=await Bn(["apply"],e);o.code!==0&&(process.stderr.write(bt(`git apply failed:
32
33
  `)+o.stderr+`
33
34
  `),process.exit(1)),process.stderr.write(Dn(`\u2713 Applied.
34
- `)),n.files>0&&process.stderr.write(yt(" Run ")+po("git diff --stat")+yt(` to review.
35
- `))}async function Ks(t){if(t)return await Ws(t,"utf8");let e=[];for await(let n of process.stdin)e.push(n);return Buffer.concat(e).toString("utf8")}function Bn(t,e){return new Promise((n,r)=>{let o=Bs("git",t,{stdio:["pipe","pipe","pipe"]}),i="",s="";o.stdout.on("data",a=>{i+=a.toString()}),o.stderr.on("data",a=>{s+=a.toString()}),o.on("error",r),o.on("close",a=>n({code:a??0,stdout:i,stderr:s})),o.stdin.write(e),o.stdin.end()})}function zs(t){let e=0,n=0,r=0;for(let o of t.split(`
36
- `))if(o.startsWith("diff --git"))e+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return e===0&&(n>0||r>0)&&(e=(t.match(/^\+\+\+ /gm)??[]).length),{files:e,added:n,removed:r}}import{bold as Hs,dim as Wn,green as Ys,red as Js}from"kleur/colors";async function mo(t){let e=await T(t.creds,"GET",`/hil${X({limit:t.limit})}`);if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(Wn("No approvals pending."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"CREW",value:r=>C(r,"crewId"),max:24},{header:"AGE",value:r=>to(r.requestedAt)},{header:"SUMMARY",value:r=>Y(r,["planSummary","summary","title","description"]),max:60}])),console.log(Wn(`
37
- ${n.length} pending \xB7 approve with `)+Hs("anyforge approve <id>"))}async function Gn(t){if(!t.approvalId)throw new y(`${t.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let e=await T(t.creds,"POST",`/hil/${encodeURIComponent(t.approvalId)}`,{decision:t.decision,...t.notes?{notes:t.notes}:{}});if(t.json){console.log(S(e));return}let n=t.decision==="APPROVED"?Ys("Approved"):Js("Rejected");console.log(`${n} ${t.approvalId}`);let r=e&&typeof e=="object"?e.signature:void 0;typeof r=="string"&&r&&console.log(Wn(`Audit signature: ${r}`))}import{bold as Qs,dim as Kn}from"kleur/colors";async function go(t){let e=await T(t.creds,"GET",`/crews${X({status:t.status,activeOnly:t.activeOnly,limit:t.limit})}`);if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(Kn(t.activeOnly?"No active crews.":"No crews."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>C(r,"status")},{header:"TASK",value:r=>Y(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>Y(r,["errorMessage"],""),max:40}]))}async function ho(t){if(!t.crewId)throw new y("crew requires a crew id.","List them with `anyforge crews`.");let e=await T(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}${X({messages:t.messages})}`);if(t.json){console.log(S(e));return}let n=e?.crew&&typeof e.crew=="object"?e.crew:e;console.log(`${Qs(Vs(Y(n,["taskDescription"],C(n,"id"))))}`),console.log(`Status: ${C(n,"status")}`),console.log(`Repo: ${Y(n,["githubRepo"])}`);let r=C(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=C(n,"url","");o&&console.log(`Console: ${o}`);let i=le(e?.chat);if(i.length>0){console.log(Kn(`
38
- Last ${i.length} messages:`));for(let s of i){let a=Y(s,["agentRole","role","author","agent","type"],"?"),c=Y(s,["content","body","text","summary"],"");c&&console.log(`${Kn(`[${a}]`)} ${Je(c.replace(/\s+/g," "),160)}`)}}}async function zn(t){if(!t.crewId)throw new y(`${t.action} requires a crew id.`,"List them with `anyforge crews`.");let e=await T(t.creds,"POST",`/crews/${encodeURIComponent(t.crewId)}/${t.action}`);if(t.json){console.log(S(e));return}console.log(`${t.action==="halt"?"Halted":"Resumed"} ${t.crewId}`)}function Vs(t){return Je(t.split(/\r?\n/).find(e=>e.trim())?.trim()??t,80)}import{bold as Xs,dim as Qe,red as wo,yellow as Oo}from"kleur/colors";var Zs=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),ea=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),ta={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 vo(t){if(!t.workItemId)throw new y("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let e=await T(t.creds,"PATCH",`/work/${encodeURIComponent(t.workItemId)}`,{action:"dispatch",...t.profileId?{runProfileId:t.profileId}:{}});if(t.json&&!t.follow){console.log(S(e));return}let n=typeof e?.crewId=="string"?e.crewId:"";if(!n)throw new f("Dispatch was accepted but returned no crew id.",m.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of e?.warnings??[])console.error(Oo(`warning: ${r}`));if(!t.follow){console.log(`Started ${Xs(n)} on ${t.workItemId}`),console.log(Qe(`Follow it with \`anyforge crew follow ${n}\``));return}await Hn({creds:t.creds,json:t.json,crewId:n,intervalSeconds:t.intervalSeconds})}var na=5,ra=10,oa=120,yo=30;async function Hn(t){if(!t.crewId)throw new y("crew follow requires a crew id.","List them with `anyforge crews --active`.");let e=Math.min(Math.max(t.intervalSeconds??ra,na),oa)*1e3,n=Date.now()+yo*6e4,r=new Set,o="",i=!1;for(;;){let s=await T(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}?messages=50`),a=s?.crew??{},c=C(a,"status","");for(let u of s?.chat??[]){let l=C(u,"id","");!l||r.has(l)||(r.add(l),i&&!t.json&&ia(u))}if(i=!0,c&&c!==o&&(t.json||console.log(Qe(`\u2500\u2500 ${c}`)),o=c),ea.has(c)){if(t.json)console.log(S({crewId:t.crewId,status:c,waiting:!0,url:C(a,"url","")}));else{console.log(Oo(`
39
- ${c} \u2014 this crew is waiting on a person.`));let u=ta[c];u&&console.log(Qe(u));let l=C(a,"url","");l&&console.log(Qe(l))}return}if(Zs.has(c)){if(t.json)console.log(S({crewId:t.crewId,status:c,waiting:!1,url:C(a,"url","")}));else{let u=`
40
- ${c}`;console.log(c==="COMPLETE"?u:wo(u));let l=C(a,"prUrl","");l&&console.log(Qe(l));let p=C(a,"errorMessage","");p&&console.log(wo(p))}if(c!=="COMPLETE")throw new f(`Crew ${t.crewId} ended ${c}.`,m.FAILURE);return}if(Date.now()>=n)throw new f(`Still ${c||"running"} after ${yo} minutes \u2014 giving up watching.`,m.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${t.crewId}\`.`);await aa(e)}}function ia(t){let e=C(t,"agentRole","")||C(t,"type","?"),n=sa(t,["content","text","summary"]);n&&console.log(`${Qe(`[${e}]`)} ${Je(n.replace(/\s+/g," "),160)}`)}function sa(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function aa(t){return new Promise(e=>{setTimeout(e,t)})}import{dim as en}from"kleur/colors";var Ro=100;function bo(t){let e=t&&typeof t=="object"?t:{};return{total:typeof e.total=="number"?e.total:null,hasMore:e.hasMore===!0,cursor:typeof e.nextCursor=="string"?e.nextCursor:null}}async function ca(t){let e=s=>`/work${X({status:t.status,type:t.type,priority:t.priority,initiative:t.initiative,program:t.program,search:t.search,assignee:t.assignee,includeArchived:t.includeArchived,limit:t.limit,cursor:s})}`,n=await T(t.creds,"GET",e()),r=le(n),o=bo(n),i=1;if(!t.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<Ro;){let s=await T(t.creds,"GET",e(o.cursor));r.push(...le(s)),o=bo(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function ko(t){let e=await ca(t);if(t.json){console.log(S(t.all?{items:e.rows,total:e.total,hasMore:e.hasMore,nextCursor:null}:e.raw));return}let n=e.rows,r=await Zr(t.creds),o=Fn(r,"work_item","plural","Work items");if(n.length===0){console.log(en(`No ${o.toLowerCase()} match that filter.`));return}console.log(J(n,[{header:"ID",value:c=>C(c,"id")},{header:"PRI",value:c=>C(c,"priority","")},{header:"TYPE",value:c=>C(c,"type","")},{header:"STATUS",value:c=>C(c,"status")},{header:"TITLE",value:c=>Y(c,["title","name","summary"]),max:58}]));let i=(n.length===1?Fn(r,"work_item","singular","work item"):o).toLowerCase(),s=e.total!==null&&e.total!==n.length?`${n.length} of ${e.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=e.hasMore?t.all?en(` \u2014 stopped after ${Ro} pages; narrow the filter`):en(" \u2014 pass --all for the rest"):"";console.log(`${en(`
41
- ${s}`)}${a}`)}import{bold as la,dim as tn}from"kleur/colors";async function Ao(t){let e=await T(t.creds,"GET","/workflows");if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(tn("No workflows defined."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>Y(r,["status","state"],"")},{header:"NAME",value:r=>Y(r,["name","title"]),max:58}])),console.log(tn(`
42
- Dispatch with `)+la("anyforge run <id>"))}async function Io(t){if(!t.workflowId)throw new y("run requires a workflow id.","List them with `anyforge workflows`.");let e;if(t.input!==void 0){try{e=JSON.parse(t.input)}catch(o){throw new y(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!e||typeof e!="object"||Array.isArray(e))throw new y("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await T(t.creds,"POST",`/workflows/${encodeURIComponent(t.workflowId)}/run`,e===void 0?void 0:{inputs:e});if(t.json){console.log(S(n));return}let r=Y(n??{},["id","runId"],"");console.log(`Queued run ${r||tn("(id not returned)")}`),console.log(tn("Runs pause at gate steps for an operator decision."))}import{dim as da}from"kleur/colors";async function xo(t){let e=t.question?.trim();if(!e)throw new y("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!t.json&&process.stderr.isTTY&&process.stderr.write(da(`Asking the Oracle (this can take a few minutes)\u2026
43
- `));let n=await T(t.creds,"POST","/oracle",{question:e,...t.context?{context:t.context}:{}});if(t.json){console.log(S(n));return}let r=n&&typeof n=="object"?["answer","text","content","response"].map(o=>n[o]).find(o=>typeof o=="string"&&o.trim()):void 0;console.log(typeof r=="string"?r:S(n))}import{bold as Yn,dim as So,green as ua,yellow as pa}from"kleur/colors";function fa(t){return typeof t=="number"?`${Math.round(t*100)}%`:"\u2014"}async function Eo(t){let e=await T(t.creds,"GET",`/backtest-corpus${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=e.incidentsInWindow??0,r=e.backTestable??0,o=e.windowDays?`last ${e.windowDays}d`:"all time";console.log(`${Yn(String(r))} of ${Yn(String(n))} incidents are back-testable `+So(`(${fa(e.coverage)} \xB7 ${o})`)),e.viable?console.log(ua("Enough to run a back-test.")):console.log(pa(`Not yet viable \u2014 ${e.shortfall??0} more needed.`));let i=(e.excluded??[]).filter(s=>s.count>0);i.length>0&&console.log(J(i,[{header:"EXCLUDED",value:s=>String(s.count)},{header:"REASON",value:s=>s.label,max:56}])),e.biggestGap&&console.log(So(`
44
- Biggest fixable gap: `)+Yn(`${e.biggestGap.label} (${e.biggestGap.count})`))}import{bold as nn,dim as Ot,green as ma,yellow as To}from"kleur/colors";var Jn=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";async function Co(t){let e=await T(t.creds,"GET",`/review-interception${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=Vt(e.windowDays,e.truncated,e.oldestReviewMs),r=i=>{console.log(i)};if(r(`${nn(String(e.seriousRaised??0))} serious findings raised across ${nn(String(e.prsReviewed??0))} pull requests ${Ot(`(${n})`)}`),e.verdict==="measured")r(`${ma(String(e.disappearedSerious??0))} no longer raised by the next round \u2014 ${nn(Jn(e.interceptionFloor))} to ${nn(Jn(e.interceptionCeiling))}`),r(Ot(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${e.measurableSerious??0} that had a later round`));else{r(To("Not enough findings had a later round to measure a rate."));for(let i of e.inconclusiveReasons??[])r(Ot(` ${i}`))}let o=(e.byLens??[]).filter(i=>i.serious>0);if(o.length>0&&r(J(o,[{header:"LENS",value:i=>i.lens,max:16},{header:"RAISED",value:i=>String(i.raised)},{header:"SERIOUS",value:i=>String(i.serious)},{header:"CHECKED",value:i=>String(i.measurable)},{header:"GONE",value:i=>String(i.disappeared)}])),e.truncated){let i=e.oldestReviewMs?new Date(e.oldestReviewMs).toISOString().slice(0,10):null;r(To(`
45
- Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}e.reviews&&e.skippedShare!=null&&e.skippedShare>0&&r(Ot(`
46
- ${e.reviews.skipped} of ${e.reviews.total} reviews were skipped (${Jn(e.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of e.caveats??[])r(Ot(`
47
- ${i}`))}import{bold as vt,dim as Ne,green as ga,red as ha,yellow as Qn}from"kleur/colors";var wa=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";function Vn(t){if(typeof t!="number")return"\u2014";if(t<60)return`${t}m`;if(t<1440){let n=Math.floor(t/60);return`${n}h ${Math.round(t-n*60)}m`}let e=Math.floor(t/1440);return`${e}d ${Math.round((t-e*1440)/60)}h`}var ya={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function _o(t){let e=await T(t.creds,"GET",`/review-coverage${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=s=>{console.log(s)},r=Vt(e.windowDays,e.truncated,e.oldestRecordMs);n(`${vt(String(e.pullRequestsReviewed??0))} of ${vt(String(e.pullRequestsSeen??0))} recorded pull requests reviewed ${e.coverageRate!=null?vt(`(${wa(e.coverageRate)})`):""} ${Ne(`(${r})`)}`),e.repositoriesReviewed&&n(`across ${vt(String(e.repositoriesReviewed))} repositories`),n(Ne("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),e.medianLatencyMinutes!=null?(n(`
48
- Feedback reached the author in ${ga(Vn(e.medianLatencyMinutes))} median, ${vt(Vn(e.p90LatencyMinutes))} at p90 ${Ne(`(${e.latencySamples??0} reviews)`)}`),e.medianOnOpenLatencyMinutes!=null&&n(Ne(` ${Vn(e.medianOnOpenLatencyMinutes)} median on pull-request open (${e.onOpenSamples??0} reviews, no quiet period in the way)`))):n(Qn(`
35
+ `)),n.files>0&&process.stderr.write(Rt(" Run ")+mo("git diff --stat")+Rt(` to review.
36
+ `))}async function Qs(t){if(t)return await Ys(t,"utf8");let e=[];for await(let n of process.stdin)e.push(n);return Buffer.concat(e).toString("utf8")}function Bn(t,e){return new Promise((n,r)=>{let o=Hs("git",t,{stdio:["pipe","pipe","pipe"]}),i="",s="";o.stdout.on("data",a=>{i+=a.toString()}),o.stderr.on("data",a=>{s+=a.toString()}),o.on("error",r),o.on("close",a=>n({code:a??0,stdout:i,stderr:s})),o.stdin.write(e),o.stdin.end()})}function Vs(t){let e=0,n=0,r=0;for(let o of t.split(`
37
+ `))if(o.startsWith("diff --git"))e+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return e===0&&(n>0||r>0)&&(e=(t.match(/^\+\+\+ /gm)??[]).length),{files:e,added:n,removed:r}}import{bold as Xs,dim as Wn,green as Zs,red as ea}from"kleur/colors";async function ho(t){let e=await T(t.creds,"GET",`/hil${X({limit:t.limit})}`);if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(Wn("No approvals pending."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"CREW",value:r=>C(r,"crewId"),max:24},{header:"AGE",value:r=>ro(r.requestedAt)},{header:"SUMMARY",value:r=>Y(r,["planSummary","summary","title","description"]),max:60}])),console.log(Wn(`
38
+ ${n.length} pending \xB7 approve with `)+Xs("anyforge approve <id>"))}async function Gn(t){if(!t.approvalId)throw new y(`${t.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let e=await T(t.creds,"POST",`/hil/${encodeURIComponent(t.approvalId)}`,{decision:t.decision,...t.notes?{notes:t.notes}:{}});if(t.json){console.log(S(e));return}let n=t.decision==="APPROVED"?Zs("Approved"):ea("Rejected");console.log(`${n} ${t.approvalId}`);let r=e&&typeof e=="object"?e.signature:void 0;typeof r=="string"&&r&&console.log(Wn(`Audit signature: ${r}`))}import{bold as ta,dim as Kn}from"kleur/colors";async function wo(t){let e=await T(t.creds,"GET",`/crews${X({status:t.status,activeOnly:t.activeOnly,limit:t.limit})}`);if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(Kn(t.activeOnly?"No active crews.":"No crews."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>C(r,"status")},{header:"TASK",value:r=>Y(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>Y(r,["errorMessage"],""),max:40}]))}async function yo(t){if(!t.crewId)throw new y("crew requires a crew id.","List them with `anyforge crews`.");let e=await T(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}${X({messages:t.messages})}`);if(t.json){console.log(S(e));return}let n=e?.crew&&typeof e.crew=="object"?e.crew:e;console.log(`${ta(na(Y(n,["taskDescription"],C(n,"id"))))}`),console.log(`Status: ${C(n,"status")}`),console.log(`Repo: ${Y(n,["githubRepo"])}`);let r=C(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=C(n,"url","");o&&console.log(`Console: ${o}`);let i=le(e?.chat);if(i.length>0){console.log(Kn(`
39
+ Last ${i.length} messages:`));for(let s of i){let a=Y(s,["agentRole","role","author","agent","type"],"?"),c=Y(s,["content","body","text","summary"],"");c&&console.log(`${Kn(`[${a}]`)} ${Ze(c.replace(/\s+/g," "),160)}`)}}}async function zn(t){if(!t.crewId)throw new y(`${t.action} requires a crew id.`,"List them with `anyforge crews`.");let e=await T(t.creds,"POST",`/crews/${encodeURIComponent(t.crewId)}/${t.action}`);if(t.json){console.log(S(e));return}console.log(`${t.action==="halt"?"Halted":"Resumed"} ${t.crewId}`)}function na(t){return Ze(t.split(/\r?\n/).find(e=>e.trim())?.trim()??t,80)}import{bold as ra,dim as et,red as Oo,yellow as bo}from"kleur/colors";var oa=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),ia=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),sa={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 Ro(t){if(!t.workItemId)throw new y("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let e=await T(t.creds,"PATCH",`/work/${encodeURIComponent(t.workItemId)}`,{action:"dispatch",...t.profileId?{runProfileId:t.profileId}:{}});if(t.json&&!t.follow){console.log(S(e));return}let n=typeof e?.crewId=="string"?e.crewId:"";if(!n)throw new f("Dispatch was accepted but returned no crew id.",m.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of e?.warnings??[])console.error(bo(`warning: ${r}`));if(!t.follow){console.log(`Started ${ra(n)} on ${t.workItemId}`),console.log(et(`Follow it with \`anyforge crew follow ${n}\``));return}await Hn({creds:t.creds,json:t.json,crewId:n,intervalSeconds:t.intervalSeconds})}var aa=5,ca=10,la=120,vo=30;async function Hn(t){if(!t.crewId)throw new y("crew follow requires a crew id.","List them with `anyforge crews --active`.");let e=Math.min(Math.max(t.intervalSeconds??ca,aa),la)*1e3,n=Date.now()+vo*6e4,r=new Set,o="",i=!1;for(;;){let s=await T(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}?messages=50`),a=s?.crew??{},c=C(a,"status","");for(let u of s?.chat??[]){let d=C(u,"id","");!d||r.has(d)||(r.add(d),i&&!t.json&&da(u))}if(i=!0,c&&c!==o&&(t.json||console.log(et(`\u2500\u2500 ${c}`)),o=c),ia.has(c)){if(t.json)console.log(S({crewId:t.crewId,status:c,waiting:!0,url:C(a,"url","")}));else{console.log(bo(`
40
+ ${c} \u2014 this crew is waiting on a person.`));let u=sa[c];u&&console.log(et(u));let d=C(a,"url","");d&&console.log(et(d))}return}if(oa.has(c)){if(t.json)console.log(S({crewId:t.crewId,status:c,waiting:!1,url:C(a,"url","")}));else{let u=`
41
+ ${c}`;console.log(c==="COMPLETE"?u:Oo(u));let d=C(a,"prUrl","");d&&console.log(et(d));let p=C(a,"errorMessage","");p&&console.log(Oo(p))}if(c!=="COMPLETE")throw new f(`Crew ${t.crewId} ended ${c}.`,m.FAILURE);return}if(Date.now()>=n)throw new f(`Still ${c||"running"} after ${vo} minutes \u2014 giving up watching.`,m.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${t.crewId}\`.`);await pa(e)}}function da(t){let e=C(t,"agentRole","")||C(t,"type","?"),n=ua(t,["content","text","summary"]);n&&console.log(`${et(`[${e}]`)} ${Ze(n.replace(/\s+/g," "),160)}`)}function ua(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function pa(t){return new Promise(e=>{setTimeout(e,t)})}import{dim as tn}from"kleur/colors";var Ao=100;function ko(t){let e=t&&typeof t=="object"?t:{};return{total:typeof e.total=="number"?e.total:null,hasMore:e.hasMore===!0,cursor:typeof e.nextCursor=="string"?e.nextCursor:null}}async function fa(t){let e=s=>`/work${X({status:t.status,type:t.type,priority:t.priority,initiative:t.initiative,program:t.program,search:t.search,assignee:t.assignee,includeArchived:t.includeArchived,limit:t.limit,cursor:s})}`,n=await T(t.creds,"GET",e()),r=le(n),o=ko(n),i=1;if(!t.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<Ao;){let s=await T(t.creds,"GET",e(o.cursor));r.push(...le(s)),o=ko(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function Io(t){let e=await fa(t);if(t.json){console.log(S(t.all?{items:e.rows,total:e.total,hasMore:e.hasMore,nextCursor:null}:e.raw));return}let n=e.rows,r=await to(t.creds),o=Fn(r,"work_item","plural","Work items");if(n.length===0){console.log(tn(`No ${o.toLowerCase()} match that filter.`));return}console.log(J(n,[{header:"ID",value:c=>C(c,"id")},{header:"PRI",value:c=>C(c,"priority","")},{header:"TYPE",value:c=>C(c,"type","")},{header:"STATUS",value:c=>C(c,"status")},{header:"TITLE",value:c=>Y(c,["title","name","summary"]),max:58}]));let i=(n.length===1?Fn(r,"work_item","singular","work item"):o).toLowerCase(),s=e.total!==null&&e.total!==n.length?`${n.length} of ${e.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=e.hasMore?t.all?tn(` \u2014 stopped after ${Ao} pages; narrow the filter`):tn(" \u2014 pass --all for the rest"):"";console.log(`${tn(`
42
+ ${s}`)}${a}`)}import{bold as ma,dim as nn}from"kleur/colors";async function xo(t){let e=await T(t.creds,"GET","/workflows");if(t.json){console.log(S(e));return}let n=le(e);if(n.length===0){console.log(nn("No workflows defined."));return}console.log(J(n,[{header:"ID",value:r=>C(r,"id")},{header:"STATUS",value:r=>Y(r,["status","state"],"")},{header:"NAME",value:r=>Y(r,["name","title"]),max:58}])),console.log(nn(`
43
+ Dispatch with `)+ma("anyforge run <id>"))}async function So(t){if(!t.workflowId)throw new y("run requires a workflow id.","List them with `anyforge workflows`.");let e;if(t.input!==void 0){try{e=JSON.parse(t.input)}catch(o){throw new y(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!e||typeof e!="object"||Array.isArray(e))throw new y("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await T(t.creds,"POST",`/workflows/${encodeURIComponent(t.workflowId)}/run`,e===void 0?void 0:{inputs:e});if(t.json){console.log(S(n));return}let r=Y(n??{},["id","runId"],"");console.log(`Queued run ${r||nn("(id not returned)")}`),console.log(nn("Runs pause at gate steps for an operator decision."))}import{dim as ga}from"kleur/colors";async function Eo(t){let e=t.question?.trim();if(!e)throw new y("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!t.json&&process.stderr.isTTY&&process.stderr.write(ga(`Asking the Oracle (this can take a few minutes)\u2026
44
+ `));let n=await T(t.creds,"POST","/oracle",{question:e,...t.context?{context:t.context}:{}});if(t.json){console.log(S(n));return}let r=n&&typeof n=="object"?["answer","text","content","response"].map(o=>n[o]).find(o=>typeof o=="string"&&o.trim()):void 0;console.log(typeof r=="string"?r:S(n))}import{bold as Yn,dim as To,green as ha,yellow as wa}from"kleur/colors";function ya(t){return typeof t=="number"?`${Math.round(t*100)}%`:"\u2014"}async function Co(t){let e=await T(t.creds,"GET",`/backtest-corpus${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=e.incidentsInWindow??0,r=e.backTestable??0,o=e.windowDays?`last ${e.windowDays}d`:"all time";console.log(`${Yn(String(r))} of ${Yn(String(n))} incidents are back-testable `+To(`(${ya(e.coverage)} \xB7 ${o})`)),e.viable?console.log(ha("Enough to run a back-test.")):console.log(wa(`Not yet viable \u2014 ${e.shortfall??0} more needed.`));let i=(e.excluded??[]).filter(s=>s.count>0);i.length>0&&console.log(J(i,[{header:"EXCLUDED",value:s=>String(s.count)},{header:"REASON",value:s=>s.label,max:56}])),e.biggestGap&&console.log(To(`
45
+ Biggest fixable gap: `)+Yn(`${e.biggestGap.label} (${e.biggestGap.count})`))}import{bold as rn,dim as kt,green as Oa,yellow as _o}from"kleur/colors";var Jn=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";async function $o(t){let e=await T(t.creds,"GET",`/review-interception${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=Xt(e.windowDays,e.truncated,e.oldestReviewMs),r=i=>{console.log(i)};if(r(`${rn(String(e.seriousRaised??0))} serious findings raised across ${rn(String(e.prsReviewed??0))} pull requests ${kt(`(${n})`)}`),e.verdict==="measured")r(`${Oa(String(e.disappearedSerious??0))} no longer raised by the next round \u2014 ${rn(Jn(e.interceptionFloor))} to ${rn(Jn(e.interceptionCeiling))}`),r(kt(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${e.measurableSerious??0} that had a later round`));else{r(_o("Not enough findings had a later round to measure a rate."));for(let i of e.inconclusiveReasons??[])r(kt(` ${i}`))}let o=(e.byLens??[]).filter(i=>i.serious>0);if(o.length>0&&r(J(o,[{header:"LENS",value:i=>i.lens,max:16},{header:"RAISED",value:i=>String(i.raised)},{header:"SERIOUS",value:i=>String(i.serious)},{header:"CHECKED",value:i=>String(i.measurable)},{header:"GONE",value:i=>String(i.disappeared)}])),e.truncated){let i=e.oldestReviewMs?new Date(e.oldestReviewMs).toISOString().slice(0,10):null;r(_o(`
46
+ Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}e.reviews&&e.skippedShare!=null&&e.skippedShare>0&&r(kt(`
47
+ ${e.reviews.skipped} of ${e.reviews.total} reviews were skipped (${Jn(e.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of e.caveats??[])r(kt(`
48
+ ${i}`))}import{bold as At,dim as Ne,green as va,red as ba,yellow as Qn}from"kleur/colors";var Ra=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";function Vn(t){if(typeof t!="number")return"\u2014";if(t<60)return`${t}m`;if(t<1440){let n=Math.floor(t/60);return`${n}h ${Math.round(t-n*60)}m`}let e=Math.floor(t/1440);return`${e}d ${Math.round((t-e*1440)/60)}h`}var ka={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function Po(t){let e=await T(t.creds,"GET",`/review-coverage${X({days:t.days})}`);if(t.json){console.log(S(e));return}let n=s=>{console.log(s)},r=Xt(e.windowDays,e.truncated,e.oldestRecordMs);n(`${At(String(e.pullRequestsReviewed??0))} of ${At(String(e.pullRequestsSeen??0))} recorded pull requests reviewed ${e.coverageRate!=null?At(`(${Ra(e.coverageRate)})`):""} ${Ne(`(${r})`)}`),e.repositoriesReviewed&&n(`across ${At(String(e.repositoriesReviewed))} repositories`),n(Ne("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),e.medianLatencyMinutes!=null?(n(`
49
+ Feedback reached the author in ${va(Vn(e.medianLatencyMinutes))} median, ${At(Vn(e.p90LatencyMinutes))} at p90 ${Ne(`(${e.latencySamples??0} reviews)`)}`),e.medianOnOpenLatencyMinutes!=null&&n(Ne(` ${Vn(e.medianOnOpenLatencyMinutes)} median on pull-request open (${e.onOpenSamples??0} reviews, no quiet period in the way)`))):n(Qn(`
49
50
  Not enough timed reviews to report a latency figure.`));let o=e.capacityGapPullRequests??0;o>0&&n(`
50
- ${ha(String(o))} pull requests went unreviewed because a limit fired `+Ne("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=e.bySkipClass??[];i.length>0&&n(J(i,[{header:"WHY UNREVIEWED",value:s=>ya[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),e.failedOnlyPullRequests&&n(Ne(`${e.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of e.inconclusiveReasons??[])n(Qn(`
51
+ ${ba(String(o))} pull requests went unreviewed because a limit fired `+Ne("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=e.bySkipClass??[];i.length>0&&n(J(i,[{header:"WHY UNREVIEWED",value:s=>ka[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),e.failedOnlyPullRequests&&n(Ne(`${e.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of e.inconclusiveReasons??[])n(Qn(`
51
52
  ${s}`));if(e.truncated){let s=e.oldestRecordMs?new Date(e.oldestRecordMs).toISOString().slice(0,10):null;n(Qn(`
52
53
  Read cap reached \u2014 these are the most recent records${s?` (back to ${s})`:""}, not the whole window. Every count is a lower bound.`))}for(let s of e.caveats??[])n(Ne(`
53
- ${s}`))}import{promises as bt}from"node:fs";import{homedir as Ra}from"node:os";import{dirname as Po,join as Fe}from"node:path";import{dim as Lo,green as ka,yellow as Aa}from"kleur/colors";var de="anyforge-platform",Oa="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",$o="anyforge://guide/platform",va="text/markdown";var rn={"SKILL.md":`---
54
+ ${s}`))}import{promises as It}from"node:fs";import{homedir as Sa}from"node:os";import{dirname as No,join as Fe}from"node:path";import{dim as Fo,green as Ea,yellow as Ta}from"kleur/colors";var de="anyforge-platform",Aa="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",Lo="anyforge://guide/platform",Ia="text/markdown";var on={"SKILL.md":`---
54
55
  name: anyforge-platform
55
56
  description: >
56
57
  Orient an agent to AnyForge's structure, delivery model, surfaces, live control
@@ -257,72 +258,72 @@ these sources can grant network, filesystem, tool, or approval authority.
257
258
  Do not place API keys, tokens, credentials, private tenant records, or customer
258
259
  data in a reusable skill, prompt, log, or generated example. Use the client's
259
260
  credential mechanism and let the server enforce access.
260
- `},hu=Object.entries(rn).map(([t,e])=>({uri:t==="SKILL.md"?$o:`${$o}/${t}`,name:t==="SKILL.md"?de:`${de}/${t.replace(/^references\//,"")}`,title:t==="SKILL.md"?"AnyForge platform guide":t,description:t==="SKILL.md"?Oa:`Reference for the ${de} skill: ${t}`,mimeType:va,size:new TextEncoder().encode(e).byteLength}));var ba=rn["SKILL.md"],wu=ba.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"");var No={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills"};function Ia(t){let e=t.scope==="user"?t.homeDir??Ra():t.cwd??process.cwd();if(t.scope==="user"&&t.client==="codex"){let n=t.codexHome??process.env.CODEX_HOME??Fe(e,".codex");return Fe(n,"skills",de)}return Fe(e,No[t.client],de)}function xa(t){if(t.scope!=="project"&&t.scope!=="user")throw new y(`--scope must be project or user, got "${t.scope}".`);if(!Object.hasOwn(No,t.client))throw new y(`--client must be agents, claude, or codex, got "${t.client}".`)}async function Xn(t){try{return(await bt.lstat(t)).isSymbolicLink()}catch(e){if(e.code==="ENOENT")return!1;throw e}}async function Sa(t){xa(t);let e=Ia(t),n=Object.entries(rn),r=n.map(([s])=>Fe(e,s));if(await Xn(e))throw new y(`Refusing to install through the symbolic link ${e}.`);let o=new Set(n.map(([s])=>Po(s)).filter(s=>s!=="."));for(let s of o)if(await Xn(Fe(e,s)))throw new y(`Refusing to install through the symbolic link ${Fe(e,s)}.`);if(!t.force){let s=[];for(let a of r)try{await bt.access(a),s.push(a)}catch(c){if(c.code!=="ENOENT")throw c}if(s.length>0)throw new y(`The ${de} skill already exists at ${e}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await bt.mkdir(e,{recursive:!0});let i=[];for(let[s,a]of n){let c=Fe(e,s);if(await bt.mkdir(Po(c),{recursive:!0}),await Xn(c))throw new y(`Refusing to replace the symbolic link ${c}.`);await bt.writeFile(c,a,{encoding:"utf8",mode:420}),i.push(s)}return{name:de,scope:t.scope,client:t.client,directory:e,files:i}}async function Fo(t){if(t.subcommand!=="install")throw new y(`Unknown skill command${t.subcommand?`: ${t.subcommand}`:""}.`,"Use `anyforge skill install anyforge-platform`.");if(t.name!==de)throw new y(`Unknown skill${t.name?`: ${t.name}`:""}.`,`The only portable platform skill is ${de}.`);let e=t.scope??"project",n=t.client??"agents";if(!["project","user"].includes(e))throw new y(`--scope must be project or user, got "${e}".`);if(!["agents","claude","codex"].includes(n))throw new y(`--client must be agents, claude, or codex, got "${n}".`);let r=await Sa({scope:e,client:n,force:t.force});if(t.json){process.stdout.write(JSON.stringify(r)+`
261
- `);return}console.log(ka("Installed ")+`${r.name} ${Lo(`(${r.scope}, ${r.client})`)}`),console.log(` ${r.directory}`),console.log(Lo(` ${r.files.length} files installed. Re-run with --force to refresh them.`)),r.scope==="project"&&r.client==="agents"&&console.log(Aa(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as Vc}from"node:crypto";import{open as Xc,realpath as Zc,stat as el}from"node:fs/promises";import{basename as tl,join as nl,resolve as rl}from"node:path";import{bold as Sr,cyan as Ki,dim as ve,yellow as xn}from"kleur/colors";import{ProcessTerminal as ol,SelectList as il,Text as sl,TuiAltScreen as al}from"@earendil-works/pi-tui";var Ea=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function Ta(t){return Ea.has(t)?"querying the code graph":t==="search_code_semantic"?"searching the code index":t==="search_codebase_docs"?"searching codebase docs":null}function on(t){let e=Ta(t);if(e)return e;let n=/^mcp__(.+?)__(.+)$/.exec(t);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:t.replace(/_/g," ")}var Ca=new Set(["ask_user","present_catch_up_decision","present_memory_candidates"]);function Ve(t){return typeof t=="string"&&Ca.has(t)}import{truncateToWidth as hn,wrapTextWithAnsi as ci}from"@earendil-works/pi-tui";import{cyan as li,dim as at,green as di,italic as cc,red as pr,yellow as fr}from"kleur/colors";import{truncateToWidth as Rt,visibleWidth as Zn,wrapTextWithAnsi as _a}from"@earendil-works/pi-tui";import{bold as $a,dim as Pa}from"kleur/colors";function U(t){return t<1024?`${t} B`:t<1024*1024?`${kt(t/1024)} KiB`:`${kt(t/(1024*1024))} MiB`}function At(t){let e=Math.max(0,t);if(e<1e4)return`${kt(e/1e3)}s`;let n=Math.round(e/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/3600),o=Math.floor(n%3600/60),i=n%60;return r?o?`${r}h ${o}m`:`${r}h`:i?`${o}m ${i}s`:`${o}m`}function er(t){let e=Math.floor(Math.max(0,t)/1e3);return e<60?`${e}s`:`${Math.floor(e/60)}m ${String(e%60).padStart(2,"0")}s`}function ie(t){return Math.abs(t)<1e3?String(Math.round(t)):Math.abs(t)<1e6?`${kt(t/1e3,t<1e5?1:0)}k`:`${kt(t/1e6)}M`}function kt(t,e=1){return t.toFixed(e).replace(/\.0+$/,"")}function La(t){return d(t).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function Na(t,e){return typeof e=="boolean"?e?"on":"off":typeof e=="string"?d(e):/Ms$/.test(t)?At(e):/Bytes$/.test(t)?U(e):/tokens?/i.test(t)?ie(e):String(e)}function qo(t){return t?Object.entries(t).filter(e=>e[1]!==null).map(([e,n])=>`${La(e)} ${Na(e,n)}`):[]}function tr(t,e,n=2){let r=Math.min(16,Math.max(...t.map(([s])=>Zn(s)),0)+2),o=Math.max(10,e-n-r),i=[];for(let[s,a]of t)_a(a,o).forEach((u,l)=>{let p=l===0?Pa(Rt(s,r-1).padEnd(r)):" ".repeat(r);i.push(Rt(`${" ".repeat(n)}${p}${u}`,e))});return i}function jo(t,e,n){return[Rt($a(t),n),...tr(e,n)]}function Mo(t,e,n){let r=Zn(n),o=e.filter(Boolean).join(" \xB7 ");if(r+4>t)return Rt(o||n,t);let i=t-r-2,s=Rt(o,i),a=Math.max(2,t-Zn(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as xt,cyan as It,dim as Se,green as Fa,italic as Uo,strikethrough as qa,underline as Do,yellow as ja}from"kleur/colors";import{Markdown as Ma}from"@earendil-works/pi-tui";var Ua={heading:t=>xt(It(t)),link:t=>Do(It(t)),linkUrl:t=>Se(t),code:t=>ja(t),codeBlock:t=>t,codeBlockBorder:t=>Se(t),quote:t=>Uo(t),quoteBorder:t=>Se(t),hr:t=>Se(t),listBullet:t=>It(t),bold:t=>xt(t),italic:t=>Uo(t),strikethrough:t=>qa(t),underline:t=>Do(t)},Ze={selectedPrefix:t=>It(t),selectedText:t=>xt(t),description:t=>Se(t),scrollInfo:t=>Se(t),noMatch:t=>Se(t)},Bo={borderColor:t=>Se(t),selectList:Ze};var Xe=class{constructor(e,n){this.linkOrigin=n;this.content=d(e),this.markdown=new Ma(Un(this.content,n),0,0,Ua)}content;markdown;cache;getText(){return this.content}setText(e){let n=d(e);n!==this.content&&(this.content=n,this.markdown.setText(Un(n,this.linkOrigin)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(e){let n=Math.max(12,e);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(so):[];return this.cache={width:n,lines:r},r}};function St(t,e){return t==="user"?`${xt(Fa(e?d(e):"You"))}`:`${xt(It("Oracle"))}`}function ge(t){return t.shared||t.visibility==="company"?`Shared with the company${t.entityKey?` \xB7 ${d(t.entityKey)}`:""}`:"Private to you"}function Wo(t){return t.shared||t.visibility==="company"?"shared":"private"}import{createReadStream as tc}from"node:fs";import{stat as nc}from"node:fs/promises";import{basename as rc}from"node:path";import{setTimeout as oi}from"node:timers/promises";var Go={txt:"text/plain",log:"text/plain",md:"text/markdown",markdown:"text/markdown",csv:"text/csv",json:"application/json",pdf:"application/pdf",ts:"text/plain",tsx:"text/plain",js:"text/plain",jsx:"text/plain",mjs:"text/plain",cjs:"text/plain",py:"text/plain",go:"text/plain",rs:"text/plain",yaml:"text/plain",yml:"text/plain",toml:"text/plain",xml:"text/plain",html:"text/plain",css:"text/plain",sh:"text/plain",sql:"text/plain",java:"text/plain",kt:"text/plain",swift:"text/plain",c:"text/plain",h:"text/plain",cpp:"text/plain",rb:"text/plain",php:"text/plain",tf:"text/plain",diff:"text/plain",patch:"text/plain",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"};function Ko(t){let e=t.slice(t.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(Go,e)?Go[e]:null}var nr="/api/v1/oracle";var zo="workspace";function Ee(t){let e;try{e=new URL(t)}catch{throw new f(`Invalid Oracle endpoint: ${t}`,m.USAGE)}if(!["http:","https:"].includes(e.protocol)||e.username||e.password)throw new f("Oracle endpoint must be an http or https URL without embedded credentials.",m.USAGE);if(e.pathname!=="/"||e.search||e.hash)throw new f("Oracle endpoint must be the workspace origin, without a path, query or fragment.",m.USAGE);return e.origin}function he(t,e){return`${Ee(t)}${nr}${e}`}function Da(t,e,n){let r;try{r=new URL(t)}catch{throw new f(`Oracle server returned an invalid ${n} endpoint.`,m.API_ERROR)}let o=new URL(Ee(e));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new f(`Oracle server returned an unsafe ${n} endpoint.`,m.API_ERROR);return r.toString()}function Ba(t,e){if(!t||typeof t!="object")throw new f("Oracle server omitted OAuth endpoints.",m.API_ERROR);let n=t,r=["registration","authorization","token","revocation"],o={};for(let i of r){if(typeof n[i]!="string")throw new f(`Oracle server omitted its OAuth ${i} endpoint.`,m.API_ERROR);o[i]=Da(n[i],e,i)}return o}async function qe(t,e=fetch,n){let r=Ee(t),o;try{o=await e(he(r,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(l){throw new f(`Cannot reach ${r}: ${l instanceof Error?l.message:String(l)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let i=await nt(o,he(r,"/config")),s=P(tt(i,o.status)),a=`${r}${nr}`;if(s.protocolVersion!==1)throw new f(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(s.protocolVersion)}.`,m.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(s.resource!==a)throw new f("Oracle server resource does not match this workspace origin.",m.API_ERROR);let c=Array.isArray(s.scopes)?s.scopes:null;if(!c||!c.every(l=>l==="read"||l==="write"||l==="approve"))throw new f("Oracle server returned an invalid scope list.",m.API_ERROR);let u={protocolVersion:1,resource:a,scopes:c,oauth:Ba(s.oauth,r)};if(s.identity!==void 0){let l=P(s.identity);if(typeof l.uid!="string"||typeof l.companyId!="string")throw new f("Oracle server returned an invalid identity.",m.API_ERROR);let p=typeof l.companyName=="string"?d(l.companyName).trim().slice(0,120):"";u.identity={uid:d(l.uid),companyId:d(l.companyId),...p?{companyName:p}:{}}}if(s.capabilities!==void 0){let l=P(s.capabilities);if(![l.read,l.write,l.approve].every(p=>typeof p=="boolean"))throw new f("Oracle server returned invalid capabilities.",m.API_ERROR);u.capabilities={read:l.read,write:l.write,approve:l.approve}}if(s.model!==void 0){let l=P(s.model);if(typeof l.id!="string"||typeof l.provider!="string")throw new f("Oracle server returned invalid model metadata.",m.API_ERROR);u.model={id:d(l.id),provider:d(l.provider)}}if(s.limits!==void 0){let l=P(s.limits);if(Object.values(l).some(p=>!["string","number","boolean"].includes(typeof p)&&p!==null))throw new f("Oracle server returned invalid limits metadata.",m.API_ERROR);u.limits=Object.fromEntries(Object.entries(l).map(([p,k])=>[d(p),typeof k=="string"?d(k):k]))}return Array.isArray(s.commands)&&(u.commands=Wa(s.commands)),u}function Wa(t){let e=[];for(let n of t.slice(0,50)){let r=P(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||e.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?d(r.args).slice(0,60).trim():"";e.push({name:r.name,description:d(r.description).slice(0,200),...o?{args:o}:{}})}return e}var je=class{endpoint;scopes;source;#e;#n;#t;cachedConfig;constructor(e,n=fetch){this.endpoint=Ee(e.endpoint),this.#e=e.getAccessToken??(async()=>e.accessToken),this.#n=e.onIdentity,this.#t=n,this.scopes=new Set(e.scopes),this.source=e.source}async config(){if(!this.cachedConfig){let e=await this.#e();try{this.cachedConfig=await qe(this.endpoint,this.#t,e)}catch(r){if(this.source!=="oauth"||!(r instanceof Ae)||r.status!==401)throw r;let o=await this.#e(e);if(o===e)throw r;this.cachedConfig=await qe(this.endpoint,this.#t,o)}let n=this.cachedConfig.identity;n&&this.#n&&await this.#n(n).catch(()=>{})}return this.cachedConfig}async listSessions(){let e=await this.json("GET","/sessions"),n=Array.isArray(e)?e:P(e).sessions;if(!Array.isArray(n))throw new f("Oracle server returned an invalid sessions list.",m.API_ERROR);return n.map(Jo)}async createSession(e={}){let n=await this.json("POST","/sessions",e),r=P(n);return!Array.isArray(r.messages)&&typeof r.sessionId=="string"?this.getSession(r.sessionId):Ho(n)}async getSession(e){return Ho(await this.json("GET",`/sessions/${encodeURIComponent(e)}`))}async submitTurn(e,n,r,o){let i,s=he(this.endpoint,`/sessions/${encodeURIComponent(e)}/turns`),a=async u=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${u}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let u=await this.#e();if(i=await a(u),i.status===401&&this.source==="oauth"){let l=await this.#e(u);l!==u&&(i=await a(l))}}catch(u){throw u instanceof f||r?.aborted?u:new f(`Oracle connection was interrupted: ${u instanceof Error?u.message:String(u)}`,m.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await et(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let u=await nt(i,he(this.endpoint,`/sessions/${e}/turns`)),l=tt(u,i.status);throw new f(`Oracle server did not start a stream (${Ga(l)}).`,m.API_ERROR)}return i}async replayEvents(e,n,r){let o=[];for await(let i of this.streamReplayEvents(e,n,r))o.push(i);return o}async*streamReplayEvents(e,n,r,o){let i=`/sessions/${encodeURIComponent(e)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await et(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*Et(s,o);return}let c=tt(await nt(s,he(this.endpoint,i)),s.status),u=Array.isArray(c)?c:P(c).events;if(!Array.isArray(u))throw new f("Oracle replay response did not contain events.",m.API_ERROR);for(let l of u)yield rr(l)}async*streamRequestEvents(e,n,r=-1,o){let i=`/sessions/${encodeURIComponent(e)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await et(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*Et(s,o);return}let c=tt(await nt(s,he(this.endpoint,i)),s.status),u=Array.isArray(c)?c:P(c).events;if(!Array.isArray(u))throw new f("Oracle request replay response did not contain events.",m.API_ERROR);for(let l of u)yield rr(l)}async cancelTurn(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{streamId:n})}async cancelRequest(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{requestId:n})}async upload(e,n){let r=new FormData;r.set("sessionId",e),r.set("file",n,n.name);let o=await this.authenticatedFetch("POST","/uploads",{method:"POST",body:r,headers:{Accept:"application/json"}});return o.ok||await et(o),Ka(tt(await nt(o,he(this.endpoint,"/uploads")),o.status))}async download(e,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(e)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await et(r),r}async json(e,n,r){let o=await this.authenticatedFetch(e,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});return o.ok||await et(o),tt(await nt(o,he(this.endpoint,n)),o.status)}async authenticatedFetch(e,n,r={},o=2e4){try{let i=he(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=r.signal||o<=0?void 0:AbortSignal.timeout(o),c=k=>this.#t(i,{...r,method:e,headers:{...s,Authorization:`Bearer ${k}`},redirect:"error",...a?{signal:a}:{}}),u=await this.#e(),l=await c(u),p=r.body===void 0||typeof r.body=="string"||r.body===null;if(l.status===401&&this.source==="oauth"){let k=await this.#e(u);k!==u&&p&&(l=await c(k))}return l}catch(i){throw i instanceof f?i:new f(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*Et(t,e){if(!t.body)throw new f("Oracle stream has no response body.",m.FAILURE);let n=t.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,u=()=>{if(s.length===0)return null;let l=s.join(`
262
- `);if(s=[],a=0,l==="[DONE]")return null;let p;try{p=JSON.parse(l)}catch{throw new f("Oracle stream returned invalid JSON.",m.API_ERROR)}let k=rr(p);return k.type==="finalizing"?k:k.idx<=c?null:(c=k.idx,k)};try{for(;;){let{value:p,done:k}=await n.read();p?.byteLength&&e?.();let x=r.decode(p,{stream:!k});if(o+=x,i+=sn(x),i>2*1024*1024)throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR);let b=0,O=o.indexOf(`
263
- `,b);for(;O>=0;){let R=o.slice(b,O).replace(/\r$/,"");if(i-=sn(o.slice(b,O+1)),b=O+1,R===""){let A=u();A&&(yield A)}else if(!R.startsWith(":")){let A=R.indexOf(":"),z=A<0?R:R.slice(0,A),j=A<0?"":R.slice(A+1).replace(/^ /,"");if(z==="data"&&(s.push(j),a+=sn(j)+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}O=o.indexOf(`
264
- `,b)}if(o=o.slice(b),k)break}if(o.trim()){let p=o.replace(/\r$/,"");if(p.startsWith("data:")&&(s.push(p.slice(5).replace(/^ /,"")),a+=sn(s[s.length-1]??"")+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}let l=u();l&&(yield l)}catch(l){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),l}finally{n.releaseLock()}}function sn(t){return Buffer.byteLength(t,"utf8")}function or(t){let e=["program","initiative","codebase"].filter(o=>typeof t[o]=="string");if(e.length>1)throw new f("Choose only one of --program, --initiative or --codebase.",m.USAGE);let n=e[0];if(!n)return;let r=t[n];if(typeof r!="string"||!r.trim())throw new f(`--${n} needs an id.`,m.USAGE);return{kind:n,id:r.trim()}}function P(t){return!t||typeof t!="object"||Array.isArray(t)?{}:t}function Ga(t){if(typeof t=="string")return d(t);try{return d(JSON.stringify(t))}catch{return"unexpected response"}}function tt(t,e){let n=P(t);if(n.ok===!1){let r=Yo(n.error,e),o=typeof n.message=="string"?d(n.message).slice(0,2e3):void 0;throw new Ae(r,e,o)}return n.ok===!0&&"data"in n?n.data:t}async function nt(t,e){try{return await t.json()}catch{throw new f(`Non-JSON response from ${e} (HTTP ${t.status}).`,m.FAILURE)}}async function et(t){let e;try{e=await t.clone().json()}catch{e=null}let n=P(e),r=Yo(n.error??n.error_description,t.status),o=typeof n.message=="string"?n.message:typeof n.error_description=="string"?n.error_description:typeof n.detail=="string"?n.detail:void 0;throw new Ae(r,t.status,typeof o=="string"?d(o).slice(0,2e3):void 0)}function Yo(t,e){if(typeof t!="string")return`http_${e}`;let n=d(t).slice(0,120);return/^[A-Za-z0-9_.-]+$/.test(n)?n:`http_${e}`}function Jo(t){let e=P(t);if(typeof e.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(e.sessionId)||typeof e.title!="string"||e.visibility!=="private"&&e.visibility!=="company"||typeof e.shared!="boolean")throw new f("Oracle server returned an invalid session summary.",m.API_ERROR);return{sessionId:e.sessionId,title:d(e.title),visibility:e.visibility,shared:e.shared,...typeof e.entityKey=="string"?{entityKey:d(e.entityKey)}:{},...typeof e.updatedAt=="number"||e.updatedAt===null?{updatedAt:e.updatedAt}:{}}}function Ho(t){let e=P(t),n=Jo(e);if(!Array.isArray(e.messages))throw new f("Oracle server returned an invalid session transcript.",m.API_ERROR);let r=e.messages.map((o,i)=>{let s=P(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new f(`Oracle session message ${i+1} is invalid.`,m.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(Ja):void 0,c=Array.isArray(s.files)?s.files.map(Qa):void 0;return{role:s.role,content:d(s.content),...typeof s.id=="string"?{id:s.id}:{},...typeof s.authorName=="string"?{authorName:d(s.authorName)}:{},...s.question&&typeof s.question=="object"?{question:za(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:Ha(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof e.activeStreamId=="string"?{activeStreamId:e.activeStreamId}:{}}}function rr(t){let e=P(t);if(e.protocolVersion!==1||typeof e.idx!="number"||!Number.isSafeInteger(e.idx)||e.idx<0||typeof e.type!="string")throw new f("Oracle stream event does not match protocol version 1.",m.API_ERROR);return me(e)}function Ka(t){let e=P(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle upload response is missing file metadata.",m.API_ERROR);return{fileId:e.fileId,name:d(e.name),mediaType:d(e.mediaType),...typeof e.sizeBytes=="number"?{sizeBytes:e.sizeBytes}:{}}}function za(t){let e=P(t);if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:d(e.id),questions:e.questions.map((n,r)=>{let o=P(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:d(o.id),header:d(o.header),question:d(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=P(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new f(`Oracle question option ${s+1} is invalid.`,m.API_ERROR);return{id:d(a.id),label:d(a.label),description:d(a.description),...typeof a.recommended=="boolean"?{recommended:a.recommended}:{},...typeof a.confirms=="boolean"?{confirms:a.confirms}:{}}})}}),optional:e.optional===!0}}function Ha(t){let e=P(t);if(typeof e.questionId!="string"||!Array.isArray(e.answers))throw new f("Oracle returned an invalid question response.",m.API_ERROR);return{questionId:d(e.questionId),answers:e.answers.map(Ya)}}function Ya(t){let e=P(t);if(typeof e.questionId!="string"||!Array.isArray(e.optionIds)||!e.optionIds.every(n=>typeof n=="string"))throw new f("Oracle returned an invalid question answer.",m.API_ERROR);return{questionId:d(e.questionId),optionIds:e.optionIds.map(n=>d(n)),...typeof e.customText=="string"?{customText:d(e.customText).slice(0,8e3)}:{}}}function Ja(t){let e=P(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle session attachment metadata is invalid.",m.API_ERROR);return{fileId:d(e.fileId),name:d(e.name),mediaType:d(e.mediaType),...typeof e.sizeBytes=="number"&&Number.isFinite(e.sizeBytes)?{sizeBytes:e.sizeBytes}:{}}}function Qa(t){let e=P(t);if(typeof e.fileId!="string"||typeof e.filename!="string"||typeof e.mediaType!="string"||typeof e.sizeBytes!="number"||!Number.isFinite(e.sizeBytes))throw new f("Oracle session file metadata is invalid.",m.API_ERROR);return{fileId:d(e.fileId),filename:d(e.filename),mediaType:d(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:d(e.format)}:{}}}import{randomUUID as Va}from"node:crypto";import{promises as we}from"node:fs";import{homedir as Xa}from"node:os";import{join as ir}from"node:path";import*as Vo from"proper-lockfile";function ln(){return ir(Xa(),".anyforge")}function cn(){return ir(ln(),"oracle")}function Xo(){return ir(ln(),"oracle.last-session")}function Za(){return{version:2,active:{},logins:[]}}function an(t){return t===void 0||typeof t=="string"}function Qo(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.endpoint!="string"||typeof e.clientId!="string"||typeof e.redirectUri!="string"||typeof e.accessToken!="string"||typeof e.refreshToken!="string"||typeof e.expiresAt!="number"||!Number.isFinite(e.expiresAt)||!Array.isArray(e.scopes)||!e.scopes.every(n=>typeof n=="string")||!an(e.companyId)||!an(e.companyName)||!an(e.uid)?null:{endpoint:e.endpoint,...e.companyId?{companyId:e.companyId}:{},...e.companyName?{companyName:e.companyName}:{},...e.uid?{uid:e.uid}:{},clientId:e.clientId,redirectUri:e.redirectUri,accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes}}function ec(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;if(e.version===1){let o=Qo(e);return o?{version:2,endpoint:o.endpoint,active:{[o.endpoint]:o.clientId},logins:[o]}:null}if(e.version!==2||!Array.isArray(e.logins)||!an(e.endpoint)||!e.active||typeof e.active!="object"||Array.isArray(e.active))return null;let n=e.logins.map(Qo);if(n.some(o=>o===null))return null;let r={};for(let[o,i]of Object.entries(e.active)){if(typeof i!="string")return null;r[o]=i}return{version:2,...e.endpoint?{endpoint:e.endpoint}:{},active:r,logins:n}}async function Z(){let t=cn(),e;try{e=await we.readFile(t,"utf8")}catch(o){if(o.code==="ENOENT")return Za();throw o}let n;try{n=JSON.parse(e)}catch{throw new Error(`Oracle credentials at ${t} are invalid JSON; run \`anyforge oracle logout --all\` and sign in again.`)}let r=ec(n);if(!r)throw new Error(`Oracle credentials at ${t} have an unsupported format; run \`anyforge oracle logout --all\` and sign in again.`);return r}async function Tt(t){if(!t.logins.length){await we.rm(cn(),{force:!0});return}await ri(cn(),t)}async function dn(t){return fn(async()=>{let e=await Z(),n=await t(e);return await Tt(e),n})}function ye(t,e){return t.logins.filter(n=>n.endpoint===e)}function un(t,e){let n=ye(t,e);return n.find(r=>r.clientId===t.active[e])??n[0]}function ee(t){return t.companyName||t.companyId||"workspace not known yet"}function Zo(t,e){let n=e.companyId?t.logins.find(r=>r.endpoint===e.endpoint&&r.companyId===e.companyId&&r.clientId!==e.clientId):void 0;return t.logins=[...t.logins.filter(r=>r!==n&&r.clientId!==e.clientId),e],t.active[e.endpoint]=e.clientId,t.endpoint=e.endpoint,n}function sr(t,e){t.logins=t.logins.filter(o=>!(o.endpoint===e.endpoint&&o.clientId===e.clientId));let n=ye(t,e.endpoint);if(!n.length){if(delete t.active[e.endpoint],t.endpoint===e.endpoint){let o=t.logins[0]?.endpoint;o?t.endpoint=o:delete t.endpoint}return}if(t.active[e.endpoint]!==e.clientId&&n.some(o=>o.clientId===t.active[e.endpoint]))return;let r=n[0];return t.active[e.endpoint]=r.clientId,r}function ei(t,e,n,r){let o=t.logins.find(a=>a.endpoint===e&&a.clientId===n);if(!o)return{changed:!1};let i=o.companyId!==r.companyId||r.companyName!==void 0&&o.companyName!==r.companyName||r.uid!==void 0&&o.uid!==r.uid;o.companyId=r.companyId,r.companyName!==void 0&&(o.companyName=r.companyName),r.uid!==void 0&&(o.uid=r.uid);let s=t.logins.find(a=>a!==o&&a.endpoint===e&&a.companyId===r.companyId);return s&&(t.logins=t.logins.filter(a=>a!==s),t.active[e]===s.clientId&&(t.active[e]=o.clientId)),{changed:i||!!s,...s?{duplicate:s}:{}}}function Me(t,e){let n=e.trim(),r=t.find(a=>a.companyId===n);if(r)return r;let o=t.filter(a=>a.companyName?.toLowerCase()===n.toLowerCase());if(o.length===1)return o[0];let i=t.map(a=>`${ee(a)}${a.companyId&&a.companyName?` (${a.companyId})`:""}`),s=i.length?`Saved workspaces: ${i.join(", ")}.`:"No Oracle logins are saved for this endpoint.";throw o.length>1?new y(`More than one saved workspace is named "${n}". Use its id instead.`,s):new y(`No saved Oracle login for workspace "${n}".`,`${s} Add one with \`anyforge oracle login --workspace "${n}"\`.`)}async function ti(){let t;try{t=await we.readFile(Xo(),"utf8")}catch(r){if(r.code==="ENOENT")return[];throw r}let e;try{e=JSON.parse(t)}catch{return[]}if(!e||typeof e!="object"||Array.isArray(e))return[];let n=e;return n.version!==2||!Array.isArray(n.sessions)?[]:n.sessions.filter(r=>{if(!r||typeof r!="object")return!1;let o=r;return typeof o.endpoint=="string"&&typeof o.companyId=="string"&&typeof o.sessionId=="string"})}async function ni(t,e,n=""){let r=(await ti()).filter(o=>!(o.endpoint===e&&o.companyId===n));await ri(Xo(),{version:2,sessions:[...r,{endpoint:e,companyId:n,sessionId:t}]})}async function pn(t,e=""){return(await ti()).find(n=>n.endpoint===t&&n.companyId===e)?.sessionId}async function ri(t,e){await we.mkdir(ln(),{recursive:!0,mode:448});let n=`${t}.${Va()}.tmp`;try{await we.writeFile(n,`${JSON.stringify(e,null,2)}
265
- `,{mode:384,flag:"wx"}),await we.rename(n,t),await we.chmod(t,384)}finally{await we.rm(n,{force:!0}).catch(()=>{})}}async function fn(t){await we.mkdir(ln(),{recursive:!0,mode:448});let e=cn(),n=await Vo.lock(e,{realpath:!1,lockfilePath:`${e}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await t()}finally{await n()}}var ar=8192,ii=10*1048576,oc=20*1048576,si=10,ai=3;function cr(t,e){if(t.type!=="tool_call"&&t.type!=="tool_call_start"||typeof t.spawnId=="string")return!1;let n=typeof t.id=="string"?t.id:void 0;if(n){if(e.has(n))return!1;e.add(n)}return!Ve(t.name)}var Ue=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(e){return e.type==="finalizing"?!0:e.idx<=this.lastIdx?!1:(this.lastIdx=e.idx,e.type==="stream_start"&&typeof e.streamId=="string"?this.streamId=d(e.streamId):e.type==="delta"&&typeof e.content=="string"?this.answer+=e.content:cr(e,this.toolIds)?this.answer="":e.type==="question"?this.question=ur(e):e.type==="error"?this.error=dr(e):e.type==="done"?this.done=e:e.type==="navigator_file_created"&&ic(this.files,e.file),!0)}get settled(){return!!(this.done||this.error)}outcome(){return{answer:this.answer,...this.question?{question:this.question}:{},...this.error?{error:this.error}:{},...this.done?{done:this.done}:{},...this.streamId?{streamId:this.streamId}:{},...this.files.length?{files:[...this.files]}:{}}}};async function mn(t,e,n,r,o,i=new Ue){let s=async p=>{let k=i.streamId;i.accept(p)&&(i.streamId&&i.streamId!==k&&r.onStream?.(i.streamId),await r.onEvent(p))},a=()=>lr(t,e,i,s,o,r.onActivity),c=async()=>{try{for await(let p of t.streamRequestEvents(e,n.requestId,-1,r.onActivity))await s(p)}catch(p){throw o?.aborted?p:new f("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new f("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)},u=async()=>{try{let p=await t.submitTurn(e,n,o);for await(let k of Et(p,r.onActivity))await s(k)}catch(p){if(o?.aborted||p instanceof f&&p.exitCode===m.API_ERROR)throw p;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},l;try{l=await t.submitTurn(e,n,o)}catch(p){if(o?.aborted||p instanceof f&&p.exitCode!==m.FAILURE)throw p;return u()}if(!l)throw new f("Oracle did not return a stream response.",m.FAILURE);r.onResponse?.();try{for await(let p of Et(l,r.onActivity))await s(p)}catch(p){if(o?.aborted||p instanceof f)throw p;return i.streamId?a():u()}return i.settled?i.outcome():i.streamId?a():u()}async function lr(t,e,n,r,o,i){let s=n.streamId;if(!s)throw new f("Oracle stream replay needs a stream id.",m.FAILURE);let a=0;for(;!n.settled&&a<ai;){if(o?.aborted)throw o.reason;try{for await(let c of t.streamReplayEvents(e,s,n.lastIdx+1,i))await r(c);if(!n.settled){if((await t.getSession(e)).activeStreamId!==s)break;await oi(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof f&&c.exitCode===m.API_ERROR||(a+=1,a>=ai))throw c;await oi(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new f("Oracle stream could not be fully replayed; the turn was not submitted again.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the session.`);return n.outcome()}function Ct(t,e){let n=e.done,r=n?.servedBy,o=De(n?.tokens),i=W(n?.rounds),s=typeof n?.exitReason=="string"?d(n.exitReason):void 0,a=n?.exitReason==="completed"&&!e.question,c=e.files??(Array.isArray(n?.files)?n.files.map(ot):void 0),u=e.error?"error":e.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:t,status:u,answer:d(e.answer),partial:!a,...typeof n?.messageId=="string"?{messageId:d(n.messageId)}:typeof n?.answerId=="string"?{messageId:d(n.answerId)}:{},...e.question?{question:e.question}:{},...e.error?{error:d(e.error)}:{},...e.streamId?{streamId:d(e.streamId)}:{},...r?{servedBy:me(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:me(c)}:{}}}function E(t,e){return typeof t=="string"?d(t).slice(0,e):""}function dr(t){return typeof t.message=="string"?d(t.message).slice(0,2e3):"Oracle turn failed."}function Q(t){return d(t instanceof Error?t.message:String(t)).slice(0,2e3)}function ur(t){let e=t.question;if(!e||typeof e!="object")throw new f("Oracle question event omitted its question card.",m.API_ERROR);return sc(e)}function ot(t){let e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};if(typeof e.fileId!="string"||!e.fileId||typeof e.filename!="string"||!e.filename||typeof e.mediaType!="string"||!e.mediaType||typeof e.sizeBytes!="number"||!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<0)throw new f("Oracle generated-file event omitted safe file metadata.",m.API_ERROR);return{fileId:d(e.fileId),filename:d(e.filename),mediaType:d(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:d(e.format)}:{}}}function ic(t,e){let n=ot(e);t.some(r=>r.fileId===n.fileId)||t.push(n)}function sc(t){let e=t;if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:d(e.id),optional:e.optional===!0,questions:e.questions.map((n,r)=>{let o=n&&typeof n=="object"?n:{};if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:d(o.id),header:d(o.header),question:d(o.question),multiSelect:o.multiSelect,options:o.options.map(i=>{let s=i&&typeof i=="object"?i:{};if(typeof s.id!="string"||typeof s.label!="string"||typeof s.description!="string")throw new f("Oracle question option is invalid.",m.API_ERROR);return{id:d(s.id),label:d(s.label),description:d(s.description),...typeof s.recommended=="boolean"?{recommended:s.recommended}:{},...typeof s.confirms=="boolean"?{confirms:s.confirms}:{}}})}})}}function W(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function De(t){if(typeof t=="number"&&Number.isFinite(t))return{totalTokens:t};if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=W(e.in)??W(e.input)??W(e.inputTokens),r=W(e.cacheRead),o=W(e.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=W(e.out)??W(e.output)??W(e.outputTokens),a=W(e.total)??W(e.totalTokens)??(i!==void 0||s!==void 0?(i??0)+(s??0):void 0);if(!(i===void 0&&s===void 0&&a===void 0))return{...i!==void 0?{inputTokens:i}:{},...r?{cachedInputTokens:r}:{},...s!==void 0?{outputTokens:s}:{},...a!==void 0?{totalTokens:a}:{}}}function it(t){if(t&&typeof t=="object"){let e=t;if(typeof e.accepted=="boolean")return e.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof e.cancelled=="boolean")return e.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function st(t,e){let n=e&&t&&(t.kind==="program"||t.kind==="initiative")?{kind:t.kind,id:t.id}:void 0;return{...!e&&t?{context:t}:{},...n?{sharedEntity:n}:{},visibility:e?"company":"private"}}async function _t(t,e,n){await ni(t,e,n).catch(()=>{})}async function gn(t,e,n,r){if(!n.length)return[];if(n.length>si)throw new y(`Attach no more than ${si} files per turn.`);let o=0,i=[];for(let a of n){let c=await nc(a);if(!c.isFile())throw new y(`Attachment is not a file: ${a}`);if(c.size>ii)throw new y(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let u=await ac(a,ii);if(o+=u.byteLength,o>oc)throw new y("Attachments exceed the 20 MiB total CLI limit.");let l=rc(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",p=Ko(l)??"";if(!p)throw new y(`Unsupported attachment type: ${a}`);i.push({content:u,name:l,mediaType:p})}let s=[];for(let{content:a,name:c,mediaType:u}of i){await r(d(c),a.byteLength);let l=new ArrayBuffer(a.byteLength);new Uint8Array(l).set(a);let p=new File([l],c,{type:u});s.push(await t.upload(e,p))}return s}async function ac(t,e){let n=[],r=0;for await(let o of tc(t)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>e)throw new y(`Attachment exceeds the ${U(e)} limit: ${t}`);n.push(i)}return Buffer.concat(n)}var $t=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],lc=2e4,dc=6,uc={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},pc={max_rounds:"reached the step limit",max_tokens:"reached the output limit",token_budget:"reached the token budget",deadline:"ran out of time",interrupted:"interrupted",loop_detected:"stopped a repeating loop",cancelled:"cancelled"},wn=class{constructor(e,n){this.startedAt=e;this.sessionId=n;this.lastSignalAt=e}phase="sending";answer="";tools=[];notices=[];files=[];lastSignalAt;endedAt;end;done;upload;round;maxRounds;serverPhase;agents=new Map;toolIds=new Set;get toolCount(){return this.tools.length}get failedCount(){return this.tools.filter(e=>e.status==="failed").length}get finished(){return this.end!==void 0}setUploading(e,n,r){this.phase="uploading",this.upload=`${e} (${U(n)})`,this.lastSignalAt=r}setPhase(e,n){this.phase=e,this.lastSignalAt=n}touch(e){this.lastSignalAt=e}apply(e,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(e);switch(e.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=W(e.round),this.maxRounds=W(e.maxRounds)??this.maxRounds;for(let r=this.tools.length-1;r>=0;r--)this.tools[r]?.started&&this.tools.splice(r,1);this.phase!=="finishing"&&(this.phase="thinking");break;case"phase":this.serverPhase=typeof e.phase=="string"?e.phase:void 0;break;case"delta":this.phase!=="finishing"&&(this.phase="writing");break;case"tool_result":this.phase!=="finishing"&&(this.phase="thinking");break;case"finalizing":this.phase="finishing";break}this.record(e)}record(e){switch(e.type){case"delta":typeof e.content=="string"&&(this.answer+=e.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(e);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===e.toolUseId);n&&(n.status=e.ok===!1?"failed":"ok");break}case"subagent_start":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"running");break;case"subagent_done":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${E(e.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${E(e.filename,200)}: ${E(e.error,500)}`});break;case"attachment_notice":if(Array.isArray(e.notices))for(let n of e.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${E(r.name,160)}: ${E(r.message,500)}`})}break;case"provider_fallback":{let n=E(e.from,120),r=E(e.to,120),o=E(e.reason,40).replaceAll("_"," ");this.notices.push({tone:"info",text:`Switched model${n?` from ${n}`:""}${r?` to ${r}`:""}${o?` (${o})`:""}.`});break}case"navigator_file_created":{let n=ot(e.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${U(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:dr(e)});break;case"done":this.done=e;break}}recordToolCall(e){let n=typeof e.id=="string"?e.id:void 0,r=cr(e,this.toolIds),o=typeof e.name=="string"?e.name:"";if(Ve(o))return;let i=E(typeof e.label=="string"?e.label:on(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,e.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof e.spawnId=="string"?{spawnId:e.spawnId}:{},...e.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=d(this.answer.trim()),this.answer=""),this.tools.push(a),this.phase!=="finishing"&&(this.phase="thinking")}note(e,n){this.notices.push({tone:e,text:d(n)})}finish(e,n){this.end=e,this.endedAt=n}label(){if(this.phase==="cancelling")return"Cancelling";if(this.phase==="uploading")return`Uploading ${this.upload??"attachment"}`;if(this.phase==="sending")return"Sending";if(this.phase==="preparing")return"Preparing context";if(this.phase==="finishing")return"Finishing up";let e=[...this.agents.values()].filter(r=>r==="running").length;if(e)return`Researching (${e} agent${e===1?"":"s"})`;let n=this.tools.filter(r=>r.status==="running"&&!r.spawnId);return n.length===1?`Running ${n[0]?.label}`:n.length>1?`Running ${n.length} tools`:this.phase==="writing"?"Writing":this.serverPhase&&uc[this.serverPhase]||"Thinking"}statusLine(e,n){let r=[this.label(),er(e-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=e-this.lastSignalAt;return o>=lc&&this.phase!=="cancelling"&&r.push(`no update for ${er(o)}`),n&&e-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let e=[],n=At((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=di("\u2713"):this.end==="awaiting_input"?o=li("?")+" Waiting for your answer":this.end==="cancelled"?o=fr("\u2717")+" Interrupted":this.end==="error"?o=pr("\u2717")+" Error":o=fr("\u2717")+` Stopped: ${r&&pc[r]||"no final answer"}`,e.push(n),this.tools.length&&e.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=De(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&e.push(`${ie(i.inputTokens??0)} in${i.cachedInputTokens?` (${ie(i.cachedInputTokens)} cached)`:""} / ${ie(i.outputTokens??0)} out`);let s=Pt(this.done?.servedBy);return s&&e.push(s),`${o} ${at(e.join(" \xB7 "))}`}};function Pt(t){if(!t||typeof t!="object")return"";let e=t,n=E(e.model??e.id,100);if(!n)return"";let r=e.fallback&&typeof e.fallback=="object"?e.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${E(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${E(r.from,100)}${o})`}return n}var yn=class{constructor(e,n){this.activity=e;this.view=n;this.answer=new Xe("",n.linkOrigin)}answer;getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(e){let n=this.activity;this.answer.setText(n.answer);let r=[St("assistant")];r.push(...this.renderTools(e)),r.push(...this.answer.render(e));for(let o of n.notices){let i=o.tone==="error"?pr:o.tone==="warning"?fr:at;r.push(...ci(i(o.text),e))}return n.finished&&r.push(hn(n.summaryLine(),e)),r}renderTools(e){let{tools:n}=this.activity;if(!n.length)return[];if(this.activity.finished&&!this.view.expanded()){let s=this.activity.failedCount,a=`Used ${n.length} tool${n.length===1?"":"s"}${s?` \xB7 ${s} failed`:""} (ctrl+o to expand)`;return[hn(at(` \u23BF ${a}`),e)]}let r=this.activity.finished?n:n.slice(-dc),o=n.length-r.length,i=[];return o&&i.push(hn(at(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),e)),r.forEach((s,a)=>{if(s.note)for(let p of ci(s.note,Math.max(10,e-4)).slice(0,3))i.push(` ${at(cc(p))}`);let c=s.status==="running"?li($t[this.view.frame()%$t.length]??"*"):s.status==="ok"?di("\u2713"):pr("\u2717"),u=a===0&&!o?" \u23BF ":" ",l=s.spawnId?` ${at("agent \xB7")} `:"";i.push(hn(`${u}${l}${c} ${s.label}`,e))}),i}};import{truncateToWidth as hc,visibleWidth as wc,wrapTextWithAnsi as pi}from"@earendil-works/pi-tui";import{bold as fi,cyan as yc,dim as Oe}from"kleur/colors";import{CombinedAutocompleteProvider as fc}from"@earendil-works/pi-tui";var Lt=[{name:"help",description:"Show commands and keyboard shortcuts"},{name:"status",description:"Show session, access, model, usage and limits"},{name:"model",description:"Show the workspace model and the model that answered last"},{name:"usage",description:"Show turns and tokens used in this terminal"},{name:"new",args:"[shared]",description:"Start a new conversation",idleOnly:!0,completions:["shared"]},{name:"clear",description:"Clear the screen and start a new private conversation",idleOnly:!0},{name:"resume",args:"[session-id]",description:"Pick or open a saved conversation",idleOnly:!0},{name:"workspace",args:"[name|id]",description:"Switch to another saved workspace and start a new conversation there",idleOnly:!0},{name:"context",args:"[clear|program|initiative|codebase <id>]",description:"Show or change the context for the next message",completions:["clear","program ","initiative ","codebase "]},{name:"attach",args:"<path>",description:"Attach a file to your next message"},{name:"copy",description:"Copy the last answer as Markdown"},{name:"files",description:"List files Oracle generated in this conversation"},{name:"exit",description:"Leave the Oracle",aliases:["quit"]}],mc=[{name:"design",args:"[topic]",description:"Talk through a technical design before anything is created"},{name:"catchup",description:"Catch up on your work: what needs you, what landed, what is running"}];function mr(t){let e=new Set(Lt.flatMap(n=>[n.name,...n.aliases??[]]));return(t??mc).filter(n=>!e.has(n.name))}function ui(t,e){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(t.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=Lt.find(a=>a.name===r||a.aliases?.includes(r));if(i)return{kind:"local",command:i,arg:o,args:o?o.split(/\s+/):[]};let s=e.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function gr(t,e){let n=[...Lt.flatMap(i=>[i,...(i.aliases??[]).map(s=>({...i,name:s}))]).map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{},...i.completions?{getArgumentCompletions:s=>gc(i.completions??[],s)}:{}})),...t.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new fc(n,e),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let u=(i[s]??"").slice(0,a);return s!==0||!u.trimStart().startsWith("/")?null:o.test(u)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,u){return r.applyCompletion(i,s,a,c,u)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function gc(t,e){let n=t.filter(r=>r.startsWith(e.toLowerCase())&&r!==e).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function Nt(t,e){return t?e?"write + approve":"write":"read only"}function ct(t){return t?`${t.kind} ${d(t.id)}`:"no context"}function Te(t){return t?d(t.companyName||t.companyId):""}function mi(t,e){let n=[`${fi(yc("AnyForge Oracle"))}${Oe(` \xB7 v${d(t.version)}`)}`,`${t.workspace?`${fi(t.workspace)} \xB7 `:""}${ge(t.session)} \xB7 ${t.access} \xB7 ${ct(t.context)}`,...t.session.messages.length?[`Resumed: ${d(t.session.title)}`]:[],Oe("Only your messages and the files you attach leave this terminal."),Oe("/help commands \xB7 /status details")];if(e<24)return n.flatMap(s=>pi(s,Math.max(1,e)));let r=Math.min(e,76),o=r-4,i=[Oe(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>pi(a,o))){let a=hc(s,o);i.push(`${Oe("\u2502")} ${a}${" ".repeat(Math.max(0,o-wc(a)))} ${Oe("\u2502")}`)}return i.push(Oe(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function gi(t){let e=(r,o)=>r?`${Oe(r)} ${o}`:o,n=[{title:"Commands",rows:Lt.map(r=>[`/${r.name}`,e(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(t.server.length){let r=t.server.map(o=>[`/${o.name}`,e(o.args,d(o.description))]);t.server.some(o=>o.name==="catchup")&&!t.canApprove&&r.push(["",Oe("Acting on /catchup decisions needs a session started with `anyforge oracle --write --approve`.")]),n.push({title:"Workspace commands (answered by Oracle)",rows:r})}return n.push({title:"Keys",rows:[["Enter","Send. While Oracle works, queues one message for when it finishes"],["Shift+Enter","New line (Ctrl+J also works)"],["Esc","Interrupt the current answer"],["Ctrl+C","Interrupt the answer, or clear the input; press twice to exit"],["Ctrl+D","Exit when the input is empty"],["Ctrl+O","Show or hide tool activity for finished answers"],["Ctrl+Shift+F","Search the conversation"],["Up / Down","Recall messages sent in this terminal"],["Tab","Complete a command, or a file path after /attach"],["PgUp / PgDn","Scroll; Home and End jump to the top and bottom"]]}),n}function hr(t){let n=[["Model",`workspace default ${t.model?`${d(t.model.provider)}/${d(t.model.id)}`:"chosen by the server"}`]],r=Pt(t.lastServedBy);if(r){let o=t.lastServedBy,i=E(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function wr(t){return[["This run",t.turns?`${t.turns} turn${t.turns===1?"":"s"} \xB7 ${t.tools} tool${t.tools===1?"":"s"} \xB7 ${ie(t.inputTokens)} in / ${ie(t.outputTokens)} out tokens`:"no turns yet"]]}function yr(t){if(!t?.finished)return[];let e=[At((t.endedAt??t.startedAt)-t.startedAt)];e.push(`${t.toolCount} tool${t.toolCount===1?"":"s"}${t.failedCount?` (${t.failedCount} failed)`:""}`);let n=W(t.done?.rounds);n!==void 0&&e.push(`${n} round${n===1?"":"s"}`);let r=De(t.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&e.push(`${ie(r.inputTokens??0)} in${r.cachedInputTokens?` (${ie(r.cachedInputTokens)} cached)`:""} / ${ie(r.outputTokens??0)} out tokens`);let o=E(t.done?.exitReason,40);return e.push(o?o.replaceAll("_"," "):t.end??""),[["Last turn",e.filter(Boolean).join(" \xB7 ")]]}function hi(t){let e=t.capabilities?["read","write","approve"].filter(o=>t.capabilities?.[o]).join(", ")||"none":"not reported",n=t.contextText?` \xB7 note ${U(Buffer.byteLength(t.contextText,"utf8"))}`:"",r=qo(t.limits);return[["Session",`${t.session.sessionId} \xB7 ${d(t.session.title)||"Untitled"}`],["Audience",ge(t.session)],["Access",`this session ${Nt(t.write,t.approve)} \xB7 grant ${t.grantScopes.join(", ")||"none"} \xB7 workspace role ${e}`],["Context",`${ct(t.context)}${n}`],...hr(t),...yr(t.lastTurn),...wr(t.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...t.identity?[["Workspace",Oc(t.identity,t.savedWorkspaces)]]:[],["Endpoint",t.endpoint],["Version",`CLI ${d(t.version)} \xB7 protocol ${1}`],["Attached",t.pendingFiles.length?`${t.pendingFiles.map(d).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function Oc(t,e){let n=t.companyName?`${d(t.companyName)} (${d(t.companyId)})`:`company ${d(t.companyId)}`,r=e!==void 0&&e>1?` \xB7 ${e} saved, /workspace to switch`:"";return`${n} \xB7 user ${d(t.uid)}${r}`}function wi(t,e){return e.length?e.map((n,r)=>[`${r+1}.`,`${d(n.filename)} (${U(n.sizeBytes)}) \xB7 anyforge oracle download ${t} ${d(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{randomUUID as kc}from"node:crypto";import{stat as Ac}from"node:fs/promises";import{basename as yi}from"node:path";import{bold as Ic,cyan as Oi,dim as vi,red as dt,yellow as xc}from"kleur/colors";import{Container as Sc,Editor as Ec,ProcessTerminal as Tc,ScrollView as Cc,SelectList as bi,TuiAltScreen as _c,VStack as $c,getNativeClipboard as Pc,matchesKey as bn,truncateToWidth as Ri,wrapTextWithAnsi as Lc}from"@earendil-works/pi-tui";import{bold as vc,cyan as Or,dim as On,yellow as bc}from"kleur/colors";import{Input as Rc,Text as Be,matchesKey as lt}from"@earendil-works/pi-tui";var vn=class{constructor(e,n,r){this.tui=e;this.question=n;this.onComplete=r;(n.questions[0]?.options.length??0)===0&&(this.mode="custom"),this.customInput.onSubmit=o=>{let i=o.trim().slice(0,8e3);if(!i){this.errorMessage="Enter a short answer before continuing.",this.tui.requestRender();return}this.recordCurrent(i)},this.customInput.onEscape=()=>{if(!this.question.questions[this.questionIndex]?.options.length){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.setValue(""),this.mode="select",this.tui.setFocus(this),this.tui.requestRender()}}focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new Rc({prompt:`${Or("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:On});invalidate(){}render(e){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,e-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new Be(`${vc(Or(d(n.header)))}${On(o)}`,0,0).render(r),...new Be(d(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Be(On(`Enter submits your text${n.options.length?" \xB7 Esc back to the choices":this.question.optional?" \xB7 Esc skip":""}`),0,0).render(r))):i.push(...new Be(On(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Be(bc(this.errorMessage),0,0).render(r)),i.map(s=>`${Or("\u2502")} ${s}`)}handleInput(e){if(this.mode==="custom"){this.customInput.handleInput(e);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(lt(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(e);return}if(lt(e,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(lt(e,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(lt(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(e.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(e);if(Number.isInteger(o)&&o>=1&&o<=n.options.length){let i=n.options[o-1]?.id;i&&(this.optionIndex=o-1,n.multiSelect?r.has(i)?r.delete(i):r.add(i):(r.clear(),r.add(i)),this.tui.requestRender());return}if(lt(e,"space")&&n.multiSelect){let i=n.options[this.optionIndex];i&&(r.has(i.id)?r.delete(i.id):r.add(i.id),this.tui.requestRender());return}if(lt(e,"enter")){if(r.size===0){this.errorMessage="Select an option explicitly, type a custom answer, or skip if optional.",this.tui.requestRender();return}this.recordCurrent()}}renderOptions(e,n){let r=this.selectedFor(e),o=[];return e.options.forEach((i,s)=>{let a=r.has(i.id),c=e.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",u=s===this.optionIndex?"\u203A":" ",l=i.recommended?" \xB7 recommended":"",p=i.confirms?" \xB7 confirms the shown action":"",k=`${u} ${s+1}. ${c} ${d(i.label)}${l}${p}`;o.push(...new Be(k,0,0).render(n)),o.push(...new Be(` ${d(i.description)}`,0,0).render(n))}),o}instructions(e){return e.options.length===0?`Write a short answer${this.question.optional?" \xB7 s or Esc skip card":""}`:`\u2191/\u2193 move \xB7 1\u2013${e.options.length} ${e.multiSelect?"toggle":"select"}${e.multiSelect?" \xB7 Space toggle":""} \xB7 Enter continue \xB7 o write your own${this.question.optional?" \xB7 s or Esc skip card":""}`}requireAnswer(){let e=this.question.questions[this.questionIndex];this.errorMessage=e?.options.length?"Oracle needs an answer to continue: pick an option, or press o to write your own.":"Oracle needs an answer to continue: type it and press Enter.",this.tui.requestRender()}selectedFor(e){let n=this.selected.get(e.id);return n||(n=new Set,this.selected.set(e.id,n)),n}recordCurrent(e){let n=this.question.questions[this.questionIndex];if(!n)return;e&&this.selectedFor(n).clear();let r=[...this.selectedFor(n)],o={questionId:n.id,optionIds:r,...e?{customText:e}:{}},i=this.answers.findIndex(s=>s.questionId===n.id);if(i>=0?this.answers.splice(i,1,o):this.answers.push(o),this.customInput.setValue(""),this.mode="select",this.questionIndex<this.question.questions.length-1){this.questionIndex+=1,this.optionIndex=0,this.mode=this.question.questions[this.questionIndex]?.options.length===0?"custom":"select",this.errorMessage="",this.tui.setFocus(this),this.tui.requestRender();return}this.finish({questionId:this.question.id,answers:this.answers.map(s=>({...s}))})}finish(e){this.onComplete(e)}};var ki=1500,Nc=100,Fc="\x1B]133;A\x07";function ut(t){return{render:t,invalidate(){}}}function Ai(t,e,n,r){let o=new Xe(e,r);return{getText:()=>o.getText(),invalidate:()=>o.invalidate(),render:i=>t==="user"?["",`${Fc}${St("user",n)}`,...o.render(i)]:[St("assistant"),...o.render(i)]}}async function Ii(t){let{client:e,config:n}=t,r=new Tc,o=new _c(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new Sc,s=new Cc(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new Ec(o,Bo),c=mr(n.commands),u=()=>typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,l=t.session,p=t.initialContext,k=t.contextText,x=t.canWrite,b=t.canApprove,O,R,A,z,j=[...t.initialFiles],q=!1,Ce=!1,Mt=!1,Sn=0,We,Tr=0,Ut=!1,_e="",ft,Dt,Ge=[],Ke={turns:0,inputTokens:0,outputTokens:0,tools:0},Bt=new Map,ue,Qi=ut(g=>{if(O){let h=Oi($t[Sn%$t.length]??"*");return[Ri(`${h} ${O.activity.statusLine(Date.now(),u())}`,g)]}return ue?[Ri(`${Oi("?")} Waiting for your answer to the question above`,g)]:[]}),Vi=ut(g=>{let h=[Te(n.identity),Nt(x,b),ct(p),Wo(l),j.length?`${j.length} file${j.length===1?"":"s"} attached`:"",R!==void 0?"1 message queued":""];return[vi(Mo(g,h,O?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new $c([{component:s,basis:0,grow:1,minSize:1},{component:Qi,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:Vi,basis:"auto",shrink:0,minSize:1}]));let te=()=>o.requestRender(),L=g=>o.flash(d(g),3e3),Re=g=>{i.addChild(g),te()},D=(g,h=vi)=>{let w=d(g);Re(ut(v=>Lc(h(w),Math.max(1,v))))},Wt=(g,h)=>{Re(ut(w=>["",...jo(g,h,w)]))},Xi=()=>{We||(We=setInterval(()=>{Sn+=1,te()},Nc),We.unref())},En=()=>{We&&clearInterval(We),We=void 0},ze=()=>{q||o.hasOverlay()||o.setFocus(ue??a)},Cr=g=>{A=g;let h=Bt.get(g.id);h&&i.removeChild(h);let w=new vn(o,g,v=>{Bt.delete(g.id),ue===w&&(ue=void 0),i.removeChild(w),ts(v??{questionId:g.id,skipped:!0,answers:[]}),ze()});Bt.set(g.id,w),ue=w,Re(w)},Gt=g=>{i.clear(),Bt.clear(),ue=void 0,l=g,A=void 0,z=void 0,Ge=[],_e="";let h={version:t.version,workspace:Te(n.identity),session:g,access:Nt(x,b),context:p};Re(ut(v=>mi(h,v)));let w;for(let v of g.messages){Re(Ai(v.role,v.content,v.authorName,e.endpoint)),v.role==="assistant"&&(_e=v.content),v.question&&(w=v.question),v.questionResponse&&(D("A stored response was recorded for this question."),w?.id===v.questionResponse.questionId&&(w=void 0));for(let I of v.files??[])Ge.some(_=>_.fileId===I.fileId)||Ge.push(I),D(`File: ${I.filename} (${I.mediaType}, ${U(I.sizeBytes)}) \xB7 anyforge oracle download ${g.sessionId} ${I.fileId} --output .`)}w&&Cr(w),ze(),_t(g.sessionId,e.endpoint,n.identity?.companyId)},_r,Zi=new Promise(g=>{_r=g}),Kt=()=>{q||(q=!0,En(),O?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),_r())},Tn=async()=>{let g=O;if(!g||g.cancelling)return;g.cancelling=!0,g.activity.setPhase("cancelling",Date.now()),te();let{streamId:h,requestId:w}=g;g.controller.abort(new Error("Turn cancelled by user."));let v;if(h)try{v=it(await e.cancelTurn(l.sessionId,h))}catch(I){v=`Could not confirm server cancellation: ${Q(I)}`}else if(w)try{v=it(await e.cancelRequest(l.sessionId,w))}catch(I){v=`Could not confirm server cancellation by request id: ${Q(I)}`}else v="The turn had not reached the server; nothing was sent.";g.activity.note("info",v),te()},He=async g=>{if(O||q)return;if(g.kind==="submit"&&g.response){let $=A;if(!$||$.id!==g.response.questionId){L("That question is no longer active. Resume the session to refresh it.");return}D(qc($,g.response)),A=void 0}else g.kind==="submit"&&Re(Ai("user",g.text));let h=l.sessionId,w=new wn(Date.now(),h),v=new yn(w,{expanded:()=>Mt,frame:()=>Sn,linkOrigin:e.endpoint}),I={activity:w,view:v,controller:new AbortController,cancelling:!1};O=I,Re(v),Xi();let _=new Ue,H=$=>{w.apply($,Date.now()),$.type==="question"&&(Cr(ur($)),ze()),te()},$e={onEvent:H,onStream:$=>{I.streamId=$},onResponse:()=>{w.phase==="sending"&&w.setPhase("preparing",Date.now())},onActivity:()=>w.touch(Date.now())},ne="error";try{if(g.kind==="replay"){_.streamId=g.streamId,I.streamId=g.streamId,w.setPhase("thinking",Date.now());let $=await lr(e,h,_,async se=>{_.accept(se)&&H(se)},I.controller.signal,$e.onActivity);ne=Ct(h,$).status}else{let $=g.response?[]:j.splice(0),se=await gn(e,h,$,(Cn,us)=>{w.setUploading(Cn,us,Date.now()),te()});I.controller.signal.throwIfAborted(),w.setPhase("sending",Date.now());let zt=kc();I.requestId=zt;let ls={requestId:zt,text:g.response?"":g.text,readOnly:!x,...b?{allowApprove:!0}:{},...p?{context:p}:{},...k?{contextText:k}:{},...g.response?{questionResponse:g.response}:{},...se.length?{attachments:se.map(Cn=>({fileId:Cn.fileId}))}:{}},ds=await mn(e,h,ls,$e,I.controller.signal,_);ne=Ct(h,ds).status}}catch($){if(I.controller.signal.aborted)ne="cancelled";else{ne="error";let se=$ instanceof f&&$.hint?` ${d($.hint)}`:"";w.note("error",`${Q($)}${se}`)}}finally{w.finish(ne,Date.now()),O=void 0,En(),q||(Ce=ne==="cancelled"),ft=w,w.answer.trim()&&(_e=w.answer),w.done?.servedBy&&(Dt=w.done.servedBy);let $=De(w.done?.tokens);Ke.turns+=1,Ke.tools+=w.toolCount,Ke.inputTokens+=$?.inputTokens??0,Ke.outputTokens+=$?.outputTokens??0;for(let se of w.files)Ge.some(zt=>zt.fileId===se.fileId)||Ge.push(se);te()}if(!q){if(I.streamId&&ne!=="cancelled"){let $=await e.getSession(h).catch(()=>{});$&&$.sessionId===l.sessionId&&(l=$)}es(ne)}},es=g=>{if(!(q||O)){if(z){let h=z;z=void 0,He({kind:"submit",text:"",response:h});return}if(R!==void 0){let h=R;if(R=void 0,g==="complete"&&!ue){He({kind:"submit",text:h});return}a.getText()||a.setText(h),L("Your queued message is back in the input; press Enter to send it.")}ze(),te()}},ts=g=>{if(O){z=g,L("Answer saved; Oracle continues once the current turn settles.");return}He({kind:"submit",text:"",response:g})},$r=async g=>{try{let h=await e.getSession(g);Gt(h),h.activeStreamId&&He({kind:"replay",streamId:h.activeStreamId}),L(`Resumed ${h.title||h.sessionId}.`)}catch(h){D(Q(h),dt)}},ns=async()=>{try{let g=await e.listSessions();if(!g.length){L("No saved conversations to resume.");return}let h=new bi(g.map(_=>({value:_.sessionId,label:_.title,description:ge(_)})),Math.min(12,g.length),Ze),w=await pn(e.endpoint,n.identity?.companyId),v=w?g.findIndex(_=>_.sessionId===w):-1;v>=0&&h.setSelectedIndex(v);let I=o.showOverlay(h,{width:"85%",maxHeight:"80%",anchor:"center"});h.onSelect=_=>{I.hide(),$r(_.value)},h.onCancel=()=>{I.hide(),ze()},I.focus()}catch(g){D(Q(g),dt)}},Pr=async g=>{if(g&&(!p||p.kind!=="program"&&p.kind!=="initiative")){L("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let h=await e.createSession(st(p,g));Gt(h),L(`Started a new conversation \xB7 ${ge(h)}.`)}catch(h){D(Q(h),dt)}},Lr=async(g,h)=>{let w=d(ee(h));if(h.companyId&&h.companyId===n.identity?.companyId){L(`Already in ${w}.`);return}Ut=!0;try{L(`Connecting to ${w}...`);let v=await g.connect(h),I=await v.client.createSession(st(void 0,!1));e=v.client,n=v.config,c=mr(n.commands),a.setAutocompleteProvider(gr(c,process.cwd()));let _=e.scopes.has("write")&&n.capabilities?.write===!0,H=e.scopes.has("approve")&&n.capabilities?.approve===!0,$e=x&&!_||b&&!H;x&&!_&&(x=!1),(!x||!H)&&(b=!1);let ne=p!==void 0;p=void 0,Dt=void 0,ft=void 0,Gt(I),D(`Switched to ${Te(n.identity)||w}. This is a new conversation in that workspace.${ne?" Context was cleared because its id belongs to the previous workspace.":""}`),$e&&D(`Access here is ${Nt(x,b)}: this workspace's login or your role there does not allow more.`,xc)}catch(v){let I=v instanceof f&&v.hint?` ${d(v.hint)}`:"";D(`Could not switch to ${w}: ${Q(v)}${I}`,dt)}finally{Ut=!1}},rs=async(g,h)=>{let w=n.identity?.companyId,v=new bi(h.map(H=>({value:H.clientId,label:ee(H),description:[H.companyId,H.scopes.join(", "),H.companyId===w?"current":""].filter(Boolean).join(" \xB7 ")})),Math.min(12,h.length),Ze),I=h.findIndex(H=>H.companyId===w);I>=0&&v.setSelectedIndex(I);let _=o.showOverlay(v,{width:"85%",maxHeight:"80%",anchor:"center"});v.onSelect=H=>{_.hide();let $e=h.find(ne=>ne.clientId===H.value);$e&&Lr(g,$e)},v.onCancel=()=>{_.hide(),ze()},_.focus()},os=async g=>{let h=t.workspaces;if(!h){D(`This terminal signs in with ANYFORGE_API_TOKEN, which is bound to ${Te(n.identity)||"one workspace"}. To switch workspaces, unset it and sign in with \`anyforge oracle login --workspace <name>\`.`);return}let w=await h.list();if(g){let v;try{v=Me(w,g)}catch(I){let _=I instanceof f&&I.hint?` ${d(I.hint)}`:"";D(`${Q(I)}${_}`,dt);return}await Lr(h,v);return}if(w.length<=1){D(`${Te(n.identity)||"This workspace"} is the only saved workspace. To add another, run \`anyforge oracle login --workspace <name>\` in another terminal, then use /workspace here.`);return}await rs(h,w)},is=g=>({session:l,write:x,approve:b,grantScopes:[...e.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...p?{context:p}:{},...k?{contextText:k}:{},...n.model?{model:n.model}:{},lastServedBy:Dt,...ft?{lastTurn:ft}:{},totals:{...Ke},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},...g!==void 0?{savedWorkspaces:g}:{},endpoint:e.endpoint,version:t.version,pendingFiles:j.map(h=>yi(h))}),ss=async()=>{if(!_e.trim()){L("There is no answer to copy yet.");return}try{let g=Pc();g?.setText?await g.setText(_e):r.write(`\x1B]52;c;${Buffer.from(_e,"utf8").toString("base64")}\x07`),L(`Copied the last answer (${_e.length} characters).`)}catch(g){L(`Could not copy: ${Q(g)}`)}},as=async(g,h,w)=>{if(g.idleOnly&&Ut){L("Wait for the workspace switch to finish.");return}if(g.idleOnly&&O){L(`Wait for Oracle to finish, or press Esc, before /${g.name}.`);return}switch(g.name){case"help":Re(ut(v=>["",...gi({server:c,canApprove:b}).flatMap(I=>[Ic(I.title),...tr(I.rows,v)])]));return;case"status":{let v=await t.workspaces?.list().then(I=>I.length).catch(()=>{});Wt("Status",hi(is(v)));return}case"workspace":await os(w);return;case"model":Wt("Model",hr({...n.model?{model:n.model}:{},lastServedBy:Dt}));return;case"usage":Wt("Usage",[...yr(ft),...wr(Ke)]);return;case"files":Wt("Generated files",wi(l.sessionId,Ge));return;case"copy":await ss();return;case"exit":Kt();return;case"new":if(w&&w!=="shared"){L("Usage: /new or /new shared");return}await Pr(w==="shared");return;case"clear":await Pr(!1);return;case"resume":w?await $r(w):await ns();return;case"context":{if(!w){D(`Context: ${ct(p)}${k?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(w==="clear")p=void 0;else{let[v,I,..._]=h;if(!["program","initiative","codebase"].includes(v??"")||!I||_.length){L("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}p={kind:v,id:I}}D(`Context for your next message: ${ct(p)}.`);return}case"attach":{if(!w){L("Usage: /attach <file path>");return}let v=await Ac(w).catch(()=>{});if(!v?.isFile()){L(`Not a readable file: ${w}`);return}j.push(w),D(`Attached ${yi(w)} (${U(v.size)}). It uploads with your next message.`);return}}},Nr=g=>{let h=g.trim();if(!h)return;a.addToHistory(h);let w=ui(h,c);if(w?.kind==="local"){as(w.command,w.args,w.arg).catch(v=>D(Q(v),dt));return}if(w?.kind==="unknown"){a.setText(h),L(`Unknown command /${w.name}. Type /help to see the commands.`);return}if(Ut){a.setText(h),L("Switching workspace; send your message once it has opened.");return}if(O){let v=R!==void 0;R=h,L(v?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),te();return}He({kind:"submit",text:h})},cs=o.addInputListener(g=>{if(bn(g,"ctrl+c")){if(O)return Tn(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),te(),{consume:!0};let h=Date.now();return h-Tr<=ki?Kt():(Tr=h,o.flash("Press Ctrl+C again to exit",ki)),{consume:!0}}if(bn(g,"escape")){let h=ue!==void 0&&o.getFocusedComponent()===ue;return O&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!h?(Tn(),{consume:!0}):void 0}if(bn(g,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(Kt(),{consume:!0}):void 0;if(bn(g,"ctrl+o"))return Mt=!Mt,L(Mt?"Showing tool activity":"Hiding tool activity"),te(),{consume:!0}}),Fr=()=>{let g=!!O;Tn().finally(()=>{g&&(Ce=!0),Kt()})};process.on("SIGINT",Fr),a.onSubmit=Nr,a.onChange=()=>te(),a.setAutocompleteProvider(gr(c,process.cwd())),Gt(t.session),o.start(),l.activeStreamId&&He({kind:"replay",streamId:l.activeStreamId}),t.initialPrompt&&Nr(t.initialPrompt),await Zi,cs(),process.off("SIGINT",Fr),En(),O?.controller.abort(),await r.drainInput().catch(()=>{}),Ce&&(process.exitCode=130)}function qc(t,e){if(e.skipped)return"Skipped the optional Oracle question.";let n=[];for(let r of e.answers){let o=t.questions.find(i=>i.id===r.questionId);for(let i of r.optionIds){let s=o?.options.find(a=>a.id===i);s&&n.push(s.label)}r.customText&&n.push(r.customText)}return`You answered: ${n.map(d).join("; ")||"no options selected"}`}import{createHash as jc,randomBytes as xi,timingSafeEqual as Mc}from"node:crypto";import{createServer as Uc}from"node:http";import Dc from"open";var Bc=6e4,Wc=5*6e4,Rn=new Map;async function vr(t){let e=Ee(t.endpoint),n=await qe(e),r=["read"];t.write&&r.push("write"),t.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=xi(32).toString("base64url"),i=await Hc(o);try{let s={client_name:"AnyForge CLI",redirect_uris:[i.redirectUri],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"},a=await Yc(n.oauth.registration,s);if(typeof a.client_id!="string"||!a.client_id)throw new f("OAuth registration did not return a client id.",m.API_ERROR);let c=xi(32).toString("base64url"),u=jc("sha256").update(c).digest("base64url"),l={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:u,code_challenge_method:"S256",resource:n.resource},p=new URL(n.oauth.authorization);for(let[q,Ce]of Object.entries(l))p.searchParams.set(q,String(Ce));let k=t.workspace?.trim();k&&p.searchParams.set(zo,k),t.onAuthorizationUrl?.(p.toString());try{t.openBrowser?await t.openBrowser(p.toString()):await Dc(p.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
261
+ `},bu=Object.entries(on).map(([t,e])=>({uri:t==="SKILL.md"?Lo:`${Lo}/${t}`,name:t==="SKILL.md"?de:`${de}/${t.replace(/^references\//,"")}`,title:t==="SKILL.md"?"AnyForge platform guide":t,description:t==="SKILL.md"?Aa:`Reference for the ${de} skill: ${t}`,mimeType:Ia,size:new TextEncoder().encode(e).byteLength}));var xa=on["SKILL.md"],Ru=xa.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"");var qo={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills"};function Ca(t){let e=t.scope==="user"?t.homeDir??Sa():t.cwd??process.cwd();if(t.scope==="user"&&t.client==="codex"){let n=t.codexHome??process.env.CODEX_HOME??Fe(e,".codex");return Fe(n,"skills",de)}return Fe(e,qo[t.client],de)}function _a(t){if(t.scope!=="project"&&t.scope!=="user")throw new y(`--scope must be project or user, got "${t.scope}".`);if(!Object.hasOwn(qo,t.client))throw new y(`--client must be agents, claude, or codex, got "${t.client}".`)}async function Xn(t){try{return(await It.lstat(t)).isSymbolicLink()}catch(e){if(e.code==="ENOENT")return!1;throw e}}async function $a(t){_a(t);let e=Ca(t),n=Object.entries(on),r=n.map(([s])=>Fe(e,s));if(await Xn(e))throw new y(`Refusing to install through the symbolic link ${e}.`);let o=new Set(n.map(([s])=>No(s)).filter(s=>s!=="."));for(let s of o)if(await Xn(Fe(e,s)))throw new y(`Refusing to install through the symbolic link ${Fe(e,s)}.`);if(!t.force){let s=[];for(let a of r)try{await It.access(a),s.push(a)}catch(c){if(c.code!=="ENOENT")throw c}if(s.length>0)throw new y(`The ${de} skill already exists at ${e}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await It.mkdir(e,{recursive:!0});let i=[];for(let[s,a]of n){let c=Fe(e,s);if(await It.mkdir(No(c),{recursive:!0}),await Xn(c))throw new y(`Refusing to replace the symbolic link ${c}.`);await It.writeFile(c,a,{encoding:"utf8",mode:420}),i.push(s)}return{name:de,scope:t.scope,client:t.client,directory:e,files:i}}async function jo(t){if(t.subcommand!=="install")throw new y(`Unknown skill command${t.subcommand?`: ${t.subcommand}`:""}.`,"Use `anyforge skill install anyforge-platform`.");if(t.name!==de)throw new y(`Unknown skill${t.name?`: ${t.name}`:""}.`,`The only portable platform skill is ${de}.`);let e=t.scope??"project",n=t.client??"agents";if(!["project","user"].includes(e))throw new y(`--scope must be project or user, got "${e}".`);if(!["agents","claude","codex"].includes(n))throw new y(`--client must be agents, claude, or codex, got "${n}".`);let r=await $a({scope:e,client:n,force:t.force});if(t.json){process.stdout.write(JSON.stringify(r)+`
262
+ `);return}console.log(Ea("Installed ")+`${r.name} ${Fo(`(${r.scope}, ${r.client})`)}`),console.log(` ${r.directory}`),console.log(Fo(` ${r.files.length} files installed. Re-run with --force to refresh them.`)),r.scope==="project"&&r.client==="agents"&&console.log(Ta(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as nl}from"node:crypto";import{open as rl,realpath as ol,stat as il}from"node:fs/promises";import{basename as sl,join as al,resolve as cl}from"node:path";import{bold as Er,cyan as Hi,dim as be,yellow as xn}from"kleur/colors";import{ProcessTerminal as ll,SelectList as dl,Text as ul,TuiAltScreen as pl}from"@earendil-works/pi-tui";var Pa=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function La(t){return Pa.has(t)?"querying the code graph":t==="search_code_semantic"?"searching the code index":t==="search_codebase_docs"?"searching codebase docs":null}function sn(t){let e=La(t);if(e)return e;let n=/^mcp__(.+?)__(.+)$/.exec(t);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:t.replace(/_/g," ")}var Na=new Set(["ask_user","present_catch_up_decision","present_memory_candidates"]);function tt(t){return typeof t=="string"&&Na.has(t)}import{truncateToWidth as Lt,wrapTextWithAnsi as ui}from"@earendil-works/pi-tui";import{cyan as pr,dim as Be,green as pi,italic as fc,red as fr,yellow as mr}from"kleur/colors";import{truncateToWidth as xt,visibleWidth as Zn,wrapTextWithAnsi as Fa}from"@earendil-works/pi-tui";import{bold as qa,dim as ja}from"kleur/colors";function D(t){return t<1024?`${t} B`:t<1024*1024?`${St(t/1024)} KiB`:`${St(t/(1024*1024))} MiB`}function Et(t){let e=Math.max(0,t);if(e<1e4)return`${St(e/1e3)}s`;let n=Math.round(e/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/3600),o=Math.floor(n%3600/60),i=n%60;return r?o?`${r}h ${o}m`:`${r}h`:i?`${o}m ${i}s`:`${o}m`}function er(t){let e=Math.floor(Math.max(0,t)/1e3);return e<60?`${e}s`:`${Math.floor(e/60)}m ${String(e%60).padStart(2,"0")}s`}function ie(t){return Math.abs(t)<1e3?String(Math.round(t)):Math.abs(t)<1e6?`${St(t/1e3,t<1e5?1:0)}k`:`${St(t/1e6)}M`}function St(t,e=1){return t.toFixed(e).replace(/\.0+$/,"")}function Ma(t){return l(t).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function Ua(t,e){return typeof e=="boolean"?e?"on":"off":typeof e=="string"?l(e):/Ms$/.test(t)?Et(e):/Bytes$/.test(t)?D(e):/tokens?/i.test(t)?ie(e):String(e)}function Mo(t){return t?Object.entries(t).filter(e=>e[1]!==null).map(([e,n])=>`${Ma(e)} ${Ua(e,n)}`):[]}function tr(t,e,n=2){let r=Math.min(16,Math.max(...t.map(([s])=>Zn(s)),0)+2),o=Math.max(10,e-n-r),i=[];for(let[s,a]of t)Fa(a,o).forEach((u,d)=>{let p=d===0?ja(xt(s,r-1).padEnd(r)):" ".repeat(r);i.push(xt(`${" ".repeat(n)}${p}${u}`,e))});return i}function Uo(t,e,n){return[xt(qa(t),n),...tr(e,n)]}function Do(t,e,n){let r=Zn(n),o=e.filter(Boolean).join(" \xB7 ");if(r+4>t)return xt(o||n,t);let i=t-r-2,s=xt(o,i),a=Math.max(2,t-Zn(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as rt,cyan as nt,dim as Ee,green as Da,italic as Bo,strikethrough as Ba,underline as Wo,yellow as Wa}from"kleur/colors";import{Markdown as Ga}from"@earendil-works/pi-tui";var Ka={heading:t=>rt(nt(t)),link:t=>Wo(nt(t)),linkUrl:t=>Ee(t),code:t=>Wa(t),codeBlock:t=>t,codeBlockBorder:t=>Ee(t),quote:t=>Bo(t),quoteBorder:t=>Ee(t),hr:t=>Ee(t),listBullet:t=>nt(t),bold:t=>rt(t),italic:t=>Bo(t),strikethrough:t=>Ba(t),underline:t=>Wo(t)},it={selectedPrefix:t=>nt(t),selectedText:t=>rt(t),description:t=>Ee(t),scrollInfo:t=>Ee(t),noMatch:t=>Ee(t)},Go={borderColor:t=>Ee(t),selectList:it};var ot=class{constructor(e,n){this.linkOrigin=n;this.content=l(e),this.markdown=new Ga(Un(this.content,n),0,0,Ka)}content;markdown;cache;getText(){return this.content}setText(e){let n=l(e);n!==this.content&&(this.content=n,this.markdown.setText(Un(n,this.linkOrigin)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(e){let n=Math.max(12,e);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(co):[];return this.cache={width:n,lines:r},r}};function Tt(t,e){return t==="user"?`${rt(Da(e?l(e):"You"))}`:`${rt(nt("Oracle"))}`}function Ko(t,e,n){let r=nt("\u2502"),o=Math.max(1,e-4);return["",`${r} ${Tt("user",n)}`,...t.render(o).map(i=>`${r} ${rt(i)}`),""]}function he(t){return t.shared||t.visibility==="company"?`Shared with the company${t.entityKey?` \xB7 ${l(t.entityKey)}`:""}`:"Private to you"}function zo(t){return t.shared||t.visibility==="company"?"shared":"private"}import{createReadStream as sc}from"node:fs";import{stat as ac}from"node:fs/promises";import{basename as cc}from"node:path";import{setTimeout as ai}from"node:timers/promises";var Ho={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 Yo(t){let e=t.slice(t.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(Ho,e)?Ho[e]:null}var nr="/api/v1/oracle";var Jo="workspace";function Te(t){let e;try{e=new URL(t)}catch{throw new f(`Invalid Oracle endpoint: ${t}`,m.USAGE)}if(!["http:","https:"].includes(e.protocol)||e.username||e.password)throw new f("Oracle endpoint must be an http or https URL without embedded credentials.",m.USAGE);if(e.pathname!=="/"||e.search||e.hash)throw new f("Oracle endpoint must be the workspace origin, without a path, query or fragment.",m.USAGE);return e.origin}function we(t,e){return`${Te(t)}${nr}${e}`}function za(t,e,n){let r;try{r=new URL(t)}catch{throw new f(`Oracle server returned an invalid ${n} endpoint.`,m.API_ERROR)}let o=new URL(Te(e));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new f(`Oracle server returned an unsafe ${n} endpoint.`,m.API_ERROR);return r.toString()}function Ha(t,e){if(!t||typeof t!="object")throw new f("Oracle server omitted OAuth endpoints.",m.API_ERROR);let n=t,r=["registration","authorization","token","revocation"],o={};for(let i of r){if(typeof n[i]!="string")throw new f(`Oracle server omitted its OAuth ${i} endpoint.`,m.API_ERROR);o[i]=za(n[i],e,i)}return o}async function qe(t,e=fetch,n){let r=Te(t),o;try{o=await e(we(r,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(d){throw new f(`Cannot reach ${r}: ${d instanceof Error?d.message:String(d)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let i=await ct(o,we(r,"/config")),s=L(at(i,o.status)),a=`${r}${nr}`;if(s.protocolVersion!==1)throw new f(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(s.protocolVersion)}.`,m.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(s.resource!==a)throw new f("Oracle server resource does not match this workspace origin.",m.API_ERROR);let c=Array.isArray(s.scopes)?s.scopes:null;if(!c||!c.every(d=>d==="read"||d==="write"||d==="approve"))throw new f("Oracle server returned an invalid scope list.",m.API_ERROR);let u={protocolVersion:1,resource:a,scopes:c,oauth:Ha(s.oauth,r)};if(s.identity!==void 0){let d=L(s.identity);if(typeof d.uid!="string"||typeof d.companyId!="string")throw new f("Oracle server returned an invalid identity.",m.API_ERROR);let p=typeof d.companyName=="string"?l(d.companyName).trim().slice(0,120):"";u.identity={uid:l(d.uid),companyId:l(d.companyId),...p?{companyName:p}:{}}}if(s.capabilities!==void 0){let d=L(s.capabilities);if(![d.read,d.write,d.approve].every(p=>typeof p=="boolean"))throw new f("Oracle server returned invalid capabilities.",m.API_ERROR);u.capabilities={read:d.read,write:d.write,approve:d.approve}}if(s.model!==void 0){let d=L(s.model);if(typeof d.id!="string"||typeof d.provider!="string")throw new f("Oracle server returned invalid model metadata.",m.API_ERROR);u.model={id:l(d.id),provider:l(d.provider)}}if(s.limits!==void 0){let d=L(s.limits);if(Object.values(d).some(p=>!["string","number","boolean"].includes(typeof p)&&p!==null))throw new f("Oracle server returned invalid limits metadata.",m.API_ERROR);u.limits=Object.fromEntries(Object.entries(d).map(([p,R])=>[l(p),typeof R=="string"?l(R):R]))}return Array.isArray(s.commands)&&(u.commands=Ya(s.commands)),u}function Ya(t){let e=[];for(let n of t.slice(0,50)){let r=L(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||e.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?l(r.args).slice(0,60).trim():"";e.push({name:r.name,description:l(r.description).slice(0,200),...o?{args:o}:{}})}return e}var je=class{endpoint;scopes;source;#e;#n;#t;cachedConfig;constructor(e,n=fetch){this.endpoint=Te(e.endpoint),this.#e=e.getAccessToken??(async()=>e.accessToken),this.#n=e.onIdentity,this.#t=n,this.scopes=new Set(e.scopes),this.source=e.source}async config(){if(!this.cachedConfig){let e=await this.#e();try{this.cachedConfig=await qe(this.endpoint,this.#t,e)}catch(r){if(this.source!=="oauth"||!(r instanceof Ie)||r.status!==401)throw r;let o=await this.#e(e);if(o===e)throw r;this.cachedConfig=await qe(this.endpoint,this.#t,o)}let n=this.cachedConfig.identity;n&&this.#n&&await this.#n(n).catch(()=>{})}return this.cachedConfig}async listSessions(){let e=await this.json("GET","/sessions"),n=Array.isArray(e)?e:L(e).sessions;if(!Array.isArray(n))throw new f("Oracle server returned an invalid sessions list.",m.API_ERROR);return n.map(Xo)}async createSession(e={}){let n=await this.json("POST","/sessions",e),r=L(n);return!Array.isArray(r.messages)&&typeof r.sessionId=="string"?this.getSession(r.sessionId):Qo(n)}async getSession(e){return Qo(await this.json("GET",`/sessions/${encodeURIComponent(e)}`))}async submitTurn(e,n,r,o){let i,s=we(this.endpoint,`/sessions/${encodeURIComponent(e)}/turns`),a=async u=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${u}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let u=await this.#e();if(i=await a(u),i.status===401&&this.source==="oauth"){let d=await this.#e(u);d!==u&&(i=await a(d))}}catch(u){throw u instanceof f||r?.aborted?u:new f(`Oracle connection was interrupted: ${u instanceof Error?u.message:String(u)}`,m.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await st(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let u=await ct(i,we(this.endpoint,`/sessions/${e}/turns`)),d=at(u,i.status);throw new f(`Oracle server did not start a stream (${Ja(d)}).`,m.API_ERROR)}return i}async replayEvents(e,n,r){let o=[];for await(let i of this.streamReplayEvents(e,n,r))o.push(i);return o}async*streamReplayEvents(e,n,r,o){let i=`/sessions/${encodeURIComponent(e)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await st(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*Ct(s,o);return}let c=at(await ct(s,we(this.endpoint,i)),s.status),u=Array.isArray(c)?c:L(c).events;if(!Array.isArray(u))throw new f("Oracle replay response did not contain events.",m.API_ERROR);for(let d of u)yield rr(d)}async*streamRequestEvents(e,n,r=-1,o){let i=`/sessions/${encodeURIComponent(e)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await st(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*Ct(s,o);return}let c=at(await ct(s,we(this.endpoint,i)),s.status),u=Array.isArray(c)?c:L(c).events;if(!Array.isArray(u))throw new f("Oracle request replay response did not contain events.",m.API_ERROR);for(let d of u)yield rr(d)}async cancelTurn(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{streamId:n})}async cancelRequest(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{requestId:n})}async upload(e,n){let r=new FormData;r.set("sessionId",e),r.set("file",n,n.name);let o=await this.authenticatedFetch("POST","/uploads",{method:"POST",body:r,headers:{Accept:"application/json"}});return o.ok||await st(o),Qa(at(await ct(o,we(this.endpoint,"/uploads")),o.status))}async download(e,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(e)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await st(r),r}async json(e,n,r){let o=await this.authenticatedFetch(e,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});return o.ok||await st(o),at(await ct(o,we(this.endpoint,n)),o.status)}async authenticatedFetch(e,n,r={},o=2e4){try{let i=we(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=r.signal||o<=0?void 0:AbortSignal.timeout(o),c=R=>this.#t(i,{...r,method:e,headers:{...s,Authorization:`Bearer ${R}`},redirect:"error",...a?{signal:a}:{}}),u=await this.#e(),d=await c(u),p=r.body===void 0||typeof r.body=="string"||r.body===null;if(d.status===401&&this.source==="oauth"){let R=await this.#e(u);R!==u&&p&&(d=await c(R))}return d}catch(i){throw i instanceof f?i:new f(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*Ct(t,e){if(!t.body)throw new f("Oracle stream has no response body.",m.FAILURE);let n=t.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,u=()=>{if(s.length===0)return null;let d=s.join(`
263
+ `);if(s=[],a=0,d==="[DONE]")return null;let p;try{p=JSON.parse(d)}catch{throw new f("Oracle stream returned invalid JSON.",m.API_ERROR)}let R=rr(p);return R.type==="finalizing"?R:R.idx<=c?null:(c=R.idx,R)};try{for(;;){let{value:p,done:R}=await n.read();p?.byteLength&&e?.();let I=r.decode(p,{stream:!R});if(o+=I,i+=an(I),i>2*1024*1024)throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR);let x=0,O=o.indexOf(`
264
+ `,x);for(;O>=0;){let v=o.slice(x,O).replace(/\r$/,"");if(i-=an(o.slice(x,O+1)),x=O+1,v===""){let k=u();k&&(yield k)}else if(!v.startsWith(":")){let k=v.indexOf(":"),P=k<0?v:v.slice(0,k),j=k<0?"":v.slice(k+1).replace(/^ /,"");if(P==="data"&&(s.push(j),a+=an(j)+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}O=o.indexOf(`
265
+ `,x)}if(o=o.slice(x),R)break}if(o.trim()){let p=o.replace(/\r$/,"");if(p.startsWith("data:")&&(s.push(p.slice(5).replace(/^ /,"")),a+=an(s[s.length-1]??"")+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}let d=u();d&&(yield d)}catch(d){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),d}finally{n.releaseLock()}}function an(t){return Buffer.byteLength(t,"utf8")}function or(t){let e=["program","initiative","codebase"].filter(o=>typeof t[o]=="string");if(e.length>1)throw new f("Choose only one of --program, --initiative or --codebase.",m.USAGE);let n=e[0];if(!n)return;let r=t[n];if(typeof r!="string"||!r.trim())throw new f(`--${n} needs an id.`,m.USAGE);return{kind:n,id:r.trim()}}function L(t){return!t||typeof t!="object"||Array.isArray(t)?{}:t}function Ja(t){if(typeof t=="string")return l(t);try{return l(JSON.stringify(t))}catch{return"unexpected response"}}function at(t,e){let n=L(t);if(n.ok===!1){let r=Vo(n.error,e),o=typeof n.message=="string"?l(n.message).slice(0,2e3):void 0;throw new Ie(r,e,o)}return n.ok===!0&&"data"in n?n.data:t}async function ct(t,e){try{return await t.json()}catch{throw new f(`Non-JSON response from ${e} (HTTP ${t.status}).`,m.FAILURE)}}async function st(t){let e;try{e=await t.clone().json()}catch{e=null}let n=L(e),r=Vo(n.error??n.error_description,t.status),o=typeof n.message=="string"?n.message:typeof n.error_description=="string"?n.error_description:typeof n.detail=="string"?n.detail:void 0;throw new Ie(r,t.status,typeof o=="string"?l(o).slice(0,2e3):void 0)}function Vo(t,e){if(typeof t!="string")return`http_${e}`;let n=l(t).slice(0,120);return/^[A-Za-z0-9_.-]+$/.test(n)?n:`http_${e}`}function Xo(t){let e=L(t);if(typeof e.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(e.sessionId)||typeof e.title!="string"||e.visibility!=="private"&&e.visibility!=="company"||typeof e.shared!="boolean")throw new f("Oracle server returned an invalid session summary.",m.API_ERROR);return{sessionId:e.sessionId,title:l(e.title),visibility:e.visibility,shared:e.shared,...typeof e.entityKey=="string"?{entityKey:l(e.entityKey)}:{},...typeof e.updatedAt=="number"||e.updatedAt===null?{updatedAt:e.updatedAt}:{}}}function Qo(t){let e=L(t),n=Xo(e);if(!Array.isArray(e.messages))throw new f("Oracle server returned an invalid session transcript.",m.API_ERROR);let r=e.messages.map((o,i)=>{let s=L(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new f(`Oracle session message ${i+1} is invalid.`,m.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(ec):void 0,c=Array.isArray(s.files)?s.files.map(tc):void 0;return{role:s.role,content:l(s.content),...typeof s.id=="string"?{id:s.id}:{},...typeof s.authorName=="string"?{authorName:l(s.authorName)}:{},...s.question&&typeof s.question=="object"?{question:Va(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:Xa(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof e.activeStreamId=="string"?{activeStreamId:e.activeStreamId}:{}}}function rr(t){let e=L(t);if(e.protocolVersion!==1||typeof e.idx!="number"||!Number.isSafeInteger(e.idx)||e.idx<0||typeof e.type!="string")throw new f("Oracle stream event does not match protocol version 1.",m.API_ERROR);return ge(e)}function Qa(t){let e=L(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle upload response is missing file metadata.",m.API_ERROR);return{fileId:e.fileId,name:l(e.name),mediaType:l(e.mediaType),...typeof e.sizeBytes=="number"?{sizeBytes:e.sizeBytes}:{}}}function Va(t){let e=L(t);if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:l(e.id),questions:e.questions.map((n,r)=>{let o=L(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:l(o.id),header:l(o.header),question:l(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=L(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new f(`Oracle question option ${s+1} is invalid.`,m.API_ERROR);return{id:l(a.id),label:l(a.label),description:l(a.description),...typeof a.recommended=="boolean"?{recommended:a.recommended}:{},...typeof a.confirms=="boolean"?{confirms:a.confirms}:{}}})}}),optional:e.optional===!0}}function Xa(t){let e=L(t);if(typeof e.questionId!="string"||!Array.isArray(e.answers))throw new f("Oracle returned an invalid question response.",m.API_ERROR);return{questionId:l(e.questionId),answers:e.answers.map(Za)}}function Za(t){let e=L(t);if(typeof e.questionId!="string"||!Array.isArray(e.optionIds)||!e.optionIds.every(n=>typeof n=="string"))throw new f("Oracle returned an invalid question answer.",m.API_ERROR);return{questionId:l(e.questionId),optionIds:e.optionIds.map(n=>l(n)),...typeof e.customText=="string"?{customText:l(e.customText).slice(0,8e3)}:{}}}function ec(t){let e=L(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle session attachment metadata is invalid.",m.API_ERROR);return{fileId:l(e.fileId),name:l(e.name),mediaType:l(e.mediaType),...typeof e.sizeBytes=="number"&&Number.isFinite(e.sizeBytes)?{sizeBytes:e.sizeBytes}:{}}}function tc(t){let e=L(t);if(typeof e.fileId!="string"||typeof e.filename!="string"||typeof e.mediaType!="string"||typeof e.sizeBytes!="number"||!Number.isFinite(e.sizeBytes))throw new f("Oracle session file metadata is invalid.",m.API_ERROR);return{fileId:l(e.fileId),filename:l(e.filename),mediaType:l(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:l(e.format)}:{}}}import{randomUUID as nc}from"node:crypto";import{promises as ye}from"node:fs";import{homedir as rc}from"node:os";import{join as ir}from"node:path";import*as ei from"proper-lockfile";function dn(){return ir(rc(),".anyforge")}function ln(){return ir(dn(),"oracle")}function ti(){return ir(dn(),"oracle.last-session")}function oc(){return{version:2,active:{},logins:[]}}function cn(t){return t===void 0||typeof t=="string"}function Zo(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.endpoint!="string"||typeof e.clientId!="string"||typeof e.redirectUri!="string"||typeof e.accessToken!="string"||typeof e.refreshToken!="string"||typeof e.expiresAt!="number"||!Number.isFinite(e.expiresAt)||!Array.isArray(e.scopes)||!e.scopes.every(n=>typeof n=="string")||!cn(e.companyId)||!cn(e.companyName)||!cn(e.uid)?null:{endpoint:e.endpoint,...e.companyId?{companyId:e.companyId}:{},...e.companyName?{companyName:e.companyName}:{},...e.uid?{uid:e.uid}:{},clientId:e.clientId,redirectUri:e.redirectUri,accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes}}function ic(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;if(e.version===1){let o=Zo(e);return o?{version:2,endpoint:o.endpoint,active:{[o.endpoint]:o.clientId},logins:[o]}:null}if(e.version!==2||!Array.isArray(e.logins)||!cn(e.endpoint)||!e.active||typeof e.active!="object"||Array.isArray(e.active))return null;let n=e.logins.map(Zo);if(n.some(o=>o===null))return null;let r={};for(let[o,i]of Object.entries(e.active)){if(typeof i!="string")return null;r[o]=i}return{version:2,...e.endpoint?{endpoint:e.endpoint}:{},active:r,logins:n}}async function Z(){let t=ln(),e;try{e=await ye.readFile(t,"utf8")}catch(o){if(o.code==="ENOENT")return oc();throw o}let n;try{n=JSON.parse(e)}catch{throw new Error(`Oracle credentials at ${t} are invalid JSON; run \`anyforge oracle logout --all\` and sign in again.`)}let r=ic(n);if(!r)throw new Error(`Oracle credentials at ${t} have an unsupported format; run \`anyforge oracle logout --all\` and sign in again.`);return r}async function _t(t){if(!t.logins.length){await ye.rm(ln(),{force:!0});return}await si(ln(),t)}async function un(t){return mn(async()=>{let e=await Z(),n=await t(e);return await _t(e),n})}function Oe(t,e){return t.logins.filter(n=>n.endpoint===e)}function pn(t,e){let n=Oe(t,e);return n.find(r=>r.clientId===t.active[e])??n[0]}function ee(t){return t.companyName||t.companyId||"workspace not known yet"}function ni(t,e){let n=e.companyId?t.logins.find(r=>r.endpoint===e.endpoint&&r.companyId===e.companyId&&r.clientId!==e.clientId):void 0;return t.logins=[...t.logins.filter(r=>r!==n&&r.clientId!==e.clientId),e],t.active[e.endpoint]=e.clientId,t.endpoint=e.endpoint,n}function sr(t,e){t.logins=t.logins.filter(o=>!(o.endpoint===e.endpoint&&o.clientId===e.clientId));let n=Oe(t,e.endpoint);if(!n.length){if(delete t.active[e.endpoint],t.endpoint===e.endpoint){let o=t.logins[0]?.endpoint;o?t.endpoint=o:delete t.endpoint}return}if(t.active[e.endpoint]!==e.clientId&&n.some(o=>o.clientId===t.active[e.endpoint]))return;let r=n[0];return t.active[e.endpoint]=r.clientId,r}function ri(t,e,n,r){let o=t.logins.find(a=>a.endpoint===e&&a.clientId===n);if(!o)return{changed:!1};let i=o.companyId!==r.companyId||r.companyName!==void 0&&o.companyName!==r.companyName||r.uid!==void 0&&o.uid!==r.uid;o.companyId=r.companyId,r.companyName!==void 0&&(o.companyName=r.companyName),r.uid!==void 0&&(o.uid=r.uid);let s=t.logins.find(a=>a!==o&&a.endpoint===e&&a.companyId===r.companyId);return s&&(t.logins=t.logins.filter(a=>a!==s),t.active[e]===s.clientId&&(t.active[e]=o.clientId)),{changed:i||!!s,...s?{duplicate:s}:{}}}function Me(t,e){let n=e.trim(),r=t.find(a=>a.companyId===n);if(r)return r;let o=t.filter(a=>a.companyName?.toLowerCase()===n.toLowerCase());if(o.length===1)return o[0];let i=t.map(a=>`${ee(a)}${a.companyId&&a.companyName?` (${a.companyId})`:""}`),s=i.length?`Saved workspaces: ${i.join(", ")}.`:"No Oracle logins are saved for this endpoint.";throw o.length>1?new y(`More than one saved workspace is named "${n}". Use its id instead.`,s):new y(`No saved Oracle login for workspace "${n}".`,`${s} Add one with \`anyforge oracle login --workspace "${n}"\`.`)}async function oi(){let t;try{t=await ye.readFile(ti(),"utf8")}catch(r){if(r.code==="ENOENT")return[];throw r}let e;try{e=JSON.parse(t)}catch{return[]}if(!e||typeof e!="object"||Array.isArray(e))return[];let n=e;return n.version!==2||!Array.isArray(n.sessions)?[]:n.sessions.filter(r=>{if(!r||typeof r!="object")return!1;let o=r;return typeof o.endpoint=="string"&&typeof o.companyId=="string"&&typeof o.sessionId=="string"})}async function ii(t,e,n=""){let r=(await oi()).filter(o=>!(o.endpoint===e&&o.companyId===n));await si(ti(),{version:2,sessions:[...r,{endpoint:e,companyId:n,sessionId:t}]})}async function fn(t,e=""){return(await oi()).find(n=>n.endpoint===t&&n.companyId===e)?.sessionId}async function si(t,e){await ye.mkdir(dn(),{recursive:!0,mode:448});let n=`${t}.${nc()}.tmp`;try{await ye.writeFile(n,`${JSON.stringify(e,null,2)}
266
+ `,{mode:384,flag:"wx"}),await ye.rename(n,t),await ye.chmod(t,384)}finally{await ye.rm(n,{force:!0}).catch(()=>{})}}async function mn(t){await ye.mkdir(dn(),{recursive:!0,mode:448});let e=ln(),n=await ei.lock(e,{realpath:!1,lockfilePath:`${e}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await t()}finally{await n()}}var ar=8192,ci=10*1048576,lc=20*1048576,li=10,di=3;function cr(t,e){if(t.type!=="tool_call"&&t.type!=="tool_call_start"||typeof t.spawnId=="string")return!1;let n=typeof t.id=="string"?t.id:void 0;if(n){if(e.has(n))return!1;e.add(n)}return!tt(t.name)}var Ue=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(e){return e.type==="finalizing"?!0:e.idx<=this.lastIdx?!1:(this.lastIdx=e.idx,e.type==="stream_start"&&typeof e.streamId=="string"?this.streamId=l(e.streamId):e.type==="delta"&&typeof e.content=="string"?this.answer+=e.content:cr(e,this.toolIds)?this.answer="":e.type==="question"?this.question=ur(e):e.type==="error"?this.error=dr(e):e.type==="done"?this.done=e:e.type==="navigator_file_created"&&dc(this.files,e.file),!0)}get settled(){return!!(this.done||this.error)}outcome(){return{answer:this.answer,...this.question?{question:this.question}:{},...this.error?{error:this.error}:{},...this.done?{done:this.done}:{},...this.streamId?{streamId:this.streamId}:{},...this.files.length?{files:[...this.files]}:{}}}};async function gn(t,e,n,r,o,i=new Ue){let s=async p=>{let R=i.streamId;i.accept(p)&&(i.streamId&&i.streamId!==R&&r.onStream?.(i.streamId),await r.onEvent(p))},a=()=>lr(t,e,i,s,o,r.onActivity),c=async()=>{try{for await(let p of t.streamRequestEvents(e,n.requestId,-1,r.onActivity))await s(p)}catch(p){throw o?.aborted?p:new f("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new f("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)},u=async()=>{try{let p=await t.submitTurn(e,n,o);for await(let R of Ct(p,r.onActivity))await s(R)}catch(p){if(o?.aborted||p instanceof f&&p.exitCode===m.API_ERROR)throw p;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},d;try{d=await t.submitTurn(e,n,o)}catch(p){if(o?.aborted||p instanceof f&&p.exitCode!==m.FAILURE)throw p;return u()}if(!d)throw new f("Oracle did not return a stream response.",m.FAILURE);r.onResponse?.();try{for await(let p of Ct(d,r.onActivity))await s(p)}catch(p){if(o?.aborted||p instanceof f)throw p;return i.streamId?a():u()}return i.settled?i.outcome():i.streamId?a():u()}async function lr(t,e,n,r,o,i){let s=n.streamId;if(!s)throw new f("Oracle stream replay needs a stream id.",m.FAILURE);let a=0;for(;!n.settled&&a<di;){if(o?.aborted)throw o.reason;try{for await(let c of t.streamReplayEvents(e,s,n.lastIdx+1,i))await r(c);if(!n.settled){if((await t.getSession(e)).activeStreamId!==s)break;await ai(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof f&&c.exitCode===m.API_ERROR||(a+=1,a>=di))throw c;await ai(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new f("Oracle stream could not be fully replayed; the turn was not submitted again.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the session.`);return n.outcome()}function $t(t,e){let n=e.done,r=n?.servedBy,o=De(n?.tokens),i=G(n?.rounds),s=typeof n?.exitReason=="string"?l(n.exitReason):void 0,a=n?.exitReason==="completed"&&!e.question,c=e.files??(Array.isArray(n?.files)?n.files.map(dt):void 0),u=e.error?"error":e.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:t,status:u,answer:l(e.answer),partial:!a,...typeof n?.messageId=="string"?{messageId:l(n.messageId)}:typeof n?.answerId=="string"?{messageId:l(n.answerId)}:{},...e.question?{question:e.question}:{},...e.error?{error:l(e.error)}:{},...e.streamId?{streamId:l(e.streamId)}:{},...r?{servedBy:ge(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:ge(c)}:{}}}function E(t,e){return typeof t=="string"?l(t).slice(0,e):""}function dr(t){return typeof t.message=="string"?l(t.message).slice(0,2e3):"Oracle turn failed."}function Q(t){return l(t instanceof Error?t.message:String(t)).slice(0,2e3)}function ur(t){let e=t.question;if(!e||typeof e!="object")throw new f("Oracle question event omitted its question card.",m.API_ERROR);return uc(e)}function dt(t){let e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};if(typeof e.fileId!="string"||!e.fileId||typeof e.filename!="string"||!e.filename||typeof e.mediaType!="string"||!e.mediaType||typeof e.sizeBytes!="number"||!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<0)throw new f("Oracle generated-file event omitted safe file metadata.",m.API_ERROR);return{fileId:l(e.fileId),filename:l(e.filename),mediaType:l(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:l(e.format)}:{}}}function dc(t,e){let n=dt(e);t.some(r=>r.fileId===n.fileId)||t.push(n)}function uc(t){let e=t;if(typeof e.id!="string"||!Array.isArray(e.questions))throw new f("Oracle returned an invalid question card.",m.API_ERROR);return{id:l(e.id),optional:e.optional===!0,questions:e.questions.map((n,r)=>{let o=n&&typeof n=="object"?n:{};if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:l(o.id),header:l(o.header),question:l(o.question),multiSelect:o.multiSelect,options:o.options.map(i=>{let s=i&&typeof i=="object"?i:{};if(typeof s.id!="string"||typeof s.label!="string"||typeof s.description!="string")throw new f("Oracle question option is invalid.",m.API_ERROR);return{id:l(s.id),label:l(s.label),description:l(s.description),...typeof s.recommended=="boolean"?{recommended:s.recommended}:{},...typeof s.confirms=="boolean"?{confirms:s.confirms}:{}}})}})}}function G(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function De(t){if(typeof t=="number"&&Number.isFinite(t))return{totalTokens:t};if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=G(e.in)??G(e.input)??G(e.inputTokens),r=G(e.cacheRead),o=G(e.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=G(e.out)??G(e.output)??G(e.outputTokens),a=G(e.total)??G(e.totalTokens)??(i!==void 0||s!==void 0?(i??0)+(s??0):void 0);if(!(i===void 0&&s===void 0&&a===void 0))return{...i!==void 0?{inputTokens:i}:{},...r?{cachedInputTokens:r}:{},...s!==void 0?{outputTokens:s}:{},...a!==void 0?{totalTokens:a}:{}}}function ut(t){if(t&&typeof t=="object"){let e=t;if(typeof e.accepted=="boolean")return e.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof e.cancelled=="boolean")return e.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function pt(t,e){let n=e&&t&&(t.kind==="program"||t.kind==="initiative")?{kind:t.kind,id:t.id}:void 0;return{...!e&&t?{context:t}:{},...n?{sharedEntity:n}:{},visibility:e?"company":"private"}}async function Pt(t,e,n){await ii(t,e,n).catch(()=>{})}async function hn(t,e,n,r){if(!n.length)return[];if(n.length>li)throw new y(`Attach no more than ${li} files per turn.`);let o=0,i=[];for(let a of n){let c=await ac(a);if(!c.isFile())throw new y(`Attachment is not a file: ${a}`);if(c.size>ci)throw new y(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let u=await pc(a,ci);if(o+=u.byteLength,o>lc)throw new y("Attachments exceed the 20 MiB total CLI limit.");let d=cc(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",p=Yo(d)??"";if(!p)throw new y(`Unsupported attachment type: ${a}`);i.push({content:u,name:d,mediaType:p})}let s=[];for(let{content:a,name:c,mediaType:u}of i){await r(l(c),a.byteLength);let d=new ArrayBuffer(a.byteLength);new Uint8Array(d).set(a);let p=new File([d],c,{type:u});s.push(await t.upload(e,p))}return s}async function pc(t,e){let n=[],r=0;for await(let o of sc(t)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>e)throw new y(`Attachment exceeds the ${D(e)} limit: ${t}`);n.push(i)}return Buffer.concat(n)}var We=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],mc=2e4,gc=6,hc={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},wc={max_rounds:"reached the step limit",max_tokens:"reached the output limit",token_budget:"reached the token budget",deadline:"ran out of time",interrupted:"interrupted",loop_detected:"stopped a repeating loop",cancelled:"cancelled"},wn=class{constructor(e,n){this.startedAt=e;this.sessionId=n;this.lastSignalAt=e}phase="sending";answer="";tools=[];notices=[];files=[];lastSignalAt;endedAt;end;done;upload;round;maxRounds;serverPhase;agents=new Map;toolIds=new Set;get toolCount(){return this.tools.length}get failedCount(){return this.tools.filter(e=>e.status==="failed").length}get finished(){return this.end!==void 0}setUploading(e,n,r){this.phase="uploading",this.upload=`${e} (${D(n)})`,this.lastSignalAt=r}setPhase(e,n){this.phase=e,this.lastSignalAt=n}touch(e){this.lastSignalAt=e}apply(e,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(e);switch(e.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=G(e.round),this.maxRounds=G(e.maxRounds)??this.maxRounds;for(let r=this.tools.length-1;r>=0;r--)this.tools[r]?.started&&this.tools.splice(r,1);this.phase!=="finishing"&&(this.phase="thinking");break;case"phase":this.serverPhase=typeof e.phase=="string"?e.phase:void 0;break;case"delta":this.phase!=="finishing"&&(this.phase="writing");break;case"tool_result":this.phase!=="finishing"&&(this.phase="thinking");break;case"finalizing":this.phase="finishing";break}this.record(e)}record(e){switch(e.type){case"delta":typeof e.content=="string"&&(this.answer+=e.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(e);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===e.toolUseId);n&&(n.status=e.ok===!1?"failed":"ok");break}case"subagent_start":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"running");break;case"subagent_done":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${E(e.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${E(e.filename,200)}: ${E(e.error,500)}`});break;case"attachment_notice":if(Array.isArray(e.notices))for(let n of e.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${E(r.name,160)}: ${E(r.message,500)}`})}break;case"provider_fallback":{let n=E(e.from,120),r=E(e.to,120),o=E(e.reason,40).replaceAll("_"," ");this.notices.push({tone:"info",text:`Switched model${n?` from ${n}`:""}${r?` to ${r}`:""}${o?` (${o})`:""}.`});break}case"navigator_file_created":{let n=dt(e.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${D(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:dr(e)});break;case"done":this.done=e;break}}recordToolCall(e){let n=typeof e.id=="string"?e.id:void 0,r=cr(e,this.toolIds),o=typeof e.name=="string"?e.name:"";if(tt(o))return;let i=E(typeof e.label=="string"?e.label:sn(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,e.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof e.spawnId=="string"?{spawnId:e.spawnId}:{},...e.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=l(this.answer.trim()),this.answer=""),this.tools.push(a),this.phase!=="finishing"&&(this.phase="thinking")}note(e,n){this.notices.push({tone:e,text:l(n)})}finish(e,n){this.end=e,this.endedAt=n}label(){if(this.phase==="cancelling")return"Cancelling";if(this.phase==="uploading")return`Uploading ${this.upload??"attachment"}`;if(this.phase==="sending")return"Sending";if(this.phase==="preparing")return"Preparing context";if(this.phase==="finishing")return"Finishing up";let e=[...this.agents.values()].filter(r=>r==="running").length;if(e)return`Researching (${e} agent${e===1?"":"s"})`;let n=this.tools.filter(r=>r.status==="running"&&!r.spawnId);return n.length===1?`Running ${n[0]?.label}`:n.length>1?`Running ${n.length} tools`:this.phase==="writing"?"Writing":this.serverPhase&&hc[this.serverPhase]||"Thinking"}statusLine(e,n){let r=[this.label(),er(e-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=e-this.lastSignalAt;return o>=mc&&this.phase!=="cancelling"&&r.push(`no update for ${er(o)}`),n&&e-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let e=[],n=Et((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=pi("\u2713"):this.end==="awaiting_input"?o=pr("?")+" Waiting for your answer":this.end==="cancelled"?o=mr("\u2717")+" Interrupted":this.end==="error"?o=fr("\u2717")+" Error":o=mr("\u2717")+` Stopped: ${r&&wc[r]||"no final answer"}`,e.push(n),this.tools.length&&e.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=De(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&e.push(`${ie(i.inputTokens??0)} in${i.cachedInputTokens?` (${ie(i.cachedInputTokens)} cached)`:""} / ${ie(i.outputTokens??0)} out`);let s=Nt(this.done?.servedBy);return s&&e.push(s),`${o} ${Be(e.join(" \xB7 "))}`}};function Nt(t){if(!t||typeof t!="object")return"";let e=t,n=E(e.model??e.id,100);if(!n)return"";let r=e.fallback&&typeof e.fallback=="object"?e.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${E(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${E(r.from,100)}${o})`}return n}var yn=class{constructor(e,n){this.activity=e;this.view=n;this.answer=new ot("",n.linkOrigin)}answer;getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(e){let n=this.activity;this.answer.setText(n.answer);let r=[Tt("assistant")];if(!n.finished&&!n.tools.length&&!n.answer.trim()){let o=pr(We[this.view.frame()%We.length]??"*");r.push(Lt(` ${o} ${Be(n.label())}`,e))}r.push(...this.renderTools(e)),r.push(...this.answer.render(e));for(let o of n.notices){let i=o.tone==="error"?fr:o.tone==="warning"?mr:Be;r.push(...ui(i(o.text),e))}return n.finished&&r.push(Lt(n.summaryLine(),e)),r}renderTools(e){let{tools:n}=this.activity;if(!n.length)return[];if(this.activity.finished&&!this.view.expanded()){let s=this.activity.failedCount,a=`Used ${n.length} tool${n.length===1?"":"s"}${s?` \xB7 ${s} failed`:""} (ctrl+o to expand)`;return[Lt(Be(` \u23BF ${a}`),e)]}let r=this.activity.finished?n:n.slice(-gc),o=n.length-r.length,i=[];return o&&i.push(Lt(Be(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),e)),r.forEach((s,a)=>{if(s.note)for(let p of ui(s.note,Math.max(10,e-4)).slice(0,3))i.push(` ${Be(fc(p))}`);let c=s.status==="running"?pr(We[this.view.frame()%We.length]??"*"):s.status==="ok"?pi("\u2713"):fr("\u2717"),u=a===0&&!o?" \u23BF ":" ",d=s.spawnId?` ${Be("agent \xB7")} `:"";i.push(Lt(`${u}${d}${c} ${s.label}`,e))}),i}};import{truncateToWidth as bc,visibleWidth as Rc,wrapTextWithAnsi as mi}from"@earendil-works/pi-tui";import{bold as gi,cyan as kc,dim as ve}from"kleur/colors";import{CombinedAutocompleteProvider as yc}from"@earendil-works/pi-tui";var Ft=[{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"]}],Oc=[{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 gr(t){let e=new Set(Ft.flatMap(n=>[n.name,...n.aliases??[]]));return(t??Oc).filter(n=>!e.has(n.name))}function fi(t,e){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(t.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=Ft.find(a=>a.name===r||a.aliases?.includes(r));if(i)return{kind:"local",command:i,arg:o,args:o?o.split(/\s+/):[]};let s=e.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function hr(t,e){let n=[...Ft.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=>vc(i.completions??[],s)}:{}})),...t.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new yc(n,e),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let u=(i[s]??"").slice(0,a);return s!==0||!u.trimStart().startsWith("/")?null:o.test(u)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,u){return r.applyCompletion(i,s,a,c,u)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function vc(t,e){let n=t.filter(r=>r.startsWith(e.toLowerCase())&&r!==e).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function qt(t,e){return t?e?"write + approve":"write":"read only"}function ft(t){return t?`${t.kind} ${l(t.id)}`:"no context"}function Ce(t){return t?l(t.companyName||t.companyId):""}function hi(t,e){let n=[`${gi(kc("\u26A1\uFE0E AnyForge Oracle"))}${ve(` \xB7 v${l(t.version)}`)}`,`${t.workspace?`${gi(t.workspace)} \xB7 `:""}${he(t.session)} \xB7 ${t.access} \xB7 ${ft(t.context)}`,...t.session.messages.length?[`Resumed: ${l(t.session.title)}`]:[],ve("Only your messages and the files you attach leave this terminal."),ve("/help commands \xB7 /status details")];if(e<24)return n.flatMap(s=>mi(s,Math.max(1,e)));let r=Math.min(e,76),o=r-4,i=[ve(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>mi(a,o))){let a=bc(s,o);i.push(`${ve("\u2502")} ${a}${" ".repeat(Math.max(0,o-Rc(a)))} ${ve("\u2502")}`)}return i.push(ve(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function wi(t){let e=(r,o)=>r?`${ve(r)} ${o}`:o,n=[{title:"Commands",rows:Ft.map(r=>[`/${r.name}`,e(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(t.server.length){let r=t.server.map(o=>[`/${o.name}`,e(o.args,l(o.description))]);t.server.some(o=>o.name==="catchup")&&!t.canApprove&&r.push(["",ve("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 wr(t){let n=[["Model",`workspace default ${t.model?`${l(t.model.provider)}/${l(t.model.id)}`:"chosen by the server"}`]],r=Nt(t.lastServedBy);if(r){let o=t.lastServedBy,i=E(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function yr(t){return[["This run",t.turns?`${t.turns} turn${t.turns===1?"":"s"} \xB7 ${t.tools} tool${t.tools===1?"":"s"} \xB7 ${ie(t.inputTokens)} in / ${ie(t.outputTokens)} out tokens`:"no turns yet"]]}function Or(t){if(!t?.finished)return[];let e=[Et((t.endedAt??t.startedAt)-t.startedAt)];e.push(`${t.toolCount} tool${t.toolCount===1?"":"s"}${t.failedCount?` (${t.failedCount} failed)`:""}`);let n=G(t.done?.rounds);n!==void 0&&e.push(`${n} round${n===1?"":"s"}`);let r=De(t.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&e.push(`${ie(r.inputTokens??0)} in${r.cachedInputTokens?` (${ie(r.cachedInputTokens)} cached)`:""} / ${ie(r.outputTokens??0)} out tokens`);let o=E(t.done?.exitReason,40);return e.push(o?o.replaceAll("_"," "):t.end??""),[["Last turn",e.filter(Boolean).join(" \xB7 ")]]}function yi(t){let e=t.capabilities?["read","write","approve"].filter(o=>t.capabilities?.[o]).join(", ")||"none":"not reported",n=t.contextText?` \xB7 note ${D(Buffer.byteLength(t.contextText,"utf8"))}`:"",r=Mo(t.limits);return[["Session",`${t.session.sessionId} \xB7 ${l(t.session.title)||"Untitled"}`],["Audience",he(t.session)],["Access",`this session ${qt(t.write,t.approve)} \xB7 grant ${t.grantScopes.join(", ")||"none"} \xB7 workspace role ${e}`],["Context",`${ft(t.context)}${n}`],...wr(t),...Or(t.lastTurn),...yr(t.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...t.identity?[["Workspace",Ac(t.identity,t.savedWorkspaces)]]:[],["Endpoint",t.endpoint],["Version",`CLI ${l(t.version)} \xB7 protocol ${1}`],["Attached",t.pendingFiles.length?`${t.pendingFiles.map(l).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function Ac(t,e){let n=t.companyName?`${l(t.companyName)} (${l(t.companyId)})`:`company ${l(t.companyId)}`,r=e!==void 0&&e>1?` \xB7 ${e} saved, /workspace to switch`:"";return`${n} \xB7 user ${l(t.uid)}${r}`}function Oi(t,e){return e.length?e.map((n,r)=>[`${r+1}.`,`${l(n.filename)} (${D(n.sizeBytes)}) \xB7 anyforge oracle download ${t} ${l(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{randomUUID as Ec}from"node:crypto";import{stat as Tc}from"node:fs/promises";import{basename as vi}from"node:path";import{bold as Cc,cyan as bi,dim as Ri,red as gt,yellow as _c}from"kleur/colors";import{Container as $c,Editor as Pc,ProcessTerminal as Lc,ScrollView as Nc,SelectList as ki,TuiAltScreen as Fc,VStack as qc,getNativeClipboard as jc,matchesKey as bn,truncateToWidth as Ai,wrapTextWithAnsi as Mc}from"@earendil-works/pi-tui";import{bold as Ic,cyan as vr,dim as On,yellow as xc}from"kleur/colors";import{Input as Sc,Text as Ge,matchesKey as mt}from"@earendil-works/pi-tui";var vn=class{constructor(e,n,r){this.tui=e;this.question=n;this.onComplete=r;(n.questions[0]?.options.length??0)===0&&(this.mode="custom"),this.customInput.onSubmit=o=>{let i=o.trim().slice(0,8e3);if(!i){this.errorMessage="Enter a short answer before continuing.",this.tui.requestRender();return}this.recordCurrent(i)},this.customInput.onEscape=()=>{if(!this.question.questions[this.questionIndex]?.options.length){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.setValue(""),this.mode="select",this.tui.setFocus(this),this.tui.requestRender()}}focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new Sc({prompt:`${vr("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:On});invalidate(){}render(e){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,e-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new Ge(`${Ic(vr(l(n.header)))}${On(o)}`,0,0).render(r),...new Ge(l(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Ge(On(`Enter submits your text${n.options.length?" \xB7 Esc back to the choices":this.question.optional?" \xB7 Esc skip":""}`),0,0).render(r))):i.push(...new Ge(On(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Ge(xc(this.errorMessage),0,0).render(r)),i.map(s=>`${vr("\u2502")} ${s}`)}handleInput(e){if(this.mode==="custom"){this.customInput.handleInput(e);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(mt(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(e);return}if(mt(e,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(mt(e,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(mt(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(e.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(e);if(Number.isInteger(o)&&o>=1&&o<=n.options.length){let i=n.options[o-1]?.id;i&&(this.optionIndex=o-1,n.multiSelect?r.has(i)?r.delete(i):r.add(i):(r.clear(),r.add(i)),this.tui.requestRender());return}if(mt(e,"space")&&n.multiSelect){let i=n.options[this.optionIndex];i&&(r.has(i.id)?r.delete(i.id):r.add(i.id),this.tui.requestRender());return}if(mt(e,"enter")){if(r.size===0){this.errorMessage="Select an option explicitly, type a custom answer, or skip if optional.",this.tui.requestRender();return}this.recordCurrent()}}renderOptions(e,n){let r=this.selectedFor(e),o=[];return e.options.forEach((i,s)=>{let a=r.has(i.id),c=e.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",u=s===this.optionIndex?"\u203A":" ",d=i.recommended?" \xB7 recommended":"",p=i.confirms?" \xB7 confirms the shown action":"",R=`${u} ${s+1}. ${c} ${l(i.label)}${d}${p}`;o.push(...new Ge(R,0,0).render(n)),o.push(...new Ge(` ${l(i.description)}`,0,0).render(n))}),o}instructions(e){return e.options.length===0?`Write a short answer${this.question.optional?" \xB7 s or Esc skip card":""}`:`\u2191/\u2193 move \xB7 1\u2013${e.options.length} ${e.multiSelect?"toggle":"select"}${e.multiSelect?" \xB7 Space toggle":""} \xB7 Enter continue \xB7 o write your own${this.question.optional?" \xB7 s or Esc skip card":""}`}requireAnswer(){let e=this.question.questions[this.questionIndex];this.errorMessage=e?.options.length?"Oracle needs an answer to continue: pick an option, or press o to write your own.":"Oracle needs an answer to continue: type it and press Enter.",this.tui.requestRender()}selectedFor(e){let n=this.selected.get(e.id);return n||(n=new Set,this.selected.set(e.id,n)),n}recordCurrent(e){let n=this.question.questions[this.questionIndex];if(!n)return;e&&this.selectedFor(n).clear();let r=[...this.selectedFor(n)],o={questionId:n.id,optionIds:r,...e?{customText:e}:{}},i=this.answers.findIndex(s=>s.questionId===n.id);if(i>=0?this.answers.splice(i,1,o):this.answers.push(o),this.customInput.setValue(""),this.mode="select",this.questionIndex<this.question.questions.length-1){this.questionIndex+=1,this.optionIndex=0,this.mode=this.question.questions[this.questionIndex]?.options.length===0?"custom":"select",this.errorMessage="",this.tui.setFocus(this),this.tui.requestRender();return}this.finish({questionId:this.question.id,answers:this.answers.map(s=>({...s}))})}finish(e){this.onComplete(e)}};var Ii=1500,Uc=100,Dc="\x1B]133;A\x07";function ht(t){return{render:t,invalidate(){}}}function xi(t,e,n,r){let o=new ot(e,r);return{getText:()=>o.getText(),invalidate:()=>o.invalidate(),render:i=>t==="user"?Ko(o,i,n).map((s,a)=>a===1?`${Dc}${s}`:s):[Tt("assistant"),...o.render(i)]}}async function Si(t){let{client:e,config:n}=t,r=new Lc,o=new Fc(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new $c,s=new Nc(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new Pc(o,Go),c=gr(n.commands),u=()=>typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,d=t.session,p=t.initialContext,R=t.contextText,I=t.canWrite,x=t.canApprove,O,v,k,P,j=[...t.initialFiles],U=!1,ue=!1,ze=!1,Sn=0,He,Cr=0,Dt=!1,_e="",wt,Bt,Ye=[],Je={turns:0,inputTokens:0,outputTokens:0,tools:0},Wt=new Map,pe,Xi=ht(g=>{if(O){let h=bi(We[Sn%We.length]??"*");return[Ai(`${h} ${O.activity.statusLine(Date.now(),u())}`,g)]}return pe?[Ai(`${bi("?")} Waiting for your answer to the question above`,g)]:[]}),Zi=ht(g=>{let h=[Ce(n.identity),qt(I,x),ft(p),zo(d),j.length?`${j.length} file${j.length===1?"":"s"} attached`:"",v!==void 0?"1 message queued":""];return[Ri(Do(g,h,O?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new qc([{component:s,basis:0,grow:1,minSize:1},{component:Xi,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:Zi,basis:"auto",shrink:0,minSize:1}]));let te=()=>o.requestRender(),N=g=>o.flash(l(g),3e3),ke=g=>{i.addChild(g),te()},B=(g,h=Ri)=>{let w=l(g);ke(ht(b=>Mc(h(w),Math.max(1,b))))},Gt=(g,h)=>{ke(ht(w=>["",...Uo(g,h,w)]))},es=()=>{He||(He=setInterval(()=>{Sn+=1,te()},Uc),He.unref())},En=()=>{He&&clearInterval(He),He=void 0},Qe=()=>{U||o.hasOverlay()||o.setFocus(pe??a)},_r=g=>{k=g;let h=Wt.get(g.id);h&&i.removeChild(h);let w=new vn(o,g,b=>{Wt.delete(g.id),pe===w&&(pe=void 0),i.removeChild(w),rs(b??{questionId:g.id,skipped:!0,answers:[]}),Qe()});Wt.set(g.id,w),pe=w,ke(w)},Kt=g=>{i.clear(),Wt.clear(),pe=void 0,d=g,k=void 0,P=void 0,Ye=[],_e="";let h={version:t.version,workspace:Ce(n.identity),session:g,access:qt(I,x),context:p};ke(ht(b=>hi(h,b)));let w;for(let b of g.messages){ke(xi(b.role,b.content,b.authorName,e.endpoint)),b.role==="assistant"&&(_e=b.content),b.question&&(w=b.question),b.questionResponse&&(B("A stored response was recorded for this question."),w?.id===b.questionResponse.questionId&&(w=void 0));for(let A of b.files??[])Ye.some(_=>_.fileId===A.fileId)||Ye.push(A),B(`File: ${A.filename} (${A.mediaType}, ${D(A.sizeBytes)}) \xB7 anyforge oracle download ${g.sessionId} ${A.fileId} --output .`)}w&&_r(w),Qe(),Pt(g.sessionId,e.endpoint,n.identity?.companyId)},$r,ts=new Promise(g=>{$r=g}),zt=()=>{U||(U=!0,En(),O?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),$r())},Tn=async()=>{let g=O;if(!g||g.cancelling)return;g.cancelling=!0,g.activity.setPhase("cancelling",Date.now()),te();let{streamId:h,requestId:w}=g;g.controller.abort(new Error("Turn cancelled by user."));let b;if(h)try{b=ut(await e.cancelTurn(d.sessionId,h))}catch(A){b=`Could not confirm server cancellation: ${Q(A)}`}else if(w)try{b=ut(await e.cancelRequest(d.sessionId,w))}catch(A){b=`Could not confirm server cancellation by request id: ${Q(A)}`}else b="The turn had not reached the server; nothing was sent.";g.activity.note("info",b),te()},Ve=async g=>{if(O||U)return;if(g.kind==="submit"&&g.response){let $=k;if(!$||$.id!==g.response.questionId){N("That question is no longer active. Resume the session to refresh it.");return}B(Bc($,g.response)),k=void 0}else g.kind==="submit"&&ke(xi("user",g.text));let h=d.sessionId,w=new wn(Date.now(),h),b=new yn(w,{expanded:()=>ze,frame:()=>Sn,linkOrigin:e.endpoint}),A={activity:w,view:b,controller:new AbortController,cancelling:!1};O=A,ke(b),es();let _=new Ue,H=$=>{w.apply($,Date.now()),$.type==="question"&&(_r(ur($)),Qe()),te()},$e={onEvent:H,onStream:$=>{A.streamId=$},onResponse:()=>{w.phase==="sending"&&w.setPhase("preparing",Date.now())},onActivity:()=>w.touch(Date.now())},ne="error";try{if(g.kind==="replay"){_.streamId=g.streamId,A.streamId=g.streamId,w.setPhase("thinking",Date.now());let $=await lr(e,h,_,async se=>{_.accept(se)&&H(se)},A.controller.signal,$e.onActivity);ne=$t(h,$).status}else{let $=g.response?[]:j.splice(0),se=await hn(e,h,$,(Cn,fs)=>{w.setUploading(Cn,fs,Date.now()),te()});A.controller.signal.throwIfAborted(),w.setPhase("sending",Date.now());let Ht=Ec();A.requestId=Ht;let us={requestId:Ht,text:g.response?"":g.text,readOnly:!I,...x?{allowApprove:!0}:{},...p?{context:p}:{},...R?{contextText:R}:{},...g.response?{questionResponse:g.response}:{},...se.length?{attachments:se.map(Cn=>({fileId:Cn.fileId}))}:{}},ps=await gn(e,h,us,$e,A.controller.signal,_);ne=$t(h,ps).status}}catch($){if(A.controller.signal.aborted)ne="cancelled";else{ne="error";let se=$ instanceof f&&$.hint?` ${l($.hint)}`:"";w.note("error",`${Q($)}${se}`)}}finally{w.finish(ne,Date.now()),O=void 0,En(),U||(ue=ne==="cancelled"),wt=w,w.answer.trim()&&(_e=w.answer),w.done?.servedBy&&(Bt=w.done.servedBy);let $=De(w.done?.tokens);Je.turns+=1,Je.tools+=w.toolCount,Je.inputTokens+=$?.inputTokens??0,Je.outputTokens+=$?.outputTokens??0;for(let se of w.files)Ye.some(Ht=>Ht.fileId===se.fileId)||Ye.push(se);te()}if(!U){if(A.streamId&&ne!=="cancelled"){let $=await e.getSession(h).catch(()=>{});$&&$.sessionId===d.sessionId&&(d=$)}ns(ne)}},ns=g=>{if(!(U||O)){if(P){let h=P;P=void 0,Ve({kind:"submit",text:"",response:h});return}if(v!==void 0){let h=v;if(v=void 0,g==="complete"&&!pe){Ve({kind:"submit",text:h});return}a.getText()||a.setText(h),N("Your queued message is back in the input; press Enter to send it.")}Qe(),te()}},rs=g=>{if(O){P=g,N("Answer saved; Oracle continues once the current turn settles.");return}Ve({kind:"submit",text:"",response:g})},Pr=async g=>{try{let h=await e.getSession(g);Kt(h),h.activeStreamId&&Ve({kind:"replay",streamId:h.activeStreamId}),N(`Resumed ${h.title||h.sessionId}.`)}catch(h){B(Q(h),gt)}},os=async()=>{try{let g=await e.listSessions();if(!g.length){N("No saved conversations to resume.");return}let h=new ki(g.map(_=>({value:_.sessionId,label:_.title,description:he(_)})),Math.min(12,g.length),it),w=await fn(e.endpoint,n.identity?.companyId),b=w?g.findIndex(_=>_.sessionId===w):-1;b>=0&&h.setSelectedIndex(b);let A=o.showOverlay(h,{width:"85%",maxHeight:"80%",anchor:"center"});h.onSelect=_=>{A.hide(),Pr(_.value)},h.onCancel=()=>{A.hide(),Qe()},A.focus()}catch(g){B(Q(g),gt)}},Lr=async g=>{if(g&&(!p||p.kind!=="program"&&p.kind!=="initiative")){N("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let h=await e.createSession(pt(p,g));Kt(h),N(`Started a new conversation \xB7 ${he(h)}.`)}catch(h){B(Q(h),gt)}},Nr=async(g,h)=>{let w=l(ee(h));if(h.companyId&&h.companyId===n.identity?.companyId){N(`Already in ${w}.`);return}Dt=!0;try{N(`Connecting to ${w}...`);let b=await g.connect(h),A=await b.client.createSession(pt(void 0,!1));e=b.client,n=b.config,c=gr(n.commands),a.setAutocompleteProvider(hr(c,process.cwd()));let _=e.scopes.has("write")&&n.capabilities?.write===!0,H=e.scopes.has("approve")&&n.capabilities?.approve===!0,$e=I&&!_||x&&!H;I&&!_&&(I=!1),(!I||!H)&&(x=!1);let ne=p!==void 0;p=void 0,Bt=void 0,wt=void 0,Kt(A),B(`Switched to ${Ce(n.identity)||w}. This is a new conversation in that workspace.${ne?" Context was cleared because its id belongs to the previous workspace.":""}`),$e&&B(`Access here is ${qt(I,x)}: this workspace's login or your role there does not allow more.`,_c)}catch(b){let A=b instanceof f&&b.hint?` ${l(b.hint)}`:"";B(`Could not switch to ${w}: ${Q(b)}${A}`,gt)}finally{Dt=!1}},is=async(g,h)=>{let w=n.identity?.companyId,b=new ki(h.map(H=>({value:H.clientId,label:ee(H),description:[H.companyId,H.scopes.join(", "),H.companyId===w?"current":""].filter(Boolean).join(" \xB7 ")})),Math.min(12,h.length),it),A=h.findIndex(H=>H.companyId===w);A>=0&&b.setSelectedIndex(A);let _=o.showOverlay(b,{width:"85%",maxHeight:"80%",anchor:"center"});b.onSelect=H=>{_.hide();let $e=h.find(ne=>ne.clientId===H.value);$e&&Nr(g,$e)},b.onCancel=()=>{_.hide(),Qe()},_.focus()},ss=async g=>{let h=t.workspaces;if(!h){B(`This terminal signs in with ANYFORGE_API_TOKEN, which is bound to ${Ce(n.identity)||"one workspace"}. To switch workspaces, unset it and sign in with \`anyforge oracle login --workspace <name>\`.`);return}let w=await h.list();if(g){let b;try{b=Me(w,g)}catch(A){let _=A instanceof f&&A.hint?` ${l(A.hint)}`:"";B(`${Q(A)}${_}`,gt);return}await Nr(h,b);return}if(w.length<=1){B(`${Ce(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 is(h,w)},as=g=>({session:d,write:I,approve:x,grantScopes:[...e.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...p?{context:p}:{},...R?{contextText:R}:{},...n.model?{model:n.model}:{},lastServedBy:Bt,...wt?{lastTurn:wt}:{},totals:{...Je},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},...g!==void 0?{savedWorkspaces:g}:{},endpoint:e.endpoint,version:t.version,pendingFiles:j.map(h=>vi(h))}),cs=async()=>{if(!_e.trim()){N("There is no answer to copy yet.");return}try{let g=jc();g?.setText?await g.setText(_e):r.write(`\x1B]52;c;${Buffer.from(_e,"utf8").toString("base64")}\x07`),N(`Copied the last answer (${_e.length} characters).`)}catch(g){N(`Could not copy: ${Q(g)}`)}},ls=async(g,h,w)=>{if(g.idleOnly&&Dt){N("Wait for the workspace switch to finish.");return}if(g.idleOnly&&O){N(`Wait for Oracle to finish, or press Esc, before /${g.name}.`);return}switch(g.name){case"help":ke(ht(b=>["",...wi({server:c,canApprove:x}).flatMap(A=>[Cc(A.title),...tr(A.rows,b)])]));return;case"status":{let b=await t.workspaces?.list().then(A=>A.length).catch(()=>{});Gt("Status",yi(as(b)));return}case"workspace":await ss(w);return;case"model":Gt("Model",wr({...n.model?{model:n.model}:{},lastServedBy:Bt}));return;case"usage":Gt("Usage",[...Or(wt),...yr(Je)]);return;case"files":Gt("Generated files",Oi(d.sessionId,Ye));return;case"copy":await cs();return;case"exit":zt();return;case"new":if(w&&w!=="shared"){N("Usage: /new or /new shared");return}await Lr(w==="shared");return;case"clear":await Lr(!1);return;case"resume":w?await Pr(w):await os();return;case"context":{if(!w){B(`Context: ${ft(p)}${R?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(w==="clear")p=void 0;else{let[b,A,..._]=h;if(!["program","initiative","codebase"].includes(b??"")||!A||_.length){N("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}p={kind:b,id:A}}B(`Context for your next message: ${ft(p)}.`);return}case"attach":{if(!w){N("Usage: /attach <file path>");return}let b=await Tc(w).catch(()=>{});if(!b?.isFile()){N(`Not a readable file: ${w}`);return}j.push(w),B(`Attached ${vi(w)} (${D(b.size)}). It uploads with your next message.`);return}}},Fr=g=>{let h=g.trim();if(!h)return;a.addToHistory(h);let w=fi(h,c);if(w?.kind==="local"){ls(w.command,w.args,w.arg).catch(b=>B(Q(b),gt));return}if(w?.kind==="unknown"){a.setText(h),N(`Unknown command /${w.name}. Type /help to see the commands.`);return}if(Dt){a.setText(h),N("Switching workspace; send your message once it has opened.");return}if(O){let b=v!==void 0;v=h,N(b?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),te();return}Ve({kind:"submit",text:h})},ds=o.addInputListener(g=>{if(bn(g,"ctrl+c")){if(O)return Tn(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),te(),{consume:!0};let h=Date.now();return h-Cr<=Ii?zt():(Cr=h,o.flash("Press Ctrl+C again to exit",Ii)),{consume:!0}}if(bn(g,"escape")){let h=pe!==void 0&&o.getFocusedComponent()===pe;return O&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!h?(Tn(),{consume:!0}):void 0}if(bn(g,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(zt(),{consume:!0}):void 0;if(bn(g,"ctrl+o"))return ze=!ze,N(ze?"Showing tool activity":"Hiding tool activity"),te(),{consume:!0}}),qr=()=>{let g=!!O;Tn().finally(()=>{g&&(ue=!0),zt()})};process.on("SIGINT",qr),a.onSubmit=Fr,a.onChange=()=>te(),a.setAutocompleteProvider(hr(c,process.cwd())),Kt(t.session),o.start(),d.activeStreamId&&Ve({kind:"replay",streamId:d.activeStreamId}),t.initialPrompt&&Fr(t.initialPrompt),await ts,ds(),process.off("SIGINT",qr),En(),O?.controller.abort(),await r.drainInput().catch(()=>{}),ue&&(process.exitCode=130)}function Bc(t,e){if(e.skipped)return"Skipped the optional Oracle question.";let n=[];for(let r of e.answers){let o=t.questions.find(i=>i.id===r.questionId);for(let i of r.optionIds){let s=o?.options.find(a=>a.id===i);s&&n.push(s.label)}r.customText&&n.push(r.customText)}return`You answered: ${n.map(l).join("; ")||"no options selected"}`}import{createHash as Wc,randomBytes as Ei,timingSafeEqual as Gc}from"node:crypto";import{createServer as Kc}from"node:http";import zc from"open";var Hc=6e4,Yc=5*6e4,Rn=new Map;async function br(t){let e=Te(t.endpoint),n=await qe(e),r=["read"];t.write&&r.push("write"),t.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=Ei(32).toString("base64url"),i=await Xc(o);try{let s={client_name:"AnyForge CLI",redirect_uris:[i.redirectUri],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"},a=await Zc(n.oauth.registration,s);if(typeof a.client_id!="string"||!a.client_id)throw new f("OAuth registration did not return a client id.",m.API_ERROR);let c=Ei(32).toString("base64url"),u=Wc("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:u,code_challenge_method:"S256",resource:n.resource},p=new URL(n.oauth.authorization);for(let[U,ue]of Object.entries(d))p.searchParams.set(U,String(ue));let R=t.workspace?.trim();R&&p.searchParams.set(Jo,R),t.onAuthorizationUrl?.(p.toString());try{t.openBrowser?await t.openBrowser(p.toString()):await zc(p.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
266
267
  ${p.toString()}
267
- `)}let x=await i.wait();if(!Ni(x.state,o))throw new f("Oracle sign-in callback state did not match; authorization was rejected.",m.API_ERROR);if(x.error)throw new f(`Oracle authorization failed: ${d(x.error)}${x.errorDescription?` (${d(x.errorDescription)})`:""}`,m.API_ERROR);if(!x.code)throw new f("Oracle authorization callback did not include a code.",m.API_ERROR);let b={client_id:a.client_id,grant_type:"authorization_code",code:x.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},O=await ji(n.oauth.token,b);qi(O);let R=Fi(O.scope);if(!R.includes("read")||R.some(q=>!r.includes(q)))throw await An(n.oauth.revocation,a.client_id,O.access_token,O.refresh_token).catch(()=>{}),new f("The granted Oracle scopes are invalid for this request.",m.API_ERROR);let A=await qe(e,fetch,O.access_token).then(q=>q.identity).catch(()=>{}),z={endpoint:e,...Ei(A),clientId:a.client_id,redirectUri:i.redirectUri,accessToken:O.access_token,refreshToken:O.refresh_token,expiresAt:Date.now()+O.expires_in*1e3,scopes:R},j=await dn(q=>Zo(q,z));return j&&await An(n.oauth.revocation,j.clientId,j.accessToken,j.refreshToken).catch(()=>{}),z}finally{await i.close()}}function Ei(t){return t?{companyId:t.companyId,...t.companyName?{companyName:t.companyName}:{},uid:t.uid}:{}}async function Ti(t={}){if(t.workspace&&!t.all){let n=Ft(await Z(),t.endpointOverride);n&&await br(n)}let e=await fn(async()=>{let n=await Z(),r=[];if(t.all)r=[...n.logins];else{let s=Ft(n,t.endpointOverride);t.workspace?r=[Me(s?ye(n,s):[],t.workspace)]:s&&(r=[un(n,s)].filter(a=>!!a))}let o=[],i;for(let s of r){try{await Ci(s)}catch(a){o.push({login:s,error:a})}i=sr(n,s)??i}return await Tt(n),{removed:r,failures:o,...i&&!t.all?{nowActive:i}:{}}});if(e.failures.length){let n=e.failures.map(({login:r,error:o})=>{let i=o instanceof Error?d(o.message):"unknown error";return e.failures.length>1||t.all?`${d(ee(r))}: ${i}`:i});throw new f(`Local Oracle credentials were cleared, but server revocation failed for ${e.failures.length===1?"one login":`${e.failures.length} logins`}: ${n.join("; ")}`,m.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire these access tokens automatically.")}return{removed:e.removed,...e.nowActive?{nowActive:e.nowActive}:{}}}async function Ci(t){let e=await qe(t.endpoint);await An(e.oauth.revocation,t.clientId,t.accessToken,t.refreshToken)}function Ft(t,e){let n=e||process.env.ANYFORGE_ENDPOINT;return n?Ee(n):t.endpoint}function _i(){return new y("ANYFORGE_API_TOKEN is set, so Oracle uses that key and its one workspace; saved Oracle logins are not used.","Unset ANYFORGE_API_TOKEN to choose between your saved workspaces.")}async function $i(t,e){let n=t||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN){if(e)throw _i();return Si(n)}let r=await Z(),o=Ft(r,n);if(e)return qt(await Gc(o,e));let i=o?un(r,o):void 0;if(i)return qt(i);try{return await Si(n)}catch(s){throw r.logins.length&&n?new ce:s instanceof ce?new ce:s}}async function Gc(t,e){if(!t)return Me([],e);let n=await In(t);return Me(n,e)}function qt(t){return{endpoint:t.endpoint,accessToken:t.accessToken,scopes:t.scopes.filter(Rr),source:"oauth",getAccessToken:async e=>Kc(t.endpoint,t.clientId,e),onIdentity:async e=>{if(t.companyId===e.companyId&&(e.companyName===void 0||t.companyName===e.companyName)&&t.uid===e.uid)return;let r=await dn(i=>ei(i,t.endpoint,t.clientId,e));Object.assign(t,Ei(e));let o=r.duplicate;o&&await Ci(o).catch(()=>{})}}}async function In(t){return await br(t),ye(await Z(),t)}async function br(t){let e=ye(await Z(),t).filter(n=>!n.companyId);for(let n of e)await new je(qt(n)).config().catch(()=>{})}async function Pi(t){let e=Ft(await Z(),t);if(!e)return{logins:[]};let n=await In(e),r=un(await Z(),e);return{endpoint:e,logins:n,...r?{active:r}:{}}}async function Li(t,e){if(process.env.ANYFORGE_API_TOKEN)throw _i();let n=Ft(await Z(),t);return n&&await br(n),dn(r=>{let o=Me(n?ye(r,n):[],e);return r.active[o.endpoint]=o.clientId,r.endpoint=o.endpoint,o})}async function Si(t){let e=await Ie(t),r=(await ht({apiKey:e.apiKey,endpoint:e.endpoint})).scopes.filter(Rr);return{endpoint:e.endpoint,accessToken:e.apiKey,scopes:r,source:"control"}}async function Kc(t,e,n){let r=Ee(t),o=`${r}
268
- ${e}`,i=Rn.get(o);if(i)return i;let s=fn(()=>zc(r,e,n));Rn.set(o,s);try{return await s}finally{Rn.get(o)===s&&Rn.delete(o)}}async function zc(t,e,n){let r=await Z(),o=r.logins.find(u=>u.endpoint===t&&u.clientId===e);if(!o)throw new ce;if(o.expiresAt>Date.now()+Bc&&(!n||o.accessToken!==n))return o.accessToken;let i=async()=>{sr(r,o),await Tt(r)},s=await qe(o.endpoint),a;try{let u={client_id:o.clientId,grant_type:"refresh_token",refresh_token:o.refreshToken,resource:s.resource};a=await ji(s.oauth.token,u)}catch(u){throw u instanceof kn&&["invalid_grant","invalid_client","invalid_target"].includes(u.code)?(await i(),new ce):u}qi(a);let c;try{c=Fi(a.scope)}catch(u){throw await i(),u}if(c.some(u=>!o.scopes.includes(u)))throw await An(s.oauth.revocation,o.clientId,a.access_token,a.refresh_token),await i(),new f("Oracle refresh attempted to widen the saved grant; credentials were cleared.",m.API_ERROR);return o.accessToken=a.access_token,o.refreshToken=a.refresh_token,o.expiresAt=Date.now()+a.expires_in*1e3,o.scopes=c,await Tt(r),o.accessToken}var kn=class extends f{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?m.NO_CREDENTIALS:m.API_ERROR);this.code=n;this.name="OAuthResponseError"}};async function Hc(t){let e,n,r=!1,o=new Promise((c,u)=>{e=c,n=u});o.catch(()=>{});let i=Uc((c,u)=>{if((c.url?.length??0)>8192){u.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let l=c.url??"/";if(!l.startsWith("/callback")||l.startsWith("//")){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let p=new URL(l,"http://127.0.0.1");if(c.method!=="GET"||p.pathname!=="/callback"){u.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let k=p.searchParams.get("code")?.slice(0,2048)??"",x=p.searchParams.get("state")?.slice(0,256)??"",b=p.searchParams.get("error")?.slice(0,256)??void 0,O=p.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!x){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!Ni(x,t)){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(r){u.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}r=!0,u.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'"}).end('<!doctype html><meta charset="utf-8"><title>AnyForge Oracle</title><p>Sign-in response received. You may close this tab.</p>'),e({code:k,state:x,...b?{error:b}:{},...O?{errorDescription:O}:{}})});await new Promise((c,u)=>{i.once("error",u),i.listen(0,"127.0.0.1",()=>{i.removeListener("error",u),c()})});let s=i.address();if(!s||typeof s=="string")throw new f("Could not bind an Oracle sign-in callback port.",m.FAILURE);let a=setTimeout(()=>{r||(r=!0,n(new f("Oracle sign-in timed out before the browser returned.",m.FAILURE)))},Wc);return a.unref(),{redirectUri:`http://127.0.0.1:${s.port}/callback`,wait:()=>o,close:async()=>{clearTimeout(a),i.listening&&(i.closeAllConnections(),await new Promise(c=>i.close(()=>c())))}}}function Ni(t,e){let n=Buffer.from(t),r=Buffer.from(e);return n.length===r.length&&Mc(n,r)}function Fi(t){let e=t.split(/[\s+]+/).filter(Boolean);if(!e.every(Rr))throw new f("OAuth server returned an unknown Oracle scope.",m.API_ERROR);let n=[...new Set(e)];if(!n.includes("read"))throw new f("Oracle OAuth grant is missing the required read scope.",m.API_ERROR);return n}function Rr(t){return t==="read"||t==="write"||t==="approve"}function qi(t){if(!t||typeof t.access_token!="string"||!t.access_token||typeof t.refresh_token!="string"||!t.refresh_token||typeof t.token_type!="string"||t.token_type.toLowerCase()!=="bearer"||typeof t.expires_in!="number"||!Number.isFinite(t.expires_in)||t.expires_in<=0||typeof t.scope!="string")throw new f("OAuth token response did not match the supported format.",m.API_ERROR)}async function Yc(t,e){return Mi(t,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)})}async function ji(t,e){return Mi(t,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(Object.entries(e).map(([n,r])=>[n,String(r)])).toString()})}async function Mi(t,e){let n;try{n=await fetch(t,{...e,redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(o){throw new f(`OAuth request failed: ${d(o instanceof Error?o.message:String(o))}`,m.FAILURE)}let r=null;try{r=await n.json()}catch{}if(!n.ok){let o=r&&typeof r=="object"?r:{},i=typeof o.error=="string"?o.error:`http_${n.status}`,s=typeof o.error_description=="string"?d(o.error_description):i;throw new kn(i,s,n.status)}if(!r||typeof r!="object"||Array.isArray(r))throw new f(`OAuth endpoint returned invalid JSON (${n.status}).`,m.API_ERROR);return r}async function An(t,e,n,r){let o=async i=>{let s=await fetch(t,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:e,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=d(c.error_description))}catch{}throw new f(`OAuth token revocation failed: ${a}`,m.API_ERROR)}};await o(r),n!==r&&await o(n)}var cl=1048576,ll=25*1048576;async function zi(t){let[e,...n]=t.positional,r=["exec","sessions","resume","login","logout","download","workspaces","use"].includes(e??""),o=pt(t.flags,"workspace")?.trim()||void 0,i=r?void 0:t.positional.join(" ");if(M(t.flags,"read-only")&&(M(t.flags,"write")||M(t.flags,"approve")))throw new y("--read-only cannot be combined with --write or --approve.");if(!r&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(e==="login"){if(n.length)throw new y("oracle login does not accept positional arguments.");let b=await vr({endpoint:t.endpointOverride??t.endpoint,write:M(t.flags,"write"),approve:M(t.flags,"approve"),...o?{workspace:o}:{}}),R=[M(t.flags,"write")?"write":void 0,M(t.flags,"approve")?"approve":void 0].filter(A=>!!A).filter(A=>!b.scopes.includes(A));process.stdout.write(`${Ui(b)}
269
- `),R.length&&process.stderr.write(`This account was granted read only; the server withheld: ${R.join(", ")}.
270
- `),await ul(b,o);return}if(e==="logout"){if(n.length)throw new y("oracle logout does not accept positional arguments.");let b=M(t.flags,"all");if(b&&o)throw new y("Choose either --workspace or --all.");let O=await Ti({...t.endpointOverride?{endpointOverride:t.endpointOverride}:{},...o?{workspace:o}:{},all:b});if(!O.removed.length){process.stdout.write(`No saved Oracle login.
271
- `);return}let R=O.removed.map(A=>d(ee(A))).join(", ");process.stdout.write(`Logged out of ${R}; ${O.removed.length===1?"its access was":"their access was"} revoked.
272
- `),O.nowActive&&process.stdout.write(`Active workspace is now ${d(ee(O.nowActive))}.
273
- `);return}if(e==="workspaces"){if(n.length)throw new y("oracle workspaces does not accept positional arguments.");await fl(t.endpointOverride,t.flags.json===!0);return}if(e==="use"){let b=n.join(" ").trim();if(!b)throw new y("oracle use needs a workspace name or id.","Run `anyforge oracle workspaces` to list your saved workspaces.");let O=await Li(t.endpointOverride,b);process.stdout.write(`Now using ${d(ee(O))} (${O.scopes.join(", ")}) at ${O.endpoint}.
274
- `);return}let s;try{s=await Wi(t.endpointOverride,o)}catch(b){if(!r&&b instanceof f&&b.exitCode===m.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let O=(await import("prompts")).default;if((await O({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw b;let A=await vr({endpoint:t.endpointOverride??t.endpoint,...o?{workspace:o}:{}});process.stderr.write(`${Ui(A)}
275
- `),s=await Wi(t.endpointOverride)}else throw b}if(e==="sessions"){if(n.length)throw new y("oracle sessions does not accept positional arguments.");let b=t.flags.json===!0;b||await Di(await s.config().catch(()=>{}));let O=await s.listSessions();gl(O,b);return}if(e==="download"){await Ol(s,n,t.flags);return}if(e==="exec"){if(M(t.flags,"write")||M(t.flags,"approve"))throw new y("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(t.flags.json===!0&&M(t.flags,"stream-json"))throw new y("Choose either --json or --stream-json.");let b=await ml(n.join(" ")),O=await s.config();Ir(s,O),t.flags.json!==!0&&!M(t.flags,"stream-json")&&await Di(O),Gi(pt(t.flags,"context"));let R=or(t.flags),A=await s.createSession(st(R,!1));await _t(A.sessionId,s.endpoint,O.identity?.companyId);let z=await gn(s,A.sessionId,Bi(t.flags),(q,Ce)=>V(process.stderr,`Uploading explicit attachment ${q} (${U(Ce)}).
276
- `)),j={requestId:Vc(),text:b,readOnly:!0,...R?{context:R}:{},...pt(t.flags,"context")?{contextText:pt(t.flags,"context")}:{},...z.length?{attachments:z.map(q=>({fileId:q.fileId}))}:{}};await wl(s,A.sessionId,j,{json:t.flags.json===!0,streamJson:M(t.flags,"stream-json"),config:O});return}if(e==="resume"&&n.length>1)throw new y("oracle resume accepts at most one session id.");if(e==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("oracle resume is interactive and needs a terminal.","Use `anyforge oracle sessions` to list sessions, or run `anyforge oracle exec` for a new scripted turn.");let a=await s.config();Ir(s,a);let c=or(t.flags),u=pt(t.flags,"context");Gi(u);let l=M(t.flags,"shared"),p=M(t.flags,"write")||M(t.flags,"approve");if(p&&(!s.scopes.has("write")||a.capabilities?.write!==!0))throw new f("This Oracle grant or current workspace role does not allow write actions.",m.API_ERROR);if(M(t.flags,"approve")&&(!s.scopes.has("approve")||a.capabilities?.approve!==!0))throw new f("This Oracle grant or current workspace role does not allow approval actions.",m.API_ERROR);if(l&&(!c||c.kind!=="program"&&c.kind!=="initiative"))throw new y("--shared requires --program or --initiative.");let k;if(e==="resume"){let O=(n[0]||void 0)??await hl(await s.listSessions(),await pn(s.endpoint,a.identity?.companyId));k=await s.getSession(O)}else k=await s.createSession(st(c,l));await _t(k.sessionId,s.endpoint,a.identity?.companyId);let x=await Promise.resolve().then(()=>(Ar(),kr));await Ii({version:x.default.version,client:s,config:a,session:k,initialPrompt:i,initialContext:c,contextText:u,shared:l,canWrite:p,canApprove:M(t.flags,"approve"),initialFiles:Bi(t.flags),...s.source==="oauth"?{workspaces:dl(s.endpoint)}:{}})}function dl(t){return{list:()=>In(t),connect:async e=>{let n=new je(qt(e)),r=await n.config();return Ir(n,r),{client:n,config:r}}}}function Ui(t){let e=t.scopes.join(", ");return t.companyId?`Connected to ${d(ee(t))} (${e}) at ${t.endpoint}.`:`Connected to ${t.endpoint} (${e}). The server did not say which workspace; \`anyforge oracle workspaces\` shows it once it does.`}async function ul(t,e){let n=d(ee(t));e&&t.companyId&&!pl(t,e)&&process.stderr.write(`You asked for "${d(e)}", but ${n} was chosen on the consent page, so this login is for ${n}.
277
- `);let r=ye(await Z(),t.endpoint).length;r>1&&process.stderr.write(`${n} is now your active workspace (${r} saved). List them with \`anyforge oracle workspaces\`; switch with \`anyforge oracle use <name>\`.
278
- `)}function pl(t,e){return t.companyId===e||t.companyName?.toLowerCase()===e.toLowerCase()}async function Di(t){let e=Te(t?.identity);e&&await V(process.stderr,`${ve(`Workspace: ${e}`)}
279
- `)}async function fl(t,e){let n=await Pi(t),r=n.logins.map(o=>({name:o.companyName??null,companyId:o.companyId??null,endpoint:o.endpoint,scopes:o.scopes,active:o.clientId===n.active?.clientId}));if(e)process.stdout.write(`${JSON.stringify(r,null,2)}
280
- `);else if(!r.length)process.stdout.write("No saved Oracle logins. Run `anyforge oracle login` to add one.\n");else{process.stdout.write(`${ve(`Oracle workspaces saved for ${n.endpoint??"this endpoint"}:`)}
281
- `);for(let o of n.logins){let i=o.clientId===n.active?.clientId,s=d(ee(o)),a=o.companyId&&o.companyName?d(o.companyId):"",c=[i?Sr(`* ${s}`):` ${s}`,a?ve(a):"",ve(o.scopes.join(", ")),i?Ki("active"):""];process.stdout.write(`${c.filter(Boolean).join(" ")}
268
+ `)}let I=await i.wait();if(!qi(I.state,o))throw new f("Oracle sign-in callback state did not match; authorization was rejected.",m.API_ERROR);if(I.error)throw new f(`Oracle authorization failed: ${l(I.error)}${I.errorDescription?` (${l(I.errorDescription)})`:""}`,m.API_ERROR);if(!I.code)throw new f("Oracle authorization callback did not include a code.",m.API_ERROR);let x={client_id:a.client_id,grant_type:"authorization_code",code:I.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},O=await Ui(n.oauth.token,x);Mi(O);let v=ji(O.scope);if(!v.includes("read")||v.some(U=>!r.includes(U)))throw await An(n.oauth.revocation,a.client_id,O.access_token,O.refresh_token).catch(()=>{}),new f("The granted Oracle scopes are invalid for this request.",m.API_ERROR);let k=await qe(e,fetch,O.access_token).then(U=>U.identity).catch(()=>{}),P={endpoint:e,...Ci(k),clientId:a.client_id,redirectUri:i.redirectUri,accessToken:O.access_token,refreshToken:O.refresh_token,expiresAt:Date.now()+O.expires_in*1e3,scopes:v},j=await un(U=>ni(U,P));return j&&await An(n.oauth.revocation,j.clientId,j.accessToken,j.refreshToken).catch(()=>{}),P}finally{await i.close()}}function Ci(t){return t?{companyId:t.companyId,...t.companyName?{companyName:t.companyName}:{},uid:t.uid}:{}}async function _i(t={}){if(t.workspace&&!t.all){let n=jt(await Z(),t.endpointOverride);n&&await Rr(n)}let e=await mn(async()=>{let n=await Z(),r=[];if(t.all)r=[...n.logins];else{let s=jt(n,t.endpointOverride);t.workspace?r=[Me(s?Oe(n,s):[],t.workspace)]:s&&(r=[pn(n,s)].filter(a=>!!a))}let o=[],i;for(let s of r){try{await $i(s)}catch(a){o.push({login:s,error:a})}i=sr(n,s)??i}return await _t(n),{removed:r,failures:o,...i&&!t.all?{nowActive:i}:{}}});if(e.failures.length){let n=e.failures.map(({login:r,error:o})=>{let i=o instanceof Error?l(o.message):"unknown error";return e.failures.length>1||t.all?`${l(ee(r))}: ${i}`:i});throw new f(`Local Oracle credentials were cleared, but server revocation failed for ${e.failures.length===1?"one login":`${e.failures.length} logins`}: ${n.join("; ")}`,m.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire these access tokens automatically.")}return{removed:e.removed,...e.nowActive?{nowActive:e.nowActive}:{}}}async function $i(t){let e=await qe(t.endpoint);await An(e.oauth.revocation,t.clientId,t.accessToken,t.refreshToken)}function jt(t,e){let n=e||process.env.ANYFORGE_ENDPOINT;return n?Te(n):t.endpoint}function Pi(){return new y("ANYFORGE_API_TOKEN is set, so Oracle uses that key and its one workspace; saved Oracle logins are not used.","Unset ANYFORGE_API_TOKEN to choose between your saved workspaces.")}async function Li(t,e){let n=t||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN){if(e)throw Pi();return Ti(n)}let r=await Z(),o=jt(r,n);if(e)return Mt(await Jc(o,e));let i=o?pn(r,o):void 0;if(i)return Mt(i);try{return await Ti(n)}catch(s){throw r.logins.length&&n?new ce:s instanceof ce?new ce:s}}async function Jc(t,e){if(!t)return Me([],e);let n=await In(t);return Me(n,e)}function Mt(t){return{endpoint:t.endpoint,accessToken:t.accessToken,scopes:t.scopes.filter(kr),source:"oauth",getAccessToken:async e=>Qc(t.endpoint,t.clientId,e),onIdentity:async e=>{if(t.companyId===e.companyId&&(e.companyName===void 0||t.companyName===e.companyName)&&t.uid===e.uid)return;let r=await un(i=>ri(i,t.endpoint,t.clientId,e));Object.assign(t,Ci(e));let o=r.duplicate;o&&await $i(o).catch(()=>{})}}}async function In(t){return await Rr(t),Oe(await Z(),t)}async function Rr(t){let e=Oe(await Z(),t).filter(n=>!n.companyId);for(let n of e)await new je(Mt(n)).config().catch(()=>{})}async function Ni(t){let e=jt(await Z(),t);if(!e)return{logins:[]};let n=await In(e),r=pn(await Z(),e);return{endpoint:e,logins:n,...r?{active:r}:{}}}async function Fi(t,e){if(process.env.ANYFORGE_API_TOKEN)throw Pi();let n=jt(await Z(),t);return n&&await Rr(n),un(r=>{let o=Me(n?Oe(r,n):[],e);return r.active[o.endpoint]=o.clientId,r.endpoint=o.endpoint,o})}async function Ti(t){let e=await xe(t),r=(await vt({apiKey:e.apiKey,endpoint:e.endpoint})).scopes.filter(kr);return{endpoint:e.endpoint,accessToken:e.apiKey,scopes:r,source:"control"}}async function Qc(t,e,n){let r=Te(t),o=`${r}
269
+ ${e}`,i=Rn.get(o);if(i)return i;let s=mn(()=>Vc(r,e,n));Rn.set(o,s);try{return await s}finally{Rn.get(o)===s&&Rn.delete(o)}}async function Vc(t,e,n){let r=await Z(),o=r.logins.find(u=>u.endpoint===t&&u.clientId===e);if(!o)throw new ce;if(o.expiresAt>Date.now()+Hc&&(!n||o.accessToken!==n))return o.accessToken;let i=async()=>{sr(r,o),await _t(r)},s=await qe(o.endpoint),a;try{let u={client_id:o.clientId,grant_type:"refresh_token",refresh_token:o.refreshToken,resource:s.resource};a=await Ui(s.oauth.token,u)}catch(u){throw u instanceof kn&&["invalid_grant","invalid_client","invalid_target"].includes(u.code)?(await i(),new ce):u}Mi(a);let c;try{c=ji(a.scope)}catch(u){throw await i(),u}if(c.some(u=>!o.scopes.includes(u)))throw await An(s.oauth.revocation,o.clientId,a.access_token,a.refresh_token),await i(),new f("Oracle refresh attempted to widen the saved grant; credentials were cleared.",m.API_ERROR);return o.accessToken=a.access_token,o.refreshToken=a.refresh_token,o.expiresAt=Date.now()+a.expires_in*1e3,o.scopes=c,await _t(r),o.accessToken}var kn=class extends f{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?m.NO_CREDENTIALS:m.API_ERROR);this.code=n;this.name="OAuthResponseError"}};async function Xc(t){let e,n,r=!1,o=new Promise((c,u)=>{e=c,n=u});o.catch(()=>{});let i=Kc((c,u)=>{if((c.url?.length??0)>8192){u.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let d=c.url??"/";if(!d.startsWith("/callback")||d.startsWith("//")){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let p=new URL(d,"http://127.0.0.1");if(c.method!=="GET"||p.pathname!=="/callback"){u.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let R=p.searchParams.get("code")?.slice(0,2048)??"",I=p.searchParams.get("state")?.slice(0,256)??"",x=p.searchParams.get("error")?.slice(0,256)??void 0,O=p.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!I){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!qi(I,t)){u.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(r){u.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}r=!0,u.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'"}).end('<!doctype html><meta charset="utf-8"><title>AnyForge Oracle</title><p>Sign-in response received. You may close this tab.</p>'),e({code:R,state:I,...x?{error:x}:{},...O?{errorDescription:O}:{}})});await new Promise((c,u)=>{i.once("error",u),i.listen(0,"127.0.0.1",()=>{i.removeListener("error",u),c()})});let s=i.address();if(!s||typeof s=="string")throw new f("Could not bind an Oracle sign-in callback port.",m.FAILURE);let a=setTimeout(()=>{r||(r=!0,n(new f("Oracle sign-in timed out before the browser returned.",m.FAILURE)))},Yc);return a.unref(),{redirectUri:`http://127.0.0.1:${s.port}/callback`,wait:()=>o,close:async()=>{clearTimeout(a),i.listening&&(i.closeAllConnections(),await new Promise(c=>i.close(()=>c())))}}}function qi(t,e){let n=Buffer.from(t),r=Buffer.from(e);return n.length===r.length&&Gc(n,r)}function ji(t){let e=t.split(/[\s+]+/).filter(Boolean);if(!e.every(kr))throw new f("OAuth server returned an unknown Oracle scope.",m.API_ERROR);let n=[...new Set(e)];if(!n.includes("read"))throw new f("Oracle OAuth grant is missing the required read scope.",m.API_ERROR);return n}function kr(t){return t==="read"||t==="write"||t==="approve"}function Mi(t){if(!t||typeof t.access_token!="string"||!t.access_token||typeof t.refresh_token!="string"||!t.refresh_token||typeof t.token_type!="string"||t.token_type.toLowerCase()!=="bearer"||typeof t.expires_in!="number"||!Number.isFinite(t.expires_in)||t.expires_in<=0||typeof t.scope!="string")throw new f("OAuth token response did not match the supported format.",m.API_ERROR)}async function Zc(t,e){return Di(t,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)})}async function Ui(t,e){return Di(t,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(Object.entries(e).map(([n,r])=>[n,String(r)])).toString()})}async function Di(t,e){let n;try{n=await fetch(t,{...e,redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(o){throw new f(`OAuth request failed: ${l(o instanceof Error?o.message:String(o))}`,m.FAILURE)}let r=null;try{r=await n.json()}catch{}if(!n.ok){let o=r&&typeof r=="object"?r:{},i=typeof o.error=="string"?o.error:`http_${n.status}`,s=typeof o.error_description=="string"?l(o.error_description):i;throw new kn(i,s,n.status)}if(!r||typeof r!="object"||Array.isArray(r))throw new f(`OAuth endpoint returned invalid JSON (${n.status}).`,m.API_ERROR);return r}async function An(t,e,n,r){let o=async i=>{let s=await fetch(t,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:e,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=l(c.error_description))}catch{}throw new f(`OAuth token revocation failed: ${a}`,m.API_ERROR)}};await o(r),n!==r&&await o(n)}var fl=1048576,ml=25*1048576;async function Yi(t){let[e,...n]=t.positional,r=["exec","sessions","resume","login","logout","download","workspaces","use"].includes(e??""),o=Ke(t.flags,"print");if(o!==void 0&&t.positional.length)throw new y("-p/--print takes the prompt as its value and cannot be combined with a subcommand or positional prompt.");let i=Ke(t.flags,"workspace")?.trim()||void 0,s=r?void 0:t.positional.join(" ");if(M(t.flags,"read-only")&&(M(t.flags,"write")||M(t.flags,"approve")))throw new y("--read-only cannot be combined with --write or --approve.");if(!r&&o===void 0&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(e==="login"){if(n.length)throw new y("oracle login does not accept positional arguments.");let O=await br({endpoint:t.endpointOverride??t.endpoint,write:M(t.flags,"write"),approve:M(t.flags,"approve"),...i?{workspace:i}:{}}),k=[M(t.flags,"write")?"write":void 0,M(t.flags,"approve")?"approve":void 0].filter(P=>!!P).filter(P=>!O.scopes.includes(P));process.stdout.write(`${Bi(O)}
270
+ `),k.length&&process.stderr.write(`This account was granted read only; the server withheld: ${k.join(", ")}.
271
+ `),await hl(O,i);return}if(e==="logout"){if(n.length)throw new y("oracle logout does not accept positional arguments.");let O=M(t.flags,"all");if(O&&i)throw new y("Choose either --workspace or --all.");let v=await _i({...t.endpointOverride?{endpointOverride:t.endpointOverride}:{},...i?{workspace:i}:{},all:O});if(!v.removed.length){process.stdout.write(`No saved Oracle login.
272
+ `);return}let k=v.removed.map(P=>l(ee(P))).join(", ");process.stdout.write(`Logged out of ${k}; ${v.removed.length===1?"its access was":"their access was"} revoked.
273
+ `),v.nowActive&&process.stdout.write(`Active workspace is now ${l(ee(v.nowActive))}.
274
+ `);return}if(e==="workspaces"){if(n.length)throw new y("oracle workspaces does not accept positional arguments.");await yl(t.endpointOverride,t.flags.json===!0);return}if(e==="use"){let O=n.join(" ").trim();if(!O)throw new y("oracle use needs a workspace name or id.","Run `anyforge oracle workspaces` to list your saved workspaces.");let v=await Fi(t.endpointOverride,O);process.stdout.write(`Now using ${l(ee(v))} (${v.scopes.join(", ")}) at ${v.endpoint}.
275
+ `);return}let a;try{a=await Ki(t.endpointOverride,i)}catch(O){if(!r&&o===void 0&&O instanceof f&&O.exitCode===m.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let v=(await import("prompts")).default;if((await v({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw O;let P=await br({endpoint:t.endpointOverride??t.endpoint,...i?{workspace:i}:{}});process.stderr.write(`${Bi(P)}
276
+ `),a=await Ki(t.endpointOverride)}else throw O}if(e==="sessions"){if(n.length)throw new y("oracle sessions does not accept positional arguments.");let O=t.flags.json===!0;O||await Wi(await a.config().catch(()=>{}));let v=await a.listSessions();vl(v,O);return}if(e==="download"){await Al(a,n,t.flags);return}if(e==="exec"||o!==void 0){if(M(t.flags,"write")||M(t.flags,"approve"))throw new y("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(t.flags.json===!0&&M(t.flags,"stream-json"))throw new y("Choose either --json or --stream-json.");let O=await Ol(o??n.join(" ")),v=await a.config();xr(a,v),t.flags.json!==!0&&!M(t.flags,"stream-json")&&await Wi(v),zi(Ke(t.flags,"context"));let k=or(t.flags),P=await a.createSession(pt(k,!1));await Pt(P.sessionId,a.endpoint,v.identity?.companyId);let j=await hn(a,P.sessionId,Gi(t.flags),(ue,ze)=>V(process.stderr,`Uploading explicit attachment ${ue} (${D(ze)}).
277
+ `)),U={requestId:nl(),text:O,readOnly:!0,...k?{context:k}:{},...Ke(t.flags,"context")?{contextText:Ke(t.flags,"context")}:{},...j.length?{attachments:j.map(ue=>({fileId:ue.fileId}))}:{}};await Rl(a,P.sessionId,U,{json:t.flags.json===!0,streamJson:M(t.flags,"stream-json"),config:v});return}if(e==="resume"&&n.length>1)throw new y("oracle resume accepts at most one session id.");if(e==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("oracle resume is interactive and needs a terminal.","Use `anyforge oracle sessions` to list sessions, or run `anyforge oracle exec` for a new scripted turn.");let c=await a.config();xr(a,c);let u=or(t.flags),d=Ke(t.flags,"context");zi(d);let p=M(t.flags,"shared"),R=M(t.flags,"write")||M(t.flags,"approve");if(R&&(!a.scopes.has("write")||c.capabilities?.write!==!0))throw new f("This Oracle grant or current workspace role does not allow write actions.",m.API_ERROR);if(M(t.flags,"approve")&&(!a.scopes.has("approve")||c.capabilities?.approve!==!0))throw new f("This Oracle grant or current workspace role does not allow approval actions.",m.API_ERROR);if(p&&(!u||u.kind!=="program"&&u.kind!=="initiative"))throw new y("--shared requires --program or --initiative.");let I;if(e==="resume"){let v=(n[0]||void 0)??await bl(await a.listSessions(),await fn(a.endpoint,c.identity?.companyId));I=await a.getSession(v)}else I=await a.createSession(pt(u,p));await Pt(I.sessionId,a.endpoint,c.identity?.companyId);let x=await Promise.resolve().then(()=>(Ir(),Ar));await Si({version:x.default.version,client:a,config:c,session:I,initialPrompt:s,initialContext:u,contextText:d,shared:p,canWrite:R,canApprove:M(t.flags,"approve"),initialFiles:Gi(t.flags),...a.source==="oauth"?{workspaces:gl(a.endpoint)}:{}})}function gl(t){return{list:()=>In(t),connect:async e=>{let n=new je(Mt(e)),r=await n.config();return xr(n,r),{client:n,config:r}}}}function Bi(t){let e=t.scopes.join(", ");return t.companyId?`Connected to ${l(ee(t))} (${e}) at ${t.endpoint}.`:`Connected to ${t.endpoint} (${e}). The server did not say which workspace; \`anyforge oracle workspaces\` shows it once it does.`}async function hl(t,e){let n=l(ee(t));e&&t.companyId&&!wl(t,e)&&process.stderr.write(`You asked for "${l(e)}", but ${n} was chosen on the consent page, so this login is for ${n}.
278
+ `);let r=Oe(await Z(),t.endpoint).length;r>1&&process.stderr.write(`${n} is now your active workspace (${r} saved). List them with \`anyforge oracle workspaces\`; switch with \`anyforge oracle use <name>\`.
279
+ `)}function wl(t,e){return t.companyId===e||t.companyName?.toLowerCase()===e.toLowerCase()}async function Wi(t){let e=Ce(t?.identity);e&&await V(process.stderr,`${be(`Workspace: ${e}`)}
280
+ `)}async function yl(t,e){let n=await Ni(t),r=n.logins.map(o=>({name:o.companyName??null,companyId:o.companyId??null,endpoint:o.endpoint,scopes:o.scopes,active:o.clientId===n.active?.clientId}));if(e)process.stdout.write(`${JSON.stringify(r,null,2)}
281
+ `);else if(!r.length)process.stdout.write("No saved Oracle logins. Run `anyforge oracle login` to add one.\n");else{process.stdout.write(`${be(`Oracle workspaces saved for ${n.endpoint??"this endpoint"}:`)}
282
+ `);for(let o of n.logins){let i=o.clientId===n.active?.clientId,s=l(ee(o)),a=o.companyId&&o.companyName?l(o.companyId):"",c=[i?Er(`* ${s}`):` ${s}`,a?be(a):"",be(o.scopes.join(", ")),i?Hi("active"):""];process.stdout.write(`${c.filter(Boolean).join(" ")}
282
283
  `)}}process.env.ANYFORGE_API_TOKEN&&process.stderr.write(`ANYFORGE_API_TOKEN is set, so Oracle commands use that key and its workspace instead of these logins.
283
- `)}function M(t,e){return t[e]===!0}function pt(t,e){let n=t[e];return typeof n=="string"?n:void 0}function Bi(t){let e=t.file;return typeof e=="string"?[e]:Array.isArray(e)?e:[]}async function Wi(t,e){try{return new je(await $i(t,e))}catch(n){throw n instanceof f&&n.exitCode===m.NO_CREDENTIALS?new f("Not authenticated for the hosted Oracle.",m.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):n}}function Ir(t,e){if(!t.scopes.has("read")||e.capabilities?.read===!1)throw new f("This credential does not have Oracle read access.",m.API_ERROR)}function Gi(t){if(t&&Buffer.byteLength(t,"utf8")>ar)throw new y(`--context must be ${ar/1024} KiB or less.`)}async function ml(t){let e=t.trim();if(process.stdin.isTTY){if(e)return e;throw new y("oracle exec requires a prompt when stdin is a terminal.",'Example: anyforge oracle exec "summarize this program"')}let n=[],r=0;for await(let i of process.stdin){let s=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=s.byteLength,r>cl)throw new y("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!e&&!o)throw new y("oracle exec needs a prompt in argv or piped stdin.");return[e,o].filter(Boolean).join(`
284
+ `)}function M(t,e){return t[e]===!0}function Ke(t,e){let n=t[e];return typeof n=="string"?n:void 0}function Gi(t){let e=t.file;return typeof e=="string"?[e]:Array.isArray(e)?e:[]}async function Ki(t,e){try{return new je(await Li(t,e))}catch(n){throw n instanceof f&&n.exitCode===m.NO_CREDENTIALS?new f("Not authenticated for the hosted Oracle.",m.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):n}}function xr(t,e){if(!t.scopes.has("read")||e.capabilities?.read===!1)throw new f("This credential does not have Oracle read access.",m.API_ERROR)}function zi(t){if(t&&Buffer.byteLength(t,"utf8")>ar)throw new y(`--context must be ${ar/1024} KiB or less.`)}async function Ol(t){let e=t.trim();if(process.stdin.isTTY){if(e)return e;throw new y("oracle exec requires a prompt when stdin is a terminal.",'Example: anyforge oracle exec "summarize this program"')}let n=[],r=0;for await(let i of process.stdin){let s=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=s.byteLength,r>fl)throw new y("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!e&&!o)throw new y("oracle exec needs a prompt in argv or piped stdin.");return[e,o].filter(Boolean).join(`
284
285
 
285
- `)}function gl(t,e){if(e){process.stdout.write(`${JSON.stringify(t,null,2)}
286
+ `)}function vl(t,e){if(e){process.stdout.write(`${JSON.stringify(t,null,2)}
286
287
  `);return}if(!t.length){process.stdout.write(`No Oracle sessions are available.
287
- `);return}for(let n of t){let r=ge(n);process.stdout.write(`${Sr(n.sessionId)} ${d(n.title)} ${ve(r)}
288
- `)}}async function hl(t,e){if(!t.length)throw new f("No accessible Oracle sessions are available.",m.API_ERROR);return new Promise((n,r)=>{let o=new ol,i=new al(o),s=new sl(Sr("Resume an Oracle session")),a=new il(t.map(p=>({value:p.sessionId,label:p.title,description:ge(p)})),12,Ze),c=e?t.findIndex(p=>p.sessionId===e):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=p=>{l(),n(p.value)},a.onCancel=()=>{l(),r(new f("Session selection cancelled.",m.FAILURE))};let u=()=>{l(),r(new f("Session selection interrupted.",m.INTERRUPTED))},l=()=>{process.off("SIGINT",u),i.stop()};process.once("SIGINT",u),i.start()})}async function V(t,e){t.write(e)||await new Promise(n=>t.once("drain",n))}async function wl(t,e,n,r){let o=new Ue,i=!1,s,a=new AbortController,c=()=>s??=u(),u=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let A=await t.cancelTurn(e,o.streamId);await V(process.stderr,`${it(A)}
289
- `)}catch(A){await V(process.stderr,`Could not confirm server cancellation: ${Q(A)}
290
- `)}else try{let A=await t.cancelRequest(e,n.requestId);await V(process.stderr,`${it(A)}
291
- `)}catch(A){await V(process.stderr,`Could not confirm server cancellation by request id: ${Q(A)}
292
- `)}},l=()=>{c().catch(()=>{})};process.on("SIGINT",l);let p=async A=>V(process.stdout,`${JSON.stringify(me(A))}
293
- `),k=new xr(e),x=-1,b=async A=>{if(r.streamJson){if(A.idx<=x)return;A.type!=="finalizing"&&(x=A.idx),await p({...A,sessionId:e})}else await k.emit(A)},O;try{O=await mn(t,e,n,{onEvent:b},a.signal,o)}catch(A){if(!i)throw process.off("SIGINT",l),A;O=o.outcome()}finally{process.off("SIGINT",l),s&&await s}let R=Ct(e,O);return r.streamJson?await p({protocolVersion:1,type:"result",result:R}):r.json?await V(process.stdout,`${JSON.stringify(R,null,2)}
294
- `):(R.answer&&await V(process.stdout,`${co(R.answer,t.endpoint)}
295
- `),R.status==="awaiting_input"&&await V(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
296
- `),R.status==="interrupted"&&await V(process.stderr,`Oracle turn ended without a complete final answer.
297
- `),R.status==="error"&&R.error&&await V(process.stderr,`Oracle error: ${d(R.error)}
298
- `),(R.servedBy||R.usage||R.rounds!==void 0)&&await V(process.stderr,yl(R.servedBy,R.usage,R.rounds))),i?process.exitCode=130:R.status==="error"?process.exitCode=m.API_ERROR:R.status==="interrupted"&&(process.exitCode=m.FAILURE),R}var xr=class{constructor(e){this.sessionId=e}labels=new Map;announced=new Set;async emit(e){let n=this.describe(e);n&&await V(process.stderr,`${n}
299
- `)}describe(e){switch(e.type){case"tool_call":{if(Ve(e.name))return"";let n=E(typeof e.label=="string"?e.label:on(E(e.name,240)),120),r=typeof e.id=="string"?e.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${ve(typeof e.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${Ki(n)}`}case"tool_result":{if(e.ok!==!1)return"";let n=typeof e.toolUseId=="string"?this.labels.get(e.toolUseId):void 0;return xn(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return xn(`Warning: ${E(e.message,500)}`);case"navigator_file_error":return xn(`Could not generate ${E(e.filename,200)}: ${E(e.error,500)}`);case"navigator_file_created":{let n=ot(e.file);return ve(`Generated ${n.filename} (${U(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=E(e.from,120),r=E(e.to,120);return ve(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(e.notices)?e.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${xn("Attachment")} ${E(r.name,160)}: ${E(r.message,500)}`}).join(`
300
- `):"";default:return""}}};function yl(t,e,n){let r=[];if(t&&typeof t=="object"){let o=t,i=Pt(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(E(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${E(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(E(o.provider,100))}return e?.inputTokens!==void 0||e?.outputTokens!==void 0?r.push(`${e.inputTokens??0} in${e.cachedInputTokens?` (${e.cachedInputTokens} cached)`:""} / ${e.outputTokens??0} out tokens`):e?.totalTokens!==void 0&&r.push(`${e.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${ve(r.join(" \xB7 "))}
301
- `:""}async function Ol(t,e,n){if(e.length!==2)throw new y("oracle download needs exactly a session id and file id.");let[r,o]=e;if(!r||!o)throw new y("oracle download needs a session id and file id.");let i=pt(n,"output");if(!i)throw new y("oracle download requires --output <existing-directory>.");let s=rl(i),a=await Zc(s);if(!(await el(a)).isDirectory())throw new y("--output must point to an existing directory.");let u=await t.download(r,o),l=bl(vl(u.headers.get("content-disposition"))),p=nl(a,l),k=await Rl(u,ll),x;try{x=await Xc(p,"wx",384),await x.writeFile(k)}catch(b){throw b.code==="EEXIST"?new f(`Refusing to overwrite ${p}.`,m.FAILURE):b}finally{await x?.close()}process.stdout.write(`Downloaded ${d(l)} to ${d(p)} (${U(k.byteLength)}).
302
- `)}function vl(t){if(!t)return"oracle-file.bin";let e=/filename\*=UTF-8''([^;]+)/i.exec(t)?.[1];if(e)try{return decodeURIComponent(e.replace(/^"|"$/g,""))}catch{return"oracle-file.bin"}let n=/filename="?([^";]+)"?/i.exec(t)?.[1];return n?n.trim():"oracle-file.bin"}function bl(t){let e=tl(t.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!e||e==="."||e===".."?"oracle-file.bin":e}async function Rl(t,e){if(!t.body)return Buffer.alloc(0);let n=t.body.getReader(),r=[],o=0;try{for(;;){let{value:i,done:s}=await n.read();if(s)break;let a=Buffer.from(i);if(o+=a.byteLength,o>e)throw new f(`Oracle download exceeds the ${U(e)} limit.`,m.API_ERROR);r.push(a)}}catch(i){throw await n.cancel("Oracle download exceeded its byte limit.").catch(()=>{}),i}finally{n.releaseLock()}return Buffer.concat(r)}var Ji="https://crew.anyforge.ai",Al=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output","workspace"]),Il=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json"]);function xl(t){let e={positional:[],flags:{}};for(let n=0;n<t.length;n+=1){let r=t[n];if(!r.startsWith("-")){e.command?e.positional.push(r):e.command=r;continue}let o=r==="-h"?"help":r==="-V"?"version":r==="-f"?"force":r.replace(/^--?/,""),[i,s]=o.includes("=")?[o.slice(0,o.indexOf("=")),o.slice(o.indexOf("=")+1)]:[o,void 0];if(Al.has(i)){let a=s??t[++n];if(a===void 0)throw new y(`--${i} needs a value.`);if(i==="file"){let c=e.flags.file;e.flags.file=[...typeof c=="string"?[c]:Array.isArray(c)?c:[],a]}else e.flags[i]=a;continue}if(Il.has(i)){e.flags[i]=s===void 0?!0:s!=="false";continue}throw new y(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return e}function be(t,e){if(t===void 0||typeof t=="boolean")return;let n=Number(t);if(!Number.isFinite(n)||n<=0)throw new y(`--${e} must be a positive number, got "${t}".`);return n}function G(t){return typeof t=="string"?t:void 0}function Er(t){return t===!0?!0:void 0}function Sl(){console.log(`
303
- ${K("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
304
-
305
- ${K("USAGE")}
288
+ `);return}for(let n of t){let r=he(n);process.stdout.write(`${Er(n.sessionId)} ${l(n.title)} ${be(r)}
289
+ `)}}async function bl(t,e){if(!t.length)throw new f("No accessible Oracle sessions are available.",m.API_ERROR);return new Promise((n,r)=>{let o=new ll,i=new pl(o),s=new ul(Er("Resume an Oracle session")),a=new dl(t.map(p=>({value:p.sessionId,label:p.title,description:he(p)})),12,it),c=e?t.findIndex(p=>p.sessionId===e):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=p=>{d(),n(p.value)},a.onCancel=()=>{d(),r(new f("Session selection cancelled.",m.FAILURE))};let u=()=>{d(),r(new f("Session selection interrupted.",m.INTERRUPTED))},d=()=>{process.off("SIGINT",u),i.stop()};process.once("SIGINT",u),i.start()})}async function V(t,e){t.write(e)||await new Promise(n=>t.once("drain",n))}async function Rl(t,e,n,r){let o=new Ue,i=!1,s,a=new AbortController,c=()=>s??=u(),u=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let k=await t.cancelTurn(e,o.streamId);await V(process.stderr,`${ut(k)}
290
+ `)}catch(k){await V(process.stderr,`Could not confirm server cancellation: ${Q(k)}
291
+ `)}else try{let k=await t.cancelRequest(e,n.requestId);await V(process.stderr,`${ut(k)}
292
+ `)}catch(k){await V(process.stderr,`Could not confirm server cancellation by request id: ${Q(k)}
293
+ `)}},d=()=>{c().catch(()=>{})};process.on("SIGINT",d);let p=async k=>V(process.stdout,`${JSON.stringify(ge(k))}
294
+ `),R=new Sr(e),I=-1,x=async k=>{if(r.streamJson){if(k.idx<=I)return;k.type!=="finalizing"&&(I=k.idx),await p({...k,sessionId:e})}else await R.emit(k)},O;try{O=await gn(t,e,n,{onEvent:x},a.signal,o)}catch(k){if(!i)throw process.off("SIGINT",d),k;O=o.outcome()}finally{process.off("SIGINT",d),s&&await s}let v=$t(e,O);return r.streamJson?await p({protocolVersion:1,type:"result",result:v}):r.json?await V(process.stdout,`${JSON.stringify(v,null,2)}
295
+ `):(v.answer&&await V(process.stdout,`${uo(v.answer,t.endpoint)}
296
+ `),v.status==="awaiting_input"&&await V(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
297
+ `),v.status==="interrupted"&&await V(process.stderr,`Oracle turn ended without a complete final answer.
298
+ `),v.status==="error"&&v.error&&await V(process.stderr,`Oracle error: ${l(v.error)}
299
+ `),(v.servedBy||v.usage||v.rounds!==void 0)&&await V(process.stderr,kl(v.servedBy,v.usage,v.rounds))),i?process.exitCode=130:v.status==="error"?process.exitCode=m.API_ERROR:v.status==="interrupted"&&(process.exitCode=m.FAILURE),v}var Sr=class{constructor(e){this.sessionId=e}labels=new Map;announced=new Set;async emit(e){let n=this.describe(e);n&&await V(process.stderr,`${n}
300
+ `)}describe(e){switch(e.type){case"tool_call":{if(tt(e.name))return"";let n=E(typeof e.label=="string"?e.label:sn(E(e.name,240)),120),r=typeof e.id=="string"?e.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${be(typeof e.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${Hi(n)}`}case"tool_result":{if(e.ok!==!1)return"";let n=typeof e.toolUseId=="string"?this.labels.get(e.toolUseId):void 0;return xn(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return xn(`Warning: ${E(e.message,500)}`);case"navigator_file_error":return xn(`Could not generate ${E(e.filename,200)}: ${E(e.error,500)}`);case"navigator_file_created":{let n=dt(e.file);return be(`Generated ${n.filename} (${D(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=E(e.from,120),r=E(e.to,120);return be(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(e.notices)?e.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${xn("Attachment")} ${E(r.name,160)}: ${E(r.message,500)}`}).join(`
301
+ `):"";default:return""}}};function kl(t,e,n){let r=[];if(t&&typeof t=="object"){let o=t,i=Nt(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(E(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${E(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(E(o.provider,100))}return e?.inputTokens!==void 0||e?.outputTokens!==void 0?r.push(`${e.inputTokens??0} in${e.cachedInputTokens?` (${e.cachedInputTokens} cached)`:""} / ${e.outputTokens??0} out tokens`):e?.totalTokens!==void 0&&r.push(`${e.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${be(r.join(" \xB7 "))}
302
+ `:""}async function Al(t,e,n){if(e.length!==2)throw new y("oracle download needs exactly a session id and file id.");let[r,o]=e;if(!r||!o)throw new y("oracle download needs a session id and file id.");let i=Ke(n,"output");if(!i)throw new y("oracle download requires --output <existing-directory>.");let s=cl(i),a=await ol(s);if(!(await il(a)).isDirectory())throw new y("--output must point to an existing directory.");let u=await t.download(r,o),d=xl(Il(u.headers.get("content-disposition"))),p=al(a,d),R=await Sl(u,ml),I;try{I=await rl(p,"wx",384),await I.writeFile(R)}catch(x){throw x.code==="EEXIST"?new f(`Refusing to overwrite ${p}.`,m.FAILURE):x}finally{await I?.close()}process.stdout.write(`Downloaded ${l(d)} to ${l(p)} (${D(R.byteLength)}).
303
+ `)}function Il(t){if(!t)return"oracle-file.bin";let e=/filename\*=UTF-8''([^;]+)/i.exec(t)?.[1];if(e)try{return decodeURIComponent(e.replace(/^"|"$/g,""))}catch{return"oracle-file.bin"}let n=/filename="?([^";]+)"?/i.exec(t)?.[1];return n?n.trim():"oracle-file.bin"}function xl(t){let e=sl(t.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!e||e==="."||e===".."?"oracle-file.bin":e}async function Sl(t,e){if(!t.body)return Buffer.alloc(0);let n=t.body.getReader(),r=[],o=0;try{for(;;){let{value:i,done:s}=await n.read();if(s)break;let a=Buffer.from(i);if(o+=a.byteLength,o>e)throw new f(`Oracle download exceeds the ${D(e)} limit.`,m.API_ERROR);r.push(a)}}catch(i){throw await n.cancel("Oracle download exceeded its byte limit.").catch(()=>{}),i}finally{n.releaseLock()}return Buffer.concat(r)}var Vi="https://crew.anyforge.ai",Tl=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output","workspace","print"]),Cl=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json"]);function _l(t){let e={positional:[],flags:{}};for(let n=0;n<t.length;n+=1){let r=t[n];if(!r.startsWith("-")){e.command?e.positional.push(r):e.command=r;continue}let o=r==="-h"?"help":r==="-V"?"version":r==="-f"?"force":r==="-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(Tl.has(i)){let a=s??t[++n];if(a===void 0)throw new y(`--${i} needs a value.`);if(i==="file"){let c=e.flags.file;e.flags.file=[...typeof c=="string"?[c]:Array.isArray(c)?c:[],a]}else e.flags[i]=a;continue}if(Cl.has(i)){e.flags[i]=s===void 0?!0:s!=="false";continue}throw new y(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return e}function Re(t,e){if(t===void 0||typeof t=="boolean")return;let n=Number(t);if(!Number.isFinite(n)||n<=0)throw new y(`--${e} must be a positive number, got "${t}".`);return n}function K(t){return typeof t=="string"?t:void 0}function Tr(t){return t===!0?!0:void 0}function $l(){console.log(`
304
+ ${z("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
305
+
306
+ ${z("USAGE")}
306
307
  npx @anyforge/control <command> [options]
307
308
 
308
- ${K("SETUP")}
309
+ ${z("SETUP")}
309
310
  init Authorise this device and patch local agent configs
310
311
  whoami Show the company, scopes and endpoint this key acts as
311
312
  status Check identity, local setup and recorded activity
312
313
  logout Clear the saved API key and revert patched configs
313
314
  apply-patch [file] Apply a unified diff (file or stdin) via git apply
314
315
 
315
- ${K("SKILLS")}
316
+ ${z("SKILLS")}
316
317
  skill install anyforge-platform
317
318
  Install the portable AnyForge platform guide
318
319
  (--scope project|user, --client agents|claude|codex)
319
320
 
320
- ${K("APPROVALS")} ${jt("(the gate that blocks a human)")}
321
+ ${z("APPROVALS")} ${Ut("(the gate that blocks a human)")}
321
322
  approvals List HIL approvals awaiting a decision
322
323
  approve <id> Approve one, optionally with --notes
323
324
  reject <id> Reject one, optionally with --notes
324
325
 
325
- ${K("CREWS")}
326
+ ${z("CREWS")}
326
327
  crews List crews (--active for running/paused only)
327
328
  crew <id> Show one crew, its status and recent output
328
329
  crew start <item> Dispatch a crew on a work item (--profile, --follow)
@@ -330,14 +331,14 @@ ${K("CREWS")}
330
331
  halt <id> Stop a crew
331
332
  resume <id> Resume a paused or halted crew
332
333
 
333
- ${K("WORK & WORKFLOWS")}
334
+ ${z("WORK & WORKFLOWS")}
334
335
  work List work items (--status, --type, --priority, --search).
335
336
  Paged: one page by default, --all walks every page
336
337
  workflows List operator workflows
337
338
  run <id> Dispatch a workflow run, with optional --input JSON
338
339
  ask <question> Ask the Oracle one question
339
340
 
340
- ${K("HOSTED ORACLE")}
341
+ ${z("HOSTED ORACLE")}
341
342
  oracle [prompt] Start an interactive hosted Oracle session
342
343
  oracle exec <text> Submit one read-only turn (--json or --stream-json)
343
344
  oracle resume Resume an Oracle session
@@ -348,7 +349,7 @@ ${K("HOSTED ORACLE")}
348
349
  oracle logout Revoke and clear the active workspace's Oracle grant (--all for every one)
349
350
  oracle --help Show Oracle options and slash commands
350
351
 
351
- ${K("MEASUREMENT")}
352
+ ${z("MEASUREMENT")}
352
353
  backtest-corpus Can this workspace be back-tested? Counts the incidents
353
354
  that could become graded replay cases (--days 30|90|180|365)
354
355
  review-interception Serious findings the reviewer raised on your pull requests,
@@ -356,9 +357,9 @@ ${K("MEASUREMENT")}
356
357
  review-coverage How many recorded pull requests got reviewed, how fast the
357
358
  author heard back, and what a limit stopped (--days 7|30|90|180)
358
359
 
359
- ${K("OPTIONS")}
360
+ ${z("OPTIONS")}
360
361
  --json Print the raw API payload instead of a table
361
- --endpoint <url> Override the base URL (default: ${jt(Ji)})
362
+ --endpoint <url> Override the base URL (default: ${Ut(Vi)})
362
363
  --limit <n> Page size on list commands (work: 1-200, default 50)
363
364
  --all work: follow the cursor until the backlog is exhausted
364
365
  --notes <text> approve/reject: reviewer notes, recorded in the audit trail
@@ -376,10 +377,10 @@ ${K("OPTIONS")}
376
377
  --help, -h Show this message
377
378
  --version, -V Print CLI version
378
379
 
379
- ${K("EXIT CODES")}
380
+ ${z("EXIT CODES")}
380
381
  0 ok 1 failure 2 usage 3 not authenticated 4 API error
381
382
 
382
- ${K("EXAMPLES")}
383
+ ${z("EXAMPLES")}
383
384
  anyforge approvals
384
385
  anyforge approve hil_123 --notes "ship it"
385
386
  anyforge crews --active --json | jq -r '.[].id'
@@ -393,11 +394,12 @@ ${K("EXAMPLES")}
393
394
  anyforge review-interception --days 30
394
395
  anyforge review-coverage --days 30
395
396
  anyforge ask "which initiatives slipped this cycle?"
396
- `)}function El(){console.log(`
397
- ${K("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
397
+ `)}function Pl(){console.log(`
398
+ ${z("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
398
399
 
399
- ${K("USAGE")}
400
+ ${z("USAGE")}
400
401
  anyforge oracle [initial prompt] [options] Start an interactive session
402
+ anyforge oracle -p <prompt> [options] Print one read-only answer and exit
401
403
  anyforge oracle exec <prompt|stdin> [options] Submit one read-only turn
402
404
  anyforge oracle resume [session-id] Resume a session in the terminal
403
405
  anyforge oracle sessions [--json] List sessions you can access
@@ -409,7 +411,8 @@ ${K("USAGE")}
409
411
  Revoke and remove the active (or named, or every) login
410
412
  anyforge oracle download <session> <file> --output <directory>
411
413
 
412
- ${K("OPTIONS")}
414
+ ${z("OPTIONS")}
415
+ -p, --print <prompt> Print one answer to stdout and exit (like oracle exec)
413
416
  --json Print one final JSON object (exec)
414
417
  --stream-json Print event JSONL followed by a final result (exec)
415
418
  --shared Share with the company (requires --program or --initiative)
@@ -431,7 +434,7 @@ CLI attachment limits are 10 MiB per file and 20 MiB total per turn. Files are
431
434
  uploaded only when named with --file or /attach. Generated files require an
432
435
  explicit \`oracle download\` destination; existing files are never overwritten.
433
436
 
434
- ${K("IN THE CONVERSATION")}
437
+ ${z("IN THE CONVERSATION")}
435
438
  /help Commands and keys /status Session, model, limits
436
439
  /new [shared] Start a conversation /clear Clear and start afresh
437
440
  /resume [id] Open a saved conversation /usage Turns and tokens so far
@@ -456,8 +459,8 @@ Examples:
456
459
  anyforge oracle login --workspace "Acme Engineering"
457
460
  anyforge oracle exec "What is blocked?" --workspace "Beta Labs"
458
461
  cat incident.log | anyforge oracle exec "Explain this log" --stream-json
459
- `)}async function Tl(t,e,n,r){let o=e.flags.json===!0,[i]=e.positional;if(t==="oracle")return zi({positional:e.positional,flags:e.flags,endpointOverride:r,endpoint:n});switch(t){case"init":return Vr({endpoint:n,force:e.flags.force===!0});case"logout":return oo();case"status":return uo({endpoint:r,json:o});case"whoami":return no({endpoint:r,json:o});case"apply-patch":return fo({patchFile:i,threeWay:e.flags["3way"]===!0,dryRun:e.flags["dry-run"]===!0});case"proxy":console.log(kl("Local proxy mode is coming in a future release.")),console.log(jt(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return Fo({subcommand:i,name:e.positional[1],scope:G(e.flags.scope),client:G(e.flags.client),force:e.flags.force===!0,json:o})}let s=await Ie(r);switch(t){case"approvals":return mo({creds:s,json:o,limit:be(e.flags.limit,"limit")});case"approve":return Gn({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:G(e.flags.notes)});case"reject":return Gn({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:G(e.flags.notes)});case"crews":return go({creds:s,json:o,status:G(e.flags.status),activeOnly:Er(e.flags.active),limit:be(e.flags.limit,"limit")});case"crew":{let[a,c]=e.positional;return a==="start"?vo({creds:s,json:o,workItemId:c,profileId:G(e.flags.profile),follow:e.flags.follow===!0,intervalSeconds:be(e.flags.interval,"interval")}):a==="follow"?Hn({creds:s,json:o,crewId:c,intervalSeconds:be(e.flags.interval,"interval")}):ho({creds:s,json:o,crewId:i,messages:be(e.flags.messages,"messages")})}case"halt":return zn({creds:s,json:o,crewId:i,action:"halt"});case"resume":return zn({creds:s,json:o,crewId:i,action:"resume"});case"work":return ko({creds:s,json:o,status:G(e.flags.status),type:G(e.flags.type),priority:G(e.flags.priority),initiative:G(e.flags.initiative),program:G(e.flags.program),search:G(e.flags.search),assignee:G(e.flags.assignee),includeArchived:Er(e.flags.archived),limit:be(e.flags.limit,"limit"),all:Er(e.flags.all)});case"workflows":return Ao({creds:s,json:o});case"run":return Io({creds:s,json:o,workflowId:i,input:G(e.flags.input)});case"ask":return xo({creds:s,json:o,question:e.positional.join(" "),context:G(e.flags.context)});case"backtest-corpus":return Eo({creds:s,json:o,days:be(e.flags.days,"days")});case"review-interception":return Co({creds:s,json:o,days:be(e.flags.days,"days")});case"review-coverage":return _o({creds:s,json:o,days:be(e.flags.days,"days")});default:throw new y(`Unknown command: ${t}`,"Run `anyforge --help` for the command list.")}}async function Cl(){let t;try{t=xl(process.argv.slice(2))}catch(r){Yi(r);return}if(t.flags.version===!0){let r=await Promise.resolve().then(()=>(Ar(),kr));console.log(r.default.version);return}if(t.command==="oracle"&&t.flags.help===!0){El();return}if(t.flags.help===!0||!t.command){Sl();return}let e=G(t.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=e??Ji;try{if(t.command!=="oracle"){let o=["approve","codebase","file","output","read-only","shared","stream-json","workspace","write"].find(i=>t.flags[i]!==void 0);if(o)throw new y(`--${o} is only supported by the oracle command.`)}await Tl(t.command,t,n,e)}catch(r){Yi(r)}}function Yi(t){t instanceof f&&(process.stderr.write(Hi("Error: ")+d(t.message)+`
460
- `),t.hint?process.stderr.write(jt(d(t.hint))+`
461
- `):t instanceof y&&process.stderr.write(jt("Run `anyforge --help`.")+`
462
- `),process.exit(t.exitCode)),process.stderr.write(Hi("Error: ")+d(t instanceof Error?t.message:String(t))+`
463
- `),process.exit(m.FAILURE)}Cl();
462
+ `)}async function Ll(t,e,n,r){let o=e.flags.json===!0,[i]=e.positional;if(t==="oracle")return Yi({positional:e.positional,flags:e.flags,endpointOverride:r,endpoint:n});switch(t){case"init":return Xr({endpoint:n,force:e.flags.force===!0});case"logout":return so();case"status":return fo({endpoint:r,json:o});case"whoami":return oo({endpoint:r,json:o});case"apply-patch":return go({patchFile:i,threeWay:e.flags["3way"]===!0,dryRun:e.flags["dry-run"]===!0});case"proxy":console.log(El("Local proxy mode is coming in a future release.")),console.log(Ut(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return jo({subcommand:i,name:e.positional[1],scope:K(e.flags.scope),client:K(e.flags.client),force:e.flags.force===!0,json:o})}let s=await xe(r);switch(t){case"approvals":return ho({creds:s,json:o,limit:Re(e.flags.limit,"limit")});case"approve":return Gn({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:K(e.flags.notes)});case"reject":return Gn({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:K(e.flags.notes)});case"crews":return wo({creds:s,json:o,status:K(e.flags.status),activeOnly:Tr(e.flags.active),limit:Re(e.flags.limit,"limit")});case"crew":{let[a,c]=e.positional;return a==="start"?Ro({creds:s,json:o,workItemId:c,profileId:K(e.flags.profile),follow:e.flags.follow===!0,intervalSeconds:Re(e.flags.interval,"interval")}):a==="follow"?Hn({creds:s,json:o,crewId:c,intervalSeconds:Re(e.flags.interval,"interval")}):yo({creds:s,json:o,crewId:i,messages:Re(e.flags.messages,"messages")})}case"halt":return zn({creds:s,json:o,crewId:i,action:"halt"});case"resume":return zn({creds:s,json:o,crewId:i,action:"resume"});case"work":return Io({creds:s,json:o,status:K(e.flags.status),type:K(e.flags.type),priority:K(e.flags.priority),initiative:K(e.flags.initiative),program:K(e.flags.program),search:K(e.flags.search),assignee:K(e.flags.assignee),includeArchived:Tr(e.flags.archived),limit:Re(e.flags.limit,"limit"),all:Tr(e.flags.all)});case"workflows":return xo({creds:s,json:o});case"run":return So({creds:s,json:o,workflowId:i,input:K(e.flags.input)});case"ask":return Eo({creds:s,json:o,question:e.positional.join(" "),context:K(e.flags.context)});case"backtest-corpus":return Co({creds:s,json:o,days:Re(e.flags.days,"days")});case"review-interception":return $o({creds:s,json:o,days:Re(e.flags.days,"days")});case"review-coverage":return Po({creds:s,json:o,days:Re(e.flags.days,"days")});default:throw new y(`Unknown command: ${t}`,"Run `anyforge --help` for the command list.")}}async function Nl(){let t;try{t=_l(process.argv.slice(2))}catch(r){Qi(r);return}if(t.flags.version===!0){let r=await Promise.resolve().then(()=>(Ir(),Ar));console.log(r.default.version);return}if(t.command==="oracle"&&t.flags.help===!0){Pl();return}if(t.flags.help===!0||!t.command){$l();return}let e=K(t.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=e??Vi;try{if(t.command!=="oracle"){let o=["approve","codebase","file","output","print","read-only","shared","stream-json","workspace","write"].find(i=>t.flags[i]!==void 0);if(o)throw new y(`--${o} is only supported by the oracle command.`)}await Ll(t.command,t,n,e)}catch(r){Qi(r)}}function Qi(t){t instanceof f&&(process.stderr.write(Ji("Error: ")+l(t.message)+`
463
+ `),t.hint?process.stderr.write(Ut(l(t.hint))+`
464
+ `):t instanceof y&&process.stderr.write(Ut("Run `anyforge --help`.")+`
465
+ `),process.exit(t.exitCode)),process.stderr.write(Ji("Error: ")+l(t instanceof Error?t.message:String(t))+`
466
+ `),process.exit(m.FAILURE)}Nl();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anyforge/control",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "AnyForge CLI — hosted Oracle conversations, a governed LLM proxy, and a scriptable client for approvals, crews, work items and workflows.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://anyforge.ai",